(* Syntax definition for Vellum *) module ::= module-definition [module-imports] ns-decl-seq module-definition ::= ['export'] 'module' module-name ';' module-name ::= identifier | identifier '::' module-name | identifier '::' '{' module-name-list '}' module-name-list ::= module-name | module-name ',' module-name-list module-imports ::= {['export'] 'import' module-name ';'} ns-decl-seq ::= { ['export'] declaration } declaration ::= fn-declaration | struct-declaration | enum-definition | trait-definition | global-var-declaration | alias-definition | extern-declaration | namespace-block fn-declaration ::= prototype fn-body | prototype ';' fn-body ::= block | '=' expression ';' | '=' 'delete' [reason-expr] ';' prototype ::= fn-prologue fn-name fn-signature anon-prototype ::= fn-prologue fn-signature fn-signature ::= argument-list [return-spec] | '(' fn-signature ')' return-spec ::= '->' type-constraint fn-prologue ::= ('fn' | 'proc') argument-list ::= '(' {arg-definition [default-arg]} ')' arg-definition ::= arg-name [':' arg-type-constraint] var-declaration ::= 'let' var-definition var-initializer ';' | 'let' 'const' var-definition var-initializer ';' | 'let' 'mut' var-definition [var-initializer] ';' var-definition ::= var-name [':' type-constraint] var-initializer ::= equal-initializer | braced-initializer equal-initializer ::= '=' expression braced-initializer ::= '{' expression-list '}' (* no mutable global variables *) global-var-declaration ::= 'let' var-definition var-initializer ';' | 'let' 'const' var-definition var-initializer ';' alias-definition ::= 'alias' identifier '=' type-id ';' extern-declaration ::= 'extern' [ string-literal ] fn-declaration | 'extern' [ string-literal ] '{' ns-decl-seq '}' namespace-block ::= 'namespace' namespace-id '{' ns-decl-seq '}' namespace-id ::= qualified-name reason-expr ::= '(' string-literal ')' struct-declaration ::= 'struct' struct-name [argument-list] (';' | struct-body) struct-body ::= '{' {struct-member} '}' struct-member ::= data-member-definition | [access-key] fn-declaration | [access-key] default-fn-definition | 'defer' trait-id 'to' identifier new-line | 'implements' trait-id new-line | alias-definition data-member-definition ::= 'let' var-name ':' type-id access-specifier access-specifier ::= '{' (access-key [',' access-key2] ['mut']) '}' access-key ::= 'public' | access-key2 access-key2 ::= 'module' | 'private' default-fn-definition ::= [access-key] 'fn' default-fn-id '=' 'default' ';' default-fn-id ::= 'new' [argument-list] [type-constraint] enum-definition ::= 'enum' enum-name '{' enumerator {',' enumerator} [','] '}' enumerator ::= identifier ['=' expression] trait-definition ::= 'trait' trait-name argument-list '{' {trait-member} '}' trait-member ::= prototype ';' | 'implements' trait-id new-line block ::= '{' {statement} '}' statement ::= expression new-line | var-declaration new-line | block | struct-declaration (* TODO: sort out precedences *) expression ::= primary-expression | assignment-expression | unary-expression | binary-expression | or-expression | rewrite-expression expression ::= assignment-expression | control-expression assignment-expression ::= and-expression ':=' assignment-expression control-expression ::= loop-expression | if-expression | match-expression | result-expression | try-expression | substrate-expression | llvm-ir-expression | 'continue' [label] result-expression ::= 'result' [label] [expression] | 'yield' [label] [expression] | 'return' [expression] | 'break' [label] | 'end' [label] primary-expression ::= literal | id-expression | '(' expression ')' | tuple-expression | call-expression | tuple-expression | subscript-expression | dot-expression | placeholder-id | lambda-expression | if-expression | match-expression | loop-expression | control-expression | await-expression expression-list ::= | expression {',' expression} assignment-expression ::= expression ':=' expression binary-expression ::= expression binary-operator expression call-expression ::= primary-expression '(' expression-list ')' subscript-expression ::= primary-expression '[' expression-list ']' substrate-expression ::= 'substrate' '{' { substrate-word } '}' | '(:' { substrate-word } ':)' substrate-word ::= literal | id-expression | control-keyword control-keyword ::= 'if' | 'result' | 'yield' | 'return' | 'break' | 'end' (* Rather than trying to define the grammar of LLVM IR here, just accept any string of tokens that has balanced brackets and then sort it out in semantic analysis *) llvm-ir-expression ::= 'llvm' '{' balanced-code '}' balanced-code ::= identifier balanced-code | literal balanced-code | operator balanced-code | non-bracket-punctuator balanced-code | keyword balanced-code | '(' balanced-code ')' | '[' balanced-code ']' | '{' balanced-code '}' | '#[' balanced-code ']' | empty if-expression ::= ('if' | 'unless') condition block ['else' (block | if-expression)] | expression '?' expression ':' expression inverted-if-expression ::= expression 'if' expression ['else' expression] match-expression ::= 'match' condition '{' match-rule {',' match-rule} [',' [trivial-match]] '}' match-rule ::= match-specifier '->' (expression | block) match-specifier ::= argument-list | case-specifier (* can stack cases *) case-specifier ::= 'case' primary-expression [case-specifier] (* Local function can be either named or anonymous. Naming allows recursion. *) lambda-expression ::= (prototype | anon-prototype) fn-body tuple-expression ::= '(' expression (',' | {',' expression} [','] ) ')' | '(' ')' (* All loops can be labeled, allowing for named multi-level break *) loop-expression ::= (* See below for examples *) 'for' [label] for-loop-header block ['else' expression] (* while and do-while loops: while keepgoing() { go() } do { go() } until stop(); *) | loop-constraint [label] condition block ['else' expression] | 'do' [label] block loop-constraint condition (';' | ['else' expression]) (* infinite loop: loop { go(); break if stop() go(); } 'loop' loops have no else because they have no condition that can be false *) | 'loop' [label] block for-loop-header ::= (* iteration: for i in range { print(i) } *) var-definition 'in' expression (* counting: //count 0 to 9 for i = 0 -> 10 { print(i) } // count 10 to 1 for i = 10 ; -1 { print(i) } // count -10 to 8 by 2s for i = -10 -> 10 ; +2 { print(i) } counting from 0: // count 0 to 9 for i -> 10 { print(i) } init and bound default to 0? step defaults to +1 or -1, to reach bound? *) | loop-var-init ['->' expression] [';' {'+' | '-'} integer-literal] (* generalized for loop: for i = 10 while i > 1 ; = i / 2 { print(i) } for i = begin() while i != end() ; = i.next() { print(i) } *) | loop-var-init loop-constraint [';' '=' expression | ';' {'+' | '-'} integer-literal] loop-constraint ::= 'while' (* equivalent to `while not` *) | 'until' loop-var-init ::= ['mut'] var-definition [equal-initializer] | '_' label ::= ':' identifier | ':' ('for' | 'while' | 'do' | 'loop') condition ::= expression | 'let' var-definition equal-initializer list-comprehension ::= dot-expression ::= expression '.' call-expression or-expression ::= and-expression 'or' and-expression and-expression ::= primary-expression 'and' primary-expression binary-operator ::= '+' | '-' | '*' | '/' | '%' | '+?' | '-?' | '+%' | '-%' | '==' | '!=' | '<=>' | '<' | '>' | '<=' | '>=' | '&' | '|' | '^' | '??' prefix-operator ::= '-' | '+' | '~' | 'not' | '@' | '#' | 'await' postfix-operator ::= '^' | '?' operator ::= binary-operator | prefix-operator | postfix-operator | special-operator (**) type-constraint ::= type-name | fn-name '(' {expression} ')' | struct-name '(' {type-constraint | value-constraint} ')' | trait-id | '[' ']' type-constraint | '[' value-constraint ']' type-constraint | '*' '"C"' type-constraint | '*' '"C"' 'mut' type-constraint | '&' type-constraint | '&' 'mut' type-constraint | '?' type-constraint | '(' [type-constraint {',' type-constraint} [',']] ')' | type-constraint {'|' type-constraint} | '$' identifier | '(' '$' arg-definition ')' | empty value-constraint ::= constant-expression | '$' arg-definition type-name ::= builtin-type | struct-id struct-id ::= struct-name ['(' {expression} ')'] builtin-type ::= 'Float32' | 'Float64' | 'Bool' | 'None' | 'Type' | 'Noreturn' | 'This' | 'i\d+' | 'u\d+' | '__int8' | '__int16' | '__int32' | '__int64' | '__uint8' | '__uint16' | '__uint32' | '__uint64' fn-name ::= identifier struct-name ::= identifier trait-name ::= identifier var-name ::= identifier [',' var-name] arg-name ::= identifier attribute-list ::= '#[' attribute {',' attribute} ']' attribute ::= qualified-name ['(' expression-list ')'] qualified-name ::= [ '::' ] {namespace-id '::'} identifier [ '!' integer-literal ] | [ 'Bool' '::' ] bool-literal new-line ::= '\n' | ';' empty ::= keyword ::= 'None' | 'Noreturn' | 'This' | 'Type' | 'alias' | 'and' | 'as' | 'Bool' | 'break' | 'continue' | 'defer' | 'delete' | 'do' | 'else' | 'end' | 'enum' | 'export' | 'Fail' | 'Float' | 'Float32' | 'Float64' | 'fn' | 'for' | 'if' | 'implements' | 'import' | 'is' | 'Int' | 'Unsigned' | 'let' | 'loop' | 'module' | 'mut' | 'or' | 'private' | 'proc' | 'public' | 'result' | 'return' | 'struct' | 'trait' | 'unless' | 'until' | 'while' | 'yield' | '__[[:alnum:]_]*' raw-identifier ::= '\p{Letter}[\p{Letter}\p{Digit}_]*' identifier ::= raw-identifier - keyword - placeholder-id - reserved-id | '`' raw-identifier '`' | '`' token { token - '`' } '`'