Skip to content

Commit

Permalink
Revert "starlark: add debug API for Locals and FreeVars"
Browse files Browse the repository at this point in the history
This reverts commit b533e7f.
  • Loading branch information
adonovan committed Apr 11, 2024
1 parent b533e7f commit 169c986
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 101 deletions.
6 changes: 3 additions & 3 deletions internal/compile/compile.go
Expand Up @@ -335,7 +335,7 @@ type Funcode struct {
pclinetab []uint16 // mapping from pc to linenum
Locals []Binding // locals, parameters first
Cells []int // indices of Locals that require cells
FreeVars []Binding // for tracing
Freevars []Binding // for tracing
MaxStack int
NumParams int
NumKwonlyParams int
Expand Down Expand Up @@ -520,7 +520,7 @@ func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.St
Name: name,
Doc: docStringFromBody(stmts),
Locals: bindings(locals),
FreeVars: bindings(freevars),
Freevars: bindings(freevars),
},
}

Expand Down Expand Up @@ -887,7 +887,7 @@ func PrintOp(fn *Funcode, pc uint32, op Opcode, arg uint32) {
case ATTR, SETFIELD, PREDECLARED, UNIVERSAL:
comment = fn.Prog.Names[arg]
case FREE:
comment = fn.FreeVars[arg].Name
comment = fn.Freevars[arg].Name
case CALL, CALL_VAR, CALL_KW, CALL_VAR_KW:
comment = fmt.Sprintf("%d pos, %d named", arg>>8, arg&0xff)
default:
Expand Down
4 changes: 2 additions & 2 deletions internal/compile/serial.go
Expand Up @@ -195,7 +195,7 @@ func (e *encoder) function(fn *Funcode) {
for _, index := range fn.Cells {
e.int(index)
}
e.bindings(fn.FreeVars)
e.bindings(fn.Freevars)
e.int(fn.MaxStack)
e.int(fn.NumParams)
e.int(fn.NumKwonlyParams)
Expand Down Expand Up @@ -389,7 +389,7 @@ func (d *decoder) function() *Funcode {
pclinetab: pclinetab,
Locals: locals,
Cells: cells,
FreeVars: freevars,
Freevars: freevars,
MaxStack: maxStack,
NumParams: numParams,
NumKwonlyParams: numKwonlyParams,
Expand Down
44 changes: 13 additions & 31 deletions starlark/debug.go
@@ -1,59 +1,41 @@
package starlark

import (
"go.starlark.net/syntax"
)
import "go.starlark.net/syntax"

// This file defines an experimental API for the debugging tools.
// Some of these declarations expose details of internal packages.
// (The debugger makes liberal use of exported fields of unexported types.)
// Breaking changes may occur without notice.

// A Binding is the name and position of a binding identifier.
type Binding struct {
Name string
Pos syntax.Position
}

// NumLocals returns the number of local variables of this frame.
// It is zero unless fr.Callable() is a *Function.
func (fr *frame) NumLocals() int { return len(fr.locals) }

// Local returns the binding (name and binding position) and value of
// the i'th local variable of the frame's function.
// Beware: the value may be nil if it has not yet been assigned!
// Local returns the value of the i'th local variable.
// It may be nil if not yet assigned.
//
// The index i must be less than [NumLocals].
// Local may be called only while the frame is active.
// Local may be called only for frames whose Callable is a *Function (a
// function defined by Starlark source code), and only while the frame
// is active; it will panic otherwise.
//
// This function is provided only for debugging tools.
func (fr *frame) Local(i int) (Binding, Value) {
return Binding(fr.callable.(*Function).funcode.Locals[i]), fr.locals[i]
}
//
// THIS API IS EXPERIMENTAL AND MAY CHANGE WITHOUT NOTICE.
func (fr *frame) Local(i int) Value { return fr.locals[i] }

// DebugFrame is the debugger API for a frame of the interpreter's call stack.
//
// Most applications have no need for this API; use CallFrame instead.
//
// It may be tempting to use this interface when implementing built-in
// functions. Beware that reflection over the call stack is easily
// abused, leading to built-in functions whose behavior is mysterious
// and unpredictable.
//
// Clients must not retain a DebugFrame nor call any of its methods once
// the current built-in call has returned or execution has resumed
// after a breakpoint as this may have unpredictable effects, including
// but not limited to retention of object that would otherwise be garbage.
type DebugFrame interface {
Callable() Callable // returns the frame's function
NumLocals() int // returns the number of local variables in this frame
Local(i int) (Binding, Value) // returns the binding and value of the (Starlark) frame's ith local variable
Position() syntax.Position // returns the current position of execution in this frame
Callable() Callable // returns the frame's function
Local(i int) Value // returns the value of the (Starlark) frame's ith local variable
Position() syntax.Position // returns the current position of execution in this frame
}

// DebugFrame returns the debugger interface for
// the specified frame of the interpreter's call stack.
// Frame numbering is as for Thread.CallFrame: 0 <= depth < thread.CallStackDepth().
// Frame numbering is as for Thread.CallFrame.
//
// This function is intended for use in debugging tools.
// Most applications should have no need for it; use CallFrame instead.
Expand Down
55 changes: 1 addition & 54 deletions starlark/eval_test.go
Expand Up @@ -824,8 +824,7 @@ func TestFrameLocals(t *testing.T) {
buf.WriteString(", ")
}
name, _ := fn.Param(i)
_, v := fr.Local(i)
fmt.Fprintf(buf, "%s=%s", name, v)
fmt.Fprintf(buf, "%s=%s", name, fr.Local(i))
}
} else {
buf.WriteString("...") // a built-in function
Expand Down Expand Up @@ -1057,55 +1056,3 @@ main()
}()
}
}

func TestDebugFrame(t *testing.T) {
predeclared := starlark.StringDict{
"env": starlark.NewBuiltin("env", func(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
if thread.CallStackDepth() < 2 {
return nil, fmt.Errorf("env must not be called directly")
}
fr := thread.DebugFrame(1) // parent
fn, ok := fr.Callable().(*starlark.Function)
if !ok {
return nil, fmt.Errorf("env must be called from a Starlark function")
}
dict := starlark.NewDict(0)
for i := 0; i < fr.NumLocals(); i++ {
bind, val := fr.Local(i)
if val == nil {
continue
}
dict.SetKey(starlark.String(bind.Name), val) // ignore error
}
for i := 0; i < fn.NumFreeVars(); i++ {
bind, val := fn.FreeVar(i)
dict.SetKey(starlark.String(bind.Name), val) // ignore error
}
dict.Freeze()
return dict, nil
}),
}
const src = `
e = [None]
def f(p):
outer = 3
def g(q):
inner = outer + 1
e[0] = env() # {"q": 2, "inner": 4, "outer": 3}
inner2 = None # not defined at call to env()
g(2)
f(1)
`
thread := new(starlark.Thread)
m, err := starlark.ExecFile(thread, "env.star", src, predeclared)
if err != nil {
t.Fatalf("ExecFile returned error %q, expected panic", err)
}
got := m["e"].(*starlark.List).Index(0).String()
want := `{"q": 2, "inner": 4, "outer": 3}`
if got != want {
t.Errorf("env() returned %s, want %s", got, want)
}
}
4 changes: 2 additions & 2 deletions starlark/interp.go
Expand Up @@ -541,7 +541,7 @@ loop:
case compile.MAKEFUNC:
funcode := f.Prog.Functions[arg]
tuple := stack[sp-1].(Tuple)
n := len(tuple) - len(funcode.FreeVars)
n := len(tuple) - len(funcode.Freevars)
defaults := tuple[:n:n]
freevars := tuple[n:]
stack[sp-1] = &Function{
Expand Down Expand Up @@ -622,7 +622,7 @@ loop:
case compile.FREECELL:
v := fn.freevars[arg].(*cell).v
if v == nil {
err = fmt.Errorf("local variable %s referenced before assignment", f.FreeVars[arg].Name)
err = fmt.Errorf("local variable %s referenced before assignment", f.Freevars[arg].Name)
break loop
}
stack[sp] = v
Expand Down
9 changes: 0 additions & 9 deletions starlark/value.go
Expand Up @@ -775,15 +775,6 @@ func (fn *Function) ParamDefault(i int) Value {
func (fn *Function) HasVarargs() bool { return fn.funcode.HasVarargs }
func (fn *Function) HasKwargs() bool { return fn.funcode.HasKwargs }

// NumFreeVars returns the number of free variables of this function.
func (fn *Function) NumFreeVars() int { return len(fn.funcode.FreeVars) }

// FreeVar returns the binding (name and binding position) and value
// of the i'th free variable of function fn.
func (fn *Function) FreeVar(i int) (Binding, Value) {
return Binding(fn.funcode.FreeVars[i]), fn.freevars[i].(*cell).v
}

// A Builtin is a function implemented in Go.
type Builtin struct {
name string
Expand Down

0 comments on commit 169c986

Please sign in to comment.