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 %}
|
<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 }}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 square‑bracket literals for clarity and performance versus building via repeated push in a hot loop.
|
Tip: Prefer square‑bracket literals for clarity and performance versus building via repeated push in a hot loop.
|
||||||
|
|
||||||
## Indexing (0‑based) and assignment
|
## Indexing (0‑based) 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"]
|
|
||||||
|
|
||||||
// index‑based loop
|
// index‑based 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 top‑level array but not nested structures.
|
Shallow copies duplicate the top‑level 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 element‑wise equality recursively.
|
Array equality compares length and element‑wise 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 one‑by‑one in very tight loops.
|
- 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
|
## 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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
```
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.).
|
||||||
|
|
|
||||||
|
|
@ -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/).
|
||||||
|
|
|
||||||
|
|
@ -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 system‑wide):
|
Basic run (installed system‑wide):
|
||||||
```
|
<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`
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,8 @@ funstx is a small command‑line 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 re‑checking.
|
- Add `--fix` to attempt safe, automatic corrections before re‑checking.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 isn’t needed because libs are placed in the system default directory (e.g., /usr/share/fun/lib).
|
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
|
## 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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,7 @@ This provides zero‑copy hand‑off 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 don’t expose shared mutability to VMs. The trick is: publish‑as‑immutab
|
||||||
|
|
||||||
#### 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 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.
|
- 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)
|
### 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 (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.
|
- 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
|
## 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 non‑string key is allowed only if your build/runtime supports it; most code uses string keys for portability.
|
- 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:
|
- 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 top‑level mapping; nested arrays/maps inside are still shared unless you clone them manually.
|
Shallow copies duplicate only the top‑level 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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
- number: signed integer (implementation‑defined width; use uclamp/sclamp for fixed‑width interop)
|
||||||
- float: IEEE‑754 double precision (64‑bit)
|
- float: IEEE‑754 double precision (64‑bit)
|
||||||
|
|
||||||
```
|
<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 you’d expect:
|
Basic arithmetic works as you’d 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 8‑bit range
|
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.
|
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 aren’t supported in your setup, use decimals: a = 6
|
||||||
a = 0b0110 // if binary literals aren’t 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 (two’s complement rules)
|
print(~a) // bitwise NOT (two’s 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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.).
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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()`.
|
||||||
|
|
|
||||||
|
|
@ -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 angle‑bracket includes resolve correctly.
|
- 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:
|
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 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.
|
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.
|
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.)
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,7 @@ Helpers used throughout:
|
||||||
|
|
||||||
Create arrays with square brackets and comma‑separated elements.
|
Create arrays with square brackets and comma‑separated 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 bounds‑checked; invalid indices cause a runtime error that you can inspect with --trace or REPL‑on‑error.
|
- 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.
|
- 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 non‑existing key returns nil; write a guard before using it as another type.
|
- 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.
|
- 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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue