54
54
import java .util .function .Consumer ;
55
55
import java .util .function .Function ;
56
56
57
+ import com .oracle .graal .python .PythonLanguage ;
57
58
import com .oracle .graal .python .builtins .objects .PNone ;
58
59
import com .oracle .graal .python .builtins .objects .code .PCode ;
59
60
import com .oracle .graal .python .builtins .objects .ellipsis .PEllipsis ;
116
117
import com .oracle .truffle .api .strings .TruffleString ;
117
118
118
119
/**
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.
121
123
* <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.
124
142
*/
125
143
public final class RootNodeCompiler implements BaseBytecodeDSLVisitor <BytecodeDSLCompilerResult > {
126
144
/**
@@ -144,7 +162,8 @@ public final class RootNodeCompiler implements BaseBytecodeDSLVisitor<BytecodeDS
144
162
private final int [] cell2arg ;
145
163
private final String selfCellName ;
146
164
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.
148
167
private final Map <String , BytecodeLocal > locals = new HashMap <>();
149
168
private final Map <String , BytecodeLocal > cellLocals = new HashMap <>();
150
169
private final Map <String , BytecodeLocal > freeLocals = new HashMap <>();
@@ -212,12 +231,13 @@ private static CompilationScope getScopeType(Scope scope, SSTNode rootNode) {
212
231
return CompilationScope .Lambda ;
213
232
} else if (rootNode instanceof AsyncFunctionDef ) {
214
233
return CompilationScope .AsyncFunction ;
234
+ } else if (rootNode instanceof DictComp || rootNode instanceof ListComp || rootNode instanceof SetComp || rootNode instanceof GeneratorExp ) {
235
+ return CompilationScope .Comprehension ;
215
236
} else {
216
237
return CompilationScope .Function ;
217
238
}
218
239
} 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 );
221
241
}
222
242
}
223
243
@@ -1326,6 +1346,8 @@ public Void visit(ExprTy.Attribute node) {
1326
1346
1327
1347
@ Override
1328
1348
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)
1329
1351
if (!scope .isFunction ()) {
1330
1352
ctx .errorCallback .onError (ErrorType .Syntax , currentLocation , "'await' outside function" );
1331
1353
}
0 commit comments