blob: 47d806466d4e6fd9f656bc0b4526e1ff7df028ed [file] [log] [blame]
/*
* 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);
}
}