aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2021-01-31 12:55:33 +0200
committerVeikka Tuominen <git@vexu.eu>2021-02-16 16:37:07 +0200
commitd835f5cce5fc3b296f55e208905d9ff4d368e497 (patch)
treedefa873d5bc10497d98599534068b409cdaa782d
parent6ecec4c8b761c9f8f272602ccb2abdfd9656c71c (diff)
downloadzig-d835f5cce5fc3b296f55e208905d9ff4d368e497.tar.gz
zig-d835f5cce5fc3b296f55e208905d9ff4d368e497.zip
translate-c: make Node more like Type
-rw-r--r--src/translate_c/ast.zig224
-rw-r--r--src/type.zig5
2 files changed, 147 insertions, 82 deletions
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index 4418971269..0585c26d18 100644
--- a/src/translate_c/ast.zig
+++ b/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");
+}
diff --git a/src/type.zig b/src/type.zig
index 7d3308e403..8fcaba6fad 100644
--- a/src/type.zig
+++ b/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.* = .{