11import  'package:analyzer/dart/ast/ast.dart' ;
2+ import  'package:analyzer/dart/ast/visitor.dart' ;
23import  'package:collection/collection.dart' ;
34import  'package:dart_eval/dart_eval_bridge.dart' ;
45import  'package:dart_eval/src/eval/compiler/builtins.dart' ;
@@ -446,45 +447,136 @@ class Compiler implements BridgeDeclarationRegistry, EvalPluginRegistry {
446447    _ctx.topLevelGlobalIndices =  _topLevelGlobalIndices;
447448
448449    try  {
449-       /// Compile statics first so we can infer their type 
450- forEach ((key, value) {
451-         final  visibleInLibrary =  visibleDeclarationsByIndex[key];
452-         if  (visibleInLibrary ==  null ) {
453-           return ;
454-         }
455-         value.forEach ((name, tlDeclaration) {
456-           if  (tlDeclaration.isBridge ||  ! visibleInLibrary.containsKey (name)) {
457-             return ;
458-           }
459-           final  declaration =  tlDeclaration.declaration! ;
460-           _ctx.library =  key;
450+       // Keep track of declarations we've already compiled to avoid processing them in the final pass. 
451+       final  alreadyCompiled =  < AstNode > {};
452+ 
453+       // We iterate once to gather consts for sorting and compile non-const statics immediately. 
454+ 
455+       final  constDeclarationsByContainer = 
456+           < AstNode , List <_ConstDeclarationInfo >> {};
457+ 
458+       _topLevelDeclarationsMap.forEach ((libraryIndex, declarations) {
459+         declarations.forEach ((name, declOrBridge) {
460+           if  (declOrBridge.isBridge) return ;
461+           final  declaration =  declOrBridge.declaration! ;
462+ 
463+           // Handle top-level variables 
461464          if  (declaration is  VariableDeclaration  && 
462-               declaration.parent! .parent is  TopLevelVariableDeclaration ) {
463-             compileDeclaration (declaration, _ctx);
464-             _ctx.resetStack ();
465-           } else  if  (declaration is  ClassDeclaration ) {
466-             _ctx.currentClass =  declaration;
467-             for  (final  d in  declaration.members
468-                 .whereType <FieldDeclaration >()
469-                 .where ((e) =>  e.isStatic)) {
470-               compileFieldDeclaration (- 1 , d, _ctx, declaration);
465+               declaration.parent? .parent is  TopLevelVariableDeclaration ) {
466+             final  topLevelVarDecl = 
467+                 declaration.parent! .parent as  TopLevelVariableDeclaration ;
468+             if  (topLevelVarDecl.variables.isConst) {
469+               (constDeclarationsByContainer[topLevelVarDecl] ?? =  []).add (
470+                   _ConstDeclarationInfo (
471+                       declaration, topLevelVarDecl, declOrBridge.sourceLib));
472+             } else  {
473+               _ctx.library =  declOrBridge.sourceLib;
474+               compileDeclaration (declaration, _ctx);
475+               alreadyCompiled.add (declaration);
471476              _ctx.resetStack ();
472477            }
473-             _ctx.currentClass =  null ;
474-           } else  if  (declaration is  EnumDeclaration ) {
478+           } else  if  (declaration is  ClassDeclaration ) {
475479            _ctx.currentClass =  declaration;
476-             for  (final  d in  declaration.members
477-                 .whereType <FieldDeclaration >()
478-                 .where ((e) =>  e.isStatic)) {
479-               compileFieldDeclaration (- 1 , d, _ctx, declaration);
480-               _ctx.resetStack ();
480+             for  (final  member
481+                 in  declaration.members.whereType <FieldDeclaration >()) {
482+               if  (member.isStatic) {
483+                 if  (member.fields.isConst) {
484+                   for  (final  fieldVar in  member.fields.variables) {
485+                     final  fqName = 
486+                         '${declaration .name .lexeme }.${fieldVar .name .lexeme }' ;
487+                     final  fieldDeclOrBridge = 
488+                         _topLevelDeclarationsMap[libraryIndex]! [fqName];
489+                     if  (fieldDeclOrBridge !=  null ) {
490+                       (constDeclarationsByContainer[declaration] ?? =  []).add (
491+                           _ConstDeclarationInfo (fieldVar, declaration,
492+                               fieldDeclOrBridge.sourceLib));
493+                     }
494+                   }
495+                 } else  {
496+                   _ctx.library =  libraryIndex;
497+                   compileFieldDeclaration (- 1 , member, _ctx, declaration);
498+                   alreadyCompiled.add (member);
499+                   _ctx.resetStack ();
500+                 }
501+               }
481502            }
482503            _ctx.currentClass =  null ;
483504          }
484505        });
485506      });
486507
487-       /// Compile the rest of the declarations 
508+       constDeclarationsByContainer.forEach ((container, constDecls) {
509+         if  (constDecls.isEmpty) return ;
510+ 
511+         _ctx.library =  constDecls.first.libraryIndex;
512+ 
513+         final  fieldMap =  {for  (var  d in  constDecls) d.name:  d};
514+         final  fieldNames =  fieldMap.keys.toSet ();
515+         final  Map <String , Set <String >> adjList =  {
516+           for  (var  name in  fieldNames) name:  {}
517+         };
518+         final  Map <String , int > inDegrees =  {
519+           for  (var  name in  fieldNames) name:  0 
520+         };
521+ 
522+         // Build dependency graph 
523+         for  (final  constDeclInfo in  constDecls) {
524+           final  dependerName =  constDeclInfo.name;
525+           final  initializer =  constDeclInfo.variable.initializer;
526+           if  (initializer !=  null ) {
527+             final  dependencyVisitor =  _DependencyVisitor (fieldNames);
528+             initializer.visitChildren (dependencyVisitor);
529+             for  (final  dependencyName in  dependencyVisitor.dependencies) {
530+               if  (adjList[dependencyName]! .add (dependerName)) {
531+                 inDegrees[dependerName] =  (inDegrees[dependerName] ??  0 ) +  1 ;
532+               }
533+             }
534+           }
535+         }
536+ 
537+         // Perform topological sort 
538+         final  sortedOrder =  < _ConstDeclarationInfo > [];
539+         final  queue =  < String > [];
540+         fieldNames.where ((name) =>  inDegrees[name] ==  0 ).forEach (queue.add);
541+ 
542+         while  (queue.isNotEmpty) {
543+           final  currentName =  queue.removeAt (0 );
544+           sortedOrder.add (fieldMap[currentName]! );
545+           for  (final  neighborName in  adjList[currentName]! ) {
546+             inDegrees[neighborName] =  inDegrees[neighborName]!  -  1 ;
547+             if  (inDegrees[neighborName] ==  0 ) {
548+               queue.add (neighborName);
549+             }
550+           }
551+         }
552+ 
553+         if  (sortedOrder.length <  constDecls.length) {
554+           final  containerName =  container is  NamedCompilationUnitMember 
555+               ?  '"${container .name .lexeme }"' 
556+               :  'the library' ;
557+           throw  CompileError (
558+               'Circular dependency detected in const declarations in $containerName .' );
559+         }
560+ 
561+         // Compile sorted consts 
562+         for  (final  declInfo in  sortedOrder) {
563+           final  parentNode =  declInfo.variable.parent! .parent! ;
564+           if  (parentNode is  TopLevelVariableDeclaration ) {
565+             compileDeclaration (declInfo.variable, _ctx);
566+             alreadyCompiled.add (declInfo.variable);
567+           } else  if  (parentNode is  FieldDeclaration  && 
568+               declInfo.parent is  ClassDeclaration ) {
569+             _ctx.currentClass =  declInfo.parent as  ClassDeclaration ;
570+             compileFieldDeclaration (
571+                 - 1 , parentNode, _ctx, declInfo.parent as  ClassDeclaration );
572+             _ctx.currentClass =  null ;
573+             alreadyCompiled.add (parentNode);
574+           }
575+           _ctx.resetStack ();
576+         }
577+       });
578+ 
579+       // Compile non-statics 
488580      _topLevelDeclarationsMap.forEach ((key, value) {
489581        _ctx.topLevelDeclarationPositions[key] =  {};
490582        _ctx.instanceDeclarationPositions[key] =  {};
@@ -498,11 +590,18 @@ class Compiler implements BridgeDeclarationRegistry, EvalPluginRegistry {
498590            return ;
499591          }
500592          final  declaration =  tlDeclaration.declaration! ;
593+ 
594+           // We've already compiled all variable declarations that are top-level or static fields. 
595+           // This pass is for compiling the bodies of classes and functions. 
501596          if  (declaration is  ConstructorDeclaration  || 
502597              declaration is  MethodDeclaration  || 
503598              declaration is  VariableDeclaration ) {
599+             // This skips top-level vars that were already compiled. 
504600            return ;
505601          }
602+ 
603+           if  (alreadyCompiled.contains (declaration)) return ;
604+ 
506605          _ctx.library =  key;
507606          compileDeclaration (declaration, _ctx);
508607          _ctx.resetStack ();
@@ -1216,3 +1315,41 @@ class _Import {
12161315        base .resolveUri (uri), import.prefix? .name, import.combinators);
12171316  }
12181317}
1318+ 
1319+ // Helper class to hold const declarations for sorting 
1320+ class  _ConstDeclarationInfo  {
1321+   _ConstDeclarationInfo (this .variable, this .parent, this .libraryIndex);
1322+ 
1323+   /// The VariableDeclaration itself (e.g., `b = 1.0` ). 
1324+ final  VariableDeclaration  variable;
1325+ 
1326+   /// The parent node (either a TopLevelVariableDeclaration or a ClassDeclaration). 
1327+ final  AstNode  parent;
1328+ 
1329+   /// The library index where this declaration is defined. 
1330+ final  int  libraryIndex;
1331+ 
1332+   String  get  name =>  variable.name.lexeme;
1333+ }
1334+ 
1335+ // Add this class at the end of compiler.dart 
1336+ 
1337+ /// A simple visitor to find identifiers within an expression that match a given set of names. 
1338+ class  _DependencyVisitor  extends  RecursiveAstVisitor <void > {
1339+   _DependencyVisitor (this .availableNames);
1340+ 
1341+   /// The set of all possible dependency names we are looking for (e.g., all static const fields in the class). 
1342+ final  Set <String > availableNames;
1343+ 
1344+   /// The set of dependencies found in the visited expression. 
1345+ final  Set <String > dependencies =  {};
1346+ 
1347+   @override 
1348+   void  visitSimpleIdentifier (SimpleIdentifier  node) {
1349+     // If this identifier is one of the fields we are analyzing, it's a dependency. 
1350+     if  (availableNames.contains (node.name)) {
1351+       dependencies.add (node.name);
1352+     }
1353+     super .visitSimpleIdentifier (node);
1354+   }
1355+ }
0 commit comments