ir: parse asm instructions
parent
82e294cf09
commit
f020999ca3
|
@ -15,7 +15,7 @@ pub const Inst = struct {
|
||||||
fieldptr,
|
fieldptr,
|
||||||
deref,
|
deref,
|
||||||
@"asm",
|
@"asm",
|
||||||
unreach,
|
@"unreachable",
|
||||||
@"fn",
|
@"fn",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ pub const Inst = struct {
|
||||||
.fieldptr => FieldPtr,
|
.fieldptr => FieldPtr,
|
||||||
.deref => Deref,
|
.deref => Deref,
|
||||||
.@"asm" => Assembly,
|
.@"asm" => Assembly,
|
||||||
.unreach => Unreach,
|
.@"unreachable" => Unreach,
|
||||||
.@"fn" => Fn,
|
.@"fn" => Fn,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,16 @@ pub const Inst = struct {
|
||||||
pub const Assembly = struct {
|
pub const Assembly = struct {
|
||||||
base: Inst = Inst{ .tag = .@"asm" },
|
base: Inst = Inst{ .tag = .@"asm" },
|
||||||
|
|
||||||
positionals: struct {},
|
positionals: struct {
|
||||||
kw_args: struct {},
|
asm_source: *Inst,
|
||||||
|
},
|
||||||
|
kw_args: struct {
|
||||||
|
@"volatile": bool = false,
|
||||||
|
output: ?*Inst = null,
|
||||||
|
inputs: []*Inst = &[0]*Inst{},
|
||||||
|
clobbers: []*Inst = &[0]*Inst{},
|
||||||
|
args: []*Inst = &[0]*Inst{},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Unreach = struct {
|
pub const Unreach = struct {
|
||||||
|
@ -174,7 +182,9 @@ fn eatByte(ctx: *ParseContext, byte: u8) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skipSpace(ctx: *ParseContext) void {
|
fn skipSpace(ctx: *ParseContext) void {
|
||||||
while (ctx.i < ctx.source.len and ctx.source[ctx.i] == ' ') : (ctx.i += 1) {}
|
while (ctx.i < ctx.source.len and (ctx.source[ctx.i] == ' ' or ctx.source[ctx.i] == '\n')) {
|
||||||
|
ctx.i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn requireEatBytes(ctx: *ParseContext, bytes: []const u8) !void {
|
fn requireEatBytes(ctx: *ParseContext, bytes: []const u8) !void {
|
||||||
|
@ -284,14 +294,17 @@ fn parseInstructionGeneric(
|
||||||
skipSpace(ctx);
|
skipSpace(ctx);
|
||||||
const name = try skipToAndOver(ctx, '=');
|
const name = try skipToAndOver(ctx, '=');
|
||||||
inline for (@typeInfo(KW_Args).Struct.fields) |arg_field| {
|
inline for (@typeInfo(KW_Args).Struct.fields) |arg_field| {
|
||||||
if (mem.eql(u8, name, arg_field.name)) {
|
const field_name = arg_field.name;
|
||||||
@field(inst_specific.kw_args, arg_field.name) = try parseParameterGeneric(
|
if (mem.eql(u8, name, field_name)) {
|
||||||
ctx,
|
const NonOptional = switch (@typeInfo(arg_field.field_type)) {
|
||||||
arg_field.field_type,
|
.Optional => |info| info.child,
|
||||||
body_ctx,
|
else => arg_field.field_type,
|
||||||
);
|
};
|
||||||
|
@field(inst_specific.kw_args, field_name) = try parseParameterGeneric(ctx, NonOptional, body_ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return parseError(ctx, "unrecognized keyword parameter: '{}'", .{name});
|
||||||
}
|
}
|
||||||
skipSpace(ctx);
|
skipSpace(ctx);
|
||||||
}
|
}
|
||||||
|
@ -317,7 +330,39 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type, body_ctx: ?*BodyC
|
||||||
}
|
}
|
||||||
switch (T) {
|
switch (T) {
|
||||||
Inst.Fn.Body => return parseBody(ctx),
|
Inst.Fn.Body => return parseBody(ctx),
|
||||||
*Inst => {
|
bool => {
|
||||||
|
const bool_value = switch (ctx.source[ctx.i]) {
|
||||||
|
'0' => false,
|
||||||
|
'1' => true,
|
||||||
|
else => |byte| return parseError(ctx, "expected '0' or '1' for boolean value, found {c}", .{byte}),
|
||||||
|
};
|
||||||
|
ctx.i += 1;
|
||||||
|
return bool_value;
|
||||||
|
},
|
||||||
|
[]*Inst => {
|
||||||
|
try requireEatBytes(ctx, "[");
|
||||||
|
skipSpace(ctx);
|
||||||
|
if (eatByte(ctx, ']')) return &[0]*Inst{};
|
||||||
|
|
||||||
|
var instructions = std.ArrayList(*Inst).init(ctx.allocator);
|
||||||
|
defer instructions.deinit();
|
||||||
|
while (true) {
|
||||||
|
skipSpace(ctx);
|
||||||
|
try instructions.append(try parseParameterInst(ctx, body_ctx));
|
||||||
|
skipSpace(ctx);
|
||||||
|
if (!eatByte(ctx, ',')) break;
|
||||||
|
}
|
||||||
|
try requireEatBytes(ctx, "]");
|
||||||
|
return instructions.toOwnedSlice();
|
||||||
|
},
|
||||||
|
*Inst => return parseParameterInst(ctx, body_ctx),
|
||||||
|
Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
|
||||||
|
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||||
|
}
|
||||||
|
return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseParameterInst(ctx: *ParseContext, body_ctx: ?*BodyContext) !*Inst {
|
||||||
const local_ref = switch (ctx.source[ctx.i]) {
|
const local_ref = switch (ctx.source[ctx.i]) {
|
||||||
'@' => false,
|
'@' => false,
|
||||||
'%' => true,
|
'%' => true,
|
||||||
|
@ -335,7 +380,7 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type, body_ctx: ?*BodyC
|
||||||
ctx.i += 1;
|
ctx.i += 1;
|
||||||
const name_start = ctx.i;
|
const name_start = ctx.i;
|
||||||
while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
|
while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
|
||||||
' ', '\n', ',', ')' => break,
|
' ', '\n', ',', ')', ']' => break,
|
||||||
else => continue,
|
else => continue,
|
||||||
};
|
};
|
||||||
const ident = ctx.source[name_start..ctx.i];
|
const ident = ctx.source[name_start..ctx.i];
|
||||||
|
@ -349,11 +394,6 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type, body_ctx: ?*BodyC
|
||||||
} else {
|
} else {
|
||||||
return ctx.decls.items[kv.value];
|
return ctx.decls.items[kv.value];
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
|
|
||||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
|
||||||
}
|
|
||||||
return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BodyContext = struct {
|
const BodyContext = struct {
|
||||||
|
|
Loading…
Reference in New Issue