/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.ast;
import static kodkod.ast.operator.IntCastOperator.BITSETCAST;
import static kodkod.ast.operator.IntCastOperator.INTCAST;
import static kodkod.ast.operator.IntCompOperator.EQ;
import static kodkod.ast.operator.IntCompOperator.GT;
import static kodkod.ast.operator.IntCompOperator.GTE;
import static kodkod.ast.operator.IntCompOperator.LT;
import static kodkod.ast.operator.IntCompOperator.LTE;
import static kodkod.ast.operator.IntOperator.ABS;
import static kodkod.ast.operator.IntOperator.AND;
import static kodkod.ast.operator.IntOperator.DIVIDE;
import static kodkod.ast.operator.IntOperator.MINUS;
import static kodkod.ast.operator.IntOperator.MODULO;
import static kodkod.ast.operator.IntOperator.MULTIPLY;
import static kodkod.ast.operator.IntOperator.NEG;
import static kodkod.ast.operator.IntOperator.NOT;
import static kodkod.ast.operator.IntOperator.OR;
import static kodkod.ast.operator.IntOperator.PLUS;
import static kodkod.ast.operator.IntOperator.SGN;
import static kodkod.ast.operator.IntOperator.SHA;
import static kodkod.ast.operator.IntOperator.SHL;
import static kodkod.ast.operator.IntOperator.SHR;
import static kodkod.ast.operator.IntOperator.XOR;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import kodkod.ast.operator.IntCastOperator;
import kodkod.ast.operator.IntCompOperator;
import kodkod.ast.operator.IntOperator;
import kodkod.ast.visitor.ReturnVisitor;
import kodkod.ast.visitor.VoidVisitor;
import kodkod.util.collections.Containers;
/**
* A Node whose value is an integer
* rather than a relational expression.
*
* @author Emina Torlak
*/
public abstract class IntExpression extends Node {
/**
* Constructs an IntExpression.
*/
IntExpression() {}
/**
* Returns a formula stating that the given int expression and
* this have the same value. The effect
* of this method is the same as calling this.compare(EQ, intExpr).
* @return this.compare(EQ, intExpr)
*/
public final Formula eq(IntExpression intExpr) {
return this.compare(EQ, intExpr);
}
/**
* Returns a formula stating that the value of this int expression is less than the
* value of the given int expression The effect
* of this method is the same as calling this.compare(LT, intExpr).
* @return this.compare(LT, intExpr)
*/
public final Formula lt(IntExpression intExpr) {
return this.compare(LT, intExpr);
}
/**
* Returns a formula stating that the value of this int expression is less than
* or equal to the value of the given int expression The effect
* of this method is the same as calling this.compare(LTE, intExpr).
* @return this.compare(LTE, intExpr)
*/
public final Formula lte(IntExpression intExpr) {
return this.compare(LTE, intExpr);
}
/**
* Returns a formula stating that the value of this int expression is greater than the
* value of the given int expression The effect
* of this method is the same as calling this.compare(GT, intExpr).
* @return this.compare(GT, intExpr)
*/
public final Formula gt(IntExpression intExpr) {
return this.compare(GT, intExpr);
}
/**
* Returns a formula stating that the value of this int expression is greater than
* or equal to the value of the given int expression The effect
* of this method is the same as calling this.compare(GTE, intExpr).
* @return this.compare(GTE, intExpr)
*/
public final Formula gte(IntExpression intExpr) {
return this.compare(GTE, intExpr);
}
/**
* Returns a formula comparing this and the given integer expression using the
* specified operator.
* @return {f: Formula | f.left = this and f.right = intExpr and f.op = op }
*/
public Formula compare(IntCompOperator op, IntExpression intExpr) {
if (op==null || intExpr==null)
throw new NullPointerException();
return new IntComparisonFormula(this, op, intExpr);
}
/**
* Returns an integer expression that is the sum of all
* values that this integer expression can take given the
* provided declarations.
* @return {e: IntExpression | e.decls = decls and e.intExpr = this }
*/
public final IntExpression sum(Decls decls) {
return new SumExpression(decls, this);
}
/**
* Returns an IntExpression that represents the sum of this and
* the given int node. The effect of this method is the same as calling
* this.compose(PLUS, intExpr).
* @return this.compose(PLUS, intExpr)
*/
public final IntExpression plus(IntExpression intExpr) {
return compose(PLUS, intExpr);
}
/**
* Returns an IntExpression that represents the difference between this and
* the given int node. The effect of this method is the same as calling
* this.compose(MINUS, intExpr).
* @return this.compose(MINUS, intExpr)
*/
public final IntExpression minus(IntExpression intExpr) {
return compose(MINUS, intExpr);
}
/**
* Returns an IntExpression that represents the product of this and
* the given int node. The effect of this method is the same as calling
* this.compose(MULTIPLY, intExpr).
* @return this.compose(MULTIPLY, intExpr)
*/
public final IntExpression multiply(IntExpression intExpr) {
return compose(MULTIPLY, intExpr);
}
/**
* Returns an IntExpression that represents the quotient of the division
* between this and the given int node. The effect of this method is the same as calling
* this.compose(DIVIDE, intExpr).
* @return this.compose(DIVIDE, intExpr)
*/
public final IntExpression divide(IntExpression intExpr) {
return compose(DIVIDE, intExpr);
}
/**
* Returns an IntExpression that represents the remainder of the division
* between this and the given int node. The effect of this method is the same as calling
* this.compose(MODULO, intExpr).
* @return this.compose(MODULO, intExpr)
*/
public final IntExpression modulo(IntExpression intExpr) {
return compose(MODULO, intExpr);
}
/**
* Returns an IntExpression that represents the bitwise AND of this and
* the given int node. The effect of this method is the same as calling
* this.compose(AND, intExpr).
* @return this.compose(AND, intExpr)
*/
public final IntExpression and(IntExpression intExpr) {
return compose(AND, intExpr);
}
/**
* Returns an IntExpression that represents the bitwise OR of this and
* the given int node. The effect of this method is the same as calling
* this.compose(OR, intExpr).
* @return this.compose(OR, intExpr)
*/
public final IntExpression or(IntExpression intExpr) {
return compose(OR, intExpr);
}
/**
* Returns an IntExpression that represents the bitwise XOR of this and
* the given int node. The effect of this method is the same as calling
* this.compose(XOR, intExpr).
* @return this.compose(XOR, intExpr)
*/
public final IntExpression xor(IntExpression intExpr) {
return compose(XOR, intExpr);
}
/**
* Returns an IntExpression that represents the left shift of this by
* the given int node. The effect of this method is the same as calling
* this.compose(SHL, intExpr).
* @return this.compose(SHL, intExpr)
*/
public final IntExpression shl(IntExpression intExpr) {
return compose(SHL, intExpr);
}
/**
* Returns an IntExpression that represents the right shift of this and
* the given int node, with zero extension. The effect of this method is the same as calling
* this.compose(SHR, intExpr).
* @return this.compose(SHR, intExpr)
*/
public final IntExpression shr(IntExpression intExpr) {
return compose(SHR, intExpr);
}
/**
* Returns an IntExpression that represents the right shift of this and
* the given int node, with sign extension. The effect of this method is the same as calling
* this.compose(SHA, intExpr).
* @return this.compose(SHA, intExpr)
*/
public final IntExpression sha(IntExpression intExpr) {
return compose(SHA, intExpr);
}
/**
* Returns an expression that combines this and the given integer expression using the
* specified operator.
* @requires op.binary()
* @return {e: IntExpression | e.left = this and e.right = intExpr and e.op = op }
*/
public final IntExpression compose(IntOperator op, IntExpression intExpr) {
if (op==null || intExpr==null)
throw new NullPointerException();
return new BinaryIntExpression(this, op, intExpr);
}
/**
* Returns the sum of the given int expressions. The effect of this method is the
* same as calling compose(PLUS, intExprs).
* @return compose(PLUS, intExprs)
*/
public static IntExpression plus(IntExpression...intExprs) {
return compose(PLUS, intExprs);
}
/**
* Returns the plus of the given int expressions. The effect of this method is the
* same as calling compose(PLUS, intExprs).
* @return compose(PLUS, intExprs)
*/
public static IntExpression plus(Collection<? extends IntExpression> intExprs) {
return compose(PLUS, intExprs);
}
/**
* Returns the product of the given int expressions. The effect of this method is the
* same as calling compose(MULTIPLY, intExprs).
* @return compose(MULTIPLY, intExprs)
*/
public static IntExpression multiply(IntExpression...intExprs) {
return compose(MULTIPLY, intExprs);
}
/**
* Returns the product of the given int expressions. The effect of this method is the
* same as calling compose(MULTIPLY, intExprs).
* @return compose(MULTIPLY, intExprs)
*/
public static IntExpression multiply(Collection<? extends IntExpression> intExprs) {
return compose(MULTIPLY, intExprs);
}
/**
* Returns the bitwise and of the given int expressions. The effect of this method is the
* same as calling compose(AND, intExprs).
* @return compose(AND, intExprs)
*/
public static IntExpression and(IntExpression...intExprs) {
return compose(AND, intExprs);
}
/**
* Returns the bitwise and of the given int expressions. The effect of this method is the
* same as calling compose(AND, intExprs).
* @return compose(AND, intExprs)
*/
public static IntExpression and(Collection<? extends IntExpression> intExprs) {
return compose(AND, intExprs);
}
/**
* Returns the bitwise or of the given int expressions. The effect of this method is the
* same as calling compose(OR, intExprs).
* @return compose(OR, intExprs)
*/
public static IntExpression or(IntExpression...intExprs) {
return compose(OR, intExprs);
}
/**
* Returns the bitwise or of the given int expressions. The effect of this method is the
* same as calling compose(OR, intExprs).
* @return compose(OR, intExprs)
*/
public static IntExpression or(Collection<? extends IntExpression> intExprs) {
return compose(OR, intExprs);
}
/**
* Returns the composition of the given int expressions using the given operator.
* @requires intExprs.length = 2 => op.binary(), intExprs.length > 2 => op.nary()
* @return intExprs.length=1 => intExprs[0] else {e: IntExpression | e.children = intExprs and e.op = this }
*/
public static IntExpression compose(IntOperator op, IntExpression...intExprs) {
switch(intExprs.length) {
case 0 : throw new IllegalArgumentException("Expected at least one argument: " + Arrays.toString(intExprs));
case 1 : return intExprs[0];
case 2 : return new BinaryIntExpression(intExprs[0], op, intExprs[1]);
default :
return new NaryIntExpression(op, Containers.copy(intExprs, new IntExpression[intExprs.length]));
}
}
/**
* Returns the composition of the given int expressions using the given operator.
* @requires intExprs.length = 2 => op.binary(), intExprs.length > 2 => op.nary()
* @return intExprs.size() = 1 => intExprs.iterator().next() else {e: IntExpression | e.children = intExprs.toArray() and e.op = this }
*/
public static IntExpression compose(IntOperator op, Collection<? extends IntExpression> intExprs) {
switch(intExprs.size()) {
case 0 : throw new IllegalArgumentException("Expected at least one argument: " + intExprs);
case 1 : return intExprs.iterator().next();
case 2 :
final Iterator<? extends IntExpression> itr = intExprs.iterator();
return new BinaryIntExpression(itr.next(), op, itr.next());
default :
return new NaryIntExpression(op, intExprs.toArray(new IntExpression[intExprs.size()]));
}
}
/**
* Returns an IntExpression that represents the negation of this int expression.
* The effect of this method is the same as calling this.apply(NEG).
* @return this.apply(NEG)
*/
public final IntExpression negate() {
return apply(NEG);
}
/**
* Returns an IntExpression that represents the bitwise negation of this int expression.
* The effect of this method is the same as calling this.apply(NOT).
* @return this.apply(NOT)
*/
public final IntExpression not() {
return apply(NOT);
}
/**
* Returns an IntExpression that represents the absolute value of this int expression.
* The effect of this method is the same as calling this.apply(ABS).
* @return this.apply(ABS)
*/
public final IntExpression abs() {
return apply(ABS);
}
/**
* Returns an IntExpression that represents the sign of this int expression.
* The effect of this method is the same as calling this.apply(SGN).
* @return this.apply(SGN)
*/
public final IntExpression signum() {
return apply(SGN);
}
/**
* Returns an expression that represents the application of the given unary
* operator to this integer expression.
* @requires op.unary()
* @return {e: IntExpression | e.op = op and e.intExpr = this }
*/
public final IntExpression apply(IntOperator op) {
return new UnaryIntExpression(op, this);
}
/**
* Returns an expression whose meaning is the singleton set containing the atom
* that represents the integer given by this integer expression.
* The effect of this method is the same as calling this.cast(INTCAST).
* @return this.cast(INTCAST)
*/
public final Expression toExpression() {
return cast(INTCAST);
}
/**
* Returns an expression whose meaning is the set containing the atoms
* that represent the powers of 2 (bits) present in this integer expression.
* The effect of this method is the same as calling this.cast(BITSETCAST).
* @return this.cast(BITSETCAST)
*/
public final Expression toBitset() {
return cast(BITSETCAST);
}
/**
* Returns an expression that is the relational representation of this
* integer expression specified by the given operator.
* @return an expression that is the relational representation of this
* integer expression specified by the given operator.
*/
public final Expression cast(IntCastOperator op) {
if (op==null) throw new NullPointerException();
return new IntToExprCast(this, op);
}
/**
* {@inheritDoc}
* @see kodkod.ast.Node#accept(kodkod.ast.visitor.ReturnVisitor)
*/
public abstract <E, F, D, I> I accept(ReturnVisitor<E, F, D, I> visitor) ;
/**
* {@inheritDoc}
* @see kodkod.ast.Node#accept(kodkod.ast.visitor.VoidVisitor)
*/
public abstract void accept(VoidVisitor visitor);
}