ir: parse types

master
Andrew Kelley 2020-04-18 20:22:54 -04:00
parent 59154a1c51
commit 7127c07f68
3 changed files with 42 additions and 28 deletions

View File

@ -143,13 +143,8 @@ pub fn parseRoot(ctx: *ParseContext) !void {
'@' => {
const at_start = ctx.i;
const ident = try skipToAndOver(ctx, ' ');
var ty: ?*Value = null;
if (eatByte(ctx, ':')) {
ty = try parseType(ctx);
skipSpace(ctx);
}
try requireEatBytes(ctx, "= ");
const inst = try parseInstruction(ctx);
const opt_type = try parseOptionalType(ctx);
const inst = try parseInstruction(ctx, opt_type);
const ident_index = ctx.decls.items.len;
if (try ctx.global_name_map.put(ident, ident_index)) |_| {
return parseError(ctx, "redefinition of identifier '{}'", .{ident});
@ -202,11 +197,27 @@ fn parseError(ctx: *ParseContext, comptime format: []const u8, args: var) error{
return error.ParseFailure;
}
fn parseType(ctx: *ParseContext) !*Value {
return parseError(ctx, "TODO parse type", .{});
/// Regardless of whether a `Type` is returned, it skips past the '='.
fn parseOptionalType(ctx: *ParseContext) !?Type {
skipSpace(ctx);
if (eatByte(ctx, ':')) {
const type_text_untrimmed = try skipToAndOver(ctx, '=');
skipSpace(ctx);
const type_text = mem.trim(u8, type_text_untrimmed, " \n");
if (mem.eql(u8, type_text, "usize")) {
return Type.initTag(.int_usize);
} else {
return parseError(ctx, "TODO parse type '{}'", .{type_text});
}
} else {
skipSpace(ctx);
try requireEatBytes(ctx, "=");
skipSpace(ctx);
return null;
}
}
fn parseInstruction(ctx: *ParseContext) error{ OutOfMemory, ParseFailure }!*Inst {
fn parseInstruction(ctx: *ParseContext, opt_type: ?Type) error{ OutOfMemory, ParseFailure }!*Inst {
switch (ctx.source[ctx.i]) {
'"' => return parseStringLiteralConst(ctx),
'0'...'9' => return parseIntegerLiteralConst(ctx),
@ -216,15 +227,26 @@ fn parseInstruction(ctx: *ParseContext) error{ OutOfMemory, ParseFailure }!*Inst
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 parseInstructionGeneric(ctx, this_name, InstType, opt_type);
}
}
return parseError(ctx, "unknown instruction '{}'", .{fn_name});
}
fn parseInstructionGeneric(ctx: *ParseContext, comptime fn_name: []const u8, comptime InstType: type) !*Inst {
fn parseInstructionGeneric(
ctx: *ParseContext,
comptime fn_name: []const u8,
comptime InstType: type,
opt_type: ?Type,
) !*Inst {
const inst_specific = try ctx.allocator.create(InstType);
if (@hasField(InstType, "ty")) {
inst_specific.ty = opt_type orelse {
return parseError(ctx, "instruction '" ++ fn_name ++ "' requires type", .{});
};
}
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);
@ -287,16 +309,8 @@ fn parseBody(ctx: *ParseContext) !Inst.Fn.Body {
'%' => {
const at_start = ctx.i;
const ident = try skipToAndOver(ctx, ' ');
var ty: ?*Value = null;
if (eatByte(ctx, ':')) {
skipSpace(ctx);
ty = try parseType(ctx);
skipSpace(ctx);
}
skipSpace(ctx);
try requireEatBytes(ctx, "=");
skipSpace(ctx);
const inst = try parseInstruction(ctx);
const opt_type = try parseOptionalType(ctx);
const inst = try parseInstruction(ctx, opt_type);
const ident_index = instructions.items.len;
if (try name_map.put(ident, ident_index)) |_| {
return parseError(ctx, "redefinition of identifier '{}'", .{ident});

View File

@ -24,9 +24,9 @@ pub const Type = extern union {
}
}
pub fn initTag(comptime tag: Tag) Type {
comptime assert(@enumToInt(tag) < Tag.no_payload_count);
return .{ .tag_if_small_enough = @enumToInt(tag) };
pub fn initTag(comptime small_tag: Tag) Type {
comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
return .{ .tag_if_small_enough = @enumToInt(small_tag) };
}
pub fn initPayload(payload: *Payload) Type {

View File

@ -37,9 +37,9 @@ pub const Value = extern union {
bytes,
};
pub fn initTag(comptime tag: Tag) Value {
comptime assert(@enumToInt(tag) < Tag.no_payload_count);
return .{ .tag_if_small_enough = @enumToInt(tag) };
pub fn initTag(comptime small_tag: Tag) Value {
comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
return .{ .tag_if_small_enough = @enumToInt(small_tag) };
}
pub fn initPayload(payload: *Payload) Value {