github.com/hashicorp/hcl/v2@v2.20.0/expr_unwrap.go (about)

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