# This is a BNF grammar for ParaFlow.  It is organized
# with expressions first, then statements.  The terminal
# tokens are either surrounded by single quotes or are
# in all-caps.  For the grammar to work the tokenizer has to 
# distinguish type names from other names. 


expression:  tuple

tuple: assignmentLevel
        | tuple ',' assignmentLevel

assignmentLevel: orLevel
	| orLevel equalsOp orLevel

equalsOp: '=' | '+=' | '-=' | '*=' | '/=' 
	| 'to' # Only allowed inside of dir/tree initialization

orLevel: andLevel
	| orLevel '||' andLevel

andLevel: cmpLevel
	| andLevel '&&' cmpLevel

cmpLevel: sumLevel
	| sumLevel cmpOp sumLevel

cmpOp: '==' | '!=' | '>=' | '<=' | '>' | '<'

sumLevel: mulLevel
	| sumLevel sumOp mulLevel

sumOp: '+' | '-' | '|' | '^'   # ^ is xor

mulLevel: negLevel
	| mulLevel mulOp negLevel

mulOp: '*' | '/' | '%' | '<<' | '>>' | '&'

negLevel: callLevel
        | negOp negLevel

negOp: '-' | '!' | '~'    # ~ is bitwise not

callLevel: indexed
	| call

call: atomLevel '(' tuple ')'

indexed: atomLevel 
	| indexed '[' expression ']'

atomLevel: CONSTANT
	| variable
	| '(' expression ')'
	
variable:  dottedName
	| type dottedName
	
type:	parameterizedType
	| type 'of' parameterizedType

parameterizedType:	TYPENAME
	| TYPENAME '[' expression ']'	
	
dottedName: NAME
	| dottedName '.' NAME

# A ParaFlow program is a list of statements.

statement:  ';'
	| compoundStatement
	| variableDefList ';'
	| assignment ';'
	| call ';'
	| ifStatement
	| whileStatement
	| forStatement
	| forInStatement
	| 'break' ';'	   # Only allowed inside of a loop
	| 'continue' ';'   # Only allowed inside of a loop
	| functionDef
	| 'return' ';'	   # Only allowed inside of function
	| classDef 

compoundStatement:	statement
	| '{' statement '}'

variableDef:	type NAME

variableDefList:  variableDef
	| variableDef '=' expression
	| variableDefList ',' variableDef '=' expression
	| variableDefList ',' variableDef
	| variableDefList ',' NAME '=' expression
	| variableDefList ',' NAME

assignment: orLevel '=' orLevel

ifStatement: 'if' '(' expression ')' statement
	| 'if' '(' expression ') statement 'else' statement
	
whileStatement: 'while' '(' expression ')' statement

forStatement: 'for' '(' expression ';' expression ';' expression')' statement

forInStatement: 'for' '(' NAME 'in' dottedName statement ')'

parameterList: '(' ')'
	| '(' variableDefList ')'

functionType: 'to' 
	| 'flow'
functionDef: functionType NAME parameterList compoundStatement  
	| functionType NAME parameterList 'into' parameterList compoundStatement

classDef: 'class' TYPENAME compoundStatement
	| 'class' TYPENAME 'extends' TYPENAME compoundStatement

program:
	| program statement

# This grammar permits a fair bit that is not yet implemented.
# Hopefully the compiler will give you helpful diagnostic messages
# in these cases.   There are other constraints on the language
# as well, not all of which can be considered context free.
# These are enforced mostly in the type-checking pass.
