blob c8ccfa49 (99516B) - Raw
1 const std = @import("std"); 2 const Type = @import("../type.zig").Type; 3 const Allocator = std.mem.Allocator; 4 5 pub const Node = extern union { 6 /// If the tag value is less than Tag.no_payload_count, then no pointer 7 /// dereference is needed. 8 tag_if_small_enough: usize, 9 ptr_otherwise: *Payload, 10 11 pub const Tag = enum { 12 /// Declarations add themselves to the correct scopes and should not be emitted as this tag. 13 declaration, 14 null_literal, 15 undefined_literal, 16 /// opaque {} 17 opaque_literal, 18 true_literal, 19 false_literal, 20 empty_block, 21 return_void, 22 zero_literal, 23 one_literal, 24 void_type, 25 noreturn_type, 26 @"anytype", 27 @"continue", 28 @"break", 29 // After this, the tag requires a payload. 30 31 integer_literal, 32 float_literal, 33 string_literal, 34 char_literal, 35 enum_literal, 36 /// "string"[0..end] 37 string_slice, 38 identifier, 39 fn_identifier, 40 @"if", 41 /// if (!operand) break; 42 if_not_break, 43 @"while", 44 /// while (true) operand 45 while_true, 46 @"switch", 47 /// else => operand, 48 switch_else, 49 /// items => body, 50 switch_prong, 51 break_val, 52 @"return", 53 field_access, 54 array_access, 55 call, 56 var_decl, 57 /// const name = struct { init } 58 static_local_var, 59 /// var name = init.* 60 mut_str, 61 func, 62 warning, 63 @"struct", 64 @"union", 65 @"comptime", 66 @"defer", 67 array_init, 68 tuple, 69 container_init, 70 container_init_dot, 71 helpers_cast, 72 /// _ = operand; 73 discard, 74 75 // a + b 76 add, 77 // a = b 78 add_assign, 79 // c = (a = b) 80 add_wrap, 81 add_wrap_assign, 82 sub, 83 sub_assign, 84 sub_wrap, 85 sub_wrap_assign, 86 mul, 87 mul_assign, 88 mul_wrap, 89 mul_wrap_assign, 90 div, 91 div_assign, 92 shl, 93 shl_assign, 94 shr, 95 shr_assign, 96 mod, 97 mod_assign, 98 @"and", 99 @"or", 100 less_than, 101 less_than_equal, 102 greater_than, 103 greater_than_equal, 104 equal, 105 not_equal, 106 bit_and, 107 bit_and_assign, 108 bit_or, 109 bit_or_assign, 110 bit_xor, 111 bit_xor_assign, 112 array_cat, 113 ellipsis3, 114 assign, 115 116 /// @import("std").zig.c_builtins.<name> 117 import_c_builtin, 118 log2_int_type, 119 /// @import("std").math.Log2Int(operand) 120 std_math_Log2Int, 121 /// @intCast(lhs, rhs) 122 int_cast, 123 /// @import("std").zig.c_translation.promoteIntLiteral(value, type, base) 124 helpers_promoteIntLiteral, 125 /// @import("std").meta.alignment(value) 126 std_meta_alignment, 127 /// @import("std").zig.c_translation.signedRemainder(lhs, rhs) 128 signed_remainder, 129 /// @divTrunc(lhs, rhs) 130 div_trunc, 131 /// @intFromBool(operand) 132 int_from_bool, 133 /// @as(lhs, rhs) 134 as, 135 /// @truncate(lhs, rhs) 136 truncate, 137 /// @bitCast(lhs, rhs) 138 bit_cast, 139 /// @floatCast(lhs, rhs) 140 float_cast, 141 /// @intFromFloat(lhs, rhs) 142 int_from_float, 143 /// @floatFromInt(lhs, rhs) 144 float_from_int, 145 /// @ptrFromInt(lhs, rhs) 146 ptr_from_int, 147 /// @intFromPtr(operand) 148 int_from_ptr, 149 /// @alignCast(lhs, rhs) 150 align_cast, 151 /// @ptrCast(lhs, rhs) 152 ptr_cast, 153 /// @divExact(lhs, rhs) 154 div_exact, 155 /// @offsetOf(lhs, rhs) 156 offset_of, 157 /// @splat(lhs, rhs) 158 vector_zero_init, 159 /// @shuffle(type, a, b, mask) 160 shuffle, 161 /// @extern(ty, .{ .name = n }) 162 builtin_extern, 163 164 /// @import("std").zig.c_translation.MacroArithmetic.<op>(lhs, rhs) 165 macro_arithmetic, 166 167 asm_simple, 168 169 negate, 170 negate_wrap, 171 bit_not, 172 not, 173 address_of, 174 /// .? 175 unwrap, 176 /// .* 177 deref, 178 179 block, 180 /// { operand } 181 block_single, 182 183 sizeof, 184 alignof, 185 typeof, 186 typeinfo, 187 type, 188 189 optional_type, 190 c_pointer, 191 single_pointer, 192 array_type, 193 null_sentinel_array_type, 194 195 /// @import("std").zig.c_translation.sizeof(operand) 196 helpers_sizeof, 197 /// @import("std").zig.c_translation.FlexibleArrayType(lhs, rhs) 198 helpers_flexible_array_type, 199 /// @import("std").zig.c_translation.shuffleVectorIndex(lhs, rhs) 200 helpers_shuffle_vector_index, 201 /// @import("std").zig.c_translation.Macro.<operand> 202 helpers_macro, 203 /// @Vector(lhs, rhs) 204 vector, 205 /// @import("std").mem.zeroes(operand) 206 std_mem_zeroes, 207 /// @import("std").mem.zeroInit(lhs, rhs) 208 std_mem_zeroinit, 209 // pub const name = @compileError(msg); 210 fail_decl, 211 // var actual = mangled; 212 arg_redecl, 213 /// pub const alias = actual; 214 alias, 215 /// const name = init; 216 var_simple, 217 /// pub const name = init; 218 pub_var_simple, 219 /// pub? const name (: type)? = value 220 enum_constant, 221 222 /// pub inline fn name(params) return_type body 223 pub_inline_fn, 224 225 /// [0]type{} 226 empty_array, 227 /// [1]type{val} ** count 228 array_filler, 229 230 pub const last_no_payload_tag = Tag.@"break"; 231 pub const no_payload_count = @intFromEnum(last_no_payload_tag) + 1; 232 233 pub fn Type(comptime t: Tag) type { 234 return switch (t) { 235 .declaration, 236 .null_literal, 237 .undefined_literal, 238 .opaque_literal, 239 .true_literal, 240 .false_literal, 241 .empty_block, 242 .return_void, 243 .zero_literal, 244 .one_literal, 245 .void_type, 246 .noreturn_type, 247 .@"anytype", 248 .@"continue", 249 .@"break", 250 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), 251 252 .std_mem_zeroes, 253 .@"return", 254 .@"comptime", 255 .@"defer", 256 .asm_simple, 257 .std_math_Log2Int, 258 .negate, 259 .negate_wrap, 260 .bit_not, 261 .not, 262 .optional_type, 263 .address_of, 264 .unwrap, 265 .deref, 266 .int_from_ptr, 267 .empty_array, 268 .while_true, 269 .if_not_break, 270 .switch_else, 271 .block_single, 272 .helpers_sizeof, 273 .std_meta_alignment, 274 .int_from_bool, 275 .sizeof, 276 .alignof, 277 .typeof, 278 .typeinfo, 279 => Payload.UnOp, 280 281 .add, 282 .add_assign, 283 .add_wrap, 284 .add_wrap_assign, 285 .sub, 286 .sub_assign, 287 .sub_wrap, 288 .sub_wrap_assign, 289 .mul, 290 .mul_assign, 291 .mul_wrap, 292 .mul_wrap_assign, 293 .div, 294 .div_assign, 295 .shl, 296 .shl_assign, 297 .shr, 298 .shr_assign, 299 .mod, 300 .mod_assign, 301 .@"and", 302 .@"or", 303 .less_than, 304 .less_than_equal, 305 .greater_than, 306 .greater_than_equal, 307 .equal, 308 .not_equal, 309 .bit_and, 310 .bit_and_assign, 311 .bit_or, 312 .bit_or_assign, 313 .bit_xor, 314 .bit_xor_assign, 315 .div_trunc, 316 .signed_remainder, 317 .int_cast, 318 .as, 319 .truncate, 320 .bit_cast, 321 .float_cast, 322 .int_from_float, 323 .float_from_int, 324 .ptr_from_int, 325 .array_cat, 326 .ellipsis3, 327 .assign, 328 .align_cast, 329 .array_access, 330 .std_mem_zeroinit, 331 .helpers_flexible_array_type, 332 .helpers_shuffle_vector_index, 333 .vector, 334 .ptr_cast, 335 .div_exact, 336 .offset_of, 337 .helpers_cast, 338 .vector_zero_init, 339 => Payload.BinOp, 340 341 .integer_literal, 342 .float_literal, 343 .string_literal, 344 .char_literal, 345 .enum_literal, 346 .identifier, 347 .fn_identifier, 348 .warning, 349 .type, 350 .helpers_macro, 351 .import_c_builtin, 352 => Payload.Value, 353 .discard => Payload.Discard, 354 .@"if" => Payload.If, 355 .@"while" => Payload.While, 356 .@"switch", .array_init, .switch_prong => Payload.Switch, 357 .break_val => Payload.BreakVal, 358 .call => Payload.Call, 359 .var_decl => Payload.VarDecl, 360 .func => Payload.Func, 361 .@"struct", .@"union" => Payload.Record, 362 .tuple => Payload.TupleInit, 363 .container_init => Payload.ContainerInit, 364 .container_init_dot => Payload.ContainerInitDot, 365 .helpers_promoteIntLiteral => Payload.PromoteIntLiteral, 366 .block => Payload.Block, 367 .c_pointer, .single_pointer => Payload.Pointer, 368 .array_type, .null_sentinel_array_type => Payload.Array, 369 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl, 370 .log2_int_type => Payload.Log2IntType, 371 .var_simple, .pub_var_simple, .static_local_var, .mut_str => Payload.SimpleVarDecl, 372 .enum_constant => Payload.EnumConstant, 373 .array_filler => Payload.ArrayFiller, 374 .pub_inline_fn => Payload.PubInlineFn, 375 .field_access => Payload.FieldAccess, 376 .string_slice => Payload.StringSlice, 377 .shuffle => Payload.Shuffle, 378 .builtin_extern => Payload.Extern, 379 .macro_arithmetic => Payload.MacroArithmetic, 380 }; 381 } 382 383 pub fn init(comptime t: Tag) Node { 384 comptime std.debug.assert(@intFromEnum(t) < Tag.no_payload_count); 385 return .{ .tag_if_small_enough = @intFromEnum(t) }; 386 } 387 388 pub fn create(comptime t: Tag, ally: Allocator, data: Data(t)) error{OutOfMemory}!Node { 389 const ptr = try ally.create(t.Type()); 390 ptr.* = .{ 391 .base = .{ .tag = t }, 392 .data = data, 393 }; 394 return Node{ .ptr_otherwise = &ptr.base }; 395 } 396 397 pub fn Data(comptime t: Tag) type { 398 return std.meta.fieldInfo(t.Type(), .data).type; 399 } 400 }; 401 402 pub fn tag(self: Node) Tag { 403 if (self.tag_if_small_enough < Tag.no_payload_count) { 404 return @enumFromInt(Tag, @intCast(std.meta.Tag(Tag), self.tag_if_small_enough)); 405 } else { 406 return self.ptr_otherwise.tag; 407 } 408 } 409 410 pub fn castTag(self: Node, comptime t: Tag) ?*t.Type() { 411 if (self.tag_if_small_enough < Tag.no_payload_count) 412 return null; 413 414 if (self.ptr_otherwise.tag == t) 415 return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); 416 417 return null; 418 } 419 420 pub fn initPayload(payload: *Payload) Node { 421 std.debug.assert(@intFromEnum(payload.tag) >= Tag.no_payload_count); 422 return .{ .ptr_otherwise = payload }; 423 } 424 425 pub fn isNoreturn(node: Node, break_counts: bool) bool { 426 switch (node.tag()) { 427 .block => { 428 const block_node = node.castTag(.block).?; 429 if (block_node.data.stmts.len == 0) return false; 430 431 const last = block_node.data.stmts[block_node.data.stmts.len - 1]; 432 return last.isNoreturn(break_counts); 433 }, 434 .@"switch" => { 435 const switch_node = node.castTag(.@"switch").?; 436 437 for (switch_node.data.cases) |case| { 438 const body = if (case.castTag(.switch_else)) |some| 439 some.data 440 else if (case.castTag(.switch_prong)) |some| 441 some.data.cond 442 else 443 unreachable; 444 445 if (!body.isNoreturn(break_counts)) return false; 446 } 447 return true; 448 }, 449 .@"return", .return_void => return true, 450 .@"break" => if (break_counts) return true, 451 else => {}, 452 } 453 return false; 454 } 455 }; 456 457 pub const Payload = struct { 458 tag: Node.Tag, 459 460 pub const Value = struct { 461 base: Payload, 462 data: []const u8, 463 }; 464 465 pub const UnOp = struct { 466 base: Payload, 467 data: Node, 468 }; 469 470 pub const BinOp = struct { 471 base: Payload, 472 data: struct { 473 lhs: Node, 474 rhs: Node, 475 }, 476 }; 477 478 pub const Discard = struct { 479 base: Payload, 480 data: struct { 481 should_skip: bool, 482 value: Node, 483 }, 484 }; 485 486 pub const If = struct { 487 base: Payload, 488 data: struct { 489 cond: Node, 490 then: Node, 491 @"else": ?Node, 492 }, 493 }; 494 495 pub const While = struct { 496 base: Payload, 497 data: struct { 498 cond: Node, 499 body: Node, 500 cont_expr: ?Node, 501 }, 502 }; 503 504 pub const Switch = struct { 505 base: Payload, 506 data: struct { 507 cond: Node, 508 cases: []Node, 509 }, 510 }; 511 512 pub const BreakVal = struct { 513 base: Payload, 514 data: struct { 515 label: ?[]const u8, 516 val: Node, 517 }, 518 }; 519 520 pub const Call = struct { 521 base: Payload, 522 data: struct { 523 lhs: Node, 524 args: []Node, 525 }, 526 }; 527 528 pub const VarDecl = struct { 529 base: Payload, 530 data: struct { 531 is_pub: bool, 532 is_const: bool, 533 is_extern: bool, 534 is_export: bool, 535 is_threadlocal: bool, 536 alignment: ?c_uint, 537 linksection_string: ?[]const u8, 538 name: []const u8, 539 type: Node, 540 init: ?Node, 541 }, 542 }; 543 544 pub const Func = struct { 545 base: Payload, 546 data: struct { 547 is_pub: bool, 548 is_extern: bool, 549 is_export: bool, 550 is_inline: bool, 551 is_var_args: bool, 552 name: ?[]const u8, 553 linksection_string: ?[]const u8, 554 explicit_callconv: ?std.builtin.CallingConvention, 555 params: []Param, 556 return_type: Node, 557 body: ?Node, 558 alignment: ?c_uint, 559 }, 560 }; 561 562 pub const Param = struct { 563 is_noalias: bool, 564 name: ?[]const u8, 565 type: Node, 566 }; 567 568 pub const Record = struct { 569 base: Payload, 570 data: struct { 571 layout: enum { @"packed", @"extern", none }, 572 fields: []Field, 573 functions: []Node, 574 variables: []Node, 575 }, 576 577 pub const Field = struct { 578 name: []const u8, 579 type: Node, 580 alignment: ?c_uint, 581 }; 582 }; 583 584 pub const TupleInit = struct { 585 base: Payload, 586 data: []Node, 587 }; 588 589 pub const ContainerInit = struct { 590 base: Payload, 591 data: struct { 592 lhs: Node, 593 inits: []Initializer, 594 }, 595 596 pub const Initializer = struct { 597 name: []const u8, 598 value: Node, 599 }; 600 }; 601 602 pub const ContainerInitDot = struct { 603 base: Payload, 604 data: []Initializer, 605 606 pub const Initializer = struct { 607 name: []const u8, 608 value: Node, 609 }; 610 }; 611 612 pub const Block = struct { 613 base: Payload, 614 data: struct { 615 label: ?[]const u8, 616 stmts: []Node, 617 }, 618 }; 619 620 pub const Array = struct { 621 base: Payload, 622 data: ArrayTypeInfo, 623 624 pub const ArrayTypeInfo = struct { 625 elem_type: Node, 626 len: usize, 627 }; 628 }; 629 630 pub const Pointer = struct { 631 base: Payload, 632 data: struct { 633 elem_type: Node, 634 is_const: bool, 635 is_volatile: bool, 636 }, 637 }; 638 639 pub const ArgRedecl = struct { 640 base: Payload, 641 data: struct { 642 actual: []const u8, 643 mangled: []const u8, 644 }, 645 }; 646 647 pub const Log2IntType = struct { 648 base: Payload, 649 data: std.math.Log2Int(u64), 650 }; 651 652 pub const SimpleVarDecl = struct { 653 base: Payload, 654 data: struct { 655 name: []const u8, 656 init: Node, 657 }, 658 }; 659 660 pub const EnumConstant = struct { 661 base: Payload, 662 data: struct { 663 name: []const u8, 664 is_public: bool, 665 type: ?Node, 666 value: Node, 667 }, 668 }; 669 670 pub const ArrayFiller = struct { 671 base: Payload, 672 data: struct { 673 type: Node, 674 filler: Node, 675 count: usize, 676 }, 677 }; 678 679 pub const PubInlineFn = struct { 680 base: Payload, 681 data: struct { 682 name: []const u8, 683 params: []Param, 684 return_type: Node, 685 body: Node, 686 }, 687 }; 688 689 pub const FieldAccess = struct { 690 base: Payload, 691 data: struct { 692 lhs: Node, 693 field_name: []const u8, 694 }, 695 }; 696 697 pub const PromoteIntLiteral = struct { 698 base: Payload, 699 data: struct { 700 value: Node, 701 type: Node, 702 base: Node, 703 }, 704 }; 705 706 pub const StringSlice = struct { 707 base: Payload, 708 data: struct { 709 string: Node, 710 end: usize, 711 }, 712 }; 713 714 pub const Shuffle = struct { 715 base: Payload, 716 data: struct { 717 element_type: Node, 718 a: Node, 719 b: Node, 720 mask_vector: Node, 721 }, 722 }; 723 724 pub const Extern = struct { 725 base: Payload, 726 data: struct { 727 type: Node, 728 name: Node, 729 }, 730 }; 731 732 pub const MacroArithmetic = struct { 733 base: Payload, 734 data: struct { 735 op: Operator, 736 lhs: Node, 737 rhs: Node, 738 }, 739 740 pub const Operator = enum { div, rem }; 741 }; 742 }; 743 744 /// Converts the nodes into a Zig Ast. 745 /// Caller must free the source slice. 746 pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast { 747 var ctx = Context{ 748 .gpa = gpa, 749 .buf = std.ArrayList(u8).init(gpa), 750 }; 751 defer ctx.buf.deinit(); 752 defer ctx.nodes.deinit(gpa); 753 defer ctx.extra_data.deinit(gpa); 754 defer ctx.tokens.deinit(gpa); 755 756 // Estimate that each top level node has 10 child nodes. 757 const estimated_node_count = nodes.len * 10; 758 try ctx.nodes.ensureTotalCapacity(gpa, estimated_node_count); 759 // Estimate that each each node has 2 tokens. 760 const estimated_tokens_count = estimated_node_count * 2; 761 try ctx.tokens.ensureTotalCapacity(gpa, estimated_tokens_count); 762 // Estimate that each each token is 3 bytes long. 763 const estimated_buf_len = estimated_tokens_count * 3; 764 try ctx.buf.ensureTotalCapacity(estimated_buf_len); 765 766 ctx.nodes.appendAssumeCapacity(.{ 767 .tag = .root, 768 .main_token = 0, 769 .data = .{ 770 .lhs = undefined, 771 .rhs = undefined, 772 }, 773 }); 774 775 const root_members = blk: { 776 var result = std.ArrayList(NodeIndex).init(gpa); 777 defer result.deinit(); 778 779 for (nodes) |node| { 780 const res = try renderNode(&ctx, node); 781 if (node.tag() == .warning) continue; 782 try result.append(res); 783 } 784 break :blk try ctx.listToSpan(result.items); 785 }; 786 787 ctx.nodes.items(.data)[0] = .{ 788 .lhs = root_members.start, 789 .rhs = root_members.end, 790 }; 791 792 try ctx.tokens.append(gpa, .{ 793 .tag = .eof, 794 .start = @intCast(u32, ctx.buf.items.len), 795 }); 796 797 return std.zig.Ast{ 798 .source = try ctx.buf.toOwnedSliceSentinel(0), 799 .tokens = ctx.tokens.toOwnedSlice(), 800 .nodes = ctx.nodes.toOwnedSlice(), 801 .extra_data = try ctx.extra_data.toOwnedSlice(gpa), 802 .errors = &.{}, 803 }; 804 } 805 806 const NodeIndex = std.zig.Ast.Node.Index; 807 const NodeSubRange = std.zig.Ast.Node.SubRange; 808 const TokenIndex = std.zig.Ast.TokenIndex; 809 const TokenTag = std.zig.Token.Tag; 810 811 const Context = struct { 812 gpa: Allocator, 813 buf: std.ArrayList(u8), 814 nodes: std.zig.Ast.NodeList = .{}, 815 extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, 816 tokens: std.zig.Ast.TokenList = .{}, 817 818 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { 819 const start_index = c.buf.items.len; 820 try c.buf.writer().print(format ++ " ", args); 821 822 try c.tokens.append(c.gpa, .{ 823 .tag = tag, 824 .start = @intCast(u32, start_index), 825 }); 826 827 return @intCast(u32, c.tokens.len - 1); 828 } 829 830 fn addToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex { 831 return c.addTokenFmt(tag, "{s}", .{bytes}); 832 } 833 834 fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { 835 if (std.zig.primitives.isPrimitive(bytes)) 836 return c.addTokenFmt(.identifier, "@\"{s}\"", .{bytes}); 837 return c.addTokenFmt(.identifier, "{s}", .{std.zig.fmtId(bytes)}); 838 } 839 840 fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange { 841 try c.extra_data.appendSlice(c.gpa, list); 842 return NodeSubRange{ 843 .start = @intCast(NodeIndex, c.extra_data.items.len - list.len), 844 .end = @intCast(NodeIndex, c.extra_data.items.len), 845 }; 846 } 847 848 fn addNode(c: *Context, elem: std.zig.Ast.Node) Allocator.Error!NodeIndex { 849 const result = @intCast(NodeIndex, c.nodes.len); 850 try c.nodes.append(c.gpa, elem); 851 return result; 852 } 853 854 fn addExtra(c: *Context, extra: anytype) Allocator.Error!NodeIndex { 855 const fields = std.meta.fields(@TypeOf(extra)); 856 try c.extra_data.ensureUnusedCapacity(c.gpa, fields.len); 857 const result = @intCast(u32, c.extra_data.items.len); 858 inline for (fields) |field| { 859 comptime std.debug.assert(field.type == NodeIndex); 860 c.extra_data.appendAssumeCapacity(@field(extra, field.name)); 861 } 862 return result; 863 } 864 }; 865 866 fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange { 867 var result = std.ArrayList(NodeIndex).init(c.gpa); 868 defer result.deinit(); 869 870 for (nodes) |node| { 871 const res = try renderNode(c, node); 872 if (node.tag() == .warning) continue; 873 try result.append(res); 874 } 875 876 return try c.listToSpan(result.items); 877 } 878 879 fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { 880 switch (node.tag()) { 881 .declaration => unreachable, 882 .warning => { 883 const payload = node.castTag(.warning).?.data; 884 try c.buf.appendSlice(payload); 885 try c.buf.append('\n'); 886 return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32' 887 }, 888 .std_math_Log2Int => { 889 const payload = node.castTag(.std_math_Log2Int).?.data; 890 const import_node = try renderStdImport(c, &.{ "math", "Log2Int" }); 891 return renderCall(c, import_node, &.{payload}); 892 }, 893 .helpers_cast => { 894 const payload = node.castTag(.helpers_cast).?.data; 895 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "cast" }); 896 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 897 }, 898 .helpers_promoteIntLiteral => { 899 const payload = node.castTag(.helpers_promoteIntLiteral).?.data; 900 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "promoteIntLiteral" }); 901 return renderCall(c, import_node, &.{ payload.type, payload.value, payload.base }); 902 }, 903 .std_meta_alignment => { 904 const payload = node.castTag(.std_meta_alignment).?.data; 905 const import_node = try renderStdImport(c, &.{ "meta", "alignment" }); 906 return renderCall(c, import_node, &.{payload}); 907 }, 908 .helpers_sizeof => { 909 const payload = node.castTag(.helpers_sizeof).?.data; 910 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "sizeof" }); 911 return renderCall(c, import_node, &.{payload}); 912 }, 913 .std_mem_zeroes => { 914 const payload = node.castTag(.std_mem_zeroes).?.data; 915 const import_node = try renderStdImport(c, &.{ "mem", "zeroes" }); 916 return renderCall(c, import_node, &.{payload}); 917 }, 918 .std_mem_zeroinit => { 919 const payload = node.castTag(.std_mem_zeroinit).?.data; 920 const import_node = try renderStdImport(c, &.{ "mem", "zeroInit" }); 921 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 922 }, 923 .helpers_flexible_array_type => { 924 const payload = node.castTag(.helpers_flexible_array_type).?.data; 925 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "FlexibleArrayType" }); 926 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 927 }, 928 .helpers_shuffle_vector_index => { 929 const payload = node.castTag(.helpers_shuffle_vector_index).?.data; 930 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "shuffleVectorIndex" }); 931 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 932 }, 933 .vector => { 934 const payload = node.castTag(.vector).?.data; 935 return renderBuiltinCall(c, "@Vector", &.{ payload.lhs, payload.rhs }); 936 }, 937 .call => { 938 const payload = node.castTag(.call).?.data; 939 // Cosmetic: avoids an unnecesary address_of on most function calls. 940 const lhs = if (payload.lhs.tag() == .fn_identifier) 941 try c.addNode(.{ 942 .tag = .identifier, 943 .main_token = try c.addIdentifier(payload.lhs.castTag(.fn_identifier).?.data), 944 .data = undefined, 945 }) 946 else 947 try renderNodeGrouped(c, payload.lhs); 948 return renderCall(c, lhs, payload.args); 949 }, 950 .null_literal => return c.addNode(.{ 951 .tag = .identifier, 952 .main_token = try c.addToken(.identifier, "null"), 953 .data = undefined, 954 }), 955 .undefined_literal => return c.addNode(.{ 956 .tag = .identifier, 957 .main_token = try c.addToken(.identifier, "undefined"), 958 .data = undefined, 959 }), 960 .true_literal => return c.addNode(.{ 961 .tag = .identifier, 962 .main_token = try c.addToken(.identifier, "true"), 963 .data = undefined, 964 }), 965 .false_literal => return c.addNode(.{ 966 .tag = .identifier, 967 .main_token = try c.addToken(.identifier, "false"), 968 .data = undefined, 969 }), 970 .zero_literal => return c.addNode(.{ 971 .tag = .number_literal, 972 .main_token = try c.addToken(.number_literal, "0"), 973 .data = undefined, 974 }), 975 .one_literal => return c.addNode(.{ 976 .tag = .number_literal, 977 .main_token = try c.addToken(.number_literal, "1"), 978 .data = undefined, 979 }), 980 .void_type => return c.addNode(.{ 981 .tag = .identifier, 982 .main_token = try c.addToken(.identifier, "void"), 983 .data = undefined, 984 }), 985 .noreturn_type => return c.addNode(.{ 986 .tag = .identifier, 987 .main_token = try c.addToken(.identifier, "noreturn"), 988 .data = undefined, 989 }), 990 .@"continue" => return c.addNode(.{ 991 .tag = .@"continue", 992 .main_token = try c.addToken(.keyword_continue, "continue"), 993 .data = .{ 994 .lhs = 0, 995 .rhs = undefined, 996 }, 997 }), 998 .return_void => return c.addNode(.{ 999 .tag = .@"return", 1000 .main_token = try c.addToken(.keyword_return, "return"), 1001 .data = .{ 1002 .lhs = 0, 1003 .rhs = undefined, 1004 }, 1005 }), 1006 .@"break" => return c.addNode(.{ 1007 .tag = .@"break", 1008 .main_token = try c.addToken(.keyword_break, "break"), 1009 .data = .{ 1010 .lhs = 0, 1011 .rhs = 0, 1012 }, 1013 }), 1014 .break_val => { 1015 const payload = node.castTag(.break_val).?.data; 1016 const tok = try c.addToken(.keyword_break, "break"); 1017 const break_label = if (payload.label) |some| blk: { 1018 _ = try c.addToken(.colon, ":"); 1019 break :blk try c.addIdentifier(some); 1020 } else 0; 1021 return c.addNode(.{ 1022 .tag = .@"break", 1023 .main_token = tok, 1024 .data = .{ 1025 .lhs = break_label, 1026 .rhs = try renderNode(c, payload.val), 1027 }, 1028 }); 1029 }, 1030 .@"return" => { 1031 const payload = node.castTag(.@"return").?.data; 1032 return c.addNode(.{ 1033 .tag = .@"return", 1034 .main_token = try c.addToken(.keyword_return, "return"), 1035 .data = .{ 1036 .lhs = try renderNode(c, payload), 1037 .rhs = undefined, 1038 }, 1039 }); 1040 }, 1041 .@"comptime" => { 1042 const payload = node.castTag(.@"comptime").?.data; 1043 return c.addNode(.{ 1044 .tag = .@"comptime", 1045 .main_token = try c.addToken(.keyword_comptime, "comptime"), 1046 .data = .{ 1047 .lhs = try renderNode(c, payload), 1048 .rhs = undefined, 1049 }, 1050 }); 1051 }, 1052 .@"defer" => { 1053 const payload = node.castTag(.@"defer").?.data; 1054 return c.addNode(.{ 1055 .tag = .@"defer", 1056 .main_token = try c.addToken(.keyword_defer, "defer"), 1057 .data = .{ 1058 .lhs = undefined, 1059 .rhs = try renderNode(c, payload), 1060 }, 1061 }); 1062 }, 1063 .asm_simple => { 1064 const payload = node.castTag(.asm_simple).?.data; 1065 const asm_token = try c.addToken(.keyword_asm, "asm"); 1066 _ = try c.addToken(.l_paren, "("); 1067 return c.addNode(.{ 1068 .tag = .asm_simple, 1069 .main_token = asm_token, 1070 .data = .{ 1071 .lhs = try renderNode(c, payload), 1072 .rhs = try c.addToken(.r_paren, ")"), 1073 }, 1074 }); 1075 }, 1076 .type => { 1077 const payload = node.castTag(.type).?.data; 1078 return c.addNode(.{ 1079 .tag = .identifier, 1080 .main_token = try c.addToken(.identifier, payload), 1081 .data = undefined, 1082 }); 1083 }, 1084 .log2_int_type => { 1085 const payload = node.castTag(.log2_int_type).?.data; 1086 return c.addNode(.{ 1087 .tag = .identifier, 1088 .main_token = try c.addTokenFmt(.identifier, "u{d}", .{payload}), 1089 .data = undefined, 1090 }); 1091 }, 1092 .identifier => { 1093 const payload = node.castTag(.identifier).?.data; 1094 return c.addNode(.{ 1095 .tag = .identifier, 1096 .main_token = try c.addIdentifier(payload), 1097 .data = undefined, 1098 }); 1099 }, 1100 .fn_identifier => { 1101 // C semantics are that a function identifier has address 1102 // value (implicit in stage1, explicit in stage2), except in 1103 // the context of an address_of, which is handled there. 1104 const payload = node.castTag(.fn_identifier).?.data; 1105 const tok = try c.addToken(.ampersand, "&"); 1106 const arg = try c.addNode(.{ 1107 .tag = .identifier, 1108 .main_token = try c.addIdentifier(payload), 1109 .data = undefined, 1110 }); 1111 return c.addNode(.{ 1112 .tag = .address_of, 1113 .main_token = tok, 1114 .data = .{ 1115 .lhs = arg, 1116 .rhs = undefined, 1117 }, 1118 }); 1119 }, 1120 .float_literal => { 1121 const payload = node.castTag(.float_literal).?.data; 1122 return c.addNode(.{ 1123 .tag = .number_literal, 1124 .main_token = try c.addToken(.number_literal, payload), 1125 .data = undefined, 1126 }); 1127 }, 1128 .integer_literal => { 1129 const payload = node.castTag(.integer_literal).?.data; 1130 return c.addNode(.{ 1131 .tag = .number_literal, 1132 .main_token = try c.addToken(.number_literal, payload), 1133 .data = undefined, 1134 }); 1135 }, 1136 .string_literal => { 1137 const payload = node.castTag(.string_literal).?.data; 1138 return c.addNode(.{ 1139 .tag = .string_literal, 1140 .main_token = try c.addToken(.string_literal, payload), 1141 .data = undefined, 1142 }); 1143 }, 1144 .char_literal => { 1145 const payload = node.castTag(.char_literal).?.data; 1146 return c.addNode(.{ 1147 .tag = .char_literal, 1148 .main_token = try c.addToken(.char_literal, payload), 1149 .data = undefined, 1150 }); 1151 }, 1152 .enum_literal => { 1153 const payload = node.castTag(.enum_literal).?.data; 1154 _ = try c.addToken(.period, "."); 1155 return c.addNode(.{ 1156 .tag = .enum_literal, 1157 .main_token = try c.addToken(.identifier, payload), 1158 .data = undefined, 1159 }); 1160 }, 1161 .helpers_macro => { 1162 const payload = node.castTag(.helpers_macro).?.data; 1163 const chain = [_][]const u8{ 1164 "zig", 1165 "c_translation", 1166 "Macros", 1167 payload, 1168 }; 1169 return renderStdImport(c, &chain); 1170 }, 1171 .import_c_builtin => { 1172 const payload = node.castTag(.import_c_builtin).?.data; 1173 const chain = [_][]const u8{ 1174 "zig", 1175 "c_builtins", 1176 payload, 1177 }; 1178 return renderStdImport(c, &chain); 1179 }, 1180 .string_slice => { 1181 const payload = node.castTag(.string_slice).?.data; 1182 1183 const string = try renderNode(c, payload.string); 1184 const l_bracket = try c.addToken(.l_bracket, "["); 1185 const start = try c.addNode(.{ 1186 .tag = .number_literal, 1187 .main_token = try c.addToken(.number_literal, "0"), 1188 .data = undefined, 1189 }); 1190 _ = try c.addToken(.ellipsis2, ".."); 1191 const end = try c.addNode(.{ 1192 .tag = .number_literal, 1193 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{payload.end}), 1194 .data = undefined, 1195 }); 1196 _ = try c.addToken(.r_bracket, "]"); 1197 1198 return c.addNode(.{ 1199 .tag = .slice, 1200 .main_token = l_bracket, 1201 .data = .{ 1202 .lhs = string, 1203 .rhs = try c.addExtra(std.zig.Ast.Node.Slice{ 1204 .start = start, 1205 .end = end, 1206 }), 1207 }, 1208 }); 1209 }, 1210 .fail_decl => { 1211 const payload = node.castTag(.fail_decl).?.data; 1212 // pub const name = @compileError(msg); 1213 _ = try c.addToken(.keyword_pub, "pub"); 1214 const const_tok = try c.addToken(.keyword_const, "const"); 1215 _ = try c.addIdentifier(payload.actual); 1216 _ = try c.addToken(.equal, "="); 1217 1218 const compile_error_tok = try c.addToken(.builtin, "@compileError"); 1219 _ = try c.addToken(.l_paren, "("); 1220 const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(payload.mangled)}); 1221 const err_msg = try c.addNode(.{ 1222 .tag = .string_literal, 1223 .main_token = err_msg_tok, 1224 .data = undefined, 1225 }); 1226 _ = try c.addToken(.r_paren, ")"); 1227 const compile_error = try c.addNode(.{ 1228 .tag = .builtin_call_two, 1229 .main_token = compile_error_tok, 1230 .data = .{ 1231 .lhs = err_msg, 1232 .rhs = 0, 1233 }, 1234 }); 1235 _ = try c.addToken(.semicolon, ";"); 1236 1237 return c.addNode(.{ 1238 .tag = .simple_var_decl, 1239 .main_token = const_tok, 1240 .data = .{ 1241 .lhs = 0, 1242 .rhs = compile_error, 1243 }, 1244 }); 1245 }, 1246 .pub_var_simple, .var_simple => { 1247 const payload = @fieldParentPtr(Payload.SimpleVarDecl, "base", node.ptr_otherwise).data; 1248 if (node.tag() == .pub_var_simple) _ = try c.addToken(.keyword_pub, "pub"); 1249 const const_tok = try c.addToken(.keyword_const, "const"); 1250 _ = try c.addIdentifier(payload.name); 1251 _ = try c.addToken(.equal, "="); 1252 1253 const init = try renderNode(c, payload.init); 1254 _ = try c.addToken(.semicolon, ";"); 1255 1256 return c.addNode(.{ 1257 .tag = .simple_var_decl, 1258 .main_token = const_tok, 1259 .data = .{ 1260 .lhs = 0, 1261 .rhs = init, 1262 }, 1263 }); 1264 }, 1265 .static_local_var => { 1266 const payload = node.castTag(.static_local_var).?.data; 1267 1268 const const_tok = try c.addToken(.keyword_const, "const"); 1269 _ = try c.addIdentifier(payload.name); 1270 _ = try c.addToken(.equal, "="); 1271 1272 const kind_tok = try c.addToken(.keyword_struct, "struct"); 1273 _ = try c.addToken(.l_brace, "{"); 1274 1275 const container_def = try c.addNode(.{ 1276 .tag = .container_decl_two_trailing, 1277 .main_token = kind_tok, 1278 .data = .{ 1279 .lhs = try renderNode(c, payload.init), 1280 .rhs = 0, 1281 }, 1282 }); 1283 _ = try c.addToken(.r_brace, "}"); 1284 _ = try c.addToken(.semicolon, ";"); 1285 1286 return c.addNode(.{ 1287 .tag = .simple_var_decl, 1288 .main_token = const_tok, 1289 .data = .{ 1290 .lhs = 0, 1291 .rhs = container_def, 1292 }, 1293 }); 1294 }, 1295 .mut_str => { 1296 const payload = node.castTag(.mut_str).?.data; 1297 1298 const var_tok = try c.addToken(.keyword_var, "var"); 1299 _ = try c.addIdentifier(payload.name); 1300 _ = try c.addToken(.equal, "="); 1301 1302 const deref = try c.addNode(.{ 1303 .tag = .deref, 1304 .data = .{ 1305 .lhs = try renderNodeGrouped(c, payload.init), 1306 .rhs = undefined, 1307 }, 1308 .main_token = try c.addToken(.period_asterisk, ".*"), 1309 }); 1310 _ = try c.addToken(.semicolon, ";"); 1311 1312 return c.addNode(.{ 1313 .tag = .simple_var_decl, 1314 .main_token = var_tok, 1315 .data = .{ .lhs = 0, .rhs = deref }, 1316 }); 1317 }, 1318 .var_decl => return renderVar(c, node), 1319 .arg_redecl, .alias => { 1320 const payload = @fieldParentPtr(Payload.ArgRedecl, "base", node.ptr_otherwise).data; 1321 if (node.tag() == .alias) _ = try c.addToken(.keyword_pub, "pub"); 1322 const mut_tok = if (node.tag() == .alias) 1323 try c.addToken(.keyword_const, "const") 1324 else 1325 try c.addToken(.keyword_var, "var"); 1326 _ = try c.addIdentifier(payload.actual); 1327 _ = try c.addToken(.equal, "="); 1328 1329 const init = try c.addNode(.{ 1330 .tag = .identifier, 1331 .main_token = try c.addIdentifier(payload.mangled), 1332 .data = undefined, 1333 }); 1334 _ = try c.addToken(.semicolon, ";"); 1335 1336 return c.addNode(.{ 1337 .tag = .simple_var_decl, 1338 .main_token = mut_tok, 1339 .data = .{ 1340 .lhs = 0, 1341 .rhs = init, 1342 }, 1343 }); 1344 }, 1345 .int_cast => { 1346 const payload = node.castTag(.int_cast).?.data; 1347 return renderBuiltinCall(c, "@intCast", &.{ payload.lhs, payload.rhs }); 1348 }, 1349 .signed_remainder => { 1350 const payload = node.castTag(.signed_remainder).?.data; 1351 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "signedRemainder" }); 1352 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 1353 }, 1354 .div_trunc => { 1355 const payload = node.castTag(.div_trunc).?.data; 1356 return renderBuiltinCall(c, "@divTrunc", &.{ payload.lhs, payload.rhs }); 1357 }, 1358 .int_from_bool => { 1359 const payload = node.castTag(.int_from_bool).?.data; 1360 return renderBuiltinCall(c, "@intFromBool", &.{payload}); 1361 }, 1362 .as => { 1363 const payload = node.castTag(.as).?.data; 1364 return renderBuiltinCall(c, "@as", &.{ payload.lhs, payload.rhs }); 1365 }, 1366 .truncate => { 1367 const payload = node.castTag(.truncate).?.data; 1368 return renderBuiltinCall(c, "@truncate", &.{ payload.lhs, payload.rhs }); 1369 }, 1370 .bit_cast => { 1371 const payload = node.castTag(.bit_cast).?.data; 1372 return renderBuiltinCall(c, "@bitCast", &.{ payload.lhs, payload.rhs }); 1373 }, 1374 .float_cast => { 1375 const payload = node.castTag(.float_cast).?.data; 1376 return renderBuiltinCall(c, "@floatCast", &.{ payload.lhs, payload.rhs }); 1377 }, 1378 .int_from_float => { 1379 const payload = node.castTag(.int_from_float).?.data; 1380 return renderBuiltinCall(c, "@intFromFloat", &.{ payload.lhs, payload.rhs }); 1381 }, 1382 .float_from_int => { 1383 const payload = node.castTag(.float_from_int).?.data; 1384 return renderBuiltinCall(c, "@floatFromInt", &.{ payload.lhs, payload.rhs }); 1385 }, 1386 .ptr_from_int => { 1387 const payload = node.castTag(.ptr_from_int).?.data; 1388 return renderBuiltinCall(c, "@ptrFromInt", &.{ payload.lhs, payload.rhs }); 1389 }, 1390 .int_from_ptr => { 1391 const payload = node.castTag(.int_from_ptr).?.data; 1392 return renderBuiltinCall(c, "@intFromPtr", &.{payload}); 1393 }, 1394 .align_cast => { 1395 const payload = node.castTag(.align_cast).?.data; 1396 return renderBuiltinCall(c, "@alignCast", &.{ payload.lhs, payload.rhs }); 1397 }, 1398 .ptr_cast => { 1399 const payload = node.castTag(.ptr_cast).?.data; 1400 return renderBuiltinCall(c, "@ptrCast", &.{ payload.lhs, payload.rhs }); 1401 }, 1402 .div_exact => { 1403 const payload = node.castTag(.div_exact).?.data; 1404 return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs }); 1405 }, 1406 .offset_of => { 1407 const payload = node.castTag(.offset_of).?.data; 1408 return renderBuiltinCall(c, "@offsetOf", &.{ payload.lhs, payload.rhs }); 1409 }, 1410 .sizeof => { 1411 const payload = node.castTag(.sizeof).?.data; 1412 return renderBuiltinCall(c, "@sizeOf", &.{payload}); 1413 }, 1414 .shuffle => { 1415 const payload = node.castTag(.shuffle).?.data; 1416 return renderBuiltinCall(c, "@shuffle", &.{ 1417 payload.element_type, 1418 payload.a, 1419 payload.b, 1420 payload.mask_vector, 1421 }); 1422 }, 1423 .builtin_extern => { 1424 const payload = node.castTag(.builtin_extern).?.data; 1425 1426 var info_inits: [1]Payload.ContainerInitDot.Initializer = .{ 1427 .{ .name = "name", .value = payload.name }, 1428 }; 1429 var info_payload: Payload.ContainerInitDot = .{ 1430 .base = .{ .tag = .container_init_dot }, 1431 .data = &info_inits, 1432 }; 1433 1434 return renderBuiltinCall(c, "@extern", &.{ 1435 payload.type, 1436 .{ .ptr_otherwise = &info_payload.base }, 1437 }); 1438 }, 1439 .macro_arithmetic => { 1440 const payload = node.castTag(.macro_arithmetic).?.data; 1441 const op = @tagName(payload.op); 1442 const import_node = try renderStdImport(c, &.{ "zig", "c_translation", "MacroArithmetic", op }); 1443 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); 1444 }, 1445 .alignof => { 1446 const payload = node.castTag(.alignof).?.data; 1447 return renderBuiltinCall(c, "@alignOf", &.{payload}); 1448 }, 1449 .typeof => { 1450 const payload = node.castTag(.typeof).?.data; 1451 return renderBuiltinCall(c, "@TypeOf", &.{payload}); 1452 }, 1453 .typeinfo => { 1454 const payload = node.castTag(.typeinfo).?.data; 1455 return renderBuiltinCall(c, "@typeInfo", &.{payload}); 1456 }, 1457 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"), 1458 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"), 1459 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"), 1460 .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"), 1461 .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"), 1462 .address_of => { 1463 const payload = node.castTag(.address_of).?.data; 1464 1465 const ampersand = try c.addToken(.ampersand, "&"); 1466 const base = if (payload.tag() == .fn_identifier) 1467 try c.addNode(.{ 1468 .tag = .identifier, 1469 .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), 1470 .data = undefined, 1471 }) 1472 else 1473 try renderNodeGrouped(c, payload); 1474 return c.addNode(.{ 1475 .tag = .address_of, 1476 .main_token = ampersand, 1477 .data = .{ 1478 .lhs = base, 1479 .rhs = undefined, 1480 }, 1481 }); 1482 }, 1483 .deref => { 1484 const payload = node.castTag(.deref).?.data; 1485 const operand = try renderNodeGrouped(c, payload); 1486 const deref_tok = try c.addToken(.period_asterisk, ".*"); 1487 return c.addNode(.{ 1488 .tag = .deref, 1489 .main_token = deref_tok, 1490 .data = .{ 1491 .lhs = operand, 1492 .rhs = undefined, 1493 }, 1494 }); 1495 }, 1496 .unwrap => { 1497 const payload = node.castTag(.unwrap).?.data; 1498 const operand = try renderNodeGrouped(c, payload); 1499 const period = try c.addToken(.period, "."); 1500 const question_mark = try c.addToken(.question_mark, "?"); 1501 return c.addNode(.{ 1502 .tag = .unwrap_optional, 1503 .main_token = period, 1504 .data = .{ 1505 .lhs = operand, 1506 .rhs = question_mark, 1507 }, 1508 }); 1509 }, 1510 .c_pointer, .single_pointer => { 1511 const payload = @fieldParentPtr(Payload.Pointer, "base", node.ptr_otherwise).data; 1512 1513 const asterisk = if (node.tag() == .single_pointer) 1514 try c.addToken(.asterisk, "*") 1515 else blk: { 1516 _ = try c.addToken(.l_bracket, "["); 1517 const res = try c.addToken(.asterisk, "*"); 1518 _ = try c.addIdentifier("c"); 1519 _ = try c.addToken(.r_bracket, "]"); 1520 break :blk res; 1521 }; 1522 if (payload.is_const) _ = try c.addToken(.keyword_const, "const"); 1523 if (payload.is_volatile) _ = try c.addToken(.keyword_volatile, "volatile"); 1524 const elem_type = try renderNodeGrouped(c, payload.elem_type); 1525 1526 return c.addNode(.{ 1527 .tag = .ptr_type_aligned, 1528 .main_token = asterisk, 1529 .data = .{ 1530 .lhs = 0, 1531 .rhs = elem_type, 1532 }, 1533 }); 1534 }, 1535 .add => return renderBinOpGrouped(c, node, .add, .plus, "+"), 1536 .add_assign => return renderBinOp(c, node, .assign_add, .plus_equal, "+="), 1537 .add_wrap => return renderBinOpGrouped(c, node, .add_wrap, .plus_percent, "+%"), 1538 .add_wrap_assign => return renderBinOp(c, node, .assign_add_wrap, .plus_percent_equal, "+%="), 1539 .sub => return renderBinOpGrouped(c, node, .sub, .minus, "-"), 1540 .sub_assign => return renderBinOp(c, node, .assign_sub, .minus_equal, "-="), 1541 .sub_wrap => return renderBinOpGrouped(c, node, .sub_wrap, .minus_percent, "-%"), 1542 .sub_wrap_assign => return renderBinOp(c, node, .assign_sub_wrap, .minus_percent_equal, "-%="), 1543 .mul => return renderBinOpGrouped(c, node, .mul, .asterisk, "*"), 1544 .mul_assign => return renderBinOp(c, node, .assign_mul, .asterisk_equal, "*="), 1545 .mul_wrap => return renderBinOpGrouped(c, node, .mul_wrap, .asterisk_percent, "*%"), 1546 .mul_wrap_assign => return renderBinOp(c, node, .assign_mul_wrap, .asterisk_percent_equal, "*%="), 1547 .div => return renderBinOpGrouped(c, node, .div, .slash, "/"), 1548 .div_assign => return renderBinOp(c, node, .assign_div, .slash_equal, "/="), 1549 .shl => return renderBinOpGrouped(c, node, .shl, .angle_bracket_angle_bracket_left, "<<"), 1550 .shl_assign => return renderBinOp(c, node, .assign_shl, .angle_bracket_angle_bracket_left_equal, "<<="), 1551 .shr => return renderBinOpGrouped(c, node, .shr, .angle_bracket_angle_bracket_right, ">>"), 1552 .shr_assign => return renderBinOp(c, node, .assign_shr, .angle_bracket_angle_bracket_right_equal, ">>="), 1553 .mod => return renderBinOpGrouped(c, node, .mod, .percent, "%"), 1554 .mod_assign => return renderBinOp(c, node, .assign_mod, .percent_equal, "%="), 1555 .@"and" => return renderBinOpGrouped(c, node, .bool_and, .keyword_and, "and"), 1556 .@"or" => return renderBinOpGrouped(c, node, .bool_or, .keyword_or, "or"), 1557 .less_than => return renderBinOpGrouped(c, node, .less_than, .angle_bracket_left, "<"), 1558 .less_than_equal => return renderBinOpGrouped(c, node, .less_or_equal, .angle_bracket_left_equal, "<="), 1559 .greater_than => return renderBinOpGrouped(c, node, .greater_than, .angle_bracket_right, ">="), 1560 .greater_than_equal => return renderBinOpGrouped(c, node, .greater_or_equal, .angle_bracket_right_equal, ">="), 1561 .equal => return renderBinOpGrouped(c, node, .equal_equal, .equal_equal, "=="), 1562 .not_equal => return renderBinOpGrouped(c, node, .bang_equal, .bang_equal, "!="), 1563 .bit_and => return renderBinOpGrouped(c, node, .bit_and, .ampersand, "&"), 1564 .bit_and_assign => return renderBinOp(c, node, .assign_bit_and, .ampersand_equal, "&="), 1565 .bit_or => return renderBinOpGrouped(c, node, .bit_or, .pipe, "|"), 1566 .bit_or_assign => return renderBinOp(c, node, .assign_bit_or, .pipe_equal, "|="), 1567 .bit_xor => return renderBinOpGrouped(c, node, .bit_xor, .caret, "^"), 1568 .bit_xor_assign => return renderBinOp(c, node, .assign_bit_xor, .caret_equal, "^="), 1569 .array_cat => return renderBinOp(c, node, .array_cat, .plus_plus, "++"), 1570 .ellipsis3 => return renderBinOpGrouped(c, node, .switch_range, .ellipsis3, "..."), 1571 .assign => return renderBinOp(c, node, .assign, .equal, "="), 1572 .empty_block => { 1573 const l_brace = try c.addToken(.l_brace, "{"); 1574 _ = try c.addToken(.r_brace, "}"); 1575 return c.addNode(.{ 1576 .tag = .block_two, 1577 .main_token = l_brace, 1578 .data = .{ 1579 .lhs = 0, 1580 .rhs = 0, 1581 }, 1582 }); 1583 }, 1584 .block_single => { 1585 const payload = node.castTag(.block_single).?.data; 1586 const l_brace = try c.addToken(.l_brace, "{"); 1587 1588 const stmt = try renderNode(c, payload); 1589 try addSemicolonIfNeeded(c, payload); 1590 1591 _ = try c.addToken(.r_brace, "}"); 1592 return c.addNode(.{ 1593 .tag = .block_two_semicolon, 1594 .main_token = l_brace, 1595 .data = .{ 1596 .lhs = stmt, 1597 .rhs = 0, 1598 }, 1599 }); 1600 }, 1601 .block => { 1602 const payload = node.castTag(.block).?.data; 1603 if (payload.label) |some| { 1604 _ = try c.addIdentifier(some); 1605 _ = try c.addToken(.colon, ":"); 1606 } 1607 const l_brace = try c.addToken(.l_brace, "{"); 1608 1609 var stmts = std.ArrayList(NodeIndex).init(c.gpa); 1610 defer stmts.deinit(); 1611 for (payload.stmts) |stmt| { 1612 const res = try renderNode(c, stmt); 1613 if (res == 0) continue; 1614 try addSemicolonIfNeeded(c, stmt); 1615 try stmts.append(res); 1616 } 1617 const span = try c.listToSpan(stmts.items); 1618 _ = try c.addToken(.r_brace, "}"); 1619 1620 const semicolon = c.tokens.items(.tag)[c.tokens.len - 2] == .semicolon; 1621 return c.addNode(.{ 1622 .tag = if (semicolon) .block_semicolon else .block, 1623 .main_token = l_brace, 1624 .data = .{ 1625 .lhs = span.start, 1626 .rhs = span.end, 1627 }, 1628 }); 1629 }, 1630 .func => return renderFunc(c, node), 1631 .pub_inline_fn => return renderMacroFunc(c, node), 1632 .discard => { 1633 const payload = node.castTag(.discard).?.data; 1634 if (payload.should_skip) return @as(NodeIndex, 0); 1635 1636 const lhs = try c.addNode(.{ 1637 .tag = .identifier, 1638 .main_token = try c.addToken(.identifier, "_"), 1639 .data = undefined, 1640 }); 1641 const main_token = try c.addToken(.equal, "="); 1642 if (payload.value.tag() == .identifier) { 1643 // Render as `_ = @TypeOf(foo);` to avoid tripping "pointless discard" error. 1644 return c.addNode(.{ 1645 .tag = .assign, 1646 .main_token = main_token, 1647 .data = .{ 1648 .lhs = lhs, 1649 .rhs = try renderBuiltinCall(c, "@TypeOf", &.{payload.value}), 1650 }, 1651 }); 1652 } else { 1653 return c.addNode(.{ 1654 .tag = .assign, 1655 .main_token = main_token, 1656 .data = .{ 1657 .lhs = lhs, 1658 .rhs = try renderNode(c, payload.value), 1659 }, 1660 }); 1661 } 1662 }, 1663 .@"while" => { 1664 const payload = node.castTag(.@"while").?.data; 1665 const while_tok = try c.addToken(.keyword_while, "while"); 1666 _ = try c.addToken(.l_paren, "("); 1667 const cond = try renderNode(c, payload.cond); 1668 _ = try c.addToken(.r_paren, ")"); 1669 1670 const cont_expr = if (payload.cont_expr) |some| blk: { 1671 _ = try c.addToken(.colon, ":"); 1672 _ = try c.addToken(.l_paren, "("); 1673 const res = try renderNode(c, some); 1674 _ = try c.addToken(.r_paren, ")"); 1675 break :blk res; 1676 } else 0; 1677 const body = try renderNode(c, payload.body); 1678 1679 if (cont_expr == 0) { 1680 return c.addNode(.{ 1681 .tag = .while_simple, 1682 .main_token = while_tok, 1683 .data = .{ 1684 .lhs = cond, 1685 .rhs = body, 1686 }, 1687 }); 1688 } else { 1689 return c.addNode(.{ 1690 .tag = .while_cont, 1691 .main_token = while_tok, 1692 .data = .{ 1693 .lhs = cond, 1694 .rhs = try c.addExtra(std.zig.Ast.Node.WhileCont{ 1695 .cont_expr = cont_expr, 1696 .then_expr = body, 1697 }), 1698 }, 1699 }); 1700 } 1701 }, 1702 .while_true => { 1703 const payload = node.castTag(.while_true).?.data; 1704 const while_tok = try c.addToken(.keyword_while, "while"); 1705 _ = try c.addToken(.l_paren, "("); 1706 const cond = try c.addNode(.{ 1707 .tag = .identifier, 1708 .main_token = try c.addToken(.identifier, "true"), 1709 .data = undefined, 1710 }); 1711 _ = try c.addToken(.r_paren, ")"); 1712 const body = try renderNode(c, payload); 1713 1714 return c.addNode(.{ 1715 .tag = .while_simple, 1716 .main_token = while_tok, 1717 .data = .{ 1718 .lhs = cond, 1719 .rhs = body, 1720 }, 1721 }); 1722 }, 1723 .@"if" => { 1724 const payload = node.castTag(.@"if").?.data; 1725 const if_tok = try c.addToken(.keyword_if, "if"); 1726 _ = try c.addToken(.l_paren, "("); 1727 const cond = try renderNode(c, payload.cond); 1728 _ = try c.addToken(.r_paren, ")"); 1729 1730 const then_expr = try renderNode(c, payload.then); 1731 const else_node = payload.@"else" orelse return c.addNode(.{ 1732 .tag = .if_simple, 1733 .main_token = if_tok, 1734 .data = .{ 1735 .lhs = cond, 1736 .rhs = then_expr, 1737 }, 1738 }); 1739 _ = try c.addToken(.keyword_else, "else"); 1740 const else_expr = try renderNode(c, else_node); 1741 1742 return c.addNode(.{ 1743 .tag = .@"if", 1744 .main_token = if_tok, 1745 .data = .{ 1746 .lhs = cond, 1747 .rhs = try c.addExtra(std.zig.Ast.Node.If{ 1748 .then_expr = then_expr, 1749 .else_expr = else_expr, 1750 }), 1751 }, 1752 }); 1753 }, 1754 .if_not_break => { 1755 const payload = node.castTag(.if_not_break).?.data; 1756 const if_tok = try c.addToken(.keyword_if, "if"); 1757 _ = try c.addToken(.l_paren, "("); 1758 const cond = try c.addNode(.{ 1759 .tag = .bool_not, 1760 .main_token = try c.addToken(.bang, "!"), 1761 .data = .{ 1762 .lhs = try renderNodeGrouped(c, payload), 1763 .rhs = undefined, 1764 }, 1765 }); 1766 _ = try c.addToken(.r_paren, ")"); 1767 const then_expr = try c.addNode(.{ 1768 .tag = .@"break", 1769 .main_token = try c.addToken(.keyword_break, "break"), 1770 .data = .{ 1771 .lhs = 0, 1772 .rhs = 0, 1773 }, 1774 }); 1775 1776 return c.addNode(.{ 1777 .tag = .if_simple, 1778 .main_token = if_tok, 1779 .data = .{ 1780 .lhs = cond, 1781 .rhs = then_expr, 1782 }, 1783 }); 1784 }, 1785 .@"switch" => { 1786 const payload = node.castTag(.@"switch").?.data; 1787 const switch_tok = try c.addToken(.keyword_switch, "switch"); 1788 _ = try c.addToken(.l_paren, "("); 1789 const cond = try renderNode(c, payload.cond); 1790 _ = try c.addToken(.r_paren, ")"); 1791 1792 _ = try c.addToken(.l_brace, "{"); 1793 var cases = try c.gpa.alloc(NodeIndex, payload.cases.len); 1794 defer c.gpa.free(cases); 1795 for (payload.cases, 0..) |case, i| { 1796 cases[i] = try renderNode(c, case); 1797 _ = try c.addToken(.comma, ","); 1798 } 1799 const span = try c.listToSpan(cases); 1800 _ = try c.addToken(.r_brace, "}"); 1801 return c.addNode(.{ 1802 .tag = .switch_comma, 1803 .main_token = switch_tok, 1804 .data = .{ 1805 .lhs = cond, 1806 .rhs = try c.addExtra(NodeSubRange{ 1807 .start = span.start, 1808 .end = span.end, 1809 }), 1810 }, 1811 }); 1812 }, 1813 .switch_else => { 1814 const payload = node.castTag(.switch_else).?.data; 1815 _ = try c.addToken(.keyword_else, "else"); 1816 return c.addNode(.{ 1817 .tag = .switch_case_one, 1818 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"), 1819 .data = .{ 1820 .lhs = 0, 1821 .rhs = try renderNode(c, payload), 1822 }, 1823 }); 1824 }, 1825 .switch_prong => { 1826 const payload = node.castTag(.switch_prong).?.data; 1827 var items = try c.gpa.alloc(NodeIndex, @max(payload.cases.len, 1)); 1828 defer c.gpa.free(items); 1829 items[0] = 0; 1830 for (payload.cases, 0..) |item, i| { 1831 if (i != 0) _ = try c.addToken(.comma, ","); 1832 items[i] = try renderNode(c, item); 1833 } 1834 _ = try c.addToken(.r_brace, "}"); 1835 if (items.len < 2) { 1836 return c.addNode(.{ 1837 .tag = .switch_case_one, 1838 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"), 1839 .data = .{ 1840 .lhs = items[0], 1841 .rhs = try renderNode(c, payload.cond), 1842 }, 1843 }); 1844 } else { 1845 const span = try c.listToSpan(items); 1846 return c.addNode(.{ 1847 .tag = .switch_case, 1848 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"), 1849 .data = .{ 1850 .lhs = try c.addExtra(NodeSubRange{ 1851 .start = span.start, 1852 .end = span.end, 1853 }), 1854 .rhs = try renderNode(c, payload.cond), 1855 }, 1856 }); 1857 } 1858 }, 1859 .opaque_literal => { 1860 const opaque_tok = try c.addToken(.keyword_opaque, "opaque"); 1861 _ = try c.addToken(.l_brace, "{"); 1862 _ = try c.addToken(.r_brace, "}"); 1863 1864 return c.addNode(.{ 1865 .tag = .container_decl_two, 1866 .main_token = opaque_tok, 1867 .data = .{ 1868 .lhs = 0, 1869 .rhs = 0, 1870 }, 1871 }); 1872 }, 1873 .array_access => { 1874 const payload = node.castTag(.array_access).?.data; 1875 const lhs = try renderNodeGrouped(c, payload.lhs); 1876 const l_bracket = try c.addToken(.l_bracket, "["); 1877 const index_expr = try renderNode(c, payload.rhs); 1878 _ = try c.addToken(.r_bracket, "]"); 1879 return c.addNode(.{ 1880 .tag = .array_access, 1881 .main_token = l_bracket, 1882 .data = .{ 1883 .lhs = lhs, 1884 .rhs = index_expr, 1885 }, 1886 }); 1887 }, 1888 .array_type => { 1889 const payload = node.castTag(.array_type).?.data; 1890 return renderArrayType(c, payload.len, payload.elem_type); 1891 }, 1892 .null_sentinel_array_type => { 1893 const payload = node.castTag(.null_sentinel_array_type).?.data; 1894 return renderNullSentinelArrayType(c, payload.len, payload.elem_type); 1895 }, 1896 .array_filler => { 1897 const payload = node.castTag(.array_filler).?.data; 1898 1899 const type_expr = try renderArrayType(c, 1, payload.type); 1900 const l_brace = try c.addToken(.l_brace, "{"); 1901 const val = try renderNode(c, payload.filler); 1902 _ = try c.addToken(.r_brace, "}"); 1903 1904 const init = try c.addNode(.{ 1905 .tag = .array_init_one, 1906 .main_token = l_brace, 1907 .data = .{ 1908 .lhs = type_expr, 1909 .rhs = val, 1910 }, 1911 }); 1912 return c.addNode(.{ 1913 .tag = .array_cat, 1914 .main_token = try c.addToken(.asterisk_asterisk, "**"), 1915 .data = .{ 1916 .lhs = init, 1917 .rhs = try c.addNode(.{ 1918 .tag = .number_literal, 1919 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{payload.count}), 1920 .data = undefined, 1921 }), 1922 }, 1923 }); 1924 }, 1925 .empty_array => { 1926 const payload = node.castTag(.empty_array).?.data; 1927 1928 const type_expr = try renderArrayType(c, 0, payload); 1929 return renderArrayInit(c, type_expr, &.{}); 1930 }, 1931 .array_init => { 1932 const payload = node.castTag(.array_init).?.data; 1933 const type_expr = try renderNode(c, payload.cond); 1934 return renderArrayInit(c, type_expr, payload.cases); 1935 }, 1936 .vector_zero_init => { 1937 const payload = node.castTag(.vector_zero_init).?.data; 1938 return renderBuiltinCall(c, "@splat", &.{ payload.lhs, payload.rhs }); 1939 }, 1940 .field_access => { 1941 const payload = node.castTag(.field_access).?.data; 1942 const lhs = try renderNodeGrouped(c, payload.lhs); 1943 return renderFieldAccess(c, lhs, payload.field_name); 1944 }, 1945 .@"struct", .@"union" => return renderRecord(c, node), 1946 .enum_constant => { 1947 const payload = node.castTag(.enum_constant).?.data; 1948 1949 if (payload.is_public) _ = try c.addToken(.keyword_pub, "pub"); 1950 const const_tok = try c.addToken(.keyword_const, "const"); 1951 _ = try c.addIdentifier(payload.name); 1952 1953 const type_node = if (payload.type) |enum_const_type| blk: { 1954 _ = try c.addToken(.colon, ":"); 1955 break :blk try renderNode(c, enum_const_type); 1956 } else 0; 1957 1958 _ = try c.addToken(.equal, "="); 1959 1960 const init_node = try renderNode(c, payload.value); 1961 _ = try c.addToken(.semicolon, ";"); 1962 1963 return c.addNode(.{ 1964 .tag = .simple_var_decl, 1965 .main_token = const_tok, 1966 .data = .{ 1967 .lhs = type_node, 1968 .rhs = init_node, 1969 }, 1970 }); 1971 }, 1972 .tuple => { 1973 const payload = node.castTag(.tuple).?.data; 1974 _ = try c.addToken(.period, "."); 1975 const l_brace = try c.addToken(.l_brace, "{"); 1976 var inits = try c.gpa.alloc(NodeIndex, @max(payload.len, 2)); 1977 defer c.gpa.free(inits); 1978 inits[0] = 0; 1979 inits[1] = 0; 1980 for (payload, 0..) |init, i| { 1981 if (i != 0) _ = try c.addToken(.comma, ","); 1982 inits[i] = try renderNode(c, init); 1983 } 1984 _ = try c.addToken(.r_brace, "}"); 1985 if (payload.len < 3) { 1986 return c.addNode(.{ 1987 .tag = .array_init_dot_two, 1988 .main_token = l_brace, 1989 .data = .{ 1990 .lhs = inits[0], 1991 .rhs = inits[1], 1992 }, 1993 }); 1994 } else { 1995 const span = try c.listToSpan(inits); 1996 return c.addNode(.{ 1997 .tag = .array_init_dot, 1998 .main_token = l_brace, 1999 .data = .{ 2000 .lhs = span.start, 2001 .rhs = span.end, 2002 }, 2003 }); 2004 } 2005 }, 2006 .container_init_dot => { 2007 const payload = node.castTag(.container_init_dot).?.data; 2008 _ = try c.addToken(.period, "."); 2009 const l_brace = try c.addToken(.l_brace, "{"); 2010 var inits = try c.gpa.alloc(NodeIndex, @max(payload.len, 2)); 2011 defer c.gpa.free(inits); 2012 inits[0] = 0; 2013 inits[1] = 0; 2014 for (payload, 0..) |init, i| { 2015 _ = try c.addToken(.period, "."); 2016 _ = try c.addIdentifier(init.name); 2017 _ = try c.addToken(.equal, "="); 2018 inits[i] = try renderNode(c, init.value); 2019 _ = try c.addToken(.comma, ","); 2020 } 2021 _ = try c.addToken(.r_brace, "}"); 2022 2023 if (payload.len < 3) { 2024 return c.addNode(.{ 2025 .tag = .struct_init_dot_two_comma, 2026 .main_token = l_brace, 2027 .data = .{ 2028 .lhs = inits[0], 2029 .rhs = inits[1], 2030 }, 2031 }); 2032 } else { 2033 const span = try c.listToSpan(inits); 2034 return c.addNode(.{ 2035 .tag = .struct_init_dot_comma, 2036 .main_token = l_brace, 2037 .data = .{ 2038 .lhs = span.start, 2039 .rhs = span.end, 2040 }, 2041 }); 2042 } 2043 }, 2044 .container_init => { 2045 const payload = node.castTag(.container_init).?.data; 2046 const lhs = try renderNode(c, payload.lhs); 2047 2048 const l_brace = try c.addToken(.l_brace, "{"); 2049 var inits = try c.gpa.alloc(NodeIndex, @max(payload.inits.len, 1)); 2050 defer c.gpa.free(inits); 2051 inits[0] = 0; 2052 for (payload.inits, 0..) |init, i| { 2053 _ = try c.addToken(.period, "."); 2054 _ = try c.addIdentifier(init.name); 2055 _ = try c.addToken(.equal, "="); 2056 inits[i] = try renderNode(c, init.value); 2057 _ = try c.addToken(.comma, ","); 2058 } 2059 _ = try c.addToken(.r_brace, "}"); 2060 2061 if (payload.inits.len < 2) { 2062 return c.addNode(.{ 2063 .tag = .struct_init_one_comma, 2064 .main_token = l_brace, 2065 .data = .{ 2066 .lhs = lhs, 2067 .rhs = inits[0], 2068 }, 2069 }); 2070 } else { 2071 const span = try c.listToSpan(inits); 2072 return c.addNode(.{ 2073 .tag = .struct_init_comma, 2074 .main_token = l_brace, 2075 .data = .{ 2076 .lhs = lhs, 2077 .rhs = try c.addExtra(NodeSubRange{ 2078 .start = span.start, 2079 .end = span.end, 2080 }), 2081 }, 2082 }); 2083 } 2084 }, 2085 .@"anytype" => unreachable, // Handled in renderParams 2086 } 2087 } 2088 2089 fn renderRecord(c: *Context, node: Node) !NodeIndex { 2090 const payload = @fieldParentPtr(Payload.Record, "base", node.ptr_otherwise).data; 2091 if (payload.layout == .@"packed") 2092 _ = try c.addToken(.keyword_packed, "packed") 2093 else if (payload.layout == .@"extern") 2094 _ = try c.addToken(.keyword_extern, "extern"); 2095 const kind_tok = if (node.tag() == .@"struct") 2096 try c.addToken(.keyword_struct, "struct") 2097 else 2098 try c.addToken(.keyword_union, "union"); 2099 2100 _ = try c.addToken(.l_brace, "{"); 2101 2102 const num_vars = payload.variables.len; 2103 const num_funcs = payload.functions.len; 2104 const total_members = payload.fields.len + num_vars + num_funcs; 2105 const members = try c.gpa.alloc(NodeIndex, @max(total_members, 2)); 2106 defer c.gpa.free(members); 2107 members[0] = 0; 2108 members[1] = 0; 2109 2110 for (payload.fields, 0..) |field, i| { 2111 const name_tok = try c.addTokenFmt(.identifier, "{s}", .{std.zig.fmtId(field.name)}); 2112 _ = try c.addToken(.colon, ":"); 2113 const type_expr = try renderNode(c, field.type); 2114 2115 const alignment = field.alignment orelse { 2116 members[i] = try c.addNode(.{ 2117 .tag = .container_field_init, 2118 .main_token = name_tok, 2119 .data = .{ 2120 .lhs = type_expr, 2121 .rhs = 0, 2122 }, 2123 }); 2124 _ = try c.addToken(.comma, ","); 2125 continue; 2126 }; 2127 _ = try c.addToken(.keyword_align, "align"); 2128 _ = try c.addToken(.l_paren, "("); 2129 const align_expr = try c.addNode(.{ 2130 .tag = .number_literal, 2131 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{alignment}), 2132 .data = undefined, 2133 }); 2134 _ = try c.addToken(.r_paren, ")"); 2135 2136 members[i] = try c.addNode(.{ 2137 .tag = .container_field_align, 2138 .main_token = name_tok, 2139 .data = .{ 2140 .lhs = type_expr, 2141 .rhs = align_expr, 2142 }, 2143 }); 2144 _ = try c.addToken(.comma, ","); 2145 } 2146 for (payload.variables, 0..) |variable, i| { 2147 members[payload.fields.len + i] = try renderNode(c, variable); 2148 } 2149 for (payload.functions, 0..) |function, i| { 2150 members[payload.fields.len + num_vars + i] = try renderNode(c, function); 2151 } 2152 _ = try c.addToken(.r_brace, "}"); 2153 2154 if (total_members == 0) { 2155 return c.addNode(.{ 2156 .tag = .container_decl_two, 2157 .main_token = kind_tok, 2158 .data = .{ 2159 .lhs = 0, 2160 .rhs = 0, 2161 }, 2162 }); 2163 } else if (total_members <= 2) { 2164 return c.addNode(.{ 2165 .tag = if (num_funcs == 0) .container_decl_two_trailing else .container_decl_two, 2166 .main_token = kind_tok, 2167 .data = .{ 2168 .lhs = members[0], 2169 .rhs = members[1], 2170 }, 2171 }); 2172 } else { 2173 const span = try c.listToSpan(members); 2174 return c.addNode(.{ 2175 .tag = if (num_funcs == 0) .container_decl_trailing else .container_decl, 2176 .main_token = kind_tok, 2177 .data = .{ 2178 .lhs = span.start, 2179 .rhs = span.end, 2180 }, 2181 }); 2182 } 2183 } 2184 2185 fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeIndex { 2186 return c.addNode(.{ 2187 .tag = .field_access, 2188 .main_token = try c.addToken(.period, "."), 2189 .data = .{ 2190 .lhs = lhs, 2191 .rhs = try c.addTokenFmt(.identifier, "{s}", .{std.zig.fmtId(field_name)}), 2192 }, 2193 }); 2194 } 2195 2196 fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex { 2197 const l_brace = try c.addToken(.l_brace, "{"); 2198 var rendered = try c.gpa.alloc(NodeIndex, @max(inits.len, 1)); 2199 defer c.gpa.free(rendered); 2200 rendered[0] = 0; 2201 for (inits, 0..) |init, i| { 2202 rendered[i] = try renderNode(c, init); 2203 _ = try c.addToken(.comma, ","); 2204 } 2205 _ = try c.addToken(.r_brace, "}"); 2206 if (inits.len < 2) { 2207 return c.addNode(.{ 2208 .tag = .array_init_one_comma, 2209 .main_token = l_brace, 2210 .data = .{ 2211 .lhs = lhs, 2212 .rhs = rendered[0], 2213 }, 2214 }); 2215 } else { 2216 const span = try c.listToSpan(rendered); 2217 return c.addNode(.{ 2218 .tag = .array_init_comma, 2219 .main_token = l_brace, 2220 .data = .{ 2221 .lhs = lhs, 2222 .rhs = try c.addExtra(NodeSubRange{ 2223 .start = span.start, 2224 .end = span.end, 2225 }), 2226 }, 2227 }); 2228 } 2229 } 2230 2231 fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex { 2232 const l_bracket = try c.addToken(.l_bracket, "["); 2233 const len_expr = try c.addNode(.{ 2234 .tag = .number_literal, 2235 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{len}), 2236 .data = undefined, 2237 }); 2238 _ = try c.addToken(.r_bracket, "]"); 2239 const elem_type_expr = try renderNode(c, elem_type); 2240 return c.addNode(.{ 2241 .tag = .array_type, 2242 .main_token = l_bracket, 2243 .data = .{ 2244 .lhs = len_expr, 2245 .rhs = elem_type_expr, 2246 }, 2247 }); 2248 } 2249 2250 fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex { 2251 const l_bracket = try c.addToken(.l_bracket, "["); 2252 const len_expr = try c.addNode(.{ 2253 .tag = .number_literal, 2254 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{len}), 2255 .data = undefined, 2256 }); 2257 _ = try c.addToken(.colon, ":"); 2258 2259 const sentinel_expr = try c.addNode(.{ 2260 .tag = .number_literal, 2261 .main_token = try c.addToken(.number_literal, "0"), 2262 .data = undefined, 2263 }); 2264 2265 _ = try c.addToken(.r_bracket, "]"); 2266 const elem_type_expr = try renderNode(c, elem_type); 2267 return c.addNode(.{ 2268 .tag = .array_type_sentinel, 2269 .main_token = l_bracket, 2270 .data = .{ 2271 .lhs = len_expr, 2272 .rhs = try c.addExtra(std.zig.Ast.Node.ArrayTypeSentinel{ 2273 .sentinel = sentinel_expr, 2274 .elem_type = elem_type_expr, 2275 }), 2276 }, 2277 }); 2278 } 2279 2280 fn addSemicolonIfNeeded(c: *Context, node: Node) !void { 2281 switch (node.tag()) { 2282 .warning => unreachable, 2283 .var_decl, .var_simple, .arg_redecl, .alias, .block, .empty_block, .block_single, .@"switch", .static_local_var, .mut_str => {}, 2284 .while_true => { 2285 const payload = node.castTag(.while_true).?.data; 2286 return addSemicolonIfNotBlock(c, payload); 2287 }, 2288 .@"while" => { 2289 const payload = node.castTag(.@"while").?.data; 2290 return addSemicolonIfNotBlock(c, payload.body); 2291 }, 2292 .@"if" => { 2293 const payload = node.castTag(.@"if").?.data; 2294 if (payload.@"else") |some| 2295 return addSemicolonIfNeeded(c, some); 2296 return addSemicolonIfNotBlock(c, payload.then); 2297 }, 2298 else => _ = try c.addToken(.semicolon, ";"), 2299 } 2300 } 2301 2302 fn addSemicolonIfNotBlock(c: *Context, node: Node) !void { 2303 switch (node.tag()) { 2304 .block, .empty_block, .block_single => {}, 2305 else => _ = try c.addToken(.semicolon, ";"), 2306 } 2307 } 2308 2309 fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { 2310 switch (node.tag()) { 2311 .declaration => unreachable, 2312 .null_literal, 2313 .undefined_literal, 2314 .true_literal, 2315 .false_literal, 2316 .return_void, 2317 .zero_literal, 2318 .one_literal, 2319 .void_type, 2320 .noreturn_type, 2321 .@"anytype", 2322 .div_trunc, 2323 .signed_remainder, 2324 .int_cast, 2325 .as, 2326 .truncate, 2327 .bit_cast, 2328 .float_cast, 2329 .int_from_float, 2330 .float_from_int, 2331 .ptr_from_int, 2332 .std_mem_zeroes, 2333 .std_math_Log2Int, 2334 .log2_int_type, 2335 .int_from_ptr, 2336 .sizeof, 2337 .alignof, 2338 .typeof, 2339 .typeinfo, 2340 .std_meta_alignment, 2341 .vector, 2342 .helpers_sizeof, 2343 .helpers_cast, 2344 .helpers_promoteIntLiteral, 2345 .helpers_shuffle_vector_index, 2346 .helpers_flexible_array_type, 2347 .std_mem_zeroinit, 2348 .integer_literal, 2349 .float_literal, 2350 .string_literal, 2351 .string_slice, 2352 .char_literal, 2353 .enum_literal, 2354 .identifier, 2355 .fn_identifier, 2356 .field_access, 2357 .ptr_cast, 2358 .type, 2359 .array_access, 2360 .align_cast, 2361 .optional_type, 2362 .c_pointer, 2363 .single_pointer, 2364 .unwrap, 2365 .deref, 2366 .not, 2367 .negate, 2368 .negate_wrap, 2369 .bit_not, 2370 .func, 2371 .call, 2372 .array_type, 2373 .null_sentinel_array_type, 2374 .int_from_bool, 2375 .div_exact, 2376 .offset_of, 2377 .shuffle, 2378 .builtin_extern, 2379 .static_local_var, 2380 .mut_str, 2381 .macro_arithmetic, 2382 => { 2383 // no grouping needed 2384 return renderNode(c, node); 2385 }, 2386 2387 .opaque_literal, 2388 .empty_array, 2389 .block_single, 2390 .add, 2391 .add_wrap, 2392 .sub, 2393 .sub_wrap, 2394 .mul, 2395 .mul_wrap, 2396 .div, 2397 .shl, 2398 .shr, 2399 .mod, 2400 .@"and", 2401 .@"or", 2402 .less_than, 2403 .less_than_equal, 2404 .greater_than, 2405 .greater_than_equal, 2406 .equal, 2407 .not_equal, 2408 .bit_and, 2409 .bit_or, 2410 .bit_xor, 2411 .empty_block, 2412 .array_cat, 2413 .array_filler, 2414 .@"if", 2415 .@"struct", 2416 .@"union", 2417 .array_init, 2418 .vector_zero_init, 2419 .tuple, 2420 .container_init, 2421 .container_init_dot, 2422 .block, 2423 .address_of, 2424 => return c.addNode(.{ 2425 .tag = .grouped_expression, 2426 .main_token = try c.addToken(.l_paren, "("), 2427 .data = .{ 2428 .lhs = try renderNode(c, node), 2429 .rhs = try c.addToken(.r_paren, ")"), 2430 }, 2431 }), 2432 .ellipsis3, 2433 .switch_prong, 2434 .warning, 2435 .var_decl, 2436 .fail_decl, 2437 .arg_redecl, 2438 .alias, 2439 .var_simple, 2440 .pub_var_simple, 2441 .enum_constant, 2442 .@"while", 2443 .@"switch", 2444 .@"break", 2445 .break_val, 2446 .pub_inline_fn, 2447 .discard, 2448 .@"continue", 2449 .@"return", 2450 .@"comptime", 2451 .@"defer", 2452 .asm_simple, 2453 .while_true, 2454 .if_not_break, 2455 .switch_else, 2456 .add_assign, 2457 .add_wrap_assign, 2458 .sub_assign, 2459 .sub_wrap_assign, 2460 .mul_assign, 2461 .mul_wrap_assign, 2462 .div_assign, 2463 .shl_assign, 2464 .shr_assign, 2465 .mod_assign, 2466 .bit_and_assign, 2467 .bit_or_assign, 2468 .bit_xor_assign, 2469 .assign, 2470 .helpers_macro, 2471 .import_c_builtin, 2472 => { 2473 // these should never appear in places where grouping might be needed. 2474 unreachable; 2475 }, 2476 } 2477 } 2478 2479 fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { 2480 const payload = @fieldParentPtr(Payload.UnOp, "base", node.ptr_otherwise).data; 2481 return c.addNode(.{ 2482 .tag = tag, 2483 .main_token = try c.addToken(tok_tag, bytes), 2484 .data = .{ 2485 .lhs = try renderNodeGrouped(c, payload), 2486 .rhs = undefined, 2487 }, 2488 }); 2489 } 2490 2491 fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { 2492 const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data; 2493 const lhs = try renderNodeGrouped(c, payload.lhs); 2494 return c.addNode(.{ 2495 .tag = tag, 2496 .main_token = try c.addToken(tok_tag, bytes), 2497 .data = .{ 2498 .lhs = lhs, 2499 .rhs = try renderNodeGrouped(c, payload.rhs), 2500 }, 2501 }); 2502 } 2503 2504 fn renderBinOp(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { 2505 const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data; 2506 const lhs = try renderNode(c, payload.lhs); 2507 return c.addNode(.{ 2508 .tag = tag, 2509 .main_token = try c.addToken(tok_tag, bytes), 2510 .data = .{ 2511 .lhs = lhs, 2512 .rhs = try renderNode(c, payload.rhs), 2513 }, 2514 }); 2515 } 2516 2517 fn renderStdImport(c: *Context, parts: []const []const u8) !NodeIndex { 2518 const import_tok = try c.addToken(.builtin, "@import"); 2519 _ = try c.addToken(.l_paren, "("); 2520 const std_tok = try c.addToken(.string_literal, "\"std\""); 2521 const std_node = try c.addNode(.{ 2522 .tag = .string_literal, 2523 .main_token = std_tok, 2524 .data = undefined, 2525 }); 2526 _ = try c.addToken(.r_paren, ")"); 2527 2528 const import_node = try c.addNode(.{ 2529 .tag = .builtin_call_two, 2530 .main_token = import_tok, 2531 .data = .{ 2532 .lhs = std_node, 2533 .rhs = 0, 2534 }, 2535 }); 2536 2537 var access_chain = import_node; 2538 for (parts) |part| { 2539 access_chain = try renderFieldAccess(c, access_chain, part); 2540 } 2541 return access_chain; 2542 } 2543 2544 fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex { 2545 const lparen = try c.addToken(.l_paren, "("); 2546 const res = switch (args.len) { 2547 0 => try c.addNode(.{ 2548 .tag = .call_one, 2549 .main_token = lparen, 2550 .data = .{ 2551 .lhs = lhs, 2552 .rhs = 0, 2553 }, 2554 }), 2555 1 => blk: { 2556 const arg = try renderNode(c, args[0]); 2557 break :blk try c.addNode(.{ 2558 .tag = .call_one, 2559 .main_token = lparen, 2560 .data = .{ 2561 .lhs = lhs, 2562 .rhs = arg, 2563 }, 2564 }); 2565 }, 2566 else => blk: { 2567 var rendered = try c.gpa.alloc(NodeIndex, args.len); 2568 defer c.gpa.free(rendered); 2569 2570 for (args, 0..) |arg, i| { 2571 if (i != 0) _ = try c.addToken(.comma, ","); 2572 rendered[i] = try renderNode(c, arg); 2573 } 2574 const span = try c.listToSpan(rendered); 2575 break :blk try c.addNode(.{ 2576 .tag = .call, 2577 .main_token = lparen, 2578 .data = .{ 2579 .lhs = lhs, 2580 .rhs = try c.addExtra(NodeSubRange{ 2581 .start = span.start, 2582 .end = span.end, 2583 }), 2584 }, 2585 }); 2586 }, 2587 }; 2588 _ = try c.addToken(.r_paren, ")"); 2589 return res; 2590 } 2591 2592 fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !NodeIndex { 2593 const builtin_tok = try c.addToken(.builtin, builtin); 2594 _ = try c.addToken(.l_paren, "("); 2595 var arg_1: NodeIndex = 0; 2596 var arg_2: NodeIndex = 0; 2597 var arg_3: NodeIndex = 0; 2598 var arg_4: NodeIndex = 0; 2599 switch (args.len) { 2600 0 => {}, 2601 1 => { 2602 arg_1 = try renderNode(c, args[0]); 2603 }, 2604 2 => { 2605 arg_1 = try renderNode(c, args[0]); 2606 _ = try c.addToken(.comma, ","); 2607 arg_2 = try renderNode(c, args[1]); 2608 }, 2609 4 => { 2610 arg_1 = try renderNode(c, args[0]); 2611 _ = try c.addToken(.comma, ","); 2612 arg_2 = try renderNode(c, args[1]); 2613 _ = try c.addToken(.comma, ","); 2614 arg_3 = try renderNode(c, args[2]); 2615 _ = try c.addToken(.comma, ","); 2616 arg_4 = try renderNode(c, args[3]); 2617 }, 2618 else => unreachable, // expand this function as needed. 2619 } 2620 2621 _ = try c.addToken(.r_paren, ")"); 2622 if (args.len <= 2) { 2623 return c.addNode(.{ 2624 .tag = .builtin_call_two, 2625 .main_token = builtin_tok, 2626 .data = .{ 2627 .lhs = arg_1, 2628 .rhs = arg_2, 2629 }, 2630 }); 2631 } else { 2632 std.debug.assert(args.len == 4); 2633 2634 const params = try c.listToSpan(&.{ arg_1, arg_2, arg_3, arg_4 }); 2635 return c.addNode(.{ 2636 .tag = .builtin_call, 2637 .main_token = builtin_tok, 2638 .data = .{ 2639 .lhs = params.start, 2640 .rhs = params.end, 2641 }, 2642 }); 2643 } 2644 } 2645 2646 fn renderVar(c: *Context, node: Node) !NodeIndex { 2647 const payload = node.castTag(.var_decl).?.data; 2648 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub"); 2649 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern"); 2650 if (payload.is_export) _ = try c.addToken(.keyword_export, "export"); 2651 if (payload.is_threadlocal) _ = try c.addToken(.keyword_threadlocal, "threadlocal"); 2652 const mut_tok = if (payload.is_const) 2653 try c.addToken(.keyword_const, "const") 2654 else 2655 try c.addToken(.keyword_var, "var"); 2656 _ = try c.addIdentifier(payload.name); 2657 _ = try c.addToken(.colon, ":"); 2658 const type_node = try renderNode(c, payload.type); 2659 2660 const align_node = if (payload.alignment) |some| blk: { 2661 _ = try c.addToken(.keyword_align, "align"); 2662 _ = try c.addToken(.l_paren, "("); 2663 const res = try c.addNode(.{ 2664 .tag = .number_literal, 2665 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{some}), 2666 .data = undefined, 2667 }); 2668 _ = try c.addToken(.r_paren, ")"); 2669 break :blk res; 2670 } else 0; 2671 2672 const section_node = if (payload.linksection_string) |some| blk: { 2673 _ = try c.addToken(.keyword_linksection, "linksection"); 2674 _ = try c.addToken(.l_paren, "("); 2675 const res = try c.addNode(.{ 2676 .tag = .string_literal, 2677 .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), 2678 .data = undefined, 2679 }); 2680 _ = try c.addToken(.r_paren, ")"); 2681 break :blk res; 2682 } else 0; 2683 2684 const init_node = if (payload.init) |some| blk: { 2685 _ = try c.addToken(.equal, "="); 2686 break :blk try renderNode(c, some); 2687 } else 0; 2688 _ = try c.addToken(.semicolon, ";"); 2689 2690 if (section_node == 0) { 2691 if (align_node == 0) { 2692 return c.addNode(.{ 2693 .tag = .simple_var_decl, 2694 .main_token = mut_tok, 2695 .data = .{ 2696 .lhs = type_node, 2697 .rhs = init_node, 2698 }, 2699 }); 2700 } else { 2701 return c.addNode(.{ 2702 .tag = .local_var_decl, 2703 .main_token = mut_tok, 2704 .data = .{ 2705 .lhs = try c.addExtra(std.zig.Ast.Node.LocalVarDecl{ 2706 .type_node = type_node, 2707 .align_node = align_node, 2708 }), 2709 .rhs = init_node, 2710 }, 2711 }); 2712 } 2713 } else { 2714 return c.addNode(.{ 2715 .tag = .global_var_decl, 2716 .main_token = mut_tok, 2717 .data = .{ 2718 .lhs = try c.addExtra(std.zig.Ast.Node.GlobalVarDecl{ 2719 .type_node = type_node, 2720 .align_node = align_node, 2721 .section_node = section_node, 2722 .addrspace_node = 0, 2723 }), 2724 .rhs = init_node, 2725 }, 2726 }); 2727 } 2728 } 2729 2730 fn renderFunc(c: *Context, node: Node) !NodeIndex { 2731 const payload = node.castTag(.func).?.data; 2732 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub"); 2733 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern"); 2734 if (payload.is_export) _ = try c.addToken(.keyword_export, "export"); 2735 if (payload.is_inline) _ = try c.addToken(.keyword_inline, "inline"); 2736 const fn_token = try c.addToken(.keyword_fn, "fn"); 2737 if (payload.name) |some| _ = try c.addIdentifier(some); 2738 2739 const params = try renderParams(c, payload.params, payload.is_var_args); 2740 defer params.deinit(); 2741 var span: NodeSubRange = undefined; 2742 if (params.items.len > 1) span = try c.listToSpan(params.items); 2743 2744 const align_expr = if (payload.alignment) |some| blk: { 2745 _ = try c.addToken(.keyword_align, "align"); 2746 _ = try c.addToken(.l_paren, "("); 2747 const res = try c.addNode(.{ 2748 .tag = .number_literal, 2749 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{some}), 2750 .data = undefined, 2751 }); 2752 _ = try c.addToken(.r_paren, ")"); 2753 break :blk res; 2754 } else 0; 2755 2756 const section_expr = if (payload.linksection_string) |some| blk: { 2757 _ = try c.addToken(.keyword_linksection, "linksection"); 2758 _ = try c.addToken(.l_paren, "("); 2759 const res = try c.addNode(.{ 2760 .tag = .string_literal, 2761 .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), 2762 .data = undefined, 2763 }); 2764 _ = try c.addToken(.r_paren, ")"); 2765 break :blk res; 2766 } else 0; 2767 2768 const callconv_expr = if (payload.explicit_callconv) |some| blk: { 2769 _ = try c.addToken(.keyword_callconv, "callconv"); 2770 _ = try c.addToken(.l_paren, "("); 2771 _ = try c.addToken(.period, "."); 2772 const res = try c.addNode(.{ 2773 .tag = .enum_literal, 2774 .main_token = try c.addTokenFmt(.identifier, "{s}", .{@tagName(some)}), 2775 .data = undefined, 2776 }); 2777 _ = try c.addToken(.r_paren, ")"); 2778 break :blk res; 2779 } else 0; 2780 2781 const return_type_expr = try renderNode(c, payload.return_type); 2782 2783 const fn_proto = try blk: { 2784 if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) { 2785 if (params.items.len < 2) 2786 break :blk c.addNode(.{ 2787 .tag = .fn_proto_simple, 2788 .main_token = fn_token, 2789 .data = .{ 2790 .lhs = params.items[0], 2791 .rhs = return_type_expr, 2792 }, 2793 }) 2794 else 2795 break :blk c.addNode(.{ 2796 .tag = .fn_proto_multi, 2797 .main_token = fn_token, 2798 .data = .{ 2799 .lhs = try c.addExtra(NodeSubRange{ 2800 .start = span.start, 2801 .end = span.end, 2802 }), 2803 .rhs = return_type_expr, 2804 }, 2805 }); 2806 } 2807 if (params.items.len < 2) 2808 break :blk c.addNode(.{ 2809 .tag = .fn_proto_one, 2810 .main_token = fn_token, 2811 .data = .{ 2812 .lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{ 2813 .param = params.items[0], 2814 .align_expr = align_expr, 2815 .addrspace_expr = 0, // TODO 2816 .section_expr = section_expr, 2817 .callconv_expr = callconv_expr, 2818 }), 2819 .rhs = return_type_expr, 2820 }, 2821 }) 2822 else 2823 break :blk c.addNode(.{ 2824 .tag = .fn_proto, 2825 .main_token = fn_token, 2826 .data = .{ 2827 .lhs = try c.addExtra(std.zig.Ast.Node.FnProto{ 2828 .params_start = span.start, 2829 .params_end = span.end, 2830 .align_expr = align_expr, 2831 .addrspace_expr = 0, // TODO 2832 .section_expr = section_expr, 2833 .callconv_expr = callconv_expr, 2834 }), 2835 .rhs = return_type_expr, 2836 }, 2837 }); 2838 }; 2839 2840 const payload_body = payload.body orelse { 2841 if (payload.is_extern) { 2842 _ = try c.addToken(.semicolon, ";"); 2843 } 2844 return fn_proto; 2845 }; 2846 const body = try renderNode(c, payload_body); 2847 return c.addNode(.{ 2848 .tag = .fn_decl, 2849 .main_token = fn_token, 2850 .data = .{ 2851 .lhs = fn_proto, 2852 .rhs = body, 2853 }, 2854 }); 2855 } 2856 2857 fn renderMacroFunc(c: *Context, node: Node) !NodeIndex { 2858 const payload = node.castTag(.pub_inline_fn).?.data; 2859 _ = try c.addToken(.keyword_pub, "pub"); 2860 _ = try c.addToken(.keyword_inline, "inline"); 2861 const fn_token = try c.addToken(.keyword_fn, "fn"); 2862 _ = try c.addIdentifier(payload.name); 2863 2864 const params = try renderParams(c, payload.params, false); 2865 defer params.deinit(); 2866 var span: NodeSubRange = undefined; 2867 if (params.items.len > 1) span = try c.listToSpan(params.items); 2868 2869 const return_type_expr = try renderNodeGrouped(c, payload.return_type); 2870 2871 const fn_proto = blk: { 2872 if (params.items.len < 2) { 2873 break :blk try c.addNode(.{ 2874 .tag = .fn_proto_simple, 2875 .main_token = fn_token, 2876 .data = .{ 2877 .lhs = params.items[0], 2878 .rhs = return_type_expr, 2879 }, 2880 }); 2881 } else { 2882 break :blk try c.addNode(.{ 2883 .tag = .fn_proto_multi, 2884 .main_token = fn_token, 2885 .data = .{ 2886 .lhs = try c.addExtra(std.zig.Ast.Node.SubRange{ 2887 .start = span.start, 2888 .end = span.end, 2889 }), 2890 .rhs = return_type_expr, 2891 }, 2892 }); 2893 } 2894 }; 2895 return c.addNode(.{ 2896 .tag = .fn_decl, 2897 .main_token = fn_token, 2898 .data = .{ 2899 .lhs = fn_proto, 2900 .rhs = try renderNode(c, payload.body), 2901 }, 2902 }); 2903 } 2904 2905 fn renderParams(c: *Context, params: []Payload.Param, is_var_args: bool) !std.ArrayList(NodeIndex) { 2906 _ = try c.addToken(.l_paren, "("); 2907 var rendered = try std.ArrayList(NodeIndex).initCapacity(c.gpa, @max(params.len, 1)); 2908 errdefer rendered.deinit(); 2909 2910 for (params, 0..) |param, i| { 2911 if (i != 0) _ = try c.addToken(.comma, ","); 2912 if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias"); 2913 if (param.name) |some| { 2914 _ = try c.addIdentifier(some); 2915 _ = try c.addToken(.colon, ":"); 2916 } 2917 if (param.type.tag() == .@"anytype") { 2918 _ = try c.addToken(.keyword_anytype, "anytype"); 2919 continue; 2920 } 2921 rendered.appendAssumeCapacity(try renderNode(c, param.type)); 2922 } 2923 if (is_var_args) { 2924 if (params.len != 0) _ = try c.addToken(.comma, ","); 2925 _ = try c.addToken(.ellipsis3, "..."); 2926 } 2927 _ = try c.addToken(.r_paren, ")"); 2928 2929 if (rendered.items.len == 0) rendered.appendAssumeCapacity(0); 2930 return rendered; 2931 }