aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/ext
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/ext')
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/README.md184
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_body.go262
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_spec.go215
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/expr_wrap.go42
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/iteration.go66
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/public.go44
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/schema.go50
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/unknown_body.go84
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/variables.go209
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/dynblock/variables_hcldec.go43
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/typeexpr/README.md67
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/typeexpr/doc.go11
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/typeexpr/get_type.go196
-rw-r--r--vendor/github.com/hashicorp/hcl2/ext/typeexpr/public.go129
14 files changed, 1602 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/README.md b/vendor/github.com/hashicorp/hcl2/ext/dynblock/README.md
new file mode 100644
index 0000000..2b24fdb
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/README.md
@@ -0,0 +1,184 @@
1# HCL Dynamic Blocks Extension
2
3This HCL extension implements a special block type named "dynamic" that can
4be used to dynamically generate blocks of other types by iterating over
5collection values.
6
7Normally the block structure in an HCL configuration file is rigid, even
8though dynamic expressions can be used within attribute values. This is
9convenient for most applications since it allows the overall structure of
10the document to be decoded easily, but in some applications it is desirable
11to allow dynamic block generation within certain portions of the configuration.
12
13Dynamic block generation is performed using the `dynamic` block type:
14
15```hcl
16toplevel {
17 nested {
18 foo = "static block 1"
19 }
20
21 dynamic "nested" {
22 for_each = ["a", "b", "c"]
23 iterator = nested
24 content {
25 foo = "dynamic block ${nested.value}"
26 }
27 }
28
29 nested {
30 foo = "static block 2"
31 }
32}
33```
34
35The above is interpreted as if it were written as follows:
36
37```hcl
38toplevel {
39 nested {
40 foo = "static block 1"
41 }
42
43 nested {
44 foo = "dynamic block a"
45 }
46
47 nested {
48 foo = "dynamic block b"
49 }
50
51 nested {
52 foo = "dynamic block c"
53 }
54
55 nested {
56 foo = "static block 2"
57 }
58}
59```
60
61Since HCL block syntax is not normally exposed to the possibility of unknown
62values, this extension must make some compromises when asked to iterate over
63an unknown collection. If the length of the collection cannot be statically
64recognized (because it is an unknown value of list, map, or set type) then
65the `dynamic` construct will generate a _single_ dynamic block whose iterator
66key and value are both unknown values of the dynamic pseudo-type, thus causing
67any attribute values derived from iteration to appear as unknown values. There
68is no explicit representation of the fact that the length of the collection may
69eventually be different than one.
70
71## Usage
72
73Pass a body to function `Expand` to obtain a new body that will, on access
74to its content, evaluate and expand any nested `dynamic` blocks.
75Dynamic block processing is also automatically propagated into any nested
76blocks that are returned, allowing users to nest dynamic blocks inside
77one another and to nest dynamic blocks inside other static blocks.
78
79HCL structural decoding does not normally have access to an `EvalContext`, so
80any variables and functions that should be available to the `for_each`
81and `labels` expressions must be passed in when calling `Expand`. Expressions
82within the `content` block are evaluated separately and so can be passed a
83separate `EvalContext` if desired, during normal attribute expression
84evaluation.
85
86## Detecting Variables
87
88Some applications dynamically generate an `EvalContext` by analyzing which
89variables are referenced by an expression before evaluating it.
90
91This unfortunately requires some extra effort when this analysis is required
92for the context passed to `Expand`: the HCL API requires a schema to be
93provided in order to do any analysis of the blocks in a body, but the low-level
94schema model provides a description of only one level of nested blocks at
95a time, and thus a new schema must be provided for each additional level of
96nesting.
97
98To make this arduous process as convenient as possbile, this package provides
99a helper function `WalkForEachVariables`, which returns a `WalkVariablesNode`
100instance that can be used to find variables directly in a given body and also
101determine which nested blocks require recursive calls. Using this mechanism
102requires that the caller be able to look up a schema given a nested block type.
103For _simple_ formats where a specific block type name always has the same schema
104regardless of context, a walk can be implemented as follows:
105
106```go
107func walkVariables(node dynblock.WalkVariablesNode, schema *hcl.BodySchema) []hcl.Traversal {
108 vars, children := node.Visit(schema)
109
110 for _, child := range children {
111 var childSchema *hcl.BodySchema
112 switch child.BlockTypeName {
113 case "a":
114 childSchema = &hcl.BodySchema{
115 Blocks: []hcl.BlockHeaderSchema{
116 {
117 Type: "b",
118 LabelNames: []string{"key"},
119 },
120 },
121 }
122 case "b":
123 childSchema = &hcl.BodySchema{
124 Attributes: []hcl.AttributeSchema{
125 {
126 Name: "val",
127 Required: true,
128 },
129 },
130 }
131 default:
132 // Should never happen, because the above cases should be exhaustive
133 // for the application's configuration format.
134 panic(fmt.Errorf("can't find schema for unknown block type %q", child.BlockTypeName))
135 }
136
137 vars = append(vars, testWalkAndAccumVars(child.Node, childSchema)...)
138 }
139}
140```
141
142### Detecting Variables with `hcldec` Specifications
143
144For applications that use the higher-level `hcldec` package to decode nested
145configuration structures into `cty` values, the same specification can be used
146to automatically drive the recursive variable-detection walk described above.
147
148The helper function `ForEachVariablesHCLDec` allows an entire recursive
149configuration structure to be analyzed in a single call given a `hcldec.Spec`
150that describes the nested block structure. This means a `hcldec`-based
151application can support dynamic blocks with only a little additional effort:
152
153```go
154func decodeBody(body hcl.Body, spec hcldec.Spec) (cty.Value, hcl.Diagnostics) {
155 // Determine which variables are needed to expand dynamic blocks
156 neededForDynamic := dynblock.ForEachVariablesHCLDec(body, spec)
157
158 // Build a suitable EvalContext and expand dynamic blocks
159 dynCtx := buildEvalContext(neededForDynamic)
160 dynBody := dynblock.Expand(body, dynCtx)
161
162 // Determine which variables are needed to fully decode the expanded body
163 // This will analyze expressions that came both from static blocks in the
164 // original body and from blocks that were dynamically added by Expand.
165 neededForDecode := hcldec.Variables(dynBody, spec)
166
167 // Build a suitable EvalContext and then fully decode the body as per the
168 // hcldec specification.
169 decCtx := buildEvalContext(neededForDecode)
170 return hcldec.Decode(dynBody, spec, decCtx)
171}
172
173func buildEvalContext(needed []hcl.Traversal) *hcl.EvalContext {
174 // (to be implemented by your application)
175}
176```
177
178# Performance
179
180This extension is going quite harshly against the grain of the HCL API, and
181so it uses lots of wrapping objects and temporary data structures to get its
182work done. HCL in general is not suitable for use in high-performance situations
183or situations sensitive to memory pressure, but that is _especially_ true for
184this extension.
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_body.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_body.go
new file mode 100644
index 0000000..dd30822
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_body.go
@@ -0,0 +1,262 @@
1package dynblock
2
3import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/zclconf/go-cty/cty"
8)
9
10// expandBody wraps another hcl.Body and expands any "dynamic" blocks found
11// inside whenever Content or PartialContent is called.
12type expandBody struct {
13 original hcl.Body
14 forEachCtx *hcl.EvalContext
15 iteration *iteration // non-nil if we're nested inside another "dynamic" block
16
17 // These are used with PartialContent to produce a "remaining items"
18 // body to return. They are nil on all bodies fresh out of the transformer.
19 //
20 // Note that this is re-implemented here rather than delegating to the
21 // existing support required by the underlying body because we need to
22 // retain access to the entire original body on subsequent decode operations
23 // so we can retain any "dynamic" blocks for types we didn't take consume
24 // on the first pass.
25 hiddenAttrs map[string]struct{}
26 hiddenBlocks map[string]hcl.BlockHeaderSchema
27}
28
29func (b *expandBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
30 extSchema := b.extendSchema(schema)
31 rawContent, diags := b.original.Content(extSchema)
32
33 blocks, blockDiags := b.expandBlocks(schema, rawContent.Blocks, false)
34 diags = append(diags, blockDiags...)
35 attrs := b.prepareAttributes(rawContent.Attributes)
36
37 content := &hcl.BodyContent{
38 Attributes: attrs,
39 Blocks: blocks,
40 MissingItemRange: b.original.MissingItemRange(),
41 }
42
43 return content, diags
44}
45
46func (b *expandBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
47 extSchema := b.extendSchema(schema)
48 rawContent, _, diags := b.original.PartialContent(extSchema)
49 // We discard the "remain" argument above because we're going to construct
50 // our own remain that also takes into account remaining "dynamic" blocks.
51
52 blocks, blockDiags := b.expandBlocks(schema, rawContent.Blocks, true)
53 diags = append(diags, blockDiags...)
54 attrs := b.prepareAttributes(rawContent.Attributes)
55
56 content := &hcl.BodyContent{
57 Attributes: attrs,
58 Blocks: blocks,
59 MissingItemRange: b.original.MissingItemRange(),
60 }
61
62 remain := &expandBody{
63 original: b.original,
64 forEachCtx: b.forEachCtx,
65 iteration: b.iteration,
66 hiddenAttrs: make(map[string]struct{}),
67 hiddenBlocks: make(map[string]hcl.BlockHeaderSchema),
68 }
69 for name := range b.hiddenAttrs {
70 remain.hiddenAttrs[name] = struct{}{}
71 }
72 for typeName, blockS := range b.hiddenBlocks {
73 remain.hiddenBlocks[typeName] = blockS
74 }
75 for _, attrS := range schema.Attributes {
76 remain.hiddenAttrs[attrS.Name] = struct{}{}
77 }
78 for _, blockS := range schema.Blocks {
79 remain.hiddenBlocks[blockS.Type] = blockS
80 }
81
82 return content, remain, diags
83}
84
85func (b *expandBody) extendSchema(schema *hcl.BodySchema) *hcl.BodySchema {
86 // We augment the requested schema to also include our special "dynamic"
87 // block type, since then we'll get instances of it interleaved with
88 // all of the literal child blocks we must also include.
89 extSchema := &hcl.BodySchema{
90 Attributes: schema.Attributes,
91 Blocks: make([]hcl.BlockHeaderSchema, len(schema.Blocks), len(schema.Blocks)+len(b.hiddenBlocks)+1),
92 }
93 copy(extSchema.Blocks, schema.Blocks)
94 extSchema.Blocks = append(extSchema.Blocks, dynamicBlockHeaderSchema)
95
96 // If we have any hiddenBlocks then we also need to register those here
97 // so that a call to "Content" on the underlying body won't fail.
98 // (We'll filter these out again once we process the result of either
99 // Content or PartialContent.)
100 for _, blockS := range b.hiddenBlocks {
101 extSchema.Blocks = append(extSchema.Blocks, blockS)
102 }
103
104 // If we have any hiddenAttrs then we also need to register these, for
105 // the same reason as we deal with hiddenBlocks above.
106 if len(b.hiddenAttrs) != 0 {
107 newAttrs := make([]hcl.AttributeSchema, len(schema.Attributes), len(schema.Attributes)+len(b.hiddenAttrs))
108 copy(newAttrs, extSchema.Attributes)
109 for name := range b.hiddenAttrs {
110 newAttrs = append(newAttrs, hcl.AttributeSchema{
111 Name: name,
112 Required: false,
113 })
114 }
115 extSchema.Attributes = newAttrs
116 }
117
118 return extSchema
119}
120
121func (b *expandBody) prepareAttributes(rawAttrs hcl.Attributes) hcl.Attributes {
122 if len(b.hiddenAttrs) == 0 && b.iteration == nil {
123 // Easy path: just pass through the attrs from the original body verbatim
124 return rawAttrs
125 }
126
127 // Otherwise we have some work to do: we must filter out any attributes
128 // that are hidden (since a previous PartialContent call already saw these)
129 // and wrap the expressions of the inner attributes so that they will
130 // have access to our iteration variables.
131 attrs := make(hcl.Attributes, len(rawAttrs))
132 for name, rawAttr := range rawAttrs {
133 if _, hidden := b.hiddenAttrs[name]; hidden {
134 continue
135 }
136 if b.iteration != nil {
137 attr := *rawAttr // shallow copy so we can mutate it
138 attr.Expr = exprWrap{
139 Expression: attr.Expr,
140 i: b.iteration,
141 }
142 attrs[name] = &attr
143 } else {
144 // If we have no active iteration then no wrapping is required.
145 attrs[name] = rawAttr
146 }
147 }
148 return attrs
149}
150
151func (b *expandBody) expandBlocks(schema *hcl.BodySchema, rawBlocks hcl.Blocks, partial bool) (hcl.Blocks, hcl.Diagnostics) {
152 var blocks hcl.Blocks
153 var diags hcl.Diagnostics
154
155 for _, rawBlock := range rawBlocks {
156 switch rawBlock.Type {
157 case "dynamic":
158 realBlockType := rawBlock.Labels[0]
159 if _, hidden := b.hiddenBlocks[realBlockType]; hidden {
160 continue
161 }
162
163 var blockS *hcl.BlockHeaderSchema
164 for _, candidate := range schema.Blocks {
165 if candidate.Type == realBlockType {
166 blockS = &candidate
167 break
168 }
169 }
170 if blockS == nil {
171 // Not a block type that the caller requested.
172 if !partial {
173 diags = append(diags, &hcl.Diagnostic{
174 Severity: hcl.DiagError,
175 Summary: "Unsupported block type",
176 Detail: fmt.Sprintf("Blocks of type %q are not expected here.", realBlockType),
177 Subject: &rawBlock.LabelRanges[0],
178 })
179 }
180 continue
181 }
182
183 spec, specDiags := b.decodeSpec(blockS, rawBlock)
184 diags = append(diags, specDiags...)
185 if specDiags.HasErrors() {
186 continue
187 }
188
189 if spec.forEachVal.IsKnown() {
190 for it := spec.forEachVal.ElementIterator(); it.Next(); {
191 key, value := it.Element()
192 i := b.iteration.MakeChild(spec.iteratorName, key, value)
193
194 block, blockDiags := spec.newBlock(i, b.forEachCtx)
195 diags = append(diags, blockDiags...)
196 if block != nil {
197 // Attach our new iteration context so that attributes
198 // and other nested blocks can refer to our iterator.
199 block.Body = b.expandChild(block.Body, i)
200 blocks = append(blocks, block)
201 }
202 }
203 } else {
204 // If our top-level iteration value isn't known then we're forced
205 // to compromise since HCL doesn't have any concept of an
206 // "unknown block". In this case then, we'll produce a single
207 // dynamic block with the iterator values set to DynamicVal,
208 // which at least makes the potential for a block visible
209 // in our result, even though it's not represented in a fully-accurate
210 // way.
211 i := b.iteration.MakeChild(spec.iteratorName, cty.DynamicVal, cty.DynamicVal)
212 block, blockDiags := spec.newBlock(i, b.forEachCtx)
213 diags = append(diags, blockDiags...)
214 if block != nil {
215 block.Body = b.expandChild(block.Body, i)
216
217 // We additionally force all of the leaf attribute values
218 // in the result to be unknown so the calling application
219 // can, if necessary, use that as a heuristic to detect
220 // when a single nested block might be standing in for
221 // multiple blocks yet to be expanded. This retains the
222 // structure of the generated body but forces all of its
223 // leaf attribute values to be unknown.
224 block.Body = unknownBody{block.Body}
225
226 blocks = append(blocks, block)
227 }
228 }
229
230 default:
231 if _, hidden := b.hiddenBlocks[rawBlock.Type]; !hidden {
232 // A static block doesn't create a new iteration context, but
233 // it does need to inherit _our own_ iteration context in
234 // case it contains expressions that refer to our inherited
235 // iterators, or nested "dynamic" blocks.
236 expandedBlock := *rawBlock // shallow copy
237 expandedBlock.Body = b.expandChild(rawBlock.Body, b.iteration)
238 blocks = append(blocks, &expandedBlock)
239 }
240 }
241 }
242
243 return blocks, diags
244}
245
246func (b *expandBody) expandChild(child hcl.Body, i *iteration) hcl.Body {
247 chiCtx := i.EvalContext(b.forEachCtx)
248 ret := Expand(child, chiCtx)
249 ret.(*expandBody).iteration = i
250 return ret
251}
252
253func (b *expandBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
254 // blocks aren't allowed in JustAttributes mode and this body can
255 // only produce blocks, so we'll just pass straight through to our
256 // underlying body here.
257 return b.original.JustAttributes()
258}
259
260func (b *expandBody) MissingItemRange() hcl.Range {
261 return b.original.MissingItemRange()
262}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_spec.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_spec.go
new file mode 100644
index 0000000..41c0be2
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_spec.go
@@ -0,0 +1,215 @@
1package dynblock
2
3import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/zclconf/go-cty/cty"
8 "github.com/zclconf/go-cty/cty/convert"
9)
10
11type expandSpec struct {
12 blockType string
13 blockTypeRange hcl.Range
14 defRange hcl.Range
15 forEachVal cty.Value
16 iteratorName string
17 labelExprs []hcl.Expression
18 contentBody hcl.Body
19 inherited map[string]*iteration
20}
21
22func (b *expandBody) decodeSpec(blockS *hcl.BlockHeaderSchema, rawSpec *hcl.Block) (*expandSpec, hcl.Diagnostics) {
23 var diags hcl.Diagnostics
24
25 var schema *hcl.BodySchema
26 if len(blockS.LabelNames) != 0 {
27 schema = dynamicBlockBodySchemaLabels
28 } else {
29 schema = dynamicBlockBodySchemaNoLabels
30 }
31
32 specContent, specDiags := rawSpec.Body.Content(schema)
33 diags = append(diags, specDiags...)
34 if specDiags.HasErrors() {
35 return nil, diags
36 }
37
38 //// for_each attribute
39
40 eachAttr := specContent.Attributes["for_each"]
41 eachVal, eachDiags := eachAttr.Expr.Value(b.forEachCtx)
42 diags = append(diags, eachDiags...)
43
44 if !eachVal.CanIterateElements() && eachVal.Type() != cty.DynamicPseudoType {
45 // We skip this error for DynamicPseudoType because that means we either
46 // have a null (which is checked immediately below) or an unknown
47 // (which is handled in the expandBody Content methods).
48 diags = append(diags, &hcl.Diagnostic{
49 Severity: hcl.DiagError,
50 Summary: "Invalid dynamic for_each value",
51 Detail: fmt.Sprintf("Cannot use a %s value in for_each. An iterable collection is required.", eachVal.Type().FriendlyName()),
52 Subject: eachAttr.Expr.Range().Ptr(),
53 Expression: eachAttr.Expr,
54 EvalContext: b.forEachCtx,
55 })
56 return nil, diags
57 }
58 if eachVal.IsNull() {
59 diags = append(diags, &hcl.Diagnostic{
60 Severity: hcl.DiagError,
61 Summary: "Invalid dynamic for_each value",
62 Detail: "Cannot use a null value in for_each.",
63 Subject: eachAttr.Expr.Range().Ptr(),
64 Expression: eachAttr.Expr,
65 EvalContext: b.forEachCtx,
66 })
67 return nil, diags
68 }
69
70 //// iterator attribute
71
72 iteratorName := blockS.Type
73 if iteratorAttr := specContent.Attributes["iterator"]; iteratorAttr != nil {
74 itTraversal, itDiags := hcl.AbsTraversalForExpr(iteratorAttr.Expr)
75 diags = append(diags, itDiags...)
76 if itDiags.HasErrors() {
77 return nil, diags
78 }
79
80 if len(itTraversal) != 1 {
81 diags = append(diags, &hcl.Diagnostic{
82 Severity: hcl.DiagError,
83 Summary: "Invalid dynamic iterator name",
84 Detail: "Dynamic iterator must be a single variable name.",
85 Subject: itTraversal.SourceRange().Ptr(),
86 })
87 return nil, diags
88 }
89
90 iteratorName = itTraversal.RootName()
91 }
92
93 var labelExprs []hcl.Expression
94 if labelsAttr := specContent.Attributes["labels"]; labelsAttr != nil {
95 var labelDiags hcl.Diagnostics
96 labelExprs, labelDiags = hcl.ExprList(labelsAttr.Expr)
97 diags = append(diags, labelDiags...)
98 if labelDiags.HasErrors() {
99 return nil, diags
100 }
101
102 if len(labelExprs) > len(blockS.LabelNames) {
103 diags = append(diags, &hcl.Diagnostic{
104 Severity: hcl.DiagError,
105 Summary: "Extraneous dynamic block label",
106 Detail: fmt.Sprintf("Blocks of type %q require %d label(s).", blockS.Type, len(blockS.LabelNames)),
107 Subject: labelExprs[len(blockS.LabelNames)].Range().Ptr(),
108 })
109 return nil, diags
110 } else if len(labelExprs) < len(blockS.LabelNames) {
111 diags = append(diags, &hcl.Diagnostic{
112 Severity: hcl.DiagError,
113 Summary: "Insufficient dynamic block labels",
114 Detail: fmt.Sprintf("Blocks of type %q require %d label(s).", blockS.Type, len(blockS.LabelNames)),
115 Subject: labelsAttr.Expr.Range().Ptr(),
116 })
117 return nil, diags
118 }
119 }
120
121 // Since our schema requests only blocks of type "content", we can assume
122 // that all entries in specContent.Blocks are content blocks.
123 if len(specContent.Blocks) == 0 {
124 diags = append(diags, &hcl.Diagnostic{
125 Severity: hcl.DiagError,
126 Summary: "Missing dynamic content block",
127 Detail: "A dynamic block must have a nested block of type \"content\" to describe the body of each generated block.",
128 Subject: &specContent.MissingItemRange,
129 })
130 return nil, diags
131 }
132 if len(specContent.Blocks) > 1 {
133 diags = append(diags, &hcl.Diagnostic{
134 Severity: hcl.DiagError,
135 Summary: "Extraneous dynamic content block",
136 Detail: "Only one nested content block is allowed for each dynamic block.",
137 Subject: &specContent.Blocks[1].DefRange,
138 })
139 return nil, diags
140 }
141
142 return &expandSpec{
143 blockType: blockS.Type,
144 blockTypeRange: rawSpec.LabelRanges[0],
145 defRange: rawSpec.DefRange,
146 forEachVal: eachVal,
147 iteratorName: iteratorName,
148 labelExprs: labelExprs,
149 contentBody: specContent.Blocks[0].Body,
150 }, diags
151}
152
153func (s *expandSpec) newBlock(i *iteration, ctx *hcl.EvalContext) (*hcl.Block, hcl.Diagnostics) {
154 var diags hcl.Diagnostics
155 var labels []string
156 var labelRanges []hcl.Range
157 lCtx := i.EvalContext(ctx)
158 for _, labelExpr := range s.labelExprs {
159 labelVal, labelDiags := labelExpr.Value(lCtx)
160 diags = append(diags, labelDiags...)
161 if labelDiags.HasErrors() {
162 return nil, diags
163 }
164
165 var convErr error
166 labelVal, convErr = convert.Convert(labelVal, cty.String)
167 if convErr != nil {
168 diags = append(diags, &hcl.Diagnostic{
169 Severity: hcl.DiagError,
170 Summary: "Invalid dynamic block label",
171 Detail: fmt.Sprintf("Cannot use this value as a dynamic block label: %s.", convErr),
172 Subject: labelExpr.Range().Ptr(),
173 Expression: labelExpr,
174 EvalContext: lCtx,
175 })
176 return nil, diags
177 }
178 if labelVal.IsNull() {
179 diags = append(diags, &hcl.Diagnostic{
180 Severity: hcl.DiagError,
181 Summary: "Invalid dynamic block label",
182 Detail: "Cannot use a null value as a dynamic block label.",
183 Subject: labelExpr.Range().Ptr(),
184 Expression: labelExpr,
185 EvalContext: lCtx,
186 })
187 return nil, diags
188 }
189 if !labelVal.IsKnown() {
190 diags = append(diags, &hcl.Diagnostic{
191 Severity: hcl.DiagError,
192 Summary: "Invalid dynamic block label",
193 Detail: "This value is not yet known. Dynamic block labels must be immediately-known values.",
194 Subject: labelExpr.Range().Ptr(),
195 Expression: labelExpr,
196 EvalContext: lCtx,
197 })
198 return nil, diags
199 }
200
201 labels = append(labels, labelVal.AsString())
202 labelRanges = append(labelRanges, labelExpr.Range())
203 }
204
205 block := &hcl.Block{
206 Type: s.blockType,
207 TypeRange: s.blockTypeRange,
208 Labels: labels,
209 LabelRanges: labelRanges,
210 DefRange: s.defRange,
211 Body: s.contentBody,
212 }
213
214 return block, diags
215}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/expr_wrap.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expr_wrap.go
new file mode 100644
index 0000000..6916fc1
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/expr_wrap.go
@@ -0,0 +1,42 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/zclconf/go-cty/cty"
6)
7
8type exprWrap struct {
9 hcl.Expression
10 i *iteration
11}
12
13func (e exprWrap) Variables() []hcl.Traversal {
14 raw := e.Expression.Variables()
15 ret := make([]hcl.Traversal, 0, len(raw))
16
17 // Filter out traversals that refer to our iterator name or any
18 // iterator we've inherited; we're going to provide those in
19 // our Value wrapper, so the caller doesn't need to know about them.
20 for _, traversal := range raw {
21 rootName := traversal.RootName()
22 if rootName == e.i.IteratorName {
23 continue
24 }
25 if _, inherited := e.i.Inherited[rootName]; inherited {
26 continue
27 }
28 ret = append(ret, traversal)
29 }
30 return ret
31}
32
33func (e exprWrap) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
34 extCtx := e.i.EvalContext(ctx)
35 return e.Expression.Value(extCtx)
36}
37
38// UnwrapExpression returns the expression being wrapped by this instance.
39// This allows the original expression to be recovered by hcl.UnwrapExpression.
40func (e exprWrap) UnwrapExpression() hcl.Expression {
41 return e.Expression
42}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/iteration.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/iteration.go
new file mode 100644
index 0000000..7056d33
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/iteration.go
@@ -0,0 +1,66 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/zclconf/go-cty/cty"
6)
7
8type iteration struct {
9 IteratorName string
10 Key cty.Value
11 Value cty.Value
12 Inherited map[string]*iteration
13}
14
15func (s *expandSpec) MakeIteration(key, value cty.Value) *iteration {
16 return &iteration{
17 IteratorName: s.iteratorName,
18 Key: key,
19 Value: value,
20 Inherited: s.inherited,
21 }
22}
23
24func (i *iteration) Object() cty.Value {
25 return cty.ObjectVal(map[string]cty.Value{
26 "key": i.Key,
27 "value": i.Value,
28 })
29}
30
31func (i *iteration) EvalContext(base *hcl.EvalContext) *hcl.EvalContext {
32 new := base.NewChild()
33
34 if i != nil {
35 new.Variables = map[string]cty.Value{}
36 for name, otherIt := range i.Inherited {
37 new.Variables[name] = otherIt.Object()
38 }
39 new.Variables[i.IteratorName] = i.Object()
40 }
41
42 return new
43}
44
45func (i *iteration) MakeChild(iteratorName string, key, value cty.Value) *iteration {
46 if i == nil {
47 // Create entirely new root iteration, then
48 return &iteration{
49 IteratorName: iteratorName,
50 Key: key,
51 Value: value,
52 }
53 }
54
55 inherited := map[string]*iteration{}
56 for name, otherIt := range i.Inherited {
57 inherited[name] = otherIt
58 }
59 inherited[i.IteratorName] = i
60 return &iteration{
61 IteratorName: iteratorName,
62 Key: key,
63 Value: value,
64 Inherited: inherited,
65 }
66}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/public.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/public.go
new file mode 100644
index 0000000..b7e8ca9
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/public.go
@@ -0,0 +1,44 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5)
6
7// Expand "dynamic" blocks in the given body, returning a new body that
8// has those blocks expanded.
9//
10// The given EvalContext is used when evaluating "for_each" and "labels"
11// attributes within dynamic blocks, allowing those expressions access to
12// variables and functions beyond the iterator variable created by the
13// iteration.
14//
15// Expand returns no diagnostics because no blocks are actually expanded
16// until a call to Content or PartialContent on the returned body, which
17// will then expand only the blocks selected by the schema.
18//
19// "dynamic" blocks are also expanded automatically within nested blocks
20// in the given body, including within other dynamic blocks, thus allowing
21// multi-dimensional iteration. However, it is not possible to
22// dynamically-generate the "dynamic" blocks themselves except through nesting.
23//
24// parent {
25// dynamic "child" {
26// for_each = child_objs
27// content {
28// dynamic "grandchild" {
29// for_each = child.value.children
30// labels = [grandchild.key]
31// content {
32// parent_key = child.key
33// value = grandchild.value
34// }
35// }
36// }
37// }
38// }
39func Expand(body hcl.Body, ctx *hcl.EvalContext) hcl.Body {
40 return &expandBody{
41 original: body,
42 forEachCtx: ctx,
43 }
44}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/schema.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/schema.go
new file mode 100644
index 0000000..dc8ed5a
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/schema.go
@@ -0,0 +1,50 @@
1package dynblock
2
3import "github.com/hashicorp/hcl2/hcl"
4
5var dynamicBlockHeaderSchema = hcl.BlockHeaderSchema{
6 Type: "dynamic",
7 LabelNames: []string{"type"},
8}
9
10var dynamicBlockBodySchemaLabels = &hcl.BodySchema{
11 Attributes: []hcl.AttributeSchema{
12 {
13 Name: "for_each",
14 Required: true,
15 },
16 {
17 Name: "iterator",
18 Required: false,
19 },
20 {
21 Name: "labels",
22 Required: true,
23 },
24 },
25 Blocks: []hcl.BlockHeaderSchema{
26 {
27 Type: "content",
28 LabelNames: nil,
29 },
30 },
31}
32
33var dynamicBlockBodySchemaNoLabels = &hcl.BodySchema{
34 Attributes: []hcl.AttributeSchema{
35 {
36 Name: "for_each",
37 Required: true,
38 },
39 {
40 Name: "iterator",
41 Required: false,
42 },
43 },
44 Blocks: []hcl.BlockHeaderSchema{
45 {
46 Type: "content",
47 LabelNames: nil,
48 },
49 },
50}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/unknown_body.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/unknown_body.go
new file mode 100644
index 0000000..932f6a3
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/unknown_body.go
@@ -0,0 +1,84 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/zclconf/go-cty/cty"
6)
7
8// unknownBody is a funny body that just reports everything inside it as
9// unknown. It uses a given other body as a sort of template for what attributes
10// and blocks are inside -- including source location information -- but
11// subsitutes unknown values of unknown type for all attributes.
12//
13// This rather odd process is used to handle expansion of dynamic blocks whose
14// for_each expression is unknown. Since a block cannot itself be unknown,
15// we instead arrange for everything _inside_ the block to be unknown instead,
16// to give the best possible approximation.
17type unknownBody struct {
18 template hcl.Body
19}
20
21var _ hcl.Body = unknownBody{}
22
23func (b unknownBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
24 content, diags := b.template.Content(schema)
25 content = b.fixupContent(content)
26
27 // We're intentionally preserving the diagnostics reported from the
28 // inner body so that we can still report where the template body doesn't
29 // match the requested schema.
30 return content, diags
31}
32
33func (b unknownBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
34 content, remain, diags := b.template.PartialContent(schema)
35 content = b.fixupContent(content)
36 remain = unknownBody{remain} // remaining content must also be wrapped
37
38 // We're intentionally preserving the diagnostics reported from the
39 // inner body so that we can still report where the template body doesn't
40 // match the requested schema.
41 return content, remain, diags
42}
43
44func (b unknownBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
45 attrs, diags := b.template.JustAttributes()
46 attrs = b.fixupAttrs(attrs)
47
48 // We're intentionally preserving the diagnostics reported from the
49 // inner body so that we can still report where the template body doesn't
50 // match the requested schema.
51 return attrs, diags
52}
53
54func (b unknownBody) MissingItemRange() hcl.Range {
55 return b.template.MissingItemRange()
56}
57
58func (b unknownBody) fixupContent(got *hcl.BodyContent) *hcl.BodyContent {
59 ret := &hcl.BodyContent{}
60 ret.Attributes = b.fixupAttrs(got.Attributes)
61 if len(got.Blocks) > 0 {
62 ret.Blocks = make(hcl.Blocks, 0, len(got.Blocks))
63 for _, gotBlock := range got.Blocks {
64 new := *gotBlock // shallow copy
65 new.Body = unknownBody{gotBlock.Body} // nested content must also be marked unknown
66 ret.Blocks = append(ret.Blocks, &new)
67 }
68 }
69
70 return ret
71}
72
73func (b unknownBody) fixupAttrs(got hcl.Attributes) hcl.Attributes {
74 if len(got) == 0 {
75 return nil
76 }
77 ret := make(hcl.Attributes, len(got))
78 for name, gotAttr := range got {
79 new := *gotAttr // shallow copy
80 new.Expr = hcl.StaticExpr(cty.DynamicVal, gotAttr.Expr.Range())
81 ret[name] = &new
82 }
83 return ret
84}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables.go
new file mode 100644
index 0000000..ad838f3
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables.go
@@ -0,0 +1,209 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/zclconf/go-cty/cty"
6)
7
8// WalkVariables begins the recursive process of walking all expressions and
9// nested blocks in the given body and its child bodies while taking into
10// account any "dynamic" blocks.
11//
12// This function requires that the caller walk through the nested block
13// structure in the given body level-by-level so that an appropriate schema
14// can be provided at each level to inform further processing. This workflow
15// is thus easiest to use for calling applications that have some higher-level
16// schema representation available with which to drive this multi-step
17// process. If your application uses the hcldec package, you may be able to
18// use VariablesHCLDec instead for a more automatic approach.
19func WalkVariables(body hcl.Body) WalkVariablesNode {
20 return WalkVariablesNode{
21 body: body,
22 includeContent: true,
23 }
24}
25
26// WalkExpandVariables is like Variables but it includes only the variables
27// required for successful block expansion, ignoring any variables referenced
28// inside block contents. The result is the minimal set of all variables
29// required for a call to Expand, excluding variables that would only be
30// needed to subsequently call Content or PartialContent on the expanded
31// body.
32func WalkExpandVariables(body hcl.Body) WalkVariablesNode {
33 return WalkVariablesNode{
34 body: body,
35 }
36}
37
38type WalkVariablesNode struct {
39 body hcl.Body
40 it *iteration
41
42 includeContent bool
43}
44
45type WalkVariablesChild struct {
46 BlockTypeName string
47 Node WalkVariablesNode
48}
49
50// Body returns the HCL Body associated with the child node, in case the caller
51// wants to do some sort of inspection of it in order to decide what schema
52// to pass to Visit.
53//
54// Most implementations should just fetch a fixed schema based on the
55// BlockTypeName field and not access this. Deciding on a schema dynamically
56// based on the body is a strange thing to do and generally necessary only if
57// your caller is already doing other bizarre things with HCL bodies.
58func (c WalkVariablesChild) Body() hcl.Body {
59 return c.Node.body
60}
61
62// Visit returns the variable traversals required for any "dynamic" blocks
63// directly in the body associated with this node, and also returns any child
64// nodes that must be visited in order to continue the walk.
65//
66// Each child node has its associated block type name given in its BlockTypeName
67// field, which the calling application should use to determine the appropriate
68// schema for the content of each child node and pass it to the child node's
69// own Visit method to continue the walk recursively.
70func (n WalkVariablesNode) Visit(schema *hcl.BodySchema) (vars []hcl.Traversal, children []WalkVariablesChild) {
71 extSchema := n.extendSchema(schema)
72 container, _, _ := n.body.PartialContent(extSchema)
73 if container == nil {
74 return vars, children
75 }
76
77 children = make([]WalkVariablesChild, 0, len(container.Blocks))
78
79 if n.includeContent {
80 for _, attr := range container.Attributes {
81 for _, traversal := range attr.Expr.Variables() {
82 var ours, inherited bool
83 if n.it != nil {
84 ours = traversal.RootName() == n.it.IteratorName
85 _, inherited = n.it.Inherited[traversal.RootName()]
86 }
87
88 if !(ours || inherited) {
89 vars = append(vars, traversal)
90 }
91 }
92 }
93 }
94
95 for _, block := range container.Blocks {
96 switch block.Type {
97
98 case "dynamic":
99 blockTypeName := block.Labels[0]
100 inner, _, _ := block.Body.PartialContent(variableDetectionInnerSchema)
101 if inner == nil {
102 continue
103 }
104
105 iteratorName := blockTypeName
106 if attr, exists := inner.Attributes["iterator"]; exists {
107 iterTraversal, _ := hcl.AbsTraversalForExpr(attr.Expr)
108 if len(iterTraversal) == 0 {
109 // Ignore this invalid dynamic block, since it'll produce
110 // an error if someone tries to extract content from it
111 // later anyway.
112 continue
113 }
114 iteratorName = iterTraversal.RootName()
115 }
116 blockIt := n.it.MakeChild(iteratorName, cty.DynamicVal, cty.DynamicVal)
117
118 if attr, exists := inner.Attributes["for_each"]; exists {
119 // Filter out iterator names inherited from parent blocks
120 for _, traversal := range attr.Expr.Variables() {
121 if _, inherited := blockIt.Inherited[traversal.RootName()]; !inherited {
122 vars = append(vars, traversal)
123 }
124 }
125 }
126 if attr, exists := inner.Attributes["labels"]; exists {
127 // Filter out both our own iterator name _and_ those inherited
128 // from parent blocks, since we provide _both_ of these to the
129 // label expressions.
130 for _, traversal := range attr.Expr.Variables() {
131 ours := traversal.RootName() == iteratorName
132 _, inherited := blockIt.Inherited[traversal.RootName()]
133
134 if !(ours || inherited) {
135 vars = append(vars, traversal)
136 }
137 }
138 }
139
140 for _, contentBlock := range inner.Blocks {
141 // We only request "content" blocks in our schema, so we know
142 // any blocks we find here will be content blocks. We require
143 // exactly one content block for actual expansion, but we'll
144 // be more liberal here so that callers can still collect
145 // variables from erroneous "dynamic" blocks.
146 children = append(children, WalkVariablesChild{
147 BlockTypeName: blockTypeName,
148 Node: WalkVariablesNode{
149 body: contentBlock.Body,
150 it: blockIt,
151 includeContent: n.includeContent,
152 },
153 })
154 }
155
156 default:
157 children = append(children, WalkVariablesChild{
158 BlockTypeName: block.Type,
159 Node: WalkVariablesNode{
160 body: block.Body,
161 it: n.it,
162 includeContent: n.includeContent,
163 },
164 })
165
166 }
167 }
168
169 return vars, children
170}
171
172func (n WalkVariablesNode) extendSchema(schema *hcl.BodySchema) *hcl.BodySchema {
173 // We augment the requested schema to also include our special "dynamic"
174 // block type, since then we'll get instances of it interleaved with
175 // all of the literal child blocks we must also include.
176 extSchema := &hcl.BodySchema{
177 Attributes: schema.Attributes,
178 Blocks: make([]hcl.BlockHeaderSchema, len(schema.Blocks), len(schema.Blocks)+1),
179 }
180 copy(extSchema.Blocks, schema.Blocks)
181 extSchema.Blocks = append(extSchema.Blocks, dynamicBlockHeaderSchema)
182
183 return extSchema
184}
185
186// This is a more relaxed schema than what's in schema.go, since we
187// want to maximize the amount of variables we can find even if there
188// are erroneous blocks.
189var variableDetectionInnerSchema = &hcl.BodySchema{
190 Attributes: []hcl.AttributeSchema{
191 {
192 Name: "for_each",
193 Required: false,
194 },
195 {
196 Name: "labels",
197 Required: false,
198 },
199 {
200 Name: "iterator",
201 Required: false,
202 },
203 },
204 Blocks: []hcl.BlockHeaderSchema{
205 {
206 Type: "content",
207 },
208 },
209}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables_hcldec.go b/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables_hcldec.go
new file mode 100644
index 0000000..a078d91
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/dynblock/variables_hcldec.go
@@ -0,0 +1,43 @@
1package dynblock
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/hashicorp/hcl2/hcldec"
6)
7
8// VariablesHCLDec is a wrapper around WalkVariables that uses the given hcldec
9// specification to automatically drive the recursive walk through nested
10// blocks in the given body.
11//
12// This is a drop-in replacement for hcldec.Variables which is able to treat
13// blocks of type "dynamic" in the same special way that dynblock.Expand would,
14// exposing both the variables referenced in the "for_each" and "labels"
15// arguments and variables used in the nested "content" block.
16func VariablesHCLDec(body hcl.Body, spec hcldec.Spec) []hcl.Traversal {
17 rootNode := WalkVariables(body)
18 return walkVariablesWithHCLDec(rootNode, spec)
19}
20
21// ExpandVariablesHCLDec is like VariablesHCLDec but it includes only the
22// minimal set of variables required to call Expand, ignoring variables that
23// are referenced only inside normal block contents. See WalkExpandVariables
24// for more information.
25func ExpandVariablesHCLDec(body hcl.Body, spec hcldec.Spec) []hcl.Traversal {
26 rootNode := WalkExpandVariables(body)
27 return walkVariablesWithHCLDec(rootNode, spec)
28}
29
30func walkVariablesWithHCLDec(node WalkVariablesNode, spec hcldec.Spec) []hcl.Traversal {
31 vars, children := node.Visit(hcldec.ImpliedSchema(spec))
32
33 if len(children) > 0 {
34 childSpecs := hcldec.ChildBlockTypes(spec)
35 for _, child := range children {
36 if childSpec, exists := childSpecs[child.BlockTypeName]; exists {
37 vars = append(vars, walkVariablesWithHCLDec(child.Node, childSpec)...)
38 }
39 }
40 }
41
42 return vars
43}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/typeexpr/README.md b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/README.md
new file mode 100644
index 0000000..ff2b3f2
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/README.md
@@ -0,0 +1,67 @@
1# HCL Type Expressions Extension
2
3This HCL extension defines a convention for describing HCL types using function
4call and variable reference syntax, allowing configuration formats to include
5type information provided by users.
6
7The type syntax is processed statically from a hcl.Expression, so it cannot
8use any of the usual language operators. This is similar to type expressions
9in statically-typed programming languages.
10
11```hcl
12variable "example" {
13 type = list(string)
14}
15```
16
17The extension is built using the `hcl.ExprAsKeyword` and `hcl.ExprCall`
18functions, and so it relies on the underlying syntax to define how "keyword"
19and "call" are interpreted. The above shows how they are interpreted in
20the HCL native syntax, while the following shows the same information
21expressed in JSON:
22
23```json
24{
25 "variable": {
26 "example": {
27 "type": "list(string)"
28 }
29 }
30}
31```
32
33Notice that since we have additional contextual information that we intend
34to allow only calls and keywords the JSON syntax is able to parse the given
35string directly as an expression, rather than as a template as would be
36the case for normal expression evaluation.
37
38For more information, see [the godoc reference](http://godoc.org/github.com/hashicorp/hcl2/ext/typeexpr).
39
40## Type Expression Syntax
41
42When expressed in the native syntax, the following expressions are permitted
43in a type expression:
44
45* `string` - string
46* `bool` - boolean
47* `number` - number
48* `any` - `cty.DynamicPseudoType` (in function `TypeConstraint` only)
49* `list(<type_expr>)` - list of the type given as an argument
50* `set(<type_expr>)` - set of the type given as an argument
51* `map(<type_expr>)` - map of the type given as an argument
52* `tuple([<type_exprs...>])` - tuple with the element types given in the single list argument
53* `object({<attr_name>=<type_expr>, ...}` - object with the attributes and corresponding types given in the single map argument
54
55For example:
56
57* `list(string)`
58* `object({name=string,age=number})`
59* `map(object({name=string,age=number}))`
60
61Note that the object constructor syntax is not fully-general for all possible
62object types because it requires the attribute names to be valid identifiers.
63In practice it is expected that any time an object type is being fixed for
64type checking it will be one that has identifiers as its attributes; object
65types with weird attributes generally show up only from arbitrary object
66constructors in configuration files, which are usually treated either as maps
67or as the dynamic pseudo-type.
diff --git a/vendor/github.com/hashicorp/hcl2/ext/typeexpr/doc.go b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/doc.go
new file mode 100644
index 0000000..c4b3795
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/doc.go
@@ -0,0 +1,11 @@
1// Package typeexpr extends HCL with a convention for describing HCL types
2// within configuration files.
3//
4// The type syntax is processed statically from a hcl.Expression, so it cannot
5// use any of the usual language operators. This is similar to type expressions
6// in statically-typed programming languages.
7//
8// variable "example" {
9// type = list(string)
10// }
11package typeexpr
diff --git a/vendor/github.com/hashicorp/hcl2/ext/typeexpr/get_type.go b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/get_type.go
new file mode 100644
index 0000000..a84338a
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/get_type.go
@@ -0,0 +1,196 @@
1package typeexpr
2
3import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/zclconf/go-cty/cty"
8)
9
10const invalidTypeSummary = "Invalid type specification"
11
12// getType is the internal implementation of both Type and TypeConstraint,
13// using the passed flag to distinguish. When constraint is false, the "any"
14// keyword will produce an error.
15func getType(expr hcl.Expression, constraint bool) (cty.Type, hcl.Diagnostics) {
16 // First we'll try for one of our keywords
17 kw := hcl.ExprAsKeyword(expr)
18 switch kw {
19 case "bool":
20 return cty.Bool, nil
21 case "string":
22 return cty.String, nil
23 case "number":
24 return cty.Number, nil
25 case "any":
26 if constraint {
27 return cty.DynamicPseudoType, nil
28 }
29 return cty.DynamicPseudoType, hcl.Diagnostics{{
30 Severity: hcl.DiagError,
31 Summary: invalidTypeSummary,
32 Detail: fmt.Sprintf("The keyword %q cannot be used in this type specification: an exact type is required.", kw),
33 Subject: expr.Range().Ptr(),
34 }}
35 case "list", "map", "set":
36 return cty.DynamicPseudoType, hcl.Diagnostics{{
37 Severity: hcl.DiagError,
38 Summary: invalidTypeSummary,
39 Detail: fmt.Sprintf("The %s type constructor requires one argument specifying the element type.", kw),
40 Subject: expr.Range().Ptr(),
41 }}
42 case "object":
43 return cty.DynamicPseudoType, hcl.Diagnostics{{
44 Severity: hcl.DiagError,
45 Summary: invalidTypeSummary,
46 Detail: "The object type constructor requires one argument specifying the attribute types and values as a map.",
47 Subject: expr.Range().Ptr(),
48 }}
49 case "tuple":
50 return cty.DynamicPseudoType, hcl.Diagnostics{{
51 Severity: hcl.DiagError,
52 Summary: invalidTypeSummary,
53 Detail: "The tuple type constructor requires one argument specifying the element types as a list.",
54 Subject: expr.Range().Ptr(),
55 }}
56 case "":
57 // okay! we'll fall through and try processing as a call, then.
58 default:
59 return cty.DynamicPseudoType, hcl.Diagnostics{{
60 Severity: hcl.DiagError,
61 Summary: invalidTypeSummary,
62 Detail: fmt.Sprintf("The keyword %q is not a valid type specification.", kw),
63 Subject: expr.Range().Ptr(),
64 }}
65 }
66
67 // If we get down here then our expression isn't just a keyword, so we'll
68 // try to process it as a call instead.
69 call, diags := hcl.ExprCall(expr)
70 if diags.HasErrors() {
71 return cty.DynamicPseudoType, hcl.Diagnostics{{
72 Severity: hcl.DiagError,
73 Summary: invalidTypeSummary,
74 Detail: "A type specification is either a primitive type keyword (bool, number, string) or a complex type constructor call, like list(string).",
75 Subject: expr.Range().Ptr(),
76 }}
77 }
78
79 switch call.Name {
80 case "bool", "string", "number", "any":
81 return cty.DynamicPseudoType, hcl.Diagnostics{{
82 Severity: hcl.DiagError,
83 Summary: invalidTypeSummary,
84 Detail: fmt.Sprintf("Primitive type keyword %q does not expect arguments.", call.Name),
85 Subject: &call.ArgsRange,
86 }}
87 }
88
89 if len(call.Arguments) != 1 {
90 contextRange := call.ArgsRange
91 subjectRange := call.ArgsRange
92 if len(call.Arguments) > 1 {
93 // If we have too many arguments (as opposed to too _few_) then
94 // we'll highlight the extraneous arguments as the diagnostic
95 // subject.
96 subjectRange = hcl.RangeBetween(call.Arguments[1].Range(), call.Arguments[len(call.Arguments)-1].Range())
97 }
98
99 switch call.Name {
100 case "list", "set", "map":
101 return cty.DynamicPseudoType, hcl.Diagnostics{{
102 Severity: hcl.DiagError,
103 Summary: invalidTypeSummary,
104 Detail: fmt.Sprintf("The %s type constructor requires one argument specifying the element type.", call.Name),
105 Subject: &subjectRange,
106 Context: &contextRange,
107 }}
108 case "object":
109 return cty.DynamicPseudoType, hcl.Diagnostics{{
110 Severity: hcl.DiagError,
111 Summary: invalidTypeSummary,
112 Detail: "The object type constructor requires one argument specifying the attribute types and values as a map.",
113 Subject: &subjectRange,
114 Context: &contextRange,
115 }}
116 case "tuple":
117 return cty.DynamicPseudoType, hcl.Diagnostics{{
118 Severity: hcl.DiagError,
119 Summary: invalidTypeSummary,
120 Detail: "The tuple type constructor requires one argument specifying the element types as a list.",
121 Subject: &subjectRange,
122 Context: &contextRange,
123 }}
124 }
125 }
126
127 switch call.Name {
128
129 case "list":
130 ety, diags := getType(call.Arguments[0], constraint)
131 return cty.List(ety), diags
132 case "set":
133 ety, diags := getType(call.Arguments[0], constraint)
134 return cty.Set(ety), diags
135 case "map":
136 ety, diags := getType(call.Arguments[0], constraint)
137 return cty.Map(ety), diags
138 case "object":
139 attrDefs, diags := hcl.ExprMap(call.Arguments[0])
140 if diags.HasErrors() {
141 return cty.DynamicPseudoType, hcl.Diagnostics{{
142 Severity: hcl.DiagError,
143 Summary: invalidTypeSummary,
144 Detail: "Object type constructor requires a map whose keys are attribute names and whose values are the corresponding attribute types.",
145 Subject: call.Arguments[0].Range().Ptr(),
146 Context: expr.Range().Ptr(),
147 }}
148 }
149
150 atys := make(map[string]cty.Type)
151 for _, attrDef := range attrDefs {
152 attrName := hcl.ExprAsKeyword(attrDef.Key)
153 if attrName == "" {
154 diags = append(diags, &hcl.Diagnostic{
155 Severity: hcl.DiagError,
156 Summary: invalidTypeSummary,
157 Detail: "Object constructor map keys must be attribute names.",
158 Subject: attrDef.Key.Range().Ptr(),
159 Context: expr.Range().Ptr(),
160 })
161 continue
162 }
163 aty, attrDiags := getType(attrDef.Value, constraint)
164 diags = append(diags, attrDiags...)
165 atys[attrName] = aty
166 }
167 return cty.Object(atys), diags
168 case "tuple":
169 elemDefs, diags := hcl.ExprList(call.Arguments[0])
170 if diags.HasErrors() {
171 return cty.DynamicPseudoType, hcl.Diagnostics{{
172 Severity: hcl.DiagError,
173 Summary: invalidTypeSummary,
174 Detail: "Tuple type constructor requires a list of element types.",
175 Subject: call.Arguments[0].Range().Ptr(),
176 Context: expr.Range().Ptr(),
177 }}
178 }
179 etys := make([]cty.Type, len(elemDefs))
180 for i, defExpr := range elemDefs {
181 ety, elemDiags := getType(defExpr, constraint)
182 diags = append(diags, elemDiags...)
183 etys[i] = ety
184 }
185 return cty.Tuple(etys), diags
186 default:
187 // Can't access call.Arguments in this path because we've not validated
188 // that it contains exactly one expression here.
189 return cty.DynamicPseudoType, hcl.Diagnostics{{
190 Severity: hcl.DiagError,
191 Summary: invalidTypeSummary,
192 Detail: fmt.Sprintf("Keyword %q is not a valid type constructor.", call.Name),
193 Subject: expr.Range().Ptr(),
194 }}
195 }
196}
diff --git a/vendor/github.com/hashicorp/hcl2/ext/typeexpr/public.go b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/public.go
new file mode 100644
index 0000000..e3f5eef
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/ext/typeexpr/public.go
@@ -0,0 +1,129 @@
1package typeexpr
2
3import (
4 "bytes"
5 "fmt"
6 "sort"
7
8 "github.com/hashicorp/hcl2/hcl/hclsyntax"
9
10 "github.com/hashicorp/hcl2/hcl"
11 "github.com/zclconf/go-cty/cty"
12)
13
14// Type attempts to process the given expression as a type expression and, if
15// successful, returns the resulting type. If unsuccessful, error diagnostics
16// are returned.
17func Type(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
18 return getType(expr, false)
19}
20
21// TypeConstraint attempts to parse the given expression as a type constraint
22// and, if successful, returns the resulting type. If unsuccessful, error
23// diagnostics are returned.
24//
25// A type constraint has the same structure as a type, but it additionally
26// allows the keyword "any" to represent cty.DynamicPseudoType, which is often
27// used as a wildcard in type checking and type conversion operations.
28func TypeConstraint(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
29 return getType(expr, true)
30}
31
32// TypeString returns a string rendering of the given type as it would be
33// expected to appear in the HCL native syntax.
34//
35// This is primarily intended for showing types to the user in an application
36// that uses typexpr, where the user can be assumed to be familiar with the
37// type expression syntax. In applications that do not use typeexpr these
38// results may be confusing to the user and so type.FriendlyName may be
39// preferable, even though it's less precise.
40//
41// TypeString produces reasonable results only for types like what would be
42// produced by the Type and TypeConstraint functions. In particular, it cannot
43// support capsule types.
44func TypeString(ty cty.Type) string {
45 // Easy cases first
46 switch ty {
47 case cty.String:
48 return "string"
49 case cty.Bool:
50 return "bool"
51 case cty.Number:
52 return "number"
53 case cty.DynamicPseudoType:
54 return "any"
55 }
56
57 if ty.IsCapsuleType() {
58 panic("TypeString does not support capsule types")
59 }
60
61 if ty.IsCollectionType() {
62 ety := ty.ElementType()
63 etyString := TypeString(ety)
64 switch {
65 case ty.IsListType():
66 return fmt.Sprintf("list(%s)", etyString)
67 case ty.IsSetType():
68 return fmt.Sprintf("set(%s)", etyString)
69 case ty.IsMapType():
70 return fmt.Sprintf("map(%s)", etyString)
71 default:
72 // Should never happen because the above is exhaustive
73 panic("unsupported collection type")
74 }
75 }
76
77 if ty.IsObjectType() {
78 var buf bytes.Buffer
79 buf.WriteString("object({")
80 atys := ty.AttributeTypes()
81 names := make([]string, 0, len(atys))
82 for name := range atys {
83 names = append(names, name)
84 }
85 sort.Strings(names)
86 first := true
87 for _, name := range names {
88 aty := atys[name]
89 if !first {
90 buf.WriteByte(',')
91 }
92 if !hclsyntax.ValidIdentifier(name) {
93 // Should never happen for any type produced by this package,
94 // but we'll do something reasonable here just so we don't
95 // produce garbage if someone gives us a hand-assembled object
96 // type that has weird attribute names.
97 // Using Go-style quoting here isn't perfect, since it doesn't
98 // exactly match HCL syntax, but it's fine for an edge-case.
99 buf.WriteString(fmt.Sprintf("%q", name))
100 } else {
101 buf.WriteString(name)
102 }
103 buf.WriteByte('=')
104 buf.WriteString(TypeString(aty))
105 first = false
106 }
107 buf.WriteString("})")
108 return buf.String()
109 }
110
111 if ty.IsTupleType() {
112 var buf bytes.Buffer
113 buf.WriteString("tuple([")
114 etys := ty.TupleElementTypes()
115 first := true
116 for _, ety := range etys {
117 if !first {
118 buf.WriteByte(',')
119 }
120 buf.WriteString(TypeString(ety))
121 first = false
122 }
123 buf.WriteString("])")
124 return buf.String()
125 }
126
127 // Should never happen because we covered all cases above.
128 panic(fmt.Errorf("unsupported type %#v", ty))
129}