authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-18 02:55:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-19 19:31:50-04:00
logf92ccf365be1e4dad74f6ac08503832ed2d7f805
tree79c1052ad6fd797670b857cd228939e2d5793596
parentbd4280decfd08b28041f96f552b3fec5087cbcd3

generic ir parsing framework


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

src-self-hosted/ir.zig+79-3
...@@ -14,6 +14,7 @@ pub const Inst = struct {...@@ -14,6 +14,7 @@ pub const Inst = struct {
14 Deref,14 Deref,
15 Assembly,15 Assembly,
16 Unreach,16 Unreach,
17 Fn,
17 };18 };
1819
19 pub const Tag = enum {20 pub const Tag = enum {
...@@ -23,6 +24,7 @@ pub const Inst = struct {...@@ -23,6 +24,7 @@ pub const Inst = struct {
23 deref,24 deref,
24 @"asm",25 @"asm",
25 unreach,26 unreach,
27 @"fn",
26 };28 };
2729
28 /// This struct owns the `Value` memory. When the struct is deallocated,30 /// This struct owns the `Value` memory. When the struct is deallocated,
...@@ -31,26 +33,59 @@ pub const Inst = struct {...@@ -31,26 +33,59 @@ pub const Inst = struct {
31 pub const Constant = struct {33 pub const Constant = struct {
32 base: Inst = Inst{ .tag = .constant },34 base: Inst = Inst{ .tag = .constant },
33 value: *Value,35 value: *Value,
36
37 positionals: struct {},
38 kw_args: struct {},
34 };39 };
3540
36 pub const PtrToInt = struct {41 pub const PtrToInt = struct {
37 base: Inst = Inst{ .tag = .ptrtoint },42 base: Inst = Inst{ .tag = .ptrtoint },
43
44 positionals: struct {},
45 kw_args: struct {},
38 };46 };
3947
40 pub const FieldPtr = struct {48 pub const FieldPtr = struct {
41 base: Inst = Inst{ .tag = .fieldptr },49 base: Inst = Inst{ .tag = .fieldptr },
50
51 positionals: struct {},
52 kw_args: struct {},
42 };53 };
4354
44 pub const Deref = struct {55 pub const Deref = struct {
45 base: Inst = Inst{ .tag = .deref },56 base: Inst = Inst{ .tag = .deref },
57
58 positionals: struct {},
59 kw_args: struct {},
46 };60 };
4761
48 pub const Assembly = struct {62 pub const Assembly = struct {
49 base: Inst = Inst{ .tag = .@"asm" },63 base: Inst = Inst{ .tag = .@"asm" },
64
65 positionals: struct {},
66 kw_args: struct {},
50 };67 };
5168
52 pub const Unreach = struct {69 pub const Unreach = struct {
53 base: Inst = Inst{ .tag = .unreach },70 base: Inst = Inst{ .tag = .unreach },
71
72 positionals: struct {},
73 kw_args: struct {},
74 };
75
76 pub const Fn = struct {
77 base: Inst = Inst{ .tag = .@"fn" },
78
79 positionals: struct {
80 body: Body,
81 },
82 kw_args: struct {
83 cc: std.builtin.CallingConvention = .Unspecified,
84 },
85
86 pub const Body = struct {
87 instructions: []*Inst,
88 };
54 };89 };
55};90};
5691
...@@ -168,8 +203,45 @@ fn parseInstruction(ctx: *ParseContext) !*Inst {...@@ -168,8 +203,45 @@ fn parseInstruction(ctx: *ParseContext) !*Inst {
168 '0'...'9' => return parseIntegerLiteralConst(ctx),203 '0'...'9' => return parseIntegerLiteralConst(ctx),
169 else => {},204 else => {},
170 }205 }
171 const fn_name = skipToAndOver(ctx, '(');206 const fn_name = try skipToAndOver(ctx, '(');
172 return parseError(ctx, "TODO parse instruction '{}'", .{fn_name});207 inline for (Inst.all_types) |InstType| {
208 const this_name = @tagName(std.meta.fieldInfo(InstType, "base").default_value.?.tag);
209 if (mem.eql(u8, this_name, fn_name)) {
210 return parseInstructionGeneric(ctx, this_name, InstType);
211 }
212 }
213 return parseError(ctx, "unknown instruction '{}'", .{fn_name});
214}
215
216fn parseInstructionGeneric(ctx: *ParseContext, comptime fn_name: []const u8, comptime InstType: type) !*Inst {
217 const inst_specific = try ctx.allocator.create(InstType);
218
219 const Positionals = @TypeOf(inst_specific.positionals);
220 inline for (@typeInfo(Positionals).Struct.fields) |arg_field| {
221 @field(inst_specific.positionals, arg_field.name) = try parseParameterGeneric(ctx, arg_field.field_type);
222 }
223
224 const KW_Args = @TypeOf(inst_specific.kw_args);
225 inst_specific.kw_args = .{}; // assign defaults
226 skipSpace(ctx);
227 while (eatByte(ctx, ',')) {
228 skipSpace(ctx);
229 const name = try skipToAndOver(ctx, '=');
230 inline for (@typeInfo(KW_Args).Struct.fields) |arg_field| {
231 if (mem.eql(u8, name, arg_field.name)) {
232 @field(inst_specific.kw_args, arg_field.name) = try parseParameterGeneric(ctx, arg_field.field_type);
233 break;
234 }
235 }
236 skipSpace(ctx);
237 }
238 try requireEatBytes(ctx, ")");
239
240 return &inst_specific.base;
241}
242
243fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {
244 return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
173}245}
174246
175fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {247fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
...@@ -192,7 +264,11 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {...@@ -192,7 +264,11 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
192 const bytes_val = try ctx.allocator.create(Value.Bytes);264 const bytes_val = try ctx.allocator.create(Value.Bytes);
193 bytes_val.* = .{ .data = parsed };265 bytes_val.* = .{ .data = parsed };
194 const const_inst = try ctx.allocator.create(Inst.Constant);266 const const_inst = try ctx.allocator.create(Inst.Constant);
195 const_inst.* = .{ .value = &bytes_val.base };267 const_inst.* = .{
268 .value = &bytes_val.base,
269 .positionals = .{},
270 .kw_args = .{},
271 };
196 return &const_inst.base;272 return &const_inst.base;
197 },273 },
198 '\\' => {274 '\\' => {
test/stage2/ir.zig+1-1
...@@ -25,7 +25,7 @@ test "hello world IR" {...@@ -25,7 +25,7 @@ test "hello world IR" {
25 \\ args=[%6, %7])25 \\ args=[%6, %7])
26 \\26 \\
27 \\ %9 = unreachable()27 \\ %9 = unreachable()
28 \\}, cc=naked);28 \\}, cc=naked)
29 \\29 \\
30 \\@2 = export("_start", @1)30 \\@2 = export("_start", @1)
31 ,31 ,