ArgumentBinder.java

package org.sterling.runtime.expression;

import static org.sterling.runtime.expression.ExpressionFactory.access;
import static org.sterling.runtime.expression.ExpressionFactory.apply;
import static org.sterling.runtime.expression.ExpressionFactory.declaration;
import static org.sterling.runtime.expression.ExpressionFactory.lambda;

import java.util.HashSet;
import java.util.Set;
import org.sterling.SterlingException;

public class ArgumentBinder implements ExpressionVisitor<Expression, Argument> {

    private static final ArgumentBinder INSTANCE = new ArgumentBinder();

    public static Expression bindArgument(Expression expression, Argument argument) throws SterlingException {
        return INSTANCE.visit(expression, argument);
    }

    private ArgumentBinder() {
        // intentionally empty
    }

    @Override
    public Expression visit(Expression expression, Argument argument) throws SterlingException {
        return expression.accept(this, argument);
    }

    @Override
    public Expression visitAccessExpression(AccessedExpression expression, Argument argument) throws SterlingException {
        return access(visit(expression.getExpression(), argument), visit(expression.getMember(), argument));
    }

    @Override
    public Expression visitApplyExpression(AppliedExpression expression, Argument argument) throws SterlingException {
        return apply(visit(expression.getExpression(), argument), visit(expression.getArgument(), argument));
    }

    @Override
    public Expression visitArgumentExpression(Argument expression, Argument argument) throws SterlingException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Expression visitBindExpression(BoundExpression expression, Argument argument) throws SterlingException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Expression visitLambda(Lambda lambda, Argument argument) throws SterlingException {
        if (argument.isApplicableTo(lambda)) {
            return lambda(lambda.getVariable(), visit(lambda.getExpression(), argument));
        } else {
            return lambda;
        }
    }

    @Override
    public Expression visitObjectExpression(ObjectExpression object, Argument argument) throws SterlingException {
        Set<DeclaredExpression> declarations = new HashSet<>();
        for (DeclaredExpression declaration : object.getMembers()) {
            declarations.add(declaration(declaration.getSymbol(), visit(declaration.getExpression(), argument)));
        }
        return new ObjectExpression(declarations);
    }

    @Override
    public Expression visitPrimaryExpression(Expression expression, Argument argument) throws SterlingException {
        if (argument.replaces(expression)) {
            return argument.getExpression();
        } else {
            return expression;
        }
    }

    @Override
    public Expression visitReference(Reference reference, Argument data) throws SterlingException {
        return visit(reference.reduce(), data);
    }
}