@@ -45,6 +45,9 @@ pub struct SymbolTable {
45
45
/// A list of sub-scopes in the order as found in the
46
46
/// AST nodes.
47
47
pub sub_tables : Vec < SymbolTable > ,
48
+
49
+ /// Variable names in definition order (parameters first, then locals)
50
+ pub varnames : Vec < String > ,
48
51
}
49
52
50
53
impl SymbolTable {
@@ -56,6 +59,7 @@ impl SymbolTable {
56
59
is_nested,
57
60
symbols : IndexMap :: default ( ) ,
58
61
sub_tables : vec ! [ ] ,
62
+ varnames : Vec :: new ( ) ,
59
63
}
60
64
}
61
65
@@ -573,6 +577,8 @@ struct SymbolTableBuilder<'src> {
573
577
tables : Vec < SymbolTable > ,
574
578
future_annotations : bool ,
575
579
source_code : SourceCode < ' src > ,
580
+ // Current scope's varnames being collected (temporary storage)
581
+ current_varnames : Vec < String > ,
576
582
}
577
583
578
584
/// Enum to indicate in what mode an expression
@@ -595,6 +601,7 @@ impl<'src> SymbolTableBuilder<'src> {
595
601
tables : vec ! [ ] ,
596
602
future_annotations : false ,
597
603
source_code,
604
+ current_varnames : Vec :: new ( ) ,
598
605
} ;
599
606
this. enter_scope ( "top" , SymbolTableType :: Module , 0 ) ;
600
607
this
@@ -605,6 +612,8 @@ impl SymbolTableBuilder<'_> {
605
612
fn finish ( mut self ) -> Result < SymbolTable , SymbolTableError > {
606
613
assert_eq ! ( self . tables. len( ) , 1 ) ;
607
614
let mut symbol_table = self . tables . pop ( ) . unwrap ( ) ;
615
+ // Save varnames for the top-level module scope
616
+ symbol_table. varnames = self . current_varnames ;
608
617
analyze_symbol_table ( & mut symbol_table) ?;
609
618
Ok ( symbol_table)
610
619
}
@@ -621,7 +630,9 @@ impl SymbolTableBuilder<'_> {
621
630
622
631
/// Pop symbol table and add to sub table of parent table.
623
632
fn leave_scope ( & mut self ) {
624
- let table = self . tables . pop ( ) . unwrap ( ) ;
633
+ let mut table = self . tables . pop ( ) . unwrap ( ) ;
634
+ // Save the collected varnames to the symbol table
635
+ table. varnames = std:: mem:: take ( & mut self . current_varnames ) ;
625
636
self . tables . last_mut ( ) . unwrap ( ) . sub_tables . push ( table) ;
626
637
}
627
638
@@ -1533,18 +1544,43 @@ impl SymbolTableBuilder<'_> {
1533
1544
}
1534
1545
SymbolUsage :: Parameter => {
1535
1546
flags. insert ( SymbolFlags :: PARAMETER ) ;
1547
+ // Parameters are always added to varnames first
1548
+ let name_str = symbol. name . clone ( ) ;
1549
+ if !self . current_varnames . contains ( & name_str) {
1550
+ self . current_varnames . push ( name_str) ;
1551
+ }
1536
1552
}
1537
1553
SymbolUsage :: AnnotationParameter => {
1538
1554
flags. insert ( SymbolFlags :: PARAMETER | SymbolFlags :: ANNOTATED ) ;
1555
+ // Annotated parameters are also added to varnames
1556
+ let name_str = symbol. name . clone ( ) ;
1557
+ if !self . current_varnames . contains ( & name_str) {
1558
+ self . current_varnames . push ( name_str) ;
1559
+ }
1539
1560
}
1540
1561
SymbolUsage :: AnnotationAssigned => {
1541
1562
flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: ANNOTATED ) ;
1542
1563
}
1543
1564
SymbolUsage :: Assigned => {
1544
1565
flags. insert ( SymbolFlags :: ASSIGNED ) ;
1566
+ // Local variables (assigned) are added to varnames if they are local scope
1567
+ // and not already in varnames
1568
+ if symbol. scope == SymbolScope :: Local {
1569
+ let name_str = symbol. name . clone ( ) ;
1570
+ if !self . current_varnames . contains ( & name_str) {
1571
+ self . current_varnames . push ( name_str) ;
1572
+ }
1573
+ }
1545
1574
}
1546
1575
SymbolUsage :: AssignedNamedExprInComprehension => {
1547
1576
flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: ASSIGNED_IN_COMPREHENSION ) ;
1577
+ // Named expressions in comprehensions might also be locals
1578
+ if symbol. scope == SymbolScope :: Local {
1579
+ let name_str = symbol. name . clone ( ) ;
1580
+ if !self . current_varnames . contains ( & name_str) {
1581
+ self . current_varnames . push ( name_str) ;
1582
+ }
1583
+ }
1548
1584
}
1549
1585
SymbolUsage :: Global => {
1550
1586
symbol. scope = SymbolScope :: GlobalExplicit ;
0 commit comments