/* * RTLConditionalExpression.java - This file is part of the Jakstab project. * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org> * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, see <http://www.gnu.org/licenses/>. */ package org.jakstab.rtl.expressions; import java.util.Set; import org.jakstab.rtl.*; import org.jakstab.ssl.Architecture; import org.jakstab.util.FastSet; import org.jakstab.util.Logger; /** * An if-then-else expression similar to the C syntax of "condition ? trueExpression : falseExpression". * * @author Johannes Kinder */ public class RTLConditionalExpression extends AbstractRTLExpression implements RTLExpression { @SuppressWarnings("unused") private final static Logger logger = Logger.getLogger(RTLConditionalExpression.class); protected Set<RTLMemoryLocation> usedMemoryLocations = null; private final RTLExpression condition; private final RTLExpression trueExpression; private final RTLExpression falseExpression; private final int size; /** * @param condition * @param trueExpression * @param falseExpression */ protected RTLConditionalExpression(RTLExpression condition, RTLExpression trueExpression, RTLExpression falseExpression) { super(); this.condition = condition; this.trueExpression = trueExpression; this.falseExpression = falseExpression; this.size = 1 + condition.size() + trueExpression.size() + falseExpression.size(); } /** * @return the condition */ public RTLExpression getCondition() { return condition; } /** * @return the trueExpression */ public RTLExpression getTrueExpression() { return trueExpression; } /** * @return the falseExpression */ public RTLExpression getFalseExpression() { return falseExpression; } @Override public String toString() { return "(" + condition.toString() + " ? " + trueExpression.toString() + " : " + falseExpression.toString() + ")"; } @Override public RTLExpression evaluate(Context context) { RTLExpression evaldCondition = this.condition.evaluate(context); if (evaldCondition.equals(ExpressionFactory.FALSE)) return this.falseExpression.evaluate(context); else if (evaldCondition.equals(ExpressionFactory.TRUE)) return this.trueExpression.evaluate(context); assert !(evaldCondition instanceof RTLNumber) : "Numeric condition result is neither TRUE nor FALSE but " + evaldCondition; RTLExpression evaldTrue = trueExpression.evaluate(context); RTLExpression evaldFalse = falseExpression.evaluate(context); // Collapse "(x == y) ? 1<1> : 0<1>" to (x == y) if (evaldTrue.equals(ExpressionFactory.TRUE) && evaldFalse.equals(ExpressionFactory.FALSE)) { return evaldCondition; } else if (evaldTrue.equals(ExpressionFactory.FALSE) && evaldFalse.equals(ExpressionFactory.TRUE)) { return ExpressionFactory.createOperation(Operator.NOT, evaldCondition); } return ExpressionFactory.createConditionalExpression(evaldCondition, evaldTrue, evaldFalse); } @Override public SetOfVariables getUsedVariables() { if (usedVariables == null) { usedVariables = new SetOfVariables(); usedVariables.addAll(condition.getUsedVariables()); usedVariables.addAll(trueExpression.getUsedVariables()); usedVariables.addAll(falseExpression.getUsedVariables()); } return usedVariables; } @Override public Set<RTLMemoryLocation> getUsedMemoryLocations() { if (usedMemoryLocations == null) { usedMemoryLocations = new FastSet<RTLMemoryLocation>(); usedMemoryLocations.addAll(condition.getUsedMemoryLocations()); usedMemoryLocations.addAll(trueExpression.getUsedMemoryLocations()); usedMemoryLocations.addAll(falseExpression.getUsedMemoryLocations()); } return usedMemoryLocations; } @Override public int size() { return size; } /* * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != this.getClass()) return false; RTLConditionalExpression other = (RTLConditionalExpression)obj; return other.condition.equals(condition) && other.trueExpression.equals(trueExpression) && other.falseExpression.equals(falseExpression); } /* * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 17 + condition.hashCode() + trueExpression.hashCode() + falseExpression.hashCode(); } @Override public int getBitWidth() { return trueExpression.getBitWidth(); } @Override public RTLExpression inferBitWidth(Architecture arch, int expectedBitWidth) throws TypeInferenceException { RTLExpression typedCondition = condition.inferBitWidth(arch, 1); RTLExpression typedTrueExpression = trueExpression.inferBitWidth(arch, expectedBitWidth); RTLExpression typedFalseExpression = falseExpression.inferBitWidth(arch, expectedBitWidth); if (typedCondition != condition || typedTrueExpression != trueExpression || typedFalseExpression != falseExpression) return ExpressionFactory.createConditionalExpression( typedCondition, typedTrueExpression, typedFalseExpression); else return this; } @Override public <T> T accept(ExpressionVisitor<T> visitor) { return visitor.visit(this); } }