2017-06-25 17:51:08 +02:00
|
|
|
// whitespace is ignored except for \n which is only ignored
|
|
|
|
// most of the time, but can serve as separator in:
|
|
|
|
// - list
|
|
|
|
// - struct
|
|
|
|
// - function args
|
|
|
|
// - statements
|
|
|
|
// - list, struct and function type constraints
|
|
|
|
ws:alias = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
|
|
|
wsnl:alias = ws | "\n";
|
|
|
|
wsc:alias = ws | comment;
|
|
|
|
wsnlc:alias = wsc | "\n";
|
|
|
|
|
|
|
|
// comments can be line or block comments
|
|
|
|
line-comment-content = [^\n]*;
|
|
|
|
line-comment:alias = "//" line-comment-content;
|
|
|
|
block-comment-content = ([^*] | "*" [^/])*;
|
|
|
|
block-comment:alias = "/*" block-comment-content "*/";
|
|
|
|
comment-part:alias = line-comment | block-comment;
|
|
|
|
comment = comment-part (ws* "\n"? ws* comment-part)*;
|
|
|
|
|
|
|
|
decimal-digit:alias = [0-9];
|
|
|
|
octal-digit:alias = [0-7];
|
|
|
|
hexa-digit:alias = [0-9a-fA-F];
|
|
|
|
|
|
|
|
// interger examples: 42, 0666, 0xfff
|
|
|
|
decimal:alias = [1-9] decimal-digit*;
|
|
|
|
octal:alias = "0" octal-digit*;
|
|
|
|
hexa:alias = "0" [xX] hexa-digit+;
|
|
|
|
int = decimal | octal | hexa;
|
|
|
|
|
|
|
|
// float examples: .0, 0., 3.14, 1E-12
|
|
|
|
exponent:alias = [eE] [+\-]? decimal-digit+;
|
|
|
|
float = decimal-digit+ "." decimal-digit* exponent?
|
|
|
|
| "." decimal-digit+ exponent?
|
|
|
|
| decimal-digit+ exponent;
|
|
|
|
|
|
|
|
// string example: "Hello, world!"
|
|
|
|
// only \ and " need to be escaped, e.g. allows new lines
|
|
|
|
// common escaped chars get unescaped, the rest gets unescaped to themselves
|
|
|
|
string = "\"" ([^\\"] | "\\" .)* "\"";
|
|
|
|
|
|
|
|
true = "true";
|
|
|
|
false = "false";
|
|
|
|
bool:alias = true | false;
|
|
|
|
|
|
|
|
// symbols normally can have only \w chars: fooBar_baz
|
|
|
|
// basic symbols cannot start with a digit
|
|
|
|
// some positions allow strings to be used as symbols, e.g: let "123" 123
|
|
|
|
// when this is not possible, dynamic symbols need to be used, but they are
|
|
|
|
// not allowed in every case, e.g: {symbol(foo()): "bar"}
|
|
|
|
// TODO: needs decision log for dynamic symbol
|
|
|
|
// TODO: exclude keywords
|
|
|
|
//
|
|
|
|
// dynamic symbol decision log:
|
|
|
|
// - every value is equatable
|
|
|
|
// - structs can act as hashtables (optimization is transparent)
|
|
|
|
// - in structs, must differentiate between symbol and value of a symbol when used as a key
|
|
|
|
// - js style [a] would be enough for the structs
|
|
|
|
// - the variables in a scope are like fields in a struct
|
|
|
|
// - [a] would be ambigous with the list as an expression
|
|
|
|
// - a logical loophole is closed with symbol(a)
|
|
|
|
// - dynamic-symbols need to be handled differently in match expressions and type expressions
|
|
|
|
symbol = [a-zA-Z_][a-zA-Z_0-9]*;
|
|
|
|
static-symbol:alias = symbol | string;
|
|
|
|
dynamic-symbol = "symbol" wsc* "(" wsnlc* expression wsnlc* ")";
|
|
|
|
symbol-expression:alias = static-symbol | dynamic-symbol;
|
|
|
|
|
|
|
|
// TODO: what happens when a dynamic symbol gets exported?
|
|
|
|
|
|
|
|
// list items are separated by comma or new line (or both)
|
|
|
|
/*
|
|
|
|
[]
|
|
|
|
[a, b, c]
|
|
|
|
[
|
|
|
|
a
|
|
|
|
b
|
|
|
|
c
|
|
|
|
]
|
|
|
|
[1, 2, a..., [b, c], [d, [e]]...]
|
|
|
|
*/
|
|
|
|
spread-expression = primary-expression wsc* "...";
|
|
|
|
list-sep:alias = wsc* ("," | "\n") (wsnlc | ",")*;
|
|
|
|
list-item:alias = expression | spread-expression;
|
|
|
|
expression-list:alias = list-item (list-sep list-item)*;
|
|
|
|
|
|
|
|
// list example: [1, 2, 3]
|
|
|
|
// lists can be constructed with other lists: [l1..., l2...]
|
|
|
|
list-fact:alias = "[" (wsnlc | ",")* expression-list? (wsnlc | ",")* "]";
|
|
|
|
list = list-fact;
|
|
|
|
mutable-list = "~" wsnlc* list-fact;
|
|
|
|
|
|
|
|
indexer-symbol = "[" wsnlc* expression wsnlc* "]";
|
|
|
|
entry = (symbol-expression | indexer-symbol) wsnlc* ":" wsnlc* expression;
|
|
|
|
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
|
|
|
struct-fact:alias = "{" (wsnlc | ",")* entry-list? (wsnlc | ",")* "}";
|
|
|
|
struct = struct-fact;
|
|
|
|
mutable-struct = "~" wsnlc* struct-fact;
|
|
|
|
|
|
|
|
channel = "<>" | "<" wsnlc* int wsnlc* ">";
|
|
|
|
|
2017-07-30 05:10:46 +02:00
|
|
|
// and-expression:doc = "and" wsc* "(" (wsnlc | ",")* expression-list? (wsnlc | ",")* ")";
|
|
|
|
// or-expression:doc = "or" wsc* "(" (wsnlc | ",")* expression-list? (wsnlc | ",")* ")";
|
2017-06-25 17:51:08 +02:00
|
|
|
|
|
|
|
argument-list:alias = static-symbol (list-sep static-symbol)*;
|
|
|
|
collect-symbol = "..." wsnlc* static-symbol;
|
|
|
|
function-fact:alias = "(" (wsnlc | ",")*
|
|
|
|
argument-list?
|
|
|
|
(wsnlc | ",")*
|
|
|
|
collect-symbol?
|
|
|
|
(wsnlc | ",")* ")" wsnlc*
|
|
|
|
expression;
|
|
|
|
function = "fn" wsnlc* function-fact; // can it ever cause a conflict with call and grouping?
|
|
|
|
effect = "fn" wsnlc* "~" wsnlc* function-fact;
|
|
|
|
|
|
|
|
/*
|
|
|
|
a[42]
|
|
|
|
a[3:9]
|
|
|
|
a[:9]
|
|
|
|
a[3:]
|
|
|
|
a[b][c][d]
|
|
|
|
a.foo
|
|
|
|
a."foo"
|
|
|
|
a.symbol(foo)
|
|
|
|
*/
|
|
|
|
range-from = expression;
|
|
|
|
range-to = expression;
|
|
|
|
range-expression:alias = range-from? wsnlc* ":" wsnlc* range-to?;
|
|
|
|
indexer-expression:alias = expression | range-expression;
|
|
|
|
expression-indexer:alias = primary-expression wsc* "[" wsnlc* indexer-expression wsnlc* "]";
|
2017-06-26 02:20:23 +02:00
|
|
|
symbol-indexer:alias = primary-expression wsnlc* "." wsnlc* symbol-expression;
|
2017-06-25 17:51:08 +02:00
|
|
|
indexer = expression-indexer | symbol-indexer;
|
|
|
|
|
|
|
|
function-application = primary-expression wsc* "(" (wsnlc | ",")* expression-list? (wsnlc | ",")* ")";
|
|
|
|
|
|
|
|
if = "if" wsnlc* expression wsnlc* block
|
|
|
|
(wsnlc* "else" wsnlc* "if" wsnlc* expression wsnlc* block)*
|
|
|
|
(wsnlc* "else" wsnlc* block)?;
|
|
|
|
|
|
|
|
default = "default" wsnlc* ":";
|
|
|
|
default-line:alias = default (wsnlc | ";")* statement?;
|
|
|
|
case = "case" wsnlc* expression wsnlc* ":";
|
2017-06-26 02:20:23 +02:00
|
|
|
case-line:alias = case (wsc | ";")* statement?;
|
2017-06-25 17:51:08 +02:00
|
|
|
switch = "switch" wsnlc* expression? wsnlc* "{" (wsnlc | ";")*
|
|
|
|
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
|
|
|
(wsnlc | ";")* "}";
|
|
|
|
|
|
|
|
int-type = "int";
|
|
|
|
float-type = "float";
|
|
|
|
string-type = "string";
|
|
|
|
bool-type = "bool";
|
|
|
|
error-type = "error";
|
|
|
|
|
2017-07-15 19:04:04 +02:00
|
|
|
/*
|
|
|
|
support:
|
|
|
|
|
|
|
|
go {
|
|
|
|
foo()
|
|
|
|
bar()
|
|
|
|
}
|
|
|
|
|
|
|
|
go { for { f() } }
|
|
|
|
go func() { for { f() } }()
|
|
|
|
fn f() { go f() }; go f()
|
|
|
|
|
|
|
|
and not:
|
|
|
|
|
|
|
|
go for {foo()}
|
|
|
|
|
|
|
|
or:
|
|
|
|
|
|
|
|
go for foo()
|
|
|
|
|
|
|
|
because we don't know what the arguments are
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
fn foo() {
|
|
|
|
bar()
|
|
|
|
baz()
|
|
|
|
}
|
|
|
|
let qux foo()
|
|
|
|
|
|
|
|
equivalent to:
|
|
|
|
|
|
|
|
let qux {
|
|
|
|
bar()
|
|
|
|
baz()
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
primitive-type:alias = int-type
|
|
|
|
| float-type
|
|
|
|
| string-type
|
|
|
|
| bool-type
|
|
|
|
| error-type;
|
|
|
|
|
|
|
|
type-alias-name:alias = static-symbol;
|
|
|
|
|
|
|
|
static-range-from = int;
|
|
|
|
static-range-to = int;
|
|
|
|
static-range-expression:alias = static-range-from? wsnlc* ":" wsnlc* static-range-to?;
|
|
|
|
items-quantifier = int | static-range-expression;
|
|
|
|
// TODO: maybe this can be confusing with matching constants. Shall we support matching constants, values?
|
|
|
|
|
|
|
|
items-type = items-quantifier
|
|
|
|
| type-set (wsnlc* ":" wsnlc* items-quantifier)?
|
|
|
|
| static-symbol wsnlc* type-set (wsnlc* ":" wsnlc* items-quantifier)?;
|
|
|
|
|
|
|
|
destructure-item = type-set | static-symbol wsnlc* type-set;
|
|
|
|
|
|
|
|
collect-destructure-item = "..." wsnlc* destructure-item?
|
|
|
|
(wsnlc* ":" items-quantifier)?;
|
|
|
|
list-destructure-type = destructure-item
|
|
|
|
(list-sep destructure-item)*
|
|
|
|
(list-sep collect-destructure-item)?
|
|
|
|
| collect-destructure-item;
|
|
|
|
list-type-fact:alias = "[" (wsnlc | ",")*
|
|
|
|
(items-type | list-destructure-type)?
|
|
|
|
(wsnlc | ",")* "]";
|
|
|
|
list-type = list-type-fact;
|
|
|
|
mutable-list-type = "~" wsnlc* list-type-fact;
|
|
|
|
|
|
|
|
destructure-match-item = match-set
|
|
|
|
| static-symbol wsnlc* match-set
|
|
|
|
| static-symbol wsnlc* static-symbol wsnlc* match-set;
|
|
|
|
|
|
|
|
collect-destructure-match-item = "..." wsnlc* destructure-match-item?
|
|
|
|
(wsnlc* ":" items-quantifier)?;
|
|
|
|
list-destructure-match = destructure-match-item
|
|
|
|
(list-sep destructure-match-item)*
|
|
|
|
(list-sep collect-destructure-match-item)?
|
|
|
|
| collect-destructure-match-item;
|
|
|
|
list-match-fact:alias = "[" (wsnlc | ",")*
|
|
|
|
(list-destructure-match | items-type)?
|
|
|
|
(wsnlc | ",")* "]";
|
|
|
|
list-match = list-match-fact;
|
|
|
|
mutable-list-match = "~" wsnlc* list-match;
|
|
|
|
|
|
|
|
entry-type = static-symbol (wsnlc* ":" wsnlc* destructure-item)?;
|
|
|
|
entry-types:alias = entry-type (list-sep entry-type)*;
|
|
|
|
struct-type-fact:alias = "{" (wsnlc | ",")* entry-types? (wsnlc | ",")* "}";
|
|
|
|
struct-type = struct-type-fact;
|
|
|
|
mutable-struct-type = "~" wsnlc* struct-type-fact;
|
|
|
|
|
|
|
|
entry-match = static-symbol (wsnlc* ":" wsnlc* destructure-match-item)?;
|
|
|
|
entry-matches:alias = entry-match (list-sep entry-match)*;
|
|
|
|
struct-match-fact:alias = "{" (wsnlc | ",")* entry-matches? (wsnlc | ",")* "}";
|
|
|
|
struct-match = struct-match-fact;
|
|
|
|
mutable-struct-match = "~" wsnlc* struct-match-fact;
|
|
|
|
|
|
|
|
arg-type = type-set | static-symbol wsnlc* type-set;
|
|
|
|
args-type:alias = arg-type (list-sep arg-type)*;
|
|
|
|
function-type-fact:alias = "(" wsnlc* args-type? wsnlc* ")"
|
|
|
|
(wsc* (type-set | static-symbol wsc* type-set))?;
|
|
|
|
function-type = "fn" wsnlc* function-type-fact;
|
|
|
|
effect-type = "fn" wsnlc* "~" wsnlc* function-type-fact;
|
|
|
|
|
|
|
|
// TODO: heavy naming crime
|
|
|
|
|
|
|
|
receive-direction = "receive";
|
|
|
|
send-direction = "send";
|
|
|
|
channel-type = "<" wsnlc*
|
|
|
|
(receive-direction | send-direction)? wsnlc*
|
|
|
|
destructure-item?
|
|
|
|
wsnlc* ">";
|
|
|
|
|
|
|
|
type-fact-group:alias = "(" wsnlc* type-fact wsnlc* ")";
|
|
|
|
type-fact:alias = primitive-type
|
|
|
|
| type-alias-name
|
|
|
|
| list-type
|
|
|
|
| mutable-list-type
|
|
|
|
| struct-type
|
|
|
|
| mutable-struct-type
|
|
|
|
| function-type
|
|
|
|
| effect-type
|
|
|
|
| channel-type
|
|
|
|
| type-fact-group;
|
|
|
|
|
|
|
|
type-set:alias = type-fact (wsnlc* "|" wsnlc* type-fact)*;
|
|
|
|
type-expression:alias = type-set | static-symbol wsc* type-set;
|
|
|
|
|
|
|
|
match-fact:alias = list-match
|
|
|
|
| mutable-list-match
|
|
|
|
| struct-match
|
|
|
|
| mutable-struct-match;
|
|
|
|
|
|
|
|
match-set:alias = type-set | match-fact;
|
|
|
|
match-expression:alias = match-set | static-symbol wsc* match-set;
|
|
|
|
|
|
|
|
match-case = "case" wsnlc* match-expression wsnlc* ":";
|
2017-06-26 02:20:23 +02:00
|
|
|
match-case-line:alias = match-case (wsc | ";")* statement?;
|
2017-06-25 17:51:08 +02:00
|
|
|
match = "match" wsnlc* expression wsnlc* "{" (wsnlc | ";")*
|
|
|
|
((match-case-line | default-line)
|
|
|
|
(sep (match-case-line | default-line | statement))*)?
|
|
|
|
(wsnlc | ";")* "}";
|
|
|
|
|
|
|
|
conditional:alias = if
|
|
|
|
| switch
|
|
|
|
| match;
|
|
|
|
|
|
|
|
receive-call = "receive" wsc* "(" (wsnlc | ",")* expression (wsnlc | ",")* ")";
|
|
|
|
receive-op = "<-" wsc* primary-expression;
|
|
|
|
receive-expression-group:alias = "(" wsnlc* receive-expression wsnlc* ")";
|
|
|
|
receive-expression:alias = receive-call | receive-op | receive-expression-group;
|
|
|
|
|
|
|
|
receive-assign-capture:alias = assignable wsnlc* ("=" wsnlc*)? receive-expression;
|
|
|
|
receive-assignment = "set" wsnlc* receive-assign-capture;
|
|
|
|
receive-assignment-equal = assignable wsnlc* "=" wsnlc* receive-expression;
|
|
|
|
receive-capture:alias = symbol-expression wsnlc* ("=" wsnlc*)? receive-expression;
|
|
|
|
receive-definition = "let" wsnlc* receive-capture;
|
2017-07-31 00:30:52 +02:00
|
|
|
receive-mutable-definition = "let" wsnlc* "~" wsnlc* receive-capture;
|
2017-06-25 17:51:08 +02:00
|
|
|
receive-statement:alias = receive-assignment | receive-definition;
|
|
|
|
|
|
|
|
send-call:alias = "send" wsc* "(" (wsnlc | ",")* expression list-sep expression (wsnlc | ",")* ")";
|
|
|
|
send-op:alias = primary-expression wsc* "<-" wsc* expression;
|
|
|
|
send-call-group:alias = "(" wsnlc* send wsnlc* ")";
|
|
|
|
send = send-call | send-op | send-call-group;
|
|
|
|
|
|
|
|
close = "close" wsc* "(" (wsnlc | ",")* expression (wsnlc | ",")* ")";
|
|
|
|
|
|
|
|
communication-group:alias = "(" wsnlc* communication wsnlc* ")";
|
|
|
|
communication:alias = receive-expression | receive-statement | send | communication-group;
|
|
|
|
|
|
|
|
select-case = "case" wsnlc* communication wsnlc* ":";
|
2017-06-26 02:20:23 +02:00
|
|
|
select-case-line:alias = select-case (wsc | ";")* statement?;
|
2017-06-25 17:51:08 +02:00
|
|
|
select = "select" wsnlc* "{" (wsnlc | ";")*
|
|
|
|
((select-case-line | default-line)
|
|
|
|
(sep (select-case-line | default-line | statement))*)?
|
|
|
|
(wsnlc | ";")* "}";
|
|
|
|
|
2017-07-15 19:04:04 +02:00
|
|
|
go = "go" wsnlc* (function-application | block);
|
2017-06-25 17:51:08 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
require . = "mml/foo"
|
|
|
|
require bar = "mml/foo"
|
|
|
|
require . "mml/foo"
|
|
|
|
require bar "mml/foo"
|
|
|
|
require "mml/foo"
|
|
|
|
require (
|
|
|
|
. = "mml/foo"
|
|
|
|
bar = "mml/foo"
|
|
|
|
. "mml/foo"
|
|
|
|
bar "mml/foo"
|
|
|
|
"mml/foo"
|
|
|
|
)
|
|
|
|
require ()
|
|
|
|
*/
|
|
|
|
require-inline = ".";
|
|
|
|
require-fact = string
|
|
|
|
| (static-symbol | require-inline) (wsnlc* "=")? wsnlc* string;
|
|
|
|
require-facts:alias = require-fact (list-sep require-fact)*;
|
|
|
|
require-statement:alias = "require" wsnlc* require-fact;
|
|
|
|
require-statement-group:alias = "require" wsc* "(" (wsnlc | ",")*
|
|
|
|
require-facts?
|
|
|
|
(wsnlc | ",")* ")";
|
|
|
|
require = require-statement | require-statement-group;
|
|
|
|
|
|
|
|
panic = "panic" wsc* "(" (wsnlc | ",")* expression (wsnlc | ",")* ")";
|
|
|
|
recover = "recover" wsc* "(" (wsnlc | ",")* ")";
|
|
|
|
|
|
|
|
block = "{" (wsnlc | ";")* statements? (wsnlc | ";")* "}";
|
|
|
|
expression-group:alias = "(" wsnlc* expression wsnlc* ")";
|
|
|
|
|
|
|
|
primary-expression:alias = int
|
|
|
|
| float
|
|
|
|
| string
|
|
|
|
| bool
|
|
|
|
| symbol
|
|
|
|
| dynamic-symbol
|
|
|
|
| list
|
|
|
|
| mutable-list
|
|
|
|
| struct
|
|
|
|
| mutable-struct
|
|
|
|
| channel
|
2017-07-30 05:10:46 +02:00
|
|
|
// | and-expression // only documentation
|
|
|
|
// | or-expression // only documentation
|
2017-06-25 17:51:08 +02:00
|
|
|
| function
|
|
|
|
| effect
|
|
|
|
| indexer
|
|
|
|
| function-application // pseudo-expression
|
|
|
|
| conditional // pseudo-expression
|
|
|
|
| receive-call
|
|
|
|
| select // pseudo-expression
|
|
|
|
| recover
|
|
|
|
| block // pseudo-expression
|
|
|
|
| expression-group;
|
|
|
|
|
|
|
|
plus = "+";
|
|
|
|
minus = "-";
|
|
|
|
logical-not = "!";
|
|
|
|
binary-not = "^";
|
|
|
|
unary-operator:alias = plus | minus | logical-not | binary-not;
|
|
|
|
unary-expression = unary-operator wsc* primary-expression | receive-op;
|
|
|
|
|
|
|
|
mul = "*";
|
|
|
|
div = "/";
|
|
|
|
mod = "%";
|
|
|
|
lshift = "<<";
|
|
|
|
rshift = ">>";
|
|
|
|
binary-and = "&";
|
|
|
|
and-not = "&^";
|
|
|
|
|
|
|
|
add = "+";
|
|
|
|
sub = "-";
|
|
|
|
binary-or = "|";
|
|
|
|
xor = "^";
|
|
|
|
|
|
|
|
eq = "==";
|
|
|
|
not-eq = "!=";
|
|
|
|
less = "<";
|
|
|
|
less-or-eq = "<=";
|
|
|
|
greater = ">";
|
|
|
|
greater-or-eq = ">=";
|
|
|
|
|
|
|
|
logical-and = "&&";
|
|
|
|
logical-or = "||";
|
|
|
|
|
|
|
|
chain = "->";
|
|
|
|
|
|
|
|
binary-op0:alias = mul | div | mod | lshift | rshift | binary-and | and-not;
|
|
|
|
binary-op1:alias = add | sub | binary-or | xor;
|
|
|
|
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
|
|
|
binary-op3:alias = logical-and;
|
|
|
|
binary-op4:alias = logical-or;
|
|
|
|
binary-op5:alias = chain;
|
|
|
|
|
|
|
|
operand0:alias = primary-expression | unary-expression;
|
|
|
|
operand1:alias = operand0 | binary0;
|
|
|
|
operand2:alias = operand1 | binary1;
|
|
|
|
operand3:alias = operand2 | binary2;
|
|
|
|
operand4:alias = operand3 | binary3;
|
|
|
|
operand5:alias = operand4 | binary4;
|
|
|
|
|
|
|
|
binary0 = operand0 wsc* binary-op0 wsc* operand0;
|
|
|
|
binary1 = operand1 wsc* binary-op1 wsc* operand1;
|
|
|
|
binary2 = operand2 wsc* binary-op2 wsc* operand2;
|
|
|
|
binary3 = operand3 wsc* binary-op3 wsc* operand3;
|
|
|
|
binary4 = operand4 wsc* binary-op4 wsc* operand4;
|
|
|
|
binary5 = operand5 wsc* binary-op5 wsc* operand5;
|
|
|
|
|
|
|
|
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4 | binary5;
|
|
|
|
|
|
|
|
ternary-expression = expression wsnlc* "?" wsnlc* expression wsnlc* ":" wsnlc* expression;
|
|
|
|
|
|
|
|
expression:alias = primary-expression
|
|
|
|
| unary-expression
|
|
|
|
| binary-expression
|
|
|
|
| ternary-expression;
|
|
|
|
|
|
|
|
// TODO: code()
|
|
|
|
// TODO: observability
|
|
|
|
|
|
|
|
break = "break";
|
|
|
|
continue = "continue";
|
|
|
|
loop-control:alias = break | continue;
|
|
|
|
|
|
|
|
in-expression = static-symbol wsnlc* "in" wsnlc* (expression | range-expression);
|
|
|
|
loop-expression = expression | in-expression;
|
|
|
|
loop = "for" wsnlc* (block | loop-expression wsnlc* block);
|
|
|
|
|
|
|
|
/*
|
|
|
|
a = b
|
|
|
|
set c = d
|
|
|
|
set e f
|
|
|
|
set (
|
|
|
|
g = h
|
|
|
|
i j
|
|
|
|
)
|
|
|
|
*/
|
|
|
|
assignable:alias = symbol-expression | indexer;
|
|
|
|
assign-capture = assignable wsnlc* ("=" wsnlc*)? expression;
|
|
|
|
assign-set:alias = "set" wsnlc* assign-capture;
|
|
|
|
assign-equal = assignable wsnlc* "=" wsnlc* expression;
|
|
|
|
assign-captures:alias = assign-capture (list-sep assign-capture)*;
|
|
|
|
assign-group:alias = "set" wsnlc* "(" (wsnlc | ",")* assign-captures? (wsnlc | ",")* ")";
|
|
|
|
assignment = assign-set | assign-equal | assign-group;
|
|
|
|
|
|
|
|
/*
|
|
|
|
let a = b
|
|
|
|
let c d
|
|
|
|
let ~ e = f
|
|
|
|
let ~ g h
|
|
|
|
let (
|
|
|
|
i = j
|
|
|
|
k l
|
|
|
|
~ m = n
|
|
|
|
~ o p
|
|
|
|
)
|
|
|
|
let ~ (
|
|
|
|
q = r
|
|
|
|
s t
|
|
|
|
)
|
|
|
|
*/
|
|
|
|
value-capture-fact:alias = symbol-expression wsnlc* ("=" wsnlc*)? expression;
|
|
|
|
value-capture = value-capture-fact;
|
|
|
|
mutable-capture = "~" wsnlc* value-capture-fact;
|
|
|
|
value-definition = "let" wsnlc* (value-capture | mutable-capture);
|
|
|
|
value-captures:alias = value-capture (list-sep value-capture)*;
|
|
|
|
mixed-captures:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
|
|
|
|
value-definition-group = "let" wsnlc* "(" (wsnlc | ",")* mixed-captures? (wsnlc | ",")* ")";
|
|
|
|
mutable-definition-group = "let" wsnlc* "~" wsnlc* "(" (wsnlc | ",")* value-captures? (wsnlc | ",")* ")";
|
|
|
|
|
|
|
|
/*
|
|
|
|
fn a() b
|
|
|
|
fn ~ c() d
|
|
|
|
fn (
|
|
|
|
e() f
|
|
|
|
~ g() h
|
|
|
|
)
|
|
|
|
fn ~ (
|
|
|
|
i()
|
|
|
|
j()
|
|
|
|
)
|
|
|
|
*/
|
|
|
|
function-definition-fact:alias = static-symbol wsnlc* function-fact;
|
|
|
|
function-capture = function-definition-fact;
|
|
|
|
effect-capture = "~" wsnlc* function-definition-fact;
|
|
|
|
function-definition = "fn" wsnlc* (function-capture | effect-capture);
|
|
|
|
function-captures:alias = function-capture (list-sep function-capture)*;
|
|
|
|
mixed-function-captures:alias = (function-capture | effect-capture)
|
|
|
|
(list-sep (function-capture | effect-capture))*;
|
|
|
|
function-definition-group = "fn" wsnlc* "(" (wsnlc | ",")*
|
|
|
|
mixed-function-captures?
|
|
|
|
(wsnlc | ",")* ")";
|
|
|
|
effect-definition-group = "fn" wsnlc* "~" wsnlc* "(" (wsnlc | ",")*
|
|
|
|
function-captures?
|
|
|
|
(wsnlc | ",")* ")";
|
|
|
|
|
|
|
|
definition:alias = value-definition
|
|
|
|
| value-definition-group
|
|
|
|
| mutable-definition-group
|
|
|
|
| function-definition
|
|
|
|
| function-definition-group
|
|
|
|
| effect-definition-group;
|
|
|
|
|
|
|
|
type-alias = "type" wsnlc* "alias" wsnlc* static-symbol wsnlc* type-set;
|
|
|
|
type-constraint = "type" wsnlc* static-symbol wsnlc* type-set;
|
|
|
|
|
|
|
|
statement-group:alias = "(" wsnlc* statement wsnlc* ")";
|
|
|
|
|
|
|
|
statement:alias = send
|
|
|
|
| close
|
|
|
|
| panic
|
|
|
|
| require
|
|
|
|
| loop-control
|
|
|
|
| go
|
|
|
|
| loop
|
|
|
|
| assignment
|
|
|
|
| definition
|
|
|
|
| expression
|
|
|
|
| type-alias
|
|
|
|
| type-constraint
|
|
|
|
| statement-group;
|
|
|
|
|
|
|
|
shebang-command = [^\n]*;
|
|
|
|
shebang = "#!" shebang-command "\n";
|
|
|
|
sep:alias = wsc* (";" | "\n") (wsnlc | ";")*;
|
|
|
|
statements:alias = statement (sep statement)*;
|
|
|
|
mml:root = shebang? (wsnlc | ";")* statements? (wsnlc | ";")*;
|