Introduce an Elemser interface.

This commit is contained in:
Qi Xiao 2016-02-19 12:07:38 +01:00
parent 83cbe3b230
commit 3d7e5a819f
5 changed files with 44 additions and 15 deletions

View File

@ -291,18 +291,18 @@ func ratFn(ec *EvalCtx, arg Value) {
out <- r
}
// unpack takes any number of tables and output their list elements.
// unpack takes Elemser's from the input and unpack them.
func unpack(ec *EvalCtx) {
in := ec.ports[0].Chan
out := ec.ports[1].Chan
for v := range in {
if list, ok := v.(List); !ok {
elemser, ok := v.(Elemser)
if !ok {
throw(ErrInput)
} else {
for _, e := range *list.inner {
out <- e
}
}
for e := range elemser.Elems() {
out <- e
}
}
}

View File

@ -693,11 +693,11 @@ func variable(qname string, p int) ValuesOp {
}
value := variable.Get()
if splice {
list, ok := value.(List)
elemser, ok := value.(Elemser)
if !ok {
ec.errorf(p, "variable $%s is not a list", qname)
ec.errorf(p, "variable $%s (kind %s) cannot be spliced", qname, value.Kind())
}
return *list.inner
return collectElems(elemser)
}
return []Value{value}
}

View File

@ -8,7 +8,7 @@ import (
// Errors
var (
ErrCanOnlyAssignList = errors.New("can only assign list")
ErrCanOnlyAssignList = errors.New("can only assign compatible values")
ErrPathMustBeString = errors.New("path must be string")
ErrPathCannotContainColonZero = errors.New(`path cannot contain colon or \0`)
)
@ -30,13 +30,12 @@ func (epl *EnvPathList) Get() Value {
}
func (epl *EnvPathList) Set(v Value) {
// TODO: maybe support assigning list-like values.
l, ok := v.(List)
elemser, ok := v.(Elemser)
if !ok {
throw(ErrCanOnlyAssignList)
}
paths := make([]string, len(*l.inner))
for i, v := range *l.inner {
var paths []string
for v := range elemser.Elems() {
s, ok := v.(String)
if !ok {
throw(ErrPathMustBeString)
@ -45,7 +44,7 @@ func (epl *EnvPathList) Set(v Value) {
if strings.ContainsAny(path, ":\x00") {
throw(ErrPathCannotContainColonZero)
}
paths[i] = string(s)
paths = append(paths, string(s))
}
epl.set(paths)
}

View File

@ -12,6 +12,13 @@ var (
ErrIndexOutOfRange = errors.New("index out of range")
)
type ListLike struct {
Value
Lener
Elemser
IndexOneer
}
// List is a list of Value's.
type List struct {
inner *[]Value
@ -38,6 +45,16 @@ func (l List) Len() int {
return len(*l.inner)
}
func (l List) Elems() <-chan Value {
ch := make(chan Value)
go func() {
for _, v := range *l.inner {
ch <- v
}
}()
return ch
}
func (l List) IndexOne(idx Value) Value {
i := intIndexWithin(idx, len(*l.inner))
return (*l.inner)[i]

View File

@ -36,6 +36,19 @@ type Lener interface {
Len() int
}
// Elemser is anything that can produce a series of Value elements.
type Elemser interface {
Elems() <-chan Value
}
func collectElems(elemser Elemser) []Value {
var vs []Value
for v := range elemser.Elems() {
vs = append(vs, v)
}
return vs
}
// Caller is anything may be called on an evalCtx with a list of Value's.
type Caller interface {
Value