| /* |
| * Copyright 2011 Google Inc. |
| * |
| * 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 com.google.gwt.dev.js; |
| |
| import com.google.gwt.dev.jjs.HasSourceInfo; |
| import com.google.gwt.dev.jjs.SourceInfo; |
| import com.google.gwt.dev.js.ast.HasName; |
| import com.google.gwt.dev.js.ast.JsArrayAccess; |
| import com.google.gwt.dev.js.ast.JsArrayLiteral; |
| import com.google.gwt.dev.js.ast.JsBinaryOperation; |
| import com.google.gwt.dev.js.ast.JsBinaryOperator; |
| import com.google.gwt.dev.js.ast.JsBlock; |
| import com.google.gwt.dev.js.ast.JsBooleanLiteral; |
| import com.google.gwt.dev.js.ast.JsBreak; |
| import com.google.gwt.dev.js.ast.JsCase; |
| import com.google.gwt.dev.js.ast.JsCatch; |
| import com.google.gwt.dev.js.ast.JsConditional; |
| import com.google.gwt.dev.js.ast.JsContinue; |
| import com.google.gwt.dev.js.ast.JsDebugger; |
| import com.google.gwt.dev.js.ast.JsDefault; |
| import com.google.gwt.dev.js.ast.JsDoWhile; |
| import com.google.gwt.dev.js.ast.JsEmpty; |
| import com.google.gwt.dev.js.ast.JsExprStmt; |
| import com.google.gwt.dev.js.ast.JsExpression; |
| import com.google.gwt.dev.js.ast.JsFor; |
| import com.google.gwt.dev.js.ast.JsForIn; |
| import com.google.gwt.dev.js.ast.JsFunction; |
| import com.google.gwt.dev.js.ast.JsIf; |
| import com.google.gwt.dev.js.ast.JsInvocation; |
| import com.google.gwt.dev.js.ast.JsLabel; |
| import com.google.gwt.dev.js.ast.JsName; |
| import com.google.gwt.dev.js.ast.JsNameOf; |
| import com.google.gwt.dev.js.ast.JsNameRef; |
| import com.google.gwt.dev.js.ast.JsNew; |
| import com.google.gwt.dev.js.ast.JsNode; |
| import com.google.gwt.dev.js.ast.JsNullLiteral; |
| import com.google.gwt.dev.js.ast.JsNumberLiteral; |
| import com.google.gwt.dev.js.ast.JsNumericEntry; |
| import com.google.gwt.dev.js.ast.JsObjectLiteral; |
| import com.google.gwt.dev.js.ast.JsParameter; |
| import com.google.gwt.dev.js.ast.JsPostfixOperation; |
| import com.google.gwt.dev.js.ast.JsPrefixOperation; |
| import com.google.gwt.dev.js.ast.JsProgram; |
| import com.google.gwt.dev.js.ast.JsProgramFragment; |
| import com.google.gwt.dev.js.ast.JsPropertyInitializer; |
| import com.google.gwt.dev.js.ast.JsRegExp; |
| import com.google.gwt.dev.js.ast.JsReturn; |
| import com.google.gwt.dev.js.ast.JsSeedIdOf; |
| import com.google.gwt.dev.js.ast.JsStatement; |
| import com.google.gwt.dev.js.ast.JsStringLiteral; |
| import com.google.gwt.dev.js.ast.JsSwitch; |
| import com.google.gwt.dev.js.ast.JsSwitchMember; |
| import com.google.gwt.dev.js.ast.JsThisRef; |
| import com.google.gwt.dev.js.ast.JsThrow; |
| import com.google.gwt.dev.js.ast.JsTry; |
| import com.google.gwt.dev.js.ast.JsUnaryOperator; |
| import com.google.gwt.dev.js.ast.JsVars; |
| import com.google.gwt.dev.js.ast.JsVars.JsVar; |
| import com.google.gwt.dev.js.ast.JsWhile; |
| import com.google.gwt.dev.js.ast.NodeKind; |
| import com.google.gwt.thirdparty.guava.common.base.Preconditions; |
| import com.google.gwt.thirdparty.guava.common.collect.Sets; |
| import com.google.gwt.thirdparty.javascript.jscomp.AstValidator; |
| import com.google.gwt.thirdparty.javascript.rhino.IR; |
| import com.google.gwt.thirdparty.javascript.rhino.InputId; |
| import com.google.gwt.thirdparty.javascript.rhino.Node; |
| import com.google.gwt.thirdparty.javascript.rhino.Token; |
| import com.google.gwt.thirdparty.javascript.rhino.jstype.SimpleSourceFile; |
| import com.google.gwt.thirdparty.javascript.rhino.jstype.StaticSourceFile; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Translate a GWT JS AST to a Closure Compiler AST. |
| */ |
| public class ClosureJsAstTranslator { |
| private static String getStringValue(double value) { |
| long longValue = (long) value; |
| |
| // Return "1" instead of "1.0" |
| if (longValue == value) { |
| return Long.toString(longValue); |
| } else { |
| return Double.toString(value); |
| } |
| } |
| |
| private final Map<String, StaticSourceFile> sourceCache = new HashMap<String, StaticSourceFile>(); |
| |
| private final boolean validate; |
| private final Set<String> globalVars = Sets.newHashSet(); |
| private final Set<String> externalProperties = Sets.newHashSet(); |
| |
| private final Set<String> externalVars = Sets.newHashSet(); |
| |
| private final JsProgram program; |
| |
| ClosureJsAstTranslator(boolean validate, JsProgram program) { |
| this.program = program; |
| this.validate = validate; |
| } |
| |
| public Node translate(JsProgramFragment fragment, InputId inputId, String source) { |
| Node script = IR.script(); |
| script.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true); |
| script.setInputId(inputId); |
| script.setStaticSourceFile(getClosureSourceFile(source)); |
| for (JsStatement s : fragment.getGlobalBlock().getStatements()) { |
| script.addChildToBack(transform(s)); |
| } |
| // Validate the structural integrity of the AST. |
| if (validate) { |
| new AstValidator().validateScript(script); |
| } |
| return script; |
| } |
| |
| Set<String> getExternalPropertyReferences() { |
| return externalProperties; |
| } |
| |
| Set<String> getExternalVariableReferences() { |
| return externalVars; |
| } |
| |
| Set<String> getGlobalVariableNames() { |
| return globalVars; |
| } |
| |
| private Node applyOriginalName(Node n, JsNode x) { |
| /* |
| * if (x instanceof HasSymbol) { Symbol symbol = ((HasSymbol)x).getSymbol(); if (symbol != null) |
| * { String originalName = symbol.getOriginalSymbolName(); n.putProp(Node.ORIGINALNAME_PROP, |
| * originalName); } } |
| */ |
| return n; |
| } |
| |
| private Node applySourceInfo(Node n, HasSourceInfo srcNode) { |
| if (n != null && srcNode != null) { |
| SourceInfo info = srcNode.getSourceInfo(); |
| if (info != null && info.getFileName() != null) { |
| n.setStaticSourceFile(getClosureSourceFile(info.getFileName())); |
| n.setLineno(info.getStartLine()); |
| n.setCharno(0); |
| } |
| } |
| return n; |
| } |
| |
| private StaticSourceFile getClosureSourceFile(String source) { |
| StaticSourceFile closureSourceFile = sourceCache.get(source); |
| if (closureSourceFile == null) { |
| closureSourceFile = new SimpleSourceFile(source, false); |
| sourceCache.put(source, closureSourceFile); |
| } |
| return closureSourceFile; |
| } |
| |
| private String getName(JsName name) { |
| return name.getShortIdent(); |
| } |
| |
| private String getName(JsNameRef name) { |
| return name.getShortIdent(); |
| } |
| |
| private Node getNameNodeFor(HasName hasName) { |
| Node n = IR.name(getName(hasName.getName())); |
| applyOriginalName(n, (JsNode) hasName); |
| return applySourceInfo(n, (HasSourceInfo) hasName); |
| } |
| |
| private int getTokenForOp(JsBinaryOperator op) { |
| switch (op) { |
| case MUL: |
| return Token.MUL; |
| case DIV: |
| return Token.DIV; |
| case MOD: |
| return Token.MOD; |
| case ADD: |
| return Token.ADD; |
| case SUB: |
| return Token.SUB; |
| case SHL: |
| return Token.LSH; |
| case SHR: |
| return Token.RSH; |
| case SHRU: |
| return Token.URSH; |
| case LT: |
| return Token.LT; |
| case LTE: |
| return Token.LE; |
| case GT: |
| return Token.GT; |
| case GTE: |
| return Token.GE; |
| case INSTANCEOF: |
| return Token.INSTANCEOF; |
| case INOP: |
| return Token.IN; |
| case EQ: |
| return Token.EQ; |
| case NEQ: |
| return Token.NE; |
| case REF_EQ: |
| return Token.SHEQ; |
| case REF_NEQ: |
| return Token.SHNE; |
| case BIT_AND: |
| return Token.BITAND; |
| case BIT_XOR: |
| return Token.BITXOR; |
| case BIT_OR: |
| return Token.BITOR; |
| case AND: |
| return Token.AND; |
| case OR: |
| return Token.OR; |
| case ASG: |
| return Token.ASSIGN; |
| case ASG_ADD: |
| return Token.ASSIGN_ADD; |
| case ASG_SUB: |
| return Token.ASSIGN_SUB; |
| case ASG_MUL: |
| return Token.ASSIGN_MUL; |
| case ASG_DIV: |
| return Token.ASSIGN_DIV; |
| case ASG_MOD: |
| return Token.ASSIGN_MOD; |
| case ASG_SHL: |
| return Token.ASSIGN_LSH; |
| case ASG_SHR: |
| return Token.ASSIGN_RSH; |
| case ASG_SHRU: |
| return Token.ASSIGN_URSH; |
| case ASG_BIT_AND: |
| return Token.ASSIGN_BITAND; |
| case ASG_BIT_OR: |
| return Token.ASSIGN_BITOR; |
| case ASG_BIT_XOR: |
| return Token.ASSIGN_BITXOR; |
| case COMMA: |
| return Token.COMMA; |
| } |
| return 0; |
| } |
| |
| private int getTokenForOp(JsUnaryOperator op) { |
| switch (op) { |
| case BIT_NOT: |
| return Token.BITNOT; |
| case DEC: |
| return Token.DEC; |
| case DELETE: |
| return Token.DELPROP; |
| case INC: |
| return Token.INC; |
| case NEG: |
| return Token.NEG; |
| case POS: |
| return Token.POS; |
| case NOT: |
| return Token.NOT; |
| case TYPEOF: |
| return Token.TYPEOF; |
| case VOID: |
| return Token.VOID; |
| } |
| throw new IllegalStateException(); |
| } |
| |
| private Node transform(JsArrayAccess x) { |
| Node n = IR.getelem(transform(x.getArrayExpr()), transform(x.getIndexExpr())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsArrayLiteral x) { |
| Node n = IR.arraylit(); |
| for (Object element : x.getExpressions()) { |
| JsExpression arg = (JsExpression) element; |
| n.addChildToBack(transform(arg)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsBinaryOperation x) { |
| JsBinaryOperator op = x.getOperator(); |
| Node n = new Node(getTokenForOp(op), transform(x.getArg1()), transform(x.getArg2())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsBlock x) { |
| Node n = IR.block(); |
| for (JsStatement s : x.getStatements()) { |
| n.addChildToBack(transform(s)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsBooleanLiteral x) { |
| Node n = x.getValue() ? IR.trueNode() : IR.falseNode(); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsBreak x) { |
| Node n; |
| JsNameRef label = x.getLabel(); |
| if (label == null) { |
| n = IR.breakNode(); |
| } else { |
| n = IR.breakNode(transformLabel(label)); |
| } |
| |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsCase x) { |
| Node expr = transform(x.getCaseExpr()); |
| Node body = IR.block(); |
| body.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true); |
| applySourceInfo(body, x); |
| |
| for (Object element : x.getStmts()) { |
| JsStatement stmt = (JsStatement) element; |
| body.addChildToBack(transform(stmt)); |
| } |
| |
| Node n = IR.caseNode(expr, body); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsCatch x) { |
| Node n = IR.catchNode(transformName(x.getParameter().getName()), transform(x.getBody())); |
| Preconditions.checkState(x.getCondition() == null); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsConditional x) { |
| Node n = |
| IR.hook(transform(x.getTestExpression()), transform(x.getThenExpression()), transform(x |
| .getElseExpression())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsContinue x) { |
| Node n; |
| JsNameRef label = x.getLabel(); |
| if (label == null) { |
| n = IR.continueNode(); |
| } else { |
| n = IR.continueNode(transformLabel(label)); |
| } |
| |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsDebugger x) { |
| Node n = new Node(Token.DEBUGGER); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsDefault x) { |
| Node body = IR.block(); |
| body.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true); |
| applySourceInfo(body, x); |
| |
| for (Object element : x.getStmts()) { |
| JsStatement stmt = (JsStatement) element; |
| body.addChildToBack(transform(stmt)); |
| } |
| Node n = IR.defaultCase(body); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsDoWhile x) { |
| Node n = IR.doNode(transformBody(x.getBody(), x), transform(x.getCondition())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsEmpty x) { |
| return IR.empty(); |
| } |
| |
| private Node transform(JsExpression x) { |
| assert x != null; |
| switch (x.getKind()) { |
| case ARRAY: |
| return transform((JsArrayLiteral) x); |
| case ARRAY_ACCESS: |
| return transform((JsArrayAccess) x); |
| case BINARY_OP: |
| return transform((JsBinaryOperation) x); |
| case CONDITIONAL: |
| return transform((JsConditional) x); |
| case INVOKE: |
| return transform((JsInvocation) x); |
| case FUNCTION: |
| return transform((JsFunction) x); |
| case OBJECT: |
| return transform((JsObjectLiteral) x); |
| case BOOLEAN: |
| return transform((JsBooleanLiteral) x); |
| case NULL: |
| return transform((JsNullLiteral) x); |
| case NUMBER: |
| if (x instanceof JsNumericEntry) { |
| return transform((JsNumericEntry) x); |
| } |
| return transform((JsNumberLiteral) x); |
| case REGEXP: |
| return transform((JsRegExp) x); |
| case STRING: |
| return transform((JsStringLiteral) x); |
| case THIS: |
| return transform((JsThisRef) x); |
| case NAME_OF: |
| return transform((JsNameOf) x); |
| case SEED_ID_OF: |
| return transform((JsSeedIdOf) x); |
| case NAME_REF: |
| return transform((JsNameRef) x); |
| case NEW: |
| return transform((JsNew) x); |
| case POSTFIX_OP: |
| return transform((JsPostfixOperation) x); |
| case PREFIX_OP: |
| return transform((JsPrefixOperation) x); |
| default: |
| throw new IllegalStateException("Unexpected expression type: " |
| + x.getClass().getSimpleName()); |
| } |
| } |
| |
| private Node transform(JsExprStmt x) { |
| // The GWT JS AST doesn't produce function declarations, instead |
| // they are expressions statements: |
| Node expr = transform(x.getExpression()); |
| if (!expr.isFunction()) { |
| return IR.exprResult(expr); |
| } else { |
| return expr; |
| } |
| } |
| |
| private Node transform(JsFor x) { |
| // The init expressions or var decl. |
| // |
| Node init; |
| if (x.getInitExpr() != null) { |
| init = transform(x.getInitExpr()); |
| } else if (x.getInitVars() != null) { |
| init = transform(x.getInitVars()); |
| } else { |
| init = IR.empty(); |
| } |
| |
| // The loop test. |
| // |
| Node cond; |
| if (x.getCondition() != null) { |
| cond = transform(x.getCondition()); |
| } else { |
| cond = IR.empty(); |
| } |
| |
| // The incr expression. |
| // |
| Node incr; |
| if (x.getIncrExpr() != null) { |
| incr = transform(x.getIncrExpr()); |
| } else { |
| incr = IR.empty(); |
| } |
| |
| Node body = transformBody(x.getBody(), x); |
| Node n = IR.forNode(init, cond, incr, body); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsForIn x) { |
| Node valueExpr; |
| if (x.getIterVarName() != null) { |
| valueExpr = new Node(Token.VAR, transformName(x.getIterVarName())); |
| } else { |
| // Just a name ref. |
| // |
| valueExpr = transform(x.getIterExpr()); |
| } |
| |
| Node n = IR.forIn(valueExpr, transform(x.getObjExpr()), transformBody(x.getBody(), x)); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsFunction x) { |
| Node name; |
| if (x.getName() != null) { |
| name = getNameNodeFor(x); |
| } else { |
| name = IR.name(""); |
| } |
| applySourceInfo(name, x); |
| |
| Node params = IR.paramList(); |
| for (Object element : x.getParameters()) { |
| JsParameter param = (JsParameter) element; |
| params.addChildToBack(transform(param)); |
| } |
| applySourceInfo(params, x); |
| |
| Node n = IR.function(name, params, transform(x.getBody())); |
| if (name.getString().isEmpty()) { |
| n.putProp(Node.ORIGINALNAME_PROP, ""); |
| } else { |
| applyOriginalName(n, x); |
| } |
| |
| /* |
| * if (x.isConstructor()) { JSDocInfoBuilder builder = new JSDocInfoBuilder(false); |
| * builder.recordConstructor(); n.setJSDocInfo(builder.build(n)); } |
| */ |
| |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsIf x) { |
| Node n = IR.ifNode(transform(x.getIfExpr()), transformBody(x.getThenStmt(), x)); |
| if (x.getElseStmt() != null) { |
| n.addChildToBack(transformBody(x.getElseStmt(), x)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsInvocation x) { |
| Node n = IR.call(transform(x.getQualifier())); |
| for (Object element : x.getArguments()) { |
| JsExpression arg = (JsExpression) element; |
| n.addChildToBack(transform(arg)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsLabel x) { |
| Node n = IR.label(transformLabel(x.getName()), transform(x.getStmt())); |
| |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsNameOf x) { |
| Node n = transformName(x.getName().getShortIdent(), x); |
| applyOriginalName(n, x); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsNameRef x) { |
| Node n; |
| JsName name = x.getName(); |
| boolean isExternal = name == null || !name.isObfuscatable(); |
| if (x.getQualifier() != null) { |
| n = IR.getprop(transform(x.getQualifier()), transformNameAsString(x.getShortIdent(), x)); |
| if (isExternal) { |
| this.externalProperties.add(x.getShortIdent()); |
| } |
| } else { |
| n = transformName(x.getShortIdent(), x); |
| if (isExternal) { |
| this.externalVars.add(x.getShortIdent()); |
| } else if (name.getEnclosing() == program.getScope()) { |
| this.globalVars.add(x.getShortIdent()); |
| } |
| } |
| applyOriginalName(n, x); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsNew x) { |
| Node n = IR.newNode(transform(x.getConstructorExpression())); |
| for (Object element : x.getArguments()) { |
| JsExpression arg = (JsExpression) element; |
| n.addChildToBack(transform(arg)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsNullLiteral x) { |
| return IR.nullNode(); |
| } |
| |
| private Node transform(JsNumericEntry x) { |
| return IR.number(x.getValue()); |
| } |
| |
| private Node transform(JsNumberLiteral x) { |
| return IR.number(x.getValue()); |
| } |
| |
| private Node transform(JsObjectLiteral x) { |
| Node n = IR.objectlit(); |
| |
| for (Object element : x.getPropertyInitializers()) { |
| JsPropertyInitializer propInit = (JsPropertyInitializer) element; |
| Node key; |
| if (propInit.getLabelExpr().getKind() == NodeKind.NUMBER) { |
| key = transformNumberAsString((JsNumberLiteral) propInit.getLabelExpr()); |
| key.putBooleanProp(Node.QUOTED_PROP, true); |
| } else if (propInit.getLabelExpr().getKind() == NodeKind.NAME_REF) { |
| key = |
| transformNameAsString(((JsNameRef) propInit.getLabelExpr()).getShortIdent(), propInit |
| .getLabelExpr()); |
| } else { |
| key = transform(propInit.getLabelExpr()); |
| } |
| Preconditions.checkState(key.isString(), key); |
| n.addChildToBack(IR.propdef(key, transform(propInit.getValueExpr()))); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsParameter x) { |
| return getNameNodeFor(x); |
| } |
| |
| private Node transform(JsPostfixOperation x) { |
| Node n = new Node(getTokenForOp(x.getOperator()), transform(x.getArg())); |
| n.putBooleanProp(Node.INCRDECR_PROP, true); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsPrefixOperation x) { |
| Node n = new Node(getTokenForOp(x.getOperator()), transform(x.getArg())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsRegExp x) { |
| String flags = x.getFlags(); |
| Node n = |
| IR.regexp(Node.newString(x.getPattern()), Node.newString(flags != null ? x.getFlags() : "")); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsReturn x) { |
| Node n = IR.returnNode(); |
| JsExpression result = x.getExpr(); |
| if (result != null) { |
| n.addChildToBack(transform(x.getExpr())); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsSeedIdOf x) { |
| Node n = Node.newNumber(x.getSeedId()); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsStatement x) { |
| switch (x.getKind()) { |
| case BLOCK: |
| return transform((JsBlock) x); |
| case BREAK: |
| return transform((JsBreak) x); |
| case CONTINUE: |
| return transform((JsContinue) x); |
| case DEBUGGER: |
| return transform((JsDebugger) x); |
| case DO: |
| return transform((JsDoWhile) x); |
| case EMPTY: |
| return transform((JsEmpty) x); |
| case EXPR_STMT: |
| return transform((JsExprStmt) x); |
| case FOR: |
| return transform((JsFor) x); |
| case FOR_IN: |
| return transform((JsForIn) x); |
| case IF: |
| return transform((JsIf) x); |
| case LABEL: |
| return transform((JsLabel) x); |
| case RETURN: |
| return transform((JsReturn) x); |
| case SWITCH: |
| return transform((JsSwitch) x); |
| case THROW: |
| return transform((JsThrow) x); |
| case TRY: |
| return transform((JsTry) x); |
| case VARS: |
| return transform((JsVars) x); |
| case WHILE: |
| return transform((JsWhile) x); |
| default: |
| throw new IllegalStateException("Unexpected statement type: " |
| + x.getClass().getSimpleName()); |
| } |
| } |
| |
| private Node transform(JsStringLiteral x) { |
| return IR.string(x.getValue()); |
| } |
| |
| private Node transform(JsSwitch x) { |
| Node n = IR.switchNode(transform(x.getExpr())); |
| for (JsSwitchMember member : x.getCases()) { |
| n.addChildToBack(transform(member)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsSwitchMember x) { |
| switch (x.getKind()) { |
| case CASE: |
| return transform((JsCase) x); |
| case DEFAULT: |
| return transform((JsDefault) x); |
| default: |
| throw new IllegalStateException("Unexpected switch member type: " |
| + x.getClass().getSimpleName()); |
| } |
| } |
| |
| private Node transform(JsThisRef x) { |
| Node n = new Node(Token.THIS); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsThrow x) { |
| Node n = IR.throwNode(transform(x.getExpr())); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsTry x) { |
| Node n = new Node(Token.TRY, transform(x.getTryBlock())); |
| |
| Node catches = new Node(Token.BLOCK); |
| for (JsCatch catchBlock : x.getCatches()) { |
| catches.addChildToBack(transform(catchBlock)); |
| } |
| n.addChildToBack(catches); |
| |
| JsBlock finallyBlock = x.getFinallyBlock(); |
| if (finallyBlock != null) { |
| n.addChildToBack(transform(finallyBlock)); |
| } |
| |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsVar x) { |
| Node n = getNameNodeFor(x); |
| JsExpression initExpr = x.getInitExpr(); |
| if (initExpr != null) { |
| n.addChildToBack(transform(initExpr)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsVars x) { |
| Node n = new Node(Token.VAR); |
| for (JsVar var : x) { |
| n.addChildToBack(transform(var)); |
| } |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transform(JsWhile x) { |
| Node n = |
| IR.forNode(IR.empty(), transform(x.getCondition()), IR.empty(), transformBody(x.getBody(), |
| x)); |
| return applySourceInfo(n, x); |
| } |
| |
| private Node transformBody(JsStatement x, HasSourceInfo parent) { |
| Node n = transform(x); |
| if (!n.isBlock()) { |
| Node stmt = n; |
| n = IR.block(); |
| if (!stmt.isEmpty()) { |
| n.addChildToBack(stmt); |
| } |
| applySourceInfo(n, parent); |
| } |
| return n; |
| } |
| |
| private Node transformLabel(JsName label) { |
| Node n = IR.labelName(getName(label)); |
| return applySourceInfo(n, label.getStaticRef()); |
| } |
| |
| private Node transformLabel(JsNameRef label) { |
| Node n = IR.labelName(getName(label)); |
| return applySourceInfo(n, label); |
| } |
| |
| private Node transformName(JsName name) { |
| Node n = IR.name(getName(name)); |
| return applySourceInfo(n, name.getStaticRef()); |
| } |
| |
| private Node transformName(String name, HasSourceInfo info) { |
| Node n = IR.name(name); |
| return applySourceInfo(n, info); |
| } |
| |
| private Node transformNameAsString(String name, HasSourceInfo info) { |
| Node n = IR.string(name); |
| return applySourceInfo(n, info); |
| } |
| |
| private Node transformNumberAsString(JsNumberLiteral literalNode) { |
| Node irNode = Node.newString(getStringValue(literalNode.getValue())); |
| return irNode; |
| } |
| } |