From: Ayo Reis Date: Wed, 25 Feb 2026 18:45:23 +0000 (+0000) Subject: Refactor and add test X-Git-Url: https://git.ayoreis.com/zlox.git/commitdiff_plain/6b16a7c343e1ebe5618400e092253b08994b94b2?ds=inline Refactor and add test --- diff --git a/src/AstPrinter.zig b/src/AstPrinter.zig new file mode 100644 index 0000000..c83d58b --- /dev/null +++ b/src/AstPrinter.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const AstPrinter = @This(); +const Expr = @import("expr.zig").Expr; +const Token = @import("Token.zig"); + +allocator: Allocator, + +pub fn init(allocator: Allocator) AstPrinter { + return .{ + .allocator = allocator, + }; +} + +pub fn print(self: *const AstPrinter, expr: *const Expr) Allocator.Error![]const u8 { + return switch (expr.*) { + .binary => |binary| visitBinaryExpr(self, binary), + .grouping => |grouping| visitGroupingExpr(self, grouping), + .literal => |literal| visitLiteralExpr(self, literal), + .unary => |unary| visitUnaryExpr(self, unary), + }; +} + +fn visitBinaryExpr(self: *const AstPrinter, expr: Expr.Binary) ![]const u8 { + return self.parenthesize(expr.operator.lexeme, &.{ expr.left, expr.right }); +} + +fn visitGroupingExpr(self: *const AstPrinter, expr: Expr.Grouping) ![]const u8 { + return self.parenthesize("group", &.{expr.expression}); +} + +fn visitLiteralExpr(self: *const AstPrinter, expr: Expr.Literal) ![]const u8 { + return switch (expr.value) { + .string => |string| self.allocator.dupe(u8, string), + .number => |number| std.fmt.allocPrint(self.allocator, "{}", .{number}), + .boolean => |boolean| std.fmt.allocPrint(self.allocator, "{}", .{boolean}), + .nil => self.allocator.dupe(u8, "nil"), + }; +} + +fn visitUnaryExpr(self: *const AstPrinter, expr: Expr.Unary) ![]const u8 { + return self.parenthesize(expr.operator.lexeme, &.{expr.right}); +} + +fn parenthesize(self: *const AstPrinter, name: []const u8, exprs: []const *const Expr) ![]const u8 { + var builder: std.ArrayList(u8) = .empty; + + try builder.append(self.allocator, '('); + try builder.appendSlice(self.allocator, name); + for (exprs) |expr| { + try builder.append(self.allocator, ' '); + const printed = try print(self, expr); + defer self.allocator.free(printed); + try builder.appendSlice(self.allocator, printed); + } + try builder.append(self.allocator, ')'); + + return builder.toOwnedSlice(self.allocator); +} + +test { + const allocator = std.testing.allocator; + + const expression = Expr{ + .binary = .init( + &.{ .unary = .init( + .init(.minus, "-", null, 1), + &.{ .literal = .init(.{ .number = 123 }) }, + ) }, + .init(.star, "*", null, 1), + &.{ .grouping = .init( + &.{ .literal = .init(.{ .number = 45.67 }) }, + ) }, + ), + }; + + const ast_printer = AstPrinter.init(allocator); + const printed = try ast_printer.print(&expression); + defer allocator.free(printed); + std.debug.print("{s}\n", .{printed}); +} diff --git a/src/ast_printer.zig b/src/ast_printer.zig deleted file mode 100644 index 2df8c8e..0000000 --- a/src/ast_printer.zig +++ /dev/null @@ -1,34 +0,0 @@ -const std = @import("std"); -const Allocator = std.mem.Allocator; -const Expr = @import("expr.zig").Expr; -const Token = @import("Token.zig"); - -pub fn print(allocator: Allocator, expr: *const Expr) Allocator.Error![]const u8 { - return switch (expr.*) { - .binary => |binary| parenthesize(allocator, binary.operator.lexeme, &.{ binary.left, binary.right }), - .grouping => |grouping| parenthesize(allocator, "group", &.{grouping.expression}), - .literal => |literal| switch (literal.value) { - .string => |string| allocator.dupe(u8, string), - .number => |number| std.fmt.allocPrint(allocator, "{}", .{number}), - .boolean => |boolean| std.fmt.allocPrint(allocator, "{}", .{boolean}), - .nil => allocator.dupe(u8, "nil"), - }, - .unary => |unary| parenthesize(allocator, unary.operator.lexeme, &.{unary.right}), - }; -} - -fn parenthesize(allocator: Allocator, name: []const u8, exprs: []const *const Expr) ![]const u8 { - var builder: std.ArrayList(u8) = .empty; - - try builder.append(allocator, '('); - try builder.appendSlice(allocator, name); - for (exprs) |expr| { - try builder.append(allocator, ' '); - const printed = try print(allocator, expr); - defer allocator.free(printed); - try builder.appendSlice(allocator, printed); - } - try builder.append(allocator, ')'); - - return builder.toOwnedSlice(allocator); -}