mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
Move pkg/eval/resolve.go to pkg/edit, and add more introspection methods on *Ns.
This commit is contained in:
parent
5c55e72e78
commit
af0c22c47a
|
@ -513,11 +513,11 @@ func (pureEvaler) EachSpecial(f func(string)) {
|
|||
}
|
||||
|
||||
func (pe pureEvaler) EachNs(f func(string)) {
|
||||
eval.EachNsInTop(pe.ev.Builtin(), pe.ev.Global(), f)
|
||||
eachNsInTop(pe.ev.Builtin(), pe.ev.Global(), f)
|
||||
}
|
||||
|
||||
func (pe pureEvaler) EachVariableInNs(ns string, f func(string)) {
|
||||
eval.EachVariableInTop(pe.ev.Builtin(), pe.ev.Global(), ns, f)
|
||||
eachVariableInTop(pe.ev.Builtin(), pe.ev.Global(), ns, f)
|
||||
}
|
||||
|
||||
func (pe pureEvaler) PurelyEvalPrimary(pn *parse.Primary) interface{} {
|
||||
|
|
66
pkg/edit/ns_helper.go
Normal file
66
pkg/edit/ns_helper.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package edit
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/elves/elvish/pkg/eval"
|
||||
"github.com/elves/elvish/pkg/fsutil"
|
||||
)
|
||||
|
||||
// Calls the passed function for each variable name in namespace ns that can be
|
||||
// found from the top context.
|
||||
func eachVariableInTop(builtin, global *eval.Ns, ns string, f func(s string)) {
|
||||
switch ns {
|
||||
case "builtin:":
|
||||
builtin.IterateNames(f)
|
||||
case "", ":":
|
||||
global.IterateNames(f)
|
||||
builtin.IterateNames(f)
|
||||
case "e:":
|
||||
fsutil.EachExternal(func(cmd string) {
|
||||
f(cmd + eval.FnSuffix)
|
||||
})
|
||||
case "E:":
|
||||
for _, s := range os.Environ() {
|
||||
if i := strings.IndexByte(s, '='); i > 0 {
|
||||
f(s[:i])
|
||||
}
|
||||
}
|
||||
default:
|
||||
segs := eval.SplitQNameSegs(ns)
|
||||
mod := global.IndexName(segs[0])
|
||||
if mod == nil {
|
||||
mod = builtin.IndexName(segs[0])
|
||||
}
|
||||
for _, seg := range segs[1:] {
|
||||
if mod == nil {
|
||||
return
|
||||
}
|
||||
mod = mod.Get().(*eval.Ns).IndexName(seg)
|
||||
}
|
||||
if mod != nil {
|
||||
mod.Get().(*eval.Ns).IterateNames(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calls the passed function for each namespace that can be used from the top
|
||||
// context.
|
||||
func eachNsInTop(builtin, global *eval.Ns, f func(s string)) {
|
||||
f("builtin:")
|
||||
f("e:")
|
||||
f("E:")
|
||||
|
||||
global.IterateNames(func(name string) {
|
||||
if strings.HasSuffix(name, eval.NsSuffix) {
|
||||
f(name)
|
||||
}
|
||||
})
|
||||
|
||||
builtin.IterateNames(func(name string) {
|
||||
if strings.HasSuffix(name, eval.NsSuffix) {
|
||||
f(name)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,43 +1,44 @@
|
|||
package eval
|
||||
package edit
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/elves/elvish/pkg/eval"
|
||||
"github.com/elves/elvish/pkg/eval/vars"
|
||||
)
|
||||
|
||||
var testVar = vars.NewReadOnly("")
|
||||
|
||||
var eachVariableInTopTests = []struct {
|
||||
builtin *Ns
|
||||
global *Ns
|
||||
builtin *eval.Ns
|
||||
global *eval.Ns
|
||||
ns string
|
||||
wantNames []string
|
||||
}{
|
||||
{
|
||||
builtin: NsBuilder{"foo": testVar, "bar": testVar}.Ns(),
|
||||
global: NsBuilder{"lorem": testVar, "ipsum": testVar}.Ns(),
|
||||
builtin: eval.NsBuilder{"foo": testVar, "bar": testVar}.Ns(),
|
||||
global: eval.NsBuilder{"lorem": testVar, "ipsum": testVar}.Ns(),
|
||||
ns: "builtin:",
|
||||
wantNames: []string{"bar", "foo"},
|
||||
},
|
||||
{
|
||||
builtin: NsBuilder{"foo": testVar, "bar": testVar}.Ns(),
|
||||
global: NsBuilder{"lorem": testVar, "ipsum": testVar}.Ns(),
|
||||
builtin: eval.NsBuilder{"foo": testVar, "bar": testVar}.Ns(),
|
||||
global: eval.NsBuilder{"lorem": testVar, "ipsum": testVar}.Ns(),
|
||||
ns: "",
|
||||
wantNames: []string{"bar", "foo", "ipsum", "lorem"},
|
||||
},
|
||||
{
|
||||
builtin: NsBuilder{
|
||||
"mod:": vars.NewReadOnly(NsBuilder{"a": testVar, "b": testVar}.Ns()),
|
||||
builtin: eval.NsBuilder{
|
||||
"mod:": vars.NewReadOnly(eval.NsBuilder{"a": testVar, "b": testVar}.Ns()),
|
||||
}.Ns(),
|
||||
ns: "mod:",
|
||||
wantNames: []string{"a", "b"},
|
||||
},
|
||||
{
|
||||
global: NsBuilder{
|
||||
"mod:": vars.NewReadOnly(NsBuilder{"a": testVar, "b": testVar}.Ns()),
|
||||
global: eval.NsBuilder{
|
||||
"mod:": vars.NewReadOnly(eval.NsBuilder{"a": testVar, "b": testVar}.Ns()),
|
||||
}.Ns(),
|
||||
ns: "mod:",
|
||||
wantNames: []string{"a", "b"},
|
||||
|
@ -54,7 +55,7 @@ func TestEachVariableInTop(t *testing.T) {
|
|||
global := getNs(test.global)
|
||||
|
||||
var names []string
|
||||
EachVariableInTop(builtin, global, test.ns,
|
||||
eachVariableInTop(builtin, global, test.ns,
|
||||
func(s string) { names = append(names, s) })
|
||||
sort.Strings(names)
|
||||
|
||||
|
@ -65,24 +66,24 @@ func TestEachVariableInTop(t *testing.T) {
|
|||
}
|
||||
|
||||
var eachNsInTopTests = []struct {
|
||||
builtin *Ns
|
||||
global *Ns
|
||||
builtin *eval.Ns
|
||||
global *eval.Ns
|
||||
wantNames []string
|
||||
}{
|
||||
{
|
||||
wantNames: []string{"E:", "builtin:", "e:"},
|
||||
},
|
||||
{
|
||||
builtin: NsBuilder{"foo:": testVar}.Ns(),
|
||||
builtin: eval.NsBuilder{"foo:": testVar}.Ns(),
|
||||
wantNames: []string{"E:", "builtin:", "e:", "foo:"},
|
||||
},
|
||||
{
|
||||
global: NsBuilder{"foo:": testVar}.Ns(),
|
||||
global: eval.NsBuilder{"foo:": testVar}.Ns(),
|
||||
wantNames: []string{"E:", "builtin:", "e:", "foo:"},
|
||||
},
|
||||
{
|
||||
builtin: NsBuilder{"foo:": testVar}.Ns(),
|
||||
global: NsBuilder{"bar:": testVar}.Ns(),
|
||||
builtin: eval.NsBuilder{"foo:": testVar}.Ns(),
|
||||
global: eval.NsBuilder{"bar:": testVar}.Ns(),
|
||||
wantNames: []string{"E:", "bar:", "builtin:", "e:", "foo:"},
|
||||
},
|
||||
}
|
||||
|
@ -93,7 +94,7 @@ func TestEachNsInTop(t *testing.T) {
|
|||
global := getNs(test.global)
|
||||
|
||||
var names []string
|
||||
EachNsInTop(builtin, global, func(s string) { names = append(names, s) })
|
||||
eachNsInTop(builtin, global, func(s string) { names = append(names, s) })
|
||||
sort.Strings(names)
|
||||
|
||||
if !reflect.DeepEqual(names, test.wantNames) {
|
||||
|
@ -102,9 +103,9 @@ func TestEachNsInTop(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func getNs(ns *Ns) *Ns {
|
||||
func getNs(ns *eval.Ns) *eval.Ns {
|
||||
if ns == nil {
|
||||
return new(Ns)
|
||||
return new(eval.Ns)
|
||||
}
|
||||
return ns
|
||||
}
|
|
@ -65,10 +65,11 @@ func (ns *Ns) Repr(int) string {
|
|||
}
|
||||
|
||||
// Index looks up a variable with the given name, and returns its value if it
|
||||
// exists. This is only used for introspection.
|
||||
// exists. This is only used for introspection from Elvish code; for
|
||||
// introspection from Go code, use IndexName.
|
||||
func (ns *Ns) Index(k interface{}) (interface{}, bool) {
|
||||
if ks, ok := k.(string); ok {
|
||||
variable := ns.indexInner(ks)
|
||||
variable := ns.IndexName(ks)
|
||||
if variable == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
@ -77,7 +78,10 @@ func (ns *Ns) Index(k interface{}) (interface{}, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
func (ns *Ns) indexInner(k string) vars.Var {
|
||||
// Index looks up a variable with the given name, and returns its value if it
|
||||
// exists, or nil if it does not. This is the type-safe version of Index and is
|
||||
// useful for introspection from Go code.
|
||||
func (ns *Ns) IndexName(k string) vars.Var {
|
||||
i := ns.lookup(k)
|
||||
if i != -1 {
|
||||
return ns.slots[i]
|
||||
|
@ -106,6 +110,17 @@ func (ns *Ns) IterateKeys(f func(interface{}) bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// IterateNames produces the names of all variables in the Ns. It is the
|
||||
// type-safe version of IterateKeys and is useful for introspection from Go
|
||||
// code. It doesn't support breaking early.
|
||||
func (ns *Ns) IterateNames(f func(string)) {
|
||||
for i, name := range ns.names {
|
||||
if ns.slots[i] != nil {
|
||||
f(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HasName reports whether the Ns has a variable with the given name.
|
||||
func (ns *Ns) HasName(k string) bool {
|
||||
for i, name := range ns.names {
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
package eval
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/elves/elvish/pkg/fsutil"
|
||||
)
|
||||
|
||||
// EachVariableInTop calls the passed function for each variable name in
|
||||
// namespace ns that can be found from the top context.
|
||||
func EachVariableInTop(builtin, global *Ns, ns string, f func(s string)) {
|
||||
switch ns {
|
||||
case "builtin:":
|
||||
for _, name := range builtin.names {
|
||||
f(name)
|
||||
}
|
||||
case "", ":":
|
||||
for _, name := range global.names {
|
||||
f(name)
|
||||
}
|
||||
for _, name := range builtin.names {
|
||||
f(name)
|
||||
}
|
||||
case "e:":
|
||||
fsutil.EachExternal(func(cmd string) {
|
||||
f(cmd + FnSuffix)
|
||||
})
|
||||
case "E:":
|
||||
for _, s := range os.Environ() {
|
||||
if i := strings.IndexByte(s, '='); i > 0 {
|
||||
f(s[:i])
|
||||
}
|
||||
}
|
||||
default:
|
||||
segs := SplitQNameSegs(ns)
|
||||
mod := global.indexInner(segs[0])
|
||||
if mod == nil {
|
||||
mod = builtin.indexInner(segs[0])
|
||||
}
|
||||
for _, seg := range segs[1:] {
|
||||
if mod == nil {
|
||||
return
|
||||
}
|
||||
mod = mod.Get().(*Ns).indexInner(seg)
|
||||
}
|
||||
if mod != nil {
|
||||
for _, name := range mod.Get().(*Ns).names {
|
||||
f(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EachNsInTop calls the passed function for each namespace that can be used
|
||||
// from the top context.
|
||||
func EachNsInTop(builtin, global *Ns, f func(s string)) {
|
||||
f("builtin:")
|
||||
f("e:")
|
||||
f("E:")
|
||||
|
||||
for _, name := range global.names {
|
||||
if strings.HasSuffix(name, NsSuffix) {
|
||||
f(name)
|
||||
}
|
||||
}
|
||||
for _, name := range builtin.names {
|
||||
if strings.HasSuffix(name, NsSuffix) {
|
||||
f(name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -134,7 +134,7 @@ func deref(fm *Frame, ref *varRef) vars.Var {
|
|||
if !ok {
|
||||
return nil
|
||||
}
|
||||
variable = ns.indexInner(subName)
|
||||
variable = ns.IndexName(subName)
|
||||
if variable == nil {
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user