]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hcl2/hcl/traversal_for_expr.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hcl2 / hcl / traversal_for_expr.go
1 package 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.
20 func 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.
52 func RelTraversalForExpr(expr Expression) (Traversal, Diagnostics) {
53 traversal, diags := AbsTraversalForExpr(expr)
54 if len(traversal) > 0 {
55 ret := make(Traversal, len(traversal))
56 copy(ret, traversal)
57 root := traversal[0].(TraverseRoot)
58 ret[0] = TraverseAttr{
59 Name: root.Name,
60 SrcRange: root.SrcRange,
61 }
62 return ret, diags
63 }
64 return traversal, diags
65 }
66
67 // ExprAsKeyword attempts to interpret the given expression as a static keyword,
68 // returning the keyword string if possible, and the empty string if not.
69 //
70 // A static keyword, for the sake of this function, is a single identifier.
71 // For example, the following attribute has an expression that would produce
72 // the keyword "foo":
73 //
74 // example = foo
75 //
76 // This function is a variant of AbsTraversalForExpr, which uses the same
77 // interface on the given expression. This helper constrains the result
78 // further by requiring only a single root identifier.
79 //
80 // This function is intended to be used with the following idiom, to recognize
81 // situations where one of a fixed set of keywords is required and arbitrary
82 // expressions are not allowed:
83 //
84 // switch hcl.ExprAsKeyword(expr) {
85 // case "allow":
86 // // (take suitable action for keyword "allow")
87 // case "deny":
88 // // (take suitable action for keyword "deny")
89 // default:
90 // diags = append(diags, &hcl.Diagnostic{
91 // // ... "invalid keyword" diagnostic message ...
92 // })
93 // }
94 //
95 // The above approach will generate the same message for both the use of an
96 // unrecognized keyword and for not using a keyword at all, which is usually
97 // reasonable if the message specifies that the given value must be a keyword
98 // from that fixed list.
99 //
100 // Note that in the native syntax the keywords "true", "false", and "null" are
101 // recognized as literal values during parsing and so these reserved words
102 // cannot not be accepted as keywords by this function.
103 //
104 // Since interpreting an expression as a keyword bypasses usual expression
105 // evaluation, it should be used sparingly for situations where e.g. one of
106 // a fixed set of keywords is used in a structural way in a special attribute
107 // to affect the further processing of a block.
108 func ExprAsKeyword(expr Expression) string {
109 type asTraversal interface {
110 AsTraversal() Traversal
111 }
112
113 physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool {
114 _, supported := expr.(asTraversal)
115 return supported
116 })
117
118 if asT, supported := physExpr.(asTraversal); supported {
119 if traversal := asT.AsTraversal(); len(traversal) == 1 {
120 return traversal.RootName()
121 }
122 }
123 return ""
124 }