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  }