You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.1 KiB
Go

package main
import (
"fmt"
"os"
"strings"
)
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: astgen <output_directory>")
os.Exit(64)
}
d := os.Args[1]
if _, err := os.Stat(d); os.IsNotExist(err) {
fmt.Println("Directory does not exist")
os.Exit(74)
}
fmt.Println("Generating AST classes in", d)
defineAst(d, "Expr", []string{
"Error : Value string",
"Binary : Left Expr, Operator token.Token, Right Expr",
"Grouping : Expression Expr",
"Literal : Value any",
"Unary : Operator token.Token, Right Expr",
})
}
func defineAst(outputDir, baseName string, types []string) {
path := outputDir + "/" + strings.ToLower(baseName) + ".go"
file, err := os.Create(path)
if err != nil {
fmt.Println("Error creating file", path)
os.Exit(74)
}
defer file.Close()
file.WriteString("package parser\n\n")
file.WriteString("import \"golox/token\"\n\n")
defineVisitor(file, baseName, types)
file.WriteString("type " + baseName + " interface {\n")
file.WriteString(" Accept(visitor " + baseName + "Visitor[any]) any\n")
file.WriteString("}\n\n")
for _, t := range types {
defineType(file, baseName, t)
}
}
func defineVisitor(file *os.File, baseName string, types []string) {
file.WriteString("type " + baseName + "Visitor[T any] interface {\n")
for _, t := range types {
typeName := strings.TrimSpace(t[:strings.Index(t, ":")-1])
file.WriteString(" Visit" + typeName + baseName + "(" + strings.ToLower(typeName) + " *" + typeName + baseName + ") T\n")
}
file.WriteString("}\n\n")
}
func defineType(file *os.File, baseName, typeString string) {
typeName := strings.TrimSpace(typeString[:strings.Index(typeString, ":")-1])
fields := strings.TrimSpace(typeString[strings.Index(typeString, ":")+1:])
file.WriteString("type " + typeName + baseName + " struct {\n")
for _, field := range strings.Split(fields, ", ") {
file.WriteString(" " + field + "\n")
}
file.WriteString("}\n\n")
file.WriteString("func (t *" + typeName + baseName + ") Accept(visitor " + baseName + "Visitor[any]) any {\n")
file.WriteString(" return visitor.Visit" + typeName + baseName + "(t)\n")
file.WriteString("}\n\n")
}