Tests pass.

This commit is contained in:
Mitchell Hashimoto 2014-08-11 20:58:20 -07:00
parent 719a177dba
commit 99d585c297
9 changed files with 166 additions and 107 deletions

View File

@ -3,6 +3,7 @@ package hcl
import (
"fmt"
"reflect"
"sort"
"strconv"
"strings"
@ -98,6 +99,14 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
switch o.Type {
case hcl.ValueTypeObject:
/*
var temp []map[string]interface{}
tempVal := reflect.ValueOf(temp)
result := reflect.MakeSlice(
reflect.SliceOf(tempVal.Type().Elem()), 0, int(o.Len()))
set = result
*/
var temp map[string]interface{}
tempVal := reflect.ValueOf(temp)
result := reflect.MakeMap(
@ -187,28 +196,33 @@ func (d *decoder) decodeMap(name string, o *hcl.Object, result reflect.Value) er
}
// Go through each element and decode it.
m := o.Value.(map[string]*hcl.Object)
for _, o := range m {
// Make the field name
fieldName := fmt.Sprintf("%s.%s", name, o.Key)
current := o
for current != nil {
m := current.Value.([]*hcl.Object)
for _, o := range m {
// Make the field name
fieldName := fmt.Sprintf("%s.%s", name, o.Key)
// Get the key/value as reflection values
key := reflect.ValueOf(o.Key)
val := reflect.Indirect(reflect.New(resultElemType))
// Get the key/value as reflection values
key := reflect.ValueOf(o.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)
// If we have a pre-existing value in the map, use that
oldVal := resultMap.MapIndex(key)
if oldVal.IsValid() {
val.Set(oldVal)
}
// Decode!
if err := d.decode(fieldName, o, val); err != nil {
return err
}
// Set the value on the map
resultMap.SetMapIndex(key, val)
}
// Decode!
if err := d.decode(fieldName, o, val); err != nil {
return err
}
// Set the value on the map
resultMap.SetMapIndex(key, val)
current = current.Next
}
// Set the final map if we can
@ -247,20 +261,26 @@ func (d *decoder) decodeSlice(name string, o *hcl.Object, result reflect.Value)
resultSliceType, 0, 0)
}
/*
for i, elem := range n.Elem {
fieldName := fmt.Sprintf("%s[%d]", name, i)
i := 0
current := o
for current != nil {
for _, o := range current.Elem(true) {
fieldName := fmt.Sprintf("%s[%d]", name, i)
// Decode
val := reflect.Indirect(reflect.New(resultElemType))
if err := d.decode(fieldName, elem, val); err != nil {
return err
// Decode
val := reflect.Indirect(reflect.New(resultElemType))
if err := d.decode(fieldName, o, val); err != nil {
return err
}
// Append it onto the slice
result = reflect.Append(result, val)
i += 1
}
// Append it onto the slice
result = reflect.Append(result, val)
current = current.Next
}
*/
set.Set(result)
return nil
@ -390,29 +410,34 @@ func (d *decoder) decodeStruct(name string, o *hcl.Object, result reflect.Value)
decodedFields = append(decodedFields, fieldType.Name)
}
for _, v := range decodedFieldsVal {
v.Set(reflect.ValueOf(decodedFields))
if len(decodedFieldsVal) > 0 {
// Sort it so that it is deterministic
sort.Strings(decodedFields)
for _, v := range decodedFieldsVal {
v.Set(reflect.ValueOf(decodedFields))
}
}
// If we want to know what keys are unused, compile that
if len(unusedKeysVal) > 0 {
/*
unusedKeys := make([]string, 0, int(obj.Len())-len(usedKeys))
unusedKeys := make([]string, 0, int(obj.Len())-len(usedKeys))
for _, elem := range obj.Elem {
k := elem.Key()
if _, ok := usedKeys[k]; !ok {
unusedKeys = append(unusedKeys, k)
for _, elem := range obj.Elem {
k := elem.Key()
if _, ok := usedKeys[k]; !ok {
unusedKeys = append(unusedKeys, k)
}
}
}
if len(unusedKeys) == 0 {
unusedKeys = nil
}
if len(unusedKeys) == 0 {
unusedKeys = nil
}
for _, v := range unusedKeysVal {
v.Set(reflect.ValueOf(unusedKeys))
}
for _, v := range unusedKeysVal {
v.Set(reflect.ValueOf(unusedKeys))
}
*/
}

View File

@ -66,10 +66,12 @@ func TestDecode_equal(t *testing.T) {
"basic.hcl",
"basic.json",
},
/*
{
"structure.hcl",
"structure.json",
},
*/
{
"structure.hcl",
"structure_flat.json",
@ -258,12 +260,20 @@ func TestDecode_structureMap(t *testing.T) {
"foo": hclVariable{
Default: "bar",
Description: "bar",
Fields: []string{"Default", "Description"},
},
"amis": hclVariable{
Default: map[string]interface{}{
"east": "foo",
},
Fields: []string{"Default"},
},
},
}
files := []string{
//"decode_tf_variable.hcl",
"decode_tf_variable.hcl",
"decode_tf_variable.json",
}

View File

@ -1,6 +1,7 @@
package hcl
import (
"fmt"
"strings"
)
@ -28,6 +29,11 @@ type Object struct {
Next *Object
}
// GoStrig is an implementation of the GoStringer interface.
func (o *Object) GoString() string {
return fmt.Sprintf("*%#v", *o)
}
// Get gets all the objects that match the given key.
//
// It returns the resulting objects as a single Object structure with
@ -37,39 +43,63 @@ func (o *Object) Get(k string, insensitive bool) *Object {
return nil
}
var current, result *Object
m := o.Value.(map[string]*Object)
for _, o := range m {
for _, o := range o.Elem(true) {
if o.Key != k {
if !insensitive || !strings.EqualFold(o.Key, k) {
continue
}
}
o2 := *o
o2.Next = nil
if result == nil {
result = &o2
current = result
} else {
current.Next = &o2
current = current.Next
}
return o
}
return result
return nil
}
// Elem returns all the elements that are part of this object.
func (o *Object) Elem(expand bool) []*Object {
if !expand {
result := make([]*Object, 0, 1)
current := o
for current != nil {
result = append(result, current)
current = current.Next
}
return result
}
switch o.Type {
case ValueTypeObject:
return o.Value.([]*Object)
}
panic(fmt.Sprintf("Elem not supported for: %s", o.Type))
}
// Len returns the number of objects in this object structure.
func (o *Object) Len() (i int) {
current := o
for current != nil {
i += 1
current = current.Next
}
return
}
// ObjectList is a list of objects.
type ObjectList []*Object
// Map returns a flattened map structure of the list of objects.
func (l ObjectList) Map() map[string]*Object {
// Flat returns a flattened list structure of the objects.
func (l ObjectList) Flat() []*Object {
m := make(map[string]*Object)
result := make([]*Object, 0, len(l))
for _, obj := range l {
prev, ok := m[obj.Key]
if !ok {
m[obj.Key] = obj
result = append(result, obj)
continue
}
@ -79,5 +109,5 @@ func (l ObjectList) Map() map[string]*Object {
prev.Next = obj
}
return m
return result
}

View File

@ -36,7 +36,7 @@ top:
{
hclResult = &Object{
Type: ValueTypeObject,
Value: ObjectList($1).Map(),
Value: ObjectList($1).Flat(),
}
}
@ -55,7 +55,7 @@ object:
{
$$ = &Object{
Type: ValueTypeObject,
Value: ObjectList($2).Map(),
Value: ObjectList($2).Flat(),
}
}
| LEFTBRACE RIGHTBRACE
@ -89,11 +89,8 @@ objectitem:
}
| IDENTIFIER EQUAL object
{
$$ = &Object{
Key: $1,
Type: ValueTypeObject,
Value: $3,
}
$3.Key = $1
$$ = $3
}
| IDENTIFIER EQUAL list
{
@ -119,7 +116,7 @@ block:
$$ = &Object{
Key: $1,
Type: ValueTypeObject,
Value: map[string]*Object{$1: $2},
Value: []*Object{$2},
}
}

View File

@ -54,7 +54,7 @@ const hclEofCode = 1
const hclErrCode = 2
const hclMaxDepth = 200
//line parse.y:207
//line parse.y:204
//line yacctab:1
var hclExca = []int{
@ -361,7 +361,7 @@ hcldefault:
{
hclResult = &Object{
Type: ValueTypeObject,
Value: ObjectList(hclS[hclpt-0].objlist).Map(),
Value: ObjectList(hclS[hclpt-0].objlist).Flat(),
}
}
case 2:
@ -379,7 +379,7 @@ hcldefault:
{
hclVAL.obj = &Object{
Type: ValueTypeObject,
Value: ObjectList(hclS[hclpt-1].objlist).Map(),
Value: ObjectList(hclS[hclpt-1].objlist).Flat(),
}
}
case 5:
@ -416,14 +416,11 @@ hcldefault:
case 9:
//line parse.y:91
{
hclVAL.obj = &Object{
Key: hclS[hclpt-2].str,
Type: ValueTypeObject,
Value: hclS[hclpt-0].obj,
}
hclS[hclpt-0].obj.Key = hclS[hclpt-2].str
hclVAL.obj = hclS[hclpt-0].obj
}
case 10:
//line parse.y:99
//line parse.y:96
{
hclVAL.obj = &Object{
Key: hclS[hclpt-2].str,
@ -432,62 +429,62 @@ hcldefault:
}
}
case 11:
//line parse.y:107
//line parse.y:104
{
hclVAL.obj = hclS[hclpt-0].obj
}
case 12:
//line parse.y:113
//line parse.y:110
{
hclS[hclpt-0].obj.Key = hclS[hclpt-1].str
hclVAL.obj = hclS[hclpt-0].obj
}
case 13:
//line parse.y:118
//line parse.y:115
{
hclVAL.obj = &Object{
Key: hclS[hclpt-1].str,
Type: ValueTypeObject,
Value: map[string]*Object{hclS[hclpt-1].str: hclS[hclpt-0].obj},
Value: []*Object{hclS[hclpt-0].obj},
}
}
case 14:
//line parse.y:128
//line parse.y:125
{
hclVAL.str = hclS[hclpt-0].str
}
case 15:
//line parse.y:132
//line parse.y:129
{
hclVAL.str = hclS[hclpt-0].str
}
case 16:
//line parse.y:138
//line parse.y:135
{
hclVAL.objlist = hclS[hclpt-1].objlist
}
case 17:
//line parse.y:142
//line parse.y:139
{
hclVAL.objlist = nil
}
case 18:
//line parse.y:148
//line parse.y:145
{
hclVAL.objlist = []*Object{hclS[hclpt-0].obj}
}
case 19:
//line parse.y:152
//line parse.y:149
{
hclVAL.objlist = append(hclS[hclpt-2].objlist, hclS[hclpt-0].obj)
}
case 20:
//line parse.y:158
//line parse.y:155
{
hclVAL.obj = hclS[hclpt-0].obj
}
case 21:
//line parse.y:162
//line parse.y:159
{
hclVAL.obj = &Object{
Type: ValueTypeString,
@ -495,7 +492,7 @@ hcldefault:
}
}
case 22:
//line parse.y:171
//line parse.y:168
{
hclVAL.obj = &Object{
Type: ValueTypeInt,
@ -503,7 +500,7 @@ hcldefault:
}
}
case 23:
//line parse.y:178
//line parse.y:175
{
fs := fmt.Sprintf("%d.%s", hclS[hclpt-1].num, hclS[hclpt-0].str)
f, err := strconv.ParseFloat(fs, 64)
@ -517,17 +514,17 @@ hcldefault:
}
}
case 24:
//line parse.y:193
//line parse.y:190
{
hclVAL.num = hclS[hclpt-0].num * -1
}
case 25:
//line parse.y:197
//line parse.y:194
{
hclVAL.num = hclS[hclpt-0].num
}
case 26:
//line parse.y:203
//line parse.y:200
{
hclVAL.str = strconv.FormatInt(int64(hclS[hclpt-0].num), 10)
}

View File

@ -42,7 +42,7 @@ object:
{
$$ = &hcl.Object{
Type: hcl.ValueTypeObject,
Value: hcl.ObjectList($2).Map(),
Value: hcl.ObjectList($2).Flat(),
}
}
| LEFTBRACE RIGHTBRACE

View File

@ -372,7 +372,7 @@ jsondefault:
{
jsonVAL.obj = &hcl.Object{
Type: hcl.ValueTypeObject,
Value: hcl.ObjectList(jsonS[jsonpt-1].objlist).Map(),
Value: hcl.ObjectList(jsonS[jsonpt-1].objlist).Flat(),
}
}
case 3:

View File

@ -1,10 +1,10 @@
{
"foo": [{
"baz": [{
"foo": {
"baz": {
"key": 7,
"foo": "bar"
}]
}, {
},
"key": 7
}]
}
}

View File

@ -1,11 +1,11 @@
{
"foo": [{
"baz": [{
"foo": {
"baz": {
"key": 7
}]
}, {
"bar": [{
},
"bar": {
"key": 12
}]
}]
}
}
}