5454import java .util .function .Consumer ;
5555import java .util .function .Function ;
5656
57+ import com .oracle .graal .python .PythonLanguage ;
5758import com .oracle .graal .python .builtins .objects .PNone ;
5859import com .oracle .graal .python .builtins .objects .code .PCode ;
5960import com .oracle .graal .python .builtins .objects .ellipsis .PEllipsis ;
116117import com .oracle .truffle .api .strings .TruffleString ;
117118
118119/**
119- * Visitor that compiles a top-level AST (modules, functions, classes, etc.) to a root node.
120- * Produces a {@link BytecodeDSLCompilerResult}.
120+ * Compiles a top-level AST (modules, functions, classes, etc.) to a root node. Produces a
121+ * {@link BytecodeDSLCompilerResult}. Every instance is associated with corresponding
122+ * {@link SSTNode} that represents the compiled top level AST.
121123 * <p>
122- * This visitor is a small wrapper that calls into another visitor, {@link StatementCompiler}, to
123- * produce bytecode for the various statements/expressions within the AST.
124+ * The class implements SST visitor, so that it can have a separate handler for each top-level AST
125+ * node type, the handler (one of the {@code visit} methods) then creates a lambda of type
126+ * {@link BytecodeParser}, which captures the node being compiled and the instance of
127+ * {@link RootNodeCompiler}, and it uses the {@link RootNodeCompiler} to do the parsing itself. The
128+ * {@link BytecodeParser} instance is passed to Truffle API
129+ * {@link PBytecodeDSLRootNodeGen#create(PythonLanguage, BytecodeConfig, BytecodeParser)} to trigger
130+ * the parsing. Truffle keeps the lambda, and it may invoke it again when it needs to perform the
131+ * parsing of the given node again.
132+ * <p>
133+ * The parsing must happen within the {@link BytecodeParser} lambda invocation.
134+ * <p>
135+ * This visitor also captures compilation unit state, such as the map of local variables, and serves
136+ * the same purpose as the {@code compiler_unit} struct in the CPython compiler. Instead of explicit
137+ * stack of compiler units, we use implicitly Java stack and new instances of
138+ * {@link RootNodeCompiler}.
139+ * <p>
140+ * For the parsing of the body of the top level AST element, this visitor delegates to the
141+ * {@link StatementCompiler}, which does all the heavy lifting.
124142 */
125143public final class RootNodeCompiler implements BaseBytecodeDSLVisitor <BytecodeDSLCompilerResult > {
126144 /**
@@ -144,7 +162,8 @@ public final class RootNodeCompiler implements BaseBytecodeDSLVisitor<BytecodeDS
144162 private final int [] cell2arg ;
145163 private final String selfCellName ;
146164
147- // Updated idempotently
165+ // Updated idempotently: the keys are filled during first parsing, on subsequent parsings the
166+ // values will be just overridden, but no new keys should be added.
148167 private final Map <String , BytecodeLocal > locals = new HashMap <>();
149168 private final Map <String , BytecodeLocal > cellLocals = new HashMap <>();
150169 private final Map <String , BytecodeLocal > freeLocals = new HashMap <>();
@@ -212,12 +231,13 @@ private static CompilationScope getScopeType(Scope scope, SSTNode rootNode) {
212231 return CompilationScope .Lambda ;
213232 } else if (rootNode instanceof AsyncFunctionDef ) {
214233 return CompilationScope .AsyncFunction ;
234+ } else if (rootNode instanceof DictComp || rootNode instanceof ListComp || rootNode instanceof SetComp || rootNode instanceof GeneratorExp ) {
235+ return CompilationScope .Comprehension ;
215236 } else {
216237 return CompilationScope .Function ;
217238 }
218239 } else {
219- assert rootNode instanceof DictComp || rootNode instanceof ListComp || rootNode instanceof SetComp || rootNode instanceof GeneratorExp ;
220- return CompilationScope .Comprehension ;
240+ throw new IllegalStateException ("Unexpected scope: " + scope );
221241 }
222242 }
223243
@@ -1326,6 +1346,8 @@ public Void visit(ExprTy.Attribute node) {
13261346
13271347 @ Override
13281348 public Void visit (ExprTy .Await node ) {
1349+ // TODO if !IS_TOP_LEVEL_AWAIT
1350+ // TODO handle await in comprehension correctly (currently, it is always allowed)
13291351 if (!scope .isFunction ()) {
13301352 ctx .errorCallback .onError (ErrorType .Syntax , currentLocation , "'await' outside function" );
13311353 }
0 commit comments