OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017, 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 /// Logic to build unlinked summaries. | |
6 library summary.src.summary_builder; | |
7 | |
8 import 'expression_serializer.dart'; | |
9 import 'model.dart'; | |
10 import 'package:front_end/src/fasta/parser/class_member_parser.dart'; | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:14
I'm surprised that the sorting of imports doesn't
Paul Berry
2017/03/09 23:26:23
Oops--I added these imports in any old location be
| |
11 import 'package:front_end/src/fasta/parser/identifier_context.dart'; | |
12 import 'package:front_end/src/fasta/parser/parser.dart'; | |
13 import 'package:front_end/src/fasta/scanner.dart'; | |
14 import 'package:front_end/src/fasta/scanner/token_constants.dart'; | |
15 import 'stack_listener.dart'; | |
16 | |
17 /// Create an unlinked summary given a null-terminated byte buffer with the | |
18 /// contents of a file. | |
19 UnlinkedUnit summarize(Uri uri, List<int> contents) { | |
20 var listener = new SummaryBuilder(uri); | |
21 var parser = new ClassMemberParser(listener); | |
22 parser.parseUnit(scan(contents).tokens); | |
23 return listener.topScope.unit; | |
24 } | |
25 | |
26 /// A listener of parser events that builds summary information as parsing | |
27 /// progresses. | |
28 class SummaryBuilder extends StackListener { | |
29 /// Whether 'dart:core' was imported explicitly by the current unit. | |
30 bool isDartCoreImported = false; | |
31 | |
32 /// Whether the current unit is part of 'dart:core'. | |
33 bool isCoreLibrary = false; | |
34 | |
35 /// Topmost scope. | |
36 TopScope topScope; | |
37 | |
38 /// Current scope where name references are resolved from. | |
39 Scope scope; | |
40 | |
41 /// Helper to build constant expressions. | |
42 final ConstExpressionBuilder constBuilder; | |
43 | |
44 /// Helper to build initializer expressions. | |
45 final InitializerBuilder initializerBuilder; | |
46 | |
47 /// Whether the current initializer has a type declared. | |
48 /// | |
49 /// Because initializers are only used for strong-mode inference, we can skip | |
50 /// parsing and building initializer expressions when a type is declared. | |
51 bool typeSeen = false; | |
52 | |
53 /// Whether we are currently in the context of a const expression. | |
54 bool inConstContext = false; | |
55 | |
56 /// Whether we need to parse the initializer of a declaration. | |
57 bool get needInitializer => !typeSeen || inConstContext; | |
58 | |
59 /// Uri of the file currently being processed, used for error reporting only. | |
60 final Uri uri; | |
61 | |
62 | |
63 /// Summaries preassign slots for computed information, this is the next | |
64 /// available slot. | |
65 int _slots = 0; | |
66 | |
67 SummaryBuilder(Uri uri) | |
68 : uri = uri, | |
69 constBuilder = new ConstExpressionBuilder(uri), | |
70 initializerBuilder = new InitializerBuilder(uri); | |
71 | |
72 void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { | |
73 debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); | |
74 } | |
75 | |
76 void beginCompilationUnit(Token token) { | |
77 scope = topScope = new TopScope(); | |
78 } | |
79 | |
80 void endCompilationUnit(int count, Token token) { | |
81 if (!isDartCoreImported) { | |
82 topScope.unit.imports.add(new UnlinkedImportBuilder(isImplicit: true)); | |
83 } | |
84 | |
85 topScope.expandLazyReferences(); | |
86 | |
87 // TODO(sigmund): could this be be optional: done by whoever consumes it? | |
88 if (const bool.fromEnvironment('SKIP_API')) return; | |
89 var apiSignature = new ApiSignature(); | |
90 topScope.unit.collectApiSignature(apiSignature); | |
91 topScope.unit.apiSignature = apiSignature.toByteList(); | |
92 } | |
93 | |
94 // Directives: imports, exports, parts | |
95 | |
96 void endHide(_) { | |
97 // ignore: strong_mode_down_cast_composite | |
98 push(new UnlinkedCombinatorBuilder(hides: pop())); | |
99 } | |
100 | |
101 void endShow(_) { | |
102 // ignore: strong_mode_down_cast_composite | |
103 push(new UnlinkedCombinatorBuilder(shows: pop())); | |
104 } | |
105 | |
106 void endCombinators(int count) { | |
107 debugEvent("Combinators"); | |
108 push(popList(count) ?? NullValue.Combinators); | |
109 } | |
110 | |
111 void endConditionalUri(Token ifKeyword, Token equalitySign) { | |
112 String dottedName = pop(); | |
113 String value = pop(); | |
114 String uri = pop(); | |
115 uri = uri.substring(1, uri.length - 1); | |
116 push(new UnlinkedConfigurationBuilder( | |
117 name: dottedName, value: value, uri: uri)); | |
118 } | |
119 | |
120 void endConditionalUris(int count) { | |
121 push(popList(count) ?? const <UnlinkedConfigurationBuilder>[]); | |
122 } | |
123 | |
124 void endExport(Token exportKeyword, Token semicolon) { | |
125 debugEvent("Export"); | |
126 // ignore: strong_mode_down_cast_composite | |
127 List<UnlinkedCombinator> combinators = pop(); | |
128 // ignore: strong_mode_down_cast_composite | |
129 List<UnlinkedConfiguration> conditionalUris = pop(); | |
130 String uri = pop(); | |
131 // ignore: strong_mode_down_cast_composite | |
132 List<UnlinkedExpr> metadata = pop(); | |
133 topScope.unit.exports.add(new UnlinkedExportNonPublicBuilder(annotations: me tadata)); | |
134 topScope.publicNamespace.exports.add(new UnlinkedExportPublicBuilder( | |
135 uri: uri, | |
136 combinators: combinators, | |
137 configurations: conditionalUris)); | |
138 checkEmpty(); | |
139 } | |
140 | |
141 void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword, | |
142 Token semicolon) { | |
143 debugEvent("endImport"); | |
144 // ignore: strong_mode_down_cast_composite | |
145 List<UnlinkedCombinator> combinators = pop(); | |
146 String prefix = popIfNotNull(asKeyword); | |
147 int prefixIndex = prefix == null ? null | |
148 : topScope.serializeReference(null, prefix); | |
149 // ignore: strong_mode_down_cast_composite | |
150 List<UnlinkedConfiguration> conditionalUris = pop(); | |
151 String uri = pop(); | |
152 // ignore: strong_mode_down_cast_composite | |
153 List<UnlinkedExpr> metadata = pop(); // metadata | |
154 | |
155 topScope.unit.imports.add(new UnlinkedImportBuilder( | |
156 uri: uri, | |
157 prefixReference: prefixIndex, | |
158 combinators: combinators, | |
159 configurations: conditionalUris, | |
160 isDeferred: deferredKeyword != null, | |
161 annotations: metadata, | |
162 )); | |
163 if (uri == 'dart:core') isDartCoreImported = true; | |
164 checkEmpty(); | |
165 } | |
166 | |
167 void endPart(Token partKeyword, Token semicolon) { | |
168 debugEvent("Part"); | |
169 String uri = pop(); | |
170 // ignore: strong_mode_down_cast_composite | |
171 List<UnlinkedExpr> metadata = pop(); | |
172 topScope.unit.parts.add(new UnlinkedPartBuilder(annotations: metadata)); | |
173 topScope.publicNamespace.parts.add(uri); | |
174 checkEmpty(); | |
175 } | |
176 | |
177 void endLibraryName(Token libraryKeyword, Token semicolon) { | |
178 debugEvent("endLibraryName"); | |
179 String name = pop(); | |
180 // ignore: strong_mode_down_cast_composite | |
181 List<UnlinkedExpr> metadata = pop(); // metadata | |
182 | |
183 topScope.unit.libraryName = name; | |
184 topScope.unit.libraryAnnotations = metadata; | |
185 if (name == 'dart.core') isCoreLibrary = true; | |
186 } | |
187 | |
188 void endPartOf(Token partKeyword, Token semicolon) { | |
189 debugEvent("endPartOf"); | |
190 String name = pop(); | |
191 pop(); // metadata | |
192 topScope.unit.isPartOf = true; | |
193 if (name == 'dart.core') isCoreLibrary = true; | |
194 } | |
195 | |
196 // classes, enums, mixins, and typedefs. | |
197 | |
198 void beginClassDeclaration(Token beginToken, Token name) { | |
199 debugEvent("beginClass"); | |
200 var classScope = scope = new ClassScope(scope); | |
201 classScope.className = name.value; | |
202 } | |
203 | |
204 void endClassBody(int memberCount, Token beginToken, Token endToken) { | |
205 debugEvent("ClassBody"); | |
206 } | |
207 | |
208 void endClassDeclaration(int interfacesCount, Token beginToken, Token classKey word, | |
209 Token extendsKeyword, Token implementsKeyword, Token endToken) { | |
210 debugEvent("endClassDeclaration"); | |
211 // ignore: strong_mode_down_cast_composite | |
212 List<EntityRefBuilder> interfaces = popList(interfacesCount); | |
213 EntityRef supertype = pop(); | |
214 // ignore: strong_mode_down_cast_composite | |
215 List<UnlinkedTypeParamBuilder> typeVariables = pop(); | |
216 String name = pop(); | |
217 int modifiers = pop(); | |
218 List metadata = pop(); | |
219 checkEmpty(); | |
220 | |
221 ClassScope s = scope; | |
222 s.className = name; | |
223 s.currentClass | |
224 ..name = name | |
225 ..isAbstract = modifiers & _abstract_flag != 0 | |
226 // ignore: strong_mode_down_cast_composite | |
227 ..annotations = metadata | |
228 ..typeParameters = typeVariables | |
229 ..interfaces = interfaces; | |
230 if (supertype != null) { | |
231 s.currentClass.supertype = supertype; | |
232 } else { | |
233 s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object'; | |
234 } | |
235 scope = scope.parent; | |
236 topScope.unit.classes.add(s.currentClass); | |
237 if (_isPrivate(name)) return; | |
238 s.publicName | |
239 ..name = name | |
240 ..kind = ReferenceKind.classOrEnum | |
241 ..numTypeParameters = typeVariables?.length; | |
242 topScope.publicNamespace.names.add(s.publicName); | |
243 } | |
244 | |
245 void beginEnum(Token token) { | |
246 debugEvent("beginEnum"); | |
247 scope = new EnumScope(scope); | |
248 } | |
249 | |
250 void endEnum(Token enumKeyword, Token endBrace, int count) { | |
251 debugEvent("Enum"); | |
252 // ignore: strong_mode_down_cast_composite | |
253 List<String> constants = popList(count); | |
254 String name = pop(); | |
255 List metadata = pop(); | |
256 checkEmpty(); | |
257 EnumScope s = scope; | |
258 scope = s.parent; | |
259 s.currentEnum | |
260 ..name = name | |
261 // ignore: strong_mode_down_cast_composite | |
262 ..annotations = metadata; | |
263 s.top.unit.enums.add(s.currentEnum); | |
264 | |
265 // public namespace: | |
266 var e = new UnlinkedPublicNameBuilder( | |
267 name: name, | |
268 kind: ReferenceKind.classOrEnum, | |
269 numTypeParameters: 0); | |
270 for (var s in constants) { | |
271 e.members.add(new UnlinkedPublicNameBuilder( | |
272 name: s, | |
273 kind: ReferenceKind.propertyAccessor, | |
274 numTypeParameters: 0)); | |
275 } | |
276 topScope.publicNamespace.names.add(e); | |
277 } | |
278 | |
279 void endMixinApplication(Token withKeyword) { | |
280 debugEvent("MixinApplication"); | |
281 ClassScope s = scope; | |
282 // ignore: strong_mode_down_cast_composite | |
283 s.currentClass.mixins = pop(); | |
284 } | |
285 | |
286 void beginNamedMixinApplication(Token beginToken, Token name) { | |
287 debugEvent('beginNamedMixinApplication'); | |
288 scope = new ClassScope(scope); | |
289 } | |
290 | |
291 void endNamedMixinApplication( | |
292 Token begin, Token classKeyword, Token equals, | |
293 Token implementsKeyword, Token endToken) { | |
294 debugEvent("endNamedMixinApplication"); | |
295 // ignore: strong_mode_down_cast_composite | |
296 List<EntityRef> interfaces = popIfNotNull(implementsKeyword); | |
297 EntityRef supertype = pop(); | |
298 List typeVariables = pop(); | |
299 String name = pop(); | |
300 int modifiers = pop(); | |
301 List metadata = pop(); | |
302 // print('TODO: end mix, $name'); | |
303 checkEmpty(); | |
304 | |
305 ClassScope s = scope; | |
306 s.currentClass | |
307 ..name = name | |
308 ..isAbstract = modifiers & _abstract_flag != 0 | |
309 ..isMixinApplication = true | |
310 // ignore: strong_mode_down_cast_composite | |
311 ..annotations = metadata | |
312 // ignore: strong_mode_down_cast_composite | |
313 ..typeParameters = typeVariables | |
314 ..interfaces = interfaces; | |
315 if (supertype != null) { | |
316 s.currentClass.supertype = supertype; | |
317 } else { | |
318 s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object'; | |
319 } | |
320 scope = scope.parent; | |
321 topScope.unit.classes.add(s.currentClass); | |
322 | |
323 _addNameIfPublic(name, ReferenceKind.classOrEnum, typeVariables.length); | |
324 } | |
325 | |
326 void beginFunctionTypeAlias(Token token) { | |
327 debugEvent('beginFunctionTypeAlias'); | |
328 // TODO: use a single scope | |
329 scope = new TypeParameterScope(scope); | |
330 } | |
331 | |
332 void endFunctionTypeAlias(Token typedefKeyword, Token equals, Token endToken) { | |
333 debugEvent("endFunctionTypeAlias"); | |
334 List formals = pop(); | |
335 List typeVariables = pop(); | |
336 String name = pop(); | |
337 EntityRef returnType = pop(); | |
338 List metadata = pop(); | |
339 // print('TODO: type alias $name'); | |
340 checkEmpty(); | |
341 | |
342 scope = scope.parent; | |
343 topScope.unit.typedefs.add(new UnlinkedTypedefBuilder( | |
344 name: name, | |
345 // ignore: strong_mode_down_cast_composite | |
346 typeParameters: typeVariables, | |
347 returnType: returnType, | |
348 // ignore: strong_mode_down_cast_composite | |
349 parameters: formals, | |
350 // ignore: strong_mode_down_cast_composite | |
351 annotations: metadata)); | |
352 | |
353 _addNameIfPublic(name, ReferenceKind.typedef, typeVariables.length); | |
354 } | |
355 | |
356 // members: fields, methods. | |
357 | |
358 void beginTopLevelMember(Token token) { | |
359 typeSeen = false; | |
360 inConstContext = false; | |
361 } | |
362 | |
363 void beginMember(Token token) { | |
364 typeSeen = false; | |
365 inConstContext = false; | |
366 } | |
367 | |
368 void endMember() { | |
369 debugEvent("Member"); | |
370 } | |
371 | |
372 void handleType(Token beginToken, Token endToken) { | |
373 debugEvent("Type"); | |
374 // ignore: strong_mode_down_cast_composite | |
375 List<EntityRef> arguments = pop(); | |
376 String name = pop(); | |
377 | |
378 var type; | |
379 if (name.contains('.')) { | |
380 var parts = name.split('.'); | |
381 for (var p in parts) { | |
382 type = type == null | |
383 ? new LazyEntityRef(p, scope) | |
384 : new NestedLazyEntityRef(type, p, scope); | |
385 } | |
386 } else { | |
387 type = new LazyEntityRef(name, scope); | |
388 } | |
389 type.typeArguments = arguments; | |
390 push(type); | |
391 typeSeen = true; | |
392 } | |
393 | |
394 void endTypeList(int count) { | |
395 debugEvent("TypeList"); | |
396 push(popList(count) ?? NullValue.TypeList); | |
397 } | |
398 | |
399 static int parsed = 0; | |
400 static int total = 0; | |
401 beginInitializer(Token token) { | |
402 // TODO(paulberry): Add support for this. | |
403 } | |
404 | |
405 beginFieldInitializer(Token token) { | |
406 // TODO(paulberry): Copied from beginFieldInitializer. Is all of this neede d? | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:13
did you mean from beginInitializer?
Paul Berry
2017/03/09 23:26:23
Oops, yes. I've removed this TODO--it was a place
| |
407 debugEvent("beginFieldInitializer"); | |
408 total++; | |
409 if (needInitializer) { | |
410 parsed++; | |
411 if (inConstContext) { | |
412 push(constBuilder.computeExpression(token.next, scope)); | |
413 } else { | |
414 push(initializerBuilder.computeExpression(token.next, scope)); | |
415 } | |
416 } | |
417 } | |
418 | |
419 void endInitializer(Token assignmentOperator) { | |
420 // TODO(paulberry): add support for this. | |
421 debugEvent("Initializer $typeSeen $assignmentOperator"); | |
422 } | |
423 | |
424 void endFieldInitializer(Token assignmentOperator) { | |
425 // TODO(paulberry): copied from endInitializer. Is all of this needed? | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:14
just to make sure I follow - you are wondering if
Paul Berry
2017/03/09 23:26:23
At the time I wrote the TODO I didn't understand t
| |
426 debugEvent("FieldInitializer $typeSeen $assignmentOperator"); | |
427 // This is a variable initializer and it's ignored for now. May also be | |
428 // constructor initializer. | |
429 var initializer = needInitializer && assignmentOperator != null | |
430 ? pop() : null; | |
431 var name = pop(); | |
432 push(new _InitializedName(name, new UnlinkedExecutableBuilder( | |
433 bodyExpr: initializer))); | |
434 } | |
435 | |
436 void endTopLevelFields(int count, Token beginToken, Token endToken) { | |
437 debugEvent("endTopLevelFields"); | |
438 _endFields(count, topScope.unit.variables, true); | |
439 checkEmpty(); | |
440 } | |
441 | |
442 void endFields(int count, Token covariantKeyword, Token beginToken, Token endT oken) { | |
443 debugEvent("Fields"); | |
444 var s = scope; | |
445 if (s is ClassScope) { | |
446 _endFields(count, s.currentClass.fields, false); | |
447 } else { | |
448 throw new UnimplementedError(); // TODO(paulberry): does this ever occur? | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:14
do you mean that we don't summarize enums altogeth
Paul Berry
2017/03/09 23:26:23
We do summarize enums, but the parsing of enums ne
| |
449 // _endFields(count, s.currentEnum.values, false); | |
450 } | |
451 } | |
452 | |
453 void _endFields(int count, List result, bool isTopLevel) { | |
454 debugEvent('EndFields: $count $isTopLevel'); | |
455 // ignore: strong_mode_down_cast_composite | |
456 List<_InitializedName> fields = popList(count); | |
457 EntityRef type = pop(); | |
458 int modifiers = pop(); | |
459 List metadata = pop(); | |
460 | |
461 bool isStatic = modifiers & _static_flag != 0; | |
462 bool isFinal = modifiers & _final_flag != 0; | |
463 bool isConst = modifiers & _const_flag != 0; | |
464 bool isInstance = !isStatic && !isTopLevel; | |
465 for (var field in fields) { | |
466 var name = field.name; | |
467 var initializer = field.initializer; | |
468 bool needsPropagatedType = initializer != null && (isFinal || isConst); | |
469 bool needsInferredType = | |
470 type == null && (initializer != null || isInstance); | |
471 result.add(new UnlinkedVariableBuilder( | |
472 isFinal: isFinal, | |
473 isConst: isConst, | |
474 isStatic: isStatic, | |
475 name: name, | |
476 type: type, | |
477 // ignore: strong_mode_down_cast_composite | |
478 annotations: metadata, | |
479 initializer: initializer, | |
480 propagatedTypeSlot: slotIf(needsPropagatedType), | |
481 inferredTypeSlot: slotIf(needsInferredType))); | |
482 | |
483 if (_isPrivate(name)) continue; | |
484 if (isTopLevel) { | |
485 _addPropertyName(name, includeSetter: !isFinal && !isConst); | |
486 } else if (isStatic) { | |
487 // Any reason setters are not added as well? | |
488 (scope as ClassScope).publicName.members.add(new UnlinkedPublicNameBuild er( | |
489 name: name, | |
490 kind: ReferenceKind.propertyAccessor, | |
491 numTypeParameters: 0)); | |
492 } | |
493 } | |
494 } | |
495 | |
496 | |
497 void endTopLevelMethod( | |
498 Token beginToken, Token getOrSet, Token endToken) { | |
499 debugEvent("endTopLevelMethod"); | |
500 int asyncModifier = pop(); | |
501 List formals = pop(); | |
502 List typeVariables = pop(); | |
503 String name = pop(); | |
504 EntityRef returnType = pop(); | |
505 int modifiers = pop(); | |
506 List metadata = pop(); | |
507 checkEmpty(); | |
508 | |
509 topScope.unit.executables.add(new UnlinkedExecutableBuilder( | |
510 name: getOrSet == 'set' ? '$name=' : name, | |
511 kind: getOrSet == 'get' | |
512 ? UnlinkedExecutableKind.getter | |
513 : (getOrSet == 'set' ? UnlinkedExecutableKind.setter | |
514 : UnlinkedExecutableKind.functionOrMethod), | |
515 isExternal: modifiers & _external_flag != 0, | |
516 isAbstract: modifiers & _abstract_flag != 0, | |
517 isAsynchronous: asyncModifier & _async_flag != 0, | |
518 isGenerator: asyncModifier & _star_flag != 0, | |
519 isStatic: modifiers & _static_flag != 0, | |
520 typeParameters: [], // TODO | |
521 returnType: returnType, | |
522 // ignore: strong_mode_down_cast_composite | |
523 parameters: formals, | |
524 // ignore: strong_mode_down_cast_composite | |
525 annotations: metadata, | |
526 inferredReturnTypeSlot: null, // not needed for top-levels | |
527 // skip body. | |
528 )); | |
529 | |
530 String normalizedName = getOrSet == 'set' ? '$name=' : name; | |
531 _addNameIfPublic( | |
532 normalizedName, | |
533 getOrSet != null ? ReferenceKind.topLevelPropertyAccessor : ReferenceKin d.topLevelFunction, | |
534 typeVariables?.length ?? 0 /* todo */); | |
535 } | |
536 | |
537 void endMethod(Token getOrSet, Token beginToken, Token endToken) { | |
538 debugEvent("Method"); | |
539 int asyncModifier = pop(); | |
540 // ignore: strong_mode_down_cast_composite | |
541 List<UnlinkedParam> formals = pop(); | |
542 // ignore: strong_mode_down_cast_composite | |
543 List<UnlinkedTypeParamBuilder> typeVariables = pop(); | |
544 String name = pop(); | |
545 EntityRef returnType = pop(); | |
546 int modifiers = pop(); | |
547 List metadata = pop(); | |
548 | |
549 ClassScope s = scope; | |
550 bool isStatic = modifiers & _static_flag != 0; | |
551 bool isConst = modifiers & _const_flag != 0; | |
552 bool isGetter = getOrSet == 'get'; | |
553 bool isSetter = getOrSet == 'set'; | |
554 bool isOperator = name == "operator"; // TODO | |
555 bool isConstructor = | |
556 name == s.className || name.startsWith('${s.className}.'); | |
557 | |
558 if (isConstructor) { | |
559 name = name == s.className ? '' : name.substring(name.indexOf('.') + 1); | |
560 } | |
561 | |
562 name = isSetter ? '$name=' : name; | |
563 // Note: we don't include bodies for any method. | |
564 s.currentClass.executables.add(new UnlinkedExecutableBuilder( | |
565 name: name, | |
566 kind: isGetter | |
567 ? UnlinkedExecutableKind.getter | |
568 : (isSetter | |
569 ? UnlinkedExecutableKind.setter | |
570 : (isConstructor | |
571 ? UnlinkedExecutableKind.constructor | |
572 : UnlinkedExecutableKind.functionOrMethod)), | |
573 isExternal: modifiers & _external_flag != 0, | |
574 isAbstract: modifiers & _abstract_flag != 0, | |
575 isAsynchronous: asyncModifier & _async_flag != 0, | |
576 isGenerator: asyncModifier & _star_flag != 0, | |
577 isStatic: isStatic, | |
578 isConst: isConst, | |
579 constCycleSlot: slotIf(isConst), | |
580 typeParameters: typeVariables, | |
581 returnType: returnType, | |
582 parameters: formals, // TODO: add inferred slot to args | |
583 // ignore: strong_mode_down_cast_composite | |
584 annotations: metadata, | |
585 inferredReturnTypeSlot: slotIf(returnType == null && !isStatic && | |
586 !isConstructor))); | |
587 | |
588 if (isConstructor && name == '') return; | |
589 if (_isPrivate(name)) return; | |
590 if (isSetter || isOperator) return; | |
591 if (!isStatic && !isConstructor) return; | |
592 s.publicName.members.add(new UnlinkedPublicNameBuilder( | |
593 name: name, | |
594 kind: isGetter ? ReferenceKind.propertyAccessor : | |
595 (isConstructor ? ReferenceKind.constructor : | |
596 ReferenceKind.method), | |
597 numTypeParameters: typeVariables.length)); | |
598 } | |
599 | |
600 void endTypeArguments(int count, Token beginToken, Token endToken) { | |
601 debugEvent("TypeArguments"); | |
602 push(popList(count) ?? const []); | |
603 } | |
604 | |
605 | |
606 void handleVoidKeyword(Token token) { | |
607 debugEvent("VoidKeyword"); | |
608 // TODO: skip the lazy mechanism | |
609 push(new LazyEntityRef("void", scope.top)); | |
610 } | |
611 | |
612 void endFormalParameter(Token covariantKeyword, Token thisKeyword, FormalParam eterType kind) { | |
613 debugEvent("FormalParameter"); | |
614 // TODO(sigmund): clean up? | |
615 var nameOrFormal = pop(); | |
616 if (nameOrFormal is String) { | |
617 EntityRef type = pop(); | |
618 pop(); // Modifiers | |
619 List metadata = pop(); | |
620 push(new UnlinkedParamBuilder( | |
621 name: nameOrFormal, | |
622 kind: _nextParamKind, | |
623 inheritsCovariantSlot: slotIf(type == null), | |
624 // ignore: strong_mode_down_cast_composite | |
625 annotations: metadata, | |
626 isInitializingFormal: thisKeyword != null, | |
627 type: type)); | |
628 } else { | |
629 push(nameOrFormal); | |
630 } | |
631 } | |
632 | |
633 // TODO(sigmund): handle metadata (this code is incomplete). | |
634 void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { | |
635 debugEvent("Metadata"); | |
636 List arguments = pop(); | |
637 var result = new UnlinkedExprBuilder(); | |
638 // If arguments are null, this is an expression, otherwise a constructor | |
639 // reference. | |
640 if (arguments == null) { | |
641 /* String postfix = */ popIfNotNull(periodBeforeName); | |
642 /* String expression = */ pop(); | |
643 //push([expression, postfix]); // @x or @p.x | |
644 } else { | |
645 /* String name = */ popIfNotNull(periodBeforeName); | |
646 // TODO(ahe): Type arguments are missing, eventually they should be | |
647 // available as part of [arguments]. | |
648 // List<String> typeArguments = null; | |
649 /* EntityRef typeName = */ pop(); | |
650 //push([typeName, typeArguments, name, arguments]); | |
651 } | |
652 push(result); | |
653 } | |
654 | |
655 void endMetadataStar(int count, bool forParameter) { | |
656 debugEvent("MetadataStar"); | |
657 push(popList(count) ?? NullValue.Metadata); | |
658 } | |
659 | |
660 void handleStringPart(token) { | |
661 debugEvent("handleStringPart"); | |
662 push(token.value.substring(1, token.value.length - 1)); | |
663 } | |
664 | |
665 void beginLiteralString(Token token) { | |
666 debugEvent("beginLiteralString"); | |
667 push(token.value.substring(1, token.value.length - 1)); | |
668 } | |
669 | |
670 void endLiteralString(int count) { | |
671 assert(count == 0); // TODO(sigmund): handle interpolation | |
672 } | |
673 | |
674 void handleQualified(Token period) { | |
675 debugEvent("handleQualified"); | |
676 String name = pop(); | |
677 String receiver = pop(); | |
678 push("$receiver.$name"); | |
679 } | |
680 | |
681 void endDottedName(count, firstIdentifier) { | |
682 push(popList(count).join('.')); | |
683 } | |
684 | |
685 void handleOperatorName(Token operatorKeyword, Token token) { | |
686 // TODO(sigmund): convert operator names to name used by summaries. | |
687 debugEvent("OperatorName"); | |
688 push(operatorKeyword.value); | |
689 } | |
690 | |
691 void endIdentifierList(int count) { | |
692 debugEvent("endIdentifierList"); | |
693 push(popList(count) ?? NullValue.IdentifierList); | |
694 } | |
695 | |
696 void handleModifier(Token token) { | |
697 debugEvent("Modifier"); | |
698 var modifier = _modifierFlag[token.stringValue]; | |
699 if (modifier & _const_flag != 0) inConstContext = true; | |
700 push(modifier); | |
701 } | |
702 | |
703 void handleModifiers(int count) { | |
704 debugEvent("Modifiers"); | |
705 push((popList(count) ?? const []).fold(0, (a, b) => a | b)); | |
706 } | |
707 | |
708 UnlinkedParamKind _nextParamKind; | |
709 void beginFormalParameters(Token begin) { | |
710 _nextParamKind = UnlinkedParamKind.required; | |
711 } | |
712 void beginOptionalFormalParameters(Token begin) { | |
713 _nextParamKind = | |
714 begin == '{' ? UnlinkedParamKind.named : UnlinkedParamKind.positional; | |
715 } | |
716 | |
717 void handleValuedFormalParameter(Token equals, Token token) { | |
718 debugEvent("ValuedFormalParameter"); | |
719 // TODO(sigmund): include default value on optional args. | |
720 } | |
721 | |
722 void endFunctionTypedFormalParameter(Token covariantKeyword, Token thisKeyword , FormalParameterType kind) { | |
723 debugEvent("FunctionTypedFormalParameter"); | |
724 // ignore: strong_mode_down_cast_composite | |
725 List<UnlinkedParamBuilder> formals = pop(); | |
726 if (formals != null) formals.forEach((p) => p.inheritsCovariantSlot = null); | |
727 | |
728 /* List typeVariables = */ pop(); | |
729 String name = pop(); | |
730 EntityRef returnType = pop(); | |
731 /* int modifiers = */ pop(); | |
732 List metadata = pop(); | |
733 | |
734 push(new UnlinkedParamBuilder( | |
735 name: name, | |
736 kind: _nextParamKind, | |
737 isFunctionTyped: true, | |
738 parameters: formals, | |
739 // ignore: strong_mode_down_cast_composite | |
740 annotations: metadata, | |
741 type: returnType)); | |
742 } | |
743 | |
744 void endOptionalFormalParameters( | |
745 int count, Token beginToken, Token endToken) { | |
746 debugEvent("OptionalFormalParameters"); | |
747 push(popList(count)); | |
748 } | |
749 | |
750 void endFormalParameters(int count, Token beginToken, Token endToken) { | |
751 debugEvent("FormalParameters"); | |
752 List formals = popList(count); | |
753 if (formals != null && formals.isNotEmpty) { | |
754 var last = formals.last; | |
755 if (last is List) { | |
756 var newList = new List(formals.length - 1 + last.length); | |
757 newList.setRange(0, formals.length - 1, formals); | |
758 newList.setRange(formals.length - 1, newList.length, last); | |
759 for (int i = 0; i < last.length; i++) { | |
760 newList[i + formals.length - 1] = last[i]; | |
761 } | |
762 formals = newList; | |
763 } | |
764 } | |
765 push(formals ?? NullValue.FormalParameters); | |
766 } | |
767 | |
768 void endTypeVariables(int count, Token beginToken, Token endToken) { | |
769 debugEvent("TypeVariables"); | |
770 push(popList(count) ?? const []); | |
771 } | |
772 | |
773 void endTypeVariable(Token token, Token extendsOrSuper) { | |
774 debugEvent("endTypeVariable"); | |
775 EntityRef bound = pop(); | |
776 String name = pop(); | |
777 | |
778 var s = scope; | |
779 if (s is TypeParameterScope) { | |
780 s.typeParameters.add(name); | |
781 } else { | |
782 throw new UnimplementedError(); // TODO(paulberry) | |
783 } | |
784 push(new UnlinkedTypeParamBuilder( | |
785 name: name, | |
786 bound: bound)); | |
787 } | |
788 | |
789 void endFactoryMethod(Token beginToken, Token endToken) { | |
790 debugEvent("FactoryMethod"); | |
791 throw new UnimplementedError(); // TODO(paulberry) | |
792 // pop(); // async-modifiers | |
793 // /* List<FormalParameterBuilder> formals = */ pop(); | |
794 // var name = pop(); | |
795 // /* List<MetadataBuilder> metadata = */ pop(); | |
796 } | |
797 | |
798 | |
799 void endRedirectingFactoryBody(Token beginToken, Token endToken) { | |
800 debugEvent("RedirectingFactoryBody"); | |
801 pop(); // Discard ConstructorReferenceBuilder. | |
802 } | |
803 | |
804 void endConstructorReference( | |
805 Token start, Token periodBeforeName, Token endToken) { | |
806 var ctorName = popIfNotNull(periodBeforeName); | |
807 var typeArguments = pop(); | |
808 var className = pop(); | |
809 push(['ctor-ref:', className, typeArguments, ctorName]); | |
810 } | |
811 | |
812 void endInitializers(int count, Token beginToken, Token endToken) { | |
813 debugEvent("Initializers"); | |
814 // TODO(sigmund): include const-constructor initializers | |
815 } | |
816 | |
817 void handleNoFieldInitializer(Token token) { | |
818 debugEvent("NoFieldInitializer"); | |
819 push(new _InitializedName(pop(), null)); | |
820 } | |
821 | |
822 void handleNoTypeVariables(Token token) { | |
823 debugEvent("NoTypeVariables"); | |
824 push(const []); | |
825 } | |
826 | |
827 void handleNoInitializers() { | |
828 debugEvent("NoInitializers"); | |
829 // This is a constructor initializer and it's ignored for now. | |
830 } | |
831 | |
832 void handleNoFunctionBody(Token token) { | |
833 debugEvent("NoFunctionBody"); | |
834 // Ignored for now. We shouldn't see any function bodies. | |
835 } | |
836 | |
837 void handleAsyncModifier(Token asyncToken, Token starToken) { | |
838 debugEvent("AsyncModifier"); | |
839 int asyncModifier = 0; | |
840 if (asyncToken == "async") asyncModifier |= _async_flag; | |
841 if (asyncToken == "sync") asyncModifier |= _sync_flag; | |
842 if (starToken != null) asyncModifier |= _star_flag; | |
843 push(asyncModifier); | |
844 } | |
845 | |
846 // helpers to work with the summary format. | |
847 | |
848 | |
849 /// Assign the next slot. | |
850 int assignSlot() => ++_slots; | |
851 | |
852 /// Assign the next slot if [condition] is true. | |
853 int slotIf(bool condition) => condition ? assignSlot() : 0; | |
854 | |
855 /// Whether a name is private and should be excluded from the public | |
856 /// namespace. | |
857 bool _isPrivate(String name) => name.startsWith('_'); | |
858 | |
859 /// Add [name] to the public namespace if it's public. | |
860 void _addNameIfPublic( | |
861 String name, ReferenceKind kind, int numTypeParameters) { | |
862 if (_isPrivate(name)) return null; | |
863 _addName(name, kind, numTypeParameters: numTypeParameters); | |
864 } | |
865 | |
866 /// Add [name] to the public namespace. | |
867 void _addName( | |
868 String name, ReferenceKind kind, {int numTypeParameters: 0}) { | |
869 topScope.publicNamespace.names.add(new UnlinkedPublicNameBuilder( | |
870 name: name, | |
871 kind: kind, | |
872 numTypeParameters: numTypeParameters)); | |
873 } | |
874 | |
875 /// Add `name` and, if requested, `name=` to the public namespace. | |
876 void _addPropertyName(String name, {bool includeSetter: false}) { | |
877 _addName(name, ReferenceKind.topLevelPropertyAccessor); | |
878 if (includeSetter) { | |
879 _addName('$name=', ReferenceKind.topLevelPropertyAccessor); | |
880 } | |
881 } | |
882 | |
883 /// If enabled, show a debug message. | |
884 void debugEvent(String name) { | |
885 if (const bool.fromEnvironment('DEBUG', defaultValue: false)) { | |
886 var s = stack.join(' :: '); | |
887 if (s == '') s = '<empty>'; | |
888 var bits = 'type?: $typeSeen, const?: $inConstContext'; | |
889 var prefix = "do $name on:"; | |
890 prefix = '$prefix${" " * (30 - prefix.length)}'; | |
891 print('$prefix $bits $s'); | |
892 } | |
893 } | |
894 | |
895 void handleFormalParameterWithoutValue(Token token) { | |
896 debugEvent("FormalParameterWithoutValue"); | |
897 } | |
898 } | |
899 | |
900 /// Internal representation of an initialized name. | |
901 class _InitializedName { | |
902 final String name; | |
903 final UnlinkedExecutableBuilder initializer; | |
904 _InitializedName(this.name, this.initializer); | |
905 | |
906 toString() => "II:" + (initializer != null ? "$name = $initializer" : name); | |
907 } | |
908 | |
909 /// Parser listener to build simplified AST expresions. | |
910 /// | |
911 /// The parser produces different trees depending on whether it is used for | |
912 /// constants or initializers, so subclasses specialize the logic accordingly. | |
913 abstract class ExpressionListener extends StackListener { | |
914 // Underlying parser that invokes this listener. | |
915 Parser get parser; | |
916 | |
917 /// Whether to ignore the next reduction. Used to ignore nested expresions | |
918 /// that are either invalid (in constants) or unnecessary (for initializers). | |
919 bool get ignore => _withinFunction > 0 || _withinCascades > 0; | |
920 | |
921 /// Whether this listener is used to build const expressions. | |
922 bool get forConst => false; | |
923 | |
924 void push(Object o); | |
925 | |
926 UnlinkedExprBuilder computeExpression(Token token, Scope scope) { | |
927 debugStart(token); | |
928 parser.parseExpression(token); | |
929 debugEvent('---- END ---'); | |
930 Expression node = pop(); | |
931 checkEmpty(); | |
932 return new Serializer(scope, forConst).run(node); | |
933 } | |
934 | |
935 void handleNoInitializer() {} | |
936 | |
937 void handleIdentifier(Token token, IdentifierContext context) { | |
938 debugEvent("Identifier"); | |
939 if (ignore) return; | |
940 push(new Ref(token.value)); | |
941 } | |
942 | |
943 | |
944 void endFormalParameter(Token covariantKeyword, Token thisKeyword, FormalParam eterType kind) { | |
945 debugEvent("FormalParameter"); | |
946 assert(ignore); | |
947 } | |
948 | |
949 void endFunctionBody(int count, Token begin, Token end) { | |
950 debugEvent("FunctionBody"); | |
951 assert(ignore); | |
952 } | |
953 | |
954 void endFunctionName(Token token) { | |
955 debugEvent("FunctionName"); | |
956 assert(ignore); | |
957 } | |
958 | |
959 void endFormalParameters(int c, begin, end) { | |
960 debugEvent("FormalParameters"); | |
961 assert(ignore); | |
962 } | |
963 | |
964 void handleAsyncModifier(Token asyncToken, Token starToken) { | |
965 debugEvent("AsyncModifier"); | |
966 assert(ignore); | |
967 } | |
968 | |
969 void endReturnStatement(hasValue, Token begin, Token end) { | |
970 debugEvent("ReturnStatement"); | |
971 assert(ignore); | |
972 } | |
973 | |
974 void handleStringPart(token) { | |
975 debugEvent("handleStringPart"); | |
976 if (ignore) return; | |
977 push(new StringLiteral(token.value)); | |
978 } | |
979 | |
980 void beginLiteralString(Token token) { | |
981 debugEvent("beginLiteralString"); | |
982 if (ignore) return; | |
983 push(new StringLiteral(token.value)); | |
984 } | |
985 | |
986 void handleStringJuxtaposition(int count) { | |
987 debugEvent("StringJuxtaposition"); | |
988 if (ignore) return; | |
989 popList(count); | |
990 push(new StringLiteral('<juxtapose $count>')); | |
991 } | |
992 | |
993 void endLiteralString(int interpolationCount) { | |
994 debugEvent("endLiteralString"); | |
995 if (interpolationCount != 0) { | |
996 popList(2 * interpolationCount + 1); | |
997 push(new StringLiteral("<interpolate $interpolationCount>")); | |
998 } | |
999 } | |
1000 | |
1001 void endThrowExpression(throwToken, token) { | |
1002 debugEvent("Throw"); | |
1003 assert(ignore); | |
1004 } | |
1005 | |
1006 void handleNoType(Token token) { | |
1007 debugEvent("NoType"); | |
1008 if (ignore) return; | |
1009 push(NullValue.Type); | |
1010 } | |
1011 | |
1012 void handleNoFormalParameters(Token token) { | |
1013 debugEvent("NoFormalParameters"); | |
1014 assert(ignore); | |
1015 } | |
1016 | |
1017 void handleNoArguments(Token token) { | |
1018 debugEvent("NoArguments"); | |
1019 if (ignore) return; | |
1020 var typeArguments = pop(); | |
1021 assert(typeArguments == null); | |
1022 push(NullValue.Arguments); | |
1023 } | |
1024 | |
1025 void handleNoFunctionBody(Token token) { | |
1026 debugEvent("NoFunctionBody"); | |
1027 assert(ignore); | |
1028 } | |
1029 | |
1030 void handleNoInitializers() { | |
1031 debugEvent("NoInitializers"); | |
1032 assert(ignore); | |
1033 } | |
1034 | |
1035 void handleNoTypeArguments(Token token) { | |
1036 debugEvent("NoTypeArguments"); | |
1037 if (ignore) return; | |
1038 push(NullValue.TypeArguments); | |
1039 } | |
1040 | |
1041 // type-arguments are expected to be type references passed to constructors | |
1042 // and generic methods, we need them to model instantiations. | |
1043 void endTypeArguments(int count, Token beginToken, Token endToken) { | |
1044 debugEvent("TypeArguments"); | |
1045 if (ignore) return; | |
1046 push(popList(count) ?? const <TypeRef>[]); | |
1047 } | |
1048 | |
1049 void handleVoidKeyword(Token token) { | |
1050 debugEvent("VoidKeyword"); | |
1051 assert(ignore); | |
1052 } | |
1053 | |
1054 void handleType(Token beginToken, Token endToken) { | |
1055 debugEvent("Type"); | |
1056 if (ignore) return; | |
1057 // ignore: strong_mode_down_cast_composite | |
1058 List<TypeRef> arguments = pop(); | |
1059 Ref name = pop(); | |
1060 push(new TypeRef(name, arguments)); | |
1061 } | |
1062 | |
1063 void endTypeList(int count) { | |
1064 debugEvent("TypeList"); | |
1065 push(popList(count) ?? const <TypeRef>[]); | |
1066 } | |
1067 | |
1068 void handleBinaryExpression(Token operator) { | |
1069 debugEvent("BinaryExpression"); | |
1070 if (ignore) return; | |
1071 Expression right = pop(); | |
1072 Expression left = pop(); | |
1073 var kind = operator.kind; | |
1074 if (kind == PERIOD_TOKEN) { | |
1075 if (left is Ref && right is Ref && right.prefix == null && left.prefixDept h < 2) { | |
1076 push(new Ref(right.name, left)); | |
1077 return; | |
1078 } | |
1079 if (right is Ref) { | |
1080 push(new Load(left, right.name)); | |
1081 return; | |
1082 } | |
1083 } | |
1084 push(new Binary(left, right, kind)); | |
1085 } | |
1086 | |
1087 void handleUnaryPrefixExpression(Token operator) { | |
1088 debugEvent("UnaryPrefix"); | |
1089 if (ignore) return; | |
1090 push(new Unary(pop(), operator.kind)); | |
1091 } | |
1092 | |
1093 void handleLiteralNull(Token token) { | |
1094 debugEvent("LiteralNull"); | |
1095 if (ignore) return; | |
1096 push(new NullLiteral()); | |
1097 } | |
1098 | |
1099 void handleConditionalExpression(Token question, Token colon) { | |
1100 debugEvent("ConditionalExpression"); | |
1101 if (ignore) return; | |
1102 var falseBranch = pop(); | |
1103 var trueBranch = pop(); | |
1104 var cond = pop(); | |
1105 push(new Conditional(cond, trueBranch, falseBranch)); | |
1106 } | |
1107 | |
1108 void handleLiteralInt(Token token) { | |
1109 debugEvent("LiteralInt"); | |
1110 if (ignore) return; | |
1111 push(new IntLiteral(int.parse(token.value))); | |
1112 } | |
1113 | |
1114 void handleLiteralDouble(Token token) { | |
1115 debugEvent("LiteralDouble"); | |
1116 if (ignore) return; | |
1117 push(new DoubleLiteral(double.parse(token.value))); | |
1118 } | |
1119 | |
1120 void handleLiteralBool(Token token) { | |
1121 debugEvent("LiteralBool"); | |
1122 if (ignore) return; | |
1123 push(new BoolLiteral(token.value == 'true')); | |
1124 } | |
1125 | |
1126 void handleIsOperator(Token operator, Token not, Token endToken) { | |
1127 debugEvent("Is"); | |
1128 if (ignore) return; | |
1129 push(new Is(pop(), pop())); | |
1130 } | |
1131 | |
1132 void handleConstExpression(Token token) { | |
1133 debugEvent("ConstExpression"); | |
1134 if (ignore) return; | |
1135 List args = pop(); | |
1136 var constructorName = pop(); | |
1137 var positional = args.where((a) => a is! NamedArg).toList(); | |
1138 var named = args.where((a) => a is NamedArg).toList(); | |
1139 // ignore: strong_mode_down_cast_composite | |
1140 push(new ConstCreation(constructorName, positional, named)); | |
1141 } | |
1142 | |
1143 void handleLiteralList(count, begin, constKeyword, end) { | |
1144 debugEvent("LiteralList"); | |
1145 if (ignore) return; | |
1146 var values = popList(count) ?? const <Expression>[]; | |
1147 // ignore: strong_mode_down_cast_composite | |
1148 List<TypeRef> typeArguments = pop(); | |
1149 var type = typeArguments?.single; | |
1150 // ignore: strong_mode_down_cast_composite | |
1151 push(new ListLiteral(type, values, constKeyword != null)); | |
1152 } | |
1153 | |
1154 void endLiteralMapEntry(colon, token) { | |
1155 debugEvent('MapEntry'); | |
1156 if (ignore) return; | |
1157 var value = pop(); | |
1158 var key = pop(); | |
1159 push(new KeyValuePair(key, value)); | |
1160 } | |
1161 | |
1162 void handleLiteralMap(count, begin, constKeyword, end) { | |
1163 debugEvent('LiteralMap'); | |
1164 if (ignore) return; | |
1165 var values = popList(count) ?? const <KeyValuePair>[]; | |
1166 var typeArgs = pop() ?? const <TypeRef>[]; | |
1167 // ignore: strong_mode_down_cast_composite | |
1168 push(new MapLiteral(typeArgs, values, constKeyword != null)); | |
1169 } | |
1170 | |
1171 void endLiteralSymbol(token, int dots) { | |
1172 debugEvent('LiteralSymbol'); | |
1173 if (ignore) return; | |
1174 push(new SymbolLiteral(popList(dots).join('.'))); | |
1175 } | |
1176 | |
1177 void handleQualified(period) { | |
1178 debugEvent('Qualified'); | |
1179 if (ignore) return; | |
1180 Ref name = pop(); | |
1181 Ref prefix = pop(); | |
1182 assert(name.prefix == null); | |
1183 assert(prefix.prefix == null); | |
1184 push(new Ref(name.name, prefix)); | |
1185 } | |
1186 | |
1187 int _withinFunction = 0; | |
1188 void beginFunctionDeclaration(token) { | |
1189 debugEvent("BeginFunctionDeclaration"); | |
1190 _withinFunction++; | |
1191 } | |
1192 | |
1193 // TODO(sigmund): remove | |
1194 static const _invariantCheckToken = "invariant check: starting a function"; | |
1195 // type-variables are the declared parameters on declarations. | |
1196 void handleNoTypeVariables(Token token) { | |
1197 debugEvent("NoTypeVariables"); | |
1198 if (ignore) return; | |
1199 push(_invariantCheckToken); | |
1200 } | |
1201 | |
1202 void endTypeVariable(Token token, Token extendsOrSuper) { | |
1203 debugEvent("endTypeVariable"); | |
1204 assert(ignore); | |
1205 } | |
1206 | |
1207 void endTypeVariables(int count, Token beginToken, Token endToken) { | |
1208 debugEvent("TypeVariables"); | |
1209 assert(ignore); | |
1210 } | |
1211 | |
1212 void beginUnnamedFunction(token) { | |
1213 debugEvent("BeginUnnamedFunction"); | |
1214 var check = pop(); | |
1215 assert(check == _invariantCheckToken); | |
1216 _withinFunction++; | |
1217 } | |
1218 | |
1219 void _endFunction(); | |
1220 void endFunctionDeclaration(token) { | |
1221 debugEvent("FunctionDeclaration"); | |
1222 _withinFunction--; | |
1223 if (ignore) return; | |
1224 _endFunction(); | |
1225 } | |
1226 void endUnnamedFunction(token) { | |
1227 debugEvent("UnnamedFunction"); | |
1228 _withinFunction--; | |
1229 if (ignore) return; | |
1230 _endFunction(); | |
1231 } | |
1232 | |
1233 int _withinCascades = 0; | |
1234 void beginCascade(Token token) { | |
1235 _withinCascades++; | |
1236 } | |
1237 | |
1238 void endCascade() { | |
1239 _withinCascades--; | |
1240 throw new UnimplementedError(); // TODO(paulberry): fix the code below. | |
1241 // _endCascade(); | |
1242 } | |
1243 | |
1244 void endSend(Token beginToken, Token endToken) { | |
1245 debugEvent("EndSend"); | |
1246 if (ignore) return; | |
1247 // ignore: strong_mode_down_cast_composite | |
1248 List<Expression> args = pop(); | |
1249 if (args != null) { | |
1250 /* var typeArgs = */ pop(); | |
1251 var receiver = pop(); | |
1252 // TODO(sigmund): consider making identical a binary operator. | |
1253 if (receiver is Ref && receiver.name == 'identical') { | |
1254 assert(receiver.prefix == null); | |
1255 assert(args.length == 2); | |
1256 push(new Identical(args[0], args[1])); | |
1257 return; | |
1258 } | |
1259 _unhandledSend(); | |
1260 } | |
1261 } | |
1262 | |
1263 void _unhandledSend(); | |
1264 | |
1265 void endConstructorReference( | |
1266 Token start, Token periodBeforeName, Token endToken) { | |
1267 debugEvent("ConstructorReference $start $periodBeforeName"); | |
1268 Ref ctorName = popIfNotNull(periodBeforeName); | |
1269 assert(ctorName?.prefix == null); | |
1270 // ignore: strong_mode_down_cast_composite | |
1271 List<TypeRef> typeArgs = pop(); | |
1272 Ref type = pop(); | |
1273 push(new ConstructorName( | |
1274 new TypeRef(type, typeArgs), ctorName?.name)); | |
1275 } | |
1276 | |
1277 void handleModifier(Token token) { | |
1278 debugEvent("Modifier"); | |
1279 assert(ignore); | |
1280 } | |
1281 | |
1282 void handleModifiers(int count) { | |
1283 debugEvent("Modifiers"); | |
1284 assert(ignore); | |
1285 } | |
1286 | |
1287 /// Overriden: the base class throws when something is not handled, we avoid | |
1288 /// implementing a few handlers when we know we can ignore them. | |
1289 @override | |
1290 void logEvent(e) { | |
1291 if (ignore) return; | |
1292 super.logEvent(e); | |
1293 } | |
1294 | |
1295 // debug helpers | |
1296 | |
1297 void debugEvent(String name) { | |
1298 if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) { | |
1299 var s = stack.join(' :: '); | |
1300 if (s == '') s = '<empty>'; | |
1301 var bits = '$_withinFunction,$_withinCascades'; | |
1302 var prefix = ignore ? "ignore $name on:" : "do $name on:"; | |
1303 prefix = '$prefix${" " * (30 - prefix.length)}'; | |
1304 print('$prefix $bits $s'); | |
1305 } | |
1306 } | |
1307 | |
1308 void debugStart(Token token) { | |
1309 debugEvent('\n---- START: $runtimeType ---'); | |
1310 if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) { | |
1311 _printExpression(token); | |
1312 } | |
1313 } | |
1314 | |
1315 void _printExpression(Token token) { | |
1316 var current = token; | |
1317 var end = new ClassMemberParser(this).skipExpression(current); | |
1318 var str = new StringBuffer(); | |
1319 while (current != end) { | |
1320 if (!["(", ",", ")"].contains(current.value)) str.write(' '); | |
1321 str.write(current.value); | |
1322 current = current.next; | |
1323 } | |
1324 print('exp: $str'); | |
1325 } | |
1326 } | |
1327 | |
1328 /// Builder for constant expressions. | |
1329 /// | |
1330 /// Any invalid subexpression is denoted with [Invalid]. | |
1331 class ConstExpressionBuilder extends ExpressionListener { | |
1332 bool get forConst => true; | |
1333 final Uri uri; | |
1334 Parser parser; | |
1335 ConstExpressionBuilder(this.uri) { | |
1336 parser = new Parser(this, | |
1337 asyncAwaitKeywordsEnabled: true); | |
1338 } | |
1339 | |
1340 void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { | |
1341 debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); | |
1342 } | |
1343 | |
1344 void handleAsOperator(Token op, Token next) { | |
1345 debugEvent("As"); | |
1346 if (ignore) return; | |
1347 push(new As(pop(), pop())); | |
1348 } | |
1349 | |
1350 void handleIndexedExpression(Token openSquareBracket, Token token) { | |
1351 debugEvent("Index"); | |
1352 if (ignore) return; | |
1353 pop(); // receiver | |
1354 pop(); // index | |
1355 push(new Invalid(hint: "index")); | |
1356 } | |
1357 | |
1358 void handleAssignmentExpression(Token operator) { | |
1359 pop(); // lhs | |
1360 pop(); // rhs | |
1361 push(new Invalid(hint: "assign")); | |
1362 } | |
1363 | |
1364 void handleUnaryPrefixAssignmentExpression(Token operator) { | |
1365 pop(); | |
1366 push(new Invalid(hint: "prefixOp")); | |
1367 } | |
1368 | |
1369 void handleUnaryPostfixAssignmentExpression(Token operator) { | |
1370 pop(); | |
1371 push(new Invalid(hint: "postfixOp")); | |
1372 } | |
1373 | |
1374 void handleNamedArgument(colon) { | |
1375 debugEvent("NamedArg"); | |
1376 if (ignore) return; | |
1377 var value = pop(); | |
1378 Ref name = pop(); | |
1379 push(new NamedArg(name.name, value)); | |
1380 } | |
1381 | |
1382 void endArguments(int count, Token begin, Token end) { | |
1383 debugEvent("Arguments"); | |
1384 if (ignore) return; | |
1385 push(popList(count) ?? const []); | |
1386 } | |
1387 | |
1388 void handleNewExpression(Token token) { | |
1389 debugEvent("NewExpression"); | |
1390 if (ignore) return; | |
1391 pop(); // args | |
1392 pop(); // ctor | |
1393 push(new Invalid(hint: "new")); | |
1394 } | |
1395 | |
1396 void _endFunction() { | |
1397 assert(_withinFunction >= 0); | |
1398 push(new Invalid(hint: 'function')); | |
1399 } | |
1400 | |
1401 // TODO(paulberry): is this needed? | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:14
really depends on how we want to handle recovery o
Paul Berry
2017/03/09 23:26:23
We *do* expect to run the summary builder on inval
| |
1402 //void _endCascade() { | |
1403 // push(new Invalid(hint: 'cascades')); | |
1404 //} | |
1405 | |
1406 void _unhandledSend() { | |
1407 push(new Invalid(hint: "call")); | |
1408 } | |
1409 } | |
1410 | |
1411 /// Builder for initializer expressions. These expressions exclude any nested | |
1412 /// expression that is not needed to infer strong mode types. | |
1413 class InitializerBuilder extends ExpressionListener { | |
1414 final Uri uri; | |
1415 Parser parser; | |
1416 | |
1417 InitializerBuilder(this.uri) { | |
1418 parser = new Parser(this, | |
1419 asyncAwaitKeywordsEnabled: true); | |
1420 } | |
1421 | |
1422 void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { | |
1423 debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); | |
1424 } | |
1425 | |
1426 bool get ignore => super.ignore || _inArguments > 0; | |
1427 | |
1428 void handleAsOperator(Token op, Token next) { | |
1429 debugEvent("As"); | |
1430 if (ignore) return; | |
1431 TypeRef type = pop(); | |
1432 pop(); | |
1433 push(new Opaque(type: type)); | |
1434 } | |
1435 | |
1436 // Not necessary, but we don't use the value, so we can abstract it: | |
1437 void handleIsOperator(Token operator, Token not, Token endToken) { | |
1438 debugEvent("Is"); | |
1439 if (ignore) return; | |
1440 throw new UnimplementedError(); // TODO(paulberry): fix the code below. | |
Siggi Cherem (dart-lang)
2017/03/09 21:02:13
is the fix related to references in general?
Paul Berry
2017/03/09 23:26:23
I don't know what the proper fix is. The reason I
| |
1441 // push(new Opaque(type: new TypeRef(new Ref('bool')))); | |
1442 } | |
1443 | |
1444 void handleIndexedExpression(Token openSquareBracket, Token token) { | |
1445 debugEvent("Index"); | |
1446 if (ignore) return; | |
1447 pop(); | |
1448 pop(); | |
1449 push(new Opaque()); | |
1450 } | |
1451 | |
1452 void handleAssignmentExpression(Token operator) { | |
1453 debugEvent("Assign"); | |
1454 if (ignore) return; | |
1455 var left = pop(); | |
1456 var right = pop(); | |
1457 var kind = operator.kind; | |
1458 if (kind == EQ_TOKEN) { | |
1459 push(new OpaqueOp(right)); | |
1460 } else { | |
1461 push(new OpaqueOp(new Binary(left, right, opForAssignOp(kind)))); | |
1462 } | |
1463 } | |
1464 | |
1465 void handleUnaryPrefixAssignmentExpression(Token operator) { | |
1466 debugEvent("Prefix"); | |
1467 if (ignore) return; | |
1468 var kind = operator.kind == PLUS_PLUS_TOKEN ? PLUS_TOKEN : MINUS_TOKEN; | |
1469 push(new OpaqueOp(new Binary(pop(), new IntLiteral(1), kind))); | |
1470 } | |
1471 | |
1472 void handleUnaryPostfixAssignmentExpression(Token operator) { | |
1473 debugEvent("PostFix"); | |
1474 if (ignore) return; | |
1475 // the post-fix effect is not visible to the enclosing expression | |
1476 push(new OpaqueOp(pop())); | |
1477 } | |
1478 | |
1479 int _inArguments = 0; | |
1480 void beginArguments(Token token) { | |
1481 // TODO(sigmund): determine if we can ignore arguments. | |
1482 //_inArguments++; | |
1483 } | |
1484 | |
1485 void handleNamedArgument(colon) { | |
1486 debugEvent("NamedArg"); | |
1487 if (ignore) return; | |
1488 pop(); | |
1489 pop(); | |
1490 push(NullValue.Arguments); | |
1491 } | |
1492 | |
1493 void endArguments(int count, Token begin, Token end) { | |
1494 debugEvent("Arguments"); | |
1495 //_inArguments--; | |
1496 if (ignore) return; | |
1497 push(popList(count) ?? const []); | |
1498 //push([new Opaque(hint: "arguments")]); | |
1499 } | |
1500 | |
1501 void handleNewExpression(Token token) { | |
1502 debugEvent("NewExpression"); | |
1503 if (ignore) return; | |
1504 pop(); // args | |
1505 /* var ctor = */ pop(); // ctor | |
1506 throw new UnimplementedError(); // TODO(paulberry): fix the code below. | |
1507 // push(new Opaque(type: ctor.type, hint: "new")); | |
1508 } | |
1509 | |
1510 void _endFunction() { | |
1511 push(new Opaque(hint: "function")); | |
1512 } | |
1513 | |
1514 // TODO(paulberry): is this needed? | |
1515 //void _endCascade() { | |
1516 // push(new OpaqueOp(pop(), hint: 'cascades')); | |
1517 //} | |
1518 | |
1519 void _unhandledSend() { | |
1520 push(new Opaque(hint: "call")); | |
1521 } | |
1522 } | |
1523 | |
1524 // bit-masks to encode modifiers as bits on an int. | |
1525 | |
1526 /// Maps modifier names to their bit-mask. | |
1527 const _modifierFlag = const { | |
1528 'const': _const_flag, | |
1529 'abstract': _abstract_flag, | |
1530 'static': _static_flag, | |
1531 'external': _external_flag, | |
1532 'final': _final_flag, | |
1533 'var': _var_flag, | |
1534 }; | |
1535 | |
1536 const _var_flag = 0; | |
1537 const _final_flag = 1; | |
1538 const _const_flag = 1 << 1; | |
1539 const _abstract_flag = 1 << 2; | |
1540 const _static_flag = 1 << 3; | |
1541 const _external_flag = 1 << 4; | |
1542 | |
1543 // bit-masks to encode async modifiers as bits on an int. | |
1544 | |
1545 const _async_flag = 1; | |
1546 const _sync_flag = 1 << 1; | |
1547 const _star_flag = 1 << 2; | |
1548 | |
1549 /// Retrieve the operator from an assignment operator (e.g. + from +=). | |
1550 /// Operators are encoded using the scanner token kind id. | |
1551 int opForAssignOp(int kind) { | |
1552 switch (kind) { | |
1553 case AMPERSAND_EQ_TOKEN: return AMPERSAND_TOKEN; | |
1554 // TODO(paulberry): add support for &&= | |
1555 // case AMPERSAND_AMPERSAND_EQ_TOKEN: return AMPERSAND_AMPERSAND_TOKEN; | |
1556 case BAR_EQ_TOKEN: return BAR_TOKEN; | |
1557 // TODO(paulberry): add support for ||= | |
1558 // case BAR_BAR_EQ_TOKEN: return BAR_BAR_TOKEN; | |
1559 case CARET_EQ_TOKEN: return CARET_TOKEN; | |
1560 case GT_GT_EQ_TOKEN: return GT_GT_TOKEN; | |
1561 case LT_LT_EQ_TOKEN: return LT_LT_TOKEN; | |
1562 case MINUS_EQ_TOKEN: return MINUS_TOKEN; | |
1563 case PERCENT_EQ_TOKEN: return PERCENT_TOKEN; | |
1564 case PLUS_EQ_TOKEN: return PLUS_TOKEN; | |
1565 case QUESTION_QUESTION_EQ_TOKEN: return QUESTION_QUESTION_TOKEN; | |
1566 case SLASH_EQ_TOKEN: return SLASH_TOKEN; | |
1567 case STAR_EQ_TOKEN: return STAR_TOKEN; | |
1568 case TILDE_SLASH_EQ_TOKEN: return TILDE_SLASH_TOKEN; | |
1569 case PLUS_EQ_TOKEN: return PLUS_TOKEN; | |
1570 default: | |
1571 throw "Unhandled kind $kind"; | |
1572 } | |
1573 } | |
OLD | NEW |