| ... | @@ -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 | }; |
| 18 | | 19 | |
| 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 | }; |
| 27 | | 29 | |
| 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 | }; |
| 35 | | 40 | |
| 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 | }; |
| 39 | | 47 | |
| 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 | }; |
| 43 | | 54 | |
| 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 | }; |
| 47 | | 61 | |
| 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 | }; |
| 51 | | 68 | |
| 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 | }; |
| 56 | | 91 | |
| ... | @@ -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 | |
| | 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 | fn parseStringLiteralConst(ctx: *ParseContext) !*Inst { | 247 | fn 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 | '\\' => { |