Merge pull request #159 from hashicorp/b-obj-parse
hcl/parser: cleaner error handling for objects with empty keys #158
This commit is contained in:
commit
99ce73d4fe
@ -50,7 +50,7 @@ func (p *Parser) Parse() (*ast.File, error) {
|
|||||||
scerr = &PosError{Pos: pos, Err: errors.New(msg)}
|
scerr = &PosError{Pos: pos, Err: errors.New(msg)}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Node, err = p.objectList()
|
f.Node, err = p.objectList(false)
|
||||||
if scerr != nil {
|
if scerr != nil {
|
||||||
return nil, scerr
|
return nil, scerr
|
||||||
}
|
}
|
||||||
@ -62,11 +62,23 @@ func (p *Parser) Parse() (*ast.File, error) {
|
|||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) objectList() (*ast.ObjectList, error) {
|
// objectList parses a list of items within an object (generally k/v pairs).
|
||||||
|
// The parameter" obj" tells this whether to we are within an object (braces:
|
||||||
|
// '{', '}') or just at the top level. If we're within an object, we end
|
||||||
|
// at an RBRACE.
|
||||||
|
func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) {
|
||||||
defer un(trace(p, "ParseObjectList"))
|
defer un(trace(p, "ParseObjectList"))
|
||||||
node := &ast.ObjectList{}
|
node := &ast.ObjectList{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
if obj {
|
||||||
|
tok := p.scan()
|
||||||
|
p.unscan()
|
||||||
|
if tok.Type == token.RBRACE {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
n, err := p.objectItem()
|
n, err := p.objectItem()
|
||||||
if err == errEofToken {
|
if err == errEofToken {
|
||||||
break // we are finished
|
break // we are finished
|
||||||
@ -288,7 +300,7 @@ func (p *Parser) objectType() (*ast.ObjectType, error) {
|
|||||||
Lbrace: p.tok.Pos,
|
Lbrace: p.tok.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
l, err := p.objectList()
|
l, err := p.objectList(true)
|
||||||
|
|
||||||
// if we hit RBRACE, we are good to go (means we parsed all Items), if it's
|
// if we hit RBRACE, we are good to go (means we parsed all Items), if it's
|
||||||
// not a RBRACE, it's an syntax error and we just return it.
|
// not a RBRACE, it's an syntax error and we just return it.
|
||||||
@ -296,9 +308,9 @@ func (p *Parser) objectType() (*ast.ObjectType, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no error, we should be at a RBRACE to end the object
|
// No error, scan and expect the ending to be a brace
|
||||||
if p.tok.Type != token.RBRACE {
|
if tok := p.scan(); tok.Type != token.RBRACE {
|
||||||
return nil, fmt.Errorf("object expected closing RBRACE got: %s", p.tok.Type)
|
return nil, fmt.Errorf("object expected closing RBRACE got: %s", tok.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
o.List = l
|
o.List = l
|
||||||
|
@ -307,6 +307,8 @@ func TestObjectType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range literals {
|
for _, l := range literals {
|
||||||
|
t.Logf("Source: %s", l.src)
|
||||||
|
|
||||||
p := newParser([]byte(l.src))
|
p := newParser([]byte(l.src))
|
||||||
// p.enableTrace = true
|
// p.enableTrace = true
|
||||||
item, err := p.objectItem()
|
item, err := p.objectItem()
|
||||||
@ -494,20 +496,34 @@ func TestParse(t *testing.T) {
|
|||||||
"object_key_without_value.hcl",
|
"object_key_without_value.hcl",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"object_key_assign_without_value.hcl",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"object_key_assign_without_value2.hcl",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"object_key_assign_without_value3.hcl",
|
||||||
|
true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const fixtureDir = "./test-fixtures"
|
const fixtureDir = "./test-fixtures"
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.Name))
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
if err != nil {
|
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.Name))
|
||||||
t.Fatalf("err: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = Parse(d)
|
v, err := Parse(d)
|
||||||
if (err != nil) != tc.Err {
|
if (err != nil) != tc.Err {
|
||||||
t.Fatalf("Input: %s\n\nError: %s", tc.Name, err)
|
t.Fatalf("Input: %s\n\nError: %s\n\nAST: %#v", tc.Name, err, v)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
foo {
|
||||||
|
bar =
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
foo {
|
||||||
|
baz = 7
|
||||||
|
bar =
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
foo {
|
||||||
|
bar =
|
||||||
|
baz = 7
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user