//===================================================================================================
//
//  HL.jjt copyright Sophie Quigley 2024
//
//  The copyright to this original work is held by Sophie Quigley, and students registered in course 
//  CPS710 taught at Toronto Metropolitan University in the Fall semester of 2022 can use this material 
//  for the purposes of this course, but no other use is permitted and there can be no sale or transfer 
//  or use of the work for any other purpose without the explicit permission of Sophie Quigley.
//  In particular, no part of this file and can be posted in code repositories, or transmitted to
//  students not registered in CPS710 in the Fall semester of 2024.
//
//===================================================================================================
options {
  IGNORE_CASE=false;
  MULTI=true;	// This will generate one AST class for each non-suppressed non-terminal
  JJTREE_OUTPUT_DIRECTORY="AST";  // This will put all your AST classes in the AST directory
  VISITOR=true;	// This won't be used until the next assignment, but will be needed to make your assignment compile properly
}

PARSER_BEGIN(HL)

public class HL {
}

PARSER_END(HL)

TOKEN_MGR_DECLS : 
{
}

SKIP : {
  " "     
  | "\t"    
  | "\n"    
  | "\r"    
  }

TOKEN : 
{
	< LESS:	"<">
|	< LESSEQ:	"<=">
|	< GREATER:	">">
|	< GREATEQ:	">=">
|	< EQUAL:	"==">
| < NOTEQ: "!=">
|	< PLUS:	"+">
|	< MINUS:	"-">
|	< TIMES:	"*">
|	< DIV:	"/">
|	< MOD:	"%">
| < AND:	"&">
| < VBAR:	"|">
| < NOT:	"!">
|	< ASSIGN:	"=">
|	< LROUND:	"(">
|	< LCURLY:	"{">
|	< LSQUARE:	"[">
|	< RROUND:	")">
|	< RCURLY:	"}">
|	< RSQUARE:	"]">
|	< COMMA:	",">
|	< SEMICOL:	";">
|	< TRUE:	"#1">
|	< FALSE:	"#0">
}

TOKEN [IGNORE_CASE]:
{
	< DO:"DO">
|	< ELIF:"ELIF">
|	< ELSE:"ELSE">
|	< END:"END">
|	< FI:"FI">
|	< FOR:"FOR">
|	< FUNCTION:"FUNCTION">
|	< IF:"IF">
| < IN:"IN">
| < ISIN:	"=IN">
| < NOTIN:	"!IN">
|	< PRINT:"PRINT">
|	< PRINTLN:"PRINTLN">
|	< RETURN:"RETURN">
| < THEN:"THEN">
|	< VAR:"VAR">
|	< WHILE:"WHILE">
}

TOKEN : 
{
	< #DIGIT:	["0"-"9"]>
|	< #LOWER:	["a"-"z"]>
|	< #UPPER:	["A"-"Z"]>
|	< #LETTER:	["a"-"z","A"-"Z"]>
|	< NUMBER:	(<DIGIT>)+ >
|	< IDNUM:	<LOWER>(<LETTER>|<DIGIT>)* >
|	< IDSET:	<UPPER>(<LETTER>|<DIGIT>)* >
|	< IDBOOL:	"#" <LETTER>(<LETTER>|<DIGIT>)* >
| < STRING: "\"" (~["\""])* "\"" >
}

// ----------------------  COMMENTS     ----------------------------

SPECIAL_TOKEN : {
        <COMMENT_SINGLE: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
    }

//==================================================================
//                         P A R S E R
//==================================================================

//------------------------    STATEMENTS, BODIES AND CLAUSES -----------------------------------

// ------------------------------- BEGINNING -----------------------------------

SimpleNode start	() #void :
{}
{  S()  { return (SimpleNode) (jjtree.popNode()); }
| < EOF > {throw new ParseException("End of File.");}
}


void S() throws ParseException		 :
{}
{	statement_LL1() ";"
| LOOKAHEAD(identifier() "=") assign_stat() ";" 
| expression() ";"
}

//------------------------    STATEMENTS, BODIES AND CLAUSES -----------------------------------

// These are all the statements which can be differentiated from each other 
// with a single lookahead

void statement_LL1()		 :
{}
{	var_decl()
| fn_decl()
| return_stat()
| print_stat()
| println_stat()
| if_stat()
| for_stat()
| while_stat()
}

void statement()	 :
{}
{	statement_LL1()
| LOOKAHEAD(2) fn_call()
| assign_stat()
}

void body()		 :
{}
{	(statement() ";")*
}

void clause()		 :
{}
{	(statement() ";")+
}

//---------------------------   DECLARATIONS ------------------------------------------------

void var_decl()	 :
{}
{	<VAR> ident_list()
}

void fn_decl()		 :
{}
{	<FUNCTION> identifier() "(" (ident_list())? ")" body() <END>
}

void ident_list()	 :
{}
{	identifier() ("," identifier())*
}

void identifier()	 :
{}
{	<IDNUM>
| <IDSET>
| <IDBOOL>
}


//---------------------------   FUNCTION CALLS AND RETURNS ----------------------------------
// parameter and return values can be numbers, sets, or booleans

void fn_call()		 :
{}
{	<IDNUM> "(" (value_list())? ")"
|	<IDSET> "(" (value_list())? ")"
}

void boolean_call()		 :
{}
{	<IDBOOL> "(" (value_list())? ")"
}

void value_list()	 :
{}
{	value() ("," value())*
}

void return_stat()	 :
{}
{	<RETURN> value()
}

void value()	 :
{}
{	LOOKAHEAD(condition()) condition()
| expression() 
}

//---------------------------   MISCELLANEOUS STATEMENTS ----------------------------------

void assign_stat() :
{}
{ <IDNUM> "=" expression()
| <IDSET> "=" expression()
| <IDBOOL> "=" condition()
}

void print_stat()  	 :
{}
{ 	<PRINT> print_list()
}

void println_stat()  	 :
{}
{ 	<PRINTLN> (print_list())?
}

void print_list()	 :
{}
{	(value() | <STRING>) ("," (value() | <STRING>))*
}

//---------------------------   IF AND LOOP STATEMENTS  ----------------------------------

void if_stat()		 :
{}
{	<IF> condition() <THEN> clause() elifs() (<ELSE> clause())? <FI>
}

void elifs()		 :
{}
{	(<ELIF> condition() <THEN> clause())*
}

void for_stat()	 :
{}
{	<FOR> <IDNUM> <IN> exp_list() <DO> body() <END>
}

void while_stat()	 :
{}
{	<WHILE> condition() <DO> body() <END>
}

//---------------------------   CONDITIONS ---------------------------------------------------
// Conditions will evaluate to Boolean value True or False

void condition()	 :
{}
{	and_clause() ("|" and_clause())*
}

void and_clause()	 :
{}
{	not_clause() ("&" not_clause())*
}

void not_clause()	 :
{}
{	"!" not_clause()
|	LOOKAHEAD(expression() comparator()) comparison() 
| "(" condition() ")"
| LOOKAHEAD(2) boolean_call()
|	<IDBOOL>
| <TRUE>
| <FALSE>
}

void comparison()	 :
{}
{	expression() comparator() expression()
}

void comparator()	 :
{}
{	"<"
| "<="
| ">"
| ">="
| "=="
| "!="
| <ISIN>
| <NOTIN>
}

//---------------------------   EXPRESSIONS ------------------------------------------------
// Expressions will evaluate to sets or numbers

void exp_list()	 :
{}
{	expression() ("," expression())*
}

void expression()	 :
{}
{	("+" | "-")? product() (("+"| "-") product())*
}

void product()		 :
{}
{	term() (("*"| "/" | "%") term())*
}

void term()		 :
{}
{	"(" expression() ")"
| "|" expression() "|"
|	LOOKAHEAD(2) fn_call()
| simple_term()
}

void simple_term()	 :
{}
{	<IDNUM>
| <IDSET>
| <NUMBER>
| interval()
|	"{" set() "}"
}

void interval()	 :
{}
{	"[" expression() "," expression() "]"
}

void set()	 :
{}
{ LOOKAHEAD(2) set_former()
| (exp_list())?                // set_const
}

void set_former()	 :
{}
{	<IDNUM> (<IN> expression())? "|" condition()
}