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..526beccbf206a2c2455595e3f6f0469350a4bb8f |
--- /dev/null |
+++ b/pkg/fasta/lib/src/analyzer/ast_builder.dart |
@@ -0,0 +1,601 @@ |
+// 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))); |
asgerf
2017/01/19 10:13:26
Long line
ahe
2017/01/19 10:59:45
Done.
|
+ 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"); |
+ print(""" |
+Analyzer AST: |
+$body |
asgerf
2017/01/19 10:13:26
Please remove these prints.
ahe
2017/01/19 10:59:45
Done.
|
+"""); |
+ var kernel = toKernel(body, elementStore, library.library, scope); |
+print(""" |
+Kernel from analyzer AST: |
+$kernel"""); |
+ 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}"); |
asgerf
2017/01/19 10:13:26
Long Line™
ahe
2017/01/19 10:59:45
Done.
|
+ } |
+ } |
+ |
+ 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); |
+ } |
+} |