aboutsummaryrefslogtreecommitdiff
path: root/src/compile.zig
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-06-03 00:34:15 +0200
committerMathias Magnusson <mathias@magnusson.space>2025-06-03 00:34:15 +0200
commit5a421bb91780e74404d83df2e99d7469b3cb8b90 (patch)
treee0b4fdf996701d7f143a59201f227c7013313e75 /src/compile.zig
parente2e77b4b06e51c7f7d3ea187defaf1ad08e513c1 (diff)
downloadhuginn-5a421bb91780e74404d83df2e99d7469b3cb8b90.tar.gz
add { blocks } with scoped local variables
Diffstat (limited to 'src/compile.zig')
-rw-r--r--src/compile.zig54
1 files changed, 43 insertions, 11 deletions
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;