feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result type for interpreter loop, add caller field to ObjFiber struct for yield resumption, and update GC marking to traverse fiber caller chains. Modify wrenNewFiber to accept a function/closure argument and initialize the first call frame. Add debug stack printing with fiber pointer. Include test suite covering fiber creation, run, yield, value passing, type checking, and caller resumption.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
var b = Fiber.create(fn {
|
||||
IO.print("fiber b")
|
||||
})
|
||||
|
||||
var a = Fiber.create(fn {
|
||||
IO.print("begin fiber a")
|
||||
b.run
|
||||
IO.print("end fiber a")
|
||||
})
|
||||
|
||||
IO.print("begin main")
|
||||
a.run
|
||||
IO.print("end main")
|
||||
|
||||
// expect: begin main
|
||||
// expect: begin fiber a
|
||||
// expect: fiber b
|
||||
// expect: end fiber a
|
||||
// expect: end main
|
||||
@@ -0,0 +1,12 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber")
|
||||
})
|
||||
|
||||
IO.print("before") // expect: before
|
||||
fiber.run // expect: fiber
|
||||
IO.print("after") // expect: after
|
||||
|
||||
// TODO: Test handles error if fiber tries to run itself.
|
||||
// TODO: Test create is passed right argument type.
|
||||
// TODO: Test closing over stuff in fiber function.
|
||||
// TODO: Test running a finished fiber.
|
||||
@@ -0,0 +1,6 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber")
|
||||
})
|
||||
|
||||
var result = fiber.run // expect: fiber
|
||||
IO.print(result) // expect: null
|
||||
@@ -0,0 +1,7 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber")
|
||||
return "result"
|
||||
})
|
||||
|
||||
var result = fiber.run // expect: fiber
|
||||
IO.print(result) // expect: result
|
||||
@@ -0,0 +1,9 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber")
|
||||
})
|
||||
|
||||
// The first value passed to the fiber is ignored, since there's no yield call
|
||||
// to return it.
|
||||
IO.print("before") // expect: before
|
||||
fiber.run("ignored") // expect: fiber
|
||||
IO.print("after") // expect: after
|
||||
@@ -0,0 +1,5 @@
|
||||
var fiber = Fiber.create(fn null)
|
||||
IO.print(fiber is Fiber) // expect: true
|
||||
IO.print(fiber is Object) // expect: true
|
||||
IO.print(fiber is Bool) // expect: false
|
||||
IO.print(fiber.type == Fiber) // expect: true
|
||||
@@ -0,0 +1,14 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber 1")
|
||||
Fiber.yield
|
||||
IO.print("fiber 2")
|
||||
Fiber.yield
|
||||
IO.print("fiber 3")
|
||||
})
|
||||
|
||||
var result = fiber.run // expect: fiber 1
|
||||
IO.print("main 1") // expect: main 1
|
||||
result = fiber.run // expect: fiber 2
|
||||
IO.print("main 2") // expect: main 2
|
||||
result = fiber.run // expect: fiber 3
|
||||
IO.print("main 3") // expect: main 3
|
||||
@@ -0,0 +1,14 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber 1")
|
||||
var result = Fiber.yield
|
||||
IO.print(result)
|
||||
result = Fiber.yield
|
||||
IO.print(result)
|
||||
})
|
||||
|
||||
fiber.run // expect: fiber 1
|
||||
IO.print("main 1") // expect: main 1
|
||||
fiber.run("run 1") // expect: run 1
|
||||
IO.print("main 2") // expect: main 2
|
||||
fiber.run // expect: null
|
||||
IO.print("main 3") // expect: main 3
|
||||
@@ -0,0 +1,14 @@
|
||||
var fiber = Fiber.create(fn {
|
||||
IO.print("fiber 1")
|
||||
Fiber.yield("yield 1")
|
||||
IO.print("fiber 2")
|
||||
Fiber.yield("yield 2")
|
||||
IO.print("fiber 3")
|
||||
})
|
||||
|
||||
var result = fiber.run // expect: fiber 1
|
||||
IO.print(result) // expect: yield 1
|
||||
result = fiber.run // expect: fiber 2
|
||||
IO.print(result) // expect: yield 2
|
||||
result = fiber.run // expect: fiber 3
|
||||
IO.print(result) // expect: null
|
||||
Reference in New Issue
Block a user