This commit is contained in:
2026-01-24 23:40:22 +01:00
parent 1a0f7f51a1
commit 8c1a721c4c
105 changed files with 23275 additions and 94 deletions
+422
View File
@@ -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>
+332
View File
@@ -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 &lt; 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>
+384
View File
@@ -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 &lt;= 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>
+302
View File
@@ -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 &lt; 2 // true
1 &lt;= 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 &lt;&lt; 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 &lt;= 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>
+376
View File
@@ -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 &lt; 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>&lt;</code></td><td><code>&lt;(other)</code></td><td>Less than</td></tr>
<tr><td><code>&gt;</code></td><td><code>>(other)</code></td><td>Greater than</td></tr>
<tr><td><code>&lt;=</code></td><td><code>&lt;=(other)</code></td><td>Less or equal</td></tr>
<tr><td><code>&gt;=</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>&amp;</code></td><td><code>&amp;(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>&lt;&lt;</code></td><td><code>&lt;&lt;(other)</code></td><td>Left shift</td></tr>
<tr><td><code>&gt;&gt;</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 &lt; 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>
+397
View File
@@ -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 &lt; 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>