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