| 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);
|
| +}
|
|
|