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