1// 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 5// Package resolve defines a name-resolution pass for Starlark abstract 6// 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 top-level comprehensions and load statements. 12// Identifiers for global variables do not get an index. 13package resolve // import "go.starlark.net/resolve" 14 15// All references to names are statically resolved. Names may be 16// predeclared, global, or local to a function or file. 17// File-local variables include those bound by top-level comprehensions 18// and by load statements. ("Top-level" means "outside of any function".) 19// 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. 27// 28// 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 30// 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 35// "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. 40// In the first pass, we inspect each function, recording in 41// '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 47// that function and discard ones that were found to be function-local. The 48// remaining ones must be either free (local to some lexically enclosing 49// function), or top-level (global, predeclared, or file-local), but we cannot tell 50// which until we have finished inspecting the outermost enclosing 51// function. At that point, we can distinguish local from top-level names 52// (and this is when Python would compute free variables). 53// 54// However, Starlark additionally requires that all references to global 55// names are satisfied by some declaration in the current module; 56// Starlark permits a function to forward-reference a global or file-local 57// that has not 58// 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// 71// 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. 74// 75// Starlark enforces that all global names are assigned at most once on 76// all control flow paths by forbidding if/else statements and loops at 77// top level. A global may be used before it is defined, leading to a 78// 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.) 83 84import ( 85 "fmt" 86 "log" 87 "sort" 88 "strings" 89 90 "go.starlark.net/internal/spell" 91 "go.starlark.net/syntax" 92) 93 94const debug = false 95const doesnt = "this Starlark dialect does not " 96 97// global options 98// These features are either not standard Starlark (yet), or deprecated 99// features of the BUILD language, so we put them behind flags. 100var ( 101 AllowSet = false // allow the 'set' built-in 102 AllowGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top-level 103 AllowRecursion = false // allow while statements and recursive functions 104 LoadBindsGlobally = false // load creates global not file-local bindings (deprecated) 105 106 // obsolete flags for features that are now standard. No effect. 107 AllowNestedDef = true 108 AllowLambda = true 109 AllowFloat = true 110 AllowBitwise = true 111) 112 113// File resolves the specified file and records information about the 114// module in file.Module. 115// 116// 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 120// starlark.Universe.Has for the second, where predeclared is the 121// module's StringDict of predeclared names and starlark.Universe is the 122// standard set of built-ins. 123// The isUniverse predicate is supplied a parameter to avoid a cyclic 124// dependency upon starlark.Universe, not because users should ever need 125// to redefine it. 126func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error { 127 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) 134 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 143 file.Module = &Module{ 144 Locals: r.moduleLocals, 145 Globals: r.moduleGlobals, 146 } 147 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. 156// 157// The isPredeclared and isUniversal predicates behave as for the File function. 158func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) { 159 r := newResolver(nil, isPredeclared, isUniversal) 160 r.expr(expr) 161 r.env.resolveLocalUses() 162 r.resolveNonLocalUses(r.env) // globals & universals 163 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 182func newResolver(isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver { 183 file := new(block) 184 return &resolver{ 185 file: file, 186 env: file, 187 isGlobal: isGlobal, 188 isPredeclared: isPredeclared, 189 isUniversal: isUniversal, 190 globals: make(map[string]*Binding), 191 predeclared: make(map[string]*Binding), 192 } 193} 194 195type resolver struct { 196 // env is the current local environment: 197 // a linked list of blocks, innermost first. 198 // The tail of the list is the file block. 199 env *block 200 file *block // file block (contains load bindings) 201 202 // moduleLocals contains the local variables of the module 203 // (due to load statements and comprehensions outside any function). 204 // moduleGlobals contains the global variables of the module. 205 moduleLocals []*Binding 206 moduleGlobals []*Binding 207 208 // globals maps each global name in the module to its binding. 209 // predeclared does the same for predeclared and universal names. 210 globals map[string]*Binding 211 predeclared map[string]*Binding 212 213 // These predicates report whether a name is 214 // 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 218 219 loops int // number of enclosing for/while loops 220 ifstmts int // number of enclosing if statements loops 221 222 errors ErrorList 223} 224 225// container returns the innermost enclosing "container" block: 226// a function (function != nil) or file (function == nil). 227// Container blocks accumulate local variable bindings. 228func (r *resolver) container() *block { 229 for b := r.env; ; b = b.parent { 230 if b.function != nil || b == r.file { 231 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 { 245 parent *block // nil for file block 246 247 // In the file (root) block, both these fields are nil. 248 function *Function // only for function blocks 249 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. 254 bindings map[string]*Binding 255 256 // children records the child blocks of the current one. 257 children []*block 258 259 // uses records all identifiers seen in this container (function or file), 260 // 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 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.Pos) 277 } 278 if b.comp != nil { 279 return "comprehension block at " + fmt.Sprint(b.comp.Span()) 280 } 281 return "file 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: 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. 300func (r *resolver) bind(id *syntax.Ident) bool { 301 // Binding outside any local (comprehension/function) block? 302 if r.env == r.file { 303 bind, ok := r.file.bindings[id.Name] 304 if !ok { 305 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) 315 } 316 } 317 if ok && !AllowGlobalReassign { 318 r.errorf(id.NamePos, "cannot reassign %s %s declared at %s", 319 bind.Scope, id.Name, bind.First.NamePos) 320 } 321 id.Binding = bind 322 return ok 323 } 324 325 return r.bindLocal(id) 326} 327 328func (r *resolver) bindLocal(id *syntax.Ident) bool { 329 // 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 { 333 var locals *[]*Binding 334 if fn := r.container().function; fn != nil { 335 locals = &fn.Locals 336 } else { 337 locals = &r.moduleLocals 338 } 339 bind := &Binding{ 340 First: id, 341 Scope: Local, 342 Index: len(*locals), 343 } 344 r.env.bind(id.Name, bind) 345 *locals = append(*locals, bind) 346 } 347 348 r.use(id) 349 return ok 350} 351 352func (r *resolver) use(id *syntax.Ident) { 353 use := use{id, r.env} 354 355 // 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. 385 if AllowGlobalReassign && r.env == r.file { 386 r.useToplevel(use) 387 return 388 } 389 390 b := r.container() 391 b.uses = append(b.uses, use) 392} 393 394// useToplevel resolves use.id as a reference to a name visible at top-level. 395// The use.env field captures the original environment for error reporting. 396func (r *resolver) useToplevel(use use) (bind *Binding) { 397 id := use.id 398 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 { 403 // use of global declared by module 404 bind = prev 405 } 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) 414 } else if prev, ok := r.predeclared[id.Name]; ok { 415 // repeated use of predeclared or universal 416 bind = prev 417 } else if r.isPredeclared(id.Name) { 418 // use of pre-declared name 419 bind = &Binding{Scope: Predeclared} 420 r.predeclared[id.Name] = bind // save it 421 } else if r.isUniversal(id.Name) { 422 // use of universal name 423 if !AllowSet && id.Name == "set" { 424 r.errorf(id.NamePos, doesnt+"support sets") 425 } 426 bind = &Binding{Scope: Universal} 427 r.predeclared[id.Name] = bind // save it 428 } else { 429 bind = &Binding{Scope: Undefined} 430 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) 435 } 436 id.Binding = bind 437 return bind 438} 439 440// 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 // 454 // We have no way to enumerate the sets whose membership 455 // tests are isPredeclared, isUniverse, and isGlobal, 456 // which includes prior names in the REPL session. 457 for _, bind := range r.moduleGlobals { 458 names = append(names, bind.First.Name) 459 } 460 461 sort.Strings(names) 462 return spell.Nearest(use.id.Name, names) 463} 464 465// resolveLocalUses is called when leaving a container (function/module) 466// block. It resolves all uses of locals/cells within that block. 467func (b *block) resolveLocalUses() { 468 unresolved := b.uses[:0] 469 for _, use := range b.uses { 470 if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) { 471 use.id.Binding = bind 472 } 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: 496 if !AllowGlobalReassign && r.container().function == nil { 497 r.errorf(stmt.If, "if statement not within a function") 498 } 499 r.expr(stmt.Cond) 500 r.ifstmts++ 501 r.stmts(stmt.True) 502 r.stmts(stmt.False) 503 r.ifstmts-- 504 505 case *syntax.AssignStmt: 506 r.expr(stmt.RHS) 507 isAugmented := stmt.Op != syntax.EQ 508 r.assign(stmt.LHS, isAugmented) 509 510 case *syntax.DefStmt: 511 r.bind(stmt.Name) 512 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) 520 521 case *syntax.ForStmt: 522 if !AllowGlobalReassign && r.container().function == nil { 523 r.errorf(stmt.For, "for loop not within a function") 524 } 525 r.expr(stmt.X) 526 const isAugmented = false 527 r.assign(stmt.Vars, isAugmented) 528 r.loops++ 529 r.stmts(stmt.Body) 530 r.loops-- 531 532 case *syntax.WhileStmt: 533 if !AllowRecursion { 534 r.errorf(stmt.While, doesnt+"support while loops") 535 } 536 if !AllowGlobalReassign && r.container().function == nil { 537 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 544 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: 553 // A load statement may not be nested in any other statement. 554 if r.container().function != nil { 555 r.errorf(stmt.Load, "load statement within a function") 556 } 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") 560 } 561 562 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 } 570 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 } 580 } 581 582 default: 583 log.Panicf("unexpected stmt %T", stmt) 584 } 585} 586 587func (r *resolver) assign(lhs syntax.Expr, isAugmented bool) { 588 switch lhs := lhs.(type) { 589 case *syntax.Ident: 590 // x = ... 591 r.bind(lhs) 592 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) = ... 604 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] = ... 613 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 620 case *syntax.ParenExpr: 621 r.assign(lhs.X, isAugmented) 622 623 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: 635 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: 667 // 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 672 // 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}) 677 678 const isAugmented = false 679 r.assign(clause.Vars, isAugmented) 680 681 for _, clause := range e.Clauses[1:] { 682 switch clause := clause.(type) { 683 case *syntax.IfClause: 684 r.expr(clause.Cond) 685 case *syntax.ForClause: 686 r.assign(clause.Vars, isAugmented) 687 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: 709 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) 718 var seenVarargs, seenKwargs bool 719 var seenName map[string]bool 720 var n, p int 721 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 741 n++ 742 if seenKwargs { 743 r.errorf(pos, "keyword argument may not follow **kwargs") 744 } else if seenVarargs { 745 r.errorf(pos, "keyword argument may not follow *args") 746 } 747 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 } 756 r.expr(binop.Y) 757 } else { 758 // positional argument 759 p++ 760 if seenVarargs { 761 r.errorf(pos, "positional argument may not follow *args") 762 } else if seenKwargs { 763 r.errorf(pos, "positional argument may not follow **kwargs") 764 } else if len(seenName) > 0 { 765 r.errorf(pos, "positional argument may not follow named") 766 } 767 r.expr(arg) 768 } 769 } 770 771 // 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 781 case *syntax.LambdaExpr: 782 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) 790 791 case *syntax.ParenExpr: 792 r.expr(e.X) 793 794 default: 795 log.Panicf("unexpected expr %T", e) 796 } 797} 798 799func (r *resolver) function(function *Function, pos syntax.Position) { 800 // 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 811 var seenOptional bool 812 var star *syntax.UnaryExpr // * or *args param 813 var starStar *syntax.Ident // **kwargs ident 814 var numKwonlyParams int 815 for _, param := range function.Params { 816 switch param := param.(type) { 817 case *syntax.Ident: 818 // e.g. x 819 if starStar != nil { 820 r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name) 821 } else if star != nil { 822 numKwonlyParams++ 823 } else if seenOptional { 824 r.errorf(param.NamePos, "required parameter may not follow optional") 825 } 826 if r.bind(param) { 827 r.errorf(param.NamePos, "duplicate parameter: %s", param.Name) 828 } 829 830 case *syntax.BinaryExpr: 831 // e.g. y=dflt 832 if starStar != nil { 833 r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name) 834 } else if star != nil { 835 numKwonlyParams++ 836 } 837 if id := param.X.(*syntax.Ident); r.bind(id) { 838 r.errorf(param.OpPos, "duplicate parameter: %s", id.Name) 839 } 840 seenOptional = true 841 842 case *syntax.UnaryExpr: 843 // * or *args or **kwargs 844 if param.Op == syntax.STAR { 845 if starStar != nil { 846 r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name) 847 } else if star != nil { 848 r.errorf(param.OpPos, "multiple * parameters not allowed") 849 } else { 850 star = param 851 } 852 } else { 853 if starStar != nil { 854 r.errorf(param.OpPos, "multiple ** parameters not allowed") 855 } 856 starStar = param.X.(*syntax.Ident) 857 } 858 } 859 } 860 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 { 874 r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters") 875 } 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 885 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 { 904 use.id.Binding = r.lookupLexical(use, use.env) 905 } 906} 907 908// lookupLocal looks up an identifier within its immediately enclosing function. 909func lookupLocal(use use) *Binding { 910 for env := use.env; env != nil; env = env.parent { 911 if bind, ok := env.bindings[use.id.Name]; ok { 912 if bind.Scope == Free { 913 // shouldn't exist till later 914 log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind) 915 } 916 return bind // found 917 } 918 if env.function != nil { 919 break 920 } 921 } 922 return nil // not found in this function 923} 924 925// lookupLexical looks up an identifier use.id within its lexically enclosing environment. 926// The use.env field captures the original environment for error reporting. 927func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) { 928 if debug { 929 fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env) 930 defer func() { fmt.Printf("= %v\n", bind) }() 931 } 932 933 // Is this the file block? 934 if env == r.file { 935 return r.useToplevel(use) // file-local, global, predeclared, or not found 936 } 937 938 // Defined in this block? 939 bind, ok := env.bindings[use.id.Name] 940 if !ok { 941 // Defined in parent block? 942 bind = r.lookupLexical(use, env.parent) 943 if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) { 944 // Found in parent block, which belongs to enclosing function. 945 // Add the parent's binding to the function's freevars, 946 // and add a new 'free' binding to the inner function's block, 947 // and turn the parent's local into cell. 948 if bind.Scope == Local { 949 bind.Scope = Cell 950 } 951 index := len(env.function.FreeVars) 952 env.function.FreeVars = append(env.function.FreeVars, bind) 953 bind = &Binding{ 954 First: bind.First, 955 Scope: Free, 956 Index: index, 957 } 958 if debug { 959 fmt.Printf("creating freevar %v in function at %s: %s\n", 960 len(env.function.FreeVars), env.function.Pos, use.id.Name) 961 } 962 } 963 964 // Memoize, to avoid duplicate free vars 965 // and redundant global (failing) lookups. 966 env.bind(use.id.Name, bind) 967 } 968 return bind 969} 970