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

%ab HexDigit        : [0-9a-fA-F];
%ab Digit           : [0-9];
%ab OctalDigit      : [0-7];
%ab TetraDigit      : [0-3];
%ab NonZeroDigit    : [1-9];
%ab Letter          : [a-zA-Z_];
%ab AnyButSlash     : [^/];
%ab AnyButAstr      : [^*];
%ab UniEsc          : [\u0001];

%ab OctEscape1      : "\\" OctalDigit;
%ab OctEscape2      : "\\" OctalDigit OctalDigit;
%ab OctEscape3      : "\\" TetraDigit OctalDigit OctalDigit;
%ab OctEscape       : OctEscape1 | OctEscape2 | OctEscape3;

%ab Escape          : [\\] [rnbft\\'"];
%ab ULetter         : Letter | UniEsc;
Identifier          : ULetter ( ULetter Digit )*;

%ab IntSuffix       : "l" | "L";
%ab DecimalNum      : NonZeroDigit Digit* IntSuffix? ;
%ab OctalNum        : "0" OctalDigit* IntSuffix? ;
%ab HexNum          : "0" ("x"|"X") HexDigit HexDigit* IntSuffix? ;
%ab IntegerLiteral  : DecimalNum | OctalNum | HexNum;
                                                                                                                                                                               
%ab Sign            : "+" | "-";
%ab FlSuffix        : "f" | "F" | "d" | "D";
%ab SignedInt       : Sign? Digit+ ;
%ab Expo            : "e" | "E" ;
%ab ExponentPart    : Expo SignedInt? ;
%ab Float1          : Digit+ "." (Digit+)? ExponentPart? FlSuffix?;
%ab Float2          : "." Digit+ ExponentPart? FlSuffix? ;
%ab Float3          : Digit+ ExponentPart FlSuffix? ;
%ab Float4          : Digit+ FlSuffix ;
%ab FloatingPoint   : Float1 | Float2 | Float3 | Float4 ;

%ab AnyChrChr       : [^\\'] ;
%ab AnyStrChr       : [^\\"] ;
%ab Character       : "'" (Escape | OctEscape | AnyChrChr)  "'" ;
%ab String          : "\"" (Escape | OctEscape | AnyStrChr)* "\"";
%ab Numeric         : IntegerLiteral | FloatingPoint ;

LITERAL         : Numeric | Character | String ;

IDENTIFIER      : ([a-zA-Z_] | [\u0001]) (([a-zA-Z_] | [\u0001]) | [0-9])*;

OP_DIM          : "[" ([\r\n\t\ ] | ( "/" "\*" ([^\*] | "\*" [^/])* "\*" "/" |
                  "//" (.*)))* "]";

%ab SPACES          : " "+;
%ab TAB             : "\t";
%ab EOL             : "\r" "\n"? | "\n" ;
// JAVADOC           : "/**" ([^*] | [*] [^/])* "*/";

JAVADOC : "/**" Description Property+ "*/";

Description : ([\*\n\r\ \t]+ | DescriptionText)* ;
DescriptionText : [A-Za-z<>%]+ ([\ \t]+ [A-Za-z<>%]+)* ;
Property : "@" PropertyIdentifier [\ \t]+ Description ;
PropertyIdentifier : [A-Za-z]+ ;

%ab MULTILINECOMMENT  : "/*" [^*] ([^*] | "*" [^/])* "*/";
%ab SINGLELINECOMMENT : "//" (.*);

WS : (SPACES|TAB|EOL|JAVADOC|MULTILINECOMMENT|SINGLELINECOMMENT)*
   ;

%start CompilationUnit;

TypeSpecifier
  : TypeName Dims?
  ;

TypeName
  : PrimitiveType
  | QualifiedName
  ;

ClassNameList
  : QualifiedName (WS "," WS QualifiedName)*
  ;

PrimitiveType
  : "boolean"
  | "char"
  | "byte"
  | "short"
  | "int"
  | "long"
  | "float"
  | "double"
  | "void"
  ;

SemiColons
  : ";"
  | SemiColons ";"
  ;

CompilationUnit
  : ProgramFile
  ;

ProgramFile
  :  WS PackageStatement   (WS ImportStatements)? (WS TypeDeclarations)? WS
  | (WS PackageStatement)?  WS ImportStatements   (WS TypeDeclarations)? WS
  | (WS PackageStatement)? (WS ImportStatements)?  WS TypeDeclarations   WS
  ;

PackageStatement
  : "package" WS QualifiedName WS SemiColons
  ;

TypeDeclarations
  : TypeDeclarationOptSemi+
  ;

TypeDeclarationOptSemi
  : TypeDeclaration SemiColons?
  ;

ImportStatements
  : ImportStatement (WS ImportStatement)*
  ;

ImportStatement
  : "import" WS QualifiedName ("." "*")? WS SemiColons
  ;

QualifiedName
  : IDENTIFIER ("." IDENTIFIER)*
  ;

TypeDeclaration
  : ClassHeader WS "{" (WS FieldDeclarations)? WS "}"
  ;

ClassHeader
  : (Modifiers WS)? ClassWord WS IDENTIFIER (WS Extends)? (WS Interfaces)?
  ;

Modifiers
  : Modifier ( WS Modifier )*
  ;

Modifier
  : "abstract"
  | "final"
  | "public"
  | "protected"
  | "private"
  | "static"
  | "transient"
  | "volatile"
  | "native"
  | "synchronized"
  ;

ClassWord
  : "class"
  | "interface"
  ;

Interfaces
  : "implements" WS ClassNameList
  ;

FieldDeclarations
  : FieldDeclaration ((WS SemiColons)? WS FieldDeclaration)*
  ;

FieldDeclaration
  : FieldVariableDeclaration WS ";"
  | MethodDeclaration
  | ConstructorDeclaration
  | StaticInitializer
  | NonStaticInitializer
  | TypeDeclaration
  ;

FieldVariableDeclaration
  : (Modifiers WS)? TypeSpecifier WS VariableDeclarators
  ;

VariableDeclarators
  : VariableDeclarator (WS "," WS VariableDeclarator)*
  ;

VariableDeclarator
  : DeclaratorName (WS "=" WS VariableInitializer)?
  ;

VariableInitializer
  : Expression
  | "{" (WS ArrayInitializers)? WS "}"
  ;

ArrayInitializers
  : VariableInitializer (WS "," WS VariableInitializer)*
  ;

MethodDeclaration
  : (Modifiers WS)? TypeSpecifier WS MethodDeclarator (WS Throws)? WS MethodBody
  ;

MethodDeclarator
  : DeclaratorName WS "(" (WS ParameterList)? WS ")"
  | MethodDeclarator OP_DIM
  ;

ParameterList
  : Parameter (WS "," WS Parameter)*
  ;

Parameter
  : "final"? TypeSpecifier WS DeclaratorName
  ;

DeclaratorName
  : IDENTIFIER
  | DeclaratorName OP_DIM
  ;

Throws
  : "throws" WS ClassNameList
  ;

MethodBody
  : Block
  | ";"
  ;

ConstructorDeclaration
  : Modifiers? ConstructorDeclarator Throws? Block
  ;

ConstructorDeclarator
  : IDENTIFIER "(" ParameterList? ")"
  ;

StaticInitializer
  : "static" Block
  ;

NonStaticInitializer
  : Block
  ;

Extends
  : "extends" TypeName ("," TypeName)*
  ;

Block
  : "{" (WS LocalVariableDeclarationsAndStatements)? WS "}"
  ;

LocalVariableDeclarationsAndStatements
  : LocalVariableDeclarationOrStatement (WS LocalVariableDeclarationOrStatement)*
  ;

LocalVariableDeclarationOrStatement
  : LocalVariableDeclarationStatement
  | Statement
  ;

LocalVariableDeclarationStatement
  : ("final" WS)? TypeSpecifier WS VariableDeclarators ";"
  ;

Statement
  : EmptyStatement
  | LabelStatement
  | ExpressionStatement ";"
  | SelectionStatement
  | IterationStatement
  | JumpStatement
  | GuardingStatement
  | Block
  ;

EmptyStatement
  : ";"
  ;

LabelStatement
  : IDENTIFIER ":"
  | "case" ConstantExpression ":"
  | "default" ":"
  ;

ExpressionStatement
  : Expression
  ;

SelectionStatement
  : "if" WS "(" WS Expression WS ")" WS Statement 
  | "if" WS "(" WS Expression WS ")" WS Statement WS "else" WS Statement
  | "switch" WS "(" WS Expression WS ")" WS Block
  ;

IterationStatement
  : "while" WS "(" WS Expression WS ")" WS Statement
  | "do" WS Statement WS "while" WS "(" WS Expression WS ")" WS ";"
  | "for" WS "(" WS ForInit WS ForExpr WS ForIncr WS ")" WS Statement
  | "for" WS "(" WS ForInit WS ForExpr            WS ")" WS Statement
  ;

ForInit
  : ExpressionStatements WS ";"
  | LocalVariableDeclarationStatement
  | ";"
  ;

ForExpr
  : Expression WS ";"
  | ";"
  ;

ForIncr
  : ExpressionStatements
  ;

ExpressionStatements
  : ExpressionStatement (WS "," WS ExpressionStatement)* 
  ;

JumpStatement
  : "break"    (WS IDENTIFIER)? WS ";"
  | "continue" (WS IDENTIFIER)? WS ";"
  | "return"   (WS Expression)? WS ";"
  | "throw"     WS Expression   WS ";"
  ;

GuardingStatement
  : "synchronized" WS "(" WS Expression WS ")" WS Statement
  | "try" WS Block             WS Finally
  | "try" WS Block WS Catches (WS Finally)?
  ;

Catches
  : Catch (WS Catch)*
  ;

Catch
  : CatchHeader WS Block
  ;

CatchHeader
  : "catch" WS "(" WS TypeSpecifier (WS IDENTIFIER)? WS ")"
  ;

Finally
  : "finally" WS Block
  ;

PrimaryExpression
  : QualifiedName 
  | NotJustName 
  ;

NotJustName
  : SpecialName 
  | NewAllocationExpression 
  | ComplexPrimary 
  ;

ComplexPrimary
  : "(" WS Expression WS ")"
  | ComplexPrimaryNoParenthesis 
  ;

ComplexPrimaryNoParenthesis
  : LITERAL
  | "true" | "false"
  | ArrayAccess
  | FieldAccess
  | MethodCall
  ;

ArrayAccess
  : QualifiedName  WS "[" WS Expression WS "]"
  | ComplexPrimary WS "[" WS Expression WS "]"
  ;

FieldAccess
  : NotJustName "." IDENTIFIER
  | RealPostfixExpression "." IDENTIFIER
  | QualifiedName "." "this"
  | QualifiedName "." "class"
  | PrimitiveType "." "class"
  ;

MethodCall
  : MethodAccess WS "(" (WS ArgumentList)? WS ")"
  ;

MethodAccess
  : ComplexPrimaryNoParenthesis
  | SpecialName
  | QualifiedName
  ;

SpecialName
  : "this"
  | "super"
  | "null"
  ;

ArgumentList
  : Expression (WS "," WS Expression)*
  ;

NewAllocationExpression
  : (QualifiedName ".")? PlainNewAllocationExpression
  ;

PlainNewAllocationExpression
   : ArrayAllocationExpression (WS "{" (WS ArrayInitializers)? WS "}")?
   | ClassAllocationExpression (WS "{" (WS FieldDeclarations)? WS "}")?
   ;

ClassAllocationExpression
  : "new" WS TypeName WS "(" (WS ArgumentList)? WS ")"
  ;

ArrayAllocationExpression
  : "new" WS TypeName WS DimExprs (WS Dims)?
  | "new" WS TypeName WS Dims
  ;

DimExprs
  : DimExpr+
  ;

DimExpr
  : "[" WS Expression WS "]"
  ;

Dims
  : OP_DIM+
  ;

PostfixExpression
  : PrimaryExpression 
  | RealPostfixExpression 
  ;

RealPostfixExpression
  : PostfixExpression WS ("++"|"--")
  ;

UnaryExpression
  : ("++"|"--") UnaryExpression
  | ("+"|"-")   CastExpression
  | LogicalUnaryExpression 
  ;

LogicalUnaryExpression
  : PostfixExpression 
  | ("~"|"!") UnaryExpression
  ;

CastExpression
  : UnaryExpression 
  | "(" WS PrimitiveTypeExpression WS ")" WS CastExpression
  | "(" WS ClassTypeExpression WS ")" WS CastExpression
  | "(" WS Expression WS ")" WS LogicalUnaryExpression
  ;

PrimitiveTypeExpression
  : PrimitiveType Dims?
  ;

ClassTypeExpression
  : QualifiedName Dims
  ;

MultiplicativeExpression
  : CastExpression (WS ("*"|"/"|"%") WS CastExpression)*
  ;

AdditiveExpression
  : MultiplicativeExpression (WS ("+"|"-") WS MultiplicativeExpression)*
  ;

ShiftExpression 
  : AdditiveExpression (WS ("<<"|">>"|">>>") WS AdditiveExpression)*
  ;

RelationalExpression
  : ShiftExpression (WS ("<"|">"|"<="|">=") WS ShiftExpression)*
  | RelationalExpression WS "instanceof" WS TypeSpecifier
  ;

EqualityExpression
  : RelationalExpression  (WS ("==" | "!=") WS RelationalExpression)*
  ;

AndExpression
  : EqualityExpression (WS "&" WS EqualityExpression)*
  ;

ExclusiveOrExpression
  : AndExpression (WS "^" WS AndExpression)*
  ;

InclusiveOrExpression
  : ExclusiveOrExpression (WS "|" WS ExclusiveOrExpression)*
  ;

ConditionalAndExpression
  : InclusiveOrExpression (WS "&&" WS InclusiveOrExpression)*
  ;

ConditionalOrExpression
  : ConditionalAndExpression (WS "||" WS ConditionalAndExpression)*
  ;

ConditionalExpression
  : ConditionalOrExpression 
  | ConditionalOrExpression "?" Expression ":" ConditionalExpression
  ;

AssignmentExpression
  : ConditionalExpression 
  | UnaryExpression WS AssignmentOperator WS AssignmentExpression
  ;

AssignmentOperator
  : "="
  | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" | "%=" | "<<=" | ">>=" | ">>>="
  ;

Expression
  : AssignmentExpression
  ;

ConstantExpression
  : ConditionalExpression
  ;
 
