diff --git a/examples/hello.ry b/examples/hello.ry index 34bcb18..adc8263 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -8,7 +8,7 @@ fn f() i32 { } fn f2() i32 { - return f() + 2; + return f.awoo; } enum B { diff --git a/src/analysis.zig b/src/analysis.zig index c9ac686..4574807 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -16,8 +16,13 @@ pub const TypeSolver = struct { err_tok: ?Token = null, hadError: bool = false, - pub fn init(allocator: *std.mem.Allocator) TypeSolver { - return TypeSolver{ .allocator = allocator }; + err_ctx_buffer: []u8, + + 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 { @@ -26,9 +31,11 @@ pub const TypeSolver = struct { return; } - // TODO allocate buffer on init() and use it - var buf = self.allocator.alloc(u8, 256) catch unreachable; - self.err_ctx = std.fmt.bufPrint(buf, fmt.?, args) catch unreachable; + self.err_ctx = std.fmt.bufPrint( + self.err_ctx_buffer, + fmt.?, + args, + ) catch unreachable; } 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 { self.hadError = true; - std.debug.warn("type error"); + std.debug.warn("analysis error"); if (self.err_tok) |tok| { std.debug.warn(" at line {}", tok.line); } @@ -53,35 +60,41 @@ pub const TypeSolver = struct { } /// Resolve a type in global scope + /// Properly resolves composite (currently opaque) types to structs/enums. fn resolveGlobalType( self: *@This(), ctx: *comp.CompilationContext, identifier: []const u8, ) ?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); switch (typ) { .OpaqueType => |val| { - // solve for opaque so it isnt opaque var sym = ctx.symbol_table.get(val); - if (sym != null) - return switch (sym.?.value) { - .Struct => SymbolUnderlyingType{ .Struct = val }, - .Enum => SymbolUnderlyingType{ .Enum = val }, - else => blk: { - self.doError( - "expected struct or enum for type '{}', got {}", - val, - sym, - ); - break :blk null; - }, - }; + if (sym == null) { + self.doError("Unknown type: '{}'", val); + return null; + } - self.doError("Unknown type: '{}'", val); - return null; + return switch (sym.?.value) { + .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, @@ -102,6 +115,7 @@ pub const TypeSolver = struct { } } + /// Compare if the given type names are equal. fn compositeIdentifierEqual( self: *@This(), typ_enum: comp.SymbolUnderlyingTypeEnum, diff --git a/src/main.zig b/src/main.zig index c32605b..2becea9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -50,7 +50,7 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result { std.debug.warn("parse tree\n"); printer.printNode(root, 0); - var solver = analysis.TypeSolver.init(allocator); + var solver = try analysis.TypeSolver.init(allocator); var ctx = try solver.pass(root); std.debug.warn("symbol table\n");