formatter script for local syntax files
This commit is contained in:
parent
b8036802f6
commit
e025778538
13
Makefile
13
Makefile
@ -19,7 +19,7 @@ default: build
|
|||||||
|
|
||||||
.build/head.go: $(sources) .build
|
.build/head.go: $(sources) .build
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
go run scripts/createhead.go -- \
|
go run script/createhead.go -- \
|
||||||
char.go \
|
char.go \
|
||||||
sequence.go \
|
sequence.go \
|
||||||
choice.go \
|
choice.go \
|
||||||
@ -36,7 +36,7 @@ head.go: .build/head.go
|
|||||||
|
|
||||||
.build/headexported.go: $(sources) .build
|
.build/headexported.go: $(sources) .build
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
go run scripts/createhead.go --exported -- \
|
go run script/createhead.go --exported -- \
|
||||||
char.go \
|
char.go \
|
||||||
sequence.go \
|
sequence.go \
|
||||||
choice.go \
|
choice.go \
|
||||||
@ -75,12 +75,12 @@ lib: $(sources) head.go headexported.go internal/self/self.go
|
|||||||
go build ./internal/self
|
go build ./internal/self
|
||||||
|
|
||||||
cmd/treerack/docreflect.gen.go: $(sources) .build
|
cmd/treerack/docreflect.gen.go: $(sources) .build
|
||||||
go run scripts/docreflect.go > .build/docreflect.gen.go
|
go run script/docreflect.go > .build/docreflect.gen.go
|
||||||
go fmt .build/docreflect.gen.go
|
go fmt .build/docreflect.gen.go
|
||||||
mv .build/docreflect.gen.go cmd/treerack
|
mv .build/docreflect.gen.go cmd/treerack
|
||||||
|
|
||||||
cmd/treerack/readme.md: $(sources) cmd/treerack/docreflect.gen.go
|
cmd/treerack/readme.md: $(sources) cmd/treerack/docreflect.gen.go
|
||||||
go run scripts/cmdreadme.go ./cmd/treerack > cmd/treerack/readme.md || \
|
go run script/cmdreadme.go ./cmd/treerack > cmd/treerack/readme.md || \
|
||||||
rm cmd/treerack/readme.md
|
rm cmd/treerack/readme.md
|
||||||
|
|
||||||
.build/treerack: $(sources) lib cmd/treerack/docreflect.gen.go .build
|
.build/treerack: $(sources) lib cmd/treerack/docreflect.gen.go .build
|
||||||
@ -88,7 +88,7 @@ cmd/treerack/readme.md: $(sources) cmd/treerack/docreflect.gen.go
|
|||||||
|
|
||||||
|
|
||||||
.build/treerack.1: $(sources) cmd/treerack/docreflect.gen.go .build
|
.build/treerack.1: $(sources) cmd/treerack/docreflect.gen.go .build
|
||||||
go run scripts/man.go $(version) $(release_date) > .build/treerack.1 || \
|
go run script/man.go $(version) $(release_date) > .build/treerack.1 || \
|
||||||
rm .build/treerack.1
|
rm .build/treerack.1
|
||||||
|
|
||||||
build: lib cmd/treerack/readme.md .build/treerack .build/treerack.1
|
build: lib cmd/treerack/readme.md .build/treerack .build/treerack.1
|
||||||
@ -135,8 +135,9 @@ cpu.out: $(sources)
|
|||||||
cpu: cpu.out
|
cpu: cpu.out
|
||||||
go tool pprof -top cpu.out
|
go tool pprof -top cpu.out
|
||||||
|
|
||||||
fmt: $(sources) head.go headexported.go internal/self/self.go cmd/treerack/docreflect.gen.go
|
fmt: $(sources) $(parsers) head.go headexported.go internal/self/self.go cmd/treerack/docreflect.gen.go
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
go run script/format.go $(parsers)
|
||||||
|
|
||||||
$(prefix)/bin/treerack: .build/treerack
|
$(prefix)/bin/treerack: .build/treerack
|
||||||
mkdir -p $(prefix)/bin
|
mkdir -p $(prefix)/bin
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
foo = "bar"
|
foo = "bar";
|
||||||
|
|||||||
@ -44,4 +44,4 @@ expression:alias = num | group | binary;
|
|||||||
//
|
//
|
||||||
// Note that we don't need to use the :root flag here, because it is our last definition, and this means that
|
// Note that we don't need to use the :root flag here, because it is our last definition, and this means that
|
||||||
// the expression is the root parser of the syntax.
|
// the expression is the root parser of the syntax.
|
||||||
result = expression | "exit"
|
result = expression | "exit";
|
||||||
14
doc/example/keyval.treerack
Normal file
14
doc/example/keyval.treerack
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
whitespace:ws = [ \b\f\r\t\v];
|
||||||
|
comment-line:alias = "#" [^\n]*;
|
||||||
|
comment = comment-line ("\n" comment-line)*;
|
||||||
|
quoted:alias:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
|
word:alias:nows = ([^\\"\n=#.\[\] \b\f\r\t\v] | "\\" .)+;
|
||||||
|
symbol = word+ | quoted;
|
||||||
|
key-form:alias = symbol ("." symbol)*;
|
||||||
|
key = key-form;
|
||||||
|
group-key = (comment "\n")? "[" key-form "]";
|
||||||
|
value-chars:alias:nows = ([^\\"\n=# \b\f\r\t\v] | "\\" .)+;
|
||||||
|
value = value-chars+ | quoted;
|
||||||
|
key-val = (comment "\n")? (key | key? "=" value?) comment-line?;
|
||||||
|
entry:alias = group-key | key-val;
|
||||||
|
doc:root = (entry | comment-line | "\n")*;
|
||||||
504
doc/example/mml-exp.treerack
Normal file
504
doc/example/mml-exp.treerack
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// comments are not ignored because they are needed during formatting
|
||||||
|
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
||||||
|
wsc:ws = comment;
|
||||||
|
nl:alias = "\n";
|
||||||
|
|
||||||
|
// comments can be line or block comments
|
||||||
|
// indentation can hold meaning
|
||||||
|
line-comment-content:nows = [^\n]*;
|
||||||
|
line-comment:alias:nows = "//" line-comment-content;
|
||||||
|
block-comment-content:nows = ([^*] | "*" [^/])*; // TODO: why is the :nows required here if it is there for block-comment?
|
||||||
|
block-comment:alias:nows = "/*" block-comment-content "*/";
|
||||||
|
comment-part:alias = line-comment | block-comment;
|
||||||
|
comment:alias = comment-part ("\n"? 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:nows = [1-9] decimal-digit*;
|
||||||
|
octal:alias:nows = "0" octal-digit*;
|
||||||
|
hexa:alias:nows = "0" [xX] hexa-digit+;
|
||||||
|
int = decimal | octal | hexa;
|
||||||
|
|
||||||
|
// float examples: .0, 0., 3.14, 1E-12
|
||||||
|
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
||||||
|
float:nows = 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:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
|
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:nows = [a-zA-Z_] [a-zA-Z_0-9]*;
|
||||||
|
static-symbol:alias = symbol | string;
|
||||||
|
dynamic-symbol = "symbol" "(" nl* expression nl* ")";
|
||||||
|
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 "...";
|
||||||
|
list-sep:alias = ("," | "\n") (nl | ",")*;
|
||||||
|
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 = "[" (nl | ",")* expression-list? (nl | ",")* "]";
|
||||||
|
list = list-fact;
|
||||||
|
mutable-list = "~" nl* list-fact;
|
||||||
|
indexer-symbol = "[" nl* expression nl* "]";
|
||||||
|
entry = (symbol-expression | indexer-symbol) nl* ":" nl* expression;
|
||||||
|
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
||||||
|
struct-fact:alias = "{" (nl | ",")* entry-list? (nl | ",")* "}";
|
||||||
|
struct = struct-fact;
|
||||||
|
mutable-struct = "~" nl* struct-fact;
|
||||||
|
channel = "<>" | "<" nl* int nl* ">";
|
||||||
|
|
||||||
|
// and-expression:doc = "and" "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
||||||
|
// or-expression:doc = "or" "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
||||||
|
|
||||||
|
argument-list:alias = static-symbol (list-sep static-symbol)*;
|
||||||
|
collect-symbol = "..." nl* static-symbol;
|
||||||
|
function-fact:alias = "(" (nl | ",")* argument-list? (nl | ",")* collect-symbol? (nl | ",")* ")" nl* expression;
|
||||||
|
function = "fn" nl* function-fact; // can it ever cause a conflict with call and grouping?
|
||||||
|
effect = "fn" nl* "~" nl* 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? nl* ":" nl* range-to?;
|
||||||
|
indexer-expression:alias = expression | range-expression;
|
||||||
|
expression-indexer:alias = primary-expression "[" nl* indexer-expression nl* "]";
|
||||||
|
symbol-indexer:alias = primary-expression nl* "." nl* symbol-expression;
|
||||||
|
indexer = expression-indexer | symbol-indexer;
|
||||||
|
function-application = primary-expression "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
||||||
|
if = "if"
|
||||||
|
nl*
|
||||||
|
expression
|
||||||
|
nl*
|
||||||
|
block
|
||||||
|
(nl* "else" nl* "if" nl* expression nl* block)*
|
||||||
|
(nl* "else" nl* block)?;
|
||||||
|
default = "default" nl* ":";
|
||||||
|
default-line:alias = default (nl | ";")* statement?;
|
||||||
|
case = "case" nl* expression nl* ":";
|
||||||
|
case-line:alias = case ";"* statement?;
|
||||||
|
switch = "switch"
|
||||||
|
nl*
|
||||||
|
expression?
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
(nl | ";")*
|
||||||
|
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
||||||
|
(nl | ";")*
|
||||||
|
"}";
|
||||||
|
int-type = "int";
|
||||||
|
float-type = "float";
|
||||||
|
string-type = "string";
|
||||||
|
bool-type = "bool";
|
||||||
|
error-type = "error";
|
||||||
|
|
||||||
|
/*
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
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? nl* ":" nl* 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 (nl* ":" nl* items-quantifier)?
|
||||||
|
| static-symbol nl* type-set (nl* ":" nl* items-quantifier)?;
|
||||||
|
destructure-item = type-set | static-symbol nl* type-set;
|
||||||
|
collect-destructure-item = "..." nl* destructure-item? (nl* ":" items-quantifier)?;
|
||||||
|
list-destructure-type = destructure-item
|
||||||
|
(list-sep destructure-item)*
|
||||||
|
(list-sep collect-destructure-item)?
|
||||||
|
| collect-destructure-item;
|
||||||
|
list-type-fact:alias = "[" (nl | ",")* (items-type | list-destructure-type)? (nl | ",")* "]";
|
||||||
|
list-type = list-type-fact;
|
||||||
|
mutable-list-type = "~" nl* list-type-fact;
|
||||||
|
destructure-match-item = match-set
|
||||||
|
| static-symbol nl* match-set
|
||||||
|
| static-symbol nl* static-symbol nl* match-set;
|
||||||
|
collect-destructure-match-item = "..." nl* destructure-match-item? (nl* ":" 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 = "[" (nl | ",")* (list-destructure-match | items-type)? (nl | ",")* "]";
|
||||||
|
list-match = list-match-fact;
|
||||||
|
mutable-list-match = "~" nl* list-match;
|
||||||
|
entry-type = static-symbol (nl* ":" nl* destructure-item)?;
|
||||||
|
entry-types:alias = entry-type (list-sep entry-type)*;
|
||||||
|
struct-type-fact:alias = "{" (nl | ",")* entry-types? (nl | ",")* "}";
|
||||||
|
struct-type = struct-type-fact;
|
||||||
|
mutable-struct-type = "~" nl* struct-type-fact;
|
||||||
|
entry-match = static-symbol (nl* ":" nl* destructure-match-item)?;
|
||||||
|
entry-matches:alias = entry-match (list-sep entry-match)*;
|
||||||
|
struct-match-fact:alias = "{" (nl | ",")* entry-matches? (nl | ",")* "}";
|
||||||
|
struct-match = struct-match-fact;
|
||||||
|
mutable-struct-match = "~" nl* struct-match-fact;
|
||||||
|
arg-type = type-set | static-symbol nl* type-set;
|
||||||
|
args-type:alias = arg-type (list-sep arg-type)*;
|
||||||
|
function-type-fact:alias = "(" nl* args-type? nl* ")" (type-set | static-symbol type-set)?;
|
||||||
|
function-type = "fn" nl* function-type-fact;
|
||||||
|
effect-type = "fn" nl* "~" nl* function-type-fact;
|
||||||
|
|
||||||
|
// TODO: heavy naming crime
|
||||||
|
|
||||||
|
receive-direction = "receive";
|
||||||
|
send-direction = "send";
|
||||||
|
channel-type = "<" nl* (receive-direction | send-direction)? nl* destructure-item? nl* ">";
|
||||||
|
type-fact-group:alias = "(" nl* type-fact nl* ")";
|
||||||
|
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 (nl* "|" nl* type-fact)*;
|
||||||
|
type-expression:alias = type-set | static-symbol 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 match-set;
|
||||||
|
match-case = "case" nl* match-expression nl* ":";
|
||||||
|
match-case-line:alias = match-case ";"* statement?;
|
||||||
|
match = "match"
|
||||||
|
nl*
|
||||||
|
expression
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
(nl | ";")*
|
||||||
|
( (match-case-line | default-line)
|
||||||
|
(sep (match-case-line | default-line | statement))*
|
||||||
|
)?
|
||||||
|
(nl | ";")*
|
||||||
|
"}";
|
||||||
|
conditional:alias = if | switch | match;
|
||||||
|
receive-call = "receive" "(" (nl | ",")* expression (nl | ",")* ")";
|
||||||
|
receive-op = "<-" primary-expression;
|
||||||
|
receive-expression-group:alias = "(" nl* receive-expression nl* ")";
|
||||||
|
receive-expression:alias = receive-call | receive-op | receive-expression-group;
|
||||||
|
receive-assign-capture:alias = assignable nl* ("=" nl*)? receive-expression;
|
||||||
|
receive-assignment = "set" nl* receive-assign-capture;
|
||||||
|
receive-assignment-equal = assignable nl* "=" nl* receive-expression;
|
||||||
|
receive-capture:alias = symbol-expression nl* ("=" nl*)? receive-expression;
|
||||||
|
receive-definition = "let" nl* receive-capture;
|
||||||
|
receive-mutable-definition = "let" nl* "~" nl* receive-capture;
|
||||||
|
receive-statement:alias = receive-assignment | receive-definition;
|
||||||
|
send-call:alias = "send" "(" (nl | ",")* expression list-sep expression (nl | ",")* ")";
|
||||||
|
send-op:alias = primary-expression "<-" expression;
|
||||||
|
send-call-group:alias = "(" nl* send nl* ")";
|
||||||
|
send = send-call | send-op | send-call-group;
|
||||||
|
close = "close" "(" (nl | ",")* expression (nl | ",")* ")";
|
||||||
|
communication-group:alias = "(" nl* communication nl* ")";
|
||||||
|
communication:alias = receive-expression | receive-statement | send | communication-group;
|
||||||
|
select-case = "case" nl* communication nl* ":";
|
||||||
|
select-case-line:alias = select-case ";"* statement?;
|
||||||
|
select = "select"
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
(nl | ";")*
|
||||||
|
( (select-case-line | default-line)
|
||||||
|
(sep (select-case-line | default-line | statement))*
|
||||||
|
)?
|
||||||
|
(nl | ";")*
|
||||||
|
"}";
|
||||||
|
go = "go" nl* (function-application | block);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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) (nl* "=")? nl* string;
|
||||||
|
require-facts:alias = require-fact (list-sep require-fact)*;
|
||||||
|
require-statement:alias = "require" nl* require-fact;
|
||||||
|
require-statement-group:alias = "require" "(" (nl | ",")* require-facts? (nl | ",")* ")";
|
||||||
|
require = require-statement | require-statement-group;
|
||||||
|
panic = "panic" "(" (nl | ",")* expression (nl | ",")* ")";
|
||||||
|
recover = "recover" "(" (nl | ",")* ")";
|
||||||
|
block = "{" (nl | ";")* statements? (nl | ";")* "}";
|
||||||
|
expression-group:alias = "(" nl* expression nl* ")";
|
||||||
|
primary-expression:alias = int
|
||||||
|
| float
|
||||||
|
| string
|
||||||
|
| bool
|
||||||
|
| symbol
|
||||||
|
| dynamic-symbol
|
||||||
|
| list
|
||||||
|
| mutable-list
|
||||||
|
| struct
|
||||||
|
| mutable-struct
|
||||||
|
| channel
|
||||||
|
// | and-expression // only documentation
|
||||||
|
// | or-expression // only documentation
|
||||||
|
| 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 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 (binary-op0 operand0)+;
|
||||||
|
binary1 = operand1 (binary-op1 operand1)+;
|
||||||
|
binary2 = operand2 (binary-op2 operand2)+;
|
||||||
|
binary3 = operand3 (binary-op3 operand3)+;
|
||||||
|
binary4 = operand4 (binary-op4 operand4)+;
|
||||||
|
binary5 = operand5 (binary-op5 operand5)+;
|
||||||
|
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4 | binary5;
|
||||||
|
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* 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 nl* "in" nl* (expression | range-expression);
|
||||||
|
loop-expression = expression | in-expression;
|
||||||
|
loop = "for" nl* (block | loop-expression nl* block);
|
||||||
|
|
||||||
|
/*
|
||||||
|
a = b
|
||||||
|
set c = d
|
||||||
|
set e f
|
||||||
|
set (
|
||||||
|
g = h
|
||||||
|
i j
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
assignable:alias = symbol-expression | indexer;
|
||||||
|
assign-capture = assignable nl* ("=" nl*)? expression;
|
||||||
|
assign-set:alias = "set" nl* assign-capture;
|
||||||
|
assign-equal = assignable nl* "=" nl* expression;
|
||||||
|
assign-captures:alias = assign-capture (list-sep assign-capture)*;
|
||||||
|
assign-group:alias = "set" nl* "(" (nl | ",")* assign-captures? (nl | ",")* ")";
|
||||||
|
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 nl* ("=" nl*)? expression;
|
||||||
|
value-capture = value-capture-fact;
|
||||||
|
mutable-capture = "~" nl* value-capture-fact;
|
||||||
|
value-definition = "let" nl* (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" nl* "(" (nl | ",")* mixed-captures? (nl | ",")* ")";
|
||||||
|
mutable-definition-group = "let" nl* "~" nl* "(" (nl | ",")* value-captures? (nl | ",")* ")";
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn a() b
|
||||||
|
fn ~ c() d
|
||||||
|
fn (
|
||||||
|
e() f
|
||||||
|
~ g() h
|
||||||
|
)
|
||||||
|
fn ~ (
|
||||||
|
i()
|
||||||
|
j()
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
function-definition-fact:alias = static-symbol nl* function-fact;
|
||||||
|
function-capture = function-definition-fact;
|
||||||
|
effect-capture = "~" nl* function-definition-fact;
|
||||||
|
function-definition = "fn" nl* (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" nl* "(" (nl | ",")* mixed-function-captures? (nl | ",")* ")";
|
||||||
|
effect-definition-group = "fn" nl* "~" nl* "(" (nl | ",")* function-captures? (nl | ",")* ")";
|
||||||
|
definition:alias = value-definition
|
||||||
|
| value-definition-group
|
||||||
|
| mutable-definition-group
|
||||||
|
| function-definition
|
||||||
|
| function-definition-group
|
||||||
|
| effect-definition-group;
|
||||||
|
type-alias = "type" nl* "alias" nl* static-symbol nl* type-set;
|
||||||
|
type-constraint = "type" nl* static-symbol nl* type-set;
|
||||||
|
statement-group:alias = "(" nl* statement nl* ")";
|
||||||
|
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 = (";" | "\n") (nl | ";")*;
|
||||||
|
statements:alias = statement (sep statement)*;
|
||||||
|
mml:root = shebang? (nl | ";")* statements? (nl | ";")*;
|
||||||
231
doc/example/mml-exp2.treerack
Normal file
231
doc/example/mml-exp2.treerack
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
||||||
|
wsc:ws = comment;
|
||||||
|
nl:alias = "\n";
|
||||||
|
line-comment-content:nows = [^\n]*;
|
||||||
|
line-comment:alias:nows = "//" line-comment-content;
|
||||||
|
block-comment-content:nows = ([^*] | "*" [^/])*;
|
||||||
|
block-comment:alias:nows = "/*" block-comment-content "*/";
|
||||||
|
comment-part:alias = line-comment | block-comment;
|
||||||
|
comment:alias = comment-part (nl? comment-part)*;
|
||||||
|
decimal-digit:alias = [0-9];
|
||||||
|
octal-digit:alias = [0-7];
|
||||||
|
hexa-digit:alias = [0-9a-fA-F];
|
||||||
|
decimal:alias:nows = [1-9] decimal-digit*;
|
||||||
|
octal:alias:nows = "0" octal-digit*;
|
||||||
|
hexa:alias:nows = "0" [xX] hexa-digit+;
|
||||||
|
int = decimal | octal | hexa;
|
||||||
|
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
||||||
|
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
||||||
|
| "." decimal-digit+ exponent?
|
||||||
|
| decimal-digit+ exponent;
|
||||||
|
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
|
true = "true";
|
||||||
|
false = "false";
|
||||||
|
bool:alias = true | false;
|
||||||
|
symbol:nows = [a-zA-Z_] [a-zA-Z_0-9]*;
|
||||||
|
spread-expression = primary-expression "...";
|
||||||
|
list-sep:alias = (nl | ",")+;
|
||||||
|
list-item:alias = expression | spread-expression;
|
||||||
|
expression-list:alias = list-item (list-sep list-item)*;
|
||||||
|
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
||||||
|
list = list-fact;
|
||||||
|
mutable-list = "~" nl* list-fact;
|
||||||
|
expression-key = "[" nl* expression nl* "]";
|
||||||
|
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
||||||
|
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
||||||
|
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
||||||
|
struct = struct-fact;
|
||||||
|
mutable-struct = "~" nl* struct-fact;
|
||||||
|
parameter-list:alias = symbol (list-sep symbol)*;
|
||||||
|
collect-parameter = "..." nl* symbol;
|
||||||
|
return = "return" (nl* expression)?;
|
||||||
|
block = "{" sep? statement-list? sep? "}";
|
||||||
|
function-fact:alias = "("
|
||||||
|
list-sep?
|
||||||
|
(parameter-list | parameter-list list-sep collect-parameter | collect-parameter)?
|
||||||
|
list-sep?
|
||||||
|
")"
|
||||||
|
nl*
|
||||||
|
(simple-statement | block);
|
||||||
|
function = "fn" nl* function-fact;
|
||||||
|
effect = "fn" nl* "~" nl* function-fact;
|
||||||
|
range-from = expression;
|
||||||
|
range-to = expression;
|
||||||
|
range:alias = range-from? nl* ":" nl* range-to?;
|
||||||
|
symbol-index = "." nl* symbol;
|
||||||
|
expression-index = "[" nl* expression nl* "]";
|
||||||
|
index:alias = symbol-index | expression-index;
|
||||||
|
index-list:alias = index (nl* index)?;
|
||||||
|
indexer = primary-expression nl* index-list;
|
||||||
|
function-application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
||||||
|
expression-group:alias = "(" nl* expression nl* ")";
|
||||||
|
primary-expression:alias = int
|
||||||
|
| float
|
||||||
|
| string
|
||||||
|
| bool
|
||||||
|
| receive
|
||||||
|
| symbol
|
||||||
|
| list
|
||||||
|
| mutable-list
|
||||||
|
| struct
|
||||||
|
| mutable-struct
|
||||||
|
| function
|
||||||
|
| effect
|
||||||
|
| indexer
|
||||||
|
| function-application
|
||||||
|
| expression-group;
|
||||||
|
binary-not = "^";
|
||||||
|
binary-and = "&";
|
||||||
|
binary-or = "|";
|
||||||
|
xor = "^";
|
||||||
|
and-not = "&^";
|
||||||
|
lshift = "<<";
|
||||||
|
rshift = ">>";
|
||||||
|
plus = "+";
|
||||||
|
minus = "-";
|
||||||
|
mul = "*";
|
||||||
|
div = "/";
|
||||||
|
mod = "%";
|
||||||
|
add = "+";
|
||||||
|
sub = "-";
|
||||||
|
logical-not = "!";
|
||||||
|
eq = "==";
|
||||||
|
not-eq = "!=";
|
||||||
|
less = "<";
|
||||||
|
less-or-eq = "<=";
|
||||||
|
greater = ">";
|
||||||
|
greater-or-eq = ">=";
|
||||||
|
logical-and = "&&";
|
||||||
|
logical-or = "||";
|
||||||
|
chain:alias = "->";
|
||||||
|
unary-operator:alias = plus | minus | binary-not | logical-not;
|
||||||
|
unary-expression = unary-operator primary-expression;
|
||||||
|
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
||||||
|
binary-op1:alias = binary-or | xor | add | sub;
|
||||||
|
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
||||||
|
binary-op3:alias = logical-and;
|
||||||
|
binary-op4:alias = logical-or;
|
||||||
|
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 (nl* binary-op0 nl* operand0)+;
|
||||||
|
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
|
||||||
|
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
|
||||||
|
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
|
||||||
|
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
|
||||||
|
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4;
|
||||||
|
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
||||||
|
chainingOperand:alias = primary-expression | unary-expression | binary-expression | ternary-expression;
|
||||||
|
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
|
||||||
|
expression:alias = primary-expression
|
||||||
|
| unary-expression
|
||||||
|
| binary-expression
|
||||||
|
| ternary-expression
|
||||||
|
| chaining;
|
||||||
|
if = "if"
|
||||||
|
nl*
|
||||||
|
expression
|
||||||
|
nl*
|
||||||
|
block
|
||||||
|
(nl* "else" nl* "if" nl* expression nl* block)*
|
||||||
|
(nl* "else" nl* block)?;
|
||||||
|
|
||||||
|
// TODO: empty switch not parsed
|
||||||
|
default = "default" nl* ":";
|
||||||
|
default-line:alias = default ";"* statement?;
|
||||||
|
case = "case" nl* expression nl* ":";
|
||||||
|
case-line:alias = case ";"* statement?;
|
||||||
|
switch = "switch"
|
||||||
|
nl*
|
||||||
|
expression?
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
send = "send" nl* primary-expression nl* primary-expression;
|
||||||
|
receive = "receive" nl* primary-expression;
|
||||||
|
receive-definition = symbol nl* receive;
|
||||||
|
communication:alias = send | receive | receive-definition;
|
||||||
|
select-case = "case" nl* communication nl* ":";
|
||||||
|
select-case-line:alias = select-case ";"* statement?;
|
||||||
|
select = "select"
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
( (select-case-line | default-line)
|
||||||
|
(sep (select-case-line | default-line | statement))*
|
||||||
|
)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
go = "go" nl* function-application;
|
||||||
|
defer = "defer" nl* function-application;
|
||||||
|
range-over-expression = symbol nl* "in" nl* (expression | range) | range;
|
||||||
|
loop-expression:alias = expression | range-over-expression;
|
||||||
|
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
||||||
|
|
||||||
|
// TODO: set(a b)
|
||||||
|
assign-capture:alias = primary-expression (nl* "=")? nl* expression;
|
||||||
|
assign-capture-list:alias = assign-capture (list-sep assign-capture)*;
|
||||||
|
assign-set:alias = "set" nl* assign-capture;
|
||||||
|
assign-eq:alias = primary-expression nl* "=" nl* expression;
|
||||||
|
assign-group:alias = "set" nl* "(" (list-sep assign-capture-list)? list-sep? ")";
|
||||||
|
assignment = assign-set | assign-eq | assign-group;
|
||||||
|
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
||||||
|
value-capture = value-capture-fact;
|
||||||
|
mutable-capture = "~" nl* value-capture-fact;
|
||||||
|
value-definition = "let" nl* (value-capture | mutable-capture);
|
||||||
|
mixed-capture-list:alias = (value-capture | mutable-capture)
|
||||||
|
(list-sep (value-capture | mutable-capture))*;
|
||||||
|
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
||||||
|
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
||||||
|
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
||||||
|
function-definition-fact:alias = symbol nl* function-fact;
|
||||||
|
function-capture = function-definition-fact;
|
||||||
|
effect-capture = "~" nl* function-definition-fact;
|
||||||
|
function-definition = "fn" nl* (function-capture | effect-capture);
|
||||||
|
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
||||||
|
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
||||||
|
(list-sep (function-capture | effect-capture))*;
|
||||||
|
function-definition-group = "fn" nl* "(" list-sep? mixed-function-capture-list? list-sep? ")";
|
||||||
|
effect-definition-group = "fn" nl* "~" nl* "(" list-sep? function-capture-list? list-sep? ")";
|
||||||
|
definition:alias = value-definition
|
||||||
|
| value-definition-group
|
||||||
|
| mutable-definition-group
|
||||||
|
| function-definition
|
||||||
|
| function-definition-group
|
||||||
|
| effect-definition-group;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - use effect
|
||||||
|
// - rename to 'use'
|
||||||
|
|
||||||
|
use-inline = ".";
|
||||||
|
use-fact = string | (symbol | use-inline) (nl* "=")? nl* string;
|
||||||
|
use-fact-list:alias = use-fact (list-sep use-fact)*;
|
||||||
|
use-statement:alias = "use" nl* use-fact;
|
||||||
|
use-statement-group:alias = "use" nl* "(" list-sep? use-fact-list? list-sep? ")";
|
||||||
|
use = use-statement | use-statement-group;
|
||||||
|
export = "export" nl* definition;
|
||||||
|
simple-statement:alias = send | go | defer | assignment | simple-statement-group | expression;
|
||||||
|
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
||||||
|
statement:alias = return
|
||||||
|
| if
|
||||||
|
| switch
|
||||||
|
| select
|
||||||
|
| loop
|
||||||
|
| definition
|
||||||
|
| use
|
||||||
|
| export
|
||||||
|
| statement-group
|
||||||
|
| simple-statement;
|
||||||
|
statement-group:alias = "(" nl* statement nl* ")";
|
||||||
|
sep:alias = (";" | nl)+;
|
||||||
|
statement-list:alias = statement (sep statement)*;
|
||||||
|
shebang-command = [^\n]*;
|
||||||
|
shebang = "#!" shebang-command "\n";
|
||||||
|
mml:root = shebang? sep? statement-list? sep?;
|
||||||
232
doc/example/mml-exp3.treerack
Normal file
232
doc/example/mml-exp3.treerack
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
||||||
|
wsc:ws = comment;
|
||||||
|
nl:alias = "\n";
|
||||||
|
wsep:alias = ws | nl;
|
||||||
|
line-comment-content:nows = [^\n]*;
|
||||||
|
line-comment:alias:nows = "//" line-comment-content;
|
||||||
|
block-comment-content:nows = ([^*] | "*" [^/])*;
|
||||||
|
block-comment:alias:nows = "/*" block-comment-content "*/";
|
||||||
|
comment-part:alias = line-comment | block-comment;
|
||||||
|
comment:alias = comment-part (nl? comment-part)*;
|
||||||
|
decimal-digit:alias = [0-9];
|
||||||
|
octal-digit:alias = [0-7];
|
||||||
|
hexa-digit:alias = [0-9a-fA-F];
|
||||||
|
decimal:alias:nows = [1-9] decimal-digit*;
|
||||||
|
octal:alias:nows = "0" octal-digit*;
|
||||||
|
hexa:alias:nows = "0" [xX] hexa-digit+;
|
||||||
|
int = decimal | octal | hexa;
|
||||||
|
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
||||||
|
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
||||||
|
| "." decimal-digit+ exponent?
|
||||||
|
| decimal-digit+ exponent;
|
||||||
|
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
|
true = "true";
|
||||||
|
false = "false";
|
||||||
|
bool:alias = true | false;
|
||||||
|
symbol:nows = [a-zA-Z_] [a-zA-Z_0-9]*;
|
||||||
|
spread-expression = primary-expression "...";
|
||||||
|
list-sep:alias = (nl | ",")+;
|
||||||
|
list-item:alias = expression | spread-expression;
|
||||||
|
expression-list:alias = list-item (list-sep list-item)*;
|
||||||
|
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
||||||
|
list = list-fact;
|
||||||
|
mutable-list = "~" nl* list-fact;
|
||||||
|
expression-key = "[" nl* expression nl* "]";
|
||||||
|
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
||||||
|
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
||||||
|
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
||||||
|
struct = struct-fact;
|
||||||
|
mutable-struct = "~" nl* struct-fact;
|
||||||
|
parameter-list:alias = symbol (list-sep symbol)*;
|
||||||
|
collect-parameter = "..." nl* symbol;
|
||||||
|
return = "return" | "return" nl* expression;
|
||||||
|
block = "{" sep? statement-list? sep? "}";
|
||||||
|
function-fact:alias = "("
|
||||||
|
list-sep?
|
||||||
|
(parameter-list | parameter-list list-sep collect-parameter | collect-parameter)?
|
||||||
|
list-sep?
|
||||||
|
")"
|
||||||
|
nl*
|
||||||
|
(expression | simple-statement | block);
|
||||||
|
function = "fn" nl* function-fact;
|
||||||
|
effect = "fn" nl* "~" nl* function-fact;
|
||||||
|
range-from = expression;
|
||||||
|
range-to = expression;
|
||||||
|
range:alias = range-from? nl* ":" nl* range-to?;
|
||||||
|
symbol-index = "." nl* symbol;
|
||||||
|
expression-index = "[" nl* expression nl* "]";
|
||||||
|
range-index = "[" nl* range nl* "]";
|
||||||
|
index:alias = symbol-index | expression-index | range-index;
|
||||||
|
index-list:alias = index (nl* index)?;
|
||||||
|
indexer = primary-expression nl* index-list;
|
||||||
|
application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
||||||
|
expression-group:alias = "(" nl* expression nl* ")";
|
||||||
|
primary-expression:alias = int
|
||||||
|
| float
|
||||||
|
| string
|
||||||
|
| bool
|
||||||
|
| symbol
|
||||||
|
| list
|
||||||
|
| mutable-list
|
||||||
|
| struct
|
||||||
|
| mutable-struct
|
||||||
|
| function
|
||||||
|
| effect
|
||||||
|
| indexer
|
||||||
|
| application
|
||||||
|
| receive
|
||||||
|
| expression-group;
|
||||||
|
binary-not = "^";
|
||||||
|
binary-and = "&";
|
||||||
|
binary-or = "|";
|
||||||
|
xor = "^";
|
||||||
|
and-not = "&^";
|
||||||
|
lshift = "<<";
|
||||||
|
rshift = ">>";
|
||||||
|
plus = "+";
|
||||||
|
minus = "-";
|
||||||
|
mul = "*";
|
||||||
|
div = "/";
|
||||||
|
mod = "%";
|
||||||
|
add = "+";
|
||||||
|
sub = "-";
|
||||||
|
logical-not = "!";
|
||||||
|
eq = "==";
|
||||||
|
not-eq = "!=";
|
||||||
|
less = "<";
|
||||||
|
less-or-eq = "<=";
|
||||||
|
greater = ">";
|
||||||
|
greater-or-eq = ">=";
|
||||||
|
logical-and = "&&";
|
||||||
|
logical-or = "||";
|
||||||
|
chain:alias = "->";
|
||||||
|
unary-operator:alias = plus | minus | binary-not | logical-not;
|
||||||
|
unary-expression = unary-operator primary-expression;
|
||||||
|
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
||||||
|
binary-op1:alias = binary-or | xor | add | sub;
|
||||||
|
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
||||||
|
binary-op3:alias = logical-and;
|
||||||
|
binary-op4:alias = logical-or;
|
||||||
|
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 (nl* binary-op0 nl* operand0)+;
|
||||||
|
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
|
||||||
|
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
|
||||||
|
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
|
||||||
|
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
|
||||||
|
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4;
|
||||||
|
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
||||||
|
chainingOperand:alias = primary-expression | unary-expression | binary-expression | ternary-expression;
|
||||||
|
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
|
||||||
|
expression:alias = primary-expression
|
||||||
|
| unary-expression
|
||||||
|
| binary-expression
|
||||||
|
| ternary-expression
|
||||||
|
| chaining;
|
||||||
|
if = "if"
|
||||||
|
nl*
|
||||||
|
expression
|
||||||
|
nl*
|
||||||
|
block
|
||||||
|
(nl* "else" nl* "if" nl* expression nl* block)*
|
||||||
|
(nl* "else" nl* block)?;
|
||||||
|
|
||||||
|
// TODO: empty switch not parsed
|
||||||
|
default = "default" nl* ":";
|
||||||
|
default-line:alias = default ";"* statement?;
|
||||||
|
case = "case" nl* expression nl* ":";
|
||||||
|
case-line:alias = case ";"* statement?;
|
||||||
|
switch = "switch"
|
||||||
|
nl*
|
||||||
|
expression?
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
send = "send" nl* primary-expression nl* primary-expression;
|
||||||
|
receive = "receive" nl* primary-expression;
|
||||||
|
receive-definition = symbol nl* receive;
|
||||||
|
communication:alias = send | receive | receive-definition;
|
||||||
|
select-case = "case" nl* communication nl* ":";
|
||||||
|
select-case-line:alias = select-case ";"* statement?;
|
||||||
|
select = "select"
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
( (select-case-line | default-line)
|
||||||
|
(sep (select-case-line | default-line | statement))*
|
||||||
|
)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
go = "go" nl* application;
|
||||||
|
defer = "defer" nl* application;
|
||||||
|
break = "break";
|
||||||
|
continue = "continue";
|
||||||
|
loop-control:alias = break | continue;
|
||||||
|
range-over = symbol nl* "in" nl* (expression | range) | range;
|
||||||
|
loop-expression:alias = expression | range-over;
|
||||||
|
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
||||||
|
assignment = (symbol | indexer) nl* "=" nl* expression;
|
||||||
|
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
||||||
|
value-capture = value-capture-fact;
|
||||||
|
mutable-capture = "~" nl* value-capture-fact;
|
||||||
|
value-definition = "let" nl* (value-capture | mutable-capture);
|
||||||
|
mixed-capture-list:alias = (value-capture | mutable-capture)
|
||||||
|
(list-sep (value-capture | mutable-capture))*;
|
||||||
|
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
||||||
|
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
||||||
|
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
||||||
|
function-definition-fact:alias = symbol nl* function-fact;
|
||||||
|
function-capture = function-definition-fact;
|
||||||
|
effect-capture = "~" nl* function-definition-fact;
|
||||||
|
function-definition = "fn" nl* (function-capture | effect-capture);
|
||||||
|
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
||||||
|
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
||||||
|
(list-sep (function-capture | effect-capture))*;
|
||||||
|
function-definition-group = "fn" nl* "(" list-sep? mixed-function-capture-list? list-sep? ")";
|
||||||
|
effect-definition-group = "fn" nl* "~" nl* "(" list-sep? function-capture-list? list-sep? ")";
|
||||||
|
definition:alias = value-definition
|
||||||
|
| value-definition-group
|
||||||
|
| mutable-definition-group
|
||||||
|
| function-definition
|
||||||
|
| function-definition-group
|
||||||
|
| effect-definition-group;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - use effect
|
||||||
|
|
||||||
|
use-inline = ".";
|
||||||
|
use-fact = string | (symbol | use-inline) (nl* "=")? nl* string;
|
||||||
|
use-fact-list:alias = use-fact (list-sep use-fact)*;
|
||||||
|
use-statement:alias = "use" nl* use-fact;
|
||||||
|
use-statement-group:alias = "use" nl* "(" list-sep? use-fact-list? list-sep? ")";
|
||||||
|
use = use-statement | use-statement-group;
|
||||||
|
export = "export" nl* definition;
|
||||||
|
simple-statement:alias = send | go | defer | assignment | simple-statement-group;
|
||||||
|
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
||||||
|
statement:alias = simple-statement
|
||||||
|
| return
|
||||||
|
| if
|
||||||
|
| switch
|
||||||
|
| select
|
||||||
|
| loop
|
||||||
|
| loop-control
|
||||||
|
| definition
|
||||||
|
| use
|
||||||
|
| export
|
||||||
|
| application
|
||||||
|
// TODO: sendSomething() and sendSomething
|
||||||
|
| chaining
|
||||||
|
| statement-group;
|
||||||
|
statement-group:alias = "(" nl* statement nl* ")";
|
||||||
|
sep:alias = (";" | nl)+;
|
||||||
|
statement-list:alias = statement (sep statement)*;
|
||||||
|
shebang-command = [^\n]*;
|
||||||
|
shebang = "#!" shebang-command "\n";
|
||||||
|
mml:root = shebang? sep? statement-list? sep?;
|
||||||
225
doc/example/mml.treerack
Normal file
225
doc/example/mml.treerack
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
||||||
|
wsc:ws = comment;
|
||||||
|
nl:alias = "\n";
|
||||||
|
line-comment-content:nows = [^\n]*;
|
||||||
|
line-comment:alias:nows = "//" line-comment-content;
|
||||||
|
block-comment-content:nows = ([^*] | "*" [^/])*;
|
||||||
|
block-comment:alias:nows = "/*" block-comment-content "*/";
|
||||||
|
comment-part:alias = line-comment | block-comment;
|
||||||
|
comment:alias = comment-part ("\n"? comment-part)*;
|
||||||
|
decimal-digit:alias = [0-9];
|
||||||
|
octal-digit:alias = [0-7];
|
||||||
|
hexa-digit:alias = [0-9a-fA-F];
|
||||||
|
decimal:alias:nows = [1-9] decimal-digit*;
|
||||||
|
octal:alias:nows = "0" octal-digit*;
|
||||||
|
hexa:alias:nows = "0" [xX] hexa-digit+;
|
||||||
|
int = decimal | octal | hexa;
|
||||||
|
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
||||||
|
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
||||||
|
| "." decimal-digit+ exponent?
|
||||||
|
| decimal-digit+ exponent;
|
||||||
|
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
|
true = "true";
|
||||||
|
false = "false";
|
||||||
|
bool:alias = true | false;
|
||||||
|
symbol:nows = [a-zA-Z_] [a-zA-Z_0-9]*;
|
||||||
|
spread-expression = primary-expression "...";
|
||||||
|
list-sep:alias = (nl | ",")+;
|
||||||
|
list-item:alias = expression | spread-expression;
|
||||||
|
expression-list:alias = list-item (list-sep list-item)*;
|
||||||
|
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
||||||
|
list = list-fact;
|
||||||
|
mutable-list = "~" nl* list-fact;
|
||||||
|
expression-key = "[" nl* expression nl* "]";
|
||||||
|
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
||||||
|
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
||||||
|
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
||||||
|
struct = struct-fact;
|
||||||
|
mutable-struct = "~" nl* struct-fact;
|
||||||
|
channel = "<>" | "<" nl* expression nl* ">";
|
||||||
|
parameter-list:alias = symbol (list-sep symbol)*;
|
||||||
|
collect-parameter = "..." nl* symbol;
|
||||||
|
return = "return" (nl* expression)?;
|
||||||
|
block = "{" sep? statement-list? sep? "}";
|
||||||
|
function-fact:alias = "("
|
||||||
|
list-sep?
|
||||||
|
parameter-list?
|
||||||
|
(list-sep collect-parameter)?
|
||||||
|
list-sep?
|
||||||
|
")"
|
||||||
|
nl*
|
||||||
|
(simple-statement | block);
|
||||||
|
function = "fn" nl* function-fact;
|
||||||
|
effect = "fn" nl* "~" nl* function-fact;
|
||||||
|
range-from = expression;
|
||||||
|
range-to = expression;
|
||||||
|
range:alias = range-from? nl* ":" nl* range-to?;
|
||||||
|
simple-indexer:alias = primary-expression "[" nl* expression nl* "]";
|
||||||
|
range-indexer:alias = primary-expression "[" nl* range nl* "]";
|
||||||
|
expression-indexer = simple-indexer | range-indexer;
|
||||||
|
symbol-indexer = primary-expression nl* "." nl* symbol;
|
||||||
|
function-application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
||||||
|
expression-group:alias = "(" nl* expression nl* ")";
|
||||||
|
primary-expression:alias = int
|
||||||
|
| float
|
||||||
|
| string
|
||||||
|
| bool
|
||||||
|
| symbol
|
||||||
|
| list
|
||||||
|
| mutable-list
|
||||||
|
| struct
|
||||||
|
| mutable-struct
|
||||||
|
| channel
|
||||||
|
| function
|
||||||
|
| effect
|
||||||
|
| expression-indexer
|
||||||
|
| symbol-indexer
|
||||||
|
| function-application
|
||||||
|
| receive
|
||||||
|
| expression-group;
|
||||||
|
binary-not = "^";
|
||||||
|
binary-and = "&";
|
||||||
|
binary-or = "|";
|
||||||
|
xor = "^";
|
||||||
|
and-not = "&^";
|
||||||
|
lshift = "<<";
|
||||||
|
rshift = ">>";
|
||||||
|
plus = "+";
|
||||||
|
minus = "-";
|
||||||
|
mul = "*";
|
||||||
|
div = "/";
|
||||||
|
mod = "%";
|
||||||
|
add = "+";
|
||||||
|
sub = "-";
|
||||||
|
logical-not = "!";
|
||||||
|
eq = "==";
|
||||||
|
not-eq = "!=";
|
||||||
|
less = "<";
|
||||||
|
less-or-eq = "<=";
|
||||||
|
greater = ">";
|
||||||
|
greater-or-eq = ">=";
|
||||||
|
logical-and = "&&";
|
||||||
|
logical-or = "||";
|
||||||
|
chain:alias = "->";
|
||||||
|
unary-operator:alias = plus | minus | binary-not | logical-not;
|
||||||
|
unary-expression = unary-operator primary-expression;
|
||||||
|
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
||||||
|
binary-op1:alias = binary-or | xor | add | sub;
|
||||||
|
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
||||||
|
binary-op3:alias = logical-and;
|
||||||
|
binary-op4:alias = logical-or;
|
||||||
|
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 (binary-op0 operand0)+;
|
||||||
|
binary1 = operand1 (binary-op1 operand1)+;
|
||||||
|
binary2 = operand2 (binary-op2 operand2)+;
|
||||||
|
binary3 = operand3 (binary-op3 operand3)+;
|
||||||
|
binary4 = operand4 (binary-op4 operand4)+;
|
||||||
|
chaining = operand5 (nl* chain nl* operand5)+;
|
||||||
|
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4 | chaining;
|
||||||
|
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
||||||
|
expression:alias = primary-expression
|
||||||
|
| unary-expression
|
||||||
|
| binary-expression
|
||||||
|
| ternary-expression;
|
||||||
|
if = "if"
|
||||||
|
nl*
|
||||||
|
expression
|
||||||
|
nl*
|
||||||
|
block
|
||||||
|
(nl* "else" nl* "if" nl* expression nl* block)*
|
||||||
|
(nl* "else" nl* block)?;
|
||||||
|
default = "default" nl* ":";
|
||||||
|
default-line:alias = default ";"* statement?;
|
||||||
|
case = "case" nl* expression nl* ":";
|
||||||
|
case-line:alias = case ";"* statement?;
|
||||||
|
switch = "switch"
|
||||||
|
nl*
|
||||||
|
expression?
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
receive = "<<>" primary-expression;
|
||||||
|
receive-definition = "let" nl* symbol nl* receive;
|
||||||
|
receive-assignment = "set" nl* symbol nl* receive;
|
||||||
|
receive-statement:alias = receive-definition | receive-assignment;
|
||||||
|
send = primary-expression "<<>" primary-expression;
|
||||||
|
communication:alias = receive | receive-statement | send;
|
||||||
|
select-case = "case" nl* communication nl* ":";
|
||||||
|
select-case-line:alias = select-case ";"* statement?;
|
||||||
|
select = "select"
|
||||||
|
nl*
|
||||||
|
"{"
|
||||||
|
sep?
|
||||||
|
( (select-case-line | default-line)
|
||||||
|
(sep (select-case-line | default-line | statement))*
|
||||||
|
)?
|
||||||
|
sep?
|
||||||
|
"}";
|
||||||
|
go = "go" nl* function-application;
|
||||||
|
defer = "defer" nl* function-application;
|
||||||
|
range-over-expression = symbol nl* "in" nl* (expression | range) | range;
|
||||||
|
loop-expression:alias = expression | range-over-expression;
|
||||||
|
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
||||||
|
assign-capture:alias = primary-expression (nl* "=")? nl* expression;
|
||||||
|
assign-capture-list:alias = assign-capture (list-sep assign-capture)*;
|
||||||
|
assign-set:alias = "set" nl* assign-capture;
|
||||||
|
assign-eq:alias = primary-expression nl* "=" nl* expression;
|
||||||
|
assign-group:alias = "set" nl* "(" (list-sep assign-capture-list)? list-sep? ")";
|
||||||
|
assignment = assign-set | assign-eq | assign-group;
|
||||||
|
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
||||||
|
value-capture = value-capture-fact;
|
||||||
|
mutable-capture = "~" nl* value-capture-fact;
|
||||||
|
value-definition = "let" nl* (value-capture | mutable-capture);
|
||||||
|
mixed-capture-list:alias = (value-capture | mutable-capture)
|
||||||
|
(list-sep (value-capture | mutable-capture))*;
|
||||||
|
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
||||||
|
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
||||||
|
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
||||||
|
function-definition-fact:alias = symbol nl* function-fact;
|
||||||
|
function-capture = function-definition-fact;
|
||||||
|
effect-capture = "~" nl* function-definition-fact;
|
||||||
|
function-definition = "fn" nl* (function-capture | effect-capture);
|
||||||
|
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
||||||
|
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
||||||
|
(list-sep (function-capture | effect-capture))*;
|
||||||
|
function-definition-group = "fn" nl* "(" list-sep? mixed-function-capture-list? list-sep? ")";
|
||||||
|
effect-definition-group = "fn" nl* "~" nl* "(" list-sep? function-capture-list? list-sep? ")";
|
||||||
|
definition:alias = value-definition
|
||||||
|
| value-definition-group
|
||||||
|
| mutable-definition-group
|
||||||
|
| function-definition
|
||||||
|
| function-definition-group
|
||||||
|
| effect-definition-group;
|
||||||
|
require-inline = ".";
|
||||||
|
require-fact = string | (symbol | require-inline) (nl* "=")? nl* string;
|
||||||
|
require-fact-list:alias = require-fact (list-sep require-fact)*;
|
||||||
|
require-statement:alias = "require" nl* require-fact;
|
||||||
|
require-statement-group:alias = "require" nl* "(" list-sep? require-fact-list? list-sep? ")";
|
||||||
|
require = require-statement | require-statement-group;
|
||||||
|
export = "export" nl* definition;
|
||||||
|
simple-statement:alias = expression | send | go | defer | assignment | simple-statement-group;
|
||||||
|
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
||||||
|
statement:alias = simple-statement
|
||||||
|
| return
|
||||||
|
| if
|
||||||
|
| switch
|
||||||
|
| select
|
||||||
|
| loop
|
||||||
|
| definition
|
||||||
|
| require
|
||||||
|
| export
|
||||||
|
| statement-group;
|
||||||
|
statement-group:alias = "(" nl* statement nl* ")";
|
||||||
|
sep:alias = (";" | nl)+;
|
||||||
|
statement-list:alias = statement (sep statement)*;
|
||||||
|
shebang-command = [^\n]*;
|
||||||
|
shebang = "#!" shebang-command "\n";
|
||||||
|
mml:root = shebang? sep? statement-list? sep?;
|
||||||
@ -3,8 +3,7 @@ comment:ws = ";" [^\n]*;
|
|||||||
number:nows = "-"? ("0" | [1-9] [0-9]*) ("." [0-9]+)? ([eE] [+\-]? [0-9]+)?;
|
number:nows = "-"? ("0" | [1-9] [0-9]*) ("." [0-9]+)? ([eE] [+\-]? [0-9]+)?;
|
||||||
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
||||||
symbol:nows = ([^\\ \n\t\b\f\r\v\"()\[\]#] | "\\" .)+;
|
symbol:nows = ([^\\ \n\t\b\f\r\v\"()\[\]#] | "\\" .)+;
|
||||||
list-form:alias = "(" expression* ")"
|
list-form:alias = "(" expression* ")" | "[" expression* "]";
|
||||||
| "[" expression* "]";
|
|
||||||
list = list-form;
|
list = list-form;
|
||||||
vector = "#" list-form;
|
vector = "#" list-form;
|
||||||
expression:alias = number | string | symbol | list;
|
expression:alias = number | string | symbol | list;
|
||||||
@ -531,7 +531,7 @@ $ go run .
|
|||||||
> exit
|
> exit
|
||||||
```
|
```
|
||||||
|
|
||||||
We can find the source files for this example here: [./examples/acalc](./examples/acalc).
|
We can find the source files for this example here: [./example/acalc](./example/acalc).
|
||||||
|
|
||||||
## Important note: unescaping
|
## Important note: unescaping
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ following workflow:
|
|||||||
- the detailed documentation of the treerack definition language: [./syntax.md](./syntax.md)
|
- the detailed documentation of the treerack definition language: [./syntax.md](./syntax.md)
|
||||||
- treerack command help: [../cmd/treerack/readme.md](../cmd/treerack/readme.md) or, if the command is installed,
|
- treerack command help: [../cmd/treerack/readme.md](../cmd/treerack/readme.md) or, if the command is installed,
|
||||||
`man treerack`, or `path/to/treerack help`
|
`man treerack`, or `path/to/treerack help`
|
||||||
- the arithmetic calculator example: [./examples/acalc](./examples/acalc).
|
- the arithmetic calculator example: [./example/acalc](./example/acalc).
|
||||||
- additional examples: [./examples](./examples)
|
- additional example: [./example](./example)
|
||||||
|
|
||||||
Happy parsing!
|
Happy parsing!
|
||||||
@ -114,6 +114,6 @@ Comments follow C-style syntax and are ignored by the definition parser.
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
- [JSON](examples/json.treerack)
|
- [JSON](example/json.treerack)
|
||||||
- [Scheme](examples/scheme.treerack)
|
- [Scheme](example/scheme.treerack)
|
||||||
- [Treerack (itself)](../syntax.treerack)
|
- [Treerack (itself)](../syntax.treerack)
|
||||||
@ -1,20 +0,0 @@
|
|||||||
whitespace:ws = [ \b\f\r\t\v];
|
|
||||||
|
|
||||||
comment-line:alias = "#" [^\n]*;
|
|
||||||
comment = comment-line ("\n" comment-line)*;
|
|
||||||
|
|
||||||
quoted:alias:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
|
||||||
word:alias:nows = ([^\\"\n=#.\[\] \b\f\r\t\v] | "\\" .)+;
|
|
||||||
symbol = word+ | quoted;
|
|
||||||
|
|
||||||
key-form:alias = symbol ("." symbol)*;
|
|
||||||
key = key-form;
|
|
||||||
|
|
||||||
group-key = (comment "\n")? "[" key-form "]";
|
|
||||||
|
|
||||||
value-chars:alias:nows = ([^\\"\n=# \b\f\r\t\v] | "\\" .)+;
|
|
||||||
value = value-chars+ | quoted;
|
|
||||||
|
|
||||||
key-val = (comment "\n")? (key | key? "=" value?) comment-line?;
|
|
||||||
entry:alias = group-key | key-val;
|
|
||||||
doc:root = (entry | comment-line | "\n")*;
|
|
||||||
@ -1,562 +0,0 @@
|
|||||||
// 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
|
|
||||||
//
|
|
||||||
// comments are not ignored because they are needed during formatting
|
|
||||||
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
|
||||||
wsc:ws = comment;
|
|
||||||
nl:alias = "\n";
|
|
||||||
|
|
||||||
// comments can be line or block comments
|
|
||||||
// indentation can hold meaning
|
|
||||||
line-comment-content:nows = [^\n]*;
|
|
||||||
line-comment:alias:nows = "//" line-comment-content;
|
|
||||||
block-comment-content:nows = ([^*] | "*" [^/])*; // TODO: why is the :nows required here if it is there for block-comment?
|
|
||||||
block-comment:alias:nows = "/*" block-comment-content "*/";
|
|
||||||
comment-part:alias = line-comment | block-comment;
|
|
||||||
comment:alias = comment-part ("\n"? 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:nows = [1-9] decimal-digit*;
|
|
||||||
octal:alias:nows = "0" octal-digit*;
|
|
||||||
hexa:alias:nows = "0" [xX] hexa-digit+;
|
|
||||||
int = decimal | octal | hexa;
|
|
||||||
|
|
||||||
// float examples: .0, 0., 3.14, 1E-12
|
|
||||||
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
|
||||||
float:nows = 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:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
|
||||||
|
|
||||||
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:nows = [a-zA-Z_][a-zA-Z_0-9]*;
|
|
||||||
static-symbol:alias = symbol | string;
|
|
||||||
dynamic-symbol = "symbol" "(" nl* expression nl* ")";
|
|
||||||
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 "...";
|
|
||||||
list-sep:alias = ("," | "\n") (nl | ",")*;
|
|
||||||
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 = "[" (nl | ",")* expression-list? (nl | ",")* "]";
|
|
||||||
list = list-fact;
|
|
||||||
mutable-list = "~" nl* list-fact;
|
|
||||||
|
|
||||||
indexer-symbol = "[" nl* expression nl* "]";
|
|
||||||
entry = (symbol-expression | indexer-symbol) nl* ":" nl* expression;
|
|
||||||
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
|
||||||
struct-fact:alias = "{" (nl | ",")* entry-list? (nl | ",")* "}";
|
|
||||||
struct = struct-fact;
|
|
||||||
mutable-struct = "~" nl* struct-fact;
|
|
||||||
|
|
||||||
channel = "<>" | "<" nl* int nl* ">";
|
|
||||||
|
|
||||||
// and-expression:doc = "and" "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
|
||||||
// or-expression:doc = "or" "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
|
||||||
|
|
||||||
argument-list:alias = static-symbol (list-sep static-symbol)*;
|
|
||||||
collect-symbol = "..." nl* static-symbol;
|
|
||||||
function-fact:alias = "(" (nl | ",")*
|
|
||||||
argument-list?
|
|
||||||
(nl | ",")*
|
|
||||||
collect-symbol?
|
|
||||||
(nl | ",")* ")" nl*
|
|
||||||
expression;
|
|
||||||
function = "fn" nl* function-fact; // can it ever cause a conflict with call and grouping?
|
|
||||||
effect = "fn" nl* "~" nl* 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? nl* ":" nl* range-to?;
|
|
||||||
indexer-expression:alias = expression | range-expression;
|
|
||||||
expression-indexer:alias = primary-expression "[" nl* indexer-expression nl* "]";
|
|
||||||
symbol-indexer:alias = primary-expression nl* "." nl* symbol-expression;
|
|
||||||
indexer = expression-indexer | symbol-indexer;
|
|
||||||
|
|
||||||
function-application = primary-expression "(" (nl | ",")* expression-list? (nl | ",")* ")";
|
|
||||||
|
|
||||||
if = "if" nl* expression nl* block
|
|
||||||
(nl* "else" nl* "if" nl* expression nl* block)*
|
|
||||||
(nl* "else" nl* block)?;
|
|
||||||
|
|
||||||
default = "default" nl* ":";
|
|
||||||
default-line:alias = default (nl | ";")* statement?;
|
|
||||||
case = "case" nl* expression nl* ":";
|
|
||||||
case-line:alias = case ";"* statement?;
|
|
||||||
switch = "switch" nl* expression? nl* "{" (nl | ";")*
|
|
||||||
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
|
||||||
(nl | ";")* "}";
|
|
||||||
|
|
||||||
int-type = "int";
|
|
||||||
float-type = "float";
|
|
||||||
string-type = "string";
|
|
||||||
bool-type = "bool";
|
|
||||||
error-type = "error";
|
|
||||||
|
|
||||||
/*
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
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? nl* ":" nl* 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 (nl* ":" nl* items-quantifier)?
|
|
||||||
| static-symbol nl* type-set (nl* ":" nl* items-quantifier)?;
|
|
||||||
|
|
||||||
destructure-item = type-set | static-symbol nl* type-set;
|
|
||||||
|
|
||||||
collect-destructure-item = "..." nl* destructure-item?
|
|
||||||
(nl* ":" items-quantifier)?;
|
|
||||||
list-destructure-type = destructure-item
|
|
||||||
(list-sep destructure-item)*
|
|
||||||
(list-sep collect-destructure-item)?
|
|
||||||
| collect-destructure-item;
|
|
||||||
list-type-fact:alias = "[" (nl | ",")*
|
|
||||||
(items-type | list-destructure-type)?
|
|
||||||
(nl | ",")* "]";
|
|
||||||
list-type = list-type-fact;
|
|
||||||
mutable-list-type = "~" nl* list-type-fact;
|
|
||||||
|
|
||||||
destructure-match-item = match-set
|
|
||||||
| static-symbol nl* match-set
|
|
||||||
| static-symbol nl* static-symbol nl* match-set;
|
|
||||||
|
|
||||||
collect-destructure-match-item = "..." nl* destructure-match-item?
|
|
||||||
(nl* ":" 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 = "[" (nl | ",")*
|
|
||||||
(list-destructure-match | items-type)?
|
|
||||||
(nl | ",")* "]";
|
|
||||||
list-match = list-match-fact;
|
|
||||||
mutable-list-match = "~" nl* list-match;
|
|
||||||
|
|
||||||
entry-type = static-symbol (nl* ":" nl* destructure-item)?;
|
|
||||||
entry-types:alias = entry-type (list-sep entry-type)*;
|
|
||||||
struct-type-fact:alias = "{" (nl | ",")* entry-types? (nl | ",")* "}";
|
|
||||||
struct-type = struct-type-fact;
|
|
||||||
mutable-struct-type = "~" nl* struct-type-fact;
|
|
||||||
|
|
||||||
entry-match = static-symbol (nl* ":" nl* destructure-match-item)?;
|
|
||||||
entry-matches:alias = entry-match (list-sep entry-match)*;
|
|
||||||
struct-match-fact:alias = "{" (nl | ",")* entry-matches? (nl | ",")* "}";
|
|
||||||
struct-match = struct-match-fact;
|
|
||||||
mutable-struct-match = "~" nl* struct-match-fact;
|
|
||||||
|
|
||||||
arg-type = type-set | static-symbol nl* type-set;
|
|
||||||
args-type:alias = arg-type (list-sep arg-type)*;
|
|
||||||
function-type-fact:alias = "(" nl* args-type? nl* ")"
|
|
||||||
(type-set | static-symbol type-set)?;
|
|
||||||
function-type = "fn" nl* function-type-fact;
|
|
||||||
effect-type = "fn" nl* "~" nl* function-type-fact;
|
|
||||||
|
|
||||||
// TODO: heavy naming crime
|
|
||||||
|
|
||||||
receive-direction = "receive";
|
|
||||||
send-direction = "send";
|
|
||||||
channel-type = "<" nl*
|
|
||||||
(receive-direction | send-direction)? nl*
|
|
||||||
destructure-item?
|
|
||||||
nl* ">";
|
|
||||||
|
|
||||||
type-fact-group:alias = "(" nl* type-fact nl* ")";
|
|
||||||
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 (nl* "|" nl* type-fact)*;
|
|
||||||
type-expression:alias = type-set | static-symbol 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 match-set;
|
|
||||||
|
|
||||||
match-case = "case" nl* match-expression nl* ":";
|
|
||||||
match-case-line:alias = match-case ";"* statement?;
|
|
||||||
match = "match" nl* expression nl* "{" (nl | ";")*
|
|
||||||
((match-case-line | default-line)
|
|
||||||
(sep (match-case-line | default-line | statement))*)?
|
|
||||||
(nl | ";")* "}";
|
|
||||||
|
|
||||||
conditional:alias = if
|
|
||||||
| switch
|
|
||||||
| match;
|
|
||||||
|
|
||||||
receive-call = "receive" "(" (nl | ",")* expression (nl | ",")* ")";
|
|
||||||
receive-op = "<-" primary-expression;
|
|
||||||
receive-expression-group:alias = "(" nl* receive-expression nl* ")";
|
|
||||||
receive-expression:alias = receive-call | receive-op | receive-expression-group;
|
|
||||||
|
|
||||||
receive-assign-capture:alias = assignable nl* ("=" nl*)? receive-expression;
|
|
||||||
receive-assignment = "set" nl* receive-assign-capture;
|
|
||||||
receive-assignment-equal = assignable nl* "=" nl* receive-expression;
|
|
||||||
receive-capture:alias = symbol-expression nl* ("=" nl*)? receive-expression;
|
|
||||||
receive-definition = "let" nl* receive-capture;
|
|
||||||
receive-mutable-definition = "let" nl* "~" nl* receive-capture;
|
|
||||||
receive-statement:alias = receive-assignment | receive-definition;
|
|
||||||
|
|
||||||
send-call:alias = "send" "(" (nl | ",")* expression list-sep expression (nl | ",")* ")";
|
|
||||||
send-op:alias = primary-expression "<-" expression;
|
|
||||||
send-call-group:alias = "(" nl* send nl* ")";
|
|
||||||
send = send-call | send-op | send-call-group;
|
|
||||||
|
|
||||||
close = "close" "(" (nl | ",")* expression (nl | ",")* ")";
|
|
||||||
|
|
||||||
communication-group:alias = "(" nl* communication nl* ")";
|
|
||||||
communication:alias = receive-expression | receive-statement | send | communication-group;
|
|
||||||
|
|
||||||
select-case = "case" nl* communication nl* ":";
|
|
||||||
select-case-line:alias = select-case ";"* statement?;
|
|
||||||
select = "select" nl* "{" (nl | ";")*
|
|
||||||
((select-case-line | default-line)
|
|
||||||
(sep (select-case-line | default-line | statement))*)?
|
|
||||||
(nl | ";")* "}";
|
|
||||||
|
|
||||||
go = "go" nl* (function-application | block);
|
|
||||||
|
|
||||||
/*
|
|
||||||
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) (nl* "=")? nl* string;
|
|
||||||
require-facts:alias = require-fact (list-sep require-fact)*;
|
|
||||||
require-statement:alias = "require" nl* require-fact;
|
|
||||||
require-statement-group:alias = "require" "(" (nl | ",")*
|
|
||||||
require-facts?
|
|
||||||
(nl | ",")* ")";
|
|
||||||
require = require-statement | require-statement-group;
|
|
||||||
|
|
||||||
panic = "panic" "(" (nl | ",")* expression (nl | ",")* ")";
|
|
||||||
recover = "recover" "(" (nl | ",")* ")";
|
|
||||||
|
|
||||||
block = "{" (nl | ";")* statements? (nl | ";")* "}";
|
|
||||||
expression-group:alias = "(" nl* expression nl* ")";
|
|
||||||
|
|
||||||
primary-expression:alias = int
|
|
||||||
| float
|
|
||||||
| string
|
|
||||||
| bool
|
|
||||||
| symbol
|
|
||||||
| dynamic-symbol
|
|
||||||
| list
|
|
||||||
| mutable-list
|
|
||||||
| struct
|
|
||||||
| mutable-struct
|
|
||||||
| channel
|
|
||||||
// | and-expression // only documentation
|
|
||||||
// | or-expression // only documentation
|
|
||||||
| 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 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 (binary-op0 operand0)+;
|
|
||||||
binary1 = operand1 (binary-op1 operand1)+;
|
|
||||||
binary2 = operand2 (binary-op2 operand2)+;
|
|
||||||
binary3 = operand3 (binary-op3 operand3)+;
|
|
||||||
binary4 = operand4 (binary-op4 operand4)+;
|
|
||||||
binary5 = operand5 (binary-op5 operand5)+;
|
|
||||||
|
|
||||||
binary-expression:alias = binary0 | binary1 | binary2 | binary3 | binary4 | binary5;
|
|
||||||
|
|
||||||
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* 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 nl* "in" nl* (expression | range-expression);
|
|
||||||
loop-expression = expression | in-expression;
|
|
||||||
loop = "for" nl* (block | loop-expression nl* block);
|
|
||||||
|
|
||||||
/*
|
|
||||||
a = b
|
|
||||||
set c = d
|
|
||||||
set e f
|
|
||||||
set (
|
|
||||||
g = h
|
|
||||||
i j
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
assignable:alias = symbol-expression | indexer;
|
|
||||||
assign-capture = assignable nl* ("=" nl*)? expression;
|
|
||||||
assign-set:alias = "set" nl* assign-capture;
|
|
||||||
assign-equal = assignable nl* "=" nl* expression;
|
|
||||||
assign-captures:alias = assign-capture (list-sep assign-capture)*;
|
|
||||||
assign-group:alias = "set" nl* "(" (nl | ",")* assign-captures? (nl | ",")* ")";
|
|
||||||
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 nl* ("=" nl*)? expression;
|
|
||||||
value-capture = value-capture-fact;
|
|
||||||
mutable-capture = "~" nl* value-capture-fact;
|
|
||||||
value-definition = "let" nl* (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" nl* "(" (nl | ",")* mixed-captures? (nl | ",")* ")";
|
|
||||||
mutable-definition-group = "let" nl* "~" nl* "(" (nl | ",")* value-captures? (nl | ",")* ")";
|
|
||||||
|
|
||||||
/*
|
|
||||||
fn a() b
|
|
||||||
fn ~ c() d
|
|
||||||
fn (
|
|
||||||
e() f
|
|
||||||
~ g() h
|
|
||||||
)
|
|
||||||
fn ~ (
|
|
||||||
i()
|
|
||||||
j()
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
function-definition-fact:alias = static-symbol nl* function-fact;
|
|
||||||
function-capture = function-definition-fact;
|
|
||||||
effect-capture = "~" nl* function-definition-fact;
|
|
||||||
function-definition = "fn" nl* (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" nl* "(" (nl | ",")*
|
|
||||||
mixed-function-captures?
|
|
||||||
(nl | ",")* ")";
|
|
||||||
effect-definition-group = "fn" nl* "~" nl* "(" (nl | ",")*
|
|
||||||
function-captures?
|
|
||||||
(nl | ",")* ")";
|
|
||||||
|
|
||||||
definition:alias = value-definition
|
|
||||||
| value-definition-group
|
|
||||||
| mutable-definition-group
|
|
||||||
| function-definition
|
|
||||||
| function-definition-group
|
|
||||||
| effect-definition-group;
|
|
||||||
|
|
||||||
type-alias = "type" nl* "alias" nl* static-symbol nl* type-set;
|
|
||||||
type-constraint = "type" nl* static-symbol nl* type-set;
|
|
||||||
|
|
||||||
statement-group:alias = "(" nl* statement nl* ")";
|
|
||||||
|
|
||||||
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 = (";" | "\n") (nl | ";")*;
|
|
||||||
statements:alias = statement (sep statement)*;
|
|
||||||
mml:root = shebang? (nl | ";")* statements? (nl | ";")*;
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
|
||||||
wsc:ws = comment;
|
|
||||||
nl:alias = "\n";
|
|
||||||
|
|
||||||
line-comment-content:nows = [^\n]*;
|
|
||||||
line-comment:alias:nows = "//" line-comment-content;
|
|
||||||
block-comment-content:nows = ([^*] | "*" [^/])*;
|
|
||||||
block-comment:alias:nows = "/*" block-comment-content "*/";
|
|
||||||
comment-part:alias = line-comment | block-comment;
|
|
||||||
comment:alias = comment-part (nl? comment-part)*;
|
|
||||||
|
|
||||||
decimal-digit:alias = [0-9];
|
|
||||||
octal-digit:alias = [0-7];
|
|
||||||
hexa-digit:alias = [0-9a-fA-F];
|
|
||||||
|
|
||||||
decimal:alias:nows = [1-9] decimal-digit*;
|
|
||||||
octal:alias:nows = "0" octal-digit*;
|
|
||||||
hexa:alias:nows = "0" [xX] hexa-digit+;
|
|
||||||
int = decimal | octal | hexa;
|
|
||||||
|
|
||||||
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
|
||||||
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
|
||||||
| "." decimal-digit+ exponent?
|
|
||||||
| decimal-digit+ exponent;
|
|
||||||
|
|
||||||
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
|
||||||
|
|
||||||
true = "true";
|
|
||||||
false = "false";
|
|
||||||
bool:alias = true | false;
|
|
||||||
|
|
||||||
symbol:nows = [a-zA-Z_][a-zA-Z_0-9]*;
|
|
||||||
|
|
||||||
spread-expression = primary-expression "...";
|
|
||||||
list-sep:alias = (nl | ",")+;
|
|
||||||
list-item:alias = expression | spread-expression;
|
|
||||||
expression-list:alias = list-item (list-sep list-item)*;
|
|
||||||
|
|
||||||
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
|
||||||
list = list-fact;
|
|
||||||
mutable-list = "~" nl* list-fact;
|
|
||||||
|
|
||||||
expression-key = "[" nl* expression nl* "]";
|
|
||||||
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
|
||||||
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
|
||||||
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
|
||||||
struct = struct-fact;
|
|
||||||
mutable-struct = "~" nl* struct-fact;
|
|
||||||
|
|
||||||
parameter-list:alias = symbol (list-sep symbol)*;
|
|
||||||
collect-parameter = "..." nl* symbol;
|
|
||||||
return = "return" (nl* expression)?;
|
|
||||||
block = "{" sep? statement-list? sep? "}";
|
|
||||||
function-fact:alias = "(" list-sep?
|
|
||||||
(parameter-list
|
|
||||||
| parameter-list list-sep collect-parameter
|
|
||||||
| collect-parameter)?
|
|
||||||
list-sep? ")" nl*
|
|
||||||
(simple-statement | block);
|
|
||||||
function = "fn" nl* function-fact;
|
|
||||||
effect = "fn" nl* "~" nl* function-fact;
|
|
||||||
|
|
||||||
range-from = expression;
|
|
||||||
range-to = expression;
|
|
||||||
range:alias = range-from? nl* ":" nl* range-to?;
|
|
||||||
|
|
||||||
symbol-index = "." nl* symbol;
|
|
||||||
expression-index = "[" nl* expression nl* "]";
|
|
||||||
index:alias = symbol-index | expression-index;
|
|
||||||
index-list:alias = index (nl* index)?;
|
|
||||||
indexer = primary-expression nl* index-list;
|
|
||||||
|
|
||||||
function-application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
|
||||||
|
|
||||||
expression-group:alias = "(" nl* expression nl* ")";
|
|
||||||
primary-expression:alias = int
|
|
||||||
| float
|
|
||||||
| string
|
|
||||||
| bool
|
|
||||||
| receive
|
|
||||||
| symbol
|
|
||||||
| list
|
|
||||||
| mutable-list
|
|
||||||
| struct
|
|
||||||
| mutable-struct
|
|
||||||
| function
|
|
||||||
| effect
|
|
||||||
| indexer
|
|
||||||
| function-application
|
|
||||||
| expression-group;
|
|
||||||
|
|
||||||
binary-not = "^";
|
|
||||||
binary-and = "&";
|
|
||||||
binary-or = "|";
|
|
||||||
xor = "^";
|
|
||||||
and-not = "&^";
|
|
||||||
lshift = "<<";
|
|
||||||
rshift = ">>";
|
|
||||||
|
|
||||||
plus = "+";
|
|
||||||
minus = "-";
|
|
||||||
mul = "*";
|
|
||||||
div = "/";
|
|
||||||
mod = "%";
|
|
||||||
add = "+";
|
|
||||||
sub = "-";
|
|
||||||
|
|
||||||
logical-not = "!";
|
|
||||||
eq = "==";
|
|
||||||
not-eq = "!=";
|
|
||||||
less = "<";
|
|
||||||
less-or-eq = "<=";
|
|
||||||
greater = ">";
|
|
||||||
greater-or-eq = ">=";
|
|
||||||
logical-and = "&&";
|
|
||||||
logical-or = "||";
|
|
||||||
|
|
||||||
chain:alias = "->";
|
|
||||||
|
|
||||||
unary-operator:alias = plus | minus | binary-not | logical-not;
|
|
||||||
unary-expression = unary-operator primary-expression;
|
|
||||||
|
|
||||||
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
|
||||||
binary-op1:alias = binary-or | xor | add | sub;
|
|
||||||
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
|
||||||
binary-op3:alias = logical-and;
|
|
||||||
binary-op4:alias = logical-or;
|
|
||||||
|
|
||||||
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 (nl* binary-op0 nl* operand0)+;
|
|
||||||
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
|
|
||||||
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
|
|
||||||
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
|
|
||||||
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
|
|
||||||
|
|
||||||
binary-expression:alias = binary0
|
|
||||||
| binary1
|
|
||||||
| binary2
|
|
||||||
| binary3
|
|
||||||
| binary4;
|
|
||||||
|
|
||||||
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
|
||||||
|
|
||||||
chainingOperand:alias = primary-expression
|
|
||||||
| unary-expression
|
|
||||||
| binary-expression
|
|
||||||
| ternary-expression;
|
|
||||||
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
|
|
||||||
|
|
||||||
expression:alias = primary-expression
|
|
||||||
| unary-expression
|
|
||||||
| binary-expression
|
|
||||||
| ternary-expression
|
|
||||||
| chaining;
|
|
||||||
|
|
||||||
if = "if" nl* expression nl* block
|
|
||||||
(nl* "else" nl* "if" nl* expression nl* block)*
|
|
||||||
(nl* "else" nl* block)?;
|
|
||||||
|
|
||||||
// TODO: empty switch not parsed
|
|
||||||
default = "default" nl* ":";
|
|
||||||
default-line:alias = default ";"* statement?;
|
|
||||||
case = "case" nl* expression nl* ":";
|
|
||||||
case-line:alias = case ";"* statement?;
|
|
||||||
switch = "switch" nl* expression? nl* "{" sep?
|
|
||||||
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
send = "send" nl* primary-expression nl* primary-expression;
|
|
||||||
receive = "receive" nl* primary-expression;
|
|
||||||
receive-definition = symbol nl* receive;
|
|
||||||
communication:alias = send | receive | receive-definition;
|
|
||||||
select-case = "case" nl* communication nl* ":";
|
|
||||||
select-case-line:alias = select-case ";"* statement?;
|
|
||||||
select = "select" nl* "{" sep?
|
|
||||||
((select-case-line | default-line)
|
|
||||||
(sep (select-case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
go = "go" nl* function-application;
|
|
||||||
defer = "defer" nl* function-application;
|
|
||||||
|
|
||||||
range-over-expression = symbol nl* "in" nl* (expression | range) | range;
|
|
||||||
loop-expression:alias = expression | range-over-expression;
|
|
||||||
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
|
||||||
|
|
||||||
// TODO: set(a b)
|
|
||||||
assign-capture:alias = primary-expression (nl* "=")? nl* expression;
|
|
||||||
assign-capture-list:alias = assign-capture (list-sep assign-capture)*;
|
|
||||||
assign-set:alias = "set" nl* assign-capture;
|
|
||||||
assign-eq:alias = primary-expression nl* "=" nl* expression;
|
|
||||||
assign-group:alias = "set" nl* "(" (list-sep assign-capture-list)? list-sep? ")";
|
|
||||||
assignment = assign-set | assign-eq | assign-group;
|
|
||||||
|
|
||||||
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
|
||||||
value-capture = value-capture-fact;
|
|
||||||
mutable-capture = "~" nl* value-capture-fact;
|
|
||||||
value-definition = "let" nl* (value-capture | mutable-capture);
|
|
||||||
mixed-capture-list:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
|
|
||||||
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
|
||||||
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
|
||||||
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
|
||||||
|
|
||||||
function-definition-fact:alias = symbol nl* function-fact;
|
|
||||||
function-capture = function-definition-fact;
|
|
||||||
effect-capture = "~" nl* function-definition-fact;
|
|
||||||
function-definition = "fn" nl* (function-capture | effect-capture);
|
|
||||||
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
|
||||||
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
|
||||||
(list-sep (function-capture | effect-capture))*;
|
|
||||||
function-definition-group = "fn" nl* "(" list-sep?
|
|
||||||
mixed-function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
effect-definition-group = "fn" nl* "~" nl* "(" list-sep?
|
|
||||||
function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
|
|
||||||
definition:alias = value-definition
|
|
||||||
| value-definition-group
|
|
||||||
| mutable-definition-group
|
|
||||||
| function-definition
|
|
||||||
| function-definition-group
|
|
||||||
| effect-definition-group;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - use effect
|
|
||||||
// - rename to 'use'
|
|
||||||
|
|
||||||
use-inline = ".";
|
|
||||||
use-fact = string
|
|
||||||
| (symbol | use-inline) (nl* "=")? nl* string;
|
|
||||||
use-fact-list:alias = use-fact (list-sep use-fact)*;
|
|
||||||
use-statement:alias = "use" nl* use-fact;
|
|
||||||
use-statement-group:alias = "use" nl* "(" list-sep?
|
|
||||||
use-fact-list?
|
|
||||||
list-sep? ")";
|
|
||||||
use = use-statement | use-statement-group;
|
|
||||||
|
|
||||||
export = "export" nl* definition;
|
|
||||||
|
|
||||||
simple-statement:alias = send
|
|
||||||
| go
|
|
||||||
| defer
|
|
||||||
| assignment
|
|
||||||
| simple-statement-group
|
|
||||||
| expression;
|
|
||||||
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
|
||||||
statement:alias = return
|
|
||||||
| if
|
|
||||||
| switch
|
|
||||||
| select
|
|
||||||
| loop
|
|
||||||
| definition
|
|
||||||
| use
|
|
||||||
| export
|
|
||||||
| statement-group
|
|
||||||
| simple-statement;
|
|
||||||
statement-group:alias = "(" nl* statement nl* ")";
|
|
||||||
|
|
||||||
sep:alias = (";" | nl)+;
|
|
||||||
statement-list:alias = statement (sep statement)*;
|
|
||||||
|
|
||||||
shebang-command = [^\n]*;
|
|
||||||
shebang = "#!" shebang-command "\n";
|
|
||||||
mml:root = shebang? sep? statement-list? sep?;
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
|
||||||
wsc:ws = comment;
|
|
||||||
nl:alias = "\n";
|
|
||||||
wsep:alias = ws | nl;
|
|
||||||
|
|
||||||
line-comment-content:nows = [^\n]*;
|
|
||||||
line-comment:alias:nows = "//" line-comment-content;
|
|
||||||
block-comment-content:nows = ([^*] | "*" [^/])*;
|
|
||||||
block-comment:alias:nows = "/*" block-comment-content "*/";
|
|
||||||
comment-part:alias = line-comment | block-comment;
|
|
||||||
comment:alias = comment-part (nl? comment-part)*;
|
|
||||||
|
|
||||||
decimal-digit:alias = [0-9];
|
|
||||||
octal-digit:alias = [0-7];
|
|
||||||
hexa-digit:alias = [0-9a-fA-F];
|
|
||||||
|
|
||||||
decimal:alias:nows = [1-9] decimal-digit*;
|
|
||||||
octal:alias:nows = "0" octal-digit*;
|
|
||||||
hexa:alias:nows = "0" [xX] hexa-digit+;
|
|
||||||
int = decimal | octal | hexa;
|
|
||||||
|
|
||||||
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
|
||||||
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
|
||||||
| "." decimal-digit+ exponent?
|
|
||||||
| decimal-digit+ exponent;
|
|
||||||
|
|
||||||
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
|
||||||
|
|
||||||
true = "true";
|
|
||||||
false = "false";
|
|
||||||
bool:alias = true | false;
|
|
||||||
|
|
||||||
symbol:nows = [a-zA-Z_][a-zA-Z_0-9]*;
|
|
||||||
|
|
||||||
spread-expression = primary-expression "...";
|
|
||||||
list-sep:alias = (nl | ",")+;
|
|
||||||
list-item:alias = expression | spread-expression;
|
|
||||||
expression-list:alias = list-item (list-sep list-item)*;
|
|
||||||
|
|
||||||
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
|
||||||
list = list-fact;
|
|
||||||
mutable-list = "~" nl* list-fact;
|
|
||||||
|
|
||||||
expression-key = "[" nl* expression nl* "]";
|
|
||||||
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
|
||||||
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
|
||||||
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
|
||||||
struct = struct-fact;
|
|
||||||
mutable-struct = "~" nl* struct-fact;
|
|
||||||
|
|
||||||
parameter-list:alias = symbol (list-sep symbol)*;
|
|
||||||
collect-parameter = "..." nl* symbol;
|
|
||||||
return = "return" | "return" nl* expression;
|
|
||||||
block = "{" sep? statement-list? sep? "}";
|
|
||||||
function-fact:alias = "(" list-sep?
|
|
||||||
(parameter-list
|
|
||||||
| parameter-list list-sep collect-parameter
|
|
||||||
| collect-parameter)?
|
|
||||||
list-sep? ")" nl*
|
|
||||||
(expression | simple-statement | block);
|
|
||||||
function = "fn" nl* function-fact;
|
|
||||||
effect = "fn" nl* "~" nl* function-fact;
|
|
||||||
|
|
||||||
range-from = expression;
|
|
||||||
range-to = expression;
|
|
||||||
range:alias = range-from? nl* ":" nl* range-to?;
|
|
||||||
|
|
||||||
symbol-index = "." nl* symbol;
|
|
||||||
expression-index = "[" nl* expression nl* "]";
|
|
||||||
range-index = "[" nl* range nl* "]";
|
|
||||||
index:alias = symbol-index | expression-index | range-index;
|
|
||||||
index-list:alias = index (nl* index)?;
|
|
||||||
indexer = primary-expression nl* index-list;
|
|
||||||
|
|
||||||
application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
|
||||||
|
|
||||||
expression-group:alias = "(" nl* expression nl* ")";
|
|
||||||
primary-expression:alias = int
|
|
||||||
| float
|
|
||||||
| string
|
|
||||||
| bool
|
|
||||||
| symbol
|
|
||||||
| list
|
|
||||||
| mutable-list
|
|
||||||
| struct
|
|
||||||
| mutable-struct
|
|
||||||
| function
|
|
||||||
| effect
|
|
||||||
| indexer
|
|
||||||
| application
|
|
||||||
| receive
|
|
||||||
| expression-group;
|
|
||||||
|
|
||||||
binary-not = "^";
|
|
||||||
binary-and = "&";
|
|
||||||
binary-or = "|";
|
|
||||||
xor = "^";
|
|
||||||
and-not = "&^";
|
|
||||||
lshift = "<<";
|
|
||||||
rshift = ">>";
|
|
||||||
|
|
||||||
plus = "+";
|
|
||||||
minus = "-";
|
|
||||||
mul = "*";
|
|
||||||
div = "/";
|
|
||||||
mod = "%";
|
|
||||||
add = "+";
|
|
||||||
sub = "-";
|
|
||||||
|
|
||||||
logical-not = "!";
|
|
||||||
eq = "==";
|
|
||||||
not-eq = "!=";
|
|
||||||
less = "<";
|
|
||||||
less-or-eq = "<=";
|
|
||||||
greater = ">";
|
|
||||||
greater-or-eq = ">=";
|
|
||||||
logical-and = "&&";
|
|
||||||
logical-or = "||";
|
|
||||||
|
|
||||||
chain:alias = "->";
|
|
||||||
|
|
||||||
unary-operator:alias = plus | minus | binary-not | logical-not;
|
|
||||||
unary-expression = unary-operator primary-expression;
|
|
||||||
|
|
||||||
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
|
||||||
binary-op1:alias = binary-or | xor | add | sub;
|
|
||||||
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
|
||||||
binary-op3:alias = logical-and;
|
|
||||||
binary-op4:alias = logical-or;
|
|
||||||
|
|
||||||
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 (nl* binary-op0 nl* operand0)+;
|
|
||||||
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
|
|
||||||
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
|
|
||||||
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
|
|
||||||
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
|
|
||||||
|
|
||||||
binary-expression:alias = binary0
|
|
||||||
| binary1
|
|
||||||
| binary2
|
|
||||||
| binary3
|
|
||||||
| binary4;
|
|
||||||
|
|
||||||
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
|
||||||
|
|
||||||
chainingOperand:alias = primary-expression
|
|
||||||
| unary-expression
|
|
||||||
| binary-expression
|
|
||||||
| ternary-expression;
|
|
||||||
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
|
|
||||||
|
|
||||||
expression:alias = primary-expression
|
|
||||||
| unary-expression
|
|
||||||
| binary-expression
|
|
||||||
| ternary-expression
|
|
||||||
| chaining;
|
|
||||||
|
|
||||||
if = "if" nl* expression nl* block
|
|
||||||
(nl* "else" nl* "if" nl* expression nl* block)*
|
|
||||||
(nl* "else" nl* block)?;
|
|
||||||
|
|
||||||
// TODO: empty switch not parsed
|
|
||||||
default = "default" nl* ":";
|
|
||||||
default-line:alias = default ";"* statement?;
|
|
||||||
case = "case" nl* expression nl* ":";
|
|
||||||
case-line:alias = case ";"* statement?;
|
|
||||||
switch = "switch" nl* expression? nl* "{" sep?
|
|
||||||
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
send = "send" nl* primary-expression nl* primary-expression;
|
|
||||||
receive = "receive" nl* primary-expression;
|
|
||||||
receive-definition = symbol nl* receive;
|
|
||||||
communication:alias = send | receive | receive-definition;
|
|
||||||
select-case = "case" nl* communication nl* ":";
|
|
||||||
select-case-line:alias = select-case ";"* statement?;
|
|
||||||
select = "select" nl* "{" sep?
|
|
||||||
((select-case-line | default-line)
|
|
||||||
(sep (select-case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
go = "go" nl* application;
|
|
||||||
defer = "defer" nl* application;
|
|
||||||
|
|
||||||
break = "break";
|
|
||||||
continue = "continue";
|
|
||||||
loop-control:alias = break | continue;
|
|
||||||
range-over = symbol nl* "in" nl* (expression | range) | range;
|
|
||||||
loop-expression:alias = expression | range-over;
|
|
||||||
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
|
||||||
|
|
||||||
assignment = (symbol | indexer) nl* "=" nl* expression;
|
|
||||||
|
|
||||||
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
|
||||||
value-capture = value-capture-fact;
|
|
||||||
mutable-capture = "~" nl* value-capture-fact;
|
|
||||||
value-definition = "let" nl* (value-capture | mutable-capture);
|
|
||||||
mixed-capture-list:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
|
|
||||||
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
|
||||||
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
|
||||||
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
|
||||||
|
|
||||||
function-definition-fact:alias = symbol nl* function-fact;
|
|
||||||
function-capture = function-definition-fact;
|
|
||||||
effect-capture = "~" nl* function-definition-fact;
|
|
||||||
function-definition = "fn" nl* (function-capture | effect-capture);
|
|
||||||
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
|
||||||
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
|
||||||
(list-sep (function-capture | effect-capture))*;
|
|
||||||
function-definition-group = "fn" nl* "(" list-sep?
|
|
||||||
mixed-function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
effect-definition-group = "fn" nl* "~" nl* "(" list-sep?
|
|
||||||
function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
|
|
||||||
definition:alias = value-definition
|
|
||||||
| value-definition-group
|
|
||||||
| mutable-definition-group
|
|
||||||
| function-definition
|
|
||||||
| function-definition-group
|
|
||||||
| effect-definition-group;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - use effect
|
|
||||||
|
|
||||||
use-inline = ".";
|
|
||||||
use-fact = string
|
|
||||||
| (symbol | use-inline) (nl* "=")? nl* string;
|
|
||||||
use-fact-list:alias = use-fact (list-sep use-fact)*;
|
|
||||||
use-statement:alias = "use" nl* use-fact;
|
|
||||||
use-statement-group:alias = "use" nl* "(" list-sep?
|
|
||||||
use-fact-list?
|
|
||||||
list-sep? ")";
|
|
||||||
use = use-statement | use-statement-group;
|
|
||||||
|
|
||||||
export = "export" nl* definition;
|
|
||||||
|
|
||||||
simple-statement:alias = send
|
|
||||||
| go
|
|
||||||
| defer
|
|
||||||
| assignment
|
|
||||||
| simple-statement-group;
|
|
||||||
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
|
||||||
statement:alias = simple-statement
|
|
||||||
| return
|
|
||||||
| if
|
|
||||||
| switch
|
|
||||||
| select
|
|
||||||
| loop
|
|
||||||
| loop-control
|
|
||||||
| definition
|
|
||||||
| use
|
|
||||||
| export
|
|
||||||
| application // TODO: sendSomething() and sendSomething
|
|
||||||
| chaining
|
|
||||||
| statement-group;
|
|
||||||
statement-group:alias = "(" nl* statement nl* ")";
|
|
||||||
|
|
||||||
sep:alias = (";" | nl)+;
|
|
||||||
statement-list:alias = statement (sep statement)*;
|
|
||||||
|
|
||||||
shebang-command = [^\n]*;
|
|
||||||
shebang = "#!" shebang-command "\n";
|
|
||||||
mml:root = shebang? sep? statement-list? sep?;
|
|
||||||
@ -1,266 +0,0 @@
|
|||||||
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
|
|
||||||
wsc:ws = comment;
|
|
||||||
nl:alias = "\n";
|
|
||||||
|
|
||||||
line-comment-content:nows = [^\n]*;
|
|
||||||
line-comment:alias:nows = "//" line-comment-content;
|
|
||||||
block-comment-content:nows = ([^*] | "*" [^/])*;
|
|
||||||
block-comment:alias:nows = "/*" block-comment-content "*/";
|
|
||||||
comment-part:alias = line-comment | block-comment;
|
|
||||||
comment:alias = comment-part ("\n"? comment-part)*;
|
|
||||||
|
|
||||||
decimal-digit:alias = [0-9];
|
|
||||||
octal-digit:alias = [0-7];
|
|
||||||
hexa-digit:alias = [0-9a-fA-F];
|
|
||||||
|
|
||||||
decimal:alias:nows = [1-9] decimal-digit*;
|
|
||||||
octal:alias:nows = "0" octal-digit*;
|
|
||||||
hexa:alias:nows = "0" [xX] hexa-digit+;
|
|
||||||
int = decimal | octal | hexa;
|
|
||||||
|
|
||||||
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
|
|
||||||
float:nows = decimal-digit+ "." decimal-digit* exponent?
|
|
||||||
| "." decimal-digit+ exponent?
|
|
||||||
| decimal-digit+ exponent;
|
|
||||||
|
|
||||||
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
|
|
||||||
|
|
||||||
true = "true";
|
|
||||||
false = "false";
|
|
||||||
bool:alias = true | false;
|
|
||||||
|
|
||||||
symbol:nows = [a-zA-Z_][a-zA-Z_0-9]*;
|
|
||||||
|
|
||||||
spread-expression = primary-expression "...";
|
|
||||||
list-sep:alias = (nl | ",")+;
|
|
||||||
list-item:alias = expression | spread-expression;
|
|
||||||
expression-list:alias = list-item (list-sep list-item)*;
|
|
||||||
|
|
||||||
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
|
|
||||||
list = list-fact;
|
|
||||||
mutable-list = "~" nl* list-fact;
|
|
||||||
|
|
||||||
expression-key = "[" nl* expression nl* "]";
|
|
||||||
entry = (symbol | string | expression-key) nl* ":" nl* expression;
|
|
||||||
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
|
|
||||||
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
|
|
||||||
struct = struct-fact;
|
|
||||||
mutable-struct = "~" nl* struct-fact;
|
|
||||||
|
|
||||||
channel = "<>" | "<" nl* expression nl* ">";
|
|
||||||
|
|
||||||
parameter-list:alias = symbol (list-sep symbol)*;
|
|
||||||
collect-parameter = "..." nl* symbol;
|
|
||||||
return = "return" (nl* expression)?;
|
|
||||||
block = "{" sep? statement-list? sep? "}";
|
|
||||||
function-fact:alias = "(" list-sep?
|
|
||||||
parameter-list?
|
|
||||||
(list-sep collect-parameter)?
|
|
||||||
list-sep? ")" nl*
|
|
||||||
(simple-statement | block);
|
|
||||||
function = "fn" nl* function-fact;
|
|
||||||
effect = "fn" nl* "~" nl* function-fact;
|
|
||||||
|
|
||||||
range-from = expression;
|
|
||||||
range-to = expression;
|
|
||||||
range:alias = range-from? nl* ":" nl* range-to?;
|
|
||||||
|
|
||||||
simple-indexer:alias = primary-expression "[" nl* expression nl* "]";
|
|
||||||
range-indexer:alias = primary-expression "[" nl* range nl* "]";
|
|
||||||
expression-indexer = simple-indexer | range-indexer;
|
|
||||||
symbol-indexer = primary-expression nl* "." nl* symbol;
|
|
||||||
|
|
||||||
function-application = primary-expression "(" list-sep? expression-list? list-sep? ")";
|
|
||||||
|
|
||||||
expression-group:alias = "(" nl* expression nl* ")";
|
|
||||||
primary-expression:alias = int
|
|
||||||
| float
|
|
||||||
| string
|
|
||||||
| bool
|
|
||||||
| symbol
|
|
||||||
| list
|
|
||||||
| mutable-list
|
|
||||||
| struct
|
|
||||||
| mutable-struct
|
|
||||||
| channel
|
|
||||||
| function
|
|
||||||
| effect
|
|
||||||
| expression-indexer
|
|
||||||
| symbol-indexer
|
|
||||||
| function-application
|
|
||||||
| receive
|
|
||||||
| expression-group;
|
|
||||||
|
|
||||||
binary-not = "^";
|
|
||||||
binary-and = "&";
|
|
||||||
binary-or = "|";
|
|
||||||
xor = "^";
|
|
||||||
and-not = "&^";
|
|
||||||
lshift = "<<";
|
|
||||||
rshift = ">>";
|
|
||||||
|
|
||||||
plus = "+";
|
|
||||||
minus = "-";
|
|
||||||
mul = "*";
|
|
||||||
div = "/";
|
|
||||||
mod = "%";
|
|
||||||
add = "+";
|
|
||||||
sub = "-";
|
|
||||||
|
|
||||||
logical-not = "!";
|
|
||||||
eq = "==";
|
|
||||||
not-eq = "!=";
|
|
||||||
less = "<";
|
|
||||||
less-or-eq = "<=";
|
|
||||||
greater = ">";
|
|
||||||
greater-or-eq = ">=";
|
|
||||||
logical-and = "&&";
|
|
||||||
logical-or = "||";
|
|
||||||
|
|
||||||
chain:alias = "->";
|
|
||||||
|
|
||||||
unary-operator:alias = plus | minus | binary-not | logical-not;
|
|
||||||
unary-expression = unary-operator primary-expression;
|
|
||||||
|
|
||||||
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
|
|
||||||
binary-op1:alias = binary-or | xor | add | sub;
|
|
||||||
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
|
|
||||||
binary-op3:alias = logical-and;
|
|
||||||
binary-op4:alias = logical-or;
|
|
||||||
|
|
||||||
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 (binary-op0 operand0)+;
|
|
||||||
binary1 = operand1 (binary-op1 operand1)+;
|
|
||||||
binary2 = operand2 (binary-op2 operand2)+;
|
|
||||||
binary3 = operand3 (binary-op3 operand3)+;
|
|
||||||
binary4 = operand4 (binary-op4 operand4)+;
|
|
||||||
chaining = operand5 (nl* chain nl* operand5)+;
|
|
||||||
|
|
||||||
binary-expression:alias = binary0
|
|
||||||
| binary1
|
|
||||||
| binary2
|
|
||||||
| binary3
|
|
||||||
| binary4
|
|
||||||
| chaining;
|
|
||||||
|
|
||||||
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
|
|
||||||
|
|
||||||
expression:alias = primary-expression
|
|
||||||
| unary-expression
|
|
||||||
| binary-expression
|
|
||||||
| ternary-expression;
|
|
||||||
|
|
||||||
if = "if" nl* expression nl* block
|
|
||||||
(nl* "else" nl* "if" nl* expression nl* block)*
|
|
||||||
(nl* "else" nl* block)?;
|
|
||||||
|
|
||||||
default = "default" nl* ":";
|
|
||||||
default-line:alias = default ";"* statement?;
|
|
||||||
case = "case" nl* expression nl* ":";
|
|
||||||
case-line:alias = case ";"* statement?;
|
|
||||||
switch = "switch" nl* expression? nl* "{" sep?
|
|
||||||
((case-line | default-line) (sep (case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
receive = "<<>" primary-expression;
|
|
||||||
receive-definition = "let" nl* symbol nl* receive;
|
|
||||||
receive-assignment = "set" nl* symbol nl* receive;
|
|
||||||
receive-statement:alias = receive-definition
|
|
||||||
| receive-assignment;
|
|
||||||
send = primary-expression "<<>" primary-expression;
|
|
||||||
communication:alias = receive | receive-statement | send;
|
|
||||||
|
|
||||||
select-case = "case" nl* communication nl* ":";
|
|
||||||
select-case-line:alias = select-case ";"* statement?;
|
|
||||||
select = "select" nl* "{" sep?
|
|
||||||
((select-case-line | default-line)
|
|
||||||
(sep (select-case-line | default-line | statement))*)?
|
|
||||||
sep? "}";
|
|
||||||
|
|
||||||
go = "go" nl* function-application;
|
|
||||||
defer = "defer" nl* function-application;
|
|
||||||
|
|
||||||
range-over-expression = symbol nl* "in" nl* (expression | range) | range;
|
|
||||||
loop-expression:alias = expression | range-over-expression;
|
|
||||||
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
|
|
||||||
|
|
||||||
assign-capture:alias = primary-expression (nl* "=")? nl* expression;
|
|
||||||
assign-capture-list:alias = assign-capture (list-sep assign-capture)*;
|
|
||||||
assign-set:alias = "set" nl* assign-capture;
|
|
||||||
assign-eq:alias = primary-expression nl* "=" nl* expression;
|
|
||||||
assign-group:alias = "set" nl* "(" (list-sep assign-capture-list)? list-sep? ")";
|
|
||||||
assignment = assign-set | assign-eq | assign-group;
|
|
||||||
|
|
||||||
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
|
|
||||||
value-capture = value-capture-fact;
|
|
||||||
mutable-capture = "~" nl* value-capture-fact;
|
|
||||||
value-definition = "let" nl* (value-capture | mutable-capture);
|
|
||||||
mixed-capture-list:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
|
|
||||||
value-capture-list:alias = value-capture (list-sep value-capture)*;
|
|
||||||
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
|
|
||||||
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
|
|
||||||
|
|
||||||
function-definition-fact:alias = symbol nl* function-fact;
|
|
||||||
function-capture = function-definition-fact;
|
|
||||||
effect-capture = "~" nl* function-definition-fact;
|
|
||||||
function-definition = "fn" nl* (function-capture | effect-capture);
|
|
||||||
function-capture-list:alias = function-capture (list-sep function-capture)*;
|
|
||||||
mixed-function-capture-list:alias = (function-capture | effect-capture)
|
|
||||||
(list-sep (function-capture | effect-capture))*;
|
|
||||||
function-definition-group = "fn" nl* "(" list-sep?
|
|
||||||
mixed-function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
effect-definition-group = "fn" nl* "~" nl* "(" list-sep?
|
|
||||||
function-capture-list?
|
|
||||||
list-sep? ")";
|
|
||||||
|
|
||||||
definition:alias = value-definition
|
|
||||||
| value-definition-group
|
|
||||||
| mutable-definition-group
|
|
||||||
| function-definition
|
|
||||||
| function-definition-group
|
|
||||||
| effect-definition-group;
|
|
||||||
|
|
||||||
require-inline = ".";
|
|
||||||
require-fact = string
|
|
||||||
| (symbol | require-inline) (nl* "=")? nl* string;
|
|
||||||
require-fact-list:alias = require-fact (list-sep require-fact)*;
|
|
||||||
require-statement:alias = "require" nl* require-fact;
|
|
||||||
require-statement-group:alias = "require" nl* "(" list-sep?
|
|
||||||
require-fact-list?
|
|
||||||
list-sep? ")";
|
|
||||||
require = require-statement | require-statement-group;
|
|
||||||
|
|
||||||
export = "export" nl* definition;
|
|
||||||
|
|
||||||
simple-statement:alias = expression
|
|
||||||
| send
|
|
||||||
| go
|
|
||||||
| defer
|
|
||||||
| assignment
|
|
||||||
| simple-statement-group;
|
|
||||||
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
|
|
||||||
statement:alias = simple-statement
|
|
||||||
| return
|
|
||||||
| if
|
|
||||||
| switch
|
|
||||||
| select
|
|
||||||
| loop
|
|
||||||
| definition
|
|
||||||
| require
|
|
||||||
| export
|
|
||||||
| statement-group;
|
|
||||||
statement-group:alias = "(" nl* statement nl* ")";
|
|
||||||
|
|
||||||
sep:alias = (";" | nl)+;
|
|
||||||
statement-list:alias = statement (sep statement)*;
|
|
||||||
|
|
||||||
shebang-command = [^\n]*;
|
|
||||||
shebang = "#!" shebang-command "\n";
|
|
||||||
mml:root = shebang? sep? statement-list? sep?;
|
|
||||||
@ -276,7 +276,7 @@ func TestErrorVerbose(t *testing.T) {
|
|||||||
// "c":3,
|
// "c":3,
|
||||||
// }`
|
// }`
|
||||||
//
|
//
|
||||||
// s, err := openSyntaxFile("examples/json.treerack")
|
// s, err := openSyntaxFile("example/json.treerack")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// t.Error(err)
|
// t.Error(err)
|
||||||
// return
|
// return
|
||||||
|
|||||||
@ -341,6 +341,7 @@ func formatSequenceItemNode(out io.Writer, targetWidth int, n *Node) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprint("}")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,6 +660,10 @@ func formatAST(out io.Writer, ast *Node) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintln(out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -396,7 +396,8 @@ flag:alias = alias | ws | nows | kw | nokw | failpass | root;
|
|||||||
definition-name:alias:nows = symbol (":" flag)*;
|
definition-name:alias:nows = symbol (":" flag)*;
|
||||||
definition = definition-name "=" expression;
|
definition = definition-name "=" expression;
|
||||||
definitions:alias = definition (";"+ definition)*;
|
definitions:alias = definition (";"+ definition)*;
|
||||||
syntax:root = ";"* definitions? ";"*;`
|
syntax:root = ";"* definitions? ";"*;
|
||||||
|
`
|
||||||
|
|
||||||
func TestDocFormat(t *testing.T) {
|
func TestDocFormat(t *testing.T) {
|
||||||
for _, test := range []struct{ title, in, out string }{{
|
for _, test := range []struct{ title, in, out string }{{
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -285,7 +285,7 @@ func jsonTreeToJSON(n *Node) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestJSON(t *testing.T) {
|
func TestJSON(t *testing.T) {
|
||||||
runTestsFile(t, "docs/examples/json.treerack", []testItem{{
|
runTestsFile(t, "doc/example/json.treerack", []testItem{{
|
||||||
title: "true",
|
title: "true",
|
||||||
text: "true",
|
text: "true",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
@ -509,7 +509,7 @@ func TestRandomJSON(t *testing.T) {
|
|||||||
|
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
|
|
||||||
s, err := openSyntaxFile("docs/examples/json.treerack")
|
s, err := openSyntaxFile("doc/example/json.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestKeyVal(t *testing.T) {
|
func TestKeyVal(t *testing.T) {
|
||||||
runTestsFile(t, "docs/examples/keyval.treerack", []testItem{{
|
runTestsFile(t, "doc/example/keyval.treerack", []testItem{{
|
||||||
title: "empty",
|
title: "empty",
|
||||||
}, {
|
}, {
|
||||||
title: "a comment",
|
title: "a comment",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestMML(t *testing.T) {
|
func TestMML(t *testing.T) {
|
||||||
s, err := openSyntaxFile("docs/examples/mml.treerack")
|
s, err := openSyntaxFile("doc/example/mml.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMMLExp2(t *testing.T) {
|
func TestMMLExp2(t *testing.T) {
|
||||||
s, err := openSyntaxFile("docs/examples/mml-exp2.treerack")
|
s, err := openSyntaxFile("doc/example/mml-exp2.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMMLExp3(t *testing.T) {
|
func TestMMLExp3(t *testing.T) {
|
||||||
s, err := openSyntaxFile("docs/examples/mml-exp3.treerack")
|
s, err := openSyntaxFile("doc/example/mml-exp3.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMMLExp(t *testing.T) {
|
func TestMMLExp(t *testing.T) {
|
||||||
s, err := openSyntaxFile("docs/examples/mml-exp.treerack")
|
s, err := openSyntaxFile("doc/example/mml-exp.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -2987,7 +2987,7 @@ func TestMMLFile(t *testing.T) {
|
|||||||
|
|
||||||
const n = 180
|
const n = 180
|
||||||
|
|
||||||
s, err := openSyntaxFile("docs/examples/mml-exp.treerack")
|
s, err := openSyntaxFile("doc/example/mml-exp.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -2995,7 +2995,7 @@ func TestMMLFile(t *testing.T) {
|
|||||||
|
|
||||||
s.Init()
|
s.Init()
|
||||||
|
|
||||||
f, err := os.Open("docs/examples/test.mml")
|
f, err := os.Open("doc/example/test.mml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -8,8 +8,8 @@ its Abstract Syntax Tree (AST) representation. It utilizes a custom syntax defin
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
- **JSON**: [docs/examples/json.treerack](docs/examples/json.treerack)
|
- **JSON**: [doc/example/json.treerack](doc/example/json.treerack)
|
||||||
- **Scheme**: [docs/examples/scheme.treerack](docs/examples/scheme.treerack)
|
- **Scheme**: [doc/example/scheme.treerack](doc/example/scheme.treerack)
|
||||||
- **Treerack (self-definition)**: [syntax.treerack](syntax.treerack)
|
- **Treerack (self-definition)**: [syntax.treerack](syntax.treerack)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@ -42,8 +42,8 @@ go install code.squareroundforest.org/arpio/treerack/cmd/treerack
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [Manual](docs/manual.md): a guide to the main use cases supported by Treerack.
|
- [Manual](doc/manual.md): a guide to the main use cases supported by Treerack.
|
||||||
- [Syntax Definition](docs/syntax.md): detailed reference for the Treerack definition language.
|
- [Syntax Definition](doc/syntax.md): detailed reference for the Treerack definition language.
|
||||||
- [Library Documentation](https://godocs.io/code.squareroundforest.org/arpio/treerack): GoDoc reference for the
|
- [Library Documentation](https://godocs.io/code.squareroundforest.org/arpio/treerack): GoDoc reference for the
|
||||||
runtime library.
|
runtime library.
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestScheme(t *testing.T) {
|
func TestScheme(t *testing.T) {
|
||||||
runTestsFile(t, "docs/examples/scheme.treerack", []testItem{{
|
runTestsFile(t, "doc/example/scheme.treerack", []testItem{{
|
||||||
title: "empty",
|
title: "empty",
|
||||||
}, {
|
}, {
|
||||||
title: "a function",
|
title: "a function",
|
||||||
|
|||||||
@ -141,7 +141,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"package %s\n\n// generated with scripts/createhead.go\nconst %s=%s",
|
"package %s\n\n// generated with script/createhead.go\nconst %s=%s",
|
||||||
packageName,
|
packageName,
|
||||||
varName,
|
varName,
|
||||||
quotedCode,
|
quotedCode,
|
||||||
46
script/format.go
Normal file
46
script/format.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"code.squareroundforest.org/arpio/treerack"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func format(name string) (err error) {
|
||||||
|
var inBytes []byte
|
||||||
|
if inBytes, err = os.ReadFile(name); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
in := bytes.NewBuffer(inBytes)
|
||||||
|
s := new(treerack.Syntax)
|
||||||
|
if err = s.ReadSyntax(in); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := bytes.NewBuffer(nil)
|
||||||
|
if err = s.Format(out); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(out.Bytes(), inBytes) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stderr, name)
|
||||||
|
if err = os.WriteFile(name, out.Bytes(), 0644); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
for _, f := range os.Args[1:] {
|
||||||
|
if err := format(f); err != nil {
|
||||||
|
log.Fatalf("%s: %v", f, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestSExpr(t *testing.T) {
|
func TestSExpr(t *testing.T) {
|
||||||
runTestsFile(t, "docs/examples/sexpr.treerack", []testItem{{
|
runTestsFile(t, "doc/example/sexpr.treerack", []testItem{{
|
||||||
title: "number",
|
title: "number",
|
||||||
text: "42",
|
text: "42",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
|
|||||||
@ -483,7 +483,7 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
|
|||||||
fprintln()
|
fprintln()
|
||||||
fprintln()
|
fprintln()
|
||||||
|
|
||||||
// generate headCode with scripts/createhead.go
|
// generate headCode with script/createhead.go
|
||||||
hc := headCode
|
hc := headCode
|
||||||
if o.Export {
|
if o.Export {
|
||||||
hc = headCodeExported
|
hc = headCodeExported
|
||||||
|
|||||||
@ -7,39 +7,49 @@
|
|||||||
/* foo
|
/* foo
|
||||||
bar baz */ // foo bar baz
|
bar baz */ // foo bar baz
|
||||||
wschar:alias = // foo
|
wschar:alias = // foo
|
||||||
/* bar */ " " | "\t" | "\n" | "\b" | "\f" | "\r" | "\v";
|
/* bar */
|
||||||
|
" " | "\t" | "\n" | "\b" | "\f" | "\r" | "\v";
|
||||||
wsc:ws = wschar | comment;
|
wsc:ws = wschar | comment;
|
||||||
|
block-comment:alias:nows = /* foo */ // bar
|
||||||
block-comment:alias:nows /* foo */ // bar
|
"/*" ("*" [^/] | [^*])* "*/";
|
||||||
= "/*" ("*" [^/] | [^*])* "*/";
|
line-comment:alias:nows = /*
|
||||||
line-comment:alias:nows /*
|
|
||||||
foo
|
foo
|
||||||
*/ = "//" [^\n]*;
|
*/
|
||||||
|
"//" [^\n]*;
|
||||||
comment-segment:alias:nows = // bar
|
comment-segment:alias:nows = // bar
|
||||||
line-comment | block-comment;
|
line-comment | block-comment;
|
||||||
ws-no-nl:alias:nows = " " | "\t" | "\b" | /* this one */ /* is a */ "\f" /* form feed */ /* for sure */ | "\r" | "\v";
|
ws-no-nl:alias:nows = " "
|
||||||
comment:nows = comment-segment /* segment is not the best name */ /* but */ (ws-no-nl* "\n"? ws-no-nl* /* fine */ comment-segment)*;
|
| "\t"
|
||||||
|
| "\b"
|
||||||
|
/* this one */ /* is a */
|
||||||
|
| "\f"
|
||||||
|
/* form feed */ /* for sure */
|
||||||
|
| "\r"
|
||||||
|
| "\v";
|
||||||
|
comment:nows = comment-segment
|
||||||
|
/* segment is not the best name */ /* but */
|
||||||
|
( ws-no-nl*
|
||||||
|
"\n"?
|
||||||
|
ws-no-nl*
|
||||||
|
/* fine */
|
||||||
|
comment-segment
|
||||||
|
)*;
|
||||||
any-char = "."; // equivalent to [^]
|
any-char = "."; // equivalent to [^]
|
||||||
|
|
||||||
// caution: newline is accepted
|
// caution: newline is accepted
|
||||||
/* class not */ class-not = "^";
|
/* class not */
|
||||||
class-char:nows = [^\\\[\]\^\-] | "\\" . /* foo
|
class-not = "^";
|
||||||
bar */;
|
class-char:nows = [^\\\[\]\^\-] | "\\" .; /* foo
|
||||||
char-range:nows = class-char "-" class-char // foo
|
bar */
|
||||||
;
|
char-range:nows = class-char "-" class-char; // foo
|
||||||
char-class:nows = "[" class-not? (class-char | char-range)* "]";
|
char-class:nows = "[" class-not? (class-char | char-range)* "]";
|
||||||
|
|
||||||
// newline is accepted
|
// newline is accepted
|
||||||
sequence-char:nows = [^\\"] | "\\" .;
|
sequence-char:nows = [^\\"] | "\\" .;
|
||||||
char-sequence:nows = "\"" sequence-char* "\"";
|
char-sequence:nows = "\"" sequence-char* "\"";
|
||||||
|
|
||||||
terminal:alias = any-char | char-class | char-sequence;
|
terminal:alias = any-char | char-class | char-sequence;
|
||||||
|
|
||||||
symbol:nows = [^\\ \n\t\b\f\r\v/.\[\]\"{}\^+*?|():=;]+;
|
symbol:nows = [^\\ \n\t\b\f\r\v/.\[\]\"{}\^+*?|():=;]+;
|
||||||
|
|
||||||
group:alias = "(" expression ")";
|
group:alias = "(" expression ")";
|
||||||
|
|
||||||
number:alias:nows = [0-9]+;
|
number:alias:nows = [0-9]+;
|
||||||
count = number;
|
count = number;
|
||||||
count-quantifier = "{" count "}";
|
count-quantifier = "{" count "}";
|
||||||
@ -49,15 +59,9 @@ range-quantifier = "{" range-from? "," range-to? "}";
|
|||||||
one-or-more = "+";
|
one-or-more = "+";
|
||||||
zero-or-more = "*";
|
zero-or-more = "*";
|
||||||
zero-or-one = "?";
|
zero-or-one = "?";
|
||||||
quantity:alias = count-quantifier
|
quantity:alias = count-quantifier | range-quantifier | one-or-more | zero-or-more | zero-or-one;
|
||||||
| range-quantifier
|
|
||||||
| one-or-more
|
|
||||||
| zero-or-more
|
|
||||||
| zero-or-one;
|
|
||||||
|
|
||||||
item:nows = (terminal | symbol | group) quantity?;
|
item:nows = (terminal | symbol | group) quantity?;
|
||||||
sequence = item+;
|
sequence = item+;
|
||||||
|
|
||||||
option:alias = terminal | symbol | group | sequence;
|
option:alias = terminal | symbol | group | sequence;
|
||||||
|
|
||||||
// DOC: how the order matters
|
// DOC: how the order matters
|
||||||
@ -66,7 +70,6 @@ choice = option ("|" option)+;
|
|||||||
// DOC: not having 'not' needs some tricks sometimes
|
// DOC: not having 'not' needs some tricks sometimes
|
||||||
|
|
||||||
expression:alias = terminal | symbol | group | sequence | choice;
|
expression:alias = terminal | symbol | group | sequence | choice;
|
||||||
|
|
||||||
alias = "alias";
|
alias = "alias";
|
||||||
ws = "ws";
|
ws = "ws";
|
||||||
nows = "nows";
|
nows = "nows";
|
||||||
@ -77,6 +80,5 @@ root = "root";
|
|||||||
flag:alias = alias | ws | nows | kw | nokw | failpass | root;
|
flag:alias = alias | ws | nows | kw | nokw | failpass | root;
|
||||||
definition-name:alias:nows = symbol (":" flag)*;
|
definition-name:alias:nows = symbol (":" flag)*;
|
||||||
definition = definition-name "=" expression;
|
definition = definition-name "=" expression;
|
||||||
|
|
||||||
definitions:alias = definition (";"+ definition)*;
|
definitions:alias = definition (";"+ definition)*;
|
||||||
syntax:root = ";"* definitions? ";"*;
|
syntax:root = ";"* definitions? ";"*;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user