wrote dsl for ast boiler plate generation
This commit is contained in:
parent
b244f7e3b2
commit
e0dd8ff9d5
16 changed files with 915 additions and 60 deletions
146
ast/gen/transpile.go
Normal file
146
ast/gen/transpile.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type defTmplData struct {
|
||||
DefName string
|
||||
Name string
|
||||
Fields []string
|
||||
}
|
||||
|
||||
type transpiler struct {
|
||||
Name string
|
||||
DefinitionNames []string
|
||||
Definitions []string
|
||||
astDefsTmpl *template.Template
|
||||
defTmpl *template.Template
|
||||
}
|
||||
|
||||
var astDefinitionsTemplate = `
|
||||
{{ $name := .Name }}
|
||||
package ast
|
||||
|
||||
// THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT MANUALLY EDIT
|
||||
|
||||
import "git.red-panda.pet/pandaware/lox-go/lexer"
|
||||
|
||||
type {{ .Name }}Visitor interface {
|
||||
{{ range .DefinitionNames }}Visit{{ . }}{{ $name }}(v *{{ . }}{{ $name }}) any{{ "\n" }}{{ end }}
|
||||
}
|
||||
|
||||
type {{ .Name }} interface {
|
||||
Accept(v {{ .Name }}Visitor) any
|
||||
}
|
||||
|
||||
{{ range .Definitions }}
|
||||
{{ . }}
|
||||
{{ end }}`
|
||||
|
||||
var definitionTemplate = `
|
||||
type {{ .DefName }}{{ .Name }} struct {
|
||||
{{ range .Fields }}{{ . }}{{ "\n" }}{{ end }}
|
||||
}
|
||||
|
||||
func (n *{{ .DefName }}{{ .Name }}) Accept(v {{ .Name }}Visitor) any {
|
||||
return v.Visit{{ .DefName }}{{ .Name }}(n)
|
||||
}
|
||||
|
||||
var _ {{ .Name }} = new({{ .DefName }}{{ .Name }})`
|
||||
|
||||
// visitASTDefinitionsNode implements visitor.
|
||||
func (t *transpiler) visitASTDefinitionsNode(a *astDefinitionsNode) (string, error) {
|
||||
t.Name = a.name
|
||||
|
||||
for _, defNode := range a.definitions {
|
||||
def, err := defNode.accept(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
t.Definitions = append(t.Definitions, def)
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := t.astDefsTmpl.Execute(buf, t)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
// visitDefinition implements visitor.
|
||||
func (t *transpiler) visitDefinition(d *definitionNode) (string, error) {
|
||||
name, err := d.identifier.accept(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t.DefinitionNames = append(t.DefinitionNames, name)
|
||||
|
||||
fields := make([]string, len(d.fields))
|
||||
|
||||
for _, fieldNode := range d.fields {
|
||||
field, err := fieldNode.accept(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err = t.defTmpl.Execute(buf, defTmplData{
|
||||
DefName: name,
|
||||
Name: t.Name,
|
||||
Fields: fields,
|
||||
})
|
||||
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
// visitField implements visitor.
|
||||
func (t *transpiler) visitField(g *fieldNode) (string, error) {
|
||||
left, err := g.left.accept(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
right, err := g.right.accept(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\t%s\t%s\n", left, right), nil
|
||||
}
|
||||
|
||||
// visitIdentifier implements visitor.
|
||||
func (t *transpiler) visitIdentifier(i *identifierNode) (string, error) {
|
||||
return i.value, nil
|
||||
}
|
||||
|
||||
// visitName implements visitor.
|
||||
func (t *transpiler) visitName(n *nameNode) (string, error) {
|
||||
return n.value, nil
|
||||
}
|
||||
|
||||
var _ visitor = new(transpiler)
|
||||
|
||||
func transpile(n node) (string, []byte, error) {
|
||||
var err error
|
||||
t := new(transpiler)
|
||||
|
||||
t.Definitions = []string{}
|
||||
t.DefinitionNames = []string{}
|
||||
|
||||
t.astDefsTmpl, err = template.New("").Parse(astDefinitionsTemplate)
|
||||
t.defTmpl, err = template.New("").Parse(definitionTemplate)
|
||||
|
||||
str, err := n.accept(t)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
bs, err := format.Source([]byte(str))
|
||||
return t.Name, bs, err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue