diff --git a/hcl/hclsyntax/parser.go b/hcl/hclsyntax/parser.go index 5513602..253ad50 100644 --- a/hcl/hclsyntax/parser.go +++ b/hcl/hclsyntax/parser.go @@ -417,6 +417,17 @@ Token: p.recoverAfterBodyItem() } + // We must never produce a nil body, since the caller may attempt to + // do analysis of a partial result when there's an error, so we'll + // insert a placeholder if we otherwise failed to produce a valid + // body due to one of the syntax error paths above. + if body == nil && diags.HasErrors() { + body = &Body{ + SrcRange: hcl.RangeBetween(oBrace.Range, cBraceRange), + EndRange: cBraceRange, + } + } + return &Block{ Type: blockType, Labels: labels, diff --git a/hcl/hclsyntax/parser_test.go b/hcl/hclsyntax/parser_test.go index 5ec30f2..79f8421 100644 --- a/hcl/hclsyntax/parser_test.go +++ b/hcl/hclsyntax/parser_test.go @@ -179,6 +179,51 @@ func TestParseConfig(t *testing.T) { }, }, }, + { + "block { block {} }\n", + 1, // can't nest another block in the single-line block syntax + &Body{ + Attributes: Attributes{}, + Blocks: Blocks{ + &Block{ + Type: "block", + Labels: nil, + Body: &Body{ + SrcRange: hcl.Range{ + Start: hcl.Pos{Line: 1, Column: 7, Byte: 6}, + End: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + }, + EndRange: hcl.Range{ // Parser recovery behavior leaves us after this whole construct, on the next line + Start: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + End: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + }, + }, + + TypeRange: hcl.Range{ + Start: hcl.Pos{Line: 1, Column: 1, Byte: 0}, + End: hcl.Pos{Line: 1, Column: 6, Byte: 5}, + }, + LabelRanges: nil, + OpenBraceRange: hcl.Range{ + Start: hcl.Pos{Line: 1, Column: 7, Byte: 6}, + End: hcl.Pos{Line: 1, Column: 8, Byte: 7}, + }, + CloseBraceRange: hcl.Range{ // Parser recovery behavior leaves us after this whole construct, on the next line + Start: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + End: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + }, + }, + }, + SrcRange: hcl.Range{ + Start: hcl.Pos{Line: 1, Column: 1, Byte: 0}, + End: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + }, + EndRange: hcl.Range{ + Start: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + End: hcl.Pos{Line: 2, Column: 1, Byte: 19}, + }, + }, + }, { "block \"foo\" {}\n", 0,