| 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 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |