diff --git a/zcl/zclsyntax/expression_test.go b/zcl/zclsyntax/expression_test.go index 335cde0..56891e0 100644 --- a/zcl/zclsyntax/expression_test.go +++ b/zcl/zclsyntax/expression_test.go @@ -529,6 +529,15 @@ upper( cty.StringVal("Steve"), 0, }, + { + `[["hello"], ["goodbye"]].*.*`, + nil, + cty.TupleVal([]cty.Value{ + cty.TupleVal([]cty.Value{cty.StringVal("hello")}), + cty.TupleVal([]cty.Value{cty.StringVal("goodbye")}), + }), + 1, + }, { `["hello"][0]`, diff --git a/zcl/zclsyntax/parser.go b/zcl/zclsyntax/parser.go index a082a8c..0272617 100644 --- a/zcl/zclsyntax/parser.go +++ b/zcl/zclsyntax/parser.go @@ -512,12 +512,21 @@ Traversal: dot := p.Read() if p.Peek().Type != TokenIdent { if !p.recovery { - diags = append(diags, &zcl.Diagnostic{ - Severity: zcl.DiagError, - Summary: "Invalid attribute name", - Detail: "An attribute name is required after a dot.", - Subject: &attrTok.Range, - }) + if p.Peek().Type == TokenStar { + diags = append(diags, &zcl.Diagnostic{ + Severity: zcl.DiagError, + Summary: "Nested splat expression not allowed", + Detail: "A splat expression (*) cannot be used inside another attribute-only splat expression.", + Subject: p.Peek().Range.Ptr(), + }) + } else { + diags = append(diags, &zcl.Diagnostic{ + Severity: zcl.DiagError, + Summary: "Invalid attribute name", + Detail: "An attribute name is required after a dot.", + Subject: &attrTok.Range, + }) + } } p.setRecovery() continue Traversal