_seps: "(){}[],.:;=<>*·+-/%^?~|&∧∨!¬∑∃∀\n\"\u005c"

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

0 fn = {
    ["fn" .w! .."("!:"name" ?w "(" ?w args ?w ")" ?w ?currents ?w {
            ["->":"returns" ?w ?type:"ret_type"]
            !"->":!"returns"
        } ?w block:"block"]
    [.."("!:"name" ?w "(" ?w args ?w ")" ?w ?currents ?w "=" ?w expr:"expr"]
}
1 args = .s?.(, arg:"arg")
2 arg = [?"mut":"mut" ?w .._seps!:"name" ?[?w ":" ?w
         ?["'" ?w .._seps!:"lifetime"] ?w ?type:"type"]]
3 imm_arg = [!"mut " .._seps!:"name" ?[?w ":" ?w !"'" ?type:"type"]]
3 closure = ["\u005c(" ?w .s?.(, imm_arg:"arg") ?w ")" ?w ?currents
             ?w "=" ?w expr:"expr"]
4 call_closure = ["\u005c" item:"item" ?w "(" .s?.(, arg_expr:"call_arg") ?w ")"]
5 named_call_closure = ["\u005c" item:"item" ?w "(" ?w
    .s?.(, [.._seps!:"word" ?w ":" ?w arg_expr:"call_arg" ?w]) ")"]
3 currents = ["~" ?w .s!.(, current:"current")]
4 current = [?"mut":"mut" ?w .._seps!:"name" ?[?w ":" ?w type:"type"]]
// Support both multi-line expressions and single line.
5 block = ["{" ?w {.l([?w expr:"expr" ?w]) [?w expr:"expr"]} ?w "}"]
6 expr = [{
    closure:"closure"
    object:"object"
    arr
    ["return" wn expr:"return"]
    for_n:"for_n"
    for:"for"
    loop:"loop"
    if:"if"
    break:"break"
    continue:"continue"
    block:"block"
    assign:"assign"
    compare:"compare"
    ["return":"return_void"]
    add:"add"
    short_loops
    items
} try]
// Interprets "return" as variable, does not expect loops or assignment.
7 arg_expr = {
    ["mut":"mut" ?w item:"item"]
    swizzle:"swizzle"
    [{
        closure:"closure"
        object:"object"
        arr
        if:"if"
        block:"block"
        compare:"compare"
        add:"add"
        short_loops
        items
    } try]
}
8 lexpr = [{
    closure:"closure"
    object:"object"
    arr
    short_loops
    block:"block"
    items
} try]
9 object = ["{" ?w .s?.(, key_value:"key_value") ?w "}"]
10 array = ["[" ?w .s?.(, expr:"array_item") ?w "]"]
11 array_fill = ["[" ?w expr:"fill" ?w ";" ?w expr:"n" ?w "]"]
12 key_value = [.._seps!:"key" ?w ":" ?w expr:"val"]
13 num = .$_:"num"
14 vec4 = ["(" ?w arg_expr:"x" , ?arg_expr:"y"
           ?[, arg_expr:"z" ?[, arg_expr:"w"]] ?, ?w ")"]
15 color = ["#" .._seps!:"color"]
16 text = .t?:"text"
17 bool = {"true":"bool" "false":!"bool"}
18 unop_not = [{"!":"!" "¬":"!"} ?w lexpr:"expr"]
18 unop_neg = ["-":"-" ?w mul_expr:"expr"]
19 norm = ["|" ?w expr:"expr" ?w "|"]
19 item = [?"~":"current" ?w .._seps!:"name" ?[?w "?":"try_item"]
    ?item_extra:"item_extra"]
20 item_extra = .r!([{
           [?w "[" ?w {.t?:"id" .$_:"id" expr:"id"} ?w "]"]
           [?w "." ?w .._seps!:"id"]} ?[?w "?":"try_id"]])
20 link = ["link" ?w "{" ?w .s?.(?w expr:"link_item") "}"]
21 for = [label "for" .w!
    expr:"init" ?w ";" ?w
    expr:"cond" ?w ";" ?w
    expr:"step" ?w block:"block"]
22 for_n = [label "for" short_body]
23 loop = [label "loop" .w!  block:"block"]
24 break = ["break" ?w ?["'" .._seps!:"label"]]
25 continue = ["continue" ?w ?["'" .._seps!:"label"]]
26 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"]]
27 call = [.._seps!:"name" wn "(" .s?.(, arg_expr:"call_arg") ?w ")"]
28 named_call = [.._seps!:"word" wn "(" ?w
    .s?.(, [.._seps!:"word" ?w ":" ?w arg_expr:"call_arg" ?w]) ")"]
29 go = ["go " ?w {call:"call" named_call:"named_call"}]
30 assign = [lexpr:"left" ?w assign_op ?w expr:"right"]
31 assign_op = {":=":":=" "=":"=" "+=":"+=" "-=":"-=" "*=":"*=" "/=":"/=" "%=":"%="}
32 compare = [lexpr:"left" ?w compare_op ?w expr:"right"]
33 compare_op = {"==":"==" "!=":"!=" "¬=":"!=" "<=":"<=" "<":"<" ">=":">=" ">":">"}
34 grab = ["grab" ?[w "'" .$:"grab_level"] w expr:"expr"]

40 label = ?["'" .._seps!:"label" ?w ":" ?w]
41 short_body = [.w! .s!.(, [.._seps!:"name" ?w
    ?{
        ["[" ?w expr:"start" , expr:"end" ?w ")"]
        [!"{" expr:"end"]
    }]) ?w block:"block"]
42 try = ?[?w "?":"try"]
43 , = [?w "," ?w]
44 arr = {array:"array" array_fill:"array_fill"}
45 items = {vec4:"vec4" link:"link" grab:"grab"
            ["(" ?w expr ?w ")"] unop_not:"unop" norm:"norm"
            text go:"go"
            call_closure:"call_closure" named_call_closure:"named_call_closure"
            call:"call" named_call:"named_call"
            num bool color item:"item"}
// Allow whitespace, but no new line.
46 wn = .r?({" " "\t" "\r"})

50 short_loops = {sum:"sum" prod:"prod" sum_vec4:"sum_vec4" min:"min" max:"max" sift:"sift"
    any:"any" all:"all" vec4_un_loop:"vec4_un_loop"}
51 sum = [label {"sum" "∑"} short_body]
52 prod = [label {"prod" "∏"} short_body]
53 min = [label "min" short_body]
54 max = [label "max" short_body]
55 sift = [label "sift" short_body]
56 any = [label {"any" "∃"} short_body]
57 all = [label {"all" "∀"} short_body]
58 sum_vec4 = [label {"sum_vec4" "∑vec4"} short_body]
59 vec4_un_loop = ["vec" {"4":"4" "3":"3" "2":"2"}
                   w .._seps!:"name" w expr:"expr"]
60 swizzle = [sw:"sw0" sw:"sw1" ?sw:"sw2" ?sw:"sw3" w expr:"expr"]
61 sw = {"x":"x" "y":"y" "z":"z" "w":"w"}

70 type = {
    "any":"any"
    "bool":"bool"
    "f64":"f64"
    "str":"str"
    "vec4":"vec4"
    "link":"link"
    ["opt" ?w "[" ?w type:"opt" ?w "]"]
    "opt":"opt_any"
    ["res" ?w "[" ?w type:"res" ?w "]"]
    "res":"res_any"
    "[]":"arr_any"
    ["[" ?w type:"arr" ?w "]"]
    "{}":"obj_any"
    ["thr" ?w "[" ?w type:"thr" ?w "]"]
    "thr":"thr_any"
    closure_type:"closure_type"
    [.._seps!:"ad_hoc" ?[?w type:"ad_hoc_ty"]]
}
71 closure_type = ["\u005c(" ?w .s?.(, type:"cl_arg") ?w ")"
    ?w "->" ?w type:"cl_ret"]

101 + = [?w {"+":"+" "||":"||" "∨":"+" ["or":"+" w]} ?w]
102 - = [wn "-":"-" ?w]
// Allow whitespace before multiplication sign, but no new line.
// This prevents `x` on a new line from being interpreted as multiplication sign.
103 * = [wn {
    "*.":"*." "·":"*."
    ["x":"x" w] "⨯":"x"
    "*":"*" "&&":"&&" "∧":"*" ["and":"*" w]
} ?w]
104 / = [?w "/":"/" ?w]
105 % = [?w "%":"%" ?w]
107 pow = [lexpr:"base" ?w "^" ?w lexpr:"exp"]
108 mul = .s!({* / %} {unop_neg:"unop" pow:"pow" lexpr:"val"})
109 mul_expr = {mul:"mul"}
109 add = .s!({+ -} mul_expr:"expr")

1000 document = .l({[.w? fn:"fn"] comment})
