// 19/06/17 //
language astro

// PROGRAM
module =
    | 


// DECLARATIONS
declaration =
    | type | abst | glob_fun | scop_fun | scop_fun 
    | glob_obj | scop_obj | inln_obj 
    | glob_subj | scop_subj | glob_lazy_subj | scop_lazy_subj

scop_declaration = 
    | glob_fun | scop_fun | scop_fun 
    | glob_obj | scop_obj | inln_obj 
    | glob_subj | scop_subj | glob_lazy_subj | scop_lazy_subj

type =
    | 'type' type_head
    | 'type' IND type_head (NL type_head)* DED

abst =
    | 'abst' abst_head
    | 'abst' IND abst_head (NL abst_head)* DED

glob_fun =
    | 'fun' glob_fun_head
    | 'fun' IND glob_fun_head (NL glob_fun_head)* DED

scop_fun =
    | 'fun' scop_fun_head
    | 'fun' IND scop_fun_head (NL scop_fun_head)* DED

glob_obj =
    | 'obj' glob_obj_head
    | 'obj' IND glob_obj_head (NL glob_obj_head)* DED

scop_obj =
    | 'obj' scop_obj_head
    | 'obj' IND scop_obj_head (NL scop_obj_head)* DED

inln_obj = 
    | 'obj' inln_obj_head

glob_subj = 
    | ('var' | 'let') glob_subj_head
    | ('var' | 'let') IND glob_subj_head (NL glob_subj_head)* DED

scop_subj = 
    | ('var' | 'let') scop_subj_head
    | ('var' | 'let') IND scop_subj_head (NL scop_subj_head)* DED

glob_lazy_subj = 
    | ('var' | 'let') glob_subj_head
    | ('var' | 'let') IND glob_subj_head (NL glob_subj_head)* DED

scop_lazy_subj = 
    | ('var' | 'let') scop_lazy_subj_head
    | ('var' | 'let') IND scop_lazy_subj_head (NL scop_subj_head)* DED

abst_element =
    | glob_name ('(' type_params? ')')?




// DECLARATION HEADS
type_head = 
    | glob_name ('<' NS ':' name (',' name)*)? ':' type_expr_or_block
    | glob_name '(' type_params? ')' ('<' NS ':' name (',' name)*)?
    | glob_name ('=' name)? (',' glob_name ('=' name)?)*

abst_head =
    | glob_name ('<' NS ':' name (',' name)*)? ':' abst_expr_or_block
    | glob_name '(' type_params? ')' ('<' NS ':' name (',' name)*)? ':' abst_el_expr_or_block
    | glob_name ('=' name)? (',' glob_name ('=' name)?)*

glob_fun_head =
    | glob_name '(' fun_params? ')' (':' expr_or_block)?
    | glob_name ('=' name)? (',' glob_name ('=' name)?)*

scop_fun_head =
    | name '(' fun_params? ')' (':' expr_or_block)?
    | name ('=' name)? (',' name ('=' name)?)*

glob_obj_head =
    | glob_name ('<' NS ':' name (',' name)*)? ':' type_expr_or_block
    | glob_name '(' type_params? ')' ('<' NS ':' name (',' name)*)? 

scop_obj_head =
    | name ('<' NS ':' name (',' name)*)? ':' type_expr_or_block
    | name '(' fun_params? ')' ('<' NS ':' name (',' name)*)?

inln_obj_head = 
    | name ('<' NS ':' name (',' name)*)? ':' inln_obj_expr_or_block
    | name '(' fun_params? ')' ('<' NS ':' name (',' name)*)?

glob_subj_head = 
    | name (',' name)*
    | glob_assign_pattern '=' subj_expr_or_block

scop_subj_head = 
    | name (',' name)*
    | assign_pattern '=' subj_expr_or_block

glob_lazy_subj_head = 
    | glob_name (',' glob_name)*
    | glob_assign_pattern ':' NS '=' subj_expr_or_block

scop_lazy_subj_head = 
    | glob_name (',' glob_name)*
    | assign_pattern ':' NS '=' subj_expr_or_block




// ARGUMENTS
fun_param_name =
    | name ('.' name?)? (':' expr)?

type_param_name = 
    | name ('.' name?)? '`'? (':' expr)? 

params =
    | fun_param_name (',' fun_param_name)*

fun_params =
    | params ('<' fun_param_name (',' fun_param_name)* '>')?
    | '<' fun_param_name (',' fun_param_name)* '>' (params)?
    
type_params =
    | type_param_name (',' type_param_name)* ('<' fun_param_name (',' fun_param_name)* '>')?
    | '<' fun_param_name (',' fun_param_name)* '>' (type_param_name (',' type_param_name)*)?




// EXPRESSION-OR-BLOCK
expr_or_block = 
    | expr NL
    | IND block DED

inln_obj_expr_or_block =
    | glob_subj (NL glob_subj)* (scop_fun (NL scop_fun)*)?
    | scop_fun (NL scop_fun)*

abst_el_expr_or_block = 
    | glob_subj (NL glob_subj)* (NL abst_element (CNL? abst_element)*)?
    | abst_element (CNL? abst_element)* (glob_subj (NL glob_subj)*)?

type_expr_or_block = 
    | glob_subj (NL glob_subj)*

var_expr_or_block = 
    | expr_or_block | get_set




// NAMES
name = 
    | NAME

unnamed_arg =
    | '$' NS INTNUM

glob_name = 
    | name '`'?

name_or_ph =
    | name | PH

glob_name_or_ph =
    | glob_name | PH

name_or_outter =
    | ('$' NS)? name

named_expr = 
    | name ':' parens_expr

pattern_name =
    | '.' NS '.' NS '.' NS name? | name | ph

glob_pattern_name =
    | '.' NS '.' NS '.' NS glob_name? | glob_name | ph

if_name =
    | ('$' | '!') NS)? name

if_pattern_name = 
    | '.' NS '.' NS '.' NS if_name? | if_name | ph

if_name_or_ph = 
    | if_name | ph




// PATTERNS 
assign_pattern =
    | pattern_name (',' pattern_name)*
    | '[' pattern_name (',' pattern_name)* ']'
    | '(' pattern_name (',' pattern_name)* ')'
    | '{' pattern_name (',' pattern_name)* '}'
    | '[' name_or_ph '|' name_or_ph ']'
    | '(' name_or_ph '|' name_or_ph ')'
    | '{' name_or_ph '|' name_or_ph '}'
    | '{' name_or_ph ':' name_or_ph '}'

glob_assign_pattern = 
    | glob_pattern_name (',' glob_pattern_name)*
    | '[' glob_pattern_name (',' glob_pattern_name)* ']'
    | '(' glob_pattern_name (',' glob_pattern_name)* ')'
    | '{' glob_pattern_name (',' glob_pattern_name)* '}'
    | '[' glob_name_or_ph '|' glob_name_or_ph ']'
    | '(' glob_name_or_ph '|' glob_name_or_ph ')'
    | '{' glob_name_or_ph '|' glob_name_or_ph '}'
    | '{' glob_name_or_ph ':' glob_name_or_ph '}'

if_assign_pattern =
    | if_pattern_name (',' if_pattern_name)*
    | '[' if_pattern_name (',' if_pattern_name)* ']'
    | '(' if_pattern_name (',' if_pattern_name)* ')'
    | '{' if_pattern_name (',' if_pattern_name)* '}'
    | '[' if_name_or_ph '|' if_name_or_ph ']'
    | '(' if_name_or_ph '|' if_name_or_ph ')'
    | '{' if_name_or_ph '|' if_name_or_ph '}'
    | '{' if_name_or_ph ':' if_name_or_ph '}'

list_comp_yield_pattern = // TO BE REMOVED 
    | parens_expr
    | '[' parens_expr ']'
    | '{' parens_expr ':' parens_expr '}'
    | '{' parens_expr '}'
    | fun_call

match_pattern = // TODO
    | 




// LAMBDAS
lambda = 
    | ('|' params '|')? '-' NS '>' expr_or_block
    | '|' assign_pattern (',' assign_pattern)* '|' '-' NS '>' expr_or_block

iife =
    | '(' parens_expr (':' assign_pattern)? (',' parens_expr (':' assign_pattern)? )* ')' '-' NS '>' expr_or_block



// CONDITIONAL STRUCTURES
cond_structure = 
    | if | if_for | if_while | if_try 
    | for | for_for | for_while | for_try
    | while | while_if | while_for | while_while | while_try 
    | try | try_if | try_for | try_while 
    | defer

ctrl_primitive =
    | break | spill | continue | yield | delegate | await | return | raise

match = 
    | '|' match_pattern '-' NS '>' expr_or_block

do_match = 
    | parens_expr 'if' parens_expr NL (match)*

list_comp =
    | list_comp_yield_pattern ('<' NS '<' for_head_content (',' if_head_content)*)+

if_head =
    | 'if' if_head_content

if_head_content =
    | (if_assign_pattern '<' NL '<')? parens_expr

while_head =
    | 'while' if_head_content

for_head =
    | 'for' for_head_content

for_head_content =
    | if_assign_pattern ('<' NS '<') parens_expr

try_head = 
    | 'try' (if_head)?

elif =
    | 'elif' if_head_content ':' expr_or_block

else =
    | 'else' ':' expr_or_block

end =
    | 'end' ':' expr_or_block

catch =
    | 'catch' '(' name ')' ':' expr_or_block

ensure =
    | 'ensure' ':' expr_or_block

if =
    | if_head ':' expr_or_block (elif* else)?

if_for =
    | if_head CNL? for_head ':' expr_or_block (end (elif* else)?)?
    
if_while =
    | if_head CNL? while_head ':' expr_or_block (end (elif* else)?)?
    
if_try =
    | if_head CNL? try_head ':' expr_or_block (catch ensure? (elif* else)?)?

for =
    | for_head ':' expr_or_block end?
    
for_for =
    | for_head CNL? for_head ':' expr_or_block (end end?)?
    
for_while =
    | for_head CNL? while_head ':' expr_or_block (end end?)?
    
for_try =
    | for_head CNL? try_head ':' expr_or_block (catch ensure? end?)?

while =
    | while_head ':' expr_or_block end?
    
while_if =
    | while_head CNL? if_head ':' expr_or_block ((elif* else)? end)?
    
while_for =
    | while_head CNL? for_head ':' expr_or_block (end end?)?
    
while_while  =
    | while_head CNL? while_head ':' expr_or_block (end end?)? 
    
while_try  =
    | while_head CNL? try_head ':' expr_or_block (catch ensure? end?)?
    
try  =
    | try_head ':' expr_or_block (catch ensure?)?
    
try_if  =
    | try_head CNL? if_head ':' expr_or_block ((elif* else)? catch ensure?)?
    
try_for  =
    | try_head CNL? for_head ':' expr_or_block (end? catch ensure?)?
    
try_while =
    | try_head CNL? while_head ':' expr_or_block (end? catch ensure?)?

defer =
    | 'defer' ':' expr_or_block

break =
    | 'break' (()? 'at' name)?

spill =
    | 'spill'

continue = 
    | 'continue' (()? 'at' name)?

yield = 
    | 'yield' (()? 'at' name)?

return =
    | 'return' (()? 'at' name)?

raise =
    | 'raise' parens_expr

delegate =
    | 'delegate' parens_expr

await =
    | 'await' parens_expr



 
 // CONDITIONAL EXPRESSIONS
cond_expr =
    | if_expr | for_expr | while_expr

if_expr =
    | parens_expr if_head ('else' parens_expr)?

for_expr =
    | parens_expr for_head (end parens_expr)?

while_expr =
    | parens_expr 'while' if_head_content





// ANNOTATIONS // TODO 





// EXPRESSIONS
expr =
    | scop_declaration
    | cond_structure
    | simple_expr (';' simple_expr)*
    | expr ';'
    
parens_expr = 
    | '(' scop_declaration ')'
    | '(' cond_structure ')'
    | '(' simple_expr (';' simple_expr)+ ')'
    | simple_expr

simple_expr = 
    | ('ref' | 'val' | 'iso' | 'acq' | 'const') expr
    | atom
    | cond_expr
    | fix_expr 
    | lambda
    | iife
    | ctrl_primitive
    | ...

atom =
    | literals 
    | '(' expr ')' 
    | dot_or_arrow
    | subj_or_fun_call
    | indexer
    | not 
    | PH
    | PASS
    | ... 

fix_expr = 
    | prefix_expr 
    | infix_expr
    | postfix_expr

infix_expr =
    | assign_pattern '=' expr_or_block
    | parens_expr dot_op? infix_op parens_expr

prefix_expr =
    | prefix_op atom

postfix_expr =
    | parens_expr postfix_op
    | atom postfix_op

subj_or_fun_call = 
    | name | fun_call 

fun_call = 
    | name ('[' name (',' name)* ']')? fun_arg // values in generics not supported yet

indexer =
    | name index

dot_or_arrow =
    | dot | arrow | cascade_dot

cascade_dot = 
    | '.' NS '|' (cascade_arg (',' cascade_arg)* '|' NS dot
    | '|' cascade_arg (',' cascade_arg)* '|' NS dot

cascade_arg = 
    | cascade_infix_expr | cascade_postfix_expr | cascade_single_arg

cascade_infix_expr = 
    | cascade_single_arg infix_op cascade_single_arg

cascade_postfix_expr = 
    | cascade_single_arg postfix_op

cascade_single_arg = 
    | subj_or_fun_call (dot_or_arrow)*

dot = 
    | NL? '.' (NS dot_op)? NS subj_or_fun_call  
    | NL? '.' NS (index | arg_tuple)

arrow =
    | NL? '=' NS '>' (NS dot_op)? NS subj_or_fun_call 
    | NL? '=' NS '>' NS (index | arg_tuple) 

index =
    | '[' parens_expr ']'
    | range_literal

fun_arg =
    | arg_tuple
    | [^NS] (subj_or_fun_call | regex_literal | num_literal | lambda )

arg_tuple = 
    | '(' ((parens_expr | named_expr) (',' (parens_expr | named_expr))*)? ')'

not =
    | '!' subj_or_fun_call 
    | '!' '(' expr ')'

get_set =
    | '(' expr ')' '>' NS '>' '(' expr ')'
    


// LITERALS
literals =
    | ns_string_literal | STRING
    | ns_int_literal | INT
    | ns_float_literal | FLOAT
    | ns_regex_literal | regex_literal
    | ns_list_literal | list_literal 
    | ns_tuple_literal | tuple_literal | open_tuple_literal
    | ns_set_literal | set_literal
    | ns_dict_literal | dict_literal

ns_string_literal = 
    | name NS '_' NS STRING 

list_literal = 
    | ((INT (('x' | '×') INT)*)? '[' name ']')? '[' ']'
    | ((INT (('x' | '×') INT)*)? '[' name ']')? '[' parens_expr (',' parens_expr)* ']'
    | ((INT (('x' | '×') INT)*)? '[' name ']')? '[' nested_list ']'

range_literal =
    | '[' parens_expr ':' parens_expr? (':' parens_expr)? ']'
    | '[' parens_expr? ':' parens_expr (':' parens_expr)? ']'

nested_list = 
    | list_literal (CNL? list_literal)+

ns_list_literal = 
    | name NS '_' NS list_literal

open_tuple_literal =
    | parens_expr (',' parens_expr)+ 

tuple_literal = 
    | '(' ')'
    | '(' parens_expr ',' ')'
    | '(' parens_expr (',' parens_expr)+ ')'

ns_tuple_literal = 
    | name NS '_' NS tuple_literal

named_tuple_literal =  // tuple key should be statically determinable
    | '(' name ':' parens_expr (',' name ':' parens_expr)* ')'

ns_named_tuple_literal = 
    | name NS '_' NS tuple_literal

set_literal =
    | '{' '}'
    | '{' parens_expr (',' parens_expr)* '}'
    | '{' nested_set '}'

nested_set = 
    | set_literal (CNL? set_literal)+

ns_set_literal = 
    | name NS '_' NS set_literal

dict_key = 
    | '$' NS name | parens_expr

dict_literal = 
    | '{' ':' '}'
    | '{' dict_key ':' parens_expr (',' dict_key ':' parens_expr)* '}'
    | '{' nested_dict '}'

nested_dict = 
    | dict_key ':' dict_literal (CNL? dict_key ':' dict_literal)+

ns_dict_literal = 
    | name NS '_' NS dict_literal

regex_literal = 
    | '/' POSSIBLEREGEX '/'

ns_regex_literal = 
    | name NS '_' NS regex_literal

ns_int_literal =
    | INT NS '_'? name 

ns_float_literal =
    | FLOAT NS '_'? name 


// OPERATORS
infix_op = // IRRELEVANT. These will be categorized under names eventually
    | '+' | '-' | '*' | '/' | '&' | '|' 
    | 'in' 
    | ... // REGISTERED NAMES

prefix_op = // IRRELEVANT. These will be categorized under names eventually
    | '+' | '-' | '+' NS '+'
    | ... // REGISTERED NAMES

postfix_op = // IRRELEVANT. These will be categorized under names eventually
    | ... // REGISTERED NAMES

dot_op =
    | '!' | '@' | '.'



// SPECIAL PUNCTUATORS
CNL = // Comma or Newline
    | ',' NL?
    | NL

NL = 
    | NEWLINE 
    | ';'

IND =
    | INDENT 

DED = 
    | DEDENT 
    | '\\' NS '\\'
    | EOI
    // | NL '..' NL

PH = 
    | '_'

PASS = 
    | 'pass'





// LEXED UNITS 
NAME = |

NEWLINE = |

IND = |

DEDENT = |

EOL = |

INT = |

FLOAT = |

STRING = |





// SPECIAL VALUES 
NS = |

POSSIBLEREGEX = |