| 22 | ) |
| 23 | |
| 24 | func main() { |
| 25 | fs := token.NewFileSet() |
| 26 | pkgs, err := parser.ParseDir(fs, ".", nil, 0) |
| 27 | if err != nil { |
| 28 | fmt.Fprintf(os.Stderr, "error while parsing: %s\n", err) |
| 29 | os.Exit(1) |
| 30 | } |
| 31 | pkg := pkgs["hclsyntax"] |
| 32 | |
| 33 | // Walk all the files and collect the receivers of any "Value" methods |
| 34 | // that look like they are trying to implement Expression. |
| 35 | var recvs []string |
| 36 | for _, f := range pkg.Files { |
| 37 | for _, decl := range f.Decls { |
| 38 | fd, ok := decl.(*ast.FuncDecl) |
| 39 | if !ok { |
| 40 | continue |
| 41 | } |
| 42 | if fd.Name.Name != "Value" { |
| 43 | continue |
| 44 | } |
| 45 | results := fd.Type.Results.List |
| 46 | if len(results) != 2 { |
| 47 | continue |
| 48 | } |
| 49 | valResult := fd.Type.Results.List[0].Type.(*ast.SelectorExpr).X.(*ast.Ident) |
| 50 | diagsResult := fd.Type.Results.List[1].Type.(*ast.SelectorExpr).X.(*ast.Ident) |
| 51 | |
| 52 | if valResult.Name != "cty" && diagsResult.Name != "hcl" { |
| 53 | continue |
| 54 | } |
| 55 | |
| 56 | // If we have a method called Value and it returns something in |
| 57 | // "cty" followed by something in "hcl" then that's specific enough |
| 58 | // for now, even though this is not 100% exact as a correct |
| 59 | // implementation of Value. |
| 60 | |
| 61 | recvTy := fd.Recv.List[0].Type |
| 62 | |
| 63 | switch rtt := recvTy.(type) { |
| 64 | case *ast.StarExpr: |
| 65 | name := rtt.X.(*ast.Ident).Name |
| 66 | recvs = append(recvs, fmt.Sprintf("*%s", name)) |
| 67 | default: |
| 68 | fmt.Fprintf(os.Stderr, "don't know what to do with a %T receiver\n", recvTy) |
| 69 | } |
| 70 | |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | sort.Strings(recvs) |
| 75 | |
| 76 | of, err := os.OpenFile("expression_vars.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) |
| 77 | if err != nil { |
| 78 | fmt.Fprintf(os.Stderr, "failed to open output file: %s\n", err) |
| 79 | os.Exit(1) |
| 80 | } |
| 81 | |