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 }