zclsyntax: Generate "Variables" implementations for all Expressions
The implementation of Variables will be identical for every Expression implementation since we just wrap our AST-walk-based "Variables" function to do the work. Rather than manually copy-pasting the declaration for each expression type, instead we'll generate this programmatically using "go generate". This will need to be re-run each time a new expression node type is added, in order to make it actually implement the Expression interface.
This commit is contained in:
parent
007b38797b
commit
bae8f83298
@ -43,10 +43,6 @@ func (e *LiteralValueExpr) StartRange() zcl.Range {
|
||||
return e.SrcRange
|
||||
}
|
||||
|
||||
func (e *LiteralValueExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
// ScopeTraversalExpr is an Expression that retrieves a value from the scope
|
||||
// using a traversal.
|
||||
type ScopeTraversalExpr struct {
|
||||
@ -69,7 +65,3 @@ func (e *ScopeTraversalExpr) Range() zcl.Range {
|
||||
func (e *ScopeTraversalExpr) StartRange() zcl.Range {
|
||||
return e.SrcRange
|
||||
}
|
||||
|
||||
func (e *ScopeTraversalExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
16
zcl/zclsyntax/expression_vars.go
Executable file
16
zcl/zclsyntax/expression_vars.go
Executable file
@ -0,0 +1,16 @@
|
||||
package zclsyntax
|
||||
|
||||
// Generated by expression_vars_get.go. DO NOT EDIT.
|
||||
// Run 'go generate' on this package to update the set of functions here.
|
||||
|
||||
import (
|
||||
"github.com/apparentlymart/go-zcl/zcl"
|
||||
)
|
||||
|
||||
func (e *LiteralValueExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
func (e *ScopeTraversalExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
99
zcl/zclsyntax/expression_vars_gen.go
Normal file
99
zcl/zclsyntax/expression_vars_gen.go
Normal file
@ -0,0 +1,99 @@
|
||||
// This is a 'go generate'-oriented program for producing the "Variables"
|
||||
// method on every Expression implementation found within this package.
|
||||
// All expressions share the same implementation for this method, which
|
||||
// just wraps the package-level function "Variables" and uses an AST walk
|
||||
// to do its work.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fs := token.NewFileSet()
|
||||
pkgs, err := parser.ParseDir(fs, ".", nil, 0)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error while parsing: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
pkg := pkgs["zclsyntax"]
|
||||
|
||||
// Walk all the files and collect the receivers of any "Value" methods
|
||||
// that look like they are trying to implement Expression.
|
||||
var recvs []string
|
||||
for _, f := range pkg.Files {
|
||||
for _, decl := range f.Decls {
|
||||
fd, ok := decl.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if fd.Name.Name != "Value" {
|
||||
continue
|
||||
}
|
||||
results := fd.Type.Results.List
|
||||
if len(results) != 2 {
|
||||
continue
|
||||
}
|
||||
valResult := fd.Type.Results.List[0].Type.(*ast.SelectorExpr).X.(*ast.Ident)
|
||||
diagsResult := fd.Type.Results.List[1].Type.(*ast.SelectorExpr).X.(*ast.Ident)
|
||||
|
||||
if valResult.Name != "cty" && diagsResult.Name != "zcl" {
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have a method called Value and its returns something in
|
||||
// cty followed by something in zcl then that's specific enough
|
||||
// for now, even though this is not 100% exact as a correct
|
||||
// implementation of Value.
|
||||
|
||||
recvTy := fd.Recv.List[0].Type
|
||||
|
||||
switch rtt := recvTy.(type) {
|
||||
case *ast.StarExpr:
|
||||
name := rtt.X.(*ast.Ident).Name
|
||||
recvs = append(recvs, fmt.Sprintf("*%s", name))
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "don't know what to do with a %T receiver\n", recvTy)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(recvs)
|
||||
|
||||
of, err := os.OpenFile("expression_vars.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to open output file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Fprint(of, outputPreamble)
|
||||
for _, recv := range recvs {
|
||||
fmt.Fprintf(of, outputMethodFmt, recv)
|
||||
}
|
||||
fmt.Fprint(of, "\n")
|
||||
|
||||
}
|
||||
|
||||
const outputPreamble = `package zclsyntax
|
||||
|
||||
// Generated by expression_vars_get.go. DO NOT EDIT.
|
||||
// Run 'go generate' on this package to update the set of functions here.
|
||||
|
||||
import (
|
||||
"github.com/apparentlymart/go-zcl/zcl"
|
||||
)`
|
||||
|
||||
const outputMethodFmt = `
|
||||
|
||||
func (e %s) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}`
|
3
zcl/zclsyntax/generate.go
Normal file
3
zcl/zclsyntax/generate.go
Normal file
@ -0,0 +1,3 @@
|
||||
package zclsyntax
|
||||
|
||||
//go:generate go run expression_vars_gen.go
|
Loading…
Reference in New Issue
Block a user