blob: 2cbfdbf7bdb9aca8e03f75155a4a993a4007ceda [file] [log] [blame]
// 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/standard_ast_factory.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<TypeAnnotation> args) {
return RawAstBuilder.typeArgumentList(args);
}
static ArgumentList argumentList(List<Expression> args) {
return RawAstBuilder.argumentList(args);
}
static TypeName typeName(Identifier id, List<TypeAnnotation> 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 astFactory.propertyAccess(target, p, name);
}
static MethodInvocation methodInvoke(Expression target, SimpleIdentifier name,
TypeArgumentList typeArguments, NodeList<Expression> args) {
var p = new Token(TokenType.PERIOD, 0);
return astFactory.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 astFactory.variableDeclarationList(null, null, varToken, null,
[astFactory.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 astFactory.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 astFactory.constructorName(type, period, name);
}
static SimpleIdentifier identifierFromString(String name) {
StringToken token = new SyntheticStringToken(TokenType.IDENTIFIER, name, 0);
return astFactory.simpleIdentifier(token);
}
static PrefixedIdentifier prefixedIdentifier(
SimpleIdentifier pre, SimpleIdentifier id) {
Token period = new Token(TokenType.PERIOD, 0);
return astFactory.prefixedIdentifier(pre, period, id);
}
static TypeParameter typeParameter(SimpleIdentifier name,
[TypeName bound = null]) {
Token keyword =
(bound == null) ? null : new KeywordToken(Keyword.EXTENDS, 0);
return astFactory.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 astFactory.typeParameterList(lb, params, rb);
}
static TypeArgumentList typeArgumentList(List<TypeAnnotation> args) {
Token lb = new Token(TokenType.LT, 0);
Token rb = new Token(TokenType.GT, 0);
return astFactory.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 astFactory.argumentList(lp, args, rp);
}
static TypeName typeName(Identifier id, TypeArgumentList l) {
return astFactory.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 astFactory.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 astFactory.booleanLiteral(k, b);
}
static NullLiteral nullLiteral() {
var n = new KeywordToken(Keyword.NULL, 0);
return astFactory.nullLiteral(n);
}
static IntegerLiteral integerLiteral(int i) {
StringToken token = new StringToken(TokenType.INT, '$i', 0);
return astFactory.integerLiteral(token, i);
}
static SimpleStringLiteral simpleStringLiteral(String s) {
StringToken token = new StringToken(TokenType.STRING, "\"" + s + "\"", 0);
return astFactory.simpleStringLiteral(token, s);
}
static SimpleStringLiteral tripleQuotedStringLiteral(String s) {
StringToken token = new StringToken(TokenType.STRING, '"""' + s + '"""', 0);
return astFactory.simpleStringLiteral(token, s);
}
static AsExpression asExpression(Expression exp, TypeName type) {
Token token = new KeywordToken(Keyword.AS, 0);
return astFactory.asExpression(exp, token, type);
}
static IsExpression isExpression(Expression exp, TypeName type) {
Token token = new KeywordToken(Keyword.IS, 0);
return astFactory.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 astFactory.parenthesizedExpression(lp, exp, rp);
}
static BinaryExpression binaryExpression(
Expression l, Token op, Expression r) {
return astFactory.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 astFactory.conditionalExpression(cond, q, tExp, c, fExp);
}
static Expression functionExpressionInvocation(
Expression function, ArgumentList es) {
return astFactory.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 astFactory.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 astFactory.block(ld, statements, rd);
}
static BlockFunctionBody blockFunctionBody(Block b) {
return astFactory.blockFunctionBody(null, null, b);
}
static ExpressionFunctionBody expressionFunctionBody(Expression body,
[bool decl = false]) {
Token semi = (decl) ? new Token(TokenType.SEMICOLON, 0) : null;
return astFactory.expressionFunctionBody(null, null, body, semi);
}
static ExpressionStatement expressionStatement(Expression expression) {
Token semi = new Token(TokenType.SEMICOLON, 0);
return astFactory.expressionStatement(expression, semi);
}
static FunctionDeclaration functionDeclaration(
TypeName rt, SimpleIdentifier f, FunctionExpression fexp) {
return astFactory.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 astFactory.methodDeclaration(
null, null, null, st, rt, null, null, m, null, fl, body);
}
static FunctionExpression functionExpression(
FormalParameterList fl, FunctionBody body) {
return astFactory.functionExpression(null, fl, body);
}
static FunctionDeclarationStatement functionDeclarationStatement(
FunctionDeclaration fd) {
return astFactory.functionDeclarationStatement(fd);
}
static Statement returnExpression([Expression e]) {
Token ret = new KeywordToken(Keyword.RETURN, 0);
Token semi = new Token(TokenType.SEMICOLON, 0);
return astFactory.returnStatement(ret, e, semi);
}
static SimpleFormalParameter simpleFormalParameter(
SimpleIdentifier v, TypeName t) {
return astFactory.simpleFormalParameter(null, <Annotation>[], null, t, v);
}
static FunctionTypedFormalParameter functionTypedFormalParameter(
TypeName ret, SimpleIdentifier v, FormalParameterList ps) {
return astFactory.functionTypedFormalParameter(
null, <Annotation>[], ret, v, null, ps);
}
static FormalParameter requiredFormalParameter(NormalFormalParameter fp) {
return fp;
}
static FormalParameter optionalFormalParameter(NormalFormalParameter fp) {
return astFactory.defaultFormalParameter(
fp, ParameterKind.POSITIONAL, null, null);
}
static FormalParameter namedFormalParameter(NormalFormalParameter fp) {
return astFactory.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 = astFactory.label(s, new Token(TokenType.COLON, 0));
return astFactory.namedExpression(l, e);
}
static VariableDeclarationStatement variableDeclarationStatement(
VariableDeclarationList varDecl) {
var semi = new Token(TokenType.SEMICOLON, 0);
return astFactory.variableDeclarationStatement(varDecl, semi);
}
}