mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
eval: Make builtin namespace a field of the Evaler.
This commit is contained in:
parent
8efbde49b9
commit
e06234efb0
|
@ -120,7 +120,7 @@ func hasProperPrefix(s, p string) bool {
|
|||
func iterateVariables(ev *eval.Evaler, ns string, f func(string)) {
|
||||
switch ns {
|
||||
case "":
|
||||
for varname := range eval.Builtin() {
|
||||
for varname := range ev.Builtin {
|
||||
f(varname)
|
||||
}
|
||||
for varname := range ev.Global {
|
||||
|
|
|
@ -24,11 +24,12 @@ func goodFormHead(head string, ed *Editor) bool {
|
|||
// XXX don't stat twice
|
||||
return util.IsExecutable(head) || isDir(head)
|
||||
} else {
|
||||
ev := ed.evaler
|
||||
explode, ns, name := eval.ParseVariable(head)
|
||||
if !explode {
|
||||
switch ns {
|
||||
case "":
|
||||
if eval.Builtin()[eval.FnPrefix+name] != nil || ed.evaler.Global[eval.FnPrefix+name] != nil {
|
||||
if ev.Builtin[eval.FnPrefix+name] != nil || ev.Global[eval.FnPrefix+name] != nil {
|
||||
return true
|
||||
}
|
||||
case "e":
|
||||
|
@ -36,7 +37,7 @@ func goodFormHead(head string, ed *Editor) bool {
|
|||
return true
|
||||
}
|
||||
default:
|
||||
if ed.evaler.Modules[ns] != nil && ed.evaler.Modules[ns][eval.FnPrefix+name] != nil {
|
||||
if ev.Modules[ns] != nil && ev.Modules[ns][eval.FnPrefix+name] != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -215,10 +215,6 @@ func init() {
|
|||
|
||||
{"-ifaddrs", _ifaddrs},
|
||||
}
|
||||
for _, b := range builtinFns {
|
||||
builtinNamespace[FnPrefix+b.Name] = NewRoVariable(b)
|
||||
}
|
||||
|
||||
// For rand and randint.
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
}
|
||||
|
|
|
@ -3,13 +3,21 @@ package eval
|
|||
import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/elves/elvish/daemon/api"
|
||||
)
|
||||
|
||||
var builtinNamespace = Namespace{
|
||||
"pid": NewRoVariable(String(strconv.Itoa(syscall.Getpid()))),
|
||||
"ok": NewRoVariable(OK),
|
||||
"true": NewRoVariable(Bool(true)),
|
||||
"false": NewRoVariable(Bool(false)),
|
||||
"paths": &EnvPathList{envName: "PATH"},
|
||||
"pwd": PwdVariable{},
|
||||
func makeBuiltinNamespace(daemon *api.Client) Namespace {
|
||||
ns := Namespace{
|
||||
"pid": NewRoVariable(String(strconv.Itoa(syscall.Getpid()))),
|
||||
"ok": NewRoVariable(OK),
|
||||
"true": NewRoVariable(Bool(true)),
|
||||
"false": NewRoVariable(Bool(false)),
|
||||
"paths": &EnvPathList{envName: "PATH"},
|
||||
"pwd": PwdVariable{daemon},
|
||||
}
|
||||
for _, b := range builtinFns {
|
||||
ns[FnPrefix+b.Name] = NewRoVariable(b)
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ type scope map[string]bool
|
|||
// compiler maintains the set of states needed when compiling a single source
|
||||
// file.
|
||||
type compiler struct {
|
||||
// Builtin scope.
|
||||
builtin scope
|
||||
// Lexical scopes.
|
||||
scopes []scope
|
||||
// Variables captured from outer scopes.
|
||||
|
@ -25,8 +27,8 @@ type compiler struct {
|
|||
name, text string
|
||||
}
|
||||
|
||||
func compile(sc scope, n *parse.Chunk, name, text string) (op Op, err error) {
|
||||
cp := &compiler{[]scope{sc}, scope{}, 0, 0, name, text}
|
||||
func compile(b, g scope, n *parse.Chunk, name, text string) (op Op, err error) {
|
||||
cp := &compiler{b, []scope{g}, scope{}, 0, 0, name, text}
|
||||
defer util.Catch(&err)
|
||||
return cp.chunkOp(n), nil
|
||||
}
|
||||
|
@ -85,7 +87,7 @@ func (cp *compiler) registerVariableGet(qname string) bool {
|
|||
}
|
||||
// Find in builtin scope
|
||||
if ns == "" || ns == "builtin" {
|
||||
_, ok := builtinNamespace[name]
|
||||
_, ok := cp.builtin[name]
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
|
|
25
eval/eval.go
25
eval/eval.go
|
@ -38,6 +38,7 @@ type Namespace map[string]Variable
|
|||
// Evaler is used to evaluate elvish sources. It maintains runtime context
|
||||
// shared among all evalCtx instances.
|
||||
type Evaler struct {
|
||||
Builtin Namespace
|
||||
Global Namespace
|
||||
Modules map[string]Namespace
|
||||
Daemon *api.Client
|
||||
|
@ -70,11 +71,20 @@ func NewEvaler(daemon *api.Client, toSpawn *daemon.Daemon, dataDir string) *Eval
|
|||
"daemon": makeDaemonNamespace(daemon),
|
||||
}
|
||||
|
||||
return &Evaler{Namespace{}, modules, daemon, toSpawn, nil, dataDir, nil}
|
||||
return &Evaler{
|
||||
Builtin: makeBuiltinNamespace(daemon),
|
||||
Global: Namespace{},
|
||||
Modules: modules,
|
||||
Daemon: daemon,
|
||||
ToSpawn: toSpawn,
|
||||
Editor: nil,
|
||||
DataDir: dataDir,
|
||||
intCh: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (ev *Evaler) searchPaths() []string {
|
||||
return builtinNamespace["paths"].(*EnvPathList).get()
|
||||
return ev.Builtin["paths"].(*EnvPathList).get()
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -256,7 +266,7 @@ func summarize(text string) string {
|
|||
// Compile compiles elvish code in the global scope. If the error is not nil, it
|
||||
// always has type CompilationError.
|
||||
func (ev *Evaler) Compile(n *parse.Chunk, name, text string) (Op, error) {
|
||||
return compile(makeScope(ev.Global), n, name, text)
|
||||
return compile(makeScope(ev.Builtin), makeScope(ev.Global), n, name, text)
|
||||
}
|
||||
|
||||
// PEval evaluates an op in a protected environment so that calls to errorf are
|
||||
|
@ -350,11 +360,6 @@ func (ev *Evaler) Source(fname string) error {
|
|||
return ev.SourceText(fname, src)
|
||||
}
|
||||
|
||||
// Builtin returns the builtin namespace.
|
||||
func Builtin() Namespace {
|
||||
return builtinNamespace
|
||||
}
|
||||
|
||||
// ErrStoreUnconnected is thrown by ResolveVar when a shared: variable needs to
|
||||
// be resolved but the store is not connected.
|
||||
var ErrStoreUnconnected = errors.New("store unconnected")
|
||||
|
@ -368,7 +373,7 @@ func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
|
|||
case "up":
|
||||
return ec.up[name]
|
||||
case "builtin":
|
||||
return builtinNamespace[name]
|
||||
return ec.Builtin[name]
|
||||
case "":
|
||||
if v := ec.getLocal(name); v != nil {
|
||||
return v
|
||||
|
@ -376,7 +381,7 @@ func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
|
|||
if v, ok := ec.up[name]; ok {
|
||||
return v
|
||||
}
|
||||
return builtinNamespace[name]
|
||||
return ec.Builtin[name]
|
||||
case "e":
|
||||
if strings.HasPrefix(name, FnPrefix) {
|
||||
return NewRoVariable(ExternalCmd{name[len(FnPrefix):]})
|
||||
|
|
|
@ -13,10 +13,11 @@ import (
|
|||
"github.com/elves/elvish/util"
|
||||
)
|
||||
|
||||
func TestBuiltinNamespace(t *testing.T) {
|
||||
func TestBuiltinPid(t *testing.T) {
|
||||
pid := strconv.Itoa(syscall.Getpid())
|
||||
if ToString(builtinNamespace["pid"].Get()) != pid {
|
||||
t.Errorf(`ev.builtin["pid"] = %v, want %v`, builtinNamespace["pid"], pid)
|
||||
builtinPid := ToString(makeBuiltinNamespace(nil)["pid"].Get())
|
||||
if builtinPid != pid {
|
||||
t.Errorf(`ev.builtin["pid"] = %v, want %v`, builtinPid, pid)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
eval/pwd.go
15
eval/pwd.go
|
@ -1,10 +1,16 @@
|
|||
package eval
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/daemon/api"
|
||||
)
|
||||
|
||||
// PwdVariable is a variable whose value always reflects the current working
|
||||
// directory. Setting it changes the current working directory.
|
||||
type PwdVariable struct{}
|
||||
type PwdVariable struct {
|
||||
daemon *api.Client
|
||||
}
|
||||
|
||||
var _ Variable = PwdVariable{}
|
||||
|
||||
|
@ -14,12 +20,11 @@ func (PwdVariable) Get() Value {
|
|||
return String(pwd)
|
||||
}
|
||||
|
||||
// TODO(xiaq): Setting $pwd should also record the new directory in the history.
|
||||
func (PwdVariable) Set(v Value) {
|
||||
func (pwd PwdVariable) Set(v Value) {
|
||||
path, ok := v.(String)
|
||||
if !ok {
|
||||
throw(ErrPathMustBeString)
|
||||
}
|
||||
err := Chdir(string(path), nil)
|
||||
err := Chdir(string(path), pwd.daemon)
|
||||
maybeThrow(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user