expr.ha (26958B)
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 return binding_expr(ctx, syn, &e, "=")?; 207 case let e: ast::break_expr => 208 let z = syn(ctx, "break", synkind::KEYWORD)?; 209 if (e != "") { 210 z += space(ctx)?; 211 z += syn(ctx, ":", synkind::LABEL)?; 212 z += syn(ctx, e, synkind::LABEL)?; 213 }; 214 return z; 215 case let e: ast::call_expr => 216 let z = 0z; 217 const needs_parens = !is_postfix(e.lvalue); 218 if (needs_parens) { 219 z += syn(ctx, "(", synkind::PUNCTUATION)?; 220 }; 221 z += _expr(ctx, syn, e.lvalue)?; 222 if (needs_parens) { 223 z += syn(ctx, ")", synkind::PUNCTUATION)?; 224 }; 225 z += syn(ctx, "(", synkind::PUNCTUATION)?; 226 for (let i = 0z; i < len(e.args); i += 1) { 227 z += _expr(ctx, syn, e.args[i])?; 228 if (i + 1 < len(e.args)) { 229 z += syn(ctx, ",", synkind::PUNCTUATION)?; 230 z += space(ctx)?; 231 }; 232 }; 233 if (e.variadic) { 234 z += syn(ctx, "...", synkind::OPERATOR)?; 235 }; 236 z += syn(ctx, ")", synkind::PUNCTUATION)?; 237 return z; 238 case let e: ast::cast_expr => 239 let z = 0z; 240 const needs_parens = !is_cast(e.value); 241 if (needs_parens) { 242 z += syn(ctx, "(", synkind::PUNCTUATION)?; 243 }; 244 z += _expr(ctx, syn, e.value)?; 245 if (needs_parens) { 246 z += syn(ctx, ")", synkind::PUNCTUATION)?; 247 }; 248 switch (e.kind) { 249 case ast::cast_kind::CAST => 250 z += syn(ctx, ":", synkind::OPERATOR)?; 251 z += space(ctx)?; 252 case ast::cast_kind::ASSERTION => 253 z += space(ctx)?; 254 z += syn(ctx, "as", synkind::OPERATOR)?; 255 z += space(ctx)?; 256 case ast::cast_kind::TEST => 257 z += space(ctx)?; 258 z += syn(ctx, "is", synkind::OPERATOR)?; 259 z += space(ctx)?; 260 }; 261 z += __type(ctx, syn, e._type)?; 262 return z; 263 case let e: ast::literal_expr => 264 return literal(ctx, syn, e)?; 265 case let e: ast::continue_expr => 266 let z = syn(ctx, "continue", synkind::KEYWORD)?; 267 if (e != "") { 268 z += space(ctx)?; 269 z += syn(ctx, ":", synkind::LABEL)?; 270 z += syn(ctx, e, synkind::LABEL)?; 271 }; 272 return z; 273 case let e: ast::defer_expr => 274 let z = syn(ctx, "defer", synkind::KEYWORD)?; 275 z += space(ctx)?; 276 z += _expr(ctx, syn, e)?; 277 return z; 278 case let e: ast::delete_expr => 279 let z = 0z; 280 if (e.is_static) { 281 z += syn(ctx, "static", synkind::KEYWORD)?; 282 z += space(ctx)?; 283 }; 284 z += syn(ctx, "delete", synkind::KEYWORD)?; 285 z += syn(ctx, "(", synkind::PUNCTUATION)?; 286 z += _expr(ctx, syn, e.object)?; 287 z += syn(ctx, ")", synkind::PUNCTUATION)?; 288 return z; 289 case let e: ast::error_assert_expr => 290 let z = 0z; 291 const needs_parens = !is_postfix(e); 292 if (needs_parens) { 293 z += syn(ctx, "(", synkind::PUNCTUATION)?; 294 }; 295 z += _expr(ctx, syn, e)?; 296 if (needs_parens) { 297 z += syn(ctx, ")", synkind::PUNCTUATION)?; 298 }; 299 z += syn(ctx, "!", synkind::OPERATOR)?; 300 return z; 301 case let e: ast::for_expr => 302 return for_expr(ctx, syn, &e)?; 303 case let e: ast::free_expr => 304 let z = syn(ctx, "free", synkind::KEYWORD)?; 305 z += syn(ctx, "(", synkind::PUNCTUATION)?; 306 z += _expr(ctx, syn, e)?; 307 z += syn(ctx, ")", synkind::PUNCTUATION)?; 308 return z; 309 case let e: ast::if_expr => 310 let z = syn(ctx, "if", synkind::KEYWORD)?; 311 z += space(ctx)?; 312 z += syn(ctx, "(", synkind::PUNCTUATION)?; 313 z += _expr(ctx, syn, e.cond)?; 314 z += syn(ctx, ")", synkind::PUNCTUATION)?; 315 z += space(ctx)?; 316 z += _expr(ctx, syn, e.tbranch)?; 317 match (e.fbranch) { 318 case null => void; 319 case let e: *ast::expr => 320 z += space(ctx)?; 321 z += syn(ctx, "else", synkind::KEYWORD)?; 322 z += space(ctx)?; 323 z += _expr(ctx, syn, e)?; 324 }; 325 return z; 326 case ast::insert_expr => 327 return append_insert_expr(ctx, syn, e); 328 case let e: ast::compound_expr => 329 let z = 0z; 330 if (e.label != "") { 331 z += syn(ctx, ":", synkind::LABEL)?; 332 z += syn(ctx, e.label, synkind::LABEL)?; 333 z += space(ctx)?; 334 }; 335 z += syn(ctx, "{", synkind::PUNCTUATION)?; 336 ctx.indent += 1; 337 for (let expr .. e.exprs) { 338 z += newline(ctx)?; 339 z += stmt(ctx, syn, expr)?; 340 }; 341 ctx.indent -= 1; 342 z += newline(ctx)?; 343 z += syn(ctx, "}", synkind::PUNCTUATION)?; 344 return z; 345 case let e: ast::match_expr => 346 return match_expr(ctx, syn, &e)?; 347 case let e: ast::len_expr => 348 let z = syn(ctx, "len", synkind::KEYWORD)?; 349 z += syn(ctx, "(", synkind::PUNCTUATION)?; 350 z += _expr(ctx, syn, e)?; 351 z += syn(ctx, ")", synkind::PUNCTUATION)?; 352 return z; 353 case let e: ast::size_expr => 354 let z = syn(ctx, "size", synkind::KEYWORD)?; 355 z += syn(ctx, "(", synkind::PUNCTUATION)?; 356 z += __type(ctx, syn, e)?; 357 z += syn(ctx, ")", synkind::PUNCTUATION)?; 358 return z; 359 case let e: ast::offset_expr => 360 let z = syn(ctx, "offset", synkind::KEYWORD)?; 361 z += syn(ctx, "(", synkind::PUNCTUATION)?; 362 z += _expr(ctx, syn, e)?; 363 z += syn(ctx, ")", synkind::PUNCTUATION)?; 364 return z; 365 case let e: ast::propagate_expr => 366 let z = 0z; 367 const needs_parens = !is_postfix(e); 368 if (needs_parens) { 369 z += syn(ctx, "(", synkind::PUNCTUATION)?; 370 }; 371 z += _expr(ctx, syn, e)?; 372 if (needs_parens) { 373 z += syn(ctx, ")", synkind::PUNCTUATION)?; 374 }; 375 z += syn(ctx, "?", synkind::OPERATOR)?; 376 return z; 377 case let e: ast::return_expr => 378 let z = syn(ctx, "return", synkind::KEYWORD)?; 379 match (e) { 380 case null => void; 381 case let e: *ast::expr => 382 z += space(ctx)?; 383 z += _expr(ctx, syn, e)?; 384 }; 385 return z; 386 case let e: ast::slice_expr => 387 let z = 0z; 388 const needs_parens = !is_postfix(e.object); 389 if (needs_parens) { 390 z += syn(ctx, "(", synkind::PUNCTUATION)?; 391 }; 392 z += _expr(ctx, syn, e.object)?; 393 if (needs_parens) { 394 z += syn(ctx, ")", synkind::PUNCTUATION)?; 395 }; 396 z += syn(ctx, "[", synkind::PUNCTUATION)?; 397 match (e.start) { 398 case null => void; 399 case let e: *ast::expr => 400 z += _expr(ctx, syn, e)?; 401 }; 402 z += syn(ctx, "..", synkind::OPERATOR)?; 403 match (e.end) { 404 case null => void; 405 case let e: *ast::expr => 406 z += _expr(ctx, syn, e)?; 407 }; 408 z += syn(ctx, "]", synkind::PUNCTUATION)?; 409 return z; 410 case let e: ast::switch_expr => 411 return switch_expr(ctx, syn, &e)?; 412 case let e: ast::unarithm_expr => 413 let z = syn(ctx, switch (e.op) { 414 case ast::unarithm_op::ADDR => 415 yield "&"; 416 case ast::unarithm_op::BNOT => 417 yield "~"; 418 case ast::unarithm_op::DEREF => 419 yield "*"; 420 case ast::unarithm_op::LNOT => 421 yield "!"; 422 case ast::unarithm_op::MINUS => 423 yield "-"; 424 }, synkind::OPERATOR)?; 425 const needs_parens = match (e.operand.expr) { 426 case let inner: ast::unarithm_expr => 427 yield e.op == ast::unarithm_op::ADDR 428 && inner.op == e.op; 429 case => 430 yield !is_unary(e.operand); 431 }; 432 if (needs_parens) { 433 z += syn(ctx, "(", synkind::PUNCTUATION)?; 434 }; 435 z += _expr(ctx, syn, e.operand)?; 436 if (needs_parens) { 437 z += syn(ctx, ")", synkind::PUNCTUATION)?; 438 }; 439 return z; 440 case let e: ast::variadic_expr => 441 match (e) { 442 case ast::vastart_expr => 443 let z = syn(ctx, "vastart", synkind::KEYWORD)?; 444 z += syn(ctx, "(", synkind::PUNCTUATION)?; 445 z += syn(ctx, ")", synkind::PUNCTUATION)?; 446 return z; 447 case let e: ast::vaarg_expr => 448 let z = syn(ctx, "vaarg", synkind::KEYWORD)?; 449 z += syn(ctx, "(", synkind::PUNCTUATION)?; 450 z += _expr(ctx, syn, e)?; 451 z += syn(ctx, ")", synkind::PUNCTUATION)?; 452 return z; 453 case let e: ast::vaend_expr => 454 let z = syn(ctx, "vaend", synkind::KEYWORD)?; 455 z += syn(ctx, "(", synkind::PUNCTUATION)?; 456 z += _expr(ctx, syn, e)?; 457 z += syn(ctx, ")", synkind::PUNCTUATION)?; 458 return z; 459 }; 460 case let e: ast::yield_expr => 461 let z = syn(ctx, "yield", synkind::KEYWORD)?; 462 if (e.label != "") { 463 z += space(ctx)?; 464 z += syn(ctx, ":", synkind::LABEL)?; 465 z += syn(ctx, e.label, synkind::LABEL)?; 466 }; 467 match (e.value) { 468 case null => void; 469 case let v: *ast::expr => 470 if (e.label != "") { 471 z += syn(ctx, ",", synkind::PUNCTUATION)?; 472 }; 473 z += space(ctx)?; 474 z += _expr(ctx, syn, v)?; 475 }; 476 return z; 477 }; 478 }; 479 480 fn binprecedence(op: binarithm_op) uint = { 481 switch (op) { 482 case binarithm_op::DIV, binarithm_op::MODULO, binarithm_op::TIMES => 483 return 10; 484 case binarithm_op::MINUS, binarithm_op::PLUS => 485 return 9; 486 case binarithm_op::LSHIFT, binarithm_op::RSHIFT => 487 return 8; 488 case binarithm_op::BAND => 489 return 7; 490 case binarithm_op::BXOR => 491 return 6; 492 case binarithm_op::BOR => 493 return 5; 494 case binarithm_op::GT, binarithm_op::GTEQ, 495 binarithm_op::LESS, binarithm_op::LESSEQ => 496 return 4; 497 case binarithm_op::LEQUAL, binarithm_op::NEQUAL => 498 return 3; 499 case binarithm_op::LAND => 500 return 2; 501 case binarithm_op::LXOR => 502 return 1; 503 case binarithm_op::LOR => 504 return 0; 505 }; 506 }; 507 508 fn binexprval( 509 ctx: *context, 510 syn: *synfunc, 511 e: *ast::expr, 512 prec: uint, 513 ) (size | io::error) = { 514 let z = 0z; 515 match (e.expr) { 516 case let b: ast::binarithm_expr => 517 if (binprecedence(b.op) < prec) { 518 z += syn(ctx, "(", synkind::PUNCTUATION)?; 519 z += _expr(ctx, syn, e)?; 520 z += syn(ctx, ")", synkind::PUNCTUATION)?; 521 return z; 522 }; 523 case => void; 524 }; 525 const needs_parens = !is_cast(e) && !(e.expr is ast::binarithm_expr); 526 if (needs_parens) { 527 z += syn(ctx, "(", synkind::PUNCTUATION)?; 528 }; 529 z += _expr(ctx, syn, e)?; 530 if (needs_parens) { 531 z += syn(ctx, ")", synkind::PUNCTUATION)?; 532 }; 533 return z; 534 }; 535 536 fn stmt(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = { 537 let n = _expr(ctx, syn, e)?; 538 n += syn(ctx, ";", synkind::PUNCTUATION)?; 539 return n; 540 }; 541 542 fn literal( 543 ctx: *context, 544 syn: *synfunc, 545 e: ast::literal_expr, 546 ) (size | io::error) = { 547 match (e) { 548 case void => 549 return syn(ctx, "void", synkind::KEYWORD)?; 550 case let v: ast::value => 551 match (v) { 552 case void => abort(); 553 case ast::_null => 554 return syn(ctx, "null", synkind::KEYWORD)?; 555 case let b: bool => 556 return syn(ctx, if (b) "true" else "false", 557 synkind::KEYWORD)?; 558 case let s: str => 559 const s = strings::multireplace(s, 560 (`\`, `\\`), (`"`, `\"`)); 561 defer free(s); 562 const s = fmt::asprintf(`"{}"`, s); 563 defer free(s); 564 return syn(ctx, s, synkind::RUNE_STRING)?; 565 case let r: rune => 566 // 4 for unicode codepoint + 2 's 567 let buf: [6]u8 = [0...]; 568 if (r == '\'' || r == '\\') { 569 return syn(ctx, fmt::bsprintf(buf, `'\{}'`, r), 570 synkind::RUNE_STRING)?; 571 } else { 572 return syn(ctx, fmt::bsprintf(buf, "'{}'", r), 573 synkind::RUNE_STRING)?; 574 }; 575 }; 576 case let ac: ast::array_literal => 577 let z = syn(ctx, "[", synkind::PUNCTUATION)?; 578 for (let i = 0z; i < len(ac.values); i += 1) { 579 z += _expr(ctx, syn, ac.values[i])?; 580 if (i + 1 < len(ac.values)) { 581 z += syn(ctx, ",", synkind::PUNCTUATION)?; 582 z += space(ctx)?; 583 }; 584 }; 585 if (ac.expand) { 586 z += syn(ctx, "...", synkind::OPERATOR)?; 587 }; 588 z += syn(ctx, "]", synkind::PUNCTUATION)?; 589 return z; 590 case let v: ast::number_literal => 591 const s = fmt::asprintf("{}{}", v.value, switch (v.suff) { 592 case ltok::LIT_U8 => 593 yield "u8"; 594 case ltok::LIT_U16 => 595 yield "u16"; 596 case ltok::LIT_U32 => 597 yield "u32"; 598 case ltok::LIT_U64 => 599 yield "u64"; 600 case ltok::LIT_UINT => 601 yield "u"; 602 case ltok::LIT_SIZE => 603 yield "z"; 604 case ltok::LIT_I8 => 605 yield "i8"; 606 case ltok::LIT_I16 => 607 yield "i16"; 608 case ltok::LIT_I32 => 609 yield "i32"; 610 case ltok::LIT_I64 => 611 yield "i64"; 612 case ltok::LIT_INT => 613 yield "i"; 614 case ltok::LIT_ICONST, ltok::LIT_FCONST => 615 yield ""; 616 case ltok::LIT_F32 => 617 yield "f32"; 618 case ltok::LIT_F64 => 619 yield "f64"; 620 case => abort(); 621 }); 622 defer free(s); 623 return syn(ctx, s, synkind::NUMBER)?; 624 case let sc: ast::struct_literal => 625 return struct_literal(ctx, syn, sc)?; 626 case let tu: ast::tuple_literal => 627 let z = syn(ctx, "(", synkind::PUNCTUATION)?; 628 for (let i = 0z; i < len(tu); i += 1) { 629 z += _expr(ctx, syn, tu[i])?; 630 if (i + 1 < len(tu)) { 631 z += syn(ctx, ",", synkind::PUNCTUATION)?; 632 z += space(ctx)?; 633 }; 634 }; 635 z += syn(ctx, ")", synkind::PUNCTUATION)?; 636 return z; 637 }; 638 }; 639 640 fn struct_literal( 641 ctx: *context, 642 syn: *synfunc, 643 sc: ast::struct_literal, 644 ) (size | io::error) = { 645 let z = 0z; 646 z += if (len(sc.alias) != 0) { 647 yield _ident(ctx, syn, sc.alias, synkind::IDENT)?; 648 } else { 649 yield syn(ctx, "struct", synkind::KEYWORD)?; 650 }; 651 z += space(ctx)?; 652 z += syn(ctx, "{", synkind::PUNCTUATION)?; 653 ctx.indent += 1; 654 for (let field .. sc.fields) { 655 z += newline(ctx)?; 656 match (field) { 657 case let sv: ast::struct_value => 658 z += syn(ctx, sv.name, synkind::SECONDARY)?; 659 match (sv._type) { 660 case null => void; 661 case let t: *ast::_type => 662 z += syn(ctx, ":", synkind::PUNCTUATION)?; 663 z += space(ctx)?; 664 z += __type(ctx, syn, t)?; 665 }; 666 z += space(ctx)?; 667 z += syn(ctx, "=", synkind::OPERATOR)?; 668 z += space(ctx)?; 669 z += _expr(ctx, syn, sv.init)?; 670 case let sc: *ast::struct_literal => 671 z += literal(ctx, syn, *sc)?; 672 }; 673 z += syn(ctx, ",", synkind::PUNCTUATION)?; 674 }; 675 if (sc.autofill) { 676 z += newline(ctx)?; 677 z += syn(ctx, "...", synkind::OPERATOR)?; 678 }; 679 ctx.indent -= 1; 680 z += newline(ctx)?; 681 z += syn(ctx, "}", synkind::PUNCTUATION)?; 682 return z; 683 }; 684 685 fn binding_expr( 686 ctx: *context, 687 syn: *synfunc, 688 e: *ast::binding_expr, 689 assign_op: str 690 ) (size | io::error) = { 691 let z = 0z; 692 if (e.is_static) { 693 z += syn(ctx, "static", synkind::KEYWORD)?; 694 z += space(ctx)?; 695 }; 696 switch (e.kind) { 697 case ast::binding_kind::DEF => 698 z += syn(ctx, "def", synkind::KEYWORD)?; 699 case ast::binding_kind::CONST => 700 z += syn(ctx, "const", synkind::KEYWORD)?; 701 case ast::binding_kind::LET => 702 z += syn(ctx, "let", synkind::KEYWORD)?; 703 }; 704 z += space(ctx)?; 705 for (let i = 0z; i < len(e.bindings); i += 1) { 706 let binding = e.bindings[i]; 707 708 match (binding.name) { 709 case let s: str => 710 z += syn(ctx, s, synkind::IDENT)?; 711 case let u: ast::binding_unpack => 712 z += syn(ctx, "(", synkind::PUNCTUATION)?; 713 for (let i = 0z; i < len(u); i += 1) { 714 match (u[i]) { 715 case let s: str => 716 z += syn(ctx, s, 717 synkind::IDENT)?; 718 case void => 719 z += syn(ctx, "_", 720 synkind::OPERATOR)?; 721 }; 722 if (i + 1 < len(u)) { 723 z += syn(ctx, ",", 724 synkind::PUNCTUATION)?; 725 z += space(ctx)?; 726 }; 727 }; 728 z += syn(ctx, ")", synkind::PUNCTUATION)?; 729 }; 730 match (binding._type) { 731 case let t: *ast::_type => 732 z += syn(ctx, ":", synkind::PUNCTUATION)?; 733 z += space(ctx)?; 734 z += __type(ctx, syn, t)?; 735 case null => void; 736 }; 737 z += space(ctx)?; 738 z += syn(ctx, assign_op, synkind::OPERATOR)?; 739 z += space(ctx)?; 740 z += _expr(ctx, syn, binding.init)?; 741 if (i + 1 < len(e.bindings)) { 742 z += syn(ctx, ",", synkind::PUNCTUATION)?; 743 z += space(ctx)?; 744 }; 745 }; 746 return z; 747 }; 748 749 fn for_expr( 750 ctx: *context, 751 syn: *synfunc, 752 e: *ast::for_expr, 753 ) (size | io::error) = { 754 let z = syn(ctx, "for", synkind::KEYWORD)?; 755 z += space(ctx)?; 756 if (e.label != "") { 757 z += syn(ctx, ":", synkind::LABEL)?; 758 z += syn(ctx, e.label, synkind::LABEL)?; 759 z += space(ctx)?; 760 }; 761 z += syn(ctx, "(", synkind::PUNCTUATION)?; 762 763 let assign_op = switch (e.kind) { 764 case ast::for_kind::ACCUMULATOR => 765 yield "="; 766 case ast::for_kind::EACH_VALUE => 767 yield ".."; 768 case ast::for_kind::EACH_POINTER => 769 yield "&.."; 770 case ast::for_kind::ITERATOR => 771 yield "=>"; 772 }; 773 774 match (e.bindings) { 775 case let bind_expr: *ast::expr => 776 z += binding_expr(ctx, syn, 777 &(bind_expr.expr as ast::binding_expr), assign_op)?; 778 779 if (e.kind == ast::for_kind::ACCUMULATOR) { 780 z += syn(ctx, ";", synkind::PUNCTUATION)?; 781 z += space(ctx)?; 782 }; 783 case null => void; 784 }; 785 786 if (e.kind == ast::for_kind::ACCUMULATOR) { 787 z += _expr(ctx, syn, e.cond as *ast::expr)?; 788 789 match (e.afterthought) { 790 case null => void; 791 case let e: *ast::expr => 792 z += syn(ctx, ";", synkind::PUNCTUATION)?; 793 z += space(ctx)?; 794 z += _expr(ctx, syn, e)?; 795 }; 796 }; 797 798 z += syn(ctx, ")", synkind::PUNCTUATION)?; 799 z += space(ctx)?; 800 z += _expr(ctx, syn, e.body)?; 801 return z; 802 }; 803 804 fn switch_expr( 805 ctx: *context, 806 syn: *synfunc, 807 e: *ast::switch_expr, 808 ) (size | io::error) = { 809 let z = syn(ctx, "switch", synkind::KEYWORD)?; 810 z += space(ctx)?; 811 if (e.label != "") { 812 z += syn(ctx, ":", synkind::LABEL)?; 813 z += syn(ctx, e.label, synkind::LABEL)?; 814 z += space(ctx)?; 815 }; 816 z += syn(ctx, "(", synkind::PUNCTUATION)?; 817 z += _expr(ctx, syn, e.value)?; 818 z += syn(ctx, ")", synkind::PUNCTUATION)?; 819 z += space(ctx)?; 820 z += syn(ctx, "{", synkind::PUNCTUATION)?; 821 822 for (let item .. e.cases) { 823 z += newline(ctx)?; 824 z += syn(ctx, "case", synkind::KEYWORD)?; 825 z += space(ctx)?; 826 if (len(item.options) == 0) { 827 z += syn(ctx, "=>", synkind::OPERATOR)?; 828 } else { 829 for (let j = 0z; j < len(item.options); j += 1) { 830 const opt = item.options[j]; 831 z += _expr(ctx, syn, opt)?; 832 if (j + 1 < len(item.options)) { 833 z += syn(ctx, ",", 834 synkind::PUNCTUATION)?; 835 z += space(ctx)?; 836 }; 837 }; 838 z += space(ctx)?; 839 z += syn(ctx, "=>", synkind::OPERATOR)?; 840 }; 841 z += case_exprs(ctx, syn, item.exprs)?; 842 }; 843 844 z += newline(ctx)?; 845 z += syn(ctx, "}", synkind::PUNCTUATION)?; 846 return z; 847 }; 848 849 fn match_expr( 850 ctx: *context, 851 syn: *synfunc, 852 e: *ast::match_expr, 853 ) (size | io::error) = { 854 let z = syn(ctx, "match", synkind::KEYWORD)?; 855 z += space(ctx)?; 856 if (e.label != "") { 857 z += syn(ctx, ":", synkind::LABEL)?; 858 z += syn(ctx, e.label, synkind::LABEL)?; 859 z += space(ctx)?; 860 }; 861 z += syn(ctx, "(", synkind::PUNCTUATION)?; 862 z += _expr(ctx, syn, e.value)?; 863 z += syn(ctx, ")", synkind::PUNCTUATION)?; 864 z += space(ctx)?; 865 z += syn(ctx, "{", synkind::PUNCTUATION)?; 866 867 for (let item .. e.cases) { 868 z += newline(ctx)?; 869 z += syn(ctx, "case", synkind::KEYWORD)?; 870 if (len(item.name) > 0) { 871 z += space(ctx)?; 872 z += syn(ctx, "let", synkind::KEYWORD)?; 873 z += space(ctx)?; 874 z += syn(ctx, item.name, synkind::IDENT)?; 875 }; 876 match (item._type) { 877 case let typ: *ast::_type => 878 if (len(item.name) > 0) { 879 z += syn(ctx, ":", synkind::PUNCTUATION)?; 880 }; 881 z += space(ctx)?; 882 z += __type(ctx, syn, typ)?; 883 case null => void; 884 }; 885 z += space(ctx)?; 886 z += syn(ctx, "=>", synkind::OPERATOR)?; 887 z += case_exprs(ctx, syn, item.exprs)?; 888 }; 889 890 z += newline(ctx)?; 891 z += syn(ctx, "}", synkind::PUNCTUATION)?; 892 return z; 893 }; 894 895 fn case_exprs( 896 ctx: *context, 897 syn: *synfunc, 898 exprs: []*ast::expr, 899 ) (size | io::error) = { 900 let z = 0z; 901 902 if (len(exprs) == 1) match (exprs[0].expr) { 903 case let e: ast::assert_expr => 904 if (e.cond == null) { 905 // abort() expression 906 z += space(ctx)?; 907 z += assert_expr(ctx, syn, &e)?; 908 z += syn(ctx, ";", synkind::PUNCTUATION)?; 909 return z; 910 }; 911 case let e: ast::value => 912 if (e is void) { 913 z += space(ctx)?; 914 { 915 ctx.stack = &stack { 916 cur = exprs[0], 917 up = ctx.stack, 918 ... 919 }; 920 defer ctx.stack = (ctx.stack as *stack).up; 921 z += syn(ctx, "void", synkind::KEYWORD)?; 922 }; 923 z += syn(ctx, ";", synkind::PUNCTUATION)?; 924 return z; 925 }; 926 case => void; 927 }; 928 ctx.indent += 1; 929 for (let expr .. exprs) { 930 z += newline(ctx)?; 931 z += stmt(ctx, syn, expr)?; 932 }; 933 ctx.indent -= 1; 934 935 return z; 936 }; 937 938 fn is_plain(e: *ast::expr) bool = { 939 match (e.expr) { 940 case ast::literal_expr => 941 return true; 942 case ast::access_identifier => 943 return true; 944 case => 945 return false; 946 }; 947 }; 948 949 fn is_postfix(e: *ast::expr) bool = { 950 if (is_plain(e)) { 951 return true; 952 }; 953 954 match (e.expr) { 955 case ast::call_expr => 956 return true; 957 case ast::access_expr => 958 return true; 959 case ast::slice_expr => 960 return true; 961 case ast::error_assert_expr => 962 return true; 963 case ast::propagate_expr => 964 return true; 965 case => 966 return false; 967 }; 968 }; 969 970 fn is_builtin(e: *ast::expr) bool = { 971 if (is_postfix(e)) { 972 return true; 973 }; 974 975 match (e.expr) { 976 case ast::alloc_expr => 977 return true; 978 case ast::assert_expr => 979 return true; 980 case ast::variadic_expr => 981 return true; 982 // measurement-expression 983 case ast::len_expr => 984 return true; 985 case ast::align_expr => 986 return true; 987 case ast::size_expr => 988 return true; 989 case ast::offset_expr => 990 return true; 991 // slice-mutation-expression 992 case ast::append_expr => 993 return true; 994 case ast::insert_expr => 995 return true; 996 case => 997 return false; 998 }; 999 }; 1000 1001 fn is_unary(e: *ast::expr) bool = { 1002 if (is_builtin(e)) { 1003 return true; 1004 }; 1005 1006 match (e.expr) { 1007 case ast::compound_expr => 1008 return true; 1009 case ast::match_expr => 1010 return true; 1011 case ast::switch_expr => 1012 return true; 1013 case ast::unarithm_expr => 1014 return true; 1015 case => 1016 return false; 1017 }; 1018 }; 1019 1020 fn is_cast(e: *ast::expr) bool = { 1021 return is_unary(e) || (e.expr is ast::cast_expr); 1022 }; 1023 1024 fn assert_expr( 1025 ctx: *context, 1026 syn: *synfunc, 1027 e: *ast::assert_expr, 1028 ) (size | io::error) = { 1029 let z = 0z; 1030 if (e.is_static) { 1031 z += syn(ctx, "static", synkind::KEYWORD)?; 1032 z += space(ctx)?; 1033 }; 1034 // assert without a condition = abort 1035 match (e.cond) { 1036 case let e: *ast::expr => 1037 z += syn(ctx, "assert", synkind::KEYWORD)?; 1038 z += syn(ctx, "(", synkind::PUNCTUATION)?; 1039 z += _expr(ctx, syn, e)?; 1040 case null => 1041 z += syn(ctx, "abort", synkind::KEYWORD)?; 1042 z += syn(ctx, "(", synkind::PUNCTUATION)?; 1043 }; 1044 match (e.message) { 1045 case let m: *ast::expr => 1046 match (e.cond) { 1047 case null => void; 1048 case *ast::expr => 1049 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1050 z += space(ctx)?; 1051 }; 1052 z += _expr(ctx, syn, m)?; 1053 case null => void; 1054 }; 1055 z += syn(ctx, ")", synkind::PUNCTUATION)?; 1056 return z; 1057 }; 1058 1059 fn append_insert_expr( 1060 ctx: *context, 1061 syn: *synfunc, 1062 e: *ast::expr, 1063 ) (size | io::error) = { 1064 let z = 0z; 1065 const e: *ast::append_expr = match (e.expr) { 1066 case let e: ast::append_expr => 1067 if (e.is_static) { 1068 z += syn(ctx, "static", synkind::KEYWORD)?; 1069 z += space(ctx)?; 1070 }; 1071 z += syn(ctx, "append", synkind::KEYWORD)?; 1072 yield &e; 1073 case let e: ast::insert_expr => 1074 if (e.is_static) { 1075 z += syn(ctx, "static", synkind::KEYWORD)?; 1076 z += space(ctx)?; 1077 }; 1078 z += syn(ctx, "insert", synkind::KEYWORD)?; 1079 yield &e; 1080 case => abort(); // unreachable 1081 }; 1082 z += syn(ctx, "(", synkind::PUNCTUATION)?; 1083 z += _expr(ctx, syn, e.object)?; 1084 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1085 z += space(ctx)?; 1086 z += _expr(ctx, syn, e.value)?; 1087 if (e.variadic) { 1088 z += syn(ctx, "...", synkind::OPERATOR)?; 1089 }; 1090 match (e.length) { 1091 case null => void; 1092 case let l: *ast::expr => 1093 z += syn(ctx, ",", synkind::PUNCTUATION)?; 1094 z += space(ctx)?; 1095 z += _expr(ctx, syn, l)?; 1096 }; 1097 z += syn(ctx, ")", synkind::PUNCTUATION)?; 1098 return z; 1099 };