plum

#treesitter#compiler#wasm

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

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


b7071c9Peter John 2026-09-04T19:42:10+05:30
refactor(libs/std): rename files to match their primary class name
examples/closures.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  fun each(cb: fn(Int) -> Int) -> Int =
2
4
  cb(5)
3
5
 
examples/control_flow.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  fun loopSum(limit: Int) -> Int =
2
4
  total := 0
3
5
  for i := range limit
examples/functions.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  fun addInts(a: Int, b: Int) -> Int =
2
4
  a + b
3
5
 
examples/io.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  # `printLn` mirrors `libs/std/os.plum`'s declaration; redeclared locally (rather
2
4
  # than `import std/os`) so this stays a self-contained example for the
3
5
  # single-file test harnesses in `plum-checker`/`plum-wasm-codegen`.
examples/match.plum CHANGED
@@ -1,4 +1,4 @@
1
- import std/option
1
+ import std/Option
2
2
 
3
3
  enum Color =
4
4
  | Red
examples/methods.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  type Cat =
2
4
  name: Str
3
5
  age: Int
examples/testing.plum CHANGED
@@ -1,3 +1,5 @@
1
+ import std/Str
2
+
1
3
  fun add(a: Int, b: Int) -> Int =
2
4
  a + b
3
5
 
examples/types.plum CHANGED
@@ -1,4 +1,4 @@
1
- import std/option
1
+ import std/Option
2
2
 
3
3
  type Point =
4
4
  x: Int
libs/std/{array.plum → Array.plum} RENAMED
File without changes
libs/std/{bool.plum → Bool.plum} RENAMED
@@ -1,5 +1,6 @@
1
1
  module std
2
- import std/result
2
+ import std/Result
3
+ import std/Str
3
4
 
4
5
  enum Bool =
5
6
  | True
libs/std/{buffer.plum → Buffer.plum} RENAMED
@@ -1,6 +1,6 @@
1
1
  module std
2
- import std/bytes
2
+ import std/ByteSlice
3
- import std/str
3
+ import std/Str
4
4
 
5
5
  # A Buffer is a growable, mutable sequence of bytes for efficiently building
6
6
  # up a `Str` piece by piece — modeled on Go's `bytes.Buffer`. Backed by a
libs/std/{byte.plum → Byte.plum} RENAMED
@@ -1,5 +1,5 @@
1
1
  module std
2
- import std/int
2
+ import std/Int
3
3
 
4
4
  # Byte is an unsigned 8-bit value (0-255) — Plum's counterpart to Go's
5
5
  # `byte`/`uint8`. `Byte(x)` converts an `Int` (wrapping, not trapping, if `x`
libs/std/{bytes.plum → ByteSlice.plum} RENAMED
@@ -1,6 +1,6 @@
1
1
  module std
2
- import std/byte
2
+ import std/Byte
3
- import std/str
3
+ import std/Str
4
4
 
5
5
  # ByteSlice is `[]Byte` — Plum's counterpart to Go's byte slice: a
6
6
  # fixed-length, mutable sequence of raw bytes backed directly by a wasm-gc
libs/std/{err.plum → Err.plum} RENAMED
File without changes
libs/std/{float.plum → Float.plum} RENAMED
@@ -1,7 +1,7 @@
1
1
  module std
2
- import std/int
2
+ import std/Int
3
- import std/result
3
+ import std/Result
4
- import std/str
4
+ import std/Str
5
5
 
6
6
  E = 2.718281828459045f # Euler's number, the base of natural logarithms, e, https://oeis.org/A001113
7
7
  LN10 = 2.302585092994046f # The natural logarithm of 10, https://oeis.org/A002392
libs/std/{int.plum → Int.plum} RENAMED
@@ -1,7 +1,7 @@
1
1
  module std
2
- import std/float
2
+ import std/Float
3
- import std/result
3
+ import std/Result
4
- import std/str
4
+ import std/Str
5
5
 
6
6
  MIN_VALUE = -0x8000_0000_0000_0000 # Lowest value of Int
7
7
  MAX_VALUE = 0x7FFF_FFFF_FFFF_FFFF # Highest value of Int
libs/std/{json.plum → Json.plum} RENAMED
@@ -1,14 +1,14 @@
1
1
  module std
2
2
 
3
- import std/option
3
+ import std/Option
4
- import std/result
4
+ import std/Result
5
- import std/list
5
+ import std/List
6
- import std/map
6
+ import std/Map
7
- import std/int
7
+ import std/Int
8
- import std/float
8
+ import std/Float
9
- import std/str
9
+ import std/Str
10
- import std/buffer
10
+ import std/Buffer
11
- import std/err
11
+ import std/Err
12
12
 
13
13
  # A parsed JSON value. Numbers are always stored as `Float` (JSON doesn't
14
14
  # distinguish integers from floats the way Plum does), and `JsonList`/
libs/std/{list.plum → List.plum} RENAMED
@@ -1,8 +1,8 @@
1
1
  module std
2
2
 
3
- import std/option
3
+ import std/Option
4
- import std/buffer
4
+ import std/Buffer
5
- import std/int
5
+ import std/Int
6
6
 
7
7
  # A node stores the data in a list and contains pointers to the previous and next sibling nodes
8
8
  type Node[T] =
libs/std/{map.plum → Map.plum} RENAMED
@@ -1,7 +1,7 @@
1
1
  module std
2
- import std/list
2
+ import std/List
3
- import std/option
3
+ import std/Option
4
- import std/array
4
+ import std/Array
5
5
 
6
6
  # Any type usable as a `Map` key needs a `hash`, so keys landing in different
7
7
  # buckets (`hash(k) % BUCKET_COUNT`) can be told apart in O(1) without a full
libs/std/{option.plum → Option.plum} RENAMED
@@ -1,6 +1,7 @@
1
1
  module std
2
2
 
3
- import std/result
3
+ import std/Result
4
+ import std/Str
4
5
 
5
6
  # Option[T] represents a value that may or may not be present — Plum's
6
7
  # counterpart to Rust's `Option`/Go's "zero value or ok bool" idiom.
libs/std/{result.plum → Result.plum} RENAMED
@@ -1,5 +1,6 @@
1
1
  module std
2
- import std/option
2
+ import std/Option
3
+ import std/Str
3
4
 
4
5
  # Result[T, E] represents either success (`Ok`, carrying a `T`) or failure
5
6
  # (`Err`, carrying an `E`) — used throughout std for fallible operations
libs/std/{str.plum → Str.plum} RENAMED
@@ -1,7 +1,7 @@
1
1
  module std
2
2
 
3
- import std/list
3
+ import std/List
4
- import std/buffer
4
+ import std/Buffer
5
5
 
6
6
  # Any type that can be converted to a str needs to implement this trait
7
7
  trait ToStr =
libs/std/{time.plum → Time.plum} RENAMED
@@ -1,6 +1,6 @@
1
1
  module std
2
- import std/int
2
+ import std/Int
3
- import std/str
3
+ import std/Str
4
4
 
5
5
  # A raw, host-provided wall-clock reading: milliseconds since the Unix epoch.
6
6
  extern fun rawNowMillis() -> Int
libs/std/{uuid.plum → Uuid.plum} RENAMED
@@ -1,7 +1,7 @@
1
1
  module std
2
- import std/int
2
+ import std/Int
3
- import std/result
3
+ import std/Result
4
- import std/str
4
+ import std/Str
5
5
 
6
6
  # A UUID, stored as its canonical 36-character
7
7
  # `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` text form.
libs/std/encoding/Base64.plum CHANGED
@@ -1,7 +1,7 @@
1
1
  module std
2
- import std/str
2
+ import std/Str
3
- import std/buffer
3
+ import std/Buffer
4
- import std/option
4
+ import std/Option
5
5
 
6
6
  # The Base64 package contains support for doing Base64 binary-to-text encodings.
7
7
  #
libs/std/http.plum CHANGED
@@ -1,12 +1,12 @@
1
1
  module std
2
2
 
3
- import std/buffer
3
+ import std/Buffer
4
- import std/json
4
+ import std/Json
5
- import std/list
5
+ import std/List
6
- import std/map
6
+ import std/Map
7
- import std/option
7
+ import std/Option
8
- import std/result
8
+ import std/Result
9
- import std/str
9
+ import std/Str
10
10
 
11
11
  # An HTTP response: status code, response headers, and the raw response
12
12
  # body as a `Str` (a byte array, so binary bodies round-trip intact).
libs/std/os.plum CHANGED
@@ -1,8 +1,8 @@
1
1
  module std
2
- import std/list
2
+ import std/List
3
- import std/result
3
+ import std/Result
4
- import std/str
4
+ import std/Str
5
- import std/uuid
5
+ import std/Uuid
6
6
 
7
7
  # NOTE: the original file modeled `stdin`/`stdout`/`stderr` as bare top-level
8
8
  # variable bindings and a `File(...)` constructor, but this language has no
libs/std/testing.plum CHANGED
@@ -1,8 +1,8 @@
1
1
  module std
2
2
 
3
- import std/option
3
+ import std/Option
4
- import std/result
4
+ import std/Result
5
- import std/list
5
+ import std/List
6
6
 
7
7
  # Small jest/rspec-style assertion helpers for use inside `test` blocks, e.g.
8
8
  #
plum-core/src/loader.rs CHANGED
@@ -27,27 +27,6 @@ pub fn loadAndMerge(entry: &Path, lib_path: &Path) -> Result<Source, String> {
27
27
  loadImport(import, lib_path, &mut visited, &mut items, &mut names)?;
28
28
  }
29
29
 
30
- // `Str` is an ordinary class (`type Str(...) = data: Buffer ...` in
31
- // `str.plum`, see its header comment) — unlike a true compiler primitive
32
- // (`Int`/`Bool`), its wasm-gc representation now depends on that real
33
- // declaration actually being present in the merged program. Loading it
34
- // implicitly here, exactly as if every file `import`ed it, keeps string
35
- // literals/`==`/`+`/`byteAt`/etc. usable with zero imports, matching how
36
- // they behaved before this was a real class (and how `Int`/`Bool` still
37
- // behave, being genuine primitives). `loadImport`'s own `visited` guard
38
- // makes this a no-op for a file that already imports `std/str` itself
39
- // (directly or transitively), so there's no duplicate-registration risk.
40
- //
41
- // Tolerates a `lib_path` that has no `std/str.plum` at all (e.g. a
42
- // minimal, deliberately stdlib-free fixture directory used to test
43
- // import resolution in isolation) — silently skipped rather than a hard
44
- // error, since a program compiled against such a `lib_path` was never
45
- // going to be able to use `Str` anyway; it'll get the same "Str must be
46
- // registered" error at the point it actually tries to.
47
- if lib_path.join("std/str.plum").exists() {
48
- loadImport(&Import { path: "std/str".to_string() }, lib_path, &mut visited, &mut items, &mut names)?;
49
- }
50
-
51
30
  Ok(Source {
52
31
  module: entry_source.module,
53
32
  imports: entry_source.imports,