package de.skuzzle.polly.core.parser.ast.lang.operators;
import de.skuzzle.polly.core.parser.Position;
import de.skuzzle.polly.core.parser.ast.declarations.Namespace;
import de.skuzzle.polly.core.parser.ast.declarations.types.Type;
import de.skuzzle.polly.core.parser.ast.expressions.literals.Literal;
import de.skuzzle.polly.core.parser.ast.expressions.literals.NumberLiteral;
import de.skuzzle.polly.core.parser.ast.lang.BinaryOperator;
import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException;
import de.skuzzle.polly.core.parser.ast.visitor.ExecutionVisitor;
import de.skuzzle.polly.core.parser.problems.ProblemReporter;
import de.skuzzle.polly.tools.collections.Stack;
/**
* Contains arithmetic operators that operate on {@link NumberLiteral}s and produce a
* new NumberLiteral.
*
* @author Simon Taddiken
*/
public class BinaryArithmetic extends BinaryOperator<NumberLiteral, NumberLiteral> {
public BinaryArithmetic(OpType id) {
super(id);
this.initTypes(Type.NUM, Type.NUM, Type.NUM);
}
@Override
protected void exec(Stack<Literal> stack, Namespace ns,
NumberLiteral left, NumberLiteral right,
Position resultPos, ExecutionVisitor execVisitor) throws ASTTraversalException {
final ProblemReporter reporter = execVisitor.getReporter();
switch (this.getOp()) {
case ADD:
stack.push(new NumberLiteral(resultPos, left.getValue() + right.getValue()));
break;
case SUB:
stack.push(new NumberLiteral(resultPos, left.getValue() - right.getValue()));
break;
case MUL:
stack.push(new NumberLiteral(resultPos, left.getValue() * right.getValue()));
break;
case DIV:
right.nonZero(reporter);
stack.push(new NumberLiteral(resultPos, left.getValue() / right.getValue()));
break;
case INTDIV:
right.nonZero(reporter);
// XXX: implicit conversion
stack.push(new NumberLiteral(resultPos,
Math.floor(left.getValue() / right.getValue())));
break;
case MOD:
int r = right.nonZeroInteger(reporter);
int l = Math.abs(left.isInteger(reporter)) % Math.abs(r);
stack.push(new NumberLiteral(resultPos, l));
break;
case INT_AND:
stack.push(new NumberLiteral(resultPos,
left.isInteger(reporter) & right.isInteger(reporter)));
break;
case INT_OR:
stack.push(new NumberLiteral(resultPos,
left.isInteger(reporter) | right.isInteger(reporter)));
break;
case LEFT_SHIFT:
stack.push(new NumberLiteral(resultPos,
left.isInteger(reporter) << right.isInteger(reporter)));
break;
case RIGHT_SHIFT:
stack.push(new NumberLiteral(resultPos,
left.isInteger(reporter) >> right.isInteger(reporter)));
break;
case URIGHT_SHIFT:
stack.push(new NumberLiteral(resultPos,
left.isInteger(reporter) >>> right.isInteger(reporter)));
break;
case RADIX:
right.setRadix(left.isInteger(reporter));
stack.push(right);
break;
case POWER:
stack.push(new NumberLiteral(resultPos,
Math.pow(left.getValue(), right.getValue())));
break;
case MIN:
stack.push(new NumberLiteral(resultPos,
Math.min(left.getValue(), right.getValue())));
break;
case MAX:
stack.push(new NumberLiteral(resultPos,
Math.max(left.getValue(), right.getValue())));
break;
case XOR:
stack.push(new NumberLiteral(
resultPos, left.isInteger(reporter) ^ right.isInteger(reporter)));
break;
case ATAN2:
stack.push(new NumberLiteral(resultPos,
Math.atan2(left.getValue(), right.getValue())));
break;
case HYPOT:
stack.push(new NumberLiteral(resultPos,
Math.hypot(left.getValue(), right.getValue())));
break;
default:
this.invalidOperatorType(this.getOp());
}
}
}