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