blob: 59c486ab79c77dd842ec696baf7ea6e551d7e150 [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
11// bound by comprehensions outside any function. Identifiers for global
12// 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
alandonovana1b28d82018-03-13 10:59:24 -040016// predeclared, global, or local to a function or module-level comprehension.
17// The resolver maps each global name to a small integer and each local
18// name to a small integer; these integers enable a fast and compact
19// representation of globals and locals in the evaluator.
20//
21// As an optimization, the resolver classifies each predeclared name as
22// either universal (e.g. None, len) or per-module (e.g. glob in Bazel's
23// build language), enabling the evaluator to share the representation
24// of the universal environment across all modules.
Alan Donovan312d1a52017-10-02 10:10:28 -040025//
26// The lexical environment is a tree of blocks with the module block at
27// its root. The module's child blocks may be of two kinds: functions
28// and comprehensions, and these may have further children of either
29// kind.
30//
31// Python-style resolution requires multiple passes because a name is
32// determined to be local to a function only if the function contains a
alandonovan4956ce92018-08-22 17:44:47 -040033// "binding" use of it; similarly, a name is determined be global (as
34// opposed to predeclared) if the module contains a binding use at the
35// top level. For both locals and globals, a non-binding use may
36// lexically precede the binding to which it is resolved.
37// In the first pass, we inspect each function, recording in
Alan Donovan312d1a52017-10-02 10:10:28 -040038// 'uses' each identifier and the environment block in which it occurs.
39// If a use of a name is binding, such as a function parameter or
40// assignment, we add the name to the block's bindings mapping and add a
41// local variable to the enclosing function.
42//
43// As we finish resolving each function, we inspect all the uses within
alandonovana1b28d82018-03-13 10:59:24 -040044// that function and discard ones that were found to be local. The
Alan Donovan312d1a52017-10-02 10:10:28 -040045// remaining ones must be either free (local to some lexically enclosing
alandonovana1b28d82018-03-13 10:59:24 -040046// function), or nonlocal (global or predeclared), but we cannot tell
47// which until we have finished inspecting the outermost enclosing
48// function. At that point, we can distinguish local from global names
49// (and this is when Python would compute free variables).
Alan Donovan312d1a52017-10-02 10:10:28 -040050//
Alan Donovane3deafe2018-10-23 11:05:09 -040051// However, Starlark additionally requires that all references to global
Alan Donovan312d1a52017-10-02 10:10:28 -040052// names are satisfied by some declaration in the current module;
Alan Donovane3deafe2018-10-23 11:05:09 -040053// Starlark permits a function to forward-reference a global that has not
Alan Donovan312d1a52017-10-02 10:10:28 -040054// been declared yet so long as it is declared before the end of the
55// module. So, instead of re-resolving the unresolved references after
56// each top-level function, we defer this until the end of the module
57// and ensure that all such references are satisfied by some definition.
58//
59// At the end of the module, we visit each of the nested function blocks
60// in bottom-up order, doing a recursive lexical lookup for each
61// unresolved name. If the name is found to be local to some enclosing
62// function, we must create a DefStmt.FreeVar (capture) parameter for
63// each intervening function. We enter these synthetic bindings into
64// the bindings map so that we create at most one freevar per name. If
65// the name was not local, we check that it was defined at module level.
66//
67// We resolve all uses of locals in the module (due to comprehensions)
68// in a similar way and compute the set of its local variables.
69//
Alan Donovane3deafe2018-10-23 11:05:09 -040070// Starlark enforces that all global names are assigned at most once on
Alan Donovan312d1a52017-10-02 10:10:28 -040071// all control flow paths by forbidding if/else statements and loops at
alandonovan4956ce92018-08-22 17:44:47 -040072// top level. A global may be used before it is defined, leading to a
73// dynamic error.
Alan Donovan312d1a52017-10-02 10:10:28 -040074//
75// TODO(adonovan): opt: reuse local slots once locals go out of scope.
76
77import (
78 "fmt"
79 "log"
80 "strings"
81
Alan Donovan6beab7e2018-10-31 17:53:09 -040082 "go.starlark.net/syntax"
Alan Donovan312d1a52017-10-02 10:10:28 -040083)
84
85const debug = false
Alan Donovane3deafe2018-10-23 11:05:09 -040086const doesnt = "this Starlark dialect does not "
Alan Donovan312d1a52017-10-02 10:10:28 -040087
88// global options
Alan Donovane3deafe2018-10-23 11:05:09 -040089// These features are either not standard Starlark (yet), or deprecated
Alan Donovan312d1a52017-10-02 10:10:28 -040090// features of the BUILD language, so we put them behind flags.
91var (
92 AllowNestedDef = false // allow def statements within function bodies
93 AllowLambda = false // allow lambda expressions
94 AllowFloat = false // allow floating point literals, the 'float' built-in, and x / y
Alan Donovan312d1a52017-10-02 10:10:28 -040095 AllowSet = false // allow the 'set' built-in
96 AllowGlobalReassign = false // allow reassignment to globals declared in same file (deprecated)
Hittorp0a5e39a2018-08-09 15:02:30 +030097 AllowBitwise = false // allow bitwise operations (&, |, ^, ~, <<, and >>)
Alessandro Arzilli678bafe2018-12-07 17:28:35 +010098 AllowRecursion = false // allow while statements and recursive functions
Alan Donovan312d1a52017-10-02 10:10:28 -040099)
100
101// File resolves the specified file.
alandonovan631f7b52017-10-11 13:04:47 -0400102//
alandonovana1b28d82018-03-13 10:59:24 -0400103// The isPredeclared and isUniversal predicates report whether a name is
104// a pre-declared identifier (visible in the current module) or a
105// universal identifier (visible in every module).
106// Clients should typically pass predeclared.Has for the first and
Alan Donovane3deafe2018-10-23 11:05:09 -0400107// starlark.Universe.Has for the second, where predeclared is the
108// module's StringDict of predeclared names and starlark.Universe is the
alandonovana1b28d82018-03-13 10:59:24 -0400109// standard set of built-ins.
110// The isUniverse predicate is supplied a parameter to avoid a cyclic
Alan Donovane3deafe2018-10-23 11:05:09 -0400111// dependency upon starlark.Universe, not because users should ever need
alandonovana1b28d82018-03-13 10:59:24 -0400112// to redefine it.
113func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error {
114 r := newResolver(isPredeclared, isUniversal)
Alan Donovan312d1a52017-10-02 10:10:28 -0400115 r.stmts(file.Stmts)
116
117 r.env.resolveLocalUses()
118
119 // At the end of the module, resolve all non-local variable references,
120 // computing closures.
121 // Function bodies may contain forward references to later global declarations.
122 r.resolveNonLocalUses(r.env)
123
124 file.Locals = r.moduleLocals
alandonovana1b28d82018-03-13 10:59:24 -0400125 file.Globals = r.moduleGlobals
Alan Donovan312d1a52017-10-02 10:10:28 -0400126
127 if len(r.errors) > 0 {
128 return r.errors
129 }
130 return nil
131}
132
133// Expr resolves the specified expression.
134// It returns the local variables bound within the expression.
alandonovan631f7b52017-10-11 13:04:47 -0400135//
alandonovana1b28d82018-03-13 10:59:24 -0400136// The isPredeclared and isUniversal predicates behave as for the File function.
137func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*syntax.Ident, error) {
138 r := newResolver(isPredeclared, isUniversal)
Alan Donovan312d1a52017-10-02 10:10:28 -0400139 r.expr(expr)
140 r.env.resolveLocalUses()
alandonovan631f7b52017-10-11 13:04:47 -0400141 r.resolveNonLocalUses(r.env) // globals & universals
Alan Donovan312d1a52017-10-02 10:10:28 -0400142 if len(r.errors) > 0 {
143 return nil, r.errors
144 }
145 return r.moduleLocals, nil
146}
147
148// An ErrorList is a non-empty list of resolver error messages.
149type ErrorList []Error // len > 0
150
151func (e ErrorList) Error() string { return e[0].Error() }
152
153// An Error describes the nature and position of a resolver error.
154type Error struct {
155 Pos syntax.Position
156 Msg string
157}
158
159func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg }
160
161// The Scope of a syntax.Ident indicates what kind of scope it has.
162type Scope uint8
163
164const (
alandonovana1b28d82018-03-13 10:59:24 -0400165 Undefined Scope = iota // name is not defined
166 Local // name is local to its function
167 Free // name is local to some enclosing function
168 Global // name is global to module
169 Predeclared // name is predeclared for this module (e.g. glob)
170 Universal // name is universal (e.g. len)
Alan Donovan312d1a52017-10-02 10:10:28 -0400171)
172
173var scopeNames = [...]string{
alandonovana1b28d82018-03-13 10:59:24 -0400174 Undefined: "undefined",
175 Local: "local",
176 Free: "free",
177 Global: "global",
178 Predeclared: "predeclared",
179 Universal: "universal",
Alan Donovan312d1a52017-10-02 10:10:28 -0400180}
181
182func (scope Scope) String() string { return scopeNames[scope] }
183
alandonovana1b28d82018-03-13 10:59:24 -0400184func newResolver(isPredeclared, isUniversal func(name string) bool) *resolver {
Alan Donovan312d1a52017-10-02 10:10:28 -0400185 return &resolver{
alandonovana1b28d82018-03-13 10:59:24 -0400186 env: new(block), // module block
187 isPredeclared: isPredeclared,
188 isUniversal: isUniversal,
189 globals: make(map[string]*syntax.Ident),
Alan Donovan312d1a52017-10-02 10:10:28 -0400190 }
191}
192
193type resolver struct {
194 // env is the current local environment:
195 // a linked list of blocks, innermost first.
196 // The tail of the list is the module block.
197 env *block
198
199 // moduleLocals contains the local variables of the module
200 // (due to comprehensions outside any function).
alandonovana1b28d82018-03-13 10:59:24 -0400201 // moduleGlobals contains the global variables of the module.
202 moduleLocals []*syntax.Ident
203 moduleGlobals []*syntax.Ident
Alan Donovan312d1a52017-10-02 10:10:28 -0400204
alandonovana1b28d82018-03-13 10:59:24 -0400205 // globals maps each global name in the module
206 // to its first binding occurrence.
207 globals map[string]*syntax.Ident
Alan Donovan312d1a52017-10-02 10:10:28 -0400208
209 // These predicates report whether a name is
alandonovana1b28d82018-03-13 10:59:24 -0400210 // pre-declared, either in this module or universally.
211 isPredeclared, isUniversal func(name string) bool
Alan Donovan312d1a52017-10-02 10:10:28 -0400212
213 loops int // number of enclosing for loops
214
215 errors ErrorList
216}
217
218// container returns the innermost enclosing "container" block:
219// a function (function != nil) or module (function == nil).
220// Container blocks accumulate local variable bindings.
221func (r *resolver) container() *block {
222 for b := r.env; ; b = b.parent {
223 if b.function != nil || b.isModule() {
224 return b
225 }
226 }
227}
228
229func (r *resolver) push(b *block) {
230 r.env.children = append(r.env.children, b)
231 b.parent = r.env
232 r.env = b
233}
234
235func (r *resolver) pop() { r.env = r.env.parent }
236
237type block struct {
238 parent *block // nil for module block
239
240 // In the module (root) block, both these fields are nil.
241 function *syntax.Function // only for function blocks
242 comp *syntax.Comprehension // only for comprehension blocks
243
244 // bindings maps a name to its binding.
245 // A local binding has an index into its innermost enclosing container's locals array.
246 // A free binding has an index into its innermost enclosing function's freevars array.
247 bindings map[string]binding
248
249 // children records the child blocks of the current one.
250 children []*block
251
252 // uses records all identifiers seen in this container (function or module),
253 // and a reference to the environment in which they appear.
254 // As we leave each container block, we resolve them,
255 // so that only free and global ones remain.
256 // At the end of each top-level function we compute closures.
257 uses []use
258}
259
260type binding struct {
261 scope Scope
262 index int
263}
264
265func (b *block) isModule() bool { return b.parent == nil }
266
267func (b *block) bind(name string, bind binding) {
268 if b.bindings == nil {
269 b.bindings = make(map[string]binding)
270 }
271 b.bindings[name] = bind
272}
273
274func (b *block) String() string {
275 if b.function != nil {
276 return "function block at " + fmt.Sprint(b.function.Span())
277 }
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 }
281 return "module block"
282}
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
294// bind creates a binding for id in the current block,
295// if there is not one already, and reports an error if
296// a global was re-bound and allowRebind is false.
297// It returns whether a binding already existed.
298func (r *resolver) bind(id *syntax.Ident, allowRebind bool) bool {
299 // Binding outside any local (comprehension/function) block?
300 if r.env.isModule() {
alandonovana1b28d82018-03-13 10:59:24 -0400301 id.Scope = uint8(Global)
302 prev, ok := r.globals[id.Name]
Alan Donovan312d1a52017-10-02 10:10:28 -0400303 if ok {
Alan Donovan312d1a52017-10-02 10:10:28 -0400304 // Global reassignments are permitted only if
305 // they are of the form x += y. We can't tell
306 // statically whether it's a reassignment
307 // (e.g. int += int) or a mutation (list += list).
308 if !allowRebind && !AllowGlobalReassign {
alandonovana1b28d82018-03-13 10:59:24 -0400309 r.errorf(id.NamePos, "cannot reassign global %s declared at %s", id.Name, prev.NamePos)
Alan Donovan312d1a52017-10-02 10:10:28 -0400310 }
alandonovana1b28d82018-03-13 10:59:24 -0400311 id.Index = prev.Index
Alan Donovan312d1a52017-10-02 10:10:28 -0400312 } else {
alandonovana1b28d82018-03-13 10:59:24 -0400313 // first global binding of this name
314 r.globals[id.Name] = id
315 id.Index = len(r.moduleGlobals)
316 r.moduleGlobals = append(r.moduleGlobals, id)
Alan Donovan312d1a52017-10-02 10:10:28 -0400317 }
318 return ok
319 }
320
321 // Mark this name as local to current block.
322 // Assign it a new local (positive) index in the current container.
323 _, ok := r.env.bindings[id.Name]
324 if !ok {
325 var locals *[]*syntax.Ident
326 if fn := r.container().function; fn != nil {
327 locals = &fn.Locals
328 } else {
329 locals = &r.moduleLocals
330 }
331 r.env.bind(id.Name, binding{Local, len(*locals)})
332 *locals = append(*locals, id)
333 }
334
335 r.use(id)
336 return ok
337}
338
339func (r *resolver) use(id *syntax.Ident) {
alandonovan84a935b2018-11-26 14:42:21 -0500340 // The spec says that if there is a global binding of a name
341 // then all references to that name in that block refer to the
342 // global, even if the use precedes the def---just as for locals.
343 // For example, in this code,
344 //
345 // print(len); len=1; print(len)
346 //
347 // both occurrences of len refer to the len=1 binding, which
348 // completely shadows the predeclared len function.
349 //
350 // The rationale for these semantics, which differ from Python,
351 // is that the static meaning of len (a reference to a global)
352 // does not change depending on where it appears in the file.
353 // Of course, its dynamic meaning does change, from an error
354 // into a valid reference, so it's not clear these semantics
355 // have any practical advantage.
356 //
357 // In any case, the Bazel implementation lags behind the spec
358 // and follows Python behavior, so the first use of len refers
359 // to the predeclared function. This typically used in a BUILD
360 // file that redefines a predeclared name half way through,
361 // for example:
362 //
363 // proto_library(...) # built-in rule
364 // load("myproto.bzl", "proto_library")
365 // proto_library(...) # user-defined rule
366 //
367 // We will piggyback support for the legacy semantics on the
368 // AllowGlobalReassign flag, which is loosely related and also
369 // required for Bazel.
370 if AllowGlobalReassign && r.env.isModule() {
371 r.useGlobal(id)
372 return
373 }
374
Alan Donovan312d1a52017-10-02 10:10:28 -0400375 b := r.container()
376 b.uses = append(b.uses, use{id, r.env})
377}
378
alandonovana1b28d82018-03-13 10:59:24 -0400379func (r *resolver) useGlobal(id *syntax.Ident) binding {
380 var scope Scope
381 if prev, ok := r.globals[id.Name]; ok {
Alan Donovan312d1a52017-10-02 10:10:28 -0400382 scope = Global // use of global declared by module
alandonovana1b28d82018-03-13 10:59:24 -0400383 id.Index = prev.Index
384 } else if r.isPredeclared(id.Name) {
385 scope = Predeclared // use of pre-declared
alandonovan631f7b52017-10-11 13:04:47 -0400386 } else if r.isUniversal(id.Name) {
387 scope = Universal // use of universal name
Alan Donovan312d1a52017-10-02 10:10:28 -0400388 if !AllowFloat && id.Name == "float" {
389 r.errorf(id.NamePos, doesnt+"support floating point")
390 }
391 if !AllowSet && id.Name == "set" {
392 r.errorf(id.NamePos, doesnt+"support sets")
393 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400394 } else {
395 scope = Undefined
396 r.errorf(id.NamePos, "undefined: %s", id.Name)
397 }
398 id.Scope = uint8(scope)
alandonovana1b28d82018-03-13 10:59:24 -0400399 return binding{scope, id.Index}
Alan Donovan312d1a52017-10-02 10:10:28 -0400400}
401
402// resolveLocalUses is called when leaving a container (function/module)
403// block. It resolves all uses of locals within that block.
404func (b *block) resolveLocalUses() {
405 unresolved := b.uses[:0]
406 for _, use := range b.uses {
407 if bind := lookupLocal(use); bind.scope == Local {
408 use.id.Scope = uint8(bind.scope)
409 use.id.Index = bind.index
410 } else {
411 unresolved = append(unresolved, use)
412 }
413 }
414 b.uses = unresolved
415}
416
417func (r *resolver) stmts(stmts []syntax.Stmt) {
418 for _, stmt := range stmts {
419 r.stmt(stmt)
420 }
421}
422
423func (r *resolver) stmt(stmt syntax.Stmt) {
424 switch stmt := stmt.(type) {
425 case *syntax.ExprStmt:
426 r.expr(stmt.X)
427
428 case *syntax.BranchStmt:
429 if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) {
430 r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token)
431 }
432
433 case *syntax.IfStmt:
434 if r.container().function == nil {
435 r.errorf(stmt.If, "if statement not within a function")
436 }
437 r.expr(stmt.Cond)
438 r.stmts(stmt.True)
439 r.stmts(stmt.False)
440
441 case *syntax.AssignStmt:
Hittorp0a5e39a2018-08-09 15:02:30 +0300442 if !AllowBitwise {
443 switch stmt.Op {
444 case syntax.AMP_EQ, syntax.PIPE_EQ, syntax.CIRCUMFLEX_EQ, syntax.LTLT_EQ, syntax.GTGT_EQ:
445 r.errorf(stmt.OpPos, doesnt+"support bitwise operations")
446 }
447 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400448 r.expr(stmt.RHS)
449 // x += y may be a re-binding of a global variable,
450 // but we cannot tell without knowing the type of x.
451 // (If x is a list it's equivalent to x.extend(y).)
452 // The use is conservatively treated as binding,
453 // but we suppress the error if it's an already-bound global.
454 isAugmented := stmt.Op != syntax.EQ
455 r.assign(stmt.LHS, isAugmented)
456
457 case *syntax.DefStmt:
458 if !AllowNestedDef && r.container().function != nil {
459 r.errorf(stmt.Def, doesnt+"support nested def")
460 }
461 const allowRebind = false
462 r.bind(stmt.Name, allowRebind)
463 r.function(stmt.Def, stmt.Name.Name, &stmt.Function)
464
465 case *syntax.ForStmt:
466 if r.container().function == nil {
467 r.errorf(stmt.For, "for loop not within a function")
468 }
469 r.expr(stmt.X)
470 const allowRebind = false
471 r.assign(stmt.Vars, allowRebind)
472 r.loops++
473 r.stmts(stmt.Body)
474 r.loops--
475
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100476 case *syntax.WhileStmt:
477 if !AllowRecursion {
478 r.errorf(stmt.While, "while loop not allowed")
479 }
480 if r.container().function == nil {
481 r.errorf(stmt.While, "while loop not within a function")
482 }
483 r.expr(stmt.Cond)
484 r.loops++
485 r.stmts(stmt.Body)
486 r.loops--
487
Alan Donovan312d1a52017-10-02 10:10:28 -0400488 case *syntax.ReturnStmt:
489 if r.container().function == nil {
490 r.errorf(stmt.Return, "return statement not within a function")
491 }
492 if stmt.Result != nil {
493 r.expr(stmt.Result)
494 }
495
496 case *syntax.LoadStmt:
497 if r.container().function != nil {
498 r.errorf(stmt.Load, "load statement within a function")
499 }
500
501 const allowRebind = false
502 for i, from := range stmt.From {
503 if from.Name == "" {
504 r.errorf(from.NamePos, "load: empty identifier")
505 continue
506 }
507 if from.Name[0] == '_' {
508 r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
509 }
510 r.bind(stmt.To[i], allowRebind)
511 }
512
513 default:
514 log.Fatalf("unexpected stmt %T", stmt)
515 }
516}
517
518func (r *resolver) assign(lhs syntax.Expr, isAugmented bool) {
519 switch lhs := lhs.(type) {
520 case *syntax.Ident:
521 // x = ...
522 allowRebind := isAugmented
523 r.bind(lhs, allowRebind)
524
525 case *syntax.IndexExpr:
526 // x[i] = ...
527 r.expr(lhs.X)
528 r.expr(lhs.Y)
529
530 case *syntax.DotExpr:
531 // x.f = ...
532 r.expr(lhs.X)
533
534 case *syntax.TupleExpr:
535 // (x, y) = ...
536 if len(lhs.List) == 0 {
537 r.errorf(syntax.Start(lhs), "can't assign to ()")
538 }
539 if isAugmented {
540 r.errorf(syntax.Start(lhs), "can't use tuple expression in augmented assignment")
541 }
542 for _, elem := range lhs.List {
543 r.assign(elem, isAugmented)
544 }
545
546 case *syntax.ListExpr:
547 // [x, y, z] = ...
548 if len(lhs.List) == 0 {
549 r.errorf(syntax.Start(lhs), "can't assign to []")
550 }
551 if isAugmented {
552 r.errorf(syntax.Start(lhs), "can't use list expression in augmented assignment")
553 }
554 for _, elem := range lhs.List {
555 r.assign(elem, isAugmented)
556 }
557
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100558 case *syntax.ParenExpr:
559 r.assign(lhs.X, isAugmented)
560
Alan Donovan312d1a52017-10-02 10:10:28 -0400561 default:
562 name := strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", lhs), "*syntax."))
563 r.errorf(syntax.Start(lhs), "can't assign to %s", name)
564 }
565}
566
567func (r *resolver) expr(e syntax.Expr) {
568 switch e := e.(type) {
569 case *syntax.Ident:
570 r.use(e)
571
572 case *syntax.Literal:
573 if !AllowFloat && e.Token == syntax.FLOAT {
574 r.errorf(e.TokenPos, doesnt+"support floating point")
575 }
576
577 case *syntax.ListExpr:
578 for _, x := range e.List {
579 r.expr(x)
580 }
581
582 case *syntax.CondExpr:
583 r.expr(e.Cond)
584 r.expr(e.True)
585 r.expr(e.False)
586
587 case *syntax.IndexExpr:
588 r.expr(e.X)
589 r.expr(e.Y)
590
591 case *syntax.DictEntry:
592 r.expr(e.Key)
593 r.expr(e.Value)
594
595 case *syntax.SliceExpr:
596 r.expr(e.X)
597 if e.Lo != nil {
598 r.expr(e.Lo)
599 }
600 if e.Hi != nil {
601 r.expr(e.Hi)
602 }
603 if e.Step != nil {
604 r.expr(e.Step)
605 }
606
607 case *syntax.Comprehension:
alandonovan0d5491b2018-03-30 10:42:13 -0400608 // The 'in' operand of the first clause (always a ForClause)
609 // is resolved in the outer block; consider: [x for x in x].
610 clause := e.Clauses[0].(*syntax.ForClause)
611 r.expr(clause.X)
612
Alan Donovan312d1a52017-10-02 10:10:28 -0400613 // A list/dict comprehension defines a new lexical block.
614 // Locals defined within the block will be allotted
615 // distinct slots in the locals array of the innermost
616 // enclosing container (function/module) block.
617 r.push(&block{comp: e})
alandonovan0d5491b2018-03-30 10:42:13 -0400618
Alan Donovan312d1a52017-10-02 10:10:28 -0400619 const allowRebind = false
alandonovan0d5491b2018-03-30 10:42:13 -0400620 r.assign(clause.Vars, allowRebind)
621
622 for _, clause := range e.Clauses[1:] {
Alan Donovan312d1a52017-10-02 10:10:28 -0400623 switch clause := clause.(type) {
624 case *syntax.IfClause:
625 r.expr(clause.Cond)
626 case *syntax.ForClause:
627 r.assign(clause.Vars, allowRebind)
628 r.expr(clause.X)
629 }
630 }
631 r.expr(e.Body) // body may be *DictEntry
632 r.pop()
633
634 case *syntax.TupleExpr:
635 for _, x := range e.List {
636 r.expr(x)
637 }
638
639 case *syntax.DictExpr:
640 for _, entry := range e.List {
641 entry := entry.(*syntax.DictEntry)
642 r.expr(entry.Key)
643 r.expr(entry.Value)
644 }
645
646 case *syntax.UnaryExpr:
Hittorp0a5e39a2018-08-09 15:02:30 +0300647 if !AllowBitwise && e.Op == syntax.TILDE {
648 r.errorf(e.OpPos, doesnt+"support bitwise operations")
649 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400650 r.expr(e.X)
651
652 case *syntax.BinaryExpr:
653 if !AllowFloat && e.Op == syntax.SLASH {
654 r.errorf(e.OpPos, doesnt+"support floating point (use //)")
655 }
Hittorp0a5e39a2018-08-09 15:02:30 +0300656 if !AllowBitwise {
657 switch e.Op {
658 case syntax.AMP, syntax.PIPE, syntax.CIRCUMFLEX, syntax.LTLT, syntax.GTGT:
659 r.errorf(e.OpPos, doesnt+"support bitwise operations")
660 }
661 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400662 r.expr(e.X)
663 r.expr(e.Y)
664
665 case *syntax.DotExpr:
666 r.expr(e.X)
667 // ignore e.Name
668
669 case *syntax.CallExpr:
670 r.expr(e.Fn)
alandonovan2c65f9e2018-12-14 13:46:48 -0500671 var seenVarargs, seenKwargs bool
672 var seenName map[string]bool
Alan Donovan312d1a52017-10-02 10:10:28 -0400673 for _, arg := range e.Args {
674 pos, _ := arg.Span()
675 if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
676 // **kwargs
677 if seenKwargs {
678 r.errorf(pos, "multiple **kwargs not allowed")
679 }
680 seenKwargs = true
681 r.expr(arg)
682 } else if ok && unop.Op == syntax.STAR {
683 // *args
684 if seenKwargs {
685 r.errorf(pos, "*args may not follow **kwargs")
686 } else if seenVarargs {
687 r.errorf(pos, "multiple *args not allowed")
688 }
689 seenVarargs = true
690 r.expr(arg)
691 } else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
692 // k=v
693 if seenKwargs {
694 r.errorf(pos, "argument may not follow **kwargs")
695 }
alandonovan2c65f9e2018-12-14 13:46:48 -0500696 x := binop.X.(*syntax.Ident)
697 if seenName[x.Name] {
698 r.errorf(x.NamePos, "keyword argument %s repeated", x.Name)
699 } else {
700 if seenName == nil {
701 seenName = make(map[string]bool)
702 }
703 seenName[x.Name] = true
704 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400705 r.expr(binop.Y)
706 } else {
707 // positional argument
708 if seenVarargs {
709 r.errorf(pos, "argument may not follow *args")
710 } else if seenKwargs {
711 r.errorf(pos, "argument may not follow **kwargs")
alandonovan2c65f9e2018-12-14 13:46:48 -0500712 } else if len(seenName) > 0 {
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500713 r.errorf(pos, "positional argument may not follow named")
Alan Donovan312d1a52017-10-02 10:10:28 -0400714 }
715 r.expr(arg)
716 }
717 }
718
719 case *syntax.LambdaExpr:
720 if !AllowLambda {
721 r.errorf(e.Lambda, doesnt+"support lambda")
722 }
723 r.function(e.Lambda, "lambda", &e.Function)
724
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100725 case *syntax.ParenExpr:
726 r.expr(e.X)
727
Alan Donovan312d1a52017-10-02 10:10:28 -0400728 default:
729 log.Fatalf("unexpected expr %T", e)
730 }
731}
732
733func (r *resolver) function(pos syntax.Position, name string, function *syntax.Function) {
734 // Resolve defaults in enclosing environment.
735 for _, param := range function.Params {
736 if binary, ok := param.(*syntax.BinaryExpr); ok {
737 r.expr(binary.Y)
738 }
739 }
740
741 // Enter function block.
742 b := &block{function: function}
743 r.push(b)
744
745 const allowRebind = false
alandonovanb7e3b1f2018-12-12 17:14:58 -0500746 var seenOptional bool
747 var star, starStar *syntax.Ident // *args, **kwargs
Alan Donovan312d1a52017-10-02 10:10:28 -0400748 for _, param := range function.Params {
749 switch param := param.(type) {
750 case *syntax.Ident:
751 // e.g. x
alandonovanb7e3b1f2018-12-12 17:14:58 -0500752 if starStar != nil {
753 r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name)
754 } else if star != nil {
755 r.errorf(param.NamePos, "required parameter may not follow * parameter")
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500756 } else if seenOptional {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500757 r.errorf(param.NamePos, "required parameter may not follow optional")
Alan Donovan312d1a52017-10-02 10:10:28 -0400758 }
759 if r.bind(param, allowRebind) {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500760 r.errorf(param.NamePos, "duplicate parameter: %s", param.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400761 }
762
763 case *syntax.BinaryExpr:
764 // e.g. y=dflt
alandonovanb7e3b1f2018-12-12 17:14:58 -0500765 if starStar != nil {
766 r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
767 } else if star != nil {
768 r.errorf(param.OpPos, "optional parameter may not follow *%s", star.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400769 }
770 if id := param.X.(*syntax.Ident); r.bind(id, allowRebind) {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500771 r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400772 }
Alan Donovan1b9d0e72017-11-28 14:19:10 -0500773 seenOptional = true
Alan Donovan312d1a52017-10-02 10:10:28 -0400774
775 case *syntax.UnaryExpr:
776 // *args or **kwargs
alandonovanb7e3b1f2018-12-12 17:14:58 -0500777 id := param.X.(*syntax.Ident)
Alan Donovan312d1a52017-10-02 10:10:28 -0400778 if param.Op == syntax.STAR {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500779 if starStar != nil {
780 r.errorf(param.OpPos, "*%s parameter may not follow **%s", id.Name, starStar.Name)
781 } else if star != nil {
782 r.errorf(param.OpPos, "multiple * parameters not allowed")
783 } else {
784 star = id
Alan Donovan312d1a52017-10-02 10:10:28 -0400785 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400786 } else {
alandonovanb7e3b1f2018-12-12 17:14:58 -0500787 if starStar != nil {
788 r.errorf(param.OpPos, "multiple ** parameters not allowed")
789 } else {
790 starStar = id
Alan Donovan312d1a52017-10-02 10:10:28 -0400791 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400792 }
alandonovanb7e3b1f2018-12-12 17:14:58 -0500793 if r.bind(id, allowRebind) {
794 r.errorf(id.NamePos, "duplicate parameter: %s", id.Name)
Alan Donovan312d1a52017-10-02 10:10:28 -0400795 }
796 }
797 }
alandonovanb7e3b1f2018-12-12 17:14:58 -0500798 function.HasVarargs = star != nil
799 function.HasKwargs = starStar != nil
Alan Donovan312d1a52017-10-02 10:10:28 -0400800 r.stmts(function.Body)
801
802 // Resolve all uses of this function's local vars,
803 // and keep just the remaining uses of free/global vars.
804 b.resolveLocalUses()
805
806 // Leave function block.
807 r.pop()
808
809 // References within the function body to globals are not
810 // resolved until the end of the module.
811}
812
813func (r *resolver) resolveNonLocalUses(b *block) {
814 // First resolve inner blocks.
815 for _, child := range b.children {
816 r.resolveNonLocalUses(child)
817 }
818 for _, use := range b.uses {
819 bind := r.lookupLexical(use.id, use.env)
820 use.id.Scope = uint8(bind.scope)
821 use.id.Index = bind.index
822 }
823}
824
825// lookupLocal looks up an identifier within its immediately enclosing function.
826func lookupLocal(use use) binding {
827 for env := use.env; env != nil; env = env.parent {
828 if bind, ok := env.bindings[use.id.Name]; ok {
829 if bind.scope == Free {
830 // shouldn't exist till later
831 log.Fatalf("%s: internal error: %s, %d", use.id.NamePos, use.id.Name, bind)
832 }
833 return bind // found
834 }
835 if env.function != nil {
836 break
837 }
838 }
839 return binding{} // not found in this function
840}
841
842// lookupLexical looks up an identifier within its lexically enclosing environment.
843func (r *resolver) lookupLexical(id *syntax.Ident, env *block) (bind binding) {
844 if debug {
845 fmt.Printf("lookupLexical %s in %s = ...\n", id.Name, env)
846 defer func() { fmt.Printf("= %d\n", bind) }()
847 }
848
849 // Is this the module block?
850 if env.isModule() {
alandonovana1b28d82018-03-13 10:59:24 -0400851 return r.useGlobal(id) // global, predeclared, or not found
Alan Donovan312d1a52017-10-02 10:10:28 -0400852 }
853
854 // Defined in this block?
855 bind, ok := env.bindings[id.Name]
856 if !ok {
857 // Defined in parent block?
858 bind = r.lookupLexical(id, env.parent)
859 if env.function != nil && (bind.scope == Local || bind.scope == Free) {
860 // Found in parent block, which belongs to enclosing function.
861 id := &syntax.Ident{
862 Name: id.Name,
863 Scope: uint8(bind.scope),
864 Index: bind.index,
865 }
866 bind.scope = Free
867 bind.index = len(env.function.FreeVars)
868 env.function.FreeVars = append(env.function.FreeVars, id)
869 if debug {
870 fmt.Printf("creating freevar %v in function at %s: %s\n",
871 len(env.function.FreeVars), fmt.Sprint(env.function.Span()), id.Name)
872 }
873 }
874
875 // Memoize, to avoid duplicate free vars
876 // and redundant global (failing) lookups.
877 env.bind(id.Name, bind)
878 }
879 return bind
880}