authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-12 13:53:04+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:40:06+02:00
log13a9db208566449cd6bcfa5fd77f2707f7c9f394
tree9b0abb133b835747258ced5576fb9db0e1f62d47
parent2a74a1ebaace8b5de1796b1756f65e421eb479a4
signature Commit is signed but in an unrecognized format.

translate-c: begin implementing ast.render


2 files changed, 181 insertions(+), 4 deletions(-)

CMakeLists.txt+1
...@@ -578,6 +578,7 @@ set(ZIG_STAGE2_SOURCES...@@ -578,6 +578,7 @@ set(ZIG_STAGE2_SOURCES
578 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"578 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
579 "${CMAKE_SOURCE_DIR}/src/zir.zig"579 "${CMAKE_SOURCE_DIR}/src/zir.zig"
580 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"580 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"
581 "${CMAKE_SOURCE_DIR}/src/translate_c/ast.zig"
581)582)
582583
583if(MSVC)584if(MSVC)
src/translate_c/ast.zig+180-4
...@@ -454,7 +454,7 @@ pub const Payload = struct {...@@ -454,7 +454,7 @@ pub const Payload = struct {
454 data: struct {454 data: struct {
455 cond: Node,455 cond: Node,
456 body: Node,456 body: Node,
457 cont_expr: ?Node457 cont_expr: ?Node,
458 },458 },
459 };459 };
460460
...@@ -568,7 +568,7 @@ pub const Payload = struct {...@@ -568,7 +568,7 @@ pub const Payload = struct {
568 base: Payload,568 base: Payload,
569 data: struct {569 data: struct {
570 label: ?[]const u8,570 label: ?[]const u8,
571 stmts: []Node571 stmts: []Node,
572 },572 },
573 };573 };
574574
...@@ -640,6 +640,182 @@ pub const Payload = struct {...@@ -640,6 +640,182 @@ pub const Payload = struct {
640};640};
641641
642/// Converts the nodes into a Zig ast.642/// Converts the nodes into a Zig ast.
643pub fn render(allocator: *Allocator, nodes: []const Node) !std.zig.ast.Tree {643/// Caller must free the source slice.
644 @panic("TODO");644pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree {
645 var ctx = Context{
646 .gpa = gpa,
647 .buf = std.ArrayList(u8).init(gpa),
648 };
649 defer ctx.buf.deinit();
650 defer ctx.nodes.deinit(gpa);
651 defer ctx.extra_data.deinit(gpa);
652 defer ctx.tokens.deinit(gpa);
653
654 // Estimate that each top level node has 25 child nodes.
655 const estimated_node_count = nodes.len * 25;
656 try ctx.nodes.ensureCapacity(gpa, estimated_node_count);
657
658 ctx.nodes.appendAssumeCapacity(.{
659 .tag = .root,
660 .main_token = 0,
661 .data = .{
662 .lhs = undefined,
663 .rhs = undefined,
664 },
665 });
666 const root_members = try renderNodes(&ctx, nodes);
667 ctx.nodes.items(.data)[0] = .{
668 .lhs = root_members.start,
669 .rhs = root_members.end,
670 };
671
672 try ctx.tokens.append(gpa, .{
673 .tag = .eof,
674 .start = @intCast(u32, ctx.buf.items.len),
675 });
676
677 return std.zig.ast.Tree{
678 .source = ctx.buf.toOwnedSlice(),
679 .tokens = ctx.tokens.toOwnedSlice(),
680 .nodes = ctx.nodes.toOwnedSlice(),
681 .extra_data = ctx.extra_data.toOwnedSlice(gpa),
682 .errors = &.{},
683 };
684}
685
686const NodeIndex = std.zig.ast.Node.Index;
687const NodeSubRange = std.zig.ast.Node.SubRange;
688const TokenIndex = std.zig.ast.TokenIndex;
689const TokenTag = std.zig.Token.Tag;
690
691const Context = struct {
692 gpa: *Allocator,
693 buf: std.ArrayList(u8) = .{},
694 nodes: std.zig.ast.NodeList = .{},
695 extra_data: std.ArrayListUnmanaged(std.zig.ast.Node.Index) = .{},
696 tokens: std.zig.ast.TokenList = .{},
697
698 fn appendTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {
699 const start_index = c.buf.items.len;
700 try c.buf.writer().print(format ++ " ", args);
701
702 try c.tokens.append(c.gpa, .{
703 .tag = tag,
704 .start = @intCast(u32, start_index),
705 });
706
707 return @intCast(u32, c.tokens.len - 1);
708 }
709
710 fn appendToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex {
711 std.debug.assert(tag != .identifier); // use appendIdentifier
712 return appendTokenFmt(c, tag, "{s}", .{bytes});
713 }
714
715 fn appendIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex {
716 return appendTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)});
717 }
718
719 fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange {
720 try c.extra_data.appendSlice(c.gpa, list);
721 return NodeSubRange{
722 .start = @intCast(NodeIndex, c.extra_data.items.len - list.len),
723 .end = @intCast(NodeIndex, c.extra_data.items.len),
724 };
725 }
726
727 fn appendNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex {
728 const result = @intCast(NodeIndex, c.nodes.len);
729 try c.nodes.append(c.gpa, elem);
730 return result;
731 }
732};
733
734fn renderNodes(c: *Context, nodes: []const Node) !NodeSubRange {
735 var result = std.ArrayList(NodeIndex).init(c.gpa);
736 defer result.deinit();
737
738 for (nodes) |node| {
739 const res = try renderNode(c, node);
740 if (res == 0) continue;
741 try result.append(res);
742 }
743
744 return try c.listToSpan(result.items);
745}
746
747fn renderNode(c: *Context, node: Node) !NodeIndex {
748 switch (node.tag()) {
749 .warning => {
750 const payload = node.castTag(.warning).?;
751 try c.buf.appendSlice(payload.data);
752 try c.buf.append('\n');
753 return 0;
754 },
755 .usingnamespace_builtins => {
756 // pub usingnamespace @import("std").c.builtins;
757 _ = try c.appendToken(.keyword_pub, "pub");
758 const usingnamespace_token = try c.appendToken(.keyword_usingnamespace, "usingnamespace");
759 const import_node = try renderStdImport(c, "c", "builtins");
760 _ = try c.appendToken(.semicolon, ";");
761
762 return c.appendNode(.{
763 .tag = .@"usingnamespace",
764 .main_token = usingnamespace_token,
765 .data = .{
766 .lhs = import_node,
767 .rhs = undefined,
768 },
769 });
770 },
771 else => {
772 try c.buf.writer().print("// TODO renderNode {}\n", .{node.tag()});
773 return @as(u32, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'
774 },
775 }
776}
777
778fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeIndex {
779 const import_tok = try c.appendToken(.builtin, "@import");
780 _ = try c.appendToken(.l_paren, "(");
781
782 const std_tok = try c.appendToken(.string_literal, "\"std\"");
783 const std_node = try c.appendNode(.{
784 .tag = .string_literal,
785 .main_token = std_tok,
786 .data = .{
787 .lhs = std_tok,
788 .rhs = std_tok,
789 },
790 });
791
792 _ = try c.appendToken(.r_paren, ")");
793
794 const import_node = try c.appendNode(.{
795 .tag = .builtin_call_two,
796 .main_token = import_tok,
797 .data = .{
798 .lhs = std_node,
799 .rhs = 0,
800 },
801 });
802
803 var access_chain = import_node;
804 access_chain = try c.appendNode(.{
805 .tag = .field_access,
806 .main_token = try c.appendToken(.period, "."),
807 .data = .{
808 .lhs = access_chain,
809 .rhs = try c.appendIdentifier(first),
810 },
811 });
812 access_chain = try c.appendNode(.{
813 .tag = .field_access,
814 .main_token = try c.appendToken(.period, "."),
815 .data = .{
816 .lhs = access_chain,
817 .rhs = try c.appendIdentifier(second),
818 },
819 });
820 return access_chain;
645}821}