hclwrite: Parsing of absolute traversals in expressions

This will allow for use-cases such as renaming a variable (changing the
content of the first token) and replacing variable references with
constant values that they evaluate to for debug purposes.
This commit is contained in:
Martin Atkins 2018-07-14 13:07:39 -07:00
parent 1718a963e6
commit d6367b5f96
3 changed files with 880 additions and 101 deletions

View File

@ -162,12 +162,12 @@ func (n *Block) Tokens() *TokenSeq {
}
type Expression struct {
AllTokens *TokenSeq
VarRefs []*VarRef
AllTokens *TokenSeq
AbsTraversals []*Traversal
}
func (n *Expression) walkChildNodes(w internalWalkFunc) {
for _, name := range n.VarRefs {
for _, name := range n.AbsTraversals {
w(name)
}
}
@ -176,16 +176,30 @@ func (n *Expression) Tokens() *TokenSeq {
return n.AllTokens
}
type VarRef struct {
// Tokens alternate between TokenIdent and TokenDot, with the first
// and last elements always being TokenIdent.
type Traversal struct {
AllTokens *TokenSeq
Steps []*Traverser
}
func (n *VarRef) walkChildNodes(w internalWalkFunc) {
// no child nodes of a variable name
func (n *Traversal) walkChildNodes(w internalWalkFunc) {
for _, step := range n.Steps {
w(step)
}
}
func (n *VarRef) Tokens() *TokenSeq {
func (n *Traversal) Tokens() *TokenSeq {
return n.AllTokens
}
type Traverser struct {
AllTokens *TokenSeq
Logical hcl.Traverser
}
func (n *Traverser) Tokens() *TokenSeq {
return n.AllTokens
}
func (n *Traverser) walkChildNodes(w internalWalkFunc) {
// No child nodes for a traversal step
}

View File

@ -327,9 +327,54 @@ func parseBlock(nativeBlock *hclsyntax.Block, from, leadComments, lineComments,
}
func parseExpression(nativeExpr hclsyntax.Expression, from inputTokens) *Expression {
// TODO: Populate VarRefs by analyzing the result of nativeExpr.Variables()
var allTokens TokenSeq
nativeVars := nativeExpr.Variables()
var absTraversals []*Traversal
for _, nativeTraversal := range nativeVars {
var traversalTokens TokenSeq
var before, traversalFrom inputTokens
before, traversalFrom, from = from.Partition(nativeTraversal.SourceRange())
if before.Len() > 0 {
allTokens = append(allTokens, before.Seq())
}
var steps []*Traverser
for _, nativeStep := range nativeTraversal {
var stepFrom inputTokens
before, stepFrom, traversalFrom = traversalFrom.Partition(nativeStep.SourceRange())
stepTokens := stepFrom.Seq()
if before.Len() > 0 {
traversalTokens = append(traversalTokens, before.Seq())
}
traversalTokens = append(traversalTokens, stepTokens)
step := &Traverser{
AllTokens: stepTokens,
Logical: nativeStep,
}
steps = append(steps, step)
}
// Attach any straggler that don't belong to a step to the traversal itself.
if traversalFrom.Len() > 0 {
traversalTokens = append(traversalTokens, traversalFrom.Seq())
}
allTokens = append(allTokens, &traversalTokens)
absTraversals = append(absTraversals, &Traversal{
AllTokens: &traversalTokens,
Steps: steps,
})
}
// Attach any stragglers that don't belong to a traversal to the expression
// itself. In an expression with no traversals at all, this is just the
// entirety of "from".
if from.Len() > 0 {
allTokens = append(allTokens, from.Seq())
}
return &Expression{
AllTokens: from.Seq(),
AllTokens: &allTokens,
AbsTraversals: absTraversals,
}
}

File diff suppressed because it is too large Load Diff