diff options
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.go | 121 |
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 @@ | |||
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 | 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. | ||
105 | func 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 | } | ||