/* * 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.gflow.constants; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JBinaryOperation; import com.google.gwt.dev.jjs.ast.JBinaryOperator; import com.google.gwt.dev.jjs.ast.JBooleanLiteral; import com.google.gwt.dev.jjs.ast.JExpression; import com.google.gwt.dev.jjs.ast.JIntLiteral; import com.google.gwt.dev.jjs.ast.JNullLiteral; import com.google.gwt.dev.jjs.ast.JPrimitiveType; import com.google.gwt.dev.jjs.ast.JValueLiteral; import com.google.gwt.dev.jjs.ast.JVariableRef; import com.google.gwt.dev.jjs.ast.JVisitor; import com.google.gwt.dev.jjs.ast.js.JMultiExpression; import com.google.gwt.dev.util.Preconditions; /** * Evaluate expression based on current assumptions. */ public class ExpressionEvaluator { /** * Main evaluation visitor. */ private static class EvaluatorVisitor extends JVisitor { private final ConstantsAssumption assumptions; /** * Contains evaluation result for visited node. Is <code>null</code> * if we can't evaluate. */ private JValueLiteral result = null; public EvaluatorVisitor(ConstantsAssumption assumptions) { this.assumptions = assumptions; } public JValueLiteral evaluate(JExpression expression) { Preconditions.checkNotNull(expression); accept(expression); return result; } @Override public boolean visit(JBinaryOperation x, Context ctx) { accept(x.getRhs()); if (result == null) { return false; } JValueLiteral rhs = result; accept(x.getLhs()); if (result == null) { return false; } JValueLiteral lhs = result; result = evalBinOp(x, lhs, rhs); return false; } @Override public boolean visit(JExpression x, Context ctx) { // We don't know what's this expression about. Can't evaluate it. result = null; return false; } @Override public boolean visit(JMultiExpression x, Context ctx) { accept(x.exprs.get(x.exprs.size() - 1)); return false; } @Override public boolean visit(JValueLiteral x, Context ctx) { result = x; return false; } @Override public boolean visit(JVariableRef x, Context ctx) { result = assumptions != null ? assumptions.get(x.getTarget()) : null; return false; } } public static JValueLiteral evalBinOp(JBinaryOperation x, JValueLiteral lhs, JValueLiteral rhs) { if (lhs instanceof JNullLiteral || rhs instanceof JNullLiteral) { if (x.getOp() == JBinaryOperator.EQ) { return JBooleanLiteral.get( (lhs instanceof JNullLiteral) && (rhs instanceof JNullLiteral)); } else if (x.getOp() == JBinaryOperator.NEQ) { return JBooleanLiteral.get( !(lhs instanceof JNullLiteral) || !(rhs instanceof JNullLiteral)); } } if (!lhs.getType().equals(rhs.getType())) { // do not even try to get type conversions right :) return null; } // TODO: support other types. if (lhs.getType().equals(JPrimitiveType.INT)) { if (!(lhs instanceof JIntLiteral) || !(rhs instanceof JIntLiteral)) { return null; } int a = ((JIntLiteral) lhs).getValue(); int b = ((JIntLiteral) rhs).getValue(); switch (x.getOp()) { case ADD: return new JIntLiteral(x.getSourceInfo(), a + b); case MUL: return new JIntLiteral(x.getSourceInfo(), a * b); case SUB: return new JIntLiteral(x.getSourceInfo(), a - b); case DIV: if (b != 0) { return new JIntLiteral(x.getSourceInfo(), a / b); } else { return null; } case EQ: return JBooleanLiteral.get(a == b); case NEQ: return JBooleanLiteral.get(a != b); case GT: return JBooleanLiteral.get(a > b); case GTE: return JBooleanLiteral.get(a >= b); case LT: return JBooleanLiteral.get(a < b); case LTE: return JBooleanLiteral.get(a <= b); default: return null; } } else if (lhs.getType().equals(JPrimitiveType.BOOLEAN)) { if (!(lhs instanceof JBooleanLiteral) || !(rhs instanceof JBooleanLiteral)) { return null; } boolean a = ((JBooleanLiteral) lhs).getValue(); boolean b = ((JBooleanLiteral) rhs).getValue(); switch (x.getOp()) { case EQ: return JBooleanLiteral.get(a == b); case NEQ: return JBooleanLiteral.get(a != b); default: return null; } } return null; } public static JValueLiteral evaluate(JExpression expression, ConstantsAssumption assumptions) { return new EvaluatorVisitor(assumptions).evaluate(expression); } }