Browse Source

Implemented Runtime.ForOf

Dmitry Panov 2 years ago
parent
commit
ba8a63e792
2 changed files with 62 additions and 0 deletions
  1. 31 0
      runtime.go
  2. 31 0
      runtime_test.go

+ 31 - 0
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)

+ 31 - 0
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)