blob: 56e33ba52c47040c67b38009c692f125d98fbe13 [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001// Copyright 2017 The Bazel Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Alan Donovane3deafe2018-10-23 11:05:09 -04005// Package resolve defines a name-resolution pass for Starlark abstract
Alan Donovan312d1a52017-10-02 10:10:28 -04006// syntax trees.
7//
8// The resolver sets the Locals and FreeVars arrays of each DefStmt and
9// the LocalIndex field of each syntax.Ident that refers to a local or
10// free variable. It also sets the Locals array of a File for locals
alandonovan754257e2019-04-03 16:43:05 -040011// bound by top-level comprehensions and load statements.
12// Identifiers for global variables do not get an index.
Alan Donovan551f3002018-11-01 09:44:00 -040013package resolve // import "go.starlark.net/resolve"
Alan Donovan312d1a52017-10-02 10:10:28 -040014
15// All references to names are statically resolved. Names may be
alandonovan754257e2019-04-03 16:43:05 -040016// 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".)
alandonovana1b28d82018-03-13 10:59:24 -040019// The resolver maps each global name to a small integer and each local
20// name to a small integer; these integers enable a fast and compact
21// representation of globals and locals in the evaluator.
22//
23// As an optimization, the resolver classifies each predeclared name as
24// either universal (e.g. None, len) or per-module (e.g. glob in Bazel's
25// build language), enabling the evaluator to share the representation
26// of the universal environment across all modules.
Alan Donovan312d1a52017-10-02 10:10:28 -040027//
alandonovan754257e2019-04-03 16:43:05 -040028// The lexical environment is a tree of blocks with the file block at
29// its root. The file's child blocks may be of two kinds: functions
Alan Donovan312d1a52017-10-02 10:10:28 -040030// and comprehensions, and these may have further children of either
31// kind.
32//
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
alandonovan754257e2019-04-03 16:43:05 -040035// "binding" use of it; similarly, a name is determined to be global (as
36// opposed to predeclared) if the module contains a top-level binding use.
37// Unlike ordinary top-level assignments, the bindings created by load
38// statements are local to the file block.
39// A non-binding use may lexically precede the binding to which it is resolved.
alandonovan4956ce92018-08-22 17:44:47 -040040// In the first pass, we inspect each function, recording in
Alan Donovan312d1a52017-10-02 10:10:28 -040041// 'uses' each identifier and the environment block in which it occurs.
42// If a use of a name is binding, such as a function parameter or
43// assignment, we add the name to the block's bindings mapping and add a
44// local variable to the enclosing function.
45//
46// As we finish resolving each function, we inspect all the uses within
alandonovan754257e2019-04-03 16:43:05 -040047// that function and discard ones that were found to be function-local. The
Alan Donovan312d1a52017-10-02 10:10:28 -040048// remaining ones must be either free (local to some lexically enclosing
alandonovan754257e2019-04-03 16:43:05 -040049// function), or top-level (global, predeclared, or file-local), but we cannot tell
alandonovana1b28d82018-03-13 10:59:24 -040050// which until we have finished inspecting the outermost enclosing
alandonovan754257e2019-04-03 16:43:05 -040051// function. At that point, we can distinguish local from top-level names
alandonovana1b28d82018-03-13 10:59:24 -040052// (and this is when Python would compute free variables).
Alan Donovan312d1a52017-10-02 10:10:28 -040053//
Alan Donovane3deafe2018-10-23 11:05:09 -040054// However, Starlark additionally requires that all references to global
Alan Donovan312d1a52017-10-02 10:10:28 -040055// names are satisfied by some declaration in the current module;
alandonovan754257e2019-04-03 16:43:05 -040056// Starlark permits a function to forward-reference a global or file-local
57// that has not
Alan Donovan312d1a52017-10-02 10:10:28 -040058// been declared yet so long as it is declared before the end of the
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
61// and ensure that all such references are satisfied by some definition.
62//
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
65// unresolved name. If the name is found to be local to some enclosing
66// function, we must create a DefStmt.FreeVar (capture) parameter for
67// each intervening function. We enter these synthetic bindings into
68// the bindings map so that we create at most one freevar per name. If
69// the name was not local, we check that it was defined at module level.
70//
alandonovan754257e2019-04-03 16:43:05 -040071// We resolve all uses of locals in the module (due to load statements
72// and comprehensions) in a similar way and compute the file's set of
73// local variables.
Alan Donovan312d1a52017-10-02 10:10:28 -040074//
Alan Donovane3deafe2018-10-23 11:05:09 -040075// Starlark enforces that all global names are assigned at most once on
Alan Donovan312d1a52017-10-02 10:10:28 -040076// all control flow paths by forbidding if/else statements and loops at
alandonovan4956ce92018-08-22 17:44:47 -040077// top level. A global may be used before it is defined, leading to a
alandonovan754257e2019-04-03 16:43:05 -040078// dynamic error. However, the AllowGlobalReassign flag (really: allow
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,
81// which in turn may make the evaluator dynamically assign multiple
82// values to a variable at top-level. (These two roles should be separated.)
Alan Donovan312d1a52017-10-02 10:10:28 -040083
84import (
85 "fmt"
86 "log"
alandonovan6afa1bb2019-02-06 17:49:05 -050087 "sort"
Alan Donovan312d1a52017-10-02 10:10:28 -040088 "strings"
89
alandonovan6afa1bb2019-02-06 17:49:05 -050090 "go.starlark.net/internal/spell"
Alan Donovan6beab7e2018-10-31 17:53:09 -040091 "go.starlark.net/syntax"
Alan Donovan312d1a52017-10-02 10:10:28 -040092)
93
94const debug = false
Alan Donovane3deafe2018-10-23 11:05:09 -040095const doesnt = "this Starlark dialect does not "
Alan Donovan312d1a52017-10-02 10:10:28 -040096
97// global options
Alan Donovane3deafe2018-10-23 11:05:09 -040098// These features are either not standard Starlark (yet), or deprecated
Alan Donovan312d1a52017-10-02 10:10:28 -040099// features of the BUILD language, so we put them behind flags.
100var (
Alan Donovan312d1a52017-10-02 10:10:28 -0400101 AllowSet = false // allow the 'set' built-in
alandonovan754257e2019-04-03 16:43:05 -0400102 AllowGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top-level
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100103 AllowRecursion = false // allow while statements and recursive functions
alandonovan754257e2019-04-03 16:43:05 -0400104 LoadBindsGlobally = false // load creates global not file-local bindings (deprecated)
alandonovancea917a2021-01-21 17:58:09 -0500105
106 // obsolete flags for features that are now standard. No effect.
107 AllowNestedDef = true
108 AllowLambda = true
109 AllowFloat = true
110 AllowBitwise = true
Alan Donovan312d1a52017-10-02 10:10:28 -0400111)
112
alandonovan6ddc71c2019-06-04 09:08:55 -0400113// File resolves the specified file and records information about the
114// module in file.Module.
alandonovan631f7b52017-10-11 13:04:47 -0400115//
alandonovana1b28d82018-03-13 10:59:24 -0400116// The isPredeclared and isUniversal predicates report whether a name is
117// a pre-declared identifier (visible in the current module) or a
118// universal identifier (visible in every module).
119// Clients should typically pass predeclared.Has for the first and
Alan Donovane3deafe2018-10-23 11:05:09 -0400120// starlark.Universe.Has for the second, where predeclared is the
121// module's StringDict of predeclared names and starlark.Universe is the
alandonovana1b28d82018-03-13 10:59:24 -0400122// standard set of built-ins.
123// The isUniverse predicate is supplied a parameter to avoid a cyclic
Alan Donovane3deafe2018-10-23 11:05:09 -0400124// dependency upon starlark.Universe, not because users should ever need
alandonovana1b28d82018-03-13 10:59:24 -0400125// to redefine it.
126func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error {
alandonovan28350e62019-10-21 14:58:36 -0400127 return REPLChunk(file, nil, isPredeclared, isUniversal)
128}
129
130// REPLChunk is a generalization of the File function that supports a
131// non-empty initial global block, as occurs in a REPL.
132func REPLChunk(file *syntax.File, isGlobal, isPredeclared, isUniversal func(name string) bool) error {
133 r := newResolver(isGlobal, isPredeclared, isUniversal)
Alan Donovan312d1a52017-10-02 10:10:28 -0400134 r.stmts(file.Stmts)
135
136 r.env.resolveLocalUses()
137
138 // At the end of the module, resolve all non-local variable references,
139 // computing closures.
140 // Function bodies may contain forward references to later global declarations.
141 r.resolveNonLocalUses(r.env)
142
alandonovan6ddc71c2019-06-04 09:08:55 -0400143 file.Module = &Module{
144 Locals: r.moduleLocals,
145 Globals: r.moduleGlobals,
146 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400147
148 if len(r.errors) > 0 {
149 return r.errors
150 }
151 return nil
152}
153
154// Expr resolves the specified expression.
155// It returns the local variables bound within the expression.
alandonovan631f7b52017-10-11 13:04:47 -0400156//
alandonovana1b28d82018-03-13 10:59:24 -0400157// The isPredeclared and isUniversal predicates behave as for the File function.
alandonovan6db5e162019-03-11 12:31:47 -0400158func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
alandonovan28350e62019-10-21 14:58:36 -0400159 r := newResolver(nil, isPredeclared, isUniversal)
Alan Donovan312d1a52017-10-02 10:10:28 -0400160 r.expr(expr)
161 r.env.resolveLocalUses()
alandonovan631f7b52017-10-11 13:04:47 -0400162 r.resolveNonLocalUses(r.env) // globals & universals
Alan Donovan312d1a52017-10-02 10:10:28 -0400163 if len(r.errors) > 0 {
164 return nil, r.errors
165 }
166 return r.moduleLocals, nil
167}
168
169// An ErrorList is a non-empty list of resolver error messages.
170type ErrorList []Error // len > 0
171
172func (e ErrorList) Error() string { return e[0].Error() }
173
174// An Error describes the nature and position of a resolver error.
175type Error struct {
176 Pos syntax.Position
177 Msg string
178}
179
180func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg }
181
alandonovan28350e62019-10-21 14:58:36 -0400182func newResolver(isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver {
alandonovan754257e2019-04-03 16:43:05 -0400183 file := new(block)
Alan Donovan312d1a52017-10-02 10:10:28 -0400184 return &resolver{
alandonovan754257e2019-04-03 16:43:05 -0400185 file: file,
186 env: file,
alandonovan28350e62019-10-21 14:58:36 -0400187 isGlobal: isGlobal,
alandonovana1b28d82018-03-13 10:59:24 -0400188 isPredeclared: isPredeclared,
189 isUniversal: isUniversal,
alandonovan6db5e162019-03-11 12:31:47 -0400190 globals: make(map[string]*Binding),
191 predeclared: make(map[string]*Binding),
Alan Donovan312d1a52017-10-02 10:10:28 -0400192 }
193}
194
195type resolver struct {
196 // env is the current local environment:
197 // a linked list of blocks, innermost first.
alandonovan754257e2019-04-03 16:43:05 -0400198 // The tail of the list is the file block.
199 env *block
200 file *block // file block (contains load bindings)
Alan Donovan312d1a52017-10-02 10:10:28 -0400201
202 // moduleLocals contains the local variables of the module
alandonovan754257e2019-04-03 16:43:05 -0400203 // (due to load statements and comprehensions outside any function).
alandonovana1b28d82018-03-13 10:59:24 -0400204 // moduleGlobals contains the global variables of the module.
alandonovan6db5e162019-03-11 12:31:47 -0400205 moduleLocals []*Binding
206 moduleGlobals []*Binding
Alan Donovan312d1a52017-10-02 10:10:28 -0400207
alandonovanf763f8b2019-03-08 15:33:54 -0500208 // globals maps each global name in the module to its binding.
209 // predeclared does the same for predeclared and universal names.
alandonovan6db5e162019-03-11 12:31:47 -0400210 globals map[string]*Binding
211 predeclared map[string]*Binding
Alan Donovan312d1a52017-10-02 10:10:28 -0400212
213 // These predicates report whether a name is
alandonovan28350e62019-10-21 14:58:36 -0400214 // pre-declared, either in this module or universally,
215 // or already declared in the module globals (as in a REPL).
216 // isGlobal may be nil.
217 isGlobal, isPredeclared, isUniversal func(name string) bool
Alan Donovan312d1a52017-10-02 10:10:28 -0400218
alandonovancd131d12020-06-09 17:58:44 -0400219 loops int // number of enclosing for/while loops
220 ifstmts int // number of enclosing if statements loops
Alan Donovan312d1a52017-10-02 10:10:28 -0400221
222 errors ErrorList
223}
224
225// container returns the innermost enclosing "container" block:
alandonovan754257e2019-04-03 16:43:05 -0400226// a function (function != nil) or file (function == nil).
Alan Donovan312d1a52017-10-02 10:10:28 -0400227// Container blocks accumulate local variable bindings.
228func (r *resolver) container() *block {
229 for b := r.env; ; b = b.parent {
alandonovan754257e2019-04-03 16:43:05 -0400230 if b.function != nil || b == r.file {
Alan Donovan312d1a52017-10-02 10:10:28 -0400231 return b
232 }
233 }
234}
235
236func (r *resolver) push(b *block) {
237 r.env.children = append(r.env.children, b)
238 b.parent = r.env
239 r.env = b
240}
241
242func (r *resolver) pop() { r.env = r.env.parent }
243
244type block struct {
alandonovan754257e2019-04-03 16:43:05 -0400245 parent *block // nil for file block
Alan Donovan312d1a52017-10-02 10:10:28 -0400246
alandonovan754257e2019-04-03 16:43:05 -0400247 // In the file (root) block, both these fields are nil.
alandonovan6ddc71c2019-06-04 09:08:55 -0400248 function *Function // only for function blocks
Alan Donovan312d1a52017-10-02 10:10:28 -0400249 comp *syntax.Comprehension // only for comprehension blocks
250
251 // bindings maps a name to its binding.
252 // A local binding has an index into its innermost enclosing container's locals array.
253 // A free binding has an index into its innermost enclosing function's freevars array.
alandonovan6db5e162019-03-11 12:31:47 -0400254 bindings map[string]*Binding
Alan Donovan312d1a52017-10-02 10:10:28 -0400255
256 // children records the child blocks of the current one.
257 children []*block
258
alandonovan754257e2019-04-03 16:43:05 -0400259 // uses records all identifiers seen in this container (function or file),
Alan Donovan312d1a52017-10-02 10:10:28 -0400260 // and a reference to the environment in which they appear.
261 // As we leave each container block, we resolve them,
262 // so that only free and global ones remain.
263 // At the end of each top-level function we compute closures.
264 uses []use
265}
266
alandonovan6db5e162019-03-11 12:31:47 -0400267func (b *block) bind(name string, bind *Binding) {
Alan Donovan312d1a52017-10-02 10:10:28 -0400268 if b.bindings == nil {
alandonovan6db5e162019-03-11 12:31:47 -0400269 b.bindings = make(map[string]*Binding)
Alan Donovan312d1a52017-10-02 10:10:28 -0400270 }
271 b.bindings[name] = bind
272}
273
274func (b *block) String() string {
275 if b.function != nil {
alandonovan6ddc71c2019-06-04 09:08:55 -0400276 return "function block at " + fmt.Sprint(b.function.Pos)
Alan Donovan312d1a52017-10-02 10:10:28 -0400277 }
278 if b.comp != nil {
alandonovan5b0e7882018-08-10 13:44:17 -0400279 return "comprehension block at " + fmt.Sprint(b.comp.Span())
Alan Donovan312d1a52017-10-02 10:10:28 -0400280 }
alandonovan754257e2019-04-03 16:43:05 -0400281 return "file block"
Alan Donovan312d1a52017-10-02 10:10:28 -0400282}
283
284func (r *resolver) errorf(posn syntax.Position, format string, args ...interface{}) {
285 r.errors = append(r.errors, Error{posn, fmt.Sprintf(format, args...)})
286}
287
288// A use records an identifier and the environment in which it appears.
289type use struct {
290 id *syntax.Ident
291 env *block
292}
293
alandonovan754257e2019-04-03 16:43:05 -0400294// 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
297// binding already exists, unless AllowGlobalReassign.
298// It sets id.Binding to the binding (whether old or new),
299// and returns whether a binding already existed.
alandonovan572ecca2019-01-23 18:41:07 -0500300func (r *resolver) bind(id *syntax.Ident) bool {
Alan Donovan312d1a52017-10-02 10:10:28 -0400301 // Binding outside any local (comprehension/function) block?
alandonovan754257e2019-04-03 16:43:05 -0400302 if r.env == r.file {
303 bind, ok := r.file.bindings[id.Name]
alandonovanf763f8b2019-03-08 15:33:54 -0500304 if !ok {
alandonovan754257e2019-04-03 16:43:05 -0400305 bind, ok = r.globals[id.Name]
306 if !ok {
307 // first global binding of this name
308 bind = &Binding{
309 First: id,
310 Scope: Global,
311 Index: len(r.moduleGlobals),
312 }
313 r.globals[id.Name] = bind
314 r.moduleGlobals = append(r.moduleGlobals, bind)
alandonovanf763f8b2019-03-08 15:33:54 -0500315 }
alandonovan754257e2019-04-03 16:43:05 -0400316 }
317 if ok && !AllowGlobalReassign {
318 r.errorf(id.NamePos, "cannot reassign %s %s declared at %s",
319 bind.Scope, id.Name, bind.First.NamePos)
Alan Donovan312d1a52017-10-02 10:10:28 -0400320 }
alandonovanf763f8b2019-03-08 15:33:54 -0500321 id.Binding = bind
Alan Donovan312d1a52017-10-02 10:10:28 -0400322 return ok
323 }
324
alandonovan754257e2019-04-03 16:43:05 -0400325 return r.bindLocal(id)
326}
327
328func (r *resolver) bindLocal(id *syntax.Ident) bool {
Alan Donovan312d1a52017-10-02 10:10:28 -0400329 // Mark this name as local to current block.
330 // Assign it a new local (positive) index in the current container.
331 _, ok := r.env.bindings[id.Name]
332 if !ok {
alandonovan6db5e162019-03-11 12:31:47 -0400333 var locals *[]*Binding
Alan Donovan312d1a52017-10-02 10:10:28 -0400334 if fn := r.container().function; fn != nil {
335 locals = &fn.Locals
336 } else {
337 locals = &r.moduleLocals
338 }
alandonovan6db5e162019-03-11 12:31:47 -0400339 bind := &Binding{
alandonovanf763f8b2019-03-08 15:33:54 -0500340 First: id,
alandonovan6db5e162019-03-11 12:31:47 -0400341 Scope: Local,
alandonovanf763f8b2019-03-08 15:33:54 -0500342 Index: len(*locals),
343 }
344 r.env.bind(id.Name, bind)
345 *locals = append(*locals, bind)
Alan Donovan312d1a52017-10-02 10:10:28 -0400346 }
347
348 r.use(id)
349 return ok
350}
351
352func (r *resolver) use(id *syntax.Ident) {
alandonovan6afa1bb2019-02-06 17:49:05 -0500353 use := use{id, r.env}
354
alandonovan84a935b2018-11-26 14:42:21 -0500355 // The spec says that if there is a global binding of a name
356 // then all references to that name in that block refer to the
357 // global, even if the use precedes the def---just as for locals.
358 // For example, in this code,
359 //
360 // print(len); len=1; print(len)
361 //
362 // both occurrences of len refer to the len=1 binding, which
363 // completely shadows the predeclared len function.
364 //
365 // The rationale for these semantics, which differ from Python,
366 // is that the static meaning of len (a reference to a global)
367 // does not change depending on where it appears in the file.
368 // Of course, its dynamic meaning does change, from an error
369 // into a valid reference, so it's not clear these semantics
370 // have any practical advantage.
371 //
372 // In any case, the Bazel implementation lags behind the spec
373 // and follows Python behavior, so the first use of len refers
374 // to the predeclared function. This typically used in a BUILD
375 // file that redefines a predeclared name half way through,
376 // for example:
377 //
378 // proto_library(...) # built-in rule
379 // load("myproto.bzl", "proto_library")
380 // proto_library(...) # user-defined rule
381 //
382 // We will piggyback support for the legacy semantics on the
383 // AllowGlobalReassign flag, which is loosely related and also
384 // required for Bazel.
alandonovan754257e2019-04-03 16:43:05 -0400385 if AllowGlobalReassign && r.env == r.file {
386 r.useToplevel(use)
alandonovan84a935b2018-11-26 14:42:21 -0500387 return
388 }
389
Alan Donovan312d1a52017-10-02 10:10:28 -0400390 b := r.container()
alandonovan6afa1bb2019-02-06 17:49:05 -0500391 b.uses = append(b.uses, use)
Alan Donovan312d1a52017-10-02 10:10:28 -0400392}
393
alandonovan754257e2019-04-03 16:43:05 -0400394// useToplevel resolves use.id as a reference to a name visible at top-level.
alandonovan6afa1bb2019-02-06 17:49:05 -0500395// The use.env field captures the original environment for error reporting.
alandonovan754257e2019-04-03 16:43:05 -0400396func (r *resolver) useToplevel(use use) (bind *Binding) {
alandonovan6afa1bb2019-02-06 17:49:05 -0500397 id := use.id
alandonovan754257e2019-04-03 16:43:05 -0400398
399 if prev, ok := r.file.bindings[id.Name]; ok {
400 // use of load-defined name in file block
401 bind = prev
402 } else if prev, ok := r.globals[id.Name]; ok {
alandonovan6db5e162019-03-11 12:31:47 -0400403 // use of global declared by module
404 bind = prev
alandonovan28350e62019-10-21 14:58:36 -0400405 } else if r.isGlobal != nil && r.isGlobal(id.Name) {
406 // use of global defined in a previous REPL chunk
407 bind = &Binding{
408 First: id, // wrong: this is not even a binding use
409 Scope: Global,
410 Index: len(r.moduleGlobals),
411 }
412 r.globals[id.Name] = bind
413 r.moduleGlobals = append(r.moduleGlobals, bind)
alandonovanf763f8b2019-03-08 15:33:54 -0500414 } else if prev, ok := r.predeclared[id.Name]; ok {
alandonovan6db5e162019-03-11 12:31:47 -0400415 // repeated use of predeclared or universal
416 bind = prev
alandonovana1b28d82018-03-13 10:59:24 -0400417 } else if r.isPredeclared(id.Name) {
alandonovan6db5e162019-03-11 12:31:47 -0400418 // use of pre-declared name
419 bind = &Binding{Scope: Predeclared}
420 r.predeclared[id.Name] = bind // save it
alandonovan631f7b52017-10-11 13:04:47 -0400421 } else if r.isUniversal(id.Name) {
alandonovan6db5e162019-03-11 12:31:47 -0400422 // use of universal name
Alan Donovan312d1a52017-10-02 10:10:28 -0400423 if !AllowSet && id.Name == "set" {
424 r.errorf(id.NamePos, doesnt+"support sets")
425 }
alandonovan6db5e162019-03-11 12:31:47 -0400426 bind = &Binding{Scope: Universal}
427 r.predeclared[id.Name] = bind // save it
Alan Donovan312d1a52017-10-02 10:10:28 -0400428 } else {
alandonovan6db5e162019-03-11 12:31:47 -0400429 bind = &Binding{Scope: Undefined}
alandonovan6afa1bb2019-02-06 17:49:05 -0500430 var hint string
431 if n := r.spellcheck(use); n != "" {
432 hint = fmt.Sprintf(" (did you mean %s?)", n)
433 }
434 r.errorf(id.NamePos, "undefined: %s%s", id.Name, hint)
Alan Donovan312d1a52017-10-02 10:10:28 -0400435 }
alandonovanf763f8b2019-03-08 15:33:54 -0500436 id.Binding = bind
437 return bind
Alan Donovan312d1a52017-10-02 10:10:28 -0400438}
439
alandonovan6afa1bb2019-02-06 17:49:05 -0500440// spellcheck returns the most likely misspelling of
441// the name use.id in the environment use.env.
442func (r *resolver) spellcheck(use use) string {
443 var names []string
444
445 // locals
446 for b := use.env; b != nil; b = b.parent {
447 for name := range b.bindings {
448 names = append(names, name)
449 }
450 }
451
452 // globals
453 //
alandonovan28350e62019-10-21 14:58:36 -0400454 // We have no way to enumerate the sets whose membership
455 // tests are isPredeclared, isUniverse, and isGlobal,
alandonovan6afa1bb2019-02-06 17:49:05 -0500456 // which includes prior names in the REPL session.
alandonovanf763f8b2019-03-08 15:33:54 -0500457 for _, bind := range r.moduleGlobals {
458 names = append(names, bind.First.Name)
alandonovan6afa1bb2019-02-06 17:49:05 -0500459 }
460
461 sort.Strings(names)
462 return spell.Nearest(use.id.Name, names)
463}
464
Alan Donovan312d1a52017-10-02 10:10:28 -0400465// resolveLocalUses is called when leaving a container (function/module)
alandonovan3d5a0612019-03-08 16:16:44 -0500466// block. It resolves all uses of locals/cells within that block.
Alan Donovan312d1a52017-10-02 10:10:28 -0400467func (b *block) resolveLocalUses() {
468 unresolved := b.uses[:0]
469 for _, use := range b.uses {
alandonovan6db5e162019-03-11 12:31:47 -0400470 if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) {
alandonovanf763f8b2019-03-08 15:33:54 -0500471 use.id.Binding = bind
Alan Donovan312d1a52017-10-02 10:10:28 -0400472 } else {
473 unresolved = append(unresolved, use)
474 }
475 }
476 b.uses = unresolved
477}
478
479func (r *resolver) stmts(stmts []syntax.Stmt) {
480 for _, stmt := range stmts {
481 r.stmt(stmt)
482 }
483}
484
485func (r *resolver) stmt(stmt syntax.Stmt) {
486 switch stmt := stmt.(type) {
487 case *syntax.ExprStmt:
488 r.expr(stmt.X)
489
490 case *syntax.BranchStmt:
491 if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) {
492 r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token)
493 }
494
495 case *syntax.IfStmt:
Alan Donovanc0b6b762018-12-18 13:09:56 -0500496 if !AllowGlobalReassign && r.container().function == nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400497 r.errorf(stmt.If, "if statement not within a function")
498 }
499 r.expr(stmt.Cond)
alandonovancd131d12020-06-09 17:58:44 -0400500 r.ifstmts++
Alan Donovan312d1a52017-10-02 10:10:28 -0400501 r.stmts(stmt.True)
502 r.stmts(stmt.False)
alandonovancd131d12020-06-09 17:58:44 -0400503 r.ifstmts--
Alan Donovan312d1a52017-10-02 10:10:28 -0400504
505 case *syntax.AssignStmt:
506 r.expr(stmt.RHS)
Alan Donovan312d1a52017-10-02 10:10:28 -0400507 isAugmented := stmt.Op != syntax.EQ
508 r.assign(stmt.LHS, isAugmented)
509
510 case *syntax.DefStmt:
alandonovan572ecca2019-01-23 18:41:07 -0500511 r.bind(stmt.Name)
alandonovan6ddc71c2019-06-04 09:08:55 -0400512 fn := &Function{
513 Name: stmt.Name.Name,
514 Pos: stmt.Def,
515 Params: stmt.Params,
516 Body: stmt.Body,
517 }
518 stmt.Function = fn
519 r.function(fn, stmt.Def)
Alan Donovan312d1a52017-10-02 10:10:28 -0400520
521 case *syntax.ForStmt:
Alan Donovanc0b6b762018-12-18 13:09:56 -0500522 if !AllowGlobalReassign && r.container().function == nil {
Alan Donovan312d1a52017-10-02 10:10:28 -0400523 r.errorf(stmt.For, "for loop not within a function")
524 }
525 r.expr(stmt.X)
alandonovan572ecca2019-01-23 18:41:07 -0500526 const isAugmented = false
527 r.assign(stmt.Vars, isAugmented)
Alan Donovan312d1a52017-10-02 10:10:28 -0400528 r.loops++
529 r.stmts(stmt.Body)
530 r.loops--
531
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100532 case *syntax.WhileStmt:
533 if !AllowRecursion {
Alan Donovanc0b6b762018-12-18 13:09:56 -0500534 r.errorf(stmt.While, doesnt+"support while loops")
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100535 }
Alan Donovanc0b6b762018-12-18 13:09:56 -0500536 if !AllowGlobalReassign && r.container().function == nil {
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100537 r.errorf(stmt.While, "while loop not within a function")
538 }
539 r.expr(stmt.Cond)
540 r.loops++
541 r.stmts(stmt.Body)
542 r.loops--
543
Alan Donovan312d1a52017-10-02 10:10:28 -0400544 case *syntax.ReturnStmt:
545 if r.container().function == nil {
546 r.errorf(stmt.Return, "return statement not within a function")
547 }
548 if stmt.Result != nil {
549 r.expr(stmt.Result)
550 }
551
552 case *syntax.LoadStmt:
alandonovancd131d12020-06-09 17:58:44 -0400553 // A load statement may not be nested in any other statement.
Alan Donovan312d1a52017-10-02 10:10:28 -0400554 if r.container().function != nil {
555 r.errorf(stmt.Load, "load statement within a function")
alandonovancd131d12020-06-09 17:58:44 -0400556 } else if r.loops > 0 {
557 r.errorf(stmt.Load, "load statement within a loop")
558 } else if r.ifstmts > 0 {
559 r.errorf(stmt.Load, "load statement within a conditional")
Alan Donovan312d1a52017-10-02 10:10:28 -0400560 }
561
Alan Donovan312d1a52017-10-02 10:10:28 -0400562 for i, from := range stmt.From {
563 if from.Name == "" {
564 r.errorf(from.NamePos, "load: empty identifier")
565 continue
566 }
567 if from.Name[0] == '_' {
568 r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
569 }
alandonovan754257e2019-04-03 16:43:05 -0400570
571 id := stmt.To[i]
572 if LoadBindsGlobally {
573 r.bind(id)
574 } else if r.bindLocal(id) && !AllowGlobalReassign {
575 // "Global" in AllowGlobalReassign is a misnomer for "toplevel".
576 // Sadly we can't report the previous declaration
577 // as id.Binding may not be set yet.
578 r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
579 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400580 }
581
582 default:
Alessandro Arzilli688506e2019-08-19 16:15:39 +0200583 log.Panicf("unexpected stmt %T", stmt)
Alan Donovan312d1a52017-10-02 10:10:28 -0400584 }
585}
586
587func (r *resolver) assign(lhs syntax.Expr, isAugmented bool) {
588 switch lhs := lhs.(type) {
589 case *syntax.Ident:
590 // x = ...
alandonovan572ecca2019-01-23 18:41:07 -0500591 r.bind(lhs)
Alan Donovan312d1a52017-10-02 10:10:28 -0400592
593 case *syntax.IndexExpr:
594 // x[i] = ...
595 r.expr(lhs.X)
596 r.expr(lhs.Y)
597
598 case *syntax.DotExpr:
599 // x.f = ...
600 r.expr(lhs.X)
601
602 case *syntax.TupleExpr:
603 // (x, y) = ...
Alan Donovan312d1a52017-10-02 10:10:28 -0400604 if isAugmented {
605 r.errorf(syntax.Start(lhs), "can't use tuple expression in augmented assignment")
606 }
607 for _, elem := range lhs.List {
608 r.assign(elem, isAugmented)
609 }
610
611 case *syntax.ListExpr:
612 // [x, y, z] = ...
Alan Donovan312d1a52017-10-02 10:10:28 -0400613 if isAugmented {
614 r.errorf(syntax.Start(lhs), "can't use list expression in augmented assignment")
615 }
616 for _, elem := range lhs.List {
617 r.assign(elem, isAugmented)
618 }
619
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100620 case *syntax.ParenExpr:
621 r.assign(lhs.X, isAugmented)
622
Alan Donovan312d1a52017-10-02 10:10:28 -0400623 default:
624 name := strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", lhs), "*syntax."))
625 r.errorf(syntax.Start(lhs), "can't assign to %s", name)
626 }
627}
628
629func (r *resolver) expr(e syntax.Expr) {
630 switch e := e.(type) {
631 case *syntax.Ident:
632 r.use(e)
633
634 case *syntax.Literal:
Alan Donovan312d1a52017-10-02 10:10:28 -0400635
636 case *syntax.ListExpr:
637 for _, x := range e.List {
638 r.expr(x)
639 }
640
641 case *syntax.CondExpr:
642 r.expr(e.Cond)
643 r.expr(e.True)
644 r.expr(e.False)
645
646 case *syntax.IndexExpr:
647 r.expr(e.X)
648 r.expr(e.Y)
649
650 case *syntax.DictEntry:
651 r.expr(e.Key)
652 r.expr(e.Value)
653
654 case *syntax.SliceExpr:
655 r.expr(e.X)
656 if e.Lo != nil {
657 r.expr(e.Lo)
658 }
659 if e.Hi != nil {
660 r.expr(e.Hi)
661 }
662 if e.Step != nil {
663 r.expr(e.Step)
664 }
665
666 case *syntax.Comprehension:
alandonovan0d5491b2018-03-30 10:42:13 -0400667 // The 'in' operand of the first clause (always a ForClause)
668 // is resolved in the outer block; consider: [x for x in x].
669 clause := e.Clauses[0].(*syntax.ForClause)
670 r.expr(clause.X)
671
Alan Donovan312d1a52017-10-02 10:10:28 -0400672 // A list/dict comprehension defines a new lexical block.
673 // Locals defined within the block will be allotted
674 // distinct slots in the locals array of the innermost
675 // enclosing container (function/module) block.
676 r.push(&block{comp: e})
alandonovan0d5491b2018-03-30 10:42:13 -0400677
alandonovan572ecca2019-01-23 18:41:07 -0500678 const isAugmented = false
679 r.assign(clause.Vars, isAugmented)
alandonovan0d5491b2018-03-30 10:42:13 -0400680
681 for _, clause := range e.Clauses[1:] {
Alan Donovan312d1a52017-10-02 10:10:28 -0400682 switch clause := clause.(type) {
683 case *syntax.IfClause:
684 r.expr(clause.Cond)
685 case *syntax.ForClause:
alandonovan572ecca2019-01-23 18:41:07 -0500686 r.assign(clause.Vars, isAugmented)
Alan Donovan312d1a52017-10-02 10:10:28 -0400687 r.expr(clause.X)
688 }
689 }
690 r.expr(e.Body) // body may be *DictEntry
691 r.pop()
692
693 case *syntax.TupleExpr:
694 for _, x := range e.List {
695 r.expr(x)
696 }
697
698 case *syntax.DictExpr:
699 for _, entry := range e.List {
700 entry := entry.(*syntax.DictEntry)
701 r.expr(entry.Key)
702 r.expr(entry.Value)
703 }
704
705 case *syntax.UnaryExpr:
706 r.expr(e.X)
707
708 case *syntax.BinaryExpr:
Alan Donovan312d1a52017-10-02 10:10:28 -0400709 r.expr(e.X)
710 r.expr(e.Y)
711
712 case *syntax.DotExpr:
713 r.expr(e.X)
714 // ignore e.Name
715
716 case *syntax.CallExpr:
717 r.expr(e.Fn)
alandonovan2c65f9e2018-12-14 13:46:48 -0500718 var seenVarargs, seenKwargs bool
719 var seenName map[string]bool
Josh Bleecher Snyder70a4f432019-01-01 12:22:42 -1000720 var n, p int
Alan Donovan312d1a52017-10-02 10:10:28 -0400721 for _, arg := range e.Args {
722 pos, _ := arg.Span()
723 if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
724 // **kwargs
725 if seenKwargs {
726 r.errorf(pos, "multiple **kwargs not allowed")
727 }
728 seenKwargs = true
729 r.expr(arg)
730 } else if ok && unop.Op == syntax.STAR {
731 // *args
732 if seenKwargs {
733 r.errorf(pos, "*args may not follow **kwargs")
734 } else if seenVarargs {
735 r.errorf(pos, "multiple *args not allowed")
736 }
737 seenVarargs = true
738 r.expr(arg)
739 } else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
740 // k=v
Josh Bleecher Snyder70a4f432019-01-01 12:22:42 -1000741 n++
Alan Donovan312d1a52017-10-02 10:10:28 -0400742 if seenKwargs {
alandonovan501b6c72020-11-13 16:43:45 -0500743 r.errorf(pos, "keyword argument may not follow **kwargs")
744 } else if seenVarargs {
745 r.errorf(pos, "keyword argument may not follow *args")
Alan Donovan312d1a52017-10-02 10:10:28 -0400746 }
alandonovan2c65f9e2018-12-14 13:46:48 -0500747 x := binop.X.(*syntax.Ident)
748 if seenName[x.Name] {
749 r.errorf(x.NamePos, "keyword argument %s repeated", x.Name)
750 } else {
751 if seenName == nil {
752 seenName = make(map[string]bool)
753 }
754 seenName[x.Name] = true
755 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400756 r.expr(binop.Y)
757 } else {
758 // positional argument
Josh Bleecher Snyder70a4f432019-01-01 12:22:42 -1000759 p++
Alan Donovan312d1a52017-10-02 10:10:28 -0400760 if seenVarargs {
alandonovan501b6c72020-11-13 16:43:45 -0500761 r.errorf(pos, "positional argument may not follow *args")
Alan Donovan312d1a52017-10-02 10:10:28 -0400762 } else if seenKwargs {
alandonovan501b6c72020-11-13 16:43:45 -0500763 r.errorf(pos, "positional argument may not follow **kwargs")
alandonovan2c65f9e2018-12-14 13:46:48 -0500764 } else if len(seenName) > 0 {
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500765 r.errorf(pos, "positional argument may not follow named")
Alan Donovan312d1a52017-10-02 10:10:28 -0400766 }
767 r.expr(arg)
768 }
769 }
770
Josh Bleecher Snyder70a4f432019-01-01 12:22:42 -1000771 // Fail gracefully if compiler-imposed limit is exceeded.
772 if p >= 256 {
773 pos, _ := e.Span()
774 r.errorf(pos, "%v positional arguments in call, limit is 255", p)
775 }
776 if n >= 256 {
777 pos, _ := e.Span()
778 r.errorf(pos, "%v keyword arguments in call, limit is 255", n)
779 }
780
Alan Donovan312d1a52017-10-02 10:10:28 -0400781 case *syntax.LambdaExpr:
alandonovan6ddc71c2019-06-04 09:08:55 -0400782 fn := &Function{
783 Name: "lambda",
784 Pos: e.Lambda,
785 Params: e.Params,
786 Body: []syntax.Stmt{&syntax.ReturnStmt{Result: e.Body}},
787 }
788 e.Function = fn
789 r.function(fn, e.Lambda)
Alan Donovan312d1a52017-10-02 10:10:28 -0400790
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100791 case *syntax.ParenExpr:
792 r.expr(e.X)
793
Alan Donovan312d1a52017-10-02 10:10:28 -0400794 default:
Alessandro Arzilli688506e2019-08-19 16:15:39 +0200795 log.Panicf("unexpected expr %T", e)
Alan Donovan312d1a52017-10-02 10:10:28 -0400796 }
797}
798
alandonovan6ddc71c2019-06-04 09:08:55 -0400799func (r *resolver) function(function *Function, pos syntax.Position) {
Alan Donovan312d1a52017-10-02 10:10:28 -0400800 // Resolve defaults in enclosing environment.
801 for _, param := range function.Params {
802 if binary, ok := param.(*syntax.BinaryExpr); ok {
803 r.expr(binary.Y)
804 }
805 }
806
807 // Enter function block.
808 b := &block{function: function}
809 r.push(b)
810
alandonovanb7e3b1f2018-12-12 17:14:58 -0500811 var seenOptional bool
Alan Donovan52153852019-02-13 19:18:15 -0500812 var star *syntax.UnaryExpr // * or *args param
813 var starStar *syntax.Ident // **kwargs ident
814 var numKwonlyParams int
Alan Donovan312d1a52017-10-02 10:10:28 -0400815 for _, param := range function.Params {
816 switch param := param.(type) {
817 case *syntax.Ident:
818 // e.g. x
alandonovanb7e3b1f2018-12-12 17:14:58 -0500819 if starStar != nil {
820 r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name)
821 } else if star != nil {
alandonovan8313b542019-02-15 13:17:43 -0500822 numKwonlyParams++
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500823 } else if seenOptional {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500824 r.errorf(param.NamePos, "required parameter may not follow optional")
Alan Donovan312d1a52017-10-02 10:10:28 -0400825 }
alandonovan572ecca2019-01-23 18:41:07 -0500826 if r.bind(param) {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500827 r.errorf(param.NamePos, "duplicate parameter: %s", param.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400828 }
829
830 case *syntax.BinaryExpr:
831 // e.g. y=dflt
alandonovanb7e3b1f2018-12-12 17:14:58 -0500832 if starStar != nil {
833 r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
834 } else if star != nil {
Alan Donovan52153852019-02-13 19:18:15 -0500835 numKwonlyParams++
Alan Donovan312d1a52017-10-02 10:10:28 -0400836 }
alandonovan572ecca2019-01-23 18:41:07 -0500837 if id := param.X.(*syntax.Ident); r.bind(id) {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500838 r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400839 }
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500840 seenOptional = true
Alan Donovan312d1a52017-10-02 10:10:28 -0400841
842 case *syntax.UnaryExpr:
Alan Donovan52153852019-02-13 19:18:15 -0500843 // * or *args or **kwargs
Alan Donovan312d1a52017-10-02 10:10:28 -0400844 if param.Op == syntax.STAR {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500845 if starStar != nil {
Alan Donovan52153852019-02-13 19:18:15 -0500846 r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name)
alandonovanb7e3b1f2018-12-12 17:14:58 -0500847 } else if star != nil {
848 r.errorf(param.OpPos, "multiple * parameters not allowed")
849 } else {
Alan Donovan52153852019-02-13 19:18:15 -0500850 star = param
Alan Donovan312d1a52017-10-02 10:10:28 -0400851 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400852 } else {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500853 if starStar != nil {
854 r.errorf(param.OpPos, "multiple ** parameters not allowed")
Alan Donovan312d1a52017-10-02 10:10:28 -0400855 }
Alan Donovan52153852019-02-13 19:18:15 -0500856 starStar = param.X.(*syntax.Ident)
Alan Donovan312d1a52017-10-02 10:10:28 -0400857 }
858 }
859 }
Alan Donovan52153852019-02-13 19:18:15 -0500860
861 // Bind the *args and **kwargs parameters at the end,
862 // so that regular parameters a/b/c are contiguous and
863 // there is no hole for the "*":
864 // def f(a, b, *args, c=0, **kwargs)
865 // def f(a, b, *, c=0, **kwargs)
866 if star != nil {
867 if id, _ := star.X.(*syntax.Ident); id != nil {
868 // *args
869 if r.bind(id) {
870 r.errorf(id.NamePos, "duplicate parameter: %s", id.Name)
871 }
872 function.HasVarargs = true
873 } else if numKwonlyParams == 0 {
alandonovan8313b542019-02-15 13:17:43 -0500874 r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters")
Alan Donovan52153852019-02-13 19:18:15 -0500875 }
876 }
877 if starStar != nil {
878 if r.bind(starStar) {
879 r.errorf(starStar.NamePos, "duplicate parameter: %s", starStar.Name)
880 }
881 function.HasKwargs = true
882 }
883
884 function.NumKwonlyParams = numKwonlyParams
Alan Donovan312d1a52017-10-02 10:10:28 -0400885 r.stmts(function.Body)
886
887 // Resolve all uses of this function's local vars,
888 // and keep just the remaining uses of free/global vars.
889 b.resolveLocalUses()
890
891 // Leave function block.
892 r.pop()
893
894 // References within the function body to globals are not
895 // resolved until the end of the module.
896}
897
898func (r *resolver) resolveNonLocalUses(b *block) {
899 // First resolve inner blocks.
900 for _, child := range b.children {
901 r.resolveNonLocalUses(child)
902 }
903 for _, use := range b.uses {
alandonovanf763f8b2019-03-08 15:33:54 -0500904 use.id.Binding = r.lookupLexical(use, use.env)
Alan Donovan312d1a52017-10-02 10:10:28 -0400905 }
906}
907
908// lookupLocal looks up an identifier within its immediately enclosing function.
alandonovan6db5e162019-03-11 12:31:47 -0400909func lookupLocal(use use) *Binding {
Alan Donovan312d1a52017-10-02 10:10:28 -0400910 for env := use.env; env != nil; env = env.parent {
911 if bind, ok := env.bindings[use.id.Name]; ok {
alandonovan6db5e162019-03-11 12:31:47 -0400912 if bind.Scope == Free {
Alan Donovan312d1a52017-10-02 10:10:28 -0400913 // shouldn't exist till later
Alessandro Arzilli688506e2019-08-19 16:15:39 +0200914 log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind)
Alan Donovan312d1a52017-10-02 10:10:28 -0400915 }
916 return bind // found
917 }
918 if env.function != nil {
919 break
920 }
921 }
alandonovanf763f8b2019-03-08 15:33:54 -0500922 return nil // not found in this function
Alan Donovan312d1a52017-10-02 10:10:28 -0400923}
924
alandonovan6afa1bb2019-02-06 17:49:05 -0500925// lookupLexical looks up an identifier use.id within its lexically enclosing environment.
926// The use.env field captures the original environment for error reporting.
alandonovan6db5e162019-03-11 12:31:47 -0400927func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) {
Alan Donovan312d1a52017-10-02 10:10:28 -0400928 if debug {
alandonovan6afa1bb2019-02-06 17:49:05 -0500929 fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env)
alandonovanf763f8b2019-03-08 15:33:54 -0500930 defer func() { fmt.Printf("= %v\n", bind) }()
Alan Donovan312d1a52017-10-02 10:10:28 -0400931 }
932
alandonovan754257e2019-04-03 16:43:05 -0400933 // Is this the file block?
934 if env == r.file {
935 return r.useToplevel(use) // file-local, global, predeclared, or not found
Alan Donovan312d1a52017-10-02 10:10:28 -0400936 }
937
938 // Defined in this block?
alandonovan6afa1bb2019-02-06 17:49:05 -0500939 bind, ok := env.bindings[use.id.Name]
Alan Donovan312d1a52017-10-02 10:10:28 -0400940 if !ok {
941 // Defined in parent block?
alandonovan6afa1bb2019-02-06 17:49:05 -0500942 bind = r.lookupLexical(use, env.parent)
alandonovan6db5e162019-03-11 12:31:47 -0400943 if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) {
Alan Donovan312d1a52017-10-02 10:10:28 -0400944 // Found in parent block, which belongs to enclosing function.
alandonovanf763f8b2019-03-08 15:33:54 -0500945 // Add the parent's binding to the function's freevars,
alandonovan3d5a0612019-03-08 16:16:44 -0500946 // and add a new 'free' binding to the inner function's block,
947 // and turn the parent's local into cell.
alandonovan6db5e162019-03-11 12:31:47 -0400948 if bind.Scope == Local {
949 bind.Scope = Cell
alandonovan3d5a0612019-03-08 16:16:44 -0500950 }
alandonovanf763f8b2019-03-08 15:33:54 -0500951 index := len(env.function.FreeVars)
952 env.function.FreeVars = append(env.function.FreeVars, bind)
alandonovan6db5e162019-03-11 12:31:47 -0400953 bind = &Binding{
alandonovanf763f8b2019-03-08 15:33:54 -0500954 First: bind.First,
alandonovan6db5e162019-03-11 12:31:47 -0400955 Scope: Free,
alandonovanf763f8b2019-03-08 15:33:54 -0500956 Index: index,
Alan Donovan312d1a52017-10-02 10:10:28 -0400957 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400958 if debug {
959 fmt.Printf("creating freevar %v in function at %s: %s\n",
alandonovan6ddc71c2019-06-04 09:08:55 -0400960 len(env.function.FreeVars), env.function.Pos, use.id.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400961 }
962 }
963
964 // Memoize, to avoid duplicate free vars
965 // and redundant global (failing) lookups.
alandonovan6afa1bb2019-02-06 17:49:05 -0500966 env.bind(use.id.Name, bind)
Alan Donovan312d1a52017-10-02 10:10:28 -0400967 }
968 return bind
969}