ast + basic printer
This commit is contained in:
parent
5385a7509c
commit
dc89e81cc5
2 changed files with 121 additions and 0 deletions
53
ast.go
Normal file
53
ast.go
Normal 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
68
astprinter.go
Normal 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
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue