2014-08-02 22:44:45 +00:00
|
|
|
package hcl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
2014-08-03 20:09:08 +00:00
|
|
|
"strconv"
|
2014-08-02 22:44:45 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/hcl/ast"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Decode reads the given input and decodes it into the structure
|
|
|
|
// given by `out`.
|
|
|
|
func Decode(out interface{}, in string) error {
|
|
|
|
obj, err := Parse(in)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return DecodeAST(out, obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeAST is a lower-level version of Decode. It decodes a
|
|
|
|
// raw AST into the given output.
|
2014-08-03 20:19:20 +00:00
|
|
|
func DecodeAST(out interface{}, n ast.Node) error {
|
2014-08-03 05:37:58 +00:00
|
|
|
var d decoder
|
2014-08-03 20:19:20 +00:00
|
|
|
return d.decode("root", n, reflect.ValueOf(out).Elem())
|
2014-08-02 22:44:45 +00:00
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
type decoder struct{}
|
|
|
|
|
|
|
|
func (d *decoder) decode(name string, n ast.Node, result reflect.Value) error {
|
2014-08-03 05:05:21 +00:00
|
|
|
k := result
|
|
|
|
|
|
|
|
// If we have an interface with a valid value, we use that
|
|
|
|
// for the check.
|
|
|
|
if result.Kind() == reflect.Interface {
|
|
|
|
elem := result.Elem()
|
|
|
|
if elem.IsValid() {
|
|
|
|
k = elem
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-03 20:19:20 +00:00
|
|
|
// If we have a pointer, unpointer it
|
|
|
|
switch rn := n.(type) {
|
|
|
|
case *ast.ObjectNode:
|
|
|
|
n = *rn
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:05:21 +00:00
|
|
|
switch k.Kind() {
|
2014-08-02 23:07:54 +00:00
|
|
|
case reflect.Int:
|
2014-08-03 05:37:58 +00:00
|
|
|
return d.decodeInt(name, n, result)
|
2014-08-02 22:44:45 +00:00
|
|
|
case reflect.Interface:
|
|
|
|
// When we see an interface, we make our own thing
|
2014-08-03 05:37:58 +00:00
|
|
|
return d.decodeInterface(name, n, result)
|
2014-08-02 22:44:45 +00:00
|
|
|
case reflect.Map:
|
2014-08-03 05:37:58 +00:00
|
|
|
return d.decodeMap(name, n, result)
|
2014-08-02 23:07:54 +00:00
|
|
|
case reflect.Slice:
|
2014-08-03 05:37:58 +00:00
|
|
|
return d.decodeSlice(name, n, result)
|
2014-08-02 22:44:45 +00:00
|
|
|
case reflect.String:
|
2014-08-03 05:37:58 +00:00
|
|
|
return d.decodeString(name, n, result)
|
2014-08-02 22:44:45 +00:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("%s: unknown kind: %s", name, result.Kind())
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
func (d *decoder) decodeInt(name string, raw ast.Node, result reflect.Value) error {
|
2014-08-02 23:07:54 +00:00
|
|
|
n, ok := raw.(ast.LiteralNode)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("%s: not a literal type", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch n.Type {
|
|
|
|
case ast.ValueTypeInt:
|
2014-08-03 05:12:51 +00:00
|
|
|
result.Set(reflect.ValueOf(int64(n.Value.(int))))
|
2014-08-02 23:07:54 +00:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("%s: unknown type %s", name, n.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
func (d *decoder) decodeInterface(name string, raw ast.Node, result reflect.Value) error {
|
2014-08-02 22:44:45 +00:00
|
|
|
var set reflect.Value
|
2014-08-02 23:07:54 +00:00
|
|
|
redecode := true
|
2014-08-02 22:44:45 +00:00
|
|
|
|
|
|
|
switch n := raw.(type) {
|
|
|
|
case ast.ObjectNode:
|
2014-08-03 04:29:59 +00:00
|
|
|
var temp map[string]interface{}
|
|
|
|
tempVal := reflect.ValueOf(temp)
|
|
|
|
result := reflect.MakeMap(
|
|
|
|
reflect.MapOf(
|
|
|
|
reflect.TypeOf(""),
|
|
|
|
tempVal.Type().Elem()))
|
|
|
|
|
|
|
|
set = result
|
2014-08-02 23:07:54 +00:00
|
|
|
case ast.ListNode:
|
2014-08-03 05:12:51 +00:00
|
|
|
/*
|
|
|
|
var temp []interface{}
|
|
|
|
tempVal := reflect.ValueOf(temp)
|
|
|
|
result := reflect.MakeSlice(
|
|
|
|
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
|
|
|
|
set = result
|
|
|
|
*/
|
2014-08-02 23:07:54 +00:00
|
|
|
redecode = false
|
|
|
|
result := make([]interface{}, 0, len(n.Elem))
|
|
|
|
|
|
|
|
for _, elem := range n.Elem {
|
|
|
|
raw := new(interface{})
|
2014-08-03 05:37:58 +00:00
|
|
|
err := d.decode(
|
2014-08-02 23:07:54 +00:00
|
|
|
name, elem, reflect.Indirect(reflect.ValueOf(raw)))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
result = append(result, *raw)
|
|
|
|
}
|
|
|
|
|
2014-08-02 22:44:45 +00:00
|
|
|
set = reflect.ValueOf(result)
|
|
|
|
case ast.LiteralNode:
|
|
|
|
switch n.Type {
|
2014-08-02 23:07:54 +00:00
|
|
|
case ast.ValueTypeInt:
|
|
|
|
var result int
|
|
|
|
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
2014-08-02 22:44:45 +00:00
|
|
|
case ast.ValueTypeString:
|
|
|
|
set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
|
|
|
|
default:
|
|
|
|
return fmt.Errorf(
|
|
|
|
"%s: unknown literal type: %s",
|
|
|
|
name, n.Type)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return fmt.Errorf(
|
|
|
|
"%s: cannot decode into interface: %T",
|
|
|
|
name, raw)
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:12:51 +00:00
|
|
|
// Set the result to what its supposed to be, then reset
|
|
|
|
// result so we don't reflect into this method anymore.
|
|
|
|
result.Set(set)
|
|
|
|
|
2014-08-02 23:07:54 +00:00
|
|
|
if redecode {
|
|
|
|
// Revisit the node so that we can use the newly instantiated
|
|
|
|
// thing and populate it.
|
2014-08-03 05:37:58 +00:00
|
|
|
if err := d.decode(name, raw, result); err != nil {
|
2014-08-02 23:07:54 +00:00
|
|
|
return err
|
|
|
|
}
|
2014-08-02 22:44:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
func (d *decoder) decodeMap(name string, raw ast.Node, result reflect.Value) error {
|
2014-08-03 20:09:08 +00:00
|
|
|
// If we have a list, then we decode each element into a map
|
|
|
|
if list, ok := raw.(ast.ListNode); ok {
|
|
|
|
for i, elem := range list.Elem {
|
|
|
|
fieldName := fmt.Sprintf("%s.%d", name, i)
|
|
|
|
err := d.decode(fieldName, elem, result)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-02 22:44:45 +00:00
|
|
|
obj, ok := raw.(ast.ObjectNode)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("%s: not an object type", name)
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:12:51 +00:00
|
|
|
// If we have an interface, then we can address the interface,
|
|
|
|
// but not the slice itself, so get the element but set the interface
|
|
|
|
set := result
|
|
|
|
if result.Kind() == reflect.Interface {
|
|
|
|
result = result.Elem()
|
|
|
|
}
|
|
|
|
|
2014-08-02 22:44:45 +00:00
|
|
|
resultType := result.Type()
|
|
|
|
resultElemType := resultType.Elem()
|
|
|
|
resultKeyType := resultType.Key()
|
|
|
|
if resultKeyType.Kind() != reflect.String {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"%s: map must have string keys", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a map if it is nil
|
|
|
|
resultMap := result
|
|
|
|
if result.IsNil() {
|
|
|
|
resultMap = reflect.MakeMap(
|
|
|
|
reflect.MapOf(resultKeyType, resultElemType))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go through each element and decode it.
|
|
|
|
for _, elem := range obj.Elem {
|
|
|
|
n := elem.(ast.AssignmentNode)
|
2014-08-03 04:29:59 +00:00
|
|
|
objValue := n.Value
|
|
|
|
|
|
|
|
// If we have an object node, expand to a list of objects
|
|
|
|
if _, ok := objValue.(ast.ObjectNode); ok {
|
|
|
|
objValue = ast.ListNode{
|
|
|
|
Elem: []ast.Node{objValue},
|
|
|
|
}
|
|
|
|
}
|
2014-08-02 22:44:45 +00:00
|
|
|
|
|
|
|
// Make the field name
|
2014-08-02 23:07:54 +00:00
|
|
|
fieldName := fmt.Sprintf("%s.%s", name, n.Key())
|
2014-08-02 22:44:45 +00:00
|
|
|
|
|
|
|
// Get the key/value as reflection values
|
|
|
|
key := reflect.ValueOf(n.Key())
|
|
|
|
val := reflect.Indirect(reflect.New(resultElemType))
|
|
|
|
|
|
|
|
// If we have a pre-existing value in the map, use that
|
|
|
|
oldVal := resultMap.MapIndex(key)
|
|
|
|
if oldVal.IsValid() {
|
|
|
|
val.Set(oldVal)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode!
|
2014-08-03 05:37:58 +00:00
|
|
|
if err := d.decode(fieldName, objValue, val); err != nil {
|
2014-08-02 22:44:45 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the value on the map
|
|
|
|
resultMap.SetMapIndex(key, val)
|
|
|
|
}
|
|
|
|
|
2014-08-03 04:29:59 +00:00
|
|
|
// Set the final map if we can
|
2014-08-03 05:12:51 +00:00
|
|
|
set.Set(resultMap)
|
2014-08-02 22:44:45 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
func (d *decoder) decodeSlice(name string, raw ast.Node, result reflect.Value) error {
|
2014-08-03 05:05:21 +00:00
|
|
|
n, ok := raw.(ast.ListNode)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("%s: not a list type", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have an interface, then we can address the interface,
|
|
|
|
// but not the slice itself, so get the element but set the interface
|
|
|
|
set := result
|
|
|
|
if result.Kind() == reflect.Interface {
|
|
|
|
result = result.Elem()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the slice if it isn't nil
|
2014-08-02 23:07:54 +00:00
|
|
|
resultType := result.Type()
|
|
|
|
resultElemType := resultType.Elem()
|
2014-08-03 05:05:21 +00:00
|
|
|
if result.IsNil() {
|
|
|
|
resultSliceType := reflect.SliceOf(resultElemType)
|
|
|
|
result = reflect.MakeSlice(
|
|
|
|
resultSliceType, 0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, elem := range n.Elem {
|
|
|
|
fieldName := fmt.Sprintf("%s[%d]", name, i)
|
|
|
|
|
|
|
|
// Decode
|
|
|
|
val := reflect.Indirect(reflect.New(resultElemType))
|
2014-08-03 05:37:58 +00:00
|
|
|
if err := d.decode(fieldName, elem, val); err != nil {
|
2014-08-03 05:05:21 +00:00
|
|
|
return err
|
|
|
|
}
|
2014-08-02 23:07:54 +00:00
|
|
|
|
2014-08-03 05:05:21 +00:00
|
|
|
// Append it onto the slice
|
|
|
|
result = reflect.Append(result, val)
|
|
|
|
}
|
2014-08-02 23:07:54 +00:00
|
|
|
|
2014-08-03 05:05:21 +00:00
|
|
|
set.Set(result)
|
2014-08-02 23:07:54 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-03 05:37:58 +00:00
|
|
|
func (d *decoder) decodeString(name string, raw ast.Node, result reflect.Value) error {
|
2014-08-02 22:44:45 +00:00
|
|
|
n, ok := raw.(ast.LiteralNode)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("%s: not a literal type", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch n.Type {
|
2014-08-03 20:09:08 +00:00
|
|
|
case ast.ValueTypeInt:
|
|
|
|
result.Set(reflect.ValueOf(
|
|
|
|
strconv.FormatInt(int64(n.Value.(int)), 10)))
|
2014-08-02 22:44:45 +00:00
|
|
|
case ast.ValueTypeString:
|
2014-08-03 05:12:51 +00:00
|
|
|
result.Set(reflect.ValueOf(n.Value.(string)))
|
2014-08-02 22:44:45 +00:00
|
|
|
default:
|
2014-08-03 20:09:08 +00:00
|
|
|
return fmt.Errorf("%s: unknown type to string: %s", name, n.Type)
|
2014-08-02 22:44:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|