expr.ha (26201B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use fmt; 5 use hare::ast; 6 use hare::ast::{binarithm_op}; 7 use hare::lex; 8 use hare::lex::{ltok}; 9 use io; 10 use strings; 11 12 // Unparses a [[hare::ast::expr]]. 13 export fn expr( 14 out: io::handle, 15 syn: *synfunc, 16 e: *ast::expr, 17 ) (size | io::error) = { 18 let ctx = context { 19 out = out, 20 ... 21 }; 22 return _expr(&ctx, syn, e); 23 }; 24 25 fn _expr(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = { 26 ctx.stack = &stack { 27 cur = e, 28 up = ctx.stack, 29 ... 30 }; 31 defer { 32 let stack = &(ctx.stack as *stack); 33 match (stack.extra) { 34 case let p: *opaque => 35 free(p); 36 case null => void; 37 }; 38 ctx.stack = stack.up; 39 }; 40 41 match (e.expr) { 42 case let e: ast::access_expr => 43 match (e) { 44 case let id: ast::access_identifier => 45 return _ident(ctx, syn, id, synkind::IDENT); 46 case let ix: ast::access_index => 47 let z = 0z; 48 const needs_parens = !is_postfix(ix.object); 49 if (needs_parens) { 50 z += syn(ctx, "(", synkind::PUNCTUATION)?; 51 }; 52 z += _expr(ctx, syn, ix.object)?; 53 if (needs_parens) { 54 z += syn(ctx, ")", synkind::PUNCTUATION)?; 55 }; 56 z += syn(ctx, "[", synkind::PUNCTUATION)?; 57 z += _expr(ctx, syn, ix.index)?; 58 z += syn(ctx, "]", synkind::PUNCTUATION)?; 59 return z; 60 case let fi: ast::access_field => 61 let z = 0z; 62 const needs_parens = !is_postfix(fi.object); 63 if (needs_parens) { 64 z += syn(ctx, "(", synkind::PUNCTUATION)?; 65 }; 66 z += _expr(ctx, syn, fi.object)?; 67 if (needs_parens) { 68 z += syn(ctx, ")", synkind::PUNCTUATION)?; 69 }; 70 z += syn(ctx, ".", synkind::OPERATOR)?; 71 z += syn(ctx, fi.field, synkind::SECONDARY)?; 72 return z; 73 case let tp: ast::access_tuple => 74 let z = 0z; 75 const needs_parens = !is_postfix(tp.object); 76 if (needs_parens) { 77 z += syn(ctx, "(", synkind::PUNCTUATION)?; 78 }; 79 z += _expr(ctx, syn, tp.object)?; 80 if (needs_parens) { 81 z += syn(ctx, ")", synkind::PUNCTUATION)?; 82 }; 83 z += syn(ctx, ".", synkind::OPERATOR)?; 84 z += _expr(ctx, syn, tp.value)?; 85 return z; 86 }; 87 case let e: ast::align_expr => 88 let z = syn(ctx, "align", synkind::KEYWORD)?; 89 z += syn(ctx, "(", synkind::PUNCTUATION)?; 90 z += __type(ctx, syn, e)?; 91 z += syn(ctx, ")", synkind::PUNCTUATION)?; 92 return z; 93 case let e: ast::alloc_expr => 94 let z = syn(ctx, "alloc", synkind::KEYWORD)?; 95 z += syn(ctx, "(", synkind::PUNCTUATION)?; 96 z += _expr(ctx, syn, e.init)?; 97 match (e.capacity) { 98 case null => 99 if (e.form == ast::alloc_form::COPY) { 100 z += syn(ctx, "...", synkind::OPERATOR)?; 101 }; 102 case let e: *ast::expr => 103 z += syn(ctx, ",", synkind::PUNCTUATION)?; 104 z += space(ctx)?; 105 z += _expr(ctx, syn, e)?; 106 }; 107 z += syn(ctx, ")", synkind::PUNCTUATION)?; 108 return z; 109 case ast::append_expr => 110 return append_insert_expr(ctx, syn, e); 111 case let e: ast::assert_expr => 112 return assert_expr(ctx, syn, &e); 113 case let e: ast::assign_expr => 114 let z = 0z; 115 z += _expr(ctx, syn, e.object)?; 116 const op = match (e.op) { 117 case void => 118 yield "="; 119 case let op: binarithm_op => 120 yield switch (op) { 121 case binarithm_op::BAND => 122 yield "&="; 123 case binarithm_op::LAND => 124 yield "&&="; 125 case binarithm_op::BOR => 126 yield "|="; 127 case binarithm_op::LOR => 128 yield "||="; 129 case binarithm_op::DIV => 130 yield "/="; 131 case binarithm_op::LSHIFT => 132 yield "<<="; 133 case binarithm_op::MINUS => 134 yield "-="; 135 case binarithm_op::MODULO => 136 yield "%="; 137 case binarithm_op::PLUS => 138 yield "+="; 139 case binarithm_op::RSHIFT => 140 yield ">>="; 141 case binarithm_op::TIMES => 142 yield "*="; 143 case binarithm_op::BXOR => 144 yield "^="; 145 case binarithm_op::LXOR => 146 yield "^^="; 147 case binarithm_op::GT, binarithm_op::GTEQ, 148 binarithm_op::LESS, binarithm_op::LESSEQ, 149 binarithm_op::LEQUAL, binarithm_op::NEQUAL => 150 abort(); // unreachable 151 }; 152 }; 153 z += space(ctx)?; 154 z += syn(ctx, op, synkind::OPERATOR)?; 155 z += space(ctx)?; 156 z += _expr(ctx, syn, e.value)?; 157 return z; 158 case let e: ast::binarithm_expr => 159 const prec = binprecedence(e.op); 160 let z = binexprval(ctx, syn, e.lvalue, prec)?; 161 z += space(ctx)?; 162 z += syn(ctx, switch (e.op) { 163 case binarithm_op::BAND => 164 yield "&"; 165 case binarithm_op::BOR => 166 yield "|"; 167 case binarithm_op::DIV => 168 yield "/"; 169 case binarithm_op::GT => 170 yield ">"; 171 case binarithm_op::GTEQ => 172 yield ">="; 173 case binarithm_op::LAND => 174 yield "&&"; 175 case binarithm_op::LEQUAL => 176 yield "=="; 177 case binarithm_op::LESS => 178 yield "<"; 179 case binarithm_op::LESSEQ => 180 yield "<="; 181 case binarithm_op::LOR => 182 yield "||"; 183 case binarithm_op::LSHIFT => 184 yield "<<"; 185 case binarithm_op::LXOR => 186 yield "^^"; 187 case binarithm_op::MINUS => 188 yield "-"; 189 case binarithm_op::MODULO => 190 yield "%"; 191 case binarithm_op::NEQUAL => 192 yield "!="; 193 case binarithm_op::PLUS => 194 yield "+"; 195 case binarithm_op::RSHIFT => 196 yield ">>"; 197 case binarithm_op::TIMES => 198 yield "*"; 199 case binarithm_op::BXOR => 200 yield "^"; 201 }, synkind::OPERATOR)?; 202 z += space(ctx)?; 203 z += binexprval(ctx, syn, e.rvalue, prec)?; 204 return z; 205 case let e: ast::binding_expr => 206 let z = 0z; 207 if (e.is_static) { 208 z += syn(ctx, "static", synkind::KEYWORD)?; 209 z += space(ctx)?; 210 }; 211 switch (e.kind) { 212 case ast::binding_kind::DEF => 213 z += syn(ctx, "def", synkind::KEYWORD)?; 214 case ast::binding_kind::CONST => 215 z += syn(ctx, "const", synkind::KEYWORD)?; 216 case ast::binding_kind::LET => 217 z += syn(ctx, "let", synkind::KEYWORD)?; 218 }; 219 z += space(ctx)?; 220 for (let i = 0z; i < len(e.bindings); i += 1) { 221 let binding = e.bindings[i]; 222 match (binding.name) { 223 case let s: str => 224 z += syn(ctx, s, synkind::IDENT)?; 225 case let u: ast::binding_unpack => 226 z += syn(ctx, "(", synkind::PUNCTUATION)?; 227 for (let i = 0z; i < len(u); i += 1) { 228 match (u[i]) { 229 case let s: str => 230 z += syn(ctx, s, 231 synkind::IDENT)?; 232 case void => 233 z += syn(ctx, "_", 234 synkind::OPERATOR)?; 235 }; 236 if (i + 1 < len(u)) { 237 z += syn(ctx, ",", 238 synkind::PUNCTUATION)?; 239 z += space(ctx)?; 240 }; 241 }; 242 z += syn(ctx, ")", synkind::PUNCTUATION)?; 243 }; 244 match (binding._type) { 245 case let t: *ast::_type => 246 z += syn(ctx, ":", synkind::PUNCTUATION)?; 247 z += space(ctx)?; 248 z += __type(ctx, syn, t)?; 249 case null => void; 250 }; 251 z += space(ctx)?; 252 z += syn(ctx, "=", synkind::OPERATOR)?; 253 z += space(ctx)?; 254 z += _expr(ctx, syn, binding.init)?; 255 if (i + 1 < len(e.bindings)) { 256 z += syn(ctx, ",", synkind::PUNCTUATION)?; 257 z += space(ctx)?; 258 }; 259 }; 260 return z; 261 case let e: ast::break_expr => 262 let z = syn(ctx, "break", synkind::KEYWORD)?; 263 if (e != "") { 264 z += space(ctx)?; 265 z += syn(ctx, ":", synkind::LABEL)?; 266 z += syn(ctx, e, synkind::LABEL)?; 267 }; 268 return z; 269 case let e: ast::call_expr => 270 let z = 0z; 271 const needs_parens = !is_postfix(e.lvalue); 272 if (needs_parens) { 273 z += syn(ctx, "(", synkind::PUNCTUATION)?; 274 }; 275 z += _expr(ctx, syn, e.lvalue)?; 276 if (needs_parens) { 277 z += syn(ctx, ")", synkind::PUNCTUATION)?; 278 }; 279 z += syn(ctx, "(", synkind::PUNCTUATION)?; 280 for (let i = 0z; i < len(e.args); i += 1) { 281 z += _expr(ctx, syn, e.args[i])?; 282 if (i + 1 < len(e.args)) { 283 z += syn(ctx, ",", synkind::PUNCTUATION)?; 284 z += space(ctx)?; 285 }; 286 }; 287 if (e.variadic) { 288 z += syn(ctx, "...", synkind::OPERATOR)?; 289 }; 290 z += syn(ctx, ")", synkind::PUNCTUATION)?; 291 return z; 292 case let e: ast::cast_expr => 293 let z = 0z; 294 const needs_parens = !is_cast(e.value); 295 if (needs_parens) { 296 z += syn(ctx, "(", synkind::PUNCTUATION)?; 297 }; 298 z += _expr(ctx, syn, e.value)?; 299 if (needs_parens) { 300 z += syn(ctx, ")", synkind::PUNCTUATION)?; 301 }; 302 switch (e.kind) { 303 case ast::cast_kind::CAST => 304 z += syn(ctx, ":", synkind::OPERATOR)?; 305 z += space(ctx)?; 306 case ast::cast_kind::ASSERTION => 307 z += space(ctx)?; 308 z += syn(ctx, "as", synkind::OPERATOR)?; 309 z += space(ctx)?; 310 case ast::cast_kind::TEST => 311 z += space(ctx)?; 312 z += syn(ctx, "is", synkind::OPERATOR)?; 313 z += space(ctx)?; 314 }; 315 z += __type(ctx, syn, e._type)?; 316 return z; 317 case let e: ast::constant_expr => 318 return constant(ctx, syn, e)?; 319 case let e: ast::continue_expr => 320 let z = syn(ctx, "continue", synkind::KEYWORD)?; 321 if (e != "") { 322 z += space(ctx)?; 323 z += syn(ctx, ":", synkind::LABEL)?; 324 z += syn(ctx, e, synkind::LABEL)?; 325 }; 326 return z; 327 case let e: ast::defer_expr => 328 let z = syn(ctx, "defer", synkind::KEYWORD)?; 329 z += space(ctx)?; 330 z += _expr(ctx, syn, e)?; 331 return z; 332 case let e: ast::delete_expr => 333 let z = 0z; 334 if (e.is_static) { 335 z += syn(ctx, "static", synkind::KEYWORD)?; 336 z += space(ctx)?; 337 }; 338 z += syn(ctx, "delete", synkind::KEYWORD)?; 339 z += syn(ctx, "(", synkind::PUNCTUATION)?; 340 z += _expr(ctx, syn, e.object)?; 341 z += syn(ctx, ")", synkind::PUNCTUATION)?; 342 return z; 343 case let e: ast::error_assert_expr => 344 let z = 0z; 345 const needs_parens = !is_postfix(e); 346 if (needs_parens) { 347 z += syn(ctx, "(", synkind::PUNCTUATION)?; 348 }; 349 z += _expr(ctx, syn, e)?; 350 if (needs_parens) { 351 z += syn(ctx, ")", synkind::PUNCTUATION)?; 352 }; 353 z += syn(ctx, "!", synkind::OPERATOR)?; 354 return z; 355 case let e: ast::for_expr => 356 return for_expr(ctx, syn, &e)?; 357 case let e: ast::free_expr => 358 let z = syn(ctx, "free", synkind::KEYWORD)?; 359 z += syn(ctx, "(", synkind::PUNCTUATION)?; 360 z += _expr(ctx, syn, e)?; 361 z += syn(ctx, ")", synkind::PUNCTUATION)?; 362 return z; 363 case let e: ast::if_expr => 364 let z = syn(ctx, "if", synkind::KEYWORD)?; 365 z += space(ctx)?; 366 z += syn(ctx, "(", synkind::PUNCTUATION)?; 367 z += _expr(ctx, syn, e.cond)?; 368 z += syn(ctx, ")", synkind::PUNCTUATION)?; 369 z += space(ctx)?; 370 z += _expr(ctx, syn, e.tbranch)?; 371 match (e.fbranch) { 372 case null => void; 373 case let e: *ast::expr => 374 z += space(ctx)?; 375 z += syn(ctx, "else", synkind::KEYWORD)?; 376 z += space(ctx)?; 377 z += _expr(ctx, syn, e)?; 378 }; 379 return z; 380 case ast::insert_expr => 381 return append_insert_expr(ctx, syn, e); 382 case let e: ast::compound_expr => 383 let z = 0z; 384 if (e.label != "") { 385 z += syn(ctx, ":", synkind::LABEL)?; 386 z += syn(ctx, e.label, synkind::LABEL)?; 387 z += space(ctx)?; 388 }; 389 z += syn(ctx, "{", synkind::PUNCTUATION)?; 390 ctx.indent += 1; 391 for (let i = 0z; i < len(e.exprs); i += 1) { 392 z += newline(ctx)?; 393 z += stmt(ctx, syn, e.exprs[i])?; 394 }; 395 ctx.indent -= 1; 396 z += newline(ctx)?; 397 z += syn(ctx, "}", synkind::PUNCTUATION)?; 398 return z; 399 case let e: ast::match_expr => 400 return match_expr(ctx, syn, &e)?; 401 case let e: ast::len_expr => 402 let z = syn(ctx, "len", synkind::KEYWORD)?; 403 z += syn(ctx, "(", synkind::PUNCTUATION)?; 404 z += _expr(ctx, syn, e)?; 405 z += syn(ctx, ")", synkind::PUNCTUATION)?; 406 return z; 407 case let e: ast::size_expr => 408 let z = syn(ctx, "size", synkind::KEYWORD)?; 409 z += syn(ctx, "(", synkind::PUNCTUATION)?; 410 z += __type(ctx, syn, e)?; 411 z += syn(ctx, ")", synkind::PUNCTUATION)?; 412 return z; 413 case let e: ast::offset_expr => 414 let z = syn(ctx, "offset", synkind::KEYWORD)?; 415 z += syn(ctx, "(", synkind::PUNCTUATION)?; 416 z += _expr(ctx, syn, e)?; 417 z += syn(ctx, ")", synkind::PUNCTUATION)?; 418 return z; 419 case let e: ast::propagate_expr => 420 let z = 0z; 421 const needs_parens = !is_postfix(e); 422 if (needs_parens) { 423 z += syn(ctx, "(", synkind::PUNCTUATION)?; 424 }; 425 z += _expr(ctx, syn, e)?; 426 if (needs_parens) { 427 z += syn(ctx, ")", synkind::PUNCTUATION)?; 428 }; 429 z += syn(ctx, "?", synkind::OPERATOR)?; 430 return z; 431 case let e: ast::return_expr => 432 let z = syn(ctx, "return", synkind::KEYWORD)?; 433 match (e) { 434 case null => void; 435 case let e: *ast::expr => 436 z += space(ctx)?; 437 z += _expr(ctx, syn, e)?; 438 }; 439 return z; 440 case let e: ast::slice_expr => 441 let z = 0z; 442 const needs_parens = !is_postfix(e.object); 443 if (needs_parens) { 444 z += syn(ctx, "(", synkind::PUNCTUATION)?; 445 }; 446 z += _expr(ctx, syn, e.object)?; 447 if (needs_parens) { 448 z += syn(ctx, ")", synkind::PUNCTUATION)?; 449 }; 450 z += syn(ctx, "[", synkind::PUNCTUATION)?; 451 match (e.start) { 452 case null => void; 453 case let e: *ast::expr => 454 z += _expr(ctx, syn, e)?; 455 }; 456 z += syn(ctx, "..", synkind::OPERATOR)?; 457 match (e.end) { 458 case null => void; 459 case let e: *ast::expr => 460 z += _expr(ctx, syn, e)?; 461 }; 462 z += syn(ctx, "]", synkind::PUNCTUATION)?; 463 return z; 464 case let e: ast::switch_expr => 465 return switch_expr(ctx, syn, &e)?; 466 case let e: ast::unarithm_expr => 467 let z = syn(ctx, switch (e.op) { 468 case ast::unarithm_op::ADDR => 469 yield "&"; 470 case ast::unarithm_op::BNOT => 471 yield "~"; 472 case ast::unarithm_op::DEREF => 473 yield "*"; 474 case ast::unarithm_op::LNOT => 475 yield "!"; 476 case ast::unarithm_op::MINUS => 477 yield "-"; 478 }, synkind::OPERATOR)?; 479 const needs_parens = match (e.operand.expr) { 480 case let inner: ast::unarithm_expr => 481 yield e.op == ast::unarithm_op::ADDR 482 && inner.op == e.op; 483 case => 484 yield !is_unary(e.operand); 485 }; 486 if (needs_parens) { 487 z += syn(ctx, "(", synkind::PUNCTUATION)?; 488 }; 489 z += _expr(ctx, syn, e.operand)?; 490 if (needs_parens) { 491 z += syn(ctx, ")", synkind::PUNCTUATION)?; 492 }; 493 return z; 494 case let e: ast::variadic_expr => 495 match (e) { 496 case ast::vastart_expr => 497 let z = syn(ctx, "vastart", synkind::KEYWORD)?; 498 z += syn(ctx, "(", synkind::PUNCTUATION)?; 499 z += syn(ctx, ")", synkind::PUNCTUATION)?; 500 return z; 501 case let e: ast::vaarg_expr => 502 let z = syn(ctx, "vaarg", synkind::KEYWORD)?; 503 z += syn(ctx, "(", synkind::PUNCTUATION)?; 504 z += _expr(ctx, syn, e)?; 505 z += syn(ctx, ")", synkind::PUNCTUATION)?; 506 return z; 507 case let e: ast::vaend_expr => 508 let z = syn(ctx, "vaend", synkind::KEYWORD)?; 509 z += syn(ctx, "(", synkind::PUNCTUATION)?; 510 z += _expr(ctx, syn, e)?; 511 z += syn(ctx, ")", synkind::PUNCTUATION)?; 512 return z; 513 }; 514 case let e: ast::yield_expr => 515 let z = syn(ctx, "yield", synkind::KEYWORD)?; 516 if (e.label != "") { 517 z += space(ctx)?; 518 z += syn(ctx, ":", synkind::LABEL)?; 519 z += syn(ctx, e.label, synkind::LABEL)?; 520 }; 521 match (e.value) { 522 case null => void; 523 case let v: *ast::expr => 524 if (e.label != "") { 525 z += syn(ctx, ",", synkind::PUNCTUATION)?; 526 }; 527 z += space(ctx)?; 528 z += _expr(ctx, syn, v)?; 529 }; 530 return z; 531 }; 532 }; 533 534 fn binprecedence(op: binarithm_op) uint = { 535 switch (op) { 536 case binarithm_op::DIV, binarithm_op::MODULO, binarithm_op::TIMES => 537 return 10; 538 case binarithm_op::MINUS, binarithm_op::PLUS => 539 return 9; 540 case binarithm_op::LSHIFT, binarithm_op::RSHIFT => 541 return 8; 542 case binarithm_op::BAND => 543 return 7; 544 case binarithm_op::BXOR => 545 return 6; 546 case binarithm_op::BOR => 547 return 5; 548 case binarithm_op::GT, binarithm_op::GTEQ, 549 binarithm_op::LESS, binarithm_op::LESSEQ => 550 return 4; 551 case binarithm_op::LEQUAL, binarithm_op::NEQUAL => 552 return 3; 553 case binarithm_op::LAND => 554 return 2; 555 case binarithm_op::LXOR => 556 return 1; 557 case binarithm_op::LOR => 558 return 0; 559 }; 560 }; 561 562 fn binexprval( 563 ctx: *context, 564 syn: *synfunc, 565 e: *ast::expr, 566 prec: uint, 567 ) (size | io::error) = { 568 let z = 0z; 569 match (e.expr) { 570 case let b: ast::binarithm_expr => 571 if (binprecedence(b.op) < prec) { 572 z += syn(ctx, "(", synkind::PUNCTUATION)?; 573 z += _expr(ctx, syn, e)?; 574 z += syn(ctx, ")", synkind::PUNCTUATION)?; 575 return z; 576 }; 577 case => void; 578 }; 579 const needs_parens = !is_cast(e) && !(e.expr is ast::binarithm_expr); 580 if (needs_parens) { 581 z += syn(ctx, "(", synkind::PUNCTUATION)?; 582 }; 583 z += _expr(ctx, syn, e)?; 584 if (needs_parens) { 585 z += syn(ctx, ")", synkind::PUNCTUATION)?; 586 }; 587 return z; 588 }; 589 590 fn stmt(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = { 591 let n = _expr(ctx, syn, e)?; 592 n += syn(ctx, ";", synkind::PUNCTUATION)?; 593 return n; 594 }; 595 596 fn constant( 597 ctx: *context, 598 syn: *synfunc, 599 e: ast::constant_expr, 600 ) (size | io::error) = { 601 match (e) { 602 case void => 603 return syn(ctx, "void", synkind::KEYWORD)?; 604 case let v: ast::value => 605 match (v) { 606 case void => abort(); 607 case ast::_null => 608 return syn(ctx, "null", synkind::KEYWORD)?; 609 case let b: bool => 610 return syn(ctx, if (b) "true" else "false", 611 synkind::KEYWORD)?; 612 case let s: str => 613 const s = strings::multireplace(s, 614 (`\`, `\\`), (`"`, `\"`)); 615 defer free(s); 616 const s = fmt::asprintf(`"{}"`, s); 617 defer free(s); 618 return syn(ctx, s, synkind::RUNE_STRING)?; 619 case let r: rune => 620 // 4 for unicode codepoint + 2 's 621 let buf: [6]u8 = [0...]; 622 if (r == '\'' || r == '\\') { 623 return syn(ctx, fmt::bsprintf(buf, `'\{}'`, r), 624 synkind::RUNE_STRING)?; 625 } else { 626 return syn(ctx, fmt::bsprintf(buf, "'{}'", r), 627 synkind::RUNE_STRING)?; 628 }; 629 }; 630 case let ac: ast::array_constant => 631 let z = syn(ctx, "[", synkind::PUNCTUATION)?; 632 for (let i = 0z; i < len(ac.values); i += 1) { 633 z += _expr(ctx, syn, ac.values[i])?; 634 if (i + 1 < len(ac.values)) { 635 z += syn(ctx, ",", synkind::PUNCTUATION)?; 636 z += space(ctx)?; 637 }; 638 }; 639 if (ac.expand) { 640 z += syn(ctx, "...", synkind::OPERATOR)?; 641 }; 642 z += syn(ctx, "]", synkind::PUNCTUATION)?; 643 return z; 644 case let v: ast::number_constant => 645 const s = fmt::asprintf("{}{}", v.value, switch (v.suff) { 646 case ltok::LIT_U8 => 647 yield "u8"; 648 case ltok::LIT_U16 => 649 yield "u16"; 650 case ltok::LIT_U32 => 651 yield "u32"; 652 case ltok::LIT_U64 => 653 yield "u64"; 654 case ltok::LIT_UINT => 655 yield "u"; 656 case ltok::LIT_SIZE => 657 yield "z"; 658 case ltok::LIT_I8 => 659 yield "i8"; 660 case ltok::LIT_I16 => 661 yield "i16"; 662 case ltok::LIT_I32 => 663 yield "i32"; 664 case ltok::LIT_I64 => 665 yield "i64"; 666 case ltok::LIT_INT => 667 yield "i"; 668 case ltok::LIT_ICONST, ltok::LIT_FCONST => 669 yield ""; 670 case ltok::LIT_F32 => 671 yield "f32"; 672 case ltok::LIT_F64 => 673 yield "f64"; 674 case => abort(); 675 }); 676 defer free(s); 677 return syn(ctx, s, synkind::NUMBER)?; 678 case let sc: ast::struct_constant => 679 return struct_constant(ctx, syn, sc)?; 680 case let tu: ast::tuple_constant => 681 let z = syn(ctx, "(", synkind::PUNCTUATION)?; 682 for (let i = 0z; i < len(tu); i += 1) { 683 z += _expr(ctx, syn, tu[i])?; 684 if (i + 1 < len(tu)) { 685 z += syn(ctx, ",", synkind::PUNCTUATION)?; 686 z += space(ctx)?; 687 }; 688 }; 689 z += syn(ctx, ")", synkind::PUNCTUATION)?; 690 return z; 691 }; 692 }; 693 694 fn struct_constant( 695 ctx: *context, 696 syn: *synfunc, 697 sc: ast::struct_constant, 698 ) (size | io::error) = { 699 let z = 0z; 700 z += if (len(sc.alias) != 0) { 701 yield _ident(ctx, syn, sc.alias, synkind::IDENT)?; 702 } else { 703 yield syn(ctx, "struct", synkind::KEYWORD)?; 704 }; 705 z += space(ctx)?; 706 z += syn(ctx, "{", synkind::PUNCTUATION)?; 707 ctx.indent += 1; 708 for (let i = 0z; i < len(sc.fields); i += 1) { 709 z += newline(ctx)?; 710 match (sc.fields[i]) { 711 case let sv: ast::struct_value => 712 z += syn(ctx, sv.name, synkind::SECONDARY)?; 713 match (sv._type) { 714 case null => void; 715 case let t: *ast::_type => 716 z += syn(ctx, ":", synkind::PUNCTUATION)?; 717 z += space(ctx)?; 718 z += __type(ctx, syn, t)?; 719 }; 720 z += space(ctx)?; 721 z += syn(ctx, "=", synkind::OPERATOR)?; 722 z += space(ctx)?; 723 z += _expr(ctx, syn, sv.init)?; 724 case let sc: *ast::struct_constant => 725 z += constant(ctx, syn, *sc)?; 726 }; 727 z += syn(ctx, ",", synkind::PUNCTUATION)?; 728 }; 729 if (sc.autofill) { 730 z += newline(ctx)?; 731 z += syn(ctx, "...", synkind::OPERATOR)?; 732 }; 733 ctx.indent -= 1; 734 z += newline(ctx)?; 735 z += syn(ctx, "}", synkind::PUNCTUATION)?; 736 return z; 737 }; 738 739 fn for_expr( 740 ctx: *context, 741 syn: *synfunc, 742 e: *ast::for_expr, 743 ) (size | io::error) = { 744 let z = syn(ctx, "for", synkind::KEYWORD)?; 745 z += space(ctx)?; 746 z += syn(ctx, "(", synkind::PUNCTUATION)?; 747 match (e.bindings) { 748 case null => void; 749 case let e: *ast::expr => 750 z += _expr(ctx, syn, e)?; 751 z += syn(ctx, ";", synkind::PUNCTUATION)?; 752 z += space(ctx)?; 753 }; 754 755 z += _expr(ctx, syn, e.cond)?; 756 757 match (e.afterthought) { 758 case null => void; 759 case let e: *ast::expr => 760 z += syn(ctx, ";", synkind::PUNCTUATION)?; 761 z += space(ctx)?; 762 z += _expr(ctx, syn, e)?; 763 }; 764 765 z += syn(ctx, ")", synkind::PUNCTUATION)?; 766 z += space(ctx)?; 767 z += _expr(ctx, syn, e.body)?; 768 return z; 769 }; 770 771 fn switch_expr( 772 ctx: *context, 773 syn: *synfunc, 774 e: *ast::switch_expr, 775 ) (size | io::error) = { 776 let z = syn(ctx, "switch", synkind::KEYWORD)?; 777 z += space(ctx)?; 778 z += syn(ctx, "(", synkind::PUNCTUATION)?; 779 z += _expr(ctx, syn, e.value)?; 780 z += syn(ctx, ")", synkind::PUNCTUATION)?; 781 z += space(ctx)?; 782 z += syn(ctx, "{", synkind::PUNCTUATION)?; 783 784 for (let i = 0z; i < len(e.cases); i += 1) { 785 z += newline(ctx)?; 786 const item = e.cases[i]; 787 z += syn(ctx, "case", synkind::KEYWORD)?; 788 z += space(ctx)?; 789 if (len(item.options) == 0) { 790 z += syn(ctx, "=>", synkind::OPERATOR)?; 791 } else { 792 for (let j = 0z; j < len(item.options); j += 1) { 793 const opt = item.options[j]; 794 z += _expr(ctx, syn, opt)?; 795 if (j + 1 < len(item.options)) { 796 z += syn(ctx, ",", 797 synkind::PUNCTUATION)?; 798 z += space(ctx)?; 799 }; 800 }; 801 z += space(ctx)?; 802 z += syn(ctx, "=>", synkind::OPERATOR)?; 803 }; 804 z += case_exprs(ctx, syn, item.exprs)?; 805 }; 806 807 z += newline(ctx)?; 808 z += syn(ctx, "}", synkind::PUNCTUATION)?; 809 return z; 810 }; 811 812 fn match_expr( 813 ctx: *context, 814 syn: *synfunc, 815 e: *ast::match_expr, 816 ) (size | io::error) = { 817 let z = syn(ctx, "match", synkind::KEYWORD)?; 818 z += space(ctx)?; 819 z += syn(ctx, "(", synkind::PUNCTUATION)?; 820 z += _expr(ctx, syn, e.value)?; 821 z += syn(ctx, ")", synkind::PUNCTUATION)?; 822 z += space(ctx)?; 823 z += syn(ctx, "{", synkind::PUNCTUATION)?; 824 825 for (let i = 0z; i < len(e.cases); i += 1) { 826 z += newline(ctx)?; 827 z += syn(ctx, "case", synkind::KEYWORD)?; 828 const item = e.cases[i]; 829 if (len(item.name) > 0) { 830 z += space(ctx)?; 831 z += syn(ctx, "let", synkind::KEYWORD)?; 832 z += space(ctx)?; 833 z += syn(ctx, item.name, synkind::IDENT)?; 834 }; 835 match (item._type) { 836 case let typ: *ast::_type => 837 if (len(item.name) > 0) { 838 z += syn(ctx, ":", synkind::PUNCTUATION)?; 839 }; 840 z += space(ctx)?; 841 z += __type(ctx, syn, typ)?; 842 case null => void; 843 }; 844 z += space(ctx)?; 845 z += syn(ctx, "=>", synkind::OPERATOR)?; 846 z += case_exprs(ctx, syn, item.exprs)?; 847 }; 848 849 z += newline(ctx)?; 850 z += syn(ctx, "}", synkind::PUNCTUATION)?; 851 return z; 852 }; 853 854 fn case_exprs( 855 ctx: *context, 856 syn: *synfunc, 857 exprs: []*ast::expr, 858 ) (size | io::error) = { 859 let z = 0z; 860 861 if (len(exprs) == 1) match (exprs[0].expr) { 862 case let e: ast::assert_expr => 863 if (e.cond == null) { 864 // abort() expression 865 z += space(ctx)?; 866 z += assert_expr(ctx, syn, &e)?; 867 z += syn(ctx, ";", synkind::PUNCTUATION)?; 868 return z; 869 }; 870 case let e: ast::value => 871 if (e is void) { 872 z += space(ctx)?; 873 { 874 ctx.stack = &stack { 875 cur = exprs[0], 876 up = ctx.stack, 877 ... 878 }; 879 defer ctx.stack = (ctx.stack as *stack).up; 880 z += syn(ctx, "void", synkind::KEYWORD)?; 881 }; 882 z += syn(ctx, ";", synkind::PUNCTUATION)?; 883 return z; 884 }; 885 case => void; 886 }; 887 ctx.indent += 1; 888 for (let j = 0z; j < len(exprs); j += 1) { 889 z += newline(ctx)?; 890 z += stmt(ctx, syn, exprs[j])?; 891 }; 892 ctx.indent -= 1; 893 894 return z; 895 }; 896 897 fn is_plain(e: *ast::expr) bool = { 898 match (e.expr) { 899 case ast::constant_expr => 900 return true; 901 case ast::access_identifier => 902 return true; 903 case => 904 return false; 905 }; 906 }; 907 908 fn is_postfix(e: *ast::expr) bool = { 909 if (is_plain(e)) { 910 return true; 911 }; 912 913 match (e.expr) { 914 case ast::call_expr => 915 return true; 916 case ast::access_expr => 917 return true; 918 case ast::slice_expr => 919 return true; 920 case ast::error_assert_expr => 921 return true; 922 case ast::propagate_expr => 923 return true; 924 case => 925 return false; 926 }; 927 }; 928 929 fn is_builtin(e: *ast::expr) bool = { 930 if (is_postfix(e)) { 931 return true; 932 }; 933 934 match (e.expr) { 935 case ast::alloc_expr => 936 return true; 937 case ast::assert_expr => 938 return true; 939 case ast::variadic_expr => 940 return true; 941 // measurement-expression 942 case ast::len_expr => 943 return true; 944 case ast::align_expr => 945 return true; 946 case ast::size_expr => 947 return true; 948 case ast::offset_expr => 949 return true; 950 // slice-mutation-expression 951 case ast::append_expr => 952 return true; 953 case ast::insert_expr => 954 return true; 955 case => 956 return false; 957 }; 958 }; 959 960 fn is_unary(e: *ast::expr) bool = { 961 if (is_builtin(e)) { 962 return true; 963 }; 964 965 match (e.expr) { 966 case ast::compound_expr => 967 return true; 968 case ast::match_expr => 969 return true; 970 case ast::switch_expr => 971 return true; 972 case ast::unarithm_expr => 973 return true; 974 case => 975 return false; 976 }; 977 }; 978 979 fn is_cast(e: *ast::expr) bool = { 980 return is_unary(e) || (e.expr is ast::cast_expr); 981 }; 982 983 fn assert_expr( 984 ctx: *context, 985 syn: *synfunc, 986 e: *ast::assert_expr, 987 ) (size | io::error) = { 988 let z = 0z; 989 if (e.is_static) { 990 z += syn(ctx, "static", synkind::KEYWORD)?; 991 z += space(ctx)?; 992 }; 993 // assert without a condition = abort 994 match (e.cond) { 995 case let e: *ast::expr => 996 z += syn(ctx, "assert", synkind::KEYWORD)?; 997 z += syn(ctx, "(", synkind::PUNCTUATION)?; 998 z += _expr(ctx, syn, e)?; 999 case null => 1000 z += syn(ctx, "abort", synkind::KEYWORD)?; 1001 z += syn(ctx, "(", synkind::PUNCTUATION)?; 1002 }; 1003 match (e.message) { 1004 case let m: *ast::expr => 1005 match (e.cond) { 1006 case null => void; 1007 case *ast::expr => 1008 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1009 z += space(ctx)?; 1010 }; 1011 z += _expr(ctx, syn, m)?; 1012 case null => void; 1013 }; 1014 z += syn(ctx, ")", synkind::PUNCTUATION)?; 1015 return z; 1016 }; 1017 1018 fn append_insert_expr( 1019 ctx: *context, 1020 syn: *synfunc, 1021 e: *ast::expr, 1022 ) (size | io::error) = { 1023 let z = 0z; 1024 const e: *ast::append_expr = match (e.expr) { 1025 case let e: ast::append_expr => 1026 if (e.is_static) { 1027 z += syn(ctx, "static", synkind::KEYWORD)?; 1028 z += space(ctx)?; 1029 }; 1030 z += syn(ctx, "append", synkind::KEYWORD)?; 1031 yield &e; 1032 case let e: ast::insert_expr => 1033 if (e.is_static) { 1034 z += syn(ctx, "static", synkind::KEYWORD)?; 1035 z += space(ctx)?; 1036 }; 1037 z += syn(ctx, "insert", synkind::KEYWORD)?; 1038 yield &e; 1039 case => abort(); // unreachable 1040 }; 1041 z += syn(ctx, "(", synkind::PUNCTUATION)?; 1042 z += _expr(ctx, syn, e.object)?; 1043 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1044 z += space(ctx)?; 1045 z += _expr(ctx, syn, e.value)?; 1046 if (e.variadic) { 1047 z += syn(ctx, "...", synkind::OPERATOR)?; 1048 }; 1049 match (e.length) { 1050 case null => void; 1051 case let l: *ast::expr => 1052 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1053 z += space(ctx)?; 1054 z += _expr(ctx, syn, l)?; 1055 }; 1056 z += syn(ctx, ")", synkind::PUNCTUATION)?; 1057 return z; 1058 };