diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/variables.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/variables.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/variables.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/variables.go new file mode 100644 index 0000000..eeee1a5 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/variables.go | |||
@@ -0,0 +1,86 @@ | |||
1 | package hclsyntax | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/hcl2/hcl" | ||
5 | ) | ||
6 | |||
7 | // Variables returns all of the variables referenced within a given experssion. | ||
8 | // | ||
9 | // This is the implementation of the "Variables" method on every native | ||
10 | // expression. | ||
11 | func Variables(expr Expression) []hcl.Traversal { | ||
12 | var vars []hcl.Traversal | ||
13 | |||
14 | walker := &variablesWalker{ | ||
15 | Callback: func(t hcl.Traversal) { | ||
16 | vars = append(vars, t) | ||
17 | }, | ||
18 | } | ||
19 | |||
20 | Walk(expr, walker) | ||
21 | |||
22 | return vars | ||
23 | } | ||
24 | |||
25 | // variablesWalker is a Walker implementation that calls its callback for any | ||
26 | // root scope traversal found while walking. | ||
27 | type variablesWalker struct { | ||
28 | Callback func(hcl.Traversal) | ||
29 | localScopes []map[string]struct{} | ||
30 | } | ||
31 | |||
32 | func (w *variablesWalker) Enter(n Node) hcl.Diagnostics { | ||
33 | switch tn := n.(type) { | ||
34 | case *ScopeTraversalExpr: | ||
35 | t := tn.Traversal | ||
36 | |||
37 | // Check if the given root name appears in any of the active | ||
38 | // local scopes. We don't want to return local variables here, since | ||
39 | // the goal of walking variables is to tell the calling application | ||
40 | // which names it needs to populate in the _root_ scope. | ||
41 | name := t.RootName() | ||
42 | for _, names := range w.localScopes { | ||
43 | if _, localized := names[name]; localized { | ||
44 | return nil | ||
45 | } | ||
46 | } | ||
47 | |||
48 | w.Callback(t) | ||
49 | case ChildScope: | ||
50 | w.localScopes = append(w.localScopes, tn.LocalNames) | ||
51 | } | ||
52 | return nil | ||
53 | } | ||
54 | |||
55 | func (w *variablesWalker) Exit(n Node) hcl.Diagnostics { | ||
56 | switch n.(type) { | ||
57 | case ChildScope: | ||
58 | // pop the latest local scope, assuming that the walker will | ||
59 | // behave symmetrically as promised. | ||
60 | w.localScopes = w.localScopes[:len(w.localScopes)-1] | ||
61 | } | ||
62 | return nil | ||
63 | } | ||
64 | |||
65 | // ChildScope is a synthetic AST node that is visited during a walk to | ||
66 | // indicate that its descendent will be evaluated in a child scope, which | ||
67 | // may mask certain variables from the parent scope as locals. | ||
68 | // | ||
69 | // ChildScope nodes don't really exist in the AST, but are rather synthesized | ||
70 | // on the fly during walk. Therefore it doesn't do any good to transform them; | ||
71 | // instead, transform either parent node that created a scope or the expression | ||
72 | // that the child scope struct wraps. | ||
73 | type ChildScope struct { | ||
74 | LocalNames map[string]struct{} | ||
75 | Expr *Expression // pointer because it can be replaced on walk | ||
76 | } | ||
77 | |||
78 | func (e ChildScope) walkChildNodes(w internalWalkFunc) { | ||
79 | *(e.Expr) = w(*(e.Expr)).(Expression) | ||
80 | } | ||
81 | |||
82 | // Range returns the range of the expression that the ChildScope is | ||
83 | // encapsulating. It isn't really very useful to call Range on a ChildScope. | ||
84 | func (e ChildScope) Range() hcl.Range { | ||
85 | return (*e.Expr).Range() | ||
86 | } | ||