package ast import ( "golox/token" "testing" ) func TestPrintExpr(t *testing.T) { tests := []struct { name string expr Expr expected string }{ { name: "Binary expression", expr: &BinaryExpr{ Left: &LiteralExpr{Value: 1}, Operator: token.Token{Type: token.PLUS, Lexeme: "+"}, Right: &LiteralExpr{Value: 2}, }, expected: "(+ 1 2)", }, { name: "Grouping expression", expr: &GroupingExpr{ Expression: &LiteralExpr{Value: 1}, }, expected: "(group 1)", }, { name: "Logical expression", expr: &LogicalExpr{Left: &LiteralExpr{Value: 1}, Operator: token.Token{Type: token.AND, Lexeme: "and"}, Right: &LiteralExpr{Value: 2}}, expected: "(and 1 2)", }, { name: "Literal expression", expr: &LiteralExpr{Value: 123}, expected: "123", }, { name: "Unary expression", expr: &UnaryExpr{ Operator: token.Token{Type: token.MINUS, Lexeme: "-"}, Right: &LiteralExpr{Value: 123}, }, expected: "(- 123)", }, { name: "Nil literal expression", expr: &LiteralExpr{Value: nil}, expected: "nil", }, { name: "Error expression", expr: &ErrorExpr{Value: "error"}, expected: "error", }, { name: "Assign expression", expr: &AssignExpr{ Name: token.Token{Type: token.IDENTIFIER, Lexeme: "foo"}, Value: &LiteralExpr{Value: 42}, }, expected: "(= foo 42)", }, { name: "Variable expression", expr: &VariableExpr{ Name: token.Token{Type: token.IDENTIFIER, Lexeme: "foo"}, }, expected: "foo", }, { name: "Call expression", expr: &CallExpr{ Callee: &VariableExpr{Name: token.Token{Type: token.IDENTIFIER, Lexeme: "foo"}}, Paren: token.Token{Type: token.LEFT_PAREN, Lexeme: "("}, Arguments: []Expr{&LiteralExpr{Value: 1}, &LiteralExpr{Value: 2}}, }, expected: "foo(1, 2)", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { printer := NewPrinter() result := printer.PrintExpr(tt.expr) if result != tt.expected { t.Errorf("expected %v, got %v", tt.expected, result) } }) } } func TestPrintStmts(t *testing.T) { tests := []struct { name string stmts []Stmt expected string }{ { name: "Print statement", stmts: []Stmt{ &PrintStmt{ Expression: &LiteralExpr{Value: 42}, }, }, expected: "(print 42)\n", }, { name: "Expression statement", stmts: []Stmt{ &ExpressionStmt{ Expression: &LiteralExpr{Value: 42}, }, }, expected: "42\n", }, { name: "Error statement", stmts: []Stmt{ &ErrorStmt{ Value: "error", }, }, expected: "error\n", }, { name: "Var statement", stmts: []Stmt{ &VarStmt{ Name: token.Token{Type: token.IDENTIFIER, Lexeme: "foo"}, Initializer: &LiteralExpr{Value: 42}, }, }, expected: "(var foo 42)\n", }, { name: "Function statement", stmts: []Stmt{ &FunctionStmt{ Name: token.Token{Type: token.IDENTIFIER, Lexeme: "foo"}, Params: []token.Token{{Type: token.IDENTIFIER, Lexeme: "bar"}}, Body: []Stmt{ &ExpressionStmt{ Expression: &LiteralExpr{Value: 42}, }, }, }, }, expected: "(fun foo(bar) {\n 42\n})\n", }, { name: "Block statement", stmts: []Stmt{ &BlockStmt{ Statements: []Stmt{ &ExpressionStmt{ Expression: &LiteralExpr{Value: 1}, }, &ExpressionStmt{ Expression: &LiteralExpr{Value: 2}, }, }, }, }, expected: "{\n 1\n 2\n}\n", }, { name: "If statement", stmts: []Stmt{ &IfStmt{ Condition: &LiteralExpr{Value: true}, ThenBranch: &ExpressionStmt{ Expression: &LiteralExpr{Value: 1}, }, ElseBranch: &ExpressionStmt{ Expression: &LiteralExpr{Value: 2}, }, }, }, expected: "(if true {\n 1\n} else {\n 2\n})\n", }, { name: "While statement", stmts: []Stmt{ &WhileStmt{ Condition: &LiteralExpr{Value: true}, Body: &ExpressionStmt{ Expression: &LiteralExpr{Value: 1}, }, }, }, expected: "(while true {\n 1\n})\n", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { printer := NewPrinter() result := printer.PrintStmts(tt.stmts) if result != tt.expected { t.Errorf("expected %v, got %v", tt.expected, result) } }) } }