refactor: new direction for error reporting
This commit is contained in:
parent
72b686d750
commit
c940374f27
11 changed files with 758 additions and 582 deletions
215
src/Ir.zig
215
src/Ir.zig
|
|
@ -4,16 +4,122 @@ const Writer = @import("print_ir.zig").Writer;
|
|||
const assert = std.debug.assert;
|
||||
const Ir = @This();
|
||||
|
||||
string_bytes: []u8,
|
||||
/// List of IR instructions for the translation unit.
|
||||
instructions: []Inst,
|
||||
globals: []Global,
|
||||
/// Interned string bytes. All strings are null-terminated.
|
||||
/// Index 0 is reserved for the empty string.
|
||||
string_bytes: []u8,
|
||||
/// Ancillary data for instructions. The meaning of this data is determined by
|
||||
/// the value of `Inst.Tag`. See `ExtraIndex` for the values of reserved indexes.
|
||||
extra: []u32,
|
||||
errors: []Ast.Error,
|
||||
globals: []Global,
|
||||
|
||||
pub const ExtraIndex = enum(u32) {
|
||||
/// If this is 0, no compile errors. Otherwise there is a `CompileErrors`
|
||||
/// payload at this index.
|
||||
compile_errors,
|
||||
_,
|
||||
};
|
||||
|
||||
fn ExtraData(comptime T: type) type {
|
||||
return struct {
|
||||
data: T,
|
||||
end: usize,
|
||||
};
|
||||
}
|
||||
|
||||
/// Extract a slice of `extra` into an `Inst` payload structure.
|
||||
pub fn extraData(ir: Ir, comptime T: type, index: usize) ExtraData(T) {
|
||||
const fields = @typeInfo(T).@"struct".fields;
|
||||
var i: usize = index;
|
||||
var result: T = undefined;
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => ir.extra[i],
|
||||
Inst.Index => @enumFromInt(ir.extra[i]),
|
||||
Inst.Ref => @enumFromInt(ir.extra[i]),
|
||||
NullTerminatedString => @enumFromInt(ir.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
return .{ .data = result, .end = i };
|
||||
}
|
||||
|
||||
pub const NullTerminatedString = enum(u32) {
|
||||
empty,
|
||||
_,
|
||||
};
|
||||
|
||||
pub fn nullTerminatedString(ir: Ir, index: NullTerminatedString) [:0]const u8 {
|
||||
const slice = ir.string_bytes[@intFromEnum(index)..];
|
||||
return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0];
|
||||
}
|
||||
|
||||
pub fn bodySlice(ir: Ir, start: usize, len: usize) []Inst.Index {
|
||||
return @ptrCast(ir.extra[start..][0..len]);
|
||||
}
|
||||
|
||||
pub fn hasCompileErrors(ir: Ir) bool {
|
||||
if (ir.extra[@intFromEnum(ExtraIndex.compile_errors)] != 0) {
|
||||
return true;
|
||||
} else {
|
||||
assert(ir.instructions.len != 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(ir: Ir, writer: *std.Io.Writer) !void {
|
||||
if (ir.instructions.len > 0) {
|
||||
var w: Writer = .{ .code = ir };
|
||||
try w.writeInst(writer, .file_inst);
|
||||
return writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dumpInfo(ir: Ir, writer: *std.Io.Writer) !void {
|
||||
const bytes = ir.string_bytes;
|
||||
|
||||
var start: usize = 0;
|
||||
while (start < bytes.len) {
|
||||
const end = std.mem.indexOfScalarPos(u8, bytes, start, 0) orelse break;
|
||||
const str = bytes[start..end];
|
||||
|
||||
try writer.print("[{d:04}] ", .{start});
|
||||
for (str) |b| try writer.print("{x:02} ", .{b});
|
||||
try writer.print("00: {s}\n", .{str});
|
||||
start = end + 1;
|
||||
}
|
||||
for (ir.globals) |global| {
|
||||
try writer.print("{any}\n", .{global});
|
||||
}
|
||||
return writer.flush();
|
||||
}
|
||||
|
||||
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
|
||||
gpa.free(ir.string_bytes);
|
||||
gpa.free(ir.instructions);
|
||||
gpa.free(ir.globals);
|
||||
gpa.free(ir.extra);
|
||||
ir.* = undefined;
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
tag: Tag,
|
||||
name: Ir.NullTerminatedString,
|
||||
is_constant: bool,
|
||||
|
||||
pub const Tag = enum {
|
||||
knot,
|
||||
variable,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Inst = struct {
|
||||
tag: Tag,
|
||||
data: Data,
|
||||
|
||||
/// An index to an IR instruction. Some values are reserved.
|
||||
pub const Index = enum(u32) {
|
||||
file_inst,
|
||||
ref_start_index = 32,
|
||||
|
|
@ -24,6 +130,15 @@ pub const Inst = struct {
|
|||
}
|
||||
};
|
||||
|
||||
/// A reference to an IR instruction, or to an statically interned value,
|
||||
/// or neither.
|
||||
///
|
||||
/// If the integer tag value is < `Index.ref_start_index`, then it
|
||||
/// corresponds to an interned value. Otherwise, this refers to a IR
|
||||
/// instruction.
|
||||
///
|
||||
/// The tag type is specified so that it is safe to bitcast between `[]u32`
|
||||
/// and `[]Ref`.
|
||||
pub const Ref = enum(u32) {
|
||||
bool_true,
|
||||
bool_false,
|
||||
|
|
@ -174,93 +289,13 @@ pub const Inst = struct {
|
|||
obj_ptr: Ref,
|
||||
field_name_start: NullTerminatedString,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Global = struct {
|
||||
tag: Tag,
|
||||
name: Ir.NullTerminatedString,
|
||||
is_constant: bool,
|
||||
pub const CompileErrors = struct {
|
||||
items_len: u32,
|
||||
|
||||
pub const Tag = enum {
|
||||
knot,
|
||||
variable,
|
||||
};
|
||||
};
|
||||
|
||||
pub const NullTerminatedString = enum(u32) {
|
||||
empty,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const IndexSlice = struct {
|
||||
index: u32,
|
||||
len: u32,
|
||||
};
|
||||
|
||||
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
|
||||
gpa.free(ir.string_bytes);
|
||||
gpa.free(ir.instructions);
|
||||
gpa.free(ir.globals);
|
||||
gpa.free(ir.extra);
|
||||
gpa.free(ir.errors);
|
||||
ir.* = undefined;
|
||||
}
|
||||
|
||||
pub fn render(ir: Ir, writer: *std.Io.Writer) !void {
|
||||
assert(ir.instructions.len > 0);
|
||||
var w: Writer = .{ .code = ir };
|
||||
try w.writeInst(writer, .file_inst);
|
||||
return writer.flush();
|
||||
}
|
||||
|
||||
pub fn dumpInfo(ir: Ir, writer: *std.Io.Writer) !void {
|
||||
const bytes = ir.string_bytes;
|
||||
|
||||
var start: usize = 0;
|
||||
while (start < bytes.len) {
|
||||
const end = std.mem.indexOfScalarPos(u8, bytes, start, 0) orelse break;
|
||||
const str = bytes[start..end];
|
||||
|
||||
try writer.print("[{d:04}] ", .{start});
|
||||
for (str) |b| try writer.print("{x:02} ", .{b});
|
||||
try writer.print("00: {s}\n", .{str});
|
||||
start = end + 1;
|
||||
}
|
||||
for (ir.globals) |global| {
|
||||
try writer.print("{any}\n", .{global});
|
||||
}
|
||||
return writer.flush();
|
||||
}
|
||||
|
||||
fn ExtraData(comptime T: type) type {
|
||||
return struct {
|
||||
data: T,
|
||||
end: usize,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn extraData(ir: Ir, comptime T: type, index: usize) ExtraData(T) {
|
||||
const fields = @typeInfo(T).@"struct".fields;
|
||||
var i: usize = index;
|
||||
var result: T = undefined;
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => ir.extra[i],
|
||||
Inst.Index => @enumFromInt(ir.extra[i]),
|
||||
Inst.Ref => @enumFromInt(ir.extra[i]),
|
||||
NullTerminatedString => @enumFromInt(ir.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
pub const Item = struct {
|
||||
msg: NullTerminatedString,
|
||||
byte_offset: u32,
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
return .{ .data = result, .end = i };
|
||||
}
|
||||
|
||||
pub fn nullTerminatedString(ir: Ir, index: NullTerminatedString) [:0]const u8 {
|
||||
const slice = ir.string_bytes[@intFromEnum(index)..];
|
||||
return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0];
|
||||
}
|
||||
|
||||
pub fn bodySlice(ir: Ir, start: usize, len: usize) []Inst.Index {
|
||||
return @ptrCast(ir.extra[start..][0..len]);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue