diff --git a/src/analysis.zig b/src/analysis.zig index f3471d8..f5c4897 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -186,6 +186,8 @@ pub const TypeSolver = struct { // TODO make return type optional and so, skip exprs that // fail to be fully resolved, instead of returning CompileError + + // TODO make the expr ptr a const since we want to implicit cast things pub fn resolveExprType( self: *@This(), ctx: *comp.CompilationContext, @@ -276,9 +278,10 @@ pub const TypeSolver = struct { }, .Variable => |vari| { - // TODO maybe we can modify vari and add the current scope - // it was found for codegen purposes - return try ctx.resolveVarType(vari.lexeme); + self.setErrToken(vari); + var metadata = try ctx.resolveVarType(vari.lexeme); + try ctx.insertMetadata(expr, metadata); + return metadata.typ; }, .Get => |get| { diff --git a/src/ast.zig b/src/ast.zig index e1e3205..02093ed 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -141,6 +141,11 @@ pub const SetExpr = struct { value: *Expr, }; +pub const VariableExpr = struct { + tok: Token, + metadata: ?*comp.VariableMetadata = null, +}; + pub const Expr = union(ExprType) { Assign: AssignExpr, @@ -150,6 +155,7 @@ pub const Expr = union(ExprType) { Struct: StructExpr, Variable: Token, + Grouping: *Expr, Call: CallExpr, diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index 431eb92..e50a5e9 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -128,6 +128,31 @@ const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" }; const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool }; +const Using = enum { + Scope, + Function, +}; + +pub const VariableMetadata = struct { + typ: SymbolUnderlyingType, + + using: Using, + + from_scope: ?*Scope = null, + from_function: ?*FunctionSymbol = null, + + pub fn withScope(scope: *Scope, typ: SymbolUnderlyingType) VariableMetadata { + return VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope }; + } + + pub fn withParam(func: *FunctionSymbol, typ: SymbolUnderlyingType) VariableMetadata { + return VariableMetadata{ .typ = typ, .from_function = func, .using = .Function }; + } +}; + +// TODO rm const? +pub const VariableMetadataMap = std.AutoHashMap(*const ast.Expr, VariableMetadata); + /// Represents the context for a full compiler run. /// This is used to manage the symbol table for the compilation unit, etc. pub const CompilationContext = struct { @@ -137,13 +162,21 @@ pub const CompilationContext = struct { cur_function: ?*FunctionSymbol = null, current_scope: ?*Scope = null, + metadata_map: VariableMetadataMap, + pub fn init(allocator: *std.mem.Allocator) CompilationContext { return CompilationContext{ .allocator = allocator, .symbol_table = SymbolTable.init(allocator), + .metadata_map = VariableMetadataMap.init(allocator), }; } + pub fn deinit(self: *@This()) void { + self.symbol_table.deinit(); + self.metadata_map.deinit(); + } + /// Create a new scope out of the current one and set it as the current. pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void { if (self.current_scope == null) { @@ -297,21 +330,21 @@ pub const CompilationContext = struct { self: *@This(), scope_opt: ?*Scope, name: []const u8, - ) ?SymbolUnderlyingType { + ) ?VariableMetadata { if (scope_opt == null) return null; var scope = scope_opt.?; var kv_opt = scope.env.get(name); if (kv_opt) |kv| { - // TODO maybe return the scope it was found in - return kv.value; + return VariableMetadata.withScope(scope, kv.value); } else { return self.resolveVarTypeInScope(scope.parent, name); } } - fn resolveVarType(self: *@This(), name: []const u8) !SymbolUnderlyingType { - var var_type: ?SymbolUnderlyingType = null; + /// Resolve a given name's type, assuming it is a variable. + pub fn resolveVarType(self: *@This(), name: []const u8) !VariableMetadata { + var var_type: ?VariableMetadata = null; if (self.current_scope) |scope| { var_type = self.resolveVarTypeInScope(scope, name); @@ -320,10 +353,15 @@ pub const CompilationContext = struct { if (self.cur_function) |cur_function| { var kv_opt = cur_function.parameters.get(name); - if (kv_opt) |kv| return kv.value; + if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value); } std.debug.warn("Unknown name {}\n", name); return CompilationError.UnknownName; } + + pub fn insertMetadata(self: *@This(), ptr: *const ast.Expr, metadata: VariableMetadata) !void { + std.debug.assert(ast.ExprType(ptr.*) == .Variable); + _ = try self.metadata_map.put(ptr, metadata); + } }; diff --git a/src/parsers.zig b/src/parsers.zig index 3bb8572..026d11e 100644 --- a/src/parsers.zig +++ b/src/parsers.zig @@ -412,9 +412,9 @@ pub const Parser = struct { return expr; } - fn mkVariable(self: *Parser, variable: Token) !*ast.Expr { + fn mkVariable(self: *Parser, tok: Token) !*ast.Expr { var expr = try self.allocator.create(Expr); - expr.* = Expr{ .Variable = variable }; + expr.* = Expr{ .Variable = tok }; return expr; }