github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/config/lang/eval.go (about)

     1  package lang
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/hashicorp/terraform/config/lang/ast"
     9  )
    10  
    11  // EvalConfig is the configuration for evaluating.
    12  type EvalConfig struct {
    13  	// GlobalScope is the global scope of execution for evaluation.
    14  	GlobalScope *ast.BasicScope
    15  
    16  	// SemanticChecks is a list of additional semantic checks that will be run
    17  	// on the tree prior to evaluating it. The type checker, identifier checker,
    18  	// etc. will be run before these automatically.
    19  	SemanticChecks []SemanticChecker
    20  }
    21  
    22  // SemanticChecker is the type that must be implemented to do a
    23  // semantic check on an AST tree. This will be called with the root node.
    24  type SemanticChecker func(ast.Node) error
    25  
    26  // Eval evaluates the given AST tree and returns its output value, the type
    27  // of the output, and any error that occurred.
    28  func Eval(root ast.Node, config *EvalConfig) (interface{}, ast.Type, error) {
    29  	// Copy the scope so we can add our builtins
    30  	if config == nil {
    31  		config = new(EvalConfig)
    32  	}
    33  	scope := registerBuiltins(config.GlobalScope)
    34  	implicitMap := map[ast.Type]map[ast.Type]string{
    35  		ast.TypeFloat: {
    36  			ast.TypeInt:    "__builtin_FloatToInt",
    37  			ast.TypeString: "__builtin_FloatToString",
    38  		},
    39  		ast.TypeInt: {
    40  			ast.TypeFloat:  "__builtin_IntToFloat",
    41  			ast.TypeString: "__builtin_IntToString",
    42  		},
    43  		ast.TypeString: {
    44  			ast.TypeInt: "__builtin_StringToInt",
    45  		},
    46  	}
    47  
    48  	// Build our own semantic checks that we always run
    49  	tv := &TypeCheck{Scope: scope, Implicit: implicitMap}
    50  	ic := &IdentifierCheck{Scope: scope}
    51  
    52  	// Build up the semantic checks for execution
    53  	checks := make(
    54  		[]SemanticChecker,
    55  		len(config.SemanticChecks),
    56  		len(config.SemanticChecks)+2)
    57  	copy(checks, config.SemanticChecks)
    58  	checks = append(checks, ic.Visit)
    59  	checks = append(checks, tv.Visit)
    60  
    61  	// Run the semantic checks
    62  	for _, check := range checks {
    63  		if err := check(root); err != nil {
    64  			return nil, ast.TypeInvalid, err
    65  		}
    66  	}
    67  
    68  	// Execute
    69  	v := &evalVisitor{Scope: scope}
    70  	return v.Visit(root)
    71  }
    72  
    73  // EvalNode is the interface that must be implemented by any ast.Node
    74  // to support evaluation. This will be called in visitor pattern order.
    75  // The result of each call to Eval is automatically pushed onto the
    76  // stack as a LiteralNode. Pop elements off the stack to get child
    77  // values.
    78  type EvalNode interface {
    79  	Eval(ast.Scope, *ast.Stack) (interface{}, ast.Type, error)
    80  }
    81  
    82  type evalVisitor struct {
    83  	Scope ast.Scope
    84  	Stack ast.Stack
    85  
    86  	err  error
    87  	lock sync.Mutex
    88  }
    89  
    90  func (v *evalVisitor) Visit(root ast.Node) (interface{}, ast.Type, error) {
    91  	// Run the actual visitor pattern
    92  	root.Accept(v.visit)
    93  
    94  	// Get our result and clear out everything else
    95  	var result *ast.LiteralNode
    96  	if v.Stack.Len() > 0 {
    97  		result = v.Stack.Pop().(*ast.LiteralNode)
    98  	} else {
    99  		result = new(ast.LiteralNode)
   100  	}
   101  	resultErr := v.err
   102  
   103  	// Clear everything else so we aren't just dangling
   104  	v.Stack.Reset()
   105  	v.err = nil
   106  
   107  	t, err := result.Type(v.Scope)
   108  	if err != nil {
   109  		return nil, ast.TypeInvalid, err
   110  	}
   111  
   112  	return result.Value, t, resultErr
   113  }
   114  
   115  func (v *evalVisitor) visit(raw ast.Node) ast.Node {
   116  	if v.err != nil {
   117  		return raw
   118  	}
   119  
   120  	en, err := evalNode(raw)
   121  	if err != nil {
   122  		v.err = err
   123  		return raw
   124  	}
   125  
   126  	out, outType, err := en.Eval(v.Scope, &v.Stack)
   127  	if err != nil {
   128  		v.err = err
   129  		return raw
   130  	}
   131  
   132  	v.Stack.Push(&ast.LiteralNode{
   133  		Value: out,
   134  		Typex: outType,
   135  	})
   136  	return raw
   137  }
   138  
   139  // evalNode is a private function that returns an EvalNode for built-in
   140  // types as well as any other EvalNode implementations.
   141  func evalNode(raw ast.Node) (EvalNode, error) {
   142  	switch n := raw.(type) {
   143  	case *ast.Call:
   144  		return &evalCall{n}, nil
   145  	case *ast.Concat:
   146  		return &evalConcat{n}, nil
   147  	case *ast.LiteralNode:
   148  		return &evalLiteralNode{n}, nil
   149  	case *ast.VariableAccess:
   150  		return &evalVariableAccess{n}, nil
   151  	default:
   152  		en, ok := n.(EvalNode)
   153  		if !ok {
   154  			return nil, fmt.Errorf("node doesn't support evaluation: %#v", raw)
   155  		}
   156  
   157  		return en, nil
   158  	}
   159  }
   160  
   161  type evalCall struct{ *ast.Call }
   162  
   163  func (v *evalCall) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) {
   164  	// Look up the function in the map
   165  	function, ok := s.LookupFunc(v.Func)
   166  	if !ok {
   167  		return nil, ast.TypeInvalid, fmt.Errorf(
   168  			"unknown function called: %s", v.Func)
   169  	}
   170  
   171  	// The arguments are on the stack in reverse order, so pop them off.
   172  	args := make([]interface{}, len(v.Args))
   173  	for i, _ := range v.Args {
   174  		node := stack.Pop().(*ast.LiteralNode)
   175  		args[len(v.Args)-1-i] = node.Value
   176  	}
   177  
   178  	// Call the function
   179  	result, err := function.Callback(args)
   180  	if err != nil {
   181  		return nil, ast.TypeInvalid, fmt.Errorf("%s: %s", v.Func, err)
   182  	}
   183  
   184  	return result, function.ReturnType, nil
   185  }
   186  
   187  type evalConcat struct{ *ast.Concat }
   188  
   189  func (v *evalConcat) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) {
   190  	// The expressions should all be on the stack in reverse
   191  	// order. So pop them off, reverse their order, and concatenate.
   192  	nodes := make([]*ast.LiteralNode, 0, len(v.Exprs))
   193  	for range v.Exprs {
   194  		nodes = append(nodes, stack.Pop().(*ast.LiteralNode))
   195  	}
   196  
   197  	var buf bytes.Buffer
   198  	for i := len(nodes) - 1; i >= 0; i-- {
   199  		buf.WriteString(nodes[i].Value.(string))
   200  	}
   201  
   202  	return buf.String(), ast.TypeString, nil
   203  }
   204  
   205  type evalLiteralNode struct{ *ast.LiteralNode }
   206  
   207  func (v *evalLiteralNode) Eval(ast.Scope, *ast.Stack) (interface{}, ast.Type, error) {
   208  	return v.Value, v.Typex, nil
   209  }
   210  
   211  type evalVariableAccess struct{ *ast.VariableAccess }
   212  
   213  func (v *evalVariableAccess) Eval(scope ast.Scope, _ *ast.Stack) (interface{}, ast.Type, error) {
   214  	// Look up the variable in the map
   215  	variable, ok := scope.LookupVar(v.Name)
   216  	if !ok {
   217  		return nil, ast.TypeInvalid, fmt.Errorf(
   218  			"unknown variable accessed: %s", v.Name)
   219  	}
   220  
   221  	return variable.Value, variable.Type, nil
   222  }