13 KiB
Fun Language Specification v0.3
This document describes Fun (Fun Uses Nothing) as of version 0.3. It supersedes v0.2 by formalizing classes/objects, inheritance, namespaced includes, richer collections and builtins, concurrency primitives, networking and OS integration, as reflected by the examples.
1) Overview and Goals
- Readable: strict, indentation-based syntax (2 spaces), no semicolons.
- Safe: explicit types, no implicit numeric coercions, bounds-checked operations, controlled side effects.
- Hackable: pragmatic stdlib, process I/O, sockets, threads.
What’s new in v0.3 (high level):
- Classes and objects with methods, constructors, and inheritance (
extends). - Dot-call sugar for method calls, and explicit
thisin method definitions. - Namespaced
#include ... as aliasfor module imports. - Maps (dictionaries) with literals and helpers.
- Control-flow additions:
breakandcontinue. - Threads:
thread_spawn,thread_joinandsleep. - Expanded system and network APIs (TCP/Unix sockets, serial, env, timers).
- Bitwise helpers (
band,bor,bxor,bnot,shl). - Exception syntax (
try/catch/finally) is defined; runtime throwing/handling may be partial.
2) Lexical Structure
- Case-sensitive identifiers: letters, digits,
_; must not start with a digit. - Comments:
- Single-line:
// comment - Multi-line:
/* ... */
- Single-line:
- Whitespace and newlines:
- Indentation is exactly 2 spaces; tabs are forbidden.
- Newline terminates statements; no semicolons.
Reserved keywords (cannot be redefined):
if,else,for,while,break,continuefun,returnclass,extendsglobal,privatetrue,falsetry,catch,finally
Notes:
#includeis a directive, not an expression;asis part of the include alias syntax (see Modules & Includes).
3) Types
Scalar types:
number: 64-bit signed integer.float: 64-bit IEEE-754 floating point.stringboolean:true/false(in conditionals0and1are accepted where noted).byte: 8-bit value (see conversions and overflow rules).
Fixed-width integers (signed/unsigned):
int8,uint8,int16,uint16,int32,uint32,int64,uint64
Aggregate types:
arrayand typed arrays:array<T>map<K, V>(dictionary / associative array)object(instances ofclass)
Examples:
number n = 42
float pi = 3.14159
string s = 'He said: "Fun!"'
boolean ok = true
byte b = 0x41
array<number> nums = [1, 2, 3]
array mixed = [1, "two", true, [3, 4]]
m = { "a": 1, "b": 2 } // map<string, number>
Dynamic typing escape hatch (discouraged; use when interacting with unknown data):
dynamic string x = 42 // allowed by spec; runtime performs dynamic checks
x = "Now I'm a string"
4) Variables and Scope
globalvariables are visible program-wide.privatevariables are file-local (module private).- Rebinding a global or shadowing a name is a compile-time error.
global string message = "Hello"
private number count = 42
number local = 23
5) Operators and Builtins
Arithmetic: +, -, *, /, %
Comparison: ==, !=, >, <, >=, <=
Boolean: &&, ||, !
Assignment: =
Bitwise helpers (functions):
band(a, b),bor(a, b),bxor(a, b),bnot(a),shl(a, n)
print(bxor(0x80000000, 0x00000001)) // 2147483649
print(shl(0x80, 24)) // 2147483648
Collection helpers (selected):
- Arrays:
push(arr, v),join(arr, sep),map(arr, f),filter(arr, pred),reduce(arr, init, f) - Maps:
has(m, key),keys(m),values(m)
Type/convert helpers (selected):
typeof(x) -> stringto_string(x)and numeric casts (see examples forcast_demo.funandconversions_showcase.fun)
6) Control Flow
If/Else:
if (x != y)
print(x)
else if (a == b || h != i)
print(a + b)
else
if (k < 1 && l > 1)
print("Buh!")
While:
number i = 0
while i < 10
if i % 2 == 0
i = i + 1
continue
if i > 5
break
i = i + 1
For:
- Range iteration:
for i in range(start, end) - Array iteration:
for x in arr - Map iteration:
for k in keys(m)thenm[k]
for i in range(0, 5)
print(i)
for x in [1, 2, 3]
print(x)
Loop control:
breakexits the innermost loop.continueskips to next iteration of the current loop.
Try/Catch/Finally (syntax defined; runtime throwing may be incomplete):
try
// protected section
risky()
catch err
print("caught error:")
print(err)
finally
print("cleanup")
7) Functions
Built-in/runtime functions (selected):
- Basic:
print(x),range(a, b),sleep(ms) - Processes:
exec(cmd) -> string,system(cmd) -> number - Async processes:
nexec(cmd) -> pid/object,nsystem(cmd) -> number,nspawn(cmd) -> pid,wait(pid),read(pid),kill(pid) - Threads:
thread_spawn(fn, argOrArgs) -> thread_id,thread_join(thread_id) -> any
User-defined functions:
fun add(a, b)
return a + b
fun divide(a, b)
if b == 0
return 0, "division by zero"
return a / b, ""
Higher-order helper (example pattern):
fun call(f, arg)
return f(arg)
Multiple return values are supported syntactically; use tuple-like unpacking via arrays as needed in user code patterns.
8) Classes and Objects
Definition:
class Name(/* optional ctor params with types */)
// field defaults
field1 = 0
field2 = ""
// method: first parameter must be `this`
fun method(this, arg1, arg2)
// ...
return 0
Constructors:
- Default constructor maps the class header parameters to fields of the same names.
- Optional explicit constructor hook: define
fun _construct(this, ...params...)to customize initialization. It is invoked automatically on instantiation.
Fields and methods:
- Fields are created/initialized with simple assignments in the class body.
- Methods are functions declared inside the class; the first parameter must be
this. - Private members: any field or method whose name starts with
_is considered private to the class. Accessing them from outside should raise an access error.
Instantiation and method calls:
p = Point(10, -2)
print(p.x) // field access via `.` or indexing
print(p["x"]) // map-like field access is supported
// Dot-call sugar: p.method(a, b) is equivalent to method(p, a, b)
print(p.toString())
Method references:
move_fn = p["move"]
move_fn(p, 3, 5) // call with explicit `this`
Inheritance:
class Parent(number start)
value = 0
fun _construct(this, s)
this.value = s
fun describe(this)
return "Parent(value=" + to_string(this.value) + ")"
class Child(number start) extends Parent
bonus = 5
fun _construct(this, s)
// runs after parent fields merged
this.value = this.value + this.bonus
fun describe(this)
return "Child(value=" + to_string(this.value) + ", bonus=" + to_string(this.bonus) + ")"
typeof on classes and instances:
typeof(Point) == "Class"typeof(p) == "Point(10, -2)"(implementation-specific descriptive form)
9) Modules and Includes
Include sources:
- System/stdlib: angle brackets search the Fun library path (e.g.,
FUN_LIB_DIR).#include <utils/math.fun> - Local file: quoted, relative to the current working directory or file.
#include "./utils/file.fun" - Absolute path is supported.
Namespaced includes:
- Use
asto bind a module into a namespace alias.
#include <utils/math.fun> as m
#include "examples/namespaced_mod.fun" as mod
print(m.add(2, 3))
g = mod.Greeter("Hi")
g.say("World")
Aliased access uses alias.symbol or alias.ClassName.
Global/private at file scope control symbol exports from a module.
10) Collections
Arrays:
- Literals with
[ ... ]; may be heterogeneous unlessarray<T>is declared. - Helpers:
push,join,map,filter,reduce, iteration viafor x in arr.
Maps:
- Literal:
{ key: value, ... } - Indexing:
m["a"], assignmentm["c"] = 5 - Introspection:
has(m, key),keys(m),values(m) - Iterate keys/values using arrays returned by
keys/values.
11) Concurrency (Threads)
thread_spawn(fn, args)startsfnin a new thread.argsmay be a single value or an array for multiple arguments.thread_join(id)waits for the thread and returns its result.sleep(ms)suspends current thread.
Example:
fun square(n)
sleep(100)
return n * n
ids = []
for x in [1, 2, 3]
push(ids, thread_spawn(square, x))
results = []
for id in ids
push(results, thread_join(id))
print(results)
12) System, Files, Environment, and Networking
Processes:
- Blocking:
exec(cmd) -> string(stdout),system(cmd) -> number(exit code) - Non-blocking:
nexec,nspawn,nsystem, withwait(pid),read(pid),kill(pid)helpers
Environment and CLI:
env(NAME) -> stringto read env variables (seeos_env.fun)argv() -> array<string>from<cli.fun>; alsoFUN_ARGC/FUN_ARGSenvironment interoperability in examples
Files:
- Basic file I/O helpers exist in the stdlib; see
file_io.fun,file_print_for_file_line_by_line.fun
Time:
- Date/time and timers (see
datetime_basic.fun,datetime_extended.fun,datetime_timer.fun)
Random:
randomhelpers (seerandom_demo.fun,random_number_example.fun)
Regex:
- Regex operations via stdlib (see
regex_demo.fun,regex_procedural.fun)
Networking:
- TCP client helpers:
tcp_connect(host, port) -> fd,sock_send(fd, data),sock_recv(fd, nbytes),sock_close(fd) - Unix domain sockets (see
unix_socket_echo.fun)
Serial:
- Serial port helpers (see
serial_demo.fun)
Progress/UI:
- Helper functions to render CLI progress (see
progress.fun,progress_inline.fun)
Note: function names may live in stdlib modules; import accordingly (system-dependent availability).
13) Error Handling and Type Safety
- No implicit type coercion between numeric types; explicit casts or constructors are required.
- Overflow/underflow on fixed-width types is an error.
- Accessing undefined variables or re-defining globals is a compile-time error.
- Shadowing internal/runtime functions is forbidden.
- Exception syntax
try/catch/finallyis standardized in v0.3; throwing and catching at runtime may be partially implemented depending on the feature (see examples likebyte_overflow_try_catch.funand notes within).
14) Examples (from the repository)
Hello:
print("Hello, World!")
Namespaced includes:
#include <utils/math.fun> as m
print(m.add(2, 3))
Classes:
class Counter
value = 0
fun inc(this)
this.value = this.value + 1
return this.value
c = Counter()
print(c.inc())
Inheritance:
class Parent(number start)
value = 0
fun _construct(this, s)
this.value = s
class Child(number start) extends Parent
bonus = 5
fun _construct(this, s)
this.value = this.value + this.bonus
Threads:
tid = thread_spawn(add3, [10, 20, 30])
print(thread_join(tid)) // 60
TCP GET:
fd = tcp_connect("example.org", 80)
req = "GET / HTTP/1.0\r\nHost: example.org\r\n\r\n"
sent = sock_send(fd, req)
print(sock_recv(fd, 8192))
sock_close(fd)
15) Versioning and Compatibility
- v0.3 keeps v0.2 syntax intact and adds new features. Where runtime support is evolving (exceptions, some stdlib facets), the syntax is stable and forward-compatible.
- Examples are authoritative for idioms and available helpers; consult
examples/andlib/modules.
16) Appendix: Notation and Conventions
- Use backticks for code identifiers in prose (
fun,class,extends, etc.). - All code blocks are in
funpseudolanguage. - Indentation is always 2 spaces; tabs will cause errors.
Changelog (from v0.2 to v0.3)
- Added:
class, methods with explicitthis, default and custom constructors via_construct. - Added: inheritance with
extends. - Added: private members by leading underscore naming convention.
- Added: dot-call sugar
obj.method(a, b)≡method(obj, a, b). - Added: namespaced includes:
#include <path> as alias,#include "path" as alias. - Added:
maptype with literals{ key: value }and helpers. - Added: loop control
break,continue. - Added: threads (
thread_spawn,thread_join), sleep. - Added: socket helpers (TCP/Unix), serial devices, CLI argv, env helpers, timers.
- Added: bitwise helper functions:
band,bor,bxor,bnot,shl. - Added: exception syntax
try/catch/finally(runtime handling is evolving).
How to use this file
- Save this content as
./spec/v0.3.mdin the repository. - Keep
examples/in sync with this spec. When adding a new feature, provide an example and update the spec accordingly.