nomen-lang 0.6.12 → 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.
- package/NOMEN_AGENTS.md +27 -13
- package/audit_runtime.c +2 -0
- package/core/System/Arena.nm +4 -4
- package/core/System/Array.nm +108 -78
- package/core/System/Atomic.nm +81 -0
- package/core/System/Awaitable.nm +12 -5
- package/core/System/BigInt.nm +1 -1
- package/core/System/Box.nm +32 -0
- package/core/System/Buffer.nm +47 -18
- package/core/System/Channel.nm +27 -11
- package/core/System/ClassBuffer.nm +24 -28
- package/core/System/Console.nm +4 -4
- package/core/System/Controls/Button.nm +8 -3
- package/core/System/Controls/CheckBox.nm +8 -3
- package/core/System/Controls/Container.nm +18 -11
- package/core/System/Controls/Layout.nm +1 -1
- package/core/System/Controls/Text.nm +9 -4
- package/core/System/Controls/TextBox.nm +8 -3
- package/core/System/Controls/Window.nm +10 -3
- package/core/System/Fiber.nm +6 -2
- package/core/System/Graph.nm +2 -2
- package/core/System/Init.nm +2 -2
- package/core/System/LinkedList.nm +2 -2
- package/core/System/List.nm +7 -7
- package/core/System/Map.nm +10 -7
- package/core/System/Math.nm +1 -1
- package/core/System/Mutex.nm +14 -2
- package/core/System/Random.nm +7 -1
- package/core/System/Result.nm +1 -1
- package/core/System/Sendable.nm +2 -2
- package/core/System/Set.nm +6 -6
- package/core/System/Spawnable.nm +9 -9
- package/core/System/Stream/Directory.nm +1 -2
- package/core/System/Stream/File.nm +8 -9
- package/core/System/Stream/Http.nm +2 -3
- package/core/System/Stream/Tcp.nm +13 -8
- package/core/System/String.nm +22 -12
- package/core/System/StringBuilder.nm +2 -2
- package/core/System/Task.nm +21 -29
- package/core/System/Test.nm +10 -4
- package/core/System/Text/CharIndex.nm +2 -3
- package/core/System/Text/Json.nm +8 -12
- package/core/System/Text/JsonTree.nm +4 -4
- package/core/System/Text/Regex.nm +7 -7
- package/core/System/Text/Utf8.nm +2 -3
- package/core/System/Thread.nm +9 -4
- package/core/System/Tree.nm +2 -2
- package/core/System/Viewable.nm +2 -2
- package/core/System/WeakHandle.nm +56 -0
- package/core/System/bool.nm +1 -1
- package/core/System/char.nm +1 -1
- package/core/System/float.nm +1 -1
- package/core/System/float32.nm +1 -1
- package/core/System/float64.nm +1 -1
- package/core/System/int.nm +1 -1
- package/core/System/int16.nm +1 -1
- package/core/System/int32.nm +1 -1
- package/core/System/int64.nm +1 -1
- package/core/System/int8.nm +1 -1
- package/core/System/ufloat.nm +1 -1
- package/core/System/ufloat32.nm +1 -1
- package/core/System/ufloat64.nm +1 -1
- package/core/System/uint.nm +1 -1
- package/core/System/uint16.nm +1 -1
- package/core/System/uint32.nm +1 -1
- package/core/System/uint64.nm +1 -1
- package/core/System/uint8.nm +1 -1
- package/core/docs/System/Result.md +2 -2
- package/dist/index.mjs +28088 -24186
- package/package.json +1 -1
- package/src/test.ts +26 -11
package/core/System/Buffer.nm
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// class, the monomorphizer rewrites a Buffer<T> field to ClassBuffer<T>.
|
|
4
4
|
//
|
|
5
5
|
// Public API is the size-aware family (`alloc`/`grow`/`load`/`replace`/
|
|
6
|
-
// `
|
|
6
|
+
// `mv`/`modify`/`shift`/`slice` plus the readonly `cap`). `replace` is the
|
|
7
7
|
// public write — it reclaims the displaced element, so it is correct on both
|
|
8
8
|
// fresh and occupied slots. `store` (which assumes a fresh slot and leaks on
|
|
9
9
|
// overwrite), `zero`, the fixed-width `*_u32`/`*_int`/`*_float` primitives,
|
|
@@ -93,6 +93,35 @@ pub struct Buffer<T> {
|
|
|
93
93
|
```
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
// Byte-width primitives (uint8 elements): the width-matched family the
|
|
97
|
+
// NEON planner's `.16b` descriptor keys on — one 16-byte group carries
|
|
98
|
+
// 16 lanes. `ldrb`/`strb` zero-extend/clobber exactly one byte.
|
|
99
|
+
internal inline func load_u8 = (self, int i: i >= 0 && i < self.cap, out uint8) {
|
|
100
|
+
```
|
|
101
|
+
#arch: c
|
|
102
|
+
return ((unsigned char*)(unsigned long long)self->data)[i];
|
|
103
|
+
```
|
|
104
|
+
```
|
|
105
|
+
#arch: aarch64
|
|
106
|
+
ldr x0, [x19, #8]
|
|
107
|
+
add x0, x0, x1
|
|
108
|
+
ldrb w0, [x0]
|
|
109
|
+
```
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
internal inline func store_u8 = (ref self, int i: i >= 0 && i < self.cap, uint8 val) {
|
|
113
|
+
```
|
|
114
|
+
#arch: c
|
|
115
|
+
((unsigned char*)(unsigned long long)self->data)[i] = val;
|
|
116
|
+
```
|
|
117
|
+
```
|
|
118
|
+
#arch: aarch64
|
|
119
|
+
ldr x0, [x19, #8]
|
|
120
|
+
add x0, x0, x1
|
|
121
|
+
strb w2, [x0]
|
|
122
|
+
```
|
|
123
|
+
}
|
|
124
|
+
|
|
96
125
|
internal func alloc_int = (ref self, int size, out int: out >= size) {
|
|
97
126
|
self.cap = size
|
|
98
127
|
self.data = calloc(size, 8)
|
|
@@ -259,7 +288,7 @@ pub struct Buffer<T> {
|
|
|
259
288
|
}
|
|
260
289
|
|
|
261
290
|
// Store `val` into slot `i`, which MUST be fresh (calloc'd, or zeroed by
|
|
262
|
-
//
|
|
291
|
+
// mv). For a mv T (string, or a struct with string fields) the
|
|
263
292
|
// specialised body deep-copies the incoming value but does NOT free the
|
|
264
293
|
// slot's previous occupant — a second `store` at an occupied index
|
|
265
294
|
// leaks it. To overwrite a live slot use replace (frees the displaced
|
|
@@ -308,11 +337,11 @@ pub struct Buffer<T> {
|
|
|
308
337
|
}
|
|
309
338
|
|
|
310
339
|
// Move a value out of a T_SIZE-sized slot: return it and zero the slot so the
|
|
311
|
-
// buffer no longer holds a (possibly
|
|
340
|
+
// buffer no longer holds a (possibly mv) copy. Declared `mv out T` so
|
|
312
341
|
// the result is treated as OWNED by the borrow checker — the slot is
|
|
313
342
|
// relinquished, so the caller is the sole remaining owner. The value
|
|
314
343
|
// counterpart of ClassBuffer.move_int — used by List.pop for any value T.
|
|
315
|
-
inline func move = (ref self, int i: i >= 0 && i < self.cap,
|
|
344
|
+
inline func move = (ref self, int i: i >= 0 && i < self.cap, mv out T) {
|
|
316
345
|
```
|
|
317
346
|
#arch: c
|
|
318
347
|
T* _slots = (T*)(unsigned long long)self->data;
|
|
@@ -375,8 +404,8 @@ pub struct Buffer<T> {
|
|
|
375
404
|
// aliases the slot's own copy (the round-trip case) is kept, not freed or
|
|
376
405
|
// re-copied. Unlike store this never leaks on overwrite, and unlike
|
|
377
406
|
// replace it is safe to derive the new value from the old one. The
|
|
378
|
-
// returned struct's
|
|
379
|
-
// the corresponding input fields (no cross-field aliasing). For
|
|
407
|
+
// returned struct's mv fields must be fresh, null, or identical to
|
|
408
|
+
// the corresponding input fields (no cross-field aliasing). For mv
|
|
380
409
|
// elements (string / structs with string fields) the build phase replaces
|
|
381
410
|
// this body with a specialized one (see owning_buffer_specialize.ts);
|
|
382
411
|
// this raw form is correct for trivially-copyable elements only. NOT
|
|
@@ -464,7 +493,7 @@ pub struct Buffer<T> {
|
|
|
464
493
|
|
|
465
494
|
// Store into a T_SIZE-sized slot, overwriting the previous value. For
|
|
466
495
|
// trivially-destructible value structs this is a plain overwrite. For
|
|
467
|
-
//
|
|
496
|
+
// mv value structs (with string fields), the build phase replaces this
|
|
468
497
|
// body with a specialised version that calls T_destroy on the old slot
|
|
469
498
|
// value, then deep-copies (strdup per string field). See
|
|
470
499
|
// owning_buffer_specialize.ts (both backends). ClassBuffer.replace
|
|
@@ -512,12 +541,12 @@ pub struct Buffer<T> {
|
|
|
512
541
|
|
|
513
542
|
// Move-taking write, mirroring `List.set`: the caller's value is
|
|
514
543
|
// consumed and an independent copy is installed in the slot (replace
|
|
515
|
-
// deep-copies
|
|
544
|
+
// deep-copies mv elements). The mv entry point a caller uses
|
|
516
545
|
// when it wants to hand over a value — `replace`'s by-value parameter
|
|
517
|
-
// cannot accept the `
|
|
546
|
+
// cannot accept the `mv` keyword, so a borrow being transferred
|
|
518
547
|
// (e.g. a loaded element) must go through here rather than be bound to
|
|
519
548
|
// a freed local.
|
|
520
|
-
pub func set = (ref self, int i: i >= 0 && i < self.cap,
|
|
549
|
+
pub func set = (ref self, int i: i >= 0 && i < self.cap, mv T value) {
|
|
521
550
|
self.replace(i, value)
|
|
522
551
|
}
|
|
523
552
|
|
|
@@ -526,7 +555,7 @@ pub struct Buffer<T> {
|
|
|
526
555
|
// ownership-transferring primitive behind backward-shift deletion
|
|
527
556
|
// (Map/Set.remove) — unlike store, which gives the slot its own deep
|
|
528
557
|
// copy and leaves the source slot intact, a shift transfers the source's
|
|
529
|
-
// heap pointers wholesale. For
|
|
558
|
+
// heap pointers wholesale. For mv elements (string / value structs
|
|
530
559
|
// with string fields) the build replaces this body with a specialized
|
|
531
560
|
// version that also reclaims dst's previous value first (see
|
|
532
561
|
// owning_buffer_specialize.ts); this raw form is correct for
|
|
@@ -555,7 +584,7 @@ pub struct Buffer<T> {
|
|
|
555
584
|
b.eq .Lbuffer_shift_T_end
|
|
556
585
|
cmp x3, #8
|
|
557
586
|
b.gt .Lbuffer_shift_T_copy
|
|
558
|
-
// Width-matched
|
|
587
|
+
// Width-matched mv: an 8-byte access on a sub-8 element would
|
|
559
588
|
// clobber the following slot (and run past the slab's end).
|
|
560
589
|
cmp x3, #1
|
|
561
590
|
b.eq .Lbuffer_shift_T_1
|
|
@@ -597,7 +626,7 @@ pub struct Buffer<T> {
|
|
|
597
626
|
```
|
|
598
627
|
}
|
|
599
628
|
|
|
600
|
-
// A non-
|
|
629
|
+
// A non-mv (ptr, len) slice [start, end) over this buffer's element
|
|
601
630
|
// storage, returned as a `view T`. It borrows from self: it may not outlive
|
|
602
631
|
// self's scope and is invalidated if self is reassigned. This is the single
|
|
603
632
|
// primitive every other slice (Array<T>, List<T>, user containers) builds
|
|
@@ -626,13 +655,13 @@ pub struct Buffer<T> {
|
|
|
626
655
|
```
|
|
627
656
|
}
|
|
628
657
|
|
|
629
|
-
// Internal: zeroes slots without reclaiming
|
|
658
|
+
// Internal: zeroes slots without reclaiming mv elements.
|
|
630
659
|
internal inline func zero = (ref self, int len) {
|
|
631
660
|
memset(self.data, 0, len * T_SIZE)
|
|
632
661
|
}
|
|
633
662
|
|
|
634
663
|
// An independent copy: fresh slab, per-element deep copies. Each slot
|
|
635
|
-
// round-trips load→replace through a local, so
|
|
664
|
+
// round-trips load→replace through a local, so mv element types get
|
|
636
665
|
// the same treatment a List<T>.copy slot does (the load materializes an
|
|
637
666
|
// owned copy, replace gives the destination its own). Class elements
|
|
638
667
|
// never reach this body (a `Buffer<T>` with T a class monomorphizes to
|
|
@@ -643,10 +672,10 @@ pub struct Buffer<T> {
|
|
|
643
672
|
dst.alloc(self.cap)
|
|
644
673
|
var i = 0
|
|
645
674
|
while i < self.cap {
|
|
646
|
-
// Bind the loaded element and hand it to `set` (
|
|
675
|
+
// Bind the loaded element and hand it to `set` (mv): for a
|
|
647
676
|
// string element load returns a BORROW of the source slot, and
|
|
648
|
-
// the
|
|
649
|
-
// reclaim (which would free the source's buffer); for
|
|
677
|
+
// the mv transfers it into the write without a scope-exit
|
|
678
|
+
// reclaim (which would free the source's buffer); for a mv
|
|
650
679
|
// struct element load returns an owned copy that transfers the
|
|
651
680
|
// same way. Mirrors List.copy's `var T v = self.at(i)` +
|
|
652
681
|
// `dst.push(v)`.
|
package/core/System/Channel.nm
CHANGED
|
@@ -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`
|
|
6
|
-
// kind stay 0); `send_string`/`receive_string`
|
|
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
|
|
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
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
self
|
|
52
|
-
self
|
|
53
|
-
self
|
|
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,
|
|
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
|
|
99
|
-
// (`
|
|
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,
|
|
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 `
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
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` (`
|
|
266
|
-
func replace = (ref self, int i: i >= 0 && i < self.cap,
|
|
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-
|
|
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.
|
package/core/System/Console.nm
CHANGED
|
@@ -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 — `
|
|
74
|
-
pub func read_line = (
|
|
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 — `
|
|
157
|
-
pub func platform = (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1458
|
-
// `struct Container
|
|
1459
|
-
//
|
|
1460
|
-
|
|
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
|
|
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
|
|
1484
|
-
// `struct Container
|
|
1485
|
-
//
|
|
1486
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
81
|
+
self.handle = (uint64_t)win;
|
|
75
82
|
```
|
|
76
83
|
```
|
|
77
84
|
#arch: aarch64_use_c
|
package/core/System/Fiber.nm
CHANGED
|
@@ -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
|
|
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,
|
|
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;
|