/*
* ASTBuilder.java
*
* Copyright (c) 2006-2007 David Holroyd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.co.badgersinfoil.metaas.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.asdt.core.internal.antlr.AS3Parser;
import uk.co.badgersinfoil.metaas.ActionScriptFactory;
import uk.co.badgersinfoil.metaas.SyntaxException;
import uk.co.badgersinfoil.metaas.dom.ASAssignmentExpression;
import uk.co.badgersinfoil.metaas.dom.ASBinaryExpression;
import uk.co.badgersinfoil.metaas.dom.ASCompilationUnit;
import uk.co.badgersinfoil.metaas.dom.Expression;
import uk.co.badgersinfoil.metaas.dom.Visibility;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListToken;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListTree;
import uk.co.badgersinfoil.metaas.impl.antlr.PlaceholderLinkedListToken;
/**
* Utilities to build and assemble Abstract Syntax Tree fragments for inclusion
* into the compilation unit being generated.
*/
public class ASTBuilder {
private ASTBuilder() {
// hide default ctor
}
public static LinkedListTree newExprStmt(LinkedListTree expr) {
LinkedListTree exprStmt = ASTUtils.newImaginaryAST(AS3Parser.EXPR_STMNT);
exprStmt.addChildWithTokens(expr);
exprStmt.appendToken(TokenBuilder.newSemi());
return exprStmt;
}
public static AS3ASTCompilationUnit synthesizeClass(String qualifiedName) {
LinkedListTree unit = ASTUtils.newImaginaryAST(AS3Parser.COMPILATION_UNIT);
LinkedListTree pkg = ASTUtils.newAST(AS3Parser.PACKAGE, "package");
pkg.appendToken(TokenBuilder.newSpace());
unit.addChildWithTokens(pkg);
pkg.appendToken(TokenBuilder.newSpace());
String packageName = packageNameFrom(qualifiedName);
if (packageName != null) {
pkg.addChildWithTokens(AS3FragmentParser.parseIdent(packageName));
}
LinkedListTree packageBlock = newBlock();
pkg.addChildWithTokens(packageBlock);
String className = typeNameFrom(qualifiedName);
LinkedListTree clazz = synthesizeAS3Class(className);
ASTUtils.addChildWithIndentation(packageBlock, clazz);
return new AS3ASTCompilationUnit(unit);
}
public static ASCompilationUnit synthesizeInterface(String qualifiedName) {
LinkedListTree unit = ASTUtils.newImaginaryAST(AS3Parser.COMPILATION_UNIT);
LinkedListTree pkg = ASTUtils.newAST(AS3Parser.PACKAGE, "package");
unit.addChildWithTokens(pkg);
pkg.appendToken(TokenBuilder.newSpace());
String packageName = packageNameFrom(qualifiedName);
if (packageName != null) {
pkg.addChildWithTokens(AS3FragmentParser.parseIdent(packageName));
}
LinkedListTree packageBlock = newBlock();
pkg.addChildWithTokens(packageBlock);
LinkedListTree iface = synthesizeAS3Interface(qualifiedName);
ASTUtils.addChildWithIndentation(packageBlock, iface);
return new AS3ASTCompilationUnit(unit);
}
private static LinkedListTree synthesizeAS3Interface(String qualifiedName) {
LinkedListTree iface = ASTUtils.newImaginaryAST(AS3Parser.INTERFACE_DEF);
LinkedListTree modifiers = ASTUtils.newImaginaryAST(AS3Parser.MODIFIERS);
iface.addChildWithTokens(modifiers);
modifiers.addChildWithTokens(ASTUtils.newAST(AS3Parser.PUBLIC, "public"));
modifiers.appendToken(TokenBuilder.newSpace());
iface.appendToken(TokenBuilder.newInterface());
iface.appendToken(TokenBuilder.newSpace());
iface.addChildWithTokens(ASTUtils.newAST(AS3Parser.IDENT, typeNameFrom(qualifiedName)));
iface.appendToken(TokenBuilder.newSpace());
iface.addChildWithTokens(newTypeBlock());
LinkedListTree annos = ASTUtils.newPlaceholderAST(AS3Parser.ANNOTATIONS);
iface.addChildWithTokens(0, annos);
return iface;
}
private static String typeNameFrom(String qualifiedName) {
int p = qualifiedName.lastIndexOf('.');
if (p == -1) {
return qualifiedName;
}
return qualifiedName.substring(p+1);
}
private static LinkedListTree synthesizeAS3Class(String className) {
LinkedListTree clazz = ASTUtils.newImaginaryAST(AS3Parser.CLASS_DEF);
LinkedListTree modifiers = ASTUtils.newImaginaryAST(AS3Parser.MODIFIERS);
clazz.addChildWithTokens(modifiers);
LinkedListTree modPublic = ASTUtils.newAST(AS3Parser.PUBLIC, "public");
modifiers.addChildWithTokens(modPublic);
modifiers.appendToken(TokenBuilder.newSpace());
clazz.appendToken(TokenBuilder.newClass());
clazz.appendToken(TokenBuilder.newSpace());
clazz.addChildWithTokens(ASTUtils.newAST(AS3Parser.IDENT, className));
clazz.appendToken(TokenBuilder.newSpace());
clazz.addChildWithTokens(newTypeBlock());
LinkedListTree annos = ASTUtils.newPlaceholderAST(AS3Parser.ANNOTATIONS);
clazz.addChildWithTokens(0, annos);
return clazz;
}
private static String packageNameFrom(String qualifiedName) {
int p = qualifiedName.lastIndexOf('.');
if (p == -1) {
return null;
}
return qualifiedName.substring(0, p);
}
public static ASTASMethod newClassMethod(String name, Visibility visibility, String returnType) {
LinkedListTree def = ASTUtils.newImaginaryAST(AS3Parser.METHOD_DEF);
LinkedListTree annos = ASTUtils.newPlaceholderAST(AS3Parser.ANNOTATIONS);
def.addChildWithTokens(annos);
def.addChildWithTokens(ModifierUtils.toModifiers(visibility));
def.appendToken(TokenBuilder.newFunction());
def.appendToken(TokenBuilder.newSpace());
LinkedListTree acc = ASTUtils.newPlaceholderAST(AS3Parser.ACCESSOR_ROLE);
def.addChildWithTokens(acc);
LinkedListTree methName = ASTUtils.newAST(AS3Parser.IDENT, name);
def.addChildWithTokens(methName);
def.addChildWithTokens(ASTUtils.newParentheticAST(AS3Parser.PARAMS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")"));
if (returnType != null) {
def.addChildWithTokens(AS3FragmentParser.parseTypeSpec(returnType));
}
def.appendToken(TokenBuilder.newSpace());
LinkedListTree block = newBlock();
def.addChildWithTokens(block);
return new ASTASMethod(def);
}
public static ASTASField newField(String name, Visibility visibility, String type) {
if (name.indexOf('.') != -1) {
throw new SyntaxException("field name must not contain '.'");
}
LinkedListTree decl = ASTUtils.newImaginaryAST(AS3Parser.VAR_DEF);
LinkedListTree annos = ASTUtils.newPlaceholderAST(AS3Parser.ANNOTATIONS);
decl.addChildWithTokens(annos);
decl.addChildWithTokens(ModifierUtils.toModifiers(visibility));
decl.addChildWithTokens(ASTUtils.newAST(AS3Parser.VAR, "var"));
decl.appendToken(TokenBuilder.newSpace());
LinkedListTree def = ASTUtils.newAST(AS3Parser.IDENT, name);
decl.addChildWithTokens(def);
if (type != null) {
def.addChildWithTokens(AS3FragmentParser.parseTypeSpec(type));
}
decl.appendToken(TokenBuilder.newSemi());
return new ASTASField(decl);
}
public static ASTASMethod newInterfaceMethod(String name, Visibility visibility, String returnType) {
LinkedListTree def = ASTUtils.newImaginaryAST(AS3Parser.METHOD_DEF);
LinkedListTree annos = ASTUtils.newPlaceholderAST(AS3Parser.ANNOTATIONS);
def.addChildWithTokens(annos);
def.addChildWithTokens(ModifierUtils.toModifiers(visibility));
def.appendToken(TokenBuilder.newFunction());
def.appendToken(TokenBuilder.newSpace());
LinkedListTree acc = ASTUtils.newPlaceholderAST(AS3Parser.ACCESSOR_ROLE);
def.addChildWithTokens(acc);
LinkedListTree methName = ASTUtils.newAST(AS3Parser.IDENT, name);
def.addChildWithTokens(methName);
def.addChildWithTokens(ASTUtils.newParentheticAST(AS3Parser.PARAMS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")"));
if (returnType != null) {
def.addChildWithTokens(AS3FragmentParser.parseTypeSpec(returnType));
}
def.appendToken(TokenBuilder.newSemi());
return new ASTASMethod(def);
}
public static LinkedListTree newBlock() {
return newBlock(AS3Parser.BLOCK);
}
public static LinkedListTree newTypeBlock() {
return newBlock(AS3Parser.TYPE_BLOCK);
}
private static LinkedListTree newBlock(int type) {
LinkedListTree ast = ASTUtils.newParentheticAST(type,
AS3Parser.LCURLY, "{",
AS3Parser.RCURLY, "}");
LinkedListToken nl = TokenBuilder.newNewline();
ast.getInitialInsertionAfter().afterInsert(nl);
ast.setInitialInsertionAfter(nl);
return ast;
}
public static LinkedListTree newMetadataTag(String name) {
LinkedListTree ast = ASTUtils.newParentheticAST(AS3Parser.ANNOTATION,
AS3Parser.LBRACK, "[",
AS3Parser.RBRACK, "]");
ast.addChildWithTokens(ASTUtils.newAST(AS3Parser.IDENT, name));
return ast;
}
/**
* returns a CONDITION node with the given expression as its child
*/
private static LinkedListTree condition(LinkedListTree expr) {
LinkedListTree cond = ASTUtils.newParentheticAST(AS3Parser.CONDITION,
AS3Parser.LPAREN, "(",
AS3Parser.RPAREN, ")");
cond.addChildWithTokens(expr);
return cond;
}
public static LinkedListTree newIf(String condition) {
return newIf(AS3FragmentParser.parseExpr(condition));
}
public static LinkedListTree newIf(LinkedListTree condition) {
LinkedListTree ifStmt = ASTUtils.newAST(AS3Parser.IF, "if");
ifStmt.appendToken(TokenBuilder.newSpace());
ifStmt.addChildWithTokens(condition(condition));
ifStmt.appendToken(TokenBuilder.newSpace());
ifStmt.addChildWithTokens(ASTBuilder.newBlock());
return ifStmt;
}
public static LinkedListTree newFor(String init, String condition, String iterate) {
return newFor(init==null ? null : AS3FragmentParser.parseForInit(init),
condition==null ? null : AS3FragmentParser.parseForCond(condition),
iterate==null ? null : AS3FragmentParser.parseForIter(iterate));
}
public static LinkedListTree newFor(LinkedListTree init, LinkedListTree condition, LinkedListTree iterate) {
LinkedListTree forStmt = ASTUtils.newAST(AS3Parser.FOR, "for");
forStmt.appendToken(TokenBuilder.newSpace());
forStmt.appendToken(TokenBuilder.newLParen());
if (init != null) {
forStmt.addChildWithTokens(init);
} else {
LinkedListTree initStmt = ASTUtils.newPlaceholderAST(AS3Parser.FOR_INIT);
forStmt.addChildWithTokens(initStmt);
}
forStmt.appendToken(TokenBuilder.newSemi());
forStmt.appendToken(TokenBuilder.newSpace());
if (condition != null) {
forStmt.addChildWithTokens(condition);
} else {
LinkedListTree condStmt = ASTUtils.newPlaceholderAST(AS3Parser.FOR_CONDITION);
forStmt.addChildWithTokens(condStmt);
}
forStmt.appendToken(TokenBuilder.newSemi());
forStmt.appendToken(TokenBuilder.newSpace());
if (iterate != null) {
forStmt.addChildWithTokens(iterate);
} else {
LinkedListTree iterStmt = ASTUtils.newPlaceholderAST(AS3Parser.FOR_ITERATOR);
forStmt.addChildWithTokens(iterStmt);
}
forStmt.appendToken(TokenBuilder.newRParen());
return forStmt;
}
public static LinkedListTree newForIn(String declaration, String expression) {
return newForIn(AS3FragmentParser.parseForInVar(declaration),
AS3FragmentParser.parseExpr(expression));
}
public static LinkedListTree newForIn(LinkedListTree declaration, LinkedListTree expression) {
LinkedListTree forStmt = ASTUtils.newAST(AS3Parser.FOR_IN, "for");
forStmt.appendToken(TokenBuilder.newSpace());
genForInSetup(forStmt, declaration, expression);
return forStmt;
}
public static LinkedListTree newForEachIn(String declaration, String expression) {
return newForEachIn(AS3FragmentParser.parseForInVar(declaration),
AS3FragmentParser.parseExpr(expression));
}
public static LinkedListTree newForEachIn(LinkedListTree declaration, LinkedListTree expression) {
LinkedListTree forStmt = ASTUtils.newAST(AS3Parser.FOR_EACH, "for");
forStmt.appendToken(TokenBuilder.newSpace());
forStmt.appendToken(TokenBuilder.newEach());
genForInSetup(forStmt, declaration, expression);
return forStmt;
}
/**
* Common code for both for-in and for-each-in loop setup
*/
private static void genForInSetup(LinkedListTree forStmt,
LinkedListTree declaration,
LinkedListTree expression)
{
forStmt.appendToken(TokenBuilder.newLParen());
forStmt.addChildWithTokens(declaration);
forStmt.appendToken(TokenBuilder.newSpace());
forStmt.appendToken(TokenBuilder.newIn());
forStmt.appendToken(TokenBuilder.newSpace());
forStmt.addChildWithTokens(expression);
forStmt.appendToken(TokenBuilder.newRParen());
}
public static LinkedListTree newWhile(String condition) {
return newWhile(AS3FragmentParser.parseExpr(condition));
}
public static LinkedListTree newWhile(LinkedListTree condition) {
LinkedListTree whileStmt = ASTUtils.newAST(AS3Parser.WHILE, "while");
whileStmt.appendToken(TokenBuilder.newSpace());
whileStmt.addChildWithTokens(condition(condition));
return whileStmt;
}
public static LinkedListTree newDoWhile(String condition) {
return newDoWhile(AS3FragmentParser.parseExpr(condition));
}
public static LinkedListTree newDoWhile(LinkedListTree condition) {
LinkedListTree doWhileStmt = ASTUtils.newAST(AS3Parser.DO, "do");
doWhileStmt.appendToken(TokenBuilder.newSpace());
LinkedListTree block = ASTBuilder.newBlock();
doWhileStmt.addChildWithTokens(block);
doWhileStmt.appendToken(TokenBuilder.newSpace());
doWhileStmt.appendToken(TokenBuilder.newWhile());
doWhileStmt.appendToken(TokenBuilder.newSpace());
doWhileStmt.addChildWithTokens(condition(condition));
doWhileStmt.appendToken(TokenBuilder.newSemi());
return doWhileStmt;
}
public static LinkedListTree newSwitch(String condition) {
return newSwitch(AS3FragmentParser.parseExpr(condition));
}
public static LinkedListTree newSwitch(LinkedListTree condition) {
LinkedListTree switchStmt = ASTUtils.newAST(AS3Parser.SWITCH, "switch");
switchStmt.appendToken(TokenBuilder.newSpace());
switchStmt.addChildWithTokens(condition(condition));
switchStmt.appendToken(TokenBuilder.newSpace());
LinkedListTree block = ASTBuilder.newBlock();
switchStmt.addChildWithTokens(block);
return switchStmt;
}
public static LinkedListTree newWith(String expr) {
return newWith(AS3FragmentParser.parseExpr(expr));
}
public static LinkedListTree newWith(LinkedListTree expr) {
LinkedListTree withStmt = ASTUtils.newAST(AS3Parser.WITH, "with");
withStmt.appendToken(TokenBuilder.newSpace());
withStmt.addChildWithTokens(condition(expr));
return withStmt;
}
public static LinkedListTree newDeclaration(String assignment) {
return newDeclaration(AS3FragmentParser.parseVariableDeclarator(assignment));
}
public static LinkedListTree newDeclaration(LinkedListTree assignment) {
LinkedListTree declStmt = ASTUtils.newAST(AS3Parser.VAR, "var");
declStmt.appendToken(TokenBuilder.newSpace());
declStmt.addChildWithTokens(assignment);
declStmt.appendToken(TokenBuilder.newSemi());
return declStmt;
}
public static LinkedListTree newReturn(String expr) {
return newReturn(expr==null ? null : AS3FragmentParser.parseExpr(expr));
}
public static LinkedListTree newReturn(LinkedListTree expr) {
LinkedListTree returnStmt = ASTUtils.newAST(AS3Parser.RETURN, "return");
if (expr != null) {
returnStmt.appendToken(TokenBuilder.newSpace());
returnStmt.addChildWithTokens(expr);
}
returnStmt.appendToken(TokenBuilder.newSemi());
return returnStmt;
}
/**
* @param args a list of ASExpression objects
*/
public static LinkedListTree newSuperStatement(List args) {
LinkedListTree superStmt = ASTUtils.newAST(AS3Parser.SUPER, "super");
LinkedListTree argumentsNode = ASTUtils.newParentheticAST(AS3Parser.ARGUMENTS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")");
ArgumentUtils.overwriteArgsWithExpressionList(argumentsNode, args);
superStmt.addChildWithTokens(argumentsNode);
superStmt.appendToken(TokenBuilder.newSemi());
return superStmt;
}
public static LinkedListTree newBreakStatement() {
LinkedListTree breakStmt = ASTUtils.newAST(AS3Parser.BREAK, "break");
breakStmt.appendToken(TokenBuilder.newSemi());
return breakStmt;
}
public static LinkedListTree newTryStatement() {
LinkedListTree tryStmt = ASTUtils.newAST(AS3Parser.TRY, "try");
tryStmt.appendToken(TokenBuilder.newSpace());
tryStmt.addChildWithTokens(newBlock());
return tryStmt;
}
public static LinkedListTree newCatchClause(String var, String type) {
LinkedListTree tryStmt = ASTUtils.newAST(AS3Parser.CATCH, "catch");
tryStmt.appendToken(TokenBuilder.newSpace());
tryStmt.appendToken(TokenBuilder.newLParen());
tryStmt.addChildWithTokens(AS3FragmentParser.parseSimpleIdent(var));
if (type != null) {
tryStmt.addChildWithTokens(AS3FragmentParser.parseTypeSpec(type));
}
tryStmt.appendToken(TokenBuilder.newRParen());
tryStmt.appendToken(TokenBuilder.newSpace());
tryStmt.addChildWithTokens(newBlock());
return tryStmt;
}
public static LinkedListTree newFinallyClause() {
LinkedListTree tryStmt = ASTUtils.newAST(AS3Parser.FINALLY, "finally");
tryStmt.appendToken(TokenBuilder.newSpace());
tryStmt.addChildWithTokens(newBlock());
return tryStmt;
}
public static LinkedListTree newContinueStatement() {
LinkedListTree continueStmt = ASTUtils.newAST(AS3Parser.CONTINUE, "continue");
continueStmt.appendToken(TokenBuilder.newSemi());
return continueStmt;
}
public static ASBinaryExpression newBinaryExpression(LinkedListToken op, Expression left, Expression right) {
LinkedListTree ast = ASTUtils.newAST(op);
LinkedListTree leftExpr = ((ASTExpression)left).getAST();
assertNoParent("left-hand expression", leftExpr);
LinkedListTree rightExpr = ((ASTExpression)right).getAST();
if (precidence(ast) < precidence(leftExpr)) {
leftExpr = parenthise(leftExpr);
}
if (precidence(ast) < precidence(rightExpr)) {
rightExpr = parenthise(rightExpr);
}
// don't use addChildWithTokens(); special handling below,
ast.addChild(leftExpr);
ast.addChild(rightExpr);
leftExpr.getStopToken().setNext(op);
rightExpr.getStartToken().setPrev(op);
ast.setStartToken(leftExpr.getStartToken());
ast.setStopToken(rightExpr.getStopToken());
spaceEitherSide(op);
return new ASTASBinaryExpression(ast);
}
public static ASAssignmentExpression newAssignExpression(LinkedListToken op, Expression left, Expression right) {
LinkedListTree ast = ASTUtils.newAST(op);
LinkedListTree leftExpr = ((ASTExpression)left).getAST();
assertNoParent("left-hand expression", leftExpr);
LinkedListTree rightExpr = ((ASTExpression)right).getAST();
if (precidence(ast) < precidence(leftExpr)) {
leftExpr = parenthise(leftExpr);
}
if (precidence(ast) < precidence(rightExpr)) {
rightExpr = parenthise(rightExpr);
}
// don't use addChildWithTokens(); special handling below,
ast.addChild(leftExpr);
ast.addChild(rightExpr);
leftExpr.getStopToken().setNext(op);
rightExpr.getStartToken().setPrev(op);
ast.setStartToken(leftExpr.getStartToken());
ast.setStopToken(rightExpr.getStopToken());
spaceEitherSide(op);
return new ASTASAssignmentExpression(ast);
}
public static void assertNoParent(String astDescription, LinkedListTree ast)
{
if (ast.getParent() != null) {
throw new SyntaxException(astDescription+" cannot be added to a second parent node");
}
}
private static LinkedListTree parenthise(LinkedListTree expr) {
LinkedListTree result = ASTUtils.newParentheticAST(AS3Parser.ENCPS_EXPR, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")");
result.addChildWithTokens(expr);
return result;
}
private static int precidence(LinkedListTree ast) {
switch (ast.getType()) {
case AS3Parser.ASSIGN:
case AS3Parser.STAR_ASSIGN:
case AS3Parser.DIV_ASSIGN:
case AS3Parser.MOD_ASSIGN:
case AS3Parser.PLUS_ASSIGN:
case AS3Parser.MINUS_ASSIGN:
case AS3Parser.SL_ASSIGN:
case AS3Parser.SR_ASSIGN:
case AS3Parser.BSR_ASSIGN:
case AS3Parser.BAND_ASSIGN:
case AS3Parser.BXOR_ASSIGN:
case AS3Parser.BOR_ASSIGN:
case AS3Parser.LAND_ASSIGN:
case AS3Parser.LOR_ASSIGN:
return 13;
case AS3Parser.QUESTION:
return 12;
case AS3Parser.LOR:
return 11;
case AS3Parser.LAND:
return 10;
case AS3Parser.BOR:
return 9;
case AS3Parser.BXOR:
return 8;
case AS3Parser.BAND:
return 7;
case AS3Parser.STRICT_EQUAL:
case AS3Parser.STRICT_NOT_EQUAL:
case AS3Parser.NOT_EQUAL:
case AS3Parser.EQUAL:
return 6;
case AS3Parser.IN:
case AS3Parser.LT:
case AS3Parser.GT:
case AS3Parser.LE:
case AS3Parser.GE:
case AS3Parser.IS:
case AS3Parser.AS:
case AS3Parser.INSTANCEOF:
return 5;
case AS3Parser.SL:
case AS3Parser.SR:
case AS3Parser.BSR:
return 4;
case AS3Parser.PLUS:
case AS3Parser.MINUS:
return 3;
case AS3Parser.STAR:
case AS3Parser.DIV:
case AS3Parser.MOD:
return 2;
default:
return 1;
}
}
public static LinkedListTree newFieldAccessExpression(LinkedListTree target, LinkedListTree name) {
LinkedListToken op = TokenBuilder.newDot();
LinkedListTree ast = ASTUtils.newAST(op);
assertNoParent("target expression", target);
// don't use addChildWithTokens(); special handling below,
ast.addChild(target);
ast.addChild(name);
target.getStopToken().setNext(op);
name.getStartToken().setPrev(op);
ast.setStartToken(target.getStartToken());
ast.setStopToken(name.getStopToken());
return ast;
}
public static LinkedListTree newConditionalExpression(LinkedListTree conditionExpr,
LinkedListTree thenExpr,
LinkedListTree elseExpr)
{
LinkedListToken op = TokenBuilder.newQuestion();
LinkedListToken colon = TokenBuilder.newColon();
LinkedListTree ast = ASTUtils.newAST(op);
// don't use addChildWithTokens(); special handling below,
ast.addChild(conditionExpr);
conditionExpr.getStopToken().setNext(op);
ast.addChild(thenExpr);
thenExpr.getStartToken().setPrev(op);
thenExpr.getStopToken().setNext(colon);
ast.addChild(elseExpr);
elseExpr.getStartToken().setPrev(colon);
ast.setStartToken(conditionExpr.getStartToken());
ast.setStopToken(elseExpr.getStopToken());
spaceEitherSide(op);
spaceEitherSide(colon);
return ast;
}
private static void spaceEitherSide(LinkedListToken token) {
token.beforeInsert(TokenBuilder.newSpace());
token.afterInsert(TokenBuilder.newSpace());
}
public static LinkedListTree newFunctionExpression() {
LinkedListTree def = ASTUtils.newImaginaryAST(AS3Parser.FUNC_DEF);
def.appendToken(TokenBuilder.newFunction());
def.appendToken(TokenBuilder.newSpace());
// TODO: placeholder for name?
def.addChildWithTokens(ASTUtils.newParentheticAST(AS3Parser.PARAMS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")"));
def.appendToken(TokenBuilder.newSpace());
LinkedListTree block = newBlock();
def.addChildWithTokens(block);
return def;
}
public static LinkedListTree newArrayLiteral() {
LinkedListTree lit = ASTUtils.newParentheticAST(AS3Parser.ARRAY_LITERAL, AS3Parser.LBRACK, "[", AS3Parser.RBRACK, "]");
return lit;
}
public static LinkedListTree newObjectLiteral() {
LinkedListTree lit = newBlock(AS3Parser.OBJECT_LITERAL);
return lit;
}
public static LinkedListTree newObjectField(String name,
LinkedListTree value)
{
LinkedListTree field = ASTUtils.newImaginaryAST(AS3Parser.OBJECT_FIELD);
field.addChildWithTokens(AS3FragmentParser.parseSimpleIdent(name));
field.appendToken(TokenBuilder.newColon());
field.appendToken(TokenBuilder.newSpace());
field.addChildWithTokens(value);
return field;
}
public static LinkedListTree newThrowStatement(LinkedListTree ast) {
LinkedListTree thrw = ASTUtils.newAST(AS3Parser.THROW, "throw");
thrw.appendToken(TokenBuilder.newSpace());
thrw.addChildWithTokens(ast);
thrw.appendToken(TokenBuilder.newSemi());
return thrw;
}
public static LinkedListTree dup(LinkedListTree ast) {
Map tokens = dupTokStream(ast);
return dupTree(ast, tokens);
}
private static LinkedListTree dupTree(LinkedListTree ast, Map tokens) {
LinkedListToken newTok = (LinkedListToken)tokens.get(ast.getToken());
LinkedListTree result = new LinkedListTree(newTok);
result.setStartToken((LinkedListToken)tokens.get(ast.getStartToken()));
result.setStopToken((LinkedListToken)tokens.get(ast.getStopToken()));
result.setTokenListUpdater(ast.getTokenListUpdater());
result.setInitialInsertionAfter(ast.getInitialInsertionAfter());
result.setInitialInsertionBefore(ast.getInitialInsertionBefore());
for (ASTIterator i=new ASTIterator(ast); i.hasNext(); ) {
LinkedListTree newChild = dupTree(i.next(), tokens);
result.addChild(newChild);
}
return result;
}
private static Map dupTokStream(LinkedListTree ast) {
Map tokens = new HashMap();
LinkedListToken last = null;
for (LinkedListToken tok=ast.getStartToken(); tok!=null&&tok.getType()!=-1; tok=tok.getNext()) {
LinkedListToken newTok = dupTok(tok);
tokens.put(tok, newTok);
if (last != null) {
last.setNext(newTok);
}
if (tok == ast.getStopToken()) {
break;
}
last = newTok;
}
return tokens;
}
private static LinkedListToken dupTok(LinkedListToken tok) {
LinkedListToken result;
if (tok instanceof PlaceholderLinkedListToken) {
result = new PlaceholderLinkedListToken(((PlaceholderLinkedListToken)tok).getHeld());
} else {
result = new LinkedListToken(tok.getType(),
tok.getText());
}
result.setChannel(tok.getChannel());
result.setCharPositionInLine(tok.getCharPositionInLine());
result.setLine(tok.getLine());
return result;
}
public static LinkedListTree newDescendantExpression(LinkedListTree target,
LinkedListTree selector)
{
LinkedListToken op = TokenBuilder.newE4XDescendant();
LinkedListTree ast = ASTUtils.newAST(op);
assertNoParent("left-hand expression", target);
// TODO: is this needed..?
if (precidence(ast) < precidence(target)) {
target = parenthise(target);
}
if (precidence(ast) < precidence(selector)) {
selector = parenthise(selector);
}
// don't use addChildWithTokens(); special handling below,
ast.addChild(target);
ast.addChild(selector);
target.getStopToken().setNext(op);
selector.getStartToken().setPrev(op);
ast.setStartToken(target.getStartToken());
ast.setStopToken(selector.getStopToken());
return ast;
}
public static LinkedListTree newFilterExpression(LinkedListTree target,
LinkedListTree selector)
{
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.E4X_FILTER);
assertNoParent("target expression", target);
assertNoParent("query expression", target);
// don't use addChildWithTokens(); special handling below,
ast.addChildWithTokens(target);
ast.appendToken(TokenBuilder.newDot());
ast.appendToken(TokenBuilder.newLParen());
ast.addChildWithTokens(selector);
ast.appendToken(TokenBuilder.newRParen());
return ast;
}
public static LinkedListTree newStarAttribute() {
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.E4X_ATTRI_STAR);
ast.appendToken(TokenBuilder.newAt());
ast.appendToken(TokenBuilder.newStar());
return ast;
}
public static LinkedListTree newPropertyAttribute(String propertyName) {
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.E4X_ATTRI_PROPERTY);
ast.appendToken(TokenBuilder.newAt());
LinkedListTree prop = AS3FragmentParser.parseQualifiedIdent(propertyName);
ast.addChildWithTokens(prop);
return ast;
}
public static LinkedListTree newExpressionAttribute(LinkedListTree expr) {
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.E4X_ATTRI_EXPR);
ast.appendToken(TokenBuilder.newAt());
ast.appendToken(TokenBuilder.newLBrack());
ast.addChildWithTokens(expr);
ast.appendToken(TokenBuilder.newRBrack());
return ast;
}
public static LinkedListTree newString(String value) {
return ASTUtils.newAST(AS3Parser.STRING_LITERAL, ActionScriptFactory.str(value));
}
public static LinkedListTree newDefaultXMLNamespace(LinkedListTree namespace) {
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.DEFAULT_XML_NAMESPACE);
ast.appendToken(TokenBuilder.newDefault());
ast.appendToken(TokenBuilder.newSpace());
ast.appendToken(TokenBuilder.newXml());
ast.appendToken(TokenBuilder.newSpace());
ast.appendToken(TokenBuilder.newNamespace());
ast.appendToken(TokenBuilder.newSpace());
ast.appendToken(TokenBuilder.newAssign());
ast.appendToken(TokenBuilder.newSpace());
ast.addChildWithTokens(namespace);
ast.appendToken(TokenBuilder.newSemi());
return ast;
}
}