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 |