analysis: create err ctx buffer on init()
- do better error message for resolveGlobalType
This commit is contained in:
parent
c3d3486163
commit
76d888bde8
3 changed files with 39 additions and 25 deletions
|
@ -8,7 +8,7 @@ fn f() i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f2() i32 {
|
fn f2() i32 {
|
||||||
return f() + 2;
|
return f.awoo;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum B {
|
enum B {
|
||||||
|
|
|
@ -16,8 +16,13 @@ pub const TypeSolver = struct {
|
||||||
err_tok: ?Token = null,
|
err_tok: ?Token = null,
|
||||||
hadError: bool = false,
|
hadError: bool = false,
|
||||||
|
|
||||||
pub fn init(allocator: *std.mem.Allocator) TypeSolver {
|
err_ctx_buffer: []u8,
|
||||||
return TypeSolver{ .allocator = allocator };
|
|
||||||
|
pub fn init(allocator: *std.mem.Allocator) !TypeSolver {
|
||||||
|
return TypeSolver{
|
||||||
|
.allocator = allocator,
|
||||||
|
.err_ctx_buffer = try allocator.alloc(u8, 512),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setErrContext(self: *@This(), comptime fmt: ?[]const u8, args: ...) void {
|
fn setErrContext(self: *@This(), comptime fmt: ?[]const u8, args: ...) void {
|
||||||
|
@ -26,9 +31,11 @@ pub const TypeSolver = struct {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO allocate buffer on init() and use it
|
self.err_ctx = std.fmt.bufPrint(
|
||||||
var buf = self.allocator.alloc(u8, 256) catch unreachable;
|
self.err_ctx_buffer,
|
||||||
self.err_ctx = std.fmt.bufPrint(buf, fmt.?, args) catch unreachable;
|
fmt.?,
|
||||||
|
args,
|
||||||
|
) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setErrToken(self: *@This(), tok: ?Token) void {
|
fn setErrToken(self: *@This(), tok: ?Token) void {
|
||||||
|
@ -38,7 +45,7 @@ pub const TypeSolver = struct {
|
||||||
fn doError(self: *@This(), comptime fmt: []const u8, args: ...) void {
|
fn doError(self: *@This(), comptime fmt: []const u8, args: ...) void {
|
||||||
self.hadError = true;
|
self.hadError = true;
|
||||||
|
|
||||||
std.debug.warn("type error");
|
std.debug.warn("analysis error");
|
||||||
if (self.err_tok) |tok| {
|
if (self.err_tok) |tok| {
|
||||||
std.debug.warn(" at line {}", tok.line);
|
std.debug.warn(" at line {}", tok.line);
|
||||||
}
|
}
|
||||||
|
@ -53,35 +60,41 @@ pub const TypeSolver = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve a type in global scope
|
/// Resolve a type in global scope
|
||||||
|
/// Properly resolves composite (currently opaque) types to structs/enums.
|
||||||
fn resolveGlobalType(
|
fn resolveGlobalType(
|
||||||
self: *@This(),
|
self: *@This(),
|
||||||
ctx: *comp.CompilationContext,
|
ctx: *comp.CompilationContext,
|
||||||
identifier: []const u8,
|
identifier: []const u8,
|
||||||
) ?SymbolUnderlyingType {
|
) ?SymbolUnderlyingType {
|
||||||
// assume the identifier references a builtin
|
// first, we assume the identifier is for a simple type
|
||||||
|
// if we fail (and this always returns OpaqueType as a fallback),
|
||||||
|
// we take it and find something in global scope
|
||||||
var typ = ctx.solveType(identifier);
|
var typ = ctx.solveType(identifier);
|
||||||
|
|
||||||
switch (typ) {
|
switch (typ) {
|
||||||
.OpaqueType => |val| {
|
.OpaqueType => |val| {
|
||||||
// solve for opaque so it isnt opaque
|
|
||||||
var sym = ctx.symbol_table.get(val);
|
var sym = ctx.symbol_table.get(val);
|
||||||
if (sym != null)
|
|
||||||
return switch (sym.?.value) {
|
|
||||||
.Struct => SymbolUnderlyingType{ .Struct = val },
|
|
||||||
.Enum => SymbolUnderlyingType{ .Enum = val },
|
|
||||||
|
|
||||||
else => blk: {
|
if (sym == null) {
|
||||||
self.doError(
|
self.doError("Unknown type: '{}'", val);
|
||||||
"expected struct or enum for type '{}', got {}",
|
return null;
|
||||||
val,
|
}
|
||||||
sym,
|
|
||||||
);
|
|
||||||
break :blk null;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.doError("Unknown type: '{}'", val);
|
return switch (sym.?.value) {
|
||||||
return null;
|
.Struct => SymbolUnderlyingType{ .Struct = val },
|
||||||
|
.Enum => SymbolUnderlyingType{ .Enum = val },
|
||||||
|
|
||||||
|
// TODO name resolution
|
||||||
|
|
||||||
|
else => blk: {
|
||||||
|
self.doError(
|
||||||
|
"expected struct or enum for '{}', got {}",
|
||||||
|
val,
|
||||||
|
@tagName(comp.SymbolType(sym.?.value)),
|
||||||
|
);
|
||||||
|
break :blk null;
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
else => return typ,
|
else => return typ,
|
||||||
|
@ -102,6 +115,7 @@ pub const TypeSolver = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compare if the given type names are equal.
|
||||||
fn compositeIdentifierEqual(
|
fn compositeIdentifierEqual(
|
||||||
self: *@This(),
|
self: *@This(),
|
||||||
typ_enum: comp.SymbolUnderlyingTypeEnum,
|
typ_enum: comp.SymbolUnderlyingTypeEnum,
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
|
||||||
std.debug.warn("parse tree\n");
|
std.debug.warn("parse tree\n");
|
||||||
printer.printNode(root, 0);
|
printer.printNode(root, 0);
|
||||||
|
|
||||||
var solver = analysis.TypeSolver.init(allocator);
|
var solver = try analysis.TypeSolver.init(allocator);
|
||||||
var ctx = try solver.pass(root);
|
var ctx = try solver.pass(root);
|
||||||
|
|
||||||
std.debug.warn("symbol table\n");
|
std.debug.warn("symbol table\n");
|
||||||
|
|
Loading…
Reference in a new issue