org.apache.vxquery.xmlquery.translator.XMLQueryTranslator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.vxquery.xmlquery.translator.XMLQueryTranslator.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
package org.apache.vxquery.xmlquery.translator;

import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.namespace.QName;

import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.vxquery.compiler.CompilerControlBlock;
import org.apache.vxquery.compiler.algebricks.VXQueryConstantValue;
import org.apache.vxquery.context.StaticContext;
import org.apache.vxquery.context.StaticContextImpl;
import org.apache.vxquery.context.ThinStaticContextImpl;
import org.apache.vxquery.context.XQueryVariable;
import org.apache.vxquery.datamodel.builders.atomic.StringValueBuilder;
import org.apache.vxquery.datamodel.values.ValueTag;
import org.apache.vxquery.exceptions.ErrorCode;
import org.apache.vxquery.exceptions.SystemException;
import org.apache.vxquery.functions.BuiltinFunctions;
import org.apache.vxquery.functions.BuiltinOperators;
import org.apache.vxquery.functions.ExternalFunction;
import org.apache.vxquery.functions.Function;
import org.apache.vxquery.functions.Signature;
import org.apache.vxquery.functions.UserDefinedXQueryFunction;
import org.apache.vxquery.metadata.QueryResultSetDataSink;
import org.apache.vxquery.runtime.functions.cast.CastToDecimalOperation;
import org.apache.vxquery.types.AnyItemType;
import org.apache.vxquery.types.AnyNodeType;
import org.apache.vxquery.types.AnyType;
import org.apache.vxquery.types.AtomicType;
import org.apache.vxquery.types.AttributeType;
import org.apache.vxquery.types.BuiltinTypeConstants;
import org.apache.vxquery.types.BuiltinTypeRegistry;
import org.apache.vxquery.types.CommentType;
import org.apache.vxquery.types.DocumentType;
import org.apache.vxquery.types.ElementType;
import org.apache.vxquery.types.EmptySequenceType;
import org.apache.vxquery.types.ItemType;
import org.apache.vxquery.types.NameTest;
import org.apache.vxquery.types.NodeType;
import org.apache.vxquery.types.ProcessingInstructionType;
import org.apache.vxquery.types.Quantifier;
import org.apache.vxquery.types.SchemaType;
import org.apache.vxquery.types.SequenceType;
import org.apache.vxquery.types.TextType;
import org.apache.vxquery.types.TypeUtils;
import org.apache.vxquery.xmlquery.ast.ASTNode;
import org.apache.vxquery.xmlquery.ast.ASTTag;
import org.apache.vxquery.xmlquery.ast.AtomicTypeNode;
import org.apache.vxquery.xmlquery.ast.AttributeTestNode;
import org.apache.vxquery.xmlquery.ast.AxisStepNode;
import org.apache.vxquery.xmlquery.ast.BaseUriDeclNode;
import org.apache.vxquery.xmlquery.ast.BoundarySpaceDeclNode;
import org.apache.vxquery.xmlquery.ast.CDataSectionNode;
import org.apache.vxquery.xmlquery.ast.ComputedAttributeConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedCommentConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedDocumentConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedElementConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedPIConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedTextConstructorNode;
import org.apache.vxquery.xmlquery.ast.ConstructionDeclNode;
import org.apache.vxquery.xmlquery.ast.ContentCharsNode;
import org.apache.vxquery.xmlquery.ast.CopyNamespacesDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultCollationDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultElementNamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultFunctionNamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.DirectAttributeConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectCommentConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectElementConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectPIConstructorNode;
import org.apache.vxquery.xmlquery.ast.DocumentTestNode;
import org.apache.vxquery.xmlquery.ast.ElementTestNode;
import org.apache.vxquery.xmlquery.ast.EmptyOrderDeclNode;
import org.apache.vxquery.xmlquery.ast.EnclosedExprNode;
import org.apache.vxquery.xmlquery.ast.ExprNode;
import org.apache.vxquery.xmlquery.ast.ExtensionExprNode;
import org.apache.vxquery.xmlquery.ast.FLWORClauseNode;
import org.apache.vxquery.xmlquery.ast.FLWORExprNode;
import org.apache.vxquery.xmlquery.ast.FilterExprNode;
import org.apache.vxquery.xmlquery.ast.ForClauseNode;
import org.apache.vxquery.xmlquery.ast.ForVarDeclNode;
import org.apache.vxquery.xmlquery.ast.FunctionDeclNode;
import org.apache.vxquery.xmlquery.ast.FunctionExprNode;
import org.apache.vxquery.xmlquery.ast.IfExprNode;
import org.apache.vxquery.xmlquery.ast.InfixExprNode;
import org.apache.vxquery.xmlquery.ast.InfixExprNode.InfixOperator;
import org.apache.vxquery.xmlquery.ast.LetClauseNode;
import org.apache.vxquery.xmlquery.ast.LetVarDeclNode;
import org.apache.vxquery.xmlquery.ast.LibraryModuleNode;
import org.apache.vxquery.xmlquery.ast.LiteralNode;
import org.apache.vxquery.xmlquery.ast.MainModuleNode;
import org.apache.vxquery.xmlquery.ast.ModuleImportNode;
import org.apache.vxquery.xmlquery.ast.ModuleNode;
import org.apache.vxquery.xmlquery.ast.NCNameNode;
import org.apache.vxquery.xmlquery.ast.NameTestNode;
import org.apache.vxquery.xmlquery.ast.NamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.OptionDeclNode;
import org.apache.vxquery.xmlquery.ast.OrderSpecNode;
import org.apache.vxquery.xmlquery.ast.OrderbyClauseNode;
import org.apache.vxquery.xmlquery.ast.OrderedExprNode;
import org.apache.vxquery.xmlquery.ast.OrderingModeDeclNode;
import org.apache.vxquery.xmlquery.ast.PITestNode;
import org.apache.vxquery.xmlquery.ast.ParamNode;
import org.apache.vxquery.xmlquery.ast.ParenthesizedExprNode;
import org.apache.vxquery.xmlquery.ast.PathExprNode;
import org.apache.vxquery.xmlquery.ast.PrologNode;
import org.apache.vxquery.xmlquery.ast.QNameNode;
import org.apache.vxquery.xmlquery.ast.QuantifiedExprNode;
import org.apache.vxquery.xmlquery.ast.QuantifiedExprNode.QuantifierType;
import org.apache.vxquery.xmlquery.ast.QuantifiedVarDeclNode;
import org.apache.vxquery.xmlquery.ast.QueryBodyNode;
import org.apache.vxquery.xmlquery.ast.RelativePathExprNode;
import org.apache.vxquery.xmlquery.ast.SchemaImportNode;
import org.apache.vxquery.xmlquery.ast.SequenceTypeNode;
import org.apache.vxquery.xmlquery.ast.SingleTypeNode;
import org.apache.vxquery.xmlquery.ast.TypeDeclNode;
import org.apache.vxquery.xmlquery.ast.TypeExprNode;
import org.apache.vxquery.xmlquery.ast.UnaryExprNode;
import org.apache.vxquery.xmlquery.ast.UnorderedExprNode;
import org.apache.vxquery.xmlquery.ast.ValidateExprNode;
import org.apache.vxquery.xmlquery.ast.VarDeclNode;
import org.apache.vxquery.xmlquery.ast.VarRefNode;
import org.apache.vxquery.xmlquery.ast.VersionDeclNode;
import org.apache.vxquery.xmlquery.ast.WhereClauseNode;
import org.apache.vxquery.xmlquery.query.Module;
import org.apache.vxquery.xmlquery.query.ModuleType;
import org.apache.vxquery.xmlquery.query.XMLQueryCompilerConstants;
import org.apache.vxquery.xmlquery.query.XQueryConstants;
import org.apache.vxquery.xmlquery.query.XQueryConstants.PathType;
import org.apache.vxquery.xmlquery.query.XQueryConstants.TypeQuantifier;

import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalPlan;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
import edu.uci.ics.hyracks.data.std.primitive.DoublePointable;
import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
import edu.uci.ics.hyracks.data.std.util.ByteArrayAccessibleOutputStream;

public class XMLQueryTranslator {
    private static final Pattern UNQUOTER = Pattern
            .compile("(<)|(>)|(')|(&)|(")|(\"\")|('')|(&#\\d+;)|(&#x(?:[A-Fa-f0-9])+;)");

    private final CompilerControlBlock ccb;

    private final StaticContext rootCtx;

    private StaticContext moduleCtx;

    private IVariableScope rootVarScope;

    private StaticContext currCtx;

    private int varCounter;

    private final ByteArrayAccessibleOutputStream baaos;

    private final DataOutput dOut;

    private final StringValueBuilder stringVB;

    public XMLQueryTranslator(CompilerControlBlock ccb) {
        this.ccb = ccb;
        varCounter = 0;
        rootCtx = ccb.getStaticContext();

        baaos = new ByteArrayAccessibleOutputStream();
        dOut = new DataOutputStream(baaos);
        stringVB = new StringValueBuilder();
    }

    private void pushContext() {
        currCtx = new ThinStaticContextImpl(currCtx);
    }

    private void popContext() {
        currCtx = currCtx.getParent();
    }

    public Module translateModule(ModuleNode moduleNode) throws SystemException {
        Module module = new Module();

        moduleCtx = new StaticContextImpl(rootCtx);
        moduleCtx.registerVariable(new XQueryVariable(XMLQueryCompilerConstants.DOT_VAR_NAME,
                SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE), newLogicalVariable()));
        rootVarScope = new RootVariableScope();
        currCtx = moduleCtx;
        module.setModuleContext(moduleCtx);
        module.setCompilerControlBlock(ccb);

        VersionDeclNode ver = moduleNode.getVersion();
        if (ver != null) {
            if (!"1.0".equals(ver.getVersion())) {
                throw new SystemException(ErrorCode.XQST0031, ver.getSourceLocation());
            }
        }

        switch (moduleNode.getTag()) {
        case LIBRARY_MODULE: {
            module.setModuleType(ModuleType.LIBRARY);
            LibraryModuleNode lmNode = (LibraryModuleNode) moduleNode;
            String prefix = lmNode.getModuleDecl().getPrefix();
            String uri = unquote(lmNode.getModuleDecl().getTargetNS());
            if (prefix != null) {
                currCtx.registerNamespaceUri(prefix, uri);
            }
            module.setNamespaceUri(uri);
            break;
        }

        case MAIN_MODULE: {
            module.setModuleType(ModuleType.MAIN);
            break;
        }

        default:
            throw new IllegalStateException("Unknown module type: " + moduleNode.getTag());
        }

        PrologNode prologNode = moduleNode.getProlog();
        parsePrologPass1(prologNode);
        parsePrologPass2(prologNode);

        ILogicalPlan plan = null;
        switch (moduleNode.getTag()) {
        case LIBRARY_MODULE:
            throw new SystemException(ErrorCode.TODO);

        case MAIN_MODULE:
            plan = translateMainModule((MainModuleNode) moduleNode);
        }

        module.setBody(plan);
        return module;
    }

    @SuppressWarnings("unchecked")
    private void parsePrologPass1(PrologNode prologNode) throws SystemException {
        if (prologNode != null) {
            List<ASTNode> decls = prologNode.getDecls();
            for (ASTNode d : decls) {
                switch (d.getTag()) {
                case DEFAULT_ELEMENT_NAMESPACE_DECLARATION: {
                    DefaultElementNamespaceDeclNode node = (DefaultElementNamespaceDeclNode) d;
                    moduleCtx.setDefaultElementNamespaceUri(node.getUri());
                    break;
                }

                case DEFAULT_FUNCTION_NAMESPACE_DECLARATION: {
                    DefaultFunctionNamespaceDeclNode node = (DefaultFunctionNamespaceDeclNode) d;
                    moduleCtx.setDefaultFunctionNamespaceUri(node.getUri());
                    break;
                }

                case BOUNDARY_SPACE_DECLARATION: {
                    BoundarySpaceDeclNode node = (BoundarySpaceDeclNode) d;
                    moduleCtx.setBoundarySpaceProperty(node.getMode());
                    break;
                }

                case DEFAULT_COLLATION_DECLARATION: {
                    DefaultCollationDeclNode node = (DefaultCollationDeclNode) d;
                    moduleCtx.setDefaultCollation(node.getCollation());
                    break;
                }

                case BASE_URI_DECLARATION: {
                    BaseUriDeclNode node = (BaseUriDeclNode) d;
                    moduleCtx.setBaseUri(node.getUri());
                    break;
                }

                case CONSTRUCTION_DECLARATION: {
                    ConstructionDeclNode node = (ConstructionDeclNode) d;
                    moduleCtx.setConstructionModeProperty(node.getMode());
                    break;
                }

                case ORDERING_MODE_DECLARATION: {
                    OrderingModeDeclNode node = (OrderingModeDeclNode) d;
                    moduleCtx.setOrderingModeProperty(node.getMode());
                    break;
                }

                case EMPTY_ORDER_DECLARATION: {
                    EmptyOrderDeclNode node = (EmptyOrderDeclNode) d;
                    moduleCtx.setEmptyOrderProperty(node.getMode());
                    break;
                }

                case COPY_NAMESPACES_DECLARATION: {
                    CopyNamespacesDeclNode node = (CopyNamespacesDeclNode) d;
                    moduleCtx.setCopyNamespacesModeProperty(node.getMode());
                    break;
                }

                case NAMESPACE_DECLARATION: {
                    NamespaceDeclNode node = (NamespaceDeclNode) d;
                    moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getUri()));
                    break;
                }

                case SCHEMA_IMPORT: {
                    SchemaImportNode node = (SchemaImportNode) d;
                    if (node.isDefaultElementNamespace()) {
                        moduleCtx.setDefaultElementNamespaceUri(node.getTargetNS());
                    }
                    if (node.getPrefix() != null) {
                        moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getTargetNS()));
                    }
                    moduleCtx.registerSchemaImport(node.getTargetNS(), node.getLocations());
                    break;
                }

                case MODULE_IMPORT: {
                    ModuleImportNode node = (ModuleImportNode) d;
                    if (node.getPrefix() != null) {
                        moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getTargetNS()));
                    }
                    moduleCtx.registerModuleImport(node.getTargetNS(), node.getLocations());
                    break;
                }

                case VARIABLE_DECLARATION: {
                    VarDeclNode node = (VarDeclNode) d;
                    QName name = createQName(node.getName());
                    SequenceType type = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
                    if (node.getType() != null) {
                        type = createSequenceType(node.getType());
                    }
                    LogicalVariable lVar = newLogicalVariable();
                    XQueryVariable var = new XQueryVariable(name, type, lVar);
                    moduleCtx.registerVariable(var);
                    break;
                }

                case FUNCTION_DECLARATION: {
                    FunctionDeclNode node = (FunctionDeclNode) d;
                    boolean external = node.getBody() == null;
                    QName name = createQName(node.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
                    String uri = name.getNamespaceURI();
                    if (XQueryConstants.FN_NSURI.equals(uri) || XQueryConstants.XS_NSURI.equals(uri)
                            || XQueryConstants.XSI_NSURI.equals(uri) || XQueryConstants.XML_NSURI.equals(uri)) {
                        throw new SystemException(ErrorCode.XQST0045, node.getSourceLocation());
                    }
                    SequenceType rType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
                    if (node.getReturnType() != null) {
                        rType = createSequenceType(node.getReturnType());
                    }
                    Pair<QName, SequenceType> paramTypes[] = new Pair[node.getParameters().size()];
                    for (int i = 0; i < paramTypes.length; ++i) {
                        ParamNode pNode = node.getParameters().get(i);
                        QName pName = createQName(pNode.getName());
                        SequenceType pType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
                        if (pNode.getType() != null) {
                            pType = createSequenceType(pNode.getType());
                        }
                        paramTypes[i] = Pair.<QName, SequenceType>of(pName, pType);
                    }
                    Signature sign = new Signature(rType, paramTypes);
                    Function f = external ? new ExternalFunction(name, sign)
                            : new UserDefinedXQueryFunction(name, sign, null);
                    moduleCtx.registerFunction(f);
                    break;
                }

                case OPTION_DECLARATION: {
                    OptionDeclNode node = (OptionDeclNode) d;
                    QName name = createQName(node.getName());
                    moduleCtx.setOption(name, node.getValue());
                    break;
                }

                default:
                    throw new IllegalStateException("Unknown node: " + d.getTag());
                }
            }
        }
    }

    private void parsePrologPass2(PrologNode prologNode) throws SystemException {
        if (prologNode != null) {
            List<ASTNode> decls = prologNode.getDecls();
            for (ASTNode d : decls) {
                switch (d.getTag()) {
                case VARIABLE_DECLARATION: {
                    VarDeclNode node = (VarDeclNode) d;
                    // TODO Support Global variables
                    break;
                }

                case FUNCTION_DECLARATION: {
                    FunctionDeclNode node = (FunctionDeclNode) d;
                    boolean external = node.getBody() == null;
                    if (!external) {
                        QName name = createQName(node.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
                        int arity = node.getParameters().size();
                        UserDefinedXQueryFunction f = (UserDefinedXQueryFunction) moduleCtx.lookupFunction(name,
                                arity);
                        Signature sign = f.getSignature();
                        TranslationContext tCtx = new TranslationContext(null, new EmptyTupleSourceOperator());
                        XQueryVariable[] params = new XQueryVariable[arity];
                        for (int i = 0; i < arity; ++i) {
                            ParamNode pNode = node.getParameters().get(i);
                            QName pName = createQName(pNode.getName());
                            SequenceType pType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
                            if (pNode.getType() != null) {
                                pType = createSequenceType(pNode.getType());
                            }
                            XQueryVariable pVar = new XQueryVariable(pName, pType, newLogicalVariable());
                            params[i] = pVar;
                            tCtx.varScope.registerVariable(pVar);
                        }
                        f.setParameters(params);
                        LogicalVariable var = translateExpression(node.getBody(), tCtx);
                        ILogicalExpression expr = treat(vre(var), sign.getReturnType());
                        var = createAssignment(expr, tCtx);
                        f.setBody(new ALogicalPlanImpl(mutable(tCtx.op)));
                    }
                    break;
                }
                }
            }
        }
    }

    private SequenceType createSequenceType(ASTNode type) throws SystemException {
        switch (type.getTag()) {
        case TYPE_DECLARATION: {
            TypeDeclNode tDecl = (TypeDeclNode) type;
            return createSequenceType(tDecl.getType());
        }

        case SEQUENCE_TYPE: {
            SequenceTypeNode sType = (SequenceTypeNode) type;

            if (sType.getItemType() == null) {
                return SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
            }

            TypeQuantifier tq = sType.getQuantifier();
            Quantifier q = Quantifier.QUANT_ONE;
            if (tq != null) {
                switch (tq) {
                case QUANT_QUESTION:
                    q = Quantifier.QUANT_QUESTION;
                    break;

                case QUANT_PLUS:
                    q = Quantifier.QUANT_PLUS;
                    break;

                case QUANT_STAR:
                    q = Quantifier.QUANT_STAR;
                    break;
                }
            }

            ItemType iType = createItemType(sType.getItemType());
            return SequenceType.create(iType, q);
        }

        case EMPTY_SEQUENCE_TYPE: {
            return SequenceType.create(EmptySequenceType.INSTANCE, Quantifier.QUANT_ZERO);
        }

        case SINGLE_TYPE: {
            SingleTypeNode stNode = (SingleTypeNode) type;
            ItemType iType = createItemType(stNode.getAtomicType());
            return SequenceType.create(iType,
                    stNode.isOptional() ? Quantifier.QUANT_QUESTION : Quantifier.QUANT_ONE);
        }

        default:
            throw new IllegalStateException("Unknown node: " + type.getTag());
        }
    }

    private ItemType createItemType(ASTNode itemType) throws SystemException {
        switch (itemType.getTag()) {
        case ITEM_TYPE:
            return AnyItemType.INSTANCE;

        case ATOMIC_TYPE: {
            AtomicTypeNode atNode = (AtomicTypeNode) itemType;
            QName tName = createQName(atNode.getName());
            SchemaType sType = moduleCtx.lookupSchemaType(tName);
            if (sType == null || !sType.isAtomicType()) {
                throw new SystemException(ErrorCode.XPST0051, atNode.getSourceLocation());
            }
            return (ItemType) sType;
        }

        case ANY_NODE_TEST:
            return AnyNodeType.INSTANCE;

        case DOCUMENT_TEST: {
            DocumentTestNode dt = (DocumentTestNode) itemType;
            if (dt.getElementTest() == null) {
                return DocumentType.ANYDOCUMENT;
            }
            ElementType eType = (ElementType) createItemType(dt.getElementTest());
            return new DocumentType(eType);
        }

        case TEXT_TEST:
            return TextType.INSTANCE;

        case COMMENT_TEST:
            return CommentType.INSTANCE;

        case PI_TEST: {
            PITestNode pit = (PITestNode) itemType;
            if (pit.getTarget() == null) {
                return ProcessingInstructionType.ANYPI;
            }
            return new ProcessingInstructionType(createUTF8String(pit.getTarget()));
        }

        case ATTRIBUTE_TEST: {
            AttributeTestNode at = (AttributeTestNode) itemType;
            if (at.getNameTest() == null) {
                return AttributeType.ANYATTRIBUTE;
            }
            NameTestNode ntNode = at.getNameTest();
            NameTest nt = NameTest.STAR_NAMETEST;
            if (ntNode.getPrefix() == null && ntNode.getLocalName() == null) {
                if (at.getTypeName() == null) {
                    return AttributeType.ANYATTRIBUTE;
                }
            } else {
                String uri;
                if (!"".equals(ntNode.getPrefix())) {
                    uri = currCtx.lookupNamespaceUri(ntNode.getPrefix());
                    if (uri == null) {
                        throw new SystemException(ErrorCode.XPST0081, ntNode.getSourceLocation());
                    }
                } else {
                    uri = "";
                }

                nt = new NameTest(createUTF8String(uri), createUTF8String(ntNode.getLocalName()));
            }
            SchemaType cType = BuiltinTypeRegistry.XS_ANY_ATOMIC;
            if (at.getTypeName() != null) {
                cType = moduleCtx.lookupSchemaType(createQName(at.getTypeName()));
                if (cType == null) {
                    throw new SystemException(ErrorCode.XPST0051, at.getSourceLocation());
                }
            }
            return new AttributeType(nt, cType);
        }

        case SCHEMA_ATTRIBUTE_TEST: {
            throw new UnsupportedOperationException("schema-attribute(...) is not supported");
        }

        case ELEMENT_TEST: {
            ElementTestNode et = (ElementTestNode) itemType;
            if (et.getNameTest() == null) {
                return ElementType.ANYELEMENT;
            }
            NameTestNode ntNode = et.getNameTest();
            NameTest nt = NameTest.STAR_NAMETEST;
            if (ntNode.getPrefix() == null && ntNode.getLocalName() == null) {
                if (et.getTypeName() == null) {
                    return ElementType.ANYELEMENT;
                }
            } else {
                String uri;
                if (!"".equals(ntNode.getPrefix())) {
                    uri = currCtx.lookupNamespaceUri(ntNode.getPrefix());
                    if (uri == null) {
                        throw new SystemException(ErrorCode.XPST0081, ntNode.getSourceLocation());
                    }
                } else {
                    uri = "";
                }
                nt = new NameTest(createUTF8String(uri), createUTF8String(ntNode.getLocalName()));
            }
            SchemaType cType = AnyType.INSTANCE;
            if (et.getTypeName() != null) {
                cType = moduleCtx.lookupSchemaType(createQName(et.getTypeName()));
                if (cType == null) {
                    throw new SystemException(ErrorCode.XPST0051, et.getSourceLocation());
                }
            }
            return new ElementType(nt, cType, et.isNillable());
        }

        case SCHEMA_ELEMENT_TEST: {
            throw new UnsupportedOperationException("schema-element(...) is not supported");
        }

        default:
            throw new IllegalStateException("Unknown node: " + itemType.getTag());
        }
    }

    private byte[] createUTF8String(String str) {
        ArrayBackedValueStorage abvs = new ArrayBackedValueStorage();
        StringValueBuilder svb = new StringValueBuilder();
        try {
            svb.write(str, abvs.getDataOutput());
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        return Arrays.copyOf(abvs.getByteArray(), abvs.getLength());
    }

    private ILogicalPlan translateMainModule(MainModuleNode moduleNode) throws SystemException {
        QueryBodyNode qbn = moduleNode.getQueryBody();
        ASTNode queryBody = qbn.getExpression();
        TranslationContext tCtx = new TranslationContext(null, new EmptyTupleSourceOperator());
        LogicalVariable lVar = translateExpression(queryBody, tCtx);
        LogicalVariable iLVar = newLogicalVariable();
        UnnestOperator unnest = new UnnestOperator(iLVar, mutable(ufce(BuiltinOperators.ITERATE, vre(lVar))));
        unnest.getInputs().add(mutable(tCtx.op));
        List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
        exprs.add(mutable(vre(iLVar)));
        QueryResultSetDataSink sink = new QueryResultSetDataSink(ccb.getResultSetId(), null);
        DistributeResultOperator op = new DistributeResultOperator(exprs, sink);
        op.getInputs().add(mutable(unnest));
        ALogicalPlanImpl lp = new ALogicalPlanImpl(mutable(op));

        return lp;
    }

    private LogicalVariable translateExpression(ASTNode value, TranslationContext tCtx) throws SystemException {
        switch (value.getTag()) {
        case EXPRESSION: {
            ExprNode node = (ExprNode) value;
            return translateExprNode(tCtx, node);
        }

        case UNARY_EXPRESSION: {
            UnaryExprNode ueNode = (UnaryExprNode) value;
            return translateUnaryExprNode(tCtx, ueNode);
        }

        case INFIX_EXPRESSION: {
            InfixExprNode ie = (InfixExprNode) value;
            return translateInfixExprNode(tCtx, ie);
        }

        case ENCLOSED_EXPRESSION: {
            EnclosedExprNode ee = (EnclosedExprNode) value;
            return translateEnclosedExprNode(tCtx, ee);
        }

        case PATH_EXPRESSION:
            return translatePathExpr((PathExprNode) value, tCtx);

        case FUNCTION_EXPRESSION: {
            FunctionExprNode fnNode = (FunctionExprNode) value;
            return translateFunctionExprNode(tCtx, fnNode);
        }

        case TYPE_EXPRESSION: {
            TypeExprNode teNode = (TypeExprNode) value;
            return translateTypeExprNode(tCtx, teNode);
        }

        case EXTENSION_EXPRESSION: {
            ExtensionExprNode eNode = (ExtensionExprNode) value;
            return translateExtensionExprNode(tCtx, eNode);
        }

        case PARENTHESIZED_EXPRESSION: {
            ParenthesizedExprNode peNode = (ParenthesizedExprNode) value;
            return translateParenthisizedExprNode(tCtx, peNode);
        }

        case LITERAL: {
            LiteralNode lNode = (LiteralNode) value;
            return translateLiteralNode(tCtx, lNode);
        }

        case DIRECT_PI_CONSTRUCTOR: {
            DirectPIConstructorNode dpicNode = (DirectPIConstructorNode) value;
            return translateDirectPIConstructorNode(tCtx, dpicNode);
        }

        case DIRECT_COMMENT_CONSTRUCTOR: {
            DirectCommentConstructorNode dccNode = (DirectCommentConstructorNode) value;
            return translateDirectCommentConstructorNode(tCtx, dccNode);
        }

        case DIRECT_ELEMENT_CONSTRUCTOR: {
            DirectElementConstructorNode decNode = (DirectElementConstructorNode) value;
            return translateDirectElementConstructorNode(tCtx, decNode);
        }

        case DIRECT_ATTRIBUTE_CONSTRUCTOR: {
            DirectAttributeConstructorNode dacNode = (DirectAttributeConstructorNode) value;
            return translateDirectAttributeConstructorNode(tCtx, dacNode);
        }

        case CONTEXT_ITEM:
            return tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable();

        case IF_EXPRESSION: {
            IfExprNode ieNode = (IfExprNode) value;
            return translateIfExprNode(tCtx, ieNode);
        }

        case VARIABLE_REFERENCE: {
            VarRefNode vrNode = (VarRefNode) value;
            return translateVarRefNode(tCtx, vrNode);
        }

        case FLWOR_EXPRESSION: {
            FLWORExprNode fNode = (FLWORExprNode) value;
            return translateFLWORExprNode(tCtx, fNode);
        }

        case QUANTIFIED_EXPRESSION: {
            QuantifiedExprNode qeNode = (QuantifiedExprNode) value;
            return translateQuantifiedExprNode(tCtx, qeNode);
        }

        /*
                    case TYPESWITCH_EXPRESSION: {
                        TypeswitchExprNode teNode = (TypeswitchExprNode) value;
                        Expression sExpr = translateExpression(teNode.getSwitchExpr());
                        ForLetVariable tVar = new ForLetVariable(VarTag.LET, createVarName(), sExpr);
                        tVar.setDeclaredStaticType(SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR));
                        pushVariableScope();
                        varScope.registerVariable(tVar);
                        List<TypeswitchExpression.Case> cases = new ArrayList<TypeswitchExpression.Case>();
                        for (CaseClauseNode ccNode : teNode.getCaseClauses()) {
                            SequenceType type = createSequenceType(ccNode.getType());
                            ForLetVariable caseVar = null;
                            pushVariableScope();
                            if (ccNode.getCaseVar() != null) {
                                caseVar = new ForLetVariable(VarTag.LET, createQName(ccNode.getCaseVar()), new TreatExpression(
                                        currCtx, new VariableReferenceExpression(currCtx, tVar), type));
                                caseVar.setDeclaredStaticType(type);
                                varScope.registerVariable(caseVar);
                            }
                            Expression cExpr = translateExpression(ccNode.getValueExpr());
                            TypeswitchExpression.Case c = new TypeswitchExpression.Case(caseVar, type, cExpr);
                            cases.add(c);
                            popVariableScope();
                        }
                        Expression dExpr = translateExpression(teNode.getDefaultClause());
                        popVariableScope();
                        return new TypeswitchExpression(currCtx, tVar, cases, dExpr);
                    }
                    */

        case COMPUTED_TEXT_CONSTRUCTOR: {
            ComputedTextConstructorNode cNode = (ComputedTextConstructorNode) value;
            return translateComputedTextConstructorNode(tCtx, cNode);
        }

        case COMPUTED_PI_CONSTRUCTOR: {
            ComputedPIConstructorNode cNode = (ComputedPIConstructorNode) value;
            return translateComputedPIConstructorNode(tCtx, cNode);
        }

        case COMPUTED_COMMENT_CONSTRUCTOR: {
            ComputedCommentConstructorNode cNode = (ComputedCommentConstructorNode) value;
            return translateComputedCommentConstructorNode(tCtx, cNode);
        }

        case COMPUTED_DOCUMENT_CONSTRUCTOR: {
            ComputedDocumentConstructorNode cNode = (ComputedDocumentConstructorNode) value;
            return translateComputedDocumentConstructorNode(tCtx, cNode);
        }

        case COMPUTED_ELEMENT_CONSTRUCTOR: {
            ComputedElementConstructorNode cNode = (ComputedElementConstructorNode) value;
            return translateComputedElementConstructorNode(tCtx, cNode);
        }

        case COMPUTED_ATTRIBUTE_CONSTRUCTOR: {
            ComputedAttributeConstructorNode cNode = (ComputedAttributeConstructorNode) value;
            return translateComputedAttributeConstructorNode(tCtx, cNode);
        }

        case QNAME: {
            QNameNode qnNode = (QNameNode) value;
            return translateQNameNode(tCtx, qnNode);
        }

        case NCNAME: {
            NCNameNode ncnNode = (NCNameNode) value;
            return translateNCNameNode(tCtx, ncnNode);
        }

        case CDATA_SECTION: {
            CDataSectionNode cdsNode = (CDataSectionNode) value;
            return translateCDataSectionNode(tCtx, cdsNode);
        }

        case ORDERED_EXPRESSION: {
            OrderedExprNode oeNode = (OrderedExprNode) value;
            return translateOrderedExprNode(tCtx, oeNode);
        }

        case UNORDERED_EXPRESSION: {
            UnorderedExprNode ueNode = (UnorderedExprNode) value;
            return translateUnorderedExprNode(tCtx, ueNode);
        }

        case VALIDATE_EXPRESSION: {
            ValidateExprNode vNode = (ValidateExprNode) value;
            return translateValidateExprNode(tCtx, vNode);
        }

        default:
            throw new IllegalStateException("Unknown node: " + value.getTag());

        }
    }

    private LogicalVariable translateQuantifiedExprNode(TranslationContext tCtx, QuantifiedExprNode qeNode)
            throws SystemException {
        tCtx = tCtx.pushContext();
        int pushCount = 0;
        for (QuantifiedVarDeclNode qvdNode : qeNode.getVariables()) {
            ILogicalExpression seq = vre(translateExpression(qvdNode.getSequence(), tCtx));
            tCtx.pushVariableScope();
            LogicalVariable forLVar = newLogicalVariable();
            UnnestOperator unnest = new UnnestOperator(forLVar, mutable(ufce(BuiltinOperators.ITERATE, seq)));
            SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
            if (qvdNode.getType() != null) {
                forVarType = createSequenceType(qvdNode.getType());
            }
            XQueryVariable forVar = new XQueryVariable(createQName(qvdNode.getVariable()), forVarType, forLVar);
            tCtx.varScope.registerVariable(forVar);
            unnest.getInputs().add(mutable(tCtx.op));
            tCtx.op = unnest;
            ++pushCount;
        }
        ILogicalExpression satExpr = sfce(BuiltinFunctions.FN_BOOLEAN_1,
                vre(translateExpression(qeNode.getSatisfiesExpr(), tCtx)));
        if (qeNode.getQuant() == QuantifierType.EVERY) {
            satExpr = sfce(BuiltinFunctions.FN_NOT_1, satExpr);
        }
        SelectOperator select = new SelectOperator(mutable(satExpr), false, null);
        select.getInputs().add(mutable(tCtx.op));
        tCtx.op = select;
        List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
        List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
        LogicalVariable var = newLogicalVariable();
        vars.add(var);
        exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_BOOLEAN, Quantifier.QUANT_ONE), Boolean.TRUE))));
        AggregateOperator aop = new AggregateOperator(vars, exprs);
        aop.getInputs().add(mutable(tCtx.op));
        tCtx.op = aop;
        for (int i = 0; i < pushCount; ++i) {
            tCtx.popVariableScope();
        }
        tCtx = tCtx.popContext();
        LogicalVariable lVar = createAssignment(
                sfce(qeNode.getQuant() == QuantifierType.EVERY ? BuiltinFunctions.FN_EMPTY_1
                        : BuiltinFunctions.FN_EXISTS_1, vre(var)),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateUnorderedExprNode(TranslationContext tCtx, UnorderedExprNode ueNode)
            throws SystemException {
        LogicalVariable lVar = createAssignment(
                sfce(BuiltinOperators.UNORDERED, vre(translateExpression(ueNode.getExpr(), tCtx))), tCtx);
        return lVar;
    }

    private LogicalVariable translateOrderedExprNode(TranslationContext tCtx, OrderedExprNode oeNode)
            throws SystemException {
        LogicalVariable lVar = createAssignment(
                sfce(BuiltinOperators.ORDERED, vre(translateExpression(oeNode.getExpr(), tCtx))), tCtx);
        return lVar;
    }

    private LogicalVariable translateCDataSectionNode(TranslationContext tCtx, CDataSectionNode cdsNode)
            throws SystemException {
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.TEXT_CONSTRUCTOR,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
                        cdsNode.getContent())),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateNCNameNode(TranslationContext tCtx, NCNameNode ncnNode)
            throws SystemException {
        LogicalVariable lVar = createAssignment(
                ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), ncnNode.getName()),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateQNameNode(TranslationContext tCtx, QNameNode qnNode) throws SystemException {
        LogicalVariable lVar = createAssignment(
                ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE), createQName(qnNode)),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateValidateExprNode(TranslationContext tCtx, ValidateExprNode vNode)
            throws SystemException {
        XQueryConstants.ValidationMode mode = vNode.getMode();
        Function fn = mode == null || XQueryConstants.ValidationMode.STRICT.equals(mode)
                ? BuiltinOperators.VALIDATE_STRICT
                : BuiltinOperators.VALIDATE_LAX;
        LogicalVariable lVar = createAssignment(sfce(fn, vre(translateExpression(vNode.getExpr(), tCtx))), tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedAttributeConstructorNode(TranslationContext tCtx,
            ComputedAttributeConstructorNode cNode) throws SystemException {
        ILogicalExpression name = cast(vre(translateExpression(cNode.getName(), tCtx)),
                SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE));
        ASTNode content = cNode.getContent();
        ILogicalExpression cExpr = content == null ? sfce(BuiltinOperators.CONCATENATE)
                : vre(translateExpression(content, tCtx));
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ATTRIBUTE_CONSTRUCTOR, name, cExpr), tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedElementConstructorNode(TranslationContext tCtx,
            ComputedElementConstructorNode cNode) throws SystemException {
        ILogicalExpression name = cast(vre(translateExpression(cNode.getName(), tCtx)),
                SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE));
        ASTNode content = cNode.getContent();
        ILogicalExpression cExpr = content == null ? sfce(BuiltinOperators.CONCATENATE)
                : vre(translateExpression(content, tCtx));
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ELEMENT_CONSTRUCTOR, name, cExpr), tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedDocumentConstructorNode(TranslationContext tCtx,
            ComputedDocumentConstructorNode cNode) throws SystemException {
        LogicalVariable lVar = createAssignment(
                sfce(BuiltinOperators.DOCUMENT_CONSTRUCTOR, vre(translateExpression(cNode.getContent(), tCtx))),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedCommentConstructorNode(TranslationContext tCtx,
            ComputedCommentConstructorNode cNode) throws SystemException {
        ASTNode content = cNode.getContent();
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.COMMENT_CONSTRUCTOR,
                content == null ? sfce(BuiltinOperators.CONCATENATE) : vre(translateExpression(content, tCtx))),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedPIConstructorNode(TranslationContext tCtx,
            ComputedPIConstructorNode cNode) throws SystemException {
        ASTNode content = cNode.getContent();
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.PI_CONSTRUCTOR,
                vre(translateExpression(cNode.getTarget(), tCtx)),
                content == null ? sfce(BuiltinOperators.CONCATENATE) : vre(translateExpression(content, tCtx))),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateComputedTextConstructorNode(TranslationContext tCtx,
            ComputedTextConstructorNode cNode) throws SystemException {
        ASTNode content = cNode.getContent();
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.TEXT_CONSTRUCTOR,
                content == null
                        ? ce(SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE), "")
                        : vre(translateExpression(content, tCtx))),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateFLWORExprNode(TranslationContext tCtx, FLWORExprNode fNode)
            throws SystemException {
        tCtx = tCtx.pushContext();
        List<FLWORClauseNode> cNodes = fNode.getClauses();
        int pushCount = 0;
        for (FLWORClauseNode cNode : cNodes) {
            switch (cNode.getTag()) {
            case FOR_CLAUSE: {
                ForClauseNode fcNode = (ForClauseNode) cNode;
                for (ForVarDeclNode fvdNode : fcNode.getVariables()) {
                    ILogicalExpression seq = vre(translateExpression(fvdNode.getSequence(), tCtx));
                    tCtx.pushVariableScope();
                    LogicalVariable forLVar = newLogicalVariable();
                    LogicalVariable posLVar = fvdNode.getPosVar() != null ? newLogicalVariable() : null;
                    UnnestOperator unnest = new UnnestOperator(forLVar,
                            mutable(ufce(BuiltinOperators.ITERATE, seq)), posLVar, BuiltinTypeRegistry.XS_INTEGER,
                            new VXQueryPositionWriter());
                    SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
                    if (fvdNode.getType() != null) {
                        forVarType = createSequenceType(fvdNode.getType());
                    }
                    XQueryVariable forVar = new XQueryVariable(createQName(fvdNode.getForVar()), forVarType,
                            forLVar);
                    tCtx.varScope.registerVariable(forVar);
                    XQueryVariable posVar = null;
                    if (fvdNode.getPosVar() != null) {
                        posVar = new XQueryVariable(createQName(fvdNode.getPosVar()),
                                SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE), posLVar);
                        tCtx.varScope.registerVariable(posVar);
                    }
                    assert fvdNode.getScoreVar() == null;
                    unnest.getInputs().add(mutable(tCtx.op));
                    tCtx.op = unnest;
                    ++pushCount;
                }
                break;
            }
            case LET_CLAUSE: {
                LetClauseNode lcNode = (LetClauseNode) cNode;
                for (LetVarDeclNode lvdNode : lcNode.getVariables()) {
                    LogicalVariable seqVar = translateExpression(lvdNode.getSequence(), tCtx);
                    tCtx.pushVariableScope();
                    SequenceType letVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
                    if (lvdNode.getType() != null) {
                        letVarType = createSequenceType(lvdNode.getType());
                    }
                    XQueryVariable letVar = new XQueryVariable(createQName(lvdNode.getLetVar()), letVarType,
                            seqVar);
                    tCtx.varScope.registerVariable(letVar);
                    ++pushCount;
                }
                break;
            }
            case WHERE_CLAUSE: {
                WhereClauseNode wcNode = (WhereClauseNode) cNode;
                ILogicalExpression condExpr = sfce(BuiltinFunctions.FN_BOOLEAN_1,
                        vre(translateExpression(wcNode.getCondition(), tCtx)));
                SelectOperator select = new SelectOperator(mutable(condExpr), false, null);
                select.getInputs().add(mutable(tCtx.op));
                tCtx.op = select;
                break;
            }
            case ORDERBY_CLAUSE: {
                OrderbyClauseNode ocNode = (OrderbyClauseNode) cNode;
                List<edu.uci.ics.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>> oExprs = new ArrayList<edu.uci.ics.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>>();
                List<String> collations = new ArrayList<String>();
                for (OrderSpecNode osNode : ocNode.getOrderSpec()) {
                    ILogicalExpression oExpr = vre(translateExpression(osNode.getExpression(), tCtx));
                    OrderOperator.IOrder o = OrderOperator.ASC_ORDER;
                    XQueryConstants.OrderDirection oDir = osNode.getDirection();
                    if (oDir != null) {
                        switch (oDir) {
                        case ASCENDING:
                            o = OrderOperator.ASC_ORDER;
                            break;
                        case DESCENDING:
                            o = OrderOperator.DESC_ORDER;
                            break;
                        }
                    }
                    /*
                    StaticContext.EmptyOrderProperty eoProp = osNode.getEmptyOrder();
                    if (eoProp != null) {
                        switch (osNode.getEmptyOrder()) {
                            case GREATEST:
                                eOrders.add(FLWORExpression.EmptyOrder.GREATEST);
                                break;
                            case LEAST:
                                eOrders.add(FLWORExpression.EmptyOrder.LEAST);
                                break;
                        }
                    } else {
                        eOrders.add(FLWORExpression.EmptyOrder.DEFAULT);
                    }
                    collations.add(osNode.getCollation());
                    */
                    oExprs.add(
                            new edu.uci.ics.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>(
                                    o, mutable(oExpr)));
                }
                OrderOperator order = new OrderOperator(oExprs);
                order.getInputs().add(mutable(tCtx.op));
                tCtx.op = order;
                break;
            }
            default:
                throw new IllegalStateException("Unknown clause: " + cNode.getTag());
            }
        }
        ILogicalExpression rExpr = vre(translateExpression(fNode.getReturnExpr(), tCtx));
        List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
        List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
        LogicalVariable var = newLogicalVariable();
        vars.add(var);
        exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false, rExpr)));
        AggregateOperator aop = new AggregateOperator(vars, exprs);
        aop.getInputs().add(mutable(tCtx.op));
        tCtx.op = aop;
        for (int i = 0; i < pushCount; ++i) {
            tCtx.popVariableScope();
        }
        tCtx = tCtx.popContext();
        return var;
    }

    private LogicalVariable translateVarRefNode(TranslationContext tCtx, VarRefNode vrNode) throws SystemException {
        QName vName = createQName(vrNode.getVariable());
        XQueryVariable var = tCtx.varScope.lookupVariable(vName);
        if (var == null) {
            throw new SystemException(ErrorCode.XPST0008, vrNode.getSourceLocation());
        }
        LogicalVariable lVar = createAssignment(treat(vre(var.getLogicalVariable()), var.getType()), tCtx);
        return lVar;
    }

    private LogicalVariable translateIfExprNode(TranslationContext tCtx, IfExprNode ieNode) throws SystemException {
        ILogicalExpression cond = sfce(BuiltinFunctions.FN_BOOLEAN_1,
                vre(translateExpression(ieNode.getIfExpr(), tCtx)));
        ILogicalExpression tExpr = vre(translateExpression(ieNode.getThenExpr(), tCtx));
        ILogicalExpression eExpr = vre(translateExpression(ieNode.getElseExpr(), tCtx));
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.IF_THEN_ELSE, cond, tExpr, eExpr), tCtx);
        return lVar;
    }

    private LogicalVariable translateDirectAttributeConstructorNode(TranslationContext tCtx,
            DirectAttributeConstructorNode dacNode) throws SystemException {
        QName aQName = createQName(dacNode.getName());
        ILogicalExpression name = ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE),
                aQName);
        List<ILogicalExpression> content = new ArrayList<ILogicalExpression>();
        for (ASTNode aVal : dacNode.getValue()) {
            switch (aVal.getTag()) {
            case CONTENT_CHARS: {
                String contentChars = ((ContentCharsNode) aVal).getContent();
                ILogicalExpression cce = ce(
                        SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
                        contentChars);
                content.add(cce);
                break;
            }

            default:
                content.add(vre(translateExpression(aVal, tCtx)));
            }
        }
        ILogicalExpression contentExpr = content.size() == 1 ? content.get(0)
                : sfce(BuiltinOperators.CONCATENATE, content.toArray(new ILogicalExpression[content.size()]));
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ATTRIBUTE_CONSTRUCTOR, name, contentExpr),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateDirectElementConstructorNode(TranslationContext tCtx,
            DirectElementConstructorNode decNode) throws SystemException {
        QNameNode startName = decNode.getStartTagName();
        QNameNode endName = decNode.getEndTagName();
        if (endName != null && (!startName.getPrefix().equals(endName.getPrefix())
                || !startName.getLocalName().equals(endName.getLocalName()))) {
            throw new SystemException(ErrorCode.XPST0003, endName.getSourceLocation());
        }
        pushContext();
        for (DirectAttributeConstructorNode acNode : decNode.getAttributes()) {
            QNameNode aName = acNode.getName();
            if ("xmlns".equals(aName.getPrefix())) {
                List<ASTNode> values = acNode.getValue();
                if (values.size() != 1 || !ASTTag.CONTENT_CHARS.equals(values.get(0).getTag())) {
                    throw new SystemException(ErrorCode.XQST0022, acNode.getSourceLocation());
                }

                currCtx.registerNamespaceUri(aName.getLocalName(),
                        unquote(((ContentCharsNode) values.get(0)).getContent()));
            }
        }
        List<ILogicalExpression> content = new ArrayList<ILogicalExpression>();
        for (DirectAttributeConstructorNode acNode : decNode.getAttributes()) {
            QNameNode aName = acNode.getName();
            if (!"xmlns".equals(aName.getPrefix())) {
                content.add(vre(translateExpression(acNode, tCtx)));
            }
        }
        ILogicalExpression name = ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE),
                createQName(startName, moduleCtx.getDefaultElementNamespaceUri()));
        for (ASTNode cVal : decNode.getContent()) {
            switch (cVal.getTag()) {
            case CONTENT_CHARS: {
                String contentChars = ((ContentCharsNode) cVal).getContent();
                ILogicalExpression cce = ce(
                        SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
                        contentChars);
                content.add(sfce(BuiltinOperators.TEXT_CONSTRUCTOR, cce));
                break;
            }

            default:
                content.add(vre(translateExpression(cVal, tCtx)));
            }
        }
        popContext();
        ILogicalExpression contentExpr = content.size() == 1 ? content.get(0)
                : sfce(BuiltinOperators.CONCATENATE, content.toArray(new ILogicalExpression[content.size()]));
        LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ELEMENT_CONSTRUCTOR, name, contentExpr),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateDirectCommentConstructorNode(TranslationContext tCtx,
            DirectCommentConstructorNode dccNode) throws SystemException {
        String content = dccNode.getContent();
        LogicalVariable lVar = createAssignment(
                sfce(BuiltinOperators.COMMENT_CONSTRUCTOR,
                        ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), content)),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateDirectPIConstructorNode(TranslationContext tCtx,
            DirectPIConstructorNode dpicNode) throws SystemException {
        String target = dpicNode.getTarget();
        String content = dpicNode.getContent();
        LogicalVariable lVar = createAssignment(
                sfce(BuiltinOperators.PI_CONSTRUCTOR,
                        ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), target),
                        ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), content)),
                tCtx);
        return lVar;
    }

    private LogicalVariable translateLiteralNode(TranslationContext tCtx, LiteralNode lNode)
            throws SystemException {
        String image = lNode.getImage();
        LiteralNode.LiteralType lType = lNode.getType();
        SequenceType t = null;
        Object value = null;
        switch (lType) {
        case DECIMAL:
            t = SequenceType.create(BuiltinTypeRegistry.XS_DECIMAL, Quantifier.QUANT_ONE);
            value = Double.parseDouble(image);
            break;
        case DOUBLE:
            t = SequenceType.create(BuiltinTypeRegistry.XS_DOUBLE, Quantifier.QUANT_ONE);
            value = Double.parseDouble(image);
            break;
        case INTEGER:
            t = SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE);
            try {
                value = Long.parseLong(image);
            } catch (NumberFormatException nfe) {
                throw new SystemException(ErrorCode.FOAR0002);
            }
            break;
        case STRING:
            t = SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE);
            value = unquote(image);
            break;
        default:
            throw new IllegalStateException("Unknown type: " + lType);
        }
        LogicalVariable lVar = createAssignment(ce(t, value), tCtx);
        return lVar;
    }

    private LogicalVariable translateParenthisizedExprNode(TranslationContext tCtx, ParenthesizedExprNode peNode)
            throws SystemException {
        ASTNode eNode = peNode.getExpr();
        if (eNode == null) {
            return createConcatenation(Collections.<LogicalVariable>emptyList(), tCtx);
        }
        return translateExpression(peNode.getExpr(), tCtx);
    }

    private LogicalVariable translateExtensionExprNode(TranslationContext tCtx, ExtensionExprNode eNode)
            throws SystemException {
        if (eNode.getExpr() == null) {
            throw new SystemException(ErrorCode.XQST0079, eNode.getSourceLocation());
        }
        return translateExpression(eNode.getExpr(), tCtx);
    }

    private LogicalVariable translateTypeExprNode(TranslationContext tCtx, TypeExprNode teNode)
            throws SystemException {
        LogicalVariable var = translateExpression(teNode.getExpr(), tCtx);
        SequenceType type = createSequenceType(teNode.getType());
        ILogicalExpression expr = null;
        switch (teNode.getOperator()) {
        case CAST:
            expr = cast(vre(var), type);
            break;

        case CASTABLE:
            expr = castable(vre(var), type);
            break;

        case INSTANCEOF:
            expr = instanceOf(vre(var), type);
            break;

        case TREAT:
            expr = treat(vre(var), type);
            break;

        default:
            throw new IllegalStateException("Unknown type operator: " + teNode.getOperator());
        }
        LogicalVariable lVar = createAssignment(expr, tCtx);
        return lVar;
    }

    private LogicalVariable translateFunctionExprNode(TranslationContext tCtx, FunctionExprNode fnNode)
            throws SystemException {
        List<LogicalVariable> args = new ArrayList<LogicalVariable>();
        for (ASTNode an : fnNode.getArguments()) {
            args.add(translateExpression(an, tCtx));
        }
        QName name = createQName(fnNode.getName());
        SchemaType type = moduleCtx.lookupSchemaType(name);
        if (type != null && args.size() < 2) {
            if (!type.isAtomicType()) {
                throw new SystemException(ErrorCode.XPST0051, fnNode.getName().getSourceLocation());
            }
            LogicalVariable var = args.isEmpty()
                    ? tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable()
                    : args.get(0);
            ILogicalExpression expr = cast(vre(var),
                    SequenceType.create((ItemType) type, Quantifier.QUANT_QUESTION));
            return createAssignment(expr, tCtx);
        }
        QName fName = createQName(fnNode.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
        if (BuiltinFunctions.FN_POSITION_QNAME.equals(fName)) {
            XQueryVariable var = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.POS_VAR_NAME);
            return var.getLogicalVariable();
        }
        if (BuiltinFunctions.FN_LAST_QNAME.equals(fName)) {
            XQueryVariable var = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.LAST_VAR_NAME);
            return var.getLogicalVariable();
        }
        int nArgs = fnNode.getArguments().size();
        Function fn = moduleCtx.lookupFunction(fName, nArgs);
        if (fn != null && fn.useContextImplicitly()) {
            args.add(tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable());
            fn = moduleCtx.lookupFunction(fName, nArgs + 1);
        }
        if (fn == null) {
            Function[] fns = moduleCtx.lookupFunctions(fName);
            if (fns != null) {
                for (int i = 0; i < fns.length && i <= nArgs; ++i) {
                    if (fns[i] != null && fns[i].getSignature().isVarArgs()) {
                        fn = fns[i];
                        break;
                    }
                }
            }
        }
        if (fn == null) {
            throw new SystemException(ErrorCode.XPST0017, fnNode.getName().getSourceLocation());
        }
        Signature sign = fn.getSignature();
        List<Mutable<ILogicalExpression>> argExprs = new ArrayList<Mutable<ILogicalExpression>>();
        for (int i = 0; i < args.size(); ++i) {
            SequenceType argType = sign.getParameterType(i);
            argExprs.add(mutable(normalize(vre(args.get(i)), argType)));
        }
        LogicalVariable lVar = createAssignment(new ScalarFunctionCallExpression(fn, argExprs), tCtx);
        return lVar;
    }

    private LogicalVariable translateEnclosedExprNode(TranslationContext tCtx, EnclosedExprNode ee)
            throws SystemException {
        return translateExpression(ee.getExpression(), tCtx);
    }

    private LogicalVariable translateInfixExprNode(TranslationContext tCtx, InfixExprNode ie)
            throws SystemException {
        Function operator = getOperator(ie.getOperator());
        Signature sign = operator.getSignature();
        LogicalVariable varLeft = translateExpression(ie.getLeftExpr(), tCtx);
        LogicalVariable varRight = translateExpression(ie.getRightExpr(), tCtx);
        ILogicalExpression arg1 = normalize(vre(varLeft), sign.getParameterType(0));
        ILogicalExpression arg2 = normalize(vre(varRight), sign.getParameterType(1));
        if (BuiltinOperators.EXCEPT.equals(operator) || BuiltinOperators.INTERSECT.equals(operator)) {
            arg1 = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, arg1);
            arg2 = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, arg2);
        }
        ILogicalExpression result = sfce(operator, arg1, arg2);
        if (BuiltinOperators.UNION.equals(operator)) {
            result = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, result);
        }
        LogicalVariable lVar = createAssignment(result, tCtx);
        return lVar;
    }

    private LogicalVariable translateUnaryExprNode(TranslationContext tCtx, UnaryExprNode ueNode)
            throws SystemException {
        boolean neg = false;
        for (UnaryExprNode.Sign s : ueNode.getSigns()) {
            if (UnaryExprNode.Sign.MINUS.equals(s)) {
                neg = !neg;
            }
        }
        LogicalVariable var = translateExpression(ueNode.getExpr(), tCtx);
        if (neg) {
            ILogicalExpression nExpr = normalize(vre(var),
                    BuiltinOperators.NUMERIC_UNARY_MINUS.getSignature().getParameterType(0));
            ILogicalExpression negExpr = sfce(BuiltinOperators.NUMERIC_UNARY_MINUS, nExpr);
            var = createAssignment(negExpr, tCtx);
        }
        return var;
    }

    private LogicalVariable translateExprNode(TranslationContext tCtx, ExprNode node) throws SystemException {
        return createConcatenation(translateExpressionList(node.getExpressions(), tCtx), tCtx);
    }

    private LogicalVariable translatePathExpr(PathExprNode pe, TranslationContext tCtx) throws SystemException {
        ILogicalExpression ctxExpr = null;
        PathType type = pe.getPathType();
        if (type != null) {
            XQueryVariable dotVar = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME);
            ILogicalExpression root = sfce(BuiltinFunctions.FN_ROOT_1, vre(dotVar.getLogicalVariable()));
            if (PathType.SLASH.equals(type)) {
                ctxExpr = root;
            } else {
                ctxExpr = sfce(BuiltinOperators.DESCENDANT_OR_SELF,
                        treat(root, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)));
            }
        }

        if (pe.getPaths() != null) {
            for (RelativePathExprNode rpen : pe.getPaths()) {
                boolean asc = true;
                if (PathType.SLASH_SLASH.equals(rpen.getPathType())) {
                    ctxExpr = sfce(BuiltinOperators.DESCENDANT_OR_SELF,
                            treat(ctxExpr, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)));
                }
                boolean popScope = false;
                if (ctxExpr != null) {
                    popScope = true;
                    tCtx = tCtx.pushContext();
                    tCtx.pushVariableScope();
                    iterateOver(ctxExpr, tCtx);
                    ctxExpr = null;
                }

                List<ASTNode> predicates = null;

                ASTNode pathNode = rpen.getPath();
                if (ASTTag.AXIS_STEP.equals(pathNode.getTag())) {
                    AxisStepNode axisNode = (AxisStepNode) pathNode;
                    predicates = axisNode.getPredicates();
                    AxisStepNode.Axis axis = axisNode.getAxis();
                    if (ctxExpr == null) {
                        ctxExpr = vre(tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME)
                                .getLogicalVariable());
                    }
                    Function axisFn = translateAxis(axis);
                    NodeType nt = translateNodeTest(axis, axisNode.getNodeTest());
                    int ntCode = currCtx.encodeSequenceType(SequenceType.create(nt, Quantifier.QUANT_ONE));
                    ctxExpr = sfce(axisFn,
                            treat(ctxExpr, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)),
                            ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), ntCode));
                    asc = isForwardAxis(axis);
                } else if (ASTTag.FILTER_EXPRESSION.equals(pathNode.getTag())) {
                    FilterExprNode filterNode = (FilterExprNode) pathNode;
                    predicates = filterNode.getPredicates();
                    ctxExpr = vre(translateExpression(filterNode.getExpr(), tCtx));
                } else {
                    throw new IllegalStateException("Unknown path node: " + pathNode.getTag());
                }
                if (predicates != null && !predicates.isEmpty()) {
                    ctxExpr = sfce(asc ? BuiltinOperators.SORT_DISTINCT_NODES_ASC_OR_ATOMICS
                            : BuiltinOperators.SORT_DISTINCT_NODES_DESC_OR_ATOMICS, ctxExpr);
                    for (ASTNode pn : predicates) {
                        tCtx = tCtx.pushContext();
                        tCtx.pushVariableScope();
                        iterateOver(ctxExpr, tCtx);
                        LogicalVariable pLVar = translateExpression(pn, tCtx);
                        ILogicalExpression tTest = instanceOf(vre(pLVar),
                                SequenceType.create(BuiltinTypeRegistry.XSEXT_NUMERIC, Quantifier.QUANT_ONE));
                        ILogicalExpression posTest = sfce(BuiltinOperators.VALUE_EQ, vre(pLVar), vre(tCtx.varScope
                                .lookupVariable(XMLQueryCompilerConstants.POS_VAR_NAME).getLogicalVariable()));
                        ILogicalExpression boolTest = sfce(BuiltinFunctions.FN_BOOLEAN_1, vre(pLVar));

                        SelectOperator select = new SelectOperator(
                                mutable(sfce(BuiltinOperators.IF_THEN_ELSE, tTest, posTest, boolTest)), false,
                                null);
                        select.getInputs().add(mutable(tCtx.op));
                        tCtx.op = select;
                        ctxExpr = vre(tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME)
                                .getLogicalVariable());
                        tCtx.popVariableScope();
                        tCtx = tCtx.popContext();
                    }
                }
                if (popScope) {
                    tCtx.popVariableScope();
                    List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
                    List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
                    LogicalVariable var = newLogicalVariable();
                    vars.add(var);
                    exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false, ctxExpr)));
                    AggregateOperator aop = new AggregateOperator(vars, exprs);
                    aop.getInputs().add(mutable(tCtx.op));
                    tCtx.op = aop;
                    tCtx = tCtx.popContext();
                    ctxExpr = vre(var);
                    ctxExpr = sfce(asc ? BuiltinOperators.SORT_DISTINCT_NODES_ASC_OR_ATOMICS
                            : BuiltinOperators.SORT_DISTINCT_NODES_DESC_OR_ATOMICS, vre(var));
                }
            }
        }
        LogicalVariable lVar = createAssignment(ctxExpr, tCtx);
        return lVar;
    }

    private void iterateOver(ILogicalExpression ctxExpr, TranslationContext tCtx) {
        LogicalVariable seqLVar = createAssignment(ctxExpr, tCtx);
        LogicalVariable lastLVar = createAssignment(sfce(BuiltinFunctions.FN_COUNT_1, vre(seqLVar)), tCtx);
        tCtx.varScope.registerVariable(new XQueryVariable(XMLQueryCompilerConstants.LAST_VAR_NAME,
                SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE), lastLVar));
        LogicalVariable forLVar = newLogicalVariable();
        LogicalVariable posLVar = newLogicalVariable();
        UnnestOperator unnest = new UnnestOperator(forLVar, mutable(ufce(BuiltinOperators.ITERATE, vre(seqLVar))),
                posLVar, BuiltinTypeRegistry.XS_INTEGER, new VXQueryPositionWriter());
        SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
        XQueryVariable forVar = new XQueryVariable(XMLQueryCompilerConstants.DOT_VAR_NAME, forVarType, forLVar);
        tCtx.varScope.registerVariable(forVar);
        SequenceType posVarType = SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE);
        XQueryVariable posVar = new XQueryVariable(XMLQueryCompilerConstants.POS_VAR_NAME, posVarType, posLVar);
        tCtx.varScope.registerVariable(posVar);
        unnest.getInputs().add(mutable(tCtx.op));
        tCtx.op = unnest;
    }

    private boolean isForwardAxis(AxisStepNode.Axis axis) {
        switch (axis) {
        case ABBREV:
        case CHILD:
        case ABBREV_ATTRIBUTE:
        case ATTRIBUTE:
        case DESCENDANT:
        case DESCENDANT_OR_SELF:
        case FOLLOWING:
        case FOLLOWING_SIBLING:
        case SELF:
            return true;

        case ANCESTOR:
        case ANCESTOR_OR_SELF:
        case DOT_DOT:
        case PARENT:
        case PRECEDING:
        case PRECEDING_SIBLING:
            return false;

        default:
            throw new IllegalStateException("Unknown axis: " + axis);
        }
    }

    private NodeType translateNodeTest(AxisStepNode.Axis axis, ASTNode nodeTest) throws SystemException {
        NodeType nt = AnyNodeType.INSTANCE;
        if (nodeTest != null) {
            switch (nodeTest.getTag()) {
            case NAME_TEST: {
                NameTestNode ntn = (NameTestNode) nodeTest;
                String uri = null;
                if (ntn.getPrefix() != null) {
                    if (!"".equals(ntn.getPrefix())) {
                        uri = currCtx.lookupNamespaceUri(ntn.getPrefix());
                        if (uri == null) {
                            throw new SystemException(ErrorCode.XPST0081, ntn.getSourceLocation());
                        }
                    } else {
                        uri = "";
                    }
                }
                String localName = ntn.getLocalName();
                NameTest nameTest = new NameTest(uri == null ? null : createUTF8String(uri),
                        localName == null ? null : createUTF8String(ntn.getLocalName()));
                if (axis == AxisStepNode.Axis.ATTRIBUTE || axis == AxisStepNode.Axis.ABBREV_ATTRIBUTE) {
                    nt = new AttributeType(nameTest, BuiltinTypeRegistry.XS_ANY_ATOMIC);
                } else {
                    nt = new ElementType(nameTest, AnyType.INSTANCE, true);
                }
                break;
            }

            case ANY_NODE_TEST:
            case DOCUMENT_TEST:
            case TEXT_TEST:
            case COMMENT_TEST:
            case PI_TEST:
            case ATTRIBUTE_TEST:
            case SCHEMA_ATTRIBUTE_TEST:
            case ELEMENT_TEST:
            case SCHEMA_ELEMENT_TEST:
                nt = (NodeType) createItemType(nodeTest);
                break;

            default:
                throw new IllegalStateException("Unknown node: " + nodeTest.getTag());
            }
        }
        return nt;
    }

    private Function translateAxis(AxisStepNode.Axis axis) {
        switch (axis) {
        case ABBREV:
        case CHILD:
            return BuiltinOperators.CHILD;

        case ABBREV_ATTRIBUTE:
        case ATTRIBUTE:
            return BuiltinOperators.ATTRIBUTE;

        case ANCESTOR:
            return BuiltinOperators.ANCESTOR;

        case ANCESTOR_OR_SELF:
            return BuiltinOperators.ANCESTOR_OR_SELF;

        case DESCENDANT:
            return BuiltinOperators.DESCENDANT;

        case DESCENDANT_OR_SELF:
            return BuiltinOperators.DESCENDANT_OR_SELF;

        case DOT_DOT:
        case PARENT:
            return BuiltinOperators.PARENT;

        case FOLLOWING:
            return BuiltinOperators.FOLLOWING;

        case FOLLOWING_SIBLING:
            return BuiltinOperators.FOLLOWING_SIBLING;

        case PRECEDING:
            return BuiltinOperators.PRECEDING;

        case PRECEDING_SIBLING:
            return BuiltinOperators.PRECEDING_SIBLING;

        case SELF:
            return BuiltinOperators.SELF;

        default:
            throw new IllegalStateException("Unknown axis: " + axis);
        }
    }

    private static String unquote(String image) throws SystemException {
        StringBuilder buffer = new StringBuilder();
        char quoteChar = image.charAt(0);
        image = image.substring(1, image.length() - 1);
        Matcher m = UNQUOTER.matcher(image);
        int i = 0;
        while (m.find()) {
            int start = m.start();
            int end = m.end();
            if (i < start) {
                buffer.append(image, i, start);
            }
            if (m.start(1) >= 0) {
                buffer.append('<');
            } else if (m.start(2) >= 0) {
                buffer.append('>');
            } else if (m.start(3) >= 0) {
                buffer.append('\'');
            } else if (m.start(4) >= 0) {
                buffer.append('&');
            } else if (m.start(5) >= 0) {
                buffer.append('"');
            } else if (m.start(6) >= 0) {
                buffer.append(quoteChar == '"' ? '"' : "\"\"");
            } else if (m.start(7) >= 0) {
                buffer.append(quoteChar == '\'' ? '\'' : "''");
            } else if (m.start(8) >= 0) {
                try {
                    buffer.appendCodePoint(Integer.parseInt(image.substring(start + 2, end - 1)));
                } catch (NumberFormatException e) {
                    throw new SystemException(ErrorCode.XQST0090);
                }
            } else if (m.start(9) >= 0) {
                try {
                    buffer.appendCodePoint(Integer.parseInt(image.substring(start + 3, end - 1), 16));
                } catch (NumberFormatException e) {
                    throw new SystemException(ErrorCode.XQST0090);
                }
            }
            i = m.end();
        }
        if (i < image.length()) {
            buffer.append(image, i, image.length());
        }
        return buffer.toString();
    }

    private QName createQName(QNameNode qnNode) throws SystemException {
        return createQName(qnNode, "");
    }

    private QName createQName(QNameNode qnNode, String defaultUri) throws SystemException {
        String prefix = qnNode.getPrefix();
        String local = qnNode.getLocalName();

        String uri;
        if (!"".equals(prefix)) {
            uri = currCtx.lookupNamespaceUri(prefix);
            if (uri == null) {
                throw new SystemException(ErrorCode.XPST0081, qnNode.getSourceLocation());
            }
        } else {
            uri = defaultUri;
        }
        return new QName(uri, local, prefix);
    }

    private static ILogicalExpression afce(Function fn, boolean isTwoStep, ILogicalExpression... argExprs) {
        List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
        for (ILogicalExpression e : argExprs) {
            args.add(mutable(e));
        }
        return new AggregateFunctionCallExpression(fn, isTwoStep, args);
    }

    private static ILogicalExpression ufce(Function fn, ILogicalExpression... argExprs) {
        List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
        for (ILogicalExpression e : argExprs) {
            args.add(mutable(e));
        }
        return new UnnestingFunctionCallExpression(fn, args);
    }

    private static ILogicalExpression sfce(Function fn, ILogicalExpression... argExprs) {
        List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
        for (ILogicalExpression e : argExprs) {
            args.add(mutable(e));
        }
        return new ScalarFunctionCallExpression(fn, args);
    }

    private Function getOperator(InfixOperator operator) {
        switch (operator) {
        case AND:
            return BuiltinOperators.AND;

        case DIV:
            return BuiltinOperators.DIVIDE;

        case EXCEPT:
            return BuiltinOperators.EXCEPT;

        case FOLLOWS:
            return BuiltinOperators.NODE_AFTER;

        case GENERAL_EQ:
            return BuiltinOperators.GENERAL_EQ;

        case GENERAL_GE:
            return BuiltinOperators.GENERAL_GE;

        case GENERAL_GT:
            return BuiltinOperators.GENERAL_GT;

        case GENERAL_LE:
            return BuiltinOperators.GENERAL_LE;

        case GENERAL_LT:
            return BuiltinOperators.GENERAL_LT;

        case GENERAL_NE:
            return BuiltinOperators.GENERAL_NE;

        case IDIV:
            return BuiltinOperators.IDIV;

        case INTERSECT:
            return BuiltinOperators.INTERSECT;

        case IS:
            return BuiltinOperators.IS_SAME_NODE;

        case MINUS:
            return BuiltinOperators.SUBTRACT;

        case MOD:
            return BuiltinOperators.MOD;

        case MULTIPLY:
            return BuiltinOperators.MULTIPLY;

        case OR:
            return BuiltinOperators.OR;

        case PLUS:
            return BuiltinOperators.ADD;

        case PRECEDES:
            return BuiltinOperators.NODE_BEFORE;

        case RANGE:
            return BuiltinOperators.TO;

        case UNION:
            return BuiltinOperators.UNION;

        case VALUE_EQ:
            return BuiltinOperators.VALUE_EQ;

        case VALUE_GE:
            return BuiltinOperators.VALUE_GE;

        case VALUE_GT:
            return BuiltinOperators.VALUE_GT;

        case VALUE_LE:
            return BuiltinOperators.VALUE_LE;

        case VALUE_LT:
            return BuiltinOperators.VALUE_LT;

        case VALUE_NE:
            return BuiltinOperators.VALUE_NE;
        }
        throw new IllegalStateException("Unknown operator: " + operator);
    }

    private ILogicalExpression ce(SequenceType type, Object value) throws SystemException {
        try {
            ItemType it = type.getItemType();
            if (it.isAtomicType()) {
                AtomicType at = (AtomicType) it;
                byte[] bytes = null;
                switch (at.getTypeId()) {
                case BuiltinTypeConstants.XS_BOOLEAN_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_BOOLEAN_TAG);
                    dOut.writeByte(((Boolean) value).booleanValue() ? 1 : 0);
                    break;
                }
                case BuiltinTypeConstants.XS_INT_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_INT_TAG);
                    dOut.writeInt(((Number) value).intValue());
                    break;
                }
                case BuiltinTypeConstants.XS_INTEGER_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_INTEGER_TAG);
                    dOut.writeLong(((Number) value).longValue());
                    break;
                }
                case BuiltinTypeConstants.XS_DOUBLE_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_DOUBLE_TAG);
                    dOut.writeDouble(((Number) value).doubleValue());
                    break;
                }
                case BuiltinTypeConstants.XS_STRING_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_STRING_TAG);
                    stringVB.write((CharSequence) value, dOut);
                    break;
                }
                case BuiltinTypeConstants.XS_DECIMAL_TYPE_ID: {
                    baaos.reset();
                    // TODO Remove the creation of the separate byte array.
                    DoublePointable doublep = (DoublePointable) DoublePointable.FACTORY.createPointable();
                    doublep.set(new byte[DoublePointable.TYPE_TRAITS.getFixedLength()], 0,
                            DoublePointable.TYPE_TRAITS.getFixedLength());
                    doublep.setDouble(((Number) value).doubleValue());
                    CastToDecimalOperation castToDecimal = new CastToDecimalOperation();
                    castToDecimal.convertDouble(doublep, dOut);
                    break;
                }
                case BuiltinTypeConstants.XS_QNAME_TYPE_ID: {
                    QName qname = (QName) value;
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_QNAME_TAG);
                    stringVB.write(qname.getNamespaceURI(), dOut);
                    stringVB.write(qname.getPrefix(), dOut);
                    stringVB.write(qname.getLocalPart(), dOut);
                    break;
                }
                case BuiltinTypeConstants.XS_UNTYPED_ATOMIC_TYPE_ID: {
                    baaos.reset();
                    dOut.write((byte) ValueTag.XS_UNTYPED_ATOMIC_TAG);
                    stringVB.write((CharSequence) value, dOut);
                    break;
                }
                default:
                    throw new SystemException(ErrorCode.SYSE0001);
                }
                bytes = Arrays.copyOf(baaos.getByteArray(), baaos.size());
                return new ConstantExpression(new VXQueryConstantValue(type, bytes));
            }
            throw new UnsupportedOperationException();
        } catch (IOException e) {
            throw new SystemException(ErrorCode.SYSE0001, e);
        }
    }

    private static ILogicalExpression vre(LogicalVariable var) {
        if (var == null) {
            throw new NullPointerException();
        }
        return new VariableReferenceExpression(var);
    }

    private LogicalVariable createConcatenation(List<LogicalVariable> vars, TranslationContext tCtx) {
        if (vars.size() == 1) {
            return vars.get(0);
        }
        return createFunctionCall(BuiltinOperators.CONCATENATE, vars, tCtx);
    }

    private LogicalVariable createFunctionCall(Function fn, List<LogicalVariable> vars, TranslationContext tCtx) {
        return createAssignment(createFunctionCall(fn, vars), tCtx);
    }

    private LogicalVariable createAssignment(ILogicalExpression expr, TranslationContext tCtx) {
        if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
            return ((VariableReferenceExpression) expr).getVariableReference();
        }
        LogicalVariable result = newLogicalVariable();
        AssignOperator aOp = new AssignOperator(result, mutable(expr));
        aOp.getInputs().add(mutable(tCtx.op));
        tCtx.op = aOp;
        return result;
    }

    private static ILogicalExpression createFunctionCall(Function fn, List<LogicalVariable> vars) {
        List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
        for (LogicalVariable var : vars) {
            args.add(mutable(new VariableReferenceExpression(var)));
        }
        return new ScalarFunctionCallExpression(fn, args);
    }

    private ILogicalExpression normalize(ILogicalExpression expr, SequenceType type) throws SystemException {
        if (type.getItemType().isAtomicType()) {
            ILogicalExpression atomizedExpr = new ScalarFunctionCallExpression(BuiltinFunctions.FN_DATA_1,
                    Collections.singletonList(mutable(expr)));
            AtomicType aType = (AtomicType) type.getItemType();
            if (TypeUtils.isSubtypeTypeOf(aType, BuiltinTypeRegistry.XS_BOOLEAN)) {
                return new ScalarFunctionCallExpression(BuiltinFunctions.FN_BOOLEAN_1,
                        Collections.singletonList(mutable(atomizedExpr)));
            }
            return promote(atomizedExpr, type);
        } else {
            return treat(expr, type);
        }
    }

    private ILogicalExpression promote(ILogicalExpression expr, SequenceType type) throws SystemException {
        int typeCode = currCtx.lookupSequenceType(type);
        return sfce(BuiltinOperators.PROMOTE, expr,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
    }

    private ILogicalExpression treat(ILogicalExpression expr, SequenceType type) throws SystemException {
        int typeCode = currCtx.lookupSequenceType(type);
        return sfce(BuiltinOperators.TREAT, expr,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
    }

    private ILogicalExpression cast(ILogicalExpression expr, SequenceType type) throws SystemException {
        int typeCode = currCtx.lookupSequenceType(type);
        return sfce(BuiltinOperators.CAST, expr,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
    }

    private ILogicalExpression castable(ILogicalExpression expr, SequenceType type) throws SystemException {
        int typeCode = currCtx.lookupSequenceType(type);
        return sfce(BuiltinOperators.CASTABLE, expr,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
    }

    private ILogicalExpression instanceOf(ILogicalExpression expr, SequenceType type) throws SystemException {
        int typeCode = currCtx.lookupSequenceType(type);
        return sfce(BuiltinOperators.INSTANCE_OF, expr,
                ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
    }

    private List<LogicalVariable> translateExpressionList(List<ASTNode> expressions, TranslationContext tCtx)
            throws SystemException {
        List<LogicalVariable> result = new ArrayList<LogicalVariable>();
        for (ASTNode e : expressions) {
            result.add(translateExpression(e, tCtx));
        }
        return result;
    }

    private static Mutable<ILogicalExpression> mutable(ILogicalExpression expr) {
        return new MutableObject<ILogicalExpression>(expr);
    }

    private static Mutable<ILogicalOperator> mutable(ILogicalOperator op) {
        return new MutableObject<ILogicalOperator>(op);
    }

    private LogicalVariable newLogicalVariable() {
        return new LogicalVariable(varCounter++);
    }

    private class RootVariableScope implements IVariableScope {
        @Override
        public IVariableScope getParentScope() {
            return null;
        }

        @Override
        public XQueryVariable lookupVariable(QName name) {
            return moduleCtx.lookupVariable(name);
        }

        @Override
        public void registerVariable(XQueryVariable var) {
            moduleCtx.registerVariable(var);
        }
    }

    private class TranslationContext {
        private final TranslationContext parent;

        private ILogicalOperator op;

        private IVariableScope varScope;

        public TranslationContext(TranslationContext parent, ILogicalOperator op) {
            this.parent = parent;
            this.op = op;
            varScope = parent == null ? rootVarScope : parent.varScope;
        }

        TranslationContext pushContext() {
            SubplanOperator sOp = new SubplanOperator();
            sOp.getInputs().add(mutable(op));
            op = sOp;
            NestedTupleSourceOperator ntsOp = new NestedTupleSourceOperator(mutable(sOp));
            TranslationContext childCtx = new TranslationContext(this, ntsOp);
            return childCtx;
        }

        TranslationContext popContext() {
            SubplanOperator sOp = (SubplanOperator) parent.op;
            sOp.setRootOp(mutable(op));
            return parent;
        }

        void pushVariableScope() {
            varScope = new ExpressionVariableScope(varScope);
        }

        void popVariableScope() {
            varScope = varScope.getParentScope();
        }
    }

    private interface IVariableScope {
        public IVariableScope getParentScope();

        public XQueryVariable lookupVariable(QName name);

        public void registerVariable(XQueryVariable var);
    }

    private static class ExpressionVariableScope implements IVariableScope {
        private final IVariableScope parent;

        private final Map<QName, XQueryVariable> varMap;

        public ExpressionVariableScope(IVariableScope parent) {
            this.parent = parent;
            varMap = new HashMap<QName, XQueryVariable>();
        }

        @Override
        public IVariableScope getParentScope() {
            return parent;
        }

        @Override
        public XQueryVariable lookupVariable(QName name) {
            if (varMap.containsKey(name)) {
                return varMap.get(name);
            }
            return parent.lookupVariable(name);
        }

        @Override
        public void registerVariable(XQueryVariable var) {
            varMap.put(var.getName(), var);
        }
    }
}