/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 *
 * Initial developer(s): Christophe Ney for France Telecom.
 * Contributor(s):
 *
 * --------------------------------------------------------------------------
 * $Id:EJBQL.jjt 11129 2007-08-03 07:15:41Z durieuxp $
 * --------------------------------------------------------------------------
 */


/**
* This is the JJTree grammar file that was used to generate
* All files of this package
* @author Christophe Ney [cney@batisseurs.com]
* contributor(s):
* - Helene Joanin: Fix the bug about the unary minus operator.
* - Helene Joanin: Add the flag 'third' for operator with optional third operand.
* - Helene Joanin: Add the counter 'opNbEnum' for the IN operator
*                  to count the number of string_literal.
* - Helene Joanin: Add the ORDER BY clause
* - Helene Joanin: Take into account the EJBQL version 2.1 syntax
* - Cyrille Blot:  Add the LIMIT clause
*
**/

options {
  // javacc options
  LOOKAHEAD = 1;
  CHOICE_AMBIGUITY_CHECK = 2;
  OTHER_AMBIGUITY_CHECK = 1;
  STATIC = false;
  DEBUG_PARSER = false;
  DEBUG_LOOKAHEAD = false;
  DEBUG_TOKEN_MANAGER = false;
  ERROR_REPORTING = true;
  JAVA_UNICODE_ESCAPE = false;
  UNICODE_INPUT = false;
  IGNORE_CASE = false;
  USER_TOKEN_MANAGER = false;
  USER_CHAR_STREAM = false;
  BUILD_PARSER = true;
  BUILD_TOKEN_MANAGER = true;
  SANITY_CHECK = true;
  FORCE_LA_CHECK = false;

  // jjtree options
  BUILD_NODE_FILES=true;  // this creates all AST* classes
  MULTI=true;
  VISITOR=true; // create a visitor method
  NODE_FACTORY= false; // build nodes using a factory
  NODE_PACKAGE=""; // package of node classes
  NODE_PREFIX="AST"; //prefix for generated classes
}


PARSER_BEGIN(EJBQL)

package org.ow2.jonas.deployment.ejb.ejbql;

public class EJBQL {
}

PARSER_END(EJBQL)

SimpleNode EJBQL() :
{}
{
 SelectClause() FromClause() ( WhereClause() )? ( OrderByClause() )? ( LimitClause() )? <EOF>
 { return jjtThis; }
}

void FromClause() :
{}
{
 <FROM> IdentificationVariableDeclaration() ( <COMMA> IdentificationVariableDeclaration() )*

}

void IdentificationVariableDeclaration() #void :
{}
{
 CollectionMemberDeclaration() | RangeVariableDeclaration()

}

void CollectionMemberDeclaration() :
{}
{
 <IN> <LPAREN>CollectionValuedPathExpression()<RPAREN> ( <AS> )? Identifier()
}

void RangeVariableDeclaration() :
{}
{
 AbstractSchemaName() ( <AS> )? Identifier()

}

void SingleValuedPathExpression() :
{}
{
 Path()
}

void CmpPathExpression() :
{}
{
 Path()
}

void SingleValuedCmrPathExpression() :
{}
{
 Path()
}

void CollectionValuedPathExpression() :
{}
{
 Path()
}

void SelectClause() :
{}
{
 <SELECT> ( <DISTINCT>{jjtThis.distinct=true;})?
 (SelectExpression() | <OBJECT> <LPAREN>IdentificationVariable()<RPAREN>)

}

void SelectExpression() :
{}
{
  SingleValuedPathExpression() | AggregateSelectExpression()

}

void AggregateSelectExpression() :
{ Token t; }
{
  (
    (t=<AVG> | t=<MAX> | t=<MIN> | t=<SUM>) {jjtThis.ops.add(new Integer(t.kind));}
    <LPAREN>
    ( <DISTINCT> {jjtThis.distinct=true;} )?
    CmpPathExpression()
    <RPAREN>
  )
  |
  (
    (t=<COUNT>) {jjtThis.ops.add(new Integer(t.kind));}
    <LPAREN>
    ( <DISTINCT> {jjtThis.distinct=true;} )?
    ( LOOKAHEAD(SingleValuedPathExpression()) SingleValuedPathExpression() | IdentificationVariable() )
    <RPAREN>
  )
}

void OrderByClause() :
{}
{
 <ORDERBY> OrderByItem() ( <COMMA> OrderByItem() )*
}

void OrderByItem() :
{}
{
 CmpPathExpression() ( <ASC> {jjtThis.asc=true;}| <DESC> {jjtThis.asc=false;} )?
}

void LimitClause() :
{}
{
 <LIMIT> LimitExpression() ( <COMMA> LimitExpression() )?
}

void LimitExpression() :
{}
{
 IntegerLiteral() | InputParameter()
}

void WhereClause() :
{}
{
 <WHERE> ConditionalExpression()

}

void ConditionalExpression() :
{}
{
 ConditionalTerm() (<OR> ConditionalTerm())*
}

void ConditionalTerm() :
{}
{
 ConditionalFactor() (<AND> ConditionalFactor())*
}

void ConditionalFactor() :
{}
{
 (<NOT> { jjtThis.not=true; })? ConditionalPrimary()
}

void ConditionalPrimary() #void :
{}
{
 LOOKAHEAD(SimpleCondExpression())
    SimpleCondExpression()
 | LOOKAHEAD(<LPAREN>ConditionalExpression()<RPAREN>)
    <LPAREN>ConditionalExpression()<RPAREN>
}

void SimpleCondExpression() #void :
{}
{
 LOOKAHEAD(ComparisonExpression())ComparisonExpression()
 | LOOKAHEAD(BetweenExpression())BetweenExpression()
 | LOOKAHEAD(LikeExpression())LikeExpression()
 | LOOKAHEAD(InExpression())InExpression()
 | LOOKAHEAD(NullComparisonExpression())NullComparisonExpression()
 | LOOKAHEAD(EmptyCollectionComparisonExpression())EmptyCollectionComparisonExpression()
 | LOOKAHEAD(CollectionMemberExpression())CollectionMemberExpression()

}

void BetweenExpression() :
{}
{
 ArithmeticExpression() ( <NOT> { jjtThis.not=true; })?
    <BETWEEN> ArithmeticExpression() <AND> ArithmeticExpression()
}

void InExpression() :
{}
{
 CmpPathExpression() ( <NOT> { jjtThis.not=true; })?
    <IN> <LPAREN> (Literal() | InputParameter()) { jjtThis.eltnum=1; }
         ( <COMMA> (Literal() | InputParameter()) { jjtThis.eltnum++; } )* <RPAREN>
}

void LikeExpression() :
{}
{
 CmpPathExpression() ( <NOT> { jjtThis.not=true; })?
    <LIKE> PatternValue() ( <ESCAPE> { jjtThis.third=true; } EscapeCharacter() )?
}

void NullComparisonExpression() :
{}
{
 ( SingleValuedPathExpression() | InputParameter() ) <IS>
    ( <NOT> { jjtThis.not=true; })? <NULL>
}

void EmptyCollectionComparisonExpression() :
{}
{
 CollectionValuedPathExpression() <IS>
    ( <NOT> { jjtThis.not=true; })? <EMPTY>
}

void CollectionMemberExpression() :
{}
{
 (LOOKAHEAD(2)SingleValuedCmrPathExpression()
 | LOOKAHEAD(2)IdentificationVariable()
 | InputParameter())
   ( <NOT> { jjtThis.not=true; })? <MEMBER> ( <OF> )? CollectionValuedPathExpression()
}

void ComparisonExpression() :
{Token t;}
{
 LOOKAHEAD(StringValue() (<EQ> | <GT> | <GE> | <LT> | <LE> | <NE>) StringExpression())
    (StringValue() (t=<EQ> |t=<GT> |t=<GE> |t=<LT> |t=<LE> |t=<NE>){jjtThis.ops.add(new Integer(t.kind));} StringExpression())
 | LOOKAHEAD(BooleanValue() (<EQ>|<NE>) BooleanExpression())
    (BooleanValue() (t=<EQ>|t=<NE>){jjtThis.ops.add(new Integer(t.kind));} BooleanExpression())
 | LOOKAHEAD(DatetimeValue() (<EQ> | <GT> | <GE> | <LT> | <LE> | <NE>) DatetimeExpression())
    (DatetimeValue() (t=<EQ> |t=<GT> |t=<GE> |t=<LT> |t=<LE> |t=<NE>){jjtThis.ops.add(new Integer(t.kind));} DatetimeExpression())
 | LOOKAHEAD(EntityBeanValue() (<EQ>|<NE>) EntityBeanExpression())
    (EntityBeanValue() (t=<EQ>|t=<NE>){jjtThis.ops.add(new Integer(t.kind));} EntityBeanExpression())
 | LOOKAHEAD(ArithmeticValue() (<EQ> | <GT> | <GE> | <LT> | <LE> | <NE>) ArithmeticExpression())
    (ArithmeticValue() (t=<EQ> |t=<GT> |t=<GE> |t=<LT> |t=<LE> |t=<NE>){jjtThis.ops.add(new Integer(t.kind));} ArithmeticExpression())


}

void ArithmeticValue() #void :
{}
{
 CmpPathExpression() | FunctionsReturningNumerics()
}

void ArithmeticExpression() :
{ Token t;}
{
 ArithmeticTerm() ((t=<PLUS>|t=<MINUS>){jjtThis.ops.add(new Integer(t.kind));} ArithmeticTerm() )*
}

void ArithmeticTerm() :
{ Token t;}
{
 ArithmeticFactor() ((t=<MULT>|t=<DIV>){jjtThis.ops.add(new Integer(t.kind));} ArithmeticFactor() )*

}

void ArithmeticFactor() :
{Token t=null;}
{
 (t=<PLUS>|t=<MINUS>)? ArithmeticPrimary()
   {
    jjtThis.ops.add(new Integer((t!=null)?t.kind:EJBQLConstants.PLUS));
   }
}

void ArithmeticPrimary() #void :
{}
{
 CmpPathExpression() | ArithmeticLiteral() | <LPAREN>ArithmeticExpression()<RPAREN>
 | InputParameter() | FunctionsReturningNumerics()

}

void StringValue() #void :
{}
{
 CmpPathExpression() | FunctionsReturningStrings()

}

void StringExpression() :
{}
{
 StringPrimary() | InputParameter()

}

void StringPrimary() #void :
{}
{
 CmpPathExpression() | StringLiteral() | <LPAREN>StringExpression()<RPAREN> | FunctionsReturningStrings()
}

void DatetimeValue() #void :
{}
{
 CmpPathExpression()
}

void DatetimeExpression() :
{}
{
 DatetimeValue() | InputParameter()
}

void BooleanValue() #void :
{}
{
 CmpPathExpression()
}

void BooleanExpression() :
{Token t=null;}
{
 CmpPathExpression() | BooleanLiteral() | InputParameter()
   {
   if (t!=null) jjtThis.ops.add(new Integer(t.kind));
   }
}

void EntityBeanValue() #void :
{}
{
 (LOOKAHEAD(2)SingleValuedCmrPathExpression() | LOOKAHEAD(2)IdentificationVariable())

}

void EntityBeanExpression() :
{}
{
 EntityBeanValue() | InputParameter()

}

void FunctionsReturningStrings() :
{ Token t;}
{
 t=<CONCAT>{jjtThis.ops.add(new Integer(t.kind));} <LPAREN>StringExpression()<COMMA> StringExpression()<RPAREN>
 | t=<SUBSTRING>{jjtThis.ops.add(new Integer(t.kind));} <LPAREN>StringExpression()<COMMA> ArithmeticExpression()<COMMA> ArithmeticExpression()<RPAREN>

}

void FunctionsReturningNumerics() :
{Token t;}
{
 t=<LENGTH>{jjtThis.ops.add(new Integer(t.kind));} <LPAREN>StringExpression()<RPAREN>
 | t=<LOCATE>{jjtThis.ops.add(new Integer(t.kind));}<LPAREN>StringExpression()<COMMA> StringExpression() ( <COMMA> { jjtThis.third=true; } ArithmeticExpression() )? <RPAREN>
 | t=<ABS>{jjtThis.ops.add(new Integer(t.kind));}<LPAREN>ArithmeticExpression()<RPAREN>
 | t=<SQRT>{jjtThis.ops.add(new Integer(t.kind));}<LPAREN>ArithmeticExpression()<RPAREN>
 | t=<MOD>{jjtThis.ops.add(new Integer(t.kind));}<LPAREN>ArithmeticExpression()<COMMA>ArithmeticExpression()<RPAREN>
}

void PatternValue() #void :
{}
{
 StringLiteral() | InputParameter()
}

void EscapeCharacter() #void :
{}
{
 StringLiteral()
}


void AbstractSchemaName() :
{ Token t; }
{
 t=<IDENTIFIER>
   {
      jjtThis.value= t.image;
   }
}

void IdentificationVariable() :
{ Token t; }
{
 t=<IDENTIFIER>
   {
      jjtThis.value= t.image;
   }
}

void Identifier() :
{ Token t; }
{
 t=<IDENTIFIER>
   {
      jjtThis.value= t.image;
   }
}

void Path() :
{Token t;
}
{
 t=<IDENTIFIER>{jjtThis.value= t.image;}
 <DOT>t=<IDENTIFIER>{jjtThis.value = jjtThis.value + "."+t.image;}
 (<DOT>t=<IDENTIFIER>{jjtThis.value = jjtThis.value + "."+t.image;})*
}

void Literal():
{}
{
 StringLiteral() | ArithmeticLiteral() | BooleanLiteral()
}

void StringLiteral():
{ Token t; }
{
 t=<string_literal>
   {
      jjtThis.value= t.image.substring(1,t.image.length()-1);
   }
}

void ArithmeticLiteral():
{}
{
 IntegerLiteral() | FloatingPointLiteral()
}

void IntegerLiteral():
{ Token t; }
{
 t=<INTEGER_LITERAL>{jjtThis.value= new Long(t.image);}
}

void FloatingPointLiteral():
{ Token t; }
{
 t=<FLOATING_POINT_LITERAL>{jjtThis.value= new Double(t.image);}
}

void BooleanLiteral() :
{Token t;}
{
 t=<TRUE>{jjtThis.value= Boolean.TRUE;}
 |t=<FALSE>{jjtThis.value= Boolean.FALSE;}
}


void InputParameter():
{ Token t; }
{
 t=<input_parameter>
   {
      jjtThis.value= new Integer(t.image.substring(1));
   }
}


/************** TOKENS **************/

SKIP : /* White Spaces */
{
  " "
| "\t"
| "\n"
| "\r"
}


TOKEN : /* predefined */
{
 < MINUS: "-" >
| < MULT: "*" >
| < GE: ">=" >
| < PLUS: "+" >
| < EQ: "=" >
| < LE: "<=" >
| < DIV: "/" >
| < DOT: "." >
| < GT: ">" >
| < COMMA: "," >
| < RPAREN: ")" >
| < NE: "<>" >
| < LPAREN: "(" >
| < LT: "<" >
}


TOKEN [IGNORE_CASE] : /* used in BNF */
{
 < ABS: "ABS" >
| < AND: "AND" >
| < AS: "AS" >
| < ASC: "ASC" >
| < AVG: "AVG" >
| < BETWEEN: "BETWEEN" >
| < CONCAT: "CONCAT" >
| < COUNT: "COUNT" >
| < DESC: "DESC" >
| < DISTINCT: "DISTINCT" >
| < EMPTY: "EMPTY" >
| < ESCAPE: "ESCAPE" >
| < FROM: "FROM" >
| < IN: "IN" >
| < IS: "IS" >
| < LENGTH: "LENGTH" >
| < LIKE: "LIKE" >
| < LIMIT: "LIMIT" >
| < LOCATE: "LOCATE" >
| < MAX: "MAX" >
| < MEMBER: "MEMBER" >
| < MIN: "MIN" >
| < MOD: "MOD" >
| < NOT: "NOT" >
| < NULL: "NULL" >
| < OBJECT: "OBJECT" >
| < OF: "OF" >
| < OR: "OR" >
| < ORDERBY: "ORDER BY" >
| < SELECT: "SELECT" >
| < SQRT: "SQRT" >
| < SUBSTRING: "SUBSTRING" >
| < SUM: "SUM" >
| < WHERE: "WHERE" >
}

<DEFAULT> TOKEN [IGNORE_CASE] : /* String Literal */
{
   < string_literal: "'" (~["'"])* ( "''" (~["'"])* )* "'" >
    | < input_parameter: "?"["1"-"9"] (["0"-"9"])*  >
    | < FALSE: "FALSE" > |  < TRUE: "TRUE" >
}

<DEFAULT> TOKEN : /* Numeric Literal */
{
   < INTEGER_LITERAL:
      <DECIMAL_LITERAL> (["l","L"])?
      | <HEX_LITERAL> (["l","L"])?
      | <OCTAL_LITERAL> (["l","L"])?
   >
|
   < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
|
   < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
|
   < #OCTAL_LITERAL: "0" (["0"-"7"])* >
|
   < FLOATING_POINT_LITERAL:
      (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
   >
|
   < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
}

<DEFAULT> TOKEN : /* identifiers */
{
  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
|
  < #LETTER:
      [
       "\u0024",
       "\u0041"-"\u005a",
       "\u005f",
       "\u0061"-"\u007a",
       "\u00c0"-"\u00d6",
       "\u00d8"-"\u00f6",
       "\u00f8"-"\u00ff",
       "\u0100"-"\u1fff",
       "\u3040"-"\u318f",
       "\u3300"-"\u337f",
       "\u3400"-"\u3d2d",
       "\u4e00"-"\u9fff",
       "\uf900"-"\ufaff"
      ]
  >
|
  < #DIGIT:
      [
       "\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",
       "\u1040"-"\u1049"
      ]
  >
}


