2018-08-01 15:45:22 +00:00
|
|
|
package hclwrite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/hcl2/hcl"
|
2018-11-04 02:09:35 +00:00
|
|
|
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
2018-08-01 15:45:22 +00:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Expression struct {
|
|
|
|
inTree
|
|
|
|
|
|
|
|
absTraversals nodeSet
|
|
|
|
}
|
|
|
|
|
|
|
|
func newExpression() *Expression {
|
|
|
|
return &Expression{
|
|
|
|
inTree: newInTree(),
|
|
|
|
absTraversals: newNodeSet(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewExpressionLiteral constructs an an expression that represents the given
|
|
|
|
// literal value.
|
2018-08-09 15:44:48 +00:00
|
|
|
//
|
|
|
|
// Since an unknown value cannot be represented in source code, this function
|
|
|
|
// will panic if the given value is unknown or contains a nested unknown value.
|
|
|
|
// Use val.IsWhollyKnown before calling to be sure.
|
|
|
|
//
|
|
|
|
// HCL native syntax does not directly represent lists, maps, and sets, and
|
|
|
|
// instead relies on the automatic conversions to those collection types from
|
|
|
|
// either list or tuple constructor syntax. Therefore converting collection
|
|
|
|
// values to source code and re-reading them will lose type information, and
|
|
|
|
// the reader must provide a suitable type at decode time to recover the
|
|
|
|
// original value.
|
2018-08-01 15:45:22 +00:00
|
|
|
func NewExpressionLiteral(val cty.Value) *Expression {
|
2018-08-09 15:44:48 +00:00
|
|
|
toks := TokensForValue(val)
|
|
|
|
expr := newExpression()
|
|
|
|
expr.children.AppendUnstructuredTokens(toks)
|
|
|
|
return expr
|
2018-08-01 15:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewExpressionAbsTraversal constructs an expression that represents the
|
|
|
|
// given traversal, which must be absolute or this function will panic.
|
2018-08-09 15:47:37 +00:00
|
|
|
func NewExpressionAbsTraversal(traversal hcl.Traversal) *Expression {
|
2018-11-04 02:09:35 +00:00
|
|
|
if traversal.IsRelative() {
|
|
|
|
panic("can't construct expression from relative traversal")
|
|
|
|
}
|
|
|
|
|
|
|
|
physT := newTraversal()
|
|
|
|
rootName := traversal.RootName()
|
|
|
|
steps := traversal[1:]
|
|
|
|
|
|
|
|
{
|
|
|
|
tn := newTraverseName()
|
|
|
|
tn.name = tn.children.Append(newIdentifier(&Token{
|
|
|
|
Type: hclsyntax.TokenIdent,
|
|
|
|
Bytes: []byte(rootName),
|
|
|
|
}))
|
|
|
|
physT.steps.Add(physT.children.Append(tn))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, step := range steps {
|
|
|
|
switch ts := step.(type) {
|
|
|
|
case hcl.TraverseAttr:
|
|
|
|
tn := newTraverseName()
|
|
|
|
tn.children.AppendUnstructuredTokens(Tokens{
|
|
|
|
{
|
|
|
|
Type: hclsyntax.TokenDot,
|
|
|
|
Bytes: []byte{'.'},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
tn.name = tn.children.Append(newIdentifier(&Token{
|
|
|
|
Type: hclsyntax.TokenIdent,
|
|
|
|
Bytes: []byte(ts.Name),
|
|
|
|
}))
|
|
|
|
physT.steps.Add(physT.children.Append(tn))
|
|
|
|
case hcl.TraverseIndex:
|
|
|
|
ti := newTraverseIndex()
|
|
|
|
ti.children.AppendUnstructuredTokens(Tokens{
|
|
|
|
{
|
|
|
|
Type: hclsyntax.TokenOBrack,
|
|
|
|
Bytes: []byte{'['},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
indexExpr := NewExpressionLiteral(ts.Key)
|
|
|
|
ti.key = ti.children.Append(indexExpr)
|
|
|
|
ti.children.AppendUnstructuredTokens(Tokens{
|
|
|
|
{
|
|
|
|
Type: hclsyntax.TokenCBrack,
|
|
|
|
Bytes: []byte{']'},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
physT.steps.Add(physT.children.Append(ti))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expr := newExpression()
|
|
|
|
expr.absTraversals.Add(expr.children.Append(physT))
|
|
|
|
return expr
|
2018-08-01 15:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Traversal struct {
|
|
|
|
inTree
|
|
|
|
|
|
|
|
steps nodeSet
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTraversal() *Traversal {
|
|
|
|
return &Traversal{
|
|
|
|
inTree: newInTree(),
|
|
|
|
steps: newNodeSet(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type TraverseName struct {
|
|
|
|
inTree
|
|
|
|
|
|
|
|
name *node
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTraverseName() *TraverseName {
|
|
|
|
return &TraverseName{
|
|
|
|
inTree: newInTree(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type TraverseIndex struct {
|
|
|
|
inTree
|
|
|
|
|
|
|
|
key *node
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTraverseIndex() *TraverseIndex {
|
|
|
|
return &TraverseIndex{
|
|
|
|
inTree: newInTree(),
|
|
|
|
}
|
|
|
|
}
|