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,135 @@ 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+       final  constDeclarationsByContainer = 
455+           < AstNode , List <_ConstDeclarationInfo >> {};
456+ 
457+       _topLevelDeclarationsMap.forEach ((libraryIndex, declarations) {
458+         declarations.forEach ((name, declOrBridge) {
459+           if  (declOrBridge.isBridge) return ;
460+           final  declaration =  declOrBridge.declaration! ;
461+ 
462+           // Handle top-level variables 
461463          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);
464+               declaration.parent? .parent is  TopLevelVariableDeclaration ) {
465+             final  topLevelVarDecl = 
466+                 declaration.parent! .parent as  TopLevelVariableDeclaration ;
467+             if  (topLevelVarDecl.variables.isConst) {
468+               (constDeclarationsByContainer[topLevelVarDecl] ?? =  []).add (
469+                   _ConstDeclarationInfo (
470+                       declaration, topLevelVarDecl, declOrBridge.sourceLib));
471+             } else  {
472+               _ctx.library =  declOrBridge.sourceLib;
473+               compileDeclaration (declaration, _ctx);
474+               alreadyCompiled.add (declaration);
471475              _ctx.resetStack ();
472476            }
473-             _ctx.currentClass =  null ;
474-           } else  if  (declaration is  EnumDeclaration ) {
477+           } else  if  (declaration is  ClassDeclaration ) {
475478            _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 ();
479+             for  (final  member
480+                 in  declaration.members.whereType <FieldDeclaration >()) {
481+               if  (member.isStatic) {
482+                 if  (member.fields.isConst) {
483+                   for  (final  fieldVar in  member.fields.variables) {
484+                     final  fqName = 
485+                         '${declaration .name .lexeme }.${fieldVar .name .lexeme }' ;
486+                     final  fieldDeclOrBridge = 
487+                         _topLevelDeclarationsMap[libraryIndex]! [fqName];
488+                     if  (fieldDeclOrBridge !=  null ) {
489+                       (constDeclarationsByContainer[declaration] ?? =  []).add (
490+                           _ConstDeclarationInfo (fieldVar, declaration,
491+                               fieldDeclOrBridge.sourceLib));
492+                     }
493+                   }
494+                 } else  {
495+                   _ctx.library =  libraryIndex;
496+                   compileFieldDeclaration (- 1 , member, _ctx, declaration);
497+                   alreadyCompiled.add (member);
498+                   _ctx.resetStack ();
499+                 }
500+               }
481501            }
482502            _ctx.currentClass =  null ;
483503          }
484504        });
485505      });
486506
487-       /// Compile the rest of the declarations 
507+       constDeclarationsByContainer.forEach ((container, constDecls) {
508+         if  (constDecls.isEmpty) return ;
509+ 
510+         _ctx.library =  constDecls.first.libraryIndex;
511+ 
512+         final  fieldMap =  {for  (var  d in  constDecls) d.name:  d};
513+         final  fieldNames =  fieldMap.keys.toSet ();
514+         final  Map <String , Set <String >> adjList =  {
515+           for  (var  name in  fieldNames) name:  {}
516+         };
517+         final  Map <String , int > inDegrees =  {
518+           for  (var  name in  fieldNames) name:  0 
519+         };
520+ 
521+         // Build dependency graph 
522+         for  (final  constDeclInfo in  constDecls) {
523+           final  dependerName =  constDeclInfo.name;
524+           final  initializer =  constDeclInfo.variable.initializer;
525+           if  (initializer !=  null ) {
526+             final  dependencyVisitor =  _DependencyVisitor (fieldNames);
527+             initializer.visitChildren (dependencyVisitor);
528+             for  (final  dependencyName in  dependencyVisitor.dependencies) {
529+               if  (adjList[dependencyName]! .add (dependerName)) {
530+                 inDegrees[dependerName] =  (inDegrees[dependerName] ??  0 ) +  1 ;
531+               }
532+             }
533+           }
534+         }
535+ 
536+         // Perform topological sort 
537+         final  sortedOrder =  < _ConstDeclarationInfo > [];
538+         final  queue =  < String > [];
539+         fieldNames.where ((name) =>  inDegrees[name] ==  0 ).forEach (queue.add);
540+ 
541+         while  (queue.isNotEmpty) {
542+           final  currentName =  queue.removeAt (0 );
543+           sortedOrder.add (fieldMap[currentName]! );
544+           for  (final  neighborName in  adjList[currentName]! ) {
545+             inDegrees[neighborName] =  inDegrees[neighborName]!  -  1 ;
546+             if  (inDegrees[neighborName] ==  0 ) {
547+               queue.add (neighborName);
548+             }
549+           }
550+         }
551+ 
552+         if  (sortedOrder.length <  constDecls.length) {
553+           final  containerName =  container is  NamedCompilationUnitMember 
554+               ?  '"${container .name .lexeme }"' 
555+               :  'the library' ;
556+           throw  CompileError (
557+               'Circular dependency detected in const declarations in $containerName .' );
558+         }
559+ 
560+         // Compile sorted consts 
561+         for  (final  declInfo in  sortedOrder) {
562+           final  parentNode =  declInfo.variable.parent! .parent! ;
563+           if  (parentNode is  TopLevelVariableDeclaration ) {
564+             compileDeclaration (declInfo.variable, _ctx);
565+             alreadyCompiled.add (declInfo.variable);
566+           } else  if  (parentNode is  FieldDeclaration  && 
567+               declInfo.parent is  ClassDeclaration ) {
568+             _ctx.currentClass =  declInfo.parent as  ClassDeclaration ;
569+             compileFieldDeclaration (
570+                 - 1 , parentNode, _ctx, declInfo.parent as  ClassDeclaration );
571+             _ctx.currentClass =  null ;
572+             alreadyCompiled.add (parentNode);
573+           }
574+           _ctx.resetStack ();
575+         }
576+       });
577+ 
578+       // Compile non-statics 
488579      _topLevelDeclarationsMap.forEach ((key, value) {
489580        _ctx.topLevelDeclarationPositions[key] =  {};
490581        _ctx.instanceDeclarationPositions[key] =  {};
@@ -498,11 +589,18 @@ class Compiler implements BridgeDeclarationRegistry, EvalPluginRegistry {
498589            return ;
499590          }
500591          final  declaration =  tlDeclaration.declaration! ;
592+ 
593+           // We've already compiled all variable declarations that are top-level or static fields. 
594+           // This pass is for compiling the bodies of classes and functions. 
501595          if  (declaration is  ConstructorDeclaration  || 
502596              declaration is  MethodDeclaration  || 
503597              declaration is  VariableDeclaration ) {
598+             // This skips top-level vars that were already compiled. 
504599            return ;
505600          }
601+ 
602+           if  (alreadyCompiled.contains (declaration)) return ;
603+ 
506604          _ctx.library =  key;
507605          compileDeclaration (declaration, _ctx);
508606          _ctx.resetStack ();
@@ -1216,3 +1314,31 @@ class _Import {
12161314        base .resolveUri (uri), import.prefix? .name, import.combinators);
12171315  }
12181316}
1317+ 
1318+ class  _ConstDeclarationInfo  {
1319+   _ConstDeclarationInfo (this .variable, this .parent, this .libraryIndex);
1320+ 
1321+   final  VariableDeclaration  variable;
1322+ 
1323+   final  AstNode  parent;
1324+ 
1325+   final  int  libraryIndex;
1326+ 
1327+   String  get  name =>  variable.name.lexeme;
1328+ }
1329+ 
1330+ class  _DependencyVisitor  extends  RecursiveAstVisitor <void > {
1331+   _DependencyVisitor (this .availableNames);
1332+ 
1333+   final  Set <String > availableNames;
1334+ 
1335+   final  Set <String > dependencies =  {};
1336+ 
1337+   @override 
1338+   void  visitSimpleIdentifier (SimpleIdentifier  node) {
1339+     if  (availableNames.contains (node.name)) {
1340+       dependencies.add (node.name);
1341+     }
1342+     super .visitSimpleIdentifier (node);
1343+   }
1344+ }
0 commit comments