| // Copyright (c) 2015, 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. |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/src/dart/ast/token.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:logging/logging.dart' as logger; |
| |
| final _log = new logger.Logger('dev_compiler.ast_builder'); |
| |
| // Wrappers around constructors for the dart ast. The AstBuilder class |
| // provides a higher-level interface, abstracting both from the lexical |
| // details and some of helper classes. The RawAstBuilder class provides |
| // a low-level wrapper class (below) abstracts from the lexical details |
| // but otherwise faithfully mirrors the construction API. |
| class AstBuilder { |
| static SimpleIdentifier identifierFromString(String name) { |
| return RawAstBuilder.identifierFromString(name); |
| } |
| |
| static PrefixedIdentifier prefixedIdentifier( |
| SimpleIdentifier pre, SimpleIdentifier id) { |
| return RawAstBuilder.prefixedIdentifier(pre, id); |
| } |
| |
| static TypeParameter typeParameter(SimpleIdentifier name, |
| [TypeName bound = null]) { |
| return RawAstBuilder.typeParameter(name, bound); |
| } |
| |
| static TypeParameterList typeParameterList(List<TypeParameter> params) { |
| return RawAstBuilder.typeParameterList(params); |
| } |
| |
| static TypeArgumentList typeArgumentList(List<TypeName> args) { |
| return RawAstBuilder.typeArgumentList(args); |
| } |
| |
| static ArgumentList argumentList(List<Expression> args) { |
| return RawAstBuilder.argumentList(args); |
| } |
| |
| static TypeName typeName(Identifier id, List<TypeName> args) { |
| TypeArgumentList argList = null; |
| if (args != null && args.length > 0) argList = typeArgumentList(args); |
| return RawAstBuilder.typeName(id, argList); |
| } |
| |
| static FunctionTypeAlias functionTypeAlias( |
| TypeName ret, |
| SimpleIdentifier name, |
| List<TypeParameter> tParams, |
| List<FormalParameter> params) { |
| TypeParameterList tps = |
| (tParams.length == 0) ? null : typeParameterList(tParams); |
| FormalParameterList fps = formalParameterList(params); |
| return RawAstBuilder.functionTypeAlias(ret, name, tps, fps); |
| } |
| |
| static BooleanLiteral booleanLiteral(bool b) { |
| return RawAstBuilder.booleanLiteral(b); |
| } |
| |
| static NullLiteral nullLiteral() { |
| return RawAstBuilder.nullLiteral(); |
| } |
| |
| static IntegerLiteral integerLiteral(int i) { |
| return RawAstBuilder.integerLiteral(i); |
| } |
| |
| static StringLiteral stringLiteral(String s) { |
| return RawAstBuilder.simpleStringLiteral(s); |
| } |
| |
| static StringLiteral multiLineStringLiteral(String s) { |
| return RawAstBuilder.tripleQuotedStringLiteral(s); |
| } |
| |
| static AsExpression asExpression(Expression exp, TypeName type) { |
| return RawAstBuilder.asExpression(exp, type); |
| } |
| |
| static IsExpression isExpression(Expression exp, TypeName type) { |
| return RawAstBuilder.isExpression(exp, type); |
| } |
| |
| static ParenthesizedExpression parenthesizedExpression(Expression exp) { |
| return RawAstBuilder.parenthesizedExpression(exp); |
| } |
| |
| static Expression parenthesize(Expression exp) { |
| if (exp is Identifier || |
| exp is ParenthesizedExpression || |
| exp is FunctionExpressionInvocation || |
| exp is MethodInvocation) return exp; |
| return parenthesizedExpression(exp); |
| } |
| |
| static PropertyAccess propertyAccess( |
| Expression target, SimpleIdentifier name) { |
| var p = new Token(TokenType.PERIOD, 0); |
| return new PropertyAccess(target, p, name); |
| } |
| |
| static MethodInvocation methodInvoke(Expression target, SimpleIdentifier name, |
| TypeArgumentList typeArguments, NodeList<Expression> args) { |
| var p = new Token(TokenType.PERIOD, 0); |
| return new MethodInvocation( |
| target, p, name, typeArguments, argumentList(args)); |
| } |
| |
| static TokenType getTokenType(String lexeme) { |
| switch (lexeme) { |
| case "&": |
| return TokenType.AMPERSAND; |
| case "&&": |
| return TokenType.AMPERSAND_AMPERSAND; |
| case "&=": |
| return TokenType.AMPERSAND_EQ; |
| case "@": |
| return TokenType.AT; |
| case "!": |
| return TokenType.BANG; |
| case "!=": |
| return TokenType.BANG_EQ; |
| case "|": |
| return TokenType.BAR; |
| case "||": |
| return TokenType.BAR_BAR; |
| case "|=": |
| return TokenType.BAR_EQ; |
| case ":": |
| return TokenType.COLON; |
| case ",": |
| return TokenType.COMMA; |
| case "^": |
| return TokenType.CARET; |
| case "^=": |
| return TokenType.CARET_EQ; |
| case "}": |
| return TokenType.CLOSE_CURLY_BRACKET; |
| case ")": |
| return TokenType.CLOSE_PAREN; |
| case "]": |
| return TokenType.CLOSE_SQUARE_BRACKET; |
| case "=": |
| return TokenType.EQ; |
| case "==": |
| return TokenType.EQ_EQ; |
| case "=>": |
| return TokenType.FUNCTION; |
| case ">": |
| return TokenType.GT; |
| case ">=": |
| return TokenType.GT_EQ; |
| case ">>": |
| return TokenType.GT_GT; |
| case ">>=": |
| return TokenType.GT_GT_EQ; |
| case "#": |
| return TokenType.HASH; |
| case "[]": |
| return TokenType.INDEX; |
| case "[]=": |
| return TokenType.INDEX_EQ; |
| case "is": |
| return TokenType.IS; |
| case "<": |
| return TokenType.LT; |
| case "<=": |
| return TokenType.LT_EQ; |
| case "<<": |
| return TokenType.LT_LT; |
| case "<<=": |
| return TokenType.LT_LT_EQ; |
| case "-": |
| return TokenType.MINUS; |
| case "-=": |
| return TokenType.MINUS_EQ; |
| case "--": |
| return TokenType.MINUS_MINUS; |
| case "{": |
| return TokenType.OPEN_CURLY_BRACKET; |
| case "(": |
| return TokenType.OPEN_PAREN; |
| case "[": |
| return TokenType.OPEN_SQUARE_BRACKET; |
| case "%": |
| return TokenType.PERCENT; |
| case "%=": |
| return TokenType.PERCENT_EQ; |
| case ".": |
| return TokenType.PERIOD; |
| case "..": |
| return TokenType.PERIOD_PERIOD; |
| case "+": |
| return TokenType.PLUS; |
| case "+=": |
| return TokenType.PLUS_EQ; |
| case "++": |
| return TokenType.PLUS_PLUS; |
| case "?": |
| return TokenType.QUESTION; |
| case ";": |
| return TokenType.SEMICOLON; |
| case "/": |
| return TokenType.SLASH; |
| case "/=": |
| return TokenType.SLASH_EQ; |
| case "*": |
| return TokenType.STAR; |
| case "*=": |
| return TokenType.STAR_EQ; |
| case "\${": |
| return TokenType.STRING_INTERPOLATION_EXPRESSION; |
| case "\$": |
| return TokenType.STRING_INTERPOLATION_IDENTIFIER; |
| case "~": |
| return TokenType.TILDE; |
| case "~/": |
| return TokenType.TILDE_SLASH; |
| case "~/=": |
| return TokenType.TILDE_SLASH_EQ; |
| case "`": |
| return TokenType.BACKPING; |
| case "\\": |
| return TokenType.BACKSLASH; |
| case "...": |
| return TokenType.PERIOD_PERIOD_PERIOD; |
| case "??": |
| return TokenType.QUESTION_QUESTION; |
| case "??=": |
| return TokenType.QUESTION_QUESTION_EQ; |
| default: |
| return null; |
| } |
| } |
| |
| static Token _binaryOperation(String oper) { |
| var type = getTokenType(oper); |
| assert(type != null); |
| return new Token(type, 0); |
| } |
| |
| static BinaryExpression binaryExpression( |
| Expression l, String oper, Expression r) { |
| Token token = _binaryOperation(oper); |
| return RawAstBuilder.binaryExpression(l, token, r); |
| } |
| |
| static ConditionalExpression conditionalExpression( |
| Expression cond, Expression tExp, Expression fExp) { |
| return RawAstBuilder.conditionalExpression(cond, tExp, fExp); |
| } |
| |
| static Expression application(Expression function, List<Expression> es) { |
| ArgumentList args = argumentList(es); |
| return RawAstBuilder.functionExpressionInvocation(function, args); |
| } |
| |
| static FormalParameterList formalParameterList(List<FormalParameter> params) { |
| return RawAstBuilder.formalParameterList(params); |
| } |
| |
| static Block block(List<Statement> statements) { |
| return RawAstBuilder.block(statements); |
| } |
| |
| static MethodDeclaration blockMethodDeclaration( |
| TypeName rt, |
| SimpleIdentifier m, |
| List<FormalParameter> params, |
| List<Statement> statements, |
| {bool isStatic: false}) { |
| FormalParameterList fl = formalParameterList(params); |
| Block b = block(statements); |
| BlockFunctionBody body = RawAstBuilder.blockFunctionBody(b); |
| return RawAstBuilder.methodDeclaration(rt, m, fl, body, isStatic: isStatic); |
| } |
| |
| static FunctionDeclaration blockFunctionDeclaration( |
| TypeName rt, |
| SimpleIdentifier f, |
| List<FormalParameter> params, |
| List<Statement> statements) { |
| FunctionExpression fexp = blockFunction(params, statements); |
| return RawAstBuilder.functionDeclaration(rt, f, fexp); |
| } |
| |
| static FunctionExpression blockFunction( |
| List<FormalParameter> params, List<Statement> statements) { |
| FormalParameterList fl = formalParameterList(params); |
| Block b = block(statements); |
| BlockFunctionBody body = RawAstBuilder.blockFunctionBody(b); |
| return RawAstBuilder.functionExpression(fl, body); |
| } |
| |
| static FunctionExpression expressionFunction( |
| List<FormalParameter> params, Expression body, |
| [bool decl = false]) { |
| FormalParameterList fl = formalParameterList(params); |
| ExpressionFunctionBody b = RawAstBuilder.expressionFunctionBody(body, decl); |
| return RawAstBuilder.functionExpression(fl, b); |
| } |
| |
| static FunctionDeclarationStatement functionDeclarationStatement( |
| TypeName rType, SimpleIdentifier name, FunctionExpression fe) { |
| var fd = RawAstBuilder.functionDeclaration(rType, name, fe); |
| return RawAstBuilder.functionDeclarationStatement(fd); |
| } |
| |
| static Statement returnExpression([Expression e]) { |
| return RawAstBuilder.returnExpression(e); |
| } |
| |
| // let b = e1 in e2 == (\b.e2)(e1) |
| static Expression letExpression( |
| FormalParameter b, Expression e1, Expression e2) { |
| FunctionExpression l = expressionFunction(<FormalParameter>[b], e2); |
| return application(parenthesize(l), <Expression>[e1]); |
| } |
| |
| static SimpleFormalParameter simpleFormal(SimpleIdentifier v, TypeName t) { |
| return RawAstBuilder.simpleFormalParameter(v, t); |
| } |
| |
| static FunctionTypedFormalParameter functionTypedFormal( |
| TypeName ret, SimpleIdentifier v, List<FormalParameter> params) { |
| FormalParameterList ps = formalParameterList(params); |
| return RawAstBuilder.functionTypedFormalParameter(ret, v, ps); |
| } |
| |
| static FormalParameter requiredFormal(NormalFormalParameter fp) { |
| return RawAstBuilder.requiredFormalParameter(fp); |
| } |
| |
| static FormalParameter optionalFormal(NormalFormalParameter fp) { |
| return RawAstBuilder.optionalFormalParameter(fp); |
| } |
| |
| static FormalParameter namedFormal(NormalFormalParameter fp) { |
| return RawAstBuilder.namedFormalParameter(fp); |
| } |
| |
| static NamedExpression namedParameter(String s, Expression e) { |
| return namedExpression(s, e); |
| } |
| |
| static NamedExpression namedExpression(String s, Expression e) { |
| return RawAstBuilder.namedExpression(identifierFromString(s), e); |
| } |
| |
| /// Declares a single variable `var <name> = <init>` with the type and name |
| /// specified by the VariableElement. See also [variableStatement]. |
| static VariableDeclarationList declareVariable(SimpleIdentifier name, |
| [Expression init]) { |
| var eqToken = init != null ? new Token(TokenType.EQ, 0) : null; |
| var varToken = new KeywordToken(Keyword.VAR, 0); |
| return new VariableDeclarationList(null, null, varToken, null, |
| [new VariableDeclaration(name, eqToken, init)]); |
| } |
| |
| static VariableDeclarationStatement variableStatement(SimpleIdentifier name, |
| [Expression init]) { |
| return RawAstBuilder |
| .variableDeclarationStatement(declareVariable(name, init)); |
| } |
| |
| static InstanceCreationExpression instanceCreation( |
| ConstructorName ctor, List<Expression> args) { |
| var newToken = new KeywordToken(Keyword.NEW, 0); |
| return new InstanceCreationExpression( |
| newToken, ctor, RawAstBuilder.argumentList(args)); |
| } |
| } |
| |
| // This class provides a low-level wrapper around the constructors for |
| // the AST. It mostly simply abstracts from the lexical tokens. |
| class RawAstBuilder { |
| static ConstructorName constructorName(TypeName type, |
| [SimpleIdentifier name]) { |
| Token period = name != null ? new Token(TokenType.PERIOD, 0) : null; |
| return new ConstructorName(type, period, name); |
| } |
| |
| static SimpleIdentifier identifierFromString(String name) { |
| StringToken token = new SyntheticStringToken(TokenType.IDENTIFIER, name, 0); |
| return new SimpleIdentifier(token); |
| } |
| |
| static PrefixedIdentifier prefixedIdentifier( |
| SimpleIdentifier pre, SimpleIdentifier id) { |
| Token period = new Token(TokenType.PERIOD, 0); |
| return new PrefixedIdentifier(pre, period, id); |
| } |
| |
| static TypeParameter typeParameter(SimpleIdentifier name, |
| [TypeName bound = null]) { |
| Token keyword = |
| (bound == null) ? null : new KeywordToken(Keyword.EXTENDS, 0); |
| return new TypeParameter(null, null, name, keyword, bound); |
| } |
| |
| static TypeParameterList typeParameterList(List<TypeParameter> params) { |
| Token lb = new Token(TokenType.LT, 0); |
| Token rb = new Token(TokenType.GT, 0); |
| return new TypeParameterList(lb, params, rb); |
| } |
| |
| static TypeArgumentList typeArgumentList(List<TypeName> args) { |
| Token lb = new Token(TokenType.LT, 0); |
| Token rb = new Token(TokenType.GT, 0); |
| return new TypeArgumentList(lb, args, rb); |
| } |
| |
| static ArgumentList argumentList(List<Expression> args) { |
| Token lp = new BeginToken(TokenType.OPEN_PAREN, 0); |
| Token rp = new Token(TokenType.CLOSE_PAREN, 0); |
| return new ArgumentList(lp, args, rp); |
| } |
| |
| static TypeName typeName(Identifier id, TypeArgumentList l) { |
| return new TypeName(id, l); |
| } |
| |
| static FunctionTypeAlias functionTypeAlias(TypeName ret, |
| SimpleIdentifier name, TypeParameterList tps, FormalParameterList fps) { |
| Token semi = new Token(TokenType.SEMICOLON, 0); |
| Token td = new KeywordToken(Keyword.TYPEDEF, 0); |
| return new FunctionTypeAlias(null, null, td, ret, name, tps, fps, semi); |
| } |
| |
| static BooleanLiteral booleanLiteral(bool b) { |
| var k = new KeywordToken(b ? Keyword.TRUE : Keyword.FALSE, 0); |
| return new BooleanLiteral(k, b); |
| } |
| |
| static NullLiteral nullLiteral() { |
| var n = new KeywordToken(Keyword.NULL, 0); |
| return new NullLiteral(n); |
| } |
| |
| static IntegerLiteral integerLiteral(int i) { |
| StringToken token = new StringToken(TokenType.INT, '$i', 0); |
| return new IntegerLiteral(token, i); |
| } |
| |
| static SimpleStringLiteral simpleStringLiteral(String s) { |
| StringToken token = new StringToken(TokenType.STRING, "\"" + s + "\"", 0); |
| return new SimpleStringLiteral(token, s); |
| } |
| |
| static SimpleStringLiteral tripleQuotedStringLiteral(String s) { |
| StringToken token = new StringToken(TokenType.STRING, '"""' + s + '"""', 0); |
| return new SimpleStringLiteral(token, s); |
| } |
| |
| static AsExpression asExpression(Expression exp, TypeName type) { |
| Token token = new KeywordToken(Keyword.AS, 0); |
| return new AsExpression(exp, token, type); |
| } |
| |
| static IsExpression isExpression(Expression exp, TypeName type) { |
| Token token = new KeywordToken(Keyword.IS, 0); |
| return new IsExpression(exp, token, null, type); |
| } |
| |
| static ParenthesizedExpression parenthesizedExpression(Expression exp) { |
| Token lp = new BeginToken(TokenType.OPEN_PAREN, exp.offset); |
| Token rp = new Token(TokenType.CLOSE_PAREN, exp.end); |
| return new ParenthesizedExpression(lp, exp, rp); |
| } |
| |
| static BinaryExpression binaryExpression( |
| Expression l, Token op, Expression r) { |
| return new BinaryExpression(l, op, r); |
| } |
| |
| static ConditionalExpression conditionalExpression( |
| Expression cond, Expression tExp, Expression fExp) { |
| var q = new Token(TokenType.QUESTION, 0); |
| var c = new Token(TokenType.COLON, 0); |
| return new ConditionalExpression(cond, q, tExp, c, fExp); |
| } |
| |
| static Expression functionExpressionInvocation( |
| Expression function, ArgumentList es) { |
| return new FunctionExpressionInvocation(function, null, es); |
| } |
| |
| static FormalParameterList formalParameterList(List<FormalParameter> params) { |
| Token lp = new BeginToken(TokenType.OPEN_PAREN, 0); |
| Token rp = new Token(TokenType.CLOSE_PAREN, 0); |
| bool hasOptional = params.any((p) => p.kind == ParameterKind.POSITIONAL); |
| bool hasNamed = params.any((p) => p.kind == ParameterKind.NAMED); |
| assert(!(hasOptional && hasNamed)); |
| Token ld = null; |
| Token rd = null; |
| if (hasOptional) { |
| ld = new BeginToken(TokenType.OPEN_SQUARE_BRACKET, 0); |
| rd = new Token(TokenType.CLOSE_SQUARE_BRACKET, 0); |
| } |
| if (hasNamed) { |
| ld = new BeginToken(TokenType.OPEN_CURLY_BRACKET, 0); |
| rd = new Token(TokenType.CLOSE_CURLY_BRACKET, 0); |
| } |
| return new FormalParameterList(lp, params, ld, rd, rp); |
| } |
| |
| static Block block(List<Statement> statements) { |
| Token ld = new BeginToken(TokenType.OPEN_CURLY_BRACKET, 0); |
| Token rd = new Token(TokenType.CLOSE_CURLY_BRACKET, 0); |
| return new Block(ld, statements, rd); |
| } |
| |
| static BlockFunctionBody blockFunctionBody(Block b) { |
| return new BlockFunctionBody(null, null, b); |
| } |
| |
| static ExpressionFunctionBody expressionFunctionBody(Expression body, |
| [bool decl = false]) { |
| Token semi = (decl) ? new Token(TokenType.SEMICOLON, 0) : null; |
| return new ExpressionFunctionBody(null, null, body, semi); |
| } |
| |
| static ExpressionStatement expressionStatement(Expression expression) { |
| Token semi = new Token(TokenType.SEMICOLON, 0); |
| return new ExpressionStatement(expression, semi); |
| } |
| |
| static FunctionDeclaration functionDeclaration( |
| TypeName rt, SimpleIdentifier f, FunctionExpression fexp) { |
| return new FunctionDeclaration(null, null, null, rt, null, f, fexp); |
| } |
| |
| static MethodDeclaration methodDeclaration(TypeName rt, SimpleIdentifier m, |
| FormalParameterList fl, FunctionBody body, |
| {bool isStatic: false}) { |
| Token st = isStatic ? new KeywordToken(Keyword.STATIC, 0) : null; |
| return new MethodDeclaration( |
| null, null, null, st, rt, null, null, m, null, fl, body); |
| } |
| |
| static FunctionExpression functionExpression( |
| FormalParameterList fl, FunctionBody body) { |
| return new FunctionExpression(null, fl, body); |
| } |
| |
| static FunctionDeclarationStatement functionDeclarationStatement( |
| FunctionDeclaration fd) { |
| return new FunctionDeclarationStatement(fd); |
| } |
| |
| static Statement returnExpression([Expression e]) { |
| Token ret = new KeywordToken(Keyword.RETURN, 0); |
| Token semi = new Token(TokenType.SEMICOLON, 0); |
| return new ReturnStatement(ret, e, semi); |
| } |
| |
| static SimpleFormalParameter simpleFormalParameter( |
| SimpleIdentifier v, TypeName t) { |
| return new SimpleFormalParameter(null, <Annotation>[], null, t, v); |
| } |
| |
| static FunctionTypedFormalParameter functionTypedFormalParameter( |
| TypeName ret, SimpleIdentifier v, FormalParameterList ps) { |
| return new FunctionTypedFormalParameter( |
| null, <Annotation>[], ret, v, null, ps); |
| } |
| |
| static FormalParameter requiredFormalParameter(NormalFormalParameter fp) { |
| return fp; |
| } |
| |
| static FormalParameter optionalFormalParameter(NormalFormalParameter fp) { |
| return new DefaultFormalParameter(fp, ParameterKind.POSITIONAL, null, null); |
| } |
| |
| static FormalParameter namedFormalParameter(NormalFormalParameter fp) { |
| return new DefaultFormalParameter(fp, ParameterKind.NAMED, null, null); |
| } |
| |
| static NamedExpression namedParameter(SimpleIdentifier s, Expression e) { |
| return namedExpression(s, e); |
| } |
| |
| static NamedExpression namedExpression(SimpleIdentifier s, Expression e) { |
| Label l = new Label(s, new Token(TokenType.COLON, 0)); |
| return new NamedExpression(l, e); |
| } |
| |
| static VariableDeclarationStatement variableDeclarationStatement( |
| VariableDeclarationList varDecl) { |
| var semi = new Token(TokenType.SEMICOLON, 0); |
| return new VariableDeclarationStatement(varDecl, semi); |
| } |
| } |