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,422 @@
|
||||
<!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>Classes - 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" class="active">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">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>Classes</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Classes</h1>
|
||||
|
||||
<p>Wren is a class-based object-oriented language. Everything in Wren is an object, and every object is an instance of a class.</p>
|
||||
|
||||
<h2>Defining Classes</h2>
|
||||
<p>Define a class with the <code>class</code> keyword:</p>
|
||||
<pre><code>class Animal {
|
||||
}</code></pre>
|
||||
|
||||
<p>This creates a class named <code>Animal</code> with no methods or fields.</p>
|
||||
|
||||
<h2>Constructors</h2>
|
||||
<p>Constructors create new instances. Define them with <code>construct</code>:</p>
|
||||
<pre><code>class Person {
|
||||
construct new(name, age) {
|
||||
_name = name
|
||||
_age = age
|
||||
}
|
||||
}
|
||||
|
||||
var alice = Person.new("Alice", 30)</code></pre>
|
||||
|
||||
<p>A class can have multiple named constructors:</p>
|
||||
<pre><code>class Point {
|
||||
construct new(x, y) {
|
||||
_x = x
|
||||
_y = y
|
||||
}
|
||||
|
||||
construct origin() {
|
||||
_x = 0
|
||||
_y = 0
|
||||
}
|
||||
|
||||
construct fromList(list) {
|
||||
_x = list[0]
|
||||
_y = list[1]
|
||||
}
|
||||
}
|
||||
|
||||
var p1 = Point.new(3, 4)
|
||||
var p2 = Point.origin()
|
||||
var p3 = Point.fromList([5, 6])</code></pre>
|
||||
|
||||
<h2>Fields</h2>
|
||||
<p>Instance fields are prefixed with <code>_</code>. They are private to the class:</p>
|
||||
<pre><code>class Counter {
|
||||
construct new() {
|
||||
_count = 0
|
||||
}
|
||||
|
||||
increment() {
|
||||
_count = _count + 1
|
||||
}
|
||||
|
||||
count { _count }
|
||||
}</code></pre>
|
||||
|
||||
<p>Fields are not declared; they are created when first assigned.</p>
|
||||
|
||||
<h2>Getters and Setters</h2>
|
||||
<p>Getters are methods without parentheses:</p>
|
||||
<pre><code>class Circle {
|
||||
construct new(radius) {
|
||||
_radius = radius
|
||||
}
|
||||
|
||||
radius { _radius }
|
||||
area { 3.14159 * _radius * _radius }
|
||||
}
|
||||
|
||||
var c = Circle.new(5)
|
||||
System.print(c.radius) // 5
|
||||
System.print(c.area) // 78.53975</code></pre>
|
||||
|
||||
<p>Setters use <code>=</code> suffix:</p>
|
||||
<pre><code>class Circle {
|
||||
construct new(radius) {
|
||||
_radius = radius
|
||||
}
|
||||
|
||||
radius { _radius }
|
||||
radius=(value) { _radius = value }
|
||||
}
|
||||
|
||||
var c = Circle.new(5)
|
||||
c.radius = 10
|
||||
System.print(c.radius) // 10</code></pre>
|
||||
|
||||
<h2>Methods</h2>
|
||||
<p>Methods are defined inside the class body:</p>
|
||||
<pre><code>class Rectangle {
|
||||
construct new(width, height) {
|
||||
_width = width
|
||||
_height = height
|
||||
}
|
||||
|
||||
area() {
|
||||
return _width * _height
|
||||
}
|
||||
|
||||
perimeter() {
|
||||
return 2 * (_width + _height)
|
||||
}
|
||||
}
|
||||
|
||||
var rect = Rectangle.new(4, 5)
|
||||
System.print(rect.area()) // 20
|
||||
System.print(rect.perimeter()) // 18</code></pre>
|
||||
|
||||
<h2>Static Members</h2>
|
||||
<p>Static methods and fields belong to the class, not instances:</p>
|
||||
<pre><code>class Math {
|
||||
static pi { 3.14159 }
|
||||
|
||||
static square(x) {
|
||||
return x * x
|
||||
}
|
||||
|
||||
static cube(x) {
|
||||
return x * x * x
|
||||
}
|
||||
}
|
||||
|
||||
System.print(Math.pi) // 3.14159
|
||||
System.print(Math.square(4)) // 16
|
||||
System.print(Math.cube(3)) // 27</code></pre>
|
||||
|
||||
<p>Static fields use double underscore:</p>
|
||||
<pre><code>class Counter {
|
||||
static count { __count }
|
||||
|
||||
static increment() {
|
||||
if (__count == null) __count = 0
|
||||
__count = __count + 1
|
||||
}
|
||||
}
|
||||
|
||||
Counter.increment()
|
||||
Counter.increment()
|
||||
System.print(Counter.count) // 2</code></pre>
|
||||
|
||||
<h2>Inheritance</h2>
|
||||
<p>Classes can inherit from a single superclass using <code>is</code>:</p>
|
||||
<pre><code>class Animal {
|
||||
construct new(name) {
|
||||
_name = name
|
||||
}
|
||||
|
||||
name { _name }
|
||||
|
||||
speak() {
|
||||
System.print("...")
|
||||
}
|
||||
}
|
||||
|
||||
class Dog is Animal {
|
||||
construct new(name, breed) {
|
||||
super(name)
|
||||
_breed = breed
|
||||
}
|
||||
|
||||
breed { _breed }
|
||||
|
||||
speak() {
|
||||
System.print("Woof!")
|
||||
}
|
||||
}
|
||||
|
||||
var dog = Dog.new("Rex", "German Shepherd")
|
||||
System.print(dog.name) // Rex
|
||||
System.print(dog.breed) // German Shepherd
|
||||
dog.speak() // Woof!</code></pre>
|
||||
|
||||
<h3>Calling Super</h3>
|
||||
<p>Use <code>super</code> to call the superclass constructor or methods:</p>
|
||||
<pre><code>class Parent {
|
||||
construct new() {
|
||||
_value = 10
|
||||
}
|
||||
|
||||
value { _value }
|
||||
|
||||
describe() {
|
||||
System.print("Parent value: %(_value)")
|
||||
}
|
||||
}
|
||||
|
||||
class Child is Parent {
|
||||
construct new() {
|
||||
super()
|
||||
_extra = 20
|
||||
}
|
||||
|
||||
describe() {
|
||||
super.describe()
|
||||
System.print("Child extra: %(_extra)")
|
||||
}
|
||||
}
|
||||
|
||||
var child = Child.new()
|
||||
child.describe()
|
||||
// Output:
|
||||
// Parent value: 10
|
||||
// Child extra: 20</code></pre>
|
||||
|
||||
<h2>This</h2>
|
||||
<p>Use <code>this</code> to refer to the current instance:</p>
|
||||
<pre><code>class Node {
|
||||
construct new(value) {
|
||||
_value = value
|
||||
_next = null
|
||||
}
|
||||
|
||||
value { _value }
|
||||
next { _next }
|
||||
|
||||
append(value) {
|
||||
_next = Node.new(value)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
var n = Node.new(1).append(2).append(3)</code></pre>
|
||||
|
||||
<h2>Object Class</h2>
|
||||
<p>All classes implicitly inherit from <code>Object</code>:</p>
|
||||
<pre><code>class Foo {}
|
||||
|
||||
System.print(Foo is Class) // true
|
||||
System.print(Foo.supertype) // Object</code></pre>
|
||||
|
||||
<h2>Type Checking</h2>
|
||||
<p>Use <code>is</code> to check if an object is an instance of a class:</p>
|
||||
<pre><code>var dog = Dog.new("Rex", "Shepherd")
|
||||
|
||||
System.print(dog is Dog) // true
|
||||
System.print(dog is Animal) // true
|
||||
System.print(dog is Object) // true
|
||||
System.print(dog is String) // false</code></pre>
|
||||
|
||||
<p>Get the class of an object with <code>type</code>:</p>
|
||||
<pre><code>System.print(dog.type) // Dog
|
||||
System.print(dog.type.name) // Dog
|
||||
System.print(dog.type.supertype) // Animal</code></pre>
|
||||
|
||||
<h2>Foreign Classes</h2>
|
||||
<p>Foreign classes are implemented in C. They can hold native data:</p>
|
||||
<pre><code>foreign class Socket {
|
||||
construct new() {}
|
||||
foreign connect(host, port)
|
||||
foreign send(data)
|
||||
foreign receive()
|
||||
foreign close()
|
||||
}</code></pre>
|
||||
|
||||
<p>Foreign classes are used by built-in modules to provide native functionality.</p>
|
||||
|
||||
<h2>Complete Example</h2>
|
||||
<pre><code>class Shape {
|
||||
construct new() {}
|
||||
|
||||
area { 0 }
|
||||
perimeter { 0 }
|
||||
|
||||
describe() {
|
||||
System.print("Area: %(area)")
|
||||
System.print("Perimeter: %(perimeter)")
|
||||
}
|
||||
}
|
||||
|
||||
class Rectangle is Shape {
|
||||
construct new(width, height) {
|
||||
_width = width
|
||||
_height = height
|
||||
}
|
||||
|
||||
width { _width }
|
||||
height { _height }
|
||||
area { _width * _height }
|
||||
perimeter { 2 * (_width + _height) }
|
||||
}
|
||||
|
||||
class Square is Rectangle {
|
||||
construct new(side) {
|
||||
super(side, side)
|
||||
}
|
||||
}
|
||||
|
||||
class Circle is Shape {
|
||||
construct new(radius) {
|
||||
_radius = radius
|
||||
}
|
||||
|
||||
static pi { 3.14159 }
|
||||
|
||||
radius { _radius }
|
||||
area { Circle.pi * _radius * _radius }
|
||||
perimeter { 2 * Circle.pi * _radius }
|
||||
}
|
||||
|
||||
var shapes = [
|
||||
Rectangle.new(4, 5),
|
||||
Square.new(3),
|
||||
Circle.new(2)
|
||||
]
|
||||
|
||||
for (shape in shapes) {
|
||||
System.print("%(shape.type.name):")
|
||||
shape.describe()
|
||||
System.print("")
|
||||
}</code></pre>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="index.html" class="prev">Syntax Overview</a>
|
||||
<a href="methods.html" class="next">Methods</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,332 @@
|
||||
<!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>Control Flow - 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" class="active">Control Flow</a></li>
|
||||
<li><a href="fibers.html">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>Control Flow</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Control Flow</h1>
|
||||
|
||||
<p>Wren provides standard control flow constructs for conditionals, loops, and early exit.</p>
|
||||
|
||||
<h2>Truthiness</h2>
|
||||
<p>Before covering control flow, understand how Wren evaluates truthiness:</p>
|
||||
<ul>
|
||||
<li><code>false</code> is falsy</li>
|
||||
<li><code>null</code> is falsy</li>
|
||||
<li>Everything else is truthy (including <code>0</code>, <code>""</code>, <code>[]</code>)</li>
|
||||
</ul>
|
||||
<pre><code>if (0) System.print("0 is truthy")
|
||||
if ("") System.print("empty string is truthy")
|
||||
if ([]) System.print("empty list is truthy")
|
||||
if (false) System.print("false is falsy") // Not printed
|
||||
if (null) System.print("null is falsy") // Not printed</code></pre>
|
||||
|
||||
<h2>If Statements</h2>
|
||||
<p>Basic conditional execution:</p>
|
||||
<pre><code>if (condition) {
|
||||
System.print("condition is true")
|
||||
}</code></pre>
|
||||
|
||||
<h3>If-Else</h3>
|
||||
<pre><code>if (score >= 90) {
|
||||
System.print("A")
|
||||
} else {
|
||||
System.print("Not A")
|
||||
}</code></pre>
|
||||
|
||||
<h3>If-Else If-Else</h3>
|
||||
<pre><code>if (score >= 90) {
|
||||
System.print("A")
|
||||
} else if (score >= 80) {
|
||||
System.print("B")
|
||||
} else if (score >= 70) {
|
||||
System.print("C")
|
||||
} else {
|
||||
System.print("F")
|
||||
}</code></pre>
|
||||
|
||||
<h3>Single Expression</h3>
|
||||
<p>For single expressions, braces are optional:</p>
|
||||
<pre><code>if (x > 0) System.print("positive")</code></pre>
|
||||
|
||||
<h2>Ternary Operator</h2>
|
||||
<p>For inline conditionals:</p>
|
||||
<pre><code>var status = age >= 18 ? "adult" : "minor"
|
||||
var max = a > b ? a : b</code></pre>
|
||||
|
||||
<h2>Logical Operators</h2>
|
||||
|
||||
<h3>And (&&)</h3>
|
||||
<p>Returns the first falsy value or the last value:</p>
|
||||
<pre><code>System.print(true && false) // false
|
||||
System.print(true && true) // true
|
||||
System.print(1 && 2) // 2
|
||||
System.print(null && 1) // null</code></pre>
|
||||
|
||||
<h3>Or (||)</h3>
|
||||
<p>Returns the first truthy value or the last value:</p>
|
||||
<pre><code>System.print(false || true) // true
|
||||
System.print(false || false) // false
|
||||
System.print(null || "default") // default
|
||||
System.print(1 || 2) // 1</code></pre>
|
||||
|
||||
<p>Use <code>||</code> for default values:</p>
|
||||
<pre><code>var name = providedName || "Anonymous"</code></pre>
|
||||
|
||||
<h2>While Loops</h2>
|
||||
<p>Repeat while a condition is true:</p>
|
||||
<pre><code>var i = 0
|
||||
while (i < 5) {
|
||||
System.print(i)
|
||||
i = i + 1
|
||||
}</code></pre>
|
||||
|
||||
<div class="example-output">0
|
||||
1
|
||||
2
|
||||
3
|
||||
4</div>
|
||||
|
||||
<h2>For Loops</h2>
|
||||
<p>Iterate over any sequence:</p>
|
||||
<pre><code>for (item in [1, 2, 3]) {
|
||||
System.print(item)
|
||||
}</code></pre>
|
||||
|
||||
<h3>Range Iteration</h3>
|
||||
<pre><code>for (i in 1..5) {
|
||||
System.print(i)
|
||||
}
|
||||
// Prints: 1 2 3 4 5
|
||||
|
||||
for (i in 1...5) {
|
||||
System.print(i)
|
||||
}
|
||||
// Prints: 1 2 3 4 (exclusive)</code></pre>
|
||||
|
||||
<h3>String Iteration</h3>
|
||||
<pre><code>for (char in "hello") {
|
||||
System.print(char)
|
||||
}
|
||||
// Prints each character</code></pre>
|
||||
|
||||
<h3>Map Iteration</h3>
|
||||
<pre><code>var person = {"name": "Alice", "age": 30}
|
||||
for (key in person.keys) {
|
||||
System.print("%(key): %(person[key])")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Break</h2>
|
||||
<p>Exit a loop early:</p>
|
||||
<pre><code>for (i in 1..100) {
|
||||
if (i > 5) break
|
||||
System.print(i)
|
||||
}
|
||||
// Prints: 1 2 3 4 5</code></pre>
|
||||
|
||||
<h2>Continue</h2>
|
||||
<p>Skip to the next iteration:</p>
|
||||
<pre><code>for (i in 1..10) {
|
||||
if (i % 2 == 0) continue
|
||||
System.print(i)
|
||||
}
|
||||
// Prints: 1 3 5 7 9 (odd numbers only)</code></pre>
|
||||
|
||||
<h2>Block Scoping</h2>
|
||||
<p>Blocks create new scopes:</p>
|
||||
<pre><code>var x = "outer"
|
||||
{
|
||||
var x = "inner"
|
||||
System.print(x) // inner
|
||||
}
|
||||
System.print(x) // outer</code></pre>
|
||||
|
||||
<p>Variables declared in a block are not visible outside:</p>
|
||||
<pre><code>if (true) {
|
||||
var temp = "temporary"
|
||||
}
|
||||
// temp is not accessible here</code></pre>
|
||||
|
||||
<h2>Iterating with Index</h2>
|
||||
<p>Use range to get indices:</p>
|
||||
<pre><code>var list = ["a", "b", "c"]
|
||||
for (i in 0...list.count) {
|
||||
System.print("%(i): %(list[i])")
|
||||
}</code></pre>
|
||||
|
||||
<div class="example-output">0: a
|
||||
1: b
|
||||
2: c</div>
|
||||
|
||||
<h2>Infinite Loops</h2>
|
||||
<p>Create with <code>while (true)</code>:</p>
|
||||
<pre><code>var count = 0
|
||||
while (true) {
|
||||
count = count + 1
|
||||
if (count >= 5) break
|
||||
System.print(count)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Nested Loops</h2>
|
||||
<pre><code>for (i in 1..3) {
|
||||
for (j in 1..3) {
|
||||
System.print("%(i), %(j)")
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p>Break only exits the innermost loop:</p>
|
||||
<pre><code>for (i in 1..3) {
|
||||
for (j in 1..10) {
|
||||
if (j > 2) break // Only breaks inner loop
|
||||
System.print("%(i), %(j)")
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h2>Iteration Patterns</h2>
|
||||
|
||||
<h3>Filtering</h3>
|
||||
<pre><code>var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
var evens = []
|
||||
for (n in numbers) {
|
||||
if (n % 2 == 0) evens.add(n)
|
||||
}
|
||||
System.print(evens) // [2, 4, 6, 8, 10]</code></pre>
|
||||
|
||||
<h3>Mapping</h3>
|
||||
<pre><code>var numbers = [1, 2, 3, 4, 5]
|
||||
var squared = []
|
||||
for (n in numbers) {
|
||||
squared.add(n * n)
|
||||
}
|
||||
System.print(squared) // [1, 4, 9, 16, 25]</code></pre>
|
||||
|
||||
<h3>Finding</h3>
|
||||
<pre><code>var numbers = [1, 3, 5, 8, 9, 11]
|
||||
var firstEven = null
|
||||
for (n in numbers) {
|
||||
if (n % 2 == 0) {
|
||||
firstEven = n
|
||||
break
|
||||
}
|
||||
}
|
||||
System.print(firstEven) // 8</code></pre>
|
||||
|
||||
<h3>Reducing</h3>
|
||||
<pre><code>var numbers = [1, 2, 3, 4, 5]
|
||||
var sum = 0
|
||||
for (n in numbers) {
|
||||
sum = sum + n
|
||||
}
|
||||
System.print(sum) // 15</code></pre>
|
||||
|
||||
<h2>Functional Alternatives</h2>
|
||||
<p>Lists provide functional methods that are often cleaner:</p>
|
||||
<pre><code>var numbers = [1, 2, 3, 4, 5]
|
||||
|
||||
var evens = numbers.where { |n| n % 2 == 0 }.toList
|
||||
var squared = numbers.map { |n| n * n }.toList
|
||||
var sum = numbers.reduce(0) { |acc, n| acc + n }</code></pre>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="methods.html" class="prev">Methods</a>
|
||||
<a href="fibers.html" class="next">Fibers</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,302 @@
|
||||
<!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>Syntax Overview - 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" class="active">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">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>
|
||||
<span>Language Reference</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Syntax Overview</h1>
|
||||
|
||||
<p>Wren is a small, fast, class-based scripting language with a clean syntax inspired by languages like Dart, Lua, and Smalltalk. This section covers the core language features.</p>
|
||||
|
||||
<div class="toc">
|
||||
<h4>Language Topics</h4>
|
||||
<ul>
|
||||
<li><a href="classes.html">Classes</a> - Object-oriented programming</li>
|
||||
<li><a href="methods.html">Methods</a> - Method definition and operators</li>
|
||||
<li><a href="control-flow.html">Control Flow</a> - Conditionals and loops</li>
|
||||
<li><a href="fibers.html">Fibers</a> - Cooperative concurrency</li>
|
||||
<li><a href="modules.html">Modules</a> - Import system</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<p>Single-line comments start with <code>//</code>:</p>
|
||||
<pre><code>// This is a comment
|
||||
var x = 42 // Inline comment</code></pre>
|
||||
|
||||
<p>Block comments use <code>/* */</code> and can nest:</p>
|
||||
<pre><code>/* This is a
|
||||
multi-line comment */
|
||||
|
||||
/* Outer /* nested */ comment */</code></pre>
|
||||
|
||||
<h2>Variables</h2>
|
||||
<p>Declare variables with <code>var</code>:</p>
|
||||
<pre><code>var name = "Wren"
|
||||
var count = 42
|
||||
var active = true
|
||||
var nothing = null</code></pre>
|
||||
|
||||
<p>Variables must be initialized when declared. They are lexically scoped:</p>
|
||||
<pre><code>var outer = "outside"
|
||||
{
|
||||
var inner = "inside"
|
||||
System.print(outer) // Works
|
||||
}
|
||||
// inner is not accessible here</code></pre>
|
||||
|
||||
<h2>Data Types</h2>
|
||||
|
||||
<h3>Numbers</h3>
|
||||
<p>All numbers are 64-bit floating point:</p>
|
||||
<pre><code>var integer = 42
|
||||
var decimal = 3.14159
|
||||
var negative = -100
|
||||
var scientific = 1.5e10
|
||||
var hex = 0xFF
|
||||
var binary = 0b1010</code></pre>
|
||||
|
||||
<h3>Strings</h3>
|
||||
<p>Strings are immutable sequences of bytes:</p>
|
||||
<pre><code>var single = "Hello"
|
||||
var escape = "Line 1\nLine 2"
|
||||
var interpolation = "Value: %(1 + 2)"</code></pre>
|
||||
|
||||
<p>Raw strings avoid escape processing:</p>
|
||||
<pre><code>var raw = """
|
||||
This is a raw string.
|
||||
Backslashes \ are literal.
|
||||
"""</code></pre>
|
||||
|
||||
<h3>Booleans</h3>
|
||||
<pre><code>var yes = true
|
||||
var no = false</code></pre>
|
||||
|
||||
<p>Only <code>false</code> and <code>null</code> are falsy. All other values, including <code>0</code> and empty strings, are truthy.</p>
|
||||
|
||||
<h3>Null</h3>
|
||||
<pre><code>var nothing = null</code></pre>
|
||||
|
||||
<h3>Ranges</h3>
|
||||
<p>Ranges represent sequences of numbers:</p>
|
||||
<pre><code>var inclusive = 1..5 // 1, 2, 3, 4, 5
|
||||
var exclusive = 1...5 // 1, 2, 3, 4</code></pre>
|
||||
|
||||
<h3>Lists</h3>
|
||||
<p>Ordered, indexable collections:</p>
|
||||
<pre><code>var empty = []
|
||||
var numbers = [1, 2, 3, 4, 5]
|
||||
var mixed = [1, "two", true, null]
|
||||
|
||||
System.print(numbers[0]) // 1
|
||||
System.print(numbers[-1]) // 5 (last element)
|
||||
numbers[0] = 10
|
||||
numbers.add(6)</code></pre>
|
||||
|
||||
<h3>Maps</h3>
|
||||
<p>Key-value collections:</p>
|
||||
<pre><code>var empty = {}
|
||||
var person = {
|
||||
"name": "Alice",
|
||||
"age": 30
|
||||
}
|
||||
|
||||
System.print(person["name"]) // Alice
|
||||
person["city"] = "Amsterdam"</code></pre>
|
||||
|
||||
<h2>Operators</h2>
|
||||
|
||||
<h3>Arithmetic</h3>
|
||||
<pre><code>1 + 2 // 3
|
||||
5 - 3 // 2
|
||||
4 * 3 // 12
|
||||
10 / 4 // 2.5
|
||||
10 % 3 // 1 (modulo)</code></pre>
|
||||
|
||||
<h3>Comparison</h3>
|
||||
<pre><code>1 == 1 // true
|
||||
1 != 2 // true
|
||||
1 < 2 // true
|
||||
1 <= 1 // true
|
||||
2 > 1 // true
|
||||
2 >= 2 // true</code></pre>
|
||||
|
||||
<h3>Logical</h3>
|
||||
<pre><code>true && false // false
|
||||
true || false // true
|
||||
!true // false</code></pre>
|
||||
|
||||
<p>Logical operators short-circuit:</p>
|
||||
<pre><code>false && expensive() // expensive() not called
|
||||
true || expensive() // expensive() not called</code></pre>
|
||||
|
||||
<h3>Bitwise</h3>
|
||||
<pre><code>5 & 3 // 1 (AND)
|
||||
5 | 3 // 7 (OR)
|
||||
5 ^ 3 // 6 (XOR)
|
||||
~5 // -6 (NOT)
|
||||
8 << 2 // 32 (left shift)
|
||||
8 >> 2 // 2 (right shift)</code></pre>
|
||||
|
||||
<h3>Ternary</h3>
|
||||
<pre><code>var result = condition ? valueIfTrue : valueIfFalse</code></pre>
|
||||
|
||||
<h2>String Interpolation</h2>
|
||||
<p>Embed expressions in strings with <code>%()</code>:</p>
|
||||
<pre><code>var name = "World"
|
||||
System.print("Hello, %(name)!")
|
||||
|
||||
var a = 3
|
||||
var b = 4
|
||||
System.print("%(a) + %(b) = %(a + b)")</code></pre>
|
||||
|
||||
<p>Any expression can be interpolated:</p>
|
||||
<pre><code>System.print("Random: %(Random.new().float())")
|
||||
System.print("List: %([1, 2, 3].map { |x| x * 2 })")</code></pre>
|
||||
|
||||
<h2>Blocks</h2>
|
||||
<p>Blocks are anonymous functions. They use curly braces:</p>
|
||||
<pre><code>var block = { System.print("Hello") }
|
||||
block.call()
|
||||
|
||||
var add = { |a, b| a + b }
|
||||
System.print(add.call(1, 2)) // 3</code></pre>
|
||||
|
||||
<p>Blocks with a single expression return that value:</p>
|
||||
<pre><code>var square = { |x| x * x }
|
||||
System.print(square.call(5)) // 25</code></pre>
|
||||
|
||||
<h2>Functions</h2>
|
||||
<p>Use <code>Fn.new</code> for functions stored in variables:</p>
|
||||
<pre><code>var greet = Fn.new { |name|
|
||||
return "Hello, %(name)!"
|
||||
}
|
||||
System.print(greet.call("World"))</code></pre>
|
||||
|
||||
<p>Functions can have multiple statements:</p>
|
||||
<pre><code>var factorial = Fn.new { |n|
|
||||
if (n <= 1) return 1
|
||||
return n * factorial.call(n - 1)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Is Operator</h2>
|
||||
<p>Check if an object is an instance of a class:</p>
|
||||
<pre><code>"hello" is String // true
|
||||
42 is Num // true
|
||||
[1, 2] is List // true</code></pre>
|
||||
|
||||
<h2>Reserved Words</h2>
|
||||
<p>The following are reserved and cannot be used as identifiers:</p>
|
||||
<pre><code>break class construct else false for foreign if import
|
||||
in is null return static super this true var while</code></pre>
|
||||
|
||||
<h2>Identifiers</h2>
|
||||
<p>Identifiers follow these conventions:</p>
|
||||
<ul>
|
||||
<li><code>camelCase</code> for variables and methods</li>
|
||||
<li><code>PascalCase</code> for class names</li>
|
||||
<li><code>_underscore</code> prefix for private fields</li>
|
||||
<li><code>UPPER_CASE</code> for constants (by convention)</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="../getting-started/repl.html" class="prev">Using the REPL</a>
|
||||
<a href="classes.html" class="next">Classes</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,376 @@
|
||||
<!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>Methods - 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" class="active">Methods</a></li>
|
||||
<li><a href="control-flow.html">Control Flow</a></li>
|
||||
<li><a href="fibers.html">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>Methods</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Methods</h1>
|
||||
|
||||
<p>Methods are the primary way to define behavior in Wren. They can be instance methods, static methods, getters, setters, or operators.</p>
|
||||
|
||||
<h2>Instance Methods</h2>
|
||||
<p>Instance methods operate on a specific object:</p>
|
||||
<pre><code>class Greeter {
|
||||
construct new(name) {
|
||||
_name = name
|
||||
}
|
||||
|
||||
greet() {
|
||||
return "Hello, %(_name)!"
|
||||
}
|
||||
|
||||
greetWith(greeting) {
|
||||
return "%(greeting), %(_name)!"
|
||||
}
|
||||
}
|
||||
|
||||
var g = Greeter.new("World")
|
||||
System.print(g.greet()) // Hello, World!
|
||||
System.print(g.greetWith("Hi")) // Hi, World!</code></pre>
|
||||
|
||||
<h2>Static Methods</h2>
|
||||
<p>Static methods belong to the class rather than instances:</p>
|
||||
<pre><code>class StringUtils {
|
||||
static reverse(s) {
|
||||
var result = ""
|
||||
for (i in (s.count - 1)..0) {
|
||||
result = result + s[i]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
static capitalize(s) {
|
||||
if (s.count == 0) return s
|
||||
return s[0].toString.toUpperCase + s[1..-1]
|
||||
}
|
||||
}
|
||||
|
||||
System.print(StringUtils.reverse("hello")) // olleh
|
||||
System.print(StringUtils.capitalize("hello")) // Hello</code></pre>
|
||||
|
||||
<h2>Getters</h2>
|
||||
<p>Getters are methods without parentheses that act like properties:</p>
|
||||
<pre><code>class Temperature {
|
||||
construct celsius(c) {
|
||||
_celsius = c
|
||||
}
|
||||
|
||||
celsius { _celsius }
|
||||
fahrenheit { _celsius * 9 / 5 + 32 }
|
||||
kelvin { _celsius + 273.15 }
|
||||
}
|
||||
|
||||
var temp = Temperature.celsius(100)
|
||||
System.print(temp.celsius) // 100
|
||||
System.print(temp.fahrenheit) // 212
|
||||
System.print(temp.kelvin) // 373.15</code></pre>
|
||||
|
||||
<h2>Setters</h2>
|
||||
<p>Setters use the <code>=</code> suffix:</p>
|
||||
<pre><code>class Box {
|
||||
construct new(value) {
|
||||
_value = value
|
||||
}
|
||||
|
||||
value { _value }
|
||||
|
||||
value=(v) {
|
||||
if (v < 0) Fiber.abort("Value must be non-negative")
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
var box = Box.new(10)
|
||||
box.value = 20
|
||||
System.print(box.value) // 20</code></pre>
|
||||
|
||||
<h2>Method Signatures</h2>
|
||||
<p>Wren distinguishes methods by their signature (name + arity):</p>
|
||||
<pre><code>class Example {
|
||||
method { "no args" }
|
||||
method() { "zero args with parens" }
|
||||
method(a) { "one arg" }
|
||||
method(a, b) { "two args" }
|
||||
}
|
||||
|
||||
var e = Example.new()
|
||||
System.print(e.method) // no args
|
||||
System.print(e.method()) // zero args with parens
|
||||
System.print(e.method(1)) // one arg
|
||||
System.print(e.method(1, 2)) // two args</code></pre>
|
||||
|
||||
<h2>Block Arguments</h2>
|
||||
<p>Methods can take a block as the last argument:</p>
|
||||
<pre><code>class List {
|
||||
static each(list, fn) {
|
||||
for (item in list) {
|
||||
fn.call(item)
|
||||
}
|
||||
}
|
||||
|
||||
static map(list, fn) {
|
||||
var result = []
|
||||
for (item in list) {
|
||||
result.add(fn.call(item))
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
var numbers = [1, 2, 3, 4, 5]
|
||||
|
||||
List.each(numbers) { |n|
|
||||
System.print(n)
|
||||
}
|
||||
|
||||
var doubled = List.map(numbers) { |n| n * 2 }
|
||||
System.print(doubled) // [2, 4, 6, 8, 10]</code></pre>
|
||||
|
||||
<h2>Operator Overloading</h2>
|
||||
<p>Classes can define custom behavior for operators:</p>
|
||||
|
||||
<h3>Binary Operators</h3>
|
||||
<pre><code>class Vector {
|
||||
construct new(x, y) {
|
||||
_x = x
|
||||
_y = y
|
||||
}
|
||||
|
||||
x { _x }
|
||||
y { _y }
|
||||
|
||||
+(other) { Vector.new(_x + other.x, _y + other.y) }
|
||||
-(other) { Vector.new(_x - other.x, _y - other.y) }
|
||||
*(scalar) { Vector.new(_x * scalar, _y * scalar) }
|
||||
/(scalar) { Vector.new(_x / scalar, _y / scalar) }
|
||||
|
||||
==(other) {
|
||||
return _x == other.x && _y == other.y
|
||||
}
|
||||
|
||||
toString { "(%(_x), %(_y))" }
|
||||
}
|
||||
|
||||
var a = Vector.new(1, 2)
|
||||
var b = Vector.new(3, 4)
|
||||
|
||||
System.print((a + b).toString) // (4, 6)
|
||||
System.print((a * 2).toString) // (2, 4)
|
||||
System.print(a == b) // false</code></pre>
|
||||
|
||||
<h3>Available Operators</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Operator</th>
|
||||
<th>Signature</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr><td><code>+</code></td><td><code>+(other)</code></td><td>Addition</td></tr>
|
||||
<tr><td><code>-</code></td><td><code>-(other)</code></td><td>Subtraction</td></tr>
|
||||
<tr><td><code>*</code></td><td><code>*(other)</code></td><td>Multiplication</td></tr>
|
||||
<tr><td><code>/</code></td><td><code>/(other)</code></td><td>Division</td></tr>
|
||||
<tr><td><code>%</code></td><td><code>%(other)</code></td><td>Modulo</td></tr>
|
||||
<tr><td><code><</code></td><td><code><(other)</code></td><td>Less than</td></tr>
|
||||
<tr><td><code>></code></td><td><code>>(other)</code></td><td>Greater than</td></tr>
|
||||
<tr><td><code><=</code></td><td><code><=(other)</code></td><td>Less or equal</td></tr>
|
||||
<tr><td><code>>=</code></td><td><code>>=(other)</code></td><td>Greater or equal</td></tr>
|
||||
<tr><td><code>==</code></td><td><code>==(other)</code></td><td>Equality</td></tr>
|
||||
<tr><td><code>!=</code></td><td><code>!=(other)</code></td><td>Inequality</td></tr>
|
||||
<tr><td><code>&</code></td><td><code>&(other)</code></td><td>Bitwise AND</td></tr>
|
||||
<tr><td><code>|</code></td><td><code>|(other)</code></td><td>Bitwise OR</td></tr>
|
||||
<tr><td><code>^</code></td><td><code>^(other)</code></td><td>Bitwise XOR</td></tr>
|
||||
<tr><td><code><<</code></td><td><code><<(other)</code></td><td>Left shift</td></tr>
|
||||
<tr><td><code>>></code></td><td><code>>>(other)</code></td><td>Right shift</td></tr>
|
||||
<tr><td><code>..</code></td><td><code>..(other)</code></td><td>Inclusive range</td></tr>
|
||||
<tr><td><code>...</code></td><td><code>...(other)</code></td><td>Exclusive range</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Unary Operators</h3>
|
||||
<pre><code>class Vector {
|
||||
construct new(x, y) {
|
||||
_x = x
|
||||
_y = y
|
||||
}
|
||||
|
||||
- { Vector.new(-_x, -_y) }
|
||||
! { Vector.new(_y, _x) } // Perpendicular
|
||||
|
||||
toString { "(%(_x), %(_y))" }
|
||||
}
|
||||
|
||||
var v = Vector.new(3, 4)
|
||||
System.print((-v).toString) // (-3, -4)</code></pre>
|
||||
|
||||
<h3>Subscript Operators</h3>
|
||||
<pre><code>class Grid {
|
||||
construct new(width, height) {
|
||||
_width = width
|
||||
_height = height
|
||||
_cells = List.filled(width * height, 0)
|
||||
}
|
||||
|
||||
[x, y] { _cells[y * _width + x] }
|
||||
[x, y]=(value) { _cells[y * _width + x] = value }
|
||||
}
|
||||
|
||||
var grid = Grid.new(10, 10)
|
||||
grid[5, 3] = 42
|
||||
System.print(grid[5, 3]) // 42</code></pre>
|
||||
|
||||
<h2>Calling Methods</h2>
|
||||
|
||||
<h3>With Parentheses</h3>
|
||||
<pre><code>object.method()
|
||||
object.method(arg1)
|
||||
object.method(arg1, arg2)</code></pre>
|
||||
|
||||
<h3>Without Parentheses (Getters)</h3>
|
||||
<pre><code>object.property
|
||||
object.count
|
||||
string.bytes</code></pre>
|
||||
|
||||
<h3>With Block Argument</h3>
|
||||
<pre><code>list.map { |x| x * 2 }
|
||||
list.where { |x| x > 5 }
|
||||
list.each { |x| System.print(x) }</code></pre>
|
||||
|
||||
<h3>Chaining</h3>
|
||||
<pre><code>var result = list
|
||||
.where { |x| x > 0 }
|
||||
.map { |x| x * 2 }
|
||||
.toList</code></pre>
|
||||
|
||||
<h2>Return Values</h2>
|
||||
<p>Methods return the last expression or use <code>return</code>:</p>
|
||||
<pre><code>class Example {
|
||||
implicit() {
|
||||
42 // Implicit return
|
||||
}
|
||||
|
||||
explicit() {
|
||||
return 42 // Explicit return
|
||||
}
|
||||
|
||||
early(x) {
|
||||
if (x < 0) return -1
|
||||
if (x > 0) return 1
|
||||
return 0
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p>Methods without a return statement return <code>null</code>.</p>
|
||||
|
||||
<h2>Method References</h2>
|
||||
<p>You cannot directly reference a method as a value. Use a block wrapper:</p>
|
||||
<pre><code>class Printer {
|
||||
static print(value) {
|
||||
System.print(value)
|
||||
}
|
||||
}
|
||||
|
||||
var fn = Fn.new { |x| Printer.print(x) }
|
||||
fn.call("Hello") // Hello</code></pre>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="classes.html" class="prev">Classes</a>
|
||||
<a href="control-flow.html" class="next">Control Flow</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,397 @@
|
||||
<!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>Modules - 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">Fibers</a></li>
|
||||
<li><a href="modules.html" class="active">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>Modules</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Modules</h1>
|
||||
|
||||
<p>Modules organize code into separate, reusable files. Wren-CLI provides built-in modules and supports user-defined modules.</p>
|
||||
|
||||
<h2>Importing</h2>
|
||||
<p>Use <code>import</code> to load a module and access its classes:</p>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"name": "Wren"}')
|
||||
System.print(data["name"])</code></pre>
|
||||
|
||||
<h3>Multiple Imports</h3>
|
||||
<p>Import multiple classes from one module:</p>
|
||||
<pre><code>import "io" for File, Directory, Stdin</code></pre>
|
||||
|
||||
<h3>Import All</h3>
|
||||
<p>Some modules export many classes. Import what you need:</p>
|
||||
<pre><code>import "os" for Process, Platform</code></pre>
|
||||
|
||||
<h2>Built-in Modules</h2>
|
||||
<p>Wren-CLI provides these modules:</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Module</th>
|
||||
<th>Description</th>
|
||||
<th>Main Classes</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/http.html">http</a></td>
|
||||
<td>HTTP client</td>
|
||||
<td>Http, HttpResponse, Url</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/websocket.html">websocket</a></td>
|
||||
<td>WebSocket client/server</td>
|
||||
<td>WebSocket, WebSocketServer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/tls.html">tls</a></td>
|
||||
<td>TLS/SSL sockets</td>
|
||||
<td>TlsSocket</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/net.html">net</a></td>
|
||||
<td>TCP networking</td>
|
||||
<td>Socket, Server</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/dns.html">dns</a></td>
|
||||
<td>DNS resolution</td>
|
||||
<td>Dns</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/json.html">json</a></td>
|
||||
<td>JSON parsing</td>
|
||||
<td>Json</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/base64.html">base64</a></td>
|
||||
<td>Base64 encoding</td>
|
||||
<td>Base64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/regex.html">regex</a></td>
|
||||
<td>Regular expressions</td>
|
||||
<td>Regex, Match</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/jinja.html">jinja</a></td>
|
||||
<td>Template engine</td>
|
||||
<td>Environment, Template</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/crypto.html">crypto</a></td>
|
||||
<td>Cryptography</td>
|
||||
<td>Hash</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/os.html">os</a></td>
|
||||
<td>OS information</td>
|
||||
<td>Process, Platform</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/env.html">env</a></td>
|
||||
<td>Environment variables</td>
|
||||
<td>Env</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/signal.html">signal</a></td>
|
||||
<td>Unix signals</td>
|
||||
<td>Signal</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/subprocess.html">subprocess</a></td>
|
||||
<td>Run processes</td>
|
||||
<td>Subprocess</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/sqlite.html">sqlite</a></td>
|
||||
<td>SQLite database</td>
|
||||
<td>Sqlite</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/datetime.html">datetime</a></td>
|
||||
<td>Date/time handling</td>
|
||||
<td>DateTime, Duration</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/timer.html">timer</a></td>
|
||||
<td>Timers and delays</td>
|
||||
<td>Timer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/io.html">io</a></td>
|
||||
<td>File I/O</td>
|
||||
<td>File, Directory, Stdin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/scheduler.html">scheduler</a></td>
|
||||
<td>Async scheduling</td>
|
||||
<td>Scheduler</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/math.html">math</a></td>
|
||||
<td>Math functions</td>
|
||||
<td>Math</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>User Modules</h2>
|
||||
<p>Create your own modules by putting code in <code>.wren</code> files.</p>
|
||||
|
||||
<h3>Creating a Module</h3>
|
||||
<p>Create <code>utils.wren</code>:</p>
|
||||
<pre><code>class StringUtils {
|
||||
static reverse(s) {
|
||||
var result = ""
|
||||
for (i in (s.count - 1)..0) {
|
||||
result = result + s[i]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
static capitalize(s) {
|
||||
if (s.count == 0) return s
|
||||
return s[0].toString.toUpperCase + s[1..-1]
|
||||
}
|
||||
}
|
||||
|
||||
class MathUtils {
|
||||
static clamp(value, min, max) {
|
||||
if (value < min) return min
|
||||
if (value > max) return max
|
||||
return value
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h3>Using a Module</h3>
|
||||
<p>Import with a relative path:</p>
|
||||
<pre><code>import "./utils" for StringUtils, MathUtils
|
||||
|
||||
System.print(StringUtils.reverse("hello")) // olleh
|
||||
System.print(StringUtils.capitalize("world")) // World
|
||||
System.print(MathUtils.clamp(15, 0, 10)) // 10</code></pre>
|
||||
|
||||
<h2>Module Resolution</h2>
|
||||
|
||||
<h3>Built-in Modules</h3>
|
||||
<p>Names without paths are built-in modules:</p>
|
||||
<pre><code>import "json" for Json // Built-in
|
||||
import "http" for Http // Built-in</code></pre>
|
||||
|
||||
<h3>Relative Paths</h3>
|
||||
<p>Paths starting with <code>./</code> or <code>../</code> are relative to the current file:</p>
|
||||
<pre><code>import "./helpers" for Helper // Same directory
|
||||
import "../utils/string" for StringUtil // Parent directory</code></pre>
|
||||
|
||||
<h3>Absolute Paths</h3>
|
||||
<p>Paths starting with <code>/</code> are absolute:</p>
|
||||
<pre><code>import "/home/user/libs/mylib" for MyClass</code></pre>
|
||||
|
||||
<h2>Module Structure</h2>
|
||||
<p>A typical project structure:</p>
|
||||
<pre><code>project/
|
||||
├── main.wren
|
||||
├── lib/
|
||||
│ ├── http_client.wren
|
||||
│ ├── database.wren
|
||||
│ └── templates.wren
|
||||
└── tests/
|
||||
└── test_http.wren</code></pre>
|
||||
|
||||
<p>In <code>main.wren</code>:</p>
|
||||
<pre><code>import "./lib/http_client" for HttpClient
|
||||
import "./lib/database" for Database
|
||||
import "./lib/templates" for TemplateEngine
|
||||
|
||||
var client = HttpClient.new()
|
||||
var db = Database.new("data.db")
|
||||
var tmpl = TemplateEngine.new()</code></pre>
|
||||
|
||||
<h2>Module Top-Level Code</h2>
|
||||
<p>Code outside classes runs when the module is first imported:</p>
|
||||
<pre><code>// config.wren
|
||||
System.print("Config module loading...")
|
||||
|
||||
class Config {
|
||||
static port { 8080 }
|
||||
static host { "localhost" }
|
||||
}
|
||||
|
||||
System.print("Config ready")</code></pre>
|
||||
|
||||
<pre><code>// main.wren
|
||||
System.print("Before import")
|
||||
import "./config" for Config
|
||||
System.print("After import")
|
||||
System.print("Port: %(Config.port)")
|
||||
|
||||
// Output:
|
||||
// Before import
|
||||
// Config module loading...
|
||||
// Config ready
|
||||
// After import
|
||||
// Port: 8080</code></pre>
|
||||
|
||||
<h2>Module Variables</h2>
|
||||
<p>Top-level variables are module-private by default:</p>
|
||||
<pre><code>// counter.wren
|
||||
var _count = 0 // Private to module
|
||||
|
||||
class Counter {
|
||||
static increment() { _count = _count + 1 }
|
||||
static count { _count }
|
||||
}</code></pre>
|
||||
|
||||
<pre><code>// main.wren
|
||||
import "./counter" for Counter
|
||||
|
||||
Counter.increment()
|
||||
Counter.increment()
|
||||
System.print(Counter.count) // 2
|
||||
// _count is not accessible here</code></pre>
|
||||
|
||||
<h2>Circular Imports</h2>
|
||||
<p>Wren handles circular imports by completing partial modules:</p>
|
||||
<pre><code>// a.wren
|
||||
import "./b" for B
|
||||
|
||||
class A {
|
||||
static greet() { "Hello from A" }
|
||||
static callB() { B.greet() }
|
||||
}
|
||||
|
||||
// b.wren
|
||||
import "./a" for A
|
||||
|
||||
class B {
|
||||
static greet() { "Hello from B" }
|
||||
static callA() { A.greet() }
|
||||
}</code></pre>
|
||||
|
||||
<p>This works because class definitions are hoisted.</p>
|
||||
|
||||
<div class="admonition warning">
|
||||
<div class="admonition-title">Warning</div>
|
||||
<p>Avoid calling imported classes in top-level code during circular imports, as they may not be fully initialized.</p>
|
||||
</div>
|
||||
|
||||
<h2>Re-exporting</h2>
|
||||
<p>Create a facade module that re-exports from multiple modules:</p>
|
||||
<pre><code>// lib/index.wren
|
||||
import "./http_client" for HttpClient
|
||||
import "./database" for Database
|
||||
import "./templates" for TemplateEngine
|
||||
|
||||
class Lib {
|
||||
static httpClient { HttpClient }
|
||||
static database { Database }
|
||||
static templates { TemplateEngine }
|
||||
}</code></pre>
|
||||
|
||||
<pre><code>// main.wren
|
||||
import "./lib/index" for Lib
|
||||
|
||||
var client = Lib.httpClient.new()</code></pre>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="fibers.html" class="prev">Fibers</a>
|
||||
<a href="../api/index.html" class="next">API Reference</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user