diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hil/check_identifier.go')
-rw-r--r-- | vendor/github.com/hashicorp/hil/check_identifier.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hil/check_identifier.go b/vendor/github.com/hashicorp/hil/check_identifier.go new file mode 100644 index 0000000..474f505 --- /dev/null +++ b/vendor/github.com/hashicorp/hil/check_identifier.go | |||
@@ -0,0 +1,88 @@ | |||
1 | package hil | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "sync" | ||
6 | |||
7 | "github.com/hashicorp/hil/ast" | ||
8 | ) | ||
9 | |||
10 | // IdentifierCheck is a SemanticCheck that checks that all identifiers | ||
11 | // resolve properly and that the right number of arguments are passed | ||
12 | // to functions. | ||
13 | type IdentifierCheck struct { | ||
14 | Scope ast.Scope | ||
15 | |||
16 | err error | ||
17 | lock sync.Mutex | ||
18 | } | ||
19 | |||
20 | func (c *IdentifierCheck) Visit(root ast.Node) error { | ||
21 | c.lock.Lock() | ||
22 | defer c.lock.Unlock() | ||
23 | defer c.reset() | ||
24 | root.Accept(c.visit) | ||
25 | return c.err | ||
26 | } | ||
27 | |||
28 | func (c *IdentifierCheck) visit(raw ast.Node) ast.Node { | ||
29 | if c.err != nil { | ||
30 | return raw | ||
31 | } | ||
32 | |||
33 | switch n := raw.(type) { | ||
34 | case *ast.Call: | ||
35 | c.visitCall(n) | ||
36 | case *ast.VariableAccess: | ||
37 | c.visitVariableAccess(n) | ||
38 | case *ast.Output: | ||
39 | // Ignore | ||
40 | case *ast.LiteralNode: | ||
41 | // Ignore | ||
42 | default: | ||
43 | // Ignore | ||
44 | } | ||
45 | |||
46 | // We never do replacement with this visitor | ||
47 | return raw | ||
48 | } | ||
49 | |||
50 | func (c *IdentifierCheck) visitCall(n *ast.Call) { | ||
51 | // Look up the function in the map | ||
52 | function, ok := c.Scope.LookupFunc(n.Func) | ||
53 | if !ok { | ||
54 | c.createErr(n, fmt.Sprintf("unknown function called: %s", n.Func)) | ||
55 | return | ||
56 | } | ||
57 | |||
58 | // Break up the args into what is variadic and what is required | ||
59 | args := n.Args | ||
60 | if function.Variadic && len(args) > len(function.ArgTypes) { | ||
61 | args = n.Args[:len(function.ArgTypes)] | ||
62 | } | ||
63 | |||
64 | // Verify the number of arguments | ||
65 | if len(args) != len(function.ArgTypes) { | ||
66 | c.createErr(n, fmt.Sprintf( | ||
67 | "%s: expected %d arguments, got %d", | ||
68 | n.Func, len(function.ArgTypes), len(n.Args))) | ||
69 | return | ||
70 | } | ||
71 | } | ||
72 | |||
73 | func (c *IdentifierCheck) visitVariableAccess(n *ast.VariableAccess) { | ||
74 | // Look up the variable in the map | ||
75 | if _, ok := c.Scope.LookupVar(n.Name); !ok { | ||
76 | c.createErr(n, fmt.Sprintf( | ||
77 | "unknown variable accessed: %s", n.Name)) | ||
78 | return | ||
79 | } | ||
80 | } | ||
81 | |||
82 | func (c *IdentifierCheck) createErr(n ast.Node, str string) { | ||
83 | c.err = fmt.Errorf("%s: %s", n.Pos(), str) | ||
84 | } | ||
85 | |||
86 | func (c *IdentifierCheck) reset() { | ||
87 | c.err = nil | ||
88 | } | ||