feat: add wasm build targets, profile hooks, os_demo example, and restructure manual source
- Add `wasm`, `wasm-clean`, and `install-emscripten` phony targets to Makefile for WebAssembly cross-compilation
- Insert `WREN_PROFILE_ENTER`/`WREN_PROFILE_EXIT` macros in `wren_vm.h` and `wren_vm.c` to support optional runtime profiling via `WREN_PROFILE_ENABLED`
- Create `example/os_demo.wren` demonstrating Platform, Process, and conditional exit usage
- Update `example/regex_demo.wren` to import `Match` and exercise Match object properties, groups, and `matchAll`
- Remove static HTML manual pages (`base64.html`, `dns.html`, `json.html`) and replace with structured `manual_src/` directory containing Jinja2 templates, YAML metadata, and content pages
- Expand `README.md` with build targets table, manual building instructions, source layout, and guide for adding new module documentation
2026-01-26 05:12:14 +01:00
{# retoor < retoor @ molodetz . nl > #}
{% extends 'page.html' %}
{% set page_title = "Fibers" %}
{% set breadcrumb = [{"url": "language/index.html", "title": "Language"}, {"title": "Fibers"}] %}
{% set prev_page = {"url": "language/control-flow.html", "title": "Control Flow"} %}
{% set next_page = {"url": "language/modules.html", "title": "Modules"} %}
{% block article %}
feat: add example scripts for argparse, bytes, dataset, html, markdown, uuid, wdantic, and web chat modules
Add comprehensive demo scripts showcasing the usage of multiple Wren modules including argument parsing, byte manipulation, in-memory dataset operations, HTML encoding/slugification, markdown-to-HTML conversion, UUID generation/validation, schema validation with wdantic, and a full web chat application with REST endpoints.
2026-01-24 23:40:22 +01:00
< h1 > Fibers< / h1 >
< p > Fibers are Wren's mechanism for cooperative concurrency. They are lightweight threads of execution that you explicitly control. Unlike OS threads, only one fiber runs at a time, and switching between them is explicit.< / p >
< h2 > Creating Fibers< / h2 >
< p > Create a fiber with < code > Fiber.new< / code > :< / p >
< pre > < code > var fiber = Fiber.new {
System.print("Inside fiber")
}< / code > < / pre >
< p > The fiber does not run immediately. It is suspended until you start it.< / p >
< h2 > Running Fibers< / h2 >
< h3 > call()< / h3 >
< p > Start a fiber and wait for it to complete or yield:< / p >
< pre > < code > var fiber = Fiber.new {
System.print("Running")
}
fiber.call() // Prints "Running"< / code > < / pre >
< h3 > try()< / h3 >
< p > Start a fiber and catch any runtime errors:< / p >
< pre > < code > var fiber = Fiber.new {
Fiber.abort("Something went wrong")
}
var error = fiber.try()
System.print("Error: %(error)") // Error: Something went wrong< / code > < / pre >
< h2 > Yielding< / h2 >
< p > Fibers can pause execution and return control to the caller:< / p >
< pre > < code > var fiber = Fiber.new {
System.print("First")
Fiber.yield()
System.print("Second")
Fiber.yield()
System.print("Third")
}
fiber.call() // Prints "First"
fiber.call() // Prints "Second"
fiber.call() // Prints "Third"< / code > < / pre >
< h3 > Yielding Values< / h3 >
< pre > < code > var counter = Fiber.new {
Fiber.yield(1)
Fiber.yield(2)
Fiber.yield(3)
}
System.print(counter.call()) // 1
System.print(counter.call()) // 2
System.print(counter.call()) // 3< / code > < / pre >
< h3 > Passing Values In< / h3 >
< pre > < code > var adder = Fiber.new {
var total = 0
while (true) {
var value = Fiber.yield(total)
total = total + value
}
}
adder.call() // Start the fiber
System.print(adder.call(5)) // 5
System.print(adder.call(10)) // 15
System.print(adder.call(3)) // 18< / code > < / pre >
< h2 > Fiber State< / h2 >
< p > Check the state of a fiber:< / p >
< pre > < code > var fiber = Fiber.new {
Fiber.yield()
}
System.print(fiber.isDone) // false
fiber.call()
System.print(fiber.isDone) // false (yielded)
fiber.call()
System.print(fiber.isDone) // true (completed)< / code > < / pre >
< h2 > Error Handling< / h2 >
< p > Fibers can abort with an error:< / p >
< pre > < code > Fiber.abort("Error message")< / code > < / pre >
< p > Use < code > try()< / code > to catch errors:< / p >
< pre > < code > var fiber = Fiber.new {
var x = 1 / 0 // Will cause infinity, not error
[1, 2, 3][10] // This will cause an error
}
var error = fiber.try()
if (error != null) {
System.print("Caught: %(error)")
}< / code > < / pre >
< h2 > Current Fiber< / h2 >
< p > Get the currently executing fiber:< / p >
< pre > < code > var current = Fiber.current
System.print(current) // Fiber instance< / code > < / pre >
< h2 > Generator Pattern< / h2 >
< p > Fibers naturally implement generators:< / p >
< pre > < code > var range = Fn.new { |start, end|
return Fiber.new {
var i = start
while (i < = end) {
Fiber.yield(i)
i = i + 1
}
}
}
var nums = range.call(1, 5)
while (!nums.isDone) {
var value = nums.call()
if (value != null) System.print(value)
}< / code > < / pre >
< h2 > Coroutine Pattern< / h2 >
< p > Two fibers can communicate back and forth:< / p >
< pre > < code > var producer = Fiber.new {
for (i in 1..5) {
System.print("Producing %(i)")
Fiber.yield(i)
}
}
var consumer = Fiber.new {
while (!producer.isDone) {
var value = producer.call()
if (value != null) {
System.print("Consuming %(value)")
}
}
}
consumer.call()< / code > < / pre >
< h2 > Async Operations with Scheduler< / h2 >
< p > Wren-CLI uses fibers for async I/O. The scheduler suspends fibers during I/O and resumes them when the operation completes:< / p >
< pre > < code > import "timer" for Timer
System.print("Before sleep")
Timer.sleep(1000) // Fiber suspends here
System.print("After sleep")< / code > < / pre >
< p > The scheduler pattern internally looks like:< / p >
< pre > < code > import "scheduler" for Scheduler
Scheduler.await_ {
Timer.sleep_(1000, Fiber.current)
}< / code > < / pre >
< h2 > Fiber Methods< / h2 >
< h3 > Static Methods< / h3 >
< table >
< tr >
< th > Method< / th >
< th > Description< / th >
< / tr >
< tr >
< td > < code > Fiber.new { block }< / code > < / td >
< td > Create a new fiber< / td >
< / tr >
< tr >
< td > < code > Fiber.current< / code > < / td >
< td > Get the current fiber< / td >
< / tr >
< tr >
< td > < code > Fiber.yield()< / code > < / td >
< td > Pause and return null< / td >
< / tr >
< tr >
< td > < code > Fiber.yield(value)< / code > < / td >
< td > Pause and return value< / td >
< / tr >
< tr >
< td > < code > Fiber.abort(message)< / code > < / td >
< td > Abort with error< / td >
< / tr >
< tr >
< td > < code > Fiber.suspend()< / code > < / td >
< td > Suspend the current fiber< / td >
< / tr >
< / table >
< h3 > Instance Methods< / h3 >
< table >
< tr >
< th > Method< / th >
< th > Description< / th >
< / tr >
< tr >
< td > < code > fiber.call()< / code > < / td >
< td > Run fiber, wait for yield/complete< / td >
< / tr >
< tr >
< td > < code > fiber.call(value)< / code > < / td >
< td > Run with value passed to yield< / td >
< / tr >
< tr >
< td > < code > fiber.try()< / code > < / td >
< td > Run and catch errors< / td >
< / tr >
< tr >
< td > < code > fiber.isDone< / code > < / td >
< td > True if completed< / td >
< / tr >
< tr >
< td > < code > fiber.error< / code > < / td >
< td > Error message if aborted< / td >
< / tr >
< tr >
< td > < code > fiber.transfer()< / code > < / td >
< td > Switch to this fiber< / td >
< / tr >
< tr >
< td > < code > fiber.transfer(value)< / code > < / td >
< td > Switch with value< / td >
< / tr >
< tr >
< td > < code > fiber.transferError(msg)< / code > < / td >
< td > Switch and raise error< / td >
< / tr >
< / table >
< h2 > Transfer vs Call< / h2 >
< p > < code > call()< / code > maintains a call stack and returns when the fiber yields:< / p >
< pre > < code > var a = Fiber.new {
System.print("a: before yield")
Fiber.yield()
System.print("a: after yield")
}
a.call()
System.print("back in main")
a.call()
// Output:
// a: before yield
// back in main
// a: after yield< / code > < / pre >
< p > < code > transfer()< / code > does not maintain a call stack:< / p >
< pre > < code > var main = Fiber.current
var a = null
var b = null
a = Fiber.new {
System.print("in a")
b.transfer()
System.print("back in a")
main.transfer()
}
b = Fiber.new {
System.print("in b")
a.transfer()
System.print("back in b")
}
a.transfer()
System.print("done")
// Output:
// in a
// in b
// back in a
// done< / code > < / pre >
feat: add wasm build targets, profile hooks, os_demo example, and restructure manual source
- Add `wasm`, `wasm-clean`, and `install-emscripten` phony targets to Makefile for WebAssembly cross-compilation
- Insert `WREN_PROFILE_ENTER`/`WREN_PROFILE_EXIT` macros in `wren_vm.h` and `wren_vm.c` to support optional runtime profiling via `WREN_PROFILE_ENABLED`
- Create `example/os_demo.wren` demonstrating Platform, Process, and conditional exit usage
- Update `example/regex_demo.wren` to import `Match` and exercise Match object properties, groups, and `matchAll`
- Remove static HTML manual pages (`base64.html`, `dns.html`, `json.html`) and replace with structured `manual_src/` directory containing Jinja2 templates, YAML metadata, and content pages
- Expand `README.md` with build targets table, manual building instructions, source layout, and guide for adding new module documentation
2026-01-26 05:12:14 +01:00
{% endblock %}