ast + basic printer

This commit is contained in:
basil 2025-06-07 21:12:44 -04:00
parent 5385a7509c
commit dc89e81cc5
Signed by: basil
SSH key fingerprint: SHA256:y04xIFL/yqNaG9ae9Vl95vELtHfApGAIoOGLeVLP/fE
2 changed files with 121 additions and 0 deletions

53
ast.go Normal file
View file

@ -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)
}

68
astprinter.go Normal file
View file

@ -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
}