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. // Collect matching variables.
var varnames []string var varnames []string
for varname := range ed.evaler.Builtin() {
if strings.HasPrefix(varname, head) {
varnames = append(varnames, varname)
}
}
for varname := range ed.evaler.Global() { for varname := range ed.evaler.Global() {
if strings.HasPrefix(varname, head) { if strings.HasPrefix(varname, head) {
varnames = append(varnames, varname) varnames = append(varnames, varname)
@ -104,6 +109,11 @@ func complFormHeadInner(head string, ed *Editor) []*candidate {
for special := range isBuiltinSpecial { for special := range isBuiltinSpecial {
foundCommand(special) 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() { for variable := range ed.evaler.Global() {
if strings.HasPrefix(variable, eval.FnPrefix) { if strings.HasPrefix(variable, eval.FnPrefix) {
foundCommand(variable[len(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 // XXX don't stat twice
return util.IsExecutable(head) || isDir(head) return util.IsExecutable(head) || isDir(head)
} else { } else {
return ed.evaler.Global()[eval.FnPrefix+head] != nil || return ed.isExternal[head] ||
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 // Evaler is used to evaluate elvish sources. It maintains runtime context
// shared among all evalCtx instances. // shared among all evalCtx instances.
type Evaler struct { type Evaler struct {
builtin Namespace
global Namespace global Namespace
modules map[string]Namespace modules map[string]Namespace
store *store.Store store *store.Store
@ -57,11 +58,9 @@ func (ec *EvalCtx) evaling(n parse.Node) {
// NewEvaler creates a new Evaler. // NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler { func NewEvaler(st *store.Store) *Evaler {
ev := &Evaler{nil, map[string]Namespace{}, st, nil, nil}
// Construct initial global namespace // Construct initial global namespace
pid := String(strconv.Itoa(syscall.Getpid())) pid := String(strconv.Itoa(syscall.Getpid()))
ev.global = Namespace{ builtin := Namespace{
"pid": NewRoVariable(pid), "pid": NewRoVariable(pid),
"ok": NewRoVariable(OK), "ok": NewRoVariable(OK),
"true": NewRoVariable(Bool(true)), "true": NewRoVariable(Bool(true)),
@ -70,14 +69,14 @@ func NewEvaler(st *store.Store) *Evaler {
"pwd": PwdVariable{}, "pwd": PwdVariable{},
} }
for _, b := range builtinFns { 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 { 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) { func (e *Evaler) AddModule(name string, ns Namespace) {
@ -326,8 +325,13 @@ func (ev *Evaler) Source(fname string) error {
return ev.SourceText(src) 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. // Global returns the global namespace.
func (ev *Evaler) Global() map[string]Variable { func (ev *Evaler) Global() Namespace {
return map[string]Variable(ev.global) return map[string]Variable(ev.global)
} }
@ -339,11 +343,16 @@ func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
return ec.local[name] return ec.local[name]
case "up": case "up":
return ec.up[name] return ec.up[name]
case "builtin":
return ec.builtin[name]
case "": case "":
if v, ok := ec.local[name]; ok { if v, ok := ec.local[name]; ok {
return v return v
} }
return ec.up[name] if v, ok := ec.up[name]; ok {
return v
}
return ec.builtin[name]
case "env", "external", "e", "E": case "env", "external", "e", "E":
if strings.HasPrefix(name, FnPrefix) { if strings.HasPrefix(name, FnPrefix) {
return NewRoVariable(ExternalCmd{name[len(FnPrefix):]}) return NewRoVariable(ExternalCmd{name[len(FnPrefix):]})

View File

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