language2.bnf (4217B)
1 # Mighty language2 sketch grammar 2 3 program ::= { nl | top nl } 4 nl ::= NEWLINE { NEWLINE } 5 6 top ::= namespace | use | decl 7 namespace ::= "ns" path 8 use ::= "use" path 9 decl ::= [ "pub" ] ( struct | function | operator ) 10 11 struct ::= "struct" Type [ generics ] "::" block(member) 12 member ::= field | decl 13 field ::= type names 14 names ::= name { "," name } 15 16 function ::= { pre nl } signature { where_part } body 17 pre ::= "pre" expr 18 where_part ::= [ nl ] where 19 where ::= "where" constraint # may mention contextual `result` 20 signature ::= type name [ generics ] "(" [ params ] ")" 21 params ::= param { "," param } 22 param ::= type [ name ] 23 body ::= [ nl ] "=" ( expr | nl expr ) | "::" block(stmt) 24 25 operator ::= "op" op [ generics ] "(" params ")" "->" type body 26 27 stmt ::= binding | ret | expr 28 binding ::= type name "=" expr 29 ret ::= "ret" expr 30 31 generics ::= "[" typevar { "," typevar } "]" 32 typevar ::= Type 33 constraint ::= expr | type_constraint 34 type_constraint ::= Type ":" trait { "+" trait } 35 trait ::= Type 36 37 type ::= primary_type { type_suffix } 38 primary_type ::= path [ type_args ] | "(" types ")" 39 type_args ::= "[" type { "," type } "]" 40 types ::= type { "," type } 41 type_suffix ::= "[]" # slice/dynamic array 42 | "[" int_lit "]" # fixed array 43 | "?" # option: T? 44 | "!" type # result: T!E 45 46 path ::= name { "." name } 47 48 expr ::= conditional 49 conditional ::= pipe [ "if" expr "else" expr ] 50 pipe ::= scan { "|" ( map | expr ) } 51 map ::= "@" "(" expr ")" # each: `.` is the current element 52 scan ::= [ op "\\" ] reduce # +\xs, *\xs 53 reduce ::= [ op "/" ] logic # +/xs, */xs, max/xs 54 55 logic ::= compare { ( "and" | "or" ) compare } 56 compare ::= range { cmp range } 57 range ::= add [ ".." [ add ] ] 58 add ::= mul { ( "+" | "-" ) mul } 59 mul ::= pow { ( "*" | "/" ) pow } 60 pow ::= unary { "^" unary } 61 unary ::= [ "-" | "#" ] postfix # #xs is length/count 62 63 postfix ::= atom { call | selector | "." name } 64 call ::= "(" [ args ] ")" 65 args ::= expr { "," expr } 66 selector ::= "[" [ items ] "]" # index, gather, mask, or filter expr 67 68 atom ::= literal | path | subject | array | record | "(" expr ")" 69 subject ::= "." [ name ] # current subject/self/element 70 array ::= "[" [ items ] "]" 71 items ::= expr { "," expr } 72 record ::= path "(" [ fields ] ")" 73 fields ::= field_value { "," field_value } 74 field_value ::= name ":" expr 75 76 literal ::= int_lit | float_lit | string | "true" | "false" | "nil" 77 op ::= "+" | "*" | "&" | "|" | "min" | "max" | name 78 cmp ::= "==" | "!=" | "<" | "<=" | ">" | ">=" 79 80 block(x) ::= INDENT { nl | x nl } DEDENT 81 82 # Lexical sketch: name is an identifier, Type is a capitalized identifier. 83 # Comments run from // to end of line. 84 85 # Selector semantics: 86 # xs[i] scalar index 87 # xs[[0, 2]] gather by int[] indices 88 # xs[mask] compress by bool[] mask 89 # xs[.valid] filter by expression evaluated per element 90 91 # Array literals use commas: [1, 2, 3], [true, false, true]. 92 93 # Named record literals use Type(field: value): Vec2(x: 1.0, y: 2.0). 94 95 # Ranges are half-open. Negative indices are relative to the end. 96 # xs[0..-1] selects from the first element up to, not including, the last. 97 98 # Reductions over empty collections are invalid unless the operator has a 99 # defined identity. max/ and min/ require non-empty collections. 100 101 # Values are passed by copy semantically. An implementation may pass by 102 # read-only reference when that is observationally identical. 103 104 # `.` semantics: 105 # In methods, `.` is the receiver. In free functions, `.` is the first argument. 106 # In selectors and @(...), `.` is the current element.