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

Unified Diff: pkg/analyzer/lib/src/summary/fasta/summary_builder.dart

Issue 2738273002: Add fasta-based summary generation code. (Closed)
Patch Set: Actually disable the test Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/summary/fasta/summary_builder.dart
diff --git a/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart b/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart
new file mode 100644
index 0000000000000000000000000000000000000000..788238b01b9f0132fe160b9194819aaec247ba3b
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart
@@ -0,0 +1,1573 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Logic to build unlinked summaries.
+library summary.src.summary_builder;
+
+import 'expression_serializer.dart';
+import 'model.dart';
+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
+import 'package:front_end/src/fasta/parser/identifier_context.dart';
+import 'package:front_end/src/fasta/parser/parser.dart';
+import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/scanner/token_constants.dart';
+import 'stack_listener.dart';
+
+/// Create an unlinked summary given a null-terminated byte buffer with the
+/// contents of a file.
+UnlinkedUnit summarize(Uri uri, List<int> contents) {
+ var listener = new SummaryBuilder(uri);
+ var parser = new ClassMemberParser(listener);
+ parser.parseUnit(scan(contents).tokens);
+ return listener.topScope.unit;
+}
+
+/// A listener of parser events that builds summary information as parsing
+/// progresses.
+class SummaryBuilder extends StackListener {
+ /// Whether 'dart:core' was imported explicitly by the current unit.
+ bool isDartCoreImported = false;
+
+ /// Whether the current unit is part of 'dart:core'.
+ bool isCoreLibrary = false;
+
+ /// Topmost scope.
+ TopScope topScope;
+
+ /// Current scope where name references are resolved from.
+ Scope scope;
+
+ /// Helper to build constant expressions.
+ final ConstExpressionBuilder constBuilder;
+
+ /// Helper to build initializer expressions.
+ final InitializerBuilder initializerBuilder;
+
+ /// Whether the current initializer has a type declared.
+ ///
+ /// Because initializers are only used for strong-mode inference, we can skip
+ /// parsing and building initializer expressions when a type is declared.
+ bool typeSeen = false;
+
+ /// Whether we are currently in the context of a const expression.
+ bool inConstContext = false;
+
+ /// Whether we need to parse the initializer of a declaration.
+ bool get needInitializer => !typeSeen || inConstContext;
+
+ /// Uri of the file currently being processed, used for error reporting only.
+ final Uri uri;
+
+
+ /// Summaries preassign slots for computed information, this is the next
+ /// available slot.
+ int _slots = 0;
+
+ SummaryBuilder(Uri uri)
+ : uri = uri,
+ constBuilder = new ConstExpressionBuilder(uri),
+ initializerBuilder = new InitializerBuilder(uri);
+
+ void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
+ debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
+ }
+
+ void beginCompilationUnit(Token token) {
+ scope = topScope = new TopScope();
+ }
+
+ void endCompilationUnit(int count, Token token) {
+ if (!isDartCoreImported) {
+ topScope.unit.imports.add(new UnlinkedImportBuilder(isImplicit: true));
+ }
+
+ topScope.expandLazyReferences();
+
+ // TODO(sigmund): could this be be optional: done by whoever consumes it?
+ if (const bool.fromEnvironment('SKIP_API')) return;
+ var apiSignature = new ApiSignature();
+ topScope.unit.collectApiSignature(apiSignature);
+ topScope.unit.apiSignature = apiSignature.toByteList();
+ }
+
+ // Directives: imports, exports, parts
+
+ void endHide(_) {
+ // ignore: strong_mode_down_cast_composite
+ push(new UnlinkedCombinatorBuilder(hides: pop()));
+ }
+
+ void endShow(_) {
+ // ignore: strong_mode_down_cast_composite
+ push(new UnlinkedCombinatorBuilder(shows: pop()));
+ }
+
+ void endCombinators(int count) {
+ debugEvent("Combinators");
+ push(popList(count) ?? NullValue.Combinators);
+ }
+
+ void endConditionalUri(Token ifKeyword, Token equalitySign) {
+ String dottedName = pop();
+ String value = pop();
+ String uri = pop();
+ uri = uri.substring(1, uri.length - 1);
+ push(new UnlinkedConfigurationBuilder(
+ name: dottedName, value: value, uri: uri));
+ }
+
+ void endConditionalUris(int count) {
+ push(popList(count) ?? const <UnlinkedConfigurationBuilder>[]);
+ }
+
+ void endExport(Token exportKeyword, Token semicolon) {
+ debugEvent("Export");
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedCombinator> combinators = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedConfiguration> conditionalUris = pop();
+ String uri = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedExpr> metadata = pop();
+ topScope.unit.exports.add(new UnlinkedExportNonPublicBuilder(annotations: metadata));
+ topScope.publicNamespace.exports.add(new UnlinkedExportPublicBuilder(
+ uri: uri,
+ combinators: combinators,
+ configurations: conditionalUris));
+ checkEmpty();
+ }
+
+ void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+ Token semicolon) {
+ debugEvent("endImport");
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedCombinator> combinators = pop();
+ String prefix = popIfNotNull(asKeyword);
+ int prefixIndex = prefix == null ? null
+ : topScope.serializeReference(null, prefix);
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedConfiguration> conditionalUris = pop();
+ String uri = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedExpr> metadata = pop(); // metadata
+
+ topScope.unit.imports.add(new UnlinkedImportBuilder(
+ uri: uri,
+ prefixReference: prefixIndex,
+ combinators: combinators,
+ configurations: conditionalUris,
+ isDeferred: deferredKeyword != null,
+ annotations: metadata,
+ ));
+ if (uri == 'dart:core') isDartCoreImported = true;
+ checkEmpty();
+ }
+
+ void endPart(Token partKeyword, Token semicolon) {
+ debugEvent("Part");
+ String uri = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedExpr> metadata = pop();
+ topScope.unit.parts.add(new UnlinkedPartBuilder(annotations: metadata));
+ topScope.publicNamespace.parts.add(uri);
+ checkEmpty();
+ }
+
+ void endLibraryName(Token libraryKeyword, Token semicolon) {
+ debugEvent("endLibraryName");
+ String name = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedExpr> metadata = pop(); // metadata
+
+ topScope.unit.libraryName = name;
+ topScope.unit.libraryAnnotations = metadata;
+ if (name == 'dart.core') isCoreLibrary = true;
+ }
+
+ void endPartOf(Token partKeyword, Token semicolon) {
+ debugEvent("endPartOf");
+ String name = pop();
+ pop(); // metadata
+ topScope.unit.isPartOf = true;
+ if (name == 'dart.core') isCoreLibrary = true;
+ }
+
+ // classes, enums, mixins, and typedefs.
+
+ void beginClassDeclaration(Token beginToken, Token name) {
+ debugEvent("beginClass");
+ var classScope = scope = new ClassScope(scope);
+ classScope.className = name.value;
+ }
+
+ void endClassBody(int memberCount, Token beginToken, Token endToken) {
+ debugEvent("ClassBody");
+ }
+
+ void endClassDeclaration(int interfacesCount, Token beginToken, Token classKeyword,
+ Token extendsKeyword, Token implementsKeyword, Token endToken) {
+ debugEvent("endClassDeclaration");
+ // ignore: strong_mode_down_cast_composite
+ List<EntityRefBuilder> interfaces = popList(interfacesCount);
+ EntityRef supertype = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedTypeParamBuilder> typeVariables = pop();
+ String name = pop();
+ int modifiers = pop();
+ List metadata = pop();
+ checkEmpty();
+
+ ClassScope s = scope;
+ s.className = name;
+ s.currentClass
+ ..name = name
+ ..isAbstract = modifiers & _abstract_flag != 0
+ // ignore: strong_mode_down_cast_composite
+ ..annotations = metadata
+ ..typeParameters = typeVariables
+ ..interfaces = interfaces;
+ if (supertype != null) {
+ s.currentClass.supertype = supertype;
+ } else {
+ s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object';
+ }
+ scope = scope.parent;
+ topScope.unit.classes.add(s.currentClass);
+ if (_isPrivate(name)) return;
+ s.publicName
+ ..name = name
+ ..kind = ReferenceKind.classOrEnum
+ ..numTypeParameters = typeVariables?.length;
+ topScope.publicNamespace.names.add(s.publicName);
+ }
+
+ void beginEnum(Token token) {
+ debugEvent("beginEnum");
+ scope = new EnumScope(scope);
+ }
+
+ void endEnum(Token enumKeyword, Token endBrace, int count) {
+ debugEvent("Enum");
+ // ignore: strong_mode_down_cast_composite
+ List<String> constants = popList(count);
+ String name = pop();
+ List metadata = pop();
+ checkEmpty();
+ EnumScope s = scope;
+ scope = s.parent;
+ s.currentEnum
+ ..name = name
+ // ignore: strong_mode_down_cast_composite
+ ..annotations = metadata;
+ s.top.unit.enums.add(s.currentEnum);
+
+ // public namespace:
+ var e = new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: ReferenceKind.classOrEnum,
+ numTypeParameters: 0);
+ for (var s in constants) {
+ e.members.add(new UnlinkedPublicNameBuilder(
+ name: s,
+ kind: ReferenceKind.propertyAccessor,
+ numTypeParameters: 0));
+ }
+ topScope.publicNamespace.names.add(e);
+ }
+
+ void endMixinApplication(Token withKeyword) {
+ debugEvent("MixinApplication");
+ ClassScope s = scope;
+ // ignore: strong_mode_down_cast_composite
+ s.currentClass.mixins = pop();
+ }
+
+ void beginNamedMixinApplication(Token beginToken, Token name) {
+ debugEvent('beginNamedMixinApplication');
+ scope = new ClassScope(scope);
+ }
+
+ void endNamedMixinApplication(
+ Token begin, Token classKeyword, Token equals,
+ Token implementsKeyword, Token endToken) {
+ debugEvent("endNamedMixinApplication");
+ // ignore: strong_mode_down_cast_composite
+ List<EntityRef> interfaces = popIfNotNull(implementsKeyword);
+ EntityRef supertype = pop();
+ List typeVariables = pop();
+ String name = pop();
+ int modifiers = pop();
+ List metadata = pop();
+ // print('TODO: end mix, $name');
+ checkEmpty();
+
+ ClassScope s = scope;
+ s.currentClass
+ ..name = name
+ ..isAbstract = modifiers & _abstract_flag != 0
+ ..isMixinApplication = true
+ // ignore: strong_mode_down_cast_composite
+ ..annotations = metadata
+ // ignore: strong_mode_down_cast_composite
+ ..typeParameters = typeVariables
+ ..interfaces = interfaces;
+ if (supertype != null) {
+ s.currentClass.supertype = supertype;
+ } else {
+ s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object';
+ }
+ scope = scope.parent;
+ topScope.unit.classes.add(s.currentClass);
+
+ _addNameIfPublic(name, ReferenceKind.classOrEnum, typeVariables.length);
+ }
+
+ void beginFunctionTypeAlias(Token token) {
+ debugEvent('beginFunctionTypeAlias');
+ // TODO: use a single scope
+ scope = new TypeParameterScope(scope);
+ }
+
+ void endFunctionTypeAlias(Token typedefKeyword, Token equals, Token endToken) {
+ debugEvent("endFunctionTypeAlias");
+ List formals = pop();
+ List typeVariables = pop();
+ String name = pop();
+ EntityRef returnType = pop();
+ List metadata = pop();
+ // print('TODO: type alias $name');
+ checkEmpty();
+
+ scope = scope.parent;
+ topScope.unit.typedefs.add(new UnlinkedTypedefBuilder(
+ name: name,
+ // ignore: strong_mode_down_cast_composite
+ typeParameters: typeVariables,
+ returnType: returnType,
+ // ignore: strong_mode_down_cast_composite
+ parameters: formals,
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata));
+
+ _addNameIfPublic(name, ReferenceKind.typedef, typeVariables.length);
+ }
+
+ // members: fields, methods.
+
+ void beginTopLevelMember(Token token) {
+ typeSeen = false;
+ inConstContext = false;
+ }
+
+ void beginMember(Token token) {
+ typeSeen = false;
+ inConstContext = false;
+ }
+
+ void endMember() {
+ debugEvent("Member");
+ }
+
+ void handleType(Token beginToken, Token endToken) {
+ debugEvent("Type");
+ // ignore: strong_mode_down_cast_composite
+ List<EntityRef> arguments = pop();
+ String name = pop();
+
+ var type;
+ if (name.contains('.')) {
+ var parts = name.split('.');
+ for (var p in parts) {
+ type = type == null
+ ? new LazyEntityRef(p, scope)
+ : new NestedLazyEntityRef(type, p, scope);
+ }
+ } else {
+ type = new LazyEntityRef(name, scope);
+ }
+ type.typeArguments = arguments;
+ push(type);
+ typeSeen = true;
+ }
+
+ void endTypeList(int count) {
+ debugEvent("TypeList");
+ push(popList(count) ?? NullValue.TypeList);
+ }
+
+ static int parsed = 0;
+ static int total = 0;
+ beginInitializer(Token token) {
+ // TODO(paulberry): Add support for this.
+ }
+
+ beginFieldInitializer(Token token) {
+ // TODO(paulberry): Copied from beginFieldInitializer. Is all of this needed?
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
+ debugEvent("beginFieldInitializer");
+ total++;
+ if (needInitializer) {
+ parsed++;
+ if (inConstContext) {
+ push(constBuilder.computeExpression(token.next, scope));
+ } else {
+ push(initializerBuilder.computeExpression(token.next, scope));
+ }
+ }
+ }
+
+ void endInitializer(Token assignmentOperator) {
+ // TODO(paulberry): add support for this.
+ debugEvent("Initializer $typeSeen $assignmentOperator");
+ }
+
+ void endFieldInitializer(Token assignmentOperator) {
+ // 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
+ debugEvent("FieldInitializer $typeSeen $assignmentOperator");
+ // This is a variable initializer and it's ignored for now. May also be
+ // constructor initializer.
+ var initializer = needInitializer && assignmentOperator != null
+ ? pop() : null;
+ var name = pop();
+ push(new _InitializedName(name, new UnlinkedExecutableBuilder(
+ bodyExpr: initializer)));
+ }
+
+ void endTopLevelFields(int count, Token beginToken, Token endToken) {
+ debugEvent("endTopLevelFields");
+ _endFields(count, topScope.unit.variables, true);
+ checkEmpty();
+ }
+
+ void endFields(int count, Token covariantKeyword, Token beginToken, Token endToken) {
+ debugEvent("Fields");
+ var s = scope;
+ if (s is ClassScope) {
+ _endFields(count, s.currentClass.fields, false);
+ } else {
+ 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
+ // _endFields(count, s.currentEnum.values, false);
+ }
+ }
+
+ void _endFields(int count, List result, bool isTopLevel) {
+ debugEvent('EndFields: $count $isTopLevel');
+ // ignore: strong_mode_down_cast_composite
+ List<_InitializedName> fields = popList(count);
+ EntityRef type = pop();
+ int modifiers = pop();
+ List metadata = pop();
+
+ bool isStatic = modifiers & _static_flag != 0;
+ bool isFinal = modifiers & _final_flag != 0;
+ bool isConst = modifiers & _const_flag != 0;
+ bool isInstance = !isStatic && !isTopLevel;
+ for (var field in fields) {
+ var name = field.name;
+ var initializer = field.initializer;
+ bool needsPropagatedType = initializer != null && (isFinal || isConst);
+ bool needsInferredType =
+ type == null && (initializer != null || isInstance);
+ result.add(new UnlinkedVariableBuilder(
+ isFinal: isFinal,
+ isConst: isConst,
+ isStatic: isStatic,
+ name: name,
+ type: type,
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata,
+ initializer: initializer,
+ propagatedTypeSlot: slotIf(needsPropagatedType),
+ inferredTypeSlot: slotIf(needsInferredType)));
+
+ if (_isPrivate(name)) continue;
+ if (isTopLevel) {
+ _addPropertyName(name, includeSetter: !isFinal && !isConst);
+ } else if (isStatic) {
+ // Any reason setters are not added as well?
+ (scope as ClassScope).publicName.members.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: ReferenceKind.propertyAccessor,
+ numTypeParameters: 0));
+ }
+ }
+ }
+
+
+ void endTopLevelMethod(
+ Token beginToken, Token getOrSet, Token endToken) {
+ debugEvent("endTopLevelMethod");
+ int asyncModifier = pop();
+ List formals = pop();
+ List typeVariables = pop();
+ String name = pop();
+ EntityRef returnType = pop();
+ int modifiers = pop();
+ List metadata = pop();
+ checkEmpty();
+
+ topScope.unit.executables.add(new UnlinkedExecutableBuilder(
+ name: getOrSet == 'set' ? '$name=' : name,
+ kind: getOrSet == 'get'
+ ? UnlinkedExecutableKind.getter
+ : (getOrSet == 'set' ? UnlinkedExecutableKind.setter
+ : UnlinkedExecutableKind.functionOrMethod),
+ isExternal: modifiers & _external_flag != 0,
+ isAbstract: modifiers & _abstract_flag != 0,
+ isAsynchronous: asyncModifier & _async_flag != 0,
+ isGenerator: asyncModifier & _star_flag != 0,
+ isStatic: modifiers & _static_flag != 0,
+ typeParameters: [], // TODO
+ returnType: returnType,
+ // ignore: strong_mode_down_cast_composite
+ parameters: formals,
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata,
+ inferredReturnTypeSlot: null, // not needed for top-levels
+ // skip body.
+ ));
+
+ String normalizedName = getOrSet == 'set' ? '$name=' : name;
+ _addNameIfPublic(
+ normalizedName,
+ getOrSet != null ? ReferenceKind.topLevelPropertyAccessor : ReferenceKind.topLevelFunction,
+ typeVariables?.length ?? 0 /* todo */);
+ }
+
+ void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+ debugEvent("Method");
+ int asyncModifier = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedParam> formals = pop();
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedTypeParamBuilder> typeVariables = pop();
+ String name = pop();
+ EntityRef returnType = pop();
+ int modifiers = pop();
+ List metadata = pop();
+
+ ClassScope s = scope;
+ bool isStatic = modifiers & _static_flag != 0;
+ bool isConst = modifiers & _const_flag != 0;
+ bool isGetter = getOrSet == 'get';
+ bool isSetter = getOrSet == 'set';
+ bool isOperator = name == "operator"; // TODO
+ bool isConstructor =
+ name == s.className || name.startsWith('${s.className}.');
+
+ if (isConstructor) {
+ name = name == s.className ? '' : name.substring(name.indexOf('.') + 1);
+ }
+
+ name = isSetter ? '$name=' : name;
+ // Note: we don't include bodies for any method.
+ s.currentClass.executables.add(new UnlinkedExecutableBuilder(
+ name: name,
+ kind: isGetter
+ ? UnlinkedExecutableKind.getter
+ : (isSetter
+ ? UnlinkedExecutableKind.setter
+ : (isConstructor
+ ? UnlinkedExecutableKind.constructor
+ : UnlinkedExecutableKind.functionOrMethod)),
+ isExternal: modifiers & _external_flag != 0,
+ isAbstract: modifiers & _abstract_flag != 0,
+ isAsynchronous: asyncModifier & _async_flag != 0,
+ isGenerator: asyncModifier & _star_flag != 0,
+ isStatic: isStatic,
+ isConst: isConst,
+ constCycleSlot: slotIf(isConst),
+ typeParameters: typeVariables,
+ returnType: returnType,
+ parameters: formals, // TODO: add inferred slot to args
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata,
+ inferredReturnTypeSlot: slotIf(returnType == null && !isStatic &&
+ !isConstructor)));
+
+ if (isConstructor && name == '') return;
+ if (_isPrivate(name)) return;
+ if (isSetter || isOperator) return;
+ if (!isStatic && !isConstructor) return;
+ s.publicName.members.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: isGetter ? ReferenceKind.propertyAccessor :
+ (isConstructor ? ReferenceKind.constructor :
+ ReferenceKind.method),
+ numTypeParameters: typeVariables.length));
+ }
+
+ void endTypeArguments(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeArguments");
+ push(popList(count) ?? const []);
+ }
+
+
+ void handleVoidKeyword(Token token) {
+ debugEvent("VoidKeyword");
+ // TODO: skip the lazy mechanism
+ push(new LazyEntityRef("void", scope.top));
+ }
+
+ void endFormalParameter(Token covariantKeyword, Token thisKeyword, FormalParameterType kind) {
+ debugEvent("FormalParameter");
+ // TODO(sigmund): clean up?
+ var nameOrFormal = pop();
+ if (nameOrFormal is String) {
+ EntityRef type = pop();
+ pop(); // Modifiers
+ List metadata = pop();
+ push(new UnlinkedParamBuilder(
+ name: nameOrFormal,
+ kind: _nextParamKind,
+ inheritsCovariantSlot: slotIf(type == null),
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata,
+ isInitializingFormal: thisKeyword != null,
+ type: type));
+ } else {
+ push(nameOrFormal);
+ }
+ }
+
+ // TODO(sigmund): handle metadata (this code is incomplete).
+ void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+ debugEvent("Metadata");
+ List arguments = pop();
+ var result = new UnlinkedExprBuilder();
+ // If arguments are null, this is an expression, otherwise a constructor
+ // reference.
+ if (arguments == null) {
+ /* String postfix = */ popIfNotNull(periodBeforeName);
+ /* String expression = */ pop();
+ //push([expression, postfix]); // @x or @p.x
+ } else {
+ /* String name = */ popIfNotNull(periodBeforeName);
+ // TODO(ahe): Type arguments are missing, eventually they should be
+ // available as part of [arguments].
+ // List<String> typeArguments = null;
+ /* EntityRef typeName = */ pop();
+ //push([typeName, typeArguments, name, arguments]);
+ }
+ push(result);
+ }
+
+ void endMetadataStar(int count, bool forParameter) {
+ debugEvent("MetadataStar");
+ push(popList(count) ?? NullValue.Metadata);
+ }
+
+ void handleStringPart(token) {
+ debugEvent("handleStringPart");
+ push(token.value.substring(1, token.value.length - 1));
+ }
+
+ void beginLiteralString(Token token) {
+ debugEvent("beginLiteralString");
+ push(token.value.substring(1, token.value.length - 1));
+ }
+
+ void endLiteralString(int count) {
+ assert(count == 0); // TODO(sigmund): handle interpolation
+ }
+
+ void handleQualified(Token period) {
+ debugEvent("handleQualified");
+ String name = pop();
+ String receiver = pop();
+ push("$receiver.$name");
+ }
+
+ void endDottedName(count, firstIdentifier) {
+ push(popList(count).join('.'));
+ }
+
+ void handleOperatorName(Token operatorKeyword, Token token) {
+ // TODO(sigmund): convert operator names to name used by summaries.
+ debugEvent("OperatorName");
+ push(operatorKeyword.value);
+ }
+
+ void endIdentifierList(int count) {
+ debugEvent("endIdentifierList");
+ push(popList(count) ?? NullValue.IdentifierList);
+ }
+
+ void handleModifier(Token token) {
+ debugEvent("Modifier");
+ var modifier = _modifierFlag[token.stringValue];
+ if (modifier & _const_flag != 0) inConstContext = true;
+ push(modifier);
+ }
+
+ void handleModifiers(int count) {
+ debugEvent("Modifiers");
+ push((popList(count) ?? const []).fold(0, (a, b) => a | b));
+ }
+
+ UnlinkedParamKind _nextParamKind;
+ void beginFormalParameters(Token begin) {
+ _nextParamKind = UnlinkedParamKind.required;
+ }
+ void beginOptionalFormalParameters(Token begin) {
+ _nextParamKind =
+ begin == '{' ? UnlinkedParamKind.named : UnlinkedParamKind.positional;
+ }
+
+ void handleValuedFormalParameter(Token equals, Token token) {
+ debugEvent("ValuedFormalParameter");
+ // TODO(sigmund): include default value on optional args.
+ }
+
+ void endFunctionTypedFormalParameter(Token covariantKeyword, Token thisKeyword, FormalParameterType kind) {
+ debugEvent("FunctionTypedFormalParameter");
+ // ignore: strong_mode_down_cast_composite
+ List<UnlinkedParamBuilder> formals = pop();
+ if (formals != null) formals.forEach((p) => p.inheritsCovariantSlot = null);
+
+ /* List typeVariables = */ pop();
+ String name = pop();
+ EntityRef returnType = pop();
+ /* int modifiers = */ pop();
+ List metadata = pop();
+
+ push(new UnlinkedParamBuilder(
+ name: name,
+ kind: _nextParamKind,
+ isFunctionTyped: true,
+ parameters: formals,
+ // ignore: strong_mode_down_cast_composite
+ annotations: metadata,
+ type: returnType));
+ }
+
+ void endOptionalFormalParameters(
+ int count, Token beginToken, Token endToken) {
+ debugEvent("OptionalFormalParameters");
+ push(popList(count));
+ }
+
+ void endFormalParameters(int count, Token beginToken, Token endToken) {
+ debugEvent("FormalParameters");
+ List formals = popList(count);
+ if (formals != null && formals.isNotEmpty) {
+ var last = formals.last;
+ if (last is List) {
+ var newList = new List(formals.length - 1 + last.length);
+ newList.setRange(0, formals.length - 1, formals);
+ newList.setRange(formals.length - 1, newList.length, last);
+ for (int i = 0; i < last.length; i++) {
+ newList[i + formals.length - 1] = last[i];
+ }
+ formals = newList;
+ }
+ }
+ push(formals ?? NullValue.FormalParameters);
+ }
+
+ void endTypeVariables(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeVariables");
+ push(popList(count) ?? const []);
+ }
+
+ void endTypeVariable(Token token, Token extendsOrSuper) {
+ debugEvent("endTypeVariable");
+ EntityRef bound = pop();
+ String name = pop();
+
+ var s = scope;
+ if (s is TypeParameterScope) {
+ s.typeParameters.add(name);
+ } else {
+ throw new UnimplementedError(); // TODO(paulberry)
+ }
+ push(new UnlinkedTypeParamBuilder(
+ name: name,
+ bound: bound));
+ }
+
+ void endFactoryMethod(Token beginToken, Token endToken) {
+ debugEvent("FactoryMethod");
+ throw new UnimplementedError(); // TODO(paulberry)
+ // pop(); // async-modifiers
+ // /* List<FormalParameterBuilder> formals = */ pop();
+ // var name = pop();
+ // /* List<MetadataBuilder> metadata = */ pop();
+ }
+
+
+ void endRedirectingFactoryBody(Token beginToken, Token endToken) {
+ debugEvent("RedirectingFactoryBody");
+ pop(); // Discard ConstructorReferenceBuilder.
+ }
+
+ void endConstructorReference(
+ Token start, Token periodBeforeName, Token endToken) {
+ var ctorName = popIfNotNull(periodBeforeName);
+ var typeArguments = pop();
+ var className = pop();
+ push(['ctor-ref:', className, typeArguments, ctorName]);
+ }
+
+ void endInitializers(int count, Token beginToken, Token endToken) {
+ debugEvent("Initializers");
+ // TODO(sigmund): include const-constructor initializers
+ }
+
+ void handleNoFieldInitializer(Token token) {
+ debugEvent("NoFieldInitializer");
+ push(new _InitializedName(pop(), null));
+ }
+
+ void handleNoTypeVariables(Token token) {
+ debugEvent("NoTypeVariables");
+ push(const []);
+ }
+
+ void handleNoInitializers() {
+ debugEvent("NoInitializers");
+ // This is a constructor initializer and it's ignored for now.
+ }
+
+ void handleNoFunctionBody(Token token) {
+ debugEvent("NoFunctionBody");
+ // Ignored for now. We shouldn't see any function bodies.
+ }
+
+ void handleAsyncModifier(Token asyncToken, Token starToken) {
+ debugEvent("AsyncModifier");
+ int asyncModifier = 0;
+ if (asyncToken == "async") asyncModifier |= _async_flag;
+ if (asyncToken == "sync") asyncModifier |= _sync_flag;
+ if (starToken != null) asyncModifier |= _star_flag;
+ push(asyncModifier);
+ }
+
+ // helpers to work with the summary format.
+
+
+ /// Assign the next slot.
+ int assignSlot() => ++_slots;
+
+ /// Assign the next slot if [condition] is true.
+ int slotIf(bool condition) => condition ? assignSlot() : 0;
+
+ /// Whether a name is private and should be excluded from the public
+ /// namespace.
+ bool _isPrivate(String name) => name.startsWith('_');
+
+ /// Add [name] to the public namespace if it's public.
+ void _addNameIfPublic(
+ String name, ReferenceKind kind, int numTypeParameters) {
+ if (_isPrivate(name)) return null;
+ _addName(name, kind, numTypeParameters: numTypeParameters);
+ }
+
+ /// Add [name] to the public namespace.
+ void _addName(
+ String name, ReferenceKind kind, {int numTypeParameters: 0}) {
+ topScope.publicNamespace.names.add(new UnlinkedPublicNameBuilder(
+ name: name,
+ kind: kind,
+ numTypeParameters: numTypeParameters));
+ }
+
+ /// Add `name` and, if requested, `name=` to the public namespace.
+ void _addPropertyName(String name, {bool includeSetter: false}) {
+ _addName(name, ReferenceKind.topLevelPropertyAccessor);
+ if (includeSetter) {
+ _addName('$name=', ReferenceKind.topLevelPropertyAccessor);
+ }
+ }
+
+ /// If enabled, show a debug message.
+ void debugEvent(String name) {
+ if (const bool.fromEnvironment('DEBUG', defaultValue: false)) {
+ var s = stack.join(' :: ');
+ if (s == '') s = '<empty>';
+ var bits = 'type?: $typeSeen, const?: $inConstContext';
+ var prefix = "do $name on:";
+ prefix = '$prefix${" " * (30 - prefix.length)}';
+ print('$prefix $bits $s');
+ }
+ }
+
+ void handleFormalParameterWithoutValue(Token token) {
+ debugEvent("FormalParameterWithoutValue");
+ }
+}
+
+/// Internal representation of an initialized name.
+class _InitializedName {
+ final String name;
+ final UnlinkedExecutableBuilder initializer;
+ _InitializedName(this.name, this.initializer);
+
+ toString() => "II:" + (initializer != null ? "$name = $initializer" : name);
+}
+
+/// Parser listener to build simplified AST expresions.
+///
+/// The parser produces different trees depending on whether it is used for
+/// constants or initializers, so subclasses specialize the logic accordingly.
+abstract class ExpressionListener extends StackListener {
+ // Underlying parser that invokes this listener.
+ Parser get parser;
+
+ /// Whether to ignore the next reduction. Used to ignore nested expresions
+ /// that are either invalid (in constants) or unnecessary (for initializers).
+ bool get ignore => _withinFunction > 0 || _withinCascades > 0;
+
+ /// Whether this listener is used to build const expressions.
+ bool get forConst => false;
+
+ void push(Object o);
+
+ UnlinkedExprBuilder computeExpression(Token token, Scope scope) {
+ debugStart(token);
+ parser.parseExpression(token);
+ debugEvent('---- END ---');
+ Expression node = pop();
+ checkEmpty();
+ return new Serializer(scope, forConst).run(node);
+ }
+
+ void handleNoInitializer() {}
+
+ void handleIdentifier(Token token, IdentifierContext context) {
+ debugEvent("Identifier");
+ if (ignore) return;
+ push(new Ref(token.value));
+ }
+
+
+ void endFormalParameter(Token covariantKeyword, Token thisKeyword, FormalParameterType kind) {
+ debugEvent("FormalParameter");
+ assert(ignore);
+ }
+
+ void endFunctionBody(int count, Token begin, Token end) {
+ debugEvent("FunctionBody");
+ assert(ignore);
+ }
+
+ void endFunctionName(Token token) {
+ debugEvent("FunctionName");
+ assert(ignore);
+ }
+
+ void endFormalParameters(int c, begin, end) {
+ debugEvent("FormalParameters");
+ assert(ignore);
+ }
+
+ void handleAsyncModifier(Token asyncToken, Token starToken) {
+ debugEvent("AsyncModifier");
+ assert(ignore);
+ }
+
+ void endReturnStatement(hasValue, Token begin, Token end) {
+ debugEvent("ReturnStatement");
+ assert(ignore);
+ }
+
+ void handleStringPart(token) {
+ debugEvent("handleStringPart");
+ if (ignore) return;
+ push(new StringLiteral(token.value));
+ }
+
+ void beginLiteralString(Token token) {
+ debugEvent("beginLiteralString");
+ if (ignore) return;
+ push(new StringLiteral(token.value));
+ }
+
+ void handleStringJuxtaposition(int count) {
+ debugEvent("StringJuxtaposition");
+ if (ignore) return;
+ popList(count);
+ push(new StringLiteral('<juxtapose $count>'));
+ }
+
+ void endLiteralString(int interpolationCount) {
+ debugEvent("endLiteralString");
+ if (interpolationCount != 0) {
+ popList(2 * interpolationCount + 1);
+ push(new StringLiteral("<interpolate $interpolationCount>"));
+ }
+ }
+
+ void endThrowExpression(throwToken, token) {
+ debugEvent("Throw");
+ assert(ignore);
+ }
+
+ void handleNoType(Token token) {
+ debugEvent("NoType");
+ if (ignore) return;
+ push(NullValue.Type);
+ }
+
+ void handleNoFormalParameters(Token token) {
+ debugEvent("NoFormalParameters");
+ assert(ignore);
+ }
+
+ void handleNoArguments(Token token) {
+ debugEvent("NoArguments");
+ if (ignore) return;
+ var typeArguments = pop();
+ assert(typeArguments == null);
+ push(NullValue.Arguments);
+ }
+
+ void handleNoFunctionBody(Token token) {
+ debugEvent("NoFunctionBody");
+ assert(ignore);
+ }
+
+ void handleNoInitializers() {
+ debugEvent("NoInitializers");
+ assert(ignore);
+ }
+
+ void handleNoTypeArguments(Token token) {
+ debugEvent("NoTypeArguments");
+ if (ignore) return;
+ push(NullValue.TypeArguments);
+ }
+
+ // type-arguments are expected to be type references passed to constructors
+ // and generic methods, we need them to model instantiations.
+ void endTypeArguments(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeArguments");
+ if (ignore) return;
+ push(popList(count) ?? const <TypeRef>[]);
+ }
+
+ void handleVoidKeyword(Token token) {
+ debugEvent("VoidKeyword");
+ assert(ignore);
+ }
+
+ void handleType(Token beginToken, Token endToken) {
+ debugEvent("Type");
+ if (ignore) return;
+ // ignore: strong_mode_down_cast_composite
+ List<TypeRef> arguments = pop();
+ Ref name = pop();
+ push(new TypeRef(name, arguments));
+ }
+
+ void endTypeList(int count) {
+ debugEvent("TypeList");
+ push(popList(count) ?? const <TypeRef>[]);
+ }
+
+ void handleBinaryExpression(Token operator) {
+ debugEvent("BinaryExpression");
+ if (ignore) return;
+ Expression right = pop();
+ Expression left = pop();
+ var kind = operator.kind;
+ if (kind == PERIOD_TOKEN) {
+ if (left is Ref && right is Ref && right.prefix == null && left.prefixDepth < 2) {
+ push(new Ref(right.name, left));
+ return;
+ }
+ if (right is Ref) {
+ push(new Load(left, right.name));
+ return;
+ }
+ }
+ push(new Binary(left, right, kind));
+ }
+
+ void handleUnaryPrefixExpression(Token operator) {
+ debugEvent("UnaryPrefix");
+ if (ignore) return;
+ push(new Unary(pop(), operator.kind));
+ }
+
+ void handleLiteralNull(Token token) {
+ debugEvent("LiteralNull");
+ if (ignore) return;
+ push(new NullLiteral());
+ }
+
+ void handleConditionalExpression(Token question, Token colon) {
+ debugEvent("ConditionalExpression");
+ if (ignore) return;
+ var falseBranch = pop();
+ var trueBranch = pop();
+ var cond = pop();
+ push(new Conditional(cond, trueBranch, falseBranch));
+ }
+
+ void handleLiteralInt(Token token) {
+ debugEvent("LiteralInt");
+ if (ignore) return;
+ push(new IntLiteral(int.parse(token.value)));
+ }
+
+ void handleLiteralDouble(Token token) {
+ debugEvent("LiteralDouble");
+ if (ignore) return;
+ push(new DoubleLiteral(double.parse(token.value)));
+ }
+
+ void handleLiteralBool(Token token) {
+ debugEvent("LiteralBool");
+ if (ignore) return;
+ push(new BoolLiteral(token.value == 'true'));
+ }
+
+ void handleIsOperator(Token operator, Token not, Token endToken) {
+ debugEvent("Is");
+ if (ignore) return;
+ push(new Is(pop(), pop()));
+ }
+
+ void handleConstExpression(Token token) {
+ debugEvent("ConstExpression");
+ if (ignore) return;
+ List args = pop();
+ var constructorName = pop();
+ var positional = args.where((a) => a is! NamedArg).toList();
+ var named = args.where((a) => a is NamedArg).toList();
+ // ignore: strong_mode_down_cast_composite
+ push(new ConstCreation(constructorName, positional, named));
+ }
+
+ void handleLiteralList(count, begin, constKeyword, end) {
+ debugEvent("LiteralList");
+ if (ignore) return;
+ var values = popList(count) ?? const <Expression>[];
+ // ignore: strong_mode_down_cast_composite
+ List<TypeRef> typeArguments = pop();
+ var type = typeArguments?.single;
+ // ignore: strong_mode_down_cast_composite
+ push(new ListLiteral(type, values, constKeyword != null));
+ }
+
+ void endLiteralMapEntry(colon, token) {
+ debugEvent('MapEntry');
+ if (ignore) return;
+ var value = pop();
+ var key = pop();
+ push(new KeyValuePair(key, value));
+ }
+
+ void handleLiteralMap(count, begin, constKeyword, end) {
+ debugEvent('LiteralMap');
+ if (ignore) return;
+ var values = popList(count) ?? const <KeyValuePair>[];
+ var typeArgs = pop() ?? const <TypeRef>[];
+ // ignore: strong_mode_down_cast_composite
+ push(new MapLiteral(typeArgs, values, constKeyword != null));
+ }
+
+ void endLiteralSymbol(token, int dots) {
+ debugEvent('LiteralSymbol');
+ if (ignore) return;
+ push(new SymbolLiteral(popList(dots).join('.')));
+ }
+
+ void handleQualified(period) {
+ debugEvent('Qualified');
+ if (ignore) return;
+ Ref name = pop();
+ Ref prefix = pop();
+ assert(name.prefix == null);
+ assert(prefix.prefix == null);
+ push(new Ref(name.name, prefix));
+ }
+
+ int _withinFunction = 0;
+ void beginFunctionDeclaration(token) {
+ debugEvent("BeginFunctionDeclaration");
+ _withinFunction++;
+ }
+
+ // TODO(sigmund): remove
+ static const _invariantCheckToken = "invariant check: starting a function";
+ // type-variables are the declared parameters on declarations.
+ void handleNoTypeVariables(Token token) {
+ debugEvent("NoTypeVariables");
+ if (ignore) return;
+ push(_invariantCheckToken);
+ }
+
+ void endTypeVariable(Token token, Token extendsOrSuper) {
+ debugEvent("endTypeVariable");
+ assert(ignore);
+ }
+
+ void endTypeVariables(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeVariables");
+ assert(ignore);
+ }
+
+ void beginUnnamedFunction(token) {
+ debugEvent("BeginUnnamedFunction");
+ var check = pop();
+ assert(check == _invariantCheckToken);
+ _withinFunction++;
+ }
+
+ void _endFunction();
+ void endFunctionDeclaration(token) {
+ debugEvent("FunctionDeclaration");
+ _withinFunction--;
+ if (ignore) return;
+ _endFunction();
+ }
+ void endUnnamedFunction(token) {
+ debugEvent("UnnamedFunction");
+ _withinFunction--;
+ if (ignore) return;
+ _endFunction();
+ }
+
+ int _withinCascades = 0;
+ void beginCascade(Token token) {
+ _withinCascades++;
+ }
+
+ void endCascade() {
+ _withinCascades--;
+ throw new UnimplementedError(); // TODO(paulberry): fix the code below.
+ // _endCascade();
+ }
+
+ void endSend(Token beginToken, Token endToken) {
+ debugEvent("EndSend");
+ if (ignore) return;
+ // ignore: strong_mode_down_cast_composite
+ List<Expression> args = pop();
+ if (args != null) {
+ /* var typeArgs = */ pop();
+ var receiver = pop();
+ // TODO(sigmund): consider making identical a binary operator.
+ if (receiver is Ref && receiver.name == 'identical') {
+ assert(receiver.prefix == null);
+ assert(args.length == 2);
+ push(new Identical(args[0], args[1]));
+ return;
+ }
+ _unhandledSend();
+ }
+ }
+
+ void _unhandledSend();
+
+ void endConstructorReference(
+ Token start, Token periodBeforeName, Token endToken) {
+ debugEvent("ConstructorReference $start $periodBeforeName");
+ Ref ctorName = popIfNotNull(periodBeforeName);
+ assert(ctorName?.prefix == null);
+ // ignore: strong_mode_down_cast_composite
+ List<TypeRef> typeArgs = pop();
+ Ref type = pop();
+ push(new ConstructorName(
+ new TypeRef(type, typeArgs), ctorName?.name));
+ }
+
+ void handleModifier(Token token) {
+ debugEvent("Modifier");
+ assert(ignore);
+ }
+
+ void handleModifiers(int count) {
+ debugEvent("Modifiers");
+ assert(ignore);
+ }
+
+ /// Overriden: the base class throws when something is not handled, we avoid
+ /// implementing a few handlers when we know we can ignore them.
+ @override
+ void logEvent(e) {
+ if (ignore) return;
+ super.logEvent(e);
+ }
+
+ // debug helpers
+
+ void debugEvent(String name) {
+ if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) {
+ var s = stack.join(' :: ');
+ if (s == '') s = '<empty>';
+ var bits = '$_withinFunction,$_withinCascades';
+ var prefix = ignore ? "ignore $name on:" : "do $name on:";
+ prefix = '$prefix${" " * (30 - prefix.length)}';
+ print('$prefix $bits $s');
+ }
+ }
+
+ void debugStart(Token token) {
+ debugEvent('\n---- START: $runtimeType ---');
+ if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) {
+ _printExpression(token);
+ }
+ }
+
+ void _printExpression(Token token) {
+ var current = token;
+ var end = new ClassMemberParser(this).skipExpression(current);
+ var str = new StringBuffer();
+ while (current != end) {
+ if (!["(", ",", ")"].contains(current.value)) str.write(' ');
+ str.write(current.value);
+ current = current.next;
+ }
+ print('exp: $str');
+ }
+}
+
+/// Builder for constant expressions.
+///
+/// Any invalid subexpression is denoted with [Invalid].
+class ConstExpressionBuilder extends ExpressionListener {
+ bool get forConst => true;
+ final Uri uri;
+ Parser parser;
+ ConstExpressionBuilder(this.uri) {
+ parser = new Parser(this,
+ asyncAwaitKeywordsEnabled: true);
+ }
+
+ void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
+ debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
+ }
+
+ void handleAsOperator(Token op, Token next) {
+ debugEvent("As");
+ if (ignore) return;
+ push(new As(pop(), pop()));
+ }
+
+ void handleIndexedExpression(Token openSquareBracket, Token token) {
+ debugEvent("Index");
+ if (ignore) return;
+ pop(); // receiver
+ pop(); // index
+ push(new Invalid(hint: "index"));
+ }
+
+ void handleAssignmentExpression(Token operator) {
+ pop(); // lhs
+ pop(); // rhs
+ push(new Invalid(hint: "assign"));
+ }
+
+ void handleUnaryPrefixAssignmentExpression(Token operator) {
+ pop();
+ push(new Invalid(hint: "prefixOp"));
+ }
+
+ void handleUnaryPostfixAssignmentExpression(Token operator) {
+ pop();
+ push(new Invalid(hint: "postfixOp"));
+ }
+
+ void handleNamedArgument(colon) {
+ debugEvent("NamedArg");
+ if (ignore) return;
+ var value = pop();
+ Ref name = pop();
+ push(new NamedArg(name.name, value));
+ }
+
+ void endArguments(int count, Token begin, Token end) {
+ debugEvent("Arguments");
+ if (ignore) return;
+ push(popList(count) ?? const []);
+ }
+
+ void handleNewExpression(Token token) {
+ debugEvent("NewExpression");
+ if (ignore) return;
+ pop(); // args
+ pop(); // ctor
+ push(new Invalid(hint: "new"));
+ }
+
+ void _endFunction() {
+ assert(_withinFunction >= 0);
+ push(new Invalid(hint: 'function'));
+ }
+
+ // 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
+ //void _endCascade() {
+ // push(new Invalid(hint: 'cascades'));
+ //}
+
+ void _unhandledSend() {
+ push(new Invalid(hint: "call"));
+ }
+}
+
+/// Builder for initializer expressions. These expressions exclude any nested
+/// expression that is not needed to infer strong mode types.
+class InitializerBuilder extends ExpressionListener {
+ final Uri uri;
+ Parser parser;
+
+ InitializerBuilder(this.uri) {
+ parser = new Parser(this,
+ asyncAwaitKeywordsEnabled: true);
+ }
+
+ void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
+ debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
+ }
+
+ bool get ignore => super.ignore || _inArguments > 0;
+
+ void handleAsOperator(Token op, Token next) {
+ debugEvent("As");
+ if (ignore) return;
+ TypeRef type = pop();
+ pop();
+ push(new Opaque(type: type));
+ }
+
+ // Not necessary, but we don't use the value, so we can abstract it:
+ void handleIsOperator(Token operator, Token not, Token endToken) {
+ debugEvent("Is");
+ if (ignore) return;
+ 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
+ // push(new Opaque(type: new TypeRef(new Ref('bool'))));
+ }
+
+ void handleIndexedExpression(Token openSquareBracket, Token token) {
+ debugEvent("Index");
+ if (ignore) return;
+ pop();
+ pop();
+ push(new Opaque());
+ }
+
+ void handleAssignmentExpression(Token operator) {
+ debugEvent("Assign");
+ if (ignore) return;
+ var left = pop();
+ var right = pop();
+ var kind = operator.kind;
+ if (kind == EQ_TOKEN) {
+ push(new OpaqueOp(right));
+ } else {
+ push(new OpaqueOp(new Binary(left, right, opForAssignOp(kind))));
+ }
+ }
+
+ void handleUnaryPrefixAssignmentExpression(Token operator) {
+ debugEvent("Prefix");
+ if (ignore) return;
+ var kind = operator.kind == PLUS_PLUS_TOKEN ? PLUS_TOKEN : MINUS_TOKEN;
+ push(new OpaqueOp(new Binary(pop(), new IntLiteral(1), kind)));
+ }
+
+ void handleUnaryPostfixAssignmentExpression(Token operator) {
+ debugEvent("PostFix");
+ if (ignore) return;
+ // the post-fix effect is not visible to the enclosing expression
+ push(new OpaqueOp(pop()));
+ }
+
+ int _inArguments = 0;
+ void beginArguments(Token token) {
+ // TODO(sigmund): determine if we can ignore arguments.
+ //_inArguments++;
+ }
+
+ void handleNamedArgument(colon) {
+ debugEvent("NamedArg");
+ if (ignore) return;
+ pop();
+ pop();
+ push(NullValue.Arguments);
+ }
+
+ void endArguments(int count, Token begin, Token end) {
+ debugEvent("Arguments");
+ //_inArguments--;
+ if (ignore) return;
+ push(popList(count) ?? const []);
+ //push([new Opaque(hint: "arguments")]);
+ }
+
+ void handleNewExpression(Token token) {
+ debugEvent("NewExpression");
+ if (ignore) return;
+ pop(); // args
+ /* var ctor = */ pop(); // ctor
+ throw new UnimplementedError(); // TODO(paulberry): fix the code below.
+ // push(new Opaque(type: ctor.type, hint: "new"));
+ }
+
+ void _endFunction() {
+ push(new Opaque(hint: "function"));
+ }
+
+ // TODO(paulberry): is this needed?
+ //void _endCascade() {
+ // push(new OpaqueOp(pop(), hint: 'cascades'));
+ //}
+
+ void _unhandledSend() {
+ push(new Opaque(hint: "call"));
+ }
+}
+
+// bit-masks to encode modifiers as bits on an int.
+
+/// Maps modifier names to their bit-mask.
+const _modifierFlag = const {
+ 'const': _const_flag,
+ 'abstract': _abstract_flag,
+ 'static': _static_flag,
+ 'external': _external_flag,
+ 'final': _final_flag,
+ 'var': _var_flag,
+};
+
+const _var_flag = 0;
+const _final_flag = 1;
+const _const_flag = 1 << 1;
+const _abstract_flag = 1 << 2;
+const _static_flag = 1 << 3;
+const _external_flag = 1 << 4;
+
+// bit-masks to encode async modifiers as bits on an int.
+
+const _async_flag = 1;
+const _sync_flag = 1 << 1;
+const _star_flag = 1 << 2;
+
+/// Retrieve the operator from an assignment operator (e.g. + from +=).
+/// Operators are encoded using the scanner token kind id.
+int opForAssignOp(int kind) {
+ switch (kind) {
+ case AMPERSAND_EQ_TOKEN: return AMPERSAND_TOKEN;
+ // TODO(paulberry): add support for &&=
+ // case AMPERSAND_AMPERSAND_EQ_TOKEN: return AMPERSAND_AMPERSAND_TOKEN;
+ case BAR_EQ_TOKEN: return BAR_TOKEN;
+ // TODO(paulberry): add support for ||=
+ // case BAR_BAR_EQ_TOKEN: return BAR_BAR_TOKEN;
+ case CARET_EQ_TOKEN: return CARET_TOKEN;
+ case GT_GT_EQ_TOKEN: return GT_GT_TOKEN;
+ case LT_LT_EQ_TOKEN: return LT_LT_TOKEN;
+ case MINUS_EQ_TOKEN: return MINUS_TOKEN;
+ case PERCENT_EQ_TOKEN: return PERCENT_TOKEN;
+ case PLUS_EQ_TOKEN: return PLUS_TOKEN;
+ case QUESTION_QUESTION_EQ_TOKEN: return QUESTION_QUESTION_TOKEN;
+ case SLASH_EQ_TOKEN: return SLASH_TOKEN;
+ case STAR_EQ_TOKEN: return STAR_TOKEN;
+ case TILDE_SLASH_EQ_TOKEN: return TILDE_SLASH_TOKEN;
+ case PLUS_EQ_TOKEN: return PLUS_TOKEN;
+ default:
+ throw "Unhandled kind $kind";
+ }
+}
« no previous file with comments | « pkg/analyzer/lib/src/summary/fasta/stack_listener.dart ('k') | pkg/analyzer/lib/src/summary/fasta/visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698