1
0
Fork 0
forked from fun/fun
fun/spec/v0.3.md

13 KiB
Raw Permalink Blame History

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.

Whats new in v0.3 (high level):

  • Classes and objects with methods, constructors, and inheritance (extends).
  • Dot-call sugar for method calls, and explicit this in method definitions.
  • Namespaced #include ... as alias for module imports.
  • Maps (dictionaries) with literals and helpers.
  • Control-flow additions: break and continue.
  • Threads: thread_spawn, thread_join and sleep.
  • 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: /* ... */
  • 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, continue
  • fun, return
  • class, extends
  • global, private
  • true, false
  • try, catch, finally

Notes:

  • #include is a directive, not an expression; as is 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.
  • string
  • boolean: true / false (in conditionals 0 and 1 are 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:

  • array and typed arrays: array<T>
  • map<K, V> (dictionary / associative array)
  • object (instances of class)

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

  • global variables are visible program-wide.
  • private variables 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) -> string
  • to_string(x) and numeric casts (see examples for cast_demo.fun and conversions_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) then m[k]
for i in range(0, 5)
  print(i)

for x in [1, 2, 3]
  print(x)

Loop control:

  • break exits the innermost loop.
  • continue skips 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 as to 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 unless array<T> is declared.
  • Helpers: push, join, map, filter, reduce, iteration via for x in arr.

Maps:

  • Literal: { key: value, ... }
  • Indexing: m["a"], assignment m["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) starts fn in a new thread. args may 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, with wait(pid), read(pid), kill(pid) helpers

Environment and CLI:

  • env(NAME) -> string to read env variables (see os_env.fun)
  • argv() -> array<string> from <cli.fun>; also FUN_ARGC/FUN_ARGS environment 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:

  • random helpers (see random_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/finally is standardized in v0.3; throwing and catching at runtime may be partially implemented depending on the feature (see examples like byte_overflow_try_catch.fun and 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/ and lib/ modules.

16) Appendix: Notation and Conventions

  • Use backticks for code identifiers in prose (fun, class, extends, etc.).
  • All code blocks are in fun pseudolanguage.
  • Indentation is always 2 spaces; tabs will cause errors.

Changelog (from v0.2 to v0.3)

  • Added: class, methods with explicit this, 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: map type 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.md in the repository.
  • Keep examples/ in sync with this spec. When adding a new feature, provide an example and update the spec accordingly.