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

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

Issue 2632663002: Fasta analyzer AST builder. (Closed)
Patch Set: Address review comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/fasta/lib/src/analyzer/analyzer.dart ('k') | pkg/fasta/lib/src/analyzer/element_store.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/fasta/lib/src/analyzer/ast_builder.dart
diff --git a/pkg/fasta/lib/src/analyzer/ast_builder.dart b/pkg/fasta/lib/src/analyzer/ast_builder.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f8348f146a8cc910e2debdeeb44f7122cf8f5b30
--- /dev/null
+++ b/pkg/fasta/lib/src/analyzer/ast_builder.dart
@@ -0,0 +1,595 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library fasta.analyzer.ast_builder;
+
+import 'package:dart_scanner/src/token.dart' show
+ BeginGroupToken,
+ Token;
+
+import 'package:analyzer/analyzer.dart';
+
+import 'package:analyzer/dart/ast/token.dart' as analyzer show
+ Token;
+
+import 'package:analyzer/dart/element/element.dart' show
+ Element;
+
+import 'package:analyzer/dart/ast/ast_factory.dart' show
+ AstFactory;
+
+import 'package:analyzer/dart/ast/standard_ast_factory.dart' as standard;
+
+import '../errors.dart' show
+ internalError;
+
+import '../source/scope_listener.dart' show
+ JumpTargetKind,
+ NullValue,
+ Scope,
+ ScopeListener;
+
+import '../kernel/kernel_builder.dart' show
+ Builder,
+ KernelLibraryBuilder,
+ ProcedureBuilder;
+
+import '../quote.dart';
+
+import '../source/outline_builder.dart' show
+ asyncMarkerFromTokens;
+
+import 'element_store.dart' show
+ AnalyzerLocalVariableElemment,
+ AnalyzerParameterElement,
+ ElementStore,
+ KernelClassElement;
+
+import 'token_utils.dart' show
+ toAnalyzerToken;
+
+import 'analyzer.dart' show
+ toKernel;
+
+class AstBuilder extends ScopeListener {
+ final AstFactory ast = standard.astFactory;
+
+ final KernelLibraryBuilder library;
+
+ final Builder member;
+
+ final ElementStore elementStore;
+
+ bool isFirstIdentifier = false;
+
+ AstBuilder(this.library, this.member, this.elementStore, Scope scope)
+ : super(scope);
+
+ Uri get uri => library.uri;
+
+ createJumpTarget(JumpTargetKind kind) {
+ // TODO(ahe): Implement jump targets.
+ return null;
+ }
+
+ void beginLiteralString(Token token) {
+ debugEvent("beginLiteralString");
+ push(token);
+ }
+
+ void handleStringPart(Token token) {
+ debugEvent("StringPart");
+ push(token);
+ }
+
+ void doStringPart(Token token) {
+ push(ast.simpleStringLiteral(toAnalyzerToken(token), token.value));
+ }
+
+ void endLiteralString(int interpolationCount) {
+ debugEvent("endLiteralString");
+ if (interpolationCount == 0) {
+ Token token = pop();
+ String value = unescapeString(token.value);
+ push(ast.simpleStringLiteral(toAnalyzerToken(token), value));
+ } else {
+ List parts = popList(1 + interpolationCount * 2);
+ Token first = parts.first;
+ Token last = parts.last;
+ Quote quote = analyzeQuote(first.value);
+ List<InterpolationElement> elements = <InterpolationElement>[];
+ elements.add(ast.interpolationString(
+ toAnalyzerToken(first),
+ unescapeFirstStringPart(first.value, quote)));
+ for (int i = 1; i < parts.length - 1; i++) {
+ var part = parts[i];
+ if (part is Token) {
+ elements.add(ast.interpolationString(
+ toAnalyzerToken(part), part.value));
+ } else if (part is Expression) {
+ elements.add(ast.interpolationExpression(null, part, null));
+ } else {
+ internalError(
+ "Unexpected part in string interpolation: ${part.runtimeType}");
+ }
+ }
+ elements.add(ast.interpolationString(toAnalyzerToken(last),
+ unescapeLastStringPart(last.value, quote)));
+ push(ast.stringInterpolation(elements));
+ }
+ }
+
+ void handleStringJuxtaposition(int literalCount) {
+ debugEvent("StringJuxtaposition");
+ push(ast.adjacentStrings(popList(literalCount)));
+ }
+
+ void endArguments(int count, Token beginToken, Token endToken) {
+ debugEvent("Arguments");
+ List expressions = popList(count);
+ ArgumentList arguments = ast.argumentList(toAnalyzerToken(beginToken),
+ expressions, toAnalyzerToken(endToken));
+ push(ast.methodInvocation(null, null, null, null, arguments));
+ }
+
+ void beginExpression(Token token) {
+ isFirstIdentifier = true;
+ }
+
+ void handleIdentifier(Token token) {
+ debugEvent("handleIdentifier");
+ String name = token.value;
+ SimpleIdentifier identifier = ast.simpleIdentifier(toAnalyzerToken(token));
+ if (isFirstIdentifier) {
+ Builder builder = scope.lookup(name);
+ if (builder != null) {
+ Element element = elementStore[builder];
+ assert(element != null);
+ identifier.staticElement = element;
+ }
+ }
+ push(identifier);
+ isFirstIdentifier = false;
+ }
+
+ void endSend(Token token) {
+ debugEvent("Send");
+ MethodInvocation arguments = pop();
+ TypeArgumentList typeArguments = pop();
+ if (arguments != null) {
+ if (typeArguments != null) {
+ arguments.typeArguments = typeArguments;
+ }
+ doInvocation(token, arguments);
+ } else {
+ doPropertyGet(token);
+ }
+ }
+
+ void doInvocation(Token token, MethodInvocation arguments) {
+ Expression receiver = pop();
+ if (receiver is SimpleIdentifier) {
+ arguments.methodName = receiver;
+ push(arguments);
+ } else {
+ internalError("Unhandled receiver in send: ${receiver.runtimeType}");
+ }
+ }
+
+ void doPropertyGet(Token token) {
+ }
+
+ void endExpressionStatement(Token token) {
+ debugEvent("ExpressionStatement");
+ push(ast.expressionStatement(pop(), toAnalyzerToken(token)));
+ }
+
+ void endFunctionBody(int count, Token beginToken, Token endToken) {
+ debugEvent("FunctionBody");
+ List statements = popList(count);
+ if (beginToken != null) {
+ exitLocalScope();
+ }
+ push(ast.block(toAnalyzerToken(beginToken), statements,
+ toAnalyzerToken(endToken)));
+ }
+
+ void finishFunction(formals, asyncModifier, Statement body) {
+ debugEvent("finishFunction");
+ var kernel = toKernel(body, elementStore, library.library, scope);
+ if (member is ProcedureBuilder) {
+ ProcedureBuilder builder = member;
+ builder.body = kernel;
+ } else {
+ internalError("Internal error: expected procedure, but got: $member");
+ }
+ }
+
+ 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();
+ CascadeExpression receiver = pop();
+ pop(); // Token.
+ receiver.cascadeSections.add(expression);
+ push(receiver);
+ }
+
+ void handleBinaryExpression(Token token) {
+ debugEvent("BinaryExpression");
+ if (identical(".", token.stringValue) ||
+ identical("..", token.stringValue)) {
+ doDotExpression(token);
+ } else {
+ Expression right = pop();
+ Expression left = pop();
+ push(ast.binaryExpression(left, toAnalyzerToken(token), right));
+ }
+ }
+
+ void doDotExpression(Token token) {
+ Expression identifierOrInvoke = pop();
+ Expression receiver = pop();
+ if (identifierOrInvoke is SimpleIdentifier) {
+ push(ast.propertyAccess(receiver, toAnalyzerToken(token),
+ identifierOrInvoke));
+ } else if (identifierOrInvoke is MethodInvocation) {
+ assert(identifierOrInvoke.target == null);
+ identifierOrInvoke
+ ..target = receiver
+ ..operator = toAnalyzerToken(token);
+ push(identifierOrInvoke);
+ } else {
+ internalError(
+ "Unhandled property access: ${identifierOrInvoke.runtimeType}");
+ }
+ }
+
+ void handleLiteralInt(Token token) {
+ debugEvent("LiteralInt");
+ push(ast.integerLiteral(toAnalyzerToken(token), int.parse(token.value)));
+ }
+
+ void endReturnStatement(
+ bool hasExpression, Token beginToken, Token endToken) {
+ debugEvent("ReturnStatement");
+ Expression expression = hasExpression ? pop() : null;
+ push(ast.returnStatement(toAnalyzerToken(beginToken), expression,
+ toAnalyzerToken(endToken)));
+ }
+
+ void endIfStatement(Token ifToken, Token elseToken) {
+ Statement elsePart = popIfNotNull(elseToken);
+ Statement thenPart = pop();
+ Expression condition = pop();
+ BeginGroupToken leftParenthesis = ifToken.next;
+ push(ast.ifStatement(
+ toAnalyzerToken(ifToken), toAnalyzerToken(ifToken.next), condition,
+ toAnalyzerToken(leftParenthesis.endGroup), thenPart,
+ toAnalyzerToken(elseToken), elsePart));
+ }
+
+ void prepareInitializers() {
+ debugEvent("prepareInitializers");
+ }
+
+ void handleNoInitializers() {
+ debugEvent("NoInitializers");
+ }
+
+ void endInitializers(int count, Token beginToken, Token endToken) {
+ debugEvent("Initializers");
+ popList(count);
+ }
+
+ void endInitializer(Token assignmentOperator) {
+ debugEvent("Initializer");
+ assert(assignmentOperator.stringValue == "=");
+ Expression initializer = pop();
+ Identifier identifier = pop();
+ // TODO(ahe): Don't push initializers, instead install them.
+ push(ast.variableDeclaration(
+ identifier, toAnalyzerToken(assignmentOperator), initializer));
+ }
+
+ void endInitializedIdentifier() {
+ debugEvent("InitializedIdentifier");
+ AstNode node = pop();
+ VariableDeclaration variable;
+ if (node is VariableDeclaration) {
+ variable = node;
+ } else if (node is SimpleIdentifier) {
+ variable = ast.variableDeclaration(node, null, null);
+ } else {
+ internalError("unhandled identifier: ${node.runtimeType}");
+ }
+ push(variable);
+ scope[variable.name.name] = variable.name.staticElement =
+ new AnalyzerLocalVariableElemment(variable);
+ }
+
+ void endVariablesDeclaration(int count, Token endToken) {
+ debugEvent("VariablesDeclaration");
+ List<VariableDeclaration> variables = popList(count);
+ TypeName type = pop();
+ pop(); // Modifiers.
+ push(ast.variableDeclarationStatement(
+ ast.variableDeclarationList(null, null, null, type, variables),
+ toAnalyzerToken(endToken)));
+ }
+
+ void handleAssignmentExpression(Token token) {
+ debugEvent("AssignmentExpression");
+ Expression rhs = pop();
+ Expression lhs = pop();
+ push(ast.assignmentExpression(lhs, toAnalyzerToken(token), rhs));
+ }
+
+ void endBlock(int count, Token beginToken, Token endToken) {
+ debugEvent("Block");
+ List<Statement> statements = popList(count) ?? <Statement>[];
+ exitLocalScope();
+ push(ast.block(toAnalyzerToken(beginToken), statements,
+ toAnalyzerToken(endToken)));
+ }
+
+ void endForStatement(
+ int updateExpressionCount, Token beginToken, Token endToken) {
+ debugEvent("ForStatement");
+ Statement body = pop();
+ List<Expression> updates = popList(updateExpressionCount);
+ ExpressionStatement condition = pop();
+ VariableDeclarationStatement variables = pop();
+ exitContinueTarget();
+ exitBreakTarget();
+ exitLocalScope();
+ BeginGroupToken leftParenthesis = beginToken.next;
+ push(ast.forStatement(
+ toAnalyzerToken(beginToken),
+ toAnalyzerToken(leftParenthesis),
+ variables?.variables,
+ null, // initialization.
+ variables?.semicolon,
+ condition.expression,
+ condition.semicolon,
+ updates,
+ toAnalyzerToken(leftParenthesis.endGroup),
+ body));
+ }
+
+ void handleLiteralList(
+ int count, Token beginToken, Token constKeyword, Token endToken) {
+ debugEvent("LiteralList");
+ List<Expression> expressions = popList(count);
+ TypeArgumentList typeArguments = pop();
+ push(ast.listLiteral(
+ toAnalyzerToken(constKeyword),
+ typeArguments,
+ toAnalyzerToken(beginToken),
+ expressions,
+ toAnalyzerToken(endToken)));
+ }
+
+ void handleAsyncModifier(Token asyncToken, Token starToken) {
+ debugEvent("AsyncModifier");
+ push(asyncMarkerFromTokens(asyncToken, starToken));
+ }
+
+ void endAwaitExpression(Token beginToken, Token endToken) {
+ debugEvent("AwaitExpression");
+ push(ast.awaitExpression(toAnalyzerToken(beginToken), pop()));
+ }
+
+ void beginLiteralSymbol(Token token) {
+ isFirstIdentifier = false;
+ }
+
+ void handleLiteralBool(Token token) {
+ debugEvent("LiteralBool");
+ bool value = identical(token.stringValue, "true");
+ assert(value || identical(token.stringValue, "false"));
+ push(ast.booleanLiteral(toAnalyzerToken(token), value));
+ }
+
+ void handleLiteralDouble(Token token) {
+ debugEvent("LiteralDouble");
+ push(ast.doubleLiteral(toAnalyzerToken(token), double.parse(token.value)));
+ }
+
+ void handleLiteralNull(Token token) {
+ debugEvent("LiteralNull");
+ push(ast.nullLiteral(toAnalyzerToken(token)));
+ }
+
+ void handleLiteralMap(
+ int count, Token beginToken, Token constKeyword, Token endToken) {
+ debugEvent("LiteralMap");
+ List<MapLiteralEntry> entries = popList(count) ?? <MapLiteralEntry>[];
+ TypeArgumentList typeArguments = pop();
+ push(ast.mapLiteral(toAnalyzerToken(constKeyword), typeArguments,
+ toAnalyzerToken(beginToken), entries, toAnalyzerToken(endToken)));
+ }
+
+ void endLiteralMapEntry(Token colon, Token endToken) {
+ debugEvent("LiteralMapEntry");
+ Expression value = pop();
+ Expression key = pop();
+ push(ast.mapLiteralEntry(key, toAnalyzerToken(colon), value));
+ }
+
+ void endLiteralSymbol(Token hashToken, int identifierCount) {
+ debugEvent("LiteralSymbol");
+ List<analyzer.Token> components = new List<analyzer.Token>(identifierCount);
+ for (int i = identifierCount - 1; i >= 0; i--) {
+ SimpleIdentifier identifier = pop();
+ components[i] = identifier.token;
+ }
+ push(ast.symbolLiteral(toAnalyzerToken(hashToken), components));
+ }
+
+ void endType(Token beginToken, Token endToken) {
+ debugEvent("Type");
+ TypeArgumentList arguments = pop();
+ SimpleIdentifier name = pop();
+ KernelClassElement cls = name.staticElement;
+ if (cls == null) {
+ Builder builder = scope.lookup(name.name);
+ if (builder == null) {
+ internalError("Undefined name: $name");
+ }
+ cls = elementStore[builder];
+ assert(cls != null);
+ name.staticElement = cls;
+ }
+ push(ast.typeName(name, arguments)..type = cls.rawType);
+ }
+
+ void handleAsOperator(Token operator, Token endToken) {
+ debugEvent("AsOperator");
+ TypeName type = pop();
+ Expression expression = pop();
+ push(ast.asExpression(expression, toAnalyzerToken(operator), type));
+ }
+
+ void handleIsOperator(Token operator, Token not, Token endToken) {
+ debugEvent("IsOperator");
+ TypeName type = pop();
+ Expression expression = pop();
+ push(ast.isExpression(expression, toAnalyzerToken(operator),
+ toAnalyzerToken(not), type));
+ }
+
+ void handleConditionalExpression(Token question, Token colon) {
+ debugEvent("ConditionalExpression");
+ Expression elseExpression = pop();
+ Expression thenExpression = pop();
+ Expression condition = pop();
+ push(ast.conditionalExpression(condition, toAnalyzerToken(question),
+ thenExpression, toAnalyzerToken(colon), elseExpression));
+ }
+
+ void endThrowExpression(Token throwToken, Token endToken) {
+ debugEvent("ThrowExpression");
+ push(ast.throwExpression(toAnalyzerToken(throwToken), pop()));
+ }
+
+ void endFormalParameter(Token thisKeyword) {
+ debugEvent("FormalParameter");
+ if (thisKeyword != null) {
+ internalError("'this' can't be used here.");
+ }
+ SimpleIdentifier name = pop();
+ TypeName type = pop();
+ pop(); // Modifiers.
+ pop(); // Metadata.
+ SimpleFormalParameter node = ast.simpleFormalParameter(null, null,
+ toAnalyzerToken(thisKeyword), type, name);
+ scope[name.name] = name.staticElement = new AnalyzerParameterElement(node);
+ push(node);
+ }
+
+ void endFormalParameters(int count, Token beginToken, Token endToken) {
+ debugEvent("FormalParameters");
+ List<FormalParameter> parameters = popList(count) ?? <FormalParameter>[];
+ push(ast.formalParameterList(toAnalyzerToken(beginToken), parameters,
+ null, null, toAnalyzerToken(endToken)));
+ }
+
+ void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+ debugEvent("CatchBlock");
+ Block body = pop();
+ FormalParameterList catchParameters = popIfNotNull(catchKeyword);
+ if (catchKeyword != null) {
+ exitLocalScope();
+ }
+ TypeName type = popIfNotNull(onKeyword);
+ SimpleIdentifier exception;
+ SimpleIdentifier stackTrace;
+ if (catchParameters != null) {
+ if (catchParameters.length > 0) {
+ exception = catchParameters.parameters[0].identifier;
+ }
+ if (catchParameters.length > 1) {
+ stackTrace = catchParameters.parameters[1].identifier;
+ }
+ }
+ BeginGroupToken leftParenthesis = catchKeyword.next;
+ push(ast.catchClause(toAnalyzerToken(onKeyword), type,
+ toAnalyzerToken(catchKeyword), toAnalyzerToken(leftParenthesis),
+ exception, null, stackTrace,
+ toAnalyzerToken(leftParenthesis.endGroup), body));
+ }
+
+ void endTryStatement(
+ int catchCount, Token tryKeyword, Token finallyKeyword) {
+ Block finallyBlock = popIfNotNull(finallyKeyword);
+ List<CatchClause> catchClauses = popList(catchCount);
+ Block body = pop();
+ push(ast.tryStatement(toAnalyzerToken(tryKeyword), body, catchClauses,
+ toAnalyzerToken(finallyKeyword), finallyBlock));
+ }
+
+ void handleNoExpression(Token token) {
+ debugEvent("NoExpression");
+ push(NullValue.Expression);
+ }
+
+ void handleIndexedExpression(
+ Token openCurlyBracket, Token closeCurlyBracket) {
+ debugEvent("IndexedExpression");
+ Expression index = pop();
+ Expression target = pop();
+ if (target == null) {
+ CascadeExpression receiver = pop();
+ Token token = peek();
+ push(receiver);
+ IndexExpression expression = ast.indexExpressionForCascade(
+ toAnalyzerToken(token), toAnalyzerToken(openCurlyBracket), index,
+ toAnalyzerToken(closeCurlyBracket));
+ assert(expression.isCascaded);
+ push(expression);
+ } else {
+ push(ast.indexExpressionForTarget(target,
+ toAnalyzerToken(openCurlyBracket), index,
+ toAnalyzerToken(closeCurlyBracket)));
+ }
+ }
+
+ void handleUnaryPrefixExpression(Token token) {
+ debugEvent("UnaryPrefixExpression");
+ push(ast.prefixExpression(toAnalyzerToken(token), pop()));
+ }
+
+ void handleUnaryPrefixAssignmentExpression(Token token) {
+ debugEvent("UnaryPrefixAssignmentExpression");
+ push(ast.prefixExpression(toAnalyzerToken(token), pop()));
+ }
+
+ void handleUnaryPostfixAssignmentExpression(Token token) {
+ debugEvent("UnaryPostfixAssignmentExpression");
+ push(ast.postfixExpression(pop(), toAnalyzerToken(token)));
+ }
+
+ void handleModifier(Token token) {
+ debugEvent("Modifier");
+ // TODO(ahe): Don't ignore modifiers.
+ }
+
+ void handleModifiers(int count) {
+ debugEvent("Modifiers");
+ // TODO(ahe): Don't ignore modifiers.
+ push(NullValue.Modifiers);
+ }
+}
« no previous file with comments | « pkg/fasta/lib/src/analyzer/analyzer.dart ('k') | pkg/fasta/lib/src/analyzer/element_store.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698