package hclwrite import ( "github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hcl/hclsyntax" "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. // // 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. func NewExpressionLiteral(val cty.Value) *Expression { toks := TokensForValue(val) expr := newExpression() expr.children.AppendUnstructuredTokens(toks) return expr } // NewExpressionAbsTraversal constructs an expression that represents the // given traversal, which must be absolute or this function will panic. func NewExpressionAbsTraversal(traversal hcl.Traversal) *Expression { 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 } 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(), } }