aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralandonovan <adonovan@google.com>2019-03-11 12:31:47 -0400
committerGitHub <noreply@github.com>2019-03-11 12:31:47 -0400
commit6db5e1645715f57c6528c4287b51a206958baa16 (patch)
treea21870befc815b24bdefb511d436af9d15a44fd7
parent3d5a06166f9f46a501d25ec0a7f251772ac820a5 (diff)
downloadstarlark-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.go37
-rw-r--r--resolve/resolve.go82
-rw-r--r--syntax/binding.go3
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 (