xref: /aosp_15_r20/external/starlark-go/resolve/resolve.go (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
1*4947cdc7SCole Faust// Copyright 2017 The Bazel Authors. All rights reserved.
2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style
3*4947cdc7SCole Faust// license that can be found in the LICENSE file.
4*4947cdc7SCole Faust
5*4947cdc7SCole Faust// Package resolve defines a name-resolution pass for Starlark abstract
6*4947cdc7SCole Faust// syntax trees.
7*4947cdc7SCole Faust//
8*4947cdc7SCole Faust// The resolver sets the Locals and FreeVars arrays of each DefStmt and
9*4947cdc7SCole Faust// the LocalIndex field of each syntax.Ident that refers to a local or
10*4947cdc7SCole Faust// free variable.  It also sets the Locals array of a File for locals
11*4947cdc7SCole Faust// bound by top-level comprehensions and load statements.
12*4947cdc7SCole Faust// Identifiers for global variables do not get an index.
13*4947cdc7SCole Faustpackage resolve // import "go.starlark.net/resolve"
14*4947cdc7SCole Faust
15*4947cdc7SCole Faust// All references to names are statically resolved.  Names may be
16*4947cdc7SCole Faust// predeclared, global, or local to a function or file.
17*4947cdc7SCole Faust// File-local variables include those bound by top-level comprehensions
18*4947cdc7SCole Faust// and by load statements. ("Top-level" means "outside of any function".)
19*4947cdc7SCole Faust// The resolver maps each global name to a small integer and each local
20*4947cdc7SCole Faust// name to a small integer; these integers enable a fast and compact
21*4947cdc7SCole Faust// representation of globals and locals in the evaluator.
22*4947cdc7SCole Faust//
23*4947cdc7SCole Faust// As an optimization, the resolver classifies each predeclared name as
24*4947cdc7SCole Faust// either universal (e.g. None, len) or per-module (e.g. glob in Bazel's
25*4947cdc7SCole Faust// build language), enabling the evaluator to share the representation
26*4947cdc7SCole Faust// of the universal environment across all modules.
27*4947cdc7SCole Faust//
28*4947cdc7SCole Faust// The lexical environment is a tree of blocks with the file block at
29*4947cdc7SCole Faust// its root. The file's child blocks may be of two kinds: functions
30*4947cdc7SCole Faust// and comprehensions, and these may have further children of either
31*4947cdc7SCole Faust// kind.
32*4947cdc7SCole Faust//
33*4947cdc7SCole Faust// Python-style resolution requires multiple passes because a name is
34*4947cdc7SCole Faust// determined to be local to a function only if the function contains a
35*4947cdc7SCole Faust// "binding" use of it; similarly, a name is determined to be global (as
36*4947cdc7SCole Faust// opposed to predeclared) if the module contains a top-level binding use.
37*4947cdc7SCole Faust// Unlike ordinary top-level assignments, the bindings created by load
38*4947cdc7SCole Faust// statements are local to the file block.
39*4947cdc7SCole Faust// A non-binding use may lexically precede the binding to which it is resolved.
40*4947cdc7SCole Faust// In the first pass, we inspect each function, recording in
41*4947cdc7SCole Faust// 'uses' each identifier and the environment block in which it occurs.
42*4947cdc7SCole Faust// If a use of a name is binding, such as a function parameter or
43*4947cdc7SCole Faust// assignment, we add the name to the block's bindings mapping and add a
44*4947cdc7SCole Faust// local variable to the enclosing function.
45*4947cdc7SCole Faust//
46*4947cdc7SCole Faust// As we finish resolving each function, we inspect all the uses within
47*4947cdc7SCole Faust// that function and discard ones that were found to be function-local. The
48*4947cdc7SCole Faust// remaining ones must be either free (local to some lexically enclosing
49*4947cdc7SCole Faust// function), or top-level (global, predeclared, or file-local), but we cannot tell
50*4947cdc7SCole Faust// which until we have finished inspecting the outermost enclosing
51*4947cdc7SCole Faust// function. At that point, we can distinguish local from top-level names
52*4947cdc7SCole Faust// (and this is when Python would compute free variables).
53*4947cdc7SCole Faust//
54*4947cdc7SCole Faust// However, Starlark additionally requires that all references to global
55*4947cdc7SCole Faust// names are satisfied by some declaration in the current module;
56*4947cdc7SCole Faust// Starlark permits a function to forward-reference a global or file-local
57*4947cdc7SCole Faust// that has not
58*4947cdc7SCole Faust// been declared yet so long as it is declared before the end of the
59*4947cdc7SCole Faust// module.  So, instead of re-resolving the unresolved references after
60*4947cdc7SCole Faust// each top-level function, we defer this until the end of the module
61*4947cdc7SCole Faust// and ensure that all such references are satisfied by some definition.
62*4947cdc7SCole Faust//
63*4947cdc7SCole Faust// At the end of the module, we visit each of the nested function blocks
64*4947cdc7SCole Faust// in bottom-up order, doing a recursive lexical lookup for each
65*4947cdc7SCole Faust// unresolved name.  If the name is found to be local to some enclosing
66*4947cdc7SCole Faust// function, we must create a DefStmt.FreeVar (capture) parameter for
67*4947cdc7SCole Faust// each intervening function.  We enter these synthetic bindings into
68*4947cdc7SCole Faust// the bindings map so that we create at most one freevar per name.  If
69*4947cdc7SCole Faust// the name was not local, we check that it was defined at module level.
70*4947cdc7SCole Faust//
71*4947cdc7SCole Faust// We resolve all uses of locals in the module (due to load statements
72*4947cdc7SCole Faust// and comprehensions) in a similar way and compute the file's set of
73*4947cdc7SCole Faust// local variables.
74*4947cdc7SCole Faust//
75*4947cdc7SCole Faust// Starlark enforces that all global names are assigned at most once on
76*4947cdc7SCole Faust// all control flow paths by forbidding if/else statements and loops at
77*4947cdc7SCole Faust// top level. A global may be used before it is defined, leading to a
78*4947cdc7SCole Faust// dynamic error. However, the AllowGlobalReassign flag (really: allow
79*4947cdc7SCole Faust// top-level reassign) makes the resolver allow multiple to a variable
80*4947cdc7SCole Faust// at top-level. It also allows if-, for-, and while-loops at top-level,
81*4947cdc7SCole Faust// which in turn may make the evaluator dynamically assign multiple
82*4947cdc7SCole Faust// values to a variable at top-level. (These two roles should be separated.)
83*4947cdc7SCole Faust
84*4947cdc7SCole Faustimport (
85*4947cdc7SCole Faust	"fmt"
86*4947cdc7SCole Faust	"log"
87*4947cdc7SCole Faust	"sort"
88*4947cdc7SCole Faust	"strings"
89*4947cdc7SCole Faust
90*4947cdc7SCole Faust	"go.starlark.net/internal/spell"
91*4947cdc7SCole Faust	"go.starlark.net/syntax"
92*4947cdc7SCole Faust)
93*4947cdc7SCole Faust
94*4947cdc7SCole Faustconst debug = false
95*4947cdc7SCole Faustconst doesnt = "this Starlark dialect does not "
96*4947cdc7SCole Faust
97*4947cdc7SCole Faust// global options
98*4947cdc7SCole Faust// These features are either not standard Starlark (yet), or deprecated
99*4947cdc7SCole Faust// features of the BUILD language, so we put them behind flags.
100*4947cdc7SCole Faustvar (
101*4947cdc7SCole Faust	AllowSet            = false // allow the 'set' built-in
102*4947cdc7SCole Faust	AllowGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top-level
103*4947cdc7SCole Faust	AllowRecursion      = false // allow while statements and recursive functions
104*4947cdc7SCole Faust	LoadBindsGlobally   = false // load creates global not file-local bindings (deprecated)
105*4947cdc7SCole Faust
106*4947cdc7SCole Faust	// obsolete flags for features that are now standard. No effect.
107*4947cdc7SCole Faust	AllowNestedDef = true
108*4947cdc7SCole Faust	AllowLambda    = true
109*4947cdc7SCole Faust	AllowFloat     = true
110*4947cdc7SCole Faust	AllowBitwise   = true
111*4947cdc7SCole Faust)
112*4947cdc7SCole Faust
113*4947cdc7SCole Faust// File resolves the specified file and records information about the
114*4947cdc7SCole Faust// module in file.Module.
115*4947cdc7SCole Faust//
116*4947cdc7SCole Faust// The isPredeclared and isUniversal predicates report whether a name is
117*4947cdc7SCole Faust// a pre-declared identifier (visible in the current module) or a
118*4947cdc7SCole Faust// universal identifier (visible in every module).
119*4947cdc7SCole Faust// Clients should typically pass predeclared.Has for the first and
120*4947cdc7SCole Faust// starlark.Universe.Has for the second, where predeclared is the
121*4947cdc7SCole Faust// module's StringDict of predeclared names and starlark.Universe is the
122*4947cdc7SCole Faust// standard set of built-ins.
123*4947cdc7SCole Faust// The isUniverse predicate is supplied a parameter to avoid a cyclic
124*4947cdc7SCole Faust// dependency upon starlark.Universe, not because users should ever need
125*4947cdc7SCole Faust// to redefine it.
126*4947cdc7SCole Faustfunc File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error {
127*4947cdc7SCole Faust	return REPLChunk(file, nil, isPredeclared, isUniversal)
128*4947cdc7SCole Faust}
129*4947cdc7SCole Faust
130*4947cdc7SCole Faust// REPLChunk is a generalization of the File function that supports a
131*4947cdc7SCole Faust// non-empty initial global block, as occurs in a REPL.
132*4947cdc7SCole Faustfunc REPLChunk(file *syntax.File, isGlobal, isPredeclared, isUniversal func(name string) bool) error {
133*4947cdc7SCole Faust	r := newResolver(isGlobal, isPredeclared, isUniversal)
134*4947cdc7SCole Faust	r.stmts(file.Stmts)
135*4947cdc7SCole Faust
136*4947cdc7SCole Faust	r.env.resolveLocalUses()
137*4947cdc7SCole Faust
138*4947cdc7SCole Faust	// At the end of the module, resolve all non-local variable references,
139*4947cdc7SCole Faust	// computing closures.
140*4947cdc7SCole Faust	// Function bodies may contain forward references to later global declarations.
141*4947cdc7SCole Faust	r.resolveNonLocalUses(r.env)
142*4947cdc7SCole Faust
143*4947cdc7SCole Faust	file.Module = &Module{
144*4947cdc7SCole Faust		Locals:  r.moduleLocals,
145*4947cdc7SCole Faust		Globals: r.moduleGlobals,
146*4947cdc7SCole Faust	}
147*4947cdc7SCole Faust
148*4947cdc7SCole Faust	if len(r.errors) > 0 {
149*4947cdc7SCole Faust		return r.errors
150*4947cdc7SCole Faust	}
151*4947cdc7SCole Faust	return nil
152*4947cdc7SCole Faust}
153*4947cdc7SCole Faust
154*4947cdc7SCole Faust// Expr resolves the specified expression.
155*4947cdc7SCole Faust// It returns the local variables bound within the expression.
156*4947cdc7SCole Faust//
157*4947cdc7SCole Faust// The isPredeclared and isUniversal predicates behave as for the File function.
158*4947cdc7SCole Faustfunc Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
159*4947cdc7SCole Faust	r := newResolver(nil, isPredeclared, isUniversal)
160*4947cdc7SCole Faust	r.expr(expr)
161*4947cdc7SCole Faust	r.env.resolveLocalUses()
162*4947cdc7SCole Faust	r.resolveNonLocalUses(r.env) // globals & universals
163*4947cdc7SCole Faust	if len(r.errors) > 0 {
164*4947cdc7SCole Faust		return nil, r.errors
165*4947cdc7SCole Faust	}
166*4947cdc7SCole Faust	return r.moduleLocals, nil
167*4947cdc7SCole Faust}
168*4947cdc7SCole Faust
169*4947cdc7SCole Faust// An ErrorList is a non-empty list of resolver error messages.
170*4947cdc7SCole Fausttype ErrorList []Error // len > 0
171*4947cdc7SCole Faust
172*4947cdc7SCole Faustfunc (e ErrorList) Error() string { return e[0].Error() }
173*4947cdc7SCole Faust
174*4947cdc7SCole Faust// An Error describes the nature and position of a resolver error.
175*4947cdc7SCole Fausttype Error struct {
176*4947cdc7SCole Faust	Pos syntax.Position
177*4947cdc7SCole Faust	Msg string
178*4947cdc7SCole Faust}
179*4947cdc7SCole Faust
180*4947cdc7SCole Faustfunc (e Error) Error() string { return e.Pos.String() + ": " + e.Msg }
181*4947cdc7SCole Faust
182*4947cdc7SCole Faustfunc newResolver(isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver {
183*4947cdc7SCole Faust	file := new(block)
184*4947cdc7SCole Faust	return &resolver{
185*4947cdc7SCole Faust		file:          file,
186*4947cdc7SCole Faust		env:           file,
187*4947cdc7SCole Faust		isGlobal:      isGlobal,
188*4947cdc7SCole Faust		isPredeclared: isPredeclared,
189*4947cdc7SCole Faust		isUniversal:   isUniversal,
190*4947cdc7SCole Faust		globals:       make(map[string]*Binding),
191*4947cdc7SCole Faust		predeclared:   make(map[string]*Binding),
192*4947cdc7SCole Faust	}
193*4947cdc7SCole Faust}
194*4947cdc7SCole Faust
195*4947cdc7SCole Fausttype resolver struct {
196*4947cdc7SCole Faust	// env is the current local environment:
197*4947cdc7SCole Faust	// a linked list of blocks, innermost first.
198*4947cdc7SCole Faust	// The tail of the list is the file block.
199*4947cdc7SCole Faust	env  *block
200*4947cdc7SCole Faust	file *block // file block (contains load bindings)
201*4947cdc7SCole Faust
202*4947cdc7SCole Faust	// moduleLocals contains the local variables of the module
203*4947cdc7SCole Faust	// (due to load statements and comprehensions outside any function).
204*4947cdc7SCole Faust	// moduleGlobals contains the global variables of the module.
205*4947cdc7SCole Faust	moduleLocals  []*Binding
206*4947cdc7SCole Faust	moduleGlobals []*Binding
207*4947cdc7SCole Faust
208*4947cdc7SCole Faust	// globals maps each global name in the module to its binding.
209*4947cdc7SCole Faust	// predeclared does the same for predeclared and universal names.
210*4947cdc7SCole Faust	globals     map[string]*Binding
211*4947cdc7SCole Faust	predeclared map[string]*Binding
212*4947cdc7SCole Faust
213*4947cdc7SCole Faust	// These predicates report whether a name is
214*4947cdc7SCole Faust	// pre-declared, either in this module or universally,
215*4947cdc7SCole Faust	// or already declared in the module globals (as in a REPL).
216*4947cdc7SCole Faust	// isGlobal may be nil.
217*4947cdc7SCole Faust	isGlobal, isPredeclared, isUniversal func(name string) bool
218*4947cdc7SCole Faust
219*4947cdc7SCole Faust	loops   int // number of enclosing for/while loops
220*4947cdc7SCole Faust	ifstmts int // number of enclosing if statements loops
221*4947cdc7SCole Faust
222*4947cdc7SCole Faust	errors ErrorList
223*4947cdc7SCole Faust}
224*4947cdc7SCole Faust
225*4947cdc7SCole Faust// container returns the innermost enclosing "container" block:
226*4947cdc7SCole Faust// a function (function != nil) or file (function == nil).
227*4947cdc7SCole Faust// Container blocks accumulate local variable bindings.
228*4947cdc7SCole Faustfunc (r *resolver) container() *block {
229*4947cdc7SCole Faust	for b := r.env; ; b = b.parent {
230*4947cdc7SCole Faust		if b.function != nil || b == r.file {
231*4947cdc7SCole Faust			return b
232*4947cdc7SCole Faust		}
233*4947cdc7SCole Faust	}
234*4947cdc7SCole Faust}
235*4947cdc7SCole Faust
236*4947cdc7SCole Faustfunc (r *resolver) push(b *block) {
237*4947cdc7SCole Faust	r.env.children = append(r.env.children, b)
238*4947cdc7SCole Faust	b.parent = r.env
239*4947cdc7SCole Faust	r.env = b
240*4947cdc7SCole Faust}
241*4947cdc7SCole Faust
242*4947cdc7SCole Faustfunc (r *resolver) pop() { r.env = r.env.parent }
243*4947cdc7SCole Faust
244*4947cdc7SCole Fausttype block struct {
245*4947cdc7SCole Faust	parent *block // nil for file block
246*4947cdc7SCole Faust
247*4947cdc7SCole Faust	// In the file (root) block, both these fields are nil.
248*4947cdc7SCole Faust	function *Function             // only for function blocks
249*4947cdc7SCole Faust	comp     *syntax.Comprehension // only for comprehension blocks
250*4947cdc7SCole Faust
251*4947cdc7SCole Faust	// bindings maps a name to its binding.
252*4947cdc7SCole Faust	// A local binding has an index into its innermost enclosing container's locals array.
253*4947cdc7SCole Faust	// A free binding has an index into its innermost enclosing function's freevars array.
254*4947cdc7SCole Faust	bindings map[string]*Binding
255*4947cdc7SCole Faust
256*4947cdc7SCole Faust	// children records the child blocks of the current one.
257*4947cdc7SCole Faust	children []*block
258*4947cdc7SCole Faust
259*4947cdc7SCole Faust	// uses records all identifiers seen in this container (function or file),
260*4947cdc7SCole Faust	// and a reference to the environment in which they appear.
261*4947cdc7SCole Faust	// As we leave each container block, we resolve them,
262*4947cdc7SCole Faust	// so that only free and global ones remain.
263*4947cdc7SCole Faust	// At the end of each top-level function we compute closures.
264*4947cdc7SCole Faust	uses []use
265*4947cdc7SCole Faust}
266*4947cdc7SCole Faust
267*4947cdc7SCole Faustfunc (b *block) bind(name string, bind *Binding) {
268*4947cdc7SCole Faust	if b.bindings == nil {
269*4947cdc7SCole Faust		b.bindings = make(map[string]*Binding)
270*4947cdc7SCole Faust	}
271*4947cdc7SCole Faust	b.bindings[name] = bind
272*4947cdc7SCole Faust}
273*4947cdc7SCole Faust
274*4947cdc7SCole Faustfunc (b *block) String() string {
275*4947cdc7SCole Faust	if b.function != nil {
276*4947cdc7SCole Faust		return "function block at " + fmt.Sprint(b.function.Pos)
277*4947cdc7SCole Faust	}
278*4947cdc7SCole Faust	if b.comp != nil {
279*4947cdc7SCole Faust		return "comprehension block at " + fmt.Sprint(b.comp.Span())
280*4947cdc7SCole Faust	}
281*4947cdc7SCole Faust	return "file block"
282*4947cdc7SCole Faust}
283*4947cdc7SCole Faust
284*4947cdc7SCole Faustfunc (r *resolver) errorf(posn syntax.Position, format string, args ...interface{}) {
285*4947cdc7SCole Faust	r.errors = append(r.errors, Error{posn, fmt.Sprintf(format, args...)})
286*4947cdc7SCole Faust}
287*4947cdc7SCole Faust
288*4947cdc7SCole Faust// A use records an identifier and the environment in which it appears.
289*4947cdc7SCole Fausttype use struct {
290*4947cdc7SCole Faust	id  *syntax.Ident
291*4947cdc7SCole Faust	env *block
292*4947cdc7SCole Faust}
293*4947cdc7SCole Faust
294*4947cdc7SCole Faust// bind creates a binding for id: a global (not file-local)
295*4947cdc7SCole Faust// binding at top-level, a local binding otherwise.
296*4947cdc7SCole Faust// At top-level, it reports an error if a global or file-local
297*4947cdc7SCole Faust// binding already exists, unless AllowGlobalReassign.
298*4947cdc7SCole Faust// It sets id.Binding to the binding (whether old or new),
299*4947cdc7SCole Faust// and returns whether a binding already existed.
300*4947cdc7SCole Faustfunc (r *resolver) bind(id *syntax.Ident) bool {
301*4947cdc7SCole Faust	// Binding outside any local (comprehension/function) block?
302*4947cdc7SCole Faust	if r.env == r.file {
303*4947cdc7SCole Faust		bind, ok := r.file.bindings[id.Name]
304*4947cdc7SCole Faust		if !ok {
305*4947cdc7SCole Faust			bind, ok = r.globals[id.Name]
306*4947cdc7SCole Faust			if !ok {
307*4947cdc7SCole Faust				// first global binding of this name
308*4947cdc7SCole Faust				bind = &Binding{
309*4947cdc7SCole Faust					First: id,
310*4947cdc7SCole Faust					Scope: Global,
311*4947cdc7SCole Faust					Index: len(r.moduleGlobals),
312*4947cdc7SCole Faust				}
313*4947cdc7SCole Faust				r.globals[id.Name] = bind
314*4947cdc7SCole Faust				r.moduleGlobals = append(r.moduleGlobals, bind)
315*4947cdc7SCole Faust			}
316*4947cdc7SCole Faust		}
317*4947cdc7SCole Faust		if ok && !AllowGlobalReassign {
318*4947cdc7SCole Faust			r.errorf(id.NamePos, "cannot reassign %s %s declared at %s",
319*4947cdc7SCole Faust				bind.Scope, id.Name, bind.First.NamePos)
320*4947cdc7SCole Faust		}
321*4947cdc7SCole Faust		id.Binding = bind
322*4947cdc7SCole Faust		return ok
323*4947cdc7SCole Faust	}
324*4947cdc7SCole Faust
325*4947cdc7SCole Faust	return r.bindLocal(id)
326*4947cdc7SCole Faust}
327*4947cdc7SCole Faust
328*4947cdc7SCole Faustfunc (r *resolver) bindLocal(id *syntax.Ident) bool {
329*4947cdc7SCole Faust	// Mark this name as local to current block.
330*4947cdc7SCole Faust	// Assign it a new local (positive) index in the current container.
331*4947cdc7SCole Faust	_, ok := r.env.bindings[id.Name]
332*4947cdc7SCole Faust	if !ok {
333*4947cdc7SCole Faust		var locals *[]*Binding
334*4947cdc7SCole Faust		if fn := r.container().function; fn != nil {
335*4947cdc7SCole Faust			locals = &fn.Locals
336*4947cdc7SCole Faust		} else {
337*4947cdc7SCole Faust			locals = &r.moduleLocals
338*4947cdc7SCole Faust		}
339*4947cdc7SCole Faust		bind := &Binding{
340*4947cdc7SCole Faust			First: id,
341*4947cdc7SCole Faust			Scope: Local,
342*4947cdc7SCole Faust			Index: len(*locals),
343*4947cdc7SCole Faust		}
344*4947cdc7SCole Faust		r.env.bind(id.Name, bind)
345*4947cdc7SCole Faust		*locals = append(*locals, bind)
346*4947cdc7SCole Faust	}
347*4947cdc7SCole Faust
348*4947cdc7SCole Faust	r.use(id)
349*4947cdc7SCole Faust	return ok
350*4947cdc7SCole Faust}
351*4947cdc7SCole Faust
352*4947cdc7SCole Faustfunc (r *resolver) use(id *syntax.Ident) {
353*4947cdc7SCole Faust	use := use{id, r.env}
354*4947cdc7SCole Faust
355*4947cdc7SCole Faust	// The spec says that if there is a global binding of a name
356*4947cdc7SCole Faust	// then all references to that name in that block refer to the
357*4947cdc7SCole Faust	// global, even if the use precedes the def---just as for locals.
358*4947cdc7SCole Faust	// For example, in this code,
359*4947cdc7SCole Faust	//
360*4947cdc7SCole Faust	//   print(len); len=1; print(len)
361*4947cdc7SCole Faust	//
362*4947cdc7SCole Faust	// both occurrences of len refer to the len=1 binding, which
363*4947cdc7SCole Faust	// completely shadows the predeclared len function.
364*4947cdc7SCole Faust	//
365*4947cdc7SCole Faust	// The rationale for these semantics, which differ from Python,
366*4947cdc7SCole Faust	// is that the static meaning of len (a reference to a global)
367*4947cdc7SCole Faust	// does not change depending on where it appears in the file.
368*4947cdc7SCole Faust	// Of course, its dynamic meaning does change, from an error
369*4947cdc7SCole Faust	// into a valid reference, so it's not clear these semantics
370*4947cdc7SCole Faust	// have any practical advantage.
371*4947cdc7SCole Faust	//
372*4947cdc7SCole Faust	// In any case, the Bazel implementation lags behind the spec
373*4947cdc7SCole Faust	// and follows Python behavior, so the first use of len refers
374*4947cdc7SCole Faust	// to the predeclared function.  This typically used in a BUILD
375*4947cdc7SCole Faust	// file that redefines a predeclared name half way through,
376*4947cdc7SCole Faust	// for example:
377*4947cdc7SCole Faust	//
378*4947cdc7SCole Faust	//	proto_library(...) 			# built-in rule
379*4947cdc7SCole Faust	//      load("myproto.bzl", "proto_library")
380*4947cdc7SCole Faust	//	proto_library(...) 			# user-defined rule
381*4947cdc7SCole Faust	//
382*4947cdc7SCole Faust	// We will piggyback support for the legacy semantics on the
383*4947cdc7SCole Faust	// AllowGlobalReassign flag, which is loosely related and also
384*4947cdc7SCole Faust	// required for Bazel.
385*4947cdc7SCole Faust	if AllowGlobalReassign && r.env == r.file {
386*4947cdc7SCole Faust		r.useToplevel(use)
387*4947cdc7SCole Faust		return
388*4947cdc7SCole Faust	}
389*4947cdc7SCole Faust
390*4947cdc7SCole Faust	b := r.container()
391*4947cdc7SCole Faust	b.uses = append(b.uses, use)
392*4947cdc7SCole Faust}
393*4947cdc7SCole Faust
394*4947cdc7SCole Faust// useToplevel resolves use.id as a reference to a name visible at top-level.
395*4947cdc7SCole Faust// The use.env field captures the original environment for error reporting.
396*4947cdc7SCole Faustfunc (r *resolver) useToplevel(use use) (bind *Binding) {
397*4947cdc7SCole Faust	id := use.id
398*4947cdc7SCole Faust
399*4947cdc7SCole Faust	if prev, ok := r.file.bindings[id.Name]; ok {
400*4947cdc7SCole Faust		// use of load-defined name in file block
401*4947cdc7SCole Faust		bind = prev
402*4947cdc7SCole Faust	} else if prev, ok := r.globals[id.Name]; ok {
403*4947cdc7SCole Faust		// use of global declared by module
404*4947cdc7SCole Faust		bind = prev
405*4947cdc7SCole Faust	} else if r.isGlobal != nil && r.isGlobal(id.Name) {
406*4947cdc7SCole Faust		// use of global defined in a previous REPL chunk
407*4947cdc7SCole Faust		bind = &Binding{
408*4947cdc7SCole Faust			First: id, // wrong: this is not even a binding use
409*4947cdc7SCole Faust			Scope: Global,
410*4947cdc7SCole Faust			Index: len(r.moduleGlobals),
411*4947cdc7SCole Faust		}
412*4947cdc7SCole Faust		r.globals[id.Name] = bind
413*4947cdc7SCole Faust		r.moduleGlobals = append(r.moduleGlobals, bind)
414*4947cdc7SCole Faust	} else if prev, ok := r.predeclared[id.Name]; ok {
415*4947cdc7SCole Faust		// repeated use of predeclared or universal
416*4947cdc7SCole Faust		bind = prev
417*4947cdc7SCole Faust	} else if r.isPredeclared(id.Name) {
418*4947cdc7SCole Faust		// use of pre-declared name
419*4947cdc7SCole Faust		bind = &Binding{Scope: Predeclared}
420*4947cdc7SCole Faust		r.predeclared[id.Name] = bind // save it
421*4947cdc7SCole Faust	} else if r.isUniversal(id.Name) {
422*4947cdc7SCole Faust		// use of universal name
423*4947cdc7SCole Faust		if !AllowSet && id.Name == "set" {
424*4947cdc7SCole Faust			r.errorf(id.NamePos, doesnt+"support sets")
425*4947cdc7SCole Faust		}
426*4947cdc7SCole Faust		bind = &Binding{Scope: Universal}
427*4947cdc7SCole Faust		r.predeclared[id.Name] = bind // save it
428*4947cdc7SCole Faust	} else {
429*4947cdc7SCole Faust		bind = &Binding{Scope: Undefined}
430*4947cdc7SCole Faust		var hint string
431*4947cdc7SCole Faust		if n := r.spellcheck(use); n != "" {
432*4947cdc7SCole Faust			hint = fmt.Sprintf(" (did you mean %s?)", n)
433*4947cdc7SCole Faust		}
434*4947cdc7SCole Faust		r.errorf(id.NamePos, "undefined: %s%s", id.Name, hint)
435*4947cdc7SCole Faust	}
436*4947cdc7SCole Faust	id.Binding = bind
437*4947cdc7SCole Faust	return bind
438*4947cdc7SCole Faust}
439*4947cdc7SCole Faust
440*4947cdc7SCole Faust// spellcheck returns the most likely misspelling of
441*4947cdc7SCole Faust// the name use.id in the environment use.env.
442*4947cdc7SCole Faustfunc (r *resolver) spellcheck(use use) string {
443*4947cdc7SCole Faust	var names []string
444*4947cdc7SCole Faust
445*4947cdc7SCole Faust	// locals
446*4947cdc7SCole Faust	for b := use.env; b != nil; b = b.parent {
447*4947cdc7SCole Faust		for name := range b.bindings {
448*4947cdc7SCole Faust			names = append(names, name)
449*4947cdc7SCole Faust		}
450*4947cdc7SCole Faust	}
451*4947cdc7SCole Faust
452*4947cdc7SCole Faust	// globals
453*4947cdc7SCole Faust	//
454*4947cdc7SCole Faust	// We have no way to enumerate the sets whose membership
455*4947cdc7SCole Faust	// tests are isPredeclared, isUniverse, and isGlobal,
456*4947cdc7SCole Faust	// which includes prior names in the REPL session.
457*4947cdc7SCole Faust	for _, bind := range r.moduleGlobals {
458*4947cdc7SCole Faust		names = append(names, bind.First.Name)
459*4947cdc7SCole Faust	}
460*4947cdc7SCole Faust
461*4947cdc7SCole Faust	sort.Strings(names)
462*4947cdc7SCole Faust	return spell.Nearest(use.id.Name, names)
463*4947cdc7SCole Faust}
464*4947cdc7SCole Faust
465*4947cdc7SCole Faust// resolveLocalUses is called when leaving a container (function/module)
466*4947cdc7SCole Faust// block.  It resolves all uses of locals/cells within that block.
467*4947cdc7SCole Faustfunc (b *block) resolveLocalUses() {
468*4947cdc7SCole Faust	unresolved := b.uses[:0]
469*4947cdc7SCole Faust	for _, use := range b.uses {
470*4947cdc7SCole Faust		if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) {
471*4947cdc7SCole Faust			use.id.Binding = bind
472*4947cdc7SCole Faust		} else {
473*4947cdc7SCole Faust			unresolved = append(unresolved, use)
474*4947cdc7SCole Faust		}
475*4947cdc7SCole Faust	}
476*4947cdc7SCole Faust	b.uses = unresolved
477*4947cdc7SCole Faust}
478*4947cdc7SCole Faust
479*4947cdc7SCole Faustfunc (r *resolver) stmts(stmts []syntax.Stmt) {
480*4947cdc7SCole Faust	for _, stmt := range stmts {
481*4947cdc7SCole Faust		r.stmt(stmt)
482*4947cdc7SCole Faust	}
483*4947cdc7SCole Faust}
484*4947cdc7SCole Faust
485*4947cdc7SCole Faustfunc (r *resolver) stmt(stmt syntax.Stmt) {
486*4947cdc7SCole Faust	switch stmt := stmt.(type) {
487*4947cdc7SCole Faust	case *syntax.ExprStmt:
488*4947cdc7SCole Faust		r.expr(stmt.X)
489*4947cdc7SCole Faust
490*4947cdc7SCole Faust	case *syntax.BranchStmt:
491*4947cdc7SCole Faust		if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) {
492*4947cdc7SCole Faust			r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token)
493*4947cdc7SCole Faust		}
494*4947cdc7SCole Faust
495*4947cdc7SCole Faust	case *syntax.IfStmt:
496*4947cdc7SCole Faust		if !AllowGlobalReassign && r.container().function == nil {
497*4947cdc7SCole Faust			r.errorf(stmt.If, "if statement not within a function")
498*4947cdc7SCole Faust		}
499*4947cdc7SCole Faust		r.expr(stmt.Cond)
500*4947cdc7SCole Faust		r.ifstmts++
501*4947cdc7SCole Faust		r.stmts(stmt.True)
502*4947cdc7SCole Faust		r.stmts(stmt.False)
503*4947cdc7SCole Faust		r.ifstmts--
504*4947cdc7SCole Faust
505*4947cdc7SCole Faust	case *syntax.AssignStmt:
506*4947cdc7SCole Faust		r.expr(stmt.RHS)
507*4947cdc7SCole Faust		isAugmented := stmt.Op != syntax.EQ
508*4947cdc7SCole Faust		r.assign(stmt.LHS, isAugmented)
509*4947cdc7SCole Faust
510*4947cdc7SCole Faust	case *syntax.DefStmt:
511*4947cdc7SCole Faust		r.bind(stmt.Name)
512*4947cdc7SCole Faust		fn := &Function{
513*4947cdc7SCole Faust			Name:   stmt.Name.Name,
514*4947cdc7SCole Faust			Pos:    stmt.Def,
515*4947cdc7SCole Faust			Params: stmt.Params,
516*4947cdc7SCole Faust			Body:   stmt.Body,
517*4947cdc7SCole Faust		}
518*4947cdc7SCole Faust		stmt.Function = fn
519*4947cdc7SCole Faust		r.function(fn, stmt.Def)
520*4947cdc7SCole Faust
521*4947cdc7SCole Faust	case *syntax.ForStmt:
522*4947cdc7SCole Faust		if !AllowGlobalReassign && r.container().function == nil {
523*4947cdc7SCole Faust			r.errorf(stmt.For, "for loop not within a function")
524*4947cdc7SCole Faust		}
525*4947cdc7SCole Faust		r.expr(stmt.X)
526*4947cdc7SCole Faust		const isAugmented = false
527*4947cdc7SCole Faust		r.assign(stmt.Vars, isAugmented)
528*4947cdc7SCole Faust		r.loops++
529*4947cdc7SCole Faust		r.stmts(stmt.Body)
530*4947cdc7SCole Faust		r.loops--
531*4947cdc7SCole Faust
532*4947cdc7SCole Faust	case *syntax.WhileStmt:
533*4947cdc7SCole Faust		if !AllowRecursion {
534*4947cdc7SCole Faust			r.errorf(stmt.While, doesnt+"support while loops")
535*4947cdc7SCole Faust		}
536*4947cdc7SCole Faust		if !AllowGlobalReassign && r.container().function == nil {
537*4947cdc7SCole Faust			r.errorf(stmt.While, "while loop not within a function")
538*4947cdc7SCole Faust		}
539*4947cdc7SCole Faust		r.expr(stmt.Cond)
540*4947cdc7SCole Faust		r.loops++
541*4947cdc7SCole Faust		r.stmts(stmt.Body)
542*4947cdc7SCole Faust		r.loops--
543*4947cdc7SCole Faust
544*4947cdc7SCole Faust	case *syntax.ReturnStmt:
545*4947cdc7SCole Faust		if r.container().function == nil {
546*4947cdc7SCole Faust			r.errorf(stmt.Return, "return statement not within a function")
547*4947cdc7SCole Faust		}
548*4947cdc7SCole Faust		if stmt.Result != nil {
549*4947cdc7SCole Faust			r.expr(stmt.Result)
550*4947cdc7SCole Faust		}
551*4947cdc7SCole Faust
552*4947cdc7SCole Faust	case *syntax.LoadStmt:
553*4947cdc7SCole Faust		// A load statement may not be nested in any other statement.
554*4947cdc7SCole Faust		if r.container().function != nil {
555*4947cdc7SCole Faust			r.errorf(stmt.Load, "load statement within a function")
556*4947cdc7SCole Faust		} else if r.loops > 0 {
557*4947cdc7SCole Faust			r.errorf(stmt.Load, "load statement within a loop")
558*4947cdc7SCole Faust		} else if r.ifstmts > 0 {
559*4947cdc7SCole Faust			r.errorf(stmt.Load, "load statement within a conditional")
560*4947cdc7SCole Faust		}
561*4947cdc7SCole Faust
562*4947cdc7SCole Faust		for i, from := range stmt.From {
563*4947cdc7SCole Faust			if from.Name == "" {
564*4947cdc7SCole Faust				r.errorf(from.NamePos, "load: empty identifier")
565*4947cdc7SCole Faust				continue
566*4947cdc7SCole Faust			}
567*4947cdc7SCole Faust			if from.Name[0] == '_' {
568*4947cdc7SCole Faust				r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
569*4947cdc7SCole Faust			}
570*4947cdc7SCole Faust
571*4947cdc7SCole Faust			id := stmt.To[i]
572*4947cdc7SCole Faust			if LoadBindsGlobally {
573*4947cdc7SCole Faust				r.bind(id)
574*4947cdc7SCole Faust			} else if r.bindLocal(id) && !AllowGlobalReassign {
575*4947cdc7SCole Faust				// "Global" in AllowGlobalReassign is a misnomer for "toplevel".
576*4947cdc7SCole Faust				// Sadly we can't report the previous declaration
577*4947cdc7SCole Faust				// as id.Binding may not be set yet.
578*4947cdc7SCole Faust				r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
579*4947cdc7SCole Faust			}
580*4947cdc7SCole Faust		}
581*4947cdc7SCole Faust
582*4947cdc7SCole Faust	default:
583*4947cdc7SCole Faust		log.Panicf("unexpected stmt %T", stmt)
584*4947cdc7SCole Faust	}
585*4947cdc7SCole Faust}
586*4947cdc7SCole Faust
587*4947cdc7SCole Faustfunc (r *resolver) assign(lhs syntax.Expr, isAugmented bool) {
588*4947cdc7SCole Faust	switch lhs := lhs.(type) {
589*4947cdc7SCole Faust	case *syntax.Ident:
590*4947cdc7SCole Faust		// x = ...
591*4947cdc7SCole Faust		r.bind(lhs)
592*4947cdc7SCole Faust
593*4947cdc7SCole Faust	case *syntax.IndexExpr:
594*4947cdc7SCole Faust		// x[i] = ...
595*4947cdc7SCole Faust		r.expr(lhs.X)
596*4947cdc7SCole Faust		r.expr(lhs.Y)
597*4947cdc7SCole Faust
598*4947cdc7SCole Faust	case *syntax.DotExpr:
599*4947cdc7SCole Faust		// x.f = ...
600*4947cdc7SCole Faust		r.expr(lhs.X)
601*4947cdc7SCole Faust
602*4947cdc7SCole Faust	case *syntax.TupleExpr:
603*4947cdc7SCole Faust		// (x, y) = ...
604*4947cdc7SCole Faust		if isAugmented {
605*4947cdc7SCole Faust			r.errorf(syntax.Start(lhs), "can't use tuple expression in augmented assignment")
606*4947cdc7SCole Faust		}
607*4947cdc7SCole Faust		for _, elem := range lhs.List {
608*4947cdc7SCole Faust			r.assign(elem, isAugmented)
609*4947cdc7SCole Faust		}
610*4947cdc7SCole Faust
611*4947cdc7SCole Faust	case *syntax.ListExpr:
612*4947cdc7SCole Faust		// [x, y, z] = ...
613*4947cdc7SCole Faust		if isAugmented {
614*4947cdc7SCole Faust			r.errorf(syntax.Start(lhs), "can't use list expression in augmented assignment")
615*4947cdc7SCole Faust		}
616*4947cdc7SCole Faust		for _, elem := range lhs.List {
617*4947cdc7SCole Faust			r.assign(elem, isAugmented)
618*4947cdc7SCole Faust		}
619*4947cdc7SCole Faust
620*4947cdc7SCole Faust	case *syntax.ParenExpr:
621*4947cdc7SCole Faust		r.assign(lhs.X, isAugmented)
622*4947cdc7SCole Faust
623*4947cdc7SCole Faust	default:
624*4947cdc7SCole Faust		name := strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", lhs), "*syntax."))
625*4947cdc7SCole Faust		r.errorf(syntax.Start(lhs), "can't assign to %s", name)
626*4947cdc7SCole Faust	}
627*4947cdc7SCole Faust}
628*4947cdc7SCole Faust
629*4947cdc7SCole Faustfunc (r *resolver) expr(e syntax.Expr) {
630*4947cdc7SCole Faust	switch e := e.(type) {
631*4947cdc7SCole Faust	case *syntax.Ident:
632*4947cdc7SCole Faust		r.use(e)
633*4947cdc7SCole Faust
634*4947cdc7SCole Faust	case *syntax.Literal:
635*4947cdc7SCole Faust
636*4947cdc7SCole Faust	case *syntax.ListExpr:
637*4947cdc7SCole Faust		for _, x := range e.List {
638*4947cdc7SCole Faust			r.expr(x)
639*4947cdc7SCole Faust		}
640*4947cdc7SCole Faust
641*4947cdc7SCole Faust	case *syntax.CondExpr:
642*4947cdc7SCole Faust		r.expr(e.Cond)
643*4947cdc7SCole Faust		r.expr(e.True)
644*4947cdc7SCole Faust		r.expr(e.False)
645*4947cdc7SCole Faust
646*4947cdc7SCole Faust	case *syntax.IndexExpr:
647*4947cdc7SCole Faust		r.expr(e.X)
648*4947cdc7SCole Faust		r.expr(e.Y)
649*4947cdc7SCole Faust
650*4947cdc7SCole Faust	case *syntax.DictEntry:
651*4947cdc7SCole Faust		r.expr(e.Key)
652*4947cdc7SCole Faust		r.expr(e.Value)
653*4947cdc7SCole Faust
654*4947cdc7SCole Faust	case *syntax.SliceExpr:
655*4947cdc7SCole Faust		r.expr(e.X)
656*4947cdc7SCole Faust		if e.Lo != nil {
657*4947cdc7SCole Faust			r.expr(e.Lo)
658*4947cdc7SCole Faust		}
659*4947cdc7SCole Faust		if e.Hi != nil {
660*4947cdc7SCole Faust			r.expr(e.Hi)
661*4947cdc7SCole Faust		}
662*4947cdc7SCole Faust		if e.Step != nil {
663*4947cdc7SCole Faust			r.expr(e.Step)
664*4947cdc7SCole Faust		}
665*4947cdc7SCole Faust
666*4947cdc7SCole Faust	case *syntax.Comprehension:
667*4947cdc7SCole Faust		// The 'in' operand of the first clause (always a ForClause)
668*4947cdc7SCole Faust		// is resolved in the outer block; consider: [x for x in x].
669*4947cdc7SCole Faust		clause := e.Clauses[0].(*syntax.ForClause)
670*4947cdc7SCole Faust		r.expr(clause.X)
671*4947cdc7SCole Faust
672*4947cdc7SCole Faust		// A list/dict comprehension defines a new lexical block.
673*4947cdc7SCole Faust		// Locals defined within the block will be allotted
674*4947cdc7SCole Faust		// distinct slots in the locals array of the innermost
675*4947cdc7SCole Faust		// enclosing container (function/module) block.
676*4947cdc7SCole Faust		r.push(&block{comp: e})
677*4947cdc7SCole Faust
678*4947cdc7SCole Faust		const isAugmented = false
679*4947cdc7SCole Faust		r.assign(clause.Vars, isAugmented)
680*4947cdc7SCole Faust
681*4947cdc7SCole Faust		for _, clause := range e.Clauses[1:] {
682*4947cdc7SCole Faust			switch clause := clause.(type) {
683*4947cdc7SCole Faust			case *syntax.IfClause:
684*4947cdc7SCole Faust				r.expr(clause.Cond)
685*4947cdc7SCole Faust			case *syntax.ForClause:
686*4947cdc7SCole Faust				r.assign(clause.Vars, isAugmented)
687*4947cdc7SCole Faust				r.expr(clause.X)
688*4947cdc7SCole Faust			}
689*4947cdc7SCole Faust		}
690*4947cdc7SCole Faust		r.expr(e.Body) // body may be *DictEntry
691*4947cdc7SCole Faust		r.pop()
692*4947cdc7SCole Faust
693*4947cdc7SCole Faust	case *syntax.TupleExpr:
694*4947cdc7SCole Faust		for _, x := range e.List {
695*4947cdc7SCole Faust			r.expr(x)
696*4947cdc7SCole Faust		}
697*4947cdc7SCole Faust
698*4947cdc7SCole Faust	case *syntax.DictExpr:
699*4947cdc7SCole Faust		for _, entry := range e.List {
700*4947cdc7SCole Faust			entry := entry.(*syntax.DictEntry)
701*4947cdc7SCole Faust			r.expr(entry.Key)
702*4947cdc7SCole Faust			r.expr(entry.Value)
703*4947cdc7SCole Faust		}
704*4947cdc7SCole Faust
705*4947cdc7SCole Faust	case *syntax.UnaryExpr:
706*4947cdc7SCole Faust		r.expr(e.X)
707*4947cdc7SCole Faust
708*4947cdc7SCole Faust	case *syntax.BinaryExpr:
709*4947cdc7SCole Faust		r.expr(e.X)
710*4947cdc7SCole Faust		r.expr(e.Y)
711*4947cdc7SCole Faust
712*4947cdc7SCole Faust	case *syntax.DotExpr:
713*4947cdc7SCole Faust		r.expr(e.X)
714*4947cdc7SCole Faust		// ignore e.Name
715*4947cdc7SCole Faust
716*4947cdc7SCole Faust	case *syntax.CallExpr:
717*4947cdc7SCole Faust		r.expr(e.Fn)
718*4947cdc7SCole Faust		var seenVarargs, seenKwargs bool
719*4947cdc7SCole Faust		var seenName map[string]bool
720*4947cdc7SCole Faust		var n, p int
721*4947cdc7SCole Faust		for _, arg := range e.Args {
722*4947cdc7SCole Faust			pos, _ := arg.Span()
723*4947cdc7SCole Faust			if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
724*4947cdc7SCole Faust				// **kwargs
725*4947cdc7SCole Faust				if seenKwargs {
726*4947cdc7SCole Faust					r.errorf(pos, "multiple **kwargs not allowed")
727*4947cdc7SCole Faust				}
728*4947cdc7SCole Faust				seenKwargs = true
729*4947cdc7SCole Faust				r.expr(arg)
730*4947cdc7SCole Faust			} else if ok && unop.Op == syntax.STAR {
731*4947cdc7SCole Faust				// *args
732*4947cdc7SCole Faust				if seenKwargs {
733*4947cdc7SCole Faust					r.errorf(pos, "*args may not follow **kwargs")
734*4947cdc7SCole Faust				} else if seenVarargs {
735*4947cdc7SCole Faust					r.errorf(pos, "multiple *args not allowed")
736*4947cdc7SCole Faust				}
737*4947cdc7SCole Faust				seenVarargs = true
738*4947cdc7SCole Faust				r.expr(arg)
739*4947cdc7SCole Faust			} else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
740*4947cdc7SCole Faust				// k=v
741*4947cdc7SCole Faust				n++
742*4947cdc7SCole Faust				if seenKwargs {
743*4947cdc7SCole Faust					r.errorf(pos, "keyword argument may not follow **kwargs")
744*4947cdc7SCole Faust				} else if seenVarargs {
745*4947cdc7SCole Faust					r.errorf(pos, "keyword argument may not follow *args")
746*4947cdc7SCole Faust				}
747*4947cdc7SCole Faust				x := binop.X.(*syntax.Ident)
748*4947cdc7SCole Faust				if seenName[x.Name] {
749*4947cdc7SCole Faust					r.errorf(x.NamePos, "keyword argument %s repeated", x.Name)
750*4947cdc7SCole Faust				} else {
751*4947cdc7SCole Faust					if seenName == nil {
752*4947cdc7SCole Faust						seenName = make(map[string]bool)
753*4947cdc7SCole Faust					}
754*4947cdc7SCole Faust					seenName[x.Name] = true
755*4947cdc7SCole Faust				}
756*4947cdc7SCole Faust				r.expr(binop.Y)
757*4947cdc7SCole Faust			} else {
758*4947cdc7SCole Faust				// positional argument
759*4947cdc7SCole Faust				p++
760*4947cdc7SCole Faust				if seenVarargs {
761*4947cdc7SCole Faust					r.errorf(pos, "positional argument may not follow *args")
762*4947cdc7SCole Faust				} else if seenKwargs {
763*4947cdc7SCole Faust					r.errorf(pos, "positional argument may not follow **kwargs")
764*4947cdc7SCole Faust				} else if len(seenName) > 0 {
765*4947cdc7SCole Faust					r.errorf(pos, "positional argument may not follow named")
766*4947cdc7SCole Faust				}
767*4947cdc7SCole Faust				r.expr(arg)
768*4947cdc7SCole Faust			}
769*4947cdc7SCole Faust		}
770*4947cdc7SCole Faust
771*4947cdc7SCole Faust		// Fail gracefully if compiler-imposed limit is exceeded.
772*4947cdc7SCole Faust		if p >= 256 {
773*4947cdc7SCole Faust			pos, _ := e.Span()
774*4947cdc7SCole Faust			r.errorf(pos, "%v positional arguments in call, limit is 255", p)
775*4947cdc7SCole Faust		}
776*4947cdc7SCole Faust		if n >= 256 {
777*4947cdc7SCole Faust			pos, _ := e.Span()
778*4947cdc7SCole Faust			r.errorf(pos, "%v keyword arguments in call, limit is 255", n)
779*4947cdc7SCole Faust		}
780*4947cdc7SCole Faust
781*4947cdc7SCole Faust	case *syntax.LambdaExpr:
782*4947cdc7SCole Faust		fn := &Function{
783*4947cdc7SCole Faust			Name:   "lambda",
784*4947cdc7SCole Faust			Pos:    e.Lambda,
785*4947cdc7SCole Faust			Params: e.Params,
786*4947cdc7SCole Faust			Body:   []syntax.Stmt{&syntax.ReturnStmt{Result: e.Body}},
787*4947cdc7SCole Faust		}
788*4947cdc7SCole Faust		e.Function = fn
789*4947cdc7SCole Faust		r.function(fn, e.Lambda)
790*4947cdc7SCole Faust
791*4947cdc7SCole Faust	case *syntax.ParenExpr:
792*4947cdc7SCole Faust		r.expr(e.X)
793*4947cdc7SCole Faust
794*4947cdc7SCole Faust	default:
795*4947cdc7SCole Faust		log.Panicf("unexpected expr %T", e)
796*4947cdc7SCole Faust	}
797*4947cdc7SCole Faust}
798*4947cdc7SCole Faust
799*4947cdc7SCole Faustfunc (r *resolver) function(function *Function, pos syntax.Position) {
800*4947cdc7SCole Faust	// Resolve defaults in enclosing environment.
801*4947cdc7SCole Faust	for _, param := range function.Params {
802*4947cdc7SCole Faust		if binary, ok := param.(*syntax.BinaryExpr); ok {
803*4947cdc7SCole Faust			r.expr(binary.Y)
804*4947cdc7SCole Faust		}
805*4947cdc7SCole Faust	}
806*4947cdc7SCole Faust
807*4947cdc7SCole Faust	// Enter function block.
808*4947cdc7SCole Faust	b := &block{function: function}
809*4947cdc7SCole Faust	r.push(b)
810*4947cdc7SCole Faust
811*4947cdc7SCole Faust	var seenOptional bool
812*4947cdc7SCole Faust	var star *syntax.UnaryExpr // * or *args param
813*4947cdc7SCole Faust	var starStar *syntax.Ident // **kwargs ident
814*4947cdc7SCole Faust	var numKwonlyParams int
815*4947cdc7SCole Faust	for _, param := range function.Params {
816*4947cdc7SCole Faust		switch param := param.(type) {
817*4947cdc7SCole Faust		case *syntax.Ident:
818*4947cdc7SCole Faust			// e.g. x
819*4947cdc7SCole Faust			if starStar != nil {
820*4947cdc7SCole Faust				r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name)
821*4947cdc7SCole Faust			} else if star != nil {
822*4947cdc7SCole Faust				numKwonlyParams++
823*4947cdc7SCole Faust			} else if seenOptional {
824*4947cdc7SCole Faust				r.errorf(param.NamePos, "required parameter may not follow optional")
825*4947cdc7SCole Faust			}
826*4947cdc7SCole Faust			if r.bind(param) {
827*4947cdc7SCole Faust				r.errorf(param.NamePos, "duplicate parameter: %s", param.Name)
828*4947cdc7SCole Faust			}
829*4947cdc7SCole Faust
830*4947cdc7SCole Faust		case *syntax.BinaryExpr:
831*4947cdc7SCole Faust			// e.g. y=dflt
832*4947cdc7SCole Faust			if starStar != nil {
833*4947cdc7SCole Faust				r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
834*4947cdc7SCole Faust			} else if star != nil {
835*4947cdc7SCole Faust				numKwonlyParams++
836*4947cdc7SCole Faust			}
837*4947cdc7SCole Faust			if id := param.X.(*syntax.Ident); r.bind(id) {
838*4947cdc7SCole Faust				r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
839*4947cdc7SCole Faust			}
840*4947cdc7SCole Faust			seenOptional = true
841*4947cdc7SCole Faust
842*4947cdc7SCole Faust		case *syntax.UnaryExpr:
843*4947cdc7SCole Faust			// * or *args or **kwargs
844*4947cdc7SCole Faust			if param.Op == syntax.STAR {
845*4947cdc7SCole Faust				if starStar != nil {
846*4947cdc7SCole Faust					r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name)
847*4947cdc7SCole Faust				} else if star != nil {
848*4947cdc7SCole Faust					r.errorf(param.OpPos, "multiple * parameters not allowed")
849*4947cdc7SCole Faust				} else {
850*4947cdc7SCole Faust					star = param
851*4947cdc7SCole Faust				}
852*4947cdc7SCole Faust			} else {
853*4947cdc7SCole Faust				if starStar != nil {
854*4947cdc7SCole Faust					r.errorf(param.OpPos, "multiple ** parameters not allowed")
855*4947cdc7SCole Faust				}
856*4947cdc7SCole Faust				starStar = param.X.(*syntax.Ident)
857*4947cdc7SCole Faust			}
858*4947cdc7SCole Faust		}
859*4947cdc7SCole Faust	}
860*4947cdc7SCole Faust
861*4947cdc7SCole Faust	// Bind the *args and **kwargs parameters at the end,
862*4947cdc7SCole Faust	// so that regular parameters a/b/c are contiguous and
863*4947cdc7SCole Faust	// there is no hole for the "*":
864*4947cdc7SCole Faust	//   def f(a, b, *args, c=0, **kwargs)
865*4947cdc7SCole Faust	//   def f(a, b, *,     c=0, **kwargs)
866*4947cdc7SCole Faust	if star != nil {
867*4947cdc7SCole Faust		if id, _ := star.X.(*syntax.Ident); id != nil {
868*4947cdc7SCole Faust			// *args
869*4947cdc7SCole Faust			if r.bind(id) {
870*4947cdc7SCole Faust				r.errorf(id.NamePos, "duplicate parameter: %s", id.Name)
871*4947cdc7SCole Faust			}
872*4947cdc7SCole Faust			function.HasVarargs = true
873*4947cdc7SCole Faust		} else if numKwonlyParams == 0 {
874*4947cdc7SCole Faust			r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters")
875*4947cdc7SCole Faust		}
876*4947cdc7SCole Faust	}
877*4947cdc7SCole Faust	if starStar != nil {
878*4947cdc7SCole Faust		if r.bind(starStar) {
879*4947cdc7SCole Faust			r.errorf(starStar.NamePos, "duplicate parameter: %s", starStar.Name)
880*4947cdc7SCole Faust		}
881*4947cdc7SCole Faust		function.HasKwargs = true
882*4947cdc7SCole Faust	}
883*4947cdc7SCole Faust
884*4947cdc7SCole Faust	function.NumKwonlyParams = numKwonlyParams
885*4947cdc7SCole Faust	r.stmts(function.Body)
886*4947cdc7SCole Faust
887*4947cdc7SCole Faust	// Resolve all uses of this function's local vars,
888*4947cdc7SCole Faust	// and keep just the remaining uses of free/global vars.
889*4947cdc7SCole Faust	b.resolveLocalUses()
890*4947cdc7SCole Faust
891*4947cdc7SCole Faust	// Leave function block.
892*4947cdc7SCole Faust	r.pop()
893*4947cdc7SCole Faust
894*4947cdc7SCole Faust	// References within the function body to globals are not
895*4947cdc7SCole Faust	// resolved until the end of the module.
896*4947cdc7SCole Faust}
897*4947cdc7SCole Faust
898*4947cdc7SCole Faustfunc (r *resolver) resolveNonLocalUses(b *block) {
899*4947cdc7SCole Faust	// First resolve inner blocks.
900*4947cdc7SCole Faust	for _, child := range b.children {
901*4947cdc7SCole Faust		r.resolveNonLocalUses(child)
902*4947cdc7SCole Faust	}
903*4947cdc7SCole Faust	for _, use := range b.uses {
904*4947cdc7SCole Faust		use.id.Binding = r.lookupLexical(use, use.env)
905*4947cdc7SCole Faust	}
906*4947cdc7SCole Faust}
907*4947cdc7SCole Faust
908*4947cdc7SCole Faust// lookupLocal looks up an identifier within its immediately enclosing function.
909*4947cdc7SCole Faustfunc lookupLocal(use use) *Binding {
910*4947cdc7SCole Faust	for env := use.env; env != nil; env = env.parent {
911*4947cdc7SCole Faust		if bind, ok := env.bindings[use.id.Name]; ok {
912*4947cdc7SCole Faust			if bind.Scope == Free {
913*4947cdc7SCole Faust				// shouldn't exist till later
914*4947cdc7SCole Faust				log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind)
915*4947cdc7SCole Faust			}
916*4947cdc7SCole Faust			return bind // found
917*4947cdc7SCole Faust		}
918*4947cdc7SCole Faust		if env.function != nil {
919*4947cdc7SCole Faust			break
920*4947cdc7SCole Faust		}
921*4947cdc7SCole Faust	}
922*4947cdc7SCole Faust	return nil // not found in this function
923*4947cdc7SCole Faust}
924*4947cdc7SCole Faust
925*4947cdc7SCole Faust// lookupLexical looks up an identifier use.id within its lexically enclosing environment.
926*4947cdc7SCole Faust// The use.env field captures the original environment for error reporting.
927*4947cdc7SCole Faustfunc (r *resolver) lookupLexical(use use, env *block) (bind *Binding) {
928*4947cdc7SCole Faust	if debug {
929*4947cdc7SCole Faust		fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env)
930*4947cdc7SCole Faust		defer func() { fmt.Printf("= %v\n", bind) }()
931*4947cdc7SCole Faust	}
932*4947cdc7SCole Faust
933*4947cdc7SCole Faust	// Is this the file block?
934*4947cdc7SCole Faust	if env == r.file {
935*4947cdc7SCole Faust		return r.useToplevel(use) // file-local, global, predeclared, or not found
936*4947cdc7SCole Faust	}
937*4947cdc7SCole Faust
938*4947cdc7SCole Faust	// Defined in this block?
939*4947cdc7SCole Faust	bind, ok := env.bindings[use.id.Name]
940*4947cdc7SCole Faust	if !ok {
941*4947cdc7SCole Faust		// Defined in parent block?
942*4947cdc7SCole Faust		bind = r.lookupLexical(use, env.parent)
943*4947cdc7SCole Faust		if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) {
944*4947cdc7SCole Faust			// Found in parent block, which belongs to enclosing function.
945*4947cdc7SCole Faust			// Add the parent's binding to the function's freevars,
946*4947cdc7SCole Faust			// and add a new 'free' binding to the inner function's block,
947*4947cdc7SCole Faust			// and turn the parent's local into cell.
948*4947cdc7SCole Faust			if bind.Scope == Local {
949*4947cdc7SCole Faust				bind.Scope = Cell
950*4947cdc7SCole Faust			}
951*4947cdc7SCole Faust			index := len(env.function.FreeVars)
952*4947cdc7SCole Faust			env.function.FreeVars = append(env.function.FreeVars, bind)
953*4947cdc7SCole Faust			bind = &Binding{
954*4947cdc7SCole Faust				First: bind.First,
955*4947cdc7SCole Faust				Scope: Free,
956*4947cdc7SCole Faust				Index: index,
957*4947cdc7SCole Faust			}
958*4947cdc7SCole Faust			if debug {
959*4947cdc7SCole Faust				fmt.Printf("creating freevar %v in function at %s: %s\n",
960*4947cdc7SCole Faust					len(env.function.FreeVars), env.function.Pos, use.id.Name)
961*4947cdc7SCole Faust			}
962*4947cdc7SCole Faust		}
963*4947cdc7SCole Faust
964*4947cdc7SCole Faust		// Memoize, to avoid duplicate free vars
965*4947cdc7SCole Faust		// and redundant global (failing) lookups.
966*4947cdc7SCole Faust		env.bind(use.id.Name, bind)
967*4947cdc7SCole Faust	}
968*4947cdc7SCole Faust	return bind
969*4947cdc7SCole Faust}
970