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