Skip to content

This a suggestion for supporting go iterators when called from goja script #696

@lnksnk

Description

@lnksnk

Just change the following in the code file vm.go this is only supported from Go 1.23

type _iterateP struct{}

var iterateP _iterateP

func (_iterateP) exec(vm *vm) {
	obj := vm.stack[vm.sp-1]
	method := toMethod(vm.r.getV(obj, SymIterator))
	if method != nil {
		iter := func() *iteratorRecord {
			iter := vm.r.toObject(method(FunctionCall{
				This: obj,
			}))

			var next func(FunctionCall) Value

			if obj, ok := iter.self.getStr("next", nil).(*Object); ok {
				if call, ok := obj.self.assertCallable(); ok {
					next = call
				}
			}

			return &iteratorRecord{
				iterator: iter,
				next:     next,
			}
		}()
		vm.iterStack = append(vm.iterStack, iterStackItem{iter: iter})
		vm.sp--
		vm.pc++
		return
	}
	if psblitr := obj.Export(); psblitr != nil {
		var itertpe = reflect.TypeOf(psblitr)
		if itertpe.Kind() == reflect.Func {
			var itrnxt func() (reflect.Value, bool)
			var itrstp func()
			if itertpe.NumIn() == 1 && itertpe.NumOut() == 0 && itertpe.CanSeq() {
				itrnxt, itrstp = iter.Pull(reflect.ValueOf(psblitr).Seq())
			} else if itertpe.NumIn() == 0 && itertpe.NumOut() == 1 && itertpe.Out(0).CanSeq() {
				if rslt := reflect.ValueOf(psblitr).Call(nil); len(rslt) > 0 {
					itrnxt, itrstp = iter.Pull(rslt[0].Seq())
				}
			}
			if itrnxt != nil && itrstp != nil {
				iter := func() *iteratorRecord {
					var outcme = map[string]any{}
					nxtval := func() (val any, vld bool) {
						if itrstp != nil {
							val, vld = itrnxt()
							if vld {
								vld = !vld
								val = val.(reflect.Value).Interface()
								return
							}
							val = nil
							vld = true
							return
						}
						return nil, true
					}
					rtrn := func() {
						if itrstp != nil {
							itrstp()
							itrstp = nil
						}
					}
					outcme["next"] = func() any {
						val, vld := nxtval()
						outcme["value"] = val
						outcme["done"] = vld
						if vld {
							rtrn()
							return outcme
						}
						return outcme
					}
					outcme["return"] = func() any {
						rtrn()
						outcme["value"] = nil
						outcme["done"] = true
						return outcme
					}

					iter := vm.r.toObject(vm.r.ToValue(outcme))

					var next func(FunctionCall) Value

					obj, ok := iter.self.getStr("next", nil).(*Object)
					if ok {
						if call, ok := obj.self.assertCallable(); ok {
							next = call
						}
					}

					return &iteratorRecord{
						iterator: iter,
						next:     next}
				}()
				vm.iterStack = append(vm.iterStack, iterStackItem{iter: iter})
				vm.sp--
				vm.pc++
				return
			}
		}
	}
	panic(vm.r.NewTypeError("object is not iterable"))
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions