plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
plum-std/Array.plum
module std
import std/Bool
import std/Number
# A fixed-length, O(1)-indexable array of `T`, backed directly by a wasm-gc
# `array<anyref>` — every `Array[T]` specialization (`Array$Int`, `Array$Str`,
# ...) shares the SAME underlying wasm array type (see
# `plum-wasm-codegen::GcTypeRegistry::array_type_idx`), exactly like `[]Byte`
# reuses `Str`'s own array type. `init`/`get`/`set`/`length` are compiler
# intrinsics (see `compileIntrinsicFnBody`) — there's no way to express raw
# array allocation/indexing in Plum source itself.
#
# LIMITATION: `T` must be a reference type (a `type`/`enum` value, `Str`,
# `List`, etc.) — every element is stored as a boxed `anyref` and `get`
# narrows it back to `T` via `ref.cast`. A primitive `T` (`Int`/`Float`/`Bool`/
# `Byte`) is NOT supported (no boxing/unboxing exists yet) and will not
# codegen correctly. Nothing in `libs/std` instantiates `Array` with a
# primitive `T` today — the only user is `Map[K, V]`'s bucket array,
# `Array[List[Pair[K, V]]]`.
#
# `init()` is deliberately zero-arg (no `Array[T](n)` constructor exists) —
# `class_call`'s grammar (`Type[Generics](...)`) only ever accepts `name:
# value` field arguments or an empty arg list, never bare positional ones
# (see `tooling/tree-sitter-plum/grammar.js`'s `class_argument_list`), and
# `Array` has no real fields for a keyword arg to bind to. Building a
# specific-length array is `push`ing onto an empty one `n` times instead
# (`Map`'s bucket array does exactly this at construction) — `push` itself
# has no in-place "grow" to fall back on either (a wasm-gc `array` is a
# fixed-length allocation once made), so it allocates a new, one-longer array
# and copies, same amortized-growth idea as `Buffer`'s own `write`.
#
# New elements start out `None`-shaped — really a null `anyref` under the
# hood — so `get` on an index that was never `set` traps rather than
# returning some default `T` value (there is no way to conjure a default `T`
# generically).
enum Array[T] =
| Array
# A new, empty array.
fun init() -> Array[T] =
todo
# The element at index `i`. Traps if `i` is out of range or was never `set`.
fun get(self, i: Int) -> T =
todo
# Overwrites the element at index `i` with `v`. Traps if `i` is out of range.
fun set(self, i: Int, v: T) -> Unit =
todo
# Number of slots in the array.
fun length(self) -> Int =
todo
# Returns a NEW array, one longer than `self`, with `v` appended at the end
# — `self` itself is left untouched (this allocates and copies, it does not
# mutate in place). Callers grow in a loop by reassigning: `arr =
# arr.push(v)`.
fun push(self, v: T) -> Array[T] =
todo