plum

#treesitter#compiler#wasm

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

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


5bb1d4c — Peter John 2026-11-02T19:37:19+05:30
T3: formatter and highlighting
plum-core/tests/formatter_test.rs CHANGED
@@ -322,3 +322,31 @@ fn formatAnnotatedDeclaration() {
322
322
  assert!(first.contains(" o: Int? := null\n"), "got: {first:?}");
323
323
  assert_eq!(first, formatSource(&first).expect("second"));
324
324
  }
325
+
326
+ #[test]
327
+ fn format_trait_idempotent() {
328
+ let input = "\
329
+ trait Ent(pos: Int,z: Int) =
330
+ fun update(self,dt: Float)
331
+ # moves it
332
+ fun moveBy(self,d: Int) =
333
+ self.pos = self.pos + d
334
+ self.z = 0
335
+ fun draw(self) -> Int = self.z
336
+
337
+ record House(Ent,k: Int) =
338
+ fun update(self,dt: Float) = 1
339
+ ";
340
+ let once = formatSource(input).expect("first pass");
341
+ assert!(once.contains("trait Ent(pos: Int, z: Int) ="), "got: {once}");
342
+ assert!(once.contains(" fun update(self, dt: Float)\n"), "got: {once}");
343
+ assert!(once.contains(" # moves it\n"), "got: {once}");
344
+ let twice = formatSource(&once).expect("second pass");
345
+ assert_eq!(once, twice, "not idempotent:\n{once}");
346
+ }
347
+
348
+ #[test]
349
+ fn format_record_embeds() {
350
+ let out = formatSource("record House(Ent,Cl,k:Int)\n").expect("format");
351
+ assert!(out.contains("record House(Ent, Cl, k: Int)"), "got: {out}");
352
+ }
plum-tooling/tree-sitter-plum/queries/plum/format.scm CHANGED
@@ -18,6 +18,9 @@
18
18
  (source
19
19
  (record) @allow_blank_line_before)
20
20
 
21
+ (source
22
+ (trait) @allow_blank_line_before)
23
+
21
24
  (source
22
25
  (primitive) @allow_blank_line_before)
23
26
 
@@ -103,6 +106,8 @@
103
106
 
104
107
  (record "record" @append_space)
105
108
 
109
+ (trait "trait" @append_space)
110
+
106
111
  (primitive "primitive" @append_space)
107
112
 
108
113
  (primitive
@@ -296,6 +301,21 @@
296
301
  (_) @append_indent_end
297
302
  .)
298
303
 
304
+ ; `trait` bodies: methods indent under the `=`; the body is optional.
305
+ (trait
306
+ (fn) @prepend_hardline)
307
+
308
+ (trait
309
+ (fn) @allow_blank_line_before)
310
+
311
+ (trait
312
+ "=" @append_indent_start)
313
+
314
+ (trait
315
+ "="
316
+ (_) @append_indent_end
317
+ .)
318
+
299
319
  ; `enum_field` (a variant like `| Circle(r: Float)`) is ALIASED to the visible
300
320
  ; node kind "field"; only it has a literal "|" — safe to target unscoped by
301
321
  ; parent.
plum-tooling/tree-sitter-plum/queries/plum/highlights.scm CHANGED
@@ -120,6 +120,7 @@
120
120
  "primitive"
121
121
  "struct"
122
122
  "record"
123
+ "trait"
123
124
  "fun"
124
125
  "fun*"
125
126
  "extern"
@@ -155,3 +156,6 @@
155
156
  "crash" @keyword.control.exception
156
157
 
157
158
  "match" @keyword
159
+
160
+ (trait
161
+ name: (type_identifier) @type.definition)
plum-tooling/tree-sitter-plum/queries/plum/tags.scm CHANGED
@@ -7,6 +7,9 @@
7
7
  (record
8
8
  name: (type_identifier) @name) @definition.class
9
9
 
10
+ (trait
11
+ name: (type_identifier) @name) @definition.interface
12
+
10
13
  (fn
11
14
  name: (fn_identifier) @name) @definition.function
12
15