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; public abstract class TernaryOperator<FIRST extends Literal, SECOND extends Literal, THIRD extends Literal> extends Operator { private final static ResolvableIdentifier FIRST_PARAM_NAME = new ResolvableIdentifier(Position.NONE, "$first"); private final static ResolvableIdentifier SECOND_PARAM_NAME = new ResolvableIdentifier(Position.NONE, "$second"); private final static ResolvableIdentifier THIRD_PARAM_NAME = new ResolvableIdentifier(Position.NONE, "$third"); protected Type first; protected Type second; protected Type third; public TernaryOperator(OpType id) { super(id); } /** * Initializes the result- and operand types for this operator. * * @param resulType The result type of this operator. * @param first Type of the first operand. * @param second Type of the second operand. * @param third Type of the third operand. */ protected final void initTypes(Type resulType, Type first, Type second, Type third) { this.addType(resulType); this.setUnique(resulType); this.first = first; this.second = second; this.third = third; } @Override protected FunctionLiteral createFunction() { Collection<Declaration> p = Arrays.asList(new Declaration[] { this.typeToParameter(this.first, FIRST_PARAM_NAME), this.typeToParameter(this.second, SECOND_PARAM_NAME), this.typeToParameter(this.third, THIRD_PARAM_NAME), }); final FunctionLiteral func = new FunctionLiteral(Position.NONE, p, this); func.setUnique( new ProductType( this.first, this.second, this.third).mapTo(this.getUnique())); return func; } @Override @SuppressWarnings("unchecked") public final void execute(Stack<Literal> stack, Namespace ns, ExecutionVisitor execVisitor) throws ASTTraversalException { final FIRST first = (FIRST) ns.resolveFirst(FIRST_PARAM_NAME).getExpression(); final SECOND second = (SECOND) ns.resolveFirst(SECOND_PARAM_NAME).getExpression(); final THIRD third = (THIRD) ns.resolveFirst(THIRD_PARAM_NAME).getExpression(); final Position resultPos = Position.correctSpan(first.getPosition(), second.getPosition(), third.getPosition()); this.exec(stack, ns, first, second, third, resultPos, execVisitor); } /** * Called to generate the result of this operator on the stack. * * @param stack The current execution stack. * @param ns The current execution namespace. * @param first First operand of this operator. * @param second Second operand of this operator. * @param third Third 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, FIRST first, SECOND second, THIRD third, Position resultPos, ExecutionVisitor execVisitor) throws ASTTraversalException; @Override public final void resolveType(Namespace ns, AbstractTypeResolver typeResolver) throws ASTTraversalException { final Expression first = ns.resolveFirst(FIRST_PARAM_NAME).getExpression(); final Expression second = ns.resolveFirst(SECOND_PARAM_NAME).getExpression(); final Expression third = ns.resolveFirst(THIRD_PARAM_NAME).getExpression(); this.resolve(first, second, third, ns, typeResolver); } /** * Called to context check this operator. Default implementation does nothing. * * @param first The first operand of the operator call. * @param second The second operand of the operator call. * @param third The third 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 first, Expression second, Expression third, Namespace ns, AbstractTypeResolver typeResolver) throws ASTTraversalException { // empty } }