/* * Copyright 2008 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.jjs.impl; import com.google.gwt.dev.jjs.InternalCompilerException; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JArrayLength; import com.google.gwt.dev.jjs.ast.JArrayRef; import com.google.gwt.dev.jjs.ast.JBinaryOperation; import com.google.gwt.dev.jjs.ast.JBooleanLiteral; import com.google.gwt.dev.jjs.ast.JCastOperation; import com.google.gwt.dev.jjs.ast.JCharLiteral; import com.google.gwt.dev.jjs.ast.JClassLiteral; import com.google.gwt.dev.jjs.ast.JClassType; import com.google.gwt.dev.jjs.ast.JConditional; import com.google.gwt.dev.jjs.ast.JDoubleLiteral; import com.google.gwt.dev.jjs.ast.JExpression; import com.google.gwt.dev.jjs.ast.JFieldRef; import com.google.gwt.dev.jjs.ast.JFloatLiteral; import com.google.gwt.dev.jjs.ast.JInstanceOf; import com.google.gwt.dev.jjs.ast.JIntLiteral; import com.google.gwt.dev.jjs.ast.JLocalRef; import com.google.gwt.dev.jjs.ast.JLongLiteral; import com.google.gwt.dev.jjs.ast.JMethodCall; import com.google.gwt.dev.jjs.ast.JNameOf; import com.google.gwt.dev.jjs.ast.JNewArray; import com.google.gwt.dev.jjs.ast.JNewInstance; import com.google.gwt.dev.jjs.ast.JNullLiteral; import com.google.gwt.dev.jjs.ast.JNumericEntry; import com.google.gwt.dev.jjs.ast.JParameterRef; import com.google.gwt.dev.jjs.ast.JPermutationDependentValue; import com.google.gwt.dev.jjs.ast.JPostfixOperation; import com.google.gwt.dev.jjs.ast.JPrefixOperation; import com.google.gwt.dev.jjs.ast.JRunAsync; import com.google.gwt.dev.jjs.ast.JStringLiteral; import com.google.gwt.dev.jjs.ast.JThisRef; import com.google.gwt.dev.jjs.ast.JUnsafeTypeCoercion; import com.google.gwt.dev.jjs.ast.JVisitor; import com.google.gwt.dev.jjs.ast.js.JMultiExpression; import com.google.gwt.dev.jjs.ast.js.JsniFieldRef; import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; import java.util.ArrayList; import java.util.List; /** * A general purpose expression cloner. */ public class CloneExpressionVisitor extends JVisitor { private JExpression expression; public CloneExpressionVisitor() { } @SuppressWarnings("unchecked") public <T extends JExpression> T cloneExpression(T expr) { if (expr == null) { return null; } // double check that the expression is successfully cloned expression = null; this.accept(expr); if (expression == null) { throw new InternalCompilerException(expr, "Unable to clone expression", null); } Class<T> originalClass = (Class<T>) expr.getClass(); return originalClass.cast(expression); } public ArrayList<JExpression> cloneExpressions(List<JExpression> exprs) { if (exprs == null) { return null; } ArrayList<JExpression> result = new ArrayList<JExpression>(); for (JExpression expr : exprs) { result.add(cloneExpression(expr)); } return result; } @Override public boolean visit(JArrayLength x, Context ctx) { expression = new JArrayLength(x.getSourceInfo(), cloneExpression(x.getInstance())); return false; } @Override public boolean visit(JArrayRef x, Context ctx) { expression = new JArrayRef(x.getSourceInfo(), cloneExpression(x.getInstance()), cloneExpression(x .getIndexExpr())); return false; } @Override public boolean visit(JBinaryOperation x, Context ctx) { expression = new JBinaryOperation(x.getSourceInfo(), x.getType(), x.getOp(), cloneExpression(x.getLhs()), cloneExpression(x.getRhs())); return false; } @Override public boolean visit(JBooleanLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JCastOperation x, Context ctx) { expression = new JCastOperation(x.getSourceInfo(), x.getCastType(), cloneExpression(x.getExpr())); return false; } @Override public boolean visit(JCharLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JClassLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JConditional x, Context ctx) { expression = new JConditional(x.getSourceInfo(), x.getType(), cloneExpression(x.getIfTest()), cloneExpression(x.getThenExpr()), cloneExpression(x.getElseExpr())); return false; } @Override public boolean visit(JDoubleLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JFieldRef x, Context ctx) { expression = new JFieldRef(x.getSourceInfo(), cloneExpression(x.getInstance()), x.getField(), x .getEnclosingType()); return false; } @Override public boolean visit(JFloatLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JInstanceOf x, Context ctx) { expression = new JInstanceOf(x.getSourceInfo(), x.getTestType(), cloneExpression(x.getExpr())); return false; } @Override public boolean visit(JIntLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JLocalRef x, Context ctx) { expression = x.getLocal().makeRef(x.getSourceInfo()); return false; } @Override public boolean visit(JLongLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JMethodCall x, Context ctx) { JMethodCall newMethodCall = new JMethodCall(x, cloneExpression(x.getInstance())); newMethodCall.addArgs(cloneExpressions(x.getArgs())); expression = newMethodCall; return false; } @Override public boolean visit(JMultiExpression x, Context ctx) { expression = new JMultiExpression(x.getSourceInfo(), cloneExpressions(x.getExpressions())); return false; } @Override public boolean visit(JNameOf x, Context ctx) { expression = new JNameOf(x.getSourceInfo(), (JClassType) x.getType().getUnderlyingType(), x.getNode()); return false; } @Override public boolean visit(JNewArray x, Context ctx) { expression = new JNewArray(x.getSourceInfo(), x.getArrayType(), cloneExpressions(x.getDimensionExpressions()), cloneExpressions(x.getInitializers()), cloneExpression(x.getLeafTypeClassLiteral())); return false; } @Override public boolean visit(JNewInstance x, Context ctx) { JNewInstance newInstance = new JNewInstance(x); newInstance.addArgs(cloneExpressions(x.getArgs())); expression = newInstance; return false; } @Override public boolean visit(JNumericEntry x, Context ctx) { expression = new JNumericEntry(x.getSourceInfo(), x.getKey(), x.getValue()); return false; } @Override public boolean visit(JNullLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JParameterRef x, Context ctx) { expression = x.getParameter().makeRef(x.getSourceInfo()); return false; } @Override public void endVisit(JPermutationDependentValue x, Context ctx) { throw new IllegalStateException("AST should not contain permutation dependent values at " + "this point but contains " + x); } @Override public boolean visit(JPostfixOperation x, Context ctx) { expression = new JPostfixOperation(x.getSourceInfo(), x.getOp(), cloneExpression(x.getArg())); return false; } @Override public boolean visit(JPrefixOperation x, Context ctx) { expression = new JPrefixOperation(x.getSourceInfo(), x.getOp(), cloneExpression(x.getArg())); return false; } @Override public boolean visit(JRunAsync x, Context ctx) { // Only the runAsync call itself needs cloning, the onSuccess can be shared. JExpression runAsyncCall = cloneExpression(x.getRunAsyncCall()); expression = new JRunAsync(x.getSourceInfo(), x.getRunAsyncId(), x.getName(), x.hasExplicitClassLiteral(), runAsyncCall, x.getOnSuccessCall()); return false; } @Override public boolean visit(JsniFieldRef x, Context ctx) { expression = x; return false; } @Override public boolean visit(JsniMethodRef x, Context ctx) { expression = x; return false; } @Override public boolean visit(JStringLiteral x, Context ctx) { expression = x; return false; } @Override public boolean visit(JThisRef x, Context ctx) { expression = new JThisRef(x.getSourceInfo(), x.getClassType()); return false; } @Override public boolean visit(JUnsafeTypeCoercion x, Context ctx) { expression = new JUnsafeTypeCoercion( x.getSourceInfo(), x.getCoercionType(), cloneExpression(x.getExpression())); return false; } }