Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart

Issue 763993002: Extract BuilderContext from ASTEmitter (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 ExecutableDefinition emit(tree.ExecutableDefinition definition) { 18 ExecutableDefinition emit(tree.ExecutableDefinition definition) {
19 return new ASTEmitter().emit(definition); 19 return new ASTEmitter().emit(definition, new BuilderContext<Statement>());
20 } 20 }
21 21
22 /// Translates the dart_tree IR to Dart backend AST. 22 // TODO(johnniwinther): Split into function/block state.
23 /// An instance of this class should only be used once; a fresh emitter 23 class BuilderContext<T> {
24 /// must be created for each function to be emitted. 24 /// Builder context for the enclosing function, or null if the current
25 class ASTEmitter extends tree.Visitor<dynamic, Expression> { 25 /// function is not a local function.
26 BuilderContext<T> _parent;
27
26 /// Variables to be hoisted at the top of the current function. 28 /// Variables to be hoisted at the top of the current function.
27 List<VariableDeclaration> variables = <VariableDeclaration>[]; 29 final List<VariableDeclaration> variables = <VariableDeclaration>[];
28 30
29 /// Maps variables to their name. 31 /// Maps variables to their name.
30 Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; 32 final Map<tree.Variable, String> variableNames = <tree.Variable, String>{};
31 33
32 /// Maps local constants to their name. 34 /// Maps local constants to their name.
33 Map<VariableElement, String> constantNames = <VariableElement, String>{}; 35 final Map<VariableElement, String> constantNames =
36 <VariableElement, String>{};
34 37
35 /// Variables that have had their declaration created. 38 /// Variables that have had their declaration created.
36 Set<tree.Variable> declaredVariables = new Set<tree.Variable>(); 39 final Set<tree.Variable> declaredVariables = new Set<tree.Variable>();
37 40
38 /// Variable names that have already been used. Used to avoid name clashes. 41 /// Variable names that have already been used. Used to avoid name clashes.
39 Set<String> usedVariableNames; 42 final Set<String> usedVariableNames;
40 43
41 /// Statements emitted by the most recent call to [visitStatement]. 44 /// Statements emitted by the most recent call to [visitStatement].
42 List<Statement> statementBuffer = <Statement>[]; 45 List<T> _statementBuffer = <T>[];
43 46
44 /// The element currently being emitted. 47 /// The element currently being emitted.
45 ExecutableElement currentElement; 48 ExecutableElement currentElement;
46 49
47 /// Bookkeeping object needed to synthesize a variable declaration. 50 /// Bookkeeping object needed to synthesize a variable declaration.
48 modelx.VariableList variableList 51 final modelx.VariableList variableList
49 = new modelx.VariableList(tree.Modifiers.EMPTY); 52 = new modelx.VariableList(tree.Modifiers.EMPTY);
50 53
51 /// Input to [visitStatement]. Denotes the statement that will execute next 54 /// Input to [visitStatement]. Denotes the statement that will execute next
52 /// if the statements produced by [visitStatement] complete normally. 55 /// if the statements produced by [visitStatement] complete normally.
53 /// Set to null if control will fall over the end of the method. 56 /// Set to null if control will fall over the end of the method.
54 tree.Statement fallthrough = null; 57 tree.Statement fallthrough = null;
55 58
56 /// Labels that could not be eliminated using fallthrough. 59 /// Labels that could not be eliminated using fallthrough.
57 Set<tree.Label> usedLabels = new Set<tree.Label>(); 60 final Set<tree.Label> _usedLabels = new Set<tree.Label>();
58 61
59 /// The first dart_tree statement that is not converted to a variable 62 /// The first dart_tree statement that is not converted to a variable
60 /// initializer. 63 /// initializer.
61 tree.Statement firstStatement; 64 tree.Statement firstStatement;
62 65
63 /// Emitter for the enclosing function, or null if the current function is 66 BuilderContext() : usedVariableNames = new Set<String>();
64 /// not a local function.
65 ASTEmitter parent;
66 67
67 ASTEmitter() : usedVariableNames = new Set<String>(); 68 BuilderContext.inner(BuilderContext<T> parent)
68 69 : this._parent = parent,
69 ASTEmitter.inner(ASTEmitter parent)
70 : this.parent = parent,
71 usedVariableNames = parent.usedVariableNames; 70 usedVariableNames = parent.usedVariableNames;
72 71
73 ExecutableDefinition emit(tree.ExecutableDefinition definition) { 72 // TODO(johnniwinther): Fully encapsulate handling of parameter, variable
73 // and local funciton declarations.
74 void addDeclaration(tree.Variable variable, [Expression initializer]) {
75 assert(!declaredVariables.contains(variable));
76 String name = getVariableName(variable);
77 VariableDeclaration decl = new VariableDeclaration(name, initializer);
78 decl.element = variable.element;
79 declaredVariables.add(variable);
80 variables.add(decl);
81 }
82
83 /// Generates a name for the given variable and synthesizes an element for it,
84 /// if necessary.
85 String getVariableName(tree.Variable variable) {
86 // If the variable belongs to an enclosing function, ask the parent emitter
87 // for the variable name.
88 if (variable.host != currentElement) {
89 return _parent.getVariableName(variable);
90 }
91
92 // Get the name if we already have one.
93 String name = variableNames[variable];
94 if (name != null) {
95 return name;
96 }
97
98 // Synthesize a variable name that isn't used elsewhere.
99 // The [usedVariableNames] set is shared between nested emitters,
100 // so this also prevents clash with variables in an enclosing/inner scope.
101 // The renaming phase after codegen will further prefix local variables
102 // so they cannot clash with top-level variables or fields.
103 String prefix = variable.element == null ? 'v' : variable.element.name;
104 int counter = 0;
105 name = variable.element == null ? '$prefix$counter' : variable.element.name;
106 while (!usedVariableNames.add(name)) {
107 ++counter;
108 name = '$prefix$counter';
109 }
110 variableNames[variable] = name;
111
112 // Synthesize an element for the variable
113 if (variable.element == null || name != variable.element.name) {
114 // TODO(johnniwinther): Replace by synthetic [Entity].
115 variable.element = new _SyntheticLocalVariableElement(
116 name,
117 currentElement,
118 variableList);
119 }
120 return name;
121 }
122
123 String getConstantName(VariableElement element) {
124 assert(element.kind == ElementKind.VARIABLE);
125 if (element.enclosingElement != currentElement) {
126 return _parent.getConstantName(element);
127 }
128 String name = constantNames[element];
129 if (name != null) {
130 return name;
131 }
132 String prefix = element.name;
133 int counter = 0;
134 name = element.name;
135 while (!usedVariableNames.add(name)) {
136 ++counter;
137 name = '$prefix$counter';
138 }
139 constantNames[element] = name;
140 return name;
141 }
142
143 List<T> inSubcontext(f(BuilderContext<T> subcontext),
144 {tree.Statement fallthrough}) {
145 List<T> savedBuffer = this._statementBuffer;
146 tree.Statement savedFallthrough = this.fallthrough;
147 List<T> buffer = this._statementBuffer = <T>[];
148 if (fallthrough != null) {
149 this.fallthrough = fallthrough;
150 }
151 f(this);
152 this.fallthrough = savedFallthrough;
153 this._statementBuffer = savedBuffer;
154 return buffer;
155 }
156
157 /// Removes a trailing "return null" from the current block.
158 void removeTrailingReturn(bool isReturnNull(T statement)) {
159 if (_statementBuffer.isEmpty) return;
160 if (isReturnNull(_statementBuffer.last)) {
161 _statementBuffer.removeLast();
162 }
163 }
164
165 /// Register [label] as used.
166 void useLabel(tree.Label label) {
167 _usedLabels.add(label);
168 }
169
170 /// Remove [label] and return `true` if it was used.
171 bool removeUsedLabel(tree.Label label) {
172 return _usedLabels.remove(label);
173 }
174
175 /// Add [statement] to the current block.
176 void addStatement(T statement) {
177 _statementBuffer.add(statement);
178 }
179
180 /// The statements in the current block.
181 Iterable<T> get statements => _statementBuffer;
182 }
183
184
185 /// Translates the dart_tree IR to Dart backend AST.
186 /// An instance of this class should only be used once; a fresh emitter
187 /// must be created for each function to be emitted.
188 class ASTEmitter
189 extends tree.Visitor1<dynamic, Expression, BuilderContext<Statement>> {
190
191 ExecutableDefinition emit(tree.ExecutableDefinition definition,
192 BuilderContext<Statement> context) {
74 if (definition is tree.FieldDefinition) { 193 if (definition is tree.FieldDefinition) {
75 return emitField(definition); 194 return emitField(definition, context);
76 } 195 }
77 assert(definition is tree.FunctionDefinition); 196 assert(definition is tree.FunctionDefinition);
78 return emitFunction(definition); 197 return emitFunction(definition, context);
79 } 198 }
80 199
81 FieldDefinition emitField(tree.FieldDefinition definition) { 200 FieldDefinition emitField(tree.FieldDefinition definition,
82 currentElement = definition.element; 201 BuilderContext<Statement> context) {
83 visitStatement(definition.body); 202 context.currentElement = definition.element;
203 visitStatement(definition.body, context);
84 List<Statement> bodyParts; 204 List<Statement> bodyParts;
85 for (tree.Variable variable in variableNames.keys) { 205 for (tree.Variable variable in context.variableNames.keys) {
86 if (!declaredVariables.contains(variable)) { 206 if (!context.declaredVariables.contains(variable)) {
87 addDeclaration(variable); 207 context.addDeclaration(variable);
88 } 208 }
89 } 209 }
90 if (variables.length > 0) { 210 if (context.variables.length > 0) {
91 bodyParts = new List<Statement>(); 211 bodyParts = new List<Statement>();
92 bodyParts.add(new VariableDeclarations(variables)); 212 bodyParts.add(new VariableDeclarations(context.variables));
93 bodyParts.addAll(statementBuffer); 213 bodyParts.addAll(context.statements);
94 } else { 214 } else {
95 bodyParts = statementBuffer; 215 bodyParts = context.statements;
96 } 216 }
97 217
98 return new FieldDefinition(definition.element, ensureExpression(bodyParts)); 218 return new FieldDefinition(definition.element, ensureExpression(bodyParts));
99 } 219 }
100 220
101 /// Returns an expression that will evaluate all of [bodyParts]. 221 /// Returns an expression that will evaluate all of [bodyParts].
102 /// If [bodyParts] is a single [Return] return its value. 222 /// If [bodyParts] is a single [Return] return its value.
103 /// Otherwise wrap the body-parts in an immediately invoked closure. 223 /// Otherwise wrap the body-parts in an immediately invoked closure.
104 Expression ensureExpression(List<Statement> bodyParts) { 224 Expression ensureExpression(List<Statement> bodyParts) {
105 if (bodyParts.length == 1) { 225 if (bodyParts.length == 1) {
106 Statement onlyStatement = bodyParts.single; 226 Statement onlyStatement = bodyParts.single;
107 if (onlyStatement is Return) { 227 if (onlyStatement is Return) {
108 return onlyStatement.expression; 228 return onlyStatement.expression;
109 } 229 }
110 } 230 }
111 Statement body = new Block(bodyParts); 231 Statement body = new Block(bodyParts);
112 FunctionExpression function = 232 FunctionExpression function =
113 new FunctionExpression(new Parameters([]), body); 233 new FunctionExpression(new Parameters([]), body);
114 function.element = null; 234 function.element = null;
115 return new CallFunction(function, []); 235 return new CallFunction(function, []);
116 } 236 }
117 237
118 FunctionExpression emitFunction(tree.FunctionDefinition definition) { 238 FunctionExpression emitFunction(tree.FunctionDefinition definition,
119 currentElement = definition.element; 239 BuilderContext<Statement> context) {
240 context.currentElement = definition.element;
120 241
121 Parameters parameters = emitRootParameters(definition); 242 Parameters parameters = emitRootParameters(definition, context);
122 243
123 // Declare parameters. 244 // Declare parameters.
124 for (tree.Variable param in definition.parameters) { 245 for (tree.Variable param in definition.parameters) {
125 variableNames[param] = param.element.name; 246 context.variableNames[param] = param.element.name;
126 usedVariableNames.add(param.element.name); 247 context.usedVariableNames.add(param.element.name);
127 declaredVariables.add(param); 248 context.declaredVariables.add(param);
128 } 249 }
129 250
130 Statement body; 251 Statement body;
131 if (definition.isAbstract) { 252 if (definition.isAbstract) {
132 body = new EmptyStatement(); 253 body = new EmptyStatement();
133 } else { 254 } else {
134 firstStatement = definition.body; 255 context.firstStatement = definition.body;
135 visitStatement(definition.body); 256 visitStatement(definition.body, context);
136 removeTrailingReturn(); 257 context.removeTrailingReturn((Statement statement) {
258 if (statement is Return) {
259 Expression expr = statement.expression;
260 if (expr is Literal && expr.value.isNull) {
261 return true;
262 }
263 }
264 return false;
265 });
137 266
138 // Some of the variable declarations have already been added 267 // Some of the variable declarations have already been added
139 // if their first assignment could be pulled into the initializer. 268 // if their first assignment could be pulled into the initializer.
140 // Add the remaining variable declarations now. 269 // Add the remaining variable declarations now.
141 for (tree.Variable variable in variableNames.keys) { 270 for (tree.Variable variable in context.variableNames.keys) {
142 if (!declaredVariables.contains(variable)) { 271 if (!context.declaredVariables.contains(variable)) {
143 addDeclaration(variable); 272 context.addDeclaration(variable);
144 } 273 }
145 } 274 }
146 275
147 // Add constant declarations. 276 // Add constant declarations.
148 List<VariableDeclaration> constants = <VariableDeclaration>[]; 277 List<VariableDeclaration> constants = <VariableDeclaration>[];
149 for (ConstDeclaration constDecl in definition.localConstants) { 278 for (ConstDeclaration constDecl in definition.localConstants) {
150 if (!constantNames.containsKey(constDecl.element)) 279 if (!context.constantNames.containsKey(constDecl.element)) {
151 continue; // Discard unused constants declarations. 280 continue; // Discard unused constants declarations.
152 String name = getConstantName(constDecl.element); 281 }
153 Expression value = emitConstant(constDecl.expression); 282 String name = context.getConstantName(constDecl.element);
283 Expression value = emitConstant(constDecl.expression, context);
154 VariableDeclaration decl = new VariableDeclaration(name, value); 284 VariableDeclaration decl = new VariableDeclaration(name, value);
155 decl.element = constDecl.element; 285 decl.element = constDecl.element;
156 constants.add(decl); 286 constants.add(decl);
157 } 287 }
158 288
159 List<Statement> bodyParts = []; 289 List<Statement> bodyParts = [];
160 if (constants.length > 0) { 290 if (constants.length > 0) {
161 bodyParts.add(new VariableDeclarations(constants, isConst: true)); 291 bodyParts.add(new VariableDeclarations(constants, isConst: true));
162 } 292 }
163 if (variables.length > 0) { 293 if (context.variables.length > 0) {
164 bodyParts.add(new VariableDeclarations(variables)); 294 bodyParts.add(new VariableDeclarations(context.variables));
165 } 295 }
166 bodyParts.addAll(statementBuffer); 296 bodyParts.addAll(context.statements);
167 297
168 body = new Block(bodyParts); 298 body = new Block(bodyParts);
169 } 299 }
170 FunctionType functionType = currentElement.type; 300 FunctionType functionType = context.currentElement.type;
171 301
172 return new FunctionExpression( 302 return new FunctionExpression(
173 parameters, 303 parameters,
174 body, 304 body,
175 name: currentElement.name, 305 name: context.currentElement.name,
176 returnType: emitOptionalType(functionType.returnType), 306 returnType: emitOptionalType(functionType.returnType),
177 isGetter: currentElement.isGetter, 307 isGetter: context.currentElement.isGetter,
178 isSetter: currentElement.isSetter) 308 isSetter: context.currentElement.isSetter)
179 ..element = currentElement; 309 ..element = context.currentElement;
180 }
181
182 void addDeclaration(tree.Variable variable, [Expression initializer]) {
183 assert(!declaredVariables.contains(variable));
184 String name = getVariableName(variable);
185 VariableDeclaration decl = new VariableDeclaration(name, initializer);
186 decl.element = variable.element;
187 declaredVariables.add(variable);
188 variables.add(decl);
189 }
190
191 /// Removes a trailing "return null" from [statementBuffer].
192 void removeTrailingReturn() {
193 if (statementBuffer.isEmpty) return;
194 if (statementBuffer.last is! Return) return;
195 Return ret = statementBuffer.last;
196 Expression expr = ret.expression;
197 if (expr is Literal && expr.value.isNull) {
198 statementBuffer.removeLast();
199 }
200 } 310 }
201 311
202 /// TODO(johnniwinther): Remove this when issue 21283 has been resolved. 312 /// TODO(johnniwinther): Remove this when issue 21283 has been resolved.
203 int pseudoNameCounter = 0; 313 int pseudoNameCounter = 0;
204 314
205 Parameter emitParameter(DartType type, 315 Parameter emitParameter(DartType type,
316 BuilderContext<Statement> context,
206 {String name, 317 {String name,
207 Element element, 318 Element element,
208 ConstantExpression defaultValue}) { 319 ConstantExpression defaultValue}) {
209 if (name == null && element != null) { 320 if (name == null && element != null) {
210 name = element.name; 321 name = element.name;
211 } 322 }
212 if (name == null) { 323 if (name == null) {
213 name = '_${pseudoNameCounter++}'; 324 name = '_${pseudoNameCounter++}';
214 } 325 }
215 Parameter parameter; 326 Parameter parameter;
216 if (type.isFunctionType) { 327 if (type.isFunctionType) {
217 FunctionType functionType = type; 328 FunctionType functionType = type;
218 TypeAnnotation returnType = emitOptionalType(functionType.returnType); 329 TypeAnnotation returnType = emitOptionalType(functionType.returnType);
219 Parameters innerParameters = emitParametersFromType(functionType); 330 Parameters innerParameters =
331 emitParametersFromType(functionType, context);
220 parameter = new Parameter.function(name, returnType, innerParameters); 332 parameter = new Parameter.function(name, returnType, innerParameters);
221 } else { 333 } else {
222 TypeAnnotation typeAnnotation = emitOptionalType(type); 334 TypeAnnotation typeAnnotation = emitOptionalType(type);
223 parameter = new Parameter(name, type: typeAnnotation); 335 parameter = new Parameter(name, type: typeAnnotation);
224 } 336 }
225 parameter.element = element; 337 parameter.element = element;
226 if (defaultValue != null && !defaultValue.value.isNull) { 338 if (defaultValue != null && !defaultValue.value.isNull) {
227 parameter.defaultValue = emitConstant(defaultValue); 339 parameter.defaultValue = emitConstant(defaultValue, context);
228 } 340 }
229 return parameter; 341 return parameter;
230 } 342 }
231 343
232 Parameters emitParametersFromType(FunctionType functionType) { 344 Parameters emitParametersFromType(FunctionType functionType,
345 BuilderContext<Statement> context) {
233 if (functionType.namedParameters.isEmpty) { 346 if (functionType.namedParameters.isEmpty) {
234 return new Parameters( 347 return new Parameters(
235 emitParameters(functionType.parameterTypes), 348 emitParameters(functionType.parameterTypes, context),
236 emitParameters(functionType.optionalParameterTypes), 349 emitParameters(functionType.optionalParameterTypes, context),
237 false); 350 false);
238 } else { 351 } else {
239 return new Parameters( 352 return new Parameters(
240 emitParameters(functionType.parameterTypes), 353 emitParameters(functionType.parameterTypes, context),
241 emitParameters(functionType.namedParameterTypes, 354 emitParameters(functionType.namedParameterTypes, context,
242 names: functionType.namedParameters), 355 names: functionType.namedParameters),
243 true); 356 true);
244 } 357 }
245 } 358 }
246 359
247 List<Parameter> emitParameters( 360 List<Parameter> emitParameters(
248 Iterable<DartType> parameterTypes, 361 Iterable<DartType> parameterTypes,
362 BuilderContext<Statement> context,
249 {Iterable<String> names: const <String>[], 363 {Iterable<String> names: const <String>[],
250 Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[], 364 Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[],
251 Iterable<Element> elements: const <Element>[]}) { 365 Iterable<Element> elements: const <Element>[]}) {
252 Iterator<String> name = names.iterator; 366 Iterator<String> name = names.iterator;
253 Iterator<ConstantExpression> defaultValue = defaultValues.iterator; 367 Iterator<ConstantExpression> defaultValue = defaultValues.iterator;
254 Iterator<Element> element = elements.iterator; 368 Iterator<Element> element = elements.iterator;
255 return parameterTypes.map((DartType type) { 369 return parameterTypes.map((DartType type) {
256 name.moveNext(); 370 name.moveNext();
257 defaultValue.moveNext(); 371 defaultValue.moveNext();
258 element.moveNext(); 372 element.moveNext();
259 return emitParameter(type, 373 return emitParameter(type, context,
260 name: name.current, 374 name: name.current,
261 defaultValue: defaultValue.current, 375 defaultValue: defaultValue.current,
262 element: element.current); 376 element: element.current);
263 }).toList(); 377 }).toList();
264 } 378 }
265 379
266 /// Emits parameters that are not nested inside other parameters. 380 /// Emits parameters that are not nested inside other parameters.
267 /// Root parameters can have default values, while inner parameters cannot. 381 /// Root parameters can have default values, while inner parameters cannot.
268 Parameters emitRootParameters(tree.FunctionDefinition function) { 382 Parameters emitRootParameters(tree.FunctionDefinition function,
383 BuilderContext<Statement> context) {
269 FunctionType functionType = function.element.type; 384 FunctionType functionType = function.element.type;
270 List<Parameter> required = emitParameters( 385 List<Parameter> required = emitParameters(
271 functionType.parameterTypes, 386 functionType.parameterTypes, context,
272 elements: function.parameters.map((p) => p.element)); 387 elements: function.parameters.map((p) => p.element));
273 bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty; 388 bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty;
274 List<Parameter> optional = emitParameters( 389 List<Parameter> optional = emitParameters(
275 optionalParametersAreNamed 390 optionalParametersAreNamed
276 ? functionType.namedParameterTypes 391 ? functionType.namedParameterTypes
277 : functionType.optionalParameterTypes, 392 : functionType.optionalParameterTypes,
393 context,
278 defaultValues: function.defaultParameterValues, 394 defaultValues: function.defaultParameterValues,
279 elements: function.parameters.skip(required.length) 395 elements: function.parameters.skip(required.length)
280 .map((p) => p.element)); 396 .map((p) => p.element));
281 return new Parameters(required, optional, optionalParametersAreNamed); 397 return new Parameters(required, optional, optionalParametersAreNamed);
282 } 398 }
283 399
284 /// True if the two expressions are a reference to the same variable. 400 /// True if the two expressions are a reference to the same variable.
285 bool isSameVariable(Receiver e1, Receiver e2) { 401 bool isSameVariable(Receiver e1, Receiver e2) {
286 return e1 is Identifier && 402 return e1 is Identifier &&
287 e2 is Identifier && 403 e2 is Identifier &&
(...skipping 26 matching lines...) Expand all
314 return new Increment.prefix(target, value.operator + value.operator); 430 return new Increment.prefix(target, value.operator + value.operator);
315 } else { 431 } else {
316 return new Assignment(target, value.operator + '=', rightOperand); 432 return new Assignment(target, value.operator + '=', rightOperand);
317 } 433 }
318 } 434 }
319 } 435 }
320 // Fall back to regular assignment 436 // Fall back to regular assignment
321 return new Assignment(target, '=', value); 437 return new Assignment(target, '=', value);
322 } 438 }
323 439
324 void visitExpressionStatement(tree.ExpressionStatement stmt) { 440 Block visitInSubContext(tree.Statement statement,
325 Expression e = visitExpression(stmt.expression); 441 BuilderContext<Statement> context,
326 statementBuffer.add(new ExpressionStatement(e)); 442 {tree.Statement fallthrough}) {
327 visitStatement(stmt.next); 443 return new Block(context.inSubcontext(
444 (BuilderContext<Statement> subcontext) {
445 visitStatement(statement, subcontext);
446 }, fallthrough: fallthrough));
328 } 447 }
329 448
330 void visitLabeledStatement(tree.LabeledStatement stmt) { 449 void addLabeledStatement(tree.Label label,
331 List<Statement> savedBuffer = statementBuffer; 450 Statement statement,
332 tree.Statement savedFallthrough = fallthrough; 451 BuilderContext<Statement> context) {
333 statementBuffer = <Statement>[]; 452 if (context.removeUsedLabel(label)) {
334 fallthrough = stmt.next; 453 context.addStatement(new LabeledStatement(label.name, statement));
335 visitStatement(stmt.body);
336 if (usedLabels.remove(stmt.label)) {
337 savedBuffer.add(new LabeledStatement(stmt.label.name,
338 new Block(statementBuffer)));
339 } else { 454 } else {
340 savedBuffer.add(new Block(statementBuffer)); 455 context.addStatement(statement);
341 } 456 }
342 fallthrough = savedFallthrough;
343 statementBuffer = savedBuffer;
344 visitStatement(stmt.next);
345 } 457 }
346 458
347 /// Generates a name for the given variable and synthesizes an element for it, 459 @override
348 /// if necessary. 460 void visitExpressionStatement(tree.ExpressionStatement stmt,
349 String getVariableName(tree.Variable variable) { 461 BuilderContext<Statement> context) {
350 // If the variable belongs to an enclosing function, ask the parent emitter 462 Expression e = visitExpression(stmt.expression, context);
351 // for the variable name. 463 context.addStatement(new ExpressionStatement(e));
352 if (variable.host != currentElement) {
353 return parent.getVariableName(variable);
354 }
355 464
356 // Get the name if we already have one. 465 visitStatement(stmt.next, context);
357 String name = variableNames[variable];
358 if (name != null) {
359 return name;
360 }
361
362 // Synthesize a variable name that isn't used elsewhere.
363 // The [usedVariableNames] set is shared between nested emitters,
364 // so this also prevents clash with variables in an enclosing/inner scope.
365 // The renaming phase after codegen will further prefix local variables
366 // so they cannot clash with top-level variables or fields.
367 String prefix = variable.element == null ? 'v' : variable.element.name;
368 int counter = 0;
369 name = variable.element == null ? '$prefix$counter' : variable.element.name;
370 while (!usedVariableNames.add(name)) {
371 ++counter;
372 name = '$prefix$counter';
373 }
374 variableNames[variable] = name;
375
376 // Synthesize an element for the variable
377 if (variable.element == null || name != variable.element.name) {
378 // TODO(johnniwinther): Replace by synthetic [Entity].
379 variable.element = new _SyntheticLocalVariableElement(
380 name,
381 currentElement,
382 variableList);
383 }
384 return name;
385 } 466 }
386 467
387 String getConstantName(VariableElement element) { 468 @override
388 assert(element.kind == ElementKind.VARIABLE); 469 void visitLabeledStatement(tree.LabeledStatement stmt,
389 if (element.enclosingElement != currentElement) { 470 BuilderContext<Statement> context) {
390 return parent.getConstantName(element); 471 Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
391 } 472 addLabeledStatement(stmt.label, block, context);
392 String name = constantNames[element]; 473
393 if (name != null) { 474 visitStatement(stmt.next, context);
394 return name;
395 }
396 String prefix = element.name;
397 int counter = 0;
398 name = element.name;
399 while (!usedVariableNames.add(name)) {
400 ++counter;
401 name = '$prefix$counter';
402 }
403 constantNames[element] = name;
404 return name;
405 } 475 }
406 476
407 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull; 477 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
408 478
409 void visitAssign(tree.Assign stmt) { 479 @override
480 void visitAssign(tree.Assign stmt,
481 BuilderContext<Statement> context) {
410 // Try to emit a local function declaration. This is useful for functions 482 // Try to emit a local function declaration. This is useful for functions
411 // that may occur in expression context, but could not be inlined anywhere. 483 // that may occur in expression context, but could not be inlined anywhere.
412 if (stmt.variable.element is FunctionElement && 484 if (stmt.variable.element is FunctionElement &&
413 stmt.definition is tree.FunctionExpression && 485 stmt.definition is tree.FunctionExpression &&
414 !declaredVariables.contains(stmt.variable)) { 486 !context.declaredVariables.contains(stmt.variable)) {
415 tree.FunctionExpression functionExp = stmt.definition; 487 tree.FunctionExpression functionExp = stmt.definition;
416 FunctionExpression function = makeSubFunction(functionExp.definition); 488 FunctionExpression function =
489 makeSubFunction(functionExp.definition, context);
417 FunctionDeclaration decl = new FunctionDeclaration(function); 490 FunctionDeclaration decl = new FunctionDeclaration(function);
418 statementBuffer.add(decl); 491 context.addStatement(decl);
419 declaredVariables.add(stmt.variable); 492 context.declaredVariables.add(stmt.variable);
420 visitStatement(stmt.next); 493
494 visitStatement(stmt.next, context);
421 return; 495 return;
422 } 496 }
423 497
424 bool isFirstOccurrence = (variableNames[stmt.variable] == null); 498 bool isFirstOccurrence = (context.variableNames[stmt.variable] == null);
425 bool isDeclaredHere = stmt.variable.host == currentElement; 499 bool isDeclaredHere = stmt.variable.host == context.currentElement;
426 String name = getVariableName(stmt.variable); 500 String name = context.getVariableName(stmt.variable);
427 Expression definition = visitExpression(stmt.definition); 501 Expression definition = visitExpression(stmt.definition, context);
428 502
429 // Try to pull into initializer. 503 // Try to pull into initializer.
430 if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { 504 if (context.firstStatement == stmt && isFirstOccurrence && isDeclaredHere) {
431 if (isNullLiteral(definition)) definition = null; 505 if (isNullLiteral(definition)) definition = null;
432 addDeclaration(stmt.variable, definition); 506 context.addDeclaration(stmt.variable, definition);
433 firstStatement = stmt.next; 507 context.firstStatement = stmt.next;
434 visitStatement(stmt.next); 508 visitStatement(stmt.next, context);
435 return; 509 return;
436 } 510 }
437 511
438 // Emit a variable declaration if we are required to do so. 512 // Emit a variable declaration if we are required to do so.
439 // This is to ensure that a fresh closure variable is created. 513 // This is to ensure that a fresh closure variable is created.
440 if (stmt.isDeclaration) { 514 if (stmt.isDeclaration) {
441 assert(isFirstOccurrence); 515 assert(isFirstOccurrence);
442 assert(isDeclaredHere); 516 assert(isDeclaredHere);
443 if (isNullLiteral(definition)) definition = null; 517 if (isNullLiteral(definition)) definition = null;
444 VariableDeclaration decl = new VariableDeclaration(name, definition) 518 VariableDeclaration decl = new VariableDeclaration(name, definition)
445 ..element = stmt.variable.element; 519 ..element = stmt.variable.element;
446 declaredVariables.add(stmt.variable); 520 context.declaredVariables.add(stmt.variable);
447 statementBuffer.add(new VariableDeclarations([decl])); 521 context.addStatement(new VariableDeclarations([decl]));
448 visitStatement(stmt.next); 522 visitStatement(stmt.next, context);
449 return; 523 return;
450 } 524 }
451 525
452 statementBuffer.add(new ExpressionStatement(makeAssignment( 526 context.addStatement(new ExpressionStatement(makeAssignment(
453 visitVariable(stmt.variable), 527 visitVariable(stmt.variable, context),
454 definition))); 528 definition)));
455 visitStatement(stmt.next); 529 visitStatement(stmt.next, context);
456 } 530 }
457 531
458 void visitReturn(tree.Return stmt) { 532 @override
459 Expression inner = visitExpression(stmt.value); 533 void visitReturn(tree.Return stmt,
460 statementBuffer.add(new Return(inner)); 534 BuilderContext<Statement> context) {
535 Expression inner = visitExpression(stmt.value, context);
536 context.addStatement(new Return(inner));
461 } 537 }
462 538
463 void visitBreak(tree.Break stmt) { 539 @override
464 tree.Statement fall = fallthrough; 540 void visitBreak(tree.Break stmt,
541 BuilderContext<Statement> context) {
542 tree.Statement fall = context.fallthrough;
465 if (stmt.target.binding.next == fall) { 543 if (stmt.target.binding.next == fall) {
466 // Fall through to break target 544 // Fall through to break target
467 } else if (fall is tree.Break && fall.target == stmt.target) { 545 } else if (fall is tree.Break && fall.target == stmt.target) {
468 // Fall through to equivalent break 546 // Fall through to equivalent break
469 } else { 547 } else {
470 usedLabels.add(stmt.target); 548 context.useLabel(stmt.target);
471 statementBuffer.add(new Break(stmt.target.name)); 549 context.addStatement(new Break(stmt.target.name));
472 } 550 }
473 } 551 }
474 552
475 void visitContinue(tree.Continue stmt) { 553 @override
476 tree.Statement fall = fallthrough; 554 void visitContinue(tree.Continue stmt,
555 BuilderContext<Statement> context) {
556 tree.Statement fall = context.fallthrough;
477 if (stmt.target.binding == fall) { 557 if (stmt.target.binding == fall) {
478 // Fall through to continue target 558 // Fall through to continue target
479 } else if (fall is tree.Continue && fall.target == stmt.target) { 559 } else if (fall is tree.Continue && fall.target == stmt.target) {
480 // Fall through to equivalent continue 560 // Fall through to equivalent continue
481 } else { 561 } else {
482 usedLabels.add(stmt.target); 562 context.useLabel(stmt.target);
483 statementBuffer.add(new Continue(stmt.target.name)); 563 context.addStatement(new Continue(stmt.target.name));
484 } 564 }
485 } 565 }
486 566
487 void visitIf(tree.If stmt) { 567 @override
488 Expression condition = visitExpression(stmt.condition); 568 void visitIf(tree.If stmt,
489 List<Statement> savedBuffer = statementBuffer; 569 BuilderContext<Statement> context) {
490 List<Statement> thenBuffer = statementBuffer = <Statement>[]; 570 Expression condition = visitExpression(stmt.condition, context);
491 visitStatement(stmt.thenStatement); 571 Block thenBlock = visitInSubContext(stmt.thenStatement, context);
492 List<Statement> elseBuffer = statementBuffer = <Statement>[]; 572 Block elseBlock= visitInSubContext(stmt.elseStatement, context);
493 visitStatement(stmt.elseStatement); 573 context.addStatement(new If(condition, thenBlock, elseBlock));
494 savedBuffer.add(
495 new If(condition, new Block(thenBuffer), new Block(elseBuffer)));
496 statementBuffer = savedBuffer;
497 } 574 }
498 575
499 void visitWhileTrue(tree.WhileTrue stmt) { 576 @override
500 List<Statement> savedBuffer = statementBuffer; 577 void visitWhileTrue(tree.WhileTrue stmt,
501 tree.Statement savedFallthrough = fallthrough; 578 BuilderContext<Statement> context) {
502 statementBuffer = <Statement>[]; 579 Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
503 fallthrough = stmt; 580 Statement statement =
504 581 new While(new Literal(new TrueConstantValue()), body);
505 visitStatement(stmt.body); 582 addLabeledStatement(stmt.label, statement, context);
506 Statement body = new Block(statementBuffer);
507 Statement statement = new While(new Literal(new TrueConstantValue()),
508 body);
509 if (usedLabels.remove(stmt.label)) {
510 statement = new LabeledStatement(stmt.label.name, statement);
511 }
512 savedBuffer.add(statement);
513
514 statementBuffer = savedBuffer;
515 fallthrough = savedFallthrough;
516 } 583 }
517 584
518 void visitWhileCondition(tree.WhileCondition stmt) { 585 @override
519 Expression condition = visitExpression(stmt.condition); 586 void visitWhileCondition(tree.WhileCondition stmt,
587 BuilderContext<Statement> context) {
588 Expression condition = visitExpression(stmt.condition, context);
589 Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
590 Statement statement = new While(condition, body);
591 addLabeledStatement(stmt.label, statement, context);
520 592
521 List<Statement> savedBuffer = statementBuffer; 593 visitStatement(stmt.next, context);
522 tree.Statement savedFallthrough = fallthrough;
523 statementBuffer = <Statement>[];
524 fallthrough = stmt;
525
526 visitStatement(stmt.body);
527 Statement body = new Block(statementBuffer);
528 Statement statement;
529 statement = new While(condition, body);
530 if (usedLabels.remove(stmt.label)) {
531 statement = new LabeledStatement(stmt.label.name, statement);
532 }
533 savedBuffer.add(statement);
534
535 statementBuffer = savedBuffer;
536 fallthrough = savedFallthrough;
537
538 visitStatement(stmt.next);
539 } 594 }
540 595
541 Expression visitConstant(tree.Constant exp) { 596 @override
542 return emitConstant(exp.expression); 597 Expression visitConstant(tree.Constant exp,
598 BuilderContext<Statement> context) {
599 return emitConstant(exp.expression, context);
543 } 600 }
544 601
545 Expression visitThis(tree.This exp) { 602 @override
603 Expression visitThis(tree.This exp,
604 BuilderContext<Statement> context) {
546 return new This(); 605 return new This();
547 } 606 }
548 607
549 Expression visitReifyTypeVar(tree.ReifyTypeVar exp) { 608 @override
609 Expression visitReifyTypeVar(tree.ReifyTypeVar exp,
610 BuilderContext<Statement> context) {
550 return new ReifyTypeVar(exp.typeVariable.name) 611 return new ReifyTypeVar(exp.typeVariable.name)
551 ..element = exp.typeVariable; 612 ..element = exp.typeVariable;
552 } 613 }
553 614
554 Expression visitLiteralList(tree.LiteralList exp) { 615 List<Expression> visitExpressions(List<tree.Expression> expressions,
555 return new LiteralList( 616 BuilderContext<Statement> context) {
556 exp.values.map(visitExpression).toList(growable: false), 617 return expressions.map((expression) => visitExpression(expression, context))
618 .toList(growable: false);
619 }
620
621 @override
622 Expression visitLiteralList(tree.LiteralList exp,
623 BuilderContext<Statement> context) {
624 return new LiteralList(visitExpressions(exp.values, context),
557 typeArgument: emitOptionalType(exp.type.typeArguments.single)); 625 typeArgument: emitOptionalType(exp.type.typeArguments.single));
558 } 626 }
559 627
560 Expression visitLiteralMap(tree.LiteralMap exp) { 628 @override
629 Expression visitLiteralMap(tree.LiteralMap exp,
630 BuilderContext<Statement> context) {
561 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( 631 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
562 exp.entries.length, 632 exp.entries.length,
563 (i) => new LiteralMapEntry(visitExpression(exp.entries[i].key), 633 (i) => new LiteralMapEntry(visitExpression(exp.entries[i].key, context),
564 visitExpression(exp.entries[i].value))); 634 visitExpression(exp.entries[i].value, context )));
565 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw 635 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
566 ? null 636 ? null
567 : exp.type.typeArguments.map(createTypeAnnotation) 637 : exp.type.typeArguments.map(createTypeAnnotation)
568 .toList(growable: false); 638 .toList(growable: false);
569 return new LiteralMap(entries, typeArguments: typeArguments); 639 return new LiteralMap(entries, typeArguments: typeArguments);
570 } 640 }
571 641
572 Expression visitTypeOperator(tree.TypeOperator exp) { 642 @override
573 return new TypeOperator(visitExpression(exp.receiver), 643 Expression visitTypeOperator(tree.TypeOperator exp,
644 BuilderContext<Statement> context) {
645 return new TypeOperator(visitExpression(exp.receiver, context),
574 exp.operator, 646 exp.operator,
575 createTypeAnnotation(exp.type)); 647 createTypeAnnotation(exp.type));
576 } 648 }
577 649
578 List<Argument> emitArguments(tree.Invoke exp) { 650 List<Argument> emitArguments(tree.Invoke exp,
651 BuilderContext<Statement> context) {
579 List<tree.Expression> args = exp.arguments; 652 List<tree.Expression> args = exp.arguments;
580 int positionalArgumentCount = exp.selector.positionalArgumentCount; 653 int positionalArgumentCount = exp.selector.positionalArgumentCount;
581 List<Argument> result = new List<Argument>.generate(positionalArgumentCount, 654 List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
582 (i) => visitExpression(exp.arguments[i])); 655 (i) => visitExpression(exp.arguments[i], context));
583 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) { 656 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
584 result.add(new NamedArgument(exp.selector.namedArguments[i], 657 result.add(new NamedArgument(exp.selector.namedArguments[i],
585 visitExpression(exp.arguments[positionalArgumentCount + i]))); 658 visitExpression(exp.arguments[positionalArgumentCount + i], context))) ;
586 } 659 }
587 return result; 660 return result;
588 } 661 }
589 662
590 Expression visitInvokeStatic(tree.InvokeStatic exp) { 663 @override
664 Expression visitInvokeStatic(tree.InvokeStatic exp,
665 BuilderContext<Statement> context) {
591 switch (exp.selector.kind) { 666 switch (exp.selector.kind) {
592 case SelectorKind.GETTER: 667 case SelectorKind.GETTER:
593 return new Identifier(exp.target.name)..element = exp.target; 668 return new Identifier(exp.target.name)..element = exp.target;
594 669
595 case SelectorKind.SETTER: 670 case SelectorKind.SETTER:
596 return new Assignment( 671 return new Assignment(
597 new Identifier(exp.target.name)..element = exp.target, 672 new Identifier(exp.target.name)..element = exp.target,
598 '=', 673 '=',
599 visitExpression(exp.arguments[0])); 674 visitExpression(exp.arguments[0], context));
600 675
601 case SelectorKind.CALL: 676 case SelectorKind.CALL:
602 return new CallStatic(null, exp.target.name, emitArguments(exp)) 677 return new CallStatic(
678 null, exp.target.name, emitArguments(exp, context))
603 ..element = exp.target; 679 ..element = exp.target;
604 680
605 default: 681 default:
606 throw "Unexpected selector kind: ${exp.selector.kind}"; 682 throw "Unexpected selector kind: ${exp.selector.kind}";
607 } 683 }
608 } 684 }
609 685
610 Expression emitMethodCall(tree.Invoke exp, Receiver receiver) { 686 Expression emitMethodCall(tree.Invoke exp, Receiver receiver,
611 List<Argument> args = emitArguments(exp); 687 BuilderContext<Statement> context) {
688 List<Argument> args = emitArguments(exp, context);
612 switch (exp.selector.kind) { 689 switch (exp.selector.kind) {
613 case SelectorKind.CALL: 690 case SelectorKind.CALL:
614 if (exp.selector.name == "call") { 691 if (exp.selector.name == "call") {
615 return new CallFunction(receiver, args); 692 return new CallFunction(receiver, args);
616 } 693 }
617 return new CallMethod(receiver, exp.selector.name, args); 694 return new CallMethod(receiver, exp.selector.name, args);
618 695
619 case SelectorKind.OPERATOR: 696 case SelectorKind.OPERATOR:
620 if (args.length == 0) { 697 if (args.length == 0) {
621 String name = exp.selector.name; 698 String name = exp.selector.name;
(...skipping 17 matching lines...) Expand all
639 if (args.length == 2) { 716 if (args.length == 2) {
640 e = makeAssignment(e, args[1]); 717 e = makeAssignment(e, args[1]);
641 } 718 }
642 return e; 719 return e;
643 720
644 default: 721 default:
645 throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}"; 722 throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}";
646 } 723 }
647 } 724 }
648 725
649 Expression visitInvokeMethod(tree.InvokeMethod exp) { 726 @override
650 Expression receiver = visitExpression(exp.receiver); 727 Expression visitInvokeMethod(tree.InvokeMethod exp,
651 return emitMethodCall(exp, receiver); 728 BuilderContext<Statement> context) {
729 Expression receiver = visitExpression(exp.receiver, context);
730 return emitMethodCall(exp, receiver, context);
652 } 731 }
653 732
654 Expression visitInvokeSuperMethod(tree.InvokeSuperMethod exp) { 733 @override
655 return emitMethodCall(exp, new SuperReceiver()); 734 Expression visitInvokeSuperMethod(tree.InvokeSuperMethod exp,
735 BuilderContext<Statement> context) {
736 return emitMethodCall(exp, new SuperReceiver(), context);
656 } 737 }
657 738
658 Expression visitInvokeConstructor(tree.InvokeConstructor exp) { 739 @override
659 List args = emitArguments(exp); 740 Expression visitInvokeConstructor(tree.InvokeConstructor exp,
741 BuilderContext<Statement> context) {
742 List args = emitArguments(exp, context);
660 FunctionElement constructor = exp.target; 743 FunctionElement constructor = exp.target;
661 String name = constructor.name.isEmpty ? null : constructor.name; 744 String name = constructor.name.isEmpty ? null : constructor.name;
662 return new CallNew(createTypeAnnotation(exp.type), 745 return new CallNew(createTypeAnnotation(exp.type),
663 args, 746 args,
664 constructorName: name, 747 constructorName: name,
665 isConst: exp.constant != null) 748 isConst: exp.constant != null)
666 ..constructor = constructor 749 ..constructor = constructor
667 ..dartType = exp.type; 750 ..dartType = exp.type;
668 } 751 }
669 752
670 Expression visitConcatenateStrings(tree.ConcatenateStrings exp) { 753 @override
671 List args = exp.arguments.map(visitExpression).toList(growable:false); 754 Expression visitConcatenateStrings(tree.ConcatenateStrings exp,
672 return new StringConcat(args); 755 BuilderContext<Statement> context) {
756 return new StringConcat(visitExpressions(exp.arguments, context));
673 } 757 }
674 758
675 Expression visitConditional(tree.Conditional exp) { 759 @override
760 Expression visitConditional(tree.Conditional exp,
761 BuilderContext<Statement> context) {
676 return new Conditional( 762 return new Conditional(
677 visitExpression(exp.condition), 763 visitExpression(exp.condition, context),
678 visitExpression(exp.thenExpression), 764 visitExpression(exp.thenExpression, context),
679 visitExpression(exp.elseExpression)); 765 visitExpression(exp.elseExpression, context));
680 } 766 }
681 767
682 Expression visitLogicalOperator(tree.LogicalOperator exp) { 768 @override
683 return new BinaryOperator(visitExpression(exp.left), 769 Expression visitLogicalOperator(tree.LogicalOperator exp,
770 BuilderContext<Statement> context) {
771 return new BinaryOperator(visitExpression(exp.left, context),
684 exp.operator, 772 exp.operator,
685 visitExpression(exp.right)); 773 visitExpression(exp.right, context));
686 } 774 }
687 775
688 Expression visitNot(tree.Not exp) { 776 @override
689 return new UnaryOperator('!', visitExpression(exp.operand)); 777 Expression visitNot(tree.Not exp,
778 BuilderContext<Statement> context) {
779 return new UnaryOperator('!', visitExpression(exp.operand, context));
690 } 780 }
691 781
692 Expression visitVariable(tree.Variable exp) { 782 @override
693 return new Identifier(getVariableName(exp)) 783 Expression visitVariable(tree.Variable exp,
784 BuilderContext<Statement> context) {
785 return new Identifier(context.getVariableName(exp))
694 ..element = exp.element; 786 ..element = exp.element;
695 } 787 }
696 788
697 FunctionExpression makeSubFunction(tree.FunctionDefinition function) { 789 FunctionExpression makeSubFunction(tree.FunctionDefinition function,
698 return new ASTEmitter.inner(this).emit(function); 790 BuilderContext<Statement> context) {
791 return emit(function, new BuilderContext<Statement>.inner(context));
699 } 792 }
700 793
701 Expression visitFunctionExpression(tree.FunctionExpression exp) { 794 @override
702 return makeSubFunction(exp.definition)..name = null; 795 Expression visitFunctionExpression(tree.FunctionExpression exp,
796 BuilderContext<Statement> context) {
797 return makeSubFunction(exp.definition, context)..name = null;
703 } 798 }
704 799
705 void visitFunctionDeclaration(tree.FunctionDeclaration node) { 800 @override
706 assert(variableNames[node.variable] == null); 801 void visitFunctionDeclaration(tree.FunctionDeclaration node,
707 String name = getVariableName(node.variable); 802 BuilderContext<Statement> context) {
708 FunctionExpression inner = makeSubFunction(node.definition); 803 assert(context.variableNames[node.variable] == null);
804 String name = context.getVariableName(node.variable);
805 FunctionExpression inner = makeSubFunction(node.definition, context);
709 inner.name = name; 806 inner.name = name;
710 FunctionDeclaration decl = new FunctionDeclaration(inner); 807 FunctionDeclaration decl = new FunctionDeclaration(inner);
711 declaredVariables.add(node.variable); 808 context.declaredVariables.add(node.variable);
712 statementBuffer.add(decl); 809 context.addStatement(decl);
713 visitStatement(node.next); 810 visitStatement(node.next, context);
714 } 811 }
715 812
716 /// Like [createTypeAnnotation] except the dynamic type is converted to null. 813 Expression emitConstant(ConstantExpression exp,
717 TypeAnnotation emitOptionalType(DartType type) { 814 BuilderContext<Statement> context) {
718 if (type.treatAsDynamic) { 815 return const ConstantEmitter().visit(exp, context);
719 return null;
720 } else {
721 return createTypeAnnotation(type);
722 }
723 }
724
725 Expression emitConstant(ConstantExpression exp) {
726 return new ConstantEmitter(this).visit(exp);
727 } 816 }
728 } 817 }
729 818
819 /// Like [createTypeAnnotation] except the dynamic type is converted to null.
820 TypeAnnotation emitOptionalType(DartType type) {
821 if (type.treatAsDynamic) {
822 return null;
823 } else {
824 return createTypeAnnotation(type);
825 }
826 }
827
730 TypeAnnotation createTypeAnnotation(DartType type) { 828 TypeAnnotation createTypeAnnotation(DartType type) {
731 if (type is GenericType) { 829 if (type is GenericType) {
732 if (type.treatAsRaw) { 830 if (type.treatAsRaw) {
733 return new TypeAnnotation(type.element.name)..dartType = type; 831 return new TypeAnnotation(type.element.name)..dartType = type;
734 } 832 }
735 return new TypeAnnotation( 833 return new TypeAnnotation(
736 type.element.name, 834 type.element.name,
737 type.typeArguments.map(createTypeAnnotation).toList(growable:false)) 835 type.typeArguments.map(createTypeAnnotation).toList(growable:false))
738 ..dartType = type; 836 ..dartType = type;
739 } else if (type is VoidType) { 837 } else if (type is VoidType) {
740 return new TypeAnnotation('void') 838 return new TypeAnnotation('void')
741 ..dartType = type; 839 ..dartType = type;
742 } else if (type is TypeVariableType) { 840 } else if (type is TypeVariableType) {
743 return new TypeAnnotation(type.name) 841 return new TypeAnnotation(type.name)
744 ..dartType = type; 842 ..dartType = type;
745 } else if (type is DynamicType) { 843 } else if (type is DynamicType) {
746 return new TypeAnnotation("dynamic") 844 return new TypeAnnotation("dynamic")
747 ..dartType = type; 845 ..dartType = type;
748 } else if (type is MalformedType) { 846 } else if (type is MalformedType) {
749 return new TypeAnnotation(type.name) 847 return new TypeAnnotation(type.name)
750 ..dartType = type; 848 ..dartType = type;
751 } else { 849 } else {
752 throw "Unsupported type annotation: $type"; 850 throw "Unsupported type annotation: $type";
753 } 851 }
754 } 852 }
755 853
756 class ConstantEmitter extends ConstantExpressionVisitor<Null, Expression> { 854 class ConstantEmitter
757 ASTEmitter parent; 855 extends ConstantExpressionVisitor<BuilderContext<Statement>, Expression> {
758 ConstantEmitter(this.parent); 856 const ConstantEmitter();
759 857
760 Expression handlePrimitiveConstant(PrimitiveConstantValue value) { 858 Expression handlePrimitiveConstant(PrimitiveConstantValue value) {
761 // Num constants may be negative, while literals must be non-negative: 859 // Num constants may be negative, while literals must be non-negative:
762 // Literals are non-negative in the specification, and a negated literal 860 // Literals are non-negative in the specification, and a negated literal
763 // parses as a call to unary `-`. The AST unparser assumes literals are 861 // parses as a call to unary `-`. The AST unparser assumes literals are
764 // non-negative and relies on this to avoid incorrectly generating `--`, 862 // non-negative and relies on this to avoid incorrectly generating `--`,
765 // the predecrement operator. 863 // the predecrement operator.
766 // Translate such constants into their positive value wrapped by 864 // Translate such constants into their positive value wrapped by
767 // the unary minus operator. 865 // the unary minus operator.
768 if (value.isNum) { 866 if (value.isNum) {
769 NumConstantValue numConstant = value; 867 NumConstantValue numConstant = value;
770 if (numConstant.primitiveValue.isNegative) { 868 if (numConstant.primitiveValue.isNegative) {
771 return negatedLiteral(numConstant); 869 return negatedLiteral(numConstant);
772 } 870 }
773 } 871 }
774 return new Literal(value); 872 return new Literal(value);
775 } 873 }
776 874
875 List<Expression> visitExpressions(List<ConstantExpression> expressions,
876 BuilderContext<Statement> context) {
877 return expressions.map((expression) => visit(expression, context))
878 .toList(growable: false);
879 }
880
777 @override 881 @override
778 Expression visitPrimitive(PrimitiveConstantExpression exp, [_]) { 882 Expression visitPrimitive(PrimitiveConstantExpression exp,
883 BuilderContext<Statement> context) {
779 return handlePrimitiveConstant(exp.value); 884 return handlePrimitiveConstant(exp.value);
780 } 885 }
781 886
782 /// Given a negative num constant, returns the corresponding positive 887 /// Given a negative num constant, returns the corresponding positive
783 /// literal wrapped by a unary minus operator. 888 /// literal wrapped by a unary minus operator.
784 Expression negatedLiteral(NumConstantValue constant, [_]) { 889 Expression negatedLiteral(NumConstantValue constant) {
785 assert(constant.primitiveValue.isNegative); 890 assert(constant.primitiveValue.isNegative);
786 NumConstantValue positiveConstant; 891 NumConstantValue positiveConstant;
787 if (constant.isInt) { 892 if (constant.isInt) {
788 positiveConstant = new IntConstantValue(-constant.primitiveValue); 893 positiveConstant = new IntConstantValue(-constant.primitiveValue);
789 } else if (constant.isDouble) { 894 } else if (constant.isDouble) {
790 positiveConstant = new DoubleConstantValue(-constant.primitiveValue); 895 positiveConstant = new DoubleConstantValue(-constant.primitiveValue);
791 } else { 896 } else {
792 throw "Unexpected type of NumConstant: $constant"; 897 throw "Unexpected type of NumConstant: $constant";
793 } 898 }
794 return new UnaryOperator('-', new Literal(positiveConstant)); 899 return new UnaryOperator('-', new Literal(positiveConstant));
795 } 900 }
796 901
797 @override 902 @override
798 Expression visitList(ListConstantExpression exp, [_]) { 903 Expression visitList(ListConstantExpression exp,
904 BuilderContext<Statement> context) {
799 return new LiteralList( 905 return new LiteralList(
800 exp.values.map(visit).toList(growable: false), 906 visitExpressions(exp.values, context),
801 isConst: true, 907 isConst: true,
802 typeArgument: parent.emitOptionalType(exp.type.typeArguments.single)); 908 typeArgument: emitOptionalType(exp.type.typeArguments.single));
803 } 909 }
804 910
805 @override 911 @override
806 Expression visitMap(MapConstantExpression exp, [_]) { 912 Expression visitMap(MapConstantExpression exp,
913 BuilderContext<Statement> context) {
807 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( 914 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
808 exp.values.length, 915 exp.values.length,
809 (i) => new LiteralMapEntry(visit(exp.keys[i]), 916 (i) => new LiteralMapEntry(visit(exp.keys[i], context),
810 visit(exp.values[i]))); 917 visit(exp.values[i], context)));
811 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw 918 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
812 ? null 919 ? null
813 : exp.type.typeArguments.map(createTypeAnnotation).toList(); 920 : exp.type.typeArguments.map(createTypeAnnotation).toList();
814 return new LiteralMap(entries, isConst: true, typeArguments: typeArguments); 921 return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
815 } 922 }
816 923
817 @override 924 @override
818 Expression visitConstructed(ConstructedConstantExpresssion exp, [_]) { 925 Expression visitConstructed(ConstructedConstantExpresssion exp,
926 BuilderContext<Statement> context) {
819 int positionalArgumentCount = exp.selector.positionalArgumentCount; 927 int positionalArgumentCount = exp.selector.positionalArgumentCount;
820 List<Argument> args = new List<Argument>.generate( 928 List<Argument> args = new List<Argument>.generate(
821 positionalArgumentCount, 929 positionalArgumentCount,
822 (i) => visit(exp.arguments[i])); 930 (i) => visit(exp.arguments[i], context));
823 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) { 931 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
824 args.add(new NamedArgument(exp.selector.namedArguments[i], 932 args.add(new NamedArgument(exp.selector.namedArguments[i],
825 visit(exp.arguments[positionalArgumentCount + i]))); 933 visit(exp.arguments[positionalArgumentCount + i], context)));
826 } 934 }
827 935
828 FunctionElement constructor = exp.target; 936 FunctionElement constructor = exp.target;
829 String name = constructor.name.isEmpty ? null : constructor.name; 937 String name = constructor.name.isEmpty ? null : constructor.name;
830 return new CallNew(createTypeAnnotation(exp.type), 938 return new CallNew(createTypeAnnotation(exp.type),
831 args, 939 args,
832 constructorName: name, 940 constructorName: name,
833 isConst: true) 941 isConst: true)
834 ..constructor = constructor 942 ..constructor = constructor
835 ..dartType = exp.type; 943 ..dartType = exp.type;
836 } 944 }
837 945
838 @override 946 @override
839 Expression visitConcatenate(ConcatenateConstantExpression exp, [_]) { 947 Expression visitConcatenate(ConcatenateConstantExpression exp,
840 return new StringConcat(exp.arguments.map(visit).toList(growable: false)); 948 BuilderContext<Statement> context) {
949
950 return new StringConcat(visitExpressions(exp.arguments, context));
841 } 951 }
842 952
843 @override 953 @override
844 Expression visitSymbol(SymbolConstantExpression exp, [_]) { 954 Expression visitSymbol(SymbolConstantExpression exp,
955 BuilderContext<Statement> context) {
845 return new LiteralSymbol(exp.name); 956 return new LiteralSymbol(exp.name);
846 } 957 }
847 958
848 @override 959 @override
849 Expression visitType(TypeConstantExpression exp, [_]) { 960 Expression visitType(TypeConstantExpression exp,
961 BuilderContext<Statement> context) {
850 DartType type = exp.type; 962 DartType type = exp.type;
851 return new LiteralType(type.name) 963 return new LiteralType(type.name)
852 ..type = type; 964 ..type = type;
853 } 965 }
854 966
855 @override 967 @override
856 Expression visitVariable(VariableConstantExpression exp, [_]) { 968 Expression visitVariable(VariableConstantExpression exp,
969 BuilderContext<Statement> context) {
857 Element element = exp.element; 970 Element element = exp.element;
858 if (element.kind != ElementKind.VARIABLE) { 971 if (element.kind != ElementKind.VARIABLE) {
859 return new Identifier(element.name)..element = element; 972 return new Identifier(element.name)..element = element;
860 } 973 }
861 String name = parent.getConstantName(element); 974 String name = context.getConstantName(element);
862 return new Identifier(name) 975 return new Identifier(name)
863 ..element = element; 976 ..element = element;
864 } 977 }
865 978
866 @override 979 @override
867 Expression visitFunction(FunctionConstantExpression exp, [_]) { 980 Expression visitFunction(FunctionConstantExpression exp,
981 BuilderContext<Statement> context) {
868 return new Identifier(exp.element.name) 982 return new Identifier(exp.element.name)
869 ..element = exp.element; 983 ..element = exp.element;
870 } 984 }
871 985
872 @override 986 @override
873 Expression visitBinary(BinaryConstantExpression exp, [_]) { 987 Expression visitBinary(BinaryConstantExpression exp,
988 BuilderContext<Statement> context) {
874 return handlePrimitiveConstant(exp.value); 989 return handlePrimitiveConstant(exp.value);
875 } 990 }
876 991
877 @override 992 @override
878 Expression visitConditional(ConditionalConstantExpression exp, [_]) { 993 Expression visitConditional(ConditionalConstantExpression exp,
994 BuilderContext<Statement> context) {
879 if (exp.condition.value.isTrue) { 995 if (exp.condition.value.isTrue) {
880 return exp.trueExp.accept(this); 996 return exp.trueExp.accept(this);
881 } else { 997 } else {
882 return exp.falseExp.accept(this); 998 return exp.falseExp.accept(this);
883 } 999 }
884 } 1000 }
885 1001
886 @override 1002 @override
887 Expression visitUnary(UnaryConstantExpression exp, [_]) { 1003 Expression visitUnary(UnaryConstantExpression exp,
1004 BuilderContext<Statement> context) {
888 return handlePrimitiveConstant(exp.value); 1005 return handlePrimitiveConstant(exp.value);
889 } 1006 }
890 } 1007 }
891 1008
892 /// Moves function parameters into a separate variable if one of its uses is 1009 /// Moves function parameters into a separate variable if one of its uses is
893 /// shadowed by an inner function parameter. 1010 /// shadowed by an inner function parameter.
894 /// This artifact is necessary because function parameters cannot be renamed. 1011 /// This artifact is necessary because function parameters cannot be renamed.
895 class UnshadowParameters extends tree.RecursiveVisitor { 1012 class UnshadowParameters extends tree.RecursiveVisitor {
896 1013
897 /// Maps parameter names to their bindings. 1014 /// Maps parameter names to their bindings.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null); 1074 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);
958 1075
959 ExecutableElement get executableContext => enclosingElement; 1076 ExecutableElement get executableContext => enclosingElement;
960 1077
961 ExecutableElement get memberContext => executableContext.memberContext; 1078 ExecutableElement get memberContext => executableContext.memberContext;
962 1079
963 bool get isLocal => true; 1080 bool get isLocal => true;
964 1081
965 LibraryElement get implementationLibrary => enclosingElement.library; 1082 LibraryElement get implementationLibrary => enclosingElement.library;
966 } 1083 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/constants/expressions.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698