in repl/repl.go [62:131]
func rep(rl *readline.Instance, thread *starlark.Thread, globals starlark.StringDict) error {
// Each item gets its own context,
// which is cancelled by a SIGINT.
//
// Note: during Readline calls, Control-C causes Readline to return
// ErrInterrupt but does not generate a SIGINT.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
select {
case <-interrupted:
cancel()
case <-ctx.Done():
}
}()
thread.SetLocal("context", ctx)
eof := false
// readline returns EOF, ErrInterrupted, or a line including "\n".
rl.SetPrompt(">>> ")
readline := func() ([]byte, error) {
line, err := rl.Readline()
rl.SetPrompt("... ")
if err != nil {
if err == io.EOF {
eof = true
}
return nil, err
}
return []byte(line + "\n"), nil
}
// parse
f, err := syntax.ParseCompoundStmt("<stdin>", readline)
if err != nil {
if eof {
return io.EOF
}
PrintError(err)
return nil
}
// Treat load bindings as global (like they used to be) in the REPL.
// This is a workaround for github.com/google/starlark-go/issues/224.
// TODO(adonovan): not safe wrt concurrent interpreters.
// Come up with a more principled solution (or plumb options everywhere).
defer func(prev bool) { resolve.LoadBindsGlobally = prev }(resolve.LoadBindsGlobally)
resolve.LoadBindsGlobally = true
if expr := soleExpr(f); expr != nil {
// eval
v, err := starlark.EvalExpr(thread, expr, globals)
if err != nil {
PrintError(err)
return nil
}
// print
if v != starlark.None {
fmt.Println(v)
}
} else if err := starlark.ExecREPLChunk(f, thread, globals); err != nil {
PrintError(err)
return nil
}
return nil
}