All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.streamx.fluent.extree.expression.SimpleExpressionVisitor Maven / Gradle / Ivy

The newest version!
package co.streamx.fluent.extree.expression;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Default expression visitor implementation.
 * 
 * 
 */

public abstract class SimpleExpressionVisitor implements ExpressionVisitor {

    private final List> argumentsStack = new ArrayList<>();

    protected List getContextArguments() {
        return argumentsStack.isEmpty() ? null : argumentsStack.get(argumentsStack.size() - 1);
    }

    protected List popContextArguments() {
        return argumentsStack.isEmpty() ? null : argumentsStack.remove(argumentsStack.size() - 1);
    }

    protected Expression resolveContextParameter(ParameterExpression p) {
        return resolveContextParameter(p, argumentsStack.size() - 1);
    }

    private Expression resolveContextParameter(ParameterExpression p,
                                               int frame) {
        Expression e = argumentsStack.get(frame).get(p.getIndex());
        if (e instanceof ParameterExpression)
            return frame == 0 ? e : resolveContextParameter((ParameterExpression) e, frame - 1);
        return e;
    }

    protected void pushContextArguments(List args) {
        argumentsStack.add(args);
    }

    protected  List visitExpressionList(List original) {
        if (original != null) {
            List list = null;
            for (int i = 0, n = original.size(); i < n; i++) {
                final T t = original.get(i);
                @SuppressWarnings("unchecked")
                final T p = t != null ? (T) t.accept(this) : null;
                if (list != null) {
                    list.add(p);
                } else if (p != t) {
                    list = new ArrayList<>(n);
                    for (int j = 0; j < i; j++) {
                        list.add(original.get(j));
                    }
                    list.add(p);
                }
            }
            if (list != null) {
                return Collections.unmodifiableList(list);
            }
        }
        return original;
    }

    protected List visitLocals(List original) {
        return visitExpressionList(original);
    }

    protected List visitArguments(List original) {
        return visitExpressionList(original);
    }

    protected List visitParameters(List original) {
        return visitExpressionList(original);
    }

    @Override
    public Expression visit(BinaryExpression e) {
        Expression first = e.getFirst();
        Expression visitedFirst = first.accept(this);

        Expression second = e.getSecond();
        Expression visitedSecond = second.accept(this);

        Expression op = e.getOperator();
        Expression visitedOp = op != null ? op.accept(this) : op;

        if (first != visitedFirst || second != visitedSecond || op != visitedOp)
            return Expression.binary(e.getExpressionType(), visitedOp, visitedFirst, visitedSecond);

        return e;
    }

    @Override
    public Expression visit(ConstantExpression e) {
        Object value = e.getValue();
        if (value instanceof Expression) {
            Object newValue = ((Expression) value).accept(this);
            if (value != newValue)
                return Expression.constant(newValue);
        }
        return e;
    }

    @Override
    public Expression visit(InvocationExpression e) {
        List arguments = e.getArguments();
        Expression target = e.getTarget();
        boolean visitTargetWithOldArgs = /*
                                          * target.getExpressionType() == ExpressionType.MethodAccess ||
                                          */ target.getExpressionType() == ExpressionType.Delegate;
        boolean cleanArgsStack = false;
        List args = arguments;
        if (!visitTargetWithOldArgs) {
            args = visitArguments(arguments);
            pushContextArguments(arguments);
            cleanArgsStack = true;
        }
        try {
            target = target.accept(this);
            if (visitTargetWithOldArgs) {
                args = visitArguments(arguments);
            }

            if (args != arguments || target != e.getTarget()) {
                return invoke((InvocableExpression) target, args, e);
            }
            return e;
        } finally {
            if (cleanArgsStack)
                popContextArguments();
        }
    }

    protected Expression invoke(InvocableExpression target,
                                List args,
                                InvocationExpression original) {
        return Expression.invoke((InvocableExpression) target, args);
    }

    @Override
    public Expression visit(LambdaExpression e) {

        List parameters = visitParameters(e.getParameters());
        List locals = visitLocals(e.getLocals());

        Expression body = e.getBody().accept(this);

        if (body != e.getBody() || parameters != e.getParameters() || locals != e.getLocals())
            return Expression.lambda(e.getResultType(), body, parameters, locals, e.getKey());

        return e;
    }

    @Override
    public Expression visit(DelegateExpression e) {

        List parameters = visitParameters(e.getParameters());
        if (parameters != e.getParameters())
            return Expression.delegate(e.getResultType(), e.getDelegate(), parameters);

        return e;
    }

    @Override
    public Expression visit(BlockExpression e) {
        List expressions = e.getExpressions();
        List visitedList = new ArrayList<>(expressions.size());
        boolean changed = false;
        for (Expression s : expressions) {
            Expression visited = s.accept(this);
            if (s != visited)
                changed = true;
            visitedList.add(visited);
        }
        return changed ? Expression.block(e.getResultType(), visitedList) : e;
    }

    @Override
    public Expression visit(MemberExpression e) {
        Expression instance = e.getInstance();
        if (instance != null) {
            List contextArguments = popContextArguments();
            try {
                instance = instance.accept(this);
            } finally {
                if (contextArguments != null)
                    pushContextArguments(contextArguments);
            }
            if (instance instanceof LambdaExpression)
                return instance;
        }
        List parameters = visitParameters(e.getParameters());
        if (instance != e.getInstance() || parameters != e.getParameters())
            return Expression.member(e.getExpressionType(), instance, e.getMember(), e.getResultType(), parameters);

        return e;
    }

    @Override
    public Expression visit(NewArrayInitExpression newArrayInitExpression) {
        Expression[] initializers = newArrayInitExpression.getInitializers().toArray(new Expression[0]);

        boolean changed = false;
        for (int i = 0; i < initializers.length; i++) {
            Expression e = initializers[i];
            Expression visited = e.accept(this);
            if (e != visited) {
                changed = true;
                initializers[i] = visited;
            }
        }
        return changed ? Expression.newArrayInit(newArrayInitExpression.getComponentType(), Arrays.asList(initializers))
                : newArrayInitExpression;
    }

    @Override
    public Expression visit(ParameterExpression e) {
        return e;
    }

    @Override
    public Expression visit(UnaryExpression e) {
        Expression operand = e.getFirst();
        Expression visitedOp = operand.accept(this);
        if (operand != visitedOp)
            return Expression.unary(e.getExpressionType(), e.getResultType(), visitedOp);

        return e;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy