old-language.bnf (6207B)
1 ---------- plan 2 3 5 scalar types: int float bool char str 4 arrays: T[] 5 structs 6 enums 7 methods 8 contracts: @pre @post @inv 9 expression functions with = 10 block functions with :: 11 match 12 conditional expression: x if cond else y 13 pipes: | f, | f(args), | [pred], | @(mapper) 14 15 drop for now: 16 17 block if/else 18 fixed-shape arrays 19 implicit whitespace arrays 20 bind-pipe 21 mutating methods 22 function overloading 23 standalone attributes 24 same-line block bodies 25 complex # shape semantics 26 27 note: pipe rules: 28 x | f // f(x) 29 x | f(a, b) // f(x, a, b) 30 x | [pred] // filter(x, pred) 31 x | @(mapper) // map(x, mapper) 32 33 34 35 36 ------------------ ebnf 37 38 39 40 41 :: opens a layout block 42 indent enters the block 43 dedent exits the block 44 newline separates statements 45 ; only separates statements on one line 46 47 = opens to a single expr line 48 49 note: the following is wrong about this 50 51 52 53 54 program = { top_decl } EOF ; 55 56 top_decl = mod_decl 57 | use_decl 58 | type_decl 59 | const_decl 60 | func_decl ; 61 62 mod_decl = "mod" path CLOSE ; 63 use_decl = "use" path CLOSE ; 64 65 path = ident { "." ident } ; 66 67 attr_decl = attr { NEWLINE attr } ; 68 attr = "@" ident expr ; 69 70 const_decl = "const" type ident "=" expr CLOSE ; 71 72 func_decl = { attr NEWLINE } 73 type ident "(" [ params ] ")" func_body ; 74 75 func_body = "=" expr CLOSE 76 | "::" block ; 77 78 params = param { "," param } ; 79 param = [ "mut" ] type ident 80 | [ "mut" ] "self" ; 81 82 type = base_type { array_suffix } ; 83 84 base_type = "int" 85 | "float" 86 | "bool" 87 | "char" 88 | "str" 89 | ident ; 90 91 array_suffix = "[]" ; 92 shape = int_lit { "," int_lit } ; 93 94 95 96 97 98 99 100 101 block = NEWLINE INDENT block_body DEDENT ; 102 103 block_body = { stmt stmt_sep } final_expr CLOSE ; 104 105 stmt_sep = NEWLINE | SEP ; 106 107 stmt = var_decl 108 | assign_stmt 109 | defer_stmt 110 | expr ; 111 112 var_decl = [ "mut" ] type ident "=" expr ; 113 114 assign_stmt = lvalue "=" expr ; 115 116 defer_stmt = "defer" expr ; 117 118 final_expr = expr ; 119 120 lvalue = ident 121 | postfix_expr "." ident 122 | postfix_expr "[" expr "]" ; 123 124 125 126 127 128 129 130 131 int main() :: 132 io.put("hello") 133 0; 134 // becomes 135 func_decl 136 block 137 stmt: io.put("hello") 138 final_expr: 0 139 CLOSE 140 141 142 143 144 145 146 147 148 149 150 151 type_decl = "type" ident "=" type_body CLOSE ; 152 153 type_body = struct_type 154 | enum_type 155 | type ; 156 157 struct_type = "struct" "::" NEWLINE INDENT 158 { struct_item } 159 DEDENT ; 160 161 struct_item = field_decl 162 | method_decl 163 | attr_decl ; 164 165 field_decl = type ident stmt_sep ; 166 167 method_decl = { attr NEWLINE } 168 type ident "(" [ params ] ")" func_body ; 169 170 enum_type = "enum" "::" NEWLINE INDENT 171 { enum_item } 172 DEDENT ; 173 174 enum_item = enum_case stmt_sep 175 | method_decl 176 | attr_decl ; 177 178 enum_case = ident [ "(" [ fields ] ")" ] ; 179 180 fields = field { "," field } ; 181 field = type ident ; 182 183 184 185 186 187 188 189 190 primary 191 postfix: call, index, field 192 prefix: -, !, #, +/, */, min/, max/, avg/ 193 power: ^ 194 multiplicative: *, /, % 195 additive: +, - 196 range: .. 197 comparison: == != < <= > >= 198 logical and 199 logical or 200 pipe: | 201 lambda: => 202 203 204 205 206 207 208 ebnf 209 210 211 expr = lambda_expr ; 212 213 lambda_expr = pipe_expr 214 | ident "=>" expr ; 215 216 pipe_expr = logic_or_expr { "|" pipe_stage } ; 217 218 pipe_stage = "[" expr "]" (* filter: x | [pred] *) 219 | "@(" expr ")" (* map: x | @(f) *) 220 | ident "=>" expr (* bind: x | y => expr *) 221 | "." ident "(" [ args ] ")" (* method: x | .len() *) 222 | postfix_expr ; (* call: x | f or x | f(a) *) 223 224 logic_or_expr = logic_and_expr { "or" logic_and_expr } ; 225 226 logic_and_expr = compare_expr { "and" compare_expr } ; 227 228 compare_expr = range_expr { compare_op range_expr } ; 229 230 compare_op = "==" | "!=" | "<" | "<=" | ">" | ">=" ; 231 232 range_expr = add_expr [ ".." add_expr ] ; 233 234 add_expr = mul_expr { add_op mul_expr } ; 235 add_op = "+" | "-" ; 236 237 mul_expr = power_expr { mul_op power_expr } ; 238 mul_op = "*" | "/" | "%" ; 239 240 power_expr = prefix_expr [ "^" power_expr ] ; 241 242 prefix_expr = prefix_op prefix_expr 243 | postfix_expr ; 244 245 prefix_op = "-" 246 | "!" 247 | "#" 248 | "+/" 249 | "*/" 250 | "min/" 251 | "max/" 252 | "avg/" ; 253 254 postfix_expr = primary_expr { postfix_suffix } ; 255 256 postfix_suffix = call_suffix 257 | index_suffix 258 | field_suffix ; 259 260 call_suffix = "(" [ args ] ")" ; 261 args = expr { "," expr } ; 262 263 index_suffix = "[" index_expr "]" ; 264 index_expr = expr 265 | [ expr ] ".." [ expr ] ; 266 267 field_suffix = "." ident ; 268 269 primary_expr = literal 270 | ident 271 | array_lit 272 | if_expr 273 | match_expr 274 | "(" expr ")" ; 275 276 277 278 279 280 281 282 283 284 expr = lambda_expr ; 285 286 lambda_expr = if_expr 287 | ident "=>" expr ; 288 289 if_expr = pipe_expr [ "if" expr "else" if_expr ] ; 290 291 292 293 294 295 296 297 298 299 300 301 literal = int_lit 302 | float_lit 303 | bool_lit 304 | char_lit 305 | str_lit ; 306 307 bool_lit = "true" | "false" ; 308 309 array_lit = "[" [ expr { "," expr } ] "]" 310 | scalar_run ; 311 312 scalar_run = scalar_atom scalar_atom { scalar_atom } ; 313 314 scalar_atom = int_lit 315 | float_lit 316 | bool_lit 317 | char_lit 318 | str_lit ; 319 320 ident = letter { letter | digit | "_" } ; 321 322 int_lit = digit { digit } ; 323 float_lit = digit { digit } "." digit { digit } ; 324 325 char_lit = "'" char_body "'" ; 326 str_lit = '"' { str_char } '"' ; 327 328 329 330 331 332 333 334 335