plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
b7071c9
— Peter John
2026-09-04T19:42:10+05:30
refactor(libs/std): rename files to match their primary class name
- examples/closures.plum +2 -0
- examples/control_flow.plum +2 -0
- examples/functions.plum +2 -0
- examples/io.plum +2 -0
- examples/match.plum +1 -1
- examples/methods.plum +2 -0
- examples/testing.plum +2 -0
- examples/types.plum +1 -1
- libs/std/{array.plum → Array.plum} +0 -0
- libs/std/{bool.plum → Bool.plum} +2 -1
- libs/std/{buffer.plum → Buffer.plum} +2 -2
- libs/std/{byte.plum → Byte.plum} +1 -1
- libs/std/{bytes.plum → ByteSlice.plum} +2 -2
- libs/std/{err.plum → Err.plum} +0 -0
- libs/std/{float.plum → Float.plum} +3 -3
- libs/std/{int.plum → Int.plum} +3 -3
- libs/std/{json.plum → Json.plum} +9 -9
- libs/std/{list.plum → List.plum} +3 -3
- libs/std/{map.plum → Map.plum} +3 -3
- libs/std/{option.plum → Option.plum} +2 -1
- libs/std/{result.plum → Result.plum} +2 -1
- libs/std/{str.plum → Str.plum} +2 -2
- libs/std/{time.plum → Time.plum} +2 -2
- libs/std/{uuid.plum → Uuid.plum} +3 -3
- libs/std/encoding/Base64.plum +3 -3
- libs/std/http.plum +7 -7
- libs/std/os.plum +4 -4
- libs/std/testing.plum +3 -3
- plum-core/src/loader.rs +0 -21
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/
|
|
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/
|
|
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/
|
|
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/
|
|
2
|
+
import std/ByteSlice
|
|
3
|
-
import std/
|
|
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/
|
|
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/
|
|
2
|
+
import std/Byte
|
|
3
|
-
import std/
|
|
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/
|
|
2
|
+
import std/Int
|
|
3
|
-
import std/
|
|
3
|
+
import std/Result
|
|
4
|
-
import std/
|
|
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/
|
|
2
|
+
import std/Float
|
|
3
|
-
import std/
|
|
3
|
+
import std/Result
|
|
4
|
-
import std/
|
|
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/
|
|
3
|
+
import std/Option
|
|
4
|
-
import std/
|
|
4
|
+
import std/Result
|
|
5
|
-
import std/
|
|
5
|
+
import std/List
|
|
6
|
-
import std/
|
|
6
|
+
import std/Map
|
|
7
|
-
import std/
|
|
7
|
+
import std/Int
|
|
8
|
-
import std/
|
|
8
|
+
import std/Float
|
|
9
|
-
import std/
|
|
9
|
+
import std/Str
|
|
10
|
-
import std/
|
|
10
|
+
import std/Buffer
|
|
11
|
-
import std/
|
|
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/
|
|
3
|
+
import std/Option
|
|
4
|
-
import std/
|
|
4
|
+
import std/Buffer
|
|
5
|
-
import std/
|
|
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/
|
|
2
|
+
import std/List
|
|
3
|
-
import std/
|
|
3
|
+
import std/Option
|
|
4
|
-
import std/
|
|
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/
|
|
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/
|
|
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/
|
|
3
|
+
import std/List
|
|
4
|
-
import std/
|
|
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/
|
|
2
|
+
import std/Int
|
|
3
|
-
import std/
|
|
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/
|
|
2
|
+
import std/Int
|
|
3
|
-
import std/
|
|
3
|
+
import std/Result
|
|
4
|
-
import std/
|
|
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/
|
|
2
|
+
import std/Str
|
|
3
|
-
import std/
|
|
3
|
+
import std/Buffer
|
|
4
|
-
import std/
|
|
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/
|
|
3
|
+
import std/Buffer
|
|
4
|
-
import std/
|
|
4
|
+
import std/Json
|
|
5
|
-
import std/
|
|
5
|
+
import std/List
|
|
6
|
-
import std/
|
|
6
|
+
import std/Map
|
|
7
|
-
import std/
|
|
7
|
+
import std/Option
|
|
8
|
-
import std/
|
|
8
|
+
import std/Result
|
|
9
|
-
import std/
|
|
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/
|
|
2
|
+
import std/List
|
|
3
|
-
import std/
|
|
3
|
+
import std/Result
|
|
4
|
-
import std/
|
|
4
|
+
import std/Str
|
|
5
|
-
import std/
|
|
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/
|
|
3
|
+
import std/Option
|
|
4
|
-
import std/
|
|
4
|
+
import std/Result
|
|
5
|
-
import std/
|
|
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,
|