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

Unified Diff: pkg/analyzer/lib/src/fasta/ast_builder.dart

Issue 3011643002: Fix several failing tests (Closed)
Patch Set: Created 3 years, 4 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/fasta/ast_builder.dart
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index c6f57cea7b1b7bb065b097aada8bc69c5879a607..cdaa2724db9994bd77516403513bdd53fcad17be 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -8,6 +8,11 @@ import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast_factory.dart' show AstFactory;
import 'package:analyzer/dart/ast/standard_ast_factory.dart' as standard;
import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:front_end/src/fasta/kernel/kernel_builder.dart'
+ show Builder, KernelLibraryBuilder, Scope;
+import 'package:front_end/src/fasta/messages.dart'
+ show Code, Message, codeExpectedExpression, codeExpectedFunctionBody;
import 'package:front_end/src/fasta/parser.dart'
show
Assert,
@@ -16,19 +21,13 @@ import 'package:front_end/src/fasta/parser.dart'
MemberKind,
Parser,
closeBraceTokenFor;
-import 'package:front_end/src/fasta/scanner/string_scanner.dart';
-import 'package:front_end/src/fasta/scanner/token.dart' show CommentToken;
-import 'package:front_end/src/scanner/token.dart' as analyzer;
-
import 'package:front_end/src/fasta/problems.dart' show unhandled;
-import 'package:front_end/src/fasta/messages.dart'
- show Code, Message, codeExpectedExpression, codeExpectedFunctionBody;
-import 'package:front_end/src/fasta/kernel/kernel_builder.dart'
- show Builder, KernelLibraryBuilder, Scope;
import 'package:front_end/src/fasta/quote.dart';
+import 'package:front_end/src/fasta/scanner/string_scanner.dart';
+import 'package:front_end/src/fasta/scanner/token.dart' show CommentToken;
import 'package:front_end/src/fasta/source/scope_listener.dart'
show JumpTargetKind, NullValue, ScopeListener;
-import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:front_end/src/scanner/token.dart' as analyzer;
class AstBuilder extends ScopeListener {
final AstFactory ast = standard.astFactory;
@@ -77,166 +76,131 @@ class AstBuilder extends ScopeListener {
: uri = uri ?? library.fileUri,
super(scope);
- createJumpTarget(JumpTargetKind kind, int charOffset) {
- // TODO(ahe): Implement jump targets.
- return null;
- }
-
- void beginLiteralString(Token token) {
- debugEvent("beginLiteralString");
- push(token);
- }
-
- void handleNamedArgument(Token colon) {
- debugEvent("NamedArgument");
- Expression expression = pop();
- SimpleIdentifier name = pop();
- push(ast.namedExpression(ast.label(name, colon), expression));
- }
-
- @override
- void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
- debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
- push(NullValue.ConstructorReferenceContinuationAfterTypeArguments);
- }
-
@override
- void endConstructorReference(
- Token start, Token periodBeforeName, Token endToken) {
- debugEvent("ConstructorReference");
- SimpleIdentifier constructorName = pop();
- TypeArgumentList typeArguments = pop();
- Identifier typeNameIdentifier = pop();
- push(ast.constructorName(ast.typeName(typeNameIdentifier, typeArguments),
- periodBeforeName, constructorName));
- }
+ void addCompileTimeError(Message message, int charOffset) {
+ Code code = message.code;
+ Map<String, dynamic> arguments = message.arguments;
- @override
- void endConstExpression(Token token) {
- debugEvent("ConstExpression");
- _handleInstanceCreation(token);
- }
+ String stringOrTokenLexeme() {
+ var text = arguments['string'];
+ if (text == null) {
+ Token token = arguments['token'];
+ if (token != null) {
+ text = token.lexeme;
+ }
+ }
+ return text;
+ }
- @override
- void endConstLiteral(Token token) {
- debugEvent("endConstLiteral");
+ switch (code.analyzerCode) {
+ case "EXPECTED_TYPE_NAME":
+ errorReporter?.reportErrorForOffset(
+ ParserErrorCode.EXPECTED_TYPE_NAME, charOffset, 1);
+ return;
+ case "NATIVE_CLAUSE_SHOULD_BE_ANNOTATION":
+ if (!allowNativeClause) {
+ errorReporter?.reportErrorForOffset(
+ ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION,
+ charOffset,
+ 1);
+ }
+ return;
+ case "EXPECTED_STRING_LITERAL":
+ errorReporter?.reportErrorForOffset(
+ ParserErrorCode.EXPECTED_STRING_LITERAL, charOffset, 1);
+ return;
+ case "EXTRANEOUS_MODIFIER":
+ String text = stringOrTokenLexeme();
+ errorReporter?.reportErrorForOffset(ParserErrorCode.EXTRANEOUS_MODIFIER,
+ charOffset, text.length, [text]);
+ return;
+ case "UNEXPECTED_TOKEN":
+ String text = stringOrTokenLexeme();
+ if (text == ';') {
+ errorReporter?.reportErrorForOffset(
+ ParserErrorCode.EXPECTED_TOKEN, charOffset, text.length, [text]);
+ } else {
+ errorReporter?.reportErrorForOffset(ParserErrorCode.UNEXPECTED_TOKEN,
+ charOffset, text.length, [text]);
+ }
+ return;
+ default:
+ // fall through
+ }
+ library.addCompileTimeError(message, charOffset, uri);
}
- void _handleInstanceCreation(Token token) {
- MethodInvocation arguments = pop();
- ConstructorName constructorName = pop();
- push(ast.instanceCreationExpression(
- token, constructorName, arguments.argumentList));
+ void beginCascade(Token token) {
+ debugEvent("beginCascade");
+ Expression expression = pop();
+ push(token);
+ if (expression is CascadeExpression) {
+ push(expression);
+ } else {
+ push(ast.cascadeExpression(expression, <Expression>[]));
+ }
+ push(NullValue.CascadeReceiver);
}
@override
- void endNewExpression(Token token) {
- debugEvent("NewExpression");
- _handleInstanceCreation(token);
+ void beginClassDeclaration(Token beginToken, Token name) {
+ assert(className == null);
+ className = name.lexeme;
}
@override
- void handleParenthesizedExpression(Token token) {
- debugEvent("ParenthesizedExpression");
- Expression expression = pop();
- push(ast.parenthesizedExpression(
- token, expression, closeBraceTokenFor(token)));
- }
-
- void handleStringPart(Token token) {
- debugEvent("StringPart");
+ void beginCompilationUnit(Token token) {
push(token);
}
- void doStringPart(Token token) {
- push(ast.simpleStringLiteral(token, token.lexeme));
+ void beginLiteralString(Token token) {
+ debugEvent("beginLiteralString");
+ push(token);
}
- void endLiteralString(int interpolationCount, Token endToken) {
- debugEvent("endLiteralString");
- if (interpolationCount == 0) {
- Token token = pop();
- String value = unescapeString(token.lexeme);
- push(ast.simpleStringLiteral(token, value));
+ @override
+ void beginMetadataStar(Token token) {
+ debugEvent("beginMetadataStar");
+ if (token.precedingComments != null) {
+ push(_toAnalyzerComment(token.precedingComments));
} else {
- List parts = popList(1 + interpolationCount * 2);
- Token first = parts.first;
- Token last = parts.last;
- Quote quote = analyzeQuote(first.lexeme);
- List<InterpolationElement> elements = <InterpolationElement>[];
- elements.add(ast.interpolationString(
- first, unescapeFirstStringPart(first.lexeme, quote)));
- for (int i = 1; i < parts.length - 1; i++) {
- var part = parts[i];
- if (part is Token) {
- elements.add(ast.interpolationString(part, part.lexeme));
- } else if (part is Expression) {
- elements.add(ast.interpolationExpression(null, part, null));
- } else {
- unhandled("${part.runtimeType}", "string interpolation",
- first.charOffset, uri);
- }
- }
- elements.add(ast.interpolationString(
- last, unescapeLastStringPart(last.lexeme, quote)));
- push(ast.stringInterpolation(elements));
+ push(NullValue.Comments);
}
}
- void handleScript(Token token) {
- debugEvent("Script");
- scriptTag = ast.scriptTag(token);
+ createJumpTarget(JumpTargetKind kind, int charOffset) {
+ // TODO(ahe): Implement jump targets.
+ return null;
}
- void handleStringJuxtaposition(int literalCount) {
- debugEvent("StringJuxtaposition");
- push(ast.adjacentStrings(popList(literalCount)));
+ @override
+ void debugEvent(String name) {
+ // printEvent(name);
}
- void endArguments(int count, Token beginToken, Token endToken) {
- debugEvent("Arguments");
- List expressions = popList(count);
- ArgumentList arguments =
- ast.argumentList(beginToken, expressions, endToken);
- push(ast.methodInvocation(null, null, null, null, arguments));
+ @override
+ void discardTypeReplacedWithCommentTypeAssign() {
+ pop();
}
- void handleIdentifier(Token token, IdentifierContext context) {
- debugEvent("handleIdentifier");
- Token analyzerToken = token;
-
- if (context.inSymbol) {
- push(analyzerToken);
- return;
- }
-
- SimpleIdentifier identifier = ast.simpleIdentifier(analyzerToken,
- isDeclaration: context.inDeclaration);
- if (context.inLibraryOrPartOfDeclaration) {
- if (!context.isContinuation) {
- push([identifier]);
+ void doDotExpression(Token token) {
+ Expression identifierOrInvoke = pop();
+ Expression receiver = pop();
+ if (identifierOrInvoke is SimpleIdentifier) {
+ if (receiver is SimpleIdentifier && identical('.', token.stringValue)) {
+ push(ast.prefixedIdentifier(receiver, token, identifierOrInvoke));
} else {
- push(identifier);
+ push(ast.propertyAccess(receiver, token, identifierOrInvoke));
}
- } else if (context == IdentifierContext.enumValueDeclaration) {
- // TODO(paulberry): analyzer's ASTs allow for enumerated values to have
- // metadata, but the spec doesn't permit it.
- List<Annotation> metadata;
- Comment comment = _toAnalyzerComment(token.precedingComments);
- push(ast.enumConstantDeclaration(comment, metadata, identifier));
- } else {
- push(identifier);
- }
- }
-
- void handleSend(Token beginToken, Token endToken) {
- debugEvent("Send");
- MethodInvocation arguments = pop();
- TypeArgumentList typeArguments = pop();
- if (arguments != null) {
- doInvocation(endToken, typeArguments, arguments);
+ } else if (identifierOrInvoke is MethodInvocation) {
+ assert(identifierOrInvoke.target == null);
+ identifierOrInvoke
+ ..target = receiver
+ ..operator = token;
+ push(identifierOrInvoke);
} else {
- doPropertyGet(endToken);
+ unhandled("${identifierOrInvoke.runtimeType}", "property access",
+ token.charOffset, uri);
}
}
@@ -257,24 +221,38 @@ class AstBuilder extends ScopeListener {
void doPropertyGet(Token token) {}
- void endExpressionStatement(Token token) {
- debugEvent("ExpressionStatement");
- push(ast.expressionStatement(pop(), token));
+ void doStringPart(Token token) {
+ push(ast.simpleStringLiteral(token, token.lexeme));
}
- @override
- void handleEmptyFunctionBody(Token semicolon) {
- debugEvent("EmptyFunctionBody");
- // TODO(scheglov) Change the parser to not produce these modifiers.
- pop(); // star
- pop(); // async
- push(ast.emptyFunctionBody(semicolon));
+ void endArguments(int count, Token beginToken, Token endToken) {
+ debugEvent("Arguments");
+ List expressions = popList(count);
+ ArgumentList arguments =
+ ast.argumentList(beginToken, expressions, endToken);
+ push(ast.methodInvocation(null, null, null, null, arguments));
}
@override
- void handleEmptyStatement(Token token) {
- debugEvent("EmptyStatement");
- push(ast.emptyStatement(token));
+ void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
+ Token comma, Token rightParenthesis, Token semicolon) {
+ debugEvent("Assert");
+ Expression message = popIfNotNull(comma);
+ Expression condition = pop();
+ push(ast.assertStatement(assertKeyword, leftParenthesis, condition, comma,
+ message, rightParenthesis, semicolon));
+ }
+
+ void endAwaitExpression(Token beginToken, Token endToken) {
+ debugEvent("AwaitExpression");
+ push(ast.awaitExpression(beginToken, pop()));
+ }
+
+ void endBlock(int count, Token beginToken, Token endToken) {
+ debugEvent("Block");
+ List<Statement> statements = popList(count) ?? <Statement>[];
+ exitLocalScope();
+ push(ast.block(beginToken, statements, endToken));
}
void endBlockFunctionBody(int count, Token beginToken, Token endToken) {
@@ -289,32 +267,6 @@ class AstBuilder extends ScopeListener {
push(ast.blockFunctionBody(asyncKeyword, star, block));
}
- void finishFunction(annotations, formals, asyncModifier, FunctionBody body) {
- debugEvent("finishFunction");
- Statement bodyStatement;
- if (body is EmptyFunctionBody) {
- bodyStatement = ast.emptyStatement(body.semicolon);
- } else if (body is ExpressionFunctionBody) {
- bodyStatement = ast.returnStatement(null, body.expression, null);
- } else {
- bodyStatement = (body as BlockFunctionBody).block;
- }
- // TODO(paulberry): what do we need to do with bodyStatement at this point?
- bodyStatement; // Suppress "unused local variable" hint
- }
-
- void beginCascade(Token token) {
- debugEvent("beginCascade");
- Expression expression = pop();
- push(token);
- if (expression is CascadeExpression) {
- push(expression);
- } else {
- push(ast.cascadeExpression(expression, <Expression>[]));
- }
- push(NullValue.CascadeReceiver);
- }
-
void endCascade() {
debugEvent("Cascade");
Expression expression = pop();
@@ -324,103 +276,597 @@ class AstBuilder extends ScopeListener {
push(receiver);
}
- void handleOperator(Token token) {
- debugEvent("Operator");
- push(token);
- }
-
- void handleSymbolVoid(Token token) {
- debugEvent("SymbolVoid");
- push(token);
+ @override
+ void endClassBody(int memberCount, Token beginToken, Token endToken) {
+ debugEvent("ClassBody");
+ push(new _ClassBody(
+ beginToken, popList(memberCount) ?? <ClassMember>[], endToken));
}
- void handleBinaryExpression(Token token) {
- debugEvent("BinaryExpression");
- if (identical(".", token.stringValue) ||
- identical("?.", token.stringValue) ||
- identical("..", token.stringValue)) {
- doDotExpression(token);
+ @override
+ void endClassDeclaration(
+ int interfacesCount,
+ Token beginToken,
+ Token classKeyword,
+ Token extendsKeyword,
+ Token implementsKeyword,
+ Token nativeToken,
+ Token endToken) {
+ debugEvent("ClassDeclaration");
+ _ClassBody body = pop();
+ NativeClause nativeClause = nativeToken != null ? pop() : null;
+ ImplementsClause implementsClause;
+ if (implementsKeyword != null) {
+ List<TypeName> interfaces = popList(interfacesCount);
+ implementsClause = ast.implementsClause(implementsKeyword, interfaces);
+ }
+ ExtendsClause extendsClause;
+ WithClause withClause;
+ var supertype = pop();
+ if (supertype == null) {
+ // No extends clause
+ } else if (supertype is TypeName) {
+ extendsClause = ast.extendsClause(extendsKeyword, supertype);
+ } else if (supertype is _MixinApplication) {
+ extendsClause = ast.extendsClause(extendsKeyword, supertype.supertype);
+ withClause = ast.withClause(supertype.withKeyword, supertype.mixinTypes);
} else {
- Expression right = pop();
- Expression left = pop();
- push(ast.binaryExpression(left, token, right));
+ unhandled("${supertype.runtimeType}", "supertype",
+ extendsKeyword.charOffset, uri);
}
+ TypeParameterList typeParameters = pop();
+ SimpleIdentifier name = pop();
+ assert(className == name.name);
+ className = null;
+ _Modifiers modifiers = pop();
+ Token abstractKeyword = modifiers?.abstractKeyword;
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ ClassDeclaration classDeclaration = ast.classDeclaration(
+ comment,
+ metadata,
+ abstractKeyword,
+ classKeyword,
+ name,
+ typeParameters,
+ extendsClause,
+ withClause,
+ implementsClause,
+ body.beginToken,
+ body.members,
+ body.endToken);
+ classDeclaration.nativeClause = nativeClause;
+ declarations.add(classDeclaration);
}
- void doDotExpression(Token token) {
- Expression identifierOrInvoke = pop();
- Expression receiver = pop();
- if (identifierOrInvoke is SimpleIdentifier) {
- if (receiver is SimpleIdentifier && identical('.', token.stringValue)) {
- push(ast.prefixedIdentifier(receiver, token, identifierOrInvoke));
- } else {
- push(ast.propertyAccess(receiver, token, identifierOrInvoke));
- }
- } else if (identifierOrInvoke is MethodInvocation) {
- assert(identifierOrInvoke.target == null);
- identifierOrInvoke
- ..target = receiver
- ..operator = token;
- push(identifierOrInvoke);
- } else {
- unhandled("${identifierOrInvoke.runtimeType}", "property access",
- token.charOffset, uri);
- }
+ @override
+ void endCompilationUnit(int count, Token endToken) {
+ debugEvent("CompilationUnit");
+ Token beginToken = pop();
+ checkEmpty(endToken.charOffset);
+
+ push(ast.compilationUnit(
+ beginToken, scriptTag, directives, declarations, endToken));
}
- void handleLiteralInt(Token token) {
- debugEvent("LiteralInt");
- push(ast.integerLiteral(token, int.parse(token.lexeme)));
+ void endConditionalUri(Token ifKeyword, Token equalitySign) {
+ debugEvent("ConditionalUri");
+ StringLiteral libraryUri = pop();
+ StringLiteral value;
+ if (equalitySign != null) {
+ value = pop();
+ }
+ DottedName name = pop();
+ // TODO(paulberry,ahe): what if there is no `(` token due to an error in the
+ // file being parsed? It seems like we need the parser to do adequate error
+ // recovery and then report both the ifKeyword and leftParen tokens to the
+ // listener.
+ Token leftParen = ifKeyword.next;
+ // TODO(paulberry,ahe): the parser should report the right paren token to
+ // the listener.
+ Token rightParen = name.endToken.next;
+ push(ast.configuration(ifKeyword, leftParen, name, equalitySign, value,
+ rightParen, libraryUri));
}
- void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
- debugEvent("ExpressionFunctionBody");
- Expression expression = pop();
- Token star = pop();
- Token asyncKeyword = pop();
- assert(star == null);
- push(ast.expressionFunctionBody(
- asyncKeyword, arrowToken, expression, endToken));
+ @override
+ void endConditionalUris(int count) {
+ debugEvent("ConditionalUris");
+ push(popList(count) ?? NullValue.ConditionalUris);
}
- void endReturnStatement(
- bool hasExpression, Token beginToken, Token endToken) {
- debugEvent("ReturnStatement");
- Expression expression = hasExpression ? pop() : null;
- push(ast.returnStatement(beginToken, expression, endToken));
+ @override
+ void endConstExpression(Token token) {
+ debugEvent("ConstExpression");
+ _handleInstanceCreation(token);
}
- void endIfStatement(Token ifToken, Token elseToken) {
- Statement elsePart = popIfNotNull(elseToken);
- Statement thenPart = pop();
- Expression condition = pop();
- analyzer.BeginToken leftParenthesis = ifToken.next;
- push(ast.ifStatement(ifToken, ifToken.next, condition,
- leftParenthesis.endGroup, thenPart, elseToken, elsePart));
+ @override
+ void endConstLiteral(Token token) {
+ debugEvent("endConstLiteral");
}
- void handleNoInitializers() {
- debugEvent("NoInitializers");
- if (!isFullAst) return;
- push(NullValue.ConstructorInitializerSeparator);
- push(NullValue.ConstructorInitializers);
+ @override
+ void endConstructorReference(
+ Token start, Token periodBeforeName, Token endToken) {
+ debugEvent("ConstructorReference");
+ SimpleIdentifier constructorName = pop();
+ TypeArgumentList typeArguments = pop();
+ Identifier typeNameIdentifier = pop();
+ push(ast.constructorName(ast.typeName(typeNameIdentifier, typeArguments),
+ periodBeforeName, constructorName));
}
- void endInitializers(int count, Token beginToken, Token endToken) {
- debugEvent("Initializers");
- List<Object> initializerObjects = popList(count) ?? const [];
- if (!isFullAst) return;
+ @override
+ void endDottedName(int count, Token firstIdentifier) {
+ debugEvent("DottedName");
+ List<SimpleIdentifier> components = popList(count);
+ push(ast.dottedName(components));
+ }
- push(beginToken);
+ @override
+ void endDoWhileStatement(
+ Token doKeyword, Token whileKeyword, Token semicolon) {
+ debugEvent("DoWhileStatement");
+ ParenthesizedExpression condition = pop();
+ Statement body = pop();
+ exitContinueTarget();
+ exitBreakTarget();
+ push(ast.doStatement(
+ doKeyword,
+ body,
+ whileKeyword,
+ condition.leftParenthesis,
+ condition.expression,
+ condition.rightParenthesis,
+ semicolon));
+ }
- var initializers = <ConstructorInitializer>[];
- for (Object initializerObject in initializerObjects) {
- if (initializerObject is FunctionExpressionInvocation) {
- Expression function = initializerObject.function;
- if (function is SuperExpression) {
- initializers.add(ast.superConstructorInvocation(function.superKeyword,
- null, null, initializerObject.argumentList));
- } else {
+ @override
+ void endEnum(Token enumKeyword, Token endBrace, int count) {
+ debugEvent("Enum");
+ List<EnumConstantDeclaration> constants = popList(count);
+ // TODO(paulberry,ahe): the parser should pass in the openBrace token.
+ var openBrace = enumKeyword.next.next as analyzer.BeginToken;
+ // TODO(paulberry): what if the '}' is missing and the parser has performed
+ // error recovery?
+ Token closeBrace = openBrace.endGroup;
+ SimpleIdentifier name = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ declarations.add(ast.enumDeclaration(comment, metadata, enumKeyword, name,
+ openBrace, constants, closeBrace));
+ }
+
+ void endExport(Token exportKeyword, Token semicolon) {
+ debugEvent("Export");
+ List<Combinator> combinators = pop();
+ List<Configuration> configurations = pop();
+ StringLiteral uri = pop();
+ List<Annotation> metadata = pop();
+ assert(metadata == null);
+ Comment comment = pop();
+ directives.add(ast.exportDirective(comment, metadata, exportKeyword, uri,
+ configurations, combinators, semicolon));
+ }
+
+ void endExpressionStatement(Token token) {
+ debugEvent("ExpressionStatement");
+ push(ast.expressionStatement(pop(), token));
+ }
+
+ @override
+ void endFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token semicolon) {
+ debugEvent("FactoryMethod");
+
+ FunctionBody body;
+ Token separator;
+ ConstructorName redirectedConstructor;
+ Object bodyObject = pop();
+ if (bodyObject is FunctionBody) {
+ body = bodyObject;
+ } else if (bodyObject is _RedirectingFactoryBody) {
+ separator = bodyObject.equalToken;
+ redirectedConstructor = bodyObject.constructorName;
+ body = ast.emptyFunctionBody(semicolon);
+ } else {
+ unhandled("${bodyObject.runtimeType}", "bodyObject",
+ beginToken.charOffset, uri);
+ }
+
+ FormalParameterList parameters = pop();
+ ConstructorName constructorName = pop();
+ _Modifiers modifiers = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+
+ // Decompose the preliminary ConstructorName into the type name and
+ // the actual constructor name.
+ SimpleIdentifier returnType;
+ Token period;
+ SimpleIdentifier name;
+ Identifier typeName = constructorName.type.name;
+ if (typeName is SimpleIdentifier) {
+ returnType = typeName;
+ } else if (typeName is PrefixedIdentifier) {
+ returnType = typeName.prefix;
+ period = typeName.period;
+ name =
+ ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
+ }
+
+ push(ast.constructorDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.finalConstOrVarKeyword,
+ factoryKeyword,
+ ast.simpleIdentifier(returnType.token),
+ period,
+ name,
+ parameters,
+ separator,
+ null,
+ redirectedConstructor,
+ body));
+ }
+
+ void endFieldInitializer(Token assignment, Token token) {
+ debugEvent("FieldInitializer");
+ Expression initializer = pop();
+ SimpleIdentifier name = pop();
+ push(ast.variableDeclaration(name, assignment, initializer));
+ }
+
+ @override
+ void endFields(int count, Token beginToken, Token endToken) {
+ debugEvent("Fields");
+ List<VariableDeclaration> variables = popList(count);
+ TypeAnnotation type = pop();
+ _Modifiers modifiers = pop();
+ var variableList = ast.variableDeclarationList(
+ null, null, modifiers?.finalConstOrVarKeyword, type, variables);
+ Token covariantKeyword = modifiers?.covariantKeyword;
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ push(ast.fieldDeclaration2(
+ comment: comment,
+ metadata: metadata,
+ covariantKeyword: covariantKeyword,
+ staticKeyword: modifiers?.staticKeyword,
+ fieldList: variableList,
+ semicolon: endToken));
+ }
+
+ @override
+ void endForIn(Token awaitToken, Token forToken, Token leftParenthesis,
+ Token inKeyword, Token rightParenthesis, Token endToken) {
+ debugEvent("ForInExpression");
+ Statement body = pop();
+ Expression iterator = pop();
+ Object variableOrDeclaration = pop();
+ exitLocalScope();
+ exitContinueTarget();
+ exitBreakTarget();
+ if (variableOrDeclaration is SimpleIdentifier) {
+ push(ast.forEachStatementWithReference(
+ awaitToken,
+ forToken,
+ leftParenthesis,
+ variableOrDeclaration,
+ inKeyword,
+ iterator,
+ rightParenthesis,
+ body));
+ } else {
+ var statement = variableOrDeclaration as VariableDeclarationStatement;
+ VariableDeclarationList variableList = statement.variables;
+ push(ast.forEachStatementWithDeclaration(
+ awaitToken,
+ forToken,
+ leftParenthesis,
+ ast.declaredIdentifier(
+ variableList.documentationComment,
+ variableList.metadata,
+ variableList.keyword,
+ variableList.type,
+ variableList.variables.single.name),
+ inKeyword,
+ iterator,
+ rightParenthesis,
+ body));
+ }
+ }
+
+ @override
+ void endForInExpression(Token token) {
+ debugEvent("ForInExpression");
+ }
+
+ void endFormalParameter(Token thisKeyword, Token nameToken,
+ FormalParameterKind kind, MemberKind memberKind) {
+ debugEvent("FormalParameter");
+ _ParameterDefaultValue defaultValue = pop();
+
+ SimpleIdentifier name = pop();
+
+ AstNode typeOrFunctionTypedParameter = pop();
+
+ _Modifiers modifiers = pop();
+ Token keyword = modifiers?.finalConstOrVarKeyword;
+ Token covariantKeyword = modifiers?.covariantKeyword;
+ pop(); // TODO(paulberry): Metadata.
+ Comment comment = pop();
+
+ FormalParameter node;
+ if (typeOrFunctionTypedParameter is FunctionTypedFormalParameter) {
+ // This is a temporary AST node that was constructed in
+ // [endFunctionTypedFormalParameter]. We now deconstruct it and create
+ // the final AST node.
+ if (thisKeyword == null) {
+ node = ast.functionTypedFormalParameter2(
+ identifier: name,
+ comment: comment,
+ covariantKeyword: covariantKeyword,
+ returnType: typeOrFunctionTypedParameter.returnType,
+ typeParameters: typeOrFunctionTypedParameter.typeParameters,
+ parameters: typeOrFunctionTypedParameter.parameters);
+ } else {
+ node = ast.fieldFormalParameter2(
+ identifier: name,
+ comment: comment,
+ covariantKeyword: covariantKeyword,
+ type: typeOrFunctionTypedParameter.returnType,
+ thisKeyword: thisKeyword,
+ period: thisKeyword.next,
+ typeParameters: typeOrFunctionTypedParameter.typeParameters,
+ parameters: typeOrFunctionTypedParameter.parameters);
+ }
+ } else {
+ TypeAnnotation type = typeOrFunctionTypedParameter;
+ if (thisKeyword == null) {
+ node = ast.simpleFormalParameter2(
+ comment: comment,
+ covariantKeyword: covariantKeyword,
+ keyword: keyword,
+ type: type,
+ identifier: name);
+ } else {
+ node = ast.fieldFormalParameter2(
+ comment: comment,
+ covariantKeyword: covariantKeyword,
+ keyword: keyword,
+ type: type,
+ thisKeyword: thisKeyword,
+ period: thisKeyword.next,
+ identifier: name);
+ }
+ }
+
+ ParameterKind analyzerKind = _toAnalyzerParameterKind(kind);
+ if (analyzerKind != ParameterKind.REQUIRED) {
+ node = ast.defaultFormalParameter(
+ node, analyzerKind, defaultValue?.separator, defaultValue?.value);
+ }
+ push(node);
+ }
+
+ void endFormalParameters(
+ int count, Token beginToken, Token endToken, MemberKind kind) {
+ debugEvent("FormalParameters");
+ List rawParameters = popList(count) ?? const <Object>[];
+ List<FormalParameter> parameters = <FormalParameter>[];
+ Token leftDelimiter;
+ Token rightDelimiter;
+ for (Object raw in rawParameters) {
+ if (raw is _OptionalFormalParameters) {
+ parameters.addAll(raw.parameters);
+ leftDelimiter = raw.leftDelimiter;
+ rightDelimiter = raw.rightDelimiter;
+ } else {
+ parameters.add(raw as FormalParameter);
+ }
+ }
+ push(ast.formalParameterList(
+ beginToken, parameters, leftDelimiter, rightDelimiter, endToken));
+ }
+
+ void endForStatement(Token forKeyword, Token leftSeparator,
+ int updateExpressionCount, Token endToken) {
+ debugEvent("ForStatement");
+ Statement body = pop();
+ List<Expression> updates = popList(updateExpressionCount);
+ Statement conditionStatement = pop();
+ Object initializerPart = pop();
+ exitLocalScope();
+ exitContinueTarget();
+ exitBreakTarget();
+ analyzer.BeginToken leftParenthesis = forKeyword.next;
+
+ VariableDeclarationList variableList;
+ Expression initializer;
+ if (initializerPart is VariableDeclarationStatement) {
+ variableList = initializerPart.variables;
+ } else {
+ initializer = initializerPart as Expression;
+ }
+
+ Expression condition;
+ Token rightSeparator;
+ if (conditionStatement is ExpressionStatement) {
+ condition = conditionStatement.expression;
+ rightSeparator = conditionStatement.semicolon;
+ } else {
+ rightSeparator = (conditionStatement as EmptyStatement).semicolon;
+ }
+
+ push(ast.forStatement(
+ forKeyword,
+ leftParenthesis,
+ variableList,
+ initializer,
+ leftSeparator,
+ condition,
+ rightSeparator,
+ updates,
+ leftParenthesis.endGroup,
+ body));
+ }
+
+ @override
+ void endFunctionExpression(Token beginToken, Token token) {
+ // TODO(paulberry): set up scopes properly to resolve parameters and type
+ // variables. Note that this is tricky due to the handling of initializers
+ // in constructors, so the logic should be shared with BodyBuilder as much
+ // as possible.
+ debugEvent("FunctionExpression");
+ FunctionBody body = pop();
+ FormalParameterList parameters = pop();
+ TypeParameterList typeParameters = pop();
+ push(ast.functionExpression(typeParameters, parameters, body));
+ }
+
+ @override
+ void endFunctionName(Token beginToken, Token token) {
+ debugEvent("FunctionName");
+ }
+
+ @override
+ void endFunctionType(Token functionToken, Token semicolon) {
+ debugEvent("FunctionType");
+ FormalParameterList parameters = pop();
+ TypeAnnotation returnType = pop();
+ TypeParameterList typeParameters = pop();
+ push(ast.genericFunctionType(
+ returnType, functionToken, typeParameters, parameters));
+ }
+
+ @override
+ void endFunctionTypeAlias(
+ Token typedefKeyword, Token equals, Token endToken) {
+ debugEvent("FunctionTypeAlias");
+ if (equals == null) {
+ FormalParameterList parameters = pop();
+ TypeParameterList typeParameters = pop();
+ SimpleIdentifier name = pop();
+ TypeAnnotation returnType = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ declarations.add(ast.functionTypeAlias(comment, metadata, typedefKeyword,
+ returnType, name, typeParameters, parameters, endToken));
+ } else {
+ TypeAnnotation type = pop();
+ TypeParameterList templateParameters = pop();
+ SimpleIdentifier name = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ if (type is! GenericFunctionType) {
+ // TODO(paulberry) Generate an error and recover (better than
+ // this).
+ type = null;
+ }
+ declarations.add(ast.genericTypeAlias(comment, metadata, typedefKeyword,
+ name, templateParameters, equals, type, endToken));
+ }
+ }
+
+ @override
+ void endFunctionTypedFormalParameter() {
+ debugEvent("FunctionTypedFormalParameter");
+
+ FormalParameterList formalParameters = pop();
+ TypeAnnotation returnType = pop();
+ TypeParameterList typeParameters = pop();
+
+ // Create a temporary formal parameter that will be dissected later in
+ // [endFormalParameter].
+ push(ast.functionTypedFormalParameter2(
+ identifier: null,
+ returnType: returnType,
+ typeParameters: typeParameters,
+ parameters: formalParameters));
+ }
+
+ @override
+ void endHide(Token hideKeyword) {
+ debugEvent("Hide");
+ List<SimpleIdentifier> hiddenNames = pop();
+ push(ast.hideCombinator(hideKeyword, hiddenNames));
+ }
+
+ @override
+ void endIdentifierList(int count) {
+ debugEvent("IdentifierList");
+ push(popList(count) ?? NullValue.IdentifierList);
+ }
+
+ void endIfStatement(Token ifToken, Token elseToken) {
+ Statement elsePart = popIfNotNull(elseToken);
+ Statement thenPart = pop();
+ Expression condition = pop();
+ analyzer.BeginToken leftParenthesis = ifToken.next;
+ push(ast.ifStatement(ifToken, ifToken.next, condition,
+ leftParenthesis.endGroup, thenPart, elseToken, elsePart));
+ }
+
+ void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+ Token semicolon) {
+ debugEvent("Import");
+ List<Combinator> combinators = pop();
+ SimpleIdentifier prefix;
+ if (asKeyword != null) prefix = pop();
+ List<Configuration> configurations = pop();
+ StringLiteral uri = pop();
+ List<Annotation> metadata = pop();
+ assert(metadata == null); // TODO(paulberry): fix.
+ Comment comment = pop();
+ directives.add(ast.importDirective(
+ comment,
+ metadata,
+ importKeyword,
+ uri,
+ configurations,
+ deferredKeyword,
+ asKeyword,
+ prefix,
+ combinators,
+ semicolon));
+ }
+
+ void endInitializedIdentifier(Token nameToken) {
+ debugEvent("InitializedIdentifier");
+ AstNode node = pop();
+ VariableDeclaration variable;
+ // TODO(paulberry): This seems kludgy. It would be preferable if we
+ // could respond to a "handleNoVariableInitializer" event by converting a
+ // SimpleIdentifier into a VariableDeclaration, and then when this code was
+ // reached, node would always be a VariableDeclaration.
+ if (node is VariableDeclaration) {
+ variable = node;
+ } else if (node is SimpleIdentifier) {
+ variable = ast.variableDeclaration(node, null, null);
+ } else {
+ unhandled("${node.runtimeType}", "identifier", nameToken.charOffset, uri);
+ }
+ push(variable);
+ }
+
+ void endInitializers(int count, Token beginToken, Token endToken) {
+ debugEvent("Initializers");
+ List<Object> initializerObjects = popList(count) ?? const [];
+ if (!isFullAst) return;
+
+ push(beginToken);
+
+ var initializers = <ConstructorInitializer>[];
+ for (Object initializerObject in initializerObjects) {
+ if (initializerObject is FunctionExpressionInvocation) {
+ Expression function = initializerObject.function;
+ if (function is SuperExpression) {
+ initializers.add(ast.superConstructorInvocation(function.superKeyword,
+ null, null, initializerObject.argumentList));
+ } else {
initializers.add(ast.redirectingConstructorInvocation(
(function as ThisExpression).thisKeyword,
null,
@@ -464,255 +910,264 @@ class AstBuilder extends ScopeListener {
}
}
- push(initializers);
- }
-
- void endVariableInitializer(Token assignmentOperator) {
- debugEvent("VariableInitializer");
- assert(assignmentOperator.stringValue == "=");
- Expression initializer = pop();
- Identifier identifier = pop();
- // TODO(ahe): Don't push initializers, instead install them.
- push(ast.variableDeclaration(identifier, assignmentOperator, initializer));
- }
-
- @override
- void endWhileStatement(Token whileKeyword, Token endToken) {
- debugEvent("WhileStatement");
- Statement body = pop();
- ParenthesizedExpression condition = pop();
- exitContinueTarget();
- exitBreakTarget();
- push(ast.whileStatement(whileKeyword, condition.leftParenthesis,
- condition.expression, condition.rightParenthesis, body));
- }
-
- @override
- void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
- debugEvent("YieldStatement");
- assert(endToken.lexeme == ';');
- Expression expression = pop();
- push(ast.yieldStatement(yieldToken, starToken, expression, endToken));
- }
-
- @override
- void handleNoVariableInitializer(Token token) {
- debugEvent("NoVariableInitializer");
- }
-
- void endInitializedIdentifier(Token nameToken) {
- debugEvent("InitializedIdentifier");
- AstNode node = pop();
- VariableDeclaration variable;
- // TODO(paulberry): This seems kludgy. It would be preferable if we
- // could respond to a "handleNoVariableInitializer" event by converting a
- // SimpleIdentifier into a VariableDeclaration, and then when this code was
- // reached, node would always be a VariableDeclaration.
- if (node is VariableDeclaration) {
- variable = node;
- } else if (node is SimpleIdentifier) {
- variable = ast.variableDeclaration(node, null, null);
- } else {
- unhandled("${node.runtimeType}", "identifier", nameToken.charOffset, uri);
- }
- push(variable);
- }
-
- void endVariablesDeclaration(int count, Token endToken) {
- debugEvent("VariablesDeclaration");
- List<VariableDeclaration> variables = popList(count);
- TypeAnnotation type = pop();
- _Modifiers modifiers = pop();
- Token keyword = modifiers?.finalConstOrVarKeyword;
- List<Annotation> metadata = pop();
- Comment comment = pop();
- push(ast.variableDeclarationStatement(
- ast.variableDeclarationList(
- comment, metadata, keyword, type, variables),
- endToken));
- }
-
- void handleAssignmentExpression(Token token) {
- debugEvent("AssignmentExpression");
- Expression rhs = pop();
- Expression lhs = pop();
- push(ast.assignmentExpression(lhs, token, rhs));
- }
-
- void endBlock(int count, Token beginToken, Token endToken) {
- debugEvent("Block");
- List<Statement> statements = popList(count) ?? <Statement>[];
- exitLocalScope();
- push(ast.block(beginToken, statements, endToken));
- }
-
- void endForStatement(Token forKeyword, Token leftSeparator,
- int updateExpressionCount, Token endToken) {
- debugEvent("ForStatement");
- Statement body = pop();
- List<Expression> updates = popList(updateExpressionCount);
- Statement conditionStatement = pop();
- Object initializerPart = pop();
- exitLocalScope();
- exitContinueTarget();
- exitBreakTarget();
- analyzer.BeginToken leftParenthesis = forKeyword.next;
-
- VariableDeclarationList variableList;
- Expression initializer;
- if (initializerPart is VariableDeclarationStatement) {
- variableList = initializerPart.variables;
- } else {
- initializer = initializerPart as Expression;
- }
-
- Expression condition;
- Token rightSeparator;
- if (conditionStatement is ExpressionStatement) {
- condition = conditionStatement.expression;
- rightSeparator = conditionStatement.semicolon;
- } else {
- rightSeparator = (conditionStatement as EmptyStatement).semicolon;
- }
+ push(initializers);
+ }
- push(ast.forStatement(
- forKeyword,
- leftParenthesis,
- variableList,
- initializer,
- leftSeparator,
- condition,
- rightSeparator,
- updates,
- leftParenthesis.endGroup,
- body));
+ @override
+ void endLabeledStatement(int labelCount) {
+ debugEvent("LabeledStatement");
+ Statement statement = pop();
+ List<Label> labels = popList(labelCount);
+ push(ast.labeledStatement(labels, statement));
}
- void handleLiteralList(
- int count, Token beginToken, Token constKeyword, Token endToken) {
- debugEvent("LiteralList");
- List<Expression> expressions = popList(count);
- TypeArgumentList typeArguments = pop();
- push(ast.listLiteral(
- constKeyword, typeArguments, beginToken, expressions, endToken));
+ @override
+ void endLibraryName(Token libraryKeyword, Token semicolon) {
+ debugEvent("LibraryName");
+ List<SimpleIdentifier> libraryName = pop();
+ var name = ast.libraryIdentifier(libraryName);
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ directives.add(ast.libraryDirective(
+ comment, metadata, libraryKeyword, name, semicolon));
}
- void handleAsyncModifier(Token asyncToken, Token starToken) {
- debugEvent("AsyncModifier");
- push(asyncToken ?? NullValue.FunctionBodyAsyncToken);
- push(starToken ?? NullValue.FunctionBodyStarToken);
+ void endLiteralMapEntry(Token colon, Token endToken) {
+ debugEvent("LiteralMapEntry");
+ Expression value = pop();
+ Expression key = pop();
+ push(ast.mapLiteralEntry(key, colon, value));
}
- void endAwaitExpression(Token beginToken, Token endToken) {
- debugEvent("AwaitExpression");
- push(ast.awaitExpression(beginToken, pop()));
+ void endLiteralString(int interpolationCount, Token endToken) {
+ debugEvent("endLiteralString");
+ if (interpolationCount == 0) {
+ Token token = pop();
+ String value = unescapeString(token.lexeme);
+ push(ast.simpleStringLiteral(token, value));
+ } else {
+ List parts = popList(1 + interpolationCount * 2);
+ Token first = parts.first;
+ Token last = parts.last;
+ Quote quote = analyzeQuote(first.lexeme);
+ List<InterpolationElement> elements = <InterpolationElement>[];
+ elements.add(ast.interpolationString(
+ first, unescapeFirstStringPart(first.lexeme, quote)));
+ for (int i = 1; i < parts.length - 1; i++) {
+ var part = parts[i];
+ if (part is Token) {
+ elements.add(ast.interpolationString(part, part.lexeme));
+ } else if (part is Expression) {
+ elements.add(ast.interpolationExpression(null, part, null));
+ } else {
+ unhandled("${part.runtimeType}", "string interpolation",
+ first.charOffset, uri);
+ }
+ }
+ elements.add(ast.interpolationString(
+ last, unescapeLastStringPart(last.lexeme, quote)));
+ push(ast.stringInterpolation(elements));
+ }
}
- void handleLiteralBool(Token token) {
- debugEvent("LiteralBool");
- bool value = identical(token.stringValue, "true");
- assert(value || identical(token.stringValue, "false"));
- push(ast.booleanLiteral(token, value));
+ void endLiteralSymbol(Token hashToken, int tokenCount) {
+ debugEvent("LiteralSymbol");
+ List<Token> components = popList(tokenCount);
+ push(ast.symbolLiteral(hashToken, components));
}
- void handleLiteralDouble(Token token) {
- debugEvent("LiteralDouble");
- push(ast.doubleLiteral(token, double.parse(token.lexeme)));
+ @override
+ void endLocalFunctionDeclaration(Token token) {
+ debugEvent("LocalFunctionDeclaration");
+ FunctionBody body = pop();
+ if (isFullAst) {
+ pop(); // constructor initializers
+ pop(); // separator before constructor initializers
+ }
+ FormalParameterList parameters = pop();
+ SimpleIdentifier name = pop();
+ TypeAnnotation returnType = pop();
+ pop(); // modifiers
+ TypeParameterList typeParameters = pop();
+ FunctionExpression functionExpression =
+ ast.functionExpression(typeParameters, parameters, body);
+ push(ast.functionDeclarationStatement(ast.functionDeclaration(
+ null, null, null, returnType, null, name, functionExpression)));
}
- void handleLiteralNull(Token token) {
- debugEvent("LiteralNull");
- push(ast.nullLiteral(token));
+ @override
+ void endMember() {
+ debugEvent("Member");
}
- void handleLiteralMap(
- int count, Token beginToken, Token constKeyword, Token endToken) {
- debugEvent("LiteralMap");
- List<MapLiteralEntry> entries = popList(count) ?? <MapLiteralEntry>[];
- TypeArgumentList typeArguments = pop();
- push(ast.mapLiteral(
- constKeyword, typeArguments, beginToken, entries, endToken));
+ @override
+ void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+ debugEvent("Metadata");
+ MethodInvocation invocation = pop();
+ SimpleIdentifier constructorName = periodBeforeName != null ? pop() : null;
+ pop(); // Type arguments, not allowed.
+ Identifier name = pop();
+ push(ast.annotation(beginToken, name, periodBeforeName, constructorName,
+ invocation?.argumentList));
}
- void endLiteralMapEntry(Token colon, Token endToken) {
- debugEvent("LiteralMapEntry");
- Expression value = pop();
- Expression key = pop();
- push(ast.mapLiteralEntry(key, colon, value));
+ @override
+ void endMetadataStar(int count, bool forParameter) {
+ debugEvent("MetadataStar");
+ push(popList(count) ?? NullValue.Metadata);
}
- void endLiteralSymbol(Token hashToken, int tokenCount) {
- debugEvent("LiteralSymbol");
- List<Token> components = popList(tokenCount);
- push(ast.symbolLiteral(hashToken, components));
+ @override
+ void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+ debugEvent("Method");
+ FunctionBody body = pop();
+ ConstructorName redirectedConstructor = null; // TODO(paulberry)
+ List<ConstructorInitializer> initializers = pop() ?? const [];
+ Token separator = pop();
+ FormalParameterList parameters = pop();
+ TypeParameterList typeParameters = pop();
+ var name = pop();
+ TypeAnnotation returnType = pop();
+ _Modifiers modifiers = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+
+ void constructor(
+ SimpleIdentifier returnType, Token period, SimpleIdentifier name) {
+ push(ast.constructorDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.finalConstOrVarKeyword,
+ null, // TODO(paulberry): factoryKeyword
+ ast.simpleIdentifier(returnType.token),
+ period,
+ name,
+ parameters,
+ separator,
+ initializers,
+ redirectedConstructor,
+ body));
+ }
+
+ void method(Token operatorKeyword, SimpleIdentifier name) {
+ push(ast.methodDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
+ returnType,
+ getOrSet,
+ operatorKeyword,
+ name,
+ typeParameters,
+ parameters,
+ body));
+ }
+
+ if (name is SimpleIdentifier) {
+ if (name.name == className) {
+ constructor(name, null, null);
+ } else {
+ method(null, name);
+ }
+ } else if (name is _OperatorName) {
+ method(name.operatorKeyword, name.name);
+ } else if (name is PrefixedIdentifier) {
+ constructor(name.prefix, name.period, name.identifier);
+ } else {
+ throw new UnimplementedError();
+ }
}
@override
- void handleSuperExpression(Token token, IdentifierContext context) {
- debugEvent("SuperExpression");
- push(ast.superExpression(token));
+ void endMixinApplication(Token withKeyword) {
+ debugEvent("MixinApplication");
+ List<TypeName> mixinTypes = pop();
+ TypeName supertype = pop();
+ push(new _MixinApplication(supertype, withKeyword, mixinTypes));
}
@override
- void handleThisExpression(Token token, IdentifierContext context) {
- debugEvent("ThisExpression");
- push(ast.thisExpression(token));
+ void endNamedFunctionExpression(Token endToken) {
+ logEvent("NamedFunctionExpression");
}
- void handleType(Token beginToken, Token endToken) {
- debugEvent("Type");
- TypeArgumentList arguments = pop();
- Identifier name = pop();
- push(ast.typeName(name, arguments));
+ @override
+ void endNamedMixinApplication(Token beginToken, Token classKeyword,
+ Token equalsToken, Token implementsKeyword, Token endToken) {
+ debugEvent("NamedMixinApplication");
+ ImplementsClause implementsClause;
+ if (implementsKeyword != null) {
+ List<TypeName> interfaces = pop();
+ implementsClause = ast.implementsClause(implementsKeyword, interfaces);
+ }
+ _MixinApplication mixinApplication = pop();
+ var superclass = mixinApplication.supertype;
+ var withClause = ast.withClause(
+ mixinApplication.withKeyword, mixinApplication.mixinTypes);
+ Token equals = equalsToken;
+ TypeParameterList typeParameters = pop();
+ SimpleIdentifier name = pop();
+ _Modifiers modifiers = pop();
+ Token abstractKeyword = modifiers?.abstractKeyword;
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ declarations.add(ast.classTypeAlias(
+ comment,
+ metadata,
+ classKeyword,
+ name,
+ typeParameters,
+ equals,
+ abstractKeyword,
+ superclass,
+ withClause,
+ implementsClause,
+ endToken));
}
@override
- void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
- Token comma, Token rightParenthesis, Token semicolon) {
- debugEvent("Assert");
- Expression message = popIfNotNull(comma);
- Expression condition = pop();
- push(ast.assertStatement(assertKeyword, leftParenthesis, condition, comma,
- message, rightParenthesis, semicolon));
- }
-
- void handleAsOperator(Token operator, Token endToken) {
- debugEvent("AsOperator");
- TypeAnnotation type = pop();
- Expression expression = pop();
- push(ast.asExpression(expression, operator, type));
+ void endNewExpression(Token token) {
+ debugEvent("NewExpression");
+ _handleInstanceCreation(token);
}
@override
- void handleBreakStatement(
- bool hasTarget, Token breakKeyword, Token semicolon) {
- debugEvent("BreakStatement");
- SimpleIdentifier label = hasTarget ? pop() : null;
- push(ast.breakStatement(breakKeyword, label, semicolon));
+ void endOptionalFormalParameters(
+ int count, Token beginToken, Token endToken) {
+ debugEvent("OptionalFormalParameters");
+ push(new _OptionalFormalParameters(popList(count), beginToken, endToken));
}
@override
- void handleContinueStatement(
- bool hasTarget, Token continueKeyword, Token semicolon) {
- debugEvent("ContinueStatement");
- SimpleIdentifier label = hasTarget ? pop() : null;
- push(ast.continueStatement(continueKeyword, label, semicolon));
- }
-
- void handleIsOperator(Token operator, Token not, Token endToken) {
- debugEvent("IsOperator");
- TypeAnnotation type = pop();
- Expression expression = pop();
- push(ast.isExpression(expression, operator, not, type));
+ void endPart(Token partKeyword, Token semicolon) {
+ debugEvent("Part");
+ StringLiteral uri = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ directives
+ .add(ast.partDirective(comment, metadata, partKeyword, uri, semicolon));
}
- void handleConditionalExpression(Token question, Token colon) {
- debugEvent("ConditionalExpression");
- Expression elseExpression = pop();
- Expression thenExpression = pop();
- Expression condition = pop();
- push(ast.conditionalExpression(
- condition, question, thenExpression, colon, elseExpression));
+ @override
+ void endPartOf(Token partKeyword, Token semicolon, bool hasName) {
+ debugEvent("PartOf");
+ var libraryNameOrUri = pop();
+ LibraryIdentifier name;
+ StringLiteral uri;
+ if (libraryNameOrUri is StringLiteral) {
+ uri = libraryNameOrUri;
+ } else {
+ name = ast.libraryIdentifier(libraryNameOrUri);
+ }
+ // TODO(paulberry,ahe): seems hacky. It would be nice if the parser passed
+ // in a reference to the "of" keyword.
+ var ofKeyword = partKeyword.next;
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ directives.add(ast.partOfDirective(
+ comment, metadata, partKeyword, ofKeyword, uri, name, semicolon));
}
@override
@@ -733,187 +1188,18 @@ class AstBuilder extends ScopeListener {
push(ast.expressionStatement(expression, endToken));
}
- void handleThrowExpression(Token throwToken, Token endToken) {
- debugEvent("ThrowExpression");
- push(ast.throwExpression(throwToken, pop()));
- }
-
- @override
- void endOptionalFormalParameters(
- int count, Token beginToken, Token endToken) {
- debugEvent("OptionalFormalParameters");
- push(new _OptionalFormalParameters(popList(count), beginToken, endToken));
- }
-
- void handleValuedFormalParameter(Token equals, Token token) {
- debugEvent("ValuedFormalParameter");
- Expression value = pop();
- push(new _ParameterDefaultValue(equals, value));
- }
-
- @override
- void endFunctionType(Token functionToken, Token semicolon) {
- debugEvent("FunctionType");
- FormalParameterList parameters = pop();
- TypeAnnotation returnType = pop();
- TypeParameterList typeParameters = pop();
- push(ast.genericFunctionType(
- returnType, functionToken, typeParameters, parameters));
- }
-
- void handleFormalParameterWithoutValue(Token token) {
- debugEvent("FormalParameterWithoutValue");
- push(NullValue.ParameterDefaultValue);
- }
-
- @override
- void endForInExpression(Token token) {
- debugEvent("ForInExpression");
- }
-
- @override
- void endForIn(Token awaitToken, Token forToken, Token leftParenthesis,
- Token inKeyword, Token rightParenthesis, Token endToken) {
- debugEvent("ForInExpression");
- Statement body = pop();
- Expression iterator = pop();
- Object variableOrDeclaration = pop();
- exitLocalScope();
- exitContinueTarget();
- exitBreakTarget();
- if (variableOrDeclaration is SimpleIdentifier) {
- push(ast.forEachStatementWithReference(
- awaitToken,
- forToken,
- leftParenthesis,
- variableOrDeclaration,
- inKeyword,
- iterator,
- rightParenthesis,
- body));
- } else {
- var statement = variableOrDeclaration as VariableDeclarationStatement;
- VariableDeclarationList variableList = statement.variables;
- push(ast.forEachStatementWithDeclaration(
- awaitToken,
- forToken,
- leftParenthesis,
- ast.declaredIdentifier(
- variableList.documentationComment,
- variableList.metadata,
- variableList.keyword,
- variableList.type,
- variableList.variables.single.name),
- inKeyword,
- iterator,
- rightParenthesis,
- body));
- }
- }
-
- void endFormalParameter(Token thisKeyword, Token nameToken,
- FormalParameterKind kind, MemberKind memberKind) {
- debugEvent("FormalParameter");
- _ParameterDefaultValue defaultValue = pop();
-
- SimpleIdentifier name = pop();
-
- AstNode typeOrFunctionTypedParameter = pop();
-
- _Modifiers modifiers = pop();
- Token keyword = modifiers?.finalConstOrVarKeyword;
- Token covariantKeyword = modifiers?.covariantKeyword;
- pop(); // TODO(paulberry): Metadata.
- Comment comment = pop();
-
- FormalParameter node;
- if (typeOrFunctionTypedParameter is FunctionTypedFormalParameter) {
- // This is a temporary AST node that was constructed in
- // [endFunctionTypedFormalParameter]. We now deconstruct it and create
- // the final AST node.
- if (thisKeyword == null) {
- node = ast.functionTypedFormalParameter2(
- identifier: name,
- comment: comment,
- covariantKeyword: covariantKeyword,
- returnType: typeOrFunctionTypedParameter.returnType,
- typeParameters: typeOrFunctionTypedParameter.typeParameters,
- parameters: typeOrFunctionTypedParameter.parameters);
- } else {
- node = ast.fieldFormalParameter2(
- identifier: name,
- comment: comment,
- covariantKeyword: covariantKeyword,
- type: typeOrFunctionTypedParameter.returnType,
- thisKeyword: thisKeyword,
- period: thisKeyword.next,
- typeParameters: typeOrFunctionTypedParameter.typeParameters,
- parameters: typeOrFunctionTypedParameter.parameters);
- }
- } else {
- TypeAnnotation type = typeOrFunctionTypedParameter;
- if (thisKeyword == null) {
- node = ast.simpleFormalParameter2(
- comment: comment,
- covariantKeyword: covariantKeyword,
- keyword: keyword,
- type: type,
- identifier: name);
- } else {
- node = ast.fieldFormalParameter2(
- comment: comment,
- covariantKeyword: covariantKeyword,
- keyword: keyword,
- type: type,
- thisKeyword: thisKeyword,
- period: thisKeyword.next,
- identifier: name);
- }
- }
-
- ParameterKind analyzerKind = _toAnalyzerParameterKind(kind);
- if (analyzerKind != ParameterKind.REQUIRED) {
- node = ast.defaultFormalParameter(
- node, analyzerKind, defaultValue?.separator, defaultValue?.value);
- }
- push(node);
+ void endReturnStatement(
+ bool hasExpression, Token beginToken, Token endToken) {
+ debugEvent("ReturnStatement");
+ Expression expression = hasExpression ? pop() : null;
+ push(ast.returnStatement(beginToken, expression, endToken));
}
@override
- void endFunctionTypedFormalParameter() {
- debugEvent("FunctionTypedFormalParameter");
-
- FormalParameterList formalParameters = pop();
- TypeAnnotation returnType = pop();
- TypeParameterList typeParameters = pop();
-
- // Create a temporary formal parameter that will be dissected later in
- // [endFormalParameter].
- push(ast.functionTypedFormalParameter2(
- identifier: null,
- returnType: returnType,
- typeParameters: typeParameters,
- parameters: formalParameters));
- }
-
- void endFormalParameters(
- int count, Token beginToken, Token endToken, MemberKind kind) {
- debugEvent("FormalParameters");
- List rawParameters = popList(count) ?? const <Object>[];
- List<FormalParameter> parameters = <FormalParameter>[];
- Token leftDelimiter;
- Token rightDelimiter;
- for (Object raw in rawParameters) {
- if (raw is _OptionalFormalParameters) {
- parameters.addAll(raw.parameters);
- leftDelimiter = raw.leftDelimiter;
- rightDelimiter = raw.rightDelimiter;
- } else {
- parameters.add(raw as FormalParameter);
- }
- }
- push(ast.formalParameterList(
- beginToken, parameters, leftDelimiter, rightDelimiter, endToken));
+ void endShow(Token showKeyword) {
+ debugEvent("Show");
+ List<SimpleIdentifier> shownNames = pop();
+ push(ast.showCombinator(showKeyword, shownNames));
}
@override
@@ -946,14 +1232,6 @@ class AstBuilder extends ScopeListener {
}
@override
- void handleCaseMatch(Token caseKeyword, Token colon) {
- debugEvent("CaseMatch");
- Expression expression = pop();
- push(ast.switchCase(
- <Label>[], caseKeyword, expression, colon, <Statement>[]));
- }
-
- @override
void endSwitchStatement(Token switchKeyword, Token endToken) {
debugEvent("SwitchStatement");
Token rightBracket = pop();
@@ -970,143 +1248,23 @@ class AstBuilder extends ScopeListener {
rightBracket));
}
- void handleCatchBlock(Token onKeyword, Token catchKeyword) {
- debugEvent("CatchBlock");
- Block body = pop();
- FormalParameterList catchParameterList = popIfNotNull(catchKeyword);
- TypeAnnotation type = popIfNotNull(onKeyword);
- SimpleIdentifier exception;
- SimpleIdentifier stackTrace;
- if (catchParameterList != null) {
- List<FormalParameter> catchParameters = catchParameterList.parameters;
- if (catchParameters.length > 0) {
- exception = catchParameters[0].identifier;
- }
- if (catchParameters.length > 1) {
- stackTrace = catchParameters[1].identifier;
- }
- }
- push(ast.catchClause(
- onKeyword,
- type,
- catchKeyword,
- catchParameterList?.leftParenthesis,
- exception,
- null,
- stackTrace,
- catchParameterList?.rightParenthesis,
- body));
- }
-
- @override
- void handleFinallyBlock(Token finallyKeyword) {
- debugEvent("FinallyBlock");
- // The finally block is popped in "endTryStatement".
- }
-
- void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
- Block finallyBlock = popIfNotNull(finallyKeyword);
- List<CatchClause> catchClauses = popList(catchCount);
- Block body = pop();
- push(ast.tryStatement(
- tryKeyword, body, catchClauses, finallyKeyword, finallyBlock));
- }
-
- @override
- void handleLabel(Token colon) {
- debugEvent("Label");
- SimpleIdentifier name = pop();
- push(ast.label(name, colon));
- }
-
- void handleNoExpression(Token token) {
- debugEvent("NoExpression");
- push(NullValue.Expression);
- }
-
- void handleIndexedExpression(
- Token openSquareBracket, Token closeSquareBracket) {
- debugEvent("IndexedExpression");
- Expression index = pop();
- Expression target = pop();
- if (target == null) {
- CascadeExpression receiver = pop();
- Token token = peek();
- push(receiver);
- IndexExpression expression = ast.indexExpressionForCascade(
- token, openSquareBracket, index, closeSquareBracket);
- assert(expression.isCascaded);
- push(expression);
- } else {
- push(ast.indexExpressionForTarget(
- target, openSquareBracket, index, closeSquareBracket));
- }
- }
-
- @override
- void handleInvalidExpression(Token token) {
- debugEvent("InvalidExpression");
- }
-
- @override
- void handleInvalidFunctionBody(Token token) {
- debugEvent("InvalidFunctionBody");
- }
-
@override
- Token handleUnrecoverableError(Token token, Message message) {
- if (message.code == codeExpectedFunctionBody) {
- if (identical('native', token.stringValue) && parser != null) {
- Token nativeKeyword = token;
- Token semicolon = parser.parseLiteralString(token.next);
- token = parser.expectSemicolon(semicolon);
- StringLiteral name = pop();
- pop(); // star
- pop(); // async
- push(ast.nativeFunctionBody(nativeKeyword, name, semicolon));
- return token;
- }
- } else if (message.code == codeExpectedExpression) {
- String lexeme = token.lexeme;
- if (identical('async', lexeme) || identical('yield', lexeme)) {
- errorReporter?.reportErrorForOffset(
- ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
- token.charOffset,
- token.charCount);
- push(ast.simpleIdentifier(token));
- return token;
- }
- }
- return super.handleUnrecoverableError(token, message);
- }
-
- void handleUnaryPrefixExpression(Token token) {
- debugEvent("UnaryPrefixExpression");
- push(ast.prefixExpression(token, pop()));
- }
-
- void handleUnaryPrefixAssignmentExpression(Token token) {
- debugEvent("UnaryPrefixAssignmentExpression");
- push(ast.prefixExpression(token, pop()));
- }
-
- void handleUnaryPostfixAssignmentExpression(Token token) {
- debugEvent("UnaryPostfixAssignmentExpression");
- push(ast.postfixExpression(pop(), token));
- }
-
- void handleModifier(Token token) {
- debugEvent("Modifier");
- push(token);
+ void endTopLevelDeclaration(Token token) {
+ debugEvent("TopLevelDeclaration");
}
- void handleModifiers(int count) {
- debugEvent("Modifiers");
- if (count == 0) {
- push(NullValue.Modifiers);
- } else {
- push(new _Modifiers(popList(count)));
- }
+ void endTopLevelFields(int count, Token beginToken, Token endToken) {
+ debugEvent("TopLevelFields");
+ List<VariableDeclaration> variables = popList(count);
+ TypeAnnotation type = pop();
+ _Modifiers modifiers = pop();
+ Token keyword = modifiers?.finalConstOrVarKeyword;
+ var variableList =
+ ast.variableDeclarationList(null, null, keyword, type, variables);
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ declarations.add(ast.topLevelVariableDeclaration(
+ comment, metadata, variableList, endToken));
}
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
@@ -1133,695 +1291,565 @@ class AstBuilder extends ScopeListener {
ast.functionExpression(typeParameters, parameters, body)));
}
- @override
- void endTopLevelDeclaration(Token token) {
- debugEvent("TopLevelDeclaration");
+ void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
+ Block finallyBlock = popIfNotNull(finallyKeyword);
+ List<CatchClause> catchClauses = popList(catchCount);
+ Block body = pop();
+ push(ast.tryStatement(
+ tryKeyword, body, catchClauses, finallyKeyword, finallyBlock));
}
@override
- void handleInvalidTopLevelDeclaration(Token endToken) {
- debugEvent("InvalidTopLevelDeclaration");
- pop(); // metadata star
- // TODO(danrubel): consider creating a AST node
- // representing the invalid declaration to better support code completion,
- // quick fixes, etc, rather than discarding the metadata and token
+ void endTypeArguments(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeArguments");
+ List<TypeAnnotation> arguments = popList(count);
+ push(ast.typeArgumentList(beginToken, arguments, endToken));
}
@override
- void beginCompilationUnit(Token token) {
- push(token);
+ void endTypeList(int count) {
+ debugEvent("TypeList");
+ push(popList(count) ?? NullValue.TypeList);
}
@override
- void endCompilationUnit(int count, Token endToken) {
- debugEvent("CompilationUnit");
- Token beginToken = pop();
- checkEmpty(endToken.charOffset);
-
- push(ast.compilationUnit(
- beginToken, scriptTag, directives, declarations, endToken));
- }
-
- void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
- Token semicolon) {
- debugEvent("Import");
- List<Combinator> combinators = pop();
- SimpleIdentifier prefix;
- if (asKeyword != null) prefix = pop();
- List<Configuration> configurations = pop();
- StringLiteral uri = pop();
+ void endTypeVariable(Token token, Token extendsOrSuper) {
+ // TODO(paulberry): set up scopes properly to resolve parameters and type
+ // variables. Note that this is tricky due to the handling of initializers
+ // in constructors, so the logic should be shared with BodyBuilder as much
+ // as possible.
+ debugEvent("TypeVariable");
+ TypeAnnotation bound = pop();
+ SimpleIdentifier name = pop();
List<Annotation> metadata = pop();
- assert(metadata == null); // TODO(paulberry): fix.
Comment comment = pop();
- directives.add(ast.importDirective(
- comment,
- metadata,
- importKeyword,
- uri,
- configurations,
- deferredKeyword,
- asKeyword,
- prefix,
- combinators,
- semicolon));
+ push(ast.typeParameter(comment, metadata, name, extendsOrSuper, bound));
}
- void endExport(Token exportKeyword, Token semicolon) {
- debugEvent("Export");
- List<Combinator> combinators = pop();
- List<Configuration> configurations = pop();
- StringLiteral uri = pop();
- List<Annotation> metadata = pop();
- assert(metadata == null);
- Comment comment = pop();
- directives.add(ast.exportDirective(comment, metadata, exportKeyword, uri,
- configurations, combinators, semicolon));
+ @override
+ void endTypeVariables(int count, Token beginToken, Token endToken) {
+ debugEvent("TypeVariables");
+ List<TypeParameter> typeParameters = popList(count);
+ push(ast.typeParameterList(beginToken, typeParameters, endToken));
}
- @override
- void endDottedName(int count, Token firstIdentifier) {
- debugEvent("DottedName");
- List<SimpleIdentifier> components = popList(count);
- push(ast.dottedName(components));
+ void endVariableInitializer(Token assignmentOperator) {
+ debugEvent("VariableInitializer");
+ assert(assignmentOperator.stringValue == "=");
+ Expression initializer = pop();
+ Identifier identifier = pop();
+ // TODO(ahe): Don't push initializers, instead install them.
+ push(ast.variableDeclaration(identifier, assignmentOperator, initializer));
+ }
+
+ void endVariablesDeclaration(int count, Token endToken) {
+ debugEvent("VariablesDeclaration");
+ List<VariableDeclaration> variables = popList(count);
+ TypeAnnotation type = pop();
+ _Modifiers modifiers = pop();
+ Token keyword = modifiers?.finalConstOrVarKeyword;
+ List<Annotation> metadata = pop();
+ Comment comment = pop();
+ push(ast.variableDeclarationStatement(
+ ast.variableDeclarationList(
+ comment, metadata, keyword, type, variables),
+ endToken));
}
@override
- void endDoWhileStatement(
- Token doKeyword, Token whileKeyword, Token semicolon) {
- debugEvent("DoWhileStatement");
- ParenthesizedExpression condition = pop();
+ void endWhileStatement(Token whileKeyword, Token endToken) {
+ debugEvent("WhileStatement");
Statement body = pop();
+ ParenthesizedExpression condition = pop();
exitContinueTarget();
exitBreakTarget();
- push(ast.doStatement(
- doKeyword,
- body,
- whileKeyword,
- condition.leftParenthesis,
- condition.expression,
- condition.rightParenthesis,
- semicolon));
+ push(ast.whileStatement(whileKeyword, condition.leftParenthesis,
+ condition.expression, condition.rightParenthesis, body));
}
- void endConditionalUri(Token ifKeyword, Token equalitySign) {
- debugEvent("ConditionalUri");
- StringLiteral libraryUri = pop();
- // TODO(paulberry,ahe): the parser should report the right paren token to
- // the listener.
- Token rightParen = null;
- StringLiteral value;
- if (equalitySign != null) {
- value = pop();
- }
- DottedName name = pop();
- // TODO(paulberry,ahe): what if there is no `(` token due to an error in the
- // file being parsed? It seems like we need the parser to do adequate error
- // recovery and then report both the ifKeyword and leftParen tokens to the
- // listener.
- Token leftParen = ifKeyword.next;
- push(ast.configuration(ifKeyword, leftParen, name, equalitySign, value,
- rightParen, libraryUri));
+ @override
+ void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+ debugEvent("YieldStatement");
+ assert(endToken.lexeme == ';');
+ Expression expression = pop();
+ push(ast.yieldStatement(yieldToken, starToken, expression, endToken));
}
@override
- void endConditionalUris(int count) {
- debugEvent("ConditionalUris");
- push(popList(count) ?? NullValue.ConditionalUris);
+ AstNode finishFields() {
+ debugEvent("finishFields");
+ return declarations.removeLast();
}
- @override
- void endIdentifierList(int count) {
- debugEvent("IdentifierList");
- push(popList(count) ?? NullValue.IdentifierList);
+ void finishFunction(annotations, formals, asyncModifier, FunctionBody body) {
+ debugEvent("finishFunction");
+ Statement bodyStatement;
+ if (body is EmptyFunctionBody) {
+ bodyStatement = ast.emptyStatement(body.semicolon);
+ } else if (body is ExpressionFunctionBody) {
+ bodyStatement = ast.returnStatement(null, body.expression, null);
+ } else {
+ bodyStatement = (body as BlockFunctionBody).block;
+ }
+ // TODO(paulberry): what do we need to do with bodyStatement at this point?
+ bodyStatement; // Suppress "unused local variable" hint
}
- @override
- void endShow(Token showKeyword) {
- debugEvent("Show");
- List<SimpleIdentifier> shownNames = pop();
- push(ast.showCombinator(showKeyword, shownNames));
+ void handleAsOperator(Token operator, Token endToken) {
+ debugEvent("AsOperator");
+ TypeAnnotation type = pop();
+ Expression expression = pop();
+ push(ast.asExpression(expression, operator, type));
}
- @override
- void endHide(Token hideKeyword) {
- debugEvent("Hide");
- List<SimpleIdentifier> hiddenNames = pop();
- push(ast.hideCombinator(hideKeyword, hiddenNames));
+ void handleAssignmentExpression(Token token) {
+ debugEvent("AssignmentExpression");
+ Expression rhs = pop();
+ Expression lhs = pop();
+ push(ast.assignmentExpression(lhs, token, rhs));
}
- @override
- void endTypeList(int count) {
- debugEvent("TypeList");
- push(popList(count) ?? NullValue.TypeList);
+ void handleAsyncModifier(Token asyncToken, Token starToken) {
+ debugEvent("AsyncModifier");
+ push(asyncToken ?? NullValue.FunctionBodyAsyncToken);
+ push(starToken ?? NullValue.FunctionBodyStarToken);
}
- @override
- void endClassBody(int memberCount, Token beginToken, Token endToken) {
- debugEvent("ClassBody");
- push(new _ClassBody(
- beginToken, popList(memberCount) ?? <ClassMember>[], endToken));
+ void handleBinaryExpression(Token token) {
+ debugEvent("BinaryExpression");
+ if (identical(".", token.stringValue) ||
+ identical("?.", token.stringValue) ||
+ identical("..", token.stringValue)) {
+ doDotExpression(token);
+ } else {
+ Expression right = pop();
+ Expression left = pop();
+ push(ast.binaryExpression(left, token, right));
+ }
}
@override
- void beginClassDeclaration(Token beginToken, Token name) {
- assert(className == null);
- className = name.lexeme;
+ void handleBreakStatement(
+ bool hasTarget, Token breakKeyword, Token semicolon) {
+ debugEvent("BreakStatement");
+ SimpleIdentifier label = hasTarget ? pop() : null;
+ push(ast.breakStatement(breakKeyword, label, semicolon));
}
@override
- void handleNativeClause(Token nativeToken, bool hasName) {
- push(ast.nativeClause(nativeToken, hasName ? pop() : null));
+ void handleCaseMatch(Token caseKeyword, Token colon) {
+ debugEvent("CaseMatch");
+ Expression expression = pop();
+ push(ast.switchCase(
+ <Label>[], caseKeyword, expression, colon, <Statement>[]));
}
- @override
- void endClassDeclaration(
- int interfacesCount,
- Token beginToken,
- Token classKeyword,
- Token extendsKeyword,
- Token implementsKeyword,
- Token nativeToken,
- Token endToken) {
- debugEvent("ClassDeclaration");
- _ClassBody body = pop();
- NativeClause nativeClause = nativeToken != null ? pop() : null;
- ImplementsClause implementsClause;
- if (implementsKeyword != null) {
- List<TypeName> interfaces = popList(interfacesCount);
- implementsClause = ast.implementsClause(implementsKeyword, interfaces);
- }
- ExtendsClause extendsClause;
- WithClause withClause;
- var supertype = pop();
- if (supertype == null) {
- // No extends clause
- } else if (supertype is TypeName) {
- extendsClause = ast.extendsClause(extendsKeyword, supertype);
- } else if (supertype is _MixinApplication) {
- extendsClause = ast.extendsClause(extendsKeyword, supertype.supertype);
- withClause = ast.withClause(supertype.withKeyword, supertype.mixinTypes);
- } else {
- unhandled("${supertype.runtimeType}", "supertype",
- extendsKeyword.charOffset, uri);
+ void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+ debugEvent("CatchBlock");
+ Block body = pop();
+ FormalParameterList catchParameterList = popIfNotNull(catchKeyword);
+ TypeAnnotation type = popIfNotNull(onKeyword);
+ SimpleIdentifier exception;
+ SimpleIdentifier stackTrace;
+ if (catchParameterList != null) {
+ List<FormalParameter> catchParameters = catchParameterList.parameters;
+ if (catchParameters.length > 0) {
+ exception = catchParameters[0].identifier;
+ }
+ if (catchParameters.length > 1) {
+ stackTrace = catchParameters[1].identifier;
+ }
}
- TypeParameterList typeParameters = pop();
- SimpleIdentifier name = pop();
- assert(className == name.name);
- className = null;
- _Modifiers modifiers = pop();
- Token abstractKeyword = modifiers?.abstractKeyword;
- List<Annotation> metadata = pop();
- Comment comment = pop();
- ClassDeclaration classDeclaration = ast.classDeclaration(
- comment,
- metadata,
- abstractKeyword,
- classKeyword,
- name,
- typeParameters,
- extendsClause,
- withClause,
- implementsClause,
- body.beginToken,
- body.members,
- body.endToken);
- classDeclaration.nativeClause = nativeClause;
- declarations.add(classDeclaration);
+ push(ast.catchClause(
+ onKeyword,
+ type,
+ catchKeyword,
+ catchParameterList?.leftParenthesis,
+ exception,
+ null,
+ stackTrace,
+ catchParameterList?.rightParenthesis,
+ body));
+ }
+
+ void handleConditionalExpression(Token question, Token colon) {
+ debugEvent("ConditionalExpression");
+ Expression elseExpression = pop();
+ Expression thenExpression = pop();
+ Expression condition = pop();
+ push(ast.conditionalExpression(
+ condition, question, thenExpression, colon, elseExpression));
}
@override
- void endMixinApplication(Token withKeyword) {
- debugEvent("MixinApplication");
- List<TypeName> mixinTypes = pop();
- TypeName supertype = pop();
- push(new _MixinApplication(supertype, withKeyword, mixinTypes));
+ void handleContinueStatement(
+ bool hasTarget, Token continueKeyword, Token semicolon) {
+ debugEvent("ContinueStatement");
+ SimpleIdentifier label = hasTarget ? pop() : null;
+ push(ast.continueStatement(continueKeyword, label, semicolon));
}
@override
- void endNamedMixinApplication(Token beginToken, Token classKeyword,
- Token equalsToken, Token implementsKeyword, Token endToken) {
- debugEvent("NamedMixinApplication");
- ImplementsClause implementsClause;
- if (implementsKeyword != null) {
- List<TypeName> interfaces = pop();
- implementsClause = ast.implementsClause(implementsKeyword, interfaces);
- }
- _MixinApplication mixinApplication = pop();
- var superclass = mixinApplication.supertype;
- var withClause = ast.withClause(
- mixinApplication.withKeyword, mixinApplication.mixinTypes);
- Token equals = equalsToken;
- TypeParameterList typeParameters = pop();
- SimpleIdentifier name = pop();
- _Modifiers modifiers = pop();
- Token abstractKeyword = modifiers?.abstractKeyword;
- List<Annotation> metadata = pop();
- Comment comment = pop();
- declarations.add(ast.classTypeAlias(
- comment,
- metadata,
- classKeyword,
- name,
- typeParameters,
- equals,
- abstractKeyword,
- superclass,
- withClause,
- implementsClause,
- endToken));
+ void handleEmptyFunctionBody(Token semicolon) {
+ debugEvent("EmptyFunctionBody");
+ // TODO(scheglov) Change the parser to not produce these modifiers.
+ pop(); // star
+ pop(); // async
+ push(ast.emptyFunctionBody(semicolon));
}
@override
- void endLabeledStatement(int labelCount) {
- debugEvent("LabeledStatement");
- Statement statement = pop();
- List<Label> labels = popList(labelCount);
- push(ast.labeledStatement(labels, statement));
+ void handleEmptyStatement(Token token) {
+ debugEvent("EmptyStatement");
+ push(ast.emptyStatement(token));
}
- @override
- void endLibraryName(Token libraryKeyword, Token semicolon) {
- debugEvent("LibraryName");
- List<SimpleIdentifier> libraryName = pop();
- var name = ast.libraryIdentifier(libraryName);
- List<Annotation> metadata = pop();
- Comment comment = pop();
- directives.add(ast.libraryDirective(
- comment, metadata, libraryKeyword, name, semicolon));
+ void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
+ debugEvent("ExpressionFunctionBody");
+ Expression expression = pop();
+ Token star = pop();
+ Token asyncKeyword = pop();
+ assert(star == null);
+ push(ast.expressionFunctionBody(
+ asyncKeyword, arrowToken, expression, endToken));
}
@override
- void handleQualified(Token period) {
- SimpleIdentifier identifier = pop();
- var prefix = pop();
- if (prefix is List) {
- // We're just accumulating components into a list.
- prefix.add(identifier);
- push(prefix);
- } else if (prefix is SimpleIdentifier) {
- // TODO(paulberry): resolve [identifier]. Note that BodyBuilder handles
- // this situation using SendAccessor.
- push(ast.prefixedIdentifier(prefix, period, identifier));
+ void handleFinallyBlock(Token finallyKeyword) {
+ debugEvent("FinallyBlock");
+ // The finally block is popped in "endTryStatement".
+ }
+
+ void handleFormalParameterWithoutValue(Token token) {
+ debugEvent("FormalParameterWithoutValue");
+ push(NullValue.ParameterDefaultValue);
+ }
+
+ void handleIdentifier(Token token, IdentifierContext context) {
+ debugEvent("handleIdentifier");
+ Token analyzerToken = token;
+
+ if (context.inSymbol) {
+ push(analyzerToken);
+ return;
+ }
+
+ SimpleIdentifier identifier = ast.simpleIdentifier(analyzerToken,
+ isDeclaration: context.inDeclaration);
+ if (context.inLibraryOrPartOfDeclaration) {
+ if (!context.isContinuation) {
+ push([identifier]);
+ } else {
+ push(identifier);
+ }
+ } else if (context == IdentifierContext.enumValueDeclaration) {
+ // TODO(paulberry): analyzer's ASTs allow for enumerated values to have
+ // metadata, but the spec doesn't permit it.
+ List<Annotation> metadata;
+ Comment comment = _toAnalyzerComment(token.precedingComments);
+ push(ast.enumConstantDeclaration(comment, metadata, identifier));
} else {
- // TODO(paulberry): implement.
- logEvent('Qualified with >1 dot');
+ push(identifier);
+ }
+ }
+
+ void handleIndexedExpression(
+ Token openSquareBracket, Token closeSquareBracket) {
+ debugEvent("IndexedExpression");
+ Expression index = pop();
+ Expression target = pop();
+ if (target == null) {
+ CascadeExpression receiver = pop();
+ Token token = peek();
+ push(receiver);
+ IndexExpression expression = ast.indexExpressionForCascade(
+ token, openSquareBracket, index, closeSquareBracket);
+ assert(expression.isCascaded);
+ push(expression);
+ } else {
+ push(ast.indexExpressionForTarget(
+ target, openSquareBracket, index, closeSquareBracket));
}
}
@override
- void endPart(Token partKeyword, Token semicolon) {
- debugEvent("Part");
- StringLiteral uri = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
- directives
- .add(ast.partDirective(comment, metadata, partKeyword, uri, semicolon));
+ void handleInvalidExpression(Token token) {
+ debugEvent("InvalidExpression");
}
@override
- void endPartOf(Token partKeyword, Token semicolon, bool hasName) {
- debugEvent("PartOf");
- var libraryNameOrUri = pop();
- LibraryIdentifier name;
- StringLiteral uri;
- if (libraryNameOrUri is StringLiteral) {
- uri = libraryNameOrUri;
- } else {
- name = ast.libraryIdentifier(libraryNameOrUri);
- }
- // TODO(paulberry,ahe): seems hacky. It would be nice if the parser passed
- // in a reference to the "of" keyword.
- var ofKeyword = partKeyword.next;
- List<Annotation> metadata = pop();
- Comment comment = pop();
- directives.add(ast.partOfDirective(
- comment, metadata, partKeyword, ofKeyword, uri, name, semicolon));
+ void handleInvalidFunctionBody(Token token) {
+ debugEvent("InvalidFunctionBody");
}
@override
- void endFunctionExpression(Token beginToken, Token token) {
- // TODO(paulberry): set up scopes properly to resolve parameters and type
- // variables. Note that this is tricky due to the handling of initializers
- // in constructors, so the logic should be shared with BodyBuilder as much
- // as possible.
- debugEvent("FunctionExpression");
- FunctionBody body = pop();
- FormalParameterList parameters = pop();
- TypeParameterList typeParameters = pop();
- push(ast.functionExpression(typeParameters, parameters, body));
+ void handleInvalidTopLevelDeclaration(Token endToken) {
+ debugEvent("InvalidTopLevelDeclaration");
+ pop(); // metadata star
+ // TODO(danrubel): consider creating a AST node
+ // representing the invalid declaration to better support code completion,
+ // quick fixes, etc, rather than discarding the metadata and token
+ }
+
+ void handleIsOperator(Token operator, Token not, Token endToken) {
+ debugEvent("IsOperator");
+ TypeAnnotation type = pop();
+ Expression expression = pop();
+ push(ast.isExpression(expression, operator, not, type));
}
@override
- void handleNoFieldInitializer(Token token) {
- debugEvent("NoFieldInitializer");
+ void handleLabel(Token colon) {
+ debugEvent("Label");
SimpleIdentifier name = pop();
- push(ast.variableDeclaration(name, null, null));
+ push(ast.label(name, colon));
}
- @override
- void endFactoryMethod(
- Token beginToken, Token factoryKeyword, Token semicolon) {
- debugEvent("FactoryMethod");
+ void handleLiteralBool(Token token) {
+ debugEvent("LiteralBool");
+ bool value = identical(token.stringValue, "true");
+ assert(value || identical(token.stringValue, "false"));
+ push(ast.booleanLiteral(token, value));
+ }
- FunctionBody body;
- Token separator;
- ConstructorName redirectedConstructor;
- Object bodyObject = pop();
- if (bodyObject is FunctionBody) {
- body = bodyObject;
- } else if (bodyObject is _RedirectingFactoryBody) {
- separator = bodyObject.equalToken;
- redirectedConstructor = bodyObject.constructorName;
- body = ast.emptyFunctionBody(semicolon);
- } else {
- unhandled("${bodyObject.runtimeType}", "bodyObject",
- beginToken.charOffset, uri);
- }
+ void handleLiteralDouble(Token token) {
+ debugEvent("LiteralDouble");
+ push(ast.doubleLiteral(token, double.parse(token.lexeme)));
+ }
- FormalParameterList parameters = pop();
- ConstructorName constructorName = pop();
- _Modifiers modifiers = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
+ void handleLiteralInt(Token token) {
+ debugEvent("LiteralInt");
+ push(ast.integerLiteral(token, int.parse(token.lexeme)));
+ }
- // Decompose the preliminary ConstructorName into the type name and
- // the actual constructor name.
- SimpleIdentifier returnType;
- Token period;
- SimpleIdentifier name;
- Identifier typeName = constructorName.type.name;
- if (typeName is SimpleIdentifier) {
- returnType = typeName;
- } else if (typeName is PrefixedIdentifier) {
- returnType = typeName.prefix;
- period = typeName.period;
- name =
- ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
- }
+ void handleLiteralList(
+ int count, Token beginToken, Token constKeyword, Token endToken) {
+ debugEvent("LiteralList");
+ List<Expression> expressions = popList(count);
+ TypeArgumentList typeArguments = pop();
+ push(ast.listLiteral(
+ constKeyword, typeArguments, beginToken, expressions, endToken));
+ }
- push(ast.constructorDeclaration(
- comment,
- metadata,
- modifiers?.externalKeyword,
- modifiers?.finalConstOrVarKeyword,
- factoryKeyword,
- ast.simpleIdentifier(returnType.token),
- period,
- name,
- parameters,
- separator,
- null,
- redirectedConstructor,
- body));
+ void handleLiteralMap(
+ int count, Token beginToken, Token constKeyword, Token endToken) {
+ debugEvent("LiteralMap");
+ List<MapLiteralEntry> entries = popList(count) ?? <MapLiteralEntry>[];
+ TypeArgumentList typeArguments = pop();
+ push(ast.mapLiteral(
+ constKeyword, typeArguments, beginToken, entries, endToken));
}
- void endFieldInitializer(Token assignment, Token token) {
- debugEvent("FieldInitializer");
- Expression initializer = pop();
- SimpleIdentifier name = pop();
- push(ast.variableDeclaration(name, assignment, initializer));
+ void handleLiteralNull(Token token) {
+ debugEvent("LiteralNull");
+ push(ast.nullLiteral(token));
+ }
+
+ void handleModifier(Token token) {
+ debugEvent("Modifier");
+ push(token);
+ }
+
+ void handleModifiers(int count) {
+ debugEvent("Modifiers");
+ if (count == 0) {
+ push(NullValue.Modifiers);
+ } else {
+ push(new _Modifiers(popList(count)));
+ }
}
- @override
- void endNamedFunctionExpression(Token endToken) {
- logEvent("NamedFunctionExpression");
+ void handleNamedArgument(Token colon) {
+ debugEvent("NamedArgument");
+ Expression expression = pop();
+ SimpleIdentifier name = pop();
+ push(ast.namedExpression(ast.label(name, colon), expression));
}
@override
- void endLocalFunctionDeclaration(Token token) {
- debugEvent("LocalFunctionDeclaration");
- FunctionBody body = pop();
- if (isFullAst) {
- pop(); // constructor initializers
- pop(); // separator before constructor initializers
- }
- FormalParameterList parameters = pop();
- SimpleIdentifier name = pop();
- TypeAnnotation returnType = pop();
- pop(); // modifiers
- TypeParameterList typeParameters = pop();
- FunctionExpression functionExpression =
- ast.functionExpression(typeParameters, parameters, body);
- push(ast.functionDeclarationStatement(ast.functionDeclaration(
- null, null, null, returnType, null, name, functionExpression)));
+ void handleNativeClause(Token nativeToken, bool hasName) {
+ push(ast.nativeClause(nativeToken, hasName ? pop() : null));
}
@override
- void endFunctionName(Token beginToken, Token token) {
- debugEvent("FunctionName");
+ void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
+ debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
+ push(NullValue.ConstructorReferenceContinuationAfterTypeArguments);
}
- void endTopLevelFields(int count, Token beginToken, Token endToken) {
- debugEvent("TopLevelFields");
- List<VariableDeclaration> variables = popList(count);
- TypeAnnotation type = pop();
- _Modifiers modifiers = pop();
- Token keyword = modifiers?.finalConstOrVarKeyword;
- var variableList =
- ast.variableDeclarationList(null, null, keyword, type, variables);
- List<Annotation> metadata = pop();
- Comment comment = pop();
- declarations.add(ast.topLevelVariableDeclaration(
- comment, metadata, variableList, endToken));
+ void handleNoExpression(Token token) {
+ debugEvent("NoExpression");
+ push(NullValue.Expression);
}
@override
- void endTypeVariable(Token token, Token extendsOrSuper) {
- // TODO(paulberry): set up scopes properly to resolve parameters and type
- // variables. Note that this is tricky due to the handling of initializers
- // in constructors, so the logic should be shared with BodyBuilder as much
- // as possible.
- debugEvent("TypeVariable");
- TypeAnnotation bound = pop();
+ void handleNoFieldInitializer(Token token) {
+ debugEvent("NoFieldInitializer");
SimpleIdentifier name = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
- push(ast.typeParameter(comment, metadata, name, extendsOrSuper, bound));
+ push(ast.variableDeclaration(name, null, null));
}
- @override
- void endTypeVariables(int count, Token beginToken, Token endToken) {
- debugEvent("TypeVariables");
- List<TypeParameter> typeParameters = popList(count);
- push(ast.typeParameterList(beginToken, typeParameters, endToken));
+ void handleNoInitializers() {
+ debugEvent("NoInitializers");
+ if (!isFullAst) return;
+ push(NullValue.ConstructorInitializerSeparator);
+ push(NullValue.ConstructorInitializers);
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token endToken) {
- debugEvent("Method");
- FunctionBody body = pop();
- ConstructorName redirectedConstructor = null; // TODO(paulberry)
- List<ConstructorInitializer> initializers = pop() ?? const [];
- Token separator = pop();
- FormalParameterList parameters = pop();
- TypeParameterList typeParameters = pop();
- var name = pop();
- TypeAnnotation returnType = pop();
- _Modifiers modifiers = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
-
- void constructor(
- SimpleIdentifier returnType, Token period, SimpleIdentifier name) {
- push(ast.constructorDeclaration(
- comment,
- metadata,
- modifiers?.externalKeyword,
- modifiers?.finalConstOrVarKeyword,
- null, // TODO(paulberry): factoryKeyword
- ast.simpleIdentifier(returnType.token),
- period,
- name,
- parameters,
- separator,
- initializers,
- redirectedConstructor,
- body));
- }
-
- void method(Token operatorKeyword, SimpleIdentifier name) {
- push(ast.methodDeclaration(
- comment,
- metadata,
- modifiers?.externalKeyword,
- modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
- returnType,
- getOrSet,
- operatorKeyword,
- name,
- typeParameters,
- parameters,
- body));
- }
+ void handleNoVariableInitializer(Token token) {
+ debugEvent("NoVariableInitializer");
+ }
- if (name is SimpleIdentifier) {
- if (name.name == className) {
- constructor(name, null, null);
- } else {
- method(null, name);
- }
- } else if (name is _OperatorName) {
- method(name.operatorKeyword, name.name);
- } else if (name is PrefixedIdentifier) {
- constructor(name.prefix, name.period, name.identifier);
- } else {
- throw new UnimplementedError();
- }
+ void handleOperator(Token token) {
+ debugEvent("Operator");
+ push(token);
}
@override
- void endMember() {
- debugEvent("Member");
+ void handleOperatorName(Token operatorKeyword, Token token) {
+ debugEvent("OperatorName");
+ push(new _OperatorName(
+ operatorKeyword, ast.simpleIdentifier(token, isDeclaration: true)));
}
@override
- void handleVoidKeyword(Token token) {
- debugEvent("VoidKeyword");
- // TODO(paulberry): is this sufficient, or do we need to hook the "void"
- // keyword up to an element?
- handleIdentifier(token, IdentifierContext.typeReference);
- handleNoTypeArguments(token);
- handleType(token, token);
+ void handleParenthesizedExpression(Token token) {
+ debugEvent("ParenthesizedExpression");
+ Expression expression = pop();
+ push(ast.parenthesizedExpression(
+ token, expression, closeBraceTokenFor(token)));
}
@override
- void endFunctionTypeAlias(
- Token typedefKeyword, Token equals, Token endToken) {
- debugEvent("FunctionTypeAlias");
- if (equals == null) {
- FormalParameterList parameters = pop();
- TypeParameterList typeParameters = pop();
- SimpleIdentifier name = pop();
- TypeAnnotation returnType = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
- declarations.add(ast.functionTypeAlias(comment, metadata, typedefKeyword,
- returnType, name, typeParameters, parameters, endToken));
+ void handleQualified(Token period) {
+ SimpleIdentifier identifier = pop();
+ var prefix = pop();
+ if (prefix is List) {
+ // We're just accumulating components into a list.
+ prefix.add(identifier);
+ push(prefix);
+ } else if (prefix is SimpleIdentifier) {
+ // TODO(paulberry): resolve [identifier]. Note that BodyBuilder handles
+ // this situation using SendAccessor.
+ push(ast.prefixedIdentifier(prefix, period, identifier));
} else {
- TypeAnnotation type = pop();
- TypeParameterList templateParameters = pop();
- SimpleIdentifier name = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
- if (type is! GenericFunctionType) {
- // TODO(paulberry) Generate an error and recover (better than
- // this).
- type = null;
- }
- declarations.add(ast.genericTypeAlias(comment, metadata, typedefKeyword,
- name, templateParameters, equals, type, endToken));
+ // TODO(paulberry): implement.
+ logEvent('Qualified with >1 dot');
}
}
- @override
- void endEnum(Token enumKeyword, Token endBrace, int count) {
- debugEvent("Enum");
- List<EnumConstantDeclaration> constants = popList(count);
- // TODO(paulberry,ahe): the parser should pass in the openBrace token.
- var openBrace = enumKeyword.next.next as analyzer.BeginToken;
- // TODO(paulberry): what if the '}' is missing and the parser has performed
- // error recovery?
- Token closeBrace = openBrace.endGroup;
- SimpleIdentifier name = pop();
- List<Annotation> metadata = pop();
- Comment comment = pop();
- declarations.add(ast.enumDeclaration(comment, metadata, enumKeyword, name,
- openBrace, constants, closeBrace));
+ void handleScript(Token token) {
+ debugEvent("Script");
+ scriptTag = ast.scriptTag(token);
}
- @override
- void endTypeArguments(int count, Token beginToken, Token endToken) {
- debugEvent("TypeArguments");
- List<TypeAnnotation> arguments = popList(count);
- push(ast.typeArgumentList(beginToken, arguments, endToken));
+ void handleSend(Token beginToken, Token endToken) {
+ debugEvent("Send");
+ MethodInvocation arguments = pop();
+ TypeArgumentList typeArguments = pop();
+ if (arguments != null) {
+ doInvocation(endToken, typeArguments, arguments);
+ } else {
+ doPropertyGet(endToken);
+ }
}
- @override
- void endFields(int count, Token beginToken, Token endToken) {
- debugEvent("Fields");
- List<VariableDeclaration> variables = popList(count);
- TypeAnnotation type = pop();
- _Modifiers modifiers = pop();
- var variableList = ast.variableDeclarationList(
- null, null, modifiers?.finalConstOrVarKeyword, type, variables);
- Token covariantKeyword = modifiers?.covariantKeyword;
- List<Annotation> metadata = pop();
- Comment comment = pop();
- push(ast.fieldDeclaration2(
- comment: comment,
- metadata: metadata,
- covariantKeyword: covariantKeyword,
- staticKeyword: modifiers?.staticKeyword,
- fieldList: variableList,
- semicolon: endToken));
+ void handleStringJuxtaposition(int literalCount) {
+ debugEvent("StringJuxtaposition");
+ push(ast.adjacentStrings(popList(literalCount)));
+ }
+
+ void handleStringPart(Token token) {
+ debugEvent("StringPart");
+ push(token);
}
@override
- AstNode finishFields() {
- debugEvent("finishFields");
- return declarations.removeLast();
+ void handleSuperExpression(Token token, IdentifierContext context) {
+ debugEvent("SuperExpression");
+ push(ast.superExpression(token));
+ }
+
+ void handleSymbolVoid(Token token) {
+ debugEvent("SymbolVoid");
+ push(token);
}
@override
- void handleOperatorName(Token operatorKeyword, Token token) {
- debugEvent("OperatorName");
- push(new _OperatorName(
- operatorKeyword, ast.simpleIdentifier(token, isDeclaration: true)));
+ void handleThisExpression(Token token, IdentifierContext context) {
+ debugEvent("ThisExpression");
+ push(ast.thisExpression(token));
}
- @override
- void beginMetadataStar(Token token) {
- debugEvent("beginMetadataStar");
- if (token.precedingComments != null) {
- push(_toAnalyzerComment(token.precedingComments));
- } else {
- push(NullValue.Comments);
- }
+ void handleThrowExpression(Token throwToken, Token endToken) {
+ debugEvent("ThrowExpression");
+ push(ast.throwExpression(throwToken, pop()));
}
- @override
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
- debugEvent("Metadata");
- MethodInvocation invocation = pop();
- SimpleIdentifier constructorName = periodBeforeName != null ? pop() : null;
- pop(); // Type arguments, not allowed.
+ void handleType(Token beginToken, Token endToken) {
+ debugEvent("Type");
+ TypeArgumentList arguments = pop();
Identifier name = pop();
- push(ast.annotation(beginToken, name, periodBeforeName, constructorName,
- invocation?.argumentList));
+ push(ast.typeName(name, arguments));
}
- @override
- void endMetadataStar(int count, bool forParameter) {
- debugEvent("MetadataStar");
- push(popList(count) ?? NullValue.Metadata);
+ void handleUnaryPostfixAssignmentExpression(Token token) {
+ debugEvent("UnaryPostfixAssignmentExpression");
+ push(ast.postfixExpression(pop(), token));
}
- ParameterKind _toAnalyzerParameterKind(FormalParameterKind type) {
- if (type == FormalParameterKind.optionalPositional) {
- return ParameterKind.POSITIONAL;
- } else if (type == FormalParameterKind.optionalNamed) {
- return ParameterKind.NAMED;
- } else {
- return ParameterKind.REQUIRED;
- }
+ void handleUnaryPrefixAssignmentExpression(Token token) {
+ debugEvent("UnaryPrefixAssignmentExpression");
+ push(ast.prefixExpression(token, pop()));
}
- Comment _toAnalyzerComment(Token comments) {
- if (comments == null) return null;
+ void handleUnaryPrefixExpression(Token token) {
+ debugEvent("UnaryPrefixExpression");
+ push(ast.prefixExpression(token, pop()));
+ }
- // This is temporary placeholder code to get tests to pass.
- // TODO(paulberry): after analyzer and fasta token representations are
- // unified, refactor the code in analyzer's parser that handles
- // documentation comments so that it is reusable, and reuse it here.
- // See Parser.parseCommentAndMetadata
- var tokens = <Token>[comments];
- var references = <CommentReference>[];
- return ast.documentationComment(tokens, references);
+ @override
+ Token handleUnrecoverableError(Token token, Message message) {
+ if (message.code == codeExpectedFunctionBody) {
+ if (identical('native', token.stringValue) && parser != null) {
+ Token nativeKeyword = token;
+ Token semicolon = parser.parseLiteralString(token.next);
+ token = parser.expectSemicolon(semicolon);
+ StringLiteral name = pop();
+ pop(); // star
+ pop(); // async
+ push(ast.nativeFunctionBody(nativeKeyword, name, semicolon));
+ return token;
+ }
+ } else if (message.code == codeExpectedExpression) {
+ String lexeme = token.lexeme;
+ if (identical('async', lexeme) || identical('yield', lexeme)) {
+ errorReporter?.reportErrorForOffset(
+ ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
+ token.charOffset,
+ token.charCount);
+ push(ast.simpleIdentifier(token));
+ return token;
+ }
+ }
+ return super.handleUnrecoverableError(token, message);
+ }
+
+ void handleValuedFormalParameter(Token equals, Token token) {
+ debugEvent("ValuedFormalParameter");
+ Expression value = pop();
+ push(new _ParameterDefaultValue(equals, value));
}
@override
- void debugEvent(String name) {
- // printEvent(name);
+ void handleVoidKeyword(Token token) {
+ debugEvent("VoidKeyword");
+ // TODO(paulberry): is this sufficient, or do we need to hook the "void"
+ // keyword up to an element?
+ handleIdentifier(token, IdentifierContext.typeReference);
+ handleNoTypeArguments(token);
+ handleType(token, token);
}
@override
@@ -1850,9 +1878,11 @@ class AstBuilder extends ScopeListener {
return tokenToStartReplacing;
}
- @override
- void discardTypeReplacedWithCommentTypeAssign() {
- pop();
+ void _handleInstanceCreation(Token token) {
+ MethodInvocation arguments = pop();
+ ConstructorName constructorName = pop();
+ push(ast.instanceCreationExpression(
+ token, constructorName, arguments.argumentList));
}
/// Check if the given [token] has a comment token with the given [type],
@@ -1902,58 +1932,27 @@ class AstBuilder extends ScopeListener {
return firstToken;
}
- @override
- void addCompileTimeError(Message message, int charOffset) {
- Code code = message.code;
- Map<String, dynamic> arguments = message.arguments;
+ Comment _toAnalyzerComment(Token comments) {
+ if (comments == null) return null;
- String stringOrTokenLexeme() {
- var text = arguments['string'];
- if (text == null) {
- Token token = arguments['token'];
- if (token != null) {
- text = token.lexeme;
- }
- }
- return text;
- }
+ // This is temporary placeholder code to get tests to pass.
+ // TODO(paulberry): after analyzer and fasta token representations are
+ // unified, refactor the code in analyzer's parser that handles
+ // documentation comments so that it is reusable, and reuse it here.
+ // See Parser.parseCommentAndMetadata
+ var tokens = <Token>[comments];
+ var references = <CommentReference>[];
+ return ast.documentationComment(tokens, references);
+ }
- switch (code.analyzerCode) {
- case "EXPECTED_TYPE_NAME":
- errorReporter?.reportErrorForOffset(
- ParserErrorCode.EXPECTED_TYPE_NAME, charOffset, 1);
- return;
- case "NATIVE_CLAUSE_SHOULD_BE_ANNOTATION":
- if (!allowNativeClause) {
- errorReporter?.reportErrorForOffset(
- ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION,
- charOffset,
- 1);
- }
- return;
- case "EXPECTED_STRING_LITERAL":
- errorReporter?.reportErrorForOffset(
- ParserErrorCode.EXPECTED_STRING_LITERAL, charOffset, 1);
- return;
- case "EXTRANEOUS_MODIFIER":
- String text = stringOrTokenLexeme();
- errorReporter?.reportErrorForOffset(ParserErrorCode.EXTRANEOUS_MODIFIER,
- charOffset, text.length, [text]);
- return;
- case "UNEXPECTED_TOKEN":
- String text = stringOrTokenLexeme();
- if (text == ';') {
- errorReporter?.reportErrorForOffset(
- ParserErrorCode.EXPECTED_TOKEN, charOffset, text.length, [text]);
- } else {
- errorReporter?.reportErrorForOffset(ParserErrorCode.UNEXPECTED_TOKEN,
- charOffset, text.length, [text]);
- }
- return;
- default:
- // fall through
+ ParameterKind _toAnalyzerParameterKind(FormalParameterKind type) {
+ if (type == FormalParameterKind.optionalPositional) {
+ return ParameterKind.POSITIONAL;
+ } else if (type == FormalParameterKind.optionalNamed) {
+ return ParameterKind.NAMED;
+ } else {
+ return ParameterKind.REQUIRED;
}
- library.addCompileTimeError(message, charOffset, uri);
}
}
@@ -1988,45 +1987,6 @@ class _MixinApplication {
_MixinApplication(this.supertype, this.withKeyword, this.mixinTypes);
}
-/// Data structure placed on the stack to represent the default parameter
-/// value with the separator token.
-class _ParameterDefaultValue {
- final Token separator;
- final Expression value;
-
- _ParameterDefaultValue(this.separator, this.value);
-}
-
-/// Data structure placed on stack to represent the redirected constructor.
-class _RedirectingFactoryBody {
- final Token asyncKeyword;
- final Token starKeyword;
- final Token equalToken;
- final ConstructorName constructorName;
-
- _RedirectingFactoryBody(this.asyncKeyword, this.starKeyword, this.equalToken,
- this.constructorName);
-}
-
-/// Data structure placed on the stack as a container for optional parameters.
-class _OptionalFormalParameters {
- final List<FormalParameter> parameters;
- final Token leftDelimiter;
- final Token rightDelimiter;
-
- _OptionalFormalParameters(
- this.parameters, this.leftDelimiter, this.rightDelimiter);
-}
-
-/// Data structure placed on the stack to represent the keyword "operator"
-/// followed by a token.
-class _OperatorName {
- final Token operatorKeyword;
- final SimpleIdentifier name;
-
- _OperatorName(this.operatorKeyword, this.name);
-}
-
/// Data structure placed on the stack to represent a non-empty sequence
/// of modifiers.
class _Modifiers {
@@ -2062,3 +2022,42 @@ class _Modifiers {
}
}
}
+
+/// Data structure placed on the stack to represent the keyword "operator"
+/// followed by a token.
+class _OperatorName {
+ final Token operatorKeyword;
+ final SimpleIdentifier name;
+
+ _OperatorName(this.operatorKeyword, this.name);
+}
+
+/// Data structure placed on the stack as a container for optional parameters.
+class _OptionalFormalParameters {
+ final List<FormalParameter> parameters;
+ final Token leftDelimiter;
+ final Token rightDelimiter;
+
+ _OptionalFormalParameters(
+ this.parameters, this.leftDelimiter, this.rightDelimiter);
+}
+
+/// Data structure placed on the stack to represent the default parameter
+/// value with the separator token.
+class _ParameterDefaultValue {
+ final Token separator;
+ final Expression value;
+
+ _ParameterDefaultValue(this.separator, this.value);
+}
+
+/// Data structure placed on stack to represent the redirected constructor.
+class _RedirectingFactoryBody {
+ final Token asyncKeyword;
+ final Token starKeyword;
+ final Token equalToken;
+ final ConstructorName constructorName;
+
+ _RedirectingFactoryBody(this.asyncKeyword, this.starKeyword, this.equalToken,
+ this.constructorName);
+}
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_fasta_test.dart » ('j') | pkg/analyzer/test/generated/parser_fasta_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698