mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
eval/vals: Simplify the handling of lists and maps.
Also introduce type aliases List and Map to save some typing.
This commit is contained in:
parent
fe6fc5b89a
commit
8b3ca8bd02
|
@ -2,8 +2,6 @@ package vals
|
|||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/xiaq/persistent/vector"
|
||||
)
|
||||
|
||||
// Assocer wraps the Assoc method.
|
||||
|
@ -21,15 +19,15 @@ var (
|
|||
|
||||
// Assoc takes a container, a key and value, and returns a modified version of
|
||||
// the container, in which the key associated with the value. It is implemented
|
||||
// for the builtin type string, and types satisfying the listAssocable,
|
||||
// mapAssocable or Assocer interface. For other types, it returns an error.
|
||||
// for the builtin type string, and List and Map types, and types satisfying the
|
||||
// Assocer interface. For other types, it returns an error.
|
||||
func Assoc(a, k, v interface{}) (interface{}, error) {
|
||||
switch a := a.(type) {
|
||||
case string:
|
||||
return assocString(a, k, v)
|
||||
case listAssocable:
|
||||
case List:
|
||||
return assocList(a, k, v)
|
||||
case mapAssocable:
|
||||
case Map:
|
||||
return a.Assoc(k, v), nil
|
||||
case Assocer:
|
||||
return a.Assoc(k, v)
|
||||
|
@ -49,14 +47,7 @@ func assocString(s string, k, v interface{}) (interface{}, error) {
|
|||
return s[:i] + repl + s[j:], nil
|
||||
}
|
||||
|
||||
type listAssocable interface {
|
||||
Lener
|
||||
Assoc(int, interface{}) vector.Vector
|
||||
}
|
||||
|
||||
var _ listAssocable = vector.Vector(nil)
|
||||
|
||||
func assocList(l listAssocable, k, v interface{}) (interface{}, error) {
|
||||
func assocList(l List, k, v interface{}) (interface{}, error) {
|
||||
kstring, ok := k.(string)
|
||||
if !ok {
|
||||
return nil, errIndexMustBeString
|
||||
|
|
|
@ -9,11 +9,11 @@ type Dissocer interface {
|
|||
|
||||
// Dissoc takes a container and a key, and returns a modified version of the
|
||||
// container, with the given key dissociated with any value. It is implemented
|
||||
// for types satisfying the mapDissocable or Dissocer interface. For other
|
||||
// for the Map type and types satisfying the Dissocer interface. For other
|
||||
// types, it returns nil.
|
||||
func Dissoc(a, k interface{}) interface{} {
|
||||
switch a := a.(type) {
|
||||
case mapDissocable:
|
||||
case Map:
|
||||
return a.Dissoc(k)
|
||||
case Dissocer:
|
||||
return a.Dissoc(k)
|
||||
|
|
|
@ -2,8 +2,6 @@ package vals
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/xiaq/persistent/hashmap"
|
||||
)
|
||||
|
||||
// Equaler wraps the Equal method.
|
||||
|
@ -14,9 +12,9 @@ type Equaler interface {
|
|||
}
|
||||
|
||||
// Equal returns whether two values are equal. It is implemented for the builtin
|
||||
// types bool and string, and types satisfying the listEqualable, mapEqualable
|
||||
// or Equaler interface. For other types, it uses reflect.DeepEqual to compare
|
||||
// the two values.
|
||||
// types bool and string, the List and Map types, and types implementing the
|
||||
// Equaler interface. For other types, it uses reflect.DeepEqual to compare the
|
||||
// two values.
|
||||
func Equal(x, y interface{}) bool {
|
||||
switch x := x.(type) {
|
||||
case nil:
|
||||
|
@ -27,13 +25,13 @@ func Equal(x, y interface{}) bool {
|
|||
return x == y
|
||||
case string:
|
||||
return x == y
|
||||
case listEqualable:
|
||||
if yy, ok := y.(listEqualable); ok {
|
||||
case List:
|
||||
if yy, ok := y.(List); ok {
|
||||
return equalList(x, yy)
|
||||
}
|
||||
return false
|
||||
case mapEqualable:
|
||||
if yy, ok := y.(mapEqualable); ok {
|
||||
case Map:
|
||||
if yy, ok := y.(Map); ok {
|
||||
return equalMap(x, yy)
|
||||
}
|
||||
return false
|
||||
|
@ -44,12 +42,7 @@ func Equal(x, y interface{}) bool {
|
|||
}
|
||||
}
|
||||
|
||||
type listEqualable interface {
|
||||
Lener
|
||||
listIterable
|
||||
}
|
||||
|
||||
func equalList(x, y listEqualable) bool {
|
||||
func equalList(x, y List) bool {
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
|
@ -65,15 +58,7 @@ func equalList(x, y listEqualable) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
type mapEqualable interface {
|
||||
Lener
|
||||
Index(interface{}) (interface{}, bool)
|
||||
Iterator() hashmap.Iterator
|
||||
}
|
||||
|
||||
var _ mapEqualable = hashmap.Map(nil)
|
||||
|
||||
func equalMap(x, y mapEqualable) bool {
|
||||
func equalMap(x, y Map) bool {
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ type Hasher interface {
|
|||
}
|
||||
|
||||
// Hash returns the 32-bit hash of a value. It is implemented for the builtin
|
||||
// types bool and string, and types satisfying the listIterable, mapIterable or
|
||||
// types bool and string, the List and Map types, and types satisfying the
|
||||
// Hasher interface. For other values, it returns 0 (which is OK in terms of
|
||||
// correctness).
|
||||
func Hash(v interface{}) uint32 {
|
||||
|
@ -23,13 +23,13 @@ func Hash(v interface{}) uint32 {
|
|||
return 0
|
||||
case string:
|
||||
return hash.String(v)
|
||||
case listIterable:
|
||||
case List:
|
||||
h := hash.DJBInit
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
h = hash.DJBCombine(h, Hash(it.Elem()))
|
||||
}
|
||||
return h
|
||||
case mapIterable:
|
||||
case Map:
|
||||
h := hash.DJBInit
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
k, v := it.Elem()
|
||||
|
|
|
@ -34,13 +34,14 @@ func (err noSuchKeyError) Error() string {
|
|||
}
|
||||
|
||||
// Index indexes a value with the given key. It is implemented for the builtin
|
||||
// string type, and types satisfying the listIndexable, ErrIndexer or Indexer
|
||||
// interface. For other types, it returns a nil value and a non-nil error.
|
||||
// string type, the List type, and types satisfying the ErrIndexer or Indexer
|
||||
// interface (the Map type implements Indexer). For other types, it returns a
|
||||
// nil value and a non-nil error.
|
||||
func Index(a, k interface{}) (interface{}, error) {
|
||||
switch a := a.(type) {
|
||||
case string:
|
||||
return indexString(a, k)
|
||||
case listIndexable:
|
||||
case List:
|
||||
return indexList(a, k)
|
||||
case ErrIndexer:
|
||||
return a.Index(k)
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/xiaq/persistent/vector"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -14,15 +12,7 @@ var (
|
|||
errIndexOutOfRange = errors.New("index out of range")
|
||||
)
|
||||
|
||||
type listIndexable interface {
|
||||
Lener
|
||||
Index(int) (interface{}, bool)
|
||||
SubVector(int, int) vector.Vector
|
||||
}
|
||||
|
||||
var _ listIndexable = vector.Vector(nil)
|
||||
|
||||
func indexList(l listIndexable, rawIndex interface{}) (interface{}, error) {
|
||||
func indexList(l List, rawIndex interface{}) (interface{}, error) {
|
||||
index, err := ConvertListIndex(rawIndex, l.Len())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -2,8 +2,6 @@ package vals
|
|||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/xiaq/persistent/vector"
|
||||
)
|
||||
|
||||
// Iterator wraps the Iterate method.
|
||||
|
@ -17,7 +15,7 @@ type Iterator interface {
|
|||
// true, calling Iterate(v, f) will not result in an error.
|
||||
func CanIterate(v interface{}) bool {
|
||||
switch v.(type) {
|
||||
case Iterator, string, listIterable:
|
||||
case Iterator, string, List:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -25,9 +23,9 @@ func CanIterate(v interface{}) bool {
|
|||
|
||||
// Iterate iterates the supplied value, and calls the supplied function in each
|
||||
// of its elements. The function can return false to break the iteration. It is
|
||||
// implemented for the builtin type string, and types satisfying the
|
||||
// listIterable or Iterator interface. For these types, it always returns a nil
|
||||
// error. For other types, it doesn't do anything and returns an error.
|
||||
// implemented for the builtin type string, the List type, and types satisfying
|
||||
// the Iterator interface. For these types, it always returns a nil error. For
|
||||
// other types, it doesn't do anything and returns an error.
|
||||
func Iterate(v interface{}, f func(interface{}) bool) error {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
|
@ -37,7 +35,7 @@ func Iterate(v interface{}, f func(interface{}) bool) error {
|
|||
break
|
||||
}
|
||||
}
|
||||
case listIterable:
|
||||
case List:
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
if !f(it.Elem()) {
|
||||
break
|
||||
|
@ -51,12 +49,6 @@ func Iterate(v interface{}, f func(interface{}) bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type listIterable interface {
|
||||
Iterator() vector.Iterator
|
||||
}
|
||||
|
||||
var _ listIterable = vector.Vector(nil)
|
||||
|
||||
// Collect collects all elements of an iterable value into a slice.
|
||||
func Collect(it interface{}) ([]interface{}, error) {
|
||||
var vs []interface{}
|
||||
|
|
|
@ -2,8 +2,6 @@ package vals
|
|||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/xiaq/persistent/hashmap"
|
||||
)
|
||||
|
||||
// KeysIterator wraps the IterateKeys method.
|
||||
|
@ -15,12 +13,12 @@ type KeysIterator interface {
|
|||
|
||||
// IterateKeys iterates the keys of the supplied value, calling the supplied
|
||||
// function for each key. The function can return false to break the iteration.
|
||||
// It is implemented for the mapKeysIterable type and types satisfying the
|
||||
// IterateKeyser interface. For these types, it always returns a nil error. For
|
||||
// other types, it doesn't do anything and returns an error.
|
||||
// It is implemented for the Map type and types satisfying the IterateKeyser
|
||||
// interface. For these types, it always returns a nil error. For other types,
|
||||
// it doesn't do anything and returns an error.
|
||||
func IterateKeys(v interface{}, f func(interface{}) bool) error {
|
||||
switch v := v.(type) {
|
||||
case mapKeysIterable:
|
||||
case Map:
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
k, _ := it.Elem()
|
||||
if !f(k) {
|
||||
|
@ -34,7 +32,3 @@ func IterateKeys(v interface{}, f func(interface{}) bool) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mapKeysIterable interface {
|
||||
Iterator() hashmap.Iterator
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@ package vals
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/xiaq/persistent/hashmap"
|
||||
"github.com/xiaq/persistent/vector"
|
||||
)
|
||||
|
||||
// Kinder wraps the Kind method.
|
||||
|
@ -14,7 +11,7 @@ type Kinder interface {
|
|||
|
||||
// Kind returns the "kind" of the value, a concept similar to type but not yet
|
||||
// very well defined. It is implemented for the builtin nil, bool and string,
|
||||
// the Vector and Map types, and types implementing the Kinder interface. For
|
||||
// the List and Map types, and types implementing the Kinder interface. For
|
||||
// other types, it returns the Go type name of the argument preceded by "!!".
|
||||
func Kind(v interface{}) string {
|
||||
switch v := v.(type) {
|
||||
|
@ -24,9 +21,9 @@ func Kind(v interface{}) string {
|
|||
return "bool"
|
||||
case string:
|
||||
return "string"
|
||||
case vector.Vector:
|
||||
case List:
|
||||
return "list"
|
||||
case hashmap.Map:
|
||||
case Map:
|
||||
return "map"
|
||||
case Kinder:
|
||||
return v.Kind()
|
||||
|
|
|
@ -7,6 +7,9 @@ import (
|
|||
"github.com/xiaq/persistent/vector"
|
||||
)
|
||||
|
||||
// List is an alias for the underlying type used for lists in Elvish.
|
||||
type List = vector.Vector
|
||||
|
||||
// EmptyList is an empty list.
|
||||
var EmptyList = vector.Empty
|
||||
|
||||
|
|
|
@ -4,22 +4,8 @@ import (
|
|||
"github.com/xiaq/persistent/hashmap"
|
||||
)
|
||||
|
||||
type mapIterable interface {
|
||||
Iterator() hashmap.Iterator
|
||||
}
|
||||
type mapAssocable interface {
|
||||
Assoc(k, v interface{}) hashmap.Map
|
||||
}
|
||||
type mapDissocable interface {
|
||||
Dissoc(interface{}) hashmap.Map
|
||||
}
|
||||
|
||||
var (
|
||||
_ mapIterable = hashmap.Map(nil)
|
||||
_ Indexer = hashmap.Map(nil)
|
||||
_ mapAssocable = hashmap.Map(nil)
|
||||
_ mapDissocable = hashmap.Map(nil)
|
||||
)
|
||||
// Map is an alias for the underlying type used for maps in Elvish.
|
||||
type Map = hashmap.Map
|
||||
|
||||
// EmptyMap is an empty map.
|
||||
var EmptyMap = hashmap.New(Equal, Hash)
|
||||
|
|
|
@ -27,8 +27,8 @@ type Reprer interface {
|
|||
// Repr returns the representation for a value, a string that is preferably (but
|
||||
// not necessarily) an Elvish expression that evaluates to the argument. If
|
||||
// indent >= 0, the representation is pretty-printed. It is implemented for the
|
||||
// builtin types nil, bool and string, and types satisfying the listReprable,
|
||||
// mapReprable or Reprer interface. For other types, it uses fmt.Sprint with the
|
||||
// builtin types nil, bool and string, the List and Map and types, and types
|
||||
// satisfying the Reprer interface. For other types, it uses fmt.Sprint with the
|
||||
// format "<unknown %v>".
|
||||
func Repr(v interface{}, indent int) string {
|
||||
switch v := v.(type) {
|
||||
|
@ -43,13 +43,13 @@ func Repr(v interface{}, indent int) string {
|
|||
return parse.Quote(v)
|
||||
case float64:
|
||||
return fmt.Sprintf("(float64 %g)", v)
|
||||
case listReprable:
|
||||
case List:
|
||||
b := ListReprBuilder{Indent: indent}
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
b.WriteElem(Repr(it.Elem(), indent+1))
|
||||
}
|
||||
return b.String()
|
||||
case mapReprable:
|
||||
case Map:
|
||||
builder := MapReprBuilder{}
|
||||
builder.Indent = indent
|
||||
for it := v.Iterator(); it.HasElem(); it.Next() {
|
||||
|
@ -63,6 +63,3 @@ func Repr(v interface{}, indent int) string {
|
|||
return fmt.Sprintf("<unknown %v>", v)
|
||||
}
|
||||
}
|
||||
|
||||
type listReprable listIterable
|
||||
type mapReprable mapIterable
|
||||
|
|
Loading…
Reference in New Issue
Block a user