dyon 0.4.0

A rusty dynamically typed scripting language
Documentation
_seps: "(){}[],.:;=<>*+-/%^?"

200 multi_line_comment = ["/*" ..."*/"? .r?({
    [!"*/" "*" ..."*/"?]
    [multi_line_comment ..."*/"?]
    ["/" ..."*/"?]
}) "*/"]
201 comment = {multi_line_comment ["//" ..."\n"?]}
// 202 w = .r!({.w! comment})
202 w = .r!({.w! comment})

0 fn = ["fn" .w! .."("!:"name" ?w "(" args ")" ?w ?"->":"returns" ?w block:"block"]
1 args = .s?.([?w "," ?w] arg:"arg")
2 arg = [.._seps!:"name" ?[?w ":" ?w "'" ?w .._seps!:"lifetime"]]
// Support both multi-line expressions and single line.
3 block = ["{" ?w {.l([?w expr:"expr" ?w]) [?w expr:"expr"]} ?w "}"]
4 expr = [{
    object:"object"
    array:"array"
    array_fill:"array_fill"
    ["return" .w! expr:"return"]
    for:"for"
    loop:"loop"
    if:"if"
    break:"break"
    continue:"continue"
    block:"block"
    assign:"assign"
    compare:"compare"
    ["return":"return_void"]
    add:"add"
    ["(" ?w expr ?w ")"]
    unop:"unop"
    text
    call:"call"
    named_call:"named_call"
    num
    bool
    item:"item"
} ?[?w "?":"try"]]
// Interprets "return" as variable, does not expect loops or assignment.
5 arg_expr = [{
    object:"object"
    array:"array"
    array_fill:"array_fill"
    if:"if"
    block:"block"
    compare:"compare"
    add:"add"
    ["(" ?w expr ?w ")"]
    unop:"unop"
    text
    call:"call"
    named_call:"named_call"
    num
    bool
    item:"item"
} ?[?w "?":"try"]]
6 lexpr = [{
    object:"object"
    array:"array"
    array_fill:"array_fill"
    block:"block"
    ["(" ?w expr ?w ")"]
    unop:"unop"
    text
    call:"call"
    named_call:"named_call"
    num
    bool
    item:"item"
} ?[?w "?":"try"]]
7 object = ["{" ?w .s?.([?w "," ?w] key_value:"key_value") ?w "}"]
8 array = ["[" ?w .s?.([?w "," ?w] expr:"array_item") ?w "]"]
9 array_fill = ["[" ?w [expr:"fill" ?w ";" ?w expr:"n"] ?w "]"]
10 key_value = [.._seps!:"key" ?w ":" ?w expr:"val"]
11 num = .$_:"num"
12 text = .t?:"text"
13 bool = {"true":"bool" "false":!"bool"}
14 unop = ["!":"!" ?w lexpr:"expr"]
15 item = [.._seps!:"name" ?[?w "?":"try_item"] .r?([{
    [?w "[" ?w {.t?:"id" .$_:"id" expr:"id"} ?w "]"]
    [?w "." ?w .._seps!:"id"]
} ?[?w "?":"try_id"]])]
16 for = [?["'" .._seps!:"label" ?w ":" ?w] "for" .w!
    expr:"init" ?w ";" ?w
    expr:"cond" ?w ";" ?w
    expr:"step" ?w block:"block"]
17 loop = [?["'" .._seps!:"label" ?w ":" ?w] "loop" .w!  block:"block"]
18 break = ["break" ?w ?["'" .._seps!:"label"]]
19 continue = ["continue" ?w ?["'" .._seps!:"label"]]
20 if = [
    "if" .w! expr:"cond" ?w block:"true_block"
    .r?([?w "else" w "if" ?w expr:"else_if_cond" ?w block:"else_if_block"])
    ?[?w "else" ?w block:"else_block"]
]
21 call = [.._seps!:"name" ?w "(" .s?.([?w "," ?w] arg_expr:"call_arg") ?w ")"]
22 named_call = [.._seps!:"word" ?w "(" ?w
    .s?.([?w "," ?w] [.._seps!:"word" ?w ":" ?w arg_expr:"call_arg" ?w]) ")"]
23 assign = [lexpr:"left" ?w assign_op ?w expr:"right"]
24 assign_op = {
    ":=":":="
    "=":"="
    "+=":"+="
    "-=":"-="
    "*=":"*="
    "/=":"/="
    "%=":"%="
}
25 compare = [lexpr:"left" ?w compare_op ?w expr:"right"]
26 compare_op = {
    "==":"=="
    "!=":"!="
    "<=":"<="
    "<":"<"
    ">=":">="
    ">":">"
}

101 + = [?w {"+":"+" "||":"+"} ?w]
102 - = [?w "-":"-" ?w]
103 * = [?w {"*":"*" "&&":"*"} ?w]
104 / = [?w "/":"/" ?w]
105 % = [?w "%":"%" ?w]
107 pow = [lexpr:"base" ?w "^" ?w lexpr:"exp"]
108 mul = .s!({* / %} {
    pow:"pow"
    lexpr:"val"
})
109 add = .s!({+ -} {
    mul:"mul"
})

1000 document = .l({fn:"fn" comment})