// Comments are introduced by # and terminated by newline program ::= (statement ';'?)*; statement ::= definition; definition ::= 'def' def-spec '=' expression | 'def' '_' '=' expression ; def-spec ::= IDENTIFIER arg-spec*; arg-spec ::= '(' arg-spec ')' | IDENTIFIER | arg-spec-tuple | '_'; arg-spec-tuple ::= '(' ')' | '(' arg-spec ',' arg-spec (',' arg-spec)* ','? ')'; expression ::= binary-expression | unary-expression; unary-expression ::= unop+ simple-expression; binary-expression ::= call-expression (binop call-expression)*; call-expression ::= member-access-expression+; binop ::= '*' | '/' | '+' | '-' | '?=' | '/=' | '>' | '>=' | '<' | '<='; unop ::= '+' | '-' | '!'; member-access-expression ::= simple-expression (member-access)*; member-access ::= '.[' expression ']'; simple-expression ::= '(' expression ')' | 'true' | 'false' | INTEGER | IDENTIFIER | STRING | array | map | tuple | do-expression | fn-expression | if-else-expression | let-in-expression ; array ::= '[' ']' | '[' expression (',' expression)* ','? ']'; map ::= '{' '}' | '{' expression '->' expression (',' expression '->' expression) ','? '}'; // Note that tuples always have either zero or at least two elements // A tuple with only one element is just '(' expression ')' -- a parenthese-wrapped expression // Also '(' expression ',' ')' is illegal tuple ::= '(' ')' | '(' expression ',' expression (',' expression)* ','? ')'; do-expression ::= 'do' expression (';' expression)* 'end'; fn-expression ::= 'fn' arg-spec+ '->' expression | 'fn' arg-spec+ do-expression ; if-else-expression ::= 'if' expression 'then' expression 'else' expression; let-in-expression ::= 'let' def-spec '=' expression ('and' def-spec '=' expression)* 'in' expression; repl-program ::= (repl-statement ';'?)* '\n'; // currently, hard-limited by the newline :sweat_smile: repl-statement ::= statement | expression; // TODO: Note that arg-spec and simple-expression are getting similar, both in grammar and in parser code