69 lines
2.4 KiB
Go
69 lines
2.4 KiB
Go
|
package hcl
|
||
|
|
||
|
type unwrapExpression interface {
|
||
|
UnwrapExpression() Expression
|
||
|
}
|
||
|
|
||
|
// UnwrapExpression removes any "wrapper" expressions from the given expression,
|
||
|
// to recover the representation of the physical expression given in source
|
||
|
// code.
|
||
|
//
|
||
|
// Sometimes wrapping expressions are used to modify expression behavior, e.g.
|
||
|
// in extensions that need to make some local variables available to certain
|
||
|
// sub-trees of the configuration. This can make it difficult to reliably
|
||
|
// type-assert on the physical AST types used by the underlying syntax.
|
||
|
//
|
||
|
// Unwrapping an expression may modify its behavior by stripping away any
|
||
|
// additional constraints or capabilities being applied to the Value and
|
||
|
// Variables methods, so this function should generally only be used prior
|
||
|
// to operations that concern themselves with the static syntax of the input
|
||
|
// configuration, and not with the effective value of the expression.
|
||
|
//
|
||
|
// Wrapper expression types must support unwrapping by implementing a method
|
||
|
// called UnwrapExpression that takes no arguments and returns the embedded
|
||
|
// Expression. Implementations of this method should peel away only one level
|
||
|
// of wrapping, if multiple are present. This method may return nil to
|
||
|
// indicate _dynamically_ that no wrapped expression is available, for
|
||
|
// expression types that might only behave as wrappers in certain cases.
|
||
|
func UnwrapExpression(expr Expression) Expression {
|
||
|
for {
|
||
|
unwrap, wrapped := expr.(unwrapExpression)
|
||
|
if !wrapped {
|
||
|
return expr
|
||
|
}
|
||
|
innerExpr := unwrap.UnwrapExpression()
|
||
|
if innerExpr == nil {
|
||
|
return expr
|
||
|
}
|
||
|
expr = innerExpr
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// UnwrapExpressionUntil is similar to UnwrapExpression except it gives the
|
||
|
// caller an opportunity to test each level of unwrapping to see each a
|
||
|
// particular expression is accepted.
|
||
|
//
|
||
|
// This could be used, for example, to unwrap until a particular other
|
||
|
// interface is satisfied, regardless of wrap wrapping level it is satisfied
|
||
|
// at.
|
||
|
//
|
||
|
// The given callback function must return false to continue wrapping, or
|
||
|
// true to accept and return the proposed expression given. If the callback
|
||
|
// function rejects even the final, physical expression then the result of
|
||
|
// this function is nil.
|
||
|
func UnwrapExpressionUntil(expr Expression, until func(Expression) bool) Expression {
|
||
|
for {
|
||
|
if until(expr) {
|
||
|
return expr
|
||
|
}
|
||
|
unwrap, wrapped := expr.(unwrapExpression)
|
||
|
if !wrapped {
|
||
|
return nil
|
||
|
}
|
||
|
expr = unwrap.UnwrapExpression()
|
||
|
if expr == nil {
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
}
|