hcl/hclsyntax: Parsing of for expressions while newline-sensitive

The fact that object constructors are newline-sensitive while object for
expressions are not requires some special consideration in the parser. We
previously make a small fix here to delay turning on newline-sensitive
scanning before peeking ahead for a "for" keyword, but that was sufficient
only when the for expression was not already in a newline-sensitive
context.

Now we force newline-sensitive parsing off while we scan for the keyword,
and also again once we begin parsing the for expression, ensuring that
the for expression is always scanned properly regardless of what context
it appears in.
This commit is contained in:
Martin Atkins 2019-02-26 15:41:59 -08:00
parent fb2bc46cdb
commit 7e26f2f346
2 changed files with 23 additions and 1 deletions

View File

@ -507,6 +507,20 @@ upper(
}),
0,
},
{
// This one is different than the previous because the extra level of
// object constructor causes the inner for expression to begin parsing
// in newline-sensitive mode, which it must then properly disable in
// order to peek the "for" keyword.
"{\n a = {\n for k, v in {hello: \"world\"}:\nk => v\n }\n}",
nil,
cty.ObjectVal(map[string]cty.Value{
"a": cty.ObjectVal(map[string]cty.Value{
"hello": cty.StringVal("world"),
}),
}),
0,
},
{
`{for k, v in {hello: "world"}: k => v if k == "hello"}`,
nil,

View File

@ -1242,7 +1242,13 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
panic("parseObjectCons called without peeker pointing to open brace")
}
if forKeyword.TokenMatches(p.Peek()) {
// We must temporarily stop looking at newlines here while we check for
// a "for" keyword, since for expressions are _not_ newline-sensitive,
// even though object constructors are.
p.PushIncludeNewlines(false)
isFor := forKeyword.TokenMatches(p.Peek())
p.PopIncludeNewlines()
if isFor {
return p.finishParsingForExpr(open)
}
@ -1377,6 +1383,8 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
}
func (p *parser) finishParsingForExpr(open Token) (Expression, hcl.Diagnostics) {
p.PushIncludeNewlines(false)
defer p.PopIncludeNewlines()
introducer := p.Read()
if !forKeyword.TokenMatches(introducer) {
// Should never happen if callers are behaving