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)