aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go246
1 files changed, 246 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
new file mode 100644
index 0000000..0b697a5
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
@@ -0,0 +1,246 @@
1package hcl2shim
2
3import (
4 "fmt"
5 "math/big"
6
7 "github.com/hashicorp/hil/ast"
8 "github.com/zclconf/go-cty/cty"
9)
10
11// UnknownVariableValue is a sentinel value that can be used
12// to denote that the value of a variable is unknown at this time.
13// RawConfig uses this information to build up data about
14// unknown keys.
15const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
16
17// ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
18// types library that HCL2 uses) to a value type that matches what would've
19// been produced from the HCL-based interpolator for an equivalent structure.
20//
21// This function will transform a cty null value into a Go nil value, which
22// isn't a possible outcome of the HCL/HIL-based decoder and so callers may
23// need to detect and reject any null values.
24func ConfigValueFromHCL2(v cty.Value) interface{} {
25 if !v.IsKnown() {
26 return UnknownVariableValue
27 }
28 if v.IsNull() {
29 return nil
30 }
31
32 switch v.Type() {
33 case cty.Bool:
34 return v.True() // like HCL.BOOL
35 case cty.String:
36 return v.AsString() // like HCL token.STRING or token.HEREDOC
37 case cty.Number:
38 // We can't match HCL _exactly_ here because it distinguishes between
39 // int and float values, but we'll get as close as we can by using
40 // an int if the number is exactly representable, and a float if not.
41 // The conversion to float will force precision to that of a float64,
42 // which is potentially losing information from the specific number
43 // given, but no worse than what HCL would've done in its own conversion
44 // to float.
45
46 f := v.AsBigFloat()
47 if i, acc := f.Int64(); acc == big.Exact {
48 // if we're on a 32-bit system and the number is too big for 32-bit
49 // int then we'll fall through here and use a float64.
50 const MaxInt = int(^uint(0) >> 1)
51 const MinInt = -MaxInt - 1
52 if i <= int64(MaxInt) && i >= int64(MinInt) {
53 return int(i) // Like HCL token.NUMBER
54 }
55 }
56
57 f64, _ := f.Float64()
58 return f64 // like HCL token.FLOAT
59 }
60
61 if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() {
62 l := make([]interface{}, 0, v.LengthInt())
63 it := v.ElementIterator()
64 for it.Next() {
65 _, ev := it.Element()
66 l = append(l, ConfigValueFromHCL2(ev))
67 }
68 return l
69 }
70
71 if v.Type().IsMapType() || v.Type().IsObjectType() {
72 l := make(map[string]interface{})
73 it := v.ElementIterator()
74 for it.Next() {
75 ek, ev := it.Element()
76 l[ek.AsString()] = ConfigValueFromHCL2(ev)
77 }
78 return l
79 }
80
81 // If we fall out here then we have some weird type that we haven't
82 // accounted for. This should never happen unless the caller is using
83 // capsule types, and we don't currently have any such types defined.
84 panic(fmt.Errorf("can't convert %#v to config value", v))
85}
86
87// HCL2ValueFromConfigValue is the opposite of configValueFromHCL2: it takes
88// a value as would be returned from the old interpolator and turns it into
89// a cty.Value so it can be used within, for example, an HCL2 EvalContext.
90func HCL2ValueFromConfigValue(v interface{}) cty.Value {
91 if v == nil {
92 return cty.NullVal(cty.DynamicPseudoType)
93 }
94 if v == UnknownVariableValue {
95 return cty.DynamicVal
96 }
97
98 switch tv := v.(type) {
99 case bool:
100 return cty.BoolVal(tv)
101 case string:
102 return cty.StringVal(tv)
103 case int:
104 return cty.NumberIntVal(int64(tv))
105 case float64:
106 return cty.NumberFloatVal(tv)
107 case []interface{}:
108 vals := make([]cty.Value, len(tv))
109 for i, ev := range tv {
110 vals[i] = HCL2ValueFromConfigValue(ev)
111 }
112 return cty.TupleVal(vals)
113 case map[string]interface{}:
114 vals := map[string]cty.Value{}
115 for k, ev := range tv {
116 vals[k] = HCL2ValueFromConfigValue(ev)
117 }
118 return cty.ObjectVal(vals)
119 default:
120 // HCL/HIL should never generate anything that isn't caught by
121 // the above, so if we get here something has gone very wrong.
122 panic(fmt.Errorf("can't convert %#v to cty.Value", v))
123 }
124}
125
126func HILVariableFromHCL2Value(v cty.Value) ast.Variable {
127 if v.IsNull() {
128 // Caller should guarantee/check this before calling
129 panic("Null values cannot be represented in HIL")
130 }
131 if !v.IsKnown() {
132 return ast.Variable{
133 Type: ast.TypeUnknown,
134 Value: UnknownVariableValue,
135 }
136 }
137
138 switch v.Type() {
139 case cty.Bool:
140 return ast.Variable{
141 Type: ast.TypeBool,
142 Value: v.True(),
143 }
144 case cty.Number:
145 v := ConfigValueFromHCL2(v)
146 switch tv := v.(type) {
147 case int:
148 return ast.Variable{
149 Type: ast.TypeInt,
150 Value: tv,
151 }
152 case float64:
153 return ast.Variable{
154 Type: ast.TypeFloat,
155 Value: tv,
156 }
157 default:
158 // should never happen
159 panic("invalid return value for configValueFromHCL2")
160 }
161 case cty.String:
162 return ast.Variable{
163 Type: ast.TypeString,
164 Value: v.AsString(),
165 }
166 }
167
168 if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() {
169 l := make([]ast.Variable, 0, v.LengthInt())
170 it := v.ElementIterator()
171 for it.Next() {
172 _, ev := it.Element()
173 l = append(l, HILVariableFromHCL2Value(ev))
174 }
175 // If we were given a tuple then this could actually produce an invalid
176 // list with non-homogenous types, which we expect to be caught inside
177 // HIL just like a user-supplied non-homogenous list would be.
178 return ast.Variable{
179 Type: ast.TypeList,
180 Value: l,
181 }
182 }
183
184 if v.Type().IsMapType() || v.Type().IsObjectType() {
185 l := make(map[string]ast.Variable)
186 it := v.ElementIterator()
187 for it.Next() {
188 ek, ev := it.Element()
189 l[ek.AsString()] = HILVariableFromHCL2Value(ev)
190 }
191 // If we were given an object then this could actually produce an invalid
192 // map with non-homogenous types, which we expect to be caught inside
193 // HIL just like a user-supplied non-homogenous map would be.
194 return ast.Variable{
195 Type: ast.TypeMap,
196 Value: l,
197 }
198 }
199
200 // If we fall out here then we have some weird type that we haven't
201 // accounted for. This should never happen unless the caller is using
202 // capsule types, and we don't currently have any such types defined.
203 panic(fmt.Errorf("can't convert %#v to HIL variable", v))
204}
205
206func HCL2ValueFromHILVariable(v ast.Variable) cty.Value {
207 switch v.Type {
208 case ast.TypeList:
209 vals := make([]cty.Value, len(v.Value.([]ast.Variable)))
210 for i, ev := range v.Value.([]ast.Variable) {
211 vals[i] = HCL2ValueFromHILVariable(ev)
212 }
213 return cty.TupleVal(vals)
214 case ast.TypeMap:
215 vals := make(map[string]cty.Value, len(v.Value.(map[string]ast.Variable)))
216 for k, ev := range v.Value.(map[string]ast.Variable) {
217 vals[k] = HCL2ValueFromHILVariable(ev)
218 }
219 return cty.ObjectVal(vals)
220 default:
221 return HCL2ValueFromConfigValue(v.Value)
222 }
223}
224
225func HCL2TypeForHILType(hilType ast.Type) cty.Type {
226 switch hilType {
227 case ast.TypeAny:
228 return cty.DynamicPseudoType
229 case ast.TypeUnknown:
230 return cty.DynamicPseudoType
231 case ast.TypeBool:
232 return cty.Bool
233 case ast.TypeInt:
234 return cty.Number
235 case ast.TypeFloat:
236 return cty.Number
237 case ast.TypeString:
238 return cty.String
239 case ast.TypeList:
240 return cty.List(cty.DynamicPseudoType)
241 case ast.TypeMap:
242 return cty.Map(cty.DynamicPseudoType)
243 default:
244 return cty.NilType // equilvalent to ast.TypeInvalid
245 }
246}