| Index: pkg/fasta/lib/src/source/diet_listener.dart
|
| diff --git a/pkg/fasta/lib/src/source/diet_listener.dart b/pkg/fasta/lib/src/source/diet_listener.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6e63f0c48e3d0cd5f47dff6943d0ed575354d38f
|
| --- /dev/null
|
| +++ b/pkg/fasta/lib/src/source/diet_listener.dart
|
| @@ -0,0 +1,471 @@
|
| +// Copyright (c) 2016, 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.
|
| +
|
| +library fasta.diet_listener;
|
| +
|
| +import 'package:kernel/ast.dart' show
|
| + AsyncMarker;
|
| +
|
| +import 'package:kernel/class_hierarchy.dart' show
|
| + ClassHierarchy;
|
| +
|
| +import 'package:kernel/core_types.dart' show
|
| + CoreTypes;
|
| +
|
| +import 'package:dart_parser/src/parser.dart' show
|
| + Parser,
|
| + optional;
|
| +
|
| +import 'package:dart_scanner/src/token.dart' show
|
| + BeginGroupToken,
|
| + Token;
|
| +
|
| +import '../errors.dart' show
|
| + Crash,
|
| + InputError,
|
| + inputError,
|
| + internalError;
|
| +
|
| +import 'stack_listener.dart' show
|
| + StackListener;
|
| +
|
| +import '../kernel/body_builder.dart' show
|
| + BodyBuilder;
|
| +
|
| +import '../builder/builder.dart';
|
| +
|
| +import '../analyzer/analyzer.dart';
|
| +
|
| +import '../builder/scope.dart' show
|
| + Scope;
|
| +
|
| +import '../ast_kind.dart' show
|
| + AstKind;
|
| +
|
| +import 'source_library_builder.dart' show
|
| + SourceLibraryBuilder;
|
| +
|
| +import 'source_class_builder.dart' show
|
| + isConstructorName;
|
| +
|
| +class DietListener extends StackListener {
|
| + final SourceLibraryBuilder library;
|
| +
|
| + final ElementStore elementStore;
|
| +
|
| + final ClassHierarchy hierarchy;
|
| +
|
| + final CoreTypes coreTypes;
|
| +
|
| + final AstKind astKind;
|
| +
|
| + ClassBuilder currentClass;
|
| +
|
| + /// For top-level declarations, this is the library scope. For class members,
|
| + /// this is the instance scope of [currentClass].
|
| + Scope memberScope;
|
| +
|
| + DietListener(SourceLibraryBuilder library, this.elementStore, this.hierarchy,
|
| + this.coreTypes, this.astKind)
|
| + : library = library,
|
| + memberScope = library.scope;
|
| +
|
| + Uri get uri => library.uri;
|
| +
|
| + void discard(int n) {
|
| + for (int i =0; i < n; i++) {
|
| + pop();
|
| + }
|
| + }
|
| +
|
| + void endMetadataStar(int count, bool forParameter) {
|
| + debugEvent("MetadataStar");
|
| + }
|
| +
|
| + void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
|
| + debugEvent("Metadata");
|
| + popIfNotNull(periodBeforeName);
|
| + discard(1);
|
| + }
|
| +
|
| + void endPartOf(Token partKeyword, Token semicolon) {
|
| + debugEvent("PartOf");
|
| + discard(1);
|
| + }
|
| +
|
| + void handleNoArguments(Token token) {
|
| + debugEvent("NoArguments");
|
| + }
|
| +
|
| + void handleModifiers(int count) {
|
| + debugEvent("Modifiers");
|
| + }
|
| +
|
| + void handleNoTypeArguments(Token token) {
|
| + debugEvent("NoTypeArguments");
|
| + }
|
| +
|
| + void handleNoType(Token token) {
|
| + debugEvent("NoType");
|
| + }
|
| +
|
| + void endType(Token beginToken, Token endToken) {
|
| + debugEvent("Type");
|
| + discard(1);
|
| + }
|
| +
|
| + void endTypeList(int count) {
|
| + debugEvent("TypeList");
|
| + }
|
| +
|
| + void endMixinApplication() {
|
| + debugEvent("MixinApplication");
|
| + }
|
| +
|
| + void endTypeArguments(int count, Token beginToken, Token endToken) {
|
| + debugEvent("TypeArguments");
|
| + }
|
| +
|
| + void endInitializer(Token assignmentOperator) {
|
| + debugEvent("Initializer");
|
| + }
|
| +
|
| + void handleNoTypeVariables(Token token) {
|
| + debugEvent("NoTypeVariables");
|
| + }
|
| +
|
| + void endFormalParameters(int count, Token beginToken, Token endToken) {
|
| + debugEvent("FormalParameters");
|
| + assert(count == 0); // Count is always 0 as the diet parser skips formals.
|
| + if (identical(peek(), "-") && identical(beginToken.next, endToken)) {
|
| + pop();
|
| + push("unary-");
|
| + }
|
| + push(beginToken);
|
| + }
|
| +
|
| + void handleNoFormalParameters(Token token) {
|
| + debugEvent("NoFormalParameters");
|
| + if (identical(peek(), "-")) {
|
| + pop();
|
| + push("unary-");
|
| + }
|
| + push(token);
|
| + }
|
| +
|
| + void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
|
| + debugEvent("FunctionTypeAlias");
|
| + discard(2); // Name + endToken.
|
| + checkEmpty();
|
| + }
|
| +
|
| + void endFields(int count, Token beginToken, Token endToken) {
|
| + debugEvent("Fields");
|
| + List<String> names = popList(count);
|
| + Builder builder = lookupBuilder(beginToken, null, names.first);
|
| + buildFields(beginToken, false, builder.isInstanceMember);
|
| + }
|
| +
|
| + void handleAsyncModifier(Token asyncToken, Token startToken) {
|
| + debugEvent("AsyncModifier");
|
| + }
|
| +
|
| + void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
|
| + debugEvent("TopLevelMethod");
|
| + Token bodyToken = pop();
|
| + String name = pop();
|
| + checkEmpty();
|
| + buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name));
|
| + }
|
| +
|
| + void handleNoFunctionBody(Token token) {
|
| + debugEvent("NoFunctionBody");
|
| + }
|
| +
|
| + void endTopLevelFields(int count, Token beginToken, Token endToken) {
|
| + debugEvent("TopLevelFields");
|
| + discard(count);
|
| + buildFields(beginToken, true, false);
|
| + }
|
| +
|
| + void handleVoidKeyword(Token token) {
|
| + debugEvent("VoidKeyword");
|
| + }
|
| +
|
| + void handleNoInitializers() {
|
| + debugEvent("NoInitializers");
|
| + }
|
| +
|
| + void endInitializers(int count, Token beginToken, Token endToken) {
|
| + debugEvent("Initializers");
|
| + }
|
| +
|
| + void handleQualified(Token period) {
|
| + debugEvent("handleQualified");
|
| + // TODO(ahe): Shared with outline_builder.dart.
|
| + String name = pop();
|
| + String receiver = pop();
|
| + push("$receiver.$name");
|
| + }
|
| +
|
| + void endLibraryName(Token libraryKeyword, Token semicolon) {
|
| + debugEvent("endLibraryName");
|
| + discard(1);
|
| + }
|
| +
|
| + void beginLiteralString(Token token) {
|
| + debugEvent("beginLiteralString");
|
| + }
|
| +
|
| + void endLiteralString(int interpolationCount) {
|
| + debugEvent("endLiteralString");
|
| + discard(interpolationCount);
|
| + }
|
| +
|
| + void handleStringJuxtaposition(int literalCount) {
|
| + debugEvent("StringJuxtaposition");
|
| + }
|
| +
|
| + void endDottedName(int count, Token firstIdentifier) {
|
| + debugEvent("DottedName");
|
| + discard(count);
|
| + }
|
| +
|
| + void endConditionalUri(Token ifKeyword, Token equalitySign) {
|
| + debugEvent("ConditionalUri");
|
| + }
|
| +
|
| + void endConditionalUris(int count) {
|
| + debugEvent("ConditionalUris");
|
| + }
|
| +
|
| + void handleOperatorName(Token operatorKeyword, Token token) {
|
| + debugEvent("OperatorName");
|
| + push(token.stringValue);
|
| + }
|
| +
|
| + void endIdentifierList(int count) {
|
| + debugEvent("IdentifierList");
|
| + discard(count);
|
| + }
|
| +
|
| + void endShow(Token showKeyword) {
|
| + debugEvent("Show");
|
| + }
|
| +
|
| + void endHide(Token hideKeyword) {
|
| + debugEvent("Hide");
|
| + }
|
| +
|
| + void endCombinators(int count) {
|
| + debugEvent("Combinators");
|
| + }
|
| +
|
| + void endImport(Token importKeyword, Token DeferredKeyword, Token asKeyword,
|
| + Token semicolon) {
|
| + debugEvent("Import");
|
| + popIfNotNull(asKeyword);
|
| + }
|
| +
|
| + void endExport(Token exportKeyword, Token semicolon) {
|
| + debugEvent("Export");
|
| + }
|
| +
|
| + void endPart(Token partKeyword, Token semicolon) {
|
| + debugEvent("Part");
|
| + }
|
| +
|
| + void endTypeVariable(Token token, Token extendsOrSuper) {
|
| + debugEvent("TypeVariable");
|
| + discard(1);
|
| + }
|
| +
|
| + void endTypeVariables(int count, Token beginToken, Token endToken) {
|
| + debugEvent("TypeVariables");
|
| + }
|
| +
|
| + void handleModifier(Token token) {
|
| + debugEvent("Modifier");
|
| + }
|
| +
|
| + void endConstructorReference(
|
| + Token start, Token periodBeforeName, Token endToken) {
|
| + debugEvent("ConstructorReference");
|
| + popIfNotNull(periodBeforeName);
|
| + }
|
| +
|
| + void endFactoryMethod(Token beginToken, Token endToken) {
|
| + debugEvent("FactoryMethod");
|
| + BeginGroupToken bodyToken = pop();
|
| + String name = pop();
|
| + checkEmpty();
|
| + if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
|
| + return;
|
| + }
|
| + buildFunctionBody(bodyToken, lookupBuilder(beginToken, null, name));
|
| + }
|
| +
|
| + void endRedirectingFactoryBody(Token beginToken, Token endToken) {
|
| + debugEvent("RedirectingFactoryBody");
|
| + discard(1); // ConstructorReference.
|
| + }
|
| +
|
| + void endMethod(Token getOrSet, Token beginToken, Token endToken) {
|
| + debugEvent("Method");
|
| + Token bodyToken = pop();
|
| + String name = pop();
|
| + checkEmpty();
|
| + if (bodyToken == null) {
|
| + return;
|
| + }
|
| + buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name));
|
| + }
|
| +
|
| + StackListener createListener(MemberBuilder builder, Scope memberScope,
|
| + bool isInstanceMember, [Scope formalParameterScope]) {
|
| + switch (astKind) {
|
| + case AstKind.Kernel:
|
| + return new BodyBuilder(library, builder, memberScope,
|
| + formalParameterScope, hierarchy, coreTypes, currentClass,
|
| + isInstanceMember);
|
| +
|
| + case AstKind.Analyzer:
|
| + return new AstBuilder(library, builder, elementStore, memberScope);
|
| + }
|
| +
|
| + return internalError("Unknown $astKind");
|
| + }
|
| +
|
| + void buildFunctionBody(Token token, ProcedureBuilder builder) {
|
| + Scope typeParameterScope = builder.computeTypeParameterScope(memberScope);
|
| + Scope formalParameterScope =
|
| + builder.computeFormalParameterScope(typeParameterScope);
|
| + assert(typeParameterScope != null);
|
| + assert(formalParameterScope != null);
|
| + parseFunctionBody(
|
| + createListener(builder, typeParameterScope, builder.isInstanceMember,
|
| + formalParameterScope),
|
| + token);
|
| + }
|
| +
|
| + void buildFields(Token token, bool isTopLevel, bool isInstanceMember) {
|
| + parseFields(createListener(null, memberScope, isInstanceMember),
|
| + token, isTopLevel);
|
| + }
|
| +
|
| + void endMember() {
|
| + debugEvent("Member");
|
| + checkEmpty();
|
| + }
|
| +
|
| + void beginClassBody(Token token) {
|
| + debugEvent("beginClassBody");
|
| + String name = pop();
|
| + assert(currentClass == null);
|
| + currentClass = lookupBuilder(token, null, name);
|
| + assert(memberScope == library.scope);
|
| + memberScope = currentClass.computeInstanceScope(memberScope);
|
| + }
|
| +
|
| + void endClassBody(int memberCount, Token beginToken, Token endToken) {
|
| + debugEvent("ClassBody");
|
| + currentClass = null;
|
| + checkEmpty();
|
| + memberScope = library.scope;
|
| + }
|
| +
|
| + void endClassDeclaration(int interfacesCount, Token beginToken,
|
| + Token extendsKeyword, Token implementsKeyword, Token endToken) {
|
| + debugEvent("ClassDeclaration");
|
| + checkEmpty();
|
| + }
|
| +
|
| + void endEnum(Token enumKeyword, Token endBrace, int count) {
|
| + debugEvent("Enum");
|
| + discard(count);
|
| + pop(); // Name.
|
| + checkEmpty();
|
| + }
|
| +
|
| + void endNamedMixinApplication(
|
| + Token classKeyword, Token implementsKeyword, Token endToken) {
|
| + debugEvent("NamedMixinApplication");
|
| + pop(); // Name.
|
| + checkEmpty();
|
| + }
|
| +
|
| + void parseFunctionBody(StackListener listener, Token token) {
|
| + try {
|
| + Parser parser = new Parser(listener);
|
| + token = parser.parseFormalParametersOpt(token);
|
| + var formals = listener.pop();
|
| + listener.checkEmpty();
|
| + listener.prepareInitializers();
|
| + token = parser.parseInitializersOpt(token);
|
| + token = parser.parseAsyncModifier(token);
|
| + AsyncMarker asyncModifier = listener.pop();
|
| + bool isExpression = false;
|
| + bool allowAbstract = true;
|
| + parser.parseFunctionBody(token, isExpression, allowAbstract);
|
| + var body = listener.pop();
|
| + listener.checkEmpty();
|
| + listener.finishFunction(formals, asyncModifier, body);
|
| + } on InputError {
|
| + rethrow;
|
| + } catch (e, s) {
|
| + throw new Crash(uri, token.charOffset, e, s);
|
| + }
|
| + }
|
| +
|
| + void parseFields(StackListener listener, Token token, bool isTopLevel) {
|
| + Parser parser = new Parser(listener);
|
| + if (isTopLevel) {
|
| + token = parser.parseTopLevelMember(token);
|
| + } else {
|
| + token = parser.parseMember(token);
|
| + }
|
| + listener.checkEmpty();
|
| + }
|
| +
|
| + Builder lookupBuilder(Token token, Token getOrSet, String name) {
|
| + Builder builder;
|
| + if (currentClass != null) {
|
| + builder = currentClass.members[name];
|
| + if (builder == null && isConstructorName(name, currentClass.name)) {
|
| + int index = name.indexOf(".");
|
| + name = index == -1 ? "" : name.substring(index + 1);
|
| + builder = currentClass.members[name];
|
| + }
|
| + } else {
|
| + builder = library.members[name];
|
| + }
|
| + if (builder == null) {
|
| + return internalError("@${token.charOffset}: builder not found: $name");
|
| + }
|
| + if (builder.next != null) {
|
| + Builder getterBuilder;
|
| + Builder setterBuilder;
|
| + Builder current = builder;
|
| + while (current != null) {
|
| + if (current.isGetter && getterBuilder == null) {
|
| + getterBuilder = current;
|
| + } else if (current.isSetter && setterBuilder == null) {
|
| + setterBuilder = current;
|
| + } else {
|
| + return inputError(uri, token.charOffset, "Duplicated name: $name");
|
| + }
|
| + current = current.next;
|
| + }
|
| + assert(getOrSet != null);
|
| + if (optional("get", getOrSet)) return getterBuilder;
|
| + if (optional("set", getOrSet)) return setterBuilder;
|
| + }
|
| + return builder;
|
| + }
|
| +
|
| + void debugEvent(String name) {
|
| + // print(" ${stack.join('\n ')}");
|
| + // print(name);
|
| + }
|
| +}
|
|
|