Index: lib/binary/ast_to_binary.dart |
diff --git a/lib/binary/ast_to_binary.dart b/lib/binary/ast_to_binary.dart |
index 4e05ca45adedc678cf0fbd898219caf7502e6655..0c628f83cbdda5dae32ce05307ba7e12a27d4bfb 100644 |
--- a/lib/binary/ast_to_binary.dart |
+++ b/lib/binary/ast_to_binary.dart |
@@ -17,7 +17,6 @@ import 'dart:collection'; |
class BinaryPrinter extends Visitor { |
ImportTable _importTable; |
- // TODO: We can do the indexing on-the-fly, but for now just keep it simple. |
VariableIndexer _variableIndexer; |
LabelIndexer _labelIndexer; |
SwitchCaseIndexer _switchCaseIndexer; |
@@ -274,7 +273,6 @@ class BinaryPrinter extends Visitor { |
void writeAnnotation(Expression annotation) { |
_variableIndexer ??= new VariableIndexer(); |
- _variableIndexer.build(annotation); |
writeNode(annotation); |
} |
@@ -293,45 +291,49 @@ class BinaryPrinter extends Visitor { |
writeStringReference(node.name ?? ''); |
writeUriReference(node.fileUri ?? ''); |
writeAnnotationList(node.annotations); |
- _typeParameterIndexer.push(node.typeParameters); |
+ _typeParameterIndexer.enter(node.typeParameters); |
writeNodeList(node.typeParameters); |
writeNode(node.supertype); |
writeNode(node.mixedInType); |
writeNodeList(node.implementedTypes); |
writeNodeList(node.constructors); |
- _typeParameterIndexer.pop(node.typeParameters); |
+ _typeParameterIndexer.exit(node.typeParameters); |
} else { |
writeByte(Tag.NormalClass); |
writeByte(flags); |
writeStringReference(node.name ?? ''); |
writeUriReference(node.fileUri ?? ''); |
writeAnnotationList(node.annotations); |
- _typeParameterIndexer.push(node.typeParameters); |
+ _typeParameterIndexer.enter(node.typeParameters); |
writeNodeList(node.typeParameters); |
writeOptionalNode(node.supertype); |
writeNodeList(node.implementedTypes); |
writeNodeList(node.fields); |
writeNodeList(node.constructors); |
writeNodeList(node.procedures); |
- _typeParameterIndexer.pop(node.typeParameters); |
+ _typeParameterIndexer.exit(node.typeParameters); |
} |
} |
static final Name _emptyName = new Name(''); |
visitConstructor(Constructor node) { |
- _variableIndexer = new VariableIndexer()..build(node); |
+ _variableIndexer = new VariableIndexer(); |
writeByte(Tag.Constructor); |
writeByte(node.flags); |
writeName(node.name ?? _emptyName); |
writeAnnotationList(node.annotations); |
assert(node.function.typeParameters.isEmpty); |
writeNode(node.function); |
+ // Parameters are in scope in the initializers. |
+ _variableIndexer.restoreScope(node.function.positionalParameters.length + |
+ node.function.namedParameters.length); |
writeNodeList(node.initializers); |
+ _variableIndexer = null; |
} |
visitProcedure(Procedure node) { |
- _variableIndexer = new VariableIndexer()..build(node); |
+ _variableIndexer = new VariableIndexer(); |
writeByte(Tag.Procedure); |
writeByte(node.kind.index); |
writeByte(node.flags); |
@@ -339,10 +341,11 @@ class BinaryPrinter extends Visitor { |
writeUriReference(node.fileUri ?? ''); |
writeAnnotationList(node.annotations); |
writeOptionalNode(node.function); |
+ _variableIndexer = null; |
} |
visitField(Field node) { |
- _variableIndexer = new VariableIndexer()..build(node); |
+ _variableIndexer = new VariableIndexer(); |
writeByte(Tag.Field); |
writeOffset(node); |
writeByte(node.flags); |
@@ -352,6 +355,7 @@ class BinaryPrinter extends Visitor { |
writeNode(node.type); |
writeOptionalInferredValue(node.inferredValue); |
writeOptionalNode(node.initializer); |
+ _variableIndexer = null; |
} |
visitInvalidInitializer(InvalidInitializer node) { |
@@ -383,12 +387,13 @@ class BinaryPrinter extends Visitor { |
visitFunctionNode(FunctionNode node) { |
assert(_variableIndexer != null); |
+ _variableIndexer.pushScope(); |
var oldLabels = _labelIndexer; |
- _labelIndexer = new LabelIndexer()..build(node); |
+ _labelIndexer = new LabelIndexer(); |
var oldCases = _switchCaseIndexer; |
- _switchCaseIndexer = new SwitchCaseIndexer()..build(node); |
+ _switchCaseIndexer = new SwitchCaseIndexer(); |
// Note: FunctionNode has no tag. |
- _typeParameterIndexer.push(node.typeParameters); |
+ _typeParameterIndexer.enter(node.typeParameters); |
writeByte(node.asyncMarker.index); |
writeNodeList(node.typeParameters); |
writeUInt30(node.requiredParameterCount); |
@@ -399,7 +404,8 @@ class BinaryPrinter extends Visitor { |
writeOptionalNode(node.body); |
_labelIndexer = oldLabels; |
_switchCaseIndexer = oldCases; |
- _typeParameterIndexer.pop(node.typeParameters); |
+ _typeParameterIndexer.exit(node.typeParameters); |
+ _variableIndexer.popScope(); |
} |
visitInvalidExpression(InvalidExpression node) { |
@@ -683,6 +689,7 @@ class BinaryPrinter extends Visitor { |
writeByte(Tag.Let); |
writeVariableDeclaration(node.variable); |
writeNode(node.body); |
+ --_variableIndexer.stackHeight; |
} |
writeStatementOrEmpty(Statement node) { |
@@ -703,8 +710,10 @@ class BinaryPrinter extends Visitor { |
} |
visitBlock(Block node) { |
+ _variableIndexer.pushScope(); |
writeByte(Tag.Block); |
writeNodeList(node.statements); |
+ _variableIndexer.popScope(); |
} |
visitEmptyStatement(EmptyStatement node) { |
@@ -718,8 +727,10 @@ class BinaryPrinter extends Visitor { |
} |
visitLabeledStatement(LabeledStatement node) { |
+ _labelIndexer.enter(node); |
writeByte(Tag.LabeledStatement); |
writeNode(node.body); |
+ _labelIndexer.exit(); |
} |
visitBreakStatement(BreakStatement node) { |
@@ -740,24 +751,30 @@ class BinaryPrinter extends Visitor { |
} |
visitForStatement(ForStatement node) { |
+ _variableIndexer.pushScope(); |
writeByte(Tag.ForStatement); |
writeVariableDeclarationList(node.variables); |
writeOptionalNode(node.condition); |
writeNodeList(node.updates); |
writeNode(node.body); |
+ _variableIndexer.popScope(); |
} |
visitForInStatement(ForInStatement node) { |
+ _variableIndexer.pushScope(); |
writeByte(node.isAsync ? Tag.AsyncForInStatement : Tag.ForInStatement); |
writeVariableDeclaration(node.variable); |
writeNode(node.iterable); |
writeNode(node.body); |
+ _variableIndexer.popScope(); |
} |
visitSwitchStatement(SwitchStatement node) { |
+ _switchCaseIndexer.enter(node); |
writeByte(Tag.SwitchStatement); |
writeNode(node.expression); |
writeNodeList(node.cases); |
+ _switchCaseIndexer.exit(node); |
} |
visitSwitchCase(SwitchCase node) { |
@@ -792,10 +809,12 @@ class BinaryPrinter extends Visitor { |
visitCatch(Catch node) { |
// Note: there is no tag on Catch. |
+ _variableIndexer.pushScope(); |
writeNode(node.guard); |
writeOptionalVariableDeclaration(node.exception); |
writeOptionalVariableDeclaration(node.stackTrace); |
writeNode(node.body); |
+ _variableIndexer.popScope(); |
} |
visitTryFinally(TryFinally node) { |
@@ -821,6 +840,9 @@ class BinaryPrinter extends Visitor { |
writeNode(node.type); |
writeOptionalInferredValue(node.inferredValue); |
writeOptionalNode(node.initializer); |
+ // Declare the variable after its initializer. It is not in scope in its |
+ // own initializer. |
+ _variableIndexer.declare(node); |
} |
void writeVariableDeclarationList(List<VariableDeclaration> nodes) { |
@@ -889,7 +911,7 @@ class BinaryPrinter extends Visitor { |
writeNode(node.returnType); |
} else { |
writeByte(Tag.FunctionType); |
- _typeParameterIndexer.push(node.typeParameters); |
+ _typeParameterIndexer.enter(node.typeParameters); |
writeNodeList(node.typeParameters); |
writeUInt30(node.requiredParameterCount); |
writeNodeList(node.positionalParameters); |
@@ -898,7 +920,7 @@ class BinaryPrinter extends Visitor { |
writeNode(node.namedParameters[name]); |
}); |
writeNode(node.returnType); |
- _typeParameterIndexer.pop(node.typeParameters); |
+ _typeParameterIndexer.exit(node.typeParameters); |
} |
} |
@@ -917,132 +939,76 @@ class BinaryPrinter extends Visitor { |
} |
} |
-class VariableIndexer extends RecursiveVisitor { |
+class VariableIndexer { |
final Map<VariableDeclaration, int> index = <VariableDeclaration, int>{}; |
+ final List<int> scopes = <int>[]; |
int stackHeight = 0; |
- void build(TreeNode node) => node.accept(this); |
- |
- visitConstructor(Constructor node) { |
- node.function.accept(this); |
- // Keep parameters in scope when traversing initializers. |
- stackHeight = node.function.positionalParameters.length + |
- node.function.namedParameters.length; |
- for (var init in node.initializers) { |
- init.accept(this); |
- } |
- stackHeight = 0; |
+ void declare(VariableDeclaration node) { |
+ index[node] = stackHeight++; |
} |
- visitFunctionNode(FunctionNode node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
+ void pushScope() { |
+ scopes.add(stackHeight); |
} |
- visitBlock(Block node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
+ void popScope() { |
+ stackHeight = scopes.removeLast(); |
} |
- visitLet(Let node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
+ void restoreScope(int numberOfVariables) { |
+ stackHeight += numberOfVariables; |
} |
- visitForInStatement(ForInStatement node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
- } |
- |
- visitForStatement(ForStatement node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
- } |
- |
- visitCatch(Catch node) { |
- int frame = stackHeight; |
- node.visitChildren(this); |
- stackHeight = frame; |
+ int operator [](VariableDeclaration node) { |
+ return index[node]; |
} |
- |
- visitVariableDeclaration(VariableDeclaration node) { |
- node.visitChildren(this); |
- assert(!index.containsKey(node)); |
- index[node] = stackHeight; |
- ++stackHeight; |
- } |
- |
- int operator [](VariableDeclaration node) => index[node]; |
} |
-class LabelIndexer extends RecursiveVisitor { |
+class LabelIndexer { |
final Map<LabeledStatement, int> index = <LabeledStatement, int>{}; |
int stackHeight = 0; |
- void build(FunctionNode node) => node.visitChildren(this); |
- |
- visitFunctionNode(FunctionNode node) { |
- // Inhibit traversal into nested functions. |
- // The client must create a separate label indexer for the |
- // nested function. |
+ void enter(LabeledStatement node) { |
+ index[node] = stackHeight++; |
} |
- visitLabeledStatement(LabeledStatement node) { |
- index[node] = stackHeight; |
- ++stackHeight; |
- node.visitChildren(this); |
+ void exit() { |
--stackHeight; |
} |
int operator [](LabeledStatement node) => index[node]; |
} |
-class SwitchCaseIndexer extends RecursiveVisitor { |
+class SwitchCaseIndexer { |
final Map<SwitchCase, int> index = <SwitchCase, int>{}; |
int stackHeight = 0; |
- void build(FunctionNode node) => node.visitChildren(this); |
- |
- visitFunctionNode(FunctionNode node) { |
- // Inhibit traversal into nested functions. |
- // The client must create a separate case indexer for the |
- // nested function. |
- } |
- |
- visitSwitchStatement(SwitchStatement node) { |
- int oldHeight = stackHeight; |
+ void enter(SwitchStatement node) { |
for (var caseNode in node.cases) { |
- index[caseNode] = stackHeight; |
- ++stackHeight; |
+ index[caseNode] = stackHeight++; |
} |
- node.visitChildren(this); |
- stackHeight = oldHeight; |
+ } |
+ |
+ void exit(SwitchStatement node) { |
+ stackHeight -= node.cases.length; |
} |
int operator [](SwitchCase node) => index[node]; |
} |
-/// The type parameter indexer works differently from the other indexers because |
-/// type parameters can be bound inside DartTypes, which can be shared by the |
-/// in-memory representation (but not the binary form) and the index depends on |
-/// the use site. |
class TypeParameterIndexer { |
final Map<TypeParameter, int> index = <TypeParameter, int>{}; |
int stackHeight = 0; |
- void push(List<TypeParameter> typeParameters) { |
+ void enter(List<TypeParameter> typeParameters) { |
for (var parameter in typeParameters) { |
index[parameter] = stackHeight; |
++stackHeight; |
} |
} |
- void pop(List<TypeParameter> typeParameters) { |
+ void exit(List<TypeParameter> typeParameters) { |
stackHeight -= typeParameters.length; |
} |