/*
 * 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.
 */

/* ----------------------------------------
    JavaCC 1.1 Options
-------------------------------------------*/

options {
    LOOKAHEAD = 1;                      // (default 1)
    CHOICE_AMBIGUITY_CHECK = 2;         // (default 2)
    OTHER_AMBIGUITY_CHECK = 1;          // (default 1)

    STATIC = false;                     // (default true)
    DEBUG_PARSER = false;               // (default false)
    DEBUG_LOOKAHEAD = false;            // (default false)
    DEBUG_TOKEN_MANAGER = false;        // (default false)
    OPTIMIZE_TOKEN_MANAGER = true;      // (default true)
    ERROR_REPORTING = true;             // (default true)
    JAVA_UNICODE_ESCAPE = false;        // (default false)
    UNICODE_INPUT = true;               // (default false)
    IGNORE_CASE = false;                // (default false)
    COMMON_TOKEN_ACTION = false;        // (default false)
    USER_TOKEN_MANAGER = false;         // (default false)
    USER_CHAR_STREAM = false;           // (default false)
    BUILD_PARSER = true;                // (default true)
    BUILD_TOKEN_MANAGER = true;         // (default true)
    SANITY_CHECK = true;                // (default true)
    FORCE_LA_CHECK = false;             // (default false)
    CACHE_TOKENS = true;                // (default false)
}

/*--------------------------------------------
    Parser Class
---------------------------------------------*/

PARSER_BEGIN(XPathParser)
    package org.apache.commons.jxpath.ri.parser;

    import org.apache.commons.jxpath.ri.Compiler;
    import java.util.ArrayList;

    public class XPathParser {
        private Compiler compiler;

        public void setCompiler(Compiler compiler){
            this.compiler = compiler;
        }

        private String unescape(String string){
            int index = string.indexOf("&apos;");
            while (index != -1){
                string = string.substring(0, index) + "\'" + string.substring(index + 6);
                index = string.indexOf("&apos;");
            }
            index = string.indexOf("&quot;");
            while (index != -1){
                string = string.substring(0, index) + "\"" + string.substring(index + 6);
                index = string.indexOf("&quot;");
            }
            return string;
        }
    }

PARSER_END(XPathParser)

/*----------------------------*/
/* Skip Whitespace everywhere */
/*----------------------------*/


/* [39]    ExprWhitespace    ::=    S  */
SKIP :
{
   " " | "\t" | "\n" | "\r" | "\f"
}

/*-----------------*/
/* Operator Tokens */
/*-----------------*/


TOKEN:
{
          <SLASH:      "/"    >
    |     <SLASHSLASH: "//"   >
    |     <UNION:      "|"    >
    |     <PLUS:       "+"    >
    |     <MINUS:      "-"    >
    |     <EQ:         "="    >
    |     <NEQ:        "!="   >
    |     <LT:         "<"    >
    |     <LTE:        "<="   >
    |     <GT:         ">"    >
    |     <GTE:        ">="   >
    |     <VARIABLE:   "$"    >
}


/*-----------------------------------------------*/
/* Unambigious Tokens (Number, Literal, Variable */
/*-----------------------------------------------*/

TOKEN:
{

/* [29] Literal    ::=    '"' [^"]* '"' | "'" [^']* "'"  */
    <Literal :
            "\"" (~["\""])* "\""
        |    "'"  (~["'"] )* "'"
    >

|

/* [31]    Digits    ::=    [0-9]+  */
    <#Digit :
        ["0"-"9"]
    >

|

/* [30]    Number    ::=    Digits ('.' Digits?)?  | '.' Digits  */
    <Number :
            (<Digit>)+ ("." ( (<Digit>)+ )? )?
        |    "." (<Digit>)+
    >
}


/*-------------------------------*/
/* XML Names and Qualified Names */
/*-------------------------------*/

TOKEN:
{
    <#Letter :
        <BaseChar> | <Ideographic>
    >
|
    <#BaseChar :
        (
        ["\u0041"-"\u005A"] | ["\u0061"-"\u007A"] | ["\u00C0"-"\u00D6"] | ["\u00D8"-"\u00F6"] |
        ["\u00F8"-"\u00FF"] | ["\u0100"-"\u0131"] | ["\u0134"-"\u013E"] | ["\u0141"-"\u0148"] |
        ["\u014A"-"\u017E"] | ["\u0180"-"\u01C3"] | ["\u01CD"-"\u01F0"] | ["\u01F4"-"\u01F5"] |
        ["\u01FA"-"\u0217"] | ["\u0250"-"\u02A8"] | ["\u02BB"-"\u02C1"] | "\u0386" | ["\u0388"-"\u038A"] |
        "\u038C" | ["\u038E"-"\u03A1"] | ["\u03A3"-"\u03CE"] | ["\u03D0"-"\u03D6"] | "\u03DA" |
        "\u03DC" |  "\u03DE" | "\u03E0" | ["\u03E2"-"\u03F3"] | ["\u0401"-"\u040C"] | ["\u040E"-"\u044F"] |
        ["\u0451"-"\u045C"] | ["\u045E"-"\u0481"] | ["\u0490"-"\u04C4"] | ["\u04C7"-"\u04C8"] |
        ["\u04CB"-"\u04CC"] | ["\u04D0"-"\u04EB"] | ["\u04EE"-"\u04F5"] | ["\u04F8"-"\u04F9"] |
        ["\u0531"-"\u0556"] | "\u0559" | ["\u0561"-"\u0586"] | ["\u05D0"-"\u05EA"] | ["\u05F0"-"\u05F2"] |
        ["\u0621"-"\u063A"] | ["\u0641"-"\u064A"] | ["\u0671"-"\u06B7"] | ["\u06BA"-"\u06BE"] |
        ["\u06C0"-"\u06CE"] | ["\u06D0"-"\u06D3"] | "\u06D5" | ["\u06E5"-"\u06E6"] | ["\u0905"-"\u0939"] |
        "\u093D" | ["\u0958"-"\u0961"] | ["\u0985"-"\u098C"] | ["\u098F"-"\u0990"] | ["\u0993"-"\u09A8"] |
        ["\u09AA"-"\u09B0"] | "\u09B2" | ["\u09B6"-"\u09B9"] | ["\u09DC"-"\u09DD"] | ["\u09DF"-"\u09E1"] |
        ["\u09F0"-"\u09F1"] | ["\u0A05"-"\u0A0A"] | ["\u0A0F"-"\u0A10"] | ["\u0A13"-"\u0A28"] |
        ["\u0A2A"-"\u0A30"] | ["\u0A32"-"\u0A33"] | ["\u0A35"-"\u0A36"] | ["\u0A38"-"\u0A39"] |
        ["\u0A59"-"\u0A5C"] | "\u0A5E" | ["\u0A72"-"\u0A74"] | ["\u0A85"-"\u0A8B"] | "\u0A8D" |
        ["\u0A8F"-"\u0A91"] | ["\u0A93"-"\u0AA8"] | ["\u0AAA"-"\u0AB0"] | ["\u0AB2"-"\u0AB3"] |
        ["\u0AB5"-"\u0AB9"] | "\u0ABD" | "\u0AE0" |  ["\u0B05"-"\u0B0C"] | ["\u0B0F"-"\u0B10"] |
        ["\u0B13"-"\u0B28"] | ["\u0B2A"-"\u0B30"] | ["\u0B32"-"\u0B33"] | ["\u0B36"-"\u0B39"] |
        "\u0B3D" | ["\u0B5C"-"\u0B5D"] | ["\u0B5F"-"\u0B61"] | ["\u0B85"-"\u0B8A"] |  ["\u0B8E"-"\u0B90"] |
        ["\u0B92"-"\u0B95"] |  ["\u0B99"-"\u0B9A"] | "\u0B9C" | ["\u0B9E"-"\u0B9F"] | ["\u0BA3"-"\u0BA4"] |
        ["\u0BA8"-"\u0BAA"] | ["\u0BAE"-"\u0BB5"] | ["\u0BB7"-"\u0BB9"] | ["\u0C05"-"\u0C0C"] |
        ["\u0C0E"-"\u0C10"] | ["\u0C12"-"\u0C28"] | ["\u0C2A"-"\u0C33"] | ["\u0C35"-"\u0C39"] |
        ["\u0C60"-"\u0C61"] | ["\u0C85"-"\u0C8C"] | ["\u0C8E"-"\u0C90"] | ["\u0C92"-"\u0CA8"] |
        ["\u0CAA"-"\u0CB3"] | ["\u0CB5"-"\u0CB9"] | "\u0CDE" | ["\u0CE0"-"\u0CE1"] | ["\u0D05"-"\u0D0C"] |
        ["\u0D0E"-"\u0D10"] | ["\u0D12"-"\u0D28"] | ["\u0D2A"-"\u0D39"] | ["\u0D60"-"\u0D61"] |
        ["\u0E01"-"\u0E2E"] | "\u0E30" | ["\u0E32"-"\u0E33"] | ["\u0E40"-"\u0E45"] | ["\u0E81"-"\u0E82"] |
        "\u0E84" | ["\u0E87"-"\u0E88"] | "\u0E8A" | "\u0E8D" | ["\u0E94"-"\u0E97"] | ["\u0E99"-"\u0E9F"] |
        ["\u0EA1"-"\u0EA3"] | "\u0EA5" | "\u0EA7" | ["\u0EAA"-"\u0EAB"] | ["\u0EAD"-"\u0EAE"] | "\u0EB0" |
        ["\u0EB2"-"\u0EB3"] | "\u0EBD" | ["\u0EC0"-"\u0EC4"] | ["\u0F40"-"\u0F47"] | ["\u0F49"-"\u0F69"] |
        ["\u10A0"-"\u10C5"] | ["\u10D0"-"\u10F6"] | "\u1100" | ["\u1102"-"\u1103"] | ["\u1105"-"\u1107"] |
        "\u1109" | ["\u110B"-"\u110C"] | ["\u110E"-"\u1112"] | "\u113C" | "\u113E" | "\u1140" | "\u114C" |
        "\u114E" | "\u1150" | ["\u1154"-"\u1155"] | "\u1159" | ["\u115F"-"\u1161"] | "\u1163" | "\u1165" |
        "\u1167" | "\u1169" | ["\u116D"-"\u116E"] | ["\u1172"-"\u1173"] | "\u1175" | "\u119E" | "\u11A8" |
        "\u11AB" | ["\u11AE"-"\u11AF"] | ["\u11B7"-"\u11B8"] | "\u11BA" |  ["\u11BC"-"\u11C2"] | "\u11EB" |
        "\u11F0" | "\u11F9" | ["\u1E00"-"\u1E9B"] | ["\u1EA0"-"\u1EF9"] | ["\u1F00"-"\u1F15"] |
        ["\u1F18"-"\u1F1D"] |
        ["\u1F20"-"\u1F45"] | ["\u1F48"-"\u1F4D"] | ["\u1F50"-"\u1F57"] | "\u1F59" | "\u1F5B" | "\u1F5D" |
        ["\u1F5F"-"\u1F7D"] | ["\u1F80"-"\u1FB4"] | ["\u1FB6"-"\u1FBC"] | "\u1FBE" |  ["\u1FC2"-"\u1FC4"] |
        ["\u1FC6"-"\u1FCC"] | ["\u1FD0"-"\u1FD3"] | ["\u1FD6"-"\u1FDB"] | ["\u1FE0"-"\u1FEC"] |
        ["\u1FF2"-"\u1FF4"] | ["\u1FF6"-"\u1FFC"] | "\u2126" | ["\u212A"-"\u212B"] | "\u212E" |
        ["\u2180"-"\u2182"] | ["\u3041"-"\u3094"] | ["\u30A1"-"\u30FA"] | ["\u3105"-"\u312C"] |
        ["\uAC00"-"\uD7A3"]
        )
    >
|
    <#Ideographic :
        (["\u4E00"-"\u9FA5"] | "\u3007" | ["\u3021"-"\u3029"])
    >
|
    <#CombiningChar :
        (
        ["\u0300"-"\u0345"]    |    ["\u0360"-"\u0361"]     |    ["\u0483"-"\u0486"]    |    ["\u0591"-"\u05A1"] |
        ["\u05A3"-"\u05B9"]    |    ["\u05BB"-"\u05BD"]        |    "\u05BF"             |    ["\u05C1"-"\u05C2"] |
        "\u05C4"             | ["\u064B"-"\u0652"] | "\u0670"             | ["\u06D6"-"\u06DC"] |
        ["\u06DD"-"\u06DF"] | ["\u06E0"-"\u06E4"] | ["\u06E7"-"\u06E8"] | ["\u06EA"-"\u06ED"] |
        ["\u0901"-"\u0903"] | "\u093C"    |["\u093E"-"\u094C"] | "\u094D" | ["\u0951"-"\u0954"] |
        ["\u0962"-"\u0963"] | ["\u0981"-"\u0983"] | "\u09BC" | "\u09BE" | "\u09BF" | ["\u09C0"-"\u09C4"] |
        ["\u09C7"-"\u09C8"] | ["\u09CB"-"\u09CD"] | "\u09D7" | ["\u09E2"-"\u09E3"] | "\u0A02" | "\u0A3C" |
        "\u0A3E" | "\u0A3F" | ["\u0A40"-"\u0A42"] |
        ["\u0A47"-"\u0A48"] | ["\u0A4B"-"\u0A4D"] | ["\u0A70"-"\u0A71"] | ["\u0A81"-"\u0A83"] | "\u0ABC" |
        ["\u0ABE"-"\u0AC5"] | ["\u0AC7"-"\u0AC9"] | ["\u0ACB"-"\u0ACD"] | ["\u0B01"-"\u0B03"] | "\u0B3C" |
        ["\u0B3E"-"\u0B43"] | ["\u0B47"-"\u0B48"] | ["\u0B4B"-"\u0B4D"] | ["\u0B56"-"\u0B57"] |
        ["\u0B82"-"\u0B83"] | ["\u0BBE"-"\u0BC2"] | ["\u0BC6"-"\u0BC8"] | ["\u0BCA"-"\u0BCD"] | "\u0BD7" |
        ["\u0C01"-"\u0C03"] | ["\u0C3E"-"\u0C44"] | ["\u0C46"-"\u0C48"] | ["\u0C4A"-"\u0C4D"] |
        ["\u0C55"-"\u0C56"] | ["\u0C82"-"\u0C83"] | ["\u0CBE"-"\u0CC4"] | ["\u0CC6"-"\u0CC8"] |
        ["\u0CCA"-"\u0CCD"] | ["\u0CD5"-"\u0CD6"] | ["\u0D02"-"\u0D03"] | ["\u0D3E"-"\u0D43"] |
        ["\u0D46"-"\u0D48"] | ["\u0D4A"-"\u0D4D"] | "\u0D57" | "\u0E31" | ["\u0E34"-"\u0E3A"] |
        ["\u0E47"-"\u0E4E"] | "\u0EB1" | ["\u0EB4"-"\u0EB9"] | ["\u0EBB"-"\u0EBC"] | ["\u0EC8"-"\u0ECD"] |
        ["\u0F18"-"\u0F19"] | "\u0F35" | "\u0F37" | "\u0F39" | "\u0F3E" | "\u0F3F" | ["\u0F71"-"\u0F84"] |
        ["\u0F86"-"\u0F8B"] | ["\u0F90"-"\u0F95"] | "\u0F97" | ["\u0F99"-"\u0FAD"] | ["\u0FB1"-"\u0FB7"] |
        "\u0FB9" | ["\u20D0"-"\u20DC"] | "\u20E1" | ["\u302A"-"\u302F"] | "\u3099" | "\u309A"
        )
    >
|
    <#UnicodeDigit :
        ["\u0030"-"\u0039"] | ["\u0660"-"\u0669"] | ["\u06F0"-"\u06F9"] | ["\u0966"-"\u096F"] |
        ["\u09E6"-"\u09EF"] | ["\u0A66"-"\u0A6F"] | ["\u0AE6"-"\u0AEF"] | ["\u0B66"-"\u0B6F"] |
        ["\u0BE7"-"\u0BEF"] | ["\u0C66"-"\u0C6F"] | ["\u0CE6"-"\u0CEF"] | ["\u0D66"-"\u0D6F"] |
        ["\u0E50"-"\u0E59"] | ["\u0ED0"-"\u0ED9"] | ["\u0F20"-"\u0F29"]
    >
|
    <#Extender :
        "\u00B7" | "\u02D0" | "\u02D1" | "\u0387" | "\u0640" | "\u0E46" | "\u0EC6" |
        "\u3005" | ["\u3031"-"\u3035"] | ["\u309D"-"\u309E"] | ["\u30FC"-"\u30FE"]
    >
|
    <OR:    "or">
|
    <AND:    "and">
|
    <MOD:    "mod">
|
    <DIV:    "div">
|
    <NODE:    "node">
|
    <TEXT:    "text">
|
    <COMMENT:    "comment">
|
    <PI:    "processing-instruction">

|
    <AXIS_SELF: "self::">
|   <AXIS_CHILD: "child::">
|   <AXIS_PARENT: "parent::">
|   <AXIS_ANCESTOR: "ancestor::">
|   <AXIS_ATTRIBUTE: "attribute::">
|   <AXIS_NAMESPACE: "namespace::">
|   <AXIS_PRECEDING: "preceding::">
|   <AXIS_FOLLOWING: "following::">
|   <AXIS_DESCENDANT: "descendant::">
|   <AXIS_ANCESTOR_OR_SELF: "ancestor-or-self::">
|   <AXIS_FOLLOWING_SIBLING: "following-sibling::">
|   <AXIS_PRECEDING_SIBLING: "preceding-sibling::">
|   <AXIS_DESCENDANT_OR_SELF: "descendant-or-self::">

|   <FUNCTION_LAST: "last">
|   <FUNCTION_POSITION: "position">
|   <FUNCTION_COUNT: "count">
|   <FUNCTION_ID: "id">
|   <FUNCTION_KEY: "key">
|   <FUNCTION_LOCAL_NAME: "local-name">
|   <FUNCTION_NAMESPACE_URI: "namespace-uri">
|   <FUNCTION_NAME: "name">
|   <FUNCTION_STRING: "string">
|   <FUNCTION_CONCAT: "concat">
|   <FUNCTION_STARTS_WITH: "starts-with">
|   <FUNCTION_CONTAINS: "contains">
|   <FUNCTION_SUBSTRING_BEFORE: "substring-before">
|   <FUNCTION_SUBSTRING_AFTER: "substring-after">
|   <FUNCTION_SUBSTRING: "substring">
|   <FUNCTION_STRING_LENGTH: "string-length">
|   <FUNCTION_NORMALIZE_SPACE: "normalize-space">
|   <FUNCTION_TRANSLATE: "translate">
|   <FUNCTION_BOOLEAN: "boolean">
|   <FUNCTION_NOT: "not">
|   <FUNCTION_TRUE: "true">
|   <FUNCTION_FALSE: "false">
|   <FUNCTION_NULL: "null">
|   <FUNCTION_LANG: "lang">
|   <FUNCTION_NUMBER: "number">
|   <FUNCTION_SUM: "sum">
|   <FUNCTION_FLOOR: "floor">
|   <FUNCTION_CEILING: "ceiling">
|   <FUNCTION_ROUND: "round">
|   <FUNCTION_FORMAT_NUMBER: "format-number">
|
    <NCName :
        (<Letter> | ["_"]) (<Letter> | <UnicodeDigit> | [".","-","_"] | <CombiningChar> | <Extender>)*
    >
}

// Note: XPath does not have reserved words, so we have to include all these terminals
String NCName() :
{}
{
    (
        NCName_Without_CoreFunctions()
    |   <NODE>
    |   <TEXT>
    |   <COMMENT>
    |   <PI>
    |   <FUNCTION_LAST>
    |   <FUNCTION_POSITION>
    |   <FUNCTION_COUNT>
    |   <FUNCTION_ID>
    |   <FUNCTION_LOCAL_NAME>
    |   <FUNCTION_NAMESPACE_URI>
    |   <FUNCTION_NAME>
    |   <FUNCTION_STRING>
    |   <FUNCTION_CONCAT>
    |   <FUNCTION_STARTS_WITH>
    |   <FUNCTION_CONTAINS>
    |   <FUNCTION_SUBSTRING_BEFORE>
    |   <FUNCTION_SUBSTRING_AFTER>
    |   <FUNCTION_SUBSTRING>
    |   <FUNCTION_STRING_LENGTH>
    |   <FUNCTION_NORMALIZE_SPACE>
    |   <FUNCTION_TRANSLATE>
    |   <FUNCTION_BOOLEAN>
    |   <FUNCTION_NOT>
    |   <FUNCTION_TRUE>
    |   <FUNCTION_FALSE>
    |   <FUNCTION_NULL>
    |   <FUNCTION_LANG>
    |   <FUNCTION_NUMBER>
    |   <FUNCTION_SUM>
    |   <FUNCTION_FLOOR>
    |   <FUNCTION_CEILING>
    |   <FUNCTION_ROUND>
    |   <FUNCTION_KEY>
    |   <FUNCTION_FORMAT_NUMBER>
    )
    {
        return token.image;
    }
}

String NCName_Without_CoreFunctions() :
{}
{
    (
        <NCName>
    |   <OR>
    |   <AND>
    |   <MOD>
    |   <DIV>
    )
    {
        return token.image;
    }
}

int CoreFunctionName() :
{
    int code;
}
{
    (
        <FUNCTION_LAST>             { code = Compiler.FUNCTION_LAST; }
    |   <FUNCTION_POSITION>         { code = Compiler.FUNCTION_POSITION; }
    |   <FUNCTION_COUNT>            { code = Compiler.FUNCTION_COUNT; }
    |   <FUNCTION_ID>               { code = Compiler.FUNCTION_ID; }
    |   <FUNCTION_LOCAL_NAME>       { code = Compiler.FUNCTION_LOCAL_NAME; }
    |   <FUNCTION_NAMESPACE_URI>    { code = Compiler.FUNCTION_NAMESPACE_URI; }
    |   <FUNCTION_NAME>             { code = Compiler.FUNCTION_NAME; }
    |   <FUNCTION_STRING>           { code = Compiler.FUNCTION_STRING; }
    |   <FUNCTION_CONCAT>           { code = Compiler.FUNCTION_CONCAT; }
    |   <FUNCTION_STARTS_WITH>      { code = Compiler.FUNCTION_STARTS_WITH; }
    |   <FUNCTION_CONTAINS>         { code = Compiler.FUNCTION_CONTAINS; }
    |   <FUNCTION_SUBSTRING_BEFORE> { code = Compiler.FUNCTION_SUBSTRING_BEFORE; }
    |   <FUNCTION_SUBSTRING_AFTER>  { code = Compiler.FUNCTION_SUBSTRING_AFTER; }
    |   <FUNCTION_SUBSTRING>        { code = Compiler.FUNCTION_SUBSTRING; }
    |   <FUNCTION_STRING_LENGTH>    { code = Compiler.FUNCTION_STRING_LENGTH; }
    |   <FUNCTION_NORMALIZE_SPACE>  { code = Compiler.FUNCTION_NORMALIZE_SPACE; }
    |   <FUNCTION_TRANSLATE>        { code = Compiler.FUNCTION_TRANSLATE; }
    |   <FUNCTION_BOOLEAN>          { code = Compiler.FUNCTION_BOOLEAN; }
    |   <FUNCTION_NOT>              { code = Compiler.FUNCTION_NOT; }
    |   <FUNCTION_TRUE>             { code = Compiler.FUNCTION_TRUE; }
    |   <FUNCTION_FALSE>            { code = Compiler.FUNCTION_FALSE; }
    |   <FUNCTION_NULL>             { code = Compiler.FUNCTION_NULL; }
    |   <FUNCTION_LANG>             { code = Compiler.FUNCTION_LANG; }
    |   <FUNCTION_NUMBER>           { code = Compiler.FUNCTION_NUMBER; }
    |   <FUNCTION_SUM>              { code = Compiler.FUNCTION_SUM; }
    |   <FUNCTION_FLOOR>            { code = Compiler.FUNCTION_FLOOR; }
    |   <FUNCTION_CEILING>          { code = Compiler.FUNCTION_CEILING; }
    |   <FUNCTION_ROUND>            { code = Compiler.FUNCTION_ROUND; }
    |   <FUNCTION_KEY>              { code = Compiler.FUNCTION_KEY; }
    |   <FUNCTION_FORMAT_NUMBER>    { code = Compiler.FUNCTION_FORMAT_NUMBER; }
    )
    {
        return code;
    }
}

Object QName() :
{String nc1, nc2 = null;}
{
    nc1 = NCName() ( ":" nc2 = NCName() )?
    {
        if (nc2 == null){
            return compiler.qname(null, nc1);
        }
        else {
            return compiler.qname(nc1, nc2);
        }
    }
}

Object QName_Without_CoreFunctions() :
{
    String nc1, nc2 = null;
}
{
    (
            LOOKAHEAD(NCName() ":") nc1 = NCName() ":" nc2 = NCName()
        |
            nc1 = NCName_Without_CoreFunctions()
    )
    {
        if (nc2 == null){
            return compiler.qname(null, nc1);
        }
        else {
            return compiler.qname(nc1, nc2);
        }
    }
}

Object parseExpression() :
{
    Object ex;
}
{
    ex = Expression()
    <EOF>
    {
        return ex;
    }
}

/* ################################################################################### */
/* XSLT Patterns (http://www.w3.org/1999/08/WD-xslt-19990813)                          */
/* ################################################################################### */

/* [XSLT1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern  */

//void Pattern() :
//{}
//{
//        LocationPathPattern() ( <UNION> LocationPathPattern() )* <EOF>
//}
//
//
///* [XSLT2] LocationPathPattern ::=
//   '/' RelativePathPattern? | IdKeyPattern (('/' | '//' RelativePathPattern)? | '//'? RelativePathPattern
//*/
//
//void LocationPathPattern() :
//{}
//{
//        <SLASH> ( RelativePathPattern() )?
//    |    (
//        LOOKAHEAD(IdKeyPattern())
//            IdKeyPattern() ( ( <SLASH> | <SLASHSLASH>) RelativePathPattern() )?
//        |    ( <SLASHSLASH> )? RelativePathPattern()
//        )
//}
//
//
//
///* [XSLT3] IdKeyPattern    ::=    'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')'  */
//
//void IdKeyPattern() :
//{}
//{
//        <ID> "(" <Literal> ")"
//    |    <KEY>  "(" <Literal> "," <Literal> ")"
//}
//
//
///* [XSLT4] RelativePathPattern    ::=    StepPattern | RelativePathPattern '/' StepPattern
//                           | RelativePathPattern '//' StepPattern
//*/
//void RelativePathPattern() :
//{}
//{
//        StepPattern() ( ( <SLASH>| <SLASHSLASH> ) StepPattern()    )*
//}
//
//
///* [XSLT5]    StepPattern    ::=    AbbreviatedAxisSpecifier NodeTest Predicate*   */
//void StepPattern() :
//{}
//{
//        AbbreviatedAxisSpecifier() NodeTest() (Predicate())*
//}



// See XPath Syntax (http://www.w3.org/TR/xpath )


//void XPath() :
//{}
//{
//    LocationPath()
//    <EOF>
//}


/* [1] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath  */
Object LocationPath() :
{Object ex = null;}
{
    (
        ex = RelativeLocationPath()
    |   ex = AbsoluteLocationPath()
    )
    {
        return ex;
    }
}

/* [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? | AbbreviatedAbsoluteLocationPath  */
/* [10]    AbbreviatedAbsoluteLocationPath    ::=    '//' RelativeLocationPath  */

Object AbsoluteLocationPath() :
{
    ArrayList steps = new ArrayList();
}
{
    (
        LOOKAHEAD(LocationStep(steps)) (LocationStep(steps) ( LocationStep(steps) )* )
      | <SLASH>
    )
    {
        return compiler.locationPath(true, steps.toArray());
    }
}

/* [3] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | AbbreviatedRelativeLocationPath */

Object RelativeLocationPath() :
{
    ArrayList steps = new ArrayList();
}
{
    (
        NodeTest(steps) ( LocationStep(steps) )*
    )
    {
        return compiler.locationPath(false, steps.toArray());
    }
}

/* [3] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | AbbreviatedRelativeLocationPath */
/* [11]    AbbreviatedRelativeLocationPath    ::=    RelativeLocationPath '//' Step  */


/*--------------------*/
/* 2.1 Location Steps */
/*--------------------*/

/* [4] Step ::= AxisSpecifier NodeTest Predicate*   | AbbreviatedStep  */

void LocationStep(ArrayList steps) :
{
    Object t;
    Object s;
}
{
    (
        <SLASH>
    |   <SLASHSLASH>
        {
            // Abbreviated step: descendant-or-self::node()
            t = compiler.nodeTypeTest(Compiler.NODE_TYPE_NODE);
            steps.add(compiler.step(Compiler.AXIS_DESCENDANT_OR_SELF, t, null));
        }
    )
    NodeTest(steps)
}

/* [7] NodeTest ::= WildcardName | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' */

void NodeTest(ArrayList steps) :
{
    int axis;
    int type = -1;
    String instruction = null;
    Object name = null;
    Object s;
    Object p;
    ArrayList ps = new ArrayList();
}
{
    (
        (
            axis = AxisSpecifier()
            (
                LOOKAHEAD(NodeType() "(" ")") type = NodeType() "(" ")"
            |   LOOKAHEAD(<PI>) <PI> "(" <Literal> {
                    instruction = unescape(token.image.substring(1, token.image.length() - 1));
                    } ")"
            |   name = WildcardName()
            )
            |   "."
                {
                    axis = Compiler.AXIS_SELF;
                    type = Compiler.NODE_TYPE_NODE;
                }
            | ".."
                {
                    axis = Compiler.AXIS_PARENT;
                    type = Compiler.NODE_TYPE_NODE;
                }
        )
        (
            p = Predicate()
            {
                ps.add(p);
            }
        )*
    )
    {
        if (name != null){
            s = compiler.nodeNameTest(name);
        }
        else if (instruction != null){
            s = compiler.processingInstructionTest(instruction);
        }
        else {
            s = compiler.nodeTypeTest(type);
        }
        steps.add(compiler.step(axis, s, ps.toArray()));
    }
}

/* [5] AxisSpecifier ::=    AxisName '::' | AbbreviatedAxisSpecifier  */

int AxisSpecifier() :
{
    int axis;
}
{
    (
        axis = AxisName()
    |   axis = AbbreviatedAxisSpecifier()
    )
    {
        return axis;
    }
}

/*----------*/
/* 2.2 Axes */
/*----------*/

/* [6] AxisName ::= 'ancestor' | 'ancestor-or-self' | 'attribute'  | 'child' | 'descendant'
                    | 'descendant-or-self' | 'following' | 'following-sibling' | 'namespace'
                       | 'parent' | 'preceding' | 'preceding-sibling' | 'self'
*/

int AxisName() :
{
    int axis = 0;
}
{
    (
            <AXIS_SELF>                 { axis = Compiler.AXIS_SELF; }
        |   <AXIS_CHILD>                { axis = Compiler.AXIS_CHILD; }
        |   <AXIS_PARENT>               { axis = Compiler.AXIS_PARENT; }
        |   <AXIS_ANCESTOR>             { axis = Compiler.AXIS_ANCESTOR; }
        |   <AXIS_ATTRIBUTE>            { axis = Compiler.AXIS_ATTRIBUTE; }
        |   <AXIS_NAMESPACE>            { axis = Compiler.AXIS_NAMESPACE; }
        |   <AXIS_PRECEDING>            { axis = Compiler.AXIS_PRECEDING; }
        |   <AXIS_FOLLOWING>            { axis = Compiler.AXIS_FOLLOWING; }
        |   <AXIS_DESCENDANT>           { axis = Compiler.AXIS_DESCENDANT; }
        |   <AXIS_ANCESTOR_OR_SELF>     { axis = Compiler.AXIS_ANCESTOR_OR_SELF; }
        |   <AXIS_FOLLOWING_SIBLING>    { axis = Compiler.AXIS_FOLLOWING_SIBLING; }
        |   <AXIS_PRECEDING_SIBLING>    { axis = Compiler.AXIS_PRECEDING_SIBLING; }
        |   <AXIS_DESCENDANT_OR_SELF>   { axis = Compiler.AXIS_DESCENDANT_OR_SELF; }
    )
    {
        return axis;
    }
}

/*----------------*/
/* 2.3 Node Tests */
/*----------------*/

/*----------------*/
/* 2.4 Predicates */
/*----------------*/

/* [8] Predicate ::= '[' PredicateExpr ']'  */
/* [9] PredicateExpr ::=  Expr  */

Object Predicate() :
{
    Object ex;
}
{
    "[" ex = Expression() "]"
    {
        return ex;
    }
}

/* [12]    AbbreviatedStep    ::=    '.'  | '..'  */

/* [13]    AbbreviatedAxisSpecifier    ::=    '@'? */
int AbbreviatedAxisSpecifier() :
{
    int axis = Compiler.AXIS_CHILD;
}
{
    ( "@" {axis = Compiler.AXIS_ATTRIBUTE; } )?

    {
        return axis;
    }
}

/*---------------*/
/* 3 Expressions */
/*---------------*/

/*------------*/
/* 3.1 Basics */
/*------------*/

/*
The effect of the grammar is that the order of precedence is (lowest precedence first):
    or
    and
    =, !=
    <=, <, >=, >
and all operators are left associative.
For example, 3 > 2 > 1 is equivalent to (3 > 2) > 1, which evaluates to false.
*/

/* [14] Expr ::= OrExpr */
Object Expression() :
{Object ex;}
{
    ex = OrExpr()
    {
        return ex;
    }
}

/* [15] PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall */

Object PrimaryExpr() :
{
    Object ex = null;
}
{
    (
         ex = VariableReference()
    |    "(" ex = Expression() ")"
    |    <Literal>  { ex = compiler.literal(unescape(token.image.substring(1, token.image.length() - 1))); }
    |    <Number>   { ex = compiler.number(token.image); }
    |    LOOKAHEAD(CoreFunctionName() "(") ex = CoreFunctionCall()
    |    ex = FunctionCall()
    )
    {
        return ex;
    }
}

/*--------------------*/
/* 3.2 Function Calls */
/*--------------------*/

/* [16]    FunctionCall    ::=    FunctionName '(' ( Argument ( ',' Argument)*)? ')'  */
Object FunctionCall() :
{
    Object name;
    ArrayList args;
}
{
    name = FunctionName() args = ArgumentList()
    {
        if (args == null){
            return compiler.function(name, null);
        }
        else {
            return compiler.function(name, args.toArray());
        }
    }
}

Object CoreFunctionCall() :
{
    int code = 0;
    ArrayList args;
}
{
    (
        code = CoreFunctionName()
    )
    args = ArgumentList()
    {
        if (args == null){
            return compiler.function(code, null);
        }
        else {
            return compiler.function(code, args.toArray());
        }
    }
}

ArrayList ArgumentList() :
{
    ArrayList args = null;
    Object arg;
}
{
    "("
        (
            arg  = Argument() { args = new ArrayList(); args.add(arg); }
            (
                "," arg = Argument() { args.add(arg); }
            )*
        )?
    ")"
    {
        return args;
    }
}

/* [17]    Argument    ::=    Expr */
Object Argument() :
{
    Object ex;
}
{
    ex = Expression()
    {
        return ex;
    }
}

/*---------------*/
/* 3.3 Node-sets */
/*---------------*/

/* [18] UnionExpr    ::=    PathExpr | UnionExpr '|' PathExpr */
Object UnionExpr() :
{
    Object ex, r;
    ArrayList list = null;
}
{
    (
        ex = PathExpr() (
            <UNION> r = PathExpr()
            {
                if (list == null){
                    list = new ArrayList();
                    list.add(ex);
                }
                list.add(r);
            }
        )*
    )
    {
        if (list != null){
            ex = compiler.union(list.toArray());
        }
        return ex;
    }
}


/* [19] PathExpr ::= LocationPath | FilterExpr | FilterExpr '/' RelativeLocationPath | FilterExpr '//' RelativeLocationPath  */

Object PathExpr() :
{
    Object ex = null;
    Object[] steps;
}
{
    (
        // Reason for LOOKAHEAD:
        // foo:bar()  - filter path
        // foo:bar    - location path

        LOOKAHEAD(PrimaryExpr()) ex = FilterExpr()
    |   ex = LocationPath()
    )
    {
        return ex;
    }
}

/* [20]    FilterExpr    ::=    PrimaryExpr    | FilterExpr Predicate */
Object FilterExpr() :
{
    Object ex, p;
    ArrayList ps = new ArrayList();
    boolean path = false;
    ArrayList steps = new ArrayList();
}
{
    (
        ex = PrimaryExpr()
        (
            p = Predicate()
            {
                path = true;
                ps.add(p);
            }
        )*
        (
            LocationStep(steps)
            {
                path = true;
            }
        )*
    )
    {
        if (path){
            return compiler.expressionPath(ex, ps.toArray(), steps.toArray());
        }
        else {
            return ex;
        }
    }
}



/*--------------*/
/* 3.4 Booleans */
/*--------------*/

/* [21] OrExpr    ::=    AndExpr | OrExpr 'or' AndExpr */
Object OrExpr() :
{
    Object ex, r;
    ArrayList list = null;
}
{
    (
        ex = AndExpr() (
            <OR> r = AndExpr()
            {
                if (list == null){
                    list = new ArrayList();
                    list.add(ex);
                }
                list.add(r);
            }
        )*
    )
    {
        if (list != null){
            ex = compiler.or(list.toArray());
        }
        return ex;
    }
}

/* [22] AndExpr    ::=    EqualityExpr  | AndExpr 'and' EqualityExpr  */
Object AndExpr() :
{
    Object ex, r;
    ArrayList list = null;
}
{
    (
        ex = EqualityExpr() (
            <AND> r = EqualityExpr()
            {
                if (list == null){
                    list = new ArrayList();
                    list.add(ex);
                }
                list.add(r);
            }
        )*
    )
    {
        if (list != null){
            ex = compiler.and(list.toArray());
        }
        return ex;
    }
}

/* [23] EqualityExpr    ::=    RelationalExpr | EqualityExpr '=' RelationalExpr | EqualityExpr '!=' RelationalExpr */
Object EqualityExpr() :
{Object ex, r;}
{
    (
        ex = RelationalExpr() ((
             <EQ>  r = RelationalExpr() { ex = compiler.equal(ex, r); }
           | <NEQ> r = RelationalExpr() { ex = compiler.notEqual(ex, r); }
        ))*
    )
    {
        return ex;
    }
}


/* [24] RelationalExpr    ::=    AdditiveExpr | RelationalExpr '<' AdditiveExpr | RelationalExpr '>' AdditiveExpr
                       | RelationalExpr '<=' AdditiveExpr  | RelationalExpr '>=' AdditiveExpr */
Object RelationalExpr() :
{Object ex, r;}
{
    (
        ex = AdditiveExpr()  ((
            <LT>   r = AdditiveExpr() { ex = compiler.lessThan(ex, r); }
          | <GT>   r = AdditiveExpr() { ex = compiler.greaterThan(ex, r); }
          | <LTE>  r = AdditiveExpr() { ex = compiler.lessThanOrEqual(ex, r); }
          | <GTE>  r = AdditiveExpr() { ex = compiler.greaterThanOrEqual(ex, r); }
        ))*
    )
    {
        return ex;
    }
}

/*-------------*/
/* 3.5 Numbers */
/*-------------*/

/* [25] AdditiveExpr ::= MultiplicativeExpr  | AdditiveExpr '+' MultiplicativeExpr  | AdditiveExpr '-' MultiplicativeExpr  */
Object AdditiveExpr() :
{
    Object ex, r;
    ArrayList list = null;
}
{
    (
        ex = SubtractiveExpr() ((
            <PLUS>  r = SubtractiveExpr()
            {
                if (list == null){
                    list = new ArrayList();
                    list.add(ex);
                }
                list.add(r);
            }
        ))*
    )
    {
        if (list != null){
            ex = compiler.sum(list.toArray());
        }
        return ex;
    }
}

Object SubtractiveExpr() :
{
    Object ex, r = null;
}
{
    (
        ex = MultiplicativeExpr() (
            <MINUS> r = MultiplicativeExpr() { ex = compiler.minus(ex, r); }
        )*
    )
    {
        return ex;
    }
}

/* [26] MultiplicativeExpr ::= UnaryExpr | MultiplicativeExpr MultiplyOperator UnaryExpr
            | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr  */
Object MultiplicativeExpr() :
{
    Object ex, r;
}
{
    (
        ex = UnaryExpr() ( (
            "*"   r = UnaryExpr() { ex = compiler.multiply(ex, r); }
        |   <DIV> r = UnaryExpr() { ex = compiler.divide(ex, r); }
        |   <MOD> r = UnaryExpr() { ex = compiler.mod(ex, r); }
        ) )*
    )
    {
        return ex;
    }
}

/* [27]    UnaryExpr    ::=    UnionExpr  | '-' UnaryExpr  */
Object UnaryExpr() :
{
    Object ex;
}
{
    (
        ex = UnionExpr()
    |    <MINUS> ex = UnaryExpr() { ex = compiler.minus(ex);}
    )
    {
        return ex;
    }
}

/*-------------*/
/* 3.6 Strings */
/*-------------*/

/*----------------------------------*/
/* 3.7 Expression Lexical Structure */
/*----------------------------------*/
/*
The following special tokenization rules must be applied in the order
specified to disambiguate the grammar:

1. If there is a preceding token and the preceding token is not one of
   @, ::, (, [, , or an Operator,
   then a * must be recognized as a MultiplyOperator and an NCName must
   be recognized as an OperatorName.

2. If the character following an NCName (possibly after intervening ExprWhitespace)
   is (, then the token must be recognized as a NodeType or a FunctionName.

3. If the two characters following an NCName (possibly after intervening ExprWhitespace)
   are ::, then the token must be recognized as an AxisName.

4. Otherwise, the token must not be recognized as a MultiplyOperator, an OperatorName,
   a NodeType, a FunctionName, or an AxisName.
*/

/*
[28]    ExprToken    ::=    '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
   | WildcardName  | NodeType  | Operator  | FunctionName  | AxisName  | Literal
   | Number  | VariableReference
*/
/* [34]    MultiplyOperator    ::=    '*'  */

/* [35]    FunctionName    ::=    QName - NodeType   */
Object FunctionName() :
{
    Object qname;
}
{
    qname = QName_Without_CoreFunctions()
    {
        return qname;
    }
}

/* [36]    VariableReference    ::=    '$' QName  */

Object VariableReference() :
{
    Object ex;
}
{
    <VARIABLE> ex = QName()
    {
        return compiler.variableReference(ex);
    }
}

/* [37]    WildcardName    ::=    '*'     | NCName ':' '*'     | QName  */
Object WildcardName() :
{
    Object qn;
    String nc1, nc2 = null;
}
{
    (
        ("*" | NCName()) { nc1 = token.image; }
        (":" ("*" | NCName()) {nc2 = token.image;} )?
    )
    {
        if (nc2 != null){
            qn = compiler.qname(nc1, nc2);
        }
        else {
            qn = compiler.qname(null, nc1);
        }
        return qn;
    }
}

/* [38]    NodeType    ::=    'comment' | 'text'  | 'processing-instruction'  | 'node'  */

int NodeType() :
{
    int type;
}
{
    (
         <TEXT>     { type = Compiler.NODE_TYPE_TEXT; }
    |    <NODE>     { type = Compiler.NODE_TYPE_NODE; }
    |    <COMMENT>  { type = Compiler.NODE_TYPE_COMMENT; }
    |    <PI>       { type = Compiler.NODE_TYPE_PI; }
    )
    {
        return type;
    }
}

