From dc89e81cc53bd22fe92268ec80160f2352c8b9d5 Mon Sep 17 00:00:00 2001 From: red Date: Sat, 7 Jun 2025 21:12:44 -0400 Subject: [PATCH] ast + basic printer --- ast.go | 53 +++++++++++++++++++++++++++++++++++++++ astprinter.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 ast.go create mode 100644 astprinter.go diff --git a/ast.go b/ast.go new file mode 100644 index 0000000..1ed396d --- /dev/null +++ b/ast.go @@ -0,0 +1,53 @@ +package main + +// todo: find something better than any here +// we can't use generics on either the visitor itself or +// each individual method because the adding it to the +// visitor itself infects every expr you use with it +// and methods cannot have generic parameters + +type exprVisitor interface { + visitBinaryExpr(b *binaryExpr) any + visitGroupingExpr(g *groupingExpr) any + visitLiteralExpr(g *literalExpr) any + visitUnaryExpr(g *unaryExpr) any +} + +type expr interface { + accept(v exprVisitor) any +} + +type binaryExpr struct { + Left expr + Operator *token + Right expr +} + +func (b *binaryExpr) accept(v exprVisitor) any { + return v.visitBinaryExpr(b) +} + +type groupingExpr struct { + Expr expr +} + +func (g *groupingExpr) accept(v exprVisitor) any { + return v.visitGroupingExpr(g) +} + +type literalExpr struct { + Value any +} + +func (l *literalExpr) accept(v exprVisitor) any { + return v.visitLiteralExpr(l) +} + +type unaryExpr struct { + Operator *token + Right expr +} + +func (u *unaryExpr) accept(v exprVisitor) any { + return v.visitUnaryExpr(u) +} diff --git a/astprinter.go b/astprinter.go new file mode 100644 index 0000000..2237513 --- /dev/null +++ b/astprinter.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "strconv" +) + +type astPrinter struct { + result string +} + +// visitBinaryExpr implements exprVisitor. +func (p *astPrinter) visitBinaryExpr(b *binaryExpr) any { + return p.parenthesize(b.Operator.Lexeme, b.Left, b.Right) +} + +// visitGroupingExpr implements exprVisitor. +func (p *astPrinter) visitGroupingExpr(g *groupingExpr) any { + return p.parenthesize("group", g.Expr) +} + +// visitLiteralExpr implements exprVisitor. +func (p *astPrinter) visitLiteralExpr(g *literalExpr) any { + switch t := g.Value.(type) { + case string: + return t + case bool: + if t { + return "true" + } + return "false" + case float64: + return strconv.FormatFloat(t, 'f', 3, 64) + case nil: + return "nil" + } + + return fmt.Sprintf("%v", g.Value) +} + +// visitUnaryExpr implements exprVisitor. +func (p *astPrinter) visitUnaryExpr(g *unaryExpr) any { + return p.parenthesize(g.Operator.Lexeme, g.Right) +} + +func (p *astPrinter) parenthesize(name string, expressions ...expr) string { + val := "(" + name + + for _, e := range expressions { + exprStr, ok := (e.accept(p)).(string) + if !ok { + panic("badly implemented visitor") + } + val += " " + exprStr + } + + val += ")" + return val + +} + +func (p *astPrinter) print(e expr) string { + str, ok := (e.accept(p)).(string) + if !ok { + panic("badly implemented visitor") + } + return str +}