API Reference
implicit scope
Symbols in @std/prelude are available in every Rasmalai
source file out-of-the-box without an explicit import. Explicit imports are supported for
disambiguation.
Untyped escape hatch. Nothing on an `Any` is resolved statically, so cast before use with `v as Int` or `v as String`.
Dense growable sequence with `Int` indexes. Methods, all compiler builtins needing no import: `length(): Int`, `len(): Int`, `isEmpty(): Bool`, `push(item)`, `pop()`, `map(closure)`, `filter(closure)`. `length` and `len` also read as properties. `map` builds a new array from the closure's return value; `filter` keeps the elements the closure accepts and keeps their original type. `pop()` takes the last element and gives `null` on an empty array. Reading an index past the end throws `index out of bounds`, so check the length first. Search and fold helpers (`find`, `findIndex`, `some`, `every`, `reduce`, `join`, `reversed`) are extension methods below.
fn every(predicate: fn(T): Bool): BoolWhether every element satisfies `predicate`.
predicate — called once per element, in index order.
returns — false on the first rejection, true for an empty array.
print([4, 9, 16].every((x: Int): Bool => x > 0));fn find(predicate: fn(T): Bool): T?First element satisfying `predicate`.
predicate — called once per element, in index order.
returns — the first match, or `null` when the array is empty or nothing matches.
let xs = [4, 9, 16];
print(xs.find((x: Int): Bool => x > 5) ?? -1);fn findIndex(predicate: fn(T): Bool): IntWhere the first matching element sits.
predicate — called once per element, in index order.
returns — the zero-based index of the first match, or -1 when the array is empty or nothing matches.
let xs = [4, 9, 16];
print(xs.findIndex((x: Int): Bool => x > 5));fn join(separator: String): StringRender every element and glue the pieces with `separator`.
separator — text between elements; `""` when omitted.
returns — the joined text, `""` for an empty array.
print([4, 9, 16].join(" | "));fn reduce(initial: U, reducer: fn(U, T): U): ULeft fold: thread `initial` through `reducer` over each element.
initial — value handed to the first `reducer` call.
reducer — called with the accumulator and the next element.
returns — the last accumulator, which is `initial` for an empty array.
print([4, 9, 16].reduce<Int>(0, (acc: Int, x: Int): Int => acc + x));fn reversed(): Array<T>Reverse this array into a copy.
returns — a new array holding the same elements back to front.
print([4, 9, 16].reversed().join(","));fn some(predicate: fn(T): Bool): BoolWhether any element satisfies `predicate`.
predicate — called once per element, in index order.
returns — true on the first match, false for an empty array.
print([4, 9, 16].some((x: Int): Bool => x == 9));Index-based iterator over an array. It holds the array and a cursor, walks the array in place, and yields `null` once the cursor passes the end. `for..in` accepts it directly.
init(arr: Array<T>)
fields
- arr: Array<T>
- i: Int
fn next(): T?Take the next element and step the cursor on.
returns — the element at the cursor, or `null` past the end.
Foundation boolean type: `true` or `false`. Methods: `toString(): String`, which prints `true` or `false`.
Single scalar view into a `String`. The checker treats a `Char` as a `String`, and `charCodeAt` is how you read the scalar value.
Calendar view over the wall clock. Catalog stub: `@std/time` owns the clocks, and none of them report calendar dates.
Error value. Catalog stub: `throw` raises a `String` message and `catch (e)` binds it, so an `Error` carries nothing on its own.
Relaxed float type. Produced by `Float.asFast()` and read back with `asStrict()`. It mixes with `Float` only after an explicit conversion, and comparing one with the other needs `82.5.asFast()`-style literals.
Foundation float type: an IEEE-754 double. Methods: `toString(): String`, `toBits(): Int`, `asFast(): FastFloat`, `asStrict(): Float`. Statics: `Float.nan()`, `Float.isNaN(x)`, `Float.fma(a, b, c)`, `Float.fromBits(bits)`. A `Float` and a `FastFloat` never mix in one expression; the mix is `E305`, so name the conversion you mean.
Generational reference for cyclic edges. `GenRef.of(x)` takes a reference without raising the owner's retain count, and `.get()` gives `null` once the owner is gone, so a back edge never keeps a graph alive. ARC owns, `GenRef` points back; use `#[Allow(CyclicReference)]` on a field for a strong cycle you mean to break yourself.
Foundation integer type: a signed 64-bit whole number. Methods: `toString(): String`. Convert a float with `Int(x)`, which truncates toward zero, and render a number with `x.toString()`.
Insertion-ordered key-value table. Catalog stub: `Map` and its methods live in `@std/collections`.
One-shot eventual value: `Pending` (0), `Fulfilled` (1), `Rejected` (2). Combinators attach continuations; `wait()` parks the OS thread until settlement. The first settlement wins and later calls are ignored. A rejection carries a `String` reason. Every combinator hands back a new promise and leaves this one as it is, so a chain of them settles independently at each link. Handlers added after settlement run at once on the calling thread.
init(state: Int, value: T, reason: String, syncId: Int)
fields
- _handlers: Array<fn(T): Void>
- _reason: String
- _rejectHandlers: Array<fn(String): Void>
- _state: Int
- _syncId: Int
- _value: T
fn all(promises: Array<Promise<T>>): Promise<Array<T>>Wait for every promise and fulfill with the payloads in input order, whatever order they settle in. The first rejection wins and rejects the result; later settlements are ignored. An empty array fulfills with `[]`.
promises — promises to wait on.
returns — a promise for the payloads, or the first rejection.
let ps: Array<Promise<Int>> = [Promise.resolve(1), Promise.resolve(2)];
let all: Result<Array<Int>, String> = Promise.all<Int>(ps).wait();
let got: Array<Int> = all.unwrap();
print(got.join(","));fn allRej(out: Promise<Array<U>>): fn(String): VoidBuild the rejection continuation `Promise.all` hands each input. Internal: one of these rejects `out` and settles the combinator.
out — promise the first rejection rejects.
returns — a continuation taking the reason.
fn allSettled(promises: Array<Promise<T>>): Promise<Array<PromiseResult<T>>>Wait for every promise and never reject. Each input turns into a `PromiseResult` in input order holding either the payload or the rejection message. An empty array fulfills with `[]`.
promises — promises to wait on.
returns — a promise for one settlement record per input.
let ps: Array<Promise<Int>> = [Promise.resolve(5), Promise.reject<Int>("bad")];
let all: Result<Array<PromiseResult<Int>>, String> = Promise.allSettled<Int>(ps).wait();
let got: Array<PromiseResult<Int>> = all.unwrap();
print(got[0].status);
print(got[1].reason);fn allSlot(slots: Array<U>, out: Promise<Array<U>>, counterId: Int, n: Int, idx: Int): fn(U): VoidBuild the fulfillment continuation `Promise.all` hands each input. Internal: one of these writes its slot, and the last one to finish fulfills `out` with the slots in input order.
slots — scratch array holding one payload per input.
out — promise the last input fulfills.
counterId — registry id of the remaining-count atomic.
n — how many inputs there are.
idx — this input's index.
returns — a continuation taking the payload.
fn any(promises: Array<Promise<T>>): Promise<T>Fulfill with the first payload to arrive. Only once every input has rejected does the result reject, and then with `"AggregateError: all promises rejected"`. An empty array rejects at once with `"AggregateError: no promises"`.
promises — promises to try.
returns — a promise for the first payload, or the aggregate rejection.
let mixed: Array<Promise<Int>> = [Promise.reject<Int>("no"), Promise.resolve(5)];
print(Promise.any<Int>(mixed).wait().unwrap());fn anyFwd(out: Promise<U>): fn(U): VoidBuild the fulfillment continuation `Promise.any` hands each input. Internal: one of these fulfills `out`, and only the first to arrive has any effect.
out — promise the winner fulfills.
returns — a continuation taking the payload.
fn anyRej(out: Promise<U>, counterId: Int): fn(String): VoidBuild the rejection continuation `Promise.any` hands each input. Internal: one of these decrements the count, and the one that finds nothing left rejects `out` with the aggregate message.
out — promise the aggregate rejection settles.
counterId — registry id of the remaining-count atomic.
returns — a continuation taking the reason.
fn attach(onF: fn(T): Void, onR: fn(String): Void): VoidRegister both continuations. A pending promise queues one pair per call; a settled promise runs the matching continuation at once on the calling thread and queues nothing. Only one of the two ever runs for a given promise.
onF — called with the payload on fulfillment.
onR — called with the message on rejection.
let wr = Promise.withResolvers<Int>();
wr.promise.attach((v: Int): Void => print("got", v), (e: String): Void => print("bad", e));
wr.resolve(7);fn catchReject(onRejected: fn(String): U): Promise<U>Chain a rejection handler. A fulfillment passes through with its payload untouched; a rejection runs the closure and the new promise fulfills with the closure's result, so the chain recovers instead of staying rejected.
onRejected — runs with the reason and produces the new payload.
returns — a promise that turns this rejection into a fulfillment.
let r: Result<Int, String> = Promise.reject<Int>("x").catchReject<Int>((e: String): Int => 99).wait();
print(r.unwrap());fn finallyDo(onFinally: fn(): Void): Promise<T>Chain a handler that runs on either outcome and leaves it alone. The closure runs before the new promise settles, so what it prints lands before the value read from `wait()`.
onFinally — runs once the promise settles, either way.
returns — a promise carrying the original outcome.
let r: Result<Int, String> = Promise.resolve(7).finallyDo(() => print("done")).wait();
print(r.unwrap());fn freshId(): IntTake the next id from the shared counter. Internal: every promise needs its own mutex and condvar id.
returns — a fresh registry id.
fn fulfill(val: T): VoidSettle as fulfilled with `val`. Ignored unless the promise is still pending, so the first settlement wins. Queued handlers run after the guard is released, never while holding it.
val — payload for the fulfillment.
fn race(promises: Array<Promise<T>>): Promise<T>Settle with whichever input settles first, fulfillment or rejection alike; the first settlement copies across and later ones are ignored. The losing inputs keep running, so avoid handing `race` work that must not continue. An empty array never settles, and `wait()` on the result gives back `Err` after its 5s timeout.
promises — promises to race.
returns — a promise carrying the first settlement.
let ps: Array<Promise<Int>> = [Promise.resolve(1), Promise.resolve(2)];
print(Promise.race<Int>(ps).wait().unwrap());fn raceFwd(out: Promise<U>): fn(U): VoidBuild the fulfillment continuation `Promise.race` hands each input. Internal: one of these fulfills `out`, and only the first to arrive has any effect.
out — promise the winner fulfills.
returns — a continuation taking the payload.
fn raceRej(out: Promise<U>): fn(String): VoidBuild the rejection continuation `Promise.race` hands each input. Internal: one of these rejects `out`, and only the first to arrive has any effect.
out — promise the first rejection rejects.
returns — a continuation taking the reason.
fn reject(reason: String): Promise<T>A promise that is already rejected.
reason — message the rejection carries.
returns — a rejected promise; `wait()` gives back `Result.Err` holding the same message.
fn rejectWith(reason: String): VoidSettle as rejected with `reason`. Ignored unless the promise is still pending, so the first settlement wins. Queued handlers run after the guard is released, never while holding it.
reason — message for the rejection.
fn resolve(val: T): Promise<T>A promise that is already fulfilled.
val — payload carried by the promise.
returns — a fulfilled promise; handlers attached later run at once.
fn settledRej(slots: Array<PromiseResult<U>>, out: Promise<Array<PromiseResult<U>>>, counterId: Int, n: Int, idx: Int): fn(String): VoidBuild the rejection continuation `Promise.allSettled` hands each input. Internal: one of these writes a `"rejected"` record and decrements the count, and the last one fulfills `out` with every record in input order.
slots — scratch array holding one record per input.
out — promise the last input fulfills.
counterId — registry id of the remaining-count atomic.
n — how many inputs there are.
idx — this input's index.
returns — a continuation taking the reason.
fn settledSlot(slots: Array<PromiseResult<U>>, out: Promise<Array<PromiseResult<U>>>, counterId: Int, n: Int, idx: Int, ok: Bool): fn(U): VoidBuild the fulfillment continuation `Promise.allSettled` hands each input. Internal: one of these writes a `"fulfilled"` record and decrements the count, and the last one fulfills `out` with every record in input order.
slots — scratch array holding one record per input.
out — promise the last input fulfills.
counterId — registry id of the remaining-count atomic.
n — how many inputs there are.
idx — this input's index.
ok — true for the fulfillment continuation.
returns — a continuation taking the payload.
fn then(onFulfilled: fn(T): U): Promise<U>Chain a fulfillment handler. A rejection skips the closure and reaches the new promise unchanged, so `catchReject` is what recovers from one. The closure's return value becomes the payload the new promise settles with.
onFulfilled — runs with the payload and produces the new payload.
returns — a promise for the closure's result.
let a: Result<Int, String> = Promise.resolve(20).then<Int>((v: Int): Int => v + 1).wait();
print(a.unwrap());
let b: Result<Int, String> = Promise.reject<Int>("bad").then<Int>((v: Int): Int => v + 1).wait();
print(b.isErr());fn wait(): Result<T, String>Park the calling OS thread until the promise settles, without spinning: it sleeps on a condvar in 1s slices and gives up after 5s. Fine in a plain function or a `Thread.spawn` body; inside an `async fn` it is a compile error, because parking an event-loop task deadlocks.
returns — `Ok(val)` on fulfillment and `Err(reason)` on rejection, and `Err` with a timeout message when nothing settles in 5s.
let r: Result<Int, String> = Promise.resolve(41).wait();
print(r.unwrap());fn waitAny(p: Promise<Any>): Result<Any, String>Park until `p` settles. This is the bridge `await` lowers to, so user code should reach for `await` or `wait()` instead.
p — promise to wait on.
returns — `Ok(val)` on fulfillment, `Err(reason)` on rejection.
fn withResolvers(): PromiseWithResolvers<T>A pending promise together with the handles that settle it. Use it when the value arrives from somewhere the promise cannot own, such as a worker thread or an OS callback.
returns — a pending promise wrapped with `resolve` and `reject`.
let wr = Promise.withResolvers<Int>();
wr.resolve(42);
let r: Result<Int, String> = wr.promise.wait();
print(r.unwrap());Settlement record for `Promise.allSettled`. One per input promise, in input order: `status` is `"fulfilled"` or `"rejected"`, `value` holds the payload of a fulfillment, and `reason` the message of a rejection.
init(status: String, value: T, reason: String)
fields
- reason: String
- status: String
- value: T
Manual settlement handles from `Promise.withResolvers`. It holds the pending promise plus the two calls that settle it, which is how a worker thread, an OS callback, or an I/O handler hands a value back into the promise chain.
init(promise: Promise<T>)
fields
- promise: Promise<T>
fn reject(reason: String): VoidReject the promise with `reason`. Ignored once the promise has settled; the first settlement wins.
reason — message carried by the rejection.
fn resolve(val: T): VoidFulfill the promise with `val`. Ignored once the promise has settled; the first settlement wins.
val — payload for the fulfillment.
Host metadata: `rnx` is ambient in every module with no import. `version` is the compiler version string, `args` holds the CLI arguments after the script path, `cwd()` reads the working directory, and `exit(code)` terminates immediately.
init()
fields
- args: Array<String>
- version: String
fn cwd(): StringRead the working directory of the process.
returns — the path the process was started in.
fn exit(code: Int)Stop the process now. Nothing after the call runs and the exit status is the code given.
code — exit status handed to the host.
Distinct-member collection. Catalog stub: `Set` and its methods live in `@std/collections`.
Canonical UTF-8 string type. Every index counts characters, not bytes, so a multi-byte character is one step like any other. Methods, all compiler builtins needing no import: `length(): Int`, `len(): Int`, `slice(start: Int, end: Int): String`, `indexOf(needle: String): Int`, `indexOf(needle: String, from: Int): Int`, `trim(): String`, `concat(other: String): String`, `charCodeAt(index: Int): Int`. `length` and `len` also read as properties. `slice` clamps both bounds to the length and gives `""` once the start reaches the end. Both `indexOf` forms give the index of the first match at or after their start, or -1 when there is none; an empty needle answers with the start it was given. `trim` strips leading and trailing whitespace. `charCodeAt` gives the Unicode code point of the character at that index, or -1 past the end. Search and transform helpers (`contains`, `startsWith`, `endsWith`, `split`, `replace`, `replaceAll`, `repeat`, `toUpperCase`, `toLowerCase`) are extension methods below.
fn contains(search: String): BoolWhether `search` occurs anywhere in this string.
search — text to look for; `""` is always contained.
returns — true on a hit, false otherwise.
print("rasmalai/compiler".contains("compiler"));fn endsWith(suffix: String): BoolWhether this string ends with `suffix`.
suffix — text to compare; `""` always matches.
returns — true on a match, false otherwise.
print("rasmalai".endsWith("ai"));fn repeat(count: Int): StringCopy this string back to back.
count — how many copies; `0` or less gives `""`.
returns — the repeated text.
print("ab".repeat(3));fn replace(target: String, replacement: String): StringSwap the first occurrence of `target` for `replacement`.
target — text to look for.
replacement — text to put in its place.
returns — a new string, or this one unchanged when `target` is absent.
print("rasmalai/compiler".replace("/", "-"));fn replaceAll(target: String, replacement: String): StringSwap every occurrence of `target` for `replacement`.
target — text to look for; `""` leaves the string unchanged.
replacement — text to put in place of each hit.
returns — a new string with every occurrence replaced.
print("a-b-c".replaceAll("-", "+"));fn split(delimiter: String): Array<String>Cut this string around every `delimiter`.
delimiter — text to cut on; `""` gives one element per character.
returns — the pieces in order, one element when there is no delimiter.
print("rasmalai/compiler".split("/").length());fn startsWith(prefix: String): BoolWhether this string begins with `prefix`.
prefix — text to compare; `""` always matches.
returns — true on a match, false otherwise.
print("rasmalai".startsWith("ras"));fn toLowerCase(): StringFold this string to lower case. Only ASCII `A` to `Z` change; every other character, accented Latin included, passes through untouched, so `"HÉLLO"` gives `"hÉllo"`.
returns — a new string with the ASCII letters lower-cased.
print("HeLLo".toLowerCase());fn toUpperCase(): StringFold this string to upper case. Only ASCII `a` to `z` change; every other character, accented Latin included, passes through untouched, so `"héllo"` gives `"HéLLO"`.
returns — a new string with the ASCII letters upper-cased.
print("hello".toUpperCase());Absence of a return value. `Void` marks a function that only has effects; `null` is the absent value itself, of type `Null`.
- Err(E)
- Ok(T)