OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library backend_ast_emitter; | 5 library backend_ast_emitter; |
6 | 6 |
7 import '../tree_ir/tree_ir_nodes.dart' as tree; | 7 import '../tree_ir/tree_ir_nodes.dart' as tree; |
8 import 'backend_ast_nodes.dart'; | 8 import 'backend_ast_nodes.dart'; |
9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
11 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
13 import '../elements/modelx.dart' as modelx; | 13 import '../elements/modelx.dart' as modelx; |
14 import '../universe/universe.dart'; | 14 import '../universe/universe.dart'; |
15 import '../tree/tree.dart' as tree show Modifiers; | 15 import '../tree/tree.dart' as tree show Modifiers; |
16 | 16 |
17 /// Translates the dart_tree IR to Dart backend AST. | 17 /// Translates the dart_tree IR to Dart backend AST. |
18 Expression emit(tree.FunctionDefinition definition) { | 18 ExecutableDefinition emit(tree.ExecutableDefinition definition) { |
19 return new ASTEmitter().emit(definition); | 19 return new ASTEmitter().emit(definition); |
20 } | 20 } |
21 | 21 |
22 /// Translates the dart_tree IR to Dart backend AST. | 22 /// Translates the dart_tree IR to Dart backend AST. |
23 /// An instance of this class should only be used once; a fresh emitter | 23 /// An instance of this class should only be used once; a fresh emitter |
24 /// must be created for each function to be emitted. | 24 /// must be created for each function to be emitted. |
25 class ASTEmitter extends tree.Visitor<dynamic, Expression> { | 25 class ASTEmitter extends tree.Visitor<dynamic, Expression> { |
26 /// Variables to be hoisted at the top of the current function. | 26 /// Variables to be hoisted at the top of the current function. |
27 List<VariableDeclaration> variables = <VariableDeclaration>[]; | 27 List<VariableDeclaration> variables = <VariableDeclaration>[]; |
28 | 28 |
29 /// Maps variables to their name. | 29 /// Maps variables to their name. |
30 Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; | 30 Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; |
31 | 31 |
32 /// Maps local constants to their name. | 32 /// Maps local constants to their name. |
33 Map<VariableElement, String> constantNames = <VariableElement, String>{}; | 33 Map<VariableElement, String> constantNames = <VariableElement, String>{}; |
34 | 34 |
35 /// Variables that have had their declaration created. | 35 /// Variables that have had their declaration created. |
36 Set<tree.Variable> declaredVariables = new Set<tree.Variable>(); | 36 Set<tree.Variable> declaredVariables = new Set<tree.Variable>(); |
37 | 37 |
38 /// Variable names that have already been used. Used to avoid name clashes. | 38 /// Variable names that have already been used. Used to avoid name clashes. |
39 Set<String> usedVariableNames; | 39 Set<String> usedVariableNames; |
40 | 40 |
41 /// Statements emitted by the most recent call to [visitStatement]. | 41 /// Statements emitted by the most recent call to [visitStatement]. |
42 List<Statement> statementBuffer = <Statement>[]; | 42 List<Statement> statementBuffer = <Statement>[]; |
43 | 43 |
44 /// The function currently being emitted. | 44 /// The element currently being emitted. |
45 FunctionElement functionElement; | 45 ExecutableElement currentElement; |
46 | 46 |
47 /// Bookkeeping object needed to synthesize a variable declaration. | 47 /// Bookkeeping object needed to synthesize a variable declaration. |
48 modelx.VariableList variableList | 48 modelx.VariableList variableList |
49 = new modelx.VariableList(tree.Modifiers.EMPTY); | 49 = new modelx.VariableList(tree.Modifiers.EMPTY); |
50 | 50 |
51 /// Input to [visitStatement]. Denotes the statement that will execute next | 51 /// Input to [visitStatement]. Denotes the statement that will execute next |
52 /// if the statements produced by [visitStatement] complete normally. | 52 /// if the statements produced by [visitStatement] complete normally. |
53 /// Set to null if control will fall over the end of the method. | 53 /// Set to null if control will fall over the end of the method. |
54 tree.Statement fallthrough = null; | 54 tree.Statement fallthrough = null; |
55 | 55 |
56 /// Labels that could not be eliminated using fallthrough. | 56 /// Labels that could not be eliminated using fallthrough. |
57 Set<tree.Label> usedLabels = new Set<tree.Label>(); | 57 Set<tree.Label> usedLabels = new Set<tree.Label>(); |
58 | 58 |
59 /// The first dart_tree statement that is not converted to a variable | 59 /// The first dart_tree statement that is not converted to a variable |
60 /// initializer. | 60 /// initializer. |
61 tree.Statement firstStatement; | 61 tree.Statement firstStatement; |
62 | 62 |
63 /// Emitter for the enclosing function, or null if the current function is | 63 /// Emitter for the enclosing function, or null if the current function is |
64 /// not a local function. | 64 /// not a local function. |
65 ASTEmitter parent; | 65 ASTEmitter parent; |
66 | 66 |
67 ASTEmitter() : usedVariableNames = new Set<String>(); | 67 ASTEmitter() : usedVariableNames = new Set<String>(); |
68 | 68 |
69 ASTEmitter.inner(ASTEmitter parent) | 69 ASTEmitter.inner(ASTEmitter parent) |
70 : this.parent = parent, | 70 : this.parent = parent, |
71 usedVariableNames = parent.usedVariableNames; | 71 usedVariableNames = parent.usedVariableNames; |
72 | 72 |
73 FunctionExpression emit(tree.FunctionDefinition definition) { | 73 ExecutableDefinition emit(tree.ExecutableDefinition definition) { |
74 functionElement = definition.element; | 74 if (definition is tree.FieldDefinition) { |
| 75 return emitField(definition); |
| 76 } |
| 77 assert(definition is tree.FunctionDefinition); |
| 78 return emitFunction(definition); |
| 79 } |
| 80 |
| 81 FieldDefinition emitField(tree.FieldDefinition definition) { |
| 82 currentElement = definition.element; |
| 83 visitStatement(definition.body); |
| 84 List<Statement> bodyParts; |
| 85 for (tree.Variable variable in variableNames.keys) { |
| 86 if (!declaredVariables.contains(variable)) { |
| 87 addDeclaration(variable); |
| 88 } |
| 89 } |
| 90 if (variables.length > 0) { |
| 91 bodyParts = new List<Statement>(); |
| 92 bodyParts.add(new VariableDeclarations(variables)); |
| 93 bodyParts.addAll(statementBuffer); |
| 94 } else { |
| 95 bodyParts = statementBuffer; |
| 96 } |
| 97 |
| 98 return new FieldDefinition(definition.element, ensureExpression(bodyParts)); |
| 99 } |
| 100 |
| 101 /// Returns an expression that will evaluate all of [bodyParts]. |
| 102 /// If [bodyParts] is a single [Return] return its value. |
| 103 /// Otherwise wrap the body-parts in an immediately invoked closure. |
| 104 Expression ensureExpression(List<Statement> bodyParts) { |
| 105 if (bodyParts.length == 1) { |
| 106 Statement onlyStatement = bodyParts.single; |
| 107 if (onlyStatement is Return) { |
| 108 return onlyStatement.expression; |
| 109 } |
| 110 } |
| 111 Statement body = new Block(bodyParts); |
| 112 FunctionExpression function = |
| 113 new FunctionExpression(new Parameters([]), body); |
| 114 function.element = null; |
| 115 return new CallFunction(function, []); |
| 116 } |
| 117 |
| 118 FunctionExpression emitFunction(tree.FunctionDefinition definition) { |
| 119 currentElement = definition.element; |
75 | 120 |
76 Parameters parameters = emitRootParameters(definition); | 121 Parameters parameters = emitRootParameters(definition); |
77 | 122 |
78 // Declare parameters. | 123 // Declare parameters. |
79 for (tree.Variable param in definition.parameters) { | 124 for (tree.Variable param in definition.parameters) { |
80 variableNames[param] = param.element.name; | 125 variableNames[param] = param.element.name; |
81 usedVariableNames.add(param.element.name); | 126 usedVariableNames.add(param.element.name); |
82 declaredVariables.add(param); | 127 declaredVariables.add(param); |
83 } | 128 } |
84 | 129 |
(...skipping 30 matching lines...) Expand all Loading... |
115 if (constants.length > 0) { | 160 if (constants.length > 0) { |
116 bodyParts.add(new VariableDeclarations(constants, isConst: true)); | 161 bodyParts.add(new VariableDeclarations(constants, isConst: true)); |
117 } | 162 } |
118 if (variables.length > 0) { | 163 if (variables.length > 0) { |
119 bodyParts.add(new VariableDeclarations(variables)); | 164 bodyParts.add(new VariableDeclarations(variables)); |
120 } | 165 } |
121 bodyParts.addAll(statementBuffer); | 166 bodyParts.addAll(statementBuffer); |
122 | 167 |
123 body = new Block(bodyParts); | 168 body = new Block(bodyParts); |
124 } | 169 } |
125 FunctionType functionType = functionElement.type; | 170 FunctionType functionType = currentElement.type; |
126 | 171 |
127 return new FunctionExpression( | 172 return new FunctionExpression( |
128 parameters, | 173 parameters, |
129 body, | 174 body, |
130 name: functionElement.name, | 175 name: currentElement.name, |
131 returnType: emitOptionalType(functionType.returnType), | 176 returnType: emitOptionalType(functionType.returnType), |
132 isGetter: functionElement.isGetter, | 177 isGetter: currentElement.isGetter, |
133 isSetter: functionElement.isSetter) | 178 isSetter: currentElement.isSetter) |
134 ..element = functionElement; | 179 ..element = currentElement; |
135 } | 180 } |
136 | 181 |
137 void addDeclaration(tree.Variable variable, [Expression initializer]) { | 182 void addDeclaration(tree.Variable variable, [Expression initializer]) { |
138 assert(!declaredVariables.contains(variable)); | 183 assert(!declaredVariables.contains(variable)); |
139 String name = getVariableName(variable); | 184 String name = getVariableName(variable); |
140 VariableDeclaration decl = new VariableDeclaration(name, initializer); | 185 VariableDeclaration decl = new VariableDeclaration(name, initializer); |
141 decl.element = variable.element; | 186 decl.element = variable.element; |
142 declaredVariables.add(variable); | 187 declaredVariables.add(variable); |
143 variables.add(decl); | 188 variables.add(decl); |
144 } | 189 } |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 fallthrough = savedFallthrough; | 342 fallthrough = savedFallthrough; |
298 statementBuffer = savedBuffer; | 343 statementBuffer = savedBuffer; |
299 visitStatement(stmt.next); | 344 visitStatement(stmt.next); |
300 } | 345 } |
301 | 346 |
302 /// Generates a name for the given variable and synthesizes an element for it, | 347 /// Generates a name for the given variable and synthesizes an element for it, |
303 /// if necessary. | 348 /// if necessary. |
304 String getVariableName(tree.Variable variable) { | 349 String getVariableName(tree.Variable variable) { |
305 // If the variable belongs to an enclosing function, ask the parent emitter | 350 // If the variable belongs to an enclosing function, ask the parent emitter |
306 // for the variable name. | 351 // for the variable name. |
307 if (variable.host.element != functionElement) { | 352 if (variable.host != currentElement) { |
308 return parent.getVariableName(variable); | 353 return parent.getVariableName(variable); |
309 } | 354 } |
310 | 355 |
311 // Get the name if we already have one. | 356 // Get the name if we already have one. |
312 String name = variableNames[variable]; | 357 String name = variableNames[variable]; |
313 if (name != null) { | 358 if (name != null) { |
314 return name; | 359 return name; |
315 } | 360 } |
316 | 361 |
317 // Synthesize a variable name that isn't used elsewhere. | 362 // Synthesize a variable name that isn't used elsewhere. |
318 // The [usedVariableNames] set is shared between nested emitters, | 363 // The [usedVariableNames] set is shared between nested emitters, |
319 // so this also prevents clash with variables in an enclosing/inner scope. | 364 // so this also prevents clash with variables in an enclosing/inner scope. |
320 // The renaming phase after codegen will further prefix local variables | 365 // The renaming phase after codegen will further prefix local variables |
321 // so they cannot clash with top-level variables or fields. | 366 // so they cannot clash with top-level variables or fields. |
322 String prefix = variable.element == null ? 'v' : variable.element.name; | 367 String prefix = variable.element == null ? 'v' : variable.element.name; |
323 int counter = 0; | 368 int counter = 0; |
324 name = variable.element == null ? '$prefix$counter' : variable.element.name; | 369 name = variable.element == null ? '$prefix$counter' : variable.element.name; |
325 while (!usedVariableNames.add(name)) { | 370 while (!usedVariableNames.add(name)) { |
326 ++counter; | 371 ++counter; |
327 name = '$prefix$counter'; | 372 name = '$prefix$counter'; |
328 } | 373 } |
329 variableNames[variable] = name; | 374 variableNames[variable] = name; |
330 | 375 |
331 // Synthesize an element for the variable | 376 // Synthesize an element for the variable |
332 if (variable.element == null || name != variable.element.name) { | 377 if (variable.element == null || name != variable.element.name) { |
333 // TODO(johnniwinther): Replace by synthetic [Entity]. | 378 // TODO(johnniwinther): Replace by synthetic [Entity]. |
334 variable.element = new _SyntheticLocalVariableElement( | 379 variable.element = new _SyntheticLocalVariableElement( |
335 name, | 380 name, |
336 functionElement, | 381 currentElement, |
337 variableList); | 382 variableList); |
338 } | 383 } |
339 return name; | 384 return name; |
340 } | 385 } |
341 | 386 |
342 String getConstantName(VariableElement element) { | 387 String getConstantName(VariableElement element) { |
343 assert(element.kind == ElementKind.VARIABLE); | 388 assert(element.kind == ElementKind.VARIABLE); |
344 if (element.enclosingElement != functionElement) { | 389 if (element.enclosingElement != currentElement) { |
345 return parent.getConstantName(element); | 390 return parent.getConstantName(element); |
346 } | 391 } |
347 String name = constantNames[element]; | 392 String name = constantNames[element]; |
348 if (name != null) { | 393 if (name != null) { |
349 return name; | 394 return name; |
350 } | 395 } |
351 String prefix = element.name; | 396 String prefix = element.name; |
352 int counter = 0; | 397 int counter = 0; |
353 name = element.name; | 398 name = element.name; |
354 while (!usedVariableNames.add(name)) { | 399 while (!usedVariableNames.add(name)) { |
(...skipping 15 matching lines...) Expand all Loading... |
370 tree.FunctionExpression functionExp = stmt.definition; | 415 tree.FunctionExpression functionExp = stmt.definition; |
371 FunctionExpression function = makeSubFunction(functionExp.definition); | 416 FunctionExpression function = makeSubFunction(functionExp.definition); |
372 FunctionDeclaration decl = new FunctionDeclaration(function); | 417 FunctionDeclaration decl = new FunctionDeclaration(function); |
373 statementBuffer.add(decl); | 418 statementBuffer.add(decl); |
374 declaredVariables.add(stmt.variable); | 419 declaredVariables.add(stmt.variable); |
375 visitStatement(stmt.next); | 420 visitStatement(stmt.next); |
376 return; | 421 return; |
377 } | 422 } |
378 | 423 |
379 bool isFirstOccurrence = (variableNames[stmt.variable] == null); | 424 bool isFirstOccurrence = (variableNames[stmt.variable] == null); |
380 bool isDeclaredHere = stmt.variable.host.element == functionElement; | 425 bool isDeclaredHere = stmt.variable.host == currentElement; |
381 String name = getVariableName(stmt.variable); | 426 String name = getVariableName(stmt.variable); |
382 Expression definition = visitExpression(stmt.definition); | 427 Expression definition = visitExpression(stmt.definition); |
383 | 428 |
384 // Try to pull into initializer. | 429 // Try to pull into initializer. |
385 if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { | 430 if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { |
386 if (isNullLiteral(definition)) definition = null; | 431 if (isNullLiteral(definition)) definition = null; |
387 addDeclaration(stmt.variable, definition); | 432 addDeclaration(stmt.variable, definition); |
388 firstStatement = stmt.next; | 433 firstStatement = stmt.next; |
389 visitStatement(stmt.next); | 434 visitStatement(stmt.next); |
390 return; | 435 return; |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 | 896 |
852 /// Maps parameter names to their bindings. | 897 /// Maps parameter names to their bindings. |
853 Map<String, tree.Variable> environment = <String, tree.Variable>{}; | 898 Map<String, tree.Variable> environment = <String, tree.Variable>{}; |
854 | 899 |
855 /// Parameters that are currently shadowed by another parameter. | 900 /// Parameters that are currently shadowed by another parameter. |
856 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>(); | 901 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>(); |
857 | 902 |
858 /// Parameters that are used in a context where it is shadowed. | 903 /// Parameters that are used in a context where it is shadowed. |
859 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>(); | 904 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>(); |
860 | 905 |
861 void unshadow(tree.FunctionDefinition definition) { | 906 void unshadow(tree.ExecutableDefinition definition) { |
862 if (definition.isAbstract) return; | 907 // Fields have no parameters. |
863 | 908 if (definition is tree.FieldDefinition) return; |
864 visitFunctionDefinition(definition); | 909 visitFunctionDefinition(definition); |
865 } | 910 } |
866 | 911 |
867 visitFunctionDefinition(tree.FunctionDefinition definition) { | 912 visitFunctionDefinition(tree.FunctionDefinition definition) { |
| 913 if (definition.isAbstract) return; |
868 var oldShadow = shadowedParameters; | 914 var oldShadow = shadowedParameters; |
869 var oldEnvironment = environment; | 915 var oldEnvironment = environment; |
870 environment = new Map<String, tree.Variable>.from(environment); | 916 environment = new Map<String, tree.Variable>.from(environment); |
871 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters); | 917 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters); |
872 for (tree.Variable param in definition.parameters) { | 918 for (tree.Variable param in definition.parameters) { |
873 tree.Variable oldVariable = environment[param.element.name]; | 919 tree.Variable oldVariable = environment[param.element.name]; |
874 if (oldVariable != null) { | 920 if (oldVariable != null) { |
875 shadowedParameters.add(oldVariable); | 921 shadowedParameters.add(oldVariable); |
876 } | 922 } |
877 environment[param.element.name] = param; | 923 environment[param.element.name] = param; |
878 } | 924 } |
879 visitStatement(definition.body); | 925 visitStatement(definition.body); |
880 environment = oldEnvironment; | 926 environment = oldEnvironment; |
881 shadowedParameters = oldShadow; | 927 shadowedParameters = oldShadow; |
882 | 928 |
883 for (int i=0; i<definition.parameters.length; i++) { | 929 for (int i=0; i<definition.parameters.length; i++) { |
884 tree.Variable param = definition.parameters[i]; | 930 tree.Variable param = definition.parameters[i]; |
885 if (hasShadowedUse.remove(param)) { | 931 if (hasShadowedUse.remove(param)) { |
886 tree.Variable newParam = new tree.Variable(definition, param.element); | 932 tree.Variable newParam = new tree.Variable(definition.element, |
| 933 param.element); |
887 definition.parameters[i] = newParam; | 934 definition.parameters[i] = newParam; |
888 definition.body = new tree.Assign(param, newParam, definition.body); | 935 definition.body = new tree.Assign(param, newParam, definition.body); |
889 newParam.writeCount = 1; // Being a parameter counts as a write. | 936 newParam.writeCount = 1; // Being a parameter counts as a write. |
890 } | 937 } |
891 } | 938 } |
892 } | 939 } |
893 | 940 |
894 visitVariable(tree.Variable variable) { | 941 visitVariable(tree.Variable variable) { |
895 if (shadowedParameters.contains(variable)) { | 942 if (shadowedParameters.contains(variable)) { |
896 hasShadowedUse.add(variable); | 943 hasShadowedUse.add(variable); |
(...skipping 13 matching lines...) Expand all Loading... |
910 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null); | 957 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null); |
911 | 958 |
912 ExecutableElement get executableContext => enclosingElement; | 959 ExecutableElement get executableContext => enclosingElement; |
913 | 960 |
914 ExecutableElement get memberContext => executableContext.memberContext; | 961 ExecutableElement get memberContext => executableContext.memberContext; |
915 | 962 |
916 bool get isLocal => true; | 963 bool get isLocal => true; |
917 | 964 |
918 LibraryElement get implementationLibrary => enclosingElement.library; | 965 LibraryElement get implementationLibrary => enclosingElement.library; |
919 } | 966 } |
OLD | NEW |