plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


plum-std/Array.plum
ea9b8c1 1
module std
73b5e55 2
import std/Bool
ca5fd6f 3
import std/Number
ea9b8c1 4
ea9b8c1 5
# A fixed-length, O(1)-indexable array of `T`, backed directly by a wasm-gc
ea9b8c1 6
# `array<anyref>` — every `Array[T]` specialization (`Array$Int`, `Array$Str`,
ea9b8c1 7
# ...) shares the SAME underlying wasm array type (see
ea9b8c1 8
# `plum-wasm-codegen::GcTypeRegistry::array_type_idx`), exactly like `[]Byte`
ea9b8c1 9
# reuses `Str`'s own array type. `init`/`get`/`set`/`length` are compiler
ea9b8c1 10
# intrinsics (see `compileIntrinsicFnBody`) — there's no way to express raw
ea9b8c1 11
# array allocation/indexing in Plum source itself.
ea9b8c1 12
#
ea9b8c1 13
# LIMITATION: `T` must be a reference type (a `type`/`enum` value, `Str`,
ea9b8c1 14
# `List`, etc.) — every element is stored as a boxed `anyref` and `get`
ea9b8c1 15
# narrows it back to `T` via `ref.cast`. A primitive `T` (`Int`/`Float`/`Bool`/
ea9b8c1 16
# `Byte`) is NOT supported (no boxing/unboxing exists yet) and will not
ea9b8c1 17
# codegen correctly. Nothing in `libs/std` instantiates `Array` with a
ea9b8c1 18
# primitive `T` today — the only user is `Map[K, V]`'s bucket array,
ea9b8c1 19
# `Array[List[Pair[K, V]]]`.
ea9b8c1 20
#
ea9b8c1 21
# `init()` is deliberately zero-arg (no `Array[T](n)` constructor exists) —
ea9b8c1 22
# `class_call`'s grammar (`Type[Generics](...)`) only ever accepts `name:
ea9b8c1 23
# value` field arguments or an empty arg list, never bare positional ones
ea9b8c1 24
# (see `tooling/tree-sitter-plum/grammar.js`'s `class_argument_list`), and
ea9b8c1 25
# `Array` has no real fields for a keyword arg to bind to. Building a
ea9b8c1 26
# specific-length array is `push`ing onto an empty one `n` times instead
ea9b8c1 27
# (`Map`'s bucket array does exactly this at construction) — `push` itself
ea9b8c1 28
# has no in-place "grow" to fall back on either (a wasm-gc `array` is a
ea9b8c1 29
# fixed-length allocation once made), so it allocates a new, one-longer array
ea9b8c1 30
# and copies, same amortized-growth idea as `Buffer`'s own `write`.
ea9b8c1 31
#
ea9b8c1 32
# New elements start out `None`-shaped — really a null `anyref` under the
ea9b8c1 33
# hood — so `get` on an index that was never `set` traps rather than
ea9b8c1 34
# returning some default `T` value (there is no way to conjure a default `T`
ea9b8c1 35
# generically).
5f2f962 36
enum Array[T] =
5f2f962 37
  | Array
5f2f962 38
ea9b8c1 39
  # A new, empty array.
ea9b8c1 40
  fun init() -> Array[T] =
ea9b8c1 41
    todo
ea9b8c1 42
ea9b8c1 43
  # The element at index `i`. Traps if `i` is out of range or was never `set`.
ea9b8c1 44
  fun get(self, i: Int) -> T =
ea9b8c1 45
    todo
ea9b8c1 46
ea9b8c1 47
  # Overwrites the element at index `i` with `v`. Traps if `i` is out of range.
ea9b8c1 48
  fun set(self, i: Int, v: T) -> Unit =
ea9b8c1 49
    todo
ea9b8c1 50
ea9b8c1 51
  # Number of slots in the array.
ea9b8c1 52
  fun length(self) -> Int =
ea9b8c1 53
    todo
ea9b8c1 54
ea9b8c1 55
  # Returns a NEW array, one longer than `self`, with `v` appended at the end
ea9b8c1 56
  # — `self` itself is left untouched (this allocates and copies, it does not
ea9b8c1 57
  # mutate in place). Callers grow in a loop by reassigning: `arr =
ea9b8c1 58
  # arr.push(v)`.
ea9b8c1 59
  fun push(self, v: T) -> Array[T] =
ea9b8c1 60
    todo