Add a builtin namespace. Now this is really Pythonic.

The "acme" builtin module finally works.
This commit is contained in:
Qi Xiao 2016-02-22 22:56:23 +01:00
parent 657448acf3
commit 6fbadd6f31
4 changed files with 32 additions and 12 deletions

View File

@ -36,6 +36,11 @@ func complVariable(n parse.Node, ed *Editor) []*candidate {
// Collect matching variables.
var varnames []string
for varname := range ed.evaler.Builtin() {
if strings.HasPrefix(varname, head) {
varnames = append(varnames, varname)
}
}
for varname := range ed.evaler.Global() {
if strings.HasPrefix(varname, head) {
varnames = append(varnames, varname)
@ -104,6 +109,11 @@ func complFormHeadInner(head string, ed *Editor) []*candidate {
for special := range isBuiltinSpecial {
foundCommand(special)
}
for variable := range ed.evaler.Builtin() {
if strings.HasPrefix(variable, eval.FnPrefix) {
foundCommand(variable[len(eval.FnPrefix):])
}
}
for variable := range ed.evaler.Global() {
if strings.HasPrefix(variable, eval.FnPrefix) {
foundCommand(variable[len(eval.FnPrefix):])

View File

@ -34,8 +34,9 @@ func goodFormHead(head string, ed *Editor) bool {
// XXX don't stat twice
return util.IsExecutable(head) || isDir(head)
} else {
return ed.evaler.Global()[eval.FnPrefix+head] != nil ||
ed.isExternal[head]
return ed.isExternal[head] ||
ed.evaler.Builtin()[eval.FnPrefix+head] != nil ||
ed.evaler.Global()[eval.FnPrefix+head] != nil
}
}

View File

@ -32,6 +32,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
store *store.Store
@ -57,11 +58,9 @@ func (ec *EvalCtx) evaling(n parse.Node) {
// NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler {
ev := &Evaler{nil, map[string]Namespace{}, st, nil, nil}
// Construct initial global namespace
pid := String(strconv.Itoa(syscall.Getpid()))
ev.global = Namespace{
builtin := Namespace{
"pid": NewRoVariable(pid),
"ok": NewRoVariable(OK),
"true": NewRoVariable(Bool(true)),
@ -70,14 +69,14 @@ func NewEvaler(st *store.Store) *Evaler {
"pwd": PwdVariable{},
}
for _, b := range builtinFns {
ev.global[FnPrefix+b.Name] = NewRoVariable(b)
builtin[FnPrefix+b.Name] = NewRoVariable(b)
}
return ev
return &Evaler{builtin, Namespace{}, map[string]Namespace{}, st, nil, nil}
}
func (e *Evaler) searchPaths() []string {
return e.global["paths"].(*EnvPathList).get()
return e.builtin["paths"].(*EnvPathList).get()
}
func (e *Evaler) AddModule(name string, ns Namespace) {
@ -326,8 +325,13 @@ func (ev *Evaler) Source(fname string) error {
return ev.SourceText(src)
}
// Builtin returns the builtin namespace.
func (ev *Evaler) Builtin() Namespace {
return map[string]Variable(ev.builtin)
}
// Global returns the global namespace.
func (ev *Evaler) Global() map[string]Variable {
func (ev *Evaler) Global() Namespace {
return map[string]Variable(ev.global)
}
@ -339,11 +343,16 @@ func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
return ec.local[name]
case "up":
return ec.up[name]
case "builtin":
return ec.builtin[name]
case "":
if v, ok := ec.local[name]; ok {
return v
}
return ec.up[name]
if v, ok := ec.up[name]; ok {
return v
}
return ec.builtin[name]
case "env", "external", "e", "E":
if strings.HasPrefix(name, FnPrefix) {
return NewRoVariable(ExternalCmd{name[len(FnPrefix):]})

View File

@ -15,8 +15,8 @@ import (
func TestNewEvaler(t *testing.T) {
ev := NewEvaler(nil)
pid := strconv.Itoa(syscall.Getpid())
if ToString(ev.global["pid"].Get()) != pid {
t.Errorf(`ev.global["pid"] = %v, want %v`, ev.global["pid"], pid)
if ToString(ev.builtin["pid"].Get()) != pid {
t.Errorf(`ev.builtin["pid"] = %v, want %v`, ev.builtin["pid"], pid)
}
}