hclsyntax: Remove hclsyntax.Transform
This was always a bit of an outlier here because the rest of the API is intentionally designed to encourage treating AST nodes as immutable. Although the transforming walkers were functionally correct, they were causing false positives in the race detector if two walks run concurrently. We may later introduce something similar to this in the hclwrite package, where the AST nodes are explicitly mutable.
This commit is contained in:
parent
3f1c5474d4
commit
cce5ae6cc5
@ -132,7 +132,7 @@ type RelativeTraversalExpr struct {
|
||||
}
|
||||
|
||||
func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Source = w(e.Source).(Expression)
|
||||
w(e.Source)
|
||||
}
|
||||
|
||||
func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
@ -181,8 +181,8 @@ type FunctionCallExpr struct {
|
||||
}
|
||||
|
||||
func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) {
|
||||
for i, arg := range e.Args {
|
||||
e.Args[i] = w(arg).(Expression)
|
||||
for _, arg := range e.Args {
|
||||
w(arg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,9 +463,9 @@ type ConditionalExpr struct {
|
||||
}
|
||||
|
||||
func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Condition = w(e.Condition).(Expression)
|
||||
e.TrueResult = w(e.TrueResult).(Expression)
|
||||
e.FalseResult = w(e.FalseResult).(Expression)
|
||||
w(e.Condition)
|
||||
w(e.TrueResult)
|
||||
w(e.FalseResult)
|
||||
}
|
||||
|
||||
func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
@ -593,8 +593,8 @@ type IndexExpr struct {
|
||||
}
|
||||
|
||||
func (e *IndexExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Collection = w(e.Collection).(Expression)
|
||||
e.Key = w(e.Key).(Expression)
|
||||
w(e.Collection)
|
||||
w(e.Key)
|
||||
}
|
||||
|
||||
func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
@ -625,8 +625,8 @@ type TupleConsExpr struct {
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) {
|
||||
for i, expr := range e.Exprs {
|
||||
e.Exprs[i] = w(expr).(Expression)
|
||||
for _, expr := range e.Exprs {
|
||||
w(expr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -674,9 +674,9 @@ type ObjectConsItem struct {
|
||||
}
|
||||
|
||||
func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) {
|
||||
for i, item := range e.Items {
|
||||
e.Items[i].KeyExpr = w(item.KeyExpr).(Expression)
|
||||
e.Items[i].ValueExpr = w(item.ValueExpr).(Expression)
|
||||
for _, item := range e.Items {
|
||||
w(item.KeyExpr)
|
||||
w(item.ValueExpr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -792,7 +792,7 @@ func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) {
|
||||
// We only treat our wrapped expression as a real expression if we're
|
||||
// not going to interpret it as a literal.
|
||||
if e.literalName() == "" {
|
||||
e.Wrapped = w(e.Wrapped).(Expression)
|
||||
w(e.Wrapped)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,7 +1157,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
}
|
||||
|
||||
func (e *ForExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.CollExpr = w(e.CollExpr).(Expression)
|
||||
w(e.CollExpr)
|
||||
|
||||
scopeNames := map[string]struct{}{}
|
||||
if e.KeyVar != "" {
|
||||
@ -1170,17 +1170,17 @@ func (e *ForExpr) walkChildNodes(w internalWalkFunc) {
|
||||
if e.KeyExpr != nil {
|
||||
w(ChildScope{
|
||||
LocalNames: scopeNames,
|
||||
Expr: &e.KeyExpr,
|
||||
Expr: e.KeyExpr,
|
||||
})
|
||||
}
|
||||
w(ChildScope{
|
||||
LocalNames: scopeNames,
|
||||
Expr: &e.ValExpr,
|
||||
Expr: e.ValExpr,
|
||||
})
|
||||
if e.CondExpr != nil {
|
||||
w(ChildScope{
|
||||
LocalNames: scopeNames,
|
||||
Expr: &e.CondExpr,
|
||||
Expr: e.CondExpr,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1266,8 +1266,8 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
}
|
||||
|
||||
func (e *SplatExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Source = w(e.Source).(Expression)
|
||||
e.Each = w(e.Each).(Expression)
|
||||
w(e.Source)
|
||||
w(e.Each)
|
||||
}
|
||||
|
||||
func (e *SplatExpr) Range() hcl.Range {
|
||||
|
@ -129,8 +129,8 @@ type BinaryOpExpr struct {
|
||||
}
|
||||
|
||||
func (e *BinaryOpExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.LHS = w(e.LHS).(Expression)
|
||||
e.RHS = w(e.RHS).(Expression)
|
||||
w(e.LHS)
|
||||
w(e.RHS)
|
||||
}
|
||||
|
||||
func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
@ -212,7 +212,7 @@ type UnaryOpExpr struct {
|
||||
}
|
||||
|
||||
func (e *UnaryOpExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Val = w(e.Val).(Expression)
|
||||
w(e.Val)
|
||||
}
|
||||
|
||||
func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
|
@ -16,8 +16,8 @@ type TemplateExpr struct {
|
||||
}
|
||||
|
||||
func (e *TemplateExpr) walkChildNodes(w internalWalkFunc) {
|
||||
for i, part := range e.Parts {
|
||||
e.Parts[i] = w(part).(Expression)
|
||||
for _, part := range e.Parts {
|
||||
w(part)
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ type TemplateJoinExpr struct {
|
||||
}
|
||||
|
||||
func (e *TemplateJoinExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Tuple = w(e.Tuple).(Expression)
|
||||
w(e.Tuple)
|
||||
}
|
||||
|
||||
func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
@ -184,7 +184,7 @@ type TemplateWrapExpr struct {
|
||||
}
|
||||
|
||||
func (e *TemplateWrapExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Wrapped = w(e.Wrapped).(Expression)
|
||||
w(e.Wrapped)
|
||||
}
|
||||
|
||||
func (e *TemplateWrapExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||
|
@ -19,4 +19,4 @@ type Node interface {
|
||||
Range() hcl.Range
|
||||
}
|
||||
|
||||
type internalWalkFunc func(Node) Node
|
||||
type internalWalkFunc func(Node)
|
||||
|
@ -47,8 +47,8 @@ type Body struct {
|
||||
var assertBodyImplBody hcl.Body = &Body{}
|
||||
|
||||
func (b *Body) walkChildNodes(w internalWalkFunc) {
|
||||
b.Attributes = w(b.Attributes).(Attributes)
|
||||
b.Blocks = w(b.Blocks).(Blocks)
|
||||
w(b.Attributes)
|
||||
w(b.Blocks)
|
||||
}
|
||||
|
||||
func (b *Body) Range() hcl.Range {
|
||||
@ -286,8 +286,8 @@ func (b *Body) MissingItemRange() hcl.Range {
|
||||
type Attributes map[string]*Attribute
|
||||
|
||||
func (a Attributes) walkChildNodes(w internalWalkFunc) {
|
||||
for k, attr := range a {
|
||||
a[k] = w(attr).(*Attribute)
|
||||
for _, attr := range a {
|
||||
w(attr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,7 +321,7 @@ type Attribute struct {
|
||||
}
|
||||
|
||||
func (a *Attribute) walkChildNodes(w internalWalkFunc) {
|
||||
a.Expr = w(a.Expr).(Expression)
|
||||
w(a.Expr)
|
||||
}
|
||||
|
||||
func (a *Attribute) Range() hcl.Range {
|
||||
@ -346,8 +346,8 @@ func (a *Attribute) AsHCLAttribute() *hcl.Attribute {
|
||||
type Blocks []*Block
|
||||
|
||||
func (bs Blocks) walkChildNodes(w internalWalkFunc) {
|
||||
for i, block := range bs {
|
||||
bs[i] = w(block).(*Block)
|
||||
for _, block := range bs {
|
||||
w(block)
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +378,7 @@ type Block struct {
|
||||
}
|
||||
|
||||
func (b *Block) walkChildNodes(w internalWalkFunc) {
|
||||
b.Body = w(b.Body).(*Body)
|
||||
w(b.Body)
|
||||
}
|
||||
|
||||
func (b *Block) Range() hcl.Range {
|
||||
|
@ -72,15 +72,15 @@ func (w *variablesWalker) Exit(n Node) hcl.Diagnostics {
|
||||
// that the child scope struct wraps.
|
||||
type ChildScope struct {
|
||||
LocalNames map[string]struct{}
|
||||
Expr *Expression // pointer because it can be replaced on walk
|
||||
Expr Expression
|
||||
}
|
||||
|
||||
func (e ChildScope) walkChildNodes(w internalWalkFunc) {
|
||||
*(e.Expr) = w(*(e.Expr)).(Expression)
|
||||
w(e.Expr)
|
||||
}
|
||||
|
||||
// Range returns the range of the expression that the ChildScope is
|
||||
// encapsulating. It isn't really very useful to call Range on a ChildScope.
|
||||
func (e ChildScope) Range() hcl.Range {
|
||||
return (*e.Expr).Range()
|
||||
return e.Expr.Range()
|
||||
}
|
||||
|
@ -15,9 +15,8 @@ type VisitFunc func(node Node) hcl.Diagnostics
|
||||
// and returned as a single set.
|
||||
func VisitAll(node Node, f VisitFunc) hcl.Diagnostics {
|
||||
diags := f(node)
|
||||
node.walkChildNodes(func(node Node) Node {
|
||||
node.walkChildNodes(func(node Node) {
|
||||
diags = append(diags, VisitAll(node, f)...)
|
||||
return node
|
||||
})
|
||||
return diags
|
||||
}
|
||||
@ -33,47 +32,10 @@ type Walker interface {
|
||||
// Enter and Exit functions.
|
||||
func Walk(node Node, w Walker) hcl.Diagnostics {
|
||||
diags := w.Enter(node)
|
||||
node.walkChildNodes(func(node Node) Node {
|
||||
node.walkChildNodes(func(node Node) {
|
||||
diags = append(diags, Walk(node, w)...)
|
||||
return node
|
||||
})
|
||||
moreDiags := w.Exit(node)
|
||||
diags = append(diags, moreDiags...)
|
||||
return diags
|
||||
}
|
||||
|
||||
// Transformer is an interface used with Transform
|
||||
type Transformer interface {
|
||||
// Transform accepts a node and returns a replacement node along with
|
||||
// a flag for whether to also visit child nodes. If the flag is false,
|
||||
// none of the child nodes will be visited and the TransformExit method
|
||||
// will not be called for the node.
|
||||
//
|
||||
// It is acceptable and appropriate for Transform to return the same node
|
||||
// it was given, for situations where no transform is needed.
|
||||
Transform(node Node) (Node, bool, hcl.Diagnostics)
|
||||
|
||||
// TransformExit signals the end of transformations of child nodes of the
|
||||
// given node. If Transform returned a new node, the given node is the
|
||||
// node that was returned, rather than the node that was originally
|
||||
// encountered.
|
||||
TransformExit(node Node) hcl.Diagnostics
|
||||
}
|
||||
|
||||
// Transform allows for in-place transformations of an AST starting with a
|
||||
// particular node. The provider Transformer implementation drives the
|
||||
// transformation process. The return value is the node that replaced the
|
||||
// given top-level node.
|
||||
func Transform(node Node, t Transformer) (Node, hcl.Diagnostics) {
|
||||
newNode, descend, diags := t.Transform(node)
|
||||
if !descend {
|
||||
return newNode, diags
|
||||
}
|
||||
node.walkChildNodes(func(node Node) Node {
|
||||
newNode, newDiags := Transform(node, t)
|
||||
diags = append(diags, newDiags...)
|
||||
return newNode
|
||||
})
|
||||
diags = append(diags, t.TransformExit(newNode)...)
|
||||
return newNode, diags
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user