Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library dart2js.constants.constructors; | |
| 6 | |
| 7 import '../elements/elements.dart'; | |
| 8 import 'expressions.dart'; | |
| 9 import 'values.dart'; | |
| 10 import '../dart_types.dart'; | |
| 11 import '../resolution/resolution.dart'; | |
| 12 import '../resolution/operators.dart'; | |
| 13 import '../resolution/semantic_visitor.dart'; | |
| 14 import '../resolution/send_structure.dart'; | |
| 15 import '../dart2jslib.dart'; | |
| 16 import '../tree/tree.dart'; | |
| 17 | |
| 18 ConstantConstructor computeConstantConstructor(ResolvedAst resolvedAst) { | |
| 19 ConstantConstructorComputer visitor = | |
| 20 new ConstantConstructorComputer(resolvedAst.elements); | |
| 21 return resolvedAst.node.accept(visitor); | |
| 22 } | |
| 23 | |
| 24 class ConstantConstructorComputer extends SemanticVisitor | |
| 25 with SemanticDeclarationResolvedMixin, | |
| 26 DeclarationResolverMixin, | |
| 27 GetBulkMixin, | |
| 28 SetBulkMixin, | |
| 29 ErrorBulkMixin, | |
| 30 InvokeBulkMixin, | |
| 31 IndexSetBulkMixin, | |
| 32 CompoundBulkMixin, | |
| 33 UnaryBulkMixin, | |
| 34 BaseBulkMixin, | |
| 35 BinaryBulkMixin, | |
| 36 PrefixBulkMixin, | |
| 37 PostfixBulkMixin, | |
| 38 NewBulkMixin, | |
| 39 InitializerBulkMixin, | |
| 40 FunctionBulkMixin, | |
| 41 VariableBulkMixin | |
| 42 implements SemanticDeclarationVisitor, SemanticSendVisitor { | |
| 43 final Map<FieldElement, ConstantExpression> fieldMap = {}; | |
|
karlklose
2015/05/11 10:23:18
Add type arguments to literals (here, below, Lines
Johnni Winther
2015/05/11 12:24:57
Done.
| |
| 44 final Map<dynamic/*int|String*/, ConstantExpression> defaultValues = {}; | |
| 45 | |
| 46 ConstantConstructorComputer(TreeElements elements) | |
| 47 : super(elements); | |
| 48 | |
| 49 SemanticDeclarationVisitor get declVisitor => this; | |
| 50 | |
| 51 SemanticSendVisitor get sendVisitor => this; | |
| 52 | |
| 53 ClassElement get currentClass => currentConstructor.enclosingClass; | |
| 54 | |
| 55 ConstructorElement get currentConstructor => elements.analyzedElement; | |
| 56 | |
| 57 apply(Node node, [_]) => node.accept(this); | |
| 58 | |
| 59 visitNode(Node node) { | |
| 60 internalError(node, 'Unhandled node $node (${node.runtimeType})'); | |
|
karlklose
2015/05/11 10:23:18
We should avoid calling 'runtimeType' if we are on
Johnni Winther
2015/05/11 12:24:57
toString unparses which is too imprecise. Will use
| |
| 61 } | |
| 62 | |
| 63 @override | |
| 64 bulkHandleNode(Node node, String template, _) { | |
| 65 internalError(node, template.replaceFirst('#' , '$node')); | |
| 66 } | |
| 67 | |
| 68 internalError(Node node, String message) { | |
| 69 throw new UnsupportedError(message); | |
| 70 } | |
| 71 | |
| 72 ConstantConstructor visitGenerativeConstructorDeclaration( | |
| 73 FunctionExpression node, | |
| 74 ConstructorElement constructor, | |
| 75 NodeList parameters, | |
| 76 NodeList initializers, | |
| 77 Node body, | |
| 78 _) { | |
| 79 applyParameters(parameters, _); | |
| 80 ConstructedConstantExpression constructorInvocation = | |
| 81 applyInitializers(initializers, _); | |
| 82 return new GenerativeConstantConstructor( | |
| 83 currentClass.thisType, defaultValues, fieldMap, constructorInvocation); | |
| 84 } | |
| 85 | |
| 86 ConstantConstructor visitRedirectingGenerativeConstructorDeclaration( | |
| 87 FunctionExpression node, | |
| 88 ConstructorElement constructor, | |
| 89 NodeList parameters, | |
| 90 NodeList initializers, | |
| 91 _) { | |
| 92 applyParameters(parameters, _); | |
| 93 ConstructedConstantExpression constructorInvocation = | |
| 94 applyInitializers(initializers, _); | |
| 95 return new RedirectingGenerativeConstantConstructor( | |
| 96 defaultValues, constructorInvocation); | |
| 97 } | |
| 98 | |
| 99 ConstantConstructor visitRedirectingFactoryConstructorDeclaration( | |
| 100 FunctionExpression node, | |
| 101 ConstructorElement constructor, | |
| 102 NodeList parameters, | |
| 103 InterfaceType redirectionType, | |
| 104 ConstructorElement redirectionTarget, | |
| 105 _) { | |
| 106 List<String> argumentNames = []; | |
| 107 List<ConstantExpression> arguments = []; | |
| 108 int index = 0; | |
| 109 for (ParameterElement parameter in constructor.parameters) { | |
| 110 if (parameter.isNamed) { | |
| 111 String name = parameter.name; | |
| 112 argumentNames.add(name); | |
| 113 arguments.add(new NamedArgumentReference(name)); | |
| 114 } else { | |
| 115 arguments.add(new PositionalArgumentReference(index)); | |
| 116 } | |
| 117 index++; | |
| 118 } | |
| 119 CallStructure callStructure = new CallStructure(index, argumentNames); | |
| 120 | |
| 121 return new RedirectingFactoryConstantConstructor( | |
| 122 new ConstructedConstantExpression(null, | |
| 123 redirectionType, | |
| 124 redirectionTarget, | |
| 125 callStructure, | |
| 126 arguments)); | |
| 127 } | |
| 128 | |
| 129 @override | |
| 130 visitFactoryConstructorDeclaration( | |
| 131 FunctionExpression node, | |
| 132 ConstructorElement constructor, | |
| 133 NodeList parameters, | |
| 134 Node body, _) { | |
| 135 // TODO(johnniwinther): Handle constant constructors with errors. | |
| 136 internalError(node, "Factory constructor cannot be constant."); | |
| 137 } | |
| 138 | |
| 139 applyParameters(NodeList parameters, _) { | |
| 140 computeParameterStructures(parameters).forEach((s) => s.dispatch(this, _)); | |
| 141 } | |
| 142 | |
| 143 visitParameterDeclaration( | |
| 144 VariableDefinitions node, | |
| 145 Node definition, | |
| 146 ParameterElement parameter, | |
| 147 int index, | |
| 148 _) { | |
| 149 // Do nothing. | |
| 150 } | |
| 151 | |
| 152 visitOptionalParameterDeclaration( | |
| 153 VariableDefinitions node, | |
| 154 Node definition, | |
| 155 ParameterElement parameter, | |
| 156 ConstantExpression defaultValue, | |
| 157 int index, | |
| 158 _) { | |
| 159 assert(invariant(node, defaultValue != null)); | |
| 160 defaultValues[index] = defaultValue; | |
| 161 } | |
| 162 | |
| 163 visitNamedParameterDeclaration( | |
| 164 VariableDefinitions node, | |
| 165 Node definition, | |
| 166 ParameterElement parameter, | |
| 167 ConstantExpression defaultValue, | |
| 168 _) { | |
| 169 assert(invariant(node, defaultValue != null)); | |
| 170 String name = parameter.name; | |
| 171 defaultValues[name] = defaultValue; | |
| 172 } | |
| 173 | |
| 174 visitInitializingFormalDeclaration( | |
| 175 VariableDefinitions node, | |
| 176 Node definition, | |
| 177 InitializingFormalElement parameter, | |
| 178 int index, | |
| 179 _) { | |
| 180 fieldMap[parameter.fieldElement] = new PositionalArgumentReference(index); | |
| 181 } | |
| 182 | |
| 183 visitOptionalInitializingFormalDeclaration( | |
| 184 VariableDefinitions node, | |
| 185 Node definition, | |
| 186 InitializingFormalElement parameter, | |
| 187 ConstantExpression defaultValue, | |
| 188 int index, | |
| 189 _) { | |
| 190 assert(invariant(node, defaultValue != null)); | |
| 191 defaultValues[index] = defaultValue; | |
| 192 fieldMap[parameter.fieldElement] = new PositionalArgumentReference(index); | |
| 193 } | |
| 194 | |
| 195 visitNamedInitializingFormalDeclaration( | |
| 196 VariableDefinitions node, | |
| 197 Node definition, | |
| 198 InitializingFormalElement parameter, | |
| 199 ConstantExpression defaultValue, | |
| 200 _) { | |
| 201 assert(invariant(node, defaultValue != null)); | |
| 202 String name = parameter.name; | |
| 203 defaultValues[name] = defaultValue; | |
| 204 fieldMap[parameter.fieldElement] = new NamedArgumentReference(name); | |
| 205 } | |
| 206 | |
| 207 /// Apply this visitor to the constructor [initializers]. | |
| 208 ConstructedConstantExpression applyInitializers(NodeList initializers, _) { | |
| 209 ConstructedConstantExpression constructorInvocation; | |
| 210 if (initializers != null) { | |
| 211 for (Node initializer in initializers) { | |
| 212 InitializerStructure structure = | |
| 213 computeInitializerStructure(initializer); | |
| 214 if (structure is SuperConstructorInvokeStructure || | |
| 215 structure is ThisConstructorInvokeStructure) { | |
| 216 constructorInvocation = structure.dispatch(this, initializer, _); | |
| 217 } else { | |
| 218 structure.dispatch(this, initializer, _); | |
| 219 } | |
| 220 } | |
| 221 } | |
| 222 if (constructorInvocation == null && !currentClass.isObject) { | |
| 223 constructorInvocation = | |
| 224 new ConstructedConstantExpression(null, | |
| 225 currentClass.supertype, | |
| 226 currentClass.superclass.lookupDefaultConstructor(), | |
| 227 CallStructure.NO_ARGS, | |
| 228 const <ConstantExpression>[]); | |
| 229 } | |
| 230 return constructorInvocation; | |
| 231 } | |
| 232 | |
| 233 visitFieldInitializer( | |
| 234 SendSet node, | |
| 235 FieldElement field, | |
| 236 Node initializer, | |
| 237 _) { | |
| 238 fieldMap[field] = apply(initializer); | |
| 239 } | |
| 240 | |
| 241 visitParameterGet( | |
| 242 Send node, | |
| 243 ParameterElement parameter, | |
| 244 _) { | |
| 245 if (parameter.isNamed) { | |
| 246 return new NamedArgumentReference(parameter.name); | |
| 247 } else { | |
| 248 return new PositionalArgumentReference( | |
| 249 parameter.functionDeclaration.parameters.indexOf(parameter)); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 ConstructedConstantExpression visitSuperConstructorInvoke( | |
| 254 Send node, | |
| 255 ConstructorElement superConstructor, | |
| 256 InterfaceType type, | |
| 257 NodeList arguments, | |
| 258 Selector selector, | |
| 259 _) { | |
| 260 List<ConstantExpression> argumentExpression = | |
| 261 arguments.nodes.map((a) => apply(a)).toList(); | |
| 262 return new ConstructedConstantExpression(null, | |
| 263 type, | |
| 264 superConstructor, | |
| 265 selector.callStructure, | |
| 266 argumentExpression); | |
| 267 } | |
| 268 | |
| 269 ConstructedConstantExpression visitThisConstructorInvoke( | |
| 270 Send node, | |
| 271 ConstructorElement thisConstructor, | |
| 272 NodeList arguments, | |
| 273 Selector selector, | |
| 274 _) { | |
| 275 List<ConstantExpression> argumentExpression = | |
| 276 arguments.nodes.map((a) => apply(a)).toList(); | |
| 277 return new ConstructedConstantExpression(null, | |
| 278 currentClass.thisType, | |
| 279 thisConstructor, | |
| 280 selector.callStructure, | |
| 281 argumentExpression); | |
| 282 } | |
| 283 | |
| 284 @override | |
| 285 ConstantExpression visitBinary( | |
| 286 Send node, | |
| 287 Node left, | |
| 288 BinaryOperator operator, | |
| 289 Node right, | |
| 290 _) { | |
| 291 return new BinaryConstantExpression(null, | |
| 292 apply(left), operator, apply(right)); | |
| 293 } | |
| 294 | |
| 295 | |
| 296 @override | |
| 297 ConstantExpression visitUnary( | |
| 298 Send node, | |
| 299 UnaryOperator operator, | |
| 300 Node expression, | |
| 301 _) { | |
| 302 return new UnaryConstantExpression(null, | |
| 303 operator, apply(expression)); | |
| 304 } | |
| 305 | |
| 306 @override | |
| 307 ConstantExpression visitStaticFieldGet( | |
| 308 Send node, | |
| 309 FieldElement field, | |
| 310 _) { | |
| 311 return new VariableConstantExpression(null, field); | |
| 312 } | |
| 313 | |
| 314 @override | |
| 315 ConstantExpression visitTopLevelFieldGet( | |
| 316 Send node, | |
| 317 FieldElement field, | |
| 318 _) { | |
| 319 return new VariableConstantExpression(null, field); | |
| 320 } | |
| 321 | |
| 322 @override | |
| 323 ConstantExpression visitLiteralInt(LiteralInt node) { | |
| 324 return new IntConstantExpression( | |
| 325 node.value, new IntConstantValue(node.value)); | |
| 326 } | |
| 327 | |
| 328 @override | |
| 329 ConstantExpression visitLiteralBool(LiteralBool node) { | |
| 330 return new BoolConstantExpression(node.value, null); | |
| 331 } | |
| 332 | |
| 333 @override | |
| 334 ConstantExpression visitLiteralNull(LiteralNull node) { | |
| 335 return new NullConstantExpression(new NullConstantValue()); | |
| 336 } | |
| 337 | |
| 338 @override | |
| 339 ConstantExpression visitLiteralString(LiteralString node) { | |
| 340 return new StringConstantExpression(node.dartString.slowToString(), null); | |
| 341 } | |
| 342 | |
| 343 @override | |
| 344 ConstantExpression visitConditional(Conditional node) { | |
| 345 return new ConditionalConstantExpression(null, | |
| 346 apply(node.condition), | |
| 347 apply(node.thenExpression), | |
| 348 apply(node.elseExpression)); | |
| 349 } | |
| 350 | |
| 351 @override | |
| 352 ConstantExpression visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 353 return apply(node.expression); | |
| 354 } | |
| 355 | |
| 356 @override | |
| 357 ConstantExpression visitTopLevelFunctionInvoke( | |
| 358 Send node, | |
| 359 MethodElement function, | |
| 360 NodeList arguments, | |
| 361 CallStructure callStructure, | |
| 362 _) { | |
| 363 if (function.name != 'identical' || !function.library.isDartCore) { | |
| 364 throw new UnsupportedError("Unexpected function call: $function"); | |
| 365 } | |
| 366 return new IdenticalConstantExpression( | |
| 367 null, apply(arguments.nodes.head), apply(arguments.nodes.tail.head)); | |
| 368 } | |
| 369 | |
| 370 @override | |
| 371 ConstantExpression visitNamedArgument(NamedArgument node) { | |
| 372 return apply(node.expression); | |
| 373 } | |
| 374 } | |
| OLD | NEW |