Documentation fixes. No code changes. (0.40.5)
This commit is contained in:
parent
e7e1343a83
commit
02f0c07bce
28 changed files with 271 additions and 496 deletions
|
|
@ -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 %}
|
||||
{% 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 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>
|
||||
<article class="post-content">
|
||||
{{ content }}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
layout: post
|
||||
published: true
|
||||
author: hanez
|
||||
author_email: you@hanez.org
|
||||
author_url: https://hanez.org
|
||||
title: Init Fun!
|
||||
description: Blog - Init Fun!
|
||||
date: 2025-10-05
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
layout: post
|
||||
published: true
|
||||
author: hanez
|
||||
author_email: you@hanez.org
|
||||
author_url: https://hanez.org
|
||||
noToc: false
|
||||
title: Announcing Fun 0.37.62
|
||||
description: Homepage and Blog
|
||||
date: 2026-01-25
|
||||
date_updated: 2026-01-31 21:45:03
|
||||
date_updated: 2026-04-11 00:56:03
|
||||
categories:
|
||||
- news
|
||||
- project
|
||||
|
|
@ -54,26 +56,22 @@ This release brings Fun closer to its vision with significant language enhanceme
|
|||
- Private members by convention (leading underscore)
|
||||
- Dot-call syntax sugar for clean method invocations: obj.method(a, b)
|
||||
|
||||
<pre>
|
||||
class Counter
|
||||
<pre>class Counter
|
||||
value = 0
|
||||
fun inc(this)
|
||||
this.value = this.value + 1
|
||||
return this.value
|
||||
|
||||
c = Counter()
|
||||
print(c.inc()) // 1
|
||||
</pre>
|
||||
print(c.inc()) // 1</pre>
|
||||
|
||||
### Module System
|
||||
|
||||
- Namespaced includes with #include <path> as alias for clean imports
|
||||
- Organize code into reusable modules without naming conflicts
|
||||
|
||||
<pre>
|
||||
#include <utils/math.fun> as m
|
||||
print(m.add(2, 3)) // 5
|
||||
</pre>
|
||||
<pre>#include <utils/math.fun> as m
|
||||
print(m.add(2, 3)) // 5</pre>
|
||||
|
||||
### Enhanced Type System
|
||||
|
||||
|
|
@ -87,14 +85,12 @@ print(m.add(2, 3)) // 5
|
|||
- Thread primitives: thread_spawn, thread_join, and sleep
|
||||
- Write concurrent programs with ease
|
||||
|
||||
<pre>
|
||||
fun square(n)
|
||||
<pre>fun square(n)
|
||||
sleep(100)
|
||||
return n * n
|
||||
|
||||
tid = thread_spawn(square, 5)
|
||||
print(thread_join(tid)) // 25
|
||||
</pre>
|
||||
print(thread_join(tid)) // 25</pre>
|
||||
|
||||
### 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:
|
||||
|
||||
- [Website](https://fun-lang.xyz)
|
||||
- [Git Repository](https://git.xw3.org/fun/fun){:class="git"}
|
||||
- [Fun Handbook](https://fun-lang.xyz/documentation/handbook/){:class="git"}
|
||||
- [Fun REPL Guide](https://fun-lang.xyz/documentation/repl/){:class="git"}
|
||||
- [Fun Handbook](/documentation/handbook/)
|
||||
- [Fun REPL Guide](/documentation/repl/)
|
||||
- [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"}
|
||||
- [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.
|
||||
|
||||
### For Developers
|
||||
|
||||
- [Fun Internals](https://fun-lang.xyz/documentation/internals/){:class="git"}
|
||||
- [Fun Opcodes](https://fun-lang.xyz/documentation/opcodes/){:class="git"}
|
||||
- [Basic Rust Opcodes Support](https://fun-lang.xyz/documentation/rust/){:class="git"}
|
||||
- [Fun Internals](/documentation/internals/){:class="git"}
|
||||
- [Fun Opcodes](/documentation/opcodes/){:class="git"}
|
||||
- [Basic Rust Opcodes Support](/documentation/rust/){:class="git"}
|
||||
|
||||
### 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!
|
||||
|
||||
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"}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
layout: post
|
||||
published: true
|
||||
author: hanez
|
||||
author_email: you@hanez.org
|
||||
author_url: https://hanez.org
|
||||
noToc: false
|
||||
title: Moving the Website to the Project Root
|
||||
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.
|
||||
|
||||
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.
|
||||
- **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.
|
||||
|
|
@ -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.
|
||||
|
||||
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?
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ $background-color: #565656;
|
|||
$headline-color: #bc6c21; //#b40000;
|
||||
$hover-color: #bc6c21;
|
||||
$topbutton-color: $headline-color;
|
||||
$brand-color: #1fa2af;
|
||||
$brand-color: #3d0e51;
|
||||
$brand-color-light: lighten($brand-color, 40%);
|
||||
$grey-color: #828282;
|
||||
$grey-color-light: #e8e8e8;
|
||||
|
|
|
|||
|
|
@ -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 square‑bracket literals for clarity and performance versus building via repeated push in a hot loop.
|
||||
|
||||
## Indexing (0‑based) 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"]
|
||||
|
||||
// index‑based 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 top‑level 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 element‑wise 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 one‑by‑one 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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.).
|
||||
|
|
|
|||
|
|
@ -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/).
|
||||
|
|
|
|||
|
|
@ -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 system‑wide):
|
||||
```
|
||||
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`
|
||||
|
|
|
|||
|
|
@ -36,10 +36,8 @@ funstx is a small command‑line 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 re‑checking.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 isn’t 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -351,8 +351,7 @@ This provides zero‑copy hand‑off 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 don’t expose shared mutability to VMs. The trick is: publish‑as‑immutab
|
|||
|
||||
#### 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 lock‑free ring buffer you manage). For that, we expose optional helpers (`fun_atomic_*`, `fun_mutex_t`, `fun_rwlock_t`), but they’re not required for the standard zero‑copy path.
|
||||
|
|
@ -477,8 +473,7 @@ It depends on what “shared” means. Our design keeps per‑VM 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 (stop‑the‑world, per‑VM). There is no global stop‑the‑world and no global lock; a GC pause in one VM does not affect others.
|
||||
|
|
|
|||
|
|
@ -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 non‑string 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 top‑level 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.
|
||||
|
|
|
|||
|
|
@ -38,96 +38,79 @@ This guide covers the numeric types in Fun, with a focus on the integer "number"
|
|||
- number: signed integer (implementation‑defined width; use uclamp/sclamp for fixed‑width interop)
|
||||
- float: IEEE‑754 double precision (64‑bit)
|
||||
|
||||
```
|
||||
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 you’d 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 8‑bit 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 aren’t supported in your setup, use decimals: a = 6
|
||||
<pre>a = 0b0110 // if binary literals aren’t 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 (two’s 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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.).
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()`.
|
||||
|
|
|
|||
|
|
@ -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 angle‑bracket 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 compile‑time `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.)
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ Helpers used throughout:
|
|||
|
||||
Create arrays with square brackets and comma‑separated 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 bounds‑checked; invalid indices cause a runtime error that you can inspect with --trace or REPL‑on‑error.
|
||||
- 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 non‑existing 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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ permalink: /
|
|||
<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>
|
||||
<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 }}
|
||||
<p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p>
|
||||
</article>
|
||||
|
|
@ -48,7 +48,7 @@ permalink: /
|
|||
<article class="post-content">
|
||||
<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" }})
|
||||
{% 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 }}
|
||||
<p style="text-align:right;"><a href="{{ post.url }}" title="{{ post.url }}">[Read post]</a></p>
|
||||
</article>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue