diff options
author | alandonovan <adonovan@google.com> | 2019-03-11 12:31:47 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-11 12:31:47 -0400 |
commit | 6db5e1645715f57c6528c4287b51a206958baa16 (patch) | |
tree | a21870befc815b24bdefb511d436af9d15a44fd7 | |
parent | 3d5a06166f9f46a501d25ec0a7f251772ac820a5 (diff) | |
download | starlark-go-6db5e1645715f57c6528c4287b51a206958baa16.tar.gz |
resolve: add aliases for Binding and Scope (#173)
This restores the nice syntax prior to the refactoring.
-rw-r--r-- | internal/compile/compile.go | 37 | ||||
-rw-r--r-- | resolve/resolve.go | 82 | ||||
-rw-r--r-- | syntax/binding.go | 3 |
3 files changed, 72 insertions, 50 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go index 48d5fc3..4160096 100644 --- a/internal/compile/compile.go +++ b/internal/compile/compile.go @@ -34,6 +34,7 @@ import ( "path/filepath" "strconv" + "go.starlark.net/resolve" "go.starlark.net/syntax" ) @@ -411,8 +412,8 @@ func (fn *Funcode) Position(pc uint32) syntax.Position { return pos } -// bindings converts syntax.Bindings to compiled form. -func bindings(bindings []*syntax.Binding) []Binding { +// bindings converts resolve.Bindings to compiled form. +func bindings(bindings []*resolve.Binding) []Binding { res := make([]Binding, len(bindings)) for i, bind := range bindings { res[i].Name = bind.First.Name @@ -422,14 +423,14 @@ func bindings(bindings []*syntax.Binding) []Binding { } // Expr compiles an expression to a program consisting of a single toplevel function. -func Expr(expr syntax.Expr, name string, locals []*syntax.Binding) *Funcode { +func Expr(expr syntax.Expr, name string, locals []*resolve.Binding) *Funcode { pos := syntax.Start(expr) stmts := []syntax.Stmt{&syntax.ReturnStmt{Result: expr}} return File(stmts, pos, name, locals, nil).Toplevel } // File compiles the statements of a file into a program. -func File(stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*syntax.Binding) *Program { +func File(stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*resolve.Binding) *Program { pcomp := &pcomp{ prog: &Program{ Globals: bindings(globals), @@ -443,7 +444,7 @@ func File(stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals return pcomp.prog } -func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.Stmt, locals, freevars []*syntax.Binding) *Funcode { +func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.Stmt, locals, freevars []*resolve.Binding) *Funcode { fcomp := &fcomp{ pcomp: pcomp, pos: pos, @@ -459,7 +460,7 @@ func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.St // Record indices of locals that require cells. for i, local := range locals { - if local.Scope == syntax.CellScope { + if local.Scope == resolve.Cell { fcomp.fn.Cells = append(fcomp.fn.Cells, i) } } @@ -917,13 +918,13 @@ func (fcomp *fcomp) setPos(pos syntax.Position) { func (fcomp *fcomp) set(id *syntax.Ident) { bind := id.Binding switch bind.Scope { - case syntax.LocalScope: + case resolve.Local: fcomp.emit1(SETLOCAL, uint32(bind.Index)) - case syntax.CellScope: + case resolve.Cell: // TODO(adonovan): opt: make a single op for LOCAL<n>, SETCELL. fcomp.emit1(LOCAL, uint32(bind.Index)) fcomp.emit(SETCELL) - case syntax.GlobalScope: + case resolve.Global: fcomp.emit1(SETGLOBAL, uint32(bind.Index)) default: log.Fatalf("%s: set(%s): not global/local/cell (%d)", id.NamePos, id.Name, bind.Scope) @@ -933,25 +934,25 @@ func (fcomp *fcomp) set(id *syntax.Ident) { // lookup emits code to push the value of the specified variable. func (fcomp *fcomp) lookup(id *syntax.Ident) { bind := id.Binding - if bind.Scope != syntax.UniversalScope { // (universal lookup can't fail) + if bind.Scope != resolve.Universal { // (universal lookup can't fail) fcomp.setPos(id.NamePos) } switch bind.Scope { - case syntax.LocalScope: + case resolve.Local: fcomp.emit1(LOCAL, uint32(bind.Index)) - case syntax.FreeScope: + case resolve.Free: // TODO(adonovan): opt: make a single op for FREE<n>, CELL. fcomp.emit1(FREE, uint32(bind.Index)) fcomp.emit(CELL) - case syntax.CellScope: + case resolve.Cell: // TODO(adonovan): opt: make a single op for LOCAL<n>, CELL. fcomp.emit1(LOCAL, uint32(bind.Index)) fcomp.emit(CELL) - case syntax.GlobalScope: + case resolve.Global: fcomp.emit1(GLOBAL, uint32(bind.Index)) - case syntax.PredeclaredScope: + case resolve.Predeclared: fcomp.emit1(PREDECLARED, fcomp.pcomp.nameIndex(id.Name)) - case syntax.UniversalScope: + case resolve.Universal: fcomp.emit1(UNIVERSAL, fcomp.pcomp.nameIndex(id.Name)) default: log.Fatalf("%s: compiler.lookup(%s): scope = %d", id.NamePos, id.Name, bind.Scope) @@ -1740,9 +1741,9 @@ func (fcomp *fcomp) function(pos syntax.Position, name string, f *syntax.Functio // Don't call fcomp.lookup because we want // the cell itself, not its content. switch freevar.Scope { - case syntax.FreeScope: + case resolve.Free: fcomp.emit1(FREE, uint32(freevar.Index)) - case syntax.CellScope: + case resolve.Cell: fcomp.emit1(LOCAL, uint32(freevar.Index)) } } diff --git a/resolve/resolve.go b/resolve/resolve.go index 18a0bf2..cb63ad8 100644 --- a/resolve/resolve.go +++ b/resolve/resolve.go @@ -137,7 +137,7 @@ func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) // It returns the local variables bound within the expression. // // The isPredeclared and isUniversal predicates behave as for the File function. -func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*syntax.Binding, error) { +func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) { r := newResolver(isPredeclared, isUniversal) r.expr(expr) r.env.resolveLocalUses() @@ -166,11 +166,25 @@ func newResolver(isPredeclared, isUniversal func(name string) bool) *resolver { env: new(block), // module block isPredeclared: isPredeclared, isUniversal: isUniversal, - globals: make(map[string]*syntax.Binding), - predeclared: make(map[string]*syntax.Binding), + globals: make(map[string]*Binding), + predeclared: make(map[string]*Binding), } } +// Declare aliases for types and constants that logically belong here. + +type Binding = syntax.Binding + +const ( + Undefined = syntax.UndefinedScope + Local = syntax.LocalScope + Cell = syntax.CellScope + Free = syntax.FreeScope + Global = syntax.GlobalScope + Predeclared = syntax.PredeclaredScope + Universal = syntax.UniversalScope +) + type resolver struct { // env is the current local environment: // a linked list of blocks, innermost first. @@ -180,13 +194,13 @@ type resolver struct { // moduleLocals contains the local variables of the module // (due to comprehensions outside any function). // moduleGlobals contains the global variables of the module. - moduleLocals []*syntax.Binding - moduleGlobals []*syntax.Binding + moduleLocals []*Binding + moduleGlobals []*Binding // globals maps each global name in the module to its binding. // predeclared does the same for predeclared and universal names. - globals map[string]*syntax.Binding - predeclared map[string]*syntax.Binding + globals map[string]*Binding + predeclared map[string]*Binding // These predicates report whether a name is // pre-declared, either in this module or universally. @@ -226,7 +240,7 @@ type block struct { // bindings maps a name to its binding. // A local binding has an index into its innermost enclosing container's locals array. // A free binding has an index into its innermost enclosing function's freevars array. - bindings map[string]*syntax.Binding + bindings map[string]*Binding // children records the child blocks of the current one. children []*block @@ -241,9 +255,9 @@ type block struct { func (b *block) isModule() bool { return b.parent == nil } -func (b *block) bind(name string, bind *syntax.Binding) { +func (b *block) bind(name string, bind *Binding) { if b.bindings == nil { - b.bindings = make(map[string]*syntax.Binding) + b.bindings = make(map[string]*Binding) } b.bindings[name] = bind } @@ -278,9 +292,9 @@ func (r *resolver) bind(id *syntax.Ident) bool { bind, ok := r.globals[id.Name] if !ok { // first global binding of this name - bind = &syntax.Binding{ + bind = &Binding{ First: id, - Scope: syntax.GlobalScope, + Scope: Global, Index: len(r.moduleGlobals), } r.globals[id.Name] = bind @@ -296,15 +310,15 @@ func (r *resolver) bind(id *syntax.Ident) bool { // Assign it a new local (positive) index in the current container. _, ok := r.env.bindings[id.Name] if !ok { - var locals *[]*syntax.Binding + var locals *[]*Binding if fn := r.container().function; fn != nil { locals = &fn.Locals } else { locals = &r.moduleLocals } - bind := &syntax.Binding{ + bind := &Binding{ First: id, - Scope: syntax.LocalScope, + Scope: Local, Index: len(*locals), } r.env.bind(id.Name, bind) @@ -359,26 +373,30 @@ func (r *resolver) use(id *syntax.Ident) { // useGlobals resolves use.id as a reference to a global. // The use.env field captures the original environment for error reporting. -func (r *resolver) useGlobal(use use) (bind *syntax.Binding) { +func (r *resolver) useGlobal(use use) (bind *Binding) { id := use.id if prev, ok := r.globals[id.Name]; ok { - bind = prev // use of global declared by module + // use of global declared by module + bind = prev } else if prev, ok := r.predeclared[id.Name]; ok { - bind = prev // repeated use of predeclared or universal + // repeated use of predeclared or universal + bind = prev } else if r.isPredeclared(id.Name) { - bind = &syntax.Binding{Scope: syntax.PredeclaredScope} // use of pre-declared name - r.predeclared[id.Name] = bind // save it + // use of pre-declared name + bind = &Binding{Scope: Predeclared} + r.predeclared[id.Name] = bind // save it } else if r.isUniversal(id.Name) { + // use of universal name if !AllowFloat && id.Name == "float" { r.errorf(id.NamePos, doesnt+"support floating point") } if !AllowSet && id.Name == "set" { r.errorf(id.NamePos, doesnt+"support sets") } - bind = &syntax.Binding{Scope: syntax.UniversalScope} // use of universal name - r.predeclared[id.Name] = bind // save it + bind = &Binding{Scope: Universal} + r.predeclared[id.Name] = bind // save it } else { - bind = &syntax.Binding{Scope: syntax.UndefinedScope} + bind = &Binding{Scope: Undefined} var hint string if n := r.spellcheck(use); n != "" { hint = fmt.Sprintf(" (did you mean %s?)", n) @@ -418,7 +436,7 @@ func (r *resolver) spellcheck(use use) string { func (b *block) resolveLocalUses() { unresolved := b.uses[:0] for _, use := range b.uses { - if bind := lookupLocal(use); bind != nil && (bind.Scope == syntax.LocalScope || bind.Scope == syntax.CellScope) { + if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) { use.id.Binding = bind } else { unresolved = append(unresolved, use) @@ -843,10 +861,10 @@ func (r *resolver) resolveNonLocalUses(b *block) { } // lookupLocal looks up an identifier within its immediately enclosing function. -func lookupLocal(use use) *syntax.Binding { +func lookupLocal(use use) *Binding { for env := use.env; env != nil; env = env.parent { if bind, ok := env.bindings[use.id.Name]; ok { - if bind.Scope == syntax.FreeScope { + if bind.Scope == Free { // shouldn't exist till later log.Fatalf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind) } @@ -861,7 +879,7 @@ func lookupLocal(use use) *syntax.Binding { // lookupLexical looks up an identifier use.id within its lexically enclosing environment. // The use.env field captures the original environment for error reporting. -func (r *resolver) lookupLexical(use use, env *block) (bind *syntax.Binding) { +func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) { if debug { fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env) defer func() { fmt.Printf("= %v\n", bind) }() @@ -877,19 +895,19 @@ func (r *resolver) lookupLexical(use use, env *block) (bind *syntax.Binding) { if !ok { // Defined in parent block? bind = r.lookupLexical(use, env.parent) - if env.function != nil && (bind.Scope == syntax.LocalScope || bind.Scope == syntax.FreeScope || bind.Scope == syntax.CellScope) { + if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) { // Found in parent block, which belongs to enclosing function. // Add the parent's binding to the function's freevars, // and add a new 'free' binding to the inner function's block, // and turn the parent's local into cell. - if bind.Scope == syntax.LocalScope { - bind.Scope = syntax.CellScope + if bind.Scope == Local { + bind.Scope = Cell } index := len(env.function.FreeVars) env.function.FreeVars = append(env.function.FreeVars, bind) - bind = &syntax.Binding{ + bind = &Binding{ First: bind.First, - Scope: syntax.FreeScope, + Scope: Free, Index: index, } if debug { diff --git a/syntax/binding.go b/syntax/binding.go index 75339cd..b640ccd 100644 --- a/syntax/binding.go +++ b/syntax/binding.go @@ -6,6 +6,8 @@ package syntax // A Binding ties together all identifiers that denote the same variable. // The resolver computes a binding for every Ident. +// +// Where possible, refer to this type using the alias resolve.Binding. type Binding struct { Scope Scope @@ -20,6 +22,7 @@ type Binding struct { } // The Scope of Binding indicates what kind of scope it has. +// Where possible, refer to these constants using the aliases resolve.Local, etc. type Scope uint8 const ( |