github.com/franklinhu/terraform@v0.6.9-0.20151202232446-81f7fb1e6f9e/config/lang/check_identifier.go (about)

     1  package lang
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/hashicorp/terraform/config/lang/ast"
     8  )
     9  
    10  // IdentifierCheck is a SemanticCheck that checks that all identifiers
    11  // resolve properly and that the right number of arguments are passed
    12  // to functions.
    13  type IdentifierCheck struct {
    14  	Scope ast.Scope
    15  
    16  	err  error
    17  	lock sync.Mutex
    18  }
    19  
    20  func (c *IdentifierCheck) Visit(root ast.Node) error {
    21  	c.lock.Lock()
    22  	defer c.lock.Unlock()
    23  	defer c.reset()
    24  	root.Accept(c.visit)
    25  	return c.err
    26  }
    27  
    28  func (c *IdentifierCheck) visit(raw ast.Node) ast.Node {
    29  	if c.err != nil {
    30  		return raw
    31  	}
    32  
    33  	switch n := raw.(type) {
    34  	case *ast.Call:
    35  		c.visitCall(n)
    36  	case *ast.VariableAccess:
    37  		c.visitVariableAccess(n)
    38  	case *ast.Concat:
    39  		// Ignore
    40  	case *ast.LiteralNode:
    41  		// Ignore
    42  	default:
    43  		// Ignore
    44  	}
    45  
    46  	// We never do replacement with this visitor
    47  	return raw
    48  }
    49  
    50  func (c *IdentifierCheck) visitCall(n *ast.Call) {
    51  	// Look up the function in the map
    52  	function, ok := c.Scope.LookupFunc(n.Func)
    53  	if !ok {
    54  		c.createErr(n, fmt.Sprintf("unknown function called: %s", n.Func))
    55  		return
    56  	}
    57  
    58  	// Break up the args into what is variadic and what is required
    59  	args := n.Args
    60  	if function.Variadic && len(args) > len(function.ArgTypes) {
    61  		args = n.Args[:len(function.ArgTypes)]
    62  	}
    63  
    64  	// Verify the number of arguments
    65  	if len(args) != len(function.ArgTypes) {
    66  		c.createErr(n, fmt.Sprintf(
    67  			"%s: expected %d arguments, got %d",
    68  			n.Func, len(function.ArgTypes), len(n.Args)))
    69  		return
    70  	}
    71  }
    72  
    73  func (c *IdentifierCheck) visitVariableAccess(n *ast.VariableAccess) {
    74  	// Look up the variable in the map
    75  	if _, ok := c.Scope.LookupVar(n.Name); !ok {
    76  		c.createErr(n, fmt.Sprintf(
    77  			"unknown variable accessed: %s", n.Name))
    78  		return
    79  	}
    80  }
    81  
    82  func (c *IdentifierCheck) createErr(n ast.Node, str string) {
    83  	c.err = fmt.Errorf("%s: %s", n.Pos(), str)
    84  }
    85  
    86  func (c *IdentifierCheck) reset() {
    87  	c.err = nil
    88  }