From ba8a63e7920169547fedec37ec81dc8d54950c97 Mon Sep 17 00:00:00 2001 From: Dmitry Panov Date: Mon, 26 Jun 2023 13:40:41 +0100 Subject: [PATCH] Implemented Runtime.ForOf --- runtime.go | 31 +++++++++++++++++++++++++++++++ runtime_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/runtime.go b/runtime.go index 83c7cc80..172039fc 100644 --- a/runtime.go +++ b/runtime.go @@ -2771,6 +2771,37 @@ func (ir *iteratorRecord) close() { ir.next = nil } +// ForOf is a Go equivalent of for-of loop. The function panics if an exception is thrown at any point +// while iterating, including if the supplied value is not iterable +// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol). +// When using outside of Runtime.Run (i.e. when calling directly from Go code, not from a JS function implemented +// in Go) it must be enclosed in Try. See the example. +func (r *Runtime) ForOf(iterable Value, step func(curValue Value) (continueIteration bool)) { + iter := r.getIterator(iterable, nil) + for { + value, ex := iter.step() + if ex != nil { + panic(ex) + } + if value != nil { + var continueIteration bool + ex := r.vm.try(func() { + continueIteration = step(value) + }) + if ex != nil { + iter.returnIter() + panic(ex) + } + if !continueIteration { + iter.returnIter() + break + } + } else { + break + } + } +} + func (r *Runtime) createIterResultObject(value Value, done bool) Value { o := r.NewObject() o.self.setOwnStr("value", value, false) diff --git a/runtime_test.go b/runtime_test.go index 02d201bf..f0ca4526 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -2844,6 +2844,37 @@ func TestAwaitInParameters(t *testing.T) { } } +func ExampleRuntime_ForOf() { + r := New() + v, err := r.RunString(` + new Map().set("a", 1).set("b", 2); + `) + if err != nil { + panic(err) + } + + var sb strings.Builder + ex := r.Try(func() { + r.ForOf(v, func(v Value) bool { + o := v.ToObject(r) + key := o.Get("0") + value := o.Get("1") + + sb.WriteString(key.String()) + sb.WriteString("=") + sb.WriteString(value.String()) + sb.WriteString(",") + + return true + }) + }) + if ex != nil { + panic(ex) + } + fmt.Println(sb.String()) + // Output: a=1,b=2, +} + /* func TestArrayConcatSparse(t *testing.T) { function foo(a,b,c)