2017-09-11 23:40:37 +00:00
|
|
|
package hclsyntax
|
2017-06-22 15:00:24 +00:00
|
|
|
|
|
|
|
import (
|
2019-09-09 23:08:19 +00:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
2017-06-22 15:00:24 +00:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ParseTraversalAbs parses an absolute traversal that is assumed to consume
|
|
|
|
// all of the remaining tokens in the peeker. The usual parser recovery
|
|
|
|
// behavior is not supported here because traversals are not expected to
|
|
|
|
// be parsed as part of a larger program.
|
2017-09-11 23:40:37 +00:00
|
|
|
func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) {
|
|
|
|
var ret hcl.Traversal
|
|
|
|
var diags hcl.Diagnostics
|
2017-06-22 15:00:24 +00:00
|
|
|
|
|
|
|
// Absolute traversal must always begin with a variable name
|
|
|
|
varTok := p.Read()
|
|
|
|
if varTok.Type != TokenIdent {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Variable name required",
|
|
|
|
Detail: "Must begin with a variable name.",
|
|
|
|
Subject: &varTok.Range,
|
|
|
|
})
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
varName := string(varTok.Bytes)
|
2017-09-11 23:40:37 +00:00
|
|
|
ret = append(ret, hcl.TraverseRoot{
|
2017-06-22 15:00:24 +00:00
|
|
|
Name: varName,
|
|
|
|
SrcRange: varTok.Range,
|
|
|
|
})
|
|
|
|
|
|
|
|
for {
|
|
|
|
next := p.Peek()
|
|
|
|
|
|
|
|
if next.Type == TokenEOF {
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
switch next.Type {
|
|
|
|
case TokenDot:
|
|
|
|
// Attribute access
|
|
|
|
dot := p.Read() // eat dot
|
|
|
|
nameTok := p.Read()
|
|
|
|
if nameTok.Type != TokenIdent {
|
|
|
|
if nameTok.Type == TokenStar {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Attribute name required",
|
|
|
|
Detail: "Splat expressions (.*) may not be used here.",
|
|
|
|
Subject: &nameTok.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
} else {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Attribute name required",
|
|
|
|
Detail: "Dot must be followed by attribute name.",
|
|
|
|
Subject: &nameTok.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
attrName := string(nameTok.Bytes)
|
2017-09-11 23:40:37 +00:00
|
|
|
ret = append(ret, hcl.TraverseAttr{
|
2017-06-22 15:00:24 +00:00
|
|
|
Name: attrName,
|
2017-09-11 23:40:37 +00:00
|
|
|
SrcRange: hcl.RangeBetween(dot.Range, nameTok.Range),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
case TokenOBrack:
|
|
|
|
// Index
|
|
|
|
open := p.Read() // eat open bracket
|
|
|
|
next := p.Peek()
|
|
|
|
|
|
|
|
switch next.Type {
|
|
|
|
case TokenNumberLit:
|
|
|
|
tok := p.Read() // eat number
|
|
|
|
numVal, numDiags := p.numberLitValue(tok)
|
|
|
|
diags = append(diags, numDiags...)
|
|
|
|
|
|
|
|
close := p.Read()
|
|
|
|
if close.Type != TokenCBrack {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Unclosed index brackets",
|
|
|
|
Detail: "Index key must be followed by a closing bracket.",
|
|
|
|
Subject: &close.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(open.Range, close.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-09-11 23:40:37 +00:00
|
|
|
ret = append(ret, hcl.TraverseIndex{
|
2017-06-22 15:00:24 +00:00
|
|
|
Key: numVal,
|
2017-09-11 23:40:37 +00:00
|
|
|
SrcRange: hcl.RangeBetween(open.Range, close.Range),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
case TokenOQuote:
|
|
|
|
str, _, strDiags := p.parseQuotedStringLiteral()
|
|
|
|
diags = append(diags, strDiags...)
|
|
|
|
|
|
|
|
close := p.Read()
|
|
|
|
if close.Type != TokenCBrack {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Unclosed index brackets",
|
|
|
|
Detail: "Index key must be followed by a closing bracket.",
|
|
|
|
Subject: &close.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(open.Range, close.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-09-11 23:40:37 +00:00
|
|
|
ret = append(ret, hcl.TraverseIndex{
|
2017-06-22 15:00:24 +00:00
|
|
|
Key: cty.StringVal(str),
|
2017-09-11 23:40:37 +00:00
|
|
|
SrcRange: hcl.RangeBetween(open.Range, close.Range),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
if next.Type == TokenStar {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Attribute name required",
|
|
|
|
Detail: "Splat expressions ([*]) may not be used here.",
|
|
|
|
Subject: &next.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
} else {
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Index value required",
|
|
|
|
Detail: "Index brackets must contain either a literal number or a literal string.",
|
|
|
|
Subject: &next.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2017-09-11 23:40:37 +00:00
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
2017-06-22 15:00:24 +00:00
|
|
|
Summary: "Invalid character",
|
|
|
|
Detail: "Expected an attribute access or an index operator.",
|
|
|
|
Subject: &next.Range,
|
2017-09-11 23:40:37 +00:00
|
|
|
Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(),
|
2017-06-22 15:00:24 +00:00
|
|
|
})
|
|
|
|
return ret, diags
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|