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