1 const std = @import("std");
2 const Allocator = std.mem.Allocator;
3 const AstPrinter = @This();
4 const Expr = @import("expr.zig").Expr;
5 const Token = @import("Token.zig");
9 pub fn init(allocator: Allocator) AstPrinter {
11 .allocator = allocator,
15 pub fn print(self: *const AstPrinter, expr: *const Expr) Allocator.Error![]const u8 {
16 return switch (expr.*) {
17 .binary => |binary| visitBinaryExpr(self, binary),
18 .grouping => |grouping| visitGroupingExpr(self, grouping),
19 .literal => |literal| visitLiteralExpr(self, literal),
20 .unary => |unary| visitUnaryExpr(self, unary),
24 fn visitBinaryExpr(self: *const AstPrinter, expr: Expr.Binary) ![]const u8 {
25 return self.parenthesize(expr.operator.lexeme, &.{ expr.left, expr.right });
28 fn visitGroupingExpr(self: *const AstPrinter, expr: Expr.Grouping) ![]const u8 {
29 return self.parenthesize("group", &.{expr.expression});
32 fn visitLiteralExpr(self: *const AstPrinter, expr: Expr.Literal) ![]const u8 {
33 return switch (expr.value) {
34 .string => |string| self.allocator.dupe(u8, string),
35 .number => |number| std.fmt.allocPrint(self.allocator, "{}", .{number}),
36 .boolean => |boolean| std.fmt.allocPrint(self.allocator, "{}", .{boolean}),
37 .nil => self.allocator.dupe(u8, "nil"),
41 fn visitUnaryExpr(self: *const AstPrinter, expr: Expr.Unary) ![]const u8 {
42 return self.parenthesize(expr.operator.lexeme, &.{expr.right});
45 fn parenthesize(self: *const AstPrinter, name: []const u8, exprs: []const *const Expr) ![]const u8 {
46 var builder: std.ArrayList(u8) = .empty;
48 try builder.append(self.allocator, '(');
49 try builder.appendSlice(self.allocator, name);
51 try builder.append(self.allocator, ' ');
52 const printed = try print(self, expr);
53 defer self.allocator.free(printed);
54 try builder.appendSlice(self.allocator, printed);
56 try builder.append(self.allocator, ')');
58 return builder.toOwnedSlice(self.allocator);
62 const allocator = std.testing.allocator;
64 const expression = Expr{
67 .init(.minus, "-", null, 1),
68 &.{ .literal = .init(.{ .number = 123 }) },
70 .init(.star, "*", null, 1),
71 &.{ .grouping = .init(
72 &.{ .literal = .init(.{ .number = 45.67 }) },
77 const ast_printer = AstPrinter.init(allocator);
78 const printed = try ast_printer.print(&expression);
79 defer allocator.free(printed);
80 std.debug.print("{s}\n", .{printed});