Commit f92ccf365b

Andrew Kelley <andrew@ziglang.org>
2020-04-18 08:55:28
generic ir parsing framework
1 parent bd4280d
Changed files (2)
src-self-hosted
test
stage2
src-self-hosted/ir.zig
@@ -14,6 +14,7 @@ pub const Inst = struct {
         Deref,
         Assembly,
         Unreach,
+        Fn,
     };
 
     pub const Tag = enum {
@@ -23,6 +24,7 @@ pub const Inst = struct {
         deref,
         @"asm",
         unreach,
+        @"fn",
     };
 
     /// This struct owns the `Value` memory. When the struct is deallocated,
@@ -31,26 +33,59 @@ pub const Inst = struct {
     pub const Constant = struct {
         base: Inst = Inst{ .tag = .constant },
         value: *Value,
+
+        positionals: struct {},
+        kw_args: struct {},
     };
 
     pub const PtrToInt = struct {
         base: Inst = Inst{ .tag = .ptrtoint },
+
+        positionals: struct {},
+        kw_args: struct {},
     };
 
     pub const FieldPtr = struct {
         base: Inst = Inst{ .tag = .fieldptr },
+
+        positionals: struct {},
+        kw_args: struct {},
     };
 
     pub const Deref = struct {
         base: Inst = Inst{ .tag = .deref },
+
+        positionals: struct {},
+        kw_args: struct {},
     };
 
     pub const Assembly = struct {
         base: Inst = Inst{ .tag = .@"asm" },
+
+        positionals: struct {},
+        kw_args: struct {},
     };
 
     pub const Unreach = struct {
         base: Inst = Inst{ .tag = .unreach },
+
+        positionals: struct {},
+        kw_args: struct {},
+    };
+
+    pub const Fn = struct {
+        base: Inst = Inst{ .tag = .@"fn" },
+
+        positionals: struct {
+            body: Body,
+        },
+        kw_args: struct {
+            cc: std.builtin.CallingConvention = .Unspecified,
+        },
+
+        pub const Body = struct {
+            instructions: []*Inst,
+        };
     };
 };
 
@@ -168,8 +203,45 @@ fn parseInstruction(ctx: *ParseContext) !*Inst {
         '0'...'9' => return parseIntegerLiteralConst(ctx),
         else => {},
     }
-    const fn_name = skipToAndOver(ctx, '(');
-    return parseError(ctx, "TODO parse instruction '{}'", .{fn_name});
+    const fn_name = try skipToAndOver(ctx, '(');
+    inline for (Inst.all_types) |InstType| {
+        const this_name = @tagName(std.meta.fieldInfo(InstType, "base").default_value.?.tag);
+        if (mem.eql(u8, this_name, fn_name)) {
+            return parseInstructionGeneric(ctx, this_name, InstType);
+        }
+    }
+    return parseError(ctx, "unknown instruction '{}'", .{fn_name});
+}
+
+fn parseInstructionGeneric(ctx: *ParseContext, comptime fn_name: []const u8, comptime InstType: type) !*Inst {
+    const inst_specific = try ctx.allocator.create(InstType);
+
+    const Positionals = @TypeOf(inst_specific.positionals);
+    inline for (@typeInfo(Positionals).Struct.fields) |arg_field| {
+        @field(inst_specific.positionals, arg_field.name) = try parseParameterGeneric(ctx, arg_field.field_type);
+    }
+
+    const KW_Args = @TypeOf(inst_specific.kw_args);
+    inst_specific.kw_args = .{}; // assign defaults
+    skipSpace(ctx);
+    while (eatByte(ctx, ',')) {
+        skipSpace(ctx);
+        const name = try skipToAndOver(ctx, '=');
+        inline for (@typeInfo(KW_Args).Struct.fields) |arg_field| {
+            if (mem.eql(u8, name, arg_field.name)) {
+                @field(inst_specific.kw_args, arg_field.name) = try parseParameterGeneric(ctx, arg_field.field_type);
+                break;
+            }
+        }
+        skipSpace(ctx);
+    }
+    try requireEatBytes(ctx, ")");
+
+    return &inst_specific.base;
+}
+
+fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {
+    return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
 }
 
 fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
@@ -192,7 +264,11 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
             const bytes_val = try ctx.allocator.create(Value.Bytes);
             bytes_val.* = .{ .data = parsed };
             const const_inst = try ctx.allocator.create(Inst.Constant);
-            const_inst.* = .{ .value = &bytes_val.base };
+            const_inst.* = .{
+                .value = &bytes_val.base,
+                .positionals = .{},
+                .kw_args = .{},
+            };
             return &const_inst.base;
         },
         '\\' => {
test/stage2/ir.zig
@@ -25,7 +25,7 @@ test "hello world IR" {
         \\    args=[%6, %7])
         \\
         \\  %9 = unreachable()
-        \\}, cc=naked);
+        \\}, cc=naked)
         \\
         \\@2 = export("_start", @1)
     ,