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.
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- retoor <retoor@molodetz.nl> -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Fibers - Wren-CLI Manual</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<button class="mobile-menu-toggle">Menu</button>
|
||||
<div class="container">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1><a href="../index.html">Wren-CLI</a></h1>
|
||||
<div class="version">v0.4.0</div>
|
||||
</div>
|
||||
<nav class="sidebar-nav">
|
||||
<div class="section">
|
||||
<span class="section-title">Getting Started</span>
|
||||
<ul>
|
||||
<li><a href="../getting-started/index.html">Overview</a></li>
|
||||
<li><a href="../getting-started/installation.html">Installation</a></li>
|
||||
<li><a href="../getting-started/first-script.html">First Script</a></li>
|
||||
<li><a href="../getting-started/repl.html">Using the REPL</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">Language</span>
|
||||
<ul>
|
||||
<li><a href="index.html">Syntax Overview</a></li>
|
||||
<li><a href="classes.html">Classes</a></li>
|
||||
<li><a href="methods.html">Methods</a></li>
|
||||
<li><a href="control-flow.html">Control Flow</a></li>
|
||||
<li><a href="fibers.html" class="active">Fibers</a></li>
|
||||
<li><a href="modules.html">Modules</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">API Reference</span>
|
||||
<ul>
|
||||
<li><a href="../api/index.html">Overview</a></li>
|
||||
<li><a href="../api/http.html">http</a></li>
|
||||
<li><a href="../api/websocket.html">websocket</a></li>
|
||||
<li><a href="../api/tls.html">tls</a></li>
|
||||
<li><a href="../api/net.html">net</a></li>
|
||||
<li><a href="../api/dns.html">dns</a></li>
|
||||
<li><a href="../api/json.html">json</a></li>
|
||||
<li><a href="../api/base64.html">base64</a></li>
|
||||
<li><a href="../api/regex.html">regex</a></li>
|
||||
<li><a href="../api/jinja.html">jinja</a></li>
|
||||
<li><a href="../api/crypto.html">crypto</a></li>
|
||||
<li><a href="../api/os.html">os</a></li>
|
||||
<li><a href="../api/env.html">env</a></li>
|
||||
<li><a href="../api/signal.html">signal</a></li>
|
||||
<li><a href="../api/subprocess.html">subprocess</a></li>
|
||||
<li><a href="../api/sqlite.html">sqlite</a></li>
|
||||
<li><a href="../api/datetime.html">datetime</a></li>
|
||||
<li><a href="../api/timer.html">timer</a></li>
|
||||
<li><a href="../api/io.html">io</a></li>
|
||||
<li><a href="../api/scheduler.html">scheduler</a></li>
|
||||
<li><a href="../api/math.html">math</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">Tutorials</span>
|
||||
<ul>
|
||||
<li><a href="../tutorials/index.html">Tutorial List</a></li>
|
||||
<li><a href="../tutorials/http-client.html">HTTP Client</a></li>
|
||||
<li><a href="../tutorials/websocket-chat.html">WebSocket Chat</a></li>
|
||||
<li><a href="../tutorials/database-app.html">Database App</a></li>
|
||||
<li><a href="../tutorials/template-rendering.html">Templates</a></li>
|
||||
<li><a href="../tutorials/cli-tool.html">CLI Tool</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">How-To Guides</span>
|
||||
<ul>
|
||||
<li><a href="../howto/index.html">How-To List</a></li>
|
||||
<li><a href="../howto/http-requests.html">HTTP Requests</a></li>
|
||||
<li><a href="../howto/json-parsing.html">JSON Parsing</a></li>
|
||||
<li><a href="../howto/regex-patterns.html">Regex Patterns</a></li>
|
||||
<li><a href="../howto/file-operations.html">File Operations</a></li>
|
||||
<li><a href="../howto/async-operations.html">Async Operations</a></li>
|
||||
<li><a href="../howto/error-handling.html">Error Handling</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
<main class="content">
|
||||
<nav class="breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span class="separator">/</span>
|
||||
<a href="index.html">Language</a>
|
||||
<span class="separator">/</span>
|
||||
<span>Fibers</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<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>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="control-flow.html" class="prev">Control Flow</a>
|
||||
<a href="modules.html" class="next">Modules</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user