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