/*
* ASSourceFactory.java
*
* Copyright (c) 2006-2008 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;
import java.util.List;
import org.asdt.core.internal.antlr.AS3Parser;
import uk.co.badgersinfoil.metaas.dom.ASArrayAccessExpression;
import uk.co.badgersinfoil.metaas.dom.ASArrayLiteral;
import uk.co.badgersinfoil.metaas.dom.ASAssignmentExpression;
import uk.co.badgersinfoil.metaas.dom.ASBinaryExpression;
import uk.co.badgersinfoil.metaas.dom.ASBlock;
import uk.co.badgersinfoil.metaas.dom.ASBooleanLiteral;
import uk.co.badgersinfoil.metaas.dom.ASCompilationUnit;
import uk.co.badgersinfoil.metaas.dom.ASConditionalExpression;
import uk.co.badgersinfoil.metaas.dom.ASDescendantExpression;
import uk.co.badgersinfoil.metaas.dom.Expression;
import uk.co.badgersinfoil.metaas.dom.ASExpressionAttribute;
import uk.co.badgersinfoil.metaas.dom.ASFieldAccessExpression;
import uk.co.badgersinfoil.metaas.dom.ASFilterExpression;
import uk.co.badgersinfoil.metaas.dom.ASFunctionExpression;
import uk.co.badgersinfoil.metaas.dom.ASInvocationExpression;
import uk.co.badgersinfoil.metaas.dom.ASNewExpression;
import uk.co.badgersinfoil.metaas.dom.ASNullLiteral;
import uk.co.badgersinfoil.metaas.dom.ASObjectLiteral;
import uk.co.badgersinfoil.metaas.dom.ASPostfixExpression;
import uk.co.badgersinfoil.metaas.dom.ASPrefixExpression;
import uk.co.badgersinfoil.metaas.dom.ASPropertyAttribute;
import uk.co.badgersinfoil.metaas.dom.ASRegexpLiteral;
import uk.co.badgersinfoil.metaas.dom.ASSimpleNameExpression;
import uk.co.badgersinfoil.metaas.dom.ASStarAttribute;
import uk.co.badgersinfoil.metaas.dom.ASStringLiteral;
import uk.co.badgersinfoil.metaas.dom.ASIntegerLiteral;
import uk.co.badgersinfoil.metaas.dom.ASUndefinedLiteral;
import uk.co.badgersinfoil.metaas.dom.ASXMLLiteral;
import uk.co.badgersinfoil.metaas.impl.AS3FragmentParser;
import uk.co.badgersinfoil.metaas.impl.ASTASArrayAccessExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASArrayLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASBooleanLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASConditionalExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASDescendantExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASExpressionAttribute;
import uk.co.badgersinfoil.metaas.impl.ASTASFieldAccessExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASFilterExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASFunctionExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASIntegerLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASInvocationExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASNewExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASNullLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASObjectLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASPostfixExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASPrefixExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASPropertyAttribute;
import uk.co.badgersinfoil.metaas.impl.ASTASRegexpLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASSimpleNameExpression;
import uk.co.badgersinfoil.metaas.impl.ASTASStarAttribute;
import uk.co.badgersinfoil.metaas.impl.ASTASStringLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTASUndefinedLiteral;
import uk.co.badgersinfoil.metaas.impl.ASTActionScriptParser;
import uk.co.badgersinfoil.metaas.impl.ASTActionScriptProject;
import uk.co.badgersinfoil.metaas.impl.ASTActionScriptWriter;
import uk.co.badgersinfoil.metaas.impl.ASTBuilder;
import uk.co.badgersinfoil.metaas.impl.ASTStatementList;
import uk.co.badgersinfoil.metaas.impl.ASTUtils;
import uk.co.badgersinfoil.metaas.impl.ASTASXMLLiteral;
import uk.co.badgersinfoil.metaas.impl.ExpressionBuilder;
import uk.co.badgersinfoil.metaas.impl.TokenBuilder;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListToken;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListTree;
// TODO: an isKeyword(String) test would be nice
/**
* Core class providing access to metaas functionality.
*/
public class ActionScriptFactory {
/**
* Creates a new CompilationUnit which defines a class with the given
* name. To populate the new class, you can do something like,
* <pre>
* CompilationUnit cu = fact.newClass("MyTest");
* ASTClassType myclass = (ASTClassType)cu.getType();
* // ... add stuff to myclass ...
* </pre>
*/
public ASCompilationUnit newClass(String qualifiedClassName) {
return ASTBuilder.synthesizeClass(qualifiedClassName);
}
/**
* Creates a new CompilationUnit which defines an interface with the
* given name. To populate the new interface, you can do something
* like,
* <pre>
* CompilationUnit cu = fact.newClass("MyTest");
* ASTClassType myiface = (ASTInterfaceType)cu.getType();
* // ... add stuff to myiface ...
* </pre>
*/
public ASCompilationUnit newInterface(String qualifiedInterfaceName) {
return ASTBuilder.synthesizeInterface(qualifiedInterfaceName);
}
public ActionScriptWriter newWriter() {
return new ASTActionScriptWriter();
}
public ActionScriptParser newParser() {
return new ASTActionScriptParser();
}
/**
* Escape the given String and place within double quotes so that it
* will be a valid ActionScript string literal.
*/
public static String str(String str) {
StringBuffer result = new StringBuffer("\"");
for (int i=0; i<str.length(); i++) {
char c = str.charAt(i);
switch (c) {
case '\n':
result.append("\\n");
break;
case '\t':
result.append("\\t");
break;
case '\r':
result.append("\\r");
break;
case '"':
result.append("\\\"");
break;
case '\\':
result.append("\\\\");
break;
default:
result.append(c);
}
}
result.append('"');
return result.toString();
}
/**
* Creates a new ActionScript block statement. Can be supplied to an
* {@link uk.co.badgersinfoil.metaas.dom.ASIfStatement}, for instance.
*/
public ASBlock newBlock() {
LinkedListTree block = ASTBuilder.newBlock();
return new ASTStatementList(block);
}
public ActionScriptProject newEmptyASProject(String outputLocation) {
ASTActionScriptProject project = new ASTActionScriptProject(this);
project.setOutputLocation(outputLocation);
return project;
}
public ASStringLiteral newStringLiteral(String string) {
return new ASTASStringLiteral(ASTUtils.newAST(AS3Parser.STRING_LITERAL, str(string)));
}
public ASIntegerLiteral newIntegerLiteral(int i) {
return new ASTASIntegerLiteral(ASTUtils.newAST(AS3Parser.DECIMAL_LITERAL, String.valueOf(i)));
}
public ASNullLiteral newNullLiteral() {
return new ASTASNullLiteral(ASTUtils.newAST(AS3Parser.NULL, "null"));
}
public ASBooleanLiteral newBooleanLiteral(boolean b) {
LinkedListTree ast = b ? ASTUtils.newAST(AS3Parser.TRUE, "true")
: ASTUtils.newAST(AS3Parser.FALSE, "false");
return new ASTASBooleanLiteral(ast);
}
public ASUndefinedLiteral newUndefinedLiteral() {
return new ASTASUndefinedLiteral(ASTUtils.newAST(AS3Parser.UNDEFINED, "undefined"));
}
public ASBinaryExpression newAddExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newPlus(), left, right);
}
public ASBinaryExpression newAndExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newAnd(), left, right);
}
public ASBinaryExpression newBitAndExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newBitAnd(), left, right);
}
public ASBinaryExpression newBitOrExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newBitOr(), left, right);
}
public ASBinaryExpression newBitXorExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newBitXor(), left, right);
}
public ASBinaryExpression newDivisionExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newDiv(), left, right);
}
public ASBinaryExpression newEqualsExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newEquals(), left, right);
}
public ASBinaryExpression newGreaterEqualsExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newGreaterEquals(), left, right);
}
public ASBinaryExpression newGreaterThanExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newGreater(), left, right);
}
public ASBinaryExpression newLessEqualsExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newLessEquals(), left, right);
}
public ASBinaryExpression newLessThanExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newLess(), left, right);
}
public ASBinaryExpression newModuloExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newModulo(), left, right);
}
public ASBinaryExpression newMultiplyExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newMult(), left, right);
}
public ASBinaryExpression newNotEqualsExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newNotEquals(), left, right);
}
public ASBinaryExpression newOrExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newOr(), left, right);
}
public ASBinaryExpression newShiftLeftExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newShiftLeft(), left, right);
}
public ASBinaryExpression newShiftRightExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newShiftRight(), left, right);
}
public ASBinaryExpression newShiftRightUnsignedExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newShiftRightUnsigned(), left, right);
}
public ASBinaryExpression newSubtractExpression(Expression left, Expression right) {
return ASTBuilder.newBinaryExpression(TokenBuilder.newMinus(), left, right);
}
/**
*
* @throws SyntaxException if the given string is not a vaild
* ActionScript 3 expression.
*/
public Expression newExpression(String expr) {
LinkedListTree ast = AS3FragmentParser.parseExpr(expr);
// ANTLR creates a 'nil' parent node (in case the result is a
// list). We break the link to that parent because we assert
// the parent is null when child nodes are attached elsewhere
// in the tree.
ast.setParent(null);
return ExpressionBuilder.build(ast);
}
private ASPrefixExpression newPrefixExpression(LinkedListToken op, Expression sub) {
LinkedListTree ast = ASTUtils.newAST(op);
LinkedListTree subExpr = ast(sub);
ASTBuilder.assertNoParent("sub-expression", subExpr);
ast.addChildWithTokens(subExpr);
return new ASTASPrefixExpression(ast);
}
public ASPrefixExpression newPreDecExpression(Expression sub) {
return newPrefixExpression(TokenBuilder.newPreDec(), sub);
}
public ASPrefixExpression newPreIncExpression(Expression sub) {
return newPrefixExpression(TokenBuilder.newPreInc(), sub);
}
public ASPrefixExpression newPositiveExpression(Expression sub) {
return newPrefixExpression(TokenBuilder.newPlus(), sub);
}
public ASPrefixExpression newNegativeExpression(Expression sub) {
return newPrefixExpression(TokenBuilder.newMinus(), sub);
}
public ASPrefixExpression newNotExpression(Expression sub) {
return newPrefixExpression(TokenBuilder.newNot(), sub);
}
private ASPostfixExpression newPostfixExpression(LinkedListToken op, Expression sub) {
LinkedListTree ast = ASTUtils.newAST(op);
LinkedListTree subExpr = ast(sub);
ASTBuilder.assertNoParent("sub-expression", subExpr);
ast.addChild(subExpr);
ast.setStartToken(subExpr.getStartToken());
subExpr.getStopToken().setNext(op);
return new ASTASPostfixExpression(ast);
}
public ASPostfixExpression newPostDecExpression(Expression sub) {
return newPostfixExpression(TokenBuilder.newPostDec(), sub);
}
public ASPostfixExpression newPostIncExpression(Expression sub) {
return newPostfixExpression(TokenBuilder.newPostInc(), sub);
}
public ASNewExpression newNewExpression(Expression subexpression, List args) {
LinkedListTree ast = ASTUtils.newAST(AS3Parser.NEW, "new");
ast.appendToken(TokenBuilder.newSpace());
LinkedListTree subExpr = ast(subexpression);
ASTBuilder.assertNoParent("sub-expression", subExpr);
// TODO: recursively check the given subexpression
ast.addChildWithTokens(subExpr);
LinkedListTree arguments = ASTUtils.newParentheticAST(AS3Parser.ARGUMENTS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")");
ast.addChildWithTokens(arguments);
ASTASNewExpression result = new ASTASNewExpression(ast);
result.setArguments(args);
return result;
}
public ASInvocationExpression newInvocationExpression(Expression sub, List args) {
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.METHOD_CALL);
LinkedListTree subExpr = ast(sub);
ASTBuilder.assertNoParent("sub-expression", subExpr);
// TODO: recursively check the given subexpression
ast.addChildWithTokens(subExpr);
LinkedListTree arguments = ASTUtils.newParentheticAST(AS3Parser.ARGUMENTS, AS3Parser.LPAREN, "(", AS3Parser.RPAREN, ")");
ast.addChildWithTokens(arguments);
ASTASInvocationExpression result = new ASTASInvocationExpression(ast);
result.setArguments(args);
return result;
}
public ASArrayAccessExpression newArrayAccessExpression(Expression target,
Expression subscript)
{
LinkedListTree ast = ASTUtils.newImaginaryAST(AS3Parser.ARRAY_ACC);
LinkedListTree targetExpr = ast(target);
ASTBuilder.assertNoParent("target expression", targetExpr);
// TODO: recursively check the given subexpression
ast.addChildWithTokens(targetExpr);
ast.appendToken(TokenBuilder.newLBrack());
LinkedListTree subscriptExpr = ast(subscript);
ASTBuilder.assertNoParent("subscript expression", subscriptExpr);
ast.addChildWithTokens(subscriptExpr);
ast.appendToken(TokenBuilder.newRBrack());
ASTASArrayAccessExpression result = new ASTASArrayAccessExpression(ast);
return result;
}
public ASAssignmentExpression newAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newAssign(),
left, right);
}
public ASAssignmentExpression newAddAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newAddAssign(),
left, right);
}
public ASAssignmentExpression newBitAndAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newBitAndAssign(),
left, right);
}
public ASAssignmentExpression newBitOrAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newBitOrAssign(),
left, right);
}
public ASAssignmentExpression newBitXorAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newBitXorAssign(),
left, right);
}
public ASAssignmentExpression newDivideAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newDivAssign(),
left, right);
}
public ASAssignmentExpression newModuloAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newModAssign(),
left, right);
}
public ASAssignmentExpression newMultiplyAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newMulAssign(),
left, right);
}
public ASAssignmentExpression newShiftLeftAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newSLAssign(),
left, right);
}
public ASAssignmentExpression newShiftRightAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newSRAssign(),
left, right);
}
public ASAssignmentExpression newShiftRightUnsignedAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newSRUAssign(),
left, right);
}
public ASAssignmentExpression newSubtractAssignExpression(Expression left,
Expression right)
{
return ASTBuilder.newAssignExpression(TokenBuilder.newSubAssign(),
left, right);
}
public ASFieldAccessExpression newFieldAccessExpression(Expression target, String name) {
LinkedListTree ast
= ASTBuilder.newFieldAccessExpression(ast(target),
ASTUtils.newAST(AS3Parser.IDENT, name));
return new ASTASFieldAccessExpression(ast);
}
public ASConditionalExpression newConditionalExpression(Expression conditionExpr,
Expression thenExpr,
Expression elseExpr)
{
LinkedListTree ast
= ASTBuilder.newConditionalExpression(ast(conditionExpr),
ast(thenExpr),
ast(elseExpr));
return new ASTASConditionalExpression(ast);
}
private static LinkedListTree ast(Expression expr) {
return ASTUtils.ast(expr);
}
public ASFunctionExpression newFunctionExpression() {
LinkedListTree ast = ASTBuilder.newFunctionExpression();
return new ASTASFunctionExpression(ast);
}
/**
* @param entries a list of {@link Expression} objects.
*/
public ASArrayLiteral newArrayLiteral() {
LinkedListTree ast = ASTBuilder.newArrayLiteral();
return new ASTASArrayLiteral(ast);
}
public ASObjectLiteral newObjectLiteral() {
LinkedListTree ast = ASTBuilder.newObjectLiteral();
return new ASTASObjectLiteral(ast);
}
public ASXMLLiteral newXMLLiteral(String value) {
LinkedListTree ast = AS3FragmentParser.parseXMLLiteral(value);
return new ASTASXMLLiteral(ast);
}
public ASRegexpLiteral newRegexpLiteral(String value, int flags) {
StringBuffer flagList = new StringBuffer();
if ((flags & ASRegexpLiteral.FLAG_DOT_ALL) != 0) {
flagList.append('s');
}
if ((flags & ASRegexpLiteral.FLAG_EXTENDED) != 0) {
flagList.append('x');
}
if ((flags & ASRegexpLiteral.FLAG_GLOBAL) != 0) {
flagList.append('g');
}
if ((flags & ASRegexpLiteral.FLAG_IGNORE_CASE) != 0) {
flagList.append('i');
}
value = regexpEscapeDelimiter(value);
LinkedListTree ast = AS3FragmentParser.parseRegexpLiteral("/"+value+"/"+flagList);
return new ASTASRegexpLiteral(ast);
}
private static String regexpEscapeDelimiter(String value) {
StringBuffer result = new StringBuffer();
for (int i=0; i<value.length(); i++) {
char c = value.charAt(i);
switch (c) {
case '/': result.append("\\/"); break;
default: result.append(c); break;
}
}
return result.toString();
}
public Expression dup(Expression expr) {
LinkedListTree ast = ASTUtils.ast(expr);
return ExpressionBuilder.build(ASTBuilder.dup(ast));
}
public ASDescendantExpression newDescendantExpression(Expression target,
Expression selector)
{
LinkedListTree ast
= ASTBuilder.newDescendantExpression(ast(target),
ast(selector));
return new ASTASDescendantExpression(ast);
}
public ASFilterExpression newFilterExpression(Expression target,
Expression selector)
{
LinkedListTree ast
= ASTBuilder.newFilterExpression(ast(target),
ast(selector));
return new ASTASFilterExpression(ast);
}
public ASStarAttribute newStarAttribute() {
LinkedListTree ast = ASTBuilder.newStarAttribute();
return new ASTASStarAttribute(ast);
}
public ASPropertyAttribute newPropertyAttribute(String propertyName) {
LinkedListTree ast = ASTBuilder.newPropertyAttribute(propertyName);
return new ASTASPropertyAttribute(ast);
}
public ASExpressionAttribute newExpressionAttribute(Expression expr) {
LinkedListTree ast = ASTBuilder.newExpressionAttribute(ast(expr));
return new ASTASExpressionAttribute(ast);
}
public ASSimpleNameExpression newSimpleName(String name) {
LinkedListTree ast = AS3FragmentParser.parseSimpleIdent(name);
return new ASTASSimpleNameExpression(ast);
}
}