add Iterable interface
This commit is contained in:
parent
c7ae181623
commit
2486457fdf
11 changed files with 107 additions and 59 deletions
|
@ -115,3 +115,11 @@ func (o *Array) IndexSet(index, value Object) (err error) {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate creates an array iterator.
|
||||||
|
func (o *Array) Iterate() Iterator {
|
||||||
|
return &ArrayIterator{
|
||||||
|
v: o.Value,
|
||||||
|
l: len(o.Value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,14 +9,6 @@ type ArrayIterator struct {
|
||||||
l int
|
l int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewArrayIterator creates an ArrayIterator.
|
|
||||||
func NewArrayIterator(v *Array) Iterator {
|
|
||||||
return &ArrayIterator{
|
|
||||||
v: v.Value,
|
|
||||||
l: len(v.Value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
func (i *ArrayIterator) TypeName() string {
|
func (i *ArrayIterator) TypeName() string {
|
||||||
return "array-iterator"
|
return "array-iterator"
|
||||||
|
|
|
@ -84,3 +84,17 @@ func (o *ImmutableMap) Equals(x Object) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate creates an immutable map iterator.
|
||||||
|
func (o *ImmutableMap) Iterate() Iterator {
|
||||||
|
var keys []string
|
||||||
|
for k := range o.Value {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ImmutableMapIterator{
|
||||||
|
v: o.Value,
|
||||||
|
k: keys,
|
||||||
|
l: len(keys),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,20 +10,6 @@ type ImmutableMapIterator struct {
|
||||||
l int
|
l int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewModuleMapIterator creates a module iterator.
|
|
||||||
func NewModuleMapIterator(v *ImmutableMap) Iterator {
|
|
||||||
var keys []string
|
|
||||||
for k := range v.Value {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ImmutableMapIterator{
|
|
||||||
v: v.Value,
|
|
||||||
k: keys,
|
|
||||||
l: len(keys),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
func (i *ImmutableMapIterator) TypeName() string {
|
func (i *ImmutableMapIterator) TypeName() string {
|
||||||
return "module-iterator"
|
return "module-iterator"
|
||||||
|
|
7
objects/iterable.go
Normal file
7
objects/iterable.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package objects
|
||||||
|
|
||||||
|
// Iterable represents an object that has iterator.
|
||||||
|
type Iterable interface {
|
||||||
|
// Iterate should return an Iterator for the type.
|
||||||
|
Iterate() Iterator
|
||||||
|
}
|
|
@ -97,3 +97,17 @@ func (o *Map) IndexSet(index, value Object) (err error) {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate creates a map iterator.
|
||||||
|
func (o *Map) Iterate() Iterator {
|
||||||
|
var keys []string
|
||||||
|
for k := range o.Value {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MapIterator{
|
||||||
|
v: o.Value,
|
||||||
|
k: keys,
|
||||||
|
l: len(keys),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,20 +10,6 @@ type MapIterator struct {
|
||||||
l int
|
l int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMapIterator creates a map iterator.
|
|
||||||
func NewMapIterator(v *Map) Iterator {
|
|
||||||
var keys []string
|
|
||||||
for k := range v.Value {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MapIterator{
|
|
||||||
v: v.Value,
|
|
||||||
k: keys,
|
|
||||||
l: len(keys),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
func (i *MapIterator) TypeName() string {
|
func (i *MapIterator) TypeName() string {
|
||||||
return "map-iterator"
|
return "map-iterator"
|
||||||
|
|
|
@ -81,3 +81,15 @@ func (o *String) IndexGet(index Object) (res Object, err error) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate creates a string iterator.
|
||||||
|
func (o *String) Iterate() Iterator {
|
||||||
|
if o.runeStr == nil {
|
||||||
|
o.runeStr = []rune(o.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StringIterator{
|
||||||
|
v: o.runeStr,
|
||||||
|
l: len(o.runeStr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,16 +9,6 @@ type StringIterator struct {
|
||||||
l int
|
l int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStringIterator creates a string iterator.
|
|
||||||
func NewStringIterator(v *String) Iterator {
|
|
||||||
r := []rune(v.Value)
|
|
||||||
|
|
||||||
return &StringIterator{
|
|
||||||
v: r,
|
|
||||||
l: len(r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
func (i *StringIterator) TypeName() string {
|
func (i *StringIterator) TypeName() string {
|
||||||
return "string-iterator"
|
return "string-iterator"
|
||||||
|
|
|
@ -921,19 +921,13 @@ func (v *VM) Run() error {
|
||||||
dst := v.stack[v.sp-1]
|
dst := v.stack[v.sp-1]
|
||||||
v.sp--
|
v.sp--
|
||||||
|
|
||||||
switch dst := (*dst).(type) {
|
iterable, ok := (*dst).(objects.Iterable)
|
||||||
case *objects.Array:
|
if !ok {
|
||||||
iterator = objects.NewArrayIterator(dst)
|
return fmt.Errorf("non-iterable type: %s", (*dst).TypeName())
|
||||||
case *objects.Map:
|
|
||||||
iterator = objects.NewMapIterator(dst)
|
|
||||||
case *objects.ImmutableMap:
|
|
||||||
iterator = objects.NewModuleMapIterator(dst)
|
|
||||||
case *objects.String:
|
|
||||||
iterator = objects.NewStringIterator(dst)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("non-iterable type: %s", dst.TypeName())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator = iterable.Iterate()
|
||||||
|
|
||||||
if v.sp >= StackSize {
|
if v.sp >= StackSize {
|
||||||
return ErrStackOverflow
|
return ErrStackOverflow
|
||||||
}
|
}
|
||||||
|
@ -945,12 +939,13 @@ func (v *VM) Run() error {
|
||||||
iterator := v.stack[v.sp-1]
|
iterator := v.stack[v.sp-1]
|
||||||
v.sp--
|
v.sp--
|
||||||
|
|
||||||
b := (*iterator).(objects.Iterator).Next()
|
hasMore := (*iterator).(objects.Iterator).Next()
|
||||||
|
|
||||||
if v.sp >= StackSize {
|
if v.sp >= StackSize {
|
||||||
return ErrStackOverflow
|
return ErrStackOverflow
|
||||||
}
|
}
|
||||||
|
|
||||||
if b {
|
if hasMore {
|
||||||
v.stack[v.sp] = truePtr
|
v.stack[v.sp] = truePtr
|
||||||
} else {
|
} else {
|
||||||
v.stack[v.sp] = falsePtr
|
v.stack[v.sp] = falsePtr
|
||||||
|
|
44
runtime/vm_iterable_test.go
Normal file
44
runtime/vm_iterable_test.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package runtime_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringArrayIterator struct {
|
||||||
|
objectImpl
|
||||||
|
strArr *StringArray
|
||||||
|
idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *StringArrayIterator) TypeName() string {
|
||||||
|
return "string-array-iterator"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *StringArrayIterator) Next() bool {
|
||||||
|
i.idx++
|
||||||
|
return i.idx <= len(i.strArr.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *StringArrayIterator) Key() objects.Object {
|
||||||
|
return &objects.Int{Value: int64(i.idx - 1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *StringArrayIterator) Value() objects.Object {
|
||||||
|
return &objects.String{Value: i.strArr.Value[i.idx-1]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *StringArray) Iterate() objects.Iterator {
|
||||||
|
return &StringArrayIterator{
|
||||||
|
strArr: o,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIterable(t *testing.T) {
|
||||||
|
strArr := func() *StringArray { return &StringArray{Value: []string{"one", "two", "three"}} }
|
||||||
|
|
||||||
|
expectWithSymbols(t, `for i, s in arr { out += i }`, 3, SYM{"arr": strArr()})
|
||||||
|
expectWithSymbols(t, `for i, s in arr { out += s }`, "onetwothree", SYM{"arr": strArr()})
|
||||||
|
expectWithSymbols(t, `for i, s in arr { out += s + i }`, "one0two1three2", SYM{"arr": strArr()})
|
||||||
|
}
|
Loading…
Reference in a new issue