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