diff options
Diffstat (limited to 'vendor/github.com/zclconf')
46 files changed, 2965 insertions, 183 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/capsule.go b/vendor/github.com/zclconf/go-cty/cty/capsule.go index 4fce92a..d273d14 100644 --- a/vendor/github.com/zclconf/go-cty/cty/capsule.go +++ b/vendor/github.com/zclconf/go-cty/cty/capsule.go | |||
@@ -19,7 +19,7 @@ func (t *capsuleType) Equals(other Type) bool { | |||
19 | return false | 19 | return false |
20 | } | 20 | } |
21 | 21 | ||
22 | func (t *capsuleType) FriendlyName() string { | 22 | func (t *capsuleType) FriendlyName(mode friendlyTypeNameMode) string { |
23 | return t.Name | 23 | return t.Name |
24 | } | 24 | } |
25 | 25 | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go index 7bfcc08..f9aacb4 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go | |||
@@ -17,6 +17,10 @@ func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion { | |||
17 | // Wrap the conversion in some standard checks that we don't want to | 17 | // Wrap the conversion in some standard checks that we don't want to |
18 | // have to repeat in every conversion function. | 18 | // have to repeat in every conversion function. |
19 | return func(in cty.Value, path cty.Path) (cty.Value, error) { | 19 | return func(in cty.Value, path cty.Path) (cty.Value, error) { |
20 | if out == cty.DynamicPseudoType { | ||
21 | // Conversion to DynamicPseudoType always just passes through verbatim. | ||
22 | return in, nil | ||
23 | } | ||
20 | if !in.IsKnown() { | 24 | if !in.IsKnown() { |
21 | return cty.UnknownVal(out), nil | 25 | return cty.UnknownVal(out), nil |
22 | } | 26 | } |
@@ -57,6 +61,12 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion { | |||
57 | } | 61 | } |
58 | return nil | 62 | return nil |
59 | 63 | ||
64 | case out.IsObjectType() && in.IsObjectType(): | ||
65 | return conversionObjectToObject(in, out, unsafe) | ||
66 | |||
67 | case out.IsTupleType() && in.IsTupleType(): | ||
68 | return conversionTupleToTuple(in, out, unsafe) | ||
69 | |||
60 | case out.IsListType() && (in.IsListType() || in.IsSetType()): | 70 | case out.IsListType() && (in.IsListType() || in.IsSetType()): |
61 | inEty := in.ElementType() | 71 | inEty := in.ElementType() |
62 | outEty := out.ElementType() | 72 | outEty := out.ElementType() |
@@ -93,10 +103,23 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion { | |||
93 | } | 103 | } |
94 | return conversionCollectionToSet(outEty, convEty) | 104 | return conversionCollectionToSet(outEty, convEty) |
95 | 105 | ||
106 | case out.IsMapType() && in.IsMapType(): | ||
107 | inEty := in.ElementType() | ||
108 | outEty := out.ElementType() | ||
109 | convEty := getConversion(inEty, outEty, unsafe) | ||
110 | if convEty == nil { | ||
111 | return nil | ||
112 | } | ||
113 | return conversionCollectionToMap(outEty, convEty) | ||
114 | |||
96 | case out.IsListType() && in.IsTupleType(): | 115 | case out.IsListType() && in.IsTupleType(): |
97 | outEty := out.ElementType() | 116 | outEty := out.ElementType() |
98 | return conversionTupleToList(in, outEty, unsafe) | 117 | return conversionTupleToList(in, outEty, unsafe) |
99 | 118 | ||
119 | case out.IsSetType() && in.IsTupleType(): | ||
120 | outEty := out.ElementType() | ||
121 | return conversionTupleToSet(in, outEty, unsafe) | ||
122 | |||
100 | case out.IsMapType() && in.IsObjectType(): | 123 | case out.IsMapType() && in.IsObjectType(): |
101 | outEty := out.ElementType() | 124 | outEty := out.ElementType() |
102 | return conversionObjectToMap(in, outEty, unsafe) | 125 | return conversionObjectToMap(in, outEty, unsafe) |
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go index eace85d..3039ba2 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go | |||
@@ -84,6 +84,120 @@ func conversionCollectionToSet(ety cty.Type, conv conversion) conversion { | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | // conversionCollectionToMap returns a conversion that will apply the given | ||
88 | // conversion to all of the elements of a collection (something that supports | ||
89 | // ForEachElement and LengthInt) and then returns the result as a map. | ||
90 | // | ||
91 | // "conv" can be nil if the elements are expected to already be of the | ||
92 | // correct type and just need to be re-wrapped into a map. | ||
93 | func conversionCollectionToMap(ety cty.Type, conv conversion) conversion { | ||
94 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
95 | elems := make(map[string]cty.Value, 0) | ||
96 | path = append(path, nil) | ||
97 | it := val.ElementIterator() | ||
98 | for it.Next() { | ||
99 | key, val := it.Element() | ||
100 | var err error | ||
101 | |||
102 | path[len(path)-1] = cty.IndexStep{ | ||
103 | Key: key, | ||
104 | } | ||
105 | |||
106 | keyStr, err := Convert(key, cty.String) | ||
107 | if err != nil { | ||
108 | // Should never happen, because keys can only be numbers or | ||
109 | // strings and both can convert to string. | ||
110 | return cty.DynamicVal, path.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName()) | ||
111 | } | ||
112 | |||
113 | if conv != nil { | ||
114 | val, err = conv(val, path) | ||
115 | if err != nil { | ||
116 | return cty.NilVal, err | ||
117 | } | ||
118 | } | ||
119 | |||
120 | elems[keyStr.AsString()] = val | ||
121 | } | ||
122 | |||
123 | if len(elems) == 0 { | ||
124 | return cty.MapValEmpty(ety), nil | ||
125 | } | ||
126 | |||
127 | return cty.MapVal(elems), nil | ||
128 | } | ||
129 | } | ||
130 | |||
131 | // conversionTupleToSet returns a conversion that will take a value of the | ||
132 | // given tuple type and return a set of the given element type. | ||
133 | // | ||
134 | // Will panic if the given tupleType isn't actually a tuple type. | ||
135 | func conversionTupleToSet(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion { | ||
136 | tupleEtys := tupleType.TupleElementTypes() | ||
137 | |||
138 | if len(tupleEtys) == 0 { | ||
139 | // Empty tuple short-circuit | ||
140 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
141 | return cty.SetValEmpty(listEty), nil | ||
142 | } | ||
143 | } | ||
144 | |||
145 | if listEty == cty.DynamicPseudoType { | ||
146 | // This is a special case where the caller wants us to find | ||
147 | // a suitable single type that all elements can convert to, if | ||
148 | // possible. | ||
149 | listEty, _ = unify(tupleEtys, unsafe) | ||
150 | if listEty == cty.NilType { | ||
151 | return nil | ||
152 | } | ||
153 | } | ||
154 | |||
155 | elemConvs := make([]conversion, len(tupleEtys)) | ||
156 | for i, tupleEty := range tupleEtys { | ||
157 | if tupleEty.Equals(listEty) { | ||
158 | // no conversion required | ||
159 | continue | ||
160 | } | ||
161 | |||
162 | elemConvs[i] = getConversion(tupleEty, listEty, unsafe) | ||
163 | if elemConvs[i] == nil { | ||
164 | // If any of our element conversions are impossible, then the our | ||
165 | // whole conversion is impossible. | ||
166 | return nil | ||
167 | } | ||
168 | } | ||
169 | |||
170 | // If we fall out here then a conversion is possible, using the | ||
171 | // element conversions in elemConvs | ||
172 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
173 | elems := make([]cty.Value, 0, len(elemConvs)) | ||
174 | path = append(path, nil) | ||
175 | i := int64(0) | ||
176 | it := val.ElementIterator() | ||
177 | for it.Next() { | ||
178 | _, val := it.Element() | ||
179 | var err error | ||
180 | |||
181 | path[len(path)-1] = cty.IndexStep{ | ||
182 | Key: cty.NumberIntVal(i), | ||
183 | } | ||
184 | |||
185 | conv := elemConvs[i] | ||
186 | if conv != nil { | ||
187 | val, err = conv(val, path) | ||
188 | if err != nil { | ||
189 | return cty.NilVal, err | ||
190 | } | ||
191 | } | ||
192 | elems = append(elems, val) | ||
193 | |||
194 | i++ | ||
195 | } | ||
196 | |||
197 | return cty.SetVal(elems), nil | ||
198 | } | ||
199 | } | ||
200 | |||
87 | // conversionTupleToList returns a conversion that will take a value of the | 201 | // conversionTupleToList returns a conversion that will take a value of the |
88 | // given tuple type and return a list of the given element type. | 202 | // given tuple type and return a list of the given element type. |
89 | // | 203 | // |
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go new file mode 100644 index 0000000..62dabb8 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go | |||
@@ -0,0 +1,76 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // conversionObjectToObject returns a conversion that will make the input | ||
8 | // object type conform to the output object type, if possible. | ||
9 | // | ||
10 | // Conversion is possible only if the output type is a subset of the input | ||
11 | // type, meaning that each attribute of the output type has a corresponding | ||
12 | // attribute in the input type where a recursive conversion is available. | ||
13 | // | ||
14 | // Shallow object conversions work the same for both safe and unsafe modes, | ||
15 | // but the safety flag is passed on to recursive conversions and may thus | ||
16 | // limit the above definition of "subset". | ||
17 | func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion { | ||
18 | inAtys := in.AttributeTypes() | ||
19 | outAtys := out.AttributeTypes() | ||
20 | attrConvs := make(map[string]conversion) | ||
21 | |||
22 | for name, outAty := range outAtys { | ||
23 | inAty, exists := inAtys[name] | ||
24 | if !exists { | ||
25 | // No conversion is available, then. | ||
26 | return nil | ||
27 | } | ||
28 | |||
29 | if inAty.Equals(outAty) { | ||
30 | // No conversion needed, but we'll still record the attribute | ||
31 | // in our map for later reference. | ||
32 | attrConvs[name] = nil | ||
33 | continue | ||
34 | } | ||
35 | |||
36 | attrConvs[name] = getConversion(inAty, outAty, unsafe) | ||
37 | if attrConvs[name] == nil { | ||
38 | // If a recursive conversion isn't available, then our top-level | ||
39 | // configuration is impossible too. | ||
40 | return nil | ||
41 | } | ||
42 | } | ||
43 | |||
44 | // If we get here then a conversion is possible, using the attribute | ||
45 | // conversions given in attrConvs. | ||
46 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
47 | attrVals := make(map[string]cty.Value, len(attrConvs)) | ||
48 | path = append(path, nil) | ||
49 | pathStep := &path[len(path)-1] | ||
50 | |||
51 | for it := val.ElementIterator(); it.Next(); { | ||
52 | nameVal, val := it.Element() | ||
53 | var err error | ||
54 | |||
55 | name := nameVal.AsString() | ||
56 | *pathStep = cty.GetAttrStep{ | ||
57 | Name: name, | ||
58 | } | ||
59 | |||
60 | conv, exists := attrConvs[name] | ||
61 | if !exists { | ||
62 | continue | ||
63 | } | ||
64 | if conv != nil { | ||
65 | val, err = conv(val, path) | ||
66 | if err != nil { | ||
67 | return cty.NilVal, err | ||
68 | } | ||
69 | } | ||
70 | |||
71 | attrVals[name] = val | ||
72 | } | ||
73 | |||
74 | return cty.ObjectVal(attrVals), nil | ||
75 | } | ||
76 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go index e563ee3..e0dbf49 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go | |||
@@ -1,8 +1,6 @@ | |||
1 | package convert | 1 | package convert |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "math/big" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | 4 | "github.com/zclconf/go-cty/cty" |
7 | ) | 5 | ) |
8 | 6 | ||
@@ -30,11 +28,11 @@ var primitiveConversionsSafe = map[cty.Type]map[cty.Type]conversion{ | |||
30 | var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{ | 28 | var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{ |
31 | cty.String: { | 29 | cty.String: { |
32 | cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) { | 30 | cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) { |
33 | f, _, err := big.ParseFloat(val.AsString(), 10, 512, big.ToNearestEven) | 31 | v, err := cty.ParseNumberVal(val.AsString()) |
34 | if err != nil { | 32 | if err != nil { |
35 | return cty.NilVal, path.NewErrorf("a number is required") | 33 | return cty.NilVal, path.NewErrorf("a number is required") |
36 | } | 34 | } |
37 | return cty.NumberVal(f), nil | 35 | return v, nil |
38 | }, | 36 | }, |
39 | cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) { | 37 | cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) { |
40 | switch val.AsString() { | 38 | switch val.AsString() { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go new file mode 100644 index 0000000..592980a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go | |||
@@ -0,0 +1,71 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // conversionTupleToTuple returns a conversion that will make the input | ||
8 | // tuple type conform to the output tuple type, if possible. | ||
9 | // | ||
10 | // Conversion is possible only if the two tuple types have the same number | ||
11 | // of elements and the corresponding elements by index can be converted. | ||
12 | // | ||
13 | // Shallow tuple conversions work the same for both safe and unsafe modes, | ||
14 | // but the safety flag is passed on to recursive conversions and may thus | ||
15 | // limit which element type conversions are possible. | ||
16 | func conversionTupleToTuple(in, out cty.Type, unsafe bool) conversion { | ||
17 | inEtys := in.TupleElementTypes() | ||
18 | outEtys := out.TupleElementTypes() | ||
19 | |||
20 | if len(inEtys) != len(outEtys) { | ||
21 | return nil // no conversion is possible | ||
22 | } | ||
23 | |||
24 | elemConvs := make([]conversion, len(inEtys)) | ||
25 | |||
26 | for i, outEty := range outEtys { | ||
27 | inEty := inEtys[i] | ||
28 | |||
29 | if inEty.Equals(outEty) { | ||
30 | // No conversion needed, so we can leave this one nil. | ||
31 | continue | ||
32 | } | ||
33 | |||
34 | elemConvs[i] = getConversion(inEty, outEty, unsafe) | ||
35 | if elemConvs[i] == nil { | ||
36 | // If a recursive conversion isn't available, then our top-level | ||
37 | // configuration is impossible too. | ||
38 | return nil | ||
39 | } | ||
40 | } | ||
41 | |||
42 | // If we get here then a conversion is possible, using the element | ||
43 | // conversions given in elemConvs. | ||
44 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
45 | elemVals := make([]cty.Value, len(elemConvs)) | ||
46 | path = append(path, nil) | ||
47 | pathStep := &path[len(path)-1] | ||
48 | |||
49 | i := 0 | ||
50 | for it := val.ElementIterator(); it.Next(); i++ { | ||
51 | _, val := it.Element() | ||
52 | var err error | ||
53 | |||
54 | *pathStep = cty.IndexStep{ | ||
55 | Key: cty.NumberIntVal(int64(i)), | ||
56 | } | ||
57 | |||
58 | conv := elemConvs[i] | ||
59 | if conv != nil { | ||
60 | val, err = conv(val, path) | ||
61 | if err != nil { | ||
62 | return cty.NilVal, err | ||
63 | } | ||
64 | } | ||
65 | |||
66 | elemVals[i] = val | ||
67 | } | ||
68 | |||
69 | return cty.TupleVal(elemVals), nil | ||
70 | } | ||
71 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go b/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go new file mode 100644 index 0000000..581304e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go | |||
@@ -0,0 +1,220 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | "sort" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | // MismatchMessage is a helper to return an English-language description of | ||
12 | // the differences between got and want, phrased as a reason why got does | ||
13 | // not conform to want. | ||
14 | // | ||
15 | // This function does not itself attempt conversion, and so it should generally | ||
16 | // be used only after a conversion has failed, to report the conversion failure | ||
17 | // to an English-speaking user. The result will be confusing got is actually | ||
18 | // conforming to or convertable to want. | ||
19 | // | ||
20 | // The shorthand helper function Convert uses this function internally to | ||
21 | // produce its error messages, so callers of that function do not need to | ||
22 | // also use MismatchMessage. | ||
23 | // | ||
24 | // This function is similar to Type.TestConformance, but it is tailored to | ||
25 | // describing conversion failures and so the messages it generates relate | ||
26 | // specifically to the conversion rules implemented in this package. | ||
27 | func MismatchMessage(got, want cty.Type) string { | ||
28 | switch { | ||
29 | |||
30 | case got.IsObjectType() && want.IsObjectType(): | ||
31 | // If both types are object types then we may be able to say something | ||
32 | // about their respective attributes. | ||
33 | return mismatchMessageObjects(got, want) | ||
34 | |||
35 | case got.IsTupleType() && want.IsListType() && want.ElementType() == cty.DynamicPseudoType: | ||
36 | // If conversion from tuple to list failed then it's because we couldn't | ||
37 | // find a common type to convert all of the tuple elements to. | ||
38 | return "all list elements must have the same type" | ||
39 | |||
40 | case got.IsTupleType() && want.IsSetType() && want.ElementType() == cty.DynamicPseudoType: | ||
41 | // If conversion from tuple to set failed then it's because we couldn't | ||
42 | // find a common type to convert all of the tuple elements to. | ||
43 | return "all set elements must have the same type" | ||
44 | |||
45 | case got.IsObjectType() && want.IsMapType() && want.ElementType() == cty.DynamicPseudoType: | ||
46 | // If conversion from object to map failed then it's because we couldn't | ||
47 | // find a common type to convert all of the object attributes to. | ||
48 | return "all map elements must have the same type" | ||
49 | |||
50 | case (got.IsTupleType() || got.IsObjectType()) && want.IsCollectionType(): | ||
51 | return mismatchMessageCollectionsFromStructural(got, want) | ||
52 | |||
53 | case got.IsCollectionType() && want.IsCollectionType(): | ||
54 | return mismatchMessageCollectionsFromCollections(got, want) | ||
55 | |||
56 | default: | ||
57 | // If we have nothing better to say, we'll just state what was required. | ||
58 | return want.FriendlyNameForConstraint() + " required" | ||
59 | } | ||
60 | } | ||
61 | |||
62 | func mismatchMessageObjects(got, want cty.Type) string { | ||
63 | // Per our conversion rules, "got" is allowed to be a superset of "want", | ||
64 | // and so we'll produce error messages here under that assumption. | ||
65 | gotAtys := got.AttributeTypes() | ||
66 | wantAtys := want.AttributeTypes() | ||
67 | |||
68 | // If we find missing attributes then we'll report those in preference, | ||
69 | // but if not then we will report a maximum of one non-conforming | ||
70 | // attribute, just to keep our messages relatively terse. | ||
71 | // We'll also prefer to report a recursive type error from an _unsafe_ | ||
72 | // conversion over a safe one, because these are subjectively more | ||
73 | // "serious". | ||
74 | var missingAttrs []string | ||
75 | var unsafeMismatchAttr string | ||
76 | var safeMismatchAttr string | ||
77 | |||
78 | for name, wantAty := range wantAtys { | ||
79 | gotAty, exists := gotAtys[name] | ||
80 | if !exists { | ||
81 | missingAttrs = append(missingAttrs, name) | ||
82 | continue | ||
83 | } | ||
84 | |||
85 | // We'll now try to convert these attributes in isolation and | ||
86 | // see if we have a nested conversion error to report. | ||
87 | // We'll try an unsafe conversion first, and then fall back on | ||
88 | // safe if unsafe is possible. | ||
89 | |||
90 | // If we already have an unsafe mismatch attr error then we won't bother | ||
91 | // hunting for another one. | ||
92 | if unsafeMismatchAttr != "" { | ||
93 | continue | ||
94 | } | ||
95 | if conv := GetConversionUnsafe(gotAty, wantAty); conv == nil { | ||
96 | unsafeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) | ||
97 | } | ||
98 | |||
99 | // If we already have a safe mismatch attr error then we won't bother | ||
100 | // hunting for another one. | ||
101 | if safeMismatchAttr != "" { | ||
102 | continue | ||
103 | } | ||
104 | if conv := GetConversion(gotAty, wantAty); conv == nil { | ||
105 | safeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // We should now have collected at least one problem. If we have more than | ||
110 | // one then we'll use our preference order to decide what is most important | ||
111 | // to report. | ||
112 | switch { | ||
113 | |||
114 | case len(missingAttrs) != 0: | ||
115 | sort.Strings(missingAttrs) | ||
116 | switch len(missingAttrs) { | ||
117 | case 1: | ||
118 | return fmt.Sprintf("attribute %q is required", missingAttrs[0]) | ||
119 | case 2: | ||
120 | return fmt.Sprintf("attributes %q and %q are required", missingAttrs[0], missingAttrs[1]) | ||
121 | default: | ||
122 | sort.Strings(missingAttrs) | ||
123 | var buf bytes.Buffer | ||
124 | for _, name := range missingAttrs[:len(missingAttrs)-1] { | ||
125 | fmt.Fprintf(&buf, "%q, ", name) | ||
126 | } | ||
127 | fmt.Fprintf(&buf, "and %q", missingAttrs[len(missingAttrs)-1]) | ||
128 | return fmt.Sprintf("attributes %s are required", buf.Bytes()) | ||
129 | } | ||
130 | |||
131 | case unsafeMismatchAttr != "": | ||
132 | return unsafeMismatchAttr | ||
133 | |||
134 | case safeMismatchAttr != "": | ||
135 | return safeMismatchAttr | ||
136 | |||
137 | default: | ||
138 | // We should never get here, but if we do then we'll return | ||
139 | // just a generic message. | ||
140 | return "incorrect object attributes" | ||
141 | } | ||
142 | } | ||
143 | |||
144 | func mismatchMessageCollectionsFromStructural(got, want cty.Type) string { | ||
145 | // First some straightforward cases where the kind is just altogether wrong. | ||
146 | switch { | ||
147 | case want.IsListType() && !got.IsTupleType(): | ||
148 | return want.FriendlyNameForConstraint() + " required" | ||
149 | case want.IsSetType() && !got.IsTupleType(): | ||
150 | return want.FriendlyNameForConstraint() + " required" | ||
151 | case want.IsMapType() && !got.IsObjectType(): | ||
152 | return want.FriendlyNameForConstraint() + " required" | ||
153 | } | ||
154 | |||
155 | // If the kinds are matched well enough then we'll move on to checking | ||
156 | // individual elements. | ||
157 | wantEty := want.ElementType() | ||
158 | switch { | ||
159 | case got.IsTupleType(): | ||
160 | for i, gotEty := range got.TupleElementTypes() { | ||
161 | if gotEty.Equals(wantEty) { | ||
162 | continue // exact match, so no problem | ||
163 | } | ||
164 | if conv := getConversion(gotEty, wantEty, true); conv != nil { | ||
165 | continue // conversion is available, so no problem | ||
166 | } | ||
167 | return fmt.Sprintf("element %d: %s", i, MismatchMessage(gotEty, wantEty)) | ||
168 | } | ||
169 | |||
170 | // If we get down here then something weird is going on but we'll | ||
171 | // return a reasonable fallback message anyway. | ||
172 | return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint()) | ||
173 | |||
174 | case got.IsObjectType(): | ||
175 | for name, gotAty := range got.AttributeTypes() { | ||
176 | if gotAty.Equals(wantEty) { | ||
177 | continue // exact match, so no problem | ||
178 | } | ||
179 | if conv := getConversion(gotAty, wantEty, true); conv != nil { | ||
180 | continue // conversion is available, so no problem | ||
181 | } | ||
182 | return fmt.Sprintf("element %q: %s", name, MismatchMessage(gotAty, wantEty)) | ||
183 | } | ||
184 | |||
185 | // If we get down here then something weird is going on but we'll | ||
186 | // return a reasonable fallback message anyway. | ||
187 | return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint()) | ||
188 | |||
189 | default: | ||
190 | // Should not be possible to get here since we only call this function | ||
191 | // with got as structural types, but... | ||
192 | return want.FriendlyNameForConstraint() + " required" | ||
193 | } | ||
194 | } | ||
195 | |||
196 | func mismatchMessageCollectionsFromCollections(got, want cty.Type) string { | ||
197 | // First some straightforward cases where the kind is just altogether wrong. | ||
198 | switch { | ||
199 | case want.IsListType() && !(got.IsListType() || got.IsSetType()): | ||
200 | return want.FriendlyNameForConstraint() + " required" | ||
201 | case want.IsSetType() && !(got.IsListType() || got.IsSetType()): | ||
202 | return want.FriendlyNameForConstraint() + " required" | ||
203 | case want.IsMapType() && !got.IsMapType(): | ||
204 | return want.FriendlyNameForConstraint() + " required" | ||
205 | } | ||
206 | |||
207 | // If the kinds are matched well enough then we'll check the element types. | ||
208 | gotEty := got.ElementType() | ||
209 | wantEty := want.ElementType() | ||
210 | noun := "element type" | ||
211 | switch { | ||
212 | case want.IsListType(): | ||
213 | noun = "list element type" | ||
214 | case want.IsSetType(): | ||
215 | noun = "set element type" | ||
216 | case want.IsMapType(): | ||
217 | noun = "map element type" | ||
218 | } | ||
219 | return fmt.Sprintf("incorrect %s: %s", noun, MismatchMessage(gotEty, wantEty)) | ||
220 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/public.go b/vendor/github.com/zclconf/go-cty/cty/convert/public.go index 55f44ae..af19bdc 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/public.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/public.go | |||
@@ -1,7 +1,7 @@ | |||
1 | package convert | 1 | package convert |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "errors" |
5 | 5 | ||
6 | "github.com/zclconf/go-cty/cty" | 6 | "github.com/zclconf/go-cty/cty" |
7 | ) | 7 | ) |
@@ -46,7 +46,7 @@ func Convert(in cty.Value, want cty.Type) (cty.Value, error) { | |||
46 | 46 | ||
47 | conv := GetConversionUnsafe(in.Type(), want) | 47 | conv := GetConversionUnsafe(in.Type(), want) |
48 | if conv == nil { | 48 | if conv == nil { |
49 | return cty.NilVal, fmt.Errorf("incorrect type; %s required", want.FriendlyName()) | 49 | return cty.NilVal, errors.New(MismatchMessage(in.Type(), want)) |
50 | } | 50 | } |
51 | return conv(in) | 51 | return conv(in) |
52 | } | 52 | } |
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/unify.go b/vendor/github.com/zclconf/go-cty/cty/convert/unify.go index bd6736b..53ebbfe 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/unify.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/unify.go | |||
@@ -21,6 +21,39 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { | |||
21 | return cty.NilType, nil | 21 | return cty.NilType, nil |
22 | } | 22 | } |
23 | 23 | ||
24 | // If all of the given types are of the same structural kind, we may be | ||
25 | // able to construct a new type that they can all be unified to, even if | ||
26 | // that is not one of the given types. We must try this before the general | ||
27 | // behavior below because in unsafe mode we can convert an object type to | ||
28 | // a subset of that type, which would be a much less useful conversion for | ||
29 | // unification purposes. | ||
30 | { | ||
31 | objectCt := 0 | ||
32 | tupleCt := 0 | ||
33 | dynamicCt := 0 | ||
34 | for _, ty := range types { | ||
35 | switch { | ||
36 | case ty.IsObjectType(): | ||
37 | objectCt++ | ||
38 | case ty.IsTupleType(): | ||
39 | tupleCt++ | ||
40 | case ty == cty.DynamicPseudoType: | ||
41 | dynamicCt++ | ||
42 | default: | ||
43 | break | ||
44 | } | ||
45 | } | ||
46 | switch { | ||
47 | case objectCt > 0 && (objectCt+dynamicCt) == len(types): | ||
48 | return unifyObjectTypes(types, unsafe, dynamicCt > 0) | ||
49 | case tupleCt > 0 && (tupleCt+dynamicCt) == len(types): | ||
50 | return unifyTupleTypes(types, unsafe, dynamicCt > 0) | ||
51 | case objectCt > 0 && tupleCt > 0: | ||
52 | // Can never unify object and tuple types since they have incompatible kinds | ||
53 | return cty.NilType, nil | ||
54 | } | ||
55 | } | ||
56 | |||
24 | prefOrder := sortTypes(types) | 57 | prefOrder := sortTypes(types) |
25 | 58 | ||
26 | // sortTypes gives us an order where earlier items are preferable as | 59 | // sortTypes gives us an order where earlier items are preferable as |
@@ -58,9 +91,224 @@ Preferences: | |||
58 | return wantType, conversions | 91 | return wantType, conversions |
59 | } | 92 | } |
60 | 93 | ||
61 | // TODO: For structural types, try to invent a new type that they | ||
62 | // can all be unified to, by unifying their respective attributes. | ||
63 | |||
64 | // If we fall out here, no unification is possible | 94 | // If we fall out here, no unification is possible |
65 | return cty.NilType, nil | 95 | return cty.NilType, nil |
66 | } | 96 | } |
97 | |||
98 | func unifyObjectTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) { | ||
99 | // If we had any dynamic types in the input here then we can't predict | ||
100 | // what path we'll take through here once these become known types, so | ||
101 | // we'll conservatively produce DynamicVal for these. | ||
102 | if hasDynamic { | ||
103 | return unifyAllAsDynamic(types) | ||
104 | } | ||
105 | |||
106 | // There are two different ways we can succeed here: | ||
107 | // - If all of the given object types have the same set of attribute names | ||
108 | // and the corresponding types are all unifyable, then we construct that | ||
109 | // type. | ||
110 | // - If the given object types have different attribute names or their | ||
111 | // corresponding types are not unifyable, we'll instead try to unify | ||
112 | // all of the attribute types together to produce a map type. | ||
113 | // | ||
114 | // Our unification behavior is intentionally stricter than our conversion | ||
115 | // behavior for subset object types because user intent is different with | ||
116 | // unification use-cases: it makes sense to allow {"foo":true} to convert | ||
117 | // to emptyobjectval, but unifying an object with an attribute with the | ||
118 | // empty object type should be an error because unifying to the empty | ||
119 | // object type would be suprising and useless. | ||
120 | |||
121 | firstAttrs := types[0].AttributeTypes() | ||
122 | for _, ty := range types[1:] { | ||
123 | thisAttrs := ty.AttributeTypes() | ||
124 | if len(thisAttrs) != len(firstAttrs) { | ||
125 | // If number of attributes is different then there can be no | ||
126 | // object type in common. | ||
127 | return unifyObjectTypesToMap(types, unsafe) | ||
128 | } | ||
129 | for name := range thisAttrs { | ||
130 | if _, ok := firstAttrs[name]; !ok { | ||
131 | // If attribute names don't exactly match then there can be | ||
132 | // no object type in common. | ||
133 | return unifyObjectTypesToMap(types, unsafe) | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // If we get here then we've proven that all of the given object types | ||
139 | // have exactly the same set of attribute names, though the types may | ||
140 | // differ. | ||
141 | retAtys := make(map[string]cty.Type) | ||
142 | atysAcross := make([]cty.Type, len(types)) | ||
143 | for name := range firstAttrs { | ||
144 | for i, ty := range types { | ||
145 | atysAcross[i] = ty.AttributeType(name) | ||
146 | } | ||
147 | retAtys[name], _ = unify(atysAcross, unsafe) | ||
148 | if retAtys[name] == cty.NilType { | ||
149 | // Cannot unify this attribute alone, which means that unification | ||
150 | // of everything down to a map type can't be possible either. | ||
151 | return cty.NilType, nil | ||
152 | } | ||
153 | } | ||
154 | retTy := cty.Object(retAtys) | ||
155 | |||
156 | conversions := make([]Conversion, len(types)) | ||
157 | for i, ty := range types { | ||
158 | if ty.Equals(retTy) { | ||
159 | continue | ||
160 | } | ||
161 | if unsafe { | ||
162 | conversions[i] = GetConversionUnsafe(ty, retTy) | ||
163 | } else { | ||
164 | conversions[i] = GetConversion(ty, retTy) | ||
165 | } | ||
166 | if conversions[i] == nil { | ||
167 | // Shouldn't be reachable, since we were able to unify | ||
168 | return unifyObjectTypesToMap(types, unsafe) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | return retTy, conversions | ||
173 | } | ||
174 | |||
175 | func unifyObjectTypesToMap(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { | ||
176 | // This is our fallback case for unifyObjectTypes, where we see if we can | ||
177 | // construct a map type that can accept all of the attribute types. | ||
178 | |||
179 | var atys []cty.Type | ||
180 | for _, ty := range types { | ||
181 | for _, aty := range ty.AttributeTypes() { | ||
182 | atys = append(atys, aty) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | ety, _ := unify(atys, unsafe) | ||
187 | if ety == cty.NilType { | ||
188 | return cty.NilType, nil | ||
189 | } | ||
190 | |||
191 | retTy := cty.Map(ety) | ||
192 | conversions := make([]Conversion, len(types)) | ||
193 | for i, ty := range types { | ||
194 | if ty.Equals(retTy) { | ||
195 | continue | ||
196 | } | ||
197 | if unsafe { | ||
198 | conversions[i] = GetConversionUnsafe(ty, retTy) | ||
199 | } else { | ||
200 | conversions[i] = GetConversion(ty, retTy) | ||
201 | } | ||
202 | if conversions[i] == nil { | ||
203 | return cty.NilType, nil | ||
204 | } | ||
205 | } | ||
206 | return retTy, conversions | ||
207 | } | ||
208 | |||
209 | func unifyTupleTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) { | ||
210 | // If we had any dynamic types in the input here then we can't predict | ||
211 | // what path we'll take through here once these become known types, so | ||
212 | // we'll conservatively produce DynamicVal for these. | ||
213 | if hasDynamic { | ||
214 | return unifyAllAsDynamic(types) | ||
215 | } | ||
216 | |||
217 | // There are two different ways we can succeed here: | ||
218 | // - If all of the given tuple types have the same sequence of element types | ||
219 | // and the corresponding types are all unifyable, then we construct that | ||
220 | // type. | ||
221 | // - If the given tuple types have different element types or their | ||
222 | // corresponding types are not unifyable, we'll instead try to unify | ||
223 | // all of the elements types together to produce a list type. | ||
224 | |||
225 | firstEtys := types[0].TupleElementTypes() | ||
226 | for _, ty := range types[1:] { | ||
227 | thisEtys := ty.TupleElementTypes() | ||
228 | if len(thisEtys) != len(firstEtys) { | ||
229 | // If number of elements is different then there can be no | ||
230 | // tuple type in common. | ||
231 | return unifyTupleTypesToList(types, unsafe) | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // If we get here then we've proven that all of the given tuple types | ||
236 | // have the same number of elements, though the types may differ. | ||
237 | retEtys := make([]cty.Type, len(firstEtys)) | ||
238 | atysAcross := make([]cty.Type, len(types)) | ||
239 | for idx := range firstEtys { | ||
240 | for tyI, ty := range types { | ||
241 | atysAcross[tyI] = ty.TupleElementTypes()[idx] | ||
242 | } | ||
243 | retEtys[idx], _ = unify(atysAcross, unsafe) | ||
244 | if retEtys[idx] == cty.NilType { | ||
245 | // Cannot unify this element alone, which means that unification | ||
246 | // of everything down to a map type can't be possible either. | ||
247 | return cty.NilType, nil | ||
248 | } | ||
249 | } | ||
250 | retTy := cty.Tuple(retEtys) | ||
251 | |||
252 | conversions := make([]Conversion, len(types)) | ||
253 | for i, ty := range types { | ||
254 | if ty.Equals(retTy) { | ||
255 | continue | ||
256 | } | ||
257 | if unsafe { | ||
258 | conversions[i] = GetConversionUnsafe(ty, retTy) | ||
259 | } else { | ||
260 | conversions[i] = GetConversion(ty, retTy) | ||
261 | } | ||
262 | if conversions[i] == nil { | ||
263 | // Shouldn't be reachable, since we were able to unify | ||
264 | return unifyTupleTypesToList(types, unsafe) | ||
265 | } | ||
266 | } | ||
267 | |||
268 | return retTy, conversions | ||
269 | } | ||
270 | |||
271 | func unifyTupleTypesToList(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { | ||
272 | // This is our fallback case for unifyTupleTypes, where we see if we can | ||
273 | // construct a list type that can accept all of the element types. | ||
274 | |||
275 | var etys []cty.Type | ||
276 | for _, ty := range types { | ||
277 | for _, ety := range ty.TupleElementTypes() { | ||
278 | etys = append(etys, ety) | ||
279 | } | ||
280 | } | ||
281 | |||
282 | ety, _ := unify(etys, unsafe) | ||
283 | if ety == cty.NilType { | ||
284 | return cty.NilType, nil | ||
285 | } | ||
286 | |||
287 | retTy := cty.List(ety) | ||
288 | conversions := make([]Conversion, len(types)) | ||
289 | for i, ty := range types { | ||
290 | if ty.Equals(retTy) { | ||
291 | continue | ||
292 | } | ||
293 | if unsafe { | ||
294 | conversions[i] = GetConversionUnsafe(ty, retTy) | ||
295 | } else { | ||
296 | conversions[i] = GetConversion(ty, retTy) | ||
297 | } | ||
298 | if conversions[i] == nil { | ||
299 | // Shouldn't be reachable, since we were able to unify | ||
300 | return unifyObjectTypesToMap(types, unsafe) | ||
301 | } | ||
302 | } | ||
303 | return retTy, conversions | ||
304 | } | ||
305 | |||
306 | func unifyAllAsDynamic(types []cty.Type) (cty.Type, []Conversion) { | ||
307 | conversions := make([]Conversion, len(types)) | ||
308 | for i := range conversions { | ||
309 | conversions[i] = func(cty.Value) (cty.Value, error) { | ||
310 | return cty.DynamicVal, nil | ||
311 | } | ||
312 | } | ||
313 | return cty.DynamicPseudoType, conversions | ||
314 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/function.go b/vendor/github.com/zclconf/go-cty/cty/function/function.go index 162f7bf..9e8bf33 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/function.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/function.go | |||
@@ -143,7 +143,7 @@ func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) | |||
143 | val := posArgs[i] | 143 | val := posArgs[i] |
144 | 144 | ||
145 | if val.IsNull() && !spec.AllowNull { | 145 | if val.IsNull() && !spec.AllowNull { |
146 | return cty.Type{}, NewArgErrorf(i, "must not be null") | 146 | return cty.Type{}, NewArgErrorf(i, "argument must not be null") |
147 | } | 147 | } |
148 | 148 | ||
149 | // AllowUnknown is ignored for type-checking, since we expect to be | 149 | // AllowUnknown is ignored for type-checking, since we expect to be |
@@ -169,7 +169,7 @@ func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) | |||
169 | realI := i + len(posArgs) | 169 | realI := i + len(posArgs) |
170 | 170 | ||
171 | if val.IsNull() && !spec.AllowNull { | 171 | if val.IsNull() && !spec.AllowNull { |
172 | return cty.Type{}, NewArgErrorf(realI, "must not be null") | 172 | return cty.Type{}, NewArgErrorf(realI, "argument must not be null") |
173 | } | 173 | } |
174 | 174 | ||
175 | if val.Type() == cty.DynamicPseudoType { | 175 | if val.Type() == cty.DynamicPseudoType { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go new file mode 100644 index 0000000..aa15b7b --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go | |||
@@ -0,0 +1,385 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "bytes" | ||
6 | "fmt" | ||
7 | "strings" | ||
8 | "time" | ||
9 | |||
10 | "github.com/zclconf/go-cty/cty" | ||
11 | "github.com/zclconf/go-cty/cty/function" | ||
12 | ) | ||
13 | |||
14 | var FormatDateFunc = function.New(&function.Spec{ | ||
15 | Params: []function.Parameter{ | ||
16 | { | ||
17 | Name: "format", | ||
18 | Type: cty.String, | ||
19 | }, | ||
20 | { | ||
21 | Name: "time", | ||
22 | Type: cty.String, | ||
23 | }, | ||
24 | }, | ||
25 | Type: function.StaticReturnType(cty.String), | ||
26 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
27 | formatStr := args[0].AsString() | ||
28 | timeStr := args[1].AsString() | ||
29 | t, err := parseTimestamp(timeStr) | ||
30 | if err != nil { | ||
31 | return cty.DynamicVal, function.NewArgError(1, err) | ||
32 | } | ||
33 | |||
34 | var buf bytes.Buffer | ||
35 | sc := bufio.NewScanner(strings.NewReader(formatStr)) | ||
36 | sc.Split(splitDateFormat) | ||
37 | const esc = '\'' | ||
38 | for sc.Scan() { | ||
39 | tok := sc.Bytes() | ||
40 | |||
41 | // The leading byte signals the token type | ||
42 | switch { | ||
43 | case tok[0] == esc: | ||
44 | if tok[len(tok)-1] != esc || len(tok) == 1 { | ||
45 | return cty.DynamicVal, function.NewArgErrorf(0, "unterminated literal '") | ||
46 | } | ||
47 | if len(tok) == 2 { | ||
48 | // Must be a single escaped quote, '' | ||
49 | buf.WriteByte(esc) | ||
50 | } else { | ||
51 | // The content (until a closing esc) is printed out verbatim | ||
52 | // except that we must un-double any double-esc escapes in | ||
53 | // the middle of the string. | ||
54 | raw := tok[1 : len(tok)-1] | ||
55 | for i := 0; i < len(raw); i++ { | ||
56 | buf.WriteByte(raw[i]) | ||
57 | if raw[i] == esc { | ||
58 | i++ // skip the escaped quote | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | case startsDateFormatVerb(tok[0]): | ||
64 | switch tok[0] { | ||
65 | case 'Y': | ||
66 | y := t.Year() | ||
67 | switch len(tok) { | ||
68 | case 2: | ||
69 | fmt.Fprintf(&buf, "%02d", y%100) | ||
70 | case 4: | ||
71 | fmt.Fprintf(&buf, "%04d", y) | ||
72 | default: | ||
73 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: year must either be \"YY\" or \"YYYY\"", tok) | ||
74 | } | ||
75 | case 'M': | ||
76 | m := t.Month() | ||
77 | switch len(tok) { | ||
78 | case 1: | ||
79 | fmt.Fprintf(&buf, "%d", m) | ||
80 | case 2: | ||
81 | fmt.Fprintf(&buf, "%02d", m) | ||
82 | case 3: | ||
83 | buf.WriteString(m.String()[:3]) | ||
84 | case 4: | ||
85 | buf.WriteString(m.String()) | ||
86 | default: | ||
87 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: month must be \"M\", \"MM\", \"MMM\", or \"MMMM\"", tok) | ||
88 | } | ||
89 | case 'D': | ||
90 | d := t.Day() | ||
91 | switch len(tok) { | ||
92 | case 1: | ||
93 | fmt.Fprintf(&buf, "%d", d) | ||
94 | case 2: | ||
95 | fmt.Fprintf(&buf, "%02d", d) | ||
96 | default: | ||
97 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: day of month must either be \"D\" or \"DD\"", tok) | ||
98 | } | ||
99 | case 'E': | ||
100 | d := t.Weekday() | ||
101 | switch len(tok) { | ||
102 | case 3: | ||
103 | buf.WriteString(d.String()[:3]) | ||
104 | case 4: | ||
105 | buf.WriteString(d.String()) | ||
106 | default: | ||
107 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: day of week must either be \"EEE\" or \"EEEE\"", tok) | ||
108 | } | ||
109 | case 'h': | ||
110 | h := t.Hour() | ||
111 | switch len(tok) { | ||
112 | case 1: | ||
113 | fmt.Fprintf(&buf, "%d", h) | ||
114 | case 2: | ||
115 | fmt.Fprintf(&buf, "%02d", h) | ||
116 | default: | ||
117 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: 24-hour must either be \"h\" or \"hh\"", tok) | ||
118 | } | ||
119 | case 'H': | ||
120 | h := t.Hour() % 12 | ||
121 | if h == 0 { | ||
122 | h = 12 | ||
123 | } | ||
124 | switch len(tok) { | ||
125 | case 1: | ||
126 | fmt.Fprintf(&buf, "%d", h) | ||
127 | case 2: | ||
128 | fmt.Fprintf(&buf, "%02d", h) | ||
129 | default: | ||
130 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: 12-hour must either be \"H\" or \"HH\"", tok) | ||
131 | } | ||
132 | case 'A', 'a': | ||
133 | if len(tok) != 2 { | ||
134 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: must be \"%s%s\"", tok, tok[0:1], tok[0:1]) | ||
135 | } | ||
136 | upper := tok[0] == 'A' | ||
137 | switch t.Hour() / 12 { | ||
138 | case 0: | ||
139 | if upper { | ||
140 | buf.WriteString("AM") | ||
141 | } else { | ||
142 | buf.WriteString("am") | ||
143 | } | ||
144 | case 1: | ||
145 | if upper { | ||
146 | buf.WriteString("PM") | ||
147 | } else { | ||
148 | buf.WriteString("pm") | ||
149 | } | ||
150 | } | ||
151 | case 'm': | ||
152 | m := t.Minute() | ||
153 | switch len(tok) { | ||
154 | case 1: | ||
155 | fmt.Fprintf(&buf, "%d", m) | ||
156 | case 2: | ||
157 | fmt.Fprintf(&buf, "%02d", m) | ||
158 | default: | ||
159 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: minute must either be \"m\" or \"mm\"", tok) | ||
160 | } | ||
161 | case 's': | ||
162 | s := t.Second() | ||
163 | switch len(tok) { | ||
164 | case 1: | ||
165 | fmt.Fprintf(&buf, "%d", s) | ||
166 | case 2: | ||
167 | fmt.Fprintf(&buf, "%02d", s) | ||
168 | default: | ||
169 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: second must either be \"s\" or \"ss\"", tok) | ||
170 | } | ||
171 | case 'Z': | ||
172 | // We'll just lean on Go's own formatter for this one, since | ||
173 | // the necessary information is unexported. | ||
174 | switch len(tok) { | ||
175 | case 1: | ||
176 | buf.WriteString(t.Format("Z07:00")) | ||
177 | case 3: | ||
178 | str := t.Format("-0700") | ||
179 | switch str { | ||
180 | case "+0000": | ||
181 | buf.WriteString("UTC") | ||
182 | default: | ||
183 | buf.WriteString(str) | ||
184 | } | ||
185 | case 4: | ||
186 | buf.WriteString(t.Format("-0700")) | ||
187 | case 5: | ||
188 | buf.WriteString(t.Format("-07:00")) | ||
189 | default: | ||
190 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: timezone must be Z, ZZZZ, or ZZZZZ", tok) | ||
191 | } | ||
192 | default: | ||
193 | return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q", tok) | ||
194 | } | ||
195 | |||
196 | default: | ||
197 | // Any other starting character indicates a literal sequence | ||
198 | buf.Write(tok) | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return cty.StringVal(buf.String()), nil | ||
203 | }, | ||
204 | }) | ||
205 | |||
206 | // FormatDate reformats a timestamp given in RFC3339 syntax into another time | ||
207 | // syntax defined by a given format string. | ||
208 | // | ||
209 | // The format string uses letter mnemonics to represent portions of the | ||
210 | // timestamp, with repetition signifying length variants of each portion. | ||
211 | // Single quote characters ' can be used to quote sequences of literal letters | ||
212 | // that should not be interpreted as formatting mnemonics. | ||
213 | // | ||
214 | // The full set of supported mnemonic sequences is listed below: | ||
215 | // | ||
216 | // YY Year modulo 100 zero-padded to two digits, like "06". | ||
217 | // YYYY Four (or more) digit year, like "2006". | ||
218 | // M Month number, like "1" for January. | ||
219 | // MM Month number zero-padded to two digits, like "01". | ||
220 | // MMM English month name abbreviated to three letters, like "Jan". | ||
221 | // MMMM English month name unabbreviated, like "January". | ||
222 | // D Day of month number, like "2". | ||
223 | // DD Day of month number zero-padded to two digits, like "02". | ||
224 | // EEE English day of week name abbreviated to three letters, like "Mon". | ||
225 | // EEEE English day of week name unabbreviated, like "Monday". | ||
226 | // h 24-hour number, like "2". | ||
227 | // hh 24-hour number zero-padded to two digits, like "02". | ||
228 | // H 12-hour number, like "2". | ||
229 | // HH 12-hour number zero-padded to two digits, like "02". | ||
230 | // AA Hour AM/PM marker in uppercase, like "AM". | ||
231 | // aa Hour AM/PM marker in lowercase, like "am". | ||
232 | // m Minute within hour, like "5". | ||
233 | // mm Minute within hour zero-padded to two digits, like "05". | ||
234 | // s Second within minute, like "9". | ||
235 | // ss Second within minute zero-padded to two digits, like "09". | ||
236 | // ZZZZ Timezone offset with just sign and digit, like "-0800". | ||
237 | // ZZZZZ Timezone offset with colon separating hours and minutes, like "-08:00". | ||
238 | // Z Like ZZZZZ but with a special case "Z" for UTC. | ||
239 | // ZZZ Like ZZZZ but with a special case "UTC" for UTC. | ||
240 | // | ||
241 | // The format syntax is optimized mainly for generating machine-oriented | ||
242 | // timestamps rather than human-oriented timestamps; the English language | ||
243 | // portions of the output reflect the use of English names in a number of | ||
244 | // machine-readable date formatting standards. For presentation to humans, | ||
245 | // a locale-aware time formatter (not included in this package) is a better | ||
246 | // choice. | ||
247 | // | ||
248 | // The format syntax is not compatible with that of any other language, but | ||
249 | // is optimized so that patterns for common standard date formats can be | ||
250 | // recognized quickly even by a reader unfamiliar with the format syntax. | ||
251 | func FormatDate(format cty.Value, timestamp cty.Value) (cty.Value, error) { | ||
252 | return FormatDateFunc.Call([]cty.Value{format, timestamp}) | ||
253 | } | ||
254 | |||
255 | func parseTimestamp(ts string) (time.Time, error) { | ||
256 | t, err := time.Parse(time.RFC3339, ts) | ||
257 | if err != nil { | ||
258 | switch err := err.(type) { | ||
259 | case *time.ParseError: | ||
260 | // If err is s time.ParseError then its string representation is not | ||
261 | // appropriate since it relies on details of Go's strange date format | ||
262 | // representation, which a caller of our functions is not expected | ||
263 | // to be familiar with. | ||
264 | // | ||
265 | // Therefore we do some light transformation to get a more suitable | ||
266 | // error that should make more sense to our callers. These are | ||
267 | // still not awesome error messages, but at least they refer to | ||
268 | // the timestamp portions by name rather than by Go's example | ||
269 | // values. | ||
270 | if err.LayoutElem == "" && err.ValueElem == "" && err.Message != "" { | ||
271 | // For some reason err.Message is populated with a ": " prefix | ||
272 | // by the time package. | ||
273 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp%s", err.Message) | ||
274 | } | ||
275 | var what string | ||
276 | switch err.LayoutElem { | ||
277 | case "2006": | ||
278 | what = "year" | ||
279 | case "01": | ||
280 | what = "month" | ||
281 | case "02": | ||
282 | what = "day of month" | ||
283 | case "15": | ||
284 | what = "hour" | ||
285 | case "04": | ||
286 | what = "minute" | ||
287 | case "05": | ||
288 | what = "second" | ||
289 | case "Z07:00": | ||
290 | what = "UTC offset" | ||
291 | case "T": | ||
292 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: missing required time introducer 'T'") | ||
293 | case ":", "-": | ||
294 | if err.ValueElem == "" { | ||
295 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string where %q is expected", err.LayoutElem) | ||
296 | } else { | ||
297 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: found %q where %q is expected", err.ValueElem, err.LayoutElem) | ||
298 | } | ||
299 | default: | ||
300 | // Should never get here, because time.RFC3339 includes only the | ||
301 | // above portions, but since that might change in future we'll | ||
302 | // be robust here. | ||
303 | what = "timestamp segment" | ||
304 | } | ||
305 | if err.ValueElem == "" { | ||
306 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string before %s", what) | ||
307 | } else { | ||
308 | return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: cannot use %q as %s", err.ValueElem, what) | ||
309 | } | ||
310 | } | ||
311 | return time.Time{}, err | ||
312 | } | ||
313 | return t, nil | ||
314 | } | ||
315 | |||
316 | // splitDataFormat is a bufio.SplitFunc used to tokenize a date format. | ||
317 | func splitDateFormat(data []byte, atEOF bool) (advance int, token []byte, err error) { | ||
318 | if len(data) == 0 { | ||
319 | return 0, nil, nil | ||
320 | } | ||
321 | |||
322 | const esc = '\'' | ||
323 | |||
324 | switch { | ||
325 | |||
326 | case data[0] == esc: | ||
327 | // If we have another quote immediately after then this is a single | ||
328 | // escaped escape. | ||
329 | if len(data) > 1 && data[1] == esc { | ||
330 | return 2, data[:2], nil | ||
331 | } | ||
332 | |||
333 | // Beginning of quoted sequence, so we will seek forward until we find | ||
334 | // the closing quote, ignoring escaped quotes along the way. | ||
335 | for i := 1; i < len(data); i++ { | ||
336 | if data[i] == esc { | ||
337 | if (i + 1) == len(data) { | ||
338 | // We need at least one more byte to decide if this is an | ||
339 | // escape or a terminator. | ||
340 | return 0, nil, nil | ||
341 | } | ||
342 | if data[i+1] == esc { | ||
343 | i++ // doubled-up quotes are an escape sequence | ||
344 | continue | ||
345 | } | ||
346 | // We've found the closing quote | ||
347 | return i + 1, data[:i+1], nil | ||
348 | } | ||
349 | } | ||
350 | // If we fall out here then we need more bytes to find the end, | ||
351 | // unless we're already at the end with an unclosed quote. | ||
352 | if atEOF { | ||
353 | return len(data), data, nil | ||
354 | } | ||
355 | return 0, nil, nil | ||
356 | |||
357 | case startsDateFormatVerb(data[0]): | ||
358 | rep := data[0] | ||
359 | for i := 1; i < len(data); i++ { | ||
360 | if data[i] != rep { | ||
361 | return i, data[:i], nil | ||
362 | } | ||
363 | } | ||
364 | if atEOF { | ||
365 | return len(data), data, nil | ||
366 | } | ||
367 | // We need more data to decide if we've found the end | ||
368 | return 0, nil, nil | ||
369 | |||
370 | default: | ||
371 | for i := 1; i < len(data); i++ { | ||
372 | if data[i] == esc || startsDateFormatVerb(data[i]) { | ||
373 | return i, data[:i], nil | ||
374 | } | ||
375 | } | ||
376 | // We might not actually be at the end of a literal sequence, | ||
377 | // but that doesn't matter since we'll concat them back together | ||
378 | // anyway. | ||
379 | return len(data), data, nil | ||
380 | } | ||
381 | } | ||
382 | |||
383 | func startsDateFormatVerb(b byte) bool { | ||
384 | return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') | ||
385 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go index fb24f20..664790b 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go | |||
@@ -84,6 +84,11 @@ var FormatListFunc = function.New(&function.Spec{ | |||
84 | argTy := arg.Type() | 84 | argTy := arg.Type() |
85 | switch { | 85 | switch { |
86 | case (argTy.IsListType() || argTy.IsSetType() || argTy.IsTupleType()) && !arg.IsNull(): | 86 | case (argTy.IsListType() || argTy.IsSetType() || argTy.IsTupleType()) && !arg.IsNull(): |
87 | if !argTy.IsTupleType() && !arg.IsKnown() { | ||
88 | // We can't iterate this one at all yet then, so we can't | ||
89 | // yet produce a result. | ||
90 | return cty.UnknownVal(retType), nil | ||
91 | } | ||
87 | thisLen := arg.LengthInt() | 92 | thisLen := arg.LengthInt() |
88 | if iterLen == -1 { | 93 | if iterLen == -1 { |
89 | iterLen = thisLen | 94 | iterLen = thisLen |
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go index 86876ba..32b1ac9 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go | |||
@@ -11,9 +11,10 @@ import ( | |||
11 | "unicode/utf8" | 11 | "unicode/utf8" |
12 | 12 | ||
13 | "github.com/zclconf/go-cty/cty" | 13 | "github.com/zclconf/go-cty/cty" |
14 | "github.com/zclconf/go-cty/cty/function" | ||
14 | ) | 15 | ) |
15 | 16 | ||
16 | // line 20 "format_fsm.go" | 17 | // line 21 "format_fsm.go" |
17 | var _formatfsm_actions []byte = []byte{ | 18 | var _formatfsm_actions []byte = []byte{ |
18 | 0, 1, 0, 1, 1, 1, 2, 1, 4, | 19 | 0, 1, 0, 1, 1, 1, 2, 1, 4, |
19 | 1, 5, 1, 6, 1, 7, 1, 8, | 20 | 1, 5, 1, 6, 1, 7, 1, 8, |
@@ -86,15 +87,16 @@ const formatfsm_error int = 0 | |||
86 | 87 | ||
87 | const formatfsm_en_main int = 8 | 88 | const formatfsm_en_main int = 8 |
88 | 89 | ||
89 | // line 19 "format_fsm.rl" | 90 | // line 20 "format_fsm.rl" |
90 | 91 | ||
91 | func formatFSM(format string, a []cty.Value) (string, error) { | 92 | func formatFSM(format string, a []cty.Value) (string, error) { |
92 | var buf bytes.Buffer | 93 | var buf bytes.Buffer |
93 | data := format | 94 | data := format |
94 | nextArg := 1 // arg numbers are 1-based | 95 | nextArg := 1 // arg numbers are 1-based |
95 | var verb formatVerb | 96 | var verb formatVerb |
97 | highestArgIdx := 0 // zero means "none", since arg numbers are 1-based | ||
96 | 98 | ||
97 | // line 153 "format_fsm.rl" | 99 | // line 159 "format_fsm.rl" |
98 | 100 | ||
99 | // Ragel state | 101 | // Ragel state |
100 | p := 0 // "Pointer" into data | 102 | p := 0 // "Pointer" into data |
@@ -109,12 +111,12 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
109 | _ = te | 111 | _ = te |
110 | _ = eof | 112 | _ = eof |
111 | 113 | ||
112 | // line 121 "format_fsm.go" | 114 | // line 123 "format_fsm.go" |
113 | { | 115 | { |
114 | cs = formatfsm_start | 116 | cs = formatfsm_start |
115 | } | 117 | } |
116 | 118 | ||
117 | // line 126 "format_fsm.go" | 119 | // line 128 "format_fsm.go" |
118 | { | 120 | { |
119 | var _klen int | 121 | var _klen int |
120 | var _trans int | 122 | var _trans int |
@@ -195,7 +197,7 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
195 | _acts++ | 197 | _acts++ |
196 | switch _formatfsm_actions[_acts-1] { | 198 | switch _formatfsm_actions[_acts-1] { |
197 | case 0: | 199 | case 0: |
198 | // line 29 "format_fsm.rl" | 200 | // line 31 "format_fsm.rl" |
199 | 201 | ||
200 | verb = formatVerb{ | 202 | verb = formatVerb{ |
201 | ArgNum: nextArg, | 203 | ArgNum: nextArg, |
@@ -205,12 +207,12 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
205 | ts = p | 207 | ts = p |
206 | 208 | ||
207 | case 1: | 209 | case 1: |
208 | // line 38 "format_fsm.rl" | 210 | // line 40 "format_fsm.rl" |
209 | 211 | ||
210 | buf.WriteByte(data[p]) | 212 | buf.WriteByte(data[p]) |
211 | 213 | ||
212 | case 4: | 214 | case 4: |
213 | // line 49 "format_fsm.rl" | 215 | // line 51 "format_fsm.rl" |
214 | 216 | ||
215 | // We'll try to slurp a whole UTF-8 sequence here, to give the user | 217 | // We'll try to slurp a whole UTF-8 sequence here, to give the user |
216 | // better feedback. | 218 | // better feedback. |
@@ -218,85 +220,89 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
218 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) | 220 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) |
219 | 221 | ||
220 | case 5: | 222 | case 5: |
221 | // line 56 "format_fsm.rl" | 223 | // line 58 "format_fsm.rl" |
222 | 224 | ||
223 | verb.Sharp = true | 225 | verb.Sharp = true |
224 | 226 | ||
225 | case 6: | 227 | case 6: |
226 | // line 59 "format_fsm.rl" | 228 | // line 61 "format_fsm.rl" |
227 | 229 | ||
228 | verb.Zero = true | 230 | verb.Zero = true |
229 | 231 | ||
230 | case 7: | 232 | case 7: |
231 | // line 62 "format_fsm.rl" | 233 | // line 64 "format_fsm.rl" |
232 | 234 | ||
233 | verb.Minus = true | 235 | verb.Minus = true |
234 | 236 | ||
235 | case 8: | 237 | case 8: |
236 | // line 65 "format_fsm.rl" | 238 | // line 67 "format_fsm.rl" |
237 | 239 | ||
238 | verb.Plus = true | 240 | verb.Plus = true |
239 | 241 | ||
240 | case 9: | 242 | case 9: |
241 | // line 68 "format_fsm.rl" | 243 | // line 70 "format_fsm.rl" |
242 | 244 | ||
243 | verb.Space = true | 245 | verb.Space = true |
244 | 246 | ||
245 | case 10: | 247 | case 10: |
246 | // line 72 "format_fsm.rl" | 248 | // line 74 "format_fsm.rl" |
247 | 249 | ||
248 | verb.ArgNum = 0 | 250 | verb.ArgNum = 0 |
249 | 251 | ||
250 | case 11: | 252 | case 11: |
251 | // line 75 "format_fsm.rl" | 253 | // line 77 "format_fsm.rl" |
252 | 254 | ||
253 | verb.ArgNum = (10 * verb.ArgNum) + (int(data[p]) - '0') | 255 | verb.ArgNum = (10 * verb.ArgNum) + (int(data[p]) - '0') |
254 | 256 | ||
255 | case 12: | 257 | case 12: |
256 | // line 79 "format_fsm.rl" | 258 | // line 81 "format_fsm.rl" |
257 | 259 | ||
258 | verb.HasWidth = true | 260 | verb.HasWidth = true |
259 | 261 | ||
260 | case 13: | 262 | case 13: |
261 | // line 82 "format_fsm.rl" | 263 | // line 84 "format_fsm.rl" |
262 | 264 | ||
263 | verb.Width = 0 | 265 | verb.Width = 0 |
264 | 266 | ||
265 | case 14: | 267 | case 14: |
266 | // line 85 "format_fsm.rl" | 268 | // line 87 "format_fsm.rl" |
267 | 269 | ||
268 | verb.Width = (10 * verb.Width) + (int(data[p]) - '0') | 270 | verb.Width = (10 * verb.Width) + (int(data[p]) - '0') |
269 | 271 | ||
270 | case 15: | 272 | case 15: |
271 | // line 89 "format_fsm.rl" | 273 | // line 91 "format_fsm.rl" |
272 | 274 | ||
273 | verb.HasPrec = true | 275 | verb.HasPrec = true |
274 | 276 | ||
275 | case 16: | 277 | case 16: |
276 | // line 92 "format_fsm.rl" | 278 | // line 94 "format_fsm.rl" |
277 | 279 | ||
278 | verb.Prec = 0 | 280 | verb.Prec = 0 |
279 | 281 | ||
280 | case 17: | 282 | case 17: |
281 | // line 95 "format_fsm.rl" | 283 | // line 97 "format_fsm.rl" |
282 | 284 | ||
283 | verb.Prec = (10 * verb.Prec) + (int(data[p]) - '0') | 285 | verb.Prec = (10 * verb.Prec) + (int(data[p]) - '0') |
284 | 286 | ||
285 | case 18: | 287 | case 18: |
286 | // line 99 "format_fsm.rl" | 288 | // line 101 "format_fsm.rl" |
287 | 289 | ||
288 | verb.Mode = rune(data[p]) | 290 | verb.Mode = rune(data[p]) |
289 | te = p + 1 | 291 | te = p + 1 |
290 | verb.Raw = data[ts:te] | 292 | verb.Raw = data[ts:te] |
291 | verb.Offset = ts | 293 | verb.Offset = ts |
292 | 294 | ||
295 | if verb.ArgNum > highestArgIdx { | ||
296 | highestArgIdx = verb.ArgNum | ||
297 | } | ||
298 | |||
293 | err := formatAppend(&verb, &buf, a) | 299 | err := formatAppend(&verb, &buf, a) |
294 | if err != nil { | 300 | if err != nil { |
295 | return buf.String(), err | 301 | return buf.String(), err |
296 | } | 302 | } |
297 | nextArg = verb.ArgNum + 1 | 303 | nextArg = verb.ArgNum + 1 |
298 | 304 | ||
299 | // line 324 "format_fsm.go" | 305 | // line 330 "format_fsm.go" |
300 | } | 306 | } |
301 | } | 307 | } |
302 | 308 | ||
@@ -319,22 +325,22 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
319 | __acts++ | 325 | __acts++ |
320 | switch _formatfsm_actions[__acts-1] { | 326 | switch _formatfsm_actions[__acts-1] { |
321 | case 2: | 327 | case 2: |
322 | // line 42 "format_fsm.rl" | 328 | // line 44 "format_fsm.rl" |
323 | 329 | ||
324 | case 3: | 330 | case 3: |
325 | // line 45 "format_fsm.rl" | 331 | // line 47 "format_fsm.rl" |
326 | 332 | ||
327 | return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) | 333 | return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) |
328 | 334 | ||
329 | case 4: | 335 | case 4: |
330 | // line 49 "format_fsm.rl" | 336 | // line 51 "format_fsm.rl" |
331 | 337 | ||
332 | // We'll try to slurp a whole UTF-8 sequence here, to give the user | 338 | // We'll try to slurp a whole UTF-8 sequence here, to give the user |
333 | // better feedback. | 339 | // better feedback. |
334 | r, _ := utf8.DecodeRuneInString(data[p:]) | 340 | r, _ := utf8.DecodeRuneInString(data[p:]) |
335 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) | 341 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) |
336 | 342 | ||
337 | // line 363 "format_fsm.go" | 343 | // line 369 "format_fsm.go" |
338 | } | 344 | } |
339 | } | 345 | } |
340 | } | 346 | } |
@@ -344,14 +350,24 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
344 | } | 350 | } |
345 | } | 351 | } |
346 | 352 | ||
347 | // line 171 "format_fsm.rl" | 353 | // line 177 "format_fsm.rl" |
348 | 354 | ||
349 | // If we fall out here without being in a final state then we've | 355 | // If we fall out here without being in a final state then we've |
350 | // encountered something that the scanner can't match, which should | 356 | // encountered something that the scanner can't match, which should |
351 | // be impossible (the scanner matches all bytes _somehow_) but we'll | 357 | // be impossible (the scanner matches all bytes _somehow_) but we'll |
352 | // flag it anyway rather than just losing data from the end. | 358 | // flag it anyway rather than just losing data from the end. |
353 | if cs < formatfsm_first_final { | 359 | if cs < formatfsm_first_final { |
354 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %i", p) | 360 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %d", p) |
361 | } | ||
362 | |||
363 | if highestArgIdx < len(a) { | ||
364 | // Extraneous args are an error, to more easily detect mistakes | ||
365 | firstBad := highestArgIdx + 1 | ||
366 | if highestArgIdx == 0 { | ||
367 | // Custom error message for this case | ||
368 | return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; no verbs in format string") | ||
369 | } | ||
370 | return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; only %d used by format string", highestArgIdx) | ||
355 | } | 371 | } |
356 | 372 | ||
357 | return buf.String(), nil | 373 | return buf.String(), nil |
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl index 85d43bb..3c642d9 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl | |||
@@ -12,6 +12,7 @@ import ( | |||
12 | "unicode/utf8" | 12 | "unicode/utf8" |
13 | 13 | ||
14 | "github.com/zclconf/go-cty/cty" | 14 | "github.com/zclconf/go-cty/cty" |
15 | "github.com/zclconf/go-cty/cty/function" | ||
15 | ) | 16 | ) |
16 | 17 | ||
17 | %%{ | 18 | %%{ |
@@ -23,6 +24,7 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
23 | data := format | 24 | data := format |
24 | nextArg := 1 // arg numbers are 1-based | 25 | nextArg := 1 // arg numbers are 1-based |
25 | var verb formatVerb | 26 | var verb formatVerb |
27 | highestArgIdx := 0 // zero means "none", since arg numbers are 1-based | ||
26 | 28 | ||
27 | %%{ | 29 | %%{ |
28 | 30 | ||
@@ -102,6 +104,10 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
102 | verb.Raw = data[ts:te] | 104 | verb.Raw = data[ts:te] |
103 | verb.Offset = ts | 105 | verb.Offset = ts |
104 | 106 | ||
107 | if verb.ArgNum > highestArgIdx { | ||
108 | highestArgIdx = verb.ArgNum | ||
109 | } | ||
110 | |||
105 | err := formatAppend(&verb, &buf, a) | 111 | err := formatAppend(&verb, &buf, a) |
106 | if err != nil { | 112 | if err != nil { |
107 | return buf.String(), err | 113 | return buf.String(), err |
@@ -175,7 +181,17 @@ func formatFSM(format string, a []cty.Value) (string, error) { | |||
175 | // be impossible (the scanner matches all bytes _somehow_) but we'll | 181 | // be impossible (the scanner matches all bytes _somehow_) but we'll |
176 | // flag it anyway rather than just losing data from the end. | 182 | // flag it anyway rather than just losing data from the end. |
177 | if cs < formatfsm_first_final { | 183 | if cs < formatfsm_first_final { |
178 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %i", p) | 184 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %d", p) |
185 | } | ||
186 | |||
187 | if highestArgIdx < len(a) { | ||
188 | // Extraneous args are an error, to more easily detect mistakes | ||
189 | firstBad := highestArgIdx+1 | ||
190 | if highestArgIdx == 0 { | ||
191 | // Custom error message for this case | ||
192 | return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; no verbs in format string") | ||
193 | } | ||
194 | return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; only %d used by format string", highestArgIdx) | ||
179 | } | 195 | } |
180 | 196 | ||
181 | return buf.String(), nil | 197 | return buf.String(), nil |
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go new file mode 100644 index 0000000..2dd6348 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go | |||
@@ -0,0 +1,233 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "regexp" | ||
6 | resyntax "regexp/syntax" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | "github.com/zclconf/go-cty/cty/function" | ||
10 | ) | ||
11 | |||
12 | var RegexFunc = function.New(&function.Spec{ | ||
13 | Params: []function.Parameter{ | ||
14 | { | ||
15 | Name: "pattern", | ||
16 | Type: cty.String, | ||
17 | }, | ||
18 | { | ||
19 | Name: "string", | ||
20 | Type: cty.String, | ||
21 | }, | ||
22 | }, | ||
23 | Type: func(args []cty.Value) (cty.Type, error) { | ||
24 | if !args[0].IsKnown() { | ||
25 | // We can't predict our type without seeing our pattern | ||
26 | return cty.DynamicPseudoType, nil | ||
27 | } | ||
28 | |||
29 | retTy, err := regexPatternResultType(args[0].AsString()) | ||
30 | if err != nil { | ||
31 | err = function.NewArgError(0, err) | ||
32 | } | ||
33 | return retTy, err | ||
34 | }, | ||
35 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
36 | if retType == cty.DynamicPseudoType { | ||
37 | return cty.DynamicVal, nil | ||
38 | } | ||
39 | |||
40 | re, err := regexp.Compile(args[0].AsString()) | ||
41 | if err != nil { | ||
42 | // Should never happen, since we checked this in the Type function above. | ||
43 | return cty.NilVal, function.NewArgErrorf(0, "error parsing pattern: %s", err) | ||
44 | } | ||
45 | str := args[1].AsString() | ||
46 | |||
47 | captureIdxs := re.FindStringSubmatchIndex(str) | ||
48 | if captureIdxs == nil { | ||
49 | return cty.NilVal, fmt.Errorf("pattern did not match any part of the given string") | ||
50 | } | ||
51 | |||
52 | return regexPatternResult(re, str, captureIdxs, retType), nil | ||
53 | }, | ||
54 | }) | ||
55 | |||
56 | var RegexAllFunc = function.New(&function.Spec{ | ||
57 | Params: []function.Parameter{ | ||
58 | { | ||
59 | Name: "pattern", | ||
60 | Type: cty.String, | ||
61 | }, | ||
62 | { | ||
63 | Name: "string", | ||
64 | Type: cty.String, | ||
65 | }, | ||
66 | }, | ||
67 | Type: func(args []cty.Value) (cty.Type, error) { | ||
68 | if !args[0].IsKnown() { | ||
69 | // We can't predict our type without seeing our pattern, | ||
70 | // but we do know it'll always be a list of something. | ||
71 | return cty.List(cty.DynamicPseudoType), nil | ||
72 | } | ||
73 | |||
74 | retTy, err := regexPatternResultType(args[0].AsString()) | ||
75 | if err != nil { | ||
76 | err = function.NewArgError(0, err) | ||
77 | } | ||
78 | return cty.List(retTy), err | ||
79 | }, | ||
80 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
81 | ety := retType.ElementType() | ||
82 | if ety == cty.DynamicPseudoType { | ||
83 | return cty.DynamicVal, nil | ||
84 | } | ||
85 | |||
86 | re, err := regexp.Compile(args[0].AsString()) | ||
87 | if err != nil { | ||
88 | // Should never happen, since we checked this in the Type function above. | ||
89 | return cty.NilVal, function.NewArgErrorf(0, "error parsing pattern: %s", err) | ||
90 | } | ||
91 | str := args[1].AsString() | ||
92 | |||
93 | captureIdxsEach := re.FindAllStringSubmatchIndex(str, -1) | ||
94 | if len(captureIdxsEach) == 0 { | ||
95 | return cty.ListValEmpty(ety), nil | ||
96 | } | ||
97 | |||
98 | elems := make([]cty.Value, len(captureIdxsEach)) | ||
99 | for i, captureIdxs := range captureIdxsEach { | ||
100 | elems[i] = regexPatternResult(re, str, captureIdxs, ety) | ||
101 | } | ||
102 | return cty.ListVal(elems), nil | ||
103 | }, | ||
104 | }) | ||
105 | |||
106 | // Regex is a function that extracts one or more substrings from a given | ||
107 | // string by applying a regular expression pattern, describing the first | ||
108 | // match. | ||
109 | // | ||
110 | // The return type depends on the composition of the capture groups (if any) | ||
111 | // in the pattern: | ||
112 | // | ||
113 | // - If there are no capture groups at all, the result is a single string | ||
114 | // representing the entire matched pattern. | ||
115 | // - If all of the capture groups are named, the result is an object whose | ||
116 | // keys are the named groups and whose values are their sub-matches, or | ||
117 | // null if a particular sub-group was inside another group that didn't | ||
118 | // match. | ||
119 | // - If none of the capture groups are named, the result is a tuple whose | ||
120 | // elements are the sub-groups in order and whose values are their | ||
121 | // sub-matches, or null if a particular sub-group was inside another group | ||
122 | // that didn't match. | ||
123 | // - It is invalid to use both named and un-named capture groups together in | ||
124 | // the same pattern. | ||
125 | // | ||
126 | // If the pattern doesn't match, this function returns an error. To test for | ||
127 | // a match, call RegexAll and check if the length of the result is greater | ||
128 | // than zero. | ||
129 | func Regex(pattern, str cty.Value) (cty.Value, error) { | ||
130 | return RegexFunc.Call([]cty.Value{pattern, str}) | ||
131 | } | ||
132 | |||
133 | // RegexAll is similar to Regex but it finds all of the non-overlapping matches | ||
134 | // in the given string and returns a list of them. | ||
135 | // | ||
136 | // The result type is always a list, whose element type is deduced from the | ||
137 | // pattern in the same way as the return type for Regex is decided. | ||
138 | // | ||
139 | // If the pattern doesn't match at all, this function returns an empty list. | ||
140 | func RegexAll(pattern, str cty.Value) (cty.Value, error) { | ||
141 | return RegexAllFunc.Call([]cty.Value{pattern, str}) | ||
142 | } | ||
143 | |||
144 | // regexPatternResultType parses the given regular expression pattern and | ||
145 | // returns the structural type that would be returned to represent its | ||
146 | // capture groups. | ||
147 | // | ||
148 | // Returns an error if parsing fails or if the pattern uses a mixture of | ||
149 | // named and unnamed capture groups, which is not permitted. | ||
150 | func regexPatternResultType(pattern string) (cty.Type, error) { | ||
151 | re, rawErr := regexp.Compile(pattern) | ||
152 | switch err := rawErr.(type) { | ||
153 | case *resyntax.Error: | ||
154 | return cty.NilType, fmt.Errorf("invalid regexp pattern: %s in %s", err.Code, err.Expr) | ||
155 | case error: | ||
156 | // Should never happen, since all regexp compile errors should | ||
157 | // be resyntax.Error, but just in case... | ||
158 | return cty.NilType, fmt.Errorf("error parsing pattern: %s", err) | ||
159 | } | ||
160 | |||
161 | allNames := re.SubexpNames()[1:] | ||
162 | var names []string | ||
163 | unnamed := 0 | ||
164 | for _, name := range allNames { | ||
165 | if name == "" { | ||
166 | unnamed++ | ||
167 | } else { | ||
168 | if names == nil { | ||
169 | names = make([]string, 0, len(allNames)) | ||
170 | } | ||
171 | names = append(names, name) | ||
172 | } | ||
173 | } | ||
174 | switch { | ||
175 | case unnamed == 0 && len(names) == 0: | ||
176 | // If there are no capture groups at all then we'll return just a | ||
177 | // single string for the whole match. | ||
178 | return cty.String, nil | ||
179 | case unnamed > 0 && len(names) > 0: | ||
180 | return cty.NilType, fmt.Errorf("invalid regexp pattern: cannot mix both named and unnamed capture groups") | ||
181 | case unnamed > 0: | ||
182 | // For unnamed captures, we return a tuple of them all in order. | ||
183 | etys := make([]cty.Type, unnamed) | ||
184 | for i := range etys { | ||
185 | etys[i] = cty.String | ||
186 | } | ||
187 | return cty.Tuple(etys), nil | ||
188 | default: | ||
189 | // For named captures, we return an object using the capture names | ||
190 | // as keys. | ||
191 | atys := make(map[string]cty.Type, len(names)) | ||
192 | for _, name := range names { | ||
193 | atys[name] = cty.String | ||
194 | } | ||
195 | return cty.Object(atys), nil | ||
196 | } | ||
197 | } | ||
198 | |||
199 | func regexPatternResult(re *regexp.Regexp, str string, captureIdxs []int, retType cty.Type) cty.Value { | ||
200 | switch { | ||
201 | case retType == cty.String: | ||
202 | start, end := captureIdxs[0], captureIdxs[1] | ||
203 | return cty.StringVal(str[start:end]) | ||
204 | case retType.IsTupleType(): | ||
205 | captureIdxs = captureIdxs[2:] // index 0 is the whole pattern span, which we ignore by skipping one pair | ||
206 | vals := make([]cty.Value, len(captureIdxs)/2) | ||
207 | for i := range vals { | ||
208 | start, end := captureIdxs[i*2], captureIdxs[i*2+1] | ||
209 | if start < 0 || end < 0 { | ||
210 | vals[i] = cty.NullVal(cty.String) // Did not match anything because containing group didn't match | ||
211 | continue | ||
212 | } | ||
213 | vals[i] = cty.StringVal(str[start:end]) | ||
214 | } | ||
215 | return cty.TupleVal(vals) | ||
216 | case retType.IsObjectType(): | ||
217 | captureIdxs = captureIdxs[2:] // index 0 is the whole pattern span, which we ignore by skipping one pair | ||
218 | vals := make(map[string]cty.Value, len(captureIdxs)/2) | ||
219 | names := re.SubexpNames()[1:] | ||
220 | for i, name := range names { | ||
221 | start, end := captureIdxs[i*2], captureIdxs[i*2+1] | ||
222 | if start < 0 || end < 0 { | ||
223 | vals[name] = cty.NullVal(cty.String) // Did not match anything because containing group didn't match | ||
224 | continue | ||
225 | } | ||
226 | vals[name] = cty.StringVal(str[start:end]) | ||
227 | } | ||
228 | return cty.ObjectVal(vals) | ||
229 | default: | ||
230 | // Should never happen | ||
231 | panic(fmt.Sprintf("invalid return type %#v", retType)) | ||
232 | } | ||
233 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go index e2c77c5..d3cc341 100644 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go | |||
@@ -119,6 +119,75 @@ var ConcatFunc = function.New(&function.Spec{ | |||
119 | }, | 119 | }, |
120 | }) | 120 | }) |
121 | 121 | ||
122 | var RangeFunc = function.New(&function.Spec{ | ||
123 | VarParam: &function.Parameter{ | ||
124 | Name: "params", | ||
125 | Type: cty.Number, | ||
126 | }, | ||
127 | Type: function.StaticReturnType(cty.List(cty.Number)), | ||
128 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
129 | var start, end, step cty.Value | ||
130 | switch len(args) { | ||
131 | case 1: | ||
132 | if args[0].LessThan(cty.Zero).True() { | ||
133 | start, end, step = cty.Zero, args[0], cty.NumberIntVal(-1) | ||
134 | } else { | ||
135 | start, end, step = cty.Zero, args[0], cty.NumberIntVal(1) | ||
136 | } | ||
137 | case 2: | ||
138 | if args[1].LessThan(args[0]).True() { | ||
139 | start, end, step = args[0], args[1], cty.NumberIntVal(-1) | ||
140 | } else { | ||
141 | start, end, step = args[0], args[1], cty.NumberIntVal(1) | ||
142 | } | ||
143 | case 3: | ||
144 | start, end, step = args[0], args[1], args[2] | ||
145 | default: | ||
146 | return cty.NilVal, fmt.Errorf("must have one, two, or three arguments") | ||
147 | } | ||
148 | |||
149 | var vals []cty.Value | ||
150 | |||
151 | if step == cty.Zero { | ||
152 | return cty.NilVal, function.NewArgErrorf(2, "step must not be zero") | ||
153 | } | ||
154 | down := step.LessThan(cty.Zero).True() | ||
155 | |||
156 | if down { | ||
157 | if end.GreaterThan(start).True() { | ||
158 | return cty.NilVal, function.NewArgErrorf(1, "end must be less than start when step is negative") | ||
159 | } | ||
160 | } else { | ||
161 | if end.LessThan(start).True() { | ||
162 | return cty.NilVal, function.NewArgErrorf(1, "end must be greater than start when step is positive") | ||
163 | } | ||
164 | } | ||
165 | |||
166 | num := start | ||
167 | for { | ||
168 | if down { | ||
169 | if num.LessThanOrEqualTo(end).True() { | ||
170 | break | ||
171 | } | ||
172 | } else { | ||
173 | if num.GreaterThanOrEqualTo(end).True() { | ||
174 | break | ||
175 | } | ||
176 | } | ||
177 | if len(vals) >= 1024 { | ||
178 | // Artificial limit to prevent bad arguments from consuming huge amounts of memory | ||
179 | return cty.NilVal, fmt.Errorf("more than 1024 values were generated; either decrease the difference between start and end or use a smaller step") | ||
180 | } | ||
181 | vals = append(vals, num) | ||
182 | num = num.Add(step) | ||
183 | } | ||
184 | if len(vals) == 0 { | ||
185 | return cty.ListValEmpty(cty.Number), nil | ||
186 | } | ||
187 | return cty.ListVal(vals), nil | ||
188 | }, | ||
189 | }) | ||
190 | |||
122 | // Concat takes one or more sequences (lists or tuples) and returns the single | 191 | // Concat takes one or more sequences (lists or tuples) and returns the single |
123 | // sequence that results from concatenating them together in order. | 192 | // sequence that results from concatenating them together in order. |
124 | // | 193 | // |
@@ -128,3 +197,22 @@ var ConcatFunc = function.New(&function.Spec{ | |||
128 | func Concat(seqs ...cty.Value) (cty.Value, error) { | 197 | func Concat(seqs ...cty.Value) (cty.Value, error) { |
129 | return ConcatFunc.Call(seqs) | 198 | return ConcatFunc.Call(seqs) |
130 | } | 199 | } |
200 | |||
201 | // Range creates a list of numbers by starting from the given starting value, | ||
202 | // then adding the given step value until the result is greater than or | ||
203 | // equal to the given stopping value. Each intermediate result becomes an | ||
204 | // element in the resulting list. | ||
205 | // | ||
206 | // When all three parameters are set, the order is (start, end, step). If | ||
207 | // only two parameters are set, they are the start and end respectively and | ||
208 | // step defaults to 1. If only one argument is set, it gives the end value | ||
209 | // with start defaulting to 0 and step defaulting to 1. | ||
210 | // | ||
211 | // Because the resulting list must be fully buffered in memory, there is an | ||
212 | // artificial cap of 1024 elements, after which this function will return | ||
213 | // an error to avoid consuming unbounded amounts of memory. The Range function | ||
214 | // is primarily intended for creating small lists of indices to iterate over, | ||
215 | // so there should be no reason to generate huge lists with it. | ||
216 | func Range(params ...cty.Value) (cty.Value, error) { | ||
217 | return RangeFunc.Call(params) | ||
218 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gob.go b/vendor/github.com/zclconf/go-cty/cty/gob.go index 3d73199..a77dace 100644 --- a/vendor/github.com/zclconf/go-cty/cty/gob.go +++ b/vendor/github.com/zclconf/go-cty/cty/gob.go | |||
@@ -103,11 +103,11 @@ func (t *Type) GobDecode(buf []byte) error { | |||
103 | // Capsule types cannot currently be gob-encoded, because they rely on pointer | 103 | // Capsule types cannot currently be gob-encoded, because they rely on pointer |
104 | // equality and we have no way to recover the original pointer on decode. | 104 | // equality and we have no way to recover the original pointer on decode. |
105 | func (t *capsuleType) GobEncode() ([]byte, error) { | 105 | func (t *capsuleType) GobEncode() ([]byte, error) { |
106 | return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName()) | 106 | return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName(friendlyTypeName)) |
107 | } | 107 | } |
108 | 108 | ||
109 | func (t *capsuleType) GobDecode() ([]byte, error) { | 109 | func (t *capsuleType) GobDecode() ([]byte, error) { |
110 | return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName()) | 110 | return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName(friendlyTypeName)) |
111 | } | 111 | } |
112 | 112 | ||
113 | type gobValue struct { | 113 | type gobValue struct { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/in.go b/vendor/github.com/zclconf/go-cty/cty/gocty/in.go index 642501b..ca9de21 100644 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/in.go +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/in.go | |||
@@ -5,6 +5,7 @@ import ( | |||
5 | "reflect" | 5 | "reflect" |
6 | 6 | ||
7 | "github.com/zclconf/go-cty/cty" | 7 | "github.com/zclconf/go-cty/cty" |
8 | "github.com/zclconf/go-cty/cty/convert" | ||
8 | "github.com/zclconf/go-cty/cty/set" | 9 | "github.com/zclconf/go-cty/cty/set" |
9 | ) | 10 | ) |
10 | 11 | ||
@@ -32,6 +33,11 @@ func ToCtyValue(val interface{}, ty cty.Type) (cty.Value, error) { | |||
32 | } | 33 | } |
33 | 34 | ||
34 | func toCtyValue(val reflect.Value, ty cty.Type, path cty.Path) (cty.Value, error) { | 35 | func toCtyValue(val reflect.Value, ty cty.Type, path cty.Path) (cty.Value, error) { |
36 | if val != (reflect.Value{}) && val.Type().AssignableTo(valueType) { | ||
37 | // If the source value is a cty.Value then we'll try to just pass | ||
38 | // through to the target type directly. | ||
39 | return toCtyPassthrough(val, ty, path) | ||
40 | } | ||
35 | 41 | ||
36 | switch ty { | 42 | switch ty { |
37 | case cty.Bool: | 43 | case cty.Bool: |
@@ -505,6 +511,20 @@ func toCtyDynamic(val reflect.Value, path cty.Path) (cty.Value, error) { | |||
505 | 511 | ||
506 | } | 512 | } |
507 | 513 | ||
514 | func toCtyPassthrough(wrappedVal reflect.Value, wantTy cty.Type, path cty.Path) (cty.Value, error) { | ||
515 | if wrappedVal = toCtyUnwrapPointer(wrappedVal); !wrappedVal.IsValid() { | ||
516 | return cty.NullVal(wantTy), nil | ||
517 | } | ||
518 | |||
519 | givenVal := wrappedVal.Interface().(cty.Value) | ||
520 | |||
521 | val, err := convert.Convert(givenVal, wantTy) | ||
522 | if err != nil { | ||
523 | return cty.NilVal, path.NewErrorf("unsuitable value: %s", err) | ||
524 | } | ||
525 | return val, nil | ||
526 | } | ||
527 | |||
508 | // toCtyUnwrapPointer is a helper for dealing with Go pointers. It has three | 528 | // toCtyUnwrapPointer is a helper for dealing with Go pointers. It has three |
509 | // possible outcomes: | 529 | // possible outcomes: |
510 | // | 530 | // |
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/out.go b/vendor/github.com/zclconf/go-cty/cty/gocty/out.go index 99b65a7..e9c2599 100644 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/out.go +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/out.go | |||
@@ -1,11 +1,10 @@ | |||
1 | package gocty | 1 | package gocty |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "math" | ||
4 | "math/big" | 5 | "math/big" |
5 | "reflect" | 6 | "reflect" |
6 | 7 | ||
7 | "math" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty" | 8 | "github.com/zclconf/go-cty/cty" |
10 | ) | 9 | ) |
11 | 10 | ||
@@ -112,11 +111,7 @@ func fromCtyBool(val cty.Value, target reflect.Value, path cty.Path) error { | |||
112 | switch target.Kind() { | 111 | switch target.Kind() { |
113 | 112 | ||
114 | case reflect.Bool: | 113 | case reflect.Bool: |
115 | if val.True() { | 114 | target.SetBool(val.True()) |
116 | target.Set(reflect.ValueOf(true)) | ||
117 | } else { | ||
118 | target.Set(reflect.ValueOf(false)) | ||
119 | } | ||
120 | return nil | 115 | return nil |
121 | 116 | ||
122 | default: | 117 | default: |
@@ -175,8 +170,7 @@ func fromCtyNumberInt(bf *big.Float, target reflect.Value, path cty.Path) error | |||
175 | return path.NewErrorf("value must be a whole number, between %d and %d", min, max) | 170 | return path.NewErrorf("value must be a whole number, between %d and %d", min, max) |
176 | } | 171 | } |
177 | 172 | ||
178 | target.Set(reflect.ValueOf(iv).Convert(target.Type())) | 173 | target.SetInt(iv) |
179 | |||
180 | return nil | 174 | return nil |
181 | } | 175 | } |
182 | 176 | ||
@@ -202,25 +196,13 @@ func fromCtyNumberUInt(bf *big.Float, target reflect.Value, path cty.Path) error | |||
202 | return path.NewErrorf("value must be a whole number, between 0 and %d inclusive", max) | 196 | return path.NewErrorf("value must be a whole number, between 0 and %d inclusive", max) |
203 | } | 197 | } |
204 | 198 | ||
205 | target.Set(reflect.ValueOf(iv).Convert(target.Type())) | 199 | target.SetUint(iv) |
206 | |||
207 | return nil | 200 | return nil |
208 | } | 201 | } |
209 | 202 | ||
210 | func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) error { | 203 | func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) error { |
211 | switch target.Kind() { | 204 | switch target.Kind() { |
212 | case reflect.Float32: | 205 | case reflect.Float32, reflect.Float64: |
213 | fv, accuracy := bf.Float32() | ||
214 | if accuracy != big.Exact { | ||
215 | // We allow the precision to be truncated as part of our conversion, | ||
216 | // but we don't want to silently introduce infinities. | ||
217 | if math.IsInf(float64(fv), 0) { | ||
218 | return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat32, math.MaxFloat32) | ||
219 | } | ||
220 | } | ||
221 | target.Set(reflect.ValueOf(fv)) | ||
222 | return nil | ||
223 | case reflect.Float64: | ||
224 | fv, accuracy := bf.Float64() | 206 | fv, accuracy := bf.Float64() |
225 | if accuracy != big.Exact { | 207 | if accuracy != big.Exact { |
226 | // We allow the precision to be truncated as part of our conversion, | 208 | // We allow the precision to be truncated as part of our conversion, |
@@ -229,7 +211,7 @@ func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) erro | |||
229 | return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat64, math.MaxFloat64) | 211 | return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat64, math.MaxFloat64) |
230 | } | 212 | } |
231 | } | 213 | } |
232 | target.Set(reflect.ValueOf(fv)) | 214 | target.SetFloat(fv) |
233 | return nil | 215 | return nil |
234 | default: | 216 | default: |
235 | panic("unsupported kind of float") | 217 | panic("unsupported kind of float") |
@@ -239,17 +221,17 @@ func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) erro | |||
239 | func fromCtyNumberBig(bf *big.Float, target reflect.Value, path cty.Path) error { | 221 | func fromCtyNumberBig(bf *big.Float, target reflect.Value, path cty.Path) error { |
240 | switch { | 222 | switch { |
241 | 223 | ||
242 | case bigFloatType.AssignableTo(target.Type()): | 224 | case bigFloatType.ConvertibleTo(target.Type()): |
243 | // Easy! | 225 | // Easy! |
244 | target.Set(reflect.ValueOf(bf).Elem()) | 226 | target.Set(reflect.ValueOf(bf).Elem().Convert(target.Type())) |
245 | return nil | 227 | return nil |
246 | 228 | ||
247 | case bigIntType.AssignableTo(target.Type()): | 229 | case bigIntType.ConvertibleTo(target.Type()): |
248 | bi, accuracy := bf.Int(nil) | 230 | bi, accuracy := bf.Int(nil) |
249 | if accuracy != big.Exact { | 231 | if accuracy != big.Exact { |
250 | return path.NewErrorf("value must be a whole number") | 232 | return path.NewErrorf("value must be a whole number") |
251 | } | 233 | } |
252 | target.Set(reflect.ValueOf(bi).Elem()) | 234 | target.Set(reflect.ValueOf(bi).Elem().Convert(target.Type())) |
253 | return nil | 235 | return nil |
254 | 236 | ||
255 | default: | 237 | default: |
@@ -259,9 +241,8 @@ func fromCtyNumberBig(bf *big.Float, target reflect.Value, path cty.Path) error | |||
259 | 241 | ||
260 | func fromCtyString(val cty.Value, target reflect.Value, path cty.Path) error { | 242 | func fromCtyString(val cty.Value, target reflect.Value, path cty.Path) error { |
261 | switch target.Kind() { | 243 | switch target.Kind() { |
262 | |||
263 | case reflect.String: | 244 | case reflect.String: |
264 | target.Set(reflect.ValueOf(val.AsString())) | 245 | target.SetString(val.AsString()) |
265 | return nil | 246 | return nil |
266 | 247 | ||
267 | default: | 248 | default: |
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go index 1a97306..0fa13f6 100644 --- a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go +++ b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go | |||
@@ -138,7 +138,7 @@ func impliedObjectType(dec *json.Decoder) (cty.Type, error) { | |||
138 | } | 138 | } |
139 | 139 | ||
140 | func impliedTupleType(dec *json.Decoder) (cty.Type, error) { | 140 | func impliedTupleType(dec *json.Decoder) (cty.Type, error) { |
141 | // By the time we get in here, we've already consumed the { delimiter | 141 | // By the time we get in here, we've already consumed the [ delimiter |
142 | // and so our next token should be the first value. | 142 | // and so our next token should be the first value. |
143 | 143 | ||
144 | var etys []cty.Type | 144 | var etys []cty.Type |
@@ -150,10 +150,9 @@ func impliedTupleType(dec *json.Decoder) (cty.Type, error) { | |||
150 | } | 150 | } |
151 | 151 | ||
152 | if ttok, ok := tok.(json.Delim); ok { | 152 | if ttok, ok := tok.(json.Delim); ok { |
153 | if rune(ttok) != ']' { | 153 | if rune(ttok) == ']' { |
154 | return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok) | 154 | break |
155 | } | 155 | } |
156 | break | ||
157 | } | 156 | } |
158 | 157 | ||
159 | ety, err := impliedTypeForTok(tok, dec) | 158 | ety, err := impliedTypeForTok(tok, dec) |
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go index 155f0b8..3810645 100644 --- a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go +++ b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go | |||
@@ -72,7 +72,7 @@ func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, e | |||
72 | } | 72 | } |
73 | switch v := tok.(type) { | 73 | switch v := tok.(type) { |
74 | case string: | 74 | case string: |
75 | val, err := convert.Convert(cty.StringVal(v), t) | 75 | val, err := cty.ParseNumberVal(v) |
76 | if err != nil { | 76 | if err != nil { |
77 | return cty.NilVal, path.NewError(err) | 77 | return cty.NilVal, path.NewError(err) |
78 | } | 78 | } |
diff --git a/vendor/github.com/zclconf/go-cty/cty/list_type.go b/vendor/github.com/zclconf/go-cty/cty/list_type.go index eadc865..2ef02a1 100644 --- a/vendor/github.com/zclconf/go-cty/cty/list_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/list_type.go | |||
@@ -33,8 +33,14 @@ func (t typeList) Equals(other Type) bool { | |||
33 | return t.ElementTypeT.Equals(ot.ElementTypeT) | 33 | return t.ElementTypeT.Equals(ot.ElementTypeT) |
34 | } | 34 | } |
35 | 35 | ||
36 | func (t typeList) FriendlyName() string { | 36 | func (t typeList) FriendlyName(mode friendlyTypeNameMode) string { |
37 | return "list of " + t.ElementTypeT.FriendlyName() | 37 | elemName := t.ElementTypeT.friendlyNameMode(mode) |
38 | if mode == friendlyTypeConstraintName { | ||
39 | if t.ElementTypeT == DynamicPseudoType { | ||
40 | elemName = "any single type" | ||
41 | } | ||
42 | } | ||
43 | return "list of " + elemName | ||
38 | } | 44 | } |
39 | 45 | ||
40 | func (t typeList) ElementType() Type { | 46 | func (t typeList) ElementType() Type { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/map_type.go b/vendor/github.com/zclconf/go-cty/cty/map_type.go index ae9abae..82d36c6 100644 --- a/vendor/github.com/zclconf/go-cty/cty/map_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/map_type.go | |||
@@ -33,8 +33,14 @@ func (t typeMap) Equals(other Type) bool { | |||
33 | return t.ElementTypeT.Equals(ot.ElementTypeT) | 33 | return t.ElementTypeT.Equals(ot.ElementTypeT) |
34 | } | 34 | } |
35 | 35 | ||
36 | func (t typeMap) FriendlyName() string { | 36 | func (t typeMap) FriendlyName(mode friendlyTypeNameMode) string { |
37 | return "map of " + t.ElementTypeT.FriendlyName() | 37 | elemName := t.ElementTypeT.friendlyNameMode(mode) |
38 | if mode == friendlyTypeConstraintName { | ||
39 | if t.ElementTypeT == DynamicPseudoType { | ||
40 | elemName = "any single type" | ||
41 | } | ||
42 | } | ||
43 | return "map of " + elemName | ||
38 | } | 44 | } |
39 | 45 | ||
40 | func (t typeMap) ElementType() Type { | 46 | func (t typeMap) ElementType() Type { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/doc.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/doc.go new file mode 100644 index 0000000..1eb99f2 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/doc.go | |||
@@ -0,0 +1,14 @@ | |||
1 | // Package msgpack provides functions for serializing cty values in the | ||
2 | // msgpack encoding, and decoding them again. | ||
3 | // | ||
4 | // If the same type information is provided both at encoding and decoding time | ||
5 | // then values can be round-tripped without loss, except for capsule types | ||
6 | // which are not currently supported. | ||
7 | // | ||
8 | // If any unknown values are passed to Marshal then they will be represented | ||
9 | // using a msgpack extension with type code zero, which is understood by | ||
10 | // the Unmarshal function within this package but will not be understood by | ||
11 | // a generic (non-cty-aware) msgpack decoder. Ensure that no unknown values | ||
12 | // are used if interoperability with other msgpack implementations is | ||
13 | // required. | ||
14 | package msgpack | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/dynamic.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/dynamic.go new file mode 100644 index 0000000..1b631d0 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/dynamic.go | |||
@@ -0,0 +1,31 @@ | |||
1 | package msgpack | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | |||
6 | "github.com/vmihailenco/msgpack" | ||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | ) | ||
9 | |||
10 | type dynamicVal struct { | ||
11 | Value cty.Value | ||
12 | Path cty.Path | ||
13 | } | ||
14 | |||
15 | func (dv *dynamicVal) MarshalMsgpack() ([]byte, error) { | ||
16 | // Rather than defining a msgpack-specific serialization of types, | ||
17 | // instead we use the existing JSON serialization. | ||
18 | typeJSON, err := dv.Value.Type().MarshalJSON() | ||
19 | if err != nil { | ||
20 | return nil, dv.Path.NewErrorf("failed to serialize type: %s", err) | ||
21 | } | ||
22 | var buf bytes.Buffer | ||
23 | enc := msgpack.NewEncoder(&buf) | ||
24 | enc.EncodeArrayLen(2) | ||
25 | enc.EncodeBytes(typeJSON) | ||
26 | err = marshal(dv.Value, dv.Value.Type(), dv.Path, enc) | ||
27 | if err != nil { | ||
28 | return nil, err | ||
29 | } | ||
30 | return buf.Bytes(), nil | ||
31 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/infinity.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/infinity.go new file mode 100644 index 0000000..6db0815 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/infinity.go | |||
@@ -0,0 +1,8 @@ | |||
1 | package msgpack | ||
2 | |||
3 | import ( | ||
4 | "math" | ||
5 | ) | ||
6 | |||
7 | var negativeInfinity = math.Inf(-1) | ||
8 | var positiveInfinity = math.Inf(1) | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/marshal.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/marshal.go new file mode 100644 index 0000000..87b096c --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/marshal.go | |||
@@ -0,0 +1,207 @@ | |||
1 | package msgpack | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "math/big" | ||
6 | "sort" | ||
7 | |||
8 | "github.com/vmihailenco/msgpack" | ||
9 | "github.com/zclconf/go-cty/cty" | ||
10 | "github.com/zclconf/go-cty/cty/convert" | ||
11 | ) | ||
12 | |||
13 | // Marshal produces a msgpack serialization of the given value that | ||
14 | // can be decoded into the given type later using Unmarshal. | ||
15 | // | ||
16 | // The given value must conform to the given type, or an error will | ||
17 | // be returned. | ||
18 | func Marshal(val cty.Value, ty cty.Type) ([]byte, error) { | ||
19 | errs := val.Type().TestConformance(ty) | ||
20 | if errs != nil { | ||
21 | // Attempt a conversion | ||
22 | var err error | ||
23 | val, err = convert.Convert(val, ty) | ||
24 | if err != nil { | ||
25 | return nil, err | ||
26 | } | ||
27 | } | ||
28 | |||
29 | // From this point onward, val can be assumed to be conforming to t. | ||
30 | |||
31 | var path cty.Path | ||
32 | var buf bytes.Buffer | ||
33 | enc := msgpack.NewEncoder(&buf) | ||
34 | |||
35 | err := marshal(val, ty, path, enc) | ||
36 | if err != nil { | ||
37 | return nil, err | ||
38 | } | ||
39 | |||
40 | return buf.Bytes(), nil | ||
41 | } | ||
42 | |||
43 | func marshal(val cty.Value, ty cty.Type, path cty.Path, enc *msgpack.Encoder) error { | ||
44 | // If we're going to decode as DynamicPseudoType then we need to save | ||
45 | // dynamic type information to recover the real type. | ||
46 | if ty == cty.DynamicPseudoType && val.Type() != cty.DynamicPseudoType { | ||
47 | return marshalDynamic(val, path, enc) | ||
48 | } | ||
49 | |||
50 | if !val.IsKnown() { | ||
51 | err := enc.Encode(unknownVal) | ||
52 | if err != nil { | ||
53 | return path.NewError(err) | ||
54 | } | ||
55 | return nil | ||
56 | } | ||
57 | if val.IsNull() { | ||
58 | err := enc.EncodeNil() | ||
59 | if err != nil { | ||
60 | return path.NewError(err) | ||
61 | } | ||
62 | return nil | ||
63 | } | ||
64 | |||
65 | // The caller should've guaranteed that the given val is conformant with | ||
66 | // the given type ty, so we'll proceed under that assumption here. | ||
67 | switch { | ||
68 | case ty.IsPrimitiveType(): | ||
69 | switch ty { | ||
70 | case cty.String: | ||
71 | err := enc.EncodeString(val.AsString()) | ||
72 | if err != nil { | ||
73 | return path.NewError(err) | ||
74 | } | ||
75 | return nil | ||
76 | case cty.Number: | ||
77 | var err error | ||
78 | switch { | ||
79 | case val.RawEquals(cty.PositiveInfinity): | ||
80 | err = enc.EncodeFloat64(positiveInfinity) | ||
81 | case val.RawEquals(cty.NegativeInfinity): | ||
82 | err = enc.EncodeFloat64(negativeInfinity) | ||
83 | default: | ||
84 | bf := val.AsBigFloat() | ||
85 | if iv, acc := bf.Int64(); acc == big.Exact { | ||
86 | err = enc.EncodeInt(iv) | ||
87 | } else if fv, acc := bf.Float64(); acc == big.Exact { | ||
88 | err = enc.EncodeFloat64(fv) | ||
89 | } else { | ||
90 | err = enc.EncodeString(bf.Text('f', -1)) | ||
91 | } | ||
92 | } | ||
93 | if err != nil { | ||
94 | return path.NewError(err) | ||
95 | } | ||
96 | return nil | ||
97 | case cty.Bool: | ||
98 | err := enc.EncodeBool(val.True()) | ||
99 | if err != nil { | ||
100 | return path.NewError(err) | ||
101 | } | ||
102 | return nil | ||
103 | default: | ||
104 | panic("unsupported primitive type") | ||
105 | } | ||
106 | case ty.IsListType(), ty.IsSetType(): | ||
107 | enc.EncodeArrayLen(val.LengthInt()) | ||
108 | ety := ty.ElementType() | ||
109 | it := val.ElementIterator() | ||
110 | path := append(path, nil) // local override of 'path' with extra element | ||
111 | for it.Next() { | ||
112 | ek, ev := it.Element() | ||
113 | path[len(path)-1] = cty.IndexStep{ | ||
114 | Key: ek, | ||
115 | } | ||
116 | err := marshal(ev, ety, path, enc) | ||
117 | if err != nil { | ||
118 | return err | ||
119 | } | ||
120 | } | ||
121 | return nil | ||
122 | case ty.IsMapType(): | ||
123 | enc.EncodeMapLen(val.LengthInt()) | ||
124 | ety := ty.ElementType() | ||
125 | it := val.ElementIterator() | ||
126 | path := append(path, nil) // local override of 'path' with extra element | ||
127 | for it.Next() { | ||
128 | ek, ev := it.Element() | ||
129 | path[len(path)-1] = cty.IndexStep{ | ||
130 | Key: ek, | ||
131 | } | ||
132 | var err error | ||
133 | err = marshal(ek, ek.Type(), path, enc) | ||
134 | if err != nil { | ||
135 | return err | ||
136 | } | ||
137 | err = marshal(ev, ety, path, enc) | ||
138 | if err != nil { | ||
139 | return err | ||
140 | } | ||
141 | } | ||
142 | return nil | ||
143 | case ty.IsTupleType(): | ||
144 | etys := ty.TupleElementTypes() | ||
145 | it := val.ElementIterator() | ||
146 | path := append(path, nil) // local override of 'path' with extra element | ||
147 | i := 0 | ||
148 | enc.EncodeArrayLen(len(etys)) | ||
149 | for it.Next() { | ||
150 | ety := etys[i] | ||
151 | ek, ev := it.Element() | ||
152 | path[len(path)-1] = cty.IndexStep{ | ||
153 | Key: ek, | ||
154 | } | ||
155 | err := marshal(ev, ety, path, enc) | ||
156 | if err != nil { | ||
157 | return err | ||
158 | } | ||
159 | i++ | ||
160 | } | ||
161 | return nil | ||
162 | case ty.IsObjectType(): | ||
163 | atys := ty.AttributeTypes() | ||
164 | path := append(path, nil) // local override of 'path' with extra element | ||
165 | |||
166 | names := make([]string, 0, len(atys)) | ||
167 | for k := range atys { | ||
168 | names = append(names, k) | ||
169 | } | ||
170 | sort.Strings(names) | ||
171 | |||
172 | enc.EncodeMapLen(len(names)) | ||
173 | |||
174 | for _, k := range names { | ||
175 | aty := atys[k] | ||
176 | av := val.GetAttr(k) | ||
177 | path[len(path)-1] = cty.GetAttrStep{ | ||
178 | Name: k, | ||
179 | } | ||
180 | var err error | ||
181 | err = marshal(cty.StringVal(k), cty.String, path, enc) | ||
182 | if err != nil { | ||
183 | return err | ||
184 | } | ||
185 | err = marshal(av, aty, path, enc) | ||
186 | if err != nil { | ||
187 | return err | ||
188 | } | ||
189 | } | ||
190 | return nil | ||
191 | case ty.IsCapsuleType(): | ||
192 | return path.NewErrorf("capsule types not supported for msgpack encoding") | ||
193 | default: | ||
194 | // should never happen | ||
195 | return path.NewErrorf("cannot msgpack-serialize %s", ty.FriendlyName()) | ||
196 | } | ||
197 | } | ||
198 | |||
199 | // marshalDynamic adds an extra wrapping object containing dynamic type | ||
200 | // information for the given value. | ||
201 | func marshalDynamic(val cty.Value, path cty.Path, enc *msgpack.Encoder) error { | ||
202 | dv := dynamicVal{ | ||
203 | Value: val, | ||
204 | Path: path, | ||
205 | } | ||
206 | return enc.Encode(&dv) | ||
207 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/type_implied.go new file mode 100644 index 0000000..6f6022e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/type_implied.go | |||
@@ -0,0 +1,167 @@ | |||
1 | package msgpack | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | "io" | ||
7 | |||
8 | "github.com/vmihailenco/msgpack" | ||
9 | msgpackcodes "github.com/vmihailenco/msgpack/codes" | ||
10 | "github.com/zclconf/go-cty/cty" | ||
11 | ) | ||
12 | |||
13 | // ImpliedType returns the cty Type implied by the structure of the given | ||
14 | // msgpack-compliant buffer. This function implements the default type mapping | ||
15 | // behavior used when decoding arbitrary msgpack without explicit cty Type | ||
16 | // information. | ||
17 | // | ||
18 | // The rules are as follows: | ||
19 | // | ||
20 | // msgpack strings, numbers and bools map to their equivalent primitive type in | ||
21 | // cty. | ||
22 | // | ||
23 | // msgpack maps become cty object types, with the attributes defined by the | ||
24 | // map keys and the types of their values. | ||
25 | // | ||
26 | // msgpack arrays become cty tuple types, with the elements defined by the | ||
27 | // types of the array members. | ||
28 | // | ||
29 | // Any nulls are typed as DynamicPseudoType, so callers of this function | ||
30 | // must be prepared to deal with this. Callers that do not wish to deal with | ||
31 | // dynamic typing should not use this function and should instead describe | ||
32 | // their required types explicitly with a cty.Type instance when decoding. | ||
33 | // | ||
34 | // Any unknown values are similarly typed as DynamicPseudoType, because these | ||
35 | // do not carry type information on the wire. | ||
36 | // | ||
37 | // Any parse errors will be returned as an error, and the type will be the | ||
38 | // invalid value cty.NilType. | ||
39 | func ImpliedType(buf []byte) (cty.Type, error) { | ||
40 | r := bytes.NewReader(buf) | ||
41 | dec := msgpack.NewDecoder(r) | ||
42 | |||
43 | ty, err := impliedType(dec) | ||
44 | if err != nil { | ||
45 | return cty.NilType, err | ||
46 | } | ||
47 | |||
48 | // We must now be at the end of the buffer | ||
49 | err = dec.Skip() | ||
50 | if err != io.EOF { | ||
51 | return ty, fmt.Errorf("extra bytes after msgpack value") | ||
52 | } | ||
53 | |||
54 | return ty, nil | ||
55 | } | ||
56 | |||
57 | func impliedType(dec *msgpack.Decoder) (cty.Type, error) { | ||
58 | // If this function returns with a nil error then it must have already | ||
59 | // consumed the next value from the decoder, since when called recursively | ||
60 | // the caller will be expecting to find a following value here. | ||
61 | |||
62 | code, err := dec.PeekCode() | ||
63 | if err != nil { | ||
64 | return cty.NilType, err | ||
65 | } | ||
66 | |||
67 | switch { | ||
68 | |||
69 | case code == msgpackcodes.Nil || msgpackcodes.IsExt(code): | ||
70 | err := dec.Skip() | ||
71 | return cty.DynamicPseudoType, err | ||
72 | |||
73 | case code == msgpackcodes.True || code == msgpackcodes.False: | ||
74 | _, err := dec.DecodeBool() | ||
75 | return cty.Bool, err | ||
76 | |||
77 | case msgpackcodes.IsFixedNum(code): | ||
78 | _, err := dec.DecodeInt64() | ||
79 | return cty.Number, err | ||
80 | |||
81 | case code == msgpackcodes.Int8 || code == msgpackcodes.Int16 || code == msgpackcodes.Int32 || code == msgpackcodes.Int64: | ||
82 | _, err := dec.DecodeInt64() | ||
83 | return cty.Number, err | ||
84 | |||
85 | case code == msgpackcodes.Uint8 || code == msgpackcodes.Uint16 || code == msgpackcodes.Uint32 || code == msgpackcodes.Uint64: | ||
86 | _, err := dec.DecodeUint64() | ||
87 | return cty.Number, err | ||
88 | |||
89 | case code == msgpackcodes.Float || code == msgpackcodes.Double: | ||
90 | _, err := dec.DecodeFloat64() | ||
91 | return cty.Number, err | ||
92 | |||
93 | case msgpackcodes.IsString(code): | ||
94 | _, err := dec.DecodeString() | ||
95 | return cty.String, err | ||
96 | |||
97 | case msgpackcodes.IsFixedMap(code) || code == msgpackcodes.Map16 || code == msgpackcodes.Map32: | ||
98 | return impliedObjectType(dec) | ||
99 | |||
100 | case msgpackcodes.IsFixedArray(code) || code == msgpackcodes.Array16 || code == msgpackcodes.Array32: | ||
101 | return impliedTupleType(dec) | ||
102 | |||
103 | default: | ||
104 | return cty.NilType, fmt.Errorf("unsupported msgpack code %#v", code) | ||
105 | } | ||
106 | } | ||
107 | |||
108 | func impliedObjectType(dec *msgpack.Decoder) (cty.Type, error) { | ||
109 | // If we get in here then we've already peeked the next code and know | ||
110 | // it's some sort of map. | ||
111 | l, err := dec.DecodeMapLen() | ||
112 | if err != nil { | ||
113 | return cty.DynamicPseudoType, nil | ||
114 | } | ||
115 | |||
116 | var atys map[string]cty.Type | ||
117 | |||
118 | for i := 0; i < l; i++ { | ||
119 | // Read the map key first. We require maps to be strings, but msgpack | ||
120 | // doesn't so we're prepared to error here if not. | ||
121 | k, err := dec.DecodeString() | ||
122 | if err != nil { | ||
123 | return cty.DynamicPseudoType, err | ||
124 | } | ||
125 | |||
126 | aty, err := impliedType(dec) | ||
127 | if err != nil { | ||
128 | return cty.DynamicPseudoType, err | ||
129 | } | ||
130 | |||
131 | if atys == nil { | ||
132 | atys = make(map[string]cty.Type) | ||
133 | } | ||
134 | atys[k] = aty | ||
135 | } | ||
136 | |||
137 | if len(atys) == 0 { | ||
138 | return cty.EmptyObject, nil | ||
139 | } | ||
140 | |||
141 | return cty.Object(atys), nil | ||
142 | } | ||
143 | |||
144 | func impliedTupleType(dec *msgpack.Decoder) (cty.Type, error) { | ||
145 | // If we get in here then we've already peeked the next code and know | ||
146 | // it's some sort of array. | ||
147 | l, err := dec.DecodeArrayLen() | ||
148 | if err != nil { | ||
149 | return cty.DynamicPseudoType, nil | ||
150 | } | ||
151 | |||
152 | if l == 0 { | ||
153 | return cty.EmptyTuple, nil | ||
154 | } | ||
155 | |||
156 | etys := make([]cty.Type, l) | ||
157 | |||
158 | for i := 0; i < l; i++ { | ||
159 | ety, err := impliedType(dec) | ||
160 | if err != nil { | ||
161 | return cty.DynamicPseudoType, err | ||
162 | } | ||
163 | etys[i] = ety | ||
164 | } | ||
165 | |||
166 | return cty.Tuple(etys), nil | ||
167 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/unknown.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/unknown.go new file mode 100644 index 0000000..6507bc4 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/unknown.go | |||
@@ -0,0 +1,16 @@ | |||
1 | package msgpack | ||
2 | |||
3 | type unknownType struct{} | ||
4 | |||
5 | var unknownVal = unknownType{} | ||
6 | |||
7 | // unknownValBytes is the raw bytes of the msgpack fixext1 value we | ||
8 | // write to represent an unknown value. It's an extension value of | ||
9 | // type zero whose value is irrelevant. Since it's irrelevant, we | ||
10 | // set it to a single byte whose value is also zero, since that's | ||
11 | // the most compact possible representation. | ||
12 | var unknownValBytes = []byte{0xd4, 0, 0} | ||
13 | |||
14 | func (uv unknownType) MarshalMsgpack() ([]byte, error) { | ||
15 | return unknownValBytes, nil | ||
16 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/msgpack/unmarshal.go b/vendor/github.com/zclconf/go-cty/cty/msgpack/unmarshal.go new file mode 100644 index 0000000..51bb76a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/msgpack/unmarshal.go | |||
@@ -0,0 +1,334 @@ | |||
1 | package msgpack | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | |||
6 | "github.com/vmihailenco/msgpack" | ||
7 | msgpackCodes "github.com/vmihailenco/msgpack/codes" | ||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | // Unmarshal interprets the given bytes as a msgpack-encoded cty Value of | ||
12 | // the given type, returning the result. | ||
13 | // | ||
14 | // If an error is returned, the error is written with a hypothetical | ||
15 | // end-user that wrote the msgpack file as its audience, using cty type | ||
16 | // system concepts rather than Go type system concepts. | ||
17 | func Unmarshal(b []byte, ty cty.Type) (cty.Value, error) { | ||
18 | r := bytes.NewReader(b) | ||
19 | dec := msgpack.NewDecoder(r) | ||
20 | |||
21 | var path cty.Path | ||
22 | return unmarshal(dec, ty, path) | ||
23 | } | ||
24 | |||
25 | func unmarshal(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) { | ||
26 | peek, err := dec.PeekCode() | ||
27 | if err != nil { | ||
28 | return cty.DynamicVal, path.NewError(err) | ||
29 | } | ||
30 | if msgpackCodes.IsExt(peek) { | ||
31 | // We just assume _all_ extensions are unknown values, | ||
32 | // since we don't have any other extensions. | ||
33 | dec.Skip() // skip what we've peeked | ||
34 | return cty.UnknownVal(ty), nil | ||
35 | } | ||
36 | if ty == cty.DynamicPseudoType { | ||
37 | return unmarshalDynamic(dec, path) | ||
38 | } | ||
39 | if peek == msgpackCodes.Nil { | ||
40 | dec.Skip() // skip what we've peeked | ||
41 | return cty.NullVal(ty), nil | ||
42 | } | ||
43 | |||
44 | switch { | ||
45 | case ty.IsPrimitiveType(): | ||
46 | val, err := unmarshalPrimitive(dec, ty, path) | ||
47 | if err != nil { | ||
48 | return cty.NilVal, err | ||
49 | } | ||
50 | return val, nil | ||
51 | case ty.IsListType(): | ||
52 | return unmarshalList(dec, ty.ElementType(), path) | ||
53 | case ty.IsSetType(): | ||
54 | return unmarshalSet(dec, ty.ElementType(), path) | ||
55 | case ty.IsMapType(): | ||
56 | return unmarshalMap(dec, ty.ElementType(), path) | ||
57 | case ty.IsTupleType(): | ||
58 | return unmarshalTuple(dec, ty.TupleElementTypes(), path) | ||
59 | case ty.IsObjectType(): | ||
60 | return unmarshalObject(dec, ty.AttributeTypes(), path) | ||
61 | default: | ||
62 | return cty.NilVal, path.NewErrorf("unsupported type %s", ty.FriendlyName()) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | func unmarshalPrimitive(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) { | ||
67 | switch ty { | ||
68 | case cty.Bool: | ||
69 | rv, err := dec.DecodeBool() | ||
70 | if err != nil { | ||
71 | return cty.DynamicVal, path.NewErrorf("bool is required") | ||
72 | } | ||
73 | return cty.BoolVal(rv), nil | ||
74 | case cty.Number: | ||
75 | // Marshal will try int and float first, if the value can be | ||
76 | // losslessly represented in these encodings, and then fall | ||
77 | // back on a string if the number is too large or too precise. | ||
78 | peek, err := dec.PeekCode() | ||
79 | if err != nil { | ||
80 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
81 | } | ||
82 | |||
83 | if msgpackCodes.IsFixedNum(peek) { | ||
84 | rv, err := dec.DecodeInt64() | ||
85 | if err != nil { | ||
86 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
87 | } | ||
88 | return cty.NumberIntVal(rv), nil | ||
89 | } | ||
90 | |||
91 | switch peek { | ||
92 | case msgpackCodes.Int8, msgpackCodes.Int16, msgpackCodes.Int32, msgpackCodes.Int64: | ||
93 | rv, err := dec.DecodeInt64() | ||
94 | if err != nil { | ||
95 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
96 | } | ||
97 | return cty.NumberIntVal(rv), nil | ||
98 | case msgpackCodes.Uint8, msgpackCodes.Uint16, msgpackCodes.Uint32, msgpackCodes.Uint64: | ||
99 | rv, err := dec.DecodeUint64() | ||
100 | if err != nil { | ||
101 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
102 | } | ||
103 | return cty.NumberUIntVal(rv), nil | ||
104 | case msgpackCodes.Float, msgpackCodes.Double: | ||
105 | rv, err := dec.DecodeFloat64() | ||
106 | if err != nil { | ||
107 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
108 | } | ||
109 | return cty.NumberFloatVal(rv), nil | ||
110 | default: | ||
111 | rv, err := dec.DecodeString() | ||
112 | if err != nil { | ||
113 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
114 | } | ||
115 | v, err := cty.ParseNumberVal(rv) | ||
116 | if err != nil { | ||
117 | return cty.DynamicVal, path.NewErrorf("number is required") | ||
118 | } | ||
119 | return v, nil | ||
120 | } | ||
121 | case cty.String: | ||
122 | rv, err := dec.DecodeString() | ||
123 | if err != nil { | ||
124 | return cty.DynamicVal, path.NewErrorf("string is required") | ||
125 | } | ||
126 | return cty.StringVal(rv), nil | ||
127 | default: | ||
128 | // should never happen | ||
129 | panic("unsupported primitive type") | ||
130 | } | ||
131 | } | ||
132 | |||
133 | func unmarshalList(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
134 | length, err := dec.DecodeArrayLen() | ||
135 | if err != nil { | ||
136 | return cty.DynamicVal, path.NewErrorf("a list is required") | ||
137 | } | ||
138 | |||
139 | switch { | ||
140 | case length < 0: | ||
141 | return cty.NullVal(cty.List(ety)), nil | ||
142 | case length == 0: | ||
143 | return cty.ListValEmpty(ety), nil | ||
144 | } | ||
145 | |||
146 | vals := make([]cty.Value, 0, length) | ||
147 | path = append(path, nil) | ||
148 | for i := 0; i < length; i++ { | ||
149 | path[len(path)-1] = cty.IndexStep{ | ||
150 | Key: cty.NumberIntVal(int64(i)), | ||
151 | } | ||
152 | |||
153 | val, err := unmarshal(dec, ety, path) | ||
154 | if err != nil { | ||
155 | return cty.DynamicVal, err | ||
156 | } | ||
157 | |||
158 | vals = append(vals, val) | ||
159 | } | ||
160 | |||
161 | return cty.ListVal(vals), nil | ||
162 | } | ||
163 | |||
164 | func unmarshalSet(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
165 | length, err := dec.DecodeArrayLen() | ||
166 | if err != nil { | ||
167 | return cty.DynamicVal, path.NewErrorf("a set is required") | ||
168 | } | ||
169 | |||
170 | switch { | ||
171 | case length < 0: | ||
172 | return cty.NullVal(cty.Set(ety)), nil | ||
173 | case length == 0: | ||
174 | return cty.SetValEmpty(ety), nil | ||
175 | } | ||
176 | |||
177 | vals := make([]cty.Value, 0, length) | ||
178 | path = append(path, nil) | ||
179 | for i := 0; i < length; i++ { | ||
180 | path[len(path)-1] = cty.IndexStep{ | ||
181 | Key: cty.NumberIntVal(int64(i)), | ||
182 | } | ||
183 | |||
184 | val, err := unmarshal(dec, ety, path) | ||
185 | if err != nil { | ||
186 | return cty.DynamicVal, err | ||
187 | } | ||
188 | |||
189 | vals = append(vals, val) | ||
190 | } | ||
191 | |||
192 | return cty.SetVal(vals), nil | ||
193 | } | ||
194 | |||
195 | func unmarshalMap(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
196 | length, err := dec.DecodeMapLen() | ||
197 | if err != nil { | ||
198 | return cty.DynamicVal, path.NewErrorf("a map is required") | ||
199 | } | ||
200 | |||
201 | switch { | ||
202 | case length < 0: | ||
203 | return cty.NullVal(cty.Map(ety)), nil | ||
204 | case length == 0: | ||
205 | return cty.MapValEmpty(ety), nil | ||
206 | } | ||
207 | |||
208 | vals := make(map[string]cty.Value, length) | ||
209 | path = append(path, nil) | ||
210 | for i := 0; i < length; i++ { | ||
211 | key, err := dec.DecodeString() | ||
212 | if err != nil { | ||
213 | path[:len(path)-1].NewErrorf("non-string key in map") | ||
214 | } | ||
215 | |||
216 | path[len(path)-1] = cty.IndexStep{ | ||
217 | Key: cty.StringVal(key), | ||
218 | } | ||
219 | |||
220 | val, err := unmarshal(dec, ety, path) | ||
221 | if err != nil { | ||
222 | return cty.DynamicVal, err | ||
223 | } | ||
224 | |||
225 | vals[key] = val | ||
226 | } | ||
227 | |||
228 | return cty.MapVal(vals), nil | ||
229 | } | ||
230 | |||
231 | func unmarshalTuple(dec *msgpack.Decoder, etys []cty.Type, path cty.Path) (cty.Value, error) { | ||
232 | length, err := dec.DecodeArrayLen() | ||
233 | if err != nil { | ||
234 | return cty.DynamicVal, path.NewErrorf("a tuple is required") | ||
235 | } | ||
236 | |||
237 | switch { | ||
238 | case length < 0: | ||
239 | return cty.NullVal(cty.Tuple(etys)), nil | ||
240 | case length == 0: | ||
241 | return cty.TupleVal(nil), nil | ||
242 | case length != len(etys): | ||
243 | return cty.DynamicVal, path.NewErrorf("a tuple of length %d is required", len(etys)) | ||
244 | } | ||
245 | |||
246 | vals := make([]cty.Value, 0, length) | ||
247 | path = append(path, nil) | ||
248 | for i := 0; i < length; i++ { | ||
249 | path[len(path)-1] = cty.IndexStep{ | ||
250 | Key: cty.NumberIntVal(int64(i)), | ||
251 | } | ||
252 | ety := etys[i] | ||
253 | |||
254 | val, err := unmarshal(dec, ety, path) | ||
255 | if err != nil { | ||
256 | return cty.DynamicVal, err | ||
257 | } | ||
258 | |||
259 | vals = append(vals, val) | ||
260 | } | ||
261 | |||
262 | return cty.TupleVal(vals), nil | ||
263 | } | ||
264 | |||
265 | func unmarshalObject(dec *msgpack.Decoder, atys map[string]cty.Type, path cty.Path) (cty.Value, error) { | ||
266 | length, err := dec.DecodeMapLen() | ||
267 | if err != nil { | ||
268 | return cty.DynamicVal, path.NewErrorf("an object is required") | ||
269 | } | ||
270 | |||
271 | switch { | ||
272 | case length < 0: | ||
273 | return cty.NullVal(cty.Object(atys)), nil | ||
274 | case length == 0: | ||
275 | return cty.ObjectVal(nil), nil | ||
276 | case length != len(atys): | ||
277 | return cty.DynamicVal, path.NewErrorf("an object with %d attributes is required (%d given)", | ||
278 | len(atys), length) | ||
279 | } | ||
280 | |||
281 | vals := make(map[string]cty.Value, length) | ||
282 | path = append(path, nil) | ||
283 | for i := 0; i < length; i++ { | ||
284 | key, err := dec.DecodeString() | ||
285 | if err != nil { | ||
286 | return cty.DynamicVal, path[:len(path)-1].NewErrorf("all keys must be strings") | ||
287 | } | ||
288 | |||
289 | path[len(path)-1] = cty.IndexStep{ | ||
290 | Key: cty.StringVal(key), | ||
291 | } | ||
292 | aty, exists := atys[key] | ||
293 | if !exists { | ||
294 | return cty.DynamicVal, path.NewErrorf("unsupported attribute") | ||
295 | } | ||
296 | |||
297 | val, err := unmarshal(dec, aty, path) | ||
298 | if err != nil { | ||
299 | return cty.DynamicVal, err | ||
300 | } | ||
301 | |||
302 | vals[key] = val | ||
303 | } | ||
304 | |||
305 | return cty.ObjectVal(vals), nil | ||
306 | } | ||
307 | |||
308 | func unmarshalDynamic(dec *msgpack.Decoder, path cty.Path) (cty.Value, error) { | ||
309 | length, err := dec.DecodeArrayLen() | ||
310 | if err != nil { | ||
311 | return cty.DynamicVal, path.NewError(err) | ||
312 | } | ||
313 | |||
314 | switch { | ||
315 | case length == -1: | ||
316 | return cty.NullVal(cty.DynamicPseudoType), nil | ||
317 | case length != 2: | ||
318 | return cty.DynamicVal, path.NewErrorf( | ||
319 | "dynamic value array must have exactly two elements", | ||
320 | ) | ||
321 | } | ||
322 | |||
323 | typeJSON, err := dec.DecodeBytes() | ||
324 | if err != nil { | ||
325 | return cty.DynamicVal, path.NewError(err) | ||
326 | } | ||
327 | var ty cty.Type | ||
328 | err = (&ty).UnmarshalJSON(typeJSON) | ||
329 | if err != nil { | ||
330 | return cty.DynamicVal, path.NewError(err) | ||
331 | } | ||
332 | |||
333 | return unmarshal(dec, ty, path) | ||
334 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/object_type.go b/vendor/github.com/zclconf/go-cty/cty/object_type.go index 2540883..187d387 100644 --- a/vendor/github.com/zclconf/go-cty/cty/object_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/object_type.go | |||
@@ -51,7 +51,7 @@ func (t typeObject) Equals(other Type) bool { | |||
51 | return false | 51 | return false |
52 | } | 52 | } |
53 | 53 | ||
54 | func (t typeObject) FriendlyName() string { | 54 | func (t typeObject) FriendlyName(mode friendlyTypeNameMode) string { |
55 | // There isn't really a friendly way to write an object type due to its | 55 | // There isn't really a friendly way to write an object type due to its |
56 | // complexity, so we'll just do something English-ish. Callers will | 56 | // complexity, so we'll just do something English-ish. Callers will |
57 | // probably want to make some extra effort to avoid ever printing out | 57 | // probably want to make some extra effort to avoid ever printing out |
diff --git a/vendor/github.com/zclconf/go-cty/cty/path.go b/vendor/github.com/zclconf/go-cty/cty/path.go index 84a9de0..bf1a7c1 100644 --- a/vendor/github.com/zclconf/go-cty/cty/path.go +++ b/vendor/github.com/zclconf/go-cty/cty/path.go | |||
@@ -15,6 +15,10 @@ import ( | |||
15 | // but callers can also feel free to just produce a slice of PathStep manually | 15 | // but callers can also feel free to just produce a slice of PathStep manually |
16 | // and convert to this type, which may be more appropriate in environments | 16 | // and convert to this type, which may be more appropriate in environments |
17 | // where memory pressure is a concern. | 17 | // where memory pressure is a concern. |
18 | // | ||
19 | // Although a Path is technically mutable, by convention callers should not | ||
20 | // mutate a path once it has been built and passed to some other subsystem. | ||
21 | // Instead, use Copy and then mutate the copy before using it. | ||
18 | type Path []PathStep | 22 | type Path []PathStep |
19 | 23 | ||
20 | // PathStep represents a single step down into a data structure, as part | 24 | // PathStep represents a single step down into a data structure, as part |
@@ -47,6 +51,11 @@ func (p Path) Index(v Value) Path { | |||
47 | return ret | 51 | return ret |
48 | } | 52 | } |
49 | 53 | ||
54 | // IndexPath is a convenience method to start a new Path with an IndexStep. | ||
55 | func IndexPath(v Value) Path { | ||
56 | return Path{}.Index(v) | ||
57 | } | ||
58 | |||
50 | // GetAttr returns a new Path that is the reciever with a GetAttrStep appended | 59 | // GetAttr returns a new Path that is the reciever with a GetAttrStep appended |
51 | // to the end. | 60 | // to the end. |
52 | // | 61 | // |
@@ -62,6 +71,11 @@ func (p Path) GetAttr(name string) Path { | |||
62 | return ret | 71 | return ret |
63 | } | 72 | } |
64 | 73 | ||
74 | // GetAttrPath is a convenience method to start a new Path with a GetAttrStep. | ||
75 | func GetAttrPath(name string) Path { | ||
76 | return Path{}.GetAttr(name) | ||
77 | } | ||
78 | |||
65 | // Apply applies each of the steps in turn to successive values starting with | 79 | // Apply applies each of the steps in turn to successive values starting with |
66 | // the given value, and returns the result. If any step returns an error, | 80 | // the given value, and returns the result. If any step returns an error, |
67 | // the whole operation returns an error. | 81 | // the whole operation returns an error. |
@@ -132,9 +146,13 @@ type IndexStep struct { | |||
132 | // Apply returns the value resulting from indexing the given value with | 146 | // Apply returns the value resulting from indexing the given value with |
133 | // our key value. | 147 | // our key value. |
134 | func (s IndexStep) Apply(val Value) (Value, error) { | 148 | func (s IndexStep) Apply(val Value) (Value, error) { |
149 | if val == NilVal || val.IsNull() { | ||
150 | return NilVal, errors.New("cannot index a null value") | ||
151 | } | ||
152 | |||
135 | switch s.Key.Type() { | 153 | switch s.Key.Type() { |
136 | case Number: | 154 | case Number: |
137 | if !val.Type().IsListType() { | 155 | if !(val.Type().IsListType() || val.Type().IsTupleType()) { |
138 | return NilVal, errors.New("not a list type") | 156 | return NilVal, errors.New("not a list type") |
139 | } | 157 | } |
140 | case String: | 158 | case String: |
@@ -170,6 +188,10 @@ type GetAttrStep struct { | |||
170 | // Apply returns the value of our named attribute from the given value, which | 188 | // Apply returns the value of our named attribute from the given value, which |
171 | // must be of an object type that has a value of that name. | 189 | // must be of an object type that has a value of that name. |
172 | func (s GetAttrStep) Apply(val Value) (Value, error) { | 190 | func (s GetAttrStep) Apply(val Value) (Value, error) { |
191 | if val == NilVal || val.IsNull() { | ||
192 | return NilVal, errors.New("cannot access attributes on a null value") | ||
193 | } | ||
194 | |||
173 | if !val.Type().IsObjectType() { | 195 | if !val.Type().IsObjectType() { |
174 | return NilVal, errors.New("not an object type") | 196 | return NilVal, errors.New("not an object type") |
175 | } | 197 | } |
diff --git a/vendor/github.com/zclconf/go-cty/cty/path_set.go b/vendor/github.com/zclconf/go-cty/cty/path_set.go new file mode 100644 index 0000000..f1c892b --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/path_set.go | |||
@@ -0,0 +1,198 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "hash/crc64" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty/set" | ||
8 | ) | ||
9 | |||
10 | // PathSet represents a set of Path objects. This can be used, for example, | ||
11 | // to talk about a subset of paths within a value that meet some criteria, | ||
12 | // without directly modifying the values at those paths. | ||
13 | type PathSet struct { | ||
14 | set set.Set | ||
15 | } | ||
16 | |||
17 | // NewPathSet creates and returns a PathSet, with initial contents optionally | ||
18 | // set by the given arguments. | ||
19 | func NewPathSet(paths ...Path) PathSet { | ||
20 | ret := PathSet{ | ||
21 | set: set.NewSet(pathSetRules{}), | ||
22 | } | ||
23 | |||
24 | for _, path := range paths { | ||
25 | ret.Add(path) | ||
26 | } | ||
27 | |||
28 | return ret | ||
29 | } | ||
30 | |||
31 | // Add inserts a single given path into the set. | ||
32 | // | ||
33 | // Paths are immutable after construction by convention. It is particularly | ||
34 | // important not to mutate a path after it has been placed into a PathSet. | ||
35 | // If a Path is mutated while in a set, behavior is undefined. | ||
36 | func (s PathSet) Add(path Path) { | ||
37 | s.set.Add(path) | ||
38 | } | ||
39 | |||
40 | // AddAllSteps is like Add but it also adds all of the steps leading to | ||
41 | // the given path. | ||
42 | // | ||
43 | // For example, if given a path representing "foo.bar", it will add both | ||
44 | // "foo" and "bar". | ||
45 | func (s PathSet) AddAllSteps(path Path) { | ||
46 | for i := 1; i <= len(path); i++ { | ||
47 | s.Add(path[:i]) | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // Has returns true if the given path is in the receiving set. | ||
52 | func (s PathSet) Has(path Path) bool { | ||
53 | return s.set.Has(path) | ||
54 | } | ||
55 | |||
56 | // List makes and returns a slice of all of the paths in the receiving set, | ||
57 | // in an undefined but consistent order. | ||
58 | func (s PathSet) List() []Path { | ||
59 | if s.Empty() { | ||
60 | return nil | ||
61 | } | ||
62 | ret := make([]Path, 0, s.set.Length()) | ||
63 | for it := s.set.Iterator(); it.Next(); { | ||
64 | ret = append(ret, it.Value().(Path)) | ||
65 | } | ||
66 | return ret | ||
67 | } | ||
68 | |||
69 | // Remove modifies the receving set to no longer include the given path. | ||
70 | // If the given path was already absent, this is a no-op. | ||
71 | func (s PathSet) Remove(path Path) { | ||
72 | s.set.Remove(path) | ||
73 | } | ||
74 | |||
75 | // Empty returns true if the length of the receiving set is zero. | ||
76 | func (s PathSet) Empty() bool { | ||
77 | return s.set.Length() == 0 | ||
78 | } | ||
79 | |||
80 | // Union returns a new set whose contents are the union of the receiver and | ||
81 | // the given other set. | ||
82 | func (s PathSet) Union(other PathSet) PathSet { | ||
83 | return PathSet{ | ||
84 | set: s.set.Union(other.set), | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // Intersection returns a new set whose contents are the intersection of the | ||
89 | // receiver and the given other set. | ||
90 | func (s PathSet) Intersection(other PathSet) PathSet { | ||
91 | return PathSet{ | ||
92 | set: s.set.Intersection(other.set), | ||
93 | } | ||
94 | } | ||
95 | |||
96 | // Subtract returns a new set whose contents are those from the receiver with | ||
97 | // any elements of the other given set subtracted. | ||
98 | func (s PathSet) Subtract(other PathSet) PathSet { | ||
99 | return PathSet{ | ||
100 | set: s.set.Subtract(other.set), | ||
101 | } | ||
102 | } | ||
103 | |||
104 | // SymmetricDifference returns a new set whose contents are the symmetric | ||
105 | // difference of the receiver and the given other set. | ||
106 | func (s PathSet) SymmetricDifference(other PathSet) PathSet { | ||
107 | return PathSet{ | ||
108 | set: s.set.SymmetricDifference(other.set), | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // Equal returns true if and only if both the receiver and the given other | ||
113 | // set contain exactly the same paths. | ||
114 | func (s PathSet) Equal(other PathSet) bool { | ||
115 | if s.set.Length() != other.set.Length() { | ||
116 | return false | ||
117 | } | ||
118 | // Now we know the lengths are the same we only need to test in one | ||
119 | // direction whether everything in one is in the other. | ||
120 | for it := s.set.Iterator(); it.Next(); { | ||
121 | if !other.set.Has(it.Value()) { | ||
122 | return false | ||
123 | } | ||
124 | } | ||
125 | return true | ||
126 | } | ||
127 | |||
128 | var crc64Table = crc64.MakeTable(crc64.ISO) | ||
129 | |||
130 | var indexStepPlaceholder = []byte("#") | ||
131 | |||
132 | // pathSetRules is an implementation of set.Rules from the set package, | ||
133 | // used internally within PathSet. | ||
134 | type pathSetRules struct { | ||
135 | } | ||
136 | |||
137 | func (r pathSetRules) Hash(v interface{}) int { | ||
138 | path := v.(Path) | ||
139 | hash := crc64.New(crc64Table) | ||
140 | |||
141 | for _, rawStep := range path { | ||
142 | switch step := rawStep.(type) { | ||
143 | case GetAttrStep: | ||
144 | // (this creates some garbage converting the string name to a | ||
145 | // []byte, but that's okay since cty is not designed to be | ||
146 | // used in tight loops under memory pressure.) | ||
147 | hash.Write([]byte(step.Name)) | ||
148 | default: | ||
149 | // For any other step type we just append a predefined value, | ||
150 | // which means that e.g. all indexes into a given collection will | ||
151 | // hash to the same value but we assume that collections are | ||
152 | // small and thus this won't hurt too much. | ||
153 | hash.Write(indexStepPlaceholder) | ||
154 | } | ||
155 | } | ||
156 | |||
157 | // We discard half of the hash on 32-bit platforms; collisions just make | ||
158 | // our lookups take marginally longer, so not a big deal. | ||
159 | return int(hash.Sum64()) | ||
160 | } | ||
161 | |||
162 | func (r pathSetRules) Equivalent(a, b interface{}) bool { | ||
163 | aPath := a.(Path) | ||
164 | bPath := b.(Path) | ||
165 | |||
166 | if len(aPath) != len(bPath) { | ||
167 | return false | ||
168 | } | ||
169 | |||
170 | for i := range aPath { | ||
171 | switch aStep := aPath[i].(type) { | ||
172 | case GetAttrStep: | ||
173 | bStep, ok := bPath[i].(GetAttrStep) | ||
174 | if !ok { | ||
175 | return false | ||
176 | } | ||
177 | |||
178 | if aStep.Name != bStep.Name { | ||
179 | return false | ||
180 | } | ||
181 | case IndexStep: | ||
182 | bStep, ok := bPath[i].(IndexStep) | ||
183 | if !ok { | ||
184 | return false | ||
185 | } | ||
186 | |||
187 | eq := aStep.Key.Equals(bStep.Key) | ||
188 | if !eq.IsKnown() || eq.False() { | ||
189 | return false | ||
190 | } | ||
191 | default: | ||
192 | // Should never happen, since we document PathStep as a closed type. | ||
193 | panic(fmt.Errorf("unsupported step type %T", aStep)) | ||
194 | } | ||
195 | } | ||
196 | |||
197 | return true | ||
198 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go index b8682dd..7b3d119 100644 --- a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go | |||
@@ -24,7 +24,7 @@ func (t primitiveType) Equals(other Type) bool { | |||
24 | return false | 24 | return false |
25 | } | 25 | } |
26 | 26 | ||
27 | func (t primitiveType) FriendlyName() string { | 27 | func (t primitiveType) FriendlyName(mode friendlyTypeNameMode) string { |
28 | switch t.Kind { | 28 | switch t.Kind { |
29 | case primitiveTypeBool: | 29 | case primitiveTypeBool: |
30 | return "bool" | 30 | return "bool" |
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/iterator.go b/vendor/github.com/zclconf/go-cty/cty/set/iterator.go index f15498e..4a60494 100644 --- a/vendor/github.com/zclconf/go-cty/cty/set/iterator.go +++ b/vendor/github.com/zclconf/go-cty/cty/set/iterator.go | |||
@@ -1,36 +1,15 @@ | |||
1 | package set | 1 | package set |
2 | 2 | ||
3 | type Iterator struct { | 3 | type Iterator struct { |
4 | bucketIds []int | 4 | vals []interface{} |
5 | vals map[int][]interface{} | 5 | idx int |
6 | bucketIdx int | ||
7 | valIdx int | ||
8 | } | 6 | } |
9 | 7 | ||
10 | func (it *Iterator) Value() interface{} { | 8 | func (it *Iterator) Value() interface{} { |
11 | return it.currentBucket()[it.valIdx] | 9 | return it.vals[it.idx] |
12 | } | 10 | } |
13 | 11 | ||
14 | func (it *Iterator) Next() bool { | 12 | func (it *Iterator) Next() bool { |
15 | if it.bucketIdx == -1 { | 13 | it.idx++ |
16 | // init | 14 | return it.idx < len(it.vals) |
17 | if len(it.bucketIds) == 0 { | ||
18 | return false | ||
19 | } | ||
20 | |||
21 | it.valIdx = 0 | ||
22 | it.bucketIdx = 0 | ||
23 | return true | ||
24 | } | ||
25 | |||
26 | it.valIdx++ | ||
27 | if it.valIdx >= len(it.currentBucket()) { | ||
28 | it.valIdx = 0 | ||
29 | it.bucketIdx++ | ||
30 | } | ||
31 | return it.bucketIdx < len(it.bucketIds) | ||
32 | } | ||
33 | |||
34 | func (it *Iterator) currentBucket() []interface{} { | ||
35 | return it.vals[it.bucketIds[it.bucketIdx]] | ||
36 | } | 15 | } |
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/ops.go b/vendor/github.com/zclconf/go-cty/cty/set/ops.go index 726e707..fd1555f 100644 --- a/vendor/github.com/zclconf/go-cty/cty/set/ops.go +++ b/vendor/github.com/zclconf/go-cty/cty/set/ops.go | |||
@@ -75,8 +75,12 @@ func (s Set) Copy() Set { | |||
75 | return ret | 75 | return ret |
76 | } | 76 | } |
77 | 77 | ||
78 | // Iterator returns an iterator over values in the set, in an undefined order | 78 | // Iterator returns an iterator over values in the set. If the set's rules |
79 | // that callers should not depend on. | 79 | // implement OrderedRules then the result is ordered per those rules. If |
80 | // no order is provided, or if it is not a total order, then the iteration | ||
81 | // order is undefined but consistent for a particular version of cty. Do not | ||
82 | // rely on specific ordering between cty releases unless the rules order is a | ||
83 | // total order. | ||
80 | // | 84 | // |
81 | // The pattern for using the returned iterator is: | 85 | // The pattern for using the returned iterator is: |
82 | // | 86 | // |
@@ -89,18 +93,11 @@ func (s Set) Copy() Set { | |||
89 | // Once an iterator has been created for a set, the set *must not* be mutated | 93 | // Once an iterator has been created for a set, the set *must not* be mutated |
90 | // until the iterator is no longer in use. | 94 | // until the iterator is no longer in use. |
91 | func (s Set) Iterator() *Iterator { | 95 | func (s Set) Iterator() *Iterator { |
92 | // Sort the bucketIds to ensure that we always traverse in a | 96 | vals := s.Values() |
93 | // consistent order. | ||
94 | bucketIds := make([]int, 0, len(s.vals)) | ||
95 | for id := range s.vals { | ||
96 | bucketIds = append(bucketIds, id) | ||
97 | } | ||
98 | sort.Ints(bucketIds) | ||
99 | 97 | ||
100 | return &Iterator{ | 98 | return &Iterator{ |
101 | bucketIds: bucketIds, | 99 | vals: vals, |
102 | vals: s.vals, | 100 | idx: -1, |
103 | bucketIdx: -1, | ||
104 | } | 101 | } |
105 | } | 102 | } |
106 | 103 | ||
@@ -113,16 +110,30 @@ func (s Set) EachValue(cb func(interface{})) { | |||
113 | } | 110 | } |
114 | } | 111 | } |
115 | 112 | ||
116 | // Values returns a slice of all of the values in the set in no particular | 113 | // Values returns a slice of all the values in the set. If the set rules have |
117 | // order. This is just a wrapper around EachValue that accumulates the results | 114 | // an order then the result is in that order. If no order is provided or if |
118 | // in a slice for caller convenience. | 115 | // it is not a total order then the result order is undefined, but consistent |
119 | // | 116 | // for a particular set value within a specific release of cty. |
120 | // The returned slice will be nil if there are no values in the set. | ||
121 | func (s Set) Values() []interface{} { | 117 | func (s Set) Values() []interface{} { |
122 | var ret []interface{} | 118 | var ret []interface{} |
123 | s.EachValue(func(v interface{}) { | 119 | // Sort the bucketIds to ensure that we always traverse in a |
124 | ret = append(ret, v) | 120 | // consistent order. |
125 | }) | 121 | bucketIDs := make([]int, 0, len(s.vals)) |
122 | for id := range s.vals { | ||
123 | bucketIDs = append(bucketIDs, id) | ||
124 | } | ||
125 | sort.Ints(bucketIDs) | ||
126 | |||
127 | for _, bucketID := range bucketIDs { | ||
128 | ret = append(ret, s.vals[bucketID]...) | ||
129 | } | ||
130 | |||
131 | if orderRules, ok := s.rules.(OrderedRules); ok { | ||
132 | sort.SliceStable(ret, func(i, j int) bool { | ||
133 | return orderRules.Less(ret[i], ret[j]) | ||
134 | }) | ||
135 | } | ||
136 | |||
126 | return ret | 137 | return ret |
127 | } | 138 | } |
128 | 139 | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/rules.go b/vendor/github.com/zclconf/go-cty/cty/set/rules.go index 7200184..51f744b 100644 --- a/vendor/github.com/zclconf/go-cty/cty/set/rules.go +++ b/vendor/github.com/zclconf/go-cty/cty/set/rules.go | |||
@@ -23,3 +23,21 @@ type Rules interface { | |||
23 | // be equivalent. | 23 | // be equivalent. |
24 | Equivalent(interface{}, interface{}) bool | 24 | Equivalent(interface{}, interface{}) bool |
25 | } | 25 | } |
26 | |||
27 | // OrderedRules is an extension of Rules that can apply a partial order to | ||
28 | // element values. When a set's Rules implements OrderedRules an iterator | ||
29 | // over the set will return items in the order described by the rules. | ||
30 | // | ||
31 | // If the given order is not a total order (that is, some pairs of non-equivalent | ||
32 | // elements do not have a defined order) then the resulting iteration order | ||
33 | // is undefined but consistent for a particular version of cty. The exact | ||
34 | // order in that case is not part of the contract and is subject to change | ||
35 | // between versions. | ||
36 | type OrderedRules interface { | ||
37 | Rules | ||
38 | |||
39 | // Less returns true if and only if the first argument should sort before | ||
40 | // the second argument. If the second argument should sort before the first | ||
41 | // or if there is no defined order for the values, return false. | ||
42 | Less(interface{}, interface{}) bool | ||
43 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set_internals.go b/vendor/github.com/zclconf/go-cty/cty/set_internals.go index ce738db..3fd4fb2 100644 --- a/vendor/github.com/zclconf/go-cty/cty/set_internals.go +++ b/vendor/github.com/zclconf/go-cty/cty/set_internals.go | |||
@@ -6,6 +6,8 @@ import ( | |||
6 | "hash/crc32" | 6 | "hash/crc32" |
7 | "math/big" | 7 | "math/big" |
8 | "sort" | 8 | "sort" |
9 | |||
10 | "github.com/zclconf/go-cty/cty/set" | ||
9 | ) | 11 | ) |
10 | 12 | ||
11 | // setRules provides a Rules implementation for the ./set package that | 13 | // setRules provides a Rules implementation for the ./set package that |
@@ -19,12 +21,26 @@ type setRules struct { | |||
19 | Type Type | 21 | Type Type |
20 | } | 22 | } |
21 | 23 | ||
24 | var _ set.OrderedRules = setRules{} | ||
25 | |||
26 | // Hash returns a hash value for the receiver that can be used for equality | ||
27 | // checks where some inaccuracy is tolerable. | ||
28 | // | ||
29 | // The hash function is value-type-specific, so it is not meaningful to compare | ||
30 | // hash results for values of different types. | ||
31 | // | ||
32 | // This function is not safe to use for security-related applications, since | ||
33 | // the hash used is not strong enough. | ||
34 | func (val Value) Hash() int { | ||
35 | hashBytes := makeSetHashBytes(val) | ||
36 | return int(crc32.ChecksumIEEE(hashBytes)) | ||
37 | } | ||
38 | |||
22 | func (r setRules) Hash(v interface{}) int { | 39 | func (r setRules) Hash(v interface{}) int { |
23 | hashBytes := makeSetHashBytes(Value{ | 40 | return Value{ |
24 | ty: r.Type, | 41 | ty: r.Type, |
25 | v: v, | 42 | v: v, |
26 | }) | 43 | }.Hash() |
27 | return int(crc32.ChecksumIEEE(hashBytes)) | ||
28 | } | 44 | } |
29 | 45 | ||
30 | func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool { | 46 | func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool { |
@@ -46,6 +62,60 @@ func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool { | |||
46 | return eqv.v == true | 62 | return eqv.v == true |
47 | } | 63 | } |
48 | 64 | ||
65 | // Less is an implementation of set.OrderedRules so that we can iterate over | ||
66 | // set elements in a consistent order, where such an order is possible. | ||
67 | func (r setRules) Less(v1, v2 interface{}) bool { | ||
68 | v1v := Value{ | ||
69 | ty: r.Type, | ||
70 | v: v1, | ||
71 | } | ||
72 | v2v := Value{ | ||
73 | ty: r.Type, | ||
74 | v: v2, | ||
75 | } | ||
76 | |||
77 | if v1v.RawEquals(v2v) { // Easy case: if they are equal then v1 can't be less | ||
78 | return false | ||
79 | } | ||
80 | |||
81 | // Null values always sort after non-null values | ||
82 | if v2v.IsNull() && !v1v.IsNull() { | ||
83 | return true | ||
84 | } else if v1v.IsNull() { | ||
85 | return false | ||
86 | } | ||
87 | // Unknown values always sort after known values | ||
88 | if v1v.IsKnown() && !v2v.IsKnown() { | ||
89 | return true | ||
90 | } else if !v1v.IsKnown() { | ||
91 | return false | ||
92 | } | ||
93 | |||
94 | switch r.Type { | ||
95 | case String: | ||
96 | // String values sort lexicographically | ||
97 | return v1v.AsString() < v2v.AsString() | ||
98 | case Bool: | ||
99 | // Weird to have a set of bools, but if we do then false sorts before true. | ||
100 | if v2v.True() || !v1v.True() { | ||
101 | return true | ||
102 | } | ||
103 | return false | ||
104 | case Number: | ||
105 | v1f := v1v.AsBigFloat() | ||
106 | v2f := v2v.AsBigFloat() | ||
107 | return v1f.Cmp(v2f) < 0 | ||
108 | default: | ||
109 | // No other types have a well-defined ordering, so we just produce a | ||
110 | // default consistent-but-undefined ordering then. This situation is | ||
111 | // not considered a compatibility constraint; callers should rely only | ||
112 | // on the ordering rules for primitive values. | ||
113 | v1h := makeSetHashBytes(v1v) | ||
114 | v2h := makeSetHashBytes(v2v) | ||
115 | return bytes.Compare(v1h, v2h) < 0 | ||
116 | } | ||
117 | } | ||
118 | |||
49 | func makeSetHashBytes(val Value) []byte { | 119 | func makeSetHashBytes(val Value) []byte { |
50 | var buf bytes.Buffer | 120 | var buf bytes.Buffer |
51 | appendSetHashBytes(val, &buf) | 121 | appendSetHashBytes(val, &buf) |
diff --git a/vendor/github.com/zclconf/go-cty/cty/set_type.go b/vendor/github.com/zclconf/go-cty/cty/set_type.go index 952a2d2..cbc3706 100644 --- a/vendor/github.com/zclconf/go-cty/cty/set_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/set_type.go | |||
@@ -31,8 +31,14 @@ func (t typeSet) Equals(other Type) bool { | |||
31 | return t.ElementTypeT.Equals(ot.ElementTypeT) | 31 | return t.ElementTypeT.Equals(ot.ElementTypeT) |
32 | } | 32 | } |
33 | 33 | ||
34 | func (t typeSet) FriendlyName() string { | 34 | func (t typeSet) FriendlyName(mode friendlyTypeNameMode) string { |
35 | return "set of " + t.ElementTypeT.FriendlyName() | 35 | elemName := t.ElementTypeT.friendlyNameMode(mode) |
36 | if mode == friendlyTypeConstraintName { | ||
37 | if t.ElementTypeT == DynamicPseudoType { | ||
38 | elemName = "any single type" | ||
39 | } | ||
40 | } | ||
41 | return "set of " + elemName | ||
36 | } | 42 | } |
37 | 43 | ||
38 | func (t typeSet) ElementType() Type { | 44 | func (t typeSet) ElementType() Type { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/tuple_type.go b/vendor/github.com/zclconf/go-cty/cty/tuple_type.go index b98349e..798cacd 100644 --- a/vendor/github.com/zclconf/go-cty/cty/tuple_type.go +++ b/vendor/github.com/zclconf/go-cty/cty/tuple_type.go | |||
@@ -44,7 +44,7 @@ func (t typeTuple) Equals(other Type) bool { | |||
44 | return false | 44 | return false |
45 | } | 45 | } |
46 | 46 | ||
47 | func (t typeTuple) FriendlyName() string { | 47 | func (t typeTuple) FriendlyName(mode friendlyTypeNameMode) string { |
48 | // There isn't really a friendly way to write a tuple type due to its | 48 | // There isn't really a friendly way to write a tuple type due to its |
49 | // complexity, so we'll just do something English-ish. Callers will | 49 | // complexity, so we'll just do something English-ish. Callers will |
50 | // probably want to make some extra effort to avoid ever printing out | 50 | // probably want to make some extra effort to avoid ever printing out |
diff --git a/vendor/github.com/zclconf/go-cty/cty/type.go b/vendor/github.com/zclconf/go-cty/cty/type.go index ae5f1c8..730cb98 100644 --- a/vendor/github.com/zclconf/go-cty/cty/type.go +++ b/vendor/github.com/zclconf/go-cty/cty/type.go | |||
@@ -19,7 +19,7 @@ type typeImpl interface { | |||
19 | 19 | ||
20 | // FriendlyName returns a human-friendly *English* name for the given | 20 | // FriendlyName returns a human-friendly *English* name for the given |
21 | // type. | 21 | // type. |
22 | FriendlyName() string | 22 | FriendlyName(mode friendlyTypeNameMode) string |
23 | 23 | ||
24 | // GoString implements the GoStringer interface from package fmt. | 24 | // GoString implements the GoStringer interface from package fmt. |
25 | GoString() string | 25 | GoString() string |
@@ -41,7 +41,25 @@ func (t Type) Equals(other Type) bool { | |||
41 | 41 | ||
42 | // FriendlyName returns a human-friendly *English* name for the given type. | 42 | // FriendlyName returns a human-friendly *English* name for the given type. |
43 | func (t Type) FriendlyName() string { | 43 | func (t Type) FriendlyName() string { |
44 | return t.typeImpl.FriendlyName() | 44 | return t.typeImpl.FriendlyName(friendlyTypeName) |
45 | } | ||
46 | |||
47 | // FriendlyNameForConstraint is similar to FriendlyName except that the | ||
48 | // result is specialized for describing type _constraints_ rather than types | ||
49 | // themselves. This is more appropriate when reporting that a particular value | ||
50 | // does not conform to an expected type constraint. | ||
51 | // | ||
52 | // In particular, this function uses the term "any type" to refer to | ||
53 | // cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName. | ||
54 | func (t Type) FriendlyNameForConstraint() string { | ||
55 | return t.typeImpl.FriendlyName(friendlyTypeConstraintName) | ||
56 | } | ||
57 | |||
58 | // friendlyNameMode is an internal combination of the various FriendlyName* | ||
59 | // variants that just directly takes a mode, for easy passthrough for | ||
60 | // recursive name construction. | ||
61 | func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string { | ||
62 | return t.typeImpl.FriendlyName(mode) | ||
45 | } | 63 | } |
46 | 64 | ||
47 | // GoString returns a string approximating how the receiver type would be | 65 | // GoString returns a string approximating how the receiver type would be |
@@ -93,3 +111,10 @@ func (t Type) HasDynamicTypes() bool { | |||
93 | panic("HasDynamicTypes does not support the given type") | 111 | panic("HasDynamicTypes does not support the given type") |
94 | } | 112 | } |
95 | } | 113 | } |
114 | |||
115 | type friendlyTypeNameMode rune | ||
116 | |||
117 | const ( | ||
118 | friendlyTypeName friendlyTypeNameMode = 'N' | ||
119 | friendlyTypeConstraintName friendlyTypeNameMode = 'C' | ||
120 | ) | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/type_conform.go b/vendor/github.com/zclconf/go-cty/cty/type_conform.go index b417dc7..476eeea 100644 --- a/vendor/github.com/zclconf/go-cty/cty/type_conform.go +++ b/vendor/github.com/zclconf/go-cty/cty/type_conform.go | |||
@@ -50,23 +50,20 @@ func testConformance(given Type, want Type, path Path, errs *[]error) { | |||
50 | givenAttrs := given.AttributeTypes() | 50 | givenAttrs := given.AttributeTypes() |
51 | wantAttrs := want.AttributeTypes() | 51 | wantAttrs := want.AttributeTypes() |
52 | 52 | ||
53 | if len(givenAttrs) != len(wantAttrs) { | 53 | for k := range givenAttrs { |
54 | // Something is missing from one of them. | 54 | if _, exists := wantAttrs[k]; !exists { |
55 | for k := range givenAttrs { | 55 | *errs = append( |
56 | if _, exists := wantAttrs[k]; !exists { | 56 | *errs, |
57 | *errs = append( | 57 | errorf(path, "unsupported attribute %q", k), |
58 | *errs, | 58 | ) |
59 | errorf(path, "unsupported attribute %q", k), | ||
60 | ) | ||
61 | } | ||
62 | } | 59 | } |
63 | for k := range wantAttrs { | 60 | } |
64 | if _, exists := givenAttrs[k]; !exists { | 61 | for k := range wantAttrs { |
65 | *errs = append( | 62 | if _, exists := givenAttrs[k]; !exists { |
66 | *errs, | 63 | *errs = append( |
67 | errorf(path, "missing required attribute %q", k), | 64 | *errs, |
68 | ) | 65 | errorf(path, "missing required attribute %q", k), |
69 | } | 66 | ) |
70 | } | 67 | } |
71 | } | 68 | } |
72 | 69 | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/unknown.go b/vendor/github.com/zclconf/go-cty/cty/unknown.go index 9f6fce9..e54179e 100644 --- a/vendor/github.com/zclconf/go-cty/cty/unknown.go +++ b/vendor/github.com/zclconf/go-cty/cty/unknown.go | |||
@@ -54,8 +54,13 @@ func (t pseudoTypeDynamic) Equals(other Type) bool { | |||
54 | return ok | 54 | return ok |
55 | } | 55 | } |
56 | 56 | ||
57 | func (t pseudoTypeDynamic) FriendlyName() string { | 57 | func (t pseudoTypeDynamic) FriendlyName(mode friendlyTypeNameMode) string { |
58 | return "dynamic" | 58 | switch mode { |
59 | case friendlyTypeConstraintName: | ||
60 | return "any type" | ||
61 | default: | ||
62 | return "dynamic" | ||
63 | } | ||
59 | } | 64 | } |
60 | 65 | ||
61 | func (t pseudoTypeDynamic) GoString() string { | 66 | func (t pseudoTypeDynamic) GoString() string { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go b/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go new file mode 100644 index 0000000..ba92647 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go | |||
@@ -0,0 +1,64 @@ | |||
1 | package cty | ||
2 | |||
3 | // UnknownAsNull returns a value of the same type as the given value but | ||
4 | // with any unknown values (including nested values) replaced with null | ||
5 | // values of the same type. | ||
6 | // | ||
7 | // This can be useful if a result is to be serialized in a format that can't | ||
8 | // represent unknowns, such as JSON, as long as the caller does not need to | ||
9 | // retain the unknown value information. | ||
10 | func UnknownAsNull(val Value) Value { | ||
11 | ty := val.Type() | ||
12 | switch { | ||
13 | case val.IsNull(): | ||
14 | return val | ||
15 | case !val.IsKnown(): | ||
16 | return NullVal(ty) | ||
17 | case ty.IsListType() || ty.IsTupleType() || ty.IsSetType(): | ||
18 | length := val.LengthInt() | ||
19 | if length == 0 { | ||
20 | // If there are no elements then we can't have unknowns | ||
21 | return val | ||
22 | } | ||
23 | vals := make([]Value, 0, length) | ||
24 | it := val.ElementIterator() | ||
25 | for it.Next() { | ||
26 | _, v := it.Element() | ||
27 | vals = append(vals, UnknownAsNull(v)) | ||
28 | } | ||
29 | switch { | ||
30 | case ty.IsListType(): | ||
31 | return ListVal(vals) | ||
32 | case ty.IsTupleType(): | ||
33 | return TupleVal(vals) | ||
34 | default: | ||
35 | return SetVal(vals) | ||
36 | } | ||
37 | case ty.IsMapType() || ty.IsObjectType(): | ||
38 | var length int | ||
39 | switch { | ||
40 | case ty.IsMapType(): | ||
41 | length = val.LengthInt() | ||
42 | default: | ||
43 | length = len(val.Type().AttributeTypes()) | ||
44 | } | ||
45 | if length == 0 { | ||
46 | // If there are no elements then we can't have unknowns | ||
47 | return val | ||
48 | } | ||
49 | vals := make(map[string]Value, length) | ||
50 | it := val.ElementIterator() | ||
51 | for it.Next() { | ||
52 | k, v := it.Element() | ||
53 | vals[k.AsString()] = UnknownAsNull(v) | ||
54 | } | ||
55 | switch { | ||
56 | case ty.IsMapType(): | ||
57 | return MapVal(vals) | ||
58 | default: | ||
59 | return ObjectVal(vals) | ||
60 | } | ||
61 | } | ||
62 | |||
63 | return val | ||
64 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/value_init.go b/vendor/github.com/zclconf/go-cty/cty/value_init.go index 495a83e..3deeba3 100644 --- a/vendor/github.com/zclconf/go-cty/cty/value_init.go +++ b/vendor/github.com/zclconf/go-cty/cty/value_init.go | |||
@@ -30,6 +30,44 @@ func NumberVal(v *big.Float) Value { | |||
30 | } | 30 | } |
31 | } | 31 | } |
32 | 32 | ||
33 | // ParseNumberVal returns a Value of type number produced by parsing the given | ||
34 | // string as a decimal real number. To ensure that two identical strings will | ||
35 | // always produce an equal number, always use this function to derive a number | ||
36 | // from a string; it will ensure that the precision and rounding mode for the | ||
37 | // internal big decimal is configured in a consistent way. | ||
38 | // | ||
39 | // If the given string cannot be parsed as a number, the returned error has | ||
40 | // the message "a number is required", making it suitable to return to an | ||
41 | // end-user to signal a type conversion error. | ||
42 | // | ||
43 | // If the given string contains a number that becomes a recurring fraction | ||
44 | // when expressed in binary then it will be truncated to have a 512-bit | ||
45 | // mantissa. Note that this is a higher precision than that of a float64, | ||
46 | // so coverting the same decimal number first to float64 and then calling | ||
47 | // NumberFloatVal will not produce an equal result; the conversion first | ||
48 | // to float64 will round the mantissa to fewer than 512 bits. | ||
49 | func ParseNumberVal(s string) (Value, error) { | ||
50 | // Base 10, precision 512, and rounding to nearest even is the standard | ||
51 | // way to handle numbers arriving as strings. | ||
52 | f, _, err := big.ParseFloat(s, 10, 512, big.ToNearestEven) | ||
53 | if err != nil { | ||
54 | return NilVal, fmt.Errorf("a number is required") | ||
55 | } | ||
56 | return NumberVal(f), nil | ||
57 | } | ||
58 | |||
59 | // MustParseNumberVal is like ParseNumberVal but it will panic in case of any | ||
60 | // error. It can be used during initialization or any other situation where | ||
61 | // the given string is a constant or otherwise known to be correct by the | ||
62 | // caller. | ||
63 | func MustParseNumberVal(s string) Value { | ||
64 | ret, err := ParseNumberVal(s) | ||
65 | if err != nil { | ||
66 | panic(err) | ||
67 | } | ||
68 | return ret | ||
69 | } | ||
70 | |||
33 | // NumberIntVal returns a Value of type Number whose internal value is equal | 71 | // NumberIntVal returns a Value of type Number whose internal value is equal |
34 | // to the given integer. | 72 | // to the given integer. |
35 | func NumberIntVal(v int64) Value { | 73 | func NumberIntVal(v int64) Value { |
diff --git a/vendor/github.com/zclconf/go-cty/cty/value_ops.go b/vendor/github.com/zclconf/go-cty/cty/value_ops.go index 967aa76..afd621c 100644 --- a/vendor/github.com/zclconf/go-cty/cty/value_ops.go +++ b/vendor/github.com/zclconf/go-cty/cty/value_ops.go | |||
@@ -3,27 +3,27 @@ package cty | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "math/big" | 5 | "math/big" |
6 | |||
7 | "reflect" | 6 | "reflect" |
8 | 7 | ||
9 | "github.com/zclconf/go-cty/cty/set" | 8 | "github.com/zclconf/go-cty/cty/set" |
10 | ) | 9 | ) |
11 | 10 | ||
11 | // GoString is an implementation of fmt.GoStringer that produces concise | ||
12 | // source-like representations of values suitable for use in debug messages. | ||
12 | func (val Value) GoString() string { | 13 | func (val Value) GoString() string { |
13 | if val == NilVal { | 14 | if val == NilVal { |
14 | return "cty.NilVal" | 15 | return "cty.NilVal" |
15 | } | 16 | } |
16 | 17 | ||
17 | if val.ty == DynamicPseudoType { | 18 | if val.IsNull() { |
19 | return fmt.Sprintf("cty.NullVal(%#v)", val.ty) | ||
20 | } | ||
21 | if val == DynamicVal { // is unknown, so must be before the IsKnown check below | ||
18 | return "cty.DynamicVal" | 22 | return "cty.DynamicVal" |
19 | } | 23 | } |
20 | |||
21 | if !val.IsKnown() { | 24 | if !val.IsKnown() { |
22 | return fmt.Sprintf("cty.UnknownVal(%#v)", val.ty) | 25 | return fmt.Sprintf("cty.UnknownVal(%#v)", val.ty) |
23 | } | 26 | } |
24 | if val.IsNull() { | ||
25 | return fmt.Sprintf("cty.NullVal(%#v)", val.ty) | ||
26 | } | ||
27 | 27 | ||
28 | // By the time we reach here we've dealt with all of the exceptions around | 28 | // By the time we reach here we've dealt with all of the exceptions around |
29 | // unknowns and nulls, so we're guaranteed that the values are the | 29 | // unknowns and nulls, so we're guaranteed that the values are the |
@@ -33,9 +33,8 @@ func (val Value) GoString() string { | |||
33 | case Bool: | 33 | case Bool: |
34 | if val.v.(bool) { | 34 | if val.v.(bool) { |
35 | return "cty.True" | 35 | return "cty.True" |
36 | } else { | ||
37 | return "cty.False" | ||
38 | } | 36 | } |
37 | return "cty.False" | ||
39 | case Number: | 38 | case Number: |
40 | fv := val.v.(*big.Float) | 39 | fv := val.v.(*big.Float) |
41 | // We'll try to use NumberIntVal or NumberFloatVal if we can, since | 40 | // We'll try to use NumberIntVal or NumberFloatVal if we can, since |
@@ -46,19 +45,42 @@ func (val Value) GoString() string { | |||
46 | if rfv, accuracy := fv.Float64(); accuracy == big.Exact { | 45 | if rfv, accuracy := fv.Float64(); accuracy == big.Exact { |
47 | return fmt.Sprintf("cty.NumberFloatVal(%#v)", rfv) | 46 | return fmt.Sprintf("cty.NumberFloatVal(%#v)", rfv) |
48 | } | 47 | } |
49 | return fmt.Sprintf("cty.NumberVal(new(big.Float).Parse(\"%#v\", 10))", fv) | 48 | return fmt.Sprintf("cty.MustParseNumberVal(%q)", fv.Text('f', -1)) |
50 | case String: | 49 | case String: |
51 | return fmt.Sprintf("cty.StringVal(%#v)", val.v) | 50 | return fmt.Sprintf("cty.StringVal(%#v)", val.v) |
52 | } | 51 | } |
53 | 52 | ||
54 | switch { | 53 | switch { |
55 | case val.ty.IsSetType(): | 54 | case val.ty.IsSetType(): |
56 | vals := val.v.(set.Set).Values() | 55 | vals := val.AsValueSlice() |
57 | if vals == nil || len(vals) == 0 { | 56 | if len(vals) == 0 { |
58 | return fmt.Sprintf("cty.SetValEmpty()") | 57 | return fmt.Sprintf("cty.SetValEmpty(%#v)", val.ty.ElementType()) |
59 | } else { | ||
60 | return fmt.Sprintf("cty.SetVal(%#v)", vals) | ||
61 | } | 58 | } |
59 | return fmt.Sprintf("cty.SetVal(%#v)", vals) | ||
60 | case val.ty.IsListType(): | ||
61 | vals := val.AsValueSlice() | ||
62 | if len(vals) == 0 { | ||
63 | return fmt.Sprintf("cty.ListValEmpty(%#v)", val.ty.ElementType()) | ||
64 | } | ||
65 | return fmt.Sprintf("cty.ListVal(%#v)", vals) | ||
66 | case val.ty.IsMapType(): | ||
67 | vals := val.AsValueMap() | ||
68 | if len(vals) == 0 { | ||
69 | return fmt.Sprintf("cty.MapValEmpty(%#v)", val.ty.ElementType()) | ||
70 | } | ||
71 | return fmt.Sprintf("cty.MapVal(%#v)", vals) | ||
72 | case val.ty.IsTupleType(): | ||
73 | if val.ty.Equals(EmptyTuple) { | ||
74 | return "cty.EmptyTupleVal" | ||
75 | } | ||
76 | vals := val.AsValueSlice() | ||
77 | return fmt.Sprintf("cty.TupleVal(%#v)", vals) | ||
78 | case val.ty.IsObjectType(): | ||
79 | if val.ty.Equals(EmptyObject) { | ||
80 | return "cty.EmptyObjectVal" | ||
81 | } | ||
82 | vals := val.AsValueMap() | ||
83 | return fmt.Sprintf("cty.ObjectVal(%#v)", vals) | ||
62 | case val.ty.IsCapsuleType(): | 84 | case val.ty.IsCapsuleType(): |
63 | return fmt.Sprintf("cty.CapsuleVal(%#v, %#v)", val.ty, val.v) | 85 | return fmt.Sprintf("cty.CapsuleVal(%#v, %#v)", val.ty, val.v) |
64 | } | 86 | } |
@@ -71,26 +93,67 @@ func (val Value) GoString() string { | |||
71 | // Equals returns True if the receiver and the given other value have the | 93 | // Equals returns True if the receiver and the given other value have the |
72 | // same type and are exactly equal in value. | 94 | // same type and are exactly equal in value. |
73 | // | 95 | // |
74 | // The usual short-circuit rules apply, so the result can be unknown or typed | 96 | // As a special case, two null values are always equal regardless of type. |
75 | // as dynamic if either of the given values are. Use RawEquals to compare | 97 | // |
76 | // if two values are equal *ignoring* the short-circuit rules. | 98 | // The usual short-circuit rules apply, so the result will be unknown if |
99 | // either of the given values are. | ||
100 | // | ||
101 | // Use RawEquals to compare if two values are equal *ignoring* the | ||
102 | // short-circuit rules and the exception for null values. | ||
77 | func (val Value) Equals(other Value) Value { | 103 | func (val Value) Equals(other Value) Value { |
78 | if val.ty.HasDynamicTypes() || other.ty.HasDynamicTypes() { | 104 | // Start by handling Unknown values before considering types. |
105 | // This needs to be done since Null values are always equal regardless of | ||
106 | // type. | ||
107 | switch { | ||
108 | case !val.IsKnown() && !other.IsKnown(): | ||
109 | // both unknown | ||
79 | return UnknownVal(Bool) | 110 | return UnknownVal(Bool) |
111 | case val.IsKnown() && !other.IsKnown(): | ||
112 | switch { | ||
113 | case val.IsNull(), other.ty.HasDynamicTypes(): | ||
114 | // If known is Null, we need to wait for the unkown value since | ||
115 | // nulls of any type are equal. | ||
116 | // An unkown with a dynamic type compares as unknown, which we need | ||
117 | // to check before the type comparison below. | ||
118 | return UnknownVal(Bool) | ||
119 | case !val.ty.Equals(other.ty): | ||
120 | // There is no null comparison or dynamic types, so unequal types | ||
121 | // will never be equal. | ||
122 | return False | ||
123 | default: | ||
124 | return UnknownVal(Bool) | ||
125 | } | ||
126 | case other.IsKnown() && !val.IsKnown(): | ||
127 | switch { | ||
128 | case other.IsNull(), val.ty.HasDynamicTypes(): | ||
129 | // If known is Null, we need to wait for the unkown value since | ||
130 | // nulls of any type are equal. | ||
131 | // An unkown with a dynamic type compares as unknown, which we need | ||
132 | // to check before the type comparison below. | ||
133 | return UnknownVal(Bool) | ||
134 | case !other.ty.Equals(val.ty): | ||
135 | // There's no null comparison or dynamic types, so unequal types | ||
136 | // will never be equal. | ||
137 | return False | ||
138 | default: | ||
139 | return UnknownVal(Bool) | ||
140 | } | ||
80 | } | 141 | } |
81 | 142 | ||
82 | if !val.ty.Equals(other.ty) { | 143 | switch { |
144 | case val.IsNull() && other.IsNull(): | ||
145 | // Nulls are always equal, regardless of type | ||
146 | return BoolVal(true) | ||
147 | case val.IsNull() || other.IsNull(): | ||
148 | // If only one is null then the result must be false | ||
83 | return BoolVal(false) | 149 | return BoolVal(false) |
84 | } | 150 | } |
85 | 151 | ||
86 | if !(val.IsKnown() && other.IsKnown()) { | 152 | if val.ty.HasDynamicTypes() || other.ty.HasDynamicTypes() { |
87 | return UnknownVal(Bool) | 153 | return UnknownVal(Bool) |
88 | } | 154 | } |
89 | 155 | ||
90 | if val.IsNull() || other.IsNull() { | 156 | if !val.ty.Equals(other.ty) { |
91 | if val.IsNull() && other.IsNull() { | ||
92 | return BoolVal(true) | ||
93 | } | ||
94 | return BoolVal(false) | 157 | return BoolVal(false) |
95 | } | 158 | } |
96 | 159 | ||
@@ -758,7 +821,7 @@ func (val Value) HasElement(elem Value) Value { | |||
758 | if val.IsNull() { | 821 | if val.IsNull() { |
759 | panic("can't call HasElement on a nil value") | 822 | panic("can't call HasElement on a nil value") |
760 | } | 823 | } |
761 | if ty.ElementType() != elem.Type() { | 824 | if !ty.ElementType().Equals(elem.Type()) { |
762 | return False | 825 | return False |
763 | } | 826 | } |
764 | 827 | ||
@@ -800,6 +863,10 @@ func (val Value) LengthInt() int { | |||
800 | // For tuples, we can return the length even if the value is not known. | 863 | // For tuples, we can return the length even if the value is not known. |
801 | return val.Type().Length() | 864 | return val.Type().Length() |
802 | } | 865 | } |
866 | if val.Type().IsObjectType() { | ||
867 | // For objects, the length is the number of attributes associated with the type. | ||
868 | return len(val.Type().AttributeTypes()) | ||
869 | } | ||
803 | if !val.IsKnown() { | 870 | if !val.IsKnown() { |
804 | panic("value is not known") | 871 | panic("value is not known") |
805 | } | 872 | } |