diff options
-rw-r--r-- | src/compile.zig | 94 | ||||
-rw-r--r-- | src/parse.zig | 76 | ||||
-rw-r--r-- | ternary.hgn | 4 |
3 files changed, 87 insertions, 87 deletions
diff --git a/src/compile.zig b/src/compile.zig index d1cac8c..69ac270 100644 --- a/src/compile.zig +++ b/src/compile.zig @@ -5,6 +5,8 @@ const Token = root.Lexer.Token; const parse = root.parse; const Location = root.Lexer.Location; +const log = std.log.scoped(.compile); + /// Virtual register pub const VReg = enum(u32) { _ }; pub const BlockRef = enum(u32) { _ }; @@ -101,7 +103,7 @@ pub const BasicBlock = struct { for (self.instrs.items, 0..) |instr, i| { const is_last = i == self.instrs.items.len - 1; if (instr.ends_block() != is_last) { - std.log.debug("Instruction at {s}last position must {s}end block. Found instruction {}. Block is: {}", .{ + log.debug("Instruction at {s}last position must {s}end block. Found instruction {}. Block is: {}", .{ if (is_last) "" else "not ", if (is_last) "" else "not ", instr, @@ -263,8 +265,7 @@ pub const Instr = struct { pub fn dest(self: *const Instr) ?VReg { return switch (self.type) { - inline .constant, .bin_op, .call, .get_local => |s| s.dest, - .branch, .jump, .ret, .assign_local => null, + inline else => |instr| if (@hasField(@TypeOf(instr), "dest")) instr.dest else null, }; } @@ -398,18 +399,11 @@ fn compileProcedure( try pctx.locals.putNoClobber(ctx.allocator, lvar, {}); break :blk lvar; } else null; - try pctx.compileBlock(proc.body); - if (!pctx.currentBlockEnded()) { - const proc_res = pctx.vreg_ctr.get(); - try pctx.addInstr(.{ - .loc = .{ .start = 0, .end = 0 }, - .type = .{ .constant = .{ .dest = proc_res, .value = 0 } }, - }); - try pctx.addInstr(.{ - .loc = .{ .start = 0, .end = 0 }, - .type = .{ .ret = .{ .val = proc_res } }, - }); - } + const body_res = try pctx.compileExpr(proc.body); + try pctx.addInstrUnlessEnded(.{ + .loc = .{ .start = 0, .end = 0 }, + .type = .{ .ret = .{ .val = body_res } }, + }); var blocks = try ctx.allocator.alloc(BasicBlock, pctx.blocks.count()); var it = pctx.blocks.iterator(); var i: usize = 0; @@ -417,6 +411,9 @@ fn compileProcedure( std.debug.assert(kv.key_ptr.* == kv.value_ptr.ref); blocks[i] = kv.value_ptr.*; } + for (blocks) |block| { + log.debug("{s}\n{}", .{ name.getIdent(ctx.source), block }); + } return try .init( ctx.allocator, name.getIdent(ctx.source), @@ -438,31 +435,13 @@ const ProcedureContext = struct { blocks: std.AutoArrayHashMapUnmanaged(BlockRef, BasicBlock), current_block: BlockRef, - fn compileBlock(self: *ProcedureContext, block: parse.Block) !void { - var parent = self.scope; - self.scope = .{ - .locals = .empty, - .parent = &parent, - }; - - for (block.stmts) |stmt| { - try self.compileStmt(stmt); - } - - self.scope.locals.deinit(self.ctx.allocator); - self.scope = parent; - } - fn compileStmt(self: *ProcedureContext, stmt: parse.Stmt) CompileError!void { switch (stmt.type) { .expr => |expr| _ = try self.compileExpr(expr), - .block => |block| { - try self.compileBlock(block); - }, .assign_var => |assign_var| { const local = if (assign_var.is_decl) blk: { - const local = self.lvar_ctr.get(); const name = assign_var.ident.getIdent(self.ctx.source); + const local = self.lvar_ctr.get(); try self.scope.locals.put(self.ctx.allocator, name, local); try self.locals.put(self.ctx.allocator, local, {}); break :blk local; @@ -472,7 +451,7 @@ const ProcedureContext = struct { if (s.locals.get(assign_var.ident.getIdent(self.ctx.source))) |local| break :blk local; } else { - std.log.debug("{s}", .{assign_var.ident.getIdent(self.ctx.source)}); + log.debug("{s}", .{assign_var.ident.getIdent(self.ctx.source)}); return error.UnknownVariable; } }; @@ -507,7 +486,7 @@ const ProcedureContext = struct { } }, }); self.current_block = do; - try self.compileBlock(@"while".do); + _ = try self.compileExpr(@"while".do); try self.addInstrUnlessEnded(.{ .loc = stmt.loc, .type = .{ .jump = .{ .to = cond_block } }, @@ -572,7 +551,7 @@ const ProcedureContext = struct { break :blk local; } } - std.log.debug("{s}", .{expr.loc.getIdent(self.ctx.source)}); + log.debug("{s}", .{expr.loc.getIdent(self.ctx.source)}); return error.UnknownVariable; }; try self.addInstr(.{ @@ -589,8 +568,14 @@ const ProcedureContext = struct { const after = try self.switchToNewBlock(); + const phony = self.lvar_ctr.get(); + try self.locals.put(self.ctx.allocator, phony, {}); const t = try self.switchToNewBlock(); - try self.compileBlock(@"if".then); + const t_val = try self.compileExpr(@"if".then); + try self.addInstrUnlessEnded(.{ + .loc = expr.loc, + .type = .{ .assign_local = .{ .local = phony, .val = t_val } }, + }); try self.addInstrUnlessEnded(.{ .loc = expr.loc, .type = .{ .jump = .{ .to = after } }, @@ -598,7 +583,11 @@ const ProcedureContext = struct { const f = if (@"if".@"else") |@"else"| blk: { const f = try self.switchToNewBlock(); - try self.compileBlock(@"else"); + const f_val = try self.compileExpr(@"else"); + try self.addInstrUnlessEnded(.{ + .loc = expr.loc, + .type = .{ .assign_local = .{ .local = phony, .val = f_val } }, + }); try self.addInstrUnlessEnded(.{ .loc = expr.loc, .type = .{ .jump = .{ .to = after } }, @@ -617,11 +606,12 @@ const ProcedureContext = struct { }); self.current_block = after; + try self.addInstr(.{ + .loc = expr.loc, + .type = .{ .get_local = .{ .dest = dest, .local = phony } }, + }); }, - .proc => |proc| { - _ = proc; - return error.CannotDefineProcedureHere; - }, + .proc => return error.CannotDefineProcedureHere, .@"return" => |ret| { const val = try self.compileExpr(ret.value); try self.addInstr(.{ @@ -629,6 +619,24 @@ const ProcedureContext = struct { .type = .{ .ret = .{ .val = val } }, }); }, + .block => |block| { + var parent = self.scope; + defer self.scope = parent; + self.scope = .{ + .locals = .empty, + .parent = &parent, + }; + defer self.scope.locals.deinit(self.ctx.allocator); + + for (block.stmts) |stmt| { + try self.compileStmt(stmt); + } + + try self.addInstrUnlessEnded(.{ + .loc = expr.loc, + .type = .{ .constant = .{ .dest = dest, .value = 0 } }, + }); + }, } return dest; } diff --git a/src/parse.zig b/src/parse.zig index 95a9bc9..4adeffb 100644 --- a/src/parse.zig +++ b/src/parse.zig @@ -44,20 +44,6 @@ pub const File = struct { } }; -pub const Block = struct { - loc: Location, - stmts: []Stmt, - - fn format(self: Block, writer: anytype, source: []const u8, indent: usize) !void { - try writer.writeAll("{\n"); - for (self.stmts) |stmt| { - try writer.print("{}\n", .{fmt(stmt, source, indent + 4)}); - } - try writer.writeByteNTimes(' ', indent); - try writer.writeAll("}"); - } -}; - pub const Stmt = struct { loc: Location, type: Type, @@ -65,7 +51,6 @@ pub const Stmt = struct { pub const Type = union(enum) { expr: *const Expr, assign_var: AssignVar, - block: Block, @"while": While, pub const AssignVar = struct { @@ -76,7 +61,7 @@ pub const Stmt = struct { pub const While = struct { cond: *const Expr, - do: Block, + do: *const Expr, }; }; @@ -84,7 +69,6 @@ pub const Stmt = struct { try writer.writeByteNTimes(' ', indent); return switch (self.type) { .expr => |expr| writer.print("{}", .{fmt(expr, source, indent)}), - .block => |b| writer.print("{}", .{fmt(b, source, indent)}), .assign_var => |assign_var| writer.print("{s} {s} {}", .{ assign_var.ident.getIdent(source), if (assign_var.is_decl) ":=" else "=", @@ -110,6 +94,7 @@ pub const Expr = struct { @"if": If, proc: Proc, @"return": Return, + block: Block, pub const BinOp = struct { lhs: *const Expr, @@ -166,18 +151,22 @@ pub const Expr = struct { pub const If = struct { cond: *const Expr, - then: Block, - @"else": ?Block, + then: *const Expr, + @"else": ?*const Expr, }; pub const Proc = struct { - body: Block, + body: *const Expr, param: ?Location, }; pub const Return = struct { value: *const Expr, }; + + pub const Block = struct { + stmts: []Stmt, + }; }; fn format(self: Expr, writer: anytype, source: []const u8, indent: usize) !void { @@ -201,6 +190,14 @@ pub const Expr = struct { }, .proc => |proc| try writer.print("proc({s}) {}", .{ if (proc.param) |p| p.getIdent(source) else "", fmt(proc.body, source, indent) }), .@"return" => |ret| try writer.print("return {}", .{fmt(ret.value, source, indent)}), + .block => |block| { + try writer.writeAll("{\n"); + for (block.stmts) |stmt| { + try writer.print("{}\n", .{fmt(stmt, source, indent + 4)}); + } + try writer.writeByteNTimes(' ', indent); + try writer.writeAll("}"); + }, } } }; @@ -230,32 +227,12 @@ pub fn file(allocator: Allocator, lexer: *Lexer) !File { }; } -fn parseBlock(allocator: Allocator, lexer: *Lexer) !Block { - const left_curly = try mustEat(lexer, .left_curly); - var stmts: std.ArrayList(Stmt) = .init(allocator); - while (lexer.peek().type != .right_curly) { - try stmts.append(try parseStatement(allocator, lexer)); - } - const right_curly = try mustEat(lexer, .right_curly); - return .{ - .loc = left_curly.loc.combine(right_curly.loc), - .stmts = try stmts.toOwnedSlice(), - }; -} - fn parseStatement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt { switch (lexer.peek().type) { - .left_curly => { - const b = try parseBlock(allocator, lexer); - return .{ - .loc = b.loc, - .type = .{ .block = b }, - }; - }, .@"while" => { const @"while" = lexer.next(); const cond = try expression(allocator, lexer); - const do = try parseBlock(allocator, lexer); + const do = try expression(allocator, lexer); return .{ .loc = @"while".loc.combine(do.loc), .type = .{ .@"while" = .{ @@ -318,7 +295,7 @@ fn parseProc(allocator: Allocator, lexer: *Lexer) ParseError!*Expr { else => return expected(&.{ .identifier, .right_paren }, param_tok), }; if (param != null) _ = try mustEat(lexer, .right_paren); - const body = try parseBlock(allocator, lexer); + const body = try expression(allocator, lexer); return allocate(Expr, allocator, .{ .loc = proc.loc.combine(body.loc), @@ -354,10 +331,10 @@ fn parseIf(allocator: Allocator, lexer: *Lexer) !*Expr { .@"if" => { const @"if" = lexer.next(); const cond = try expression(allocator, lexer); - const then = try parseBlock(allocator, lexer); + const then = try expression(allocator, lexer); const @"else" = if (lexer.peek().type == .@"else") blk: { _ = lexer.next(); - break :blk try parseBlock(allocator, lexer); + break :blk try expression(allocator, lexer); } else null; return try allocate(Expr, allocator, .{ .loc = @"if".loc.combine((@"else" orelse then).loc), @@ -397,6 +374,17 @@ fn parsePrimaryExpr(allocator: Allocator, lexer: *Lexer) !*Expr { return error.ExpectedRightParen; return res; }, + .left_curly => { + var stmts: std.ArrayList(Stmt) = .init(allocator); + while (lexer.peek().type != .right_curly) { + try stmts.append(try parseStatement(allocator, lexer)); + } + const right_curly = try mustEat(lexer, .right_curly); + return allocate(Expr, allocator, .{ + .loc = token.loc.combine(right_curly.loc), + .type = .{ .block = .{ .stmts = try stmts.toOwnedSlice() } }, + }); + }, .integer_literal => .{ .loc = token.loc, .type = .integer_literal }, .identifier => .{ .loc = token.loc, .type = .identifier }, else => return expected(&.{ .left_paren, .integer_literal, .identifier }, token), diff --git a/ternary.hgn b/ternary.hgn new file mode 100644 index 0000000..3740fd8 --- /dev/null +++ b/ternary.hgn @@ -0,0 +1,4 @@ +main := proc() { + print(if read_int(0) 1 else 2) + if 1 exit(0) +} |