Start the decoder

This commit is contained in:
Mitchell Hashimoto 2014-08-02 15:44:45 -07:00
parent 3a02b49a51
commit 59e0ca9d5a
10 changed files with 320 additions and 104 deletions

View File

@ -17,6 +17,13 @@ type Node interface {
Accept(Visitor) Accept(Visitor)
} }
// KeyedNode is a node that has a key associated with it.
type KeyedNode interface {
Node
Key() string
}
// Visitor is the interface that must be implemented by any // Visitor is the interface that must be implemented by any
// structures who want to be visited as part of the visitor pattern // structures who want to be visited as part of the visitor pattern
// on the AST. // on the AST.
@ -29,14 +36,14 @@ type Visitor interface {
// be validated/removed at a semantic check, rather than at a // be validated/removed at a semantic check, rather than at a
// syntax level. // syntax level.
type ObjectNode struct { type ObjectNode struct {
Key string K string
Elem []Node Elem []KeyedNode
} }
// AssignmentNode represents a direct assignment with an equals // AssignmentNode represents a direct assignment with an equals
// sign. // sign.
type AssignmentNode struct { type AssignmentNode struct {
Key string K string
Value Node Value Node
} }
@ -52,24 +59,32 @@ type LiteralNode struct {
} }
func (n ObjectNode) Accept(v Visitor) { func (n ObjectNode) Accept(v Visitor) {
v.Visit(n)
for _, e := range n.Elem { for _, e := range n.Elem {
e.Accept(v) e.Accept(v)
} }
}
v.Visit(n) func (n ObjectNode) Key() string {
return n.K
} }
func (n AssignmentNode) Accept(v Visitor) { func (n AssignmentNode) Accept(v Visitor) {
n.Value.Accept(v)
v.Visit(n) v.Visit(n)
n.Value.Accept(v)
}
func (n AssignmentNode) Key() string {
return n.K
} }
func (n ListNode) Accept(v Visitor) { func (n ListNode) Accept(v Visitor) {
v.Visit(n)
for _, e := range n.Elem { for _, e := range n.Elem {
e.Accept(v) e.Accept(v)
} }
v.Visit(n)
} }
func (n LiteralNode) Accept(v Visitor) { func (n LiteralNode) Accept(v Visitor) {

View File

@ -7,13 +7,13 @@ import (
func TestAssignmentNode_accept(t *testing.T) { func TestAssignmentNode_accept(t *testing.T) {
n := AssignmentNode{ n := AssignmentNode{
Key: "foo", K: "foo",
Value: LiteralNode{Value: "foo"}, Value: LiteralNode{Value: "foo"},
} }
expected := []Node{ expected := []Node{
n.Value,
n, n,
n.Value,
} }
v := new(MockVisitor) v := new(MockVisitor)
@ -33,9 +33,9 @@ func TestListNode_accept(t *testing.T) {
} }
expected := []Node{ expected := []Node{
n,
n.Elem[0], n.Elem[0],
n.Elem[1], n.Elem[1],
n,
} }
v := new(MockVisitor) v := new(MockVisitor)
@ -48,17 +48,19 @@ func TestListNode_accept(t *testing.T) {
func TestObjectNode_accept(t *testing.T) { func TestObjectNode_accept(t *testing.T) {
n := ObjectNode{ n := ObjectNode{
Key: "foo", K: "foo",
Elem: []Node{ Elem: []KeyedNode{
LiteralNode{Value: "foo"}, AssignmentNode{K: "foo", Value: LiteralNode{Value: "foo"}},
LiteralNode{Value: "bar"}, AssignmentNode{K: "bar", Value: LiteralNode{Value: "bar"}},
}, },
} }
expected := []Node{ expected := []Node{
n.Elem[0],
n.Elem[1],
n, n,
n.Elem[0],
n.Elem[0].(AssignmentNode).Value,
n.Elem[1],
n.Elem[1].(AssignmentNode).Value,
} }
v := new(MockVisitor) v := new(MockVisitor)

144
decoder.go Normal file
View File

@ -0,0 +1,144 @@
package hcl
import (
"fmt"
"reflect"
"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.
func DecodeAST(out interface{}, obj *ast.ObjectNode) error {
return decode("", *obj, reflect.ValueOf(out).Elem())
}
func decode(name string, n ast.Node, result reflect.Value) error {
switch result.Kind() {
case reflect.Interface:
// When we see an interface, we make our own thing
return decodeInterface(name, n, result)
case reflect.Map:
return decodeMap(name, n, result)
case reflect.String:
return decodeString(name, n, result)
default:
return fmt.Errorf("%s: unknown kind: %s", name, result.Kind())
}
return nil
}
func decodeInterface(name string, raw ast.Node, result reflect.Value) error {
var set reflect.Value
switch n := raw.(type) {
case ast.ObjectNode:
result := make(map[string]interface{})
set = reflect.ValueOf(result)
case ast.LiteralNode:
switch n.Type {
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)
}
// Revisit the node so that we can use the newly instantiated
// thing and populate it.
if err := decode(name, raw, set); err != nil {
return err
}
// Set the result to what its supposed to be, then reset
// result so we don't reflect into this method anymore.
result.Set(set)
return nil
}
func decodeMap(name string, raw ast.Node, result reflect.Value) error {
obj, ok := raw.(ast.ObjectNode)
if !ok {
return fmt.Errorf("%s: not an object type", name)
}
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)
// Make the field name
fieldName := fmt.Sprintf("%s[%s]", name, n.Key())
// 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!
if err := decode(fieldName, n.Value, val); err != nil {
return err
}
// Set the value on the map
resultMap.SetMapIndex(key, val)
}
// Set the final map
result.Set(resultMap)
return nil
}
func decodeString(name string, raw ast.Node, result reflect.Value) error {
n, ok := raw.(ast.LiteralNode)
if !ok {
return fmt.Errorf("%s: not a literal type", name)
}
switch n.Type {
case ast.ValueTypeString:
println(n.Value.(string))
result.SetString(n.Value.(string))
default:
return fmt.Errorf("%s: unknown type %s", name, n.Type)
}
return nil
}

41
decoder_test.go Normal file
View File

@ -0,0 +1,41 @@
package hcl
import (
"io/ioutil"
"path/filepath"
"reflect"
"testing"
)
func TestDecode(t *testing.T) {
cases := []struct {
File string
Err bool
Out interface{}
}{
{
"basic.hcl",
false,
map[string]interface{}{
"foo": "bar",
},
},
}
for _, tc := range cases {
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.File))
if err != nil {
t.Fatalf("err: %s", err)
}
var out map[string]interface{}
err = Decode(&out, string(d))
if (err != nil) != tc.Err {
t.Fatalf("Input: %s\n\nError: %s", tc.File, err)
}
if !reflect.DeepEqual(out, tc.Out) {
t.Fatalf("Input: %s\n\n%#v", tc.File, out)
}
}
}

View File

@ -11,14 +11,18 @@ import (
%union { %union {
list []ast.Node list []ast.Node
klist []ast.KeyedNode
kitem ast.KeyedNode
listitem ast.Node listitem ast.Node
num int num int
obj ast.ObjectNode obj ast.ObjectNode
str string str string
} }
%type <list> list objectlist %type <list> list
%type <listitem> listitem objectitem %type <klist> objectlist
%type <kitem> objectitem
%type <listitem> listitem
%type <obj> block object %type <obj> block object
%type <str> blockId %type <str> blockId
@ -32,7 +36,7 @@ top:
objectlist objectlist
{ {
hclResult = &ast.ObjectNode{ hclResult = &ast.ObjectNode{
Key: "", K: "",
Elem: $1, Elem: $1,
} }
} }
@ -40,7 +44,7 @@ top:
objectlist: objectlist:
objectitem objectitem
{ {
$$ = []ast.Node{$1} $$ = []ast.KeyedNode{$1}
} }
| objectitem objectlist | objectitem objectlist
{ {
@ -61,7 +65,7 @@ objectitem:
IDENTIFIER EQUAL NUMBER IDENTIFIER EQUAL NUMBER
{ {
$$ = ast.AssignmentNode{ $$ = ast.AssignmentNode{
Key: $1, K: $1,
Value: ast.LiteralNode{ Value: ast.LiteralNode{
Type: ast.ValueTypeInt, Type: ast.ValueTypeInt,
Value: $3, Value: $3,
@ -71,7 +75,7 @@ objectitem:
| IDENTIFIER EQUAL STRING | IDENTIFIER EQUAL STRING
{ {
$$ = ast.AssignmentNode{ $$ = ast.AssignmentNode{
Key: $1, K: $1,
Value: ast.LiteralNode{ Value: ast.LiteralNode{
Type: ast.ValueTypeString, Type: ast.ValueTypeString,
Value: $3, Value: $3,
@ -81,14 +85,14 @@ objectitem:
| IDENTIFIER EQUAL object | IDENTIFIER EQUAL object
{ {
$$ = ast.AssignmentNode{ $$ = ast.AssignmentNode{
Key: $1, K: $1,
Value: $3, Value: $3,
} }
} }
| IDENTIFIER EQUAL LEFTBRACKET list RIGHTBRACKET | IDENTIFIER EQUAL LEFTBRACKET list RIGHTBRACKET
{ {
$$ = ast.AssignmentNode{ $$ = ast.AssignmentNode{
Key: $1, K: $1,
Value: ast.ListNode{Elem: $4}, Value: ast.ListNode{Elem: $4},
} }
} }
@ -101,13 +105,13 @@ block:
blockId object blockId object
{ {
$$ = $2 $$ = $2
$$.Key = $1 $$.K = $1
} }
| blockId block | blockId block
{ {
$$ = ast.ObjectNode{ $$ = ast.ObjectNode{
Key: $1, K: $1,
Elem: []ast.Node{$2}, Elem: []ast.KeyedNode{$2},
} }
} }

View File

@ -12,6 +12,8 @@ import (
type hclSymType struct { type hclSymType struct {
yys int yys int
list []ast.Node list []ast.Node
klist []ast.KeyedNode
kitem ast.KeyedNode
listitem ast.Node listitem ast.Node
num int num int
obj ast.ObjectNode obj ast.ObjectNode
@ -47,7 +49,7 @@ const hclEofCode = 1
const hclErrCode = 2 const hclErrCode = 2
const hclMaxDepth = 200 const hclMaxDepth = 200
//line parse.y:150 //line parse.y:154
//line yacctab:1 //line yacctab:1
var hclExca = []int{ var hclExca = []int{
@ -79,12 +81,12 @@ var hclPact = []int{
} }
var hclPgo = []int{ var hclPgo = []int{
0, 29, 4, 0, 28, 25, 12, 26, 5, 0, 29, 4, 28, 0, 25, 12, 26, 5,
} }
var hclR1 = []int{ var hclR1 = []int{
0, 8, 2, 2, 6, 6, 4, 4, 4, 4, 0, 8, 2, 2, 6, 6, 3, 3, 3, 3,
4, 5, 5, 7, 7, 1, 1, 3, 3, 3, 5, 5, 7, 7, 1, 1, 4, 4,
} }
var hclR2 = []int{ var hclR2 = []int{
@ -93,9 +95,9 @@ var hclR2 = []int{
} }
var hclChk = []int{ var hclChk = []int{
-1000, -8, -2, -4, 6, -5, -7, 9, -2, 7, -1000, -8, -2, -3, 6, -5, -7, 9, -2, 7,
-6, -5, 10, 6, 4, 9, -6, 12, -2, 11, -6, -5, 10, 6, 4, 9, -6, 12, -2, 11,
-1, -3, 4, 9, 11, 13, 5, -3, -1, -4, 4, 9, 11, 13, 5, -4,
} }
var hclDef = []int{ var hclDef = []int{
@ -342,38 +344,38 @@ hcldefault:
switch hclnt { switch hclnt {
case 1: case 1:
//line parse.y:33 //line parse.y:37
{ {
hclResult = &ast.ObjectNode{ hclResult = &ast.ObjectNode{
Key: "", K: "",
Elem: hclS[hclpt-0].list, Elem: hclS[hclpt-0].klist,
} }
} }
case 2: case 2:
//line parse.y:42
{
hclVAL.list = []ast.Node{hclS[hclpt-0].listitem}
}
case 3:
//line parse.y:46 //line parse.y:46
{ {
hclVAL.list = append(hclS[hclpt-0].list, hclS[hclpt-1].listitem) hclVAL.klist = []ast.KeyedNode{hclS[hclpt-0].kitem}
}
case 3:
//line parse.y:50
{
hclVAL.klist = append(hclS[hclpt-0].klist, hclS[hclpt-1].kitem)
} }
case 4: case 4:
//line parse.y:52 //line parse.y:56
{ {
hclVAL.obj = ast.ObjectNode{Elem: hclS[hclpt-1].list} hclVAL.obj = ast.ObjectNode{Elem: hclS[hclpt-1].klist}
} }
case 5: case 5:
//line parse.y:56 //line parse.y:60
{ {
hclVAL.obj = ast.ObjectNode{} hclVAL.obj = ast.ObjectNode{}
} }
case 6: case 6:
//line parse.y:62 //line parse.y:66
{ {
hclVAL.listitem = ast.AssignmentNode{ hclVAL.kitem = ast.AssignmentNode{
Key: hclS[hclpt-2].str, K: hclS[hclpt-2].str,
Value: ast.LiteralNode{ Value: ast.LiteralNode{
Type: ast.ValueTypeInt, Type: ast.ValueTypeInt,
Value: hclS[hclpt-0].num, Value: hclS[hclpt-0].num,
@ -381,10 +383,10 @@ hcldefault:
} }
} }
case 7: case 7:
//line parse.y:72 //line parse.y:76
{ {
hclVAL.listitem = ast.AssignmentNode{ hclVAL.kitem = ast.AssignmentNode{
Key: hclS[hclpt-2].str, K: hclS[hclpt-2].str,
Value: ast.LiteralNode{ Value: ast.LiteralNode{
Type: ast.ValueTypeString, Type: ast.ValueTypeString,
Value: hclS[hclpt-0].str, Value: hclS[hclpt-0].str,
@ -392,62 +394,62 @@ hcldefault:
} }
} }
case 8: case 8:
//line parse.y:82 //line parse.y:86
{ {
hclVAL.listitem = ast.AssignmentNode{ hclVAL.kitem = ast.AssignmentNode{
Key: hclS[hclpt-2].str, K: hclS[hclpt-2].str,
Value: hclS[hclpt-0].obj, Value: hclS[hclpt-0].obj,
} }
} }
case 9: case 9:
//line parse.y:89 //line parse.y:93
{ {
hclVAL.listitem = ast.AssignmentNode{ hclVAL.kitem = ast.AssignmentNode{
Key: hclS[hclpt-4].str, K: hclS[hclpt-4].str,
Value: ast.ListNode{Elem: hclS[hclpt-1].list}, Value: ast.ListNode{Elem: hclS[hclpt-1].list},
} }
} }
case 10: case 10:
//line parse.y:96 //line parse.y:100
{ {
hclVAL.listitem = hclS[hclpt-0].obj hclVAL.kitem = hclS[hclpt-0].obj
} }
case 11: case 11:
//line parse.y:102 //line parse.y:106
{ {
hclVAL.obj = hclS[hclpt-0].obj hclVAL.obj = hclS[hclpt-0].obj
hclVAL.obj.Key = hclS[hclpt-1].str hclVAL.obj.K = hclS[hclpt-1].str
} }
case 12: case 12:
//line parse.y:107 //line parse.y:111
{ {
hclVAL.obj = ast.ObjectNode{ hclVAL.obj = ast.ObjectNode{
Key: hclS[hclpt-1].str, K: hclS[hclpt-1].str,
Elem: []ast.Node{hclS[hclpt-0].obj}, Elem: []ast.KeyedNode{hclS[hclpt-0].obj},
} }
} }
case 13: case 13:
//line parse.y:116
{
hclVAL.str = hclS[hclpt-0].str
}
case 14:
//line parse.y:120 //line parse.y:120
{ {
hclVAL.str = hclS[hclpt-0].str hclVAL.str = hclS[hclpt-0].str
} }
case 14:
//line parse.y:124
{
hclVAL.str = hclS[hclpt-0].str
}
case 15: case 15:
//line parse.y:126 //line parse.y:130
{ {
hclVAL.list = []ast.Node{hclS[hclpt-0].listitem} hclVAL.list = []ast.Node{hclS[hclpt-0].listitem}
} }
case 16: case 16:
//line parse.y:130 //line parse.y:134
{ {
hclVAL.list = append(hclS[hclpt-2].list, hclS[hclpt-0].listitem) hclVAL.list = append(hclS[hclpt-2].list, hclS[hclpt-0].listitem)
} }
case 17: case 17:
//line parse.y:136 //line parse.y:140
{ {
hclVAL.listitem = ast.LiteralNode{ hclVAL.listitem = ast.LiteralNode{
Type: ast.ValueTypeInt, Type: ast.ValueTypeInt,
@ -455,7 +457,7 @@ hcldefault:
} }
} }
case 18: case 18:
//line parse.y:143 //line parse.y:147
{ {
hclVAL.listitem = ast.LiteralNode{ hclVAL.listitem = ast.LiteralNode{
Type: ast.ValueTypeString, Type: ast.ValueTypeString,

4
hcl_test.go Normal file
View File

@ -0,0 +1,4 @@
package hcl
// This is the directory where our test fixtures are.
const fixtureDir = "./test-fixtures"

View File

@ -13,6 +13,7 @@ import (
array ast.ListNode array ast.ListNode
assign ast.AssignmentNode assign ast.AssignmentNode
item ast.Node item ast.Node
klist []ast.KeyedNode
list []ast.Node list []ast.Node
num int num int
str string str string
@ -22,7 +23,8 @@ import (
%type <array> array %type <array> array
%type <assign> pair %type <assign> pair
%type <item> value %type <item> value
%type <list> elements members %type <klist> members
%type <list> elements
%type <obj> object %type <obj> object
%token <num> NUMBER %token <num> NUMBER
@ -52,7 +54,7 @@ object:
members: members:
pair pair
{ {
$$ = []ast.Node{$1} $$ = []ast.KeyedNode{$1}
} }
| pair COMMA members | pair COMMA members
{ {
@ -63,7 +65,7 @@ pair:
STRING COLON value STRING COLON value
{ {
$$ = ast.AssignmentNode{ $$ = ast.AssignmentNode{
Key: $1, K: $1,
Value: $3, Value: $3,
} }
} }

View File

@ -14,6 +14,7 @@ type jsonSymType struct {
array ast.ListNode array ast.ListNode
assign ast.AssignmentNode assign ast.AssignmentNode
item ast.Node item ast.Node
klist []ast.KeyedNode
list []ast.Node list []ast.Node
num int num int
str string str string
@ -57,7 +58,7 @@ const jsonEofCode = 1
const jsonErrCode = 2 const jsonErrCode = 2
const jsonMaxDepth = 200 const jsonMaxDepth = 200
//line parse.y:136 //line parse.y:138
//line yacctab:1 //line yacctab:1
var jsonExca = []int{ var jsonExca = []int{
@ -89,12 +90,12 @@ var jsonPact = []int{
} }
var jsonPgo = []int{ var jsonPgo = []int{
0, 34, 32, 17, 0, 23, 29, 31, 0, 34, 32, 17, 23, 0, 29, 31,
} }
var jsonR1 = []int{ var jsonR1 = []int{
0, 7, 6, 6, 5, 5, 2, 3, 3, 3, 0, 7, 6, 6, 4, 4, 2, 3, 3, 3,
3, 3, 3, 3, 1, 1, 4, 4, 3, 3, 3, 3, 1, 1, 5, 5,
} }
var jsonR2 = []int{ var jsonR2 = []int{
@ -103,9 +104,9 @@ var jsonR2 = []int{
} }
var jsonChk = []int{ var jsonChk = []int{
-1000, -7, -6, 11, -5, 12, -2, 10, 12, 6, -1000, -7, -6, 11, -4, 12, -2, 10, 12, 6,
5, -5, -3, 10, 4, -6, -1, 15, 16, 17, 5, -4, -3, 10, 4, -6, -1, 15, 16, 17,
13, 14, -4, -3, 14, 6, -4, 13, 14, -5, -3, 14, 6, -5,
} }
var jsonDef = []int{ var jsonDef = []int{
@ -352,41 +353,41 @@ jsondefault:
switch jsonnt { switch jsonnt {
case 1: case 1:
//line parse.y:37 //line parse.y:39
{ {
obj := jsonS[jsonpt-0].obj obj := jsonS[jsonpt-0].obj
jsonResult = &obj jsonResult = &obj
} }
case 2: case 2:
//line parse.y:44 //line parse.y:46
{ {
jsonVAL.obj = ast.ObjectNode{Elem: jsonS[jsonpt-1].list} jsonVAL.obj = ast.ObjectNode{Elem: jsonS[jsonpt-1].klist}
} }
case 3: case 3:
//line parse.y:48 //line parse.y:50
{ {
jsonVAL.obj = ast.ObjectNode{} jsonVAL.obj = ast.ObjectNode{}
} }
case 4: case 4:
//line parse.y:54 //line parse.y:56
{ {
jsonVAL.list = []ast.Node{jsonS[jsonpt-0].assign} jsonVAL.klist = []ast.KeyedNode{jsonS[jsonpt-0].assign}
} }
case 5: case 5:
//line parse.y:58 //line parse.y:60
{ {
jsonVAL.list = append(jsonS[jsonpt-0].list, jsonS[jsonpt-2].assign) jsonVAL.klist = append(jsonS[jsonpt-0].klist, jsonS[jsonpt-2].assign)
} }
case 6: case 6:
//line parse.y:64 //line parse.y:66
{ {
jsonVAL.assign = ast.AssignmentNode{ jsonVAL.assign = ast.AssignmentNode{
Key: jsonS[jsonpt-2].str, K: jsonS[jsonpt-2].str,
Value: jsonS[jsonpt-0].item, Value: jsonS[jsonpt-0].item,
} }
} }
case 7: case 7:
//line parse.y:73 //line parse.y:75
{ {
jsonVAL.item = ast.LiteralNode{ jsonVAL.item = ast.LiteralNode{
Type: ast.ValueTypeString, Type: ast.ValueTypeString,
@ -394,7 +395,7 @@ jsondefault:
} }
} }
case 8: case 8:
//line parse.y:80 //line parse.y:82
{ {
jsonVAL.item = ast.LiteralNode{ jsonVAL.item = ast.LiteralNode{
Type: ast.ValueTypeInt, Type: ast.ValueTypeInt,
@ -402,17 +403,17 @@ jsondefault:
} }
} }
case 9: case 9:
//line parse.y:87 //line parse.y:89
{ {
jsonVAL.item = jsonS[jsonpt-0].obj jsonVAL.item = jsonS[jsonpt-0].obj
} }
case 10: case 10:
//line parse.y:91 //line parse.y:93
{ {
jsonVAL.item = jsonS[jsonpt-0].array jsonVAL.item = jsonS[jsonpt-0].array
} }
case 11: case 11:
//line parse.y:95 //line parse.y:97
{ {
jsonVAL.item = ast.LiteralNode{ jsonVAL.item = ast.LiteralNode{
Type: ast.ValueTypeBool, Type: ast.ValueTypeBool,
@ -420,7 +421,7 @@ jsondefault:
} }
} }
case 12: case 12:
//line parse.y:102 //line parse.y:104
{ {
jsonVAL.item = ast.LiteralNode{ jsonVAL.item = ast.LiteralNode{
Type: ast.ValueTypeBool, Type: ast.ValueTypeBool,
@ -428,7 +429,7 @@ jsondefault:
} }
} }
case 13: case 13:
//line parse.y:109 //line parse.y:111
{ {
jsonVAL.item = ast.LiteralNode{ jsonVAL.item = ast.LiteralNode{
Type: ast.ValueTypeNil, Type: ast.ValueTypeNil,
@ -436,22 +437,22 @@ jsondefault:
} }
} }
case 14: case 14:
//line parse.y:118 //line parse.y:120
{ {
jsonVAL.array = ast.ListNode{} jsonVAL.array = ast.ListNode{}
} }
case 15: case 15:
//line parse.y:122 //line parse.y:124
{ {
jsonVAL.array = ast.ListNode{Elem: jsonS[jsonpt-1].list} jsonVAL.array = ast.ListNode{Elem: jsonS[jsonpt-1].list}
} }
case 16: case 16:
//line parse.y:128 //line parse.y:130
{ {
jsonVAL.list = []ast.Node{jsonS[jsonpt-0].item} jsonVAL.list = []ast.Node{jsonS[jsonpt-0].item}
} }
case 17: case 17:
//line parse.y:132 //line parse.y:134
{ {
jsonVAL.list = append(jsonS[jsonpt-0].list, jsonS[jsonpt-2].item) jsonVAL.list = append(jsonS[jsonpt-0].list, jsonS[jsonpt-2].item)
} }

1
test-fixtures/basic.hcl Normal file
View File

@ -0,0 +1 @@
foo = "bar"