translate-c: make Node more like Type

This commit is contained in:
Veikka Tuominen 2021-01-31 12:55:33 +02:00
parent 6ecec4c8b7
commit d835f5cce5
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 146 additions and 81 deletions

View File

@ -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,
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 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");
}

View File

@ -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.* = .{