| ... | ... | @@ -14,6 +14,7 @@ pub const Inst = struct { |
| 14 | 14 | Deref, |
| 15 | 15 | Assembly, |
| 16 | 16 | Unreach, |
| 17 | Fn, |
| 17 | 18 | }; |
| 18 | 19 | |
| 19 | 20 | pub const Tag = enum { |
| ... | ... | @@ -23,6 +24,7 @@ pub const Inst = struct { |
| 23 | 24 | deref, |
| 24 | 25 | @"asm", |
| 25 | 26 | unreach, |
| 27 | @"fn", |
| 26 | 28 | }; |
| 27 | 29 | |
| 28 | 30 | /// This struct owns the `Value` memory. When the struct is deallocated, |
| ... | ... | @@ -31,26 +33,59 @@ pub const Inst = struct { |
| 31 | 33 | pub const Constant = struct { |
| 32 | 34 | base: Inst = Inst{ .tag = .constant }, |
| 33 | 35 | value: *Value, |
| 36 | |
| 37 | positionals: struct {}, |
| 38 | kw_args: struct {}, |
| 34 | 39 | }; |
| 35 | 40 | |
| 36 | 41 | pub const PtrToInt = struct { |
| 37 | 42 | base: Inst = Inst{ .tag = .ptrtoint }, |
| 43 | |
| 44 | positionals: struct {}, |
| 45 | kw_args: struct {}, |
| 38 | 46 | }; |
| 39 | 47 | |
| 40 | 48 | pub const FieldPtr = struct { |
| 41 | 49 | base: Inst = Inst{ .tag = .fieldptr }, |
| 50 | |
| 51 | positionals: struct {}, |
| 52 | kw_args: struct {}, |
| 42 | 53 | }; |
| 43 | 54 | |
| 44 | 55 | pub const Deref = struct { |
| 45 | 56 | base: Inst = Inst{ .tag = .deref }, |
| 57 | |
| 58 | positionals: struct {}, |
| 59 | kw_args: struct {}, |
| 46 | 60 | }; |
| 47 | 61 | |
| 48 | 62 | pub const Assembly = struct { |
| 49 | 63 | base: Inst = Inst{ .tag = .@"asm" }, |
| 64 | |
| 65 | positionals: struct {}, |
| 66 | kw_args: struct {}, |
| 50 | 67 | }; |
| 51 | 68 | |
| 52 | 69 | pub const Unreach = struct { |
| 53 | 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 | }; |
| 56 | 91 | |
| ... | ... | @@ -168,8 +203,45 @@ fn parseInstruction(ctx: *ParseContext) !*Inst { |
| 168 | 203 | '0'...'9' => return parseIntegerLiteralConst(ctx), |
| 169 | 204 | else => {}, |
| 170 | 205 | } |
| 171 | | const fn_name = skipToAndOver(ctx, '('); |
| 172 | | return parseError(ctx, "TODO parse instruction '{}'", .{fn_name}); |
| 206 | const fn_name = try skipToAndOver(ctx, '('); |
| 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 | |
| 216 | fn 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 | |
| 243 | fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T { |
| 244 | return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)}); |
| 173 | 245 | } |
| 174 | 246 | |
| 175 | 247 | fn parseStringLiteralConst(ctx: *ParseContext) !*Inst { |
| ... | ... | @@ -192,7 +264,11 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst { |
| 192 | 264 | const bytes_val = try ctx.allocator.create(Value.Bytes); |
| 193 | 265 | bytes_val.* = .{ .data = parsed }; |
| 194 | 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 | 272 | return &const_inst.base; |
| 197 | 273 | }, |
| 198 | 274 | '\\' => { |