aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go')
-rw-r--r--vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go121
1 files changed, 121 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go b/vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go
new file mode 100644
index 0000000..5f52946
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go
@@ -0,0 +1,121 @@
1package hcl
2
3// AbsTraversalForExpr attempts to interpret the given expression as
4// an absolute traversal, or returns error diagnostic(s) if that is
5// not possible for the given expression.
6//
7// A particular Expression implementation can support this function by
8// offering a method called AsTraversal that takes no arguments and
9// returns either a valid absolute traversal or nil to indicate that
10// no traversal is possible. Alternatively, an implementation can support
11// UnwrapExpression to delegate handling of this function to a wrapped
12// Expression object.
13//
14// In most cases the calling application is interested in the value
15// that results from an expression, but in rarer cases the application
16// needs to see the the name of the variable and subsequent
17// attributes/indexes itself, for example to allow users to give references
18// to the variables themselves rather than to their values. An implementer
19// of this function should at least support attribute and index steps.
20func AbsTraversalForExpr(expr Expression) (Traversal, Diagnostics) {
21 type asTraversal interface {
22 AsTraversal() Traversal
23 }
24
25 physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool {
26 _, supported := expr.(asTraversal)
27 return supported
28 })
29
30 if asT, supported := physExpr.(asTraversal); supported {
31 if traversal := asT.AsTraversal(); traversal != nil {
32 return traversal, nil
33 }
34 }
35 return nil, Diagnostics{
36 &Diagnostic{
37 Severity: DiagError,
38 Summary: "Invalid expression",
39 Detail: "A static variable reference is required.",
40 Subject: expr.Range().Ptr(),
41 },
42 }
43}
44
45// RelTraversalForExpr is similar to AbsTraversalForExpr but it returns
46// a relative traversal instead. Due to the nature of HCL expressions, the
47// first element of the returned traversal is always a TraverseAttr, and
48// then it will be followed by zero or more other expressions.
49//
50// Any expression accepted by AbsTraversalForExpr is also accepted by
51// RelTraversalForExpr.
52func RelTraversalForExpr(expr Expression) (Traversal, Diagnostics) {
53 traversal, diags := AbsTraversalForExpr(expr)
54 if len(traversal) > 0 {
55 root := traversal[0].(TraverseRoot)
56 traversal[0] = TraverseAttr{
57 Name: root.Name,
58 SrcRange: root.SrcRange,
59 }
60 }
61 return traversal, diags
62}
63
64// ExprAsKeyword attempts to interpret the given expression as a static keyword,
65// returning the keyword string if possible, and the empty string if not.
66//
67// A static keyword, for the sake of this function, is a single identifier.
68// For example, the following attribute has an expression that would produce
69// the keyword "foo":
70//
71// example = foo
72//
73// This function is a variant of AbsTraversalForExpr, which uses the same
74// interface on the given expression. This helper constrains the result
75// further by requiring only a single root identifier.
76//
77// This function is intended to be used with the following idiom, to recognize
78// situations where one of a fixed set of keywords is required and arbitrary
79// expressions are not allowed:
80//
81// switch hcl.ExprAsKeyword(expr) {
82// case "allow":
83// // (take suitable action for keyword "allow")
84// case "deny":
85// // (take suitable action for keyword "deny")
86// default:
87// diags = append(diags, &hcl.Diagnostic{
88// // ... "invalid keyword" diagnostic message ...
89// })
90// }
91//
92// The above approach will generate the same message for both the use of an
93// unrecognized keyword and for not using a keyword at all, which is usually
94// reasonable if the message specifies that the given value must be a keyword
95// from that fixed list.
96//
97// Note that in the native syntax the keywords "true", "false", and "null" are
98// recognized as literal values during parsing and so these reserved words
99// cannot not be accepted as keywords by this function.
100//
101// Since interpreting an expression as a keyword bypasses usual expression
102// evaluation, it should be used sparingly for situations where e.g. one of
103// a fixed set of keywords is used in a structural way in a special attribute
104// to affect the further processing of a block.
105func ExprAsKeyword(expr Expression) string {
106 type asTraversal interface {
107 AsTraversal() Traversal
108 }
109
110 physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool {
111 _, supported := expr.(asTraversal)
112 return supported
113 })
114
115 if asT, supported := physExpr.(asTraversal); supported {
116 if traversal := asT.AsTraversal(); len(traversal) == 1 {
117 return traversal.RootName()
118 }
119 }
120 return ""
121}