nomen-lang 0.6.13 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/NOMEN_AGENTS.md +27 -13
  2. package/audit_runtime.c +2 -0
  3. package/core/System/Arena.nm +4 -4
  4. package/core/System/Array.nm +108 -78
  5. package/core/System/Atomic.nm +81 -0
  6. package/core/System/Awaitable.nm +12 -5
  7. package/core/System/BigInt.nm +1 -1
  8. package/core/System/Box.nm +32 -0
  9. package/core/System/Buffer.nm +18 -18
  10. package/core/System/Channel.nm +27 -11
  11. package/core/System/ClassBuffer.nm +24 -28
  12. package/core/System/Console.nm +4 -4
  13. package/core/System/Controls/Button.nm +8 -3
  14. package/core/System/Controls/CheckBox.nm +8 -3
  15. package/core/System/Controls/Container.nm +18 -11
  16. package/core/System/Controls/Layout.nm +1 -1
  17. package/core/System/Controls/Text.nm +9 -4
  18. package/core/System/Controls/TextBox.nm +8 -3
  19. package/core/System/Controls/Window.nm +10 -3
  20. package/core/System/Fiber.nm +6 -2
  21. package/core/System/Graph.nm +2 -2
  22. package/core/System/Init.nm +2 -2
  23. package/core/System/LinkedList.nm +2 -2
  24. package/core/System/List.nm +7 -7
  25. package/core/System/Map.nm +10 -7
  26. package/core/System/Math.nm +1 -1
  27. package/core/System/Mutex.nm +14 -2
  28. package/core/System/Random.nm +7 -1
  29. package/core/System/Result.nm +1 -1
  30. package/core/System/Sendable.nm +2 -2
  31. package/core/System/Set.nm +6 -6
  32. package/core/System/Spawnable.nm +9 -9
  33. package/core/System/Stream/Directory.nm +1 -2
  34. package/core/System/Stream/File.nm +8 -9
  35. package/core/System/Stream/Http.nm +2 -3
  36. package/core/System/Stream/Tcp.nm +13 -8
  37. package/core/System/String.nm +22 -12
  38. package/core/System/StringBuilder.nm +2 -2
  39. package/core/System/Task.nm +21 -29
  40. package/core/System/Test.nm +10 -4
  41. package/core/System/Text/CharIndex.nm +2 -3
  42. package/core/System/Text/Json.nm +8 -12
  43. package/core/System/Text/JsonTree.nm +4 -4
  44. package/core/System/Text/Regex.nm +7 -7
  45. package/core/System/Text/Utf8.nm +2 -3
  46. package/core/System/Thread.nm +9 -4
  47. package/core/System/Tree.nm +2 -2
  48. package/core/System/Viewable.nm +2 -2
  49. package/core/System/WeakHandle.nm +56 -0
  50. package/core/System/bool.nm +1 -1
  51. package/core/System/char.nm +1 -1
  52. package/core/System/float.nm +1 -1
  53. package/core/System/float32.nm +1 -1
  54. package/core/System/float64.nm +1 -1
  55. package/core/System/int.nm +1 -1
  56. package/core/System/int16.nm +1 -1
  57. package/core/System/int32.nm +1 -1
  58. package/core/System/int64.nm +1 -1
  59. package/core/System/int8.nm +1 -1
  60. package/core/System/ufloat.nm +1 -1
  61. package/core/System/ufloat32.nm +1 -1
  62. package/core/System/ufloat64.nm +1 -1
  63. package/core/System/uint.nm +1 -1
  64. package/core/System/uint16.nm +1 -1
  65. package/core/System/uint32.nm +1 -1
  66. package/core/System/uint64.nm +1 -1
  67. package/core/System/uint8.nm +1 -1
  68. package/core/docs/System/Result.md +2 -2
  69. package/dist/index.mjs +29031 -25546
  70. package/package.json +1 -1
  71. package/src/test.ts +26 -11
@@ -2,8 +2,8 @@
2
2
  // tasks. Unbounded, FIFO, blocking receive.
3
3
  //
4
4
  // The queue node's payload is three words wide: every message carries a
5
- // (value, len, kind) triple. `send`/`receive` move uint64 values (len and
6
- // kind stay 0); `send_string`/`receive_string` move fat strings (kind = 1)
5
+ // (value, len, kind) triple. `send`/`receive` mv uint64 values (len and
6
+ // kind stay 0); `send_string`/`receive_string` mv fat strings (kind = 1)
7
7
  // without truncating the len half. `#destroy` frees only string payloads —
8
8
  // a raw uint64 payload is a value, not a pointer. A typed Channel<T>
9
9
  // wrapper can come later — the storage story is identical, only the
@@ -19,10 +19,22 @@
19
19
  // Default stance in Nomen is "no shared mutable state" — channels are the
20
20
  // preferred way for tasks to communicate. See ASYNC.md.
21
21
 
22
+ // Channel is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
23
+ // menu): every field is an opaque handle/counter word, so the value is
24
+ // movable and its `#destroy` closes what the handles name. Sharing one
25
+ // across tasks rides the checked region borrows (`async { }` — the join
26
+ // bounds the borrow) or a transfer (`mv ch` — the receiver owns the
27
+ // queue). The send/receive methods take the receiver bare (struct receivers
28
+ // travel by address), so queue mutations land in the one shared instance,
29
+ // never in a copy.
30
+ //
31
+ // Default stance in Nomen is "no shared mutable state" — channels are the
32
+ // preferred way for tasks to communicate. See ASYNC.md.
33
+
22
34
  /**
23
35
  * A thread-safe, blocking FIFO queue for passing values between tasks
24
36
  **/
25
- pub class Channel: Sendable {
37
+ pub mv struct Channel {
26
38
  pub var uint64 mu = 0
27
39
  pub var uint64 not_empty_cv = 0
28
40
  pub var uint64 head = 0
@@ -44,13 +56,17 @@ pub class Channel: Sendable {
44
56
  ```
45
57
  ```
46
58
  #arch: c
47
- self->mu = (unsigned long long)malloc(sizeof(pthread_mutex_t));
48
- self->not_empty_cv = (unsigned long long)malloc(sizeof(pthread_cond_t));
49
- pthread_mutex_init((pthread_mutex_t *)self->mu, NULL);
50
- pthread_cond_init((pthread_cond_t *)self->not_empty_cv, NULL);
51
- self->head = 0;
52
- self->tail = 0;
53
- self->waiters = 0;
59
+ // The constructor's `self` is the INLINE instance (a local value in
60
+ // the C lowering — methods take the pointer form, the ctor does not),
61
+ // so this body uses the `.` accessor; the aarch64 body writes through
62
+ // x19 = &instance as always.
63
+ self.mu = (unsigned long long)malloc(sizeof(pthread_mutex_t));
64
+ self.not_empty_cv = (unsigned long long)malloc(sizeof(pthread_cond_t));
65
+ pthread_mutex_init((pthread_mutex_t *)self.mu, NULL);
66
+ pthread_cond_init((pthread_cond_t *)self.not_empty_cv, NULL);
67
+ self.head = 0;
68
+ self.tail = 0;
69
+ self.waiters = 0;
54
70
  ```
55
71
  ```
56
72
  #arch: aarch64
@@ -251,7 +267,7 @@ pub class Channel: Sendable {
251
267
  // (the node's copy is moved out — the payload leaves the channel, and a
252
268
  // second receive of the same message is not possible). The fat (ptr, len)
253
269
  // pair survives intact. Pair with send_string.
254
- pub func receive_string = (self, move out string) {
270
+ pub func receive_string = (self, mv out string) {
255
271
  ```
256
272
  #arch: c
257
273
  pthread_mutex_lock((pthread_mutex_t *)self->mu);
@@ -95,15 +95,15 @@ pub struct ClassBuffer<T> {
95
95
  }
96
96
 
97
97
  // Store the owned class pointer `val` into slot `i`, which MUST be fresh
98
- // (calloc'd, or zeroed by move/move_int). Takes OWNERSHIP of `val`
99
- // (`move`): the slot's #destroy reclaims the instance, so the caller must
98
+ // (calloc'd, or zeroed by mv/move_int). Takes OWNERSHIP of `val`
99
+ // (`mv`): the slot's #destroy reclaims the instance, so the caller must
100
100
  // not free its copy — a fresh constructor result transfers here directly,
101
101
  // and a local must be moved (its own cleanup is suppressed at the call
102
102
  // site). This is a plain pointer store — it does NOT destroy/free the
103
103
  // slot's previous occupant, so a second `store` at an occupied index
104
104
  // leaks that instance. Use replace (or replace_int) to overwrite a live
105
105
  // slot.
106
- internal inline func store = (ref self, int i: i >= 0 && i < self.cap, move T val: val != 0) {
106
+ internal inline func store = (ref self, int i: i >= 0 && i < self.cap, mv T val: val != 0) {
107
107
  ```
108
108
  #arch: c
109
109
  ((long*)(unsigned long long)self->data)[i] = (long)val;
@@ -118,14 +118,14 @@ pub struct ClassBuffer<T> {
118
118
  }
119
119
 
120
120
  // Move a class pointer out of a slot: return it and zero the slot so the
121
- // buffer no longer references it. Declared `move out T` so the borrow
121
+ // buffer no longer references it. Declared `mv out T` so the borrow
122
122
  // checker treats the result as OWNED — the slot is relinquished, so the
123
- // caller is the sole remaining owner. This is the owning-extract primitive
123
+ // caller is the sole remaining owner. This is the mv-extract primitive
124
124
  // (parallel to List.pop); use it (not load) when transferring ownership
125
- // out of a ClassBuffer slot, or moving a value into a fresh owning
125
+ // out of a ClassBuffer slot, or moving a value into a fresh mv
126
126
  // container — load returns a BORROW (the slot is unchanged) and storing
127
127
  // it elsewhere would create shared ownership (double-free at destroy).
128
- inline func move = (ref self, int i: i >= 0 && i < self.cap, move out T) {
128
+ inline func move = (ref self, int i: i >= 0 && i < self.cap, mv out T) {
129
129
  ```
130
130
  #arch: c
131
131
  long *slots = (long*)(unsigned long long)self->data;
@@ -143,13 +143,19 @@ pub struct ClassBuffer<T> {
143
143
  ```
144
144
  }
145
145
 
146
- // Apply `f` to slot `i` in place — the owning-counterpart of Buffer's
146
+ // Apply `f` to slot `i` in place — the mv-counterpart of Buffer's
147
147
  // modify for class elements. `f` receives the current instance pointer
148
- // as a borrow and returns the replacement instance (fresh, or the same
149
- // pointer); the primitive frees the displaced instance (destroy + free)
150
- // unless `f` returned it. Storing the returned instance raw is sound:
151
- // the slot takes sole ownership and `f`'s return is not retained
152
- // elsewhere. NOT `inline`: the body calls through the fn pointer.
148
+ // as a MOVE argument — the only expressible parameter mode for a
149
+ // class-tier element (a bare `Box<T>` param is rejected — B2/T2 — and a
150
+ // `ref` param's &binding lowering mismatches this raw call) — so the
151
+ // displaced instance's reclamation is the CALLEE's mv-param contract:
152
+ // a function whose parameter is not returned frees it at its own exit
153
+ // (the C auto-free registration / the aarch64 return-compare arm). The
154
+ // body frees nothing — freeing here too was a double free (the
155
+ // aarch64 callee already reclaimed it; the audit caught the stale
156
+ // free). Storing the returned instance raw is sound: the slot takes
157
+ // sole ownership and `f`'s return is not retained elsewhere. NOT
158
+ // `inline`: the body calls through the fn pointer.
153
159
  func modify = (ref self, int i: i >= 0 && i < self.cap, func(T, out T) f) {
154
160
  ```
155
161
  #arch: c
@@ -157,15 +163,13 @@ pub struct ClassBuffer<T> {
157
163
  void *old = (void*)slots[i];
158
164
  void *new_value = (void*)((void *(*)(void *, void *))f->code)(f->env, old);
159
165
  slots[i] = (long)new_value;
160
- if (old != new_value) {
161
- T_destroy(old);
162
- free(old);
163
- }
164
166
  ```
165
167
  ```
166
168
  #arch: aarch64
167
169
  // x19 = self, x1 = i, x2 = f (a closure descriptor — env goes in x0,
168
170
  // the old slot value shifts to x1). Class slots are one pointer wide.
171
+ // `old` is MOVED into f — the callee's mv-param contract reclaims
172
+ // it; this body frees nothing.
169
173
  stp x20, x21, [sp, #-16]!
170
174
  stp x22, x23, [sp, #-16]!
171
175
  stp x24, x25, [sp, #-16]!
@@ -178,15 +182,7 @@ pub struct ClassBuffer<T> {
178
182
  ldr x1, [x20]
179
183
  blr x24
180
184
  mov x23, x0
181
- ldr x9, [x20]
182
185
  str x23, [x20]
183
- cmp x9, x23
184
- b.eq .Lcb_modify_T_done
185
- mov x0, x9
186
- bl T_destroy
187
- mov x0, x9
188
- bl _free
189
- .Lcb_modify_T_done:
190
186
  ldp x24, x25, [sp], #16
191
187
  ldp x22, x23, [sp], #16
192
188
  ldp x20, x21, [sp], #16
@@ -262,8 +258,8 @@ pub struct ClassBuffer<T> {
262
258
  // free) then store the new one. Used by List.set so the uniform API
263
259
  // preserves ownership for class elements.
264
260
  // Overwrite a live slot: destroy + free the displaced instance, then take
265
- // OWNERSHIP of `val` (`move`) — same transfer rule as store.
266
- func replace = (ref self, int i: i >= 0 && i < self.cap, move T val: val != 0) {
261
+ // OWNERSHIP of `val` (`mv`) — same transfer rule as store.
262
+ func replace = (ref self, int i: i >= 0 && i < self.cap, mv T val: val != 0) {
267
263
  ```
268
264
  #arch: c
269
265
  long *slots = (long*)(unsigned long long)self->data;
@@ -343,7 +339,7 @@ pub struct ClassBuffer<T> {
343
339
  ```
344
340
  }
345
341
 
346
- // A non-owning (ptr, len) slice [start, end) over this buffer's class
342
+ // A non-mv (ptr, len) slice [start, end) over this buffer's class
347
343
  // pointers, returned as a `view T` (T is a class, so each element is an
348
344
  // 8-byte pointer). Borrows from self — invalidated on reassignment. Mirrors
349
345
  // Buffer.slice; ClassBuffer stores 8-byte slots, so the element width is 8.
@@ -70,8 +70,8 @@ pub struct Console {
70
70
  }
71
71
 
72
72
  // Read one line from stdin (newline stripped). The raw body mallocs the
73
- // buffer — `move out string` transfers ownership to the caller.
74
- pub func read_line = (move out string) {
73
+ // buffer — `mv out string` transfers ownership to the caller.
74
+ pub func read_line = (mv out string) {
75
75
  ```
76
76
  #arch: c
77
77
  int cap = 16;
@@ -153,8 +153,8 @@ pub struct Console {
153
153
  }
154
154
 
155
155
  // The platform name ("macos" / "ios" / …). The raw body strdups a static
156
- // string — `move out string` transfers the owned copy to the caller.
157
- pub func platform = (move out string) {
156
+ // string — `mv out string` transfers the owned copy to the caller.
157
+ pub func platform = (mv out string) {
158
158
  ```
159
159
  #arch: c
160
160
  #platform: macos
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * A push-button control that triggers an action when clicked
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * single field is an AppKit handle, so the value is movable and its
6
+ * `#destroy` releases what the handle names. The constructor's `self` is
7
+ * the inline instance (the `.` accessor); methods keep the pointer form.
3
8
  **/
4
- pub class Button: Control {
9
+ pub mv struct Button : Control {
5
10
  var uint64 handle = 0
6
11
 
7
12
  pub func #init = (self, Window window, string title) {
@@ -22,7 +27,7 @@ pub class Button: Control {
22
27
  (id)window->handle, sel_registerName("contentView"));
23
28
  ((void(*)(id, SEL, id))objc_msgSend)(
24
29
  contentView, sel_registerName("addSubview:"), btn);
25
- self->handle = (uint64_t)btn;
30
+ self.handle = (uint64_t)btn;
26
31
  ```
27
32
  ```
28
33
  #arch: aarch64_use_c
@@ -61,7 +66,7 @@ pub class Button: Control {
61
66
  sel_registerName("view"));
62
67
  ((void(*)(id, SEL, id))objc_msgSend)(
63
68
  parentView, sel_registerName("addSubview:"), btn);
64
- self->handle = (uint64_t)btn;
69
+ self.handle = (uint64_t)btn;
65
70
  ```
66
71
  ```
67
72
  #arch: aarch64_use_c
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * A toggle control with a title and checked/hidden state
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * single field is an AppKit handle, so the value is movable and its
6
+ * `#destroy` releases what the handle names. The constructor's `self` is
7
+ * the inline instance (the `.` accessor); methods keep the pointer form.
3
8
  **/
4
- pub class CheckBox: Control {
9
+ pub mv struct CheckBox : Control {
5
10
  var uint64 handle = 0
6
11
 
7
12
  pub func #init = (self, Window window) {
@@ -20,7 +25,7 @@ pub class CheckBox: Control {
20
25
  (id)window->handle, sel_registerName("contentView"));
21
26
  ((void(*)(id, SEL, id))objc_msgSend)(
22
27
  contentView, sel_registerName("addSubview:"), cb);
23
- self->handle = (uint64_t)cb;
28
+ self.handle = (uint64_t)cb;
24
29
  ```
25
30
  ```
26
31
  #arch: aarch64_use_c
@@ -52,7 +57,7 @@ pub class CheckBox: Control {
52
57
  sel_registerName("view"));
53
58
  ((void(*)(id, SEL, id))objc_msgSend)(
54
59
  parentView, sel_registerName("addSubview:"), cb);
55
- self->handle = (uint64_t)cb;
60
+ self.handle = (uint64_t)cb;
56
61
  ```
57
62
  ```
58
63
  #arch: aarch64_use_c
@@ -241,6 +241,9 @@ pub func native_intrinsic = (uint64 handle, out [int, int]) {
241
241
  /**
242
242
  * A flexbox-style container that measures and arranges its child controls.
243
243
  *
244
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
245
+ * SoA buffers mv with the value and a scope-exit destroy reclaims them.
246
+ * *
244
247
  * Conforms to `Control`: `measure(BoxConstraints)` measures the whole subtree,
245
248
  * `set_frame` arranges it into a rectangle, and `intrinsic_size` reports the
246
249
  * unbounded-content size. The handle-based `add` API and the SoA engine are
@@ -248,7 +251,7 @@ pub func native_intrinsic = (uint64 handle, out [int, int]) {
248
251
  * so a `Container` can also be driven polymorphically as a `Control` (passed to
249
252
  * a `Control`-taking function, stored in a `ClassBuffer<Control>`, etc.).
250
253
  **/
251
- pub class Container: Control {
254
+ pub mv struct Container : Control {
252
255
  var kinds = Buffer<int>()
253
256
  // Per-leaf requested size, stored as a (kind, value) pair per axis. The
254
257
  // kind is one of LEN_* (auto/fixed/percent/fill); the value is the pixel
@@ -1454,10 +1457,12 @@ pub class Container: Control {
1454
1457
  // nomen_layout_thunk is a free function (defined in Nomen below) that
1455
1458
  // forwards to Container.layout — exported for C linkage on both
1456
1459
  // backends, unlike the layout method itself. It takes the Container by
1457
- // `ref` (mutable reference): as a `class`, `ref Container` lowers to
1458
- // `struct Container **` (reference to the instance pointer), so the
1459
- // callback passes the address of the stored instance pointer.
1460
- extern void nomen_layout_thunk(struct Container**, struct Window*);
1460
+ // `ref` (mutable reference): as a mv struct, `ref Container` lowers
1461
+ // to `struct Container *` (the address of the value), so the callback
1462
+ // passes the stored instance address directly. The address must stay
1463
+ // valid for as long as the delegate is installed — an app-lifetime
1464
+ // Container binding (or a Box<Container>).
1465
+ extern void nomen_layout_thunk(struct Container*, struct Window*);
1461
1466
  static void *g_resize_grid = 0;
1462
1467
  static void *g_resize_win = 0;
1463
1468
  void nomen_set_resize_target(void *grid, void *win) {
@@ -1467,7 +1472,7 @@ pub class Container: Control {
1467
1472
  void nomen_window_did_resize(id self, SEL cmd, id notification) {
1468
1473
  (void)self; (void)cmd; (void)notification;
1469
1474
  if (g_resize_grid && g_resize_win) {
1470
- nomen_layout_thunk((struct Container**)&g_resize_grid, (struct Window*)g_resize_win);
1475
+ nomen_layout_thunk((struct Container*)g_resize_grid, (struct Window*)g_resize_win);
1471
1476
  }
1472
1477
  }
1473
1478
  ```
@@ -1480,10 +1485,12 @@ pub class Container: Control {
1480
1485
  // nomen_layout_thunk is a free function (defined in Nomen below) that
1481
1486
  // forwards to Container.layout — exported for C linkage on both
1482
1487
  // backends, unlike the layout method itself. It takes the Container by
1483
- // `ref` (mutable reference): as a `class`, `ref Container` lowers to
1484
- // `struct Container **` (reference to the instance pointer), so the
1485
- // callback passes the address of the stored instance pointer.
1486
- extern void nomen_layout_thunk(struct Container**, struct Window*);
1488
+ // `ref` (mutable reference): as a mv struct, `ref Container` lowers
1489
+ // to `struct Container *` (the address of the value), so the callback
1490
+ // passes the stored instance address directly. The address must stay
1491
+ // valid for as long as the delegate is installed — an app-lifetime
1492
+ // Container binding (or a Box<Container>).
1493
+ extern void nomen_layout_thunk(struct Container*, struct Window*);
1487
1494
  static void *g_resize_grid = 0;
1488
1495
  static void *g_resize_win = 0;
1489
1496
  void nomen_set_resize_target(void *grid, void *win) {
@@ -1493,7 +1500,7 @@ pub class Container: Control {
1493
1500
  void nomen_window_did_resize(id self, SEL cmd, id notification) {
1494
1501
  (void)self; (void)cmd; (void)notification;
1495
1502
  if (g_resize_grid && g_resize_win) {
1496
- nomen_layout_thunk((struct Container**)&g_resize_grid, (struct Window*)g_resize_win);
1503
+ nomen_layout_thunk((struct Container*)g_resize_grid, (struct Window*)g_resize_win);
1497
1504
  }
1498
1505
  }
1499
1506
  ```
@@ -4,7 +4,7 @@
4
4
  /**
5
5
  * A flat, buffer-backed layout tree — nodes stored in parallel arrays for the layout engine
6
6
  **/
7
- pub struct Layout {
7
+ pub mv struct Layout {
8
8
  var kinds = Buffer<int>() // 0=leaf, 1=vstack, 2=hstack
9
9
  var ws = Buffer<int>() // intrinsic width (leaf) or 0
10
10
  var hs = Buffer<int>() // intrinsic height (leaf) or 0
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * A read-only text label control
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * AppKit handle plus the cached label text mv with the value, and the
6
+ * `#destroy` releases what the handle names. The constructor's `self` is
7
+ * the inline instance (the `.` accessor); methods keep the pointer form.
3
8
  **/
4
- pub class Text: Control {
9
+ pub mv struct Text : Control {
5
10
  var uint64 handle = 0
6
11
  var text = ""
7
12
 
@@ -25,7 +30,7 @@ pub class Text: Control {
25
30
  (id)window->handle, sel_registerName("contentView"));
26
31
  ((void(*)(id, SEL, id))objc_msgSend)(
27
32
  contentView, sel_registerName("addSubview:"), label);
28
- self->handle = (uint64_t)label;
33
+ self.handle = (uint64_t)label;
29
34
  ```
30
35
  ```
31
36
  #arch: aarch64_use_c
@@ -67,7 +72,7 @@ pub class Text: Control {
67
72
  sel_registerName("view"));
68
73
  ((void(*)(id, SEL, id))objc_msgSend)(
69
74
  parentView, sel_registerName("addSubview:"), label);
70
- self->handle = (uint64_t)label;
75
+ self.handle = (uint64_t)label;
71
76
  ```
72
77
  ```
73
78
  #arch: aarch64_use_c
@@ -93,7 +98,7 @@ pub class Text: Control {
93
98
  }
94
99
 
95
100
  pub func set_text = (ref self, string text) {
96
- self.text = text
101
+ self.text = text.copy()
97
102
  ```
98
103
  #arch: c
99
104
  #platform: macos
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * An editable single-line text input control
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * single field is an AppKit handle, so the value is movable and its
6
+ * `#destroy` releases what the handle names. The constructor's `self` is
7
+ * the inline instance (the `.` accessor); methods keep the pointer form.
3
8
  **/
4
- pub class TextBox: Control {
9
+ pub mv struct TextBox : Control {
5
10
  var uint64 handle = 0
6
11
 
7
12
  pub func #init = (self, Window window) {
@@ -30,7 +35,7 @@ pub class TextBox: Control {
30
35
  (id)window->handle, sel_registerName("contentView"));
31
36
  ((void(*)(id, SEL, id))objc_msgSend)(
32
37
  contentView, sel_registerName("addSubview:"), field);
33
- self->handle = (uint64_t)field;
38
+ self.handle = (uint64_t)field;
34
39
  ```
35
40
  ```
36
41
  #arch: aarch64_use_c
@@ -74,7 +79,7 @@ pub class TextBox: Control {
74
79
  sel_registerName("view"));
75
80
  ((void(*)(id, SEL, id))objc_msgSend)(
76
81
  parentView, sel_registerName("addSubview:"), field);
77
- self->handle = (uint64_t)field;
82
+ self.handle = (uint64_t)field;
78
83
  ```
79
84
  ```
80
85
  #arch: aarch64_use_c
@@ -1,7 +1,14 @@
1
1
  /**
2
2
  * A top-level native window that hosts controls and dispatches events
3
+ *
4
+ * An OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 4 — the shape menu): the
5
+ * single field is an AppKit handle, so the value is movable and its
6
+ * `#destroy` releases what the handle names. The methods take the receiver
7
+ * bare (struct receivers travel by address — the raw bodies keep the
8
+ * pointer form); the constructor's `self` is the inline instance (the `.`
9
+ * accessor).
3
10
  **/
4
- pub class Window: Control {
11
+ pub mv struct Window : Control {
5
12
  var uint64 handle = 0
6
13
 
7
14
  pub func #init = (self, string title, int width, int height) {
@@ -32,7 +39,7 @@ pub class Window: Control {
32
39
  id cv = ((id(*)(id, SEL))objc_msgSend)(win, sel_registerName("contentView"));
33
40
  ((void(*)(id, SEL, unsigned long))objc_msgSend)(cv, sel_registerName("setAutoresizingMask:"), 18UL);
34
41
  ((void(*)(id, SEL, BOOL))objc_msgSend)(cv, sel_registerName("setAutoresizesSubviews:"), 1);
35
- self->handle = (uint64_t)win;
42
+ self.handle = (uint64_t)win;
36
43
  ```
37
44
  ```
38
45
  #arch: aarch64_use_c
@@ -71,7 +78,7 @@ pub class Window: Control {
71
78
  sel_registerName("initWithFrame:"),
72
79
  ((CGRect(*)(double, double, double, double))CGRectMake)(0, 0, (double)width, (double)height));
73
80
  ((void(*)(id, SEL))objc_msgSend)(win, sel_registerName("makeKeyAndVisible"));
74
- self->handle = (uint64_t)win;
81
+ self.handle = (uint64_t)win;
75
82
  ```
76
83
  ```
77
84
  #arch: aarch64_use_c
@@ -29,6 +29,10 @@
29
29
  // reads the packed handles from the instance's fields and drives the
30
30
  // scheduler. The runtime (scheduler, context switch) lives in the build's
31
31
  // emitted companion C — see build_fiber_spawn.
32
+ //
33
+ // Fiber is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 2 — the shape
34
+ // menu), exactly like Thread: handle fields only, movable, `#destroy`
35
+ // enforces must-start.
32
36
 
33
37
  // The launch surface's return type (ASYNC.md: the dependency is
34
38
  // declared by the library file, not inferred from user-source tokens).
@@ -37,7 +41,7 @@ import Task
37
41
  /**
38
42
  * A stackful coroutine: lightweight, cooperatively scheduled, parks instead of blocking
39
43
  **/
40
- pub class Fiber<T> : Sendable, Spawnable<T> {
44
+ pub mv struct Fiber<T> : Spawnable<T> {
41
45
  // The construction hook (see Thread.nm): the deferred-call special form.
42
46
  #spawn = () {
43
47
  }
@@ -67,7 +71,7 @@ pub class Fiber<T> : Sendable, Spawnable<T> {
67
71
  // out of the instance (started; #destroy no-ops), return the handle.
68
72
  // While the fiber waits, it parks and frees its worker instead of
69
73
  // blocking it.
70
- pub func start = (ref self, move out Task<T>) {
74
+ pub func start = (ref self, mv out Task<T>) {
71
75
  ```
72
76
  #arch: c
73
77
  struct nomen_future *_f = (struct nomen_future *)self->future;
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * A graph of values connected by edges
8
8
  **/
9
- pub struct Graph<T>: Enumerable {
9
+ pub mv struct Graph<T>: Enumerable {
10
10
  var values = Buffer<T>()
11
11
  var head_edge = Buffer<int>()
12
12
  var edge_target = Buffer<int>()
@@ -14,7 +14,7 @@ pub struct Graph<T>: Enumerable {
14
14
  var node_count = 0
15
15
  var edge_count = 0
16
16
 
17
- pub func add_node = (ref self, move T value) {
17
+ pub func add_node = (ref self, mv T value) {
18
18
  var int idx = self.node_count
19
19
  self.values.grow(idx + 1)
20
20
  self.values.store(idx, value)
@@ -2,14 +2,14 @@
2
2
  * Program startup state — the argument count and argument list passed to `main`,
3
3
  * plus whether stdout is a terminal (for renderer selection).
4
4
  **/
5
- pub struct Init {
5
+ pub mv struct Init {
6
6
  var int argc
7
7
  var string[16] args
8
8
  var bool is_tty
9
9
  }
10
10
 
11
11
  // FFI: the C library's decimal-string parser (stdlib.h).
12
- extern func atoi = (string s, out int)
12
+ foreign func atoi = (string s, out int)
13
13
 
14
14
  /**
15
15
  * Parses a decimal string into an int
@@ -6,14 +6,14 @@
6
6
  /**
7
7
  * A doubly-linked list of values
8
8
  **/
9
- pub struct LinkedList<T>: Enumerable {
9
+ pub mv struct LinkedList<T>: Enumerable {
10
10
  var values = Buffer<T>()
11
11
  var nexts = Buffer<int>()
12
12
  var prevs = Buffer<int>()
13
13
  var int head = -1
14
14
  var count = 0
15
15
 
16
- pub func add = (ref self, move T value) {
16
+ pub func add = (ref self, mv T value) {
17
17
  var int idx = self.count
18
18
  self.values.grow(idx + 1)
19
19
  self.values.store(idx, value)
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * A growable, ordered list of values (`push`/`pop`/`at`)
3
3
  **/
4
- pub struct List<T>: Viewable {
4
+ pub mv struct List<T>: Viewable {
5
5
  var length = 0
6
6
  var items = Buffer<T>()
7
7
 
8
- pub func push = (ref self, move T value) {
8
+ pub func push = (ref self, mv T value) {
9
9
  if self.length >= self.items.cap {
10
10
  var new_cap = 4
11
11
  var int old_cap = self.items.cap
@@ -18,7 +18,7 @@ pub struct List<T>: Viewable {
18
18
  self.length += 1
19
19
  }
20
20
 
21
- pub func pop = (ref self, move out T) {
21
+ pub func pop = (ref self, mv out T) {
22
22
  if self.length <= 0 {
23
23
  return self.items.move(0)
24
24
  }
@@ -51,13 +51,13 @@ pub struct List<T>: Viewable {
51
51
  panic("index out of range")
52
52
  }
53
53
 
54
- // A non-owning `view T` over [start, end). Delegates to the backing Buffer's
54
+ // A non-mv `view T` over [start, end). Delegates to the backing Buffer's
55
55
  // #arch slice primitive — no #arch code here. Borrows from self.
56
56
  pub func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
57
57
  return self.items.slice(start, end)
58
58
  }
59
59
 
60
- pub func set = (ref self, int i: i >= 0 && i < self.length, move T value) {
60
+ pub func set = (ref self, int i: i >= 0 && i < self.length, mv T value) {
61
61
  self.items.replace(i, value)
62
62
  }
63
63
 
@@ -65,7 +65,7 @@ pub struct List<T>: Viewable {
65
65
  // for indices that can't be proven at compile time (cross-module calls
66
66
  // can never discharge `set`'s parameter constraint) and out-of-range is
67
67
  // a bug, not a case.
68
- pub func set_or_panic = (ref self, int i, move T value) {
68
+ pub func set_or_panic = (ref self, int i, mv T value) {
69
69
  if i >= 0 && i < self.length {
70
70
  self.set(i, value)
71
71
  return
@@ -74,7 +74,7 @@ pub struct List<T>: Viewable {
74
74
  }
75
75
 
76
76
  // A deep copy: a fresh List<T> with an independent copy of every element.
77
- // For owning element types (strings, owning value structs) each slot in the
77
+ // For mv element types (strings, mv value structs) each slot in the
78
78
  // copy owns its own heap data (Buffer deep-copies on store), so the source
79
79
  // and the copy share nothing. Not available for class/trait element types
80
80
  // (the copy would share the stored instances — the checker rejects it).
@@ -8,7 +8,7 @@
8
8
  * it is correct for negative hashes too: two's-complement `&` already lands
9
9
  * in `[0, cap)`, which is why no negative adjustment is needed.
10
10
  **/
11
- pub struct Map<TK: Hashable + Equatable, TV> {
11
+ pub mv struct Map<TK: Hashable + Equatable, TV> {
12
12
  var length = 0
13
13
  var keys = Buffer<TK>()
14
14
  var values = Buffer<TV>()
@@ -17,6 +17,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
17
17
  // Variadic-tuple constructor: Map<string, int>(["a", 1], ["b", 2]) or
18
18
  // Map(["a", 1], ["b", 2]) (type args inferred from the first pair).
19
19
  // Zero pairs yields an empty Map, so this also covers Map<K, V>().
20
+ // The pair reads are temp-rooted (`pairs.at(i)` is a statement temp):
21
+ // the element transfer is absorbed by set's mv store (store_T
22
+ // deep-copies string-field elements), so no explicit mv is spelled.
20
23
  pub func #init = (self, ...[TK, TV] pairs) {
21
24
  var i = 0
22
25
  while i < pairs.length; i += 1 {
@@ -24,7 +27,7 @@ pub struct Map<TK: Hashable + Equatable, TV> {
24
27
  }
25
28
  }
26
29
 
27
- pub func set = (ref self, move TK key, move TV value) {
30
+ pub func set = (ref self, mv TK key, mv TV value) {
28
31
  var int cap = self.keys.cap
29
32
  if cap == 0 {
30
33
  // alloc_T: for Buffer<TK> it is T_SIZE-aware (string keys are
@@ -169,9 +172,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
169
172
  }
170
173
 
171
174
  func rehash = (ref self, int new_cap) {
172
- var Buffer<TK> old_keys = move self.keys swap Buffer<TK>()
173
- var Buffer<TV> old_values = move self.values swap Buffer<TV>()
174
- var Buffer<int> old_used = move self.used swap Buffer<int>()
175
+ var Buffer<TK> old_keys = mv self.keys swap Buffer<TK>()
176
+ var Buffer<TV> old_values = mv self.values swap Buffer<TV>()
177
+ var Buffer<int> old_used = mv self.used swap Buffer<int>()
175
178
  var int old_cap = old_keys.cap
176
179
 
177
180
  self.keys.alloc(new_cap)
@@ -187,13 +190,13 @@ pub struct Map<TK: Hashable + Equatable, TV> {
187
190
  // afterwards. load_T would leave the old slot referencing
188
191
  // the same class pointer — a double-free when old_keys is
189
192
  // destroyed. The results are bound to locals so an
190
- // owning-element copy (e.g. a `Buffer<string>` slot, which
193
+ // mv-element copy (e.g. a `Buffer<string>` slot, which
191
194
  // store_T strdup's) is freed here once the new buffer has
192
195
  // made its own copy — passing them inline would orphan the
193
196
  // move_T results.
194
197
  var TK k = old_keys.move(i)
195
198
  var TV v = old_values.move(i)
196
- self.set(move k, move v)
199
+ self.set(mv k, mv v)
197
200
  }
198
201
  }
199
202
  }