]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package hcl |
2 | ||
3 | type unwrapExpression interface { | |
4 | UnwrapExpression() Expression | |
5 | } | |
6 | ||
7 | // UnwrapExpression removes any "wrapper" expressions from the given expression, | |
8 | // to recover the representation of the physical expression given in source | |
9 | // code. | |
10 | // | |
11 | // Sometimes wrapping expressions are used to modify expression behavior, e.g. | |
12 | // in extensions that need to make some local variables available to certain | |
13 | // sub-trees of the configuration. This can make it difficult to reliably | |
14 | // type-assert on the physical AST types used by the underlying syntax. | |
15 | // | |
16 | // Unwrapping an expression may modify its behavior by stripping away any | |
17 | // additional constraints or capabilities being applied to the Value and | |
18 | // Variables methods, so this function should generally only be used prior | |
19 | // to operations that concern themselves with the static syntax of the input | |
20 | // configuration, and not with the effective value of the expression. | |
21 | // | |
22 | // Wrapper expression types must support unwrapping by implementing a method | |
23 | // called UnwrapExpression that takes no arguments and returns the embedded | |
24 | // Expression. Implementations of this method should peel away only one level | |
25 | // of wrapping, if multiple are present. This method may return nil to | |
26 | // indicate _dynamically_ that no wrapped expression is available, for | |
27 | // expression types that might only behave as wrappers in certain cases. | |
28 | func UnwrapExpression(expr Expression) Expression { | |
29 | for { | |
30 | unwrap, wrapped := expr.(unwrapExpression) | |
31 | if !wrapped { | |
32 | return expr | |
33 | } | |
34 | innerExpr := unwrap.UnwrapExpression() | |
35 | if innerExpr == nil { | |
36 | return expr | |
37 | } | |
38 | expr = innerExpr | |
39 | } | |
40 | } | |
41 | ||
42 | // UnwrapExpressionUntil is similar to UnwrapExpression except it gives the | |
43 | // caller an opportunity to test each level of unwrapping to see each a | |
44 | // particular expression is accepted. | |
45 | // | |
46 | // This could be used, for example, to unwrap until a particular other | |
47 | // interface is satisfied, regardless of wrap wrapping level it is satisfied | |
48 | // at. | |
49 | // | |
50 | // The given callback function must return false to continue wrapping, or | |
51 | // true to accept and return the proposed expression given. If the callback | |
52 | // function rejects even the final, physical expression then the result of | |
53 | // this function is nil. | |
54 | func UnwrapExpressionUntil(expr Expression, until func(Expression) bool) Expression { | |
55 | for { | |
56 | if until(expr) { | |
57 | return expr | |
58 | } | |
59 | unwrap, wrapped := expr.(unwrapExpression) | |
60 | if !wrapped { | |
61 | return nil | |
62 | } | |
63 | expr = unwrap.UnwrapExpression() | |
64 | if expr == nil { | |
65 | return nil | |
66 | } | |
67 | } | |
68 | } |