Lines Matching +full:function +full:- +full:bind
2 // Use of this source code is governed by a BSD-style
5 // Package resolve defines a name-resolution pass for Starlark abstract
11 // bound by top-level comprehensions and load statements.
16 // predeclared, global, or local to a function or file.
17 // File-local variables include those bound by top-level comprehensions
18 // and by load statements. ("Top-level" means "outside of any function".)
24 // either universal (e.g. None, len) or per-module (e.g. glob in Bazel's
33 // Python-style resolution requires multiple passes because a name is
34 // determined to be local to a function only if the function contains a
36 // opposed to predeclared) if the module contains a top-level binding use.
37 // Unlike ordinary top-level assignments, the bindings created by load
39 // A non-binding use may lexically precede the binding to which it is resolved.
40 // In the first pass, we inspect each function, recording in
42 // If a use of a name is binding, such as a function parameter or
44 // local variable to the enclosing function.
46 // As we finish resolving each function, we inspect all the uses within
47 // that function and discard ones that were found to be function-local. The
49 // function), or top-level (global, predeclared, or file-local), but we cannot tell
51 // function. At that point, we can distinguish local from top-level names
56 // Starlark permits a function to forward-reference a global or file-local
59 // module. So, instead of re-resolving the unresolved references after
60 // each top-level function, we defer this until the end of the module
63 // At the end of the module, we visit each of the nested function blocks
64 // in bottom-up order, doing a recursive lexical lookup for each
66 // function, we must create a DefStmt.FreeVar (capture) parameter for
67 // each intervening function. We enter these synthetic bindings into
79 // top-level reassign) makes the resolver allow multiple to a variable
80 // at top-level. It also allows if-, for-, and while-loops at top-level,
82 // values to a variable at top-level. (These two roles should be separated.)
101 AllowSet = false // allow the 'set' built-in
102 …owGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top…
104 LoadBindsGlobally = false // load creates global not file-local bindings (deprecated)
117 // a pre-declared identifier (visible in the current module) or a
122 // standard set of built-ins.
130 // REPLChunk is a generalization of the File function that supports a
131 // non-empty initial global block, as occurs in a REPL.
138 // At the end of the module, resolve all non-local variable references,
140 // Function bodies may contain forward references to later global declarations.
157 // The isPredeclared and isUniversal predicates behave as for the File function.
169 // An ErrorList is a non-empty list of resolver error messages.
203 // (due to load statements and comprehensions outside any function).
214 // pre-declared, either in this module or universally,
226 // a function (function != nil) or file (function == nil).
230 if b.function != nil || b == r.file {
248 function *Function // only for function blocks member
253 // A free binding has an index into its innermost enclosing function's freevars array.
259 // uses records all identifiers seen in this container (function or file),
263 // At the end of each top-level function we compute closures.
267 func (b *block) bind(name string, bind *Binding) { func
271 b.bindings[name] = bind
275 if b.function != nil {
276 return "function block at " + fmt.Sprint(b.function.Pos)
294 // bind creates a binding for id: a global (not file-local)
295 // binding at top-level, a local binding otherwise.
296 // At top-level, it reports an error if a global or file-local
300 func (r *resolver) bind(id *syntax.Ident) bool { func
301 // Binding outside any local (comprehension/function) block?
303 bind, ok := r.file.bindings[id.Name]
305 bind, ok = r.globals[id.Name]
308 bind = &Binding{
313 r.globals[id.Name] = bind
314 r.moduleGlobals = append(r.moduleGlobals, bind)
319 bind.Scope, id.Name, bind.First.NamePos)
321 id.Binding = bind
334 if fn := r.container().function; fn != nil {
339 bind := &Binding{
344 r.env.bind(id.Name, bind)
345 *locals = append(*locals, bind)
357 // global, even if the use precedes the def---just as for locals.
363 // completely shadows the predeclared len function.
374 // to the predeclared function. This typically used in a BUILD
378 // proto_library(...) # built-in rule
380 // proto_library(...) # user-defined rule
394 // useToplevel resolves use.id as a reference to a name visible at top-level.
396 func (r *resolver) useToplevel(use use) (bind *Binding) {
400 // use of load-defined name in file block
401 bind = prev
404 bind = prev
407 bind = &Binding{
412 r.globals[id.Name] = bind
413 r.moduleGlobals = append(r.moduleGlobals, bind)
416 bind = prev
418 // use of pre-declared name
419 bind = &Binding{Scope: Predeclared}
420 r.predeclared[id.Name] = bind // save it
426 bind = &Binding{Scope: Universal}
427 r.predeclared[id.Name] = bind // save it
429 bind = &Binding{Scope: Undefined}
436 id.Binding = bind
437 return bind
457 for _, bind := range r.moduleGlobals {
458 names = append(names, bind.First.Name)
465 // resolveLocalUses is called when leaving a container (function/module)
470 if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) {
471 use.id.Binding = bind
496 if !AllowGlobalReassign && r.container().function == nil {
497 r.errorf(stmt.If, "if statement not within a function")
503 r.ifstmts--
511 r.bind(stmt.Name)
512 fn := &Function{
518 stmt.Function = fn
519 r.function(fn, stmt.Def)
522 if !AllowGlobalReassign && r.container().function == nil {
523 r.errorf(stmt.For, "for loop not within a function")
530 r.loops--
536 if !AllowGlobalReassign && r.container().function == nil {
537 r.errorf(stmt.While, "while loop not within a function")
542 r.loops--
545 if r.container().function == nil {
546 r.errorf(stmt.Return, "return statement not within a function")
554 if r.container().function != nil {
555 r.errorf(stmt.Load, "load statement within a function")
573 r.bind(id)
578 r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
591 r.bind(lhs)
675 // enclosing container (function/module) block.
771 // Fail gracefully if compiler-imposed limit is exceeded.
782 fn := &Function{
788 e.Function = fn
789 r.function(fn, e.Lambda)
799 func (r *resolver) function(function *Function, pos syntax.Position) { func
801 for _, param := range function.Params {
807 // Enter function block.
808 b := &block{function: function}
815 for _, param := range function.Params {
826 if r.bind(param) {
837 if id := param.X.(*syntax.Ident); r.bind(id) {
861 // Bind the *args and **kwargs parameters at the end,
869 if r.bind(id) {
872 function.HasVarargs = true
874 r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters")
878 if r.bind(starStar) {
881 function.HasKwargs = true
884 function.NumKwonlyParams = numKwonlyParams
885 r.stmts(function.Body)
887 // Resolve all uses of this function's local vars,
891 // Leave function block.
894 // References within the function body to globals are not
908 // lookupLocal looks up an identifier within its immediately enclosing function.
911 if bind, ok := env.bindings[use.id.Name]; ok {
912 if bind.Scope == Free {
914 log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind)
916 return bind // found
918 if env.function != nil {
922 return nil // not found in this function
927 func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) {
930 defer func() { fmt.Printf("= %v\n", bind) }()
935 return r.useToplevel(use) // file-local, global, predeclared, or not found
939 bind, ok := env.bindings[use.id.Name]
942 bind = r.lookupLexical(use, env.parent)
943 if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) {
944 // Found in parent block, which belongs to enclosing function.
945 // Add the parent's binding to the function's freevars,
946 // and add a new 'free' binding to the inner function's block,
948 if bind.Scope == Local {
949 bind.Scope = Cell
951 index := len(env.function.FreeVars)
952 env.function.FreeVars = append(env.function.FreeVars, bind)
953 bind = &Binding{
954 First: bind.First,
959 fmt.Printf("creating freevar %v in function at %s: %s\n",
960 len(env.function.FreeVars), env.function.Pos, use.id.Name)
966 env.bind(use.id.Name, bind)
968 return bind