grammar Boppi;
import BoppiTokens;

program: stats EOF;

stats
	: stat (COMPOUND stat?)*
	;

stat
	: declareStat
	| assignStat
	| expr
	;

declareStat
	: DECLARE CONSTANT? type IDENTIFIER #declare
	| FUNCTION (result=type)? name=IDENTIFIER PAROPEN parameters? PARCLOSE body=expr #declareFunction
	;

assignStat
	: variable ASSIGN (assignStat | expr) #assign
	;

expr
	: PAROPEN stats PARCLOSE #parens
	| BRAOPEN stats BRACLOSE #block
	| op=(PLUS|MINUS|NOT) expr #prefix1
	| lhs=expr op=(MULTIPLY|DIVIDE) rhs=expr #infix1
	| lhs=expr op=(PLUS|MINUS) rhs=expr #infix2
	| lhs=expr op=(LT|LEQ|GTE|GT|EQ|NEQ) rhs=expr #infix3
	| lhs=expr AND rhs=expr #infix4
	| lhs=expr OR rhs=expr #infix5
	| IN PAROPEN variable (LISTDELIM variable)* PARCLOSE #read
	| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
	| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
	| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
	| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
	| variable #getVariable
	| ARRAY PAROPEN type LISTDELIM size=expr LISTDELIM offset=expr PARCLOSE #defineArray
	| ARROPEN expr (LISTDELIM expr)* ARRCLOSE #literalArray
	| LITERAL10 #literalInteger
	| CHAR #literalCharacter
	| (TRUE|FALSE) #literalBoolean
	;

type
	: type ARROPEN ARRCLOSE #typeArray
	| type ARROW type #typeFunction
	| staticType=(INTTYPE | BOOLTYPE | CHARTYPE) #typeSimple
	| PAROPEN (type (LISTDELIM type)*)? PARCLOSE #typeTuple
	| variable #typeVariable
	;

variable
	: variable ARROPEN expr ARRCLOSE #variableArray
	| variable PROP IDENTIFIER #variableProperty
	| IDENTIFIER #variableSimple
	;

parameters
	: type IDENTIFIER (LISTDELIM type IDENTIFIER)*
	;
