130 lines
3.3 KiB
Go
130 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/zclconf/go-cty/cty"
|
|
"github.com/zclconf/go-cty/cty/function"
|
|
)
|
|
|
|
var typeType = cty.Capsule("type", reflect.TypeOf(cty.NilType))
|
|
|
|
var typeEvalCtx = &hcl.EvalContext{
|
|
Variables: map[string]cty.Value{
|
|
"string": wrapTypeType(cty.String),
|
|
"bool": wrapTypeType(cty.Bool),
|
|
"number": wrapTypeType(cty.Number),
|
|
"any": wrapTypeType(cty.DynamicPseudoType),
|
|
},
|
|
Functions: map[string]function.Function{
|
|
"list": function.New(&function.Spec{
|
|
Params: []function.Parameter{
|
|
{
|
|
Name: "element_type",
|
|
Type: typeType,
|
|
},
|
|
},
|
|
Type: function.StaticReturnType(typeType),
|
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
|
ety := unwrapTypeType(args[0])
|
|
ty := cty.List(ety)
|
|
return wrapTypeType(ty), nil
|
|
},
|
|
}),
|
|
"set": function.New(&function.Spec{
|
|
Params: []function.Parameter{
|
|
{
|
|
Name: "element_type",
|
|
Type: typeType,
|
|
},
|
|
},
|
|
Type: function.StaticReturnType(typeType),
|
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
|
ety := unwrapTypeType(args[0])
|
|
ty := cty.Set(ety)
|
|
return wrapTypeType(ty), nil
|
|
},
|
|
}),
|
|
"map": function.New(&function.Spec{
|
|
Params: []function.Parameter{
|
|
{
|
|
Name: "element_type",
|
|
Type: typeType,
|
|
},
|
|
},
|
|
Type: function.StaticReturnType(typeType),
|
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
|
ety := unwrapTypeType(args[0])
|
|
ty := cty.Map(ety)
|
|
return wrapTypeType(ty), nil
|
|
},
|
|
}),
|
|
"tuple": function.New(&function.Spec{
|
|
Params: []function.Parameter{
|
|
{
|
|
Name: "element_types",
|
|
Type: cty.List(typeType),
|
|
},
|
|
},
|
|
Type: function.StaticReturnType(typeType),
|
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
|
etysVal := args[0]
|
|
etys := make([]cty.Type, 0, etysVal.LengthInt())
|
|
for it := etysVal.ElementIterator(); it.Next(); {
|
|
_, wrapEty := it.Element()
|
|
etys = append(etys, unwrapTypeType(wrapEty))
|
|
}
|
|
ty := cty.Tuple(etys)
|
|
return wrapTypeType(ty), nil
|
|
},
|
|
}),
|
|
"object": function.New(&function.Spec{
|
|
Params: []function.Parameter{
|
|
{
|
|
Name: "attribute_types",
|
|
Type: cty.Map(typeType),
|
|
},
|
|
},
|
|
Type: function.StaticReturnType(typeType),
|
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
|
atysVal := args[0]
|
|
atys := make(map[string]cty.Type)
|
|
for it := atysVal.ElementIterator(); it.Next(); {
|
|
nameVal, wrapAty := it.Element()
|
|
name := nameVal.AsString()
|
|
atys[name] = unwrapTypeType(wrapAty)
|
|
}
|
|
ty := cty.Object(atys)
|
|
return wrapTypeType(ty), nil
|
|
},
|
|
}),
|
|
},
|
|
}
|
|
|
|
func evalTypeExpr(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
|
|
result, diags := expr.Value(typeEvalCtx)
|
|
if result.IsNull() {
|
|
return cty.DynamicPseudoType, diags
|
|
}
|
|
if !result.Type().Equals(typeType) {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid type expression",
|
|
Detail: fmt.Sprintf("A type is required, not %s.", result.Type().FriendlyName()),
|
|
})
|
|
return cty.DynamicPseudoType, diags
|
|
}
|
|
|
|
return unwrapTypeType(result), diags
|
|
}
|
|
|
|
func wrapTypeType(ty cty.Type) cty.Value {
|
|
return cty.CapsuleVal(typeType, &ty)
|
|
}
|
|
|
|
func unwrapTypeType(val cty.Value) cty.Type {
|
|
return *(val.EncapsulatedValue().(*cty.Type))
|
|
}
|