expr.ha (33101B)
1 // License: MPL-2.0 2 // (c) 2021 Alexey Yerin <yyp@disroot.org> 3 // (c) 2021 Bor Grošelj Simić <bor.groseljsimic@telemach.net> 4 // (c) 2021 Drew DeVault <sir@cmpwn.com> 5 // (c) 2021 Ember Sawady <ecs@d2evs.net> 6 // (c) 2022 Sebastian <sebastian@sebsite.pw> 7 use hare::ast; 8 use hare::lex::{ltok}; 9 use hare::lex; 10 use math; 11 use types; 12 use strings; 13 14 // Parses an expression. 15 export fn expr(lexer: *lex::lexer) (ast::expr | error) = { 16 const loc = lex::mkloc(lexer); 17 const indirect = try(lexer, ltok::TIMES)? is lex::token; 18 19 // All assignment-op tokens 20 const atoks: []ltok = [ 21 ltok::EQUAL, ltok::BANDEQ, ltok::BOREQ, ltok::BXOREQ, 22 ltok::DIVEQ, ltok::LANDEQ, ltok::LOREQ, ltok::LXOREQ, 23 ltok::LSHIFTEQ, ltok::MINUSEQ, ltok::MODEQ, ltok::PLUSEQ, 24 ltok::RSHIFTEQ, ltok::TIMESEQ, 25 ]; 26 27 const ex: ast::expr = if (indirect) { 28 const ex = cast(lexer, void)?; 29 // Disambiguate between 30 // * unary-expression assignment-op expression 31 // and 32 // binary-expression 33 yield if (peek(lexer, atoks...)? is lex::token) { 34 yield ex; 35 } else return binarithm(lexer, ast::expr { 36 start = loc, 37 end = lex::prevloc(lexer), 38 expr = ast::unarithm_expr { 39 op = ast::unarithm_op::DEREF, 40 operand = alloc(ex), 41 }, 42 }, 0); 43 } else match (peek(lexer, ltok::IF, ltok::FOR, 44 ltok::BREAK, ltok::CONTINUE, ltok::RETURN, ltok::LET, 45 ltok::CONST, ltok::YIELD)?) { 46 case void => 47 yield binarithm(lexer, void, 0)?; 48 case let tok: lex::token => 49 yield switch (tok.0) { 50 case ltok::IF => 51 yield if_expr(lexer)?; 52 case ltok::FOR => 53 yield for_expr(lexer)?; 54 case ltok::BREAK, ltok::CONTINUE, ltok::RETURN => 55 yield control(lexer)?; 56 case ltok::LET, ltok::CONST => 57 yield binding(lexer, false)?; 58 case ltok::YIELD => 59 yield yield_expr(lexer)?; 60 case => abort(); // Invariant 61 }; 62 }; 63 64 const tok = match (try(lexer, atoks...)?) { 65 case let tok: lex::token => 66 yield tok; 67 case => 68 return ex; 69 }; 70 71 synassert(lex::mkloc(lexer), 72 ex.expr is ast::access_expr || ex.expr is ast::slice_expr || indirect, 73 "Expected an object-selector or slice for assignment target")?; 74 const ex = ast::assign_expr { 75 op = switch (tok.0) { 76 case ltok::EQUAL => 77 yield void; 78 case ltok::BANDEQ => 79 yield ast::binarithm_op::BAND; 80 case ltok::BOREQ => 81 yield ast::binarithm_op::BOR; 82 case ltok::BXOREQ => 83 yield ast::binarithm_op::BXOR; 84 case ltok::DIVEQ => 85 yield ast::binarithm_op::DIV; 86 case ltok::LANDEQ => 87 yield ast::binarithm_op::LAND; 88 case ltok::LOREQ => 89 yield ast::binarithm_op::LOR; 90 case ltok::LSHIFTEQ => 91 yield ast::binarithm_op::LSHIFT; 92 case ltok::LXOREQ => 93 yield ast::binarithm_op::LXOR; 94 case ltok::MINUSEQ => 95 yield ast::binarithm_op::MINUS; 96 case ltok::MODEQ => 97 yield ast::binarithm_op::MODULO; 98 case ltok::PLUSEQ => 99 yield ast::binarithm_op::PLUS; 100 case ltok::RSHIFTEQ => 101 yield ast::binarithm_op::RSHIFT; 102 case ltok::TIMESEQ => 103 yield ast::binarithm_op::TIMES; 104 }, 105 object = alloc(ex), 106 value = alloc(expr(lexer)?), 107 indirect = indirect, 108 }; 109 110 return ast::expr { 111 start = loc, 112 end = lex::prevloc(lexer), 113 expr = ex, 114 }; 115 }; 116 117 fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { 118 const tok = want(lexer, ltok::ABORT, ltok::ASSERT)?; 119 120 let expr = switch (tok.0) { 121 case ltok::ABORT => 122 want(lexer, ltok::LPAREN)?; 123 const msg: nullable *ast::expr = 124 match (peek(lexer, ltok::RPAREN)?) { 125 case lex::token => 126 yield null; 127 case => 128 yield alloc(expr(lexer)?); 129 }; 130 want(lexer, ltok::RPAREN)?; 131 132 yield ast::assert_expr { 133 cond = null, 134 message = msg, 135 is_static = is_static, 136 }; 137 case ltok::ASSERT => 138 want(lexer, ltok::LPAREN)?; 139 const cond: nullable *ast::expr = 140 alloc(expr(lexer)?); 141 const msg: nullable *ast::expr = 142 match (try(lexer, ltok::COMMA)?) { 143 case lex::token => 144 yield alloc(expr(lexer)?); 145 case => 146 yield null; 147 }; 148 want(lexer, ltok::RPAREN)?; 149 150 yield ast::assert_expr { 151 cond = cond, 152 message = msg, 153 is_static = is_static, 154 }; 155 case => abort(); // unreachable 156 }; 157 158 return ast::expr { 159 start = tok.2, 160 end = lex::prevloc(lexer), 161 expr = expr, 162 }; 163 }; 164 165 fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = { 166 const start = want(lexer, ltok::ALLOC)?; 167 want(lexer, ltok::LPAREN)?; 168 169 const init = alloc(expr(lexer)?); 170 const expr = 171 switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) { 172 case ltok::COMMA => 173 const cap = alloc(expr(lexer)?); 174 want(lexer, ltok::RPAREN)?; 175 yield ast::alloc_expr { 176 init = init, 177 form = ast::alloc_form::COPY, 178 capacity = cap, 179 }; 180 case ltok::ELLIPSIS => 181 want(lexer, ltok::RPAREN)?; 182 yield ast::alloc_expr { 183 init = init, 184 form = ast::alloc_form::COPY, 185 capacity = null, 186 }; 187 case ltok::RPAREN => 188 yield ast::alloc_expr { 189 init = init, 190 form = ast::alloc_form::OBJECT, 191 capacity = null, 192 }; 193 }; 194 195 return ast::expr { 196 start = start.2, 197 end = lex::prevloc(lexer), 198 expr = expr, 199 }; 200 }; 201 202 fn append_insert_expr( 203 lexer: *lex::lexer, 204 is_static: bool, 205 ) (ast::expr | error) = { 206 const tok = want(lexer, ltok::APPEND, ltok::INSERT)?; 207 want(lexer, ltok::LPAREN)?; 208 209 const object = if (tok.0 == ltok::APPEND) objsel(lexer)? 210 else idxexpr(lexer)?; 211 want(lexer, ltok::COMMA)?; 212 213 let variadic: nullable *ast::expr = null; 214 let values: []*ast::expr = []; 215 for (true) { 216 if (try(lexer, ltok::RPAREN)? is lex::token) break; 217 218 const expr = alloc(expr(lexer)?); 219 switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) { 220 case ltok::COMMA => 221 append(values, expr); 222 case ltok::ELLIPSIS => 223 variadic = expr; 224 try(lexer, ltok::COMMA)?; 225 want(lexer, ltok::RPAREN)?; 226 break; 227 case ltok::RPAREN => 228 append(values, expr); 229 break; 230 case => abort(); 231 }; 232 }; 233 234 synassert(lex::mkloc(lexer), variadic != null || len(values) != 0, 235 "Expected values to append")?; 236 237 const expr = if (tok.0 == ltok::APPEND) ast::append_expr { 238 object = alloc(object), 239 variadic = variadic, 240 values = values, 241 is_static = is_static, 242 } else ast::insert_expr { 243 object = alloc(object), 244 variadic = variadic, 245 values = values, 246 is_static = is_static, 247 }; 248 249 return ast::expr { 250 start = tok.2, 251 end = lex::prevloc(lexer), 252 expr = expr, 253 }; 254 }; 255 256 fn measurement(lexer: *lex::lexer) (ast::expr | error) = { 257 const tok = want(lexer, ltok::LEN, ltok::SIZE, ltok::OFFSET)?; 258 want(lexer, ltok::LPAREN)?; 259 const expr = switch (tok.0) { 260 case ltok::LEN => 261 yield alloc(expr(lexer)?): ast::len_expr; 262 case ltok::SIZE => 263 yield alloc(_type(lexer)?): ast::size_expr; 264 case ltok::OFFSET => 265 yield alloc(expr(lexer)?): ast::offset_expr; 266 }; 267 want(lexer, ltok::RPAREN)?; 268 269 return ast::expr { 270 start = tok.2, 271 end = lex::prevloc(lexer), 272 expr = expr, 273 }; 274 }; 275 276 fn binarithm( 277 lexer: *lex::lexer, 278 lvalue: (ast::expr | void), 279 i: int, 280 ) (ast::expr | error) = { 281 // Precedence climbing parser 282 // https://en.wikipedia.org/wiki/Operator-precedence_parser 283 let lvalue = match (lvalue) { 284 case void => 285 yield cast(lexer, void)?; 286 case let expr: ast::expr => 287 yield expr; 288 }; 289 290 let tok = lex::lex(lexer)?; 291 for (let j = precedence(tok); j >= i; j = precedence(tok)) { 292 const op = binop_for_tok(tok); 293 294 let rvalue = cast(lexer, void)?; 295 tok = lex::lex(lexer)?; 296 297 for (let k = precedence(tok); k > j; k = precedence(tok)) { 298 lex::unlex(lexer, tok); 299 rvalue = binarithm(lexer, rvalue, k)?; 300 tok = lex::lex(lexer)?; 301 }; 302 303 const expr = ast::expr { 304 start = lvalue.start, 305 end = lex::prevloc(lexer), 306 expr = ast::binarithm_expr { 307 op = op, 308 lvalue = alloc(lvalue), 309 rvalue = alloc(rvalue), 310 }, 311 }; 312 lvalue = expr; 313 }; 314 315 lex::unlex(lexer, tok); 316 return lvalue; 317 }; 318 319 fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = { 320 let fields: ast::binding_unpack = []; 321 for (true) { 322 const (tok, value, _) = want(lexer, ltok::NAME, 323 ltok::UNDERSCORE)?; 324 if (tok == ltok::UNDERSCORE) { 325 append(fields, void); 326 } else { 327 append(fields, value as str); 328 }; 329 if (len(fields) == 1) { 330 want(lexer, ltok::COMMA)?; 331 } else { 332 match (try(lexer, ltok::COMMA)?) { 333 case void => break; 334 case lex::token => void; 335 }; 336 }; 337 }; 338 want(lexer, ltok::RPAREN)?; 339 return fields; 340 }; 341 342 fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { 343 const loc = lex::mkloc(lexer); 344 const is_const = want(lexer, ltok::LET, ltok::CONST)?.0 == ltok::CONST; 345 346 let bindings: []ast::binding = []; 347 for (true) { 348 const (tok, value, _) = want(lexer, ltok::NAME, ltok::LPAREN)?; 349 const name = switch (tok) { 350 case ltok::NAME => 351 yield value as str; 352 case ltok::LPAREN => 353 yield binding_unpack(lexer)?; 354 case => abort(); 355 }; 356 const btype: nullable *ast::_type = 357 if (try(lexer, ltok::COLON)? is lex::token) { 358 yield alloc(_type(lexer)?); 359 } else null; 360 want(lexer, ltok::EQUAL)?; 361 const init = alloc(expr(lexer)?); 362 append(bindings, ast::binding { 363 name = name, 364 _type = btype, 365 init = init, 366 }); 367 match (try(lexer, ltok::COMMA)?) { 368 case void => break; 369 case lex::token => void; 370 }; 371 }; 372 373 return ast::expr { 374 start = loc, 375 end = lex::prevloc(lexer), 376 expr = ast::binding_expr { 377 is_static = is_static, 378 is_const = is_const, 379 bindings = bindings, 380 }, 381 }; 382 }; 383 384 fn builtin(lexer: *lex::lexer) (ast::expr | error) = { 385 const tok = match (peek(lexer, ltok::ALLOC, ltok::APPEND, ltok::FREE, 386 ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT, 387 ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET, 388 ltok::DEFER, ltok::VASTART, ltok::VAARG, ltok::VAEND)?) { 389 case let tok: lex::token => 390 yield tok; 391 case void => 392 return postfix(lexer, void); 393 }; 394 switch (tok.0) { 395 case ltok::ALLOC => 396 return alloc_expr(lexer); 397 case ltok::APPEND, ltok::INSERT => 398 return append_insert_expr(lexer, false); 399 case ltok::DELETE => 400 return delete_expr(lexer, false); 401 case ltok::FREE => 402 return free_expr(lexer); 403 case ltok::ABORT, ltok::ASSERT => 404 return assert_expr(lexer, false); 405 case ltok::STATIC => 406 want(lexer, ltok::STATIC)?; 407 let tok = match (peek(lexer, ltok::LET, ltok::CONST, 408 ltok::ABORT, ltok::ASSERT, ltok::APPEND, ltok::INSERT, 409 ltok::DELETE)?) { 410 case let tok: lex::token => 411 yield tok; 412 case void => 413 // TODO: The following is lame: 414 return syntaxerr(tok.2, "Expected let, const, or assert"); 415 }; 416 switch (tok.0) { 417 case ltok::LET, ltok::CONST => 418 return binding(lexer, true); 419 case ltok::ABORT, ltok::ASSERT => 420 return assert_expr(lexer, true); 421 case ltok::APPEND, ltok::INSERT => 422 return append_insert_expr(lexer, true); 423 case ltok::DELETE => 424 return delete_expr(lexer, true); 425 case => abort(); 426 }; 427 case ltok::SIZE, ltok::LEN, ltok::OFFSET => 428 return measurement(lexer); 429 case ltok::DEFER => 430 want(lexer, ltok::DEFER)?; 431 let expr = alloc(expr(lexer)?); 432 return ast::expr { 433 start = tok.2, 434 end = lex::prevloc(lexer), 435 expr = expr: ast::defer_expr, 436 }; 437 case ltok::VASTART => 438 want(lexer, ltok::VASTART)?; 439 want(lexer, ltok::LPAREN)?; 440 want(lexer, ltok::RPAREN)?; 441 return ast::expr { 442 start = tok.2, 443 end = lex::prevloc(lexer), 444 expr = void: ast::vastart_expr: ast::variadic_expr, 445 }; 446 case ltok::VAARG => 447 want(lexer, ltok::VAARG)?; 448 want(lexer, ltok::LPAREN)?; 449 const expr = alloc(expr(lexer)?); 450 want(lexer, ltok::RPAREN)?; 451 return ast::expr { 452 start = tok.2, 453 end = lex::prevloc(lexer), 454 expr = expr: ast::vaarg_expr: ast::variadic_expr, 455 }; 456 case ltok::VAEND => 457 want(lexer, ltok::VAEND)?; 458 want(lexer, ltok::LPAREN)?; 459 const expr = alloc(expr(lexer)?); 460 want(lexer, ltok::RPAREN)?; 461 return ast::expr { 462 start = tok.2, 463 end = lex::prevloc(lexer), 464 expr = expr: ast::vaend_expr: ast::variadic_expr, 465 }; 466 case => abort(); // Invariant 467 }; 468 }; 469 470 fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { 471 let args: []*ast::expr = []; 472 let variadic = false; 473 474 for (true) { 475 match (try(lexer, ltok::RPAREN)?) { 476 case lex::token => break; 477 case void => void; 478 }; 479 480 append(args, alloc(expr(lexer)?)); 481 482 match (try(lexer, ltok::ELLIPSIS)?) { 483 case lex::token => 484 variadic = true; 485 try(lexer, ltok::COMMA)?; 486 want(lexer, ltok::RPAREN)?; 487 break; 488 case void => void; 489 }; 490 491 switch (want(lexer, ltok::COMMA, ltok::RPAREN)?.0) { 492 case ltok::RPAREN => break; 493 case => void; 494 }; 495 }; 496 497 return ast::expr { 498 start = lvalue.start, 499 end = lex::prevloc(lexer), 500 expr = ast::call_expr { 501 lvalue = alloc(lvalue), 502 variadic = variadic, 503 args = args, 504 }, 505 }; 506 }; 507 508 fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { 509 const lvalue = match (lvalue) { 510 case void => 511 yield unarithm(lexer)?; 512 case let e: ast::expr => 513 yield e; 514 }; 515 const tok = match (try(lexer, ltok::COLON, ltok::AS, ltok::IS)?) { 516 case void => 517 return lvalue; 518 case let tok: lex::token => 519 yield tok.0; 520 }; 521 const kind = switch (tok) { 522 case ltok::COLON => 523 yield ast::cast_kind::CAST; 524 case ltok::AS => 525 yield ast::cast_kind::ASSERTION; 526 case ltok::IS => 527 yield ast::cast_kind::TEST; 528 case => abort(); 529 }; 530 let typ = alloc(_type(lexer)?); 531 return cast(lexer, ast::expr { 532 start = lvalue.start, 533 end = lex::prevloc(lexer), 534 expr = ast::cast_expr { 535 kind = kind, 536 value = alloc(lvalue), 537 _type = typ, 538 }, 539 })?; 540 }; 541 542 fn constant(lexer: *lex::lexer) (ast::expr | error) = { 543 const tok = want(lexer)?; 544 const expr: ast::constant_expr = switch (tok.0) { 545 case ltok::LIT_RUNE, ltok::LIT_STR => 546 yield tok.1 as (rune | str); 547 case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64, 548 ltok::LIT_UINT, ltok::LIT_SIZE => 549 yield ast::number_constant { 550 suff = tok.0, 551 value = tok.1 as u64, 552 sign = false, 553 }; 554 case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64, 555 ltok::LIT_INT => 556 const n = tok.1 as u64; 557 yield ast::number_constant { 558 suff = tok.0, 559 value = n: i64, 560 sign = false, 561 }; 562 case ltok::LIT_ICONST => 563 const n = tok.1 as u64; 564 yield ast::number_constant { 565 suff = tok.0, 566 value = if (n <= types::I64_MAX: u64) n: i64 else n, 567 sign = false, 568 }; 569 case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => 570 yield ast::number_constant { 571 suff = tok.0, 572 value = tok.1 as f64, 573 sign = false, 574 }; 575 case ltok::VOID => 576 yield void; 577 case ltok::TRUE => 578 yield true; 579 case ltok::FALSE => 580 yield false; 581 case ltok::NULL => 582 yield ast::_null; 583 case => 584 return syntaxerr(lex::mkloc(lexer), "Expected constant expression"); 585 }; 586 return ast::expr { 587 start = tok.2, 588 end = lex::prevloc(lexer), 589 expr = expr, 590 }; 591 }; 592 593 fn control(lexer: *lex::lexer) (ast::expr | error) = { 594 let tok = want(lexer, ltok::BREAK, ltok::CONTINUE, ltok::RETURN)?; 595 let label = if (tok.0 == ltok::BREAK || tok.0 == ltok::CONTINUE) { 596 yield match (try(lexer, ltok::COLON)?) { 597 case lex::token => 598 yield want(lexer, ltok::NAME)?.1 as str; 599 case void => 600 yield ""; 601 }; 602 } else ""; 603 const expr = switch (tok.0) { 604 case ltok::BREAK => 605 yield label: ast::break_expr; 606 case ltok::CONTINUE => 607 yield label: ast::continue_expr; 608 case ltok::RETURN => 609 yield match (peek(lexer, ltok::COMMA, 610 ltok::SEMICOLON, ltok::EOF)?) { 611 case void => 612 yield alloc(expr(lexer)?): ast::return_expr; 613 case lex::token => 614 yield null: ast::return_expr; 615 }; 616 }; 617 return ast::expr { 618 start = tok.2, 619 end = lex::prevloc(lexer), 620 expr = expr, 621 }; 622 }; 623 624 fn delete_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { 625 const start = want(lexer, ltok::DELETE)?; 626 want(lexer, ltok::LPAREN)?; 627 const expr = alloc(postfix(lexer, void)?); 628 // TODO: Assert that this was an indexing expression 629 want(lexer, ltok::RPAREN)?; 630 return ast::expr { 631 start = start.2, 632 end = lex::prevloc(lexer), 633 expr = ast::delete_expr { 634 object = expr, 635 is_static = is_static, 636 }, 637 }; 638 }; 639 640 fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = { 641 let items: []*ast::expr = []; 642 643 const start = want(lexer, ltok::LBRACE, ltok::COLON)?; 644 const label = switch (start.0) { 645 case ltok::COLON => 646 const tok = want(lexer, ltok::NAME)?; 647 want(lexer, ltok::LBRACE)?; 648 yield tok.1 as str; 649 case => 650 yield ""; 651 }; 652 653 for (let more = true; more) { 654 const item = match (peek(lexer, ltok::RBRACE)?) { 655 case lex::token => break; 656 case void => 657 yield expr(lexer)?; 658 }; 659 append(items, alloc(item)); 660 want(lexer, ltok::SEMICOLON)?; 661 }; 662 663 want(lexer, ltok::RBRACE)?; 664 return ast::expr { 665 start = start.2, 666 end = lex::prevloc(lexer), 667 expr = ast::compound_expr { 668 exprs = items, 669 label = label, 670 }, 671 }; 672 }; 673 674 fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { 675 const tok = want(lexer, ltok::FOR)?; 676 want(lexer, ltok::LPAREN)?; 677 678 const bindings: nullable *ast::expr = 679 match (peek(lexer, ltok::LET, ltok::CONST, ltok::STATIC)?) { 680 case void => 681 yield null; 682 case let tok: lex::token => 683 let is_static = if (tok.0 == ltok::STATIC) { 684 want(lexer, ltok::STATIC)?; 685 yield true; 686 } else false; 687 const bindings = alloc(binding(lexer, is_static)?); 688 want(lexer, ltok::SEMICOLON)?; 689 yield bindings; 690 }; 691 const cond = alloc(expr(lexer)?); 692 const afterthought: nullable *ast::expr = 693 match (peek(lexer, ltok::SEMICOLON)?) { 694 case void => 695 yield null; 696 case lex::token => 697 want(lexer, ltok::SEMICOLON)?; 698 yield alloc(expr(lexer)?); 699 }; 700 701 want(lexer, ltok::RPAREN)?; 702 703 const body = alloc(expr(lexer)?); 704 return ast::expr { 705 start = tok.2, 706 end = lex::prevloc(lexer), 707 expr = ast::for_expr { 708 bindings = bindings, 709 cond = cond, 710 afterthought = afterthought, 711 body = body, 712 }, 713 }; 714 }; 715 716 fn free_expr(lexer: *lex::lexer) (ast::expr | error) = { 717 const start = want(lexer, ltok::FREE)?; 718 want(lexer, ltok::LPAREN)?; 719 const expr = alloc(expr(lexer)?); 720 want(lexer, ltok::RPAREN)?; 721 return ast::expr { 722 start = start.2, 723 end = lex::prevloc(lexer), 724 expr = expr: ast::free_expr, 725 }; 726 }; 727 728 fn if_expr(lexer: *lex::lexer) (ast::expr | error) = { 729 const start = want(lexer, ltok::IF)?; 730 want(lexer, ltok::LPAREN)?; 731 const cond = alloc(expr(lexer)?); 732 want(lexer, ltok::RPAREN)?; 733 const tbranch = alloc(expr(lexer)?); 734 const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) { 735 case void => 736 yield null; 737 case lex::token => 738 yield alloc(expr(lexer)?); 739 }; 740 return ast::expr { 741 start = start.2, 742 end = lex::prevloc(lexer), 743 expr = ast::if_expr { 744 cond = cond, 745 tbranch = tbranch, 746 fbranch = fbranch, 747 }, 748 }; 749 }; 750 751 fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { 752 let is_slice = false; 753 let start: nullable *ast::expr = null, end: nullable *ast::expr = null; 754 755 if (try(lexer, ltok::SLICE)? is lex::token) { 756 is_slice = true; 757 } else { 758 start = alloc(expr(lexer)?); 759 }; 760 if (!is_slice && try(lexer, ltok::SLICE)? is lex::token) { 761 is_slice = true; 762 }; 763 if (is_slice && peek(lexer, ltok::RBRACKET)? is void) { 764 end = alloc(expr(lexer)?); 765 }; 766 767 want(lexer, ltok::RBRACKET)?; 768 return ast::expr { 769 start = lvalue.start, 770 end = lex::prevloc(lexer), 771 expr = if (is_slice) ast::slice_expr { 772 object = alloc(lvalue), 773 start = start, 774 end = end, 775 } else ast::access_index { 776 object = alloc(lvalue), 777 index = { 778 assert(end == null); 779 yield start as *ast::expr; 780 }, 781 }, 782 }; 783 }; 784 785 fn objsel(lexer: *lex::lexer) (ast::expr | error) = { 786 let expr = postfix(lexer, void)?; 787 synassert(lex::mkloc(lexer), expr.expr is ast::access_expr, 788 "Expected object selector")?; 789 return expr; 790 }; 791 792 fn idxexpr(lexer: *lex::lexer) (ast::expr | error) = { 793 const expr = postfix(lexer, void)?; 794 synassert(lex::mkloc(lexer), expr.expr is ast::access_expr 795 && expr.expr as ast::access_expr is ast::access_index, 796 "Expected indexing expression")?; 797 return expr; 798 }; 799 800 fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = { 801 let tok = peek(lexer)? as lex::token; 802 if (tok.0 >= ltok::LIT_U8 && tok.0 <= ltok::LAST_LITERAL) { 803 return constant(lexer); 804 }; 805 switch (tok.0) { 806 case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID => 807 return constant(lexer); 808 case ltok::LBRACKET => 809 return plain_array(lexer)?; 810 case ltok::STRUCT => 811 let s = plain_struct(lexer, [])?; 812 return ast::expr { 813 start = tok.2, 814 end = lex::prevloc(lexer), 815 expr = s, 816 }; 817 case ltok::LPAREN => 818 want(lexer, ltok::LPAREN)?; 819 let ex = expr(lexer)?; 820 switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) { 821 case ltok::RPAREN => 822 return ex; 823 case ltok::COMMA => 824 return plain_tuple(lexer, ex, tok.2)?; 825 case => abort(); 826 }; 827 case ltok::NAME => 828 let id = ident(lexer)?; 829 match (peek(lexer, ltok::LBRACE)?) { 830 case void => 831 return ast::expr { 832 start = tok.2, 833 end = lex::prevloc(lexer), 834 expr = id: ast::access_identifier, 835 }; 836 case lex::token => 837 let s = plain_struct(lexer, id)?; 838 return ast::expr { 839 start = tok.2, 840 end = lex::prevloc(lexer), 841 expr = s, 842 }; 843 }; 844 case => 845 return syntaxerr(lex::mkloc(lexer), 846 "Unexpected {}, was expecting an expression", 847 lex::tokstr(tok)); 848 }; 849 }; 850 851 fn plain_array(lexer: *lex::lexer) (ast::expr | error) = { 852 const start = want(lexer, ltok::LBRACKET)?; 853 854 let values: []*ast::expr = []; 855 let expand = false; 856 for (true) { 857 match (try(lexer, ltok::RBRACKET)?) { 858 case lex::token => break; 859 case void => void; 860 }; 861 862 append(values, alloc(expr(lexer)?)); 863 864 match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) { 865 case void => 866 want(lexer, ltok::RBRACKET)?; 867 break; 868 case let tok: lex::token => 869 switch (tok.0) { 870 case ltok::ELLIPSIS => 871 expand = true; 872 try(lexer, ltok::COMMA)?; 873 want(lexer, ltok::RBRACKET)?; 874 break; 875 case ltok::COMMA => void; 876 case => abort(); 877 }; 878 }; 879 }; 880 return ast::expr { 881 start = start.2, 882 end = lex::prevloc(lexer), 883 expr = ast::array_constant { 884 expand = expand, 885 values = values, 886 }, 887 }; 888 }; 889 890 fn plain_struct( 891 lexer: *lex::lexer, 892 alias: ast::ident, 893 ) (ast::struct_constant | error) = { 894 if (len(alias) == 0) { 895 want(lexer, ltok::STRUCT)?; 896 }; 897 want(lexer, ltok::LBRACE)?; 898 899 let autofill = false; 900 let fields: [](ast::struct_value | *ast::struct_constant) = []; 901 for (true) { 902 const tok = want(lexer, ltok::ELLIPSIS, 903 ltok::NAME, ltok::STRUCT)?; 904 switch (tok.0) { 905 case ltok::ELLIPSIS => 906 synassert(lex::mkloc(lexer), len(alias) != 0, 907 "Cannot use auto-fill with anonymous struct")?; 908 autofill = true; 909 try(lexer, ltok::COMMA)?; 910 want(lexer, ltok::RBRACE)?; 911 break; 912 case ltok::NAME, ltok::STRUCT => 913 lex::unlex(lexer, tok); 914 append(fields, struct_field(lexer)?); 915 }; 916 917 switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { 918 case ltok::RBRACE => break; 919 case ltok::COMMA => 920 if (try(lexer, ltok::RBRACE)? is lex::token) { 921 break; 922 }; 923 }; 924 }; 925 926 return ast::struct_constant { 927 autofill = autofill, 928 alias = alias, 929 fields = fields, 930 }; 931 }; 932 933 fn struct_field( 934 lexer: *lex::lexer, 935 ) (ast::struct_value | *ast::struct_constant | error) = { 936 const tok = want(lexer, ltok::NAME, ltok::STRUCT)?; 937 switch (tok.0) { 938 case ltok::NAME => 939 const name = strings::dup(tok.1 as str); 940 const tok = match (try(lexer, ltok::COLON, 941 ltok::DOUBLE_COLON, ltok::EQUAL)?) { 942 case let tok: lex::token => 943 yield tok; 944 case void => 945 let id: ast::ident = alloc([name]); 946 return alloc(plain_struct(lexer, id)?); 947 }; 948 949 switch (tok.0) { 950 case ltok::COLON => 951 const _type = alloc(_type(lexer)?); 952 want(lexer, ltok::EQUAL)?; 953 const init = alloc(expr(lexer)?); 954 return ast::struct_value { 955 name = name, 956 _type = _type, 957 init = init, 958 }; 959 case ltok::DOUBLE_COLON => 960 let id: ast::ident = alloc([name]); 961 let rest = ident(lexer)?; 962 append(id, rest...); 963 return alloc(plain_struct(lexer, id)?); 964 case ltok::EQUAL => 965 return ast::struct_value { 966 name = name, 967 _type = null, 968 init = alloc(expr(lexer)?), 969 }; 970 case => abort(); // Invariant 971 }; 972 case ltok::STRUCT => 973 lex::unlex(lexer, tok); 974 return alloc(plain_struct(lexer, [])?); 975 case => abort(); // Invariant 976 }; 977 }; 978 979 fn plain_tuple( 980 lexer: *lex::lexer, 981 ex: ast::expr, 982 start: lex::location 983 ) (ast::expr | error) = { 984 let values: []*ast::expr = []; 985 append(values, alloc(ex)); 986 987 for (true) { 988 match (try(lexer, ltok::RPAREN)?) { 989 case lex::token => break; 990 case void => void; 991 }; 992 993 append(values, alloc(expr(lexer)?)); 994 995 match (try(lexer, ltok::COMMA)?) { 996 case lex::token => void; 997 case void => 998 want(lexer, ltok::RPAREN)?; 999 break; 1000 }; 1001 }; 1002 1003 return ast::expr { 1004 start = start, 1005 end = lex::prevloc(lexer), 1006 expr = values: ast::tuple_constant, 1007 }; 1008 }; 1009 1010 fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { 1011 let lvalue = match (lvalue) { 1012 case void => 1013 yield plain_expression(lexer)?; 1014 case let ex: ast::expr => 1015 yield ex; 1016 }; 1017 1018 let tok = match (try(lexer, ltok::LPAREN, ltok::DOT, 1019 ltok::LBRACKET, ltok::QUESTION, ltok::LNOT)?) { 1020 case void => 1021 return lvalue; 1022 case let tok: lex::token => 1023 yield tok; 1024 }; 1025 1026 let next = switch (tok.0) { 1027 case ltok::LPAREN => 1028 yield call(lexer, lvalue)?; 1029 case ltok::DOT => 1030 yield postfix_dot(lexer, lvalue)?; 1031 case ltok::LBRACKET => 1032 yield indexing(lexer, lvalue)?; 1033 case ltok::QUESTION => 1034 yield ast::expr { 1035 start = lvalue.start, 1036 end = lex::prevloc(lexer), 1037 expr = ast::propagate_expr { 1038 is_abort = false, 1039 expr = alloc(lvalue), 1040 }, 1041 }; 1042 case ltok::LNOT => 1043 yield ast::expr { 1044 start = lvalue.start, 1045 end = lex::prevloc(lexer), 1046 expr = ast::propagate_expr { 1047 is_abort = true, 1048 expr = alloc(lvalue), 1049 }, 1050 }; 1051 case => abort(); 1052 }; 1053 1054 return postfix(lexer, next); 1055 }; 1056 1057 fn postfix_dot( 1058 lexer: *lex::lexer, 1059 lvalue: ast::expr, 1060 ) (ast::expr | error) = { 1061 match (try(lexer, ltok::NAME)?) { 1062 case let tok: lex::token => 1063 return ast::expr { 1064 start = lvalue.start, 1065 end = lex::prevloc(lexer), 1066 expr = ast::access_field { 1067 object = alloc(lvalue), 1068 field = tok.1 as str, 1069 }, 1070 }; 1071 case void => 1072 let con = constant(lexer)?; 1073 let val = con.expr as ast::constant_expr; 1074 synassert(lex::mkloc(lexer), val is ast::number_constant, 1075 "Expected integer constant")?; 1076 let val = val as ast::number_constant; 1077 return ast::expr { 1078 start = lvalue.start, 1079 end = lex::prevloc(lexer), 1080 expr = ast::access_tuple { 1081 object = alloc(lvalue), 1082 value = alloc(con), 1083 }, 1084 }; 1085 }; 1086 }; 1087 1088 fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { 1089 const start = want(lexer, ltok::SWITCH)?; 1090 1091 want(lexer, ltok::LPAREN)?; 1092 const value = expr(lexer)?; 1093 want(lexer, ltok::RPAREN)?; 1094 1095 want(lexer, ltok::LBRACE)?; 1096 1097 let cases: []ast::switch_case = []; 1098 for (true) { 1099 want(lexer, ltok::CASE)?; 1100 1101 let opts: []*ast::expr = []; 1102 if (try(lexer, ltok::ARROW)? is void) for (true) { 1103 append(opts, alloc(expr(lexer)?)); 1104 switch (want(lexer, ltok::ARROW, ltok::COMMA)?.0) { 1105 case ltok::ARROW => 1106 break; 1107 case ltok::COMMA => 1108 if (try(lexer, ltok::ARROW)? is lex::token) { 1109 break; 1110 }; 1111 }; 1112 }; 1113 1114 let exprs: []*ast::expr = []; 1115 for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) { 1116 append(exprs, alloc(expr(lexer)?)); 1117 want(lexer, ltok::SEMICOLON)?; 1118 }; 1119 1120 append(cases, ast::switch_case { 1121 options = opts, 1122 exprs = exprs, 1123 }); 1124 1125 if (try(lexer, ltok::RBRACE)? is lex::token) { 1126 break; 1127 }; 1128 }; 1129 1130 synassert(start.2, len(cases) != 0, "Expected a list of switch cases")?; 1131 1132 return ast::expr { 1133 start = start.2, 1134 end = lex::prevloc(lexer), 1135 expr = ast::switch_expr { 1136 value = alloc(value), 1137 cases = cases, 1138 }, 1139 }; 1140 }; 1141 1142 fn match_case(lexer: *lex::lexer) (ast::match_case | error) = { 1143 let tok = lex::lex(lexer)?; 1144 let loc = tok.2; 1145 let name: str = "", typ: nullable *ast::_type = null; 1146 switch (tok.0) { 1147 case ltok::NULL => 1148 typ = alloc(ast::_type { 1149 start = loc, 1150 end = lex::prevloc(lexer), 1151 flags = 0, 1152 repr = ast::builtin_type::NULL, 1153 }); 1154 case ltok::LET => 1155 name = want(lexer, ltok::NAME)?.1 as str; 1156 want(lexer, ltok::COLON)?; 1157 typ = alloc(_type(lexer)?); 1158 case ltok::ARROW => void; 1159 case => 1160 lex::unlex(lexer, tok); 1161 typ = alloc(_type(lexer)?); 1162 }; 1163 want(lexer, ltok::ARROW)?; 1164 let exprs: []*ast::expr = []; 1165 for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) { 1166 append(exprs, alloc(expr(lexer)?)); 1167 want(lexer, ltok::SEMICOLON)?; 1168 }; 1169 1170 synassert(lex::mkloc(lexer), len(exprs) != 0, "Expected a match case")?; 1171 1172 return ast::match_case { 1173 name = name, 1174 _type = typ, 1175 exprs = exprs, 1176 }; 1177 }; 1178 1179 fn match_expr(lexer: *lex::lexer) (ast::expr | error) = { 1180 const start = want(lexer, ltok::MATCH)?; 1181 want(lexer, ltok::LPAREN)?; 1182 const value = expr(lexer)?; 1183 want(lexer, ltok::RPAREN)?; 1184 want(lexer, ltok::LBRACE)?; 1185 1186 let cases: []ast::match_case = []; 1187 let default: []*ast::expr = []; 1188 for (true) { 1189 want(lexer, ltok::CASE)?; 1190 1191 match (try(lexer, ltok::ARROW)?) { 1192 case let t: lex::token => 1193 if (len(default) != 0) { 1194 return syntaxerr(t.2, 1195 "More than one default match case"); 1196 }; 1197 for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) { 1198 append(default, alloc(expr(lexer)?)); 1199 want(lexer, ltok::SEMICOLON)?; 1200 }; 1201 case void => 1202 append(cases, match_case(lexer)?); 1203 }; 1204 1205 if (try(lexer, ltok::RBRACE)? is lex::token) { 1206 break; 1207 }; 1208 }; 1209 1210 return ast::expr { 1211 start = start.2, 1212 end = lex::prevloc(lexer), 1213 expr = ast::match_expr { 1214 value = alloc(value), 1215 cases = cases, 1216 default = default, 1217 }, 1218 }; 1219 }; 1220 1221 fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { 1222 const tok = match (try(lexer, 1223 ltok::PLUS, ltok::MINUS, ltok::BNOT, 1224 ltok::LNOT, ltok::TIMES, ltok::BAND, 1225 ltok::SWITCH, ltok::MATCH, ltok::COLON, ltok::LBRACE)?) { 1226 case void => 1227 return builtin(lexer); 1228 case let tok: lex::token => 1229 yield switch (tok.0) { 1230 case ltok::SWITCH => 1231 lex::unlex(lexer, tok); 1232 return switch_expr(lexer); 1233 case ltok::MATCH => 1234 lex::unlex(lexer, tok); 1235 return match_expr(lexer); 1236 case ltok::COLON, ltok::LBRACE => 1237 lex::unlex(lexer, tok); 1238 return compound_expr(lexer); 1239 case => 1240 yield tok; 1241 }; 1242 }; 1243 1244 const op = switch (tok.0) { 1245 case ltok::PLUS => 1246 yield ast::unarithm_op::PLUS; 1247 case ltok::MINUS => 1248 yield ast::unarithm_op::MINUS; 1249 case ltok::BNOT => 1250 yield ast::unarithm_op::BNOT; 1251 case ltok::LNOT => 1252 yield ast::unarithm_op::LNOT; 1253 case ltok::TIMES => 1254 yield ast::unarithm_op::DEREF; 1255 case ltok::BAND => 1256 yield ast::unarithm_op::ADDR; 1257 case => abort(); 1258 }; 1259 1260 const operand = unarithm(lexer)?; 1261 const expr = :blk { 1262 if (op == ast::unarithm_op::MINUS) match (operand.expr) { 1263 case let c: ast::constant_expr => 1264 match (c) { 1265 case let n: ast::number_constant => 1266 let sign = false; 1267 const val = match (n.value) { 1268 case let i: i64 => 1269 sign = i < 0; 1270 yield -i; 1271 case let u: u64 => void; 1272 case let f: f64 => 1273 sign = math::signf64(f) < 0; 1274 yield -f; 1275 }; 1276 1277 if (val is void) yield; 1278 yield :blk, ast::number_constant { 1279 suff = n.suff, 1280 value = val as (i64 | f64), 1281 sign = sign, 1282 }: ast::constant_expr; 1283 case => void; 1284 }; 1285 case => void; 1286 }; 1287 1288 yield ast::unarithm_expr { 1289 op = op, 1290 operand = alloc(operand), 1291 }; 1292 }; 1293 return ast::expr { 1294 start = tok.2, 1295 end = lex::prevloc(lexer), 1296 expr = expr, 1297 }; 1298 }; 1299 1300 fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = { 1301 const start = want(lexer, ltok::YIELD)?; 1302 let label = ""; 1303 let value: nullable *ast::expr = null; 1304 match (try(lexer, ltok::SEMICOLON, ltok::COLON, ltok::EOF)?) { 1305 case void => 1306 value = alloc(expr(lexer)?); 1307 case let t: lex::token => 1308 switch (t.0) { 1309 case ltok::SEMICOLON, ltok::EOF => 1310 lex::unlex(lexer, t); 1311 case ltok::COLON => 1312 label = want(lexer, ltok::NAME)?.1 as str; 1313 match (try(lexer, ltok::COMMA)?) { 1314 case void => void; 1315 case lex::token => 1316 value = alloc(expr(lexer)?); 1317 }; 1318 }; 1319 }; 1320 return ast::expr { 1321 start = start.2, 1322 end = lex::prevloc(lexer), 1323 expr = ast::yield_expr { 1324 label = label, 1325 value = value, 1326 }, 1327 }; 1328 }; 1329 1330 fn binop_for_tok(tok: lex::token) ast::binarithm_op = { 1331 switch (tok.0) { 1332 case ltok::BAND => 1333 return ast::binarithm_op::BAND; 1334 case ltok::BOR => 1335 return ast::binarithm_op::BOR; 1336 case ltok::BXOR => 1337 return ast::binarithm_op::BXOR; 1338 case ltok::DIV => 1339 return ast::binarithm_op::DIV; 1340 case ltok::GT => 1341 return ast::binarithm_op::GT; 1342 case ltok::GTEQ => 1343 return ast::binarithm_op::GTEQ; 1344 case ltok::LAND => 1345 return ast::binarithm_op::LAND; 1346 case ltok::LEQUAL => 1347 return ast::binarithm_op::LEQUAL; 1348 case ltok::LESS => 1349 return ast::binarithm_op::LESS; 1350 case ltok::LESSEQ => 1351 return ast::binarithm_op::LESSEQ; 1352 case ltok::LOR => 1353 return ast::binarithm_op::LOR; 1354 case ltok::LSHIFT => 1355 return ast::binarithm_op::LSHIFT; 1356 case ltok::LXOR => 1357 return ast::binarithm_op::LXOR; 1358 case ltok::MINUS => 1359 return ast::binarithm_op::MINUS; 1360 case ltok::MODULO => 1361 return ast::binarithm_op::MODULO; 1362 case ltok::NEQUAL => 1363 return ast::binarithm_op::NEQUAL; 1364 case ltok::PLUS => 1365 return ast::binarithm_op::PLUS; 1366 case ltok::RSHIFT => 1367 return ast::binarithm_op::RSHIFT; 1368 case ltok::TIMES => 1369 return ast::binarithm_op::TIMES; 1370 case => abort(); 1371 }; 1372 }; 1373 1374 fn precedence(tok: lex::token) int = { 1375 switch (tok.0) { 1376 case ltok::LOR => 1377 return 0; 1378 case ltok::LXOR => 1379 return 1; 1380 case ltok::LAND => 1381 return 2; 1382 case ltok::LEQUAL, ltok::NEQUAL => 1383 return 3; 1384 case ltok::LESS, ltok::LESSEQ, ltok::GT, ltok::GTEQ => 1385 return 4; 1386 case ltok::BOR => 1387 return 5; 1388 case ltok::BXOR => 1389 return 6; 1390 case ltok::BAND => 1391 return 7; 1392 case ltok::LSHIFT, ltok::RSHIFT => 1393 return 8; 1394 case ltok::PLUS, ltok::MINUS => 1395 return 9; 1396 case ltok::TIMES, ltok::DIV, ltok::MODULO => 1397 return 10; 1398 case => 1399 return -1; 1400 }; 1401 };