| 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 |
| } |
| } |
| } |