:-load_library('alice.tuprolog.lib.TokenizerLibrary').
:-load_library('alice.tuprolog.lib.BNFParserLibrary').

%TOKENIZER
skiplist ['(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)','\n','\s','@.*'].

tokenlist [assert,abstract,boolean,break,byte,case,catch,char,class,const,continue].
tokenlist [default,do,double,else,extends,false,finally,final,float,for,goto].
tokenlist [if,implements,import,instanceof,int,interface,long,native].
tokenlist [new,null,package,private,protected,public,return,short,static].
tokenlist [strictfp,super,switch,synchronized,this,throw,throws,transient,true].
tokenlist [try,void,volatile,while].

type decimal : '([1-9][0-9]*)|(0)'.
type hexadecimal : '0[xX][0-9a-fA-F]+'.
type octal : '0[0-7]+'.
type fraction : '[0-9]+\.[0-9]*([eE][\+-]?[0-9]+)?'.
type string : '\".*\"'.
type character : "''.''".
type literal : '[a-zA-Z[_]][a-zA-Z0-9[_]]*'.

token '(' becomes lpar.
token ')' becomes rpar.
token '{' becomes lbrace.
token '}' becomes rbrace.
token '[' becomes lbracket.
token ']' becomes rbracket.
token ';' becomes semicolon.
token ',' becomes comma.
token '.' becomes dot.
token '<=' becomes le.
token '>=' becomes ge.
token '==' becomes eq.
token '!=' becomes ne.
token '=' becomes assign.
token '<<=' becomes lshiftassign.
token '>>>=' becomes runsignedshiftassign.
token '>>=' becomes rsignedshiftassign.
%token '>>>' becomes runsignedshift.
%token '>>' becomes rsignedshift.
%token '<<' becomes lshift.
token '>' becomes gt.
token '<' becomes lt.
token '!' becomes bang.
token '~' becomes tilde.
token '?' becomes hook.
token ':' becomes colon.
token '||' becomes sc_or.
token '&&' becomes sc_and.
token '+=' becomes plusassign.
token '-=' becomes minusassign.
token '*=' becomes starassign.
token '/=' becomes slashassign.
token '&=' becomes andassign.
token '|=' becomes orassign.
token '^=' becomes xorassign.
token '%=0' becomes remassign.
token '++' becomes incr.
token '--' becomes decr.
token '+' becomes plus.
token '-' becomes minus.
token '*' becomes star.
token '/' becomes slash.
token '&' becomes bit_and.
token '|' becomes bit_or.
token '^' becomes xor.
token '%' becomes rem.

%PARSER
identifier::=
	[literal(_)].
map literal(X) : X.

qualified_identifier::=
	identifier,identifier_rest.
map qualified_identifier(identifier(X),L) : Z :- string_append(X,L,Z).

identifier_rest ::= [] or 
	[dot],identifier,identifier_rest.
map identifier_rest : ''.
map identifier_rest(_,identifier(X),L): Y :- string_append('.',X,X1),string_append(X1,L,Y).

literal::=
	[decimal(_)] or 
	[octal(_)] or 
	[hexadecimal(_)] or 	
	[fraction(_)] or 	
	[character(_)] or 	
	[string(_)] or 	
	[true] or 
	[false] or
	[null].

expression_opt ::= [] or 
	expression.
dont_gen_node expression_opt.

expression::=
	expression1,assign_opt.
dont_gen_single_node expression.

map expression(X,assign_opt(Y,Z)) : W :- W=..[Y,X,Z].

assign_opt ::= 
	assignment_operator, expression1 or 
	[].
dont_gen_if_void assign_opt.

assignment_operator ::= 
	[assign] or 
	[plusassign] or 
	[minusassign] or 
	[starassign] or 
	[slashassign] or 
	[andassign] or 
	[orassign] or 
	[xorassign] or 
	[remassign] or 
	[lshiftassign] or 
	[rsignedshiftassign] or 
	[runsignedshiftassign].
map assignment_operator(X) : X.

type1::=
	identifier, type_arguments_opt,type_rest, brackets_opt or
	basic_type.
map type1(X) : type(X).
map type1(identifier(X),Y,Z,W) : type(R) :- string_append(X,Y,X1),string_append(X1,Z,X2),string_append(X2,W,R).

type_rest ::= 
	[] or 
	[dot],identifier,type_arguments_opt,type_rest.
map type_rest : ''.
map type_rest(_,identifier(X),Y,Z) : R :- string_append('.',X,X1),string_append(X1,Y,X2),string_append(X2,Z,R).	

type_arguments_opt ::= 
	[] or 
	type_arguments.
map type_arguments_opt : ''.
dont_gen_single_node type_arguments_opt.

type_arguments ::= 
	[lt],type_argument,type_arguments_rest,[gt].
map type_arguments(_,X,Y,_) : R :- string_append('<',X,X1),string_append(X1,Y,X2),string_append(X2,'>',R).

type_arguments_rest ::= 
	[comma],type_argument,type_arguments_rest or 
	[].
map type_arguments_rest : ''.
map type_arguments_rest(_,X,Z) : R :- string_append(',',X,X1),string_append(X1,Z,R).

type_argument ::= 
	type1 or
	[hook],type_argument_suffix.
map type_argument(type(X)) : X.
map type_argument(_,X) : R :- string_append('?',X,R).

type_argument_suffix ::= 
	[extends],type1 or
	[super],type1 or
	[].
map type_argument_suffix(X,type(Y)) : Z :- string_append(X,Y,Z).
map type_argument_suffix : ''.

statement_expression::=
	expression.
dont_gen_single_node statement_expression.

constant_expression::= 
	expression.
dont_gen_single_node constant_expression.

expression1::= 
	expression2, expression1_rest.
dont_gen_single_node expression1.
map expression1(E,expression1_rest(_,E1,_,E2)) : mark_colon(E,E1,E2).

expression1_rest::= 
	[] or  
	[hook], expression,   [colon],   expression1.
dont_gen_if_void expression1_rest.

%expression2 ::=
%	expression3,instance_or_infix.
%dont_gen_single_node expression2.
%map expression2(E,expression2_rest(infixop(X),E2)) : infixop(X,E,E2).
%map expression2(E,instance_or_infix(instanceof,T)) : instanceof(T,E).
%map expression2(E,instance_or_infix(instanceof,T,E2)) : instanceof(T,E,E2).

%instance_or_infix ::=  %questa parte è modificata rispetto alla java language specification da verificare...
%	expression2_rest or 
%	[instanceof],type1,expression2_rest.
%dont_gen_single_node instance_or_infix.
%dont_gen_if_void instance_or_infix.

expression2 ::= equals_exp, bool_exp_rest.
dont_gen_single_node expression2.
map expression2(X,bool_exp_rest(bool_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

bool_exp_rest ::= bool_infix_op,equals_exp,bool_exp_rest or
	[].
dont_gen_if_void bool_exp_rest.
map bool_exp_rest(Z,X,bool_exp_rest(bool_infix_op(OP),Y)) : bool_exp_rest(Z,B) :- B=..[OP,X,Y].

bool_infix_op ::= [sc_and] or [sc_or].

equals_exp ::= compare_exp,equals_exp_rest.
dont_gen_single_node equals_exp.
map equals_exp(X,equals_exp_rest(equals_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

equals_exp_rest ::= equals_infix_op,compare_exp,equals_exp_rest or 
	[].
dont_gen_if_void equals_exp_rest.
map equals_exp_rest(Z,X,equals_exp_rest(equals_infix_op(OP),Y)) : equals_exp_rest(Z,B) :- B=..[OP,X,Y].

equals_infix_op ::= [eq] or 
	[ne].

compare_exp ::= add_exp, compare_exp_rest.
dont_gen_single_node compare_exp.
map compare_exp(X,compare_exp_rest(compare_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

compare_exp_rest ::= compare_infix_op,add_exp,compare_exp_rest or 
	[].
dont_gen_if_void compare_exp_rest.
map compare_exp_rest(Z,X,compare_exp_rest(compare_infix_op(OP),Y)) : compare_exp_rest(Z,B) :- B=..[OP,X,Y].

compare_infix_op ::= [gt] or 
	[lt] or 
	[ge] or 
	[le].


add_exp ::= mul_exp,add_exp_rest.
dont_gen_single_node add_exp.
map add_exp(X,add_exp_rest(add_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

add_exp_rest ::= add_infix_op,mul_exp,add_exp_rest or [].
dont_gen_if_void add_exp_rest.
map add_exp_rest(Z,X,add_exp_rest(add_infix_op(OP),Y)) : add_exp_rest(Z,B) :- B=..[OP,X,Y].

add_infix_op ::= [plus] or [minus].

mul_exp ::= bit_exp,mul_exp_rest.
dont_gen_single_node mul_exp.
map mul_exp(X,mul_exp_rest(mul_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

mul_exp_rest ::= mul_infix_op,bit_exp,mul_exp_rest or [].
dont_gen_if_void mul_exp_rest.
map mul_exp_rest(Z,X,mul_exp_rest(mul_infix_op(OP),Y)) : mul_exp_rest(Z,MUL) :- MUL=..[OP,X,Y].

mul_infix_op ::= [rem] or 
	[slash] or 
	[star].

bit_exp ::= instanceof_exp, bit_exp_rest.
dont_gen_single_node bit_exp.
map bit_exp(X,bit_exp_rest(bit_infix_op(OP),Y)) : Z :- Z=..[OP,X,Y].

bit_exp_rest ::= bit_infix_op, instanceof_exp,bit_exp_rest or [].
dont_gen_if_void bit_exp_rest.
map bit_exp_rest(Z,X,bit_exp_rest(bit_infix_op(OP),Y)) : bit_exp_rest(Z,B) :- B=..[OP,X,Y].

bit_infix_op ::= 
	[bit_or] or 
	[xor] or 
	[bit_and] or
	[lt],[lt] or
	[gt],[gt],[gt] or
	[gt],[gt].
map bit_infix_op(lt,lt) : bit_infix_op(lshift).
map bit_infix_op(gt,gt,gt) : bit_infix_op(runsignedshift).
map bit_infix_op(gt,gt) : bit_infix_op(rsignedshift).

%expression2_rest ::= [] or
%	infixop,instanceof_exp,expression2_rest.

instanceof_exp ::= expression3,instanceof_opt.
dont_gen_single_node instanceof_exp.
map instanceof_exp(E,instanceof,T) : instanceof(E,T).

instanceof_opt ::= [] or
	[instanceof],type1.
dont_gen_if_void instanceof_opt.

%expression2_rest::= [] or
%	infixop,expression3,expression2_rest.
%dont_gen_if_void expression2_rest.
%map expression2_rest(I,E,expression2_rest(infixop(X),E2)) : expression2_rest(I,infixop(X,E,E2)).

%infixop ::= [sc_or] or 
%	[sc_and] or 
%	[bit_or] or 
%	[xor] or 
%	[bit_and] or
%	[eq] or 
%	[ne] or 
%	[lt],[lt] or
%	[gt],[gt],[gt] or
%	[gt],[gt] or
%	[lt] or 
%	[gt] or 
%	[le] or 
%	[ge] or 
%	[plus] or 
%	[minus] or 
%	[star] or 
%	[slash] or 
%	[rem].
%map infixop(lt,lt) : infixop(lshift).
%map infixop(gt,gt,gt) : infix_op(runsignedshift).
%map infixop(gt,gt) : infixop(rsignedshift).

expression3::= 
	prefix_op, expression3 or
	[lpar],expression,[rpar],expression3 or %cos'è??rallenta un poco.. è simile ad una produzione della primary
	[lpar],type1,[rpar],expression3 or %cast
	primary ,selector, postfix_op.
dont_gen_single_node expression3.
map expression3(X,S,postfix_op(O)) : postfix_op(O,X,S).
map expression3(X,postfix_op(O)) : postfix_op(O,X).
map expression3(prefix_op(X),E) : prefix_op(X,E).
map expression3(lpar,T,rpar,E) : cast(T,E).
map expression3(X,selector(dot,Y)) : select(X,Y).
map expression3(X,selector(dot,Y,A)) : select(X,Y,A).

primary::=
%	[lpar], expression, [rpar] or
	par_expression or
	non_wildcard_type_arguments, arguments_or_invocation or
	[this],arguments_opt or
	[super], super_suffix or
	literal or
	[new], creator or
	qualified_identifier, identifier_suffix or
	basic_type, brackets_opt,[dot],[class] or
	[void],[dot],[class].
map primary(par_expression(_,E,_)) : expression(E).
map primary(X) : X.
map primary(X,arguments(Y)) : method_call(X,arguments(Y)).
map primary(new,C) : new(C).


arguments_or_invocation ::= 
	explicit_generic_invocation_suffix or
	[this],arguments.
identifier_suffix::= [] or
	[lbracket],[rbracket], brackets_opt,   [dot],   [class] or 
	[lbracket], expression,[rbracket] or
	arguments or
	[dot],[class] or 
	[dot],explicit_generic_invocation or
	[dot],[this] or 
	[dot],[super],arguments or 
	[dot],[new],non_wildcard_type_arguments_opt,inner_creator.
dont_gen_single_node identifier_suffix.
dont_gen_if_void identifier_suffix.
map identifier_suffix(_,expression(E),_) : expression(E).

explicit_generic_invocation ::= 
	non_wildcard_type_arguments,explicit_generic_invocation_suffix.
non_wildcard_type_arguments_opt ::= [] or 
	non_wildcard_type_arguments.
dont_gen_node non_wildcard_type_arguments_opt.

non_wildcard_type_arguments ::= 
	[lt],type_list,[gt].
map non_wildcard_type_arguments(_,L,_) : non_wildcard_type_arguments(L).

explicit_generic_invocation_suffix ::= 
	[super],super_suffix or
	identifier,arguments.

prefix_op ::= 
	[incr] or 
	[decr] or 
	[bang] or 
	[tilde] or 
	[plus] or 
	[minus].

postfix_op ::= [] or 
	[incr],postfix_op or 
	[decr],postfix_op.
dont_gen_if_void postfix_op.
map postfix_op(X,postfix_op(Y)) : postfix_op([X,Y]) :- not(list(Y)).
map postfix_op(X,postfix_op(Y)) : postfix_op([X|Y]).

selector ::= [] or 
	[dot],identifier,arguments_opt,selector or 
	[dot],explicit_generic_invocation, selector or
	[dot],[this],selector or
	[dot],[super],super_suffix,selector or 
	[dot],[new], non_wildcard_type_arguments_opt,inner_creator,selector or
	[lbracket],expression,[rbracket],selector.
dont_gen_if_void selector.

super_suffix::= 
	arguments or
	[dot], identifier, arguments_opt.

basic_type::= 
	[byte] or 
	[short] or
	[char] or
	[int] or
	[long] or
	[float] or
	[double] or
	[boolean].
map basic_type(X) : X.

arguments_opt::= [] or arguments.
dont_gen_node arguments_opt.

arguments::=
	[lpar],[rpar] or 
	[lpar],expression,arguments_rest,[rpar].
map arguments(_,_) : arguments(null).
map arguments(_,E,L,_) : arguments([E|L]).

arguments_rest ::= [] or 
	[comma],expression,arguments_rest.
map arguments_rest : [].
map arguments_rest(_,E,L) : [E|L].

brackets_opt::= 
	[] or 
	[lbracket],[rbracket],brackets_opt.
map brackets_opt : ''.
map brackets_opt(_,_,X) : Z :- string_append('[]',X,Z).
creator::=
	non_wildcard_type_arguments_opt,created_name,array_or_class_creator_rest.
map creator(X,A) : Z :- X=..[created_class_name|T],append(T,[A],W), Z =.. [class_creator|W].
map creator(N,X,A) : Z :- X=..[created_class_name|T],append([N|T],[A],W), Z =.. [class_creator|W].

array_or_class_creator_rest ::= 
	array_creator_rest or 
	class_creator_rest.
dont_gen_node array_or_class_creator_rest.

created_name ::= 
	identifier,non_wildcard_type_arguments_opt,created_name_rest.
map created_name(ID,W,X) : Z :- X=..[_|T],Z=..[created_class_name,ID,W|T].
map created_name(ID,X) : Z :- X=..[_|T],Z=..[created_class_name,ID|T].

created_name_rest ::= [] or 
	[dot],identifier,non_wildcard_type_arguments_opt,created_name_rest.
map created_name_rest(_,ID,created_name_rest) : created_name_rest(ID).
map created_name_rest(_,ID,W,created_name_rest) : created_name_rest(ID,W).
map created_name_rest(_,ID,W,X) : Z :- X=..[_|T],Z=..[created_name_rest,ID,W|T].
map created_name_rest(_,ID,X) : Z :- X=..[_|T],Z=..[created_name_rest,ID|T].
inner_creator::=
	identifier, class_creator_rest.

array_creator_rest::= 
	[lbracket],[rbracket],brackets_opt,array_initializer or 
	[lbracket],expression, [rbracket], array_rest, brackets_opt.

array_rest::= [] or 
	[lbracket], expression, [rbracket],array_rest.

class_creator_rest::= 
	arguments,class_body_opt.
dont_gen_node class_creator_rest.

class_body_opt ::= [] or 
	class_body.
dont_gen_node class_body_opt.

array_initializer::= 
	[lbrace],[rbrace] or 
	[lbrace],variable_initializer,variable_rest,[rbrace],comma_opt.
map array_initializer(_,_) : array_initializer([]).
map array_initializer(_,X,R,_,_) : array_initializer([X|R]).

comma_opt ::= [comma] or 
	[].

variable_rest ::= [] or 
	[comma],variable_initializer,variable_rest.
map variable_rest : [].
map variable_rest(_,V,L) : [V|L].

variable_initializer::= 
	array_initializer or
	expression.
dont_gen_single_node variable_initializer.

par_expression::= 
	[lpar], expression,[rpar].
map par_expression(_,expression(X),_) : expression(X).

block::= 
	[lbrace],block_statements,[rbrace].
map block(_,X,_) : block(X).

block_statements::= [] or 
	 block_statement,block_statements .
map block_statements : [].
map block_statements(X,L) : [X|L].

block_statement ::=
	local_variable_declaration_statement or
	class_or_interface_declaration or
	identifier,[colon],statement or
	statement.
map block_statement(X) : X.
map block_statement(I,_,S) : label(I,S).

local_variable_declaration_statement::=
	[final], type1, variable_declarators,[semicolon] or 
	type1, variable_declarators,[semicolon].  
map local_variable_declaration_statement(final,T,variable_declarators(L),_) : local_variable_declaration(final,T,vars(L)).
map local_variable_declaration_statement(T,variable_declarators(L),_) : local_variable_declaration(T,vars(L)).

else_statement ::= [] or 
	[else], statement.
map else_statement(_,S) : else_statement(S).
dont_gen_if_void else_statement.

catch_or_finally ::= 
	catches,finally_opt or 
	[finally],block.
map catch_or_finally(finally,B) : finally(B).
map catch_or_finally(C,F) : catch_and_finally(C,F).
map catch_or_finally(C) : catch(C).

finally_opt ::= 
	[finally],block or 
	[].
dont_gen_if_void finally_opt.
map finally_opt(B) : B.

assert_rest ::= [] or 
	[colon],expression.
statement::=
	block or
	[assert], expression,assert_rest,[semicolon] or
	[if], par_expression, statement, else_statement or
	[for],[lpar], for_control,[rpar],statement or
	[while], par_expression, statement or
	[do], statement , [while] ,par_expression, [semicolon] or 
	[try], block,catch_or_finally or
	[switch], par_expression,[lbrace], switch_block_statement_groups,[rbrace] or
	[synchronized], par_expression, block or
	[return], expression_opt, [semicolon] or 
	[throw], expression,[semicolon] or 
	[break], identifier or 
	[break] or 
	[continue],identifier or 
	[continue] or
	[semicolon] or 
	statement_expression,[semicolon] or
	identifier,[colon],statement.
map statement(I,colon,S) : statement(label(I,S)).
map statement(throw,E,_) : statement(throw(E)).
map statement(X,semicolon) : statement(X).
map statement(return,E,semicolon) : statement(return(E)).
map statement(assert,E,R,_) : statement(assert(E,R)).
map statement(for,lpar,X,rpar,L) : statement(for(X,for_body(L))).
map statement(if,par_expression(_,EX,_),S,E) : statement(if(EX,S),else(E)).
map statement(if,par_expression(_,EX,_),S) : statement(if(EX,S)).
map statement(while,par_expression(_,EX,_),S) : statement(while(EX,while_body(S))).
map statement(do,S,while,par_expression(_,E,_),_) : statement(repeat(S),until(E)).
map statement(try,B,C) : statement(try(B),C).
map statement(switch,par_expression(_,X,_),_,B,_) : statement(switch(X),switch_body(B)).
map statement(synchronized,par_expression(_,E,_),B) : statement(synchronized(E),synchronized_body(B)).

catches::=
	catch_clause,catches_rest.
map catches(C,R) : [C|R].

catches_rest ::= [] or 
	catch_clause,catches_rest.
map catches_rest : [].
map catches_rest(C,R) : [C|R].

catch_clause::= 
	[catch],[lpar],formal_parameter,[rpar], block.
map catch_clause(_,_,P,_,B) : catch_clause(P,B).

switch_block_statement_groups::= 
	[] or 
	switch_block_statement_group,switch_block_statement_groups.
map switch_block_statement_groups : [].
map switch_block_statement_groups(X,L) : [X|L].

switch_block_statement_group::= 
	switch_label, block_statements.
map switch_block_statement_group(L,B) : switch(L,B).

switch_label::= 
	[case], constant_expression,[colon] or
	[case], enum_constant_name, [colon] or
	[default], [colon].  
map switch_label(_,E,_) : label(E).
map switch_label(default,_) : label(default).

more_statement_expressions::= [] or 
	[comma],statement_expression, more_statement_expressions.
dont_gen_if_void more_statement_expressions.
map more_statement_expressions(_,S,M) : [S|M] :- list(M).
map more_statement_expressions(_,S,M) : [S,M].
map more_statement_expressions(_,S): S.

for_control ::= for_var_control or
	for_init,[semicolon],expression_opt,[semicolon],for_update.
dont_gen_single_node for_control.

for_var_control ::= [final],type1,identifier,for_var_control_rest or
 	type1,identifier,for_var_control_rest.
map for_var_control(final,T,ID,for_var_control_rest(variable_declarator_rest(B,assigment_opt(_,X)))) : for_var_control(final,T,assign(I,X)) :- string_append(ID,B,I).
map for_var_control(T,ID,for_var_control_rest(assignment(B,X))) : for_var_control(T,assign(I,X)) :- string_append(ID,B,I).

for_var_control_rest ::= 
	variable_declarators_rest,[semicolon],expression_opt,[semicolon],for_update or
	[colon],expression.
map for_var_control_rest(V,R,_,E,_,U) : for_var_control_rest(V,R,E,U).
map for_var_control_rest(V,R,_,_,U) : for_var_control_rest(V,R,U).
map for_var_control_rest(V,[],_,_) : for_var_control_rest(V).

for_init ::= 
	statement_expression, more_statement_expressions.
	%[final], type1, variable_declarators or 
	%type1, variable_declarators.
map for_init(S,M) : for_init([S|M]) :- list(M).
map for_init(S,M) : for_init([S,M]).

for_update::= 
	[] or 
	statement_expression, more_statement_expressions.
dont_gen_if_void for_update.
map for_update(S,M) : for_update([S|M]) :- list(M).
map for_update(S,M) : for_update([S,M]).

modifiers_opt::= [] or 
	modifier,modifiers_opt. 
map modifiers_opt : modifiers([]).
map modifiers_opt(modifier(X),modifiers(L)) : modifiers([X|L]).

modifier::= 
	[public] or 
	[protected] or 
	[private] or 
	[static] or 
	[abstract] or 
	[final] or 
	[native] or 
	[synchronized] or 
	[transient] or 
	[volatile] or
	[strictfp].

variable_declarators::= 
	variable_declarator, variable_declarators_r.
map variable_declarators(C,L) : variable_declarators([C|L]).

variable_declarators_r::= [] or 
	[comma],variable_declarator,variable_declarators_r.
map variable_declarators_r(_,V,L) : [V|L].
map variable_declarators_r : [].

variable_declarators_rest ::= variable_declarator_rest,variable_declarators_r.
dont_gen_node variable_declarators_rest.
map variable_declarators_rest(variable_declarator_rest,L) : variable_declarators_rest(L).

constant_declarators_rest ::= constant_declarator_rest,constant_declarators_r.
constant_declarators_r::= [] or 
	[comma],constant_declarator,constant_declarators_r.

variable_declarator::= 
	identifier, variable_declarator_rest.
map variable_declarator(I,assignment(B,A)) : variable_decl(assign(ID,A)) :- string_append(I,B,ID).
map variable_declarator(I,variable_declarator_rest) : I.

constant_declarator::= 
	identifier, constant_declarator_rest.
map constant_declarator(ID,assign(B,A)) : constant_declarator(assign(I,A)) :- string_append(ID,B,I).

variable_declarator_rest::= 
	brackets_opt,assignment_opt.
map variable_declarator_rest('') : variable_declarator_rest.
map variable_declarator_rest(B,assignment_opt(_,I)) : assignment(B,I).

assignment_opt ::= [] or 
	[assign],variable_initializer.
dont_gen_if_void(assignment_opt).

constant_declarator_rest::= 
	brackets_opt,[assign], variable_initializer.
map constant_declarator_rest(B,_,A) : assign(B,A).

variable_declarator_id::= 
	identifier, brackets_opt.
map variable_declarator_id(identifier(X),Y) : variable_id(Z) :- string_append(X,Y,Z).

package_statement ::= [] or 
	[package],qualified_identifier,[semicolon].
dont_gen_if_void package_statement.
map package_statement(_,qualified_identifier(X),_) : package(X).

compilation_unit::= package_statement,import_declaration, type_declaration.

import_declaration::= [] or 
	[import], qualified_identifier,dot_star,[semicolon],import_declaration or
	[import],[static],qualified_identifier,dot_star,[semicolon],import_declaration.
dont_gen_if_void import_declaration.
map import_declaration(_,I,D,semicolon,L) : [import(ID) | L] :- list(L),string_append(I,D,ID).
map import_declaration(_,I,D,semicolon,L) : [import(ID) , L] :- string_append(I,D,ID).
map import_declaration(_,static,I,D,semicolon,L) : [import_static(ID) | L] :- list(L),string_append(I,D,ID).
map import_declaration(_,static,I,D,semicolon,L) : [import_static(ID) , L] :- string_append(I,D,ID).
map import_declaration(_,I,D,semicolon) : import(ID) :- string_append(I,D,ID).
map import_declaration(_,static,I,D,semicolon) : import_static(ID) :- string_append(I,D,ID).		
	
dot_star ::= [dot],[star] or [] .  
map dot_star : ''.
map dot_star(_,_) : '.*'.

type_declaration::= [] or 
	class_or_interface_declaration,type_declaration or
	[semicolon],type_declaration.
map type_declaration(semicolon,type_declaration(X)) : type_declaration(X).
map type_declaration : type_declaration([]).
map type_declaration(X,type_declaration(L)) : type_declaration([X|L]).

class_or_interface_declaration::= 
	modifiers_opt,class_or_interface_or_enum_decl.
map class_or_interface_declaration(X,Y) : Z :-Y=..[A|W],Z=..[A,X|W].
		
class_or_interface_or_enum_decl ::= class_declaration or 
	interface_declaration or 
	enum_declaration.
dont_gen_single_node class_or_interface_or_enum_decl.

class_declaration::= 
	[class], identifier,type_parameters_opt,extends_opt,implements_opt,class_body.
map class_declaration(_,N,T,E,I,B) : class(N,T,E,I,B).
map class_declaration(_,N,T,E,B) : class(N,T,E,B).
map class_declaration(_,N,T,B) : class(N,T,B).
map class_declaration(_,N,B) : class(N,B).

type_parameters_opt ::= [] or 
	type_parameters.
dont_gen_if_void type_parameters_opt.

extends_opt ::= [] or 
	[extends],type1.
dont_gen_if_void extends_opt.

implements_opt ::= [] or 
	[implements],type_list.
dont_gen_if_void implements_opt.

interface_declaration::= 
	[interface], identifier,type_parameters_opt,extends_opt, interface_body.

type_parameters ::= [lt],type_parameter,type_parameters_rest,[gt].
type_parameters_rest ::= [comma],type_parameter,type_parameters_rest.
type_parameter ::= identifier, extends_bound_opt.
extends_bound_opt ::= [extends],bound or 
	[].
bound ::= type1,bound_rest.
bound_rest ::= [] or 
	[bit_and],type1,bound_rest.

enum_declaration ::= [enum],identifier,implements_opt,enum_body.

enum_body ::= [] or 
	enum_constants,comma_opt,enum_body_declarations,enum_body.
enum_constants ::= 
	enum_constant,enum_constants_rest.
	
enum_constants_rest ::= [] or enum_constant,enum_constants_rest.

enum_constant ::= identifier,arguments_opt,class_body_opt.
enum_body_declarations ::= [] or 
	[semicolon],class_body_declaration_list.

class_body_declaration_list ::= [] or 
	class_body_declaration,class_body_declaration_list.
map class_body_declaration_list : [].
map class_body_declaration_list(X,L) : [X|L].

type_list::=
	type1,type_list_rest.
map type_list(T,L) : type_list([T|L]).

type_list_rest ::= [] or 
	[comma],type1,type_list_rest.
map type_list_rest : [].
map type_list_rest(_,T,L) : [T|L].

class_body::= 
	[lbrace], class_body_declaration, [rbrace].
map class_body(_,X,_) : class_body(X).

interface_body::= 
	[lbrace],interface_body_declaration,[rbrace].
map interface_body(_,X,_) : interface_body(X).

class_body_declaration::=
	[semicolon],class_body_declaration_rest or
	[static], block,class_body_declaration_rest or
	block,class_body_declaration_rest or
	modifiers_opt, member_decl,class_body_declaration_rest.
class_body_declaration_rest ::= [] or
	[semicolon],class_body_declaration_rest or
	[static], block,class_body_declaration_rest or
	block,class_body_declaration_rest or
	modifiers_opt, member_decl,class_body_declaration_rest.

map class_body_declaration_rest : [].
map class_body_declaration_rest(semicolon,L) : L.
map class_body_declaration_rest(static,block(X),L) : [static_block(X)|L].
map class_body_declaration_rest(X,L) : [X|L].
map class_body_declaration_rest(X,Y,L) : [Z|L] :- Y=..[W|T],Z=..[W,X|T].	
map class_body_declaration : [].
map class_body_declaration(semicolon,L) : L.
map class_body_declaration(static,block(X),L) : [static_block(X)|L].
map class_body_declaration(X,L) : [X|L].
map class_body_declaration(X,Y,L) : [Z|L] :- Y=..[W|T],Z=..[W,X|T].

member_decl::=
	generic_method_or_constructor_decl or
	method_or_field_decl or
	[void], identifier, void_method_declarator_rest or
	identifier, constructor_declarator_rest or
	class_or_interface_declaration.
map member_decl(X) : X.
map member_decl(_,ID,X) : W :- X=..[_|T],W=..[void_method_declarator,ID|T].
map member_decl(ID,X) : constructor_declarator(ID,X).

method_or_field_decl::=
	type1, identifier, method_or_field_rest.
map method_or_field_decl(X,Y,Z) : method_or_field_decl(X,Y) :- atomic(Z).
map method_or_field_decl(T,ID,variable_declarator_rest(B)) : field_decl(T,I) :- string_append(ID,B,I).
map method_or_field_decl(T,ID,variable_declarator_rest(B,V)) : field_decl(T,assign(I,V)) :- string_append(ID,B,I).

method_or_field_rest::=
	variable_declarator_rest or
	method_declarator_rest.
map method_or_field_rest(variable_declarator_rest) : method_or_field_rest.
map method_or_field_rest(variable_declarator_rest(B)) : variable_declarator_rest(B).
map method_or_field_rest(variable_declarator_rest(B,assignment_opt(_,V))) : variable_declarator_rest(B,V).

interface_body_declaration::= [] or
	[semicolon],interface_body_declaration or 
	modifiers_opt, interface_member_decl,interface_body_declaration.

interface_member_decl::=
	interface_method_or_field_decl or
	interface_generic_method_decl or
	[void], identifier, void_interface_method_declarator_rest or
	class_or_interface_declaration.

generic_method_or_constructor_decl ::= 
	type_parameters,generic_method_or_constructor_rest.
generic_method_or_constructor_rest ::= 
	type1,identifier,method_declarator_rest or
	[void],identifier,method_declarator_rest or
	identifier, constructor_declarator_rest.

interface_method_or_field_decl::=
	type1, identifier, interface_method_or_field_rest.

interface_method_or_field_rest::=
	constant_declarators_rest,[semicolon] or
	interface_method_declarator_rest.

method_declarator_rest::=
		formal_parameters, brackets_opt, throws_opt, method_body_opt.

method_body_opt ::= [semicolon] or 
	method_body.
map method_body_opt(semicolon) : method_body(null).
map method_body_opt(X) : X.

throws_opt ::= [] or 
	[throws], qualified_identifier_list.
dont_gen_if_void throws_opt.
map throws_opt(_,L) : throws(L).

void_method_declarator_rest::=
		formal_parameters,throws_opt,method_body_opt.
%dont_gen_node void_method_declarator_rest.

interface_method_declarator_rest::=
	formal_parameters, brackets_opt,throws_opt, [semicolon].  

interface_generic_method_decl ::= type_parameters,type_or_void,identifier,interface_method_declarator_rest.
type_or_void ::= [void] or 
	type1.

void_interface_method_declarator_rest::=
	formal_parameters, throws_opt,[semicolon].

constructor_declarator_rest::=
	formal_parameters,throws_opt, method_body.

qualified_identifier_list::= 
	qualified_identifier,qualified_identifier_list_rest.
map qualified_identifier_list(X,L) : [X|L].

qualified_identifier_list_rest ::= [] or 
	[comma],qualified_identifier,qualified_identifier_list_rest.
map qualified_identifier_list_rest : [].
map qualified_identifier_list_rest(_,I,L) : [I|L].

formal_parameters::= 
	[lpar],formal_parameters_decls_opt,[rpar].
map formal_parameters(_,X,_) : formal_parameters(X).

formal_parameters_decls_opt ::= [] or 
	formal_parameters_decls.
map formal_parameters_decls_opt : [].
map formal_parameters_decls_opt(X) : X.

formal_parameters_decls ::= [final],type1,formal_parameter_decls_rest or
	type1,formal_parameter_decls_rest.
map formal_parameters_decls(final,T,ID,L) : [formal_parameter(final,T,ID)|L].
map formal_parameters_decls(T,ID,L) : [formal_parameter(T,ID)|L].
map formal_parameters_decls(final,T,dot,dot,dot,ID) : [formal_parameter_obj_list(final,T,ID)].
map formal_parameters_decls(T,dot,dot,dot,ID) : [formal_parameter_obj_list(T,ID)].

formal_parameter_decls_rest ::= 
	variable_declarator_id,other_formal_parameter or
	[dot],[dot],[dot],variable_declarator_id.
dont_gen_node formal_parameter_decls_rest.

other_formal_parameter ::= [] or 
	[comma],formal_parameters_decls.
map other_formal_parameter : [].
map other_formal_parameter(_,X) : X.
%formal_parameters_list::= formal_parameter,formal_parameters_list_rest or 
%	[].

%formal_parameters_list_rest ::= [comma],formal_parameter,formal_parameters_list_rest or [].

formal_parameter::= 
	[final], type1, variable_declarator_id or 
	type1, variable_declarator_id.
	
method_body::=
	block.
map method_body(block(X)) : method_body(X).

enum_constant_name ::= 
	identifier.
dont_gen_single_node enum_constant_name.