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

@ -8,7 +8,7 @@ layout: default
<p class="post-meta" style="padding: 0px 0px 0px 0px;">{% if page.date %}{{ page.date | date: "%b %-d, %Y %H:%M:%S" }}{% endif %} <p class="post-meta" style="padding: 0px 0px 0px 0px;">{% if page.date %}{{ page.date | date: "%b %-d, %Y %H:%M:%S" }}{% endif %}
{% if page.date and page.date_updated %} - {% endif %} {% if page.date and page.date_updated %} - {% endif %}
{% if page.date_updated %}Edited: {{ page.date_updated | date: "%b %-d, %Y %H:%M:%S" }}{% endif %} {% if page.date_updated %}Edited: {{ page.date_updated | date: "%b %-d, %Y %H:%M:%S" }}{% endif %}
{% if page.date or page.date_updated %} ({{ page.date | date: "%Z" }}){% endif %}{% if page.author %}, <a href="{{ site.git_short }}/{{ page.author }}" target="_blank" class="user">{{ page.author }}</a>{% endif %}</p> {% if page.date or page.date_updated %} ({{ page.date | date: "%Z" }}){% endif %}{% if page.author %}, <a href="{{ page.author_url }}" target="_blank" class="user">{{ page.author }}</a>{% endif %}</p>
</header> </header>
<article class="post-content"> <article class="post-content">
{{ content }} {{ content }}

View file

@ -2,6 +2,8 @@
layout: post layout: post
published: true published: true
author: hanez author: hanez
author_email: you@hanez.org
author_url: https://hanez.org
title: Init Fun! title: Init Fun!
description: Blog - Init Fun! description: Blog - Init Fun!
date: 2025-10-05 date: 2025-10-05

View file

@ -2,11 +2,13 @@
layout: post layout: post
published: true published: true
author: hanez author: hanez
author_email: you@hanez.org
author_url: https://hanez.org
noToc: false noToc: false
title: Announcing Fun 0.37.62 title: Announcing Fun 0.37.62
description: Homepage and Blog description: Homepage and Blog
date: 2026-01-25 date: 2026-01-25
date_updated: 2026-01-31 21:45:03 date_updated: 2026-04-11 00:56:03
categories: categories:
- news - news
- project - project
@ -54,26 +56,22 @@ This release brings Fun closer to its vision with significant language enhanceme
- Private members by convention (leading underscore) - Private members by convention (leading underscore)
- Dot-call syntax sugar for clean method invocations: obj.method(a, b) - Dot-call syntax sugar for clean method invocations: obj.method(a, b)
<pre> <pre>class Counter
class Counter
value = 0 value = 0
fun inc(this) fun inc(this)
this.value = this.value + 1 this.value = this.value + 1
return this.value return this.value
c = Counter() c = Counter()
print(c.inc()) // 1 print(c.inc()) // 1</pre>
</pre>
### Module System ### Module System
- Namespaced includes with #include <path> as alias for clean imports - Namespaced includes with #include <path> as alias for clean imports
- Organize code into reusable modules without naming conflicts - Organize code into reusable modules without naming conflicts
<pre> <pre>#include <utils/math.fun> as m
#include <utils/math.fun> as m print(m.add(2, 3)) // 5</pre>
print(m.add(2, 3)) // 5
</pre>
### Enhanced Type System ### Enhanced Type System
@ -87,14 +85,12 @@ print(m.add(2, 3)) // 5
- Thread primitives: thread_spawn, thread_join, and sleep - Thread primitives: thread_spawn, thread_join, and sleep
- Write concurrent programs with ease - Write concurrent programs with ease
<pre> <pre>fun square(n)
fun square(n)
sleep(100) sleep(100)
return n * n return n * n
tid = thread_spawn(square, 5) tid = thread_spawn(square, 5)
print(thread_join(tid)) // 25 print(thread_join(tid)) // 25</pre>
</pre>
### Control Flow Improvements ### Control Flow Improvements
@ -146,22 +142,21 @@ Important: Fun is not developed on third-party Git servers like GitHub or GitLab
If you're curious about Fun, check out: If you're curious about Fun, check out:
- [Website](https://fun-lang.xyz)
- [Git Repository](https://git.xw3.org/fun/fun){:class="git"} - [Git Repository](https://git.xw3.org/fun/fun){:class="git"}
- [Fun Handbook](https://fun-lang.xyz/documentation/handbook/){:class="git"} - [Fun Handbook](/documentation/handbook/)
- [Fun REPL Guide](https://fun-lang.xyz/documentation/repl/){:class="git"} - [Fun REPL Guide](/documentation/repl/)
- [Specification v0.3](https://git.xw3.org/fun/fun/src/branch/main/spec/v0.3.md){:class="git"} - [Specification v0.3](https://git.xw3.org/fun/fun/src/branch/main/spec/v0.3.md){:class="git"}
- [Examples](https://git.xw3.org/fun/fun/src/branch/main/examples){:class="git"} - [Examples](https://git.xw3.org/fun/fun/src/branch/main/examples){:class="git"}
- [Standard Library](https://git.xw3.org/fun/fun/src/branch/main/lib){:class="git"} - [Standard Library](https://git.xw3.org/fun/fun/src/branch/main/lib){:class="git"}
- [Community](https://fun-lang.xyz/community/) - [Community](/community/)
The examples directory contains demonstrations of most Fun features, from basic "Hello, World!" to threading, networking, classes, and more. The lib directory includes modules written in Fun itself — and in the future, most enhancements will be written in Fun rather than C. The examples directory contains demonstrations of most Fun features, from basic "Hello, World!" to threading, networking, classes, and more. The lib directory includes modules written in Fun itself — and in the future, most enhancements will be written in Fun rather than C.
### For Developers ### For Developers
- [Fun Internals](https://fun-lang.xyz/documentation/internals/){:class="git"} - [Fun Internals](/documentation/internals/){:class="git"}
- [Fun Opcodes](https://fun-lang.xyz/documentation/opcodes/){:class="git"} - [Fun Opcodes](/documentation/opcodes/){:class="git"}
- [Basic Rust Opcodes Support](https://fun-lang.xyz/documentation/rust/){:class="git"} - [Basic Rust Opcodes Support](/documentation/rust/){:class="git"}
### The Road Ahead ### The Road Ahead
@ -173,5 +168,4 @@ Fun is and will always be 100% free under the terms of the [Apache-2.0 License](
Happy hacking, and remember: Fun is Fun! Happy hacking, and remember: Fun is Fun!
Johannes Findeisen (hanez) - [hanez@fun-lang.org](mailto:hanez@fun-lang.org){:class="mail"} Johannes Findeisen (hanez) - [hanez@fun-lang.xyz](mailto:hanez@fun-lang.xyz){:class="mail"}

View file

@ -2,6 +2,8 @@
layout: post layout: post
published: true published: true
author: hanez author: hanez
author_email: you@hanez.org
author_url: https://hanez.org
noToc: false noToc: false
title: Moving the Website to the Project Root title: Moving the Website to the Project Root
description: Relocating the fun-lang.xyz source code for easier maintenance. description: Relocating the fun-lang.xyz source code for easier maintenance.
@ -23,6 +25,7 @@ We've recently completed a significant change to our project structure: the sour
The main reason for merging this code into the root of the Fun project is that it is much easier for me to maintain the whole project this way. The main reason for merging this code into the root of the Fun project is that it is much easier for me to maintain the whole project this way.
Having everything in one place simplifies our development workflow: Having everything in one place simplifies our development workflow:
- **Unified Versioning:** All project components, including the website and its documentation, now share the same version control history. - **Unified Versioning:** All project components, including the website and its documentation, now share the same version control history.
- **Simplified Maintenance:** Updating documentation and the website together ensures that the online presence stays in sync with the language's development. - **Simplified Maintenance:** Updating documentation and the website together ensures that the online presence stays in sync with the language's development.
- **Streamlined Workflow:** It's now possible to update the language, its libraries, the documentation, and the blog in a single commit if needed. - **Streamlined Workflow:** It's now possible to update the language, its libraries, the documentation, and the blog in a single commit if needed.
@ -31,7 +34,7 @@ Having everything in one place simplifies our development workflow:
You can now find the website source in the `./web/` directory of the repository. It continues to use the [Jekyll](https://jekyllrb.com/){:class="ext"} static site generator. You can now find the website source in the `./web/` directory of the repository. It continues to use the [Jekyll](https://jekyllrb.com/){:class="ext"} static site generator.
For those interested in the technical details or looking to contribute to the website, we have added a new documentation file: [docs/website.md](https://git.xw3.org/fun/fun/src/branch/main/docs/website.md){:class="git"}. This document covers the technology stack, the directory structure, and the available `Makefile` targets for local development and deployment. For those interested in the technical details or looking to contribute to the website, we have added a new documentation file: [/web/documentation/website/](../documentation/website/){:class="git"}. This document covers the technology stack, the directory structure, and the available `Makefile` targets for local development and deployment.
### What changes for you? ### What changes for you?

View file

@ -15,7 +15,7 @@ $background-color: #565656;
$headline-color: #bc6c21; //#b40000; $headline-color: #bc6c21; //#b40000;
$hover-color: #bc6c21; $hover-color: #bc6c21;
$topbutton-color: $headline-color; $topbutton-color: $headline-color;
$brand-color: #1fa2af; $brand-color: #3d0e51;
$brand-color-light: lighten($brand-color, 40%); $brand-color-light: lighten($brand-color, 40%);
$grey-color: #828282; $grey-color: #828282;
$grey-color-light: #e8e8e8; $grey-color-light: #e8e8e8;

View file

@ -31,8 +31,7 @@ This guide focuses on arrays: creation, indexing, mutation, iteration, slicing,
## Creating arrays ## Creating arrays
``` <pre>// literals
// literals
a = [1, 2, 3] a = [1, 2, 3]
b = ["alpha", "beta"] b = ["alpha", "beta"]
empty = [] empty = []
@ -42,30 +41,27 @@ grid = [[1,2], [3,4]]
print(typeof(a)) // "array" print(typeof(a)) // "array"
print(len(a)) // 3 print(len(a)) // 3
``` </pre>
Tip: Prefer squarebracket literals for clarity and performance versus building via repeated push in a hot loop. Tip: Prefer squarebracket literals for clarity and performance versus building via repeated push in a hot loop.
## Indexing (0based) and assignment ## Indexing (0based) and assignment
``` <pre>a = [10, 20, 30]
a = [10, 20, 30]
print(a[0]) // 10 print(a[0]) // 10
print(a[2]) // 30 print(a[2]) // 30
// update in place // update in place
a[1] = 42 a[1] = 42
print(a) // [10, 42, 30] print(a) // [10, 42, 30]
``` </pre>
Notes: Notes:
- Valid indices are 0..len(a)-1. Using an invalid index raises a runtime error. - 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. - Assignment updates the existing array; references pointing to it observe the change.
## Appending, popping, inserting, removing ## Appending, popping, inserting, removing
``` <pre>a = [1]
a = [1]
// append to end; returns new length // append to end; returns new length
push(a, 7) // => 2, a is now [1, 7] 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 at index (shifts left)
remove(a, 2) // a => [1, 99, 3] remove(a, 2) // a => [1, 99, 3]
``` </pre>
## Slicing and concatenation ## Slicing and concatenation
``` <pre>a = [0,1,2,3,4]
a = [0,1,2,3,4]
// slice(startInclusive, endExclusive) // slice(startInclusive, endExclusive)
head = slice(a, 0, 3) // [0,1,2] head = slice(a, 0, 3) // [0,1,2]
@ -93,14 +87,12 @@ mid = slice(a, 1, 4) // [1,2,3]
// concat: join two arrays // concat: join two arrays
b = ["x", "y"] b = ["x", "y"]
ab = concat(a, b) // [0,1,2,3,4,"x","y"] ab = concat(a, b) // [0,1,2,3,4,"x","y"]
``` </pre>
Slicing returns a new array. The original is unchanged. Slicing returns a new array. The original is unchanged.
## Iteration patterns ## Iteration patterns
``` <pre>a = ["a", "b", "c"]
a = ["a", "b", "c"]
// indexbased loop // indexbased loop
for i = 0; i < len(a); i = i + 1 { for i = 0; i < len(a); i = i + 1 {
@ -114,14 +106,12 @@ for pair in it.enumerate(a) {
val = pair[1] val = pair[1]
print(to_string(idx) + ":" + val) print(to_string(idx) + ":" + val)
} }
``` </pre>
## Copying vs. referencing ## Copying vs. referencing
Arrays are reference types. Assigning just copies the reference, not the contents: Arrays are reference types. Assigning just copies the reference, not the contents:
``` <pre>orig = [1, 2]
orig = [1, 2]
alias = orig // points to the same array alias = orig // points to the same array
alias[0] = 9 alias[0] = 9
print(orig) // [9, 2] print(orig) // [9, 2]
@ -131,17 +121,14 @@ copy = slice(orig, 0, len(orig))
copy[1] = 7 copy[1] = 7
print(orig) // [9, 2] print(orig) // [9, 2]
print(copy) // [9, 7] print(copy) // [9, 7]
``` </pre>
Shallow copies duplicate the toplevel array but not nested structures. Shallow copies duplicate the toplevel array but not nested structures.
## Equality ## Equality
``` <pre>print([1,2] == [1,2]) // true
print([1,2] == [1,2]) // true
print([1,2] == [2,1]) // false print([1,2] == [2,1]) // false
``` </pre>
Array equality compares length and elementwise equality recursively. Array equality compares length and elementwise equality recursively.
## Common utilities ## Common utilities
@ -160,19 +147,16 @@ Check your lib directory (e.g., lib/utils) for additional helpers.
## Error handling and bounds ## Error handling and bounds
``` <pre>a = [0]
a = [0]
// a[1] is out of range → runtime error // a[1] is out of range → runtime error
``` </pre>
Tips: Tips:
- Guard indices: if i < 0 or i >= len(a) { /* handle */ } - Guard indices: if i < 0 or i >= len(a) { /* handle */ }
- Use remove/insert carefully inside loops; indices of following items change. - Use remove/insert carefully inside loops; indices of following items change.
## Interop with maps and strings ## Interop with maps and strings
``` <pre>// arrays of maps
// arrays of maps
users = [ {"name":"Ada"}, {"name":"Lin"} ] users = [ {"name":"Ada"}, {"name":"Lin"} ]
print(users[1]["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 #include <utils/strings.fun> as su // adjust if present in your tree
parts = su.split("a,b,c", ",") // ["a","b","c"] parts = su.split("a,b,c", ",") // ["a","b","c"]
csv = su.join(parts, ",") // "a,b,c" csv = su.join(parts, ",") // "a,b,c"
``` </pre>
## Performance tips ## Performance tips
- Preallocate by building from literals or chunked appends rather than onebyone in very tight loops. - 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 ## Examples
``` <pre>// filter even numbers
// filter even numbers
src = [0,1,2,3,4,5] src = [0,1,2,3,4,5]
dst = [] dst = []
for i = 0; i < len(src); i = i + 1 { 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] print(flat) // [1,2,3,4,5]
``` </pre>
## See also ## See also
- types.md — broader overview of core types with quick array examples. - 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 ## Typical patterns
1) Connect and switch to non-blocking 1) Connect and switch to non-blocking
``` <pre>fd = tcp_connect(host, port)
fd = tcp_connect(host, port)
if (fd == 0) if (fd == 0)
// handle connect error // handle connect error
ok = fd_set_nonblock(fd, 1) ok = fd_set_nonblock(fd, 1)
if (ok == 0) if (ok == 0)
// handle mode switch error // handle mode switch error
``` </pre>
2) Non-blocking write loop with readiness polling 2) Non-blocking write loop with readiness polling
``` <pre>remaining = req
remaining = req
while (len(remaining) > 0) while (len(remaining) > 0)
wr = fd_poll_write(fd, 1000) // wait up to 1s wr = fd_poll_write(fd, 1000) // wait up to 1s
if (wr < 0) if (wr < 0)
@ -79,11 +76,9 @@ while (len(remaining) > 0)
if (n < 0) if (n < 0)
// send error; abort // send error; abort
remaining = substr(remaining, n, len(remaining) - n) remaining = substr(remaining, n, len(remaining) - n)
``` </pre>
3) Non-blocking read-until-close 3) Non-blocking read-until-close
``` <pre>buf = ""
buf = ""
while (true) while (true)
rd = fd_poll_read(fd, 2000) // wait up to 2s rd = fd_poll_read(fd, 2000) // wait up to 2s
if (rd < 0) if (rd < 0)
@ -99,8 +94,7 @@ while (true)
if (len(data) == 0) if (len(data) == 0)
break // closed break // closed
buf = buf + data buf = buf + data
``` </pre>
## Timeouts and responsiveness ## Timeouts and responsiveness
- timeout_ms controls how long poll waits. Use small timeouts inside loops to interleave work across multiple sockets or tasks. - 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 - lib/net/http_cgi_server.fun — Library helpers used by the server examples
Run client example from a build tree: Run client example from a build tree:
``` <pre>FUN_LIB_DIR=./lib ./build/fun examples/io/async_http_client.fun
FUN_LIB_DIR=./lib ./build/fun examples/io/async_http_client.fun </pre>
```
If installed system-wide, just: If installed system-wide, just:
``` <pre>fun /usr/share/fun/examples/io/async_http_client.fun
fun /usr/share/fun/examples/io/async_http_client.fun </pre>
```
Or to try the await-style client using the cooperative scheduler: Or to try the await-style client using the cooperative scheduler:
``` <pre>FUN_LIB_DIR=./lib ./build/fun examples/io/await_http_client.fun
FUN_LIB_DIR=./lib ./build/fun examples/io/await_http_client.fun </pre>
```
## Cooperative scheduler helpers (library-level) ## 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: 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. - Mark the task to be skipped for roughly ms milliseconds; cleared automatically when it wakes.
Example skeleton using the scheduler: Example skeleton using the scheduler:
``` <pre>#include <async/scheduler.fun>
#include <async/scheduler.fun>
fun my_task_step(t) fun my_task_step(t)
if (t.phase == nil) if (t.phase == nil)
@ -205,8 +192,7 @@ fun my_task_step(t)
task = task_spawn(my_task_step, {}) task = task_spawn(my_task_step, {})
run_until_done() 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. 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 ## 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: When configuring, the build prints a summary like:
``` <pre>==== Fun build options ====
==== Fun build options ====
FUN_DEBUG: ENABLED|DISABLED FUN_DEBUG: ENABLED|DISABLED
FUN_USE_MUSL: ENABLED|DISABLED FUN_USE_MUSL: ENABLED|DISABLED
FUN_WITH_CPP: ENABLED|DISABLED FUN_WITH_CPP: ENABLED|DISABLED
FUN_WITH_RUST: ENABLED|DISABLED FUN_WITH_RUST: ENABLED|DISABLED
=========================== ===========================
``` </pre>
## Example commands ## Example commands
Use the CLion-provided build directories or your own. Typical invocations: Use the CLion-provided build directories or your own. Typical invocations:
### Debug ### Debug
``` <pre>cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
-DFUN_DEBUG=ON -DFUN_WITH_RUST=OFF -DFUN_DEBUG=ON -DFUN_WITH_RUST=OFF
cmake --build build --target build cmake --build build --target build
``` </pre>
### Release ### Release
``` <pre>cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
-DFUN_DEBUG=OFF -DFUN_WITH_RUST=OFF -DFUN_DEBUG=OFF -DFUN_WITH_RUST=OFF
cmake --build build_release --target build cmake --build build_release --target build
``` </pre>
### Enabling optional extensions ### Enabling optional extensions
``` <pre>cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release \
-DFUN_WITH_CPP=ON -DFUN_WITH_RUST=ON -DFUN_WITH_OPENSSL=ON -DFUN_WITH_CPP=ON -DFUN_WITH_RUST=ON -DFUN_WITH_OPENSSL=ON
cmake --build build_release --target build cmake --build build_release --target build
``` </pre>
### Customizing VM limits ### Customizing VM limits
``` <pre>cmake -S . -B build_custom -DSTACK_SIZE=4096 -DMAX_GLOBALS=512
cmake -S . -B build_custom -DSTACK_SIZE=4096 -DMAX_GLOBALS=512
cmake --build build_custom --target fun 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_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). 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/). For a complete usage guide (including REPL details, environment variables, include paths, examples, and install locations), see [fun.md](./fun/).
## Synopsis ## Synopsis
``` <pre>fun [options] <script.fun> [-- args...]
fun [options] <script.fun> [-- args...] </pre>
```
If no script is supplied and interactive mode is available, `fun` starts a REPL (see [repl.md](./repl/)). If no script is supplied and interactive mode is available, `fun` starts a REPL (see [repl.md](./repl/)).
## Common options ## Common options
@ -54,11 +52,8 @@ See also: [includes.md](./includes/) for namespaced includes and search order.
## Examples ## Examples
Run a script: Run a script:
``` <pre>FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun </pre>
```
Start the REPL: Start the REPL:
``` <pre>./build/fun -i
./build/fun -i </pre>
```

View file

@ -5,7 +5,7 @@ noToc: false
noComments: false noComments: false
noDate: false noDate: false
title: Fun - Documentation 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 description: The Fun Documentation Index
permalink: /documentation/ permalink: /documentation/
lang: en lang: en
@ -68,7 +68,7 @@ The examples directory contains demonstrations of most Fun features, from basic
## Examples ## 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 ## External extensions

View file

@ -33,35 +33,27 @@ All commands assume you are in the repository root.
Example (Linux/macOS/BSD): Example (Linux/macOS/BSD):
``` <pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun examples/include_lib.fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun examples/include_lib.fun </pre>
```
Windows (PowerShell): Windows (PowerShell):
``` <pre>$env:FUN_LIB_DIR = "$PWD/lib"
$env:FUN_LIB_DIR = "$PWD/lib"
./build/fun.exe .\examples\include_lib.fun ./build/fun.exe .\examples\include_lib.fun
``` </pre>
## Interactive showcase: play.fun ## Interactive showcase: play.fun
The script `./play.fun` discovers all `.fun` files under `./examples` and offers to run them one by one: The script `./play.fun` discovers all `.fun` files under `./examples` and offers to run them one by one:
``` <pre>./play.fun
./play.fun </pre>
```
Notes: 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. - 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. - It shows the exit code for each run and summarizes failures at the end.
Tip: you can run specific examples directly too: Tip: you can run specific examples directly too:
``` <pre>FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun
FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun </pre>
```
## Example categories ## Example categories
Browse the `examples/` tree for areas of interest: 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: 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:
``` <pre>#include "examples/my_lib/common.fun"
#include "examples/my_lib/common.fun"
#include <io/console.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.). 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 - quick
--- ---
Answers to common questions. Answers to common questions.
## I built Fun but includes aren't found ## I built Fun but includes aren't found
Set `FUN_LIB_DIR` to the repository's `./lib` directory when running without installation: Set `FUN_LIB_DIR` to the repository's `./lib` directory when running without installation:
``` <pre>FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun </pre>
``` See [includes/](../includes/).
See [includes.md](./includes/).
## How do I start the REPL? ## 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? ## 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? ## 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? ## 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. 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 ## Synopsis
``` <pre>fun [options] [<script.fun>] [-- args...]
fun [options] [<script.fun>] [-- args...] </pre>
```
- If `<script.fun>` is provided, `fun` runs the script. - If `<script.fun>` is provided, `fun` runs the script.
- If omitted and the build enables the REPL, `fun` starts an interactive session. - If omitted and the build enables the REPL, `fun` starts an interactive session.
@ -66,20 +64,14 @@ Useful commands/patterns in REPL:
## Running scripts ## Running scripts
Basic run (installed systemwide): Basic run (installed systemwide):
``` <pre>fun /usr/share/fun/examples/hello.fun
fun /usr/share/fun/examples/hello.fun </pre>
```
Running from a build tree (not installed): Running from a build tree (not installed):
``` <pre>FUN_LIB_DIR=./lib /path/to/build_dir/fun examples/hello.fun
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): Passing arguments to scripts (arguments after `--` are forwarded to the script environment):
``` <pre>fun myscript.fun -- arg1 arg2
fun myscript.fun -- arg1 arg2 </pre>
```
## Build and install locations ## 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`. - 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): - Install locations (by default):
@ -88,11 +80,9 @@ fun myscript.fun -- arg1 arg2
- Examples (optional): `/usr/share/fun/examples` - Examples (optional): `/usr/share/fun/examples`
To stage an install without touching the system: To stage an install without touching the system:
``` <pre>DESTDIR=./tmp/stage cmake --build <build_dir> --target install
DESTDIR=./tmp/stage cmake --build <build_dir> --target install
./tmp/stage/usr/bin/fun ./examples/hello.fun ./tmp/stage/usr/bin/fun ./examples/hello.fun
``` </pre>
## See also ## See also
- `documentation/cli.md` — concise CLI reference (synopsis/options/exit codes) - `documentation/cli.md` — concise CLI reference (synopsis/options/exit codes)
- `documentation/funstx.md` — syntax checker for `.fun` files with optional `--fix` - `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 ## Usage
``` <pre>funstx [--fix] <file1.fun> [file2.fun ...]
funstx [--fix] <file1.fun> [file2.fun ...] </pre>
```
- Provide one or more .fun files to check. - Provide one or more .fun files to check.
- Add `--fix` to attempt safe, automatic corrections before rechecking. - Add `--fix` to attempt safe, automatic corrections before rechecking.

View file

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

View file

@ -4,7 +4,7 @@ published: true
noToc: false noToc: false
noComments: false noComments: false
noDate: 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`. 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`. description: Using local vs. system includes, FUN_LIB_DIR, DEFAULT_LIB_DIR, and namespaced includes with `as`.
permalink: /documentation/includes/ 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. Use double quotes to include files relative to the directory you execute `fun` from.
Example: Example:
``` <pre>#include "examples/include_local_util.fun"
#include "examples/include_local_util.fun"
print("== include local demo ==") print("== include local demo ==")
greet("Fun") greet("Fun")
@ -48,8 +47,7 @@ greet("Fun")
number a = 2 number a = 2
number b = 3 number b = 3
print("sum(" + to_string(a) + ", " + to_string(b) + ") = " + to_string(sum(a, b))) 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`. - 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. - 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. Use angle brackets to include modules from the Fun standard library or any library directory you point `FUN_LIB_DIR` to.
Example: Example:
``` <pre>#include <hello.fun>
#include <hello.fun>
#include <utils/math.fun> #include <utils/math.fun>
print("== include lib demo ==") print("== include lib demo ==")
@ -69,8 +66,7 @@ number x = 10
number y = 32 number y = 32
print("add(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(add(x, y))) 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))) print("times(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(times(x, y)))
``` </pre>
Resolution order for `#include <...>`: Resolution order for `#include <...>`:
1) `FUN_LIB_DIR` (environment variable), with automatic handling of trailing `/` or `\` 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. You can import a module into a namespace to avoid symbol collisions or to make intent explicit.
Examples: Examples:
``` <pre>// Import stdlib helpers under alias 'm'
// Import stdlib helpers under alias 'm'
#include <utils/math.fun> as m #include <utils/math.fun> as m
print("m.add(2, 3) = " + to_string(m.add(2, 3))) print("m.add(2, 3) = " + to_string(m.add(2, 3)))
print("m.times(4, 5) = " + to_string(m.times(4, 5))) 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")) print(mod.hello("Fun"))
g = mod.Greeter("Hi") g = mod.Greeter("Hi")
g.say("World") g.say("World")
``` </pre>
Rules: Rules:
- `as` must be followed by a valid identifier (letters, digits, underscore, starting with a letter or underscore). - `as` must be followed by a valid identifier (letters, digits, underscore, starting with a letter or underscore).
- Works for both local (`"..."`) and system (`<...>`) includes. - 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) #### Minimal API (illustrative)
```c <pre>// Zero-copy shared buffers (immutable inside VMs)
// Zero-copy shared buffers (immutable inside VMs)
fun_shared_buffer_t* fun_shared_buffer_new(size_t n); fun_shared_buffer_t* fun_shared_buffer_new(size_t n);
void* fun_shared_buffer_data(fun_shared_buffer_t*); void* fun_shared_buffer_data(fun_shared_buffer_t*);
void fun_shared_buffer_retain(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*); 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_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); int fun_recv(fun_port_t*, fun_value_t* out, uint64_t timeout_ms);
``` </pre>
#### Practical usage tips #### Practical usage tips
- Default to isolates + ports for logic; use `fun_shared_buffer` only for large payloads (images, tensors, blobs). - 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) #### Typical pattern (no locks needed)
```c <pre>fun_shared_buffer_t* b = fun_shared_buffer_new(n);
fun_shared_buffer_t* b = fun_shared_buffer_new(n);
void* p = fun_shared_buffer_data(b); void* p = fun_shared_buffer_data(b);
memcpy(p, src, n); // fill while private memcpy(p, src, n); // fill while private
@ -411,8 +408,7 @@ if (fun_recv(port, &v, 1000) == 0) {
fun_shared_buffer_release(r); fun_shared_buffer_release(r);
} }
``` </pre>
#### When would the host ever sync? #### 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. - 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) ### Minimal API surface (illustrative)
```c <pre>// Create/destroy VMs
// Create/destroy VMs
fun_vm_t* vm = fun_vm_create(const fun_vm_config_t*); fun_vm_t* vm = fun_vm_create(const fun_vm_config_t*);
void fun_vm_destroy(fun_vm_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_data(fun_shared_buffer_t*);
void fun_shared_buffer_retain(fun_shared_buffer_t*); void fun_shared_buffer_retain(fun_shared_buffer_t*);
void fun_shared_buffer_release(fun_shared_buffer_t*); void fun_shared_buffer_release(fun_shared_buffer_t*);
``` </pre>
### Glossary ### 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. - 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 ## Creating maps
``` <pre>// literals
// literals
user = { "name": "Ada", "age": 37 } user = { "name": "Ada", "age": 37 }
empty = {} empty = {}
print(typeof(user)) // "map" print(typeof(user)) // "map"
``` </pre>
Nested structures are natural and common: Nested structures are natural and common:
``` <pre>book = {
book = {
"title": "Fun Handbook", "title": "Fun Handbook",
"meta": { "pages": 120, "isbn": "123-456" }, "meta": { "pages": 120, "isbn": "123-456" },
"tags": ["lang", "vm"] "tags": ["lang", "vm"]
} }
print(book["meta"]["pages"]) // 120 print(book["meta"]["pages"]) // 120
``` </pre>
## Getting and setting by key ## Getting and setting by key
``` <pre>profile = { "name": "Lin" }
profile = { "name": "Lin" }
// read existing key // read existing key
print(profile["name"]) // Lin print(profile["name"]) // Lin
@ -67,35 +62,29 @@ print(profile["email"]) // nil
profile["email"] = "lin@example.org" profile["email"] = "lin@example.org"
profile["name"] = "Linus" profile["name"] = "Linus"
print(profile) // {"name":"Linus","email":"lin@example.org"} print(profile) // {"name":"Linus","email":"lin@example.org"}
``` </pre>
Notes: Notes:
- Using a nonstring key is allowed only if your build/runtime supports it; most code uses string keys for portability. - 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: - Missing keys produce nil. Compare against nil before converting or indexing:
``` <pre>v = profile["phone"]
v = profile["phone"]
if v == nil { print("no phone on file") } if v == nil { print("no phone on file") }
``` </pre>
## Checking key existence ## Checking key existence
Use has(m, key) to check if a key is present (returns 1 or 0): Use has(m, key) to check if a key is present (returns 1 or 0):
``` <pre>cfg = { "debug": 1 }
cfg = { "debug": 1 }
print(has(cfg, "debug")) // 1 print(has(cfg, "debug")) // 1
print(has(cfg, "port")) // 0 print(has(cfg, "port")) // 0
if has(cfg, "port") { print(cfg["port"]) } else { print("using default port") } if has(cfg, "port") { print(cfg["port"]) } else { print("using default port") }
``` </pre>
## Iterating maps ## Iterating maps
Maps are not inherently ordered. To iterate, first obtain an array of keys or values. Maps are not inherently ordered. To iterate, first obtain an array of keys or values.
``` <pre>user = { "name": "Ada", "age": 38 }
user = { "name": "Ada", "age": 38 }
// iterate known keys (explicit order you choose) // iterate known keys (explicit order you choose)
order = ["name", "age"] order = ["name", "age"]
@ -114,8 +103,7 @@ for i = 0; i < len(ks); i = i + 1 {
// values only // values only
vs = values(user) // -> ["Ada", 38] vs = values(user) // -> ["Ada", 38]
for i = 0; i < len(vs); i = i + 1 { print(to_string(vs[i])) } for i = 0; i < len(vs); i = i + 1 { print(to_string(vs[i])) }
``` </pre>
Tip: 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. - 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: Maps are reference types. Assigning copies the reference, not the contents:
``` <pre>orig = { "a": 1 }
orig = { "a": 1 }
alias = orig alias = orig
alias["a"] = 9 alias["a"] = 9
print(orig["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 dst["x"] = 7
print(src["x"]) // 1 print(src["x"]) // 1
print(dst["x"]) // 7 print(dst["x"]) // 7
``` </pre>
Shallow copies duplicate only the toplevel mapping; nested arrays/maps inside are still shared unless you clone them manually. Shallow copies duplicate only the toplevel mapping; nested arrays/maps inside are still shared unless you clone them manually.
## Equality ## Equality
``` <pre>print({"a":1,"b":2} == {"b":2,"a":1}) // true
print({"a":1,"b":2} == {"b":2,"a":1}) // true
print({"a":1} == {"a":2}) // false print({"a":1} == {"a":2}) // false
``` </pre>
Map equality compares sets of keys and their corresponding values for equality (order does not matter). Map equality compares sets of keys and their corresponding values for equality (order does not matter).
## Common utilities ## 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 ## Interop with arrays and strings
``` <pre>// maps inside arrays
// maps inside arrays
users = [ {"name":"Ada"}, {"name":"Lin"} ] users = [ {"name":"Ada"}, {"name":"Lin"} ]
for i = 0; i < len(users); i = i + 1 { for i = 0; i < len(users); i = i + 1 {
print(users[i]["name"]) // Ada, Lin 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) // 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 #include <io/json.fun> as json // adjust to your tree and build flags
s = json.stringify({"ok":1}) // "{"ok":1}" s = json.stringify({"ok":1}) // "{"ok":1}"
``` </pre>
## Error handling and edge cases ## Error handling and edge cases
- Accessing a missing key returns nil. Guard before arithmetic or nested indexing. - Accessing a missing key returns nil. Guard before arithmetic or nested indexing.
@ -196,8 +178,7 @@ s = json.stringify({"ok":1}) // "{"ok":1}"
## Examples ## Examples
``` <pre>// merge defaults into config (without overwriting explicit keys)
// merge defaults into config (without overwriting explicit keys)
defaults = { "host":"127.0.0.1", "port":8080, "debug":0 } defaults = { "host":"127.0.0.1", "port":8080, "debug":0 }
cfg = { "port": 9000 } cfg = { "port": 9000 }
@ -216,8 +197,7 @@ for i = 0; i < len(rows); i = i + 1 {
by_id[r["id"]] = r by_id[r["id"]] = r
} }
print(by_id["u2"]["name"]) // Lin print(by_id["u2"]["name"]) // Lin
``` </pre>
## See also ## See also
- types.md — broader overview of core types with quick map examples. - 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) - number: signed integer (implementationdefined width; use uclamp/sclamp for fixedwidth interop)
- float: IEEE754 double precision (64bit) - float: IEEE754 double precision (64bit)
``` <pre>an = 42 // number
an = 42 // number
af = 3.14159 // float af = 3.14159 // float
print(typeof(an)) // "number" print(typeof(an)) // "number"
print(typeof(af)) // "float" print(typeof(af)) // "float"
``` </pre>
## Literals ## Literals
- Integer (number): 0, 1, -7, 120 - Integer (number): 0, 1, -7, 120
- Floating point (float): 0.0, 1.5, -2.75, 1e3, -4.2e-1 - Floating point (float): 0.0, 1.5, -2.75, 1e3, -4.2e-1
``` <pre>x = 10
x = 10
y = 2.5 y = 2.5
z = -3 z = -3
``` </pre>
## Arithmetic ## Arithmetic
Basic arithmetic works as youd expect: Basic arithmetic works as youd expect:
``` <pre>a = 7
a = 7
b = 2 b = 2
print(a + b) // 9 print(a + b) // 9
print(a - b) // 5 print(a - b) // 5
print(a * b) // 14 print(a * b) // 14
print(a % b) // 1 (modulo) print(a % b) // 1 (modulo)
``` </pre>
Division and result type: Division and result type:
``` <pre>// If you need a fractional result, ensure a float is involved
// 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(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(cast(7, "float") / 2) // 3.5 (recommended when you need fractions)
print(7 / 2.0) // 3.5 print(7 / 2.0) // 3.5
``` </pre>
Mixing numbers and floats promotes the operation to float semantics: Mixing numbers and floats promotes the operation to float semantics:
``` <pre>print(2 + 0.5) // 2.5
print(2 + 0.5) // 2.5 </pre>
```
## Comparisons ## Comparisons
``` <pre>print(3 < 5) // 1 (true)
print(3 < 5) // 1 (true)
print(3 == 3) // 1 print(3 == 3) // 1
print(3 != 4) // 1 print(3 != 4) // 1
// Be explicit when comparing ints vs floats if types matter // Be explicit when comparing ints vs floats if types matter
print(1 == 1.0) // may be true, but types differ print(1 == 1.0) // may be true, but types differ
print(cast(1.0, "number") == 1) // 1 (true) with explicit cast print(cast(1.0, "number") == 1) // 1 (true) with explicit cast
``` </pre>
## Conversions and parsing ## Conversions and parsing
``` <pre>n = to_number("123") // 123 (number)
n = to_number("123") // 123 (number)
f = cast(n, "float") // 123.0 (float) f = cast(n, "float") // 123.0 (float)
n2 = cast(3.9, "number") // 3 (truncation semantics) n2 = cast(3.9, "number") // 3 (truncation semantics)
print(to_string(f)) // "123" print(to_string(f)) // "123"
``` </pre>
If parsing fails (e.g., to_number("abc")), expect a runtime error; guard accordingly. If parsing fails (e.g., to_number("abc")), expect a runtime error; guard accordingly.
## Clamping to fixed widths ## Clamping to fixed widths
When interoperating with bytecode, C APIs, or binary formats, clamp integers to a specific bit width. When interoperating with bytecode, C APIs, or binary formats, clamp integers to a specific bit width.
``` <pre>// Unsigned clamp to N bits
// Unsigned clamp to N bits
u8 = uclamp(300, 8) // 44 u8 = uclamp(300, 8) // 44
u16 = uclamp(70000, 16) u16 = uclamp(70000, 16)
// Signed clamp to N bits // Signed clamp to N bits
s8 = sclamp(-130, 8) // wraps into signed 8bit range 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. Choose the bits according to the target field (8, 16, 32, 64). See your interop API docs for exact ranges.
## Bitwise operations (numbers) ## Bitwise operations (numbers)
Bitwise operators apply to the integer number type. Bitwise operators apply to the integer number type.
``` <pre>a = 0b0110 // if binary literals arent supported in your setup, use decimals: a = 6
a = 0b0110 // if binary literals arent supported in your setup, use decimals: a = 6
b = 0b0011 // or b = 3 b = 0b0011 // or b = 3
print(a & b) // 0b0010 -> 2 print(a & b) // 0b0010 -> 2
@ -136,41 +119,34 @@ print(a ^ b) // 0b0101 -> 5
print(~a) // bitwise NOT (twos complement rules) print(~a) // bitwise NOT (twos complement rules)
print(a << 1) // 12 print(a << 1) // 12
print(a >> 1) // 3 print(a >> 1) // 3
``` </pre>
Note: Bitwise ops are defined for numbers, not floats. Cast floats to numbers first when needed. Note: Bitwise ops are defined for numbers, not floats. Cast floats to numbers first when needed.
## Common patterns ## Common patterns
Ensuring float math to avoid unintended truncation: Ensuring float math to avoid unintended truncation:
``` <pre>avg = cast(sum, "float") / cast(count, "float")
avg = cast(sum, "float") / cast(count, "float") </pre>
```
Safe division with guard against zero: Safe division with guard against zero:
``` <pre>num = 10
num = 10
den = 0 den = 0
if den == 0 { if den == 0 {
print("division by zero") print("division by zero")
} else { } else {
print(num / den) print(num / den)
} }
``` </pre>
Parsing user input with fallback: Parsing user input with fallback:
``` <pre>raw = "not-a-number"
raw = "not-a-number"
val = 0 val = 0
// simplistic guard pattern; adapt to your error handling style // simplistic guard pattern; adapt to your error handling style
if find(raw, "0") >= 0 || find(raw, "1") >= 0 { // crude pre-check if find(raw, "0") >= 0 || find(raw, "1") >= 0 { // crude pre-check
val = to_number(raw) val = to_number(raw)
} }
``` </pre>
## Gotchas ## Gotchas
- Integer division vs float division: promote to float when you need fractional results. - 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 - Build flag: -DFUN_WITH_REPL=ON
- Typical CMake configuration example: - Typical CMake configuration example:
``` <pre>cmake -S . -B build \
cmake -S . -B build \
-DFUN_WITH_REPL=ON -DFUN_WITH_REPL=ON
cmake --build build --target fun 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): 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):
``` <pre>cmake -S . -B build -DFUN_WITH_REPL=ON -DDEFAULT_LIB_DIR="/usr/share/fun/lib"
cmake -S . -B build -DFUN_WITH_REPL=ON -DDEFAULT_LIB_DIR="/usr/share/fun/lib" </pre>
```
## Launching the REPL ## Launching the REPL
- Directly run the main executable (ensure FUN_WITH_REPL=ON): - Directly run the main executable (ensure FUN_WITH_REPL=ON):
``` <pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun </pre>
```
- With the CMake “repl” convenience target (available only if built with FUN_WITH_REPL=ON): - With the CMake “repl” convenience target (available only if built with FUN_WITH_REPL=ON):
``` <pre>cmake --build build --target repl
cmake --build build --target repl </pre>
```
On startup, you should see something like: On startup, you should see something like:
``` <pre>Fun X.Y.Z REPL
Fun X.Y.Z REPL
Type :help for commands. Submit an empty line to run. 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. 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 ## Running scripts and REPL-on-error
- Run a script file normally: - Run a script file normally:
``` <pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun ./demo.fun </pre>
```
- Enable tracing, and drop into a REPL automatically when a runtime error occurs: - Enable tracing, and drop into a REPL automatically when a runtime error occurs:
``` <pre>FUN_LIB_DIR="$(pwd)/lib" ./build/fun --repl-on-error --trace ./demo.fun
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. 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 ## Prompts and input model

View file

@ -77,8 +77,7 @@ Example: integer addition opcode implemented in Rust.
In src/rust/src/lib.rs: In src/rust/src/lib.rs:
``` <pre>#![no_std]
#![no_std]
#[repr(C)] #[repr(C)]
pub struct Vm; pub struct Vm;
@ -100,8 +99,7 @@ In src/rust/src/lib.rs:
#[panic_handler] #[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
``` </pre>
What this does: What this does:
- Pops two 64-bit integers from the VM stack. - Pops two 64-bit integers from the VM stack.
- Pushes back their sum. - 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 String demo wiring (already present): src/vm/rust/hello.c
``` <pre>case OP_RUST_HELLO: {
case OP_RUST_HELLO: {
#ifdef FUN_WITH_RUST #ifdef FUN_WITH_RUST
const char *s = fun_rust_get_string(); const char *s = fun_rust_get_string();
if (!s) s = ""; if (!s) s = "";
@ -127,12 +124,10 @@ case OP_RUST_HELLO: {
#endif #endif
break; break;
} }
``` </pre>
For a stack-based math opcode (like fun_op_radd), you would declare and call the Rust function similarly: For a stack-based math opcode (like fun_op_radd), you would declare and call the Rust function similarly:
``` <pre>#ifdef FUN_WITH_RUST
#ifdef FUN_WITH_RUST
extern int fun_op_radd(void* vm); // or use the proper VM type if available extern int fun_op_radd(void* vm); // or use the proper VM type if available
#endif #endif
@ -145,8 +140,7 @@ case OP_RADD: {
#endif #endif
break; break;
} }
``` </pre>
Notes: Notes:
- Follow the existing opcode conventions for your module (core, math, strings, etc.). - 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. 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 ## Using modules
```fun <pre>#include <strings.fun>
#include <strings.fun>
let s = trim(" hello ") let s = trim(" hello ")
print(s) print(s)
``` </pre>
For search paths and namespacing details, see [includes.md](./includes/) and [cli.md](./cli/) (FUN_LIB_DIR and DEFAULT_LIB_DIR). 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 ## Literals and escaping
``` <pre>s1 = "hello"
s1 = "hello"
s2 = "line1\nline2" // newline s2 = "line1\nline2" // newline
s3 = "quote: \" and backslash: \\" // escaped quote and backslash s3 = "quote: \" and backslash: \\" // escaped quote and backslash
print(s1) // hello print(s1) // hello
``` </pre>
Notes: Notes:
- Strings are immutable; operations return new strings rather than modifying in place. - Strings are immutable; operations return new strings rather than modifying in place.
- Use to_string(x) when concatenating non-string values. - Use to_string(x) when concatenating non-string values.
@ -49,66 +47,54 @@ Notes:
Length and concatenation: Length and concatenation:
``` <pre>name = "Ada"
name = "Ada"
greet = "Hello, " + name + "!" // "Hello, Ada!" greet = "Hello, " + name + "!" // "Hello, Ada!"
print(len(greet)) // 12 print(len(greet)) // 12
``` </pre>
Substring (start, length) and search: Substring (start, length) and search:
``` <pre>s = "hello, world"
s = "hello, world"
print(substr(s, 7, 5)) // world print(substr(s, 7, 5)) // world
idx = find(s, ",") // 5, or -1 if not found idx = find(s, ",") // 5, or -1 if not found
if idx >= 0 { print("comma at index " + to_string(idx)) } if idx >= 0 { print("comma at index " + to_string(idx)) }
``` </pre>
Splitting into arrays: Splitting into arrays:
``` <pre>parts = split("a,b,c", ",") // ["a","b","c"]
parts = split("a,b,c", ",") // ["a","b","c"]
for i = 0; i < len(parts); i = i + 1 { for i = 0; i < len(parts); i = i + 1 {
print(parts[i]) print(parts[i])
} }
``` </pre>
## Conversions and formatting ## Conversions and formatting
``` <pre>n = 42
n = 42
pi = 3.14 pi = 3.14
msg = "n=" + to_string(n) + ", pi=" + to_string(pi) msg = "n=" + to_string(n) + ", pi=" + to_string(pi)
print(msg) print(msg)
// parsing (may error if the string is not numeric) // parsing (may error if the string is not numeric)
n2 = to_number("123") // 123 n2 = to_number("123") // 123
``` </pre>
If you need a specific type, you can use cast for advanced cases, e.g. cast("123", "number"). If you need a specific type, you can use cast for advanced cases, e.g. cast("123", "number").
## Common patterns ## Common patterns
- Guard on find results before slicing: - Guard on find results before slicing:
``` <pre>email = "user@example.org"
email = "user@example.org"
at = find(email, "@") at = find(email, "@")
if at >= 0 { if at >= 0 {
user = substr(email, 0, at) user = substr(email, 0, at)
host = substr(email, at + 1, len(email) - at - 1) host = substr(email, at + 1, len(email) - at - 1)
print(user + " on " + host) print(user + " on " + host)
} }
``` </pre>
- Building paths or messages: - Building paths or messages:
``` <pre>base = "/tmp"
base = "/tmp"
file = "log.txt" file = "log.txt"
path = base + "/" + file path = base + "/" + file
``` </pre>
## Gotchas ## 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. - 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: Debug profile example:
``` <pre>cmake --build build --target test_opcodes && ./build/test_opcodes
cmake --build build --target test_opcodes && ./build/test_opcodes </pre>
```
Release profile example: Release profile example:
``` <pre>cmake --build build_release --target test_opcodes && ./build/test_opcodes
cmake --build build_release --target test_opcodes && ./build/test_opcodes </pre>
```
If `fun_test` exists in your configuration: If `fun_test` exists in your configuration:
``` <pre>cmake --build build --target fun_test && ./build/fun_test
cmake --build build --target fun_test && ./build/fun_test </pre>
```
You can also invoke CTest to run any tests registered with `add_test()`: You can also invoke CTest to run any tests registered with `add_test()`:
``` <pre>cmake --build build --target test
cmake --build build --target test
ctest --test-dir build -j ctest --test-dir build -j
``` </pre>
## Adding new tests ## 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()`. - 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: Error example:
``` <pre>Include error: cannot read '<io/console.fun>'
Include error: cannot read '<io/console.fun>' </pre>
```
Fix: Fix:
- When running from the repository without installing, set `FUN_LIB_DIR` to the local `./lib` directory so anglebracket includes resolve correctly. - When running from the repository without installing, set `FUN_LIB_DIR` to the local `./lib` directory so anglebracket includes resolve correctly.
Linux/macOS/BSD: Linux/macOS/BSD:
``` <pre>export FUN_LIB_DIR="$(pwd)/lib"
export FUN_LIB_DIR="$(pwd)/lib"
./build/fun examples/include_lib.fun ./build/fun examples/include_lib.fun
``` </pre>
Windows (PowerShell): Windows (PowerShell):
``` <pre>$env:FUN_LIB_DIR = "$PWD/lib"
$env:FUN_LIB_DIR = "$PWD/lib"
./build/fun.exe .\examples\include_lib.fun ./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. 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. See includes.md for more details.
@ -59,12 +53,10 @@ Symptoms:
Fix: Fix:
- Build with `-DFUN_WITH_REPL=ON` and rebuild the `fun` target. Then launch without arguments: - Build with `-DFUN_WITH_REPL=ON` and rebuild the `fun` target. Then launch without arguments:
``` <pre>cmake -S . -B build -DFUN_WITH_REPL=ON
cmake -S . -B build -DFUN_WITH_REPL=ON
cmake --build build --target fun cmake --build build --target fun
FUN_LIB_DIR="$(pwd)/lib" ./build/fun FUN_LIB_DIR="$(pwd)/lib" ./build/fun
``` </pre>
See repl.md for usage tips and features. See repl.md for usage tips and features.
## Linker errors for optional libraries (JSON, PCRE2, CURL, SQLite, etc.) ## 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. Create arrays with square brackets and commaseparated elements.
``` <pre>// creation
// creation
a = [1, 2, 3] a = [1, 2, 3]
b = ["alpha", "beta"] b = ["alpha", "beta"]
c = [] // empty array c = [] // empty array
@ -96,8 +95,7 @@ for pair in it.enumerate(["x", "y"]) {
val = pair[1] val = pair[1]
print(idx + ":" + val) print(idx + ":" + val)
} }
``` </pre>
Notes: Notes:
- Indexing is boundschecked; invalid indices cause a runtime error that you can inspect with --trace or REPLonerror. - 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. - 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. Create maps with curly braces. Keys are typically strings; values can be any type.
``` <pre>// creation
// creation
user = { "name": "Ada", "age": 37 } user = { "name": "Ada", "age": 37 }
cfg = {} cfg = {}
@ -134,57 +131,48 @@ for i = 0; i < len(keys); i = i + 1 {
k = keys[i] k = keys[i]
print(k + " = " + to_string(user[k])) print(k + " = " + to_string(user[k]))
} }
``` </pre>
Notes: Notes:
- Accessing a nonexisting key returns nil; write a guard before using it as another type. - 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. - Maps are mutable; assigning with map["k"] = v updates in place.
## Strings (brief) ## Strings (brief)
``` <pre>s = "hello, world"
s = "hello, world"
print(len(s)) // 12 print(len(s)) // 12
print(substr(s, 7, 5)) // world print(substr(s, 7, 5)) // world
print(find(s, ",")) // 5 (index) or -1 if not found print(find(s, ",")) // 5 (index) or -1 if not found
parts = split("a,b,c", ",") // ["a","b","c"] parts = split("a,b,c", ",") // ["a","b","c"]
print(join(parts, ";")) // a;b;c print(join(parts, ";")) // a;b;c
``` </pre>
## Numbers and floats (brief) ## Numbers and floats (brief)
``` <pre>n = 10
n = 10
f = 3.14 f = 3.14
print(n + 2) // 12 print(n + 2) // 12
print(f * 2) // 6.28 print(f * 2) // 6.28
// clamp to widths when needed // clamp to widths when needed
print(uclamp(300, 8)) // 44 (300 mod 256) print(uclamp(300, 8)) // 44 (300 mod 256)
``` </pre>
## Booleans and nil ## Booleans and nil
``` <pre>ok = 1 // true
ok = 1 // true
no = 0 // false no = 0 // false
none = nil none = nil
if ok && !no { print("yay") } if ok && !no { print("yay") }
if none == nil { print("is nil") } if none == nil { print("is nil") }
``` </pre>
## Conversions and typing ## Conversions and typing
``` <pre>x = "42"
x = "42"
print(to_number(x) + 1) // 43 print(to_number(x) + 1) // 43
print(typeof([1,2,3])) // "array" print(typeof([1,2,3])) // "array"
print(typeof({})) // "map" print(typeof({})) // "map"
``` </pre>
## Common patterns ## Common patterns
- Accumulate values: - Accumulate values:

View file

@ -5,8 +5,8 @@ noToc: false
noComments: false noComments: false
noDate: false noDate: false
title: Fun - Website Documentation (fun-lang.xyz) title: Fun - Website Documentation (fun-lang.xyz)
subtitle: 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](https,//fun-lang.xyz) website in the `./web/` directory. description: Documentation for the fun-lang.xyz website in the `./web/` directory.
permalink: /documentation/website/ permalink: /documentation/website/
lang: en lang: en
tags: tags:
@ -93,9 +93,7 @@ To run the website locally for development:
The website can be deployed using the Makefile: The website can be deployed using the Makefile:
```bash <pre>cd web/
cd web/
make release 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. 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.

View file

@ -37,7 +37,7 @@ permalink: /
<article class="post-content"> <article class="post-content">
<h2><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a> <span style="cursor:help; float: right;" title="Pinned Post!">📌</span></h2> <h2><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a> <span style="cursor:help; float: right;" title="Pinned Post!">📌</span></h2>
<p class="post-meta">{{ post.date | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}) <p class="post-meta">{{ post.date | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }})
{% if post.date_updated %} - Edited: {{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}){% endif %}{% if post.author %}, <a href="{{ site.git_short }}/{{ post.author }}" target="_blank" class="user">{{ post.author }}</a>{% endif %}</p> {% if post.date_updated %} - Edited: {{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}){% endif %}{% if post.author %}, <a href="{{ post.author_url }}" target="_blank" class="user">{{ post.author }}</a>{% endif %}</p>
{{ post.content | truncatewords: site.truncatewords_length }} {{ post.content | truncatewords: site.truncatewords_length }}
<p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p> <p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p>
</article> </article>
@ -48,7 +48,7 @@ permalink: /
<article class="post-content"> <article class="post-content">
<h2><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a></h2> <h2><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a></h2>
<p class="post-meta">{{ post.date | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}) <p class="post-meta">{{ post.date | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }})
{% if post.date_updated %} - Edited: {{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}){% endif %}{% if post.author %}, <a href="{{ site.git_short }}/{{ post.author }}" target="_blank" class="user">{{ post.author }}</a>{% endif %}</p> {% if post.date_updated %} - Edited: {{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" }} ({{ post.date_updated | date: "%b %-d, %Y %H:%M:%S" | date: "%Z" }}){% endif %}{% if post.author %}, <a href="{{ post.author_url }}" target="_blank" class="user">{{ post.author }}</a>{% endif %}</p>
{{ post.content | truncatewords: site.truncatewords_length }} {{ post.content | truncatewords: site.truncatewords_length }}
<p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p> <p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p>
</article> </article>