From 5a421bb91780e74404d83df2e99d7469b3cb8b90 Mon Sep 17 00:00:00 2001 From: Mathias Magnusson Date: Tue, 3 Jun 2025 00:34:15 +0200 Subject: add { blocks } with scoped local variables --- src/compile.zig | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'src/compile.zig') diff --git a/src/compile.zig b/src/compile.zig index ac7768e..5d57e71 100644 --- a/src/compile.zig +++ b/src/compile.zig @@ -72,12 +72,12 @@ pub const Instr = struct { pub const Sources = std.BoundedArray(VReg, 2); }; -pub const Block = struct { +pub const BasicBlock = struct { // arguments: []Reg, instrs: []Instr, vreg_last_use: std.AutoHashMap(VReg, usize), - fn init(allocator: Allocator, instrs: []Instr) !Block { + fn init(allocator: Allocator, instrs: []Instr) !BasicBlock { var vreg_last_use: std.AutoHashMap(VReg, usize) = .init(allocator); for (0.., instrs) |i, instr| { for (instr.sources().slice()) |src| @@ -92,41 +92,67 @@ pub const Block = struct { } }; -pub fn compile(allocator: Allocator, source: []const u8, stmts: []parse.Stmt) !Block { +pub fn compile(allocator: Allocator, source: []const u8, block: parse.Block) !BasicBlock { const instrs: std.ArrayListUnmanaged(Instr) = try .initCapacity(allocator, 0); var ctx: CompileContext = .{ .allocator = allocator, .source = source, .register_counter = 0, - .scope = .empty, + .scope = .{ .locals = .empty, .parent = null }, .instrs = instrs, }; - for (stmts) |stmt| { - try ctx.compileStmt(stmt); - } + try ctx.compileBlock(block); return .init(allocator, ctx.instrs.items); } +const CompileError = error{ + OutOfMemory, + CanOnlyCallIdentifiers, + UnknownProcedure, + UnknownVariable, +}; + const CompileContext = struct { allocator: Allocator, source: []const u8, register_counter: u32, - scope: std.StringHashMapUnmanaged(VReg), + scope: Scope, instrs: std.ArrayListUnmanaged(Instr), + const Scope = struct { + locals: std.StringHashMapUnmanaged(VReg), + parent: ?*Scope, + }; + const Self = @This(); fn addInstr(self: *Self, instr: Instr) !void { try self.instrs.append(self.allocator, instr); } - fn compileStmt(self: *Self, stmt: parse.Stmt) !void { + fn compileBlock(self: *Self, block: parse.Block) !void { + const parent = try self.allocator.create(Scope); + defer self.allocator.destroy(parent); + parent.* = self.scope; + self.scope = .{ + .locals = .empty, + .parent = parent, + }; + for (block.stmts) |stmt| { + try self.compileStmt(stmt); + } + self.scope.locals.deinit(self.allocator); + self.scope = parent.*; + } + + fn compileStmt(self: *Self, stmt: parse.Stmt) CompileError!void { switch (stmt.type) { .expr => |expr| _ = try self.compileExpr(expr), + .block => |block| try self.compileBlock(block), .declare_var => |declare_var| { const val = try self.compileExpr(declare_var.value); const name = declare_var.ident.getIdent(self.source); - try self.scope.put(self.allocator, name, val); + try self.scope.locals.put(self.allocator, name, val); }, } } @@ -168,7 +194,13 @@ const CompileContext = struct { }); }, .identifier => { - return self.scope.get(expr.loc.getIdent(self.source)) orelse return error.UnknownVariable; + var scope: ?*Scope = &self.scope; + while (scope) |s| : (scope = s.parent) { + if (s.locals.get(expr.loc.getIdent(self.source))) |reg| { + return reg; + } + } + return error.UnknownVariable; }, } return dest; -- cgit v1.2.3