2
0
Dan Korostelev 4 жил өмнө
parent
commit
a666b9487b

+ 1 - 0
tests/misc/coroutines/src/Main.hx

@@ -1,6 +1,7 @@
 function main() {
 	utest.UTest.run([
 		new TestStaticFields(),
+		new TestGenerator(),
 		#if js
 		new TestJsPromise(),
 		#end

+ 77 - 0
tests/misc/coroutines/src/TestGenerator.hx

@@ -0,0 +1,77 @@
+class TestGenerator extends utest.Test {
+	function testSimple() {
+		var iter = sequence(yield -> {
+			yield(1);
+			yield(2);
+			yield(3);
+		});
+		Assert.same([1,2,3], [for (v in iter) v]);
+	}
+
+	function testTreeIter() {
+		@:coroutine function iterTreeRec<T>(yield:Yield<T>, tree:Tree<T>) {
+			yield(tree.leaf);
+			if (tree.left != null) iterTreeRec(yield, tree.left);
+			if (tree.right != null) iterTreeRec(yield, tree.right);
+		}
+
+		function iterTree<T>(tree:Tree<T>):Iterator<T> {
+			return sequence(yield -> iterTreeRec(yield, tree));
+		}
+
+		var tree:Tree<Int> = {
+			leaf: 1,
+			left: {
+				leaf: 2,
+				left: {leaf: 3},
+				right: {leaf: 4, left: {leaf: 5}},
+			},
+			right: {
+				leaf: 6,
+				left: {leaf: 7}
+			}
+		};
+
+		Assert.same([1,2,3,4,5,6,7], [for (v in iterTree(tree)) v]);
+	}
+}
+
+private typedef Yield<T> = Coroutine<T->Void>;
+
+private function sequence<T>(f:Coroutine<Yield<T>->Void>):Iterator<T> {
+	var finished = false;
+	var nextValue:T = null;
+
+	var nextStep = null;
+
+	function finish(_) {
+		finished = true;
+	}
+
+	@:coroutine function yield(value:T) {
+		nextValue = value;
+		Coroutine.suspend(cont -> nextStep = cont);
+	}
+
+	function hasNext():Bool {
+		if (nextStep == null) {
+			nextStep = f.create(yield, finish);
+			nextStep(null);
+		}
+		return !finished;
+	}
+
+	function next():T {
+		var value = nextValue;
+		nextStep(null);
+		return value;
+	}
+
+	return {hasNext: hasNext, next: next};
+}
+
+private typedef Tree<T> = {
+	var leaf:T;
+	var ?left:Tree<T>;
+	var ?right:Tree<T>;
+}