Commit d835f5cce5

Veikka Tuominen <git@vexu.eu>
2021-01-31 11:55:33
translate-c: make Node more like Type
1 parent 6ecec4c
Changed files (2)
src
translate_c
src/translate_c/ast.zig
@@ -2,14 +2,19 @@ const std = @import("std");
 const Type = @import("../type.zig").Type;
 
 pub const Node = struct {
-    tag: Tag,
-    // type: Type = Type.initTag(.noreturn),
+    /// If the tag value is less than Tag.no_payload_count, then no pointer
+    /// dereference is needed.
+    tag_if_small_enough: usize,
+    ptr_otherwise: *Payload,
 
     pub const Tag = enum {
         null_literal,
         undefined_literal,
         opaque_literal,
-        bool_literal,
+        true_literal,
+        false_literal,
+        // After this, the tag requires a payload.
+
         int,
         float,
         string,
@@ -39,12 +44,18 @@ pub const Node = struct {
         discard,
         block,
 
+        pub const last_no_payload_tag = Tag.false_literal;
+        pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
+
         pub fn Type(tag: Tag) ?type {
             return switch (tag) {
-                .null_literal => null,
-                .undefined_literal => null,
-                .opaque_literal => null,
-                .bool_literal,
+                .null_literal,
+                .undefined_literal,
+                .opaque_literal,
+                .true_literal,
+                .false_litral,
+                => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
+
                 .int,
                 .float,
                 .string,
@@ -54,144 +65,186 @@ pub const Node = struct {
                 .field_access_arrow,
                 .warning,
                 .failed_decl,
-                => Value,
-                .@"if" => If,
-                .@"while" => While,
-                .@"switch" => Switch,
-                .@"break" => Break,
-                .call => Call,
+                => Payload.Value,
+                .@"if" => Payload.If,
+                .@"while" => Payload.While,
+                .@"switch" => Payload.Switch,
+                .@"break" => Payload.Break,
+                .call => Payload.Call,
                 .array_access,
                 .std_mem_zeroes,
                 .@"return",
                 .discard,
-                => SingleArg,
-                .var_decl => VarDecl,
-                .func => Func,
-                .@"enum" => Enum,
-                .@"struct", .@"union" => Record,
-                .array_init => ArrayInit,
-                .container_init => ContainerInit,
-                .std_meta_cast => Infix,
-                .block => Block,
+                => Payload.SingleArg,
+                .var_decl => Payload.VarDecl,
+                .func => Payload.Func,
+                .@"enum" => Payload.Enum,
+                .@"struct", .@"union" => Payload.Record,
+                .array_init => Payload.ArrayInit,
+                .container_init => Payload.ContainerInit,
+                .std_meta_cast => Payload.Infix,
+                .block => Payload.Block,
+            };
+        }
+
+        pub fn init(comptime t: Tag) Node {
+            comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count);
+            return .{ .tag_if_small_enough = @enumToInt(t) };
+        }
+
+        pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Node {
+            const ptr = try ally.create(t.Type());
+            ptr.* = .{
+                .base = .{ .tag = t },
+                .data = data,
             };
+            return Node{ .ptr_otherwise = &ptr.base };
+        }
+
+        pub fn Data(comptime t: Tag) type {
+            return std.meta.fieldInfo(t.Type(), .data).field_type;
         }
     };
+};
+
+pub const Payload = struct {
+    tag: Tag,
 
     pub const Infix = struct {
         base: Node,
-        lhs: *Node,
-        rhs: *Node,
+        data: struct {
+            lhs: *Node,
+            rhs: *Node,
+        },
     };
 
     pub const Value = struct {
         base: Node,
-        val: []const u8,
+        data: []const u8,
     };
 
     pub const SingleArg = struct {
         base: Node,
-        index: *Node,
+        data: *Node,
     };
 
     pub const If = struct {
         base: Node = .{ .tag = .@"if" },
-        cond: *Node,
-        then: *Node,
-        @"else": ?*Node,
+        data: struct {
+            cond: *Node,
+            then: *Node,
+            @"else": ?*Node,
+        },
     };
 
     pub const While = struct {
         base: Node = .{ .tag = .@"while" },
-        cond: *Node,
-        body: *Node,
+        data: struct {
+            cond: *Node,
+            body: *Node,
+        },
     };
 
     pub const Switch = struct {
         base: Node = .{ .tag = .@"switch" },
-        cond: *Node,
-        cases: []Prong,
-        default: ?[]const u8,
+        data: struct {
+            cond: *Node,
+            cases: []Prong,
+            default: ?[]const u8,
 
-        pub const Prong = struct {
-            lhs: *Node,
-            rhs: ?*Node,
-            label: []const u8,
-        };
+            pub const Prong = struct {
+                lhs: *Node,
+                rhs: ?*Node,
+                label: []const u8,
+            };
+        },
     };
 
     pub const Break = struct {
         base: Node = .{ .tag = .@"break" },
-        label: ?[]const u8,
-        rhs: ?*Node,
+        data: struct {
+            label: ?[]const u8,
+            rhs: ?*Node,
+        },
     };
 
     pub const Call = struct {
         base: Node = .{.call},
-        lhs: *Node,
-        args: []*Node,
+        data: struct {
+            lhs: *Node,
+            args: []*Node,
+        },
     };
 
     pub const VarDecl = struct {
         base: Node = .{ .tag = .var_decl },
-        @"pub": bool,
-        @"const": bool,
-        @"extern": bool,
-        @"export": bool,
-        name: []const u8,
-        type: Type,
-        init: *Node,
+        data: struct {
+            @"pub": bool,
+            @"const": bool,
+            @"extern": bool,
+            @"export": bool,
+            name: []const u8,
+            type: Type,
+            init: *Node,
+        },
     };
 
     pub const Func = struct {
         base: Node = .{.func},
-        @"pub": bool,
-        @"extern": bool,
-        @"export": bool,
-        name: []const u8,
-        cc: std.builtin.CallingConvention,
-        params: []Param,
-        return_type: Type,
-        body: ?*Node,
-
-        pub const Param = struct {
-            @"noalias": bool,
-            name: ?[]const u8,
-            type: Type,
-        };
+        data: struct {
+            @"pub": bool,
+            @"extern": bool,
+            @"export": bool,
+            name: []const u8,
+            cc: std.builtin.CallingConvention,
+            params: []Param,
+            return_type: Type,
+            body: ?*Node,
+
+            pub const Param = struct {
+                @"noalias": bool,
+                name: ?[]const u8,
+                type: Type,
+            };
+        },
     };
 
     pub const Enum = struct {
         base: Node = .{ .tag = .@"enum" },
-        name: ?[]const u8,
-        fields: []Field,
+        data: struct {
+            name: ?[]const u8,
+            fields: []Field,
 
-        pub const Field = struct {
-            name: []const u8,
-            value: ?[]const u8,
-        };
+            pub const Field = struct {
+                name: []const u8,
+                value: ?[]const u8,
+            };
+        },
     };
 
     pub const Record = struct {
         base: Node,
-        name: ?[]const u8,
-        @"packed": bool,
-        fields: []Field,
+        data: struct {
+            name: ?[]const u8,
+            @"packed": bool,
+            fields: []Field,
 
-        pub const Field = struct {
-            name: []const u8,
-            type: Type,
-            alignment: c_uint,
-        };
+            pub const Field = struct {
+                name: []const u8,
+                type: Type,
+                alignment: c_uint,
+            };
+        },
     };
 
     pub const ArrayInit = struct {
         base: Node = .{ .tag = .array_init },
-        values: []*Node,
+        data: []*Node,
     };
 
     pub const ContainerInit = struct {
         base: Node = .{ .tag = .container_init },
-        values: []Initializer,
+        data: []Initializer,
 
         pub const Initializer = struct {
             name: []const u8,
@@ -201,7 +254,14 @@ pub const Node = struct {
 
     pub const Block = struct {
         base: Node = .{ .tag = .block },
-        label: ?[]const u8,
-        stmts: []*Node,
+        data: struct {
+            label: ?[]const u8,
+            stmts: []*Node,
+        },
     };
 };
+
+/// Converts the nodes into a Zig ast and then renders it.
+pub fn render(allocator: *Allocator, nodes: []const Node) !void {
+    @panic("TODO");
+}
src/type.zig
@@ -3408,6 +3408,11 @@ pub const Type = extern union {
             };
         }
 
+        pub fn init(comptime t: Tag) Type {
+            comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count);
+            return .{ .tag_if_small_enough = @enumToInt(t) };
+        }
+
         pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Type {
             const ptr = try ally.create(t.Type());
             ptr.* = .{