@@ -10,17 +10,24 @@ namespace Bond.Parser.Parser;
1010/// </summary>
1111public class SymbolTable
1212{
13- private readonly List < Declaration > _declarations = [ ] ;
13+ private readonly List < Declaration > _globalDeclarations = [ ] ;
14+ private readonly Stack < List < AliasDeclaration > > _aliasScopes = new ( ) ;
1415 private readonly HashSet < string > _processedImports = [ ] ;
1516
1617 /// <summary>
1718 /// Adds a declaration to the symbol table with duplicate checking
1819 /// </summary>
19- public void AddDeclaration ( Declaration declaration , Namespace [ ] currentNamespaces )
20+ public void AddDeclaration ( Declaration declaration )
2021 {
22+ if ( declaration is AliasDeclaration alias )
23+ {
24+ AddAliasDeclaration ( alias ) ;
25+ return ;
26+ }
27+
2128 // Find duplicates in the same namespace
22- var duplicates = _declarations
23- . Where ( d => d . Name == declaration . Name && d . Namespaces . Any ( ns1 => currentNamespaces . Any ( ns2 => NamespacesMatch ( ns1 , ns2 ) ) ) )
29+ var duplicates = _globalDeclarations
30+ . Where ( d => d . Name == declaration . Name && d . Namespaces . Any ( ns1 => declaration . Namespaces . Any ( ns2 => NamespacesMatch ( ns1 , ns2 ) ) ) )
2431 . ToList ( ) ;
2532
2633 foreach ( var duplicate in duplicates )
@@ -33,18 +40,32 @@ public void AddDeclaration(Declaration declaration, Namespace[] currentNamespace
3340 }
3441 }
3542
36- _declarations . Add ( declaration ) ;
43+ _globalDeclarations . Add ( declaration ) ;
3744 }
3845
3946 /// <summary>
4047 /// Finds a symbol by qualified name in the given namespaces
4148 /// </summary>
4249 public Declaration ? FindSymbol ( string [ ] qualifiedName , Namespace [ ] currentNamespaces )
50+ {
51+ var alias = FindAlias ( qualifiedName , currentNamespaces ) ;
52+ if ( alias != null )
53+ {
54+ return alias ;
55+ }
56+
57+ return FindGlobalSymbol ( qualifiedName , currentNamespaces ) ;
58+ }
59+
60+ /// <summary>
61+ /// Finds a symbol by qualified name in the given namespaces from global declarations
62+ /// </summary>
63+ private Declaration ? FindGlobalSymbol ( string [ ] qualifiedName , Namespace [ ] currentNamespaces )
4364 {
4465 if ( qualifiedName . Length == 1 )
4566 {
4667 // Unqualified name - search in current namespaces
47- return _declarations . FirstOrDefault ( d =>
68+ return _globalDeclarations . FirstOrDefault ( d =>
4869 d . Name == qualifiedName [ 0 ] &&
4970 d . Namespaces . Any ( ns1 => currentNamespaces . Any ( ns2 => NamespacesMatch ( ns1 , ns2 ) ) ) ) ;
5071 }
@@ -54,7 +75,7 @@ public void AddDeclaration(Declaration declaration, Namespace[] currentNamespace
5475 var namespacePart = qualifiedName [ ..^ 1 ] ;
5576 var namePart = qualifiedName [ ^ 1 ] ;
5677
57- return _declarations . FirstOrDefault ( d =>
78+ return _globalDeclarations . FirstOrDefault ( d =>
5879 d . Name == namePart &&
5980 d . Namespaces . Any ( ns => ns . Name . SequenceEqual ( namespacePart ) ) ) ;
6081 }
@@ -65,7 +86,7 @@ public void AddDeclaration(Declaration declaration, Namespace[] currentNamespace
6586 /// </summary>
6687 public StructDeclaration ? FindStruct ( string [ ] qualifiedName , Namespace [ ] currentNamespaces )
6788 {
68- var symbol = FindSymbol ( qualifiedName , currentNamespaces ) ;
89+ var symbol = FindGlobalSymbol ( qualifiedName , currentNamespaces ) ;
6990 return symbol as StructDeclaration ;
7091 }
7192
@@ -88,15 +109,87 @@ public void MarkImportProcessed(string canonicalPath)
88109 /// <summary>
89110 /// Gets all declarations
90111 /// </summary>
91- public IReadOnlyList < Declaration > Declarations => _declarations . AsReadOnly ( ) ;
112+ public IReadOnlyList < Declaration > GlobalDeclarations => _globalDeclarations . AsReadOnly ( ) ;
113+
114+ /// <summary>
115+ /// Pushes a new alias scope for a file.
116+ /// </summary>
117+ public void PushAliasScope ( )
118+ {
119+ _aliasScopes . Push ( [ ] ) ;
120+ }
121+
122+ /// <summary>
123+ /// Pops the current alias scope.
124+ /// </summary>
125+ public void PopAliasScope ( )
126+ {
127+ if ( _aliasScopes . Count == 0 )
128+ {
129+ throw new InvalidOperationException ( "Alias scope stack is empty" ) ;
130+ }
131+
132+ _aliasScopes . Pop ( ) ;
133+ }
92134
93135 /// <summary>
94136 /// Clears all declarations from the symbol table
95137 /// </summary>
96- public void Clear ( )
138+ public void ClearGlobalDeclarations ( )
97139 {
98- _declarations . Clear ( ) ;
99- // Don't clear processed imports as those are still valid
140+ _globalDeclarations . Clear ( ) ;
141+ }
142+
143+ /// <summary>
144+ /// Clears all alias scopes
145+ /// </summary>
146+ public void ClearAliasScopes ( )
147+ {
148+ _aliasScopes . Clear ( ) ;
149+ }
150+
151+ private void AddAliasDeclaration ( AliasDeclaration alias )
152+ {
153+ if ( _aliasScopes . Count == 0 )
154+ {
155+ throw new InvalidOperationException ( "Alias scope is not initialized" ) ;
156+ }
157+
158+ var scope = _aliasScopes . Peek ( ) ;
159+ var duplicates = scope
160+ . Where ( d => d . Name == alias . Name && d . Namespaces . Any ( ns1 => alias . Namespaces . Any ( ns2 => NamespacesMatch ( ns1 , ns2 ) ) ) )
161+ . ToList ( ) ;
162+
163+ if ( duplicates . Count > 0 )
164+ {
165+ throw new InvalidOperationException (
166+ $ "Duplicate declaration: alias '{ alias . Name } ' was already declared as alias") ;
167+ }
168+
169+ scope . Add ( alias ) ;
170+ }
171+
172+ private AliasDeclaration ? FindAlias ( string [ ] qualifiedName , Namespace [ ] currentNamespaces )
173+ {
174+ if ( _aliasScopes . Count == 0 )
175+ {
176+ return null ;
177+ }
178+
179+ var scope = _aliasScopes . Peek ( ) ;
180+
181+ if ( qualifiedName . Length == 1 )
182+ {
183+ return scope . FirstOrDefault ( d =>
184+ d . Name == qualifiedName [ 0 ] &&
185+ d . Namespaces . Any ( ns1 => currentNamespaces . Any ( ns2 => NamespacesMatch ( ns1 , ns2 ) ) ) ) ;
186+ }
187+
188+ var namespacePart = qualifiedName [ ..^ 1 ] ;
189+ var namePart = qualifiedName [ ^ 1 ] ;
190+ return scope . FirstOrDefault ( d =>
191+ d . Name == namePart &&
192+ d . Namespaces . Any ( ns => ns . Name . SequenceEqual ( namespacePart ) ) ) ;
100193 }
101194
102195 private static bool NamespacesMatch ( Namespace ns1 , Namespace ns2 )
0 commit comments