1 // This is a 'go generate'-oriented program for producing the "Variables"
2 // method on every Expression implementation found within this package.
3 // All expressions share the same implementation for this method, which
4 // just wraps the package-level function "Variables" and uses an AST walk
21 fs := token.NewFileSet()
22 pkgs, err := parser.ParseDir(fs, ".", nil, 0)
24 fmt.Fprintf(os.Stderr, "error while parsing: %s\n", err)
27 pkg := pkgs["hclsyntax"]
29 // Walk all the files and collect the receivers of any "Value" methods
30 // that look like they are trying to implement Expression.
32 for _, f := range pkg.Files {
33 for _, decl := range f.Decls {
34 fd, ok := decl.(*ast.FuncDecl)
38 if fd.Name.Name != "Value" {
41 results := fd.Type.Results.List
42 if len(results) != 2 {
45 valResult := fd.Type.Results.List[0].Type.(*ast.SelectorExpr).X.(*ast.Ident)
46 diagsResult := fd.Type.Results.List[1].Type.(*ast.SelectorExpr).X.(*ast.Ident)
48 if valResult.Name != "cty" && diagsResult.Name != "hcl" {
52 // If we have a method called Value and it returns something in
53 // "cty" followed by something in "hcl" then that's specific enough
54 // for now, even though this is not 100% exact as a correct
55 // implementation of Value.
57 recvTy := fd.Recv.List[0].Type
59 switch rtt := recvTy.(type) {
61 name := rtt.X.(*ast.Ident).Name
62 recvs = append(recvs, fmt.Sprintf("*%s", name))
64 fmt.Fprintf(os.Stderr, "don't know what to do with a %T receiver\n", recvTy)
72 of, err := os.OpenFile("expression_vars.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
74 fmt.Fprintf(os.Stderr, "failed to open output file: %s\n", err)
78 fmt.Fprint(of, outputPreamble)
79 for _, recv := range recvs {
80 fmt.Fprintf(of, outputMethodFmt, recv)
86 const outputPreamble = `package hclsyntax
88 // Generated by expression_vars_get.go. DO NOT EDIT.
89 // Run 'go generate' on this package to update the set of functions here.
92 "github.com/hashicorp/hcl2/hcl"
95 const outputMethodFmt = `
97 func (e %s) Variables() []hcl.Traversal {