Package xbird.xquery.optim

Source Code of xbird.xquery.optim.LoopInvariantsTransformer

/*
* @(#)$Id: LoopInvariantsTransformer.java 3619 2008-03-26 07:23:03Z yui $
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.xquery.optim;

import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import xbird.xquery.XQueryException;
import xbird.xquery.XQueryModule;
import xbird.xquery.expr.LiteralExpr;
import xbird.xquery.expr.XQExpression;
import xbird.xquery.expr.comp.ComparisonOp;
import xbird.xquery.expr.cond.IfExpr;
import xbird.xquery.expr.cond.QuantifiedExpr;
import xbird.xquery.expr.constructor.AttributeConstructor;
import xbird.xquery.expr.constructor.AttributeConstructorBase;
import xbird.xquery.expr.constructor.CommentConstructor;
import xbird.xquery.expr.constructor.DocConstructor;
import xbird.xquery.expr.constructor.ElementConstructor;
import xbird.xquery.expr.constructor.NamespaceConstructor;
import xbird.xquery.expr.constructor.PIConstructor;
import xbird.xquery.expr.constructor.TextConstructor;
import xbird.xquery.expr.decorative.ExtensionExpr;
import xbird.xquery.expr.decorative.ParenthesizedExpr;
import xbird.xquery.expr.decorative.UnorderedExpr;
import xbird.xquery.expr.dyna.ContextItemExpr;
import xbird.xquery.expr.dyna.ValidateOp;
import xbird.xquery.expr.ext.BDQExpr;
import xbird.xquery.expr.flwr.Binding;
import xbird.xquery.expr.flwr.FLWRExpr;
import xbird.xquery.expr.flwr.ForClause;
import xbird.xquery.expr.flwr.GroupingSpec;
import xbird.xquery.expr.flwr.LetClause;
import xbird.xquery.expr.flwr.OrderSpec;
import xbird.xquery.expr.func.DirectFunctionCall;
import xbird.xquery.expr.func.FunctionCall;
import xbird.xquery.expr.func.LazyFunctionCall;
import xbird.xquery.expr.func.RecursiveCall;
import xbird.xquery.expr.logical.AndExpr;
import xbird.xquery.expr.logical.OrExpr;
import xbird.xquery.expr.math.AdditiveExpr;
import xbird.xquery.expr.math.MultiplicativeExpr;
import xbird.xquery.expr.math.NegativeExpr;
import xbird.xquery.expr.opt.DistinctSortExpr;
import xbird.xquery.expr.opt.ExpressionProxy;
import xbird.xquery.expr.opt.PathIndexAccessExpr;
import xbird.xquery.expr.opt.PathVariable;
import xbird.xquery.expr.opt.TypePromotedExpr;
import xbird.xquery.expr.opt.Join.PromoteJoinExpression;
import xbird.xquery.expr.path.FilterExpr;
import xbird.xquery.expr.path.NodeTest;
import xbird.xquery.expr.path.PathExpr;
import xbird.xquery.expr.path.FilterExpr.ConditionalFilter;
import xbird.xquery.expr.path.FilterExpr.Instruction;
import xbird.xquery.expr.path.PathExpr.CompositePath;
import xbird.xquery.expr.path.axis.AxisStep;
import xbird.xquery.expr.seq.SequenceExpression;
import xbird.xquery.expr.seq.SequenceOp;
import xbird.xquery.expr.seq.UnionOp;
import xbird.xquery.expr.types.CaseClause;
import xbird.xquery.expr.types.CastExpr;
import xbird.xquery.expr.types.CastableExpr;
import xbird.xquery.expr.types.InstanceofOp;
import xbird.xquery.expr.types.TreatExpr;
import xbird.xquery.expr.types.TypeswitchExpr;
import xbird.xquery.expr.var.BindingVariable;
import xbird.xquery.expr.var.VarRef;
import xbird.xquery.expr.var.Variable;
import xbird.xquery.expr.var.BindingVariable.ForVariable;
import xbird.xquery.expr.var.BindingVariable.LetVariable;
import xbird.xquery.expr.var.BindingVariable.LoopInvariantLetVariable;
import xbird.xquery.expr.var.BindingVariable.ParametricVariable;
import xbird.xquery.expr.var.BindingVariable.PositionalVariable;
import xbird.xquery.expr.var.Variable.ExternalVariable;
import xbird.xquery.expr.var.Variable.PreEvaluatedVariable;
import xbird.xquery.func.BuiltInFunction;
import xbird.xquery.func.UserFunction;
import xbird.xquery.meta.XQueryContext;
import xbird.xquery.misc.QNameTable.QualifiedName;
import xbird.xquery.parser.XQueryParserVisitor;

/**
* Attempt 'loop-invariants code motion' optimization.
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
* @deprecated
*/
public final class LoopInvariantsTransformer implements XQueryParserVisitor {

    private final FLWRExpr _flwr;
    private final ForClause _forClause;
    private final ForVariable _loopForVar;
    private final PositionalVariable _loopPosVar;
    private final int _noFollowBefore;

    private boolean _protectHook = false;
    private final Map<XQExpression, ExpressionProxy> _invarients = new IdentityHashMap<XQExpression, ExpressionProxy>(16);
    private final Map<LetClause, List<Binding>> _pullup = new IdentityHashMap<LetClause, List<Binding>>(4);

    public LoopInvariantsTransformer(FLWRExpr flwr, ForClause forClause) {
        this._flwr = flwr;
        this._forClause = forClause;
        ForVariable forVar = forClause.getVariable();
        this._loopForVar = forVar;
        this._loopPosVar = forClause.getPositionVariable();
        this._noFollowBefore = forVar.getBirthId();
    }

    public XQExpression visit(AdditiveExpr op, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression left = op.getLeftOperand();
        XQExpression left2 = left.visit(this, ctxt);
        if(left2 != left) {
            op.setLeftOperand(left2);
        }
        isLoopInvariant &= left.isLoopInvariant();
        XQExpression right = op.getRightOperand();
        XQExpression right2 = right.visit(this, ctxt);
        if(right2 != right) {
            op.setRightOperand(right2);
        }
        isLoopInvariant &= right.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(left);
            removeInvariants(right);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(AndExpr andExpr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        List<XQExpression> exprs = andExpr.getExpressions();
        int exprsSize = exprs.size();
        for(int i = 0; i < exprsSize; i++) {
            XQExpression e = exprs.get(i);
            XQExpression e2 = e.visit(this, ctxt);
            if(e2 != e) {
                exprs.set(i, e2);
            }
            isLoopInvariant &= e.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(XQExpression e : andExpr.getExpressions()) {
                removeInvariants(e);
            }
            return hookLoopInvariant(andExpr);
        }
        return andExpr;
    }

    public XQExpression visit(AttributeConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        boolean isLoopInvariant = true;
        QualifiedName name = constructor.getName();
        if(name == null) {
            XQExpression nameExpr = constructor.getNameExpr();
            XQExpression nameExpr2 = nameExpr.visit(this, ctxt);
            if(nameExpr2 != nameExpr) {
                constructor.setNameExpr(nameExpr2);
            }
            isLoopInvariant &= nameExpr.isLoopInvariant();
        }
        for(XQExpression ve : constructor.getValueExprs()) {
            ve.visit(this, ctxt);
            isLoopInvariant &= ve.isLoopInvariant();
        }
        if(isLoopInvariant) {
            if(name == null) {
                XQExpression nameExpr = constructor.getNameExpr();
                removeInvariants(nameExpr);
            }
            for(XQExpression ve : constructor.getValueExprs()) {
                removeInvariants(ve);
            }
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(AxisStep step, XQueryContext ctxt) throws XQueryException {
        NodeTest nt = step.getNodeTest();
        nt.visit(this, ctxt);
        boolean isLoopInvariant = nt.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(nt);
            return hookLoopInvariant(step);
        }
        return step;
    }

    public XQExpression visit(BindingVariable variable, XQueryContext ctxt) throws XQueryException {
        XQExpression inExpr = variable.getValue();
        if(inExpr == null) {
            assert (variable instanceof PositionalVariable) : variable.getName();
            return variable; // TODO REVIEWME
        }
        inExpr.visit(this, ctxt);
        boolean isLoopInvariant = inExpr.isLoopInvariant();//TODO REVIEWME
        if(isLoopInvariant) {
            if(variable == _loopForVar || variable == _loopPosVar) {
                removeInvariants(inExpr);
                variable.setLoopInvariant(false);
            } else {
                int birth = variable.getBirthId();
                if(birth < _noFollowBefore) {
                    removeInvariants(inExpr);
                    if(variable instanceof ForVariable || variable instanceof PositionalVariable) {
                        variable.setLoopInvariant(false);
                    } else {
                        variable.setLoopInvariant(true);
                    }
                } else {
                    variable.setLoopInvariant(false);
                }
            }
        }
        return variable;
    }

    public XQExpression visit(BuiltInFunction function, XQueryContext ctxt) throws XQueryException {
        return null;
    }

    public XQExpression visit(CaseClause clause, XQueryContext ctxt) throws XQueryException {
        XQExpression e = clause.getReturnExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(clause);
        }
        return clause;
    }

    public XQExpression visit(CastableExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(CastExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(CommentConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        boolean isLoopInvariant = true;
        String content = constructor.getContent();
        if(content == null) {
            XQExpression contentExpr = constructor.getContentExpr();
            assert (contentExpr != null);
            contentExpr.visit(this, ctxt);
            isLoopInvariant &= constructor.isLoopInvariant();
        }
        if(isLoopInvariant) {
            XQExpression contentExpr = constructor.getContentExpr();
            removeInvariants(contentExpr);
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(ComparisonOp comp, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression left = comp.getLeftOperand();
        left.visit(this, ctxt);
        isLoopInvariant &= left.isLoopInvariant();
        XQExpression right = comp.getRightOperand();
        right.visit(this, ctxt);
        isLoopInvariant &= right.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(left);
            removeInvariants(right);
            return hookLoopInvariant(comp);
        }
        return comp;
    }

    public XQExpression visit(CompositePath fragment, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression src = fragment.getSourceExpr();
        src.visit(this, ctxt);
        isLoopInvariant &= src.isLoopInvariant();
        if(!isLoopInvariant) {
            return fragment;
        }
        XQExpression filter = fragment.getFilterExpr();
        filter.visit(this, ctxt);
        isLoopInvariant &= filter.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(src);
            removeInvariants(filter);
            return hookLoopInvariant(fragment);
        }
        return fragment;
    }

    public XQExpression visit(ContextItemExpr expr, XQueryContext ctxt) throws XQueryException {
        expr.setLoopInvariant(false);
        return expr;
    }

    public XQExpression visit(DirectFunctionCall call, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true; // TODO REVIEWME
        for(XQExpression p : call.getParams()) {
            p.visit(this, ctxt);
            isLoopInvariant &= p.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(XQExpression p : call.getParams()) {
                removeInvariants(p);
            }
            return hookLoopInvariant(call);
        }
        return call;
    }

    public XQExpression visit(DistinctSortExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression step = expr.getStepExpr();
        assert (step != null);
        step.visit(this, ctxt);
        boolean isLoopInvariant = step.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(step);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(DocConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        XQExpression expr = constructor.getExpr();
        expr.visit(this, ctxt);
        boolean isLoopInvariant = expr.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(expr);
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(ElementConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        boolean isLoopInvariant = true;
        String name = constructor.getElemName();
        if(name == null) {
            XQExpression nameExpr = constructor.getNameExpr();
            nameExpr.visit(this, ctxt);
            isLoopInvariant &= nameExpr.isLoopInvariant();
        }
        for(AttributeConstructorBase att : constructor.getAttributes()) {
            att.visit(this, ctxt);
            isLoopInvariant &= att.isLoopInvariant();
        }
        for(XQExpression v : constructor.getContents()) {
            v.visit(this, ctxt);
            isLoopInvariant &= v.isLoopInvariant();
        }
        if(isLoopInvariant) {
            if(name != null) {
                XQExpression nameExpr = constructor.getNameExpr();
                removeInvariants(nameExpr);
                for(AttributeConstructorBase att : constructor.getAttributes()) {
                    removeInvariants(att);
                }
                for(XQExpression v : constructor.getContents()) {
                    removeInvariants(v);
                }
            }
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(ExpressionProxy proxy, XQueryContext ctxt) throws XQueryException {
        return proxy;
    }

    public XQExpression visit(ExtensionExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(ExternalVariable var, XQueryContext ctxt) throws XQueryException {
        var.setLoopInvariant(false);
        return var;
    }

    public XQExpression visit(FilterExpr expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression e = expr.getSourceExpr();
        e.visit(this, ctxt);
        isLoopInvariant &= e.isLoopInvariant();
        for(XQExpression p : expr.getPredicates()) {
            p.visit(this, ctxt);
            isLoopInvariant &= p.isLoopInvariant();
        }
        if(isLoopInvariant) {
            removeInvariants(e);
            for(XQExpression p : expr.getPredicates()) {
                removeInvariants(p);
            }
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(FLWRExpr flwr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        // #1 for loop
        List<Binding> bindings = flwr.getClauses();
        for(int i = 0; i < bindings.size(); i++) {
            Binding b = bindings.get(i);
            int type = b.getExpressionType();
            if(flwr.isTransformed()) {
                if(type == Binding.FOR_CLAUSE) {
                    // no need to analyze
                    return flwr;
                } else {
                    LetClause lc = (LetClause) b;
                    lc.visit(this, ctxt);
                    if(lc.isLoopInvariant()) {
                        _pullup.put(lc, bindings);
                    }
                }
            } else {
                if(type == Binding.FOR_CLAUSE) {
                    ForClause forClause = (ForClause) b;
                    int loopDepth = forClause.getLoopDepth();
                    if(loopDepth <= 1) {
                        _protectHook = true;
                    }
                    forClause.visit(this, ctxt);
                    _protectHook = false;
                } else {
                    b.visit(this, ctxt);
                }
            }
            isLoopInvariant &= b.isLoopInvariant();
        }
        // #2 return
        XQExpression filteredRet = flwr.getFilteredReturnExpr();
        if(filteredRet != null) {
            XQExpression filteredRet2 = filteredRet.visit(this, ctxt);
            flwr.setFilteredReturnExpr(filteredRet2);
            isLoopInvariant &= filteredRet2.isLoopInvariant();
        } else {
            // #2-1 where filtering
            XQExpression where = flwr.getWhereExpr();
            if(where != null) {
                where.visit(this, ctxt);
                isLoopInvariant &= where.isLoopInvariant();
            }
            // #2-2 return
            XQExpression ret = flwr.getReturnExpr();
            assert (ret != null);
            ret.visit(this, ctxt);
            isLoopInvariant &= ret.isLoopInvariant();
        }
        // #3 order by sorting
        for(OrderSpec o : flwr.getOrderSpecs()) {
            o.visit(this, ctxt);
            isLoopInvariant &= o.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(Binding b : bindings) {
                removeInvariants(b);
            }
            if(filteredRet != null) {
                removeInvariants(filteredRet);
            } else {
                XQExpression where = flwr.getWhereExpr();
                if(where != null) {
                    removeInvariants(where);
                }
                XQExpression ret = flwr.getReturnExpr();
                removeInvariants(ret);
            }
            for(OrderSpec o : flwr.getOrderSpecs()) {
                removeInvariants(o);
            }
            return hookLoopInvariant(flwr);
        }
        return flwr;
    }

    public ForClause visit(ForClause clause, XQueryContext ctxt) throws XQueryException {
        XQExpression e = clause.getInExpr();
        XQExpression e2 = e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            clause.setInExpr(e2);
            clause.setLoopInvariant(true);
        }
        return clause;
    }

    public XQExpression visit(FunctionCall call, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        for(XQExpression p : call.getParams()) {
            p.visit(this, ctxt);
            isLoopInvariant &= p.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(XQExpression p : call.getParams()) {
                removeInvariants(p);
            }
            return hookLoopInvariant(call);
        }
        return call;
    }
   
    public XQExpression visit(GroupingSpec spec, XQueryContext ctxt) throws XQueryException {
        return spec;
    }

    public XQExpression visit(IfExpr expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        // if
        XQExpression cond = expr.getCondExpr();
        cond.visit(this, ctxt);
        isLoopInvariant &= cond.isLoopInvariant();
        // then
        XQExpression then = expr.getThenExpr();
        then.visit(this, ctxt);
        isLoopInvariant &= then.isLoopInvariant();
        // else
        XQExpression els = expr.getElseExpr();
        els.visit(this, ctxt);
        isLoopInvariant &= els.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(cond);
            removeInvariants(then);
            removeInvariants(els);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(InstanceofOp op, XQueryContext ctxt) throws XQueryException {
        XQExpression e = op.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(Instruction instruction, XQueryContext ctxt) throws XQueryException {
        assert (!(instruction instanceof ConditionalFilter));
        instruction.setLoopInvariant(false);
        return instruction;
    }

    public XQExpression visit(LazyFunctionCall call, XQueryContext ctxt) throws XQueryException {
        this.visit((FunctionCall) call, ctxt);
        return call;
    }

    public LetClause visit(LetClause clause, XQueryContext ctxt) throws XQueryException {
        XQExpression e = clause.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            clause.setLoopInvariant(true);
        }
        return clause;
    }

    public XQExpression visit(LiteralExpr expr, XQueryContext ctxt) throws XQueryException {
        expr.setLoopInvariant(true);
        return expr;
    }

    public XQExpression visit(MultiplicativeExpr op, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression left = op.getLeftOperand();
        left.visit(this, ctxt);
        isLoopInvariant &= left.isLoopInvariant();
        XQExpression right = op.getRightOperand();
        right.visit(this, ctxt);
        isLoopInvariant &= right.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(left);
            removeInvariants(right);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(NamespaceConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        constructor.setLoopInvariant(true);
        return constructor;
    }

    public XQExpression visit(NegativeExpr op, XQueryContext ctxt) throws XQueryException {
        XQExpression e = op.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(NodeTest nt, XQueryContext ctxt) throws XQueryException {
        nt.setLoopInvariant(true);
        return nt;
    }

    public XQExpression visit(OrderSpec spec, XQueryContext ctxt) throws XQueryException {
        XQExpression e = spec.getKeyExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(spec);
        }
        return spec;
    }

    public XQExpression visit(OrExpr expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        for(XQExpression e : expr.getExpressions()) {
            e.visit(this, ctxt);
            isLoopInvariant &= e.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(XQExpression e : expr.getExpressions()) {
                removeInvariants(e);
            }
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(ParametricVariable variable, XQueryContext ctxt)
            throws XQueryException {
        this.visit((Variable) variable, ctxt);
        return variable;
    }

    public XQExpression visit(ParenthesizedExpr paren, XQueryContext ctxt) throws XQueryException {
        XQExpression e = paren.getExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(paren);
        }
        return paren;
    }

    public XQExpression visit(PathExpr path, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        List<XQExpression> steps = path.getSteps();
        int steplen = steps.size();
        for(int i = 0; i < steplen; i++) {
            XQExpression s = steps.get(i);
            XQExpression s2 = s.visit(this, ctxt);
            if(s != s2) {
                steps.set(i, s2);
            }
            isLoopInvariant &= s.isLoopInvariant();
        }
        if(isLoopInvariant) {
            for(XQExpression s : path.getSteps()) {
                removeInvariants(s);
            }
            return hookLoopInvariant(path);
        }
        return path;
    }

    public XQExpression visit(PathIndexAccessExpr variable, XQueryContext ctxt)
            throws XQueryException {
        variable.setLoopInvariant(true);
        return variable;
    }

    public XQExpression visit(PathVariable variable, XQueryContext ctxt) throws XQueryException {
        XQExpression e = variable.getValue();
        assert (e != null);
        XQExpression e2 = e.visit(this, ctxt);
        variable.setValue(e2);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(variable);
        }
        return variable;
    }

    public XQExpression visit(PIConstructor constructor, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        String target = constructor.getTarget();
        if(target == null) {
            XQExpression t = constructor.getTargetExpr();
            t.visit(this, ctxt);
            isLoopInvariant &= t.isLoopInvariant();
        }
        String content = constructor.getContent();
        if(content == null) {
            XQExpression c = constructor.getContentExpr();
            c.visit(this, ctxt);
            isLoopInvariant &= c.isLoopInvariant();
        }
        if(isLoopInvariant) {
            XQExpression t = constructor.getTargetExpr();
            if(t != null) {
                removeInvariants(t);
            }
            XQExpression c = constructor.getContentExpr();
            if(c != null) {
                removeInvariants(c);
            }
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(PreEvaluatedVariable variable, XQueryContext ctxt)
            throws XQueryException {
        variable.setLoopInvariant(true);
        return variable;
    }

    public XQExpression visit(PromoteJoinExpression join, XQueryContext ctxt)
            throws XQueryException {
        XQExpression srcExpr = join.getSrcExpr();
        XQExpression replaced = srcExpr.visit(this, ctxt);
        join.setSrcExpr(replaced);

        List<XQExpression> searchKeys = join.getSearchKeyExprs();
        for(int i = 0; i < searchKeys.size(); i++) {
            XQExpression key = searchKeys.get(i);
            XQExpression newKey = key.visit(this, ctxt);
            if(newKey != key) {
                searchKeys.set(i, newKey);
            }
        }

        join.setLoopInvariant(false);
        return join;
    }

    public XQExpression visit(QuantifiedExpr expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        BindingVariable binding = expr.getBinding();
        visit(binding, ctxt);
        isLoopInvariant &= binding.isLoopInvariant();

        XQExpression cond = expr.getCondExpr();
        cond.visit(this, ctxt);
        isLoopInvariant &= cond.isLoopInvariant();

        if(isLoopInvariant) {
            removeInvariants(binding);
            removeInvariants(cond);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(RecursiveCall call, XQueryContext ctxt) throws XQueryException {
        visit((FunctionCall) call, ctxt);
        return call;
    }

    public XQExpression visit(SequenceExpression expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        for(XQExpression e : expr.getExpressions()) {
            e.visit(this, ctxt);
            isLoopInvariant &= e.isLoopInvariant();
        }
        if(isLoopInvariant) {
            List<XQExpression> exprs = expr.getExpressions();
            if(exprs.isEmpty()) {
                expr.setLoopInvariant(true);
            } else {
                for(XQExpression e : exprs) {
                    removeInvariants(e);
                }
                return hookLoopInvariant(expr);
            }
        }
        return expr;
    }

    public XQExpression visit(SequenceOp op, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression left = op.getLeftOperand();
        left.visit(this, ctxt);
        isLoopInvariant &= left.isLoopInvariant();
        XQExpression right = op.getRightOperand();
        right.visit(this, ctxt);
        isLoopInvariant &= right.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(left);
            removeInvariants(right);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(TextConstructor constructor, XQueryContext ctxt)
            throws XQueryException {
        XQExpression content = constructor.getContent();
        content.visit(this, ctxt);
        boolean isLoopInvariant = content.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(content);
            return hookLoopInvariant(constructor);
        }
        return constructor;
    }

    public XQExpression visit(TreatExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(TypePromotedExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getPromotedExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(TypeswitchExpr expr, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = true;
        XQExpression opr = expr.getOperandExpr();
        opr.visit(this, ctxt);
        isLoopInvariant &= opr.isLoopInvariant();
        for(XQExpression c : expr.getCaseClauses()) {
            c.visit(this, ctxt);
            isLoopInvariant &= c.isLoopInvariant();
        }
        XQExpression def = expr.getDefaultClause();
        if(def != null) {
            def.visit(this, ctxt);
            isLoopInvariant &= def.isLoopInvariant();
        }
        if(isLoopInvariant) {
            removeInvariants(opr);
            for(XQExpression c : expr.getCaseClauses()) {
                removeInvariants(c);
            }
            def = expr.getDefaultClause();
            if(def != null) {
                removeInvariants(def);
            }
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(UnionOp op, XQueryContext ctxt) throws XQueryException {
        visit((SequenceOp) op, ctxt);
        return op;
    }

    public XQExpression visit(UnorderedExpr expr, XQueryContext ctxt) throws XQueryException {
        XQExpression e = expr.getExpr();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(expr);
        }
        return expr;
    }

    public XQExpression visit(UserFunction function, XQueryContext ctxt) throws XQueryException {
        XQExpression body = function.getBodyExpression();
        body.visit(this, ctxt);
        boolean isLoopInvariant = body.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(body); // TODO REVIEWME
        }
        return null;
    }

    public XQExpression visit(ValidateOp op, XQueryContext ctxt) throws XQueryException {
        XQExpression e = op.getExpression();
        e.visit(this, ctxt);
        boolean isLoopInvariant = e.isLoopInvariant();
        if(isLoopInvariant) {
            removeInvariants(e);
            return hookLoopInvariant(op);
        }
        return op;
    }

    public XQExpression visit(Variable variable, XQueryContext ctxt) throws XQueryException {
        boolean isLoopInvariant = false;
        if(variable.getResult() == null) {
            XQExpression e = variable.getValue();
            if(e == null) {
                return variable;
            }
            e.visit(this, ctxt);
            isLoopInvariant = e.isLoopInvariant();
            if(isLoopInvariant) {
                removeInvariants(e);
            }
        }
        if(isLoopInvariant) {
            return hookLoopInvariant(variable);
        }
        return variable;
    }

    public XQExpression visit(VarRef ref, XQueryContext ctxt) throws XQueryException {
        Variable var = ref.getValue();
        var.visit(this, ctxt);
        boolean isLoopInvariant = var.isLoopInvariant();
        if(isLoopInvariant) {
            return hookLoopInvariant(ref);
        }
        return ref;
    }

    public XQExpression visit(BDQExpr expr, XQueryContext ctxt) throws XQueryException {
        // TODO REVIEWME
        XQExpression body = expr.getBodyExpression();
        expr.visit(this, ctxt);
        return expr;
    }

    public XQExpression visit(XQueryModule module, XQueryContext ctxt) throws XQueryException {
        XQExpression body = module.getExpression();
        body.visit(this, ctxt);
        return null;
    }

    public XQExpression visit(XQExpression expr, XQueryContext ctxt) throws XQueryException {
        if(expr instanceof AdditiveExpr) {
            return visit((AdditiveExpr) expr, ctxt);
        } else if(expr instanceof AndExpr) {
            return visit((AndExpr) expr, ctxt);
        } else if(expr instanceof AttributeConstructor) {
            return visit((AttributeConstructor) expr, ctxt);
        } else if(expr instanceof AxisStep) {
            return visit((AxisStep) expr, ctxt);
        } else if(expr instanceof BindingVariable) {
            return visit((BindingVariable) expr, ctxt);
        } else if(expr instanceof BuiltInFunction) {
            return visit((BuiltInFunction) expr, ctxt);
        } else if(expr instanceof CaseClause) {
            return visit((CaseClause) expr, ctxt);
        } else if(expr instanceof CastableExpr) {
            return visit((CastableExpr) expr, ctxt);
        } else if(expr instanceof CastExpr) {
            return visit((CastExpr) expr, ctxt);
        } else if(expr instanceof CommentConstructor) {
            return visit((CommentConstructor) expr, ctxt);
        } else if(expr instanceof ComparisonOp) {
            return visit((ComparisonOp) expr, ctxt);
        } else if(expr instanceof CompositePath) {
            return visit((CompositePath) expr, ctxt);
        } else if(expr instanceof ContextItemExpr) {
            return visit((ContextItemExpr) expr, ctxt);
        } else if(expr instanceof DirectFunctionCall) {
            return visit((DirectFunctionCall) expr, ctxt);
        } else if(expr instanceof DistinctSortExpr) {
            return visit((DistinctSortExpr) expr, ctxt);
        } else if(expr instanceof DocConstructor) {
            return visit((DocConstructor) expr, ctxt);
        } else if(expr instanceof ElementConstructor) {
            return visit((ElementConstructor) expr, ctxt);
        } else if(expr instanceof ExtensionExpr) {
            return visit((ExtensionExpr) expr, ctxt);
        } else if(expr instanceof ExternalVariable) {
            return visit((ExternalVariable) expr, ctxt);
        } else if(expr instanceof FilterExpr) {
            return visit((FilterExpr) expr, ctxt);
        } else if(expr instanceof FLWRExpr) {
            return visit((FLWRExpr) expr, ctxt);
        } else if(expr instanceof ForClause) {
            return visit((ForClause) expr, ctxt);
        } else if(expr instanceof FunctionCall) {
            return visit((FunctionCall) expr, ctxt);
        } else if(expr instanceof IfExpr) {
            return visit((IfExpr) expr, ctxt);
        } else if(expr instanceof InstanceofOp) {
            return visit((InstanceofOp) expr, ctxt);
        } else if(expr instanceof Instruction) {
            return visit((Instruction) expr, ctxt);
        } else if(expr instanceof LetClause) {
            return visit((LetClause) expr, ctxt);
        } else if(expr instanceof LiteralExpr) {
            return visit((LiteralExpr) expr, ctxt);
        } else if(expr instanceof MultiplicativeExpr) {
            return visit((MultiplicativeExpr) expr, ctxt);
        } else if(expr instanceof NamespaceConstructor) {
            return visit((NamespaceConstructor) expr, ctxt);
        } else if(expr instanceof NegativeExpr) {
            return visit((NegativeExpr) expr, ctxt);
        } else if(expr instanceof NodeTest) {
            return visit((NodeTest) expr, ctxt);
        } else if(expr instanceof OrderSpec) {
            return visit((OrderSpec) expr, ctxt);
        } else if(expr instanceof OrExpr) {
            return visit((OrExpr) expr, ctxt);
        } else if(expr instanceof ParenthesizedExpr) {
            return visit((ParenthesizedExpr) expr, ctxt);
        } else if(expr instanceof PathExpr) {
            return visit((PathExpr) expr, ctxt);
        } else if(expr instanceof PathVariable) {
            return visit((PathVariable) expr, ctxt);
        } else if(expr instanceof PIConstructor) {
            return visit((PIConstructor) expr, ctxt);
        } else if(expr instanceof PreEvaluatedVariable) {
            return visit((PreEvaluatedVariable) expr, ctxt);
        } else if(expr instanceof PromoteJoinExpression) {
            return visit((PromoteJoinExpression) expr, ctxt);
        } else if(expr instanceof QuantifiedExpr) {
            return visit((QuantifiedExpr) expr, ctxt);
        } else if(expr instanceof SequenceExpression) {
            return visit((SequenceExpression) expr, ctxt);
        } else if(expr instanceof SequenceOp) {
            return visit((SequenceOp) expr, ctxt);
        } else if(expr instanceof TextConstructor) {
            return visit((TextConstructor) expr, ctxt);
        } else if(expr instanceof TreatExpr) {
            return visit((TreatExpr) expr, ctxt);
        } else if(expr instanceof TypePromotedExpr) {
            return visit((TypePromotedExpr) expr, ctxt);
        } else if(expr instanceof TypeswitchExpr) {
            return visit((TypeswitchExpr) expr, ctxt);
        } else if(expr instanceof UnionOp) {
            return visit((UnionOp) expr, ctxt);
        } else if(expr instanceof UnorderedExpr) {
            return visit((UnorderedExpr) expr, ctxt);
        } else if(expr instanceof UserFunction) {
            return visit((UserFunction) expr, ctxt);
        } else if(expr instanceof ValidateOp) {
            return visit((ValidateOp) expr, ctxt);
        } else if(expr instanceof Variable) {
            return visit((Variable) expr, ctxt);
        } else if(expr instanceof VarRef) {
            return visit((VarRef) expr, ctxt);
        } else if(expr instanceof BDQExpr) {
            return visit((BDQExpr) expr, ctxt);
        } else if(expr instanceof XQueryModule) {
            return visit((XQueryModule) expr, ctxt);
        } else {
            throw new IllegalStateException("Unexpected expression: " + expr.getClass().getName());
        }
    }

    private void removeInvariants(XQExpression expr) {
        ExpressionProxy removed = _invarients.remove(expr);
    }

    private XQExpression hookLoopInvariant(XQExpression expr) {
        if(_protectHook) {
            expr.setLoopInvariant(true);
            return expr;
        }
        ExpressionProxy proxy = new ExpressionProxy(expr);
        proxy.setLoopInvariant(true);
        _invarients.put(expr, proxy);
        return proxy;
    }

    @Deprecated
    public void transform() {//TODO
        _flwr.setTransformed(true);

        List<Binding> clauses = _flwr.getClauses();
        int clauselen = clauses.size();
        int insertionPoint = 0;
        for(int i = 0; i < clauselen; i++) {
            Binding binding = clauses.get(i);
            if(binding == _forClause) {
                insertionPoint = i;
                break;
            }
        }

        if(!_pullup.isEmpty()) {
            final Set<Entry<LetClause, List<Binding>>> entries = _pullup.entrySet();
            for(Entry<LetClause, List<Binding>> e : entries) {
                final LetClause lc = e.getKey();
                clauses.add(insertionPoint, lc);
                final List<Binding> srcClauses = e.getValue();
                srcClauses.remove(lc);
            }
            _pullup.clear();
        }

        final Collection<ExpressionProxy> proxys = _invarients.values();
        if(!proxys.isEmpty()) {
            for(ExpressionProxy proxy : proxys) {
                final XQExpression orig = proxy.getOriginalExpr();
                final LetVariable lv = new LoopInvariantLetVariable(orig);
                proxy.setReplacedExpr(lv);
                final LetClause lc = new LetClause(lv);
                clauses.add(insertionPoint, lc);
            }
            _invarients.clear();
        }
    }

}
TOP

Related Classes of xbird.xquery.optim.LoopInvariantsTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.