package de.skuzzle.polly.core.parser.ast.lang; import java.util.Arrays; import java.util.Collection; import de.skuzzle.polly.core.parser.Position; import de.skuzzle.polly.core.parser.ast.ResolvableIdentifier; import de.skuzzle.polly.core.parser.ast.declarations.Declaration; import de.skuzzle.polly.core.parser.ast.declarations.Namespace; import de.skuzzle.polly.core.parser.ast.declarations.types.ProductType; import de.skuzzle.polly.core.parser.ast.declarations.types.Type; import de.skuzzle.polly.core.parser.ast.expressions.Expression; import de.skuzzle.polly.core.parser.ast.expressions.literals.FunctionLiteral; import de.skuzzle.polly.core.parser.ast.expressions.literals.Literal; import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException; import de.skuzzle.polly.core.parser.ast.visitor.ExecutionVisitor; import de.skuzzle.polly.core.parser.ast.visitor.resolving.AbstractTypeResolver; import de.skuzzle.polly.tools.collections.Stack; /** * Superclass for binary operators. The {@link #createDeclaration()} method is * pre-implemented to return a matching declaration for this operator. * * @author Simon Taddiken * @param <L> Literal type of the left operand of this operator. * @param <R> Literal type of the right operand of this operator. */ public abstract class BinaryOperator<L extends Literal, R extends Literal> extends Operator { private final static ResolvableIdentifier LEFT_PARAM_NAME = new ResolvableIdentifier(Position.NONE, "$left"); private final static ResolvableIdentifier RIGHT_PARAM_NAME = new ResolvableIdentifier(Position.NONE, "$right"); protected Type left; protected Type right; /** * Creates a new binary operator. * * @param id The type of the operator. */ public BinaryOperator(OpType id) { super(id); } /** * Initializes the result- and operand types for this operator. * * @param resultType The type of the value that this operator returns. * @param left Type of the left operand. * @param right Type of the right operand. */ protected final void initTypes(Type resultType, Type left, Type right) { this.addType(resultType); this.setUnique(resultType); this.left = left; this.right = right; } @Override protected FunctionLiteral createFunction() { final Collection<Declaration> p = Arrays.asList(new Declaration[] { this.typeToParameter(this.left, LEFT_PARAM_NAME), this.typeToParameter(this.right, RIGHT_PARAM_NAME) }); final FunctionLiteral func = new FunctionLiteral(Position.NONE, p, this); final ProductType source = new ProductType( this.left, this.right); func.setUnique(source.mapTo(this.getUnique())); return func; } @Override @SuppressWarnings("unchecked") public final void execute(Stack<Literal> stack, Namespace ns, ExecutionVisitor execVisitor) throws ASTTraversalException { final L left = (L) ns.resolveFirst(LEFT_PARAM_NAME).getExpression(); final R right = (R) ns.resolveFirst(RIGHT_PARAM_NAME).getExpression(); final Position resultPos = Position.correctSpan(left.getPosition(), right.getPosition()); this.exec(stack, ns, left, right, resultPos, execVisitor); } @Override public final void resolveType(Namespace ns, AbstractTypeResolver typeResolver) throws ASTTraversalException { final Expression left = ns.resolveFirst(LEFT_PARAM_NAME).getExpression(); final Expression right = ns.resolveFirst(RIGHT_PARAM_NAME).getExpression(); this.resolve(left, right, ns, typeResolver); } /** * Called to context check this operator. Default implementation does nothing. * * @param left The left operand of the operator call. * @param right The right operand of the operator call. * @param ns The current namespace. * @param typeResolver The {@link TypeResolver}. * @throws ASTTraversalException If context checking fails. */ protected void resolve(Expression left, Expression right, Namespace ns, AbstractTypeResolver typeResolver) throws ASTTraversalException { // empty } /** * Called to generate the result of this operator on the stack. * * @param stack The current execution stack. * @param ns The current execution namespace. * @param left Left operand of this operator. * @param right Right operand of this operator. * @param resultPos Position that can be used as position for the result literal. * @param execVisitor Current execution visitor. * @throws ASTTraversalException If executing fails for any reason. */ protected abstract void exec(Stack<Literal> stack, Namespace ns, L left, R right, Position resultPos, ExecutionVisitor execVisitor) throws ASTTraversalException; }