plum

#treesitter#compiler#wasm

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

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


98bcd99Peter John 2026-09-04T20:50:43+05:30
chore: fix stale Bool/Str doc comments and test fixture breakage
examples/io.plum CHANGED
@@ -1,9 +1,12 @@
1
1
  import std/Str
2
2
  import std/Bool
3
3
 
4
- # `printLn` mirrors `libs/std/os.plum`'s declaration; redeclared locally (rather
4
+ # `printLn` mirrors `libs/std/os.plum`'s declaration; redeclared locally
5
- # than `import std/os`) so this stays a self-contained example for the
5
+ # (rather than `import std/os`) so this stays the SMALLEST possible example
6
+ # — `import std/os` pulls in every other filesystem extern os.plum declares
6
- # single-file test harnesses in `plum-checker`/`plum-wasm-codegen`.
7
+ # too, which the Rust-level `ioExampleCompilesAndRunsCorrectly` test (which
8
+ # actually RUNS this module under wasmtime, providing real host imports)
9
+ # would then all need stubs for.
7
10
  extern fun printLn(s: Str)
8
11
 
9
12
  fun main() =
plum-cli/tests/compile_tests.rs CHANGED
@@ -11,13 +11,24 @@ fn plumBin() -> std::path::PathBuf {
11
11
  path
12
12
  }
13
13
 
14
+ /// A fresh subdirectory under the system temp dir, named for this test run
15
+ /// (so parallel test binaries don't collide) — these tests write their own
16
+ /// minimal fixture files here rather than depending on anything checked into
17
+ /// the repo, so they stay self-contained regardless of what `test/` holds.
18
+ fn freshTempDir(name: &str) -> std::path::PathBuf {
19
+ let dir = std::env::temp_dir().join(format!("plum_{}_{}", name, std::process::id()));
20
+ std::fs::create_dir_all(&dir).expect("failed to create temp dir");
21
+ dir
22
+ }
23
+
14
24
  #[test]
15
25
  fn compileSimpleAddProducesWasm() {
26
+ let dir = freshTempDir("simple_add");
16
- let src_path = concat!(env!("CARGO_MANIFEST_DIR"), "/../test/simple_add.plum");
27
+ let src_path = dir.join("simple_add.plum");
28
+ std::fs::write(&src_path, "fun add(a: Int, b: Int) -> Int =\n a + b\n").unwrap();
17
- let out_path = std::env::temp_dir().join(format!("plum_test_{}.wasm", std::process::id()));
29
+ let out_path = dir.join("simple_add.wasm");
18
- let out_path_str = out_path.to_str().unwrap();
19
30
  let status = Command::new(plumBin())
20
- .args(["compile", src_path, "-o", out_path_str])
31
+ .args(["compile", src_path.to_str().unwrap(), "-o", out_path.to_str().unwrap()])
21
32
  .status()
22
33
  .expect("failed to run plum compile");
23
34
  assert!(status.success(), "plum compile exited with: {}", status);
@@ -27,12 +38,20 @@ fn compileSimpleAddProducesWasm() {
27
38
 
28
39
  #[test]
29
40
  fn compileWithImportResolvesViaLibPath() {
30
- let src_path = concat!(env!("CARGO_MANIFEST_DIR"), "/../test/import_fixtures/main.plum");
41
+ let dir = freshTempDir("import_fixtures");
31
- let lib_path = concat!(env!("CARGO_MANIFEST_DIR"), "/../test/import_fixtures");
42
+ std::fs::write(dir.join("helper.plum"), "fun helperValue() -> Int =\n 42\n").unwrap();
32
- let out_path = std::env::temp_dir().join(format!("plum_test_import_{}.wasm", std::process::id()));
43
+ let src_path = dir.join("main.plum");
44
+ std::fs::write(&src_path, "module fixtures\n\nimport helper\n\nfun main() -> Int =\n helperValue()\n").unwrap();
33
- let out_path_str = out_path.to_str().unwrap();
45
+ let out_path = dir.join("main.wasm");
34
46
  let status = Command::new(plumBin())
47
+ .args([
48
+ "compile",
49
+ src_path.to_str().unwrap(),
35
- .args(["compile", src_path, "--lib-path", lib_path, "-o", out_path_str])
50
+ "--lib-path",
51
+ dir.to_str().unwrap(),
52
+ "-o",
53
+ out_path.to_str().unwrap(),
54
+ ])
36
55
  .status()
37
56
  .expect("failed to run plum compile");
38
57
  assert!(status.success(), "plum compile exited with: {}", status);
plum-wasm-codegen/src/lib.rs CHANGED
@@ -614,14 +614,16 @@ pub struct GcTypeRegistry {
614
614
  /// Concrete class/struct name -> its one wasm-gc `struct` type index.
615
615
  pub class_type_idx: HashMap<String, u32>,
616
616
  /// Enum name -> its abstract supertype `struct` type index (every variant
617
- /// subtypes this) — includes the built-in `Bool` enum, which has no
617
+ /// subtypes this) — including `Bool` (`enum Bool = | True | False` in
618
- /// `ast::Item::Enum` of its own (`buildGlobalTables` hardcodes its
619
- /// `True`/`False` variants directly into `EnumVariants`).
618
+ /// `libs/std/Bool.plum`), an ordinary enum like any other, present only
619
+ /// if actually imported.
620
620
  pub enum_super_type_idx: HashMap<String, u32>,
621
621
  /// Variant name (flat namespace, matching `EnumVariants`) -> its concrete
622
622
  /// subtype `struct` type index.
623
623
  pub variant_type_idx: HashMap<String, u32>,
624
- /// The single shared `array<i8>` type index every `Str` value uses.
624
+ /// The single shared `array<i8>` type index `[]Byte`/`Buffer`'s own
625
+ /// `data` field use — NOT `Str`'s own representation (`Str` is an
626
+ /// ordinary class, `data: Buffer`; see `libs/std/Str.plum`'s header).
625
627
  pub byte_array_type_idx: u32,
626
628
  /// The single shared closure-value struct type index — `{table_idx: i32, env:
627
629
  /// anyref}` — every closure (and zero-capture "trampoline") uses regardless of
@@ -694,8 +696,9 @@ fn plumTypeToGcValtype(t: &PlumType, registry: &GcTypeRegistry) -> ValType {
694
696
  }
695
697
  }
696
698
 
697
- /// Builds the wasm-gc type registry for every concrete class/enum in `source`, plus
699
+ /// Builds the wasm-gc type registry for every concrete class/enum actually declared
700
+ /// in `source` (`Bool`/`Str`/etc included, but only if imported — no builtin is
698
- /// the built-in `Bool` enum and the shared `Str` array type, and declares them all as
701
+ /// hardcoded here), plus the shared raw byte-array type, and declares them all as
699
702
  /// ONE `rec` group via `module.addGcTypes` — a single group sidesteps every ordering
700
703
  /// question about mutual/self-references (a class field of another class's type, an
701
704
  /// enum variant field referencing its own enum, `Node.next: Option[Node]`, etc.),