const std = @import("std"); const Allocator = std.mem.Allocator; const root = @import("root"); const Token = root.Lexer.Token; const Expr = root.Expr; const Location = root.Lexer.Location; pub const Reg = enum(u32) { _ }; pub const Instr = union(enum) { constant: Constant, bin_op: BinOp, const Constant = struct { dest: Reg, value: Location, }; const BinOp = struct { dest: Reg, lhs: Reg, rhs: Reg, op: Op, const Op = enum { add, }; }; }; pub const Block = struct { // arguments: []Reg, instrs: []Instr, }; pub fn compile(allocator: Allocator, expr: *const Expr) !Block { const instrs: std.ArrayListUnmanaged(Instr) = try .initCapacity(allocator, 0); var ctx: CompileContext = .{ .allocator = allocator, .register_counter = 0, .instrs = instrs, }; _ = try ctx.compileExpr(expr); return .{ .instrs = ctx.instrs.items }; } const CompileContext = struct { allocator: Allocator, register_counter: u32, instrs: std.ArrayListUnmanaged(Instr), const Self = @This(); fn addInstr(self: *Self, instr: Instr) !void { try self.instrs.append(self.allocator, instr); } fn compileExpr(self: *Self, expr: *const Expr) !Reg { const dest = self.register(); switch (expr.type) { .integer_literal => try addInstr(self, .{ .constant = .{ .dest = dest, .value = expr.loc }, }), .bin_op => |binop| { const lhs = try self.compileExpr(binop.lhs); const rhs = try self.compileExpr(binop.rhs); try addInstr(self, .{ .bin_op = .{ .dest = dest, .lhs = lhs, .rhs = rhs, .op = switch (binop.op) { .plus => .add, }, }, }); }, .invalid => return error.CantCompileInvalidExpr, } return dest; } fn register(self: *Self) Reg { const reg: Reg = @enumFromInt(self.register_counter); self.register_counter += 1; return reg; } };