1
0
Fork 0
forked from fun/fun

Documentation fixes. No code changes. (0.40.5)

This commit is contained in:
Johannes Findeisen 2026-04-11 02:38:47 +02:00
commit 02f0c07bce
28 changed files with 271 additions and 496 deletions

View file

@ -31,8 +31,7 @@ This guide focuses on arrays: creation, indexing, mutation, iteration, slicing,
## Creating arrays
```
// literals
<pre>// literals
a = [1, 2, 3]
b = ["alpha", "beta"]
empty = []
@ -42,30 +41,27 @@ grid = [[1,2], [3,4]]
print(typeof(a)) // "array"
print(len(a)) // 3
```
</pre>
Tip: Prefer squarebracket literals for clarity and performance versus building via repeated push in a hot loop.
## Indexing (0based) and assignment
```
a = [10, 20, 30]
<pre>a = [10, 20, 30]
print(a[0]) // 10
print(a[2]) // 30
// update in place
a[1] = 42
print(a) // [10, 42, 30]
```
</pre>
Notes:
- Valid indices are 0..len(a)-1. Using an invalid index raises a runtime error.
- Assignment updates the existing array; references pointing to it observe the change.
## Appending, popping, inserting, removing
```
a = [1]
<pre>a = [1]
// append to end; returns new length
push(a, 7) // => 2, a is now [1, 7]
@ -79,12 +75,10 @@ insert(a, 1, 99) // a => [1, 99, 2, 3]
// remove at index (shifts left)
remove(a, 2) // a => [1, 99, 3]
```
</pre>
## Slicing and concatenation
```
a = [0,1,2,3,4]
<pre>a = [0,1,2,3,4]
// slice(startInclusive, endExclusive)
head = slice(a, 0, 3) // [0,1,2]
@ -93,14 +87,12 @@ mid = slice(a, 1, 4) // [1,2,3]
// concat: join two arrays
b = ["x", "y"]
ab = concat(a, b) // [0,1,2,3,4,"x","y"]
```
</pre>
Slicing returns a new array. The original is unchanged.
## Iteration patterns
```
a = ["a", "b", "c"]
<pre>a = ["a", "b", "c"]
// indexbased loop
for i = 0; i < len(a); i = i + 1 {
@ -114,14 +106,12 @@ for pair in it.enumerate(a) {
val = pair[1]
print(to_string(idx) + ":" + val)
}
```
</pre>
## Copying vs. referencing
Arrays are reference types. Assigning just copies the reference, not the contents:
```
orig = [1, 2]
<pre>orig = [1, 2]
alias = orig // points to the same array
alias[0] = 9
print(orig) // [9, 2]
@ -131,17 +121,14 @@ copy = slice(orig, 0, len(orig))
copy[1] = 7
print(orig) // [9, 2]
print(copy) // [9, 7]
```
</pre>
Shallow copies duplicate the toplevel array but not nested structures.
## Equality
```
print([1,2] == [1,2]) // true
<pre>print([1,2] == [1,2]) // true
print([1,2] == [2,1]) // false
```
</pre>
Array equality compares length and elementwise equality recursively.
## Common utilities
@ -160,19 +147,16 @@ Check your lib directory (e.g., lib/utils) for additional helpers.
## Error handling and bounds
```
a = [0]
<pre>a = [0]
// a[1] is out of range → runtime error
```
</pre>
Tips:
- Guard indices: if i < 0 or i >= len(a) { /* handle */ }
- Use remove/insert carefully inside loops; indices of following items change.
## Interop with maps and strings
```
// arrays of maps
<pre>// arrays of maps
users = [ {"name":"Ada"}, {"name":"Lin"} ]
print(users[1]["name"]) // Lin
@ -180,8 +164,7 @@ print(users[1]["name"]) // Lin
#include <utils/strings.fun> as su // adjust if present in your tree
parts = su.split("a,b,c", ",") // ["a","b","c"]
csv = su.join(parts, ",") // "a,b,c"
```
</pre>
## Performance tips
- Preallocate by building from literals or chunked appends rather than onebyone in very tight loops.
@ -190,8 +173,7 @@ csv = su.join(parts, ",") // "a,b,c"
## Examples
```
// filter even numbers
<pre>// filter even numbers
src = [0,1,2,3,4,5]
dst = []
for i = 0; i < len(src); i = i + 1 {
@ -210,8 +192,7 @@ for i = 0; i < len(nested); i = i + 1 {
}
}
print(flat) // [1,2,3,4,5]
```
</pre>
## See also
- types.md — broader overview of core types with quick array examples.

View file

@ -57,18 +57,15 @@ Tip: Always check return values. In non-blocking mode, partial writes and short
## Typical patterns
1) Connect and switch to non-blocking
```
fd = tcp_connect(host, port)
<pre>fd = tcp_connect(host, port)
if (fd == 0)
// handle connect error
ok = fd_set_nonblock(fd, 1)
if (ok == 0)
// handle mode switch error
```
</pre>
2) Non-blocking write loop with readiness polling
```
remaining = req
<pre>remaining = req
while (len(remaining) > 0)
wr = fd_poll_write(fd, 1000) // wait up to 1s
if (wr < 0)
@ -79,11 +76,9 @@ while (len(remaining) > 0)
if (n < 0)
// send error; abort
remaining = substr(remaining, n, len(remaining) - n)
```
</pre>
3) Non-blocking read-until-close
```
buf = ""
<pre>buf = ""
while (true)
rd = fd_poll_read(fd, 2000) // wait up to 2s
if (rd < 0)
@ -99,8 +94,7 @@ while (true)
if (len(data) == 0)
break // closed
buf = buf + data
```
</pre>
## Timeouts and responsiveness
- timeout_ms controls how long poll waits. Use small timeouts inside loops to interleave work across multiple sockets or tasks.
@ -125,20 +119,14 @@ Because Fun keeps the primitives low-level and explicit, you can build simple co
- lib/net/http_cgi_server.fun — Library helpers used by the server examples
Run client example from a build tree:
```
FUN_LIB_DIR=./lib ./build/fun examples/io/async_http_client.fun
```
<pre>FUN_LIB_DIR=./lib ./build/fun examples/io/async_http_client.fun
</pre>
If installed system-wide, just:
```
fun /usr/share/fun/examples/io/async_http_client.fun
```
<pre>fun /usr/share/fun/examples/io/async_http_client.fun
</pre>
Or to try the await-style client using the cooperative scheduler:
```
FUN_LIB_DIR=./lib ./build/fun examples/io/await_http_client.fun
```
<pre>FUN_LIB_DIR=./lib ./build/fun examples/io/await_http_client.fun
</pre>
## Cooperative scheduler helpers (library-level)
The file lib/async/scheduler.fun provides a minimal cooperative scheduler built on the existing primitives. There is no VM-level suspension: each task is a small state machine advanced one step per tick. API summary:
@ -159,8 +147,7 @@ The file lib/async/scheduler.fun provides a minimal cooperative scheduler built
- Mark the task to be skipped for roughly ms milliseconds; cleared automatically when it wakes.
Example skeleton using the scheduler:
```
#include <async/scheduler.fun>
<pre>#include <async/scheduler.fun>
fun my_task_step(t)
if (t.phase == nil)
@ -205,8 +192,7 @@ fun my_task_step(t)
task = task_spawn(my_task_step, {})
run_until_done()
```
</pre>
This approach is 100% compatible with current runtimes and serves as a stepping stone towards potential future VM-level async/await opcodes.
## Error handling and cleanup

View file

@ -61,45 +61,35 @@ These are defined as `CACHE` variables, so they will persist in your `CMakeCache
When configuring, the build prints a summary like:
```
==== Fun build options ====
<pre>==== Fun build options ====
FUN_DEBUG: ENABLED|DISABLED
FUN_USE_MUSL: ENABLED|DISABLED
FUN_WITH_CPP: ENABLED|DISABLED
FUN_WITH_RUST: ENABLED|DISABLED
===========================
```
</pre>
## Example commands
Use the CLion-provided build directories or your own. Typical invocations:
### Debug
```
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
<pre>cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
-DFUN_DEBUG=ON -DFUN_WITH_RUST=OFF
cmake --build build --target build
```
</pre>
### Release
```
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
<pre>cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
-DFUN_DEBUG=OFF -DFUN_WITH_RUST=OFF
cmake --build build_release --target build
```
</pre>
### Enabling optional extensions
```
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
<pre>cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
-DFUN_WITH_CPP=ON -DFUN_WITH_RUST=ON -DFUN_WITH_OPENSSL=ON
cmake --build build_release --target build
```
</pre>
### Customizing VM limits
```
cmake -S . -B build_custom -DSTACK_SIZE=4096 -DMAX_GLOBALS=512
<pre>cmake -S . -B build_custom -DSTACK_SIZE=4096 -DMAX_GLOBALS=512
cmake --build build_custom --target fun
```
</pre>
If `FUN_WITH_RUST` is enabled, ensure `cargo` is available in PATH; the build will invoke it and link the produced static library.
If `FUN_WITH_OPENSSL` is enabled, CMake must detect your system OpenSSL (libcrypto).

View file

@ -29,10 +29,8 @@ Reference for the `fun` command-line interface.
For a complete usage guide (including REPL details, environment variables, include paths, examples, and install locations), see [fun.md](./fun/).
## Synopsis
```
fun [options] <script.fun> [-- args...]
```
<pre>fun [options] <script.fun> [-- args...]
</pre>
If no script is supplied and interactive mode is available, `fun` starts a REPL (see [repl.md](./repl/)).
## Common options
@ -54,11 +52,8 @@ See also: [includes.md](./includes/) for namespaced includes and search order.
## Examples
Run a script:
```
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
```
<pre>FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
</pre>
Start the REPL:
```
./build/fun -i
```
<pre>./build/fun -i
</pre>

View file

@ -5,7 +5,7 @@ noToc: false
noComments: false
noDate: false
title: Fun - Documentation
subtitle: Detailed documentation for the Fun programming language.
subtitle: Detailed documentation for the Fun programming language.<br><br><span style="color:red;">The documentation is always a work in progress! It will always be behind the development of the code. It will be 100% aligned with a 1.0 release... ;)</span>
description: The Fun Documentation Index
permalink: /documentation/
lang: en
@ -68,7 +68,7 @@ The examples directory contains demonstrations of most Fun features, from basic
## Examples
- [examples/README/](./examples/README/) - Catalog of all example scripts under ./examples/: what each area contains, how to run them, required env vars, and extension requirements.
- [examples/](./examples/) - Catalog of all example scripts under [https://git.xw3.org/fun/fun/src/branch/main/examples](https://git.xw3.org/fun/fun/src/branch/main/examples){:class="git"}: what each area contains, how to run them, required env vars, and extension requirements.
## External extensions

View file

@ -33,35 +33,27 @@ All commands assume you are in the repository root.
Example (Linux/macOS/BSD):
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun examples/include_lib.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun examples/include_lib.fun
</pre>
Windows (PowerShell):
```
$env:FUN_LIB_DIR = "$PWD/lib"
<pre>$env:FUN_LIB_DIR = "$PWD/lib"
./build/fun.exe .\examples\include_lib.fun
```
</pre>
## Interactive showcase: play.fun
The script `./play.fun` discovers all `.fun` files under `./examples` and offers to run them one by one:
```
./play.fun
```
<pre>./play.fun
</pre>
Notes:
- The script auto-picks your interpreter (FUN_BIN env or `fun` in PATH) and ensures `FUN_LIB_DIR=./lib` so examples resolve includes correctly.
- It shows the exit code for each run and summarizes failures at the end.
Tip: you can run specific examples directly too:
```
FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun
</pre>
## Example categories
Browse the `examples/` tree for areas of interest:
@ -77,9 +69,7 @@ Browse the `examples/` tree for areas of interest:
Place your `.fun` files anywhere under `examples/` to have them picked up by `play.fun`. Use quoted includes for project-local helpers and angle brackets for stdlib modules:
```
#include "examples/my_lib/common.fun"
<pre>#include "examples/my_lib/common.fun"
#include <io/console.fun>
```
</pre>
If you add an example showcasing a new feature, also consider adding a brief note to the relevant doc (types.md, includes.md, opcodes.md, etc.).

View file

@ -18,24 +18,27 @@ tags:
- quick
---
Answers to common questions.
## I built Fun but includes aren't found
Set `FUN_LIB_DIR` to the repository's `./lib` directory when running without installation:
```
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
```
See [includes.md](./includes/).
<pre>FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
</pre>
See [includes/](../includes/).
## How do I start the REPL?
Run `fun -i` (or run `fun` without a script, depending on version). See [repl.md](./repl/).
Run `fun -i` (or run `fun` without a script, depending on version). See [repl/](../repl/).
## Which build target should I use?
Use the aggregate `build` target to build `fun`, `fun_test`, and `test_opcodes`. See [build.md](./build/).
Use the aggregate `build` target to build `fun`, `fun_test`, and `test_opcodes`. See [build/](../build/).
## Where are the standard libraries?
Under [`./lib/`](../lib/). See [stdlib.md](./stdlib/) for an overview.
Under [https://git.xw3.org/fun/fun/src/branch/main/lib](https://git.xw3.org/fun/fun/src/branch/main/lib){:class="git"}. See [stdlib/](../stdlib/) for an overview.
## Where can I find internals and opcodes?
Browse [src/vm](../src/vm/) and [internals.md](./internals/) / [opcodes.md](./opcodes/).
Browse [https://git.xw3.org/fun/fun/src/branch/main/src/vm](https://git.xw3.org/fun/fun/src/branch/main/src/vm/) and [internals/](../internals/) / [opcodes/](../opcodes/).

View file

@ -27,10 +27,8 @@ tags:
This document explains how to use the `fun` binary after building or installing it: invocation patterns, options, environment variables, include/search paths, REPL, and examples.
## Synopsis
```
fun [options] [<script.fun>] [-- args...]
```
<pre>fun [options] [<script.fun>] [-- args...]
</pre>
- If `<script.fun>` is provided, `fun` runs the script.
- If omitted and the build enables the REPL, `fun` starts an interactive session.
@ -66,20 +64,14 @@ Useful commands/patterns in REPL:
## Running scripts
Basic run (installed systemwide):
```
fun /usr/share/fun/examples/hello.fun
```
<pre>fun /usr/share/fun/examples/hello.fun
</pre>
Running from a build tree (not installed):
```
FUN_LIB_DIR=./lib /path/to/build_dir/fun examples/hello.fun
```
<pre>FUN_LIB_DIR=./lib /path/to/build_dir/fun examples/hello.fun
</pre>
Passing arguments to scripts (arguments after `--` are forwarded to the script environment):
```
fun myscript.fun -- arg1 arg2
```
<pre>fun myscript.fun -- arg1 arg2
</pre>
## Build and install locations
- Build targets: `fun` is produced by the `fun` target. In CLion/CMake, typical build directories are `build_debug` or `build_release`.
- Install locations (by default):
@ -88,11 +80,9 @@ fun myscript.fun -- arg1 arg2
- Examples (optional): `/usr/share/fun/examples`
To stage an install without touching the system:
```
DESTDIR=./tmp/stage cmake --build <build_dir> --target install
<pre>DESTDIR=./tmp/stage cmake --build <build_dir> --target install
./tmp/stage/usr/bin/fun ./examples/hello.fun
```
</pre>
## See also
- `documentation/cli.md` — concise CLI reference (synopsis/options/exit codes)
- `documentation/funstx.md` — syntax checker for `.fun` files with optional `--fix`

View file

@ -36,10 +36,8 @@ funstx is a small commandline tool that parses .fun source files to verify sy
## Usage
```
funstx [--fix] <file1.fun> [file2.fun ...]
```
<pre>funstx [--fix] <file1.fun> [file2.fun ...]
</pre>
- Provide one or more .fun files to check.
- Add `--fix` to attempt safe, automatic corrections before rechecking.

View file

@ -64,16 +64,12 @@ Linux/UNIX and Cygwin are covered here.
Clone repository:
```
git clone https://git.xw3.org/fun/fun.git
<pre>git clone https://git.xw3.org/fun/fun.git
cd fun
```
</pre>
Configure and build (examples shown with several optional features enabled):
```
cmake -S . -B build \
<pre>cmake -S . -B build \
-DFUN_DEBUG=OFF \
-DFUN_WITH_REPL=ON \
-DFUN_WITH_JSON=ON \
@ -82,32 +78,23 @@ cmake -S . -B build \
-DFUN_WITH_PCSC=OFF \
-DFUN_WITH_SQLITE=OFF
cmake --build build --target fun
```
</pre>
Run the demo (without installing):
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun
</pre>
Tracing execution:
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun --trace ./demo.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun --trace ./demo.fun
</pre>
Drop into the REPL when an error occurs:
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun --repl-on-error --trace ./demo.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun --repl-on-error --trace ./demo.fun
</pre>
Start the REPL directly (build with -DFUN_WITH_REPL=ON):
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun
</pre>
#### CMake options
Pass all options as -DNAME=VALUE. The most relevant toggles are:
@ -124,10 +111,8 @@ Pass all options as -DNAME=VALUE. The most relevant toggles are:
You can also set the default search path for the bundled stdlib with DEFAULT_LIB_DIR:
```
cmake -S . -B build -DDEFAULT_LIB_DIR="/usr/share/fun/lib" -DFUN_WITH_REPL=ON
```
<pre>cmake -S . -B build -DDEFAULT_LIB_DIR="/usr/share/fun/lib" -DFUN_WITH_REPL=ON
</pre>
If you encounter a CMake error such as:
CMake Error: Parse error in command line argument: FUN_WITH_JSON
@ -139,8 +124,7 @@ it means you passed a -D option without a value. Always use the form -DNAME=VALU
SQLite support is optional and disabled by default. To build with it and run the example:
```
cmake -S . -B build -DFUN_WITH_SQLITE=ON
<pre>cmake -S . -B build -DFUN_WITH_SQLITE=ON
cmake --build build --target fun
@ -148,20 +132,17 @@ sqlite3 ./database.sqlite < ./examples/data/database.sql
FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./examples/sqlite_example.fun
```
</pre>
#### XML example (optional feature)
XML support (via libxml2) is optional and disabled by default. To build with it and run the example:
```
cmake -S . -B build -DFUN_WITH_XML2=ON
<pre>cmake -S . -B build -DFUN_WITH_XML2=ON
cmake --build build --target fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./examples/xml_class_example.fun
```
</pre>
Available VM builtins when built with -DFUN_WITH_XML2=ON:
- xml_parse(text: string) -> doc_handle (int > 0) or 0 on error
- xml_root(doc_handle: int) -> node_handle (int > 0) or 0 if missing
@ -177,8 +158,7 @@ Standard library wrapper (lib/io/xml.fun):
- text(node: int): string
Example Fun code:
```
include <io/xml.fun>
<pre>include <io/xml.fun>
xml = XML()
doc = xml.from_file("./examples/data/example.xml")
@ -188,8 +168,7 @@ else
root = xml.root(doc)
print(xml.name(root))
print(xml.text(root))
```
</pre>
Notes:
- Handles are simple integers managed by the VM; nodes are owned by their document.
- This initial integration focuses on parsing and basic navigation. Attributes, children iteration, and XPath may be added later.
@ -198,20 +177,16 @@ Notes:
Not recommended during early development, but supported:
```
sudo cmake --build build --target install
```
<pre>sudo cmake --build build --target install
</pre>
After installation, FUN_LIB_DIR usually isnt needed because libs are placed in the system default directory (e.g., /usr/share/fun/lib).
## Usage
Run a script:
```
fun ./demo.fun
```
<pre>fun ./demo.fun
</pre>
## Table of contents
- Language overview and VM internals
@ -470,8 +445,7 @@ Stdlib wrapper:
- class JSON (lib/io/json.fun) — convenience methods mirroring the VM API.
Example:
```
include <io/json.fun>
<pre>include <io/json.fun>
j = JSON()
data = j.parse('{"name":"Fun","year":2026,"ok":true,"tags":["vm","lang"]}')
@ -480,8 +454,7 @@ print(data["name"])
ok = j.to_file("./tmp/out.json", data, 1) // pretty = 1
print("saved:", ok)
```
</pre>
Notes:
- JSON types map to Fun types: object -> map, array -> array, string -> string, number -> number/float, true/false -> 1/0, null -> nil.
- When writing, prettyFlag=1 enables pretty printing.
@ -499,15 +472,13 @@ Stdlib wrapper:
- None (call built-ins directly). See examples in examples/extra/.
Example:
```
url = "https://httpbin.org/get"
<pre>url = "https://httpbin.org/get"
resp = curl_get(url)
if (len(resp) == 0)
print("GET failed")
else
print(substr(resp, 0, 60), "...")
```
</pre>
Examples:
- curl_get_json.fun, curl_post.fun, curl_download.fun
@ -526,8 +497,7 @@ Stdlib wrapper:
- class PCSC (lib/io/pcsc.fun) — higher-level helpers for listing readers, connecting, and APDU I/O.
Example:
```
include <io/pcsc.fun>
<pre>include <io/pcsc.fun>
sc = PCSC()
ctx = pcsc_establish()
@ -544,8 +514,7 @@ else
res = pcsc_transmit(h, [0x00, 0xC0, 0x00, 0x00, 0x00])
print("SW:", res["sw1"], res["sw2"], "code:", res["code"])
pcsc_disconnect(h)
```
</pre>
Examples:
- examples/extra/pcsc_example.fun, examples/extra/pcsc_demo.fun
@ -596,8 +565,7 @@ Notes:
- Always free handles with ini_free when done.
Example:
```
h = ini_load("./examples/data/example.ini")
<pre>h = ini_load("./examples/data/example.ini")
if (h == 0)
print("Failed to load INI")
else
@ -608,8 +576,7 @@ else
if (ok)
ini_save(h, "./tmp/updated.ini")
ini_free(h)
```
</pre>
### XML (optional)
Build flag: -DFUN_WITH_XML2=ON; requires libxml2.
@ -629,8 +596,7 @@ Stdlib wrapper:
- text(node): string
Example:
```
include <io/xml.fun>
<pre>include <io/xml.fun>
xml = XML()
doc = xml.from_file("./examples/data/example.xml")
@ -640,8 +606,7 @@ else
root = xml.root(doc)
print(xml.name(root))
print(xml.text(root))
```
</pre>
Notes:
- Handles are integers managed by the VM; nodes belong to their document.

View file

@ -4,7 +4,7 @@ published: true
noToc: false
noComments: false
noDate: false
title: Fun - Includes in Fun: local vs. system and the FUN_LIB_DIR environment variable
title: Fun - Includes in Fun, local vs. system and the FUN_LIB_DIR environment variable
subtitle: Using local vs. system includes, FUN_LIB_DIR, DEFAULT_LIB_DIR, and namespaced includes with `as`.
description: Using local vs. system includes, FUN_LIB_DIR, DEFAULT_LIB_DIR, and namespaced includes with `as`.
permalink: /documentation/includes/
@ -39,8 +39,7 @@ This document explains how to use local and system includes in Fun source files
Use double quotes to include files relative to the directory you execute `fun` from.
Example:
```
#include "examples/include_local_util.fun"
<pre>#include "examples/include_local_util.fun"
print("== include local demo ==")
greet("Fun")
@ -48,8 +47,7 @@ greet("Fun")
number a = 2
number b = 3
print("sum(" + to_string(a) + ", " + to_string(b) + ") = " + to_string(sum(a, b)))
```
</pre>
- Resolution rule: quoted includes are read directly from the given path relative to `$PWD`.
- Typical use: including helper modules that live within your project tree.
@ -58,8 +56,7 @@ print("sum(" + to_string(a) + ", " + to_string(b) + ") = " + to_string(sum(a, b)
Use angle brackets to include modules from the Fun standard library or any library directory you point `FUN_LIB_DIR` to.
Example:
```
#include <hello.fun>
<pre>#include <hello.fun>
#include <utils/math.fun>
print("== include lib demo ==")
@ -69,8 +66,7 @@ number x = 10
number y = 32
print("add(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(add(x, y)))
print("times(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(times(x, y)))
```
</pre>
Resolution order for `#include <...>`:
1) `FUN_LIB_DIR` (environment variable), with automatic handling of trailing `/` or `\`
@ -84,8 +80,7 @@ If the file cannot be read from any location, an "Include error" is printed with
You can import a module into a namespace to avoid symbol collisions or to make intent explicit.
Examples:
```
// Import stdlib helpers under alias 'm'
<pre>// Import stdlib helpers under alias 'm'
#include <utils/math.fun> as m
print("m.add(2, 3) = " + to_string(m.add(2, 3)))
print("m.times(4, 5) = " + to_string(m.times(4, 5)))
@ -95,8 +90,7 @@ print("m.times(4, 5) = " + to_string(m.times(4, 5)))
print(mod.hello("Fun"))
g = mod.Greeter("Hi")
g.say("World")
```
</pre>
Rules:
- `as` must be followed by a valid identifier (letters, digits, underscore, starting with a letter or underscore).
- Works for both local (`"..."`) and system (`<...>`) includes.

View file

@ -351,8 +351,7 @@ This provides zerocopy handoff without coupling VMs or their collectors.
#### Minimal API (illustrative)
```c
// Zero-copy shared buffers (immutable inside VMs)
<pre>// Zero-copy shared buffers (immutable inside VMs)
fun_shared_buffer_t* fun_shared_buffer_new(size_t n);
void* fun_shared_buffer_data(fun_shared_buffer_t*);
void fun_shared_buffer_retain(fun_shared_buffer_t*);
@ -362,8 +361,7 @@ void fun_shared_buffer_release(fun_shared_buffer_t*);
fun_port_t* fun_port_create(fun_vm_t*);
int fun_send(fun_port_t*, fun_value_t value); // can carry a shared buffer handle
int fun_recv(fun_port_t*, fun_value_t* out, uint64_t timeout_ms);
```
</pre>
#### Practical usage tips
- Default to isolates + ports for logic; use `fun_shared_buffer` only for large payloads (images, tensors, blobs).
@ -393,8 +391,7 @@ We dont expose shared mutability to VMs. The trick is: publishasimmutab
#### Typical pattern (no locks needed)
```c
fun_shared_buffer_t* b = fun_shared_buffer_new(n);
<pre>fun_shared_buffer_t* b = fun_shared_buffer_new(n);
void* p = fun_shared_buffer_data(b);
memcpy(p, src, n); // fill while private
@ -411,8 +408,7 @@ if (fun_recv(port, &v, 1000) == 0) {
fun_shared_buffer_release(r);
}
```
</pre>
#### When would the host ever sync?
- Only if you choose shared mutability outside the VM (e.g., a lockfree ring buffer you manage). For that, we expose optional helpers (`fun_atomic_*`, `fun_mutex_t`, `fun_rwlock_t`), but theyre not required for the standard zerocopy path.
@ -477,8 +473,7 @@ It depends on what “shared” means. Our design keeps perVM GCs independent
### Minimal API surface (illustrative)
```c
// Create/destroy VMs
<pre>// Create/destroy VMs
fun_vm_t* vm = fun_vm_create(const fun_vm_config_t*);
void fun_vm_destroy(fun_vm_t*);
@ -500,8 +495,7 @@ fun_shared_buffer_t* fun_shared_buffer_new(size_t n);
void* fun_shared_buffer_data(fun_shared_buffer_t*);
void fun_shared_buffer_retain(fun_shared_buffer_t*);
void fun_shared_buffer_release(fun_shared_buffer_t*);
```
</pre>
### Glossary
- GC: garbage collection. In our context, each `fun_vm_t` isolate has its own GC (stoptheworld, perVM). There is no global stoptheworld and no global lock; a GC pause in one VM does not affect others.

View file

@ -33,29 +33,24 @@ This guide focuses on maps: creation, reading/writing by key, checking key prese
## Creating maps
```
// literals
<pre>// literals
user = { "name": "Ada", "age": 37 }
empty = {}
print(typeof(user)) // "map"
```
</pre>
Nested structures are natural and common:
```
book = {
<pre>book = {
"title": "Fun Handbook",
"meta": { "pages": 120, "isbn": "123-456" },
"tags": ["lang", "vm"]
}
print(book["meta"]["pages"]) // 120
```
</pre>
## Getting and setting by key
```
profile = { "name": "Lin" }
<pre>profile = { "name": "Lin" }
// read existing key
print(profile["name"]) // Lin
@ -67,35 +62,29 @@ print(profile["email"]) // nil
profile["email"] = "lin@example.org"
profile["name"] = "Linus"
print(profile) // {"name":"Linus","email":"lin@example.org"}
```
</pre>
Notes:
- Using a nonstring key is allowed only if your build/runtime supports it; most code uses string keys for portability.
- Missing keys produce nil. Compare against nil before converting or indexing:
```
v = profile["phone"]
<pre>v = profile["phone"]
if v == nil { print("no phone on file") }
```
</pre>
## Checking key existence
Use has(m, key) to check if a key is present (returns 1 or 0):
```
cfg = { "debug": 1 }
<pre>cfg = { "debug": 1 }
print(has(cfg, "debug")) // 1
print(has(cfg, "port")) // 0
if has(cfg, "port") { print(cfg["port"]) } else { print("using default port") }
```
</pre>
## Iterating maps
Maps are not inherently ordered. To iterate, first obtain an array of keys or values.
```
user = { "name": "Ada", "age": 38 }
<pre>user = { "name": "Ada", "age": 38 }
// iterate known keys (explicit order you choose)
order = ["name", "age"]
@ -114,8 +103,7 @@ for i = 0; i < len(ks); i = i + 1 {
// values only
vs = values(user) // -> ["Ada", 38]
for i = 0; i < len(vs); i = i + 1 { print(to_string(vs[i])) }
```
</pre>
Tip:
- If you need deterministic output, either define the order array explicitly or sort the result of keys(user) using your available utilities before looping.
@ -123,8 +111,7 @@ Tip:
Maps are reference types. Assigning copies the reference, not the contents:
```
orig = { "a": 1 }
<pre>orig = { "a": 1 }
alias = orig
alias["a"] = 9
print(orig["a"]) // 9
@ -138,17 +125,14 @@ for i = 0; i < len(ks); i = i + 1 { k = ks[i]; dst[k] = src[k] }
dst["x"] = 7
print(src["x"]) // 1
print(dst["x"]) // 7
```
</pre>
Shallow copies duplicate only the toplevel mapping; nested arrays/maps inside are still shared unless you clone them manually.
## Equality
```
print({"a":1,"b":2} == {"b":2,"a":1}) // true
<pre>print({"a":1,"b":2} == {"b":2,"a":1}) // true
print({"a":1} == {"a":2}) // false
```
</pre>
Map equality compares sets of keys and their corresponding values for equality (order does not matter).
## Common utilities
@ -164,8 +148,7 @@ Check your lib or VM docs (e.g., src/vm/maps) and documentation/types.md for ava
## Interop with arrays and strings
```
// maps inside arrays
<pre>// maps inside arrays
users = [ {"name":"Ada"}, {"name":"Lin"} ]
for i = 0; i < len(users); i = i + 1 {
print(users[i]["name"]) // Ada, Lin
@ -180,8 +163,7 @@ print(m["nums"]) // [1,2,3,4]
// JSON interop is typically via lib/io/json.fun (if enabled in your build)
#include <io/json.fun> as json // adjust to your tree and build flags
s = json.stringify({"ok":1}) // "{"ok":1}"
```
</pre>
## Error handling and edge cases
- Accessing a missing key returns nil. Guard before arithmetic or nested indexing.
@ -196,8 +178,7 @@ s = json.stringify({"ok":1}) // "{"ok":1}"
## Examples
```
// merge defaults into config (without overwriting explicit keys)
<pre>// merge defaults into config (without overwriting explicit keys)
defaults = { "host":"127.0.0.1", "port":8080, "debug":0 }
cfg = { "port": 9000 }
@ -216,8 +197,7 @@ for i = 0; i < len(rows); i = i + 1 {
by_id[r["id"]] = r
}
print(by_id["u2"]["name"]) // Lin
```
</pre>
## See also
- types.md — broader overview of core types with quick map examples.

View file

@ -38,96 +38,79 @@ This guide covers the numeric types in Fun, with a focus on the integer "number"
- number: signed integer (implementationdefined width; use uclamp/sclamp for fixedwidth interop)
- float: IEEE754 double precision (64bit)
```
an = 42 // number
<pre>an = 42 // number
af = 3.14159 // float
print(typeof(an)) // "number"
print(typeof(af)) // "float"
```
</pre>
## Literals
- Integer (number): 0, 1, -7, 120
- Floating point (float): 0.0, 1.5, -2.75, 1e3, -4.2e-1
```
x = 10
<pre>x = 10
y = 2.5
z = -3
```
</pre>
## Arithmetic
Basic arithmetic works as youd expect:
```
a = 7
<pre>a = 7
b = 2
print(a + b) // 9
print(a - b) // 5
print(a * b) // 14
print(a % b) // 1 (modulo)
```
</pre>
Division and result type:
```
// If you need a fractional result, ensure a float is involved
<pre>// If you need a fractional result, ensure a float is involved
print(7 / 2) // implementation may yield 3 or 3.5 depending on numeric rules
print(cast(7, "float") / 2) // 3.5 (recommended when you need fractions)
print(7 / 2.0) // 3.5
```
</pre>
Mixing numbers and floats promotes the operation to float semantics:
```
print(2 + 0.5) // 2.5
```
<pre>print(2 + 0.5) // 2.5
</pre>
## Comparisons
```
print(3 < 5) // 1 (true)
<pre>print(3 < 5) // 1 (true)
print(3 == 3) // 1
print(3 != 4) // 1
// Be explicit when comparing ints vs floats if types matter
print(1 == 1.0) // may be true, but types differ
print(cast(1.0, "number") == 1) // 1 (true) with explicit cast
```
</pre>
## Conversions and parsing
```
n = to_number("123") // 123 (number)
<pre>n = to_number("123") // 123 (number)
f = cast(n, "float") // 123.0 (float)
n2 = cast(3.9, "number") // 3 (truncation semantics)
print(to_string(f)) // "123"
```
</pre>
If parsing fails (e.g., to_number("abc")), expect a runtime error; guard accordingly.
## Clamping to fixed widths
When interoperating with bytecode, C APIs, or binary formats, clamp integers to a specific bit width.
```
// Unsigned clamp to N bits
<pre>// Unsigned clamp to N bits
u8 = uclamp(300, 8) // 44
u16 = uclamp(70000, 16)
// Signed clamp to N bits
s8 = sclamp(-130, 8) // wraps into signed 8bit range
```
</pre>
Choose the bits according to the target field (8, 16, 32, 64). See your interop API docs for exact ranges.
## Bitwise operations (numbers)
Bitwise operators apply to the integer number type.
```
a = 0b0110 // if binary literals arent supported in your setup, use decimals: a = 6
<pre>a = 0b0110 // if binary literals arent supported in your setup, use decimals: a = 6
b = 0b0011 // or b = 3
print(a & b) // 0b0010 -> 2
@ -136,41 +119,34 @@ print(a ^ b) // 0b0101 -> 5
print(~a) // bitwise NOT (twos complement rules)
print(a << 1) // 12
print(a >> 1) // 3
```
</pre>
Note: Bitwise ops are defined for numbers, not floats. Cast floats to numbers first when needed.
## Common patterns
Ensuring float math to avoid unintended truncation:
```
avg = cast(sum, "float") / cast(count, "float")
```
<pre>avg = cast(sum, "float") / cast(count, "float")
</pre>
Safe division with guard against zero:
```
num = 10
<pre>num = 10
den = 0
if den == 0 {
print("division by zero")
} else {
print(num / den)
}
```
</pre>
Parsing user input with fallback:
```
raw = "not-a-number"
<pre>raw = "not-a-number"
val = 0
// simplistic guard pattern; adapt to your error handling style
if find(raw, "0") >= 0 || find(raw, "1") >= 0 { // crude pre-check
val = to_number(raw)
}
```
</pre>
## Gotchas
- Integer division vs float division: promote to float when you need fractional results.

View file

@ -29,55 +29,41 @@ The REPL is optional at build time. It provides a fast feedback loop for experim
- Build flag: -DFUN_WITH_REPL=ON
- Typical CMake configuration example:
```
cmake -S . -B build \
<pre>cmake -S . -B build \
-DFUN_WITH_REPL=ON
cmake --build build --target fun
```
</pre>
You can also set a default search path for the bundled stdlib using DEFAULT_LIB_DIR at configure time (used for completions and library loading):
```
cmake -S . -B build -DFUN_WITH_REPL=ON -DDEFAULT_LIB_DIR="/usr/share/fun/lib"
```
<pre>cmake -S . -B build -DFUN_WITH_REPL=ON -DDEFAULT_LIB_DIR="/usr/share/fun/lib"
</pre>
## Launching the REPL
- Directly run the main executable (ensure FUN_WITH_REPL=ON):
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun
</pre>
- With the CMake “repl” convenience target (available only if built with FUN_WITH_REPL=ON):
```
cmake --build build --target repl
```
<pre>cmake --build build --target repl
</pre>
On startup, you should see something like:
```
Fun X.Y.Z REPL
<pre>Fun X.Y.Z REPL
Type :help for commands. Submit an empty line to run.
```
</pre>
Environment variable FUN_LIB_DIR can be used to point the REPL to the standard library directory for symbol completion and library loading. If not set, a compile-time DEFAULT_LIB_DIR (if provided) or "lib" is used.
## Running scripts and REPL-on-error
- Run a script file normally:
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun
</pre>
- Enable tracing, and drop into a REPL automatically when a runtime error occurs:
```
FUN_LIB_DIR="$(pwd)/lib" ./build/fun --repl-on-error --trace ./demo.fun
```
<pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun --repl-on-error --trace ./demo.fun
</pre>
Inside REPL-on-error, you can inspect frames, locals, disassembly, set breakpoints, and continue or step. Use :help to see available commands.
## Prompts and input model

View file

@ -77,8 +77,7 @@ Example: integer addition opcode implemented in Rust.
In src/rust/src/lib.rs:
```
#![no_std]
<pre>#![no_std]
#[repr(C)]
pub struct Vm;
@ -100,8 +99,7 @@ In src/rust/src/lib.rs:
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
```
</pre>
What this does:
- Pops two 64-bit integers from the VM stack.
- Pushes back their sum.
@ -115,8 +113,7 @@ To make the VM call your Rust opcode, add a small C-side case that invokes the e
String demo wiring (already present): src/vm/rust/hello.c
```
case OP_RUST_HELLO: {
<pre>case OP_RUST_HELLO: {
#ifdef FUN_WITH_RUST
const char *s = fun_rust_get_string();
if (!s) s = "";
@ -127,12 +124,10 @@ case OP_RUST_HELLO: {
#endif
break;
}
```
</pre>
For a stack-based math opcode (like fun_op_radd), you would declare and call the Rust function similarly:
```
#ifdef FUN_WITH_RUST
<pre>#ifdef FUN_WITH_RUST
extern int fun_op_radd(void* vm); // or use the proper VM type if available
#endif
@ -145,8 +140,7 @@ case OP_RADD: {
#endif
break;
}
```
</pre>
Notes:
- Follow the existing opcode conventions for your module (core, math, strings, etc.).

View file

@ -80,11 +80,9 @@ The stdlib is written in Fun and organized by domain. Below is the current layou
Note: Availability of some modules can depend on optional extensions selected at build time (see [build.md](./build/)). For instance, `regex/pcre2.fun` requires PCRE2 support; `ui/*` depends on chosen UI backends.
## Using modules
```fun
#include <strings.fun>
<pre>#include <strings.fun>
let s = trim(" hello ")
print(s)
```
</pre>
For search paths and namespacing details, see [includes.md](./includes/) and [cli.md](./cli/) (FUN_LIB_DIR and DEFAULT_LIB_DIR).

View file

@ -33,14 +33,12 @@ This guide covers string literals, common operations (length, concatenation, sub
## Literals and escaping
```
s1 = "hello"
<pre>s1 = "hello"
s2 = "line1\nline2" // newline
s3 = "quote: \" and backslash: \\" // escaped quote and backslash
print(s1) // hello
```
</pre>
Notes:
- Strings are immutable; operations return new strings rather than modifying in place.
- Use to_string(x) when concatenating non-string values.
@ -49,66 +47,54 @@ Notes:
Length and concatenation:
```
name = "Ada"
<pre>name = "Ada"
greet = "Hello, " + name + "!" // "Hello, Ada!"
print(len(greet)) // 12
```
</pre>
Substring (start, length) and search:
```
s = "hello, world"
<pre>s = "hello, world"
print(substr(s, 7, 5)) // world
idx = find(s, ",") // 5, or -1 if not found
if idx >= 0 { print("comma at index " + to_string(idx)) }
```
</pre>
Splitting into arrays:
```
parts = split("a,b,c", ",") // ["a","b","c"]
<pre>parts = split("a,b,c", ",") // ["a","b","c"]
for i = 0; i < len(parts); i = i + 1 {
print(parts[i])
}
```
</pre>
## Conversions and formatting
```
n = 42
<pre>n = 42
pi = 3.14
msg = "n=" + to_string(n) + ", pi=" + to_string(pi)
print(msg)
// parsing (may error if the string is not numeric)
n2 = to_number("123") // 123
```
</pre>
If you need a specific type, you can use cast for advanced cases, e.g. cast("123", "number").
## Common patterns
- Guard on find results before slicing:
```
email = "user@example.org"
<pre>email = "user@example.org"
at = find(email, "@")
if at >= 0 {
user = substr(email, 0, at)
host = substr(email, at + 1, len(email) - at - 1)
print(user + " on " + host)
}
```
</pre>
- Building paths or messages:
```
base = "/tmp"
<pre>base = "/tmp"
file = "log.txt"
path = base + "/" + file
```
</pre>
## Gotchas
- Strings are immutable: repeated concatenation in big loops can be costly; consider collecting pieces in an array and joining at the end if you have a helper for that in your setup.

View file

@ -41,29 +41,21 @@ To list targets with CMake directly, consult your IDE or run the build system
Debug profile example:
```
cmake --build build --target test_opcodes && ./build/test_opcodes
```
<pre>cmake --build build --target test_opcodes && ./build/test_opcodes
</pre>
Release profile example:
```
cmake --build build_release --target test_opcodes && ./build/test_opcodes
```
<pre>cmake --build build_release --target test_opcodes && ./build/test_opcodes
</pre>
If `fun_test` exists in your configuration:
```
cmake --build build --target fun_test && ./build/fun_test
```
<pre>cmake --build build --target fun_test && ./build/fun_test
</pre>
You can also invoke CTest to run any tests registered with `add_test()`:
```
cmake --build build --target test
<pre>cmake --build build --target test
ctest --test-dir build -j
```
</pre>
## Adding new tests
- C/C++/VM-side tests: look for existing tests under `src` or `spec` and mirror the structure. Add a new source and register it in CMake with an executable or via `add_test()`.

View file

@ -26,27 +26,21 @@ This page lists common issues when building and running Fun from a source checko
Error example:
```
Include error: cannot read '<io/console.fun>'
```
<pre>Include error: cannot read '<io/console.fun>'
</pre>
Fix:
- When running from the repository without installing, set `FUN_LIB_DIR` to the local `./lib` directory so anglebracket includes resolve correctly.
Linux/macOS/BSD:
```
export FUN_LIB_DIR="$(pwd)/lib"
<pre>export FUN_LIB_DIR="$(pwd)/lib"
./build/fun examples/include_lib.fun
```
</pre>
Windows (PowerShell):
```
$env:FUN_LIB_DIR = "$PWD/lib"
<pre>$env:FUN_LIB_DIR = "$PWD/lib"
./build/fun.exe .\examples\include_lib.fun
```
</pre>
If `FUN_LIB_DIR` is not set, the interpreter tries a compiletime `DEFAULT_LIB_DIR`, and finally falls back to `./lib` relative to the current working directory. Be mindful of where you run the `fun` binary from.
See includes.md for more details.
@ -59,12 +53,10 @@ Symptoms:
Fix:
- Build with `-DFUN_WITH_REPL=ON` and rebuild the `fun` target. Then launch without arguments:
```
cmake -S . -B build -DFUN_WITH_REPL=ON
<pre>cmake -S . -B build -DFUN_WITH_REPL=ON
cmake --build build --target fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun
```
</pre>
See repl.md for usage tips and features.
## Linker errors for optional libraries (JSON, PCRE2, CURL, SQLite, etc.)

View file

@ -56,8 +56,7 @@ Helpers used throughout:
Create arrays with square brackets and commaseparated elements.
```
// creation
<pre>// creation
a = [1, 2, 3]
b = ["alpha", "beta"]
c = [] // empty array
@ -96,8 +95,7 @@ for pair in it.enumerate(["x", "y"]) {
val = pair[1]
print(idx + ":" + val)
}
```
</pre>
Notes:
- Indexing is boundschecked; invalid indices cause a runtime error that you can inspect with --trace or REPLonerror.
- Arrays are mutable; operations modify in place unless documented otherwise.
@ -106,8 +104,7 @@ Notes:
Create maps with curly braces. Keys are typically strings; values can be any type.
```
// creation
<pre>// creation
user = { "name": "Ada", "age": 37 }
cfg = {}
@ -134,57 +131,48 @@ for i = 0; i < len(keys); i = i + 1 {
k = keys[i]
print(k + " = " + to_string(user[k]))
}
```
</pre>
Notes:
- Accessing a nonexisting key returns nil; write a guard before using it as another type.
- Maps are mutable; assigning with map["k"] = v updates in place.
## Strings (brief)
```
s = "hello, world"
<pre>s = "hello, world"
print(len(s)) // 12
print(substr(s, 7, 5)) // world
print(find(s, ",")) // 5 (index) or -1 if not found
parts = split("a,b,c", ",") // ["a","b","c"]
print(join(parts, ";")) // a;b;c
```
</pre>
## Numbers and floats (brief)
```
n = 10
<pre>n = 10
f = 3.14
print(n + 2) // 12
print(f * 2) // 6.28
// clamp to widths when needed
print(uclamp(300, 8)) // 44 (300 mod 256)
```
</pre>
## Booleans and nil
```
ok = 1 // true
<pre>ok = 1 // true
no = 0 // false
none = nil
if ok && !no { print("yay") }
if none == nil { print("is nil") }
```
</pre>
## Conversions and typing
```
x = "42"
<pre>x = "42"
print(to_number(x) + 1) // 43
print(typeof([1,2,3])) // "array"
print(typeof({})) // "map"
```
</pre>
## Common patterns
- Accumulate values:

View file

@ -5,8 +5,8 @@ noToc: false
noComments: false
noDate: false
title: Fun - Website Documentation (fun-lang.xyz)
subtitle: Documentation for the [fun-lang.xyz](https,//fun-lang.xyz) website in the `./web/` directory.
description: Documentation for the [fun-lang.xyz](https,//fun-lang.xyz) website in the `./web/` directory.
subtitle: Documentation for the fun-lang.xyz website in the `./web/` directory.
description: Documentation for the fun-lang.xyz website in the `./web/` directory.
permalink: /documentation/website/
lang: en
tags:
@ -93,9 +93,7 @@ To run the website locally for development:
The website can be deployed using the Makefile:
```bash
cd web/
<pre>cd web/
make release
```
</pre>
The `release` target builds the site, minifies the assets, and syncs the files to [fun-lang.xyz](https://fun-lang.xyz) via `rsync`. Ensure you have the necessary SSH permissions for the sync to succeed.