Package org.stjs.generator.javascript.rhino

Source Code of org.stjs.generator.javascript.rhino.RhinoJavaScriptBuilder

package org.stjs.generator.javascript.rhino;

import java.io.File;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;

import org.mozilla.javascript.Token.CommentType;
import org.mozilla.javascript.ast.ArrayLiteral;
import org.mozilla.javascript.ast.Assignment;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.Block;
import org.mozilla.javascript.ast.BreakStatement;
import org.mozilla.javascript.ast.CatchClause;
import org.mozilla.javascript.ast.Comment;
import org.mozilla.javascript.ast.ConditionalExpression;
import org.mozilla.javascript.ast.ContinueStatement;
import org.mozilla.javascript.ast.DoLoop;
import org.mozilla.javascript.ast.ElementGet;
import org.mozilla.javascript.ast.EmptyExpression;
import org.mozilla.javascript.ast.EmptyStatement;
import org.mozilla.javascript.ast.ExpressionStatement;
import org.mozilla.javascript.ast.ForInLoop;
import org.mozilla.javascript.ast.ForLoop;
import org.mozilla.javascript.ast.FunctionCall;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.IfStatement;
import org.mozilla.javascript.ast.InfixExpression;
import org.mozilla.javascript.ast.KeywordLiteral;
import org.mozilla.javascript.ast.Label;
import org.mozilla.javascript.ast.LabeledStatement;
import org.mozilla.javascript.ast.Name;
import org.mozilla.javascript.ast.NewExpression;
import org.mozilla.javascript.ast.NumberLiteral;
import org.mozilla.javascript.ast.ObjectLiteral;
import org.mozilla.javascript.ast.ObjectProperty;
import org.mozilla.javascript.ast.ParenthesizedExpression;
import org.mozilla.javascript.ast.PropertyGet;
import org.mozilla.javascript.ast.ReturnStatement;
import org.mozilla.javascript.ast.StringLiteral;
import org.mozilla.javascript.ast.SwitchCase;
import org.mozilla.javascript.ast.SwitchStatement;
import org.mozilla.javascript.ast.ThrowStatement;
import org.mozilla.javascript.ast.TryStatement;
import org.mozilla.javascript.ast.UnaryExpression;
import org.mozilla.javascript.ast.VariableDeclaration;
import org.mozilla.javascript.ast.VariableInitializer;
import org.mozilla.javascript.ast.WhileLoop;
import org.stjs.generator.STJSRuntimeException;
import org.stjs.generator.javascript.AssignOperator;
import org.stjs.generator.javascript.BinaryOperator;
import org.stjs.generator.javascript.JavaScriptBuilder;
import org.stjs.generator.javascript.Keyword;
import org.stjs.generator.javascript.NameValue;
import org.stjs.generator.javascript.UnaryOperator;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.debugging.sourcemap.SourceMapGenerator;

/**
* this JavaScript builder uses the rhino AST nodes to build the synthax tree.
*
* @author acraciun
*/
@SuppressWarnings("PMD.ExcessivePublicCount")
public class RhinoJavaScriptBuilder implements JavaScriptBuilder<AstNode> {
  private static int propId = AstNode.LAST_PROP + 1;
  private static final int PROP_JAVA_LINE_NO = propId++;
  private static final int PROP_JAVA_COLUMN_NO = propId++;
  private static final int PROP_JAVA_END_LINE_NO = propId++;
  private static final int PROP_JAVA_END_COLUMN_NO = propId++;

  @Override
  public AstNode name(CharSequence name) {
    Name n = new Name();
    n.setIdentifier(name.toString());
    return n;
  }

  @Override
  public AstNode label(CharSequence name) {
    Label n = new Label();
    n.setName(name.toString());
    return n;
  }

  @Override
  public AstNode asExpressionList(Iterable<AstNode> nodes) {
    return binary(BinaryOperator.COMMA, nodes);
  }

  @Override
  public AstNode block(Iterable<AstNode> statements) {
    Block block = new Block();
    for (AstNode stmt : statements) {
      if (stmt != null) {
        block.addStatement(stmt);
      }
    }
    return block;
  }

  @Override
  public AstNode elementGet(AstNode target, AstNode index) {
    ElementGet prop = new ElementGet();
    prop.setTarget(target);
    prop.setElement(index);
    return prop;
  }

  @Override
  public AstNode newExpression(AstNode target, Iterable<AstNode> arguments) {
    NewExpression ne = new NewExpression();
    ne.setTarget(target);
    if (!Iterables.isEmpty(arguments)) {
      ne.setArguments(list(arguments));
    }
    return ne;
  }

  @Override
  public AstNode array(Iterable<AstNode> values) {
    ArrayLiteral array = new ArrayLiteral();
    for (AstNode value : values) {
      array.addElement(value);
    }
    return array;
  }

  @Override
  public AstNode string(String value) {
    StringLiteral expr = new StringLiteral();
    expr.setQuoteCharacter('"');
    expr.setValue(value);
    return expr;
  }

  @Override
  public AstNode paren(AstNode expr) {
    ParenthesizedExpression paren = new ParenthesizedExpression();
    paren.setExpression(expr);
    return paren;
  }

  @Override
  public AstNode position(AstNode node, int javaStartLineNumber, int javaStartColumnNumber, int javaEndLineNumber, int javaEndColumnNumber) {
    node.putIntProp(PROP_JAVA_LINE_NO, javaStartLineNumber);
    node.putIntProp(PROP_JAVA_COLUMN_NO, javaStartColumnNumber);
    node.putIntProp(PROP_JAVA_END_LINE_NO, javaEndLineNumber);
    node.putIntProp(PROP_JAVA_END_COLUMN_NO, javaEndColumnNumber);
    return node;
  }

  public static int getLineNumber(AstNode node) {
    return node.getIntProp(PROP_JAVA_LINE_NO, -1);
  }

  public static int getColumnNumber(AstNode node) {
    return node.getIntProp(PROP_JAVA_COLUMN_NO, -1);
  }

  public static int getEndLineNumber(AstNode node) {
    return node.getIntProp(PROP_JAVA_END_LINE_NO, -1);
  }

  public static int getEndColumnNumber(AstNode node) {
    return node.getIntProp(PROP_JAVA_END_COLUMN_NO, -1);
  }

  @Override
  public AstNode breakStatement(AstNode label) {
    BreakStatement b = new BreakStatement();
    b.setBreakLabel(cast(label, Name.class));
    return b;
  }

  @SuppressWarnings("unchecked")
  @edu.umd.cs.findbugs.annotations.SuppressWarnings(justification = "Checked cast", value = "BC_UNCONFIRMED_CAST")
  private <T extends AstNode> T cast(AstNode node, Class<T> clazz) {
    if (node == null) {
      return null;
    }
    if (!clazz.isAssignableFrom(node.getClass())) {
      throw new STJSRuntimeException("Received wrong JavaScript node type:" + node.getClass().getName() + " instead of " + clazz.getName()
          + ". This is probably a ST-JS bug. Please report it to our website");
    }
    return (T) node;
  }

  @Override
  public AstNode caseStatement(AstNode expression, Iterable<AstNode> statements) {
    SwitchCase s = new SwitchCase();
    s.setExpression(expression);
    for (AstNode stmt : statements) {
      if (stmt != null) {
        s.addStatement(stmt);
      }
    }
    return s;
  }

  @Override
  public AstNode catchClause(AstNode varName, AstNode body) {
    CatchClause c = new CatchClause();
    c.setVarName(cast(varName, Name.class));
    if (body instanceof Block) {
      c.setBody((Block) body);
    } else {
      Block b = new Block();
      b.addStatement(body);
      c.setBody(b);
    }
    return c;
  }

  @Override
  public AstNode continueStatement(AstNode label) {
    ContinueStatement c = new ContinueStatement();
    c.setLabel(cast(label, Name.class));
    return c;
  }

  @Override
  public AstNode function(String name, Iterable<AstNode> params, AstNode body) {
    FunctionNode func = new FunctionNode();
    if (name != null) {
      func.setFunctionName((Name) name(name));
    }
    func.setParams(list(params));
    if (body == null) {
      func.setBody(new Block());
    } else if (body instanceof Block) {
      func.setBody(body);
    } else {
      func.setBody(addStatement(null, body));
    }
    return func;
  }

  private ObjectProperty objectProperty(CharSequence name, AstNode value) {
    ObjectProperty prop = new ObjectProperty();
    prop.setLeft(name(name));
    prop.setRight(value);
    return prop;
  }

  @Override
  public AstNode object(Iterable<NameValue<AstNode>> props) {
    ObjectLiteral object = new ObjectLiteral();
    for (NameValue<AstNode> prop : props) {
      object.addElement(objectProperty(prop.getName(), prop.getValue()));
    }
    return object;
  }

  @Override
  public AstNode doLoop(AstNode condition, AstNode body) {
    DoLoop loop = new DoLoop();
    loop.setCondition(condition);
    loop.setBody(body);
    return loop;
  }

  @Override
  public AstNode emptyStatement() {
    return new EmptyStatement();
  }

  @Override
  public AstNode emptyExpression() {
    return new EmptyExpression();
  }

  @Override
  public AstNode forInLoop(AstNode iterator, AstNode iterated, AstNode body) {
    ForInLoop loop = new ForInLoop();
    loop.setIteratedObject(iterated);
    loop.setIterator(iterator);
    loop.setBody(body);
    return loop;
  }

  @Override
  public AstNode forLoop(AstNode init, AstNode condition, AstNode update, AstNode body) {
    ForLoop loop = new ForLoop();
    loop.setInitializer(init);
    loop.setCondition(condition);
    loop.setIncrement(update);
    loop.setBody(body);
    return loop;
  }

  @Override
  public AstNode ifStatement(AstNode condition, AstNode thenPart, AstNode elsePart) {
    IfStatement ifs = new IfStatement();
    ifs.setCondition(condition);
    ifs.setThenPart(thenPart);
    ifs.setElsePart(elsePart);
    return ifs;
  }

  @Override
  public AstNode addStatement(AstNode blockOrStatement, AstNode statement) {
    if (blockOrStatement instanceof Block) {
      ((Block) blockOrStatement).addStatement(statement);
      return blockOrStatement;
    }
    Block block = new Block();
    if (blockOrStatement != null) {
      block.addStatement(blockOrStatement);
    }
    if (statement != null) {
      block.addStatement(statement);
    }
    return block;
  }

  @Override
  public AstNode addStatementBeginning(AstNode blockOrStatement, AstNode statement) {
    if (blockOrStatement instanceof Block) {
      if (statement != null) {
        blockOrStatement.addChildrenToFront(statement);
        statement.setParent(blockOrStatement);
      }
      return blockOrStatement;
    }
    Block block = new Block();
    if (statement != null) {
      block.addStatement(statement);
    }
    if (blockOrStatement != null) {
      block.addStatement(blockOrStatement);
    }
    return block;
  }

  @Override
  public AstNode labeledStatement(AstNode label, AstNode statement) {
    LabeledStatement s = new LabeledStatement();
    s.addLabel(cast(label, Label.class));
    s.setStatement(statement);
    return s;
  }

  @Override
  public AstNode returnStatement(AstNode returnValue) {
    ReturnStatement r = new ReturnStatement();
    r.setReturnValue(returnValue);
    return r;
  }

  @Override
  public AstNode switchStatement(AstNode expr, Iterable<AstNode> cases) {
    SwitchStatement s = new SwitchStatement();
    s.setExpression(expr);
    for (AstNode c : cases) {
      // the user must make sure it sends the correct types. TODO the code can check and build the correct type if
      // needed
      s.addCase((SwitchCase) c);
    }
    return s;
  }

  @Override
  public AstNode functionCall(AstNode target, Iterable<AstNode> arguments) {
    FunctionCall fc = new FunctionCall();
    fc.setTarget(target);
    if (!Iterables.isEmpty(arguments)) {
      fc.setArguments(list(arguments));
    }
    return fc;
  }

  @Override
  public AstNode property(AstNode target, CharSequence name) {
    if (target == null) {
      return name(name);
    }
    PropertyGet prop = new PropertyGet();
    prop.setTarget(target);
    prop.setProperty((Name) name(name));
    return prop;
  }

  @Override
  public AstNode variableDeclaration(boolean statement, Iterable<NameValue<AstNode>> vars) {
    VariableDeclaration varDecl = new VariableDeclaration();
    varDecl.setIsStatement(statement);
    for (NameValue<AstNode> v : vars) {
      VariableInitializer var = new VariableInitializer();
      var.setTarget(name(v.getName()));
      var.setInitializer(v.getValue());
      varDecl.addVariable(var);
    }
    return varDecl;
  }

  @Override
  public AstNode variableDeclaration(boolean statement, CharSequence name, AstNode init) {
    VariableDeclaration vars = new VariableDeclaration();
    vars.setIsStatement(statement);
    VariableInitializer var = new VariableInitializer();
    var.setTarget(name(name));
    var.setInitializer(init);
    vars.addVariable(var);
    return vars;
  }

  @Override
  public AstNode tryStatement(AstNode tryBlock, Iterable<AstNode> catchClauses, AstNode finallyBlock) {
    TryStatement t = new TryStatement();
    t.setTryBlock(tryBlock);
    for (AstNode c : catchClauses) {
      t.addCatchClause((CatchClause) c);
    }
    t.setFinallyBlock(finallyBlock);
    return t;
  }

  @Override
  public AstNode whileLoop(AstNode condition, AstNode body) {
    WhileLoop w = new WhileLoop();
    w.setCondition(condition);
    w.setBody(body);
    return w;
  }

  @Override
  public AstNode root(Iterable<AstNode> children) {
    AstRoot r = new AstRoot();
    for (AstNode c : children) {
      if (c != null) {
        r.addChild(c);
      }
    }
    return r;
  }

  @Override
  public AstNode code(String code) {
    CodeFragment c = new CodeFragment();
    c.setCode(code);
    return c;
  }

  @Override
  public String toString(AstNode node) {
    return node.toSource();
  }

  @Override
  public AstNode conditionalExpression(AstNode test, AstNode trueExpr, AstNode falseExpr) {
    ConditionalExpression c = new ConditionalExpression();
    c.setTestExpression(test);
    c.setTrueExpression(trueExpr);
    c.setFalseExpression(falseExpr);
    return c;
  }

  @Override
  public AstNode character(String c) {
    StringLiteral s = new StringLiteral();
    s.setQuoteCharacter('\'');
    s.setValue(c);
    return s;
  }

  @Override
  public AstNode number(Number n) {
    NumberLiteral l = new NumberLiteral();
    l.setValue(n.toString());
    return l;
  }

  @Override
  public AstNode statements(Iterable<AstNode> stmts) {
    Statements s = new Statements();
    for (AstNode stmt : stmts) {
      if (stmt != null) {
        s.addStatement(stmt);
      }
    }
    return s;
  }

  @Override
  public AstNode assignment(AssignOperator operator, AstNode left, AstNode right) {
    Assignment a = new Assignment();
    a.setOperator(operator.getJavaScript());
    a.setLeft(left);
    a.setRight(right);
    return a;
  }

  @Override
  public AstNode binary(BinaryOperator operator, Iterable<AstNode> operands) {
    // this is to deal with the COMMA operator who can have less than two operands
    if (Iterables.isEmpty(operands)) {
      return new EmptyExpression();
    }
    if (Iterables.size(operands) == 1) {
      return operands.iterator().next();
    }
    InfixExpression list = new InfixExpression();
    list.setOperator(operator.getJavaScript());
    Iterator<AstNode> it = operands.iterator();
    list.setLeft(it.next());
    list.setRight(it.next());
    while (it.hasNext()) {
      InfixExpression tmpIncrements = new InfixExpression();
      tmpIncrements.setOperator(operator.getJavaScript());
      tmpIncrements.setLeft(list);
      tmpIncrements.setRight(it.next());
      list = tmpIncrements;
    }
    return list;
  }

  @Override
  public AstNode keyword(Keyword token) {
    KeywordLiteral k = new KeywordLiteral();
    k.setType(token.getJavaScript());
    return k;
  }

  @Override
  public AstNode unary(UnaryOperator operator, AstNode operand) {
    UnaryExpression u = new UnaryExpression();
    u.setIsPostfix(operator.isPostfix());
    u.setOperator(operator.getJavaScript());
    u.setOperand(operand);
    return u;
  }

  @Override
  public AstNode expressionStatement(AstNode expr) {
    ExpressionStatement e = new ExpressionStatement();
    e.setExpression(expr);
    return e;
  }

  private static <T extends AstNode> List<T> list(Iterable<T> it) {
    if (it instanceof List) {
      return (List<T>) it;
    }
    return Lists.newArrayList(it);

  }

  @Override
  public SourceMapGenerator writeJavaScript(AstNode javascriptRoot, File inputFile, boolean generateSourceMap, Writer writer) {
    RhinoJavaScriptWriter jsw = new RhinoJavaScriptWriter(writer, inputFile, generateSourceMap);

    jsw.visitAstRoot(cast(javascriptRoot, AstRoot.class), null);

    return jsw.getSourceMapGenerator();
  }

  @Override
  public AstNode comment(AstNode node, String comment) {
    if (node == null) {
      return null;
    }
    if (comment != null) {
      node.setJsDocNode(new Comment(0, comment.length(), CommentType.JSDOC, comment));
    }
    return node;
  }

  @Override
  public AstNode throwStatement(AstNode expr) {
    ThrowStatement s = new ThrowStatement();
    s.setExpression(expr);
    return s;
  }

}
TOP

Related Classes of org.stjs.generator.javascript.rhino.RhinoJavaScriptBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.