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/Task.nm
CHANGED
|
@@ -11,13 +11,18 @@
|
|
|
11
11
|
// on the first spawn — not in Task's own methods — so that Task can be
|
|
12
12
|
// generic without duplicating the pool per instantiation.
|
|
13
13
|
//
|
|
14
|
+
// Task is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 2 — the shape
|
|
15
|
+
// menu): every field is an opaque handle (uint64/bool), so the handle value
|
|
16
|
+
// is movable and its `#destroy` releases the future reference it holds.
|
|
17
|
+
// Moving a Task transfers that reference; there is no aliasing copy.
|
|
18
|
+
//
|
|
14
19
|
// See ASYNC.md for the design.
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* A handle to an asynchronously-running computation, backed by a shared thread pool.
|
|
18
23
|
* Conforms to `Awaitable`: `.wait()` may park the current execution context.
|
|
19
24
|
**/
|
|
20
|
-
pub
|
|
25
|
+
pub mv struct Task<T> : Awaitable {
|
|
21
26
|
pub var uint64 handle = 0
|
|
22
27
|
pub var done = false
|
|
23
28
|
pub var uint64 result_slot = 0
|
|
@@ -35,40 +40,27 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
35
40
|
// Block until the task finishes. Idempotent — calling twice is safe, and
|
|
36
41
|
// a Task captured from a nursery spawn can be waited on here AND joined
|
|
37
42
|
// by the nursery at block exit (both wait on the same shared future).
|
|
38
|
-
|
|
43
|
+
//
|
|
44
|
+
// The receiver is a bare VALUE self (matching the Awaitable trait):
|
|
45
|
+
// waiting never mutates the handle — it parks on the future the handle
|
|
46
|
+
// names. Struct receivers travel by address regardless (the raw body
|
|
47
|
+
// reads `self->future`), so the ABI is unchanged; the bare spelling is
|
|
48
|
+
// what lets the read-only `Awaitable` dispatch form typecheck.
|
|
49
|
+
// The legacy `pthread_join` fallback is gone — `handle` has been
|
|
50
|
+
// permanently zero since the pool migration.
|
|
51
|
+
pub func wait = (self) {
|
|
39
52
|
```
|
|
40
53
|
#arch: c
|
|
41
54
|
if (self->future) {
|
|
42
55
|
__nomen_future_wait((struct nomen_future *)self->future);
|
|
43
|
-
} else if (self->handle && !self->done) {
|
|
44
|
-
void *ret;
|
|
45
|
-
pthread_join((pthread_t)self->handle, &ret);
|
|
46
|
-
self->handle = 0;
|
|
47
|
-
self->done = 1;
|
|
48
56
|
}
|
|
49
57
|
```
|
|
50
58
|
```
|
|
51
59
|
#arch: aarch64
|
|
52
|
-
// if (self->future)
|
|
60
|
+
// if (self->future) __nomen_future_wait(self->future)
|
|
53
61
|
ldr x0, [x19, #40]
|
|
54
|
-
cbz x0, .Lwait_handle
|
|
55
|
-
bl ___nomen_future_wait
|
|
56
|
-
b .Lwait_done
|
|
57
|
-
.Lwait_handle:
|
|
58
|
-
// else if (self->handle && !self->done)
|
|
59
|
-
ldr x0, [x19, #8]
|
|
60
62
|
cbz x0, .Lwait_done
|
|
61
|
-
|
|
62
|
-
cbnz w1, .Lwait_done
|
|
63
|
-
// pthread_join((pthread_t)self->handle, &ret)
|
|
64
|
-
sub sp, sp, #16
|
|
65
|
-
mov x1, sp
|
|
66
|
-
bl _pthread_join
|
|
67
|
-
add sp, sp, #16
|
|
68
|
-
// self->handle = 0; self->done = 1
|
|
69
|
-
str xzr, [x19, #8]
|
|
70
|
-
mov w0, #1
|
|
71
|
-
strb w0, [x19, #16]
|
|
63
|
+
bl ___nomen_future_wait
|
|
72
64
|
.Lwait_done:
|
|
73
65
|
```
|
|
74
66
|
}
|
|
@@ -78,10 +70,10 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
78
70
|
// the full return value — including the 16-byte fat-string pair — and the
|
|
79
71
|
// trampoline writes the function's return value there before exiting.
|
|
80
72
|
// The result is MOVED OUT: the slot is zeroed as the value leaves, and
|
|
81
|
-
// `
|
|
73
|
+
// `mv out T` marks the caller as the owner. Call it once; a second call
|
|
82
74
|
// returns the zero value. For tasks with no return value (void
|
|
83
75
|
// functions), returns the zero value.
|
|
84
|
-
pub func result = (ref self,
|
|
76
|
+
pub func result = (ref self, mv out T) {
|
|
85
77
|
```
|
|
86
78
|
#arch: c
|
|
87
79
|
if (self->future) {
|
|
@@ -284,7 +276,7 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
284
276
|
// ---- User-defined async primitive seam (ASYNC.md, "User-defined async
|
|
285
277
|
// primitives") ----
|
|
286
278
|
// The construction sugar stores the packed-task machinery in a user
|
|
287
|
-
//
|
|
279
|
+
// spawnable's plain uint64 fields (task / result_slot / cancel_flag /
|
|
288
280
|
// future); these statics are the library boundary its own launch
|
|
289
281
|
// methods drive the runtime through — the same calls the generated
|
|
290
282
|
// Thread/Fiber launch code makes, so a user primitive parks fibers,
|
|
@@ -294,7 +286,7 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
294
286
|
|
|
295
287
|
// Submit a packed task closure (the `task` field's value) to the shared
|
|
296
288
|
// worker pool. The closure must come from a construction of an
|
|
297
|
-
// Awaitable-conforming
|
|
289
|
+
// Awaitable-conforming spawnable — it is not callable.
|
|
298
290
|
pub func pool_submit = (uint64 closure) {
|
|
299
291
|
```
|
|
300
292
|
#arch: c
|
package/core/System/Test.nm
CHANGED
|
@@ -32,6 +32,12 @@
|
|
|
32
32
|
//
|
|
33
33
|
// See TESTING.md for the full design.
|
|
34
34
|
|
|
35
|
+
// Tester is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
|
|
36
|
+
// menu): the harness builds exactly one per run, so the single-owner rule
|
|
37
|
+
// costs nothing and the record state moves with the value. The string
|
|
38
|
+
// fields (current/bench_label) are normalized heap-owned by the compiler's
|
|
39
|
+
// struct string machinery, so `#destroy` reclaims them cleanly.
|
|
40
|
+
|
|
35
41
|
/**
|
|
36
42
|
* Records assertions and benchmarks for one test file.
|
|
37
43
|
*
|
|
@@ -47,7 +53,7 @@
|
|
|
47
53
|
* skipped, so a single root cause reports as a single failure. Check
|
|
48
54
|
* `t.has_failed` to bail out of expensive follow-up work yourself.
|
|
49
55
|
**/
|
|
50
|
-
pub
|
|
56
|
+
pub mv struct Tester {
|
|
51
57
|
// Has the *current* test recorded a failure? Reset by `begin_test`.
|
|
52
58
|
pub var has_failed = false
|
|
53
59
|
|
|
@@ -94,7 +100,7 @@ pub class Tester {
|
|
|
94
100
|
self.has_failed = false
|
|
95
101
|
self.passed = 0
|
|
96
102
|
self.failed = 0
|
|
97
|
-
self.current = name
|
|
103
|
+
self.current = name.copy()
|
|
98
104
|
Console.write_line("\\nomen|start|" + name)
|
|
99
105
|
self.started = Time.now_ns()
|
|
100
106
|
}
|
|
@@ -211,7 +217,7 @@ pub class Tester {
|
|
|
211
217
|
return
|
|
212
218
|
}
|
|
213
219
|
self.bench_pending = true
|
|
214
|
-
self.bench_label = label
|
|
220
|
+
self.bench_label = label.copy()
|
|
215
221
|
self.bench_samples = 1000
|
|
216
222
|
}
|
|
217
223
|
|
|
@@ -225,7 +231,7 @@ pub class Tester {
|
|
|
225
231
|
return
|
|
226
232
|
}
|
|
227
233
|
self.bench_pending = true
|
|
228
|
-
self.bench_label = label
|
|
234
|
+
self.bench_label = label.copy()
|
|
229
235
|
self.bench_samples = samples
|
|
230
236
|
}
|
|
231
237
|
|
|
@@ -20,7 +20,7 @@ pub struct CharRun {
|
|
|
20
20
|
* A run-length character-width index (construct with `CharIndex(text)`,
|
|
21
21
|
* then `byte_offset_of` / `char_index_of` / `char_at` in O(log runs))
|
|
22
22
|
**/
|
|
23
|
-
pub struct CharIndex {
|
|
23
|
+
pub mv struct CharIndex {
|
|
24
24
|
var view string source
|
|
25
25
|
var runs = List<CharRun>()
|
|
26
26
|
var char_count = 0
|
|
@@ -50,7 +50,7 @@ pub struct CharIndex {
|
|
|
50
50
|
pos = pos + w
|
|
51
51
|
chars = chars + 1
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
} else {
|
|
54
54
|
if open_at >= 0 {
|
|
55
55
|
self.runs.push(CharRun(open_at, open_start, open_width, open_count))
|
|
56
56
|
}
|
|
@@ -61,7 +61,6 @@ pub struct CharIndex {
|
|
|
61
61
|
pos = pos + w
|
|
62
62
|
chars = chars + 1
|
|
63
63
|
}
|
|
64
|
-
}
|
|
65
64
|
}
|
|
66
65
|
if open_at >= 0 {
|
|
67
66
|
self.runs.push(CharRun(open_at, open_start, open_width, open_count))
|
package/core/System/Text/Json.nm
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
**/
|
|
15
15
|
pub struct Json {
|
|
16
16
|
// Serialize a string to a JSON string literal, escaping the special
|
|
17
|
-
// characters ", \, newline, tab and carriage return. `
|
|
17
|
+
// characters ", \, newline, tab and carriage return. `mv out string`:
|
|
18
18
|
// returns the StringBuilder's owned heap copy.
|
|
19
|
-
pub func serialize = (string value,
|
|
19
|
+
pub func serialize = (string value, mv out string) {
|
|
20
20
|
var sb = StringBuilder()
|
|
21
21
|
sb.append_char('"')
|
|
22
22
|
var i = 0
|
|
@@ -40,18 +40,17 @@ pub struct Json {
|
|
|
40
40
|
case code == 13 {
|
|
41
41
|
sb.append_string("\x5cr")
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
} else {
|
|
44
44
|
sb.append_char(c)
|
|
45
45
|
}
|
|
46
|
-
}
|
|
47
46
|
}
|
|
48
47
|
sb.append_char('"')
|
|
49
48
|
return sb.to_string()
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
// Deserialize a JSON string literal to the raw, unescaped value.
|
|
53
|
-
// `
|
|
54
|
-
pub func deserialize = (string json,
|
|
52
|
+
// `mv out string`: returns the StringBuilder's owned heap copy.
|
|
53
|
+
pub func deserialize = (string json, mv out string) {
|
|
55
54
|
var sb = StringBuilder()
|
|
56
55
|
var int len = json.length
|
|
57
56
|
var i = 0
|
|
@@ -90,10 +89,9 @@ pub struct Json {
|
|
|
90
89
|
case ec == 92 {
|
|
91
90
|
sb.append_string("\x5c")
|
|
92
91
|
}
|
|
93
|
-
|
|
92
|
+
} else {
|
|
94
93
|
sb.append_char(e)
|
|
95
94
|
}
|
|
96
|
-
}
|
|
97
95
|
}
|
|
98
96
|
} else {
|
|
99
97
|
sb.append_char(c)
|
|
@@ -165,10 +163,9 @@ func json_parse_string = (string s, ref Buffer<int> pos, int len, ref JsonTree t
|
|
|
165
163
|
case ec == 92 {
|
|
166
164
|
sb.append_string("\x5c")
|
|
167
165
|
}
|
|
168
|
-
|
|
166
|
+
} else {
|
|
169
167
|
sb.append_char(e)
|
|
170
168
|
}
|
|
171
|
-
}
|
|
172
169
|
}
|
|
173
170
|
} else {
|
|
174
171
|
sb.append_char(c)
|
|
@@ -218,11 +215,10 @@ func json_parse_literal = (string s, ref Buffer<int> pos, int len, ref JsonTree
|
|
|
218
215
|
tree.set_kind(n, 6)
|
|
219
216
|
adv = 5
|
|
220
217
|
}
|
|
221
|
-
|
|
218
|
+
} else {
|
|
222
219
|
tree.set_kind(n, 0)
|
|
223
220
|
adv = 4
|
|
224
221
|
}
|
|
225
|
-
}
|
|
226
222
|
pos.store_int(0, i + adv)
|
|
227
223
|
return n
|
|
228
224
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// A node in a parsed JSON tree, stored by value in the pool.
|
|
12
12
|
// kind: 0=null, 1=true, 2=number, 3=string, 4=array, 5=object, 6=false
|
|
13
13
|
// child/next/val are node indices, -1 = none.
|
|
14
|
-
struct JsonNode {
|
|
14
|
+
mv struct JsonNode {
|
|
15
15
|
var kind = 0
|
|
16
16
|
var text = ""
|
|
17
17
|
var int child = -1
|
|
@@ -22,7 +22,7 @@ struct JsonNode {
|
|
|
22
22
|
/**
|
|
23
23
|
* A flat, buffer-backed pool of JSON tree nodes — the parsed representation `Json.parse` produces
|
|
24
24
|
**/
|
|
25
|
-
pub struct JsonTree {
|
|
25
|
+
pub mv struct JsonTree {
|
|
26
26
|
var nodes = Buffer<JsonNode>()
|
|
27
27
|
var count = 0
|
|
28
28
|
|
|
@@ -32,7 +32,7 @@ pub struct JsonTree {
|
|
|
32
32
|
self.count = idx + 1
|
|
33
33
|
var default = JsonNode()
|
|
34
34
|
self.nodes.store(idx, default)
|
|
35
|
-
// store_T deep-copies the
|
|
35
|
+
// store_T deep-copies the mv `text` field (strdup of the shared
|
|
36
36
|
// empty-string literal) into the slot. JsonTree manages node texts
|
|
37
37
|
// manually (set_text strdup's into the slab; free_text/release frees
|
|
38
38
|
// them; NULL means "no text"), so the slot must start NULL — free the
|
|
@@ -136,7 +136,7 @@ pub struct JsonTree {
|
|
|
136
136
|
|
|
137
137
|
func get_text = (self, int idx, out string) {
|
|
138
138
|
var JsonNode n = self.nodes.load(idx)
|
|
139
|
-
return n.text
|
|
139
|
+
return n.text.copy()
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
func get_child = (self, int idx, out int) {
|
|
@@ -33,9 +33,9 @@ pub struct Regex {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Return the first substring of input matching pattern, or "" if none.
|
|
36
|
-
// `
|
|
36
|
+
// `mv out string`: the built match (or the copied empty literal) is
|
|
37
37
|
// handed to the caller as an owned value.
|
|
38
|
-
pub func match = (string pattern, string input,
|
|
38
|
+
pub func match = (string pattern, string input, mv out string) {
|
|
39
39
|
var match_result = ""
|
|
40
40
|
var int pat_len = pattern.length
|
|
41
41
|
var int len = input.length
|
|
@@ -89,7 +89,7 @@ pub struct Regex {
|
|
|
89
89
|
var int end = match_here(pattern, 0, pat_len, input, i, len, ref caps)
|
|
90
90
|
if end >= 0 {
|
|
91
91
|
var string whole = input.substring(i, end)
|
|
92
|
-
dst.push(whole)
|
|
92
|
+
dst.push(mv whole)
|
|
93
93
|
var g = 1
|
|
94
94
|
while g <= groups; g += 1 {
|
|
95
95
|
var int at = last_capture_index(caps, g)
|
|
@@ -97,7 +97,7 @@ pub struct Regex {
|
|
|
97
97
|
var int s = caps.at(at + 1)
|
|
98
98
|
if s >= 0 {
|
|
99
99
|
var string cap = input.substring(s, caps.at(at + 2))
|
|
100
|
-
dst.push(cap)
|
|
100
|
+
dst.push(mv cap)
|
|
101
101
|
} else {
|
|
102
102
|
dst.push("")
|
|
103
103
|
}
|
|
@@ -221,7 +221,7 @@ pub struct Regex {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
// First match of pattern in input, ignoring ASCII case ("" if none).
|
|
224
|
-
pub func match_ci = (string pattern, string input,
|
|
224
|
+
pub func match_ci = (string pattern, string input, mv out string) {
|
|
225
225
|
var string folded = fold_pattern(pattern)
|
|
226
226
|
return Regex.match(folded, input)
|
|
227
227
|
}
|
|
@@ -250,7 +250,7 @@ pub struct Regex {
|
|
|
250
250
|
// their case counterparts ([a-z] -> [a-zA-Z]). Structural syntax — groups,
|
|
251
251
|
// alternation, quantifiers, anchors, escaped punctuation — is copied
|
|
252
252
|
// through unchanged.
|
|
253
|
-
func fold_pattern = (string pattern,
|
|
253
|
+
func fold_pattern = (string pattern, mv out string) {
|
|
254
254
|
var int n = pattern.length
|
|
255
255
|
var sb = StringBuilder()
|
|
256
256
|
var i = 0
|
|
@@ -1925,7 +1925,7 @@ func last_capture_index = (List<int> caps, int group, out int) {
|
|
|
1925
1925
|
/**
|
|
1926
1926
|
* A Regex.find result: whether the pattern matched, where, and what
|
|
1927
1927
|
**/
|
|
1928
|
-
pub struct RegexMatch {
|
|
1928
|
+
pub mv struct RegexMatch {
|
|
1929
1929
|
var found = false
|
|
1930
1930
|
var start = 0
|
|
1931
1931
|
var end = 0
|
package/core/System/Text/Utf8.nm
CHANGED
|
@@ -103,7 +103,7 @@ pub struct Utf8 {
|
|
|
103
103
|
|
|
104
104
|
// Encode a code point as UTF-8. Out-of-range values and surrogate halves
|
|
105
105
|
// encode as U+FFFD.
|
|
106
|
-
pub func encode = (int code_point,
|
|
106
|
+
pub func encode = (int code_point, mv out string) {
|
|
107
107
|
var int code = code_point
|
|
108
108
|
if code < 0 || code > 0x10FFFF {
|
|
109
109
|
code = 0xFFFD
|
|
@@ -125,13 +125,12 @@ pub struct Utf8 {
|
|
|
125
125
|
sb.append_char(((0x80 | ((code >> 6) & 0x3F)) as char))
|
|
126
126
|
sb.append_char(((0x80 | (code & 0x3F)) as char))
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
} else {
|
|
129
129
|
sb.append_char(((0xF0 | (code >> 18)) as char))
|
|
130
130
|
sb.append_char(((0x80 | ((code >> 12) & 0x3F)) as char))
|
|
131
131
|
sb.append_char(((0x80 | ((code >> 6) & 0x3F)) as char))
|
|
132
132
|
sb.append_char(((0x80 | (code & 0x3F)) as char))
|
|
133
133
|
}
|
|
134
|
-
}
|
|
135
134
|
return sb.to_string()
|
|
136
135
|
}
|
|
137
136
|
|
package/core/System/Thread.nm
CHANGED
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
// (and nursery.start) transfer ownership of the packed task out of the
|
|
31
31
|
// value, so a started Thread destroys as a no-op.
|
|
32
32
|
//
|
|
33
|
+
// Thread is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 2 — the shape
|
|
34
|
+
// menu): every field is an opaque handle (uint64/bool), so the value is
|
|
35
|
+
// movable and its `#destroy` closes what the handles name. Moving a Thread
|
|
36
|
+
// transfers the handles; there is no aliasing copy to misuse.
|
|
37
|
+
//
|
|
33
38
|
// See ASYNC.md for the design.
|
|
34
39
|
|
|
35
40
|
// The launch surface's return type (ASYNC.md: the dependency is
|
|
@@ -39,11 +44,11 @@ import Task
|
|
|
39
44
|
/**
|
|
40
45
|
* A deferred function call, startable on the shared worker pool
|
|
41
46
|
**/
|
|
42
|
-
pub
|
|
43
|
-
// The construction hook (ASYNC.md): declares this
|
|
47
|
+
pub mv struct Thread<T> : Spawnable<T> {
|
|
48
|
+
// The construction hook (ASYNC.md): declares this type's
|
|
44
49
|
// construction as the deferred-call special form — the single argument
|
|
45
50
|
// is a call (args packed eagerly, call deferred) or a zero-arg function
|
|
46
|
-
// value. The compiler matches this member, never the
|
|
51
|
+
// value. The compiler matches this member, never the type name; the
|
|
47
52
|
// construction itself is compiler-generated (pack the args, allocate the
|
|
48
53
|
// future machinery, build the instance), so the body is a declaration.
|
|
49
54
|
#spawn = () {
|
|
@@ -77,7 +82,7 @@ pub class Thread<T> : Sendable, Spawnable<T> {
|
|
|
77
82
|
// fields, so #destroy becomes a no-op afterwards. The future's refs
|
|
78
83
|
// account for the trampoline, the returned handle, and the nursery (when
|
|
79
84
|
// captured).
|
|
80
|
-
pub func start = (ref self,
|
|
85
|
+
pub func start = (ref self, mv out Task<T>) {
|
|
81
86
|
```
|
|
82
87
|
#arch: c
|
|
83
88
|
struct nomen_future *_f = (struct nomen_future *)self->future;
|
package/core/System/Tree.nm
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* A tree of values connected by parent/child links
|
|
8
8
|
**/
|
|
9
|
-
pub struct Tree<T>: Enumerable {
|
|
9
|
+
pub mv struct Tree<T>: Enumerable {
|
|
10
10
|
var values = Buffer<T>()
|
|
11
11
|
var lefts = Buffer<int>()
|
|
12
12
|
var rights = Buffer<int>()
|
|
13
13
|
var parents = Buffer<int>()
|
|
14
14
|
var count = 0
|
|
15
15
|
|
|
16
|
-
pub func add = (ref self,
|
|
16
|
+
pub func add = (ref self, mv T value) {
|
|
17
17
|
const int idx = self.count
|
|
18
18
|
self.values.grow_int(idx + 1)
|
|
19
19
|
const int v = value
|
package/core/System/Viewable.nm
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Marker trait for containers that can be borrowed as a non-
|
|
1
|
+
// Marker trait for containers that can be borrowed as a non-mv `view T`
|
|
2
2
|
// slice via a `slice(start, end, out view T)` method. Conforming types
|
|
3
3
|
// implement slice — almost always by delegating to an internal Buffer's slice
|
|
4
4
|
// (`return self.items.slice(start, end)`), so no #arch code is needed in user
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// }
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* A trait for containers that can be borrowed as a non-
|
|
24
|
+
* A trait for containers that can be borrowed as a non-mv `view T` slice
|
|
25
25
|
**/
|
|
26
26
|
pub trait Viewable {
|
|
27
27
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// WeakHandle<T> (STRUCT_PLAN_3 N3) — a checked back-pointer / OS-retained
|
|
2
|
+
// handle. The residue of OS/AppKit retention and child→parent edges: a
|
|
3
|
+
// handle to a registry slot, not a reference — no refcounts, no cycles.
|
|
4
|
+
//
|
|
5
|
+
// var WeakHandle<Window> w = WeakHandle<Window>(window)
|
|
6
|
+
// ...
|
|
7
|
+
// var Window? live = w.get() // nil check at the use site
|
|
8
|
+
//
|
|
9
|
+
// The CREATION is the marker (nothing aliases without one). The race is
|
|
10
|
+
// inherently dynamic — the OS may have torn the object down — so the
|
|
11
|
+
// runtime check in `get` is the only truthful one. The registry is ONE
|
|
12
|
+
// process-wide (pointer, generation) slot table with a free list,
|
|
13
|
+
// internally synchronized (handles are consulted from workers); the
|
|
14
|
+
// tracked type's `#destroy` invalidates every slot holding the pointer
|
|
15
|
+
// (generation bump), and a recycled slot never resets its generation, so a
|
|
16
|
+
// stale handle can never alias a new object. Move-safe by construction: a
|
|
17
|
+
// handle owns nothing.
|
|
18
|
+
//
|
|
19
|
+
// `T` must be a class (enforced at the construction site) — a weak handle
|
|
20
|
+
// to a value-struct local would outlive the stack storage it names.
|
|
21
|
+
//
|
|
22
|
+
// `get` returns the instance pointer, NULL once the instance is gone —
|
|
23
|
+
// bind it to a `T?` and nil-check at the use site.
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A checked, generation-validated handle to a possibly-gone object
|
|
27
|
+
**/
|
|
28
|
+
pub struct WeakHandle<T> {
|
|
29
|
+
// The construction hook (the library-tier marker, beside #init and
|
|
30
|
+
// #destroy): `WeakHandle<T>(obj)` registers `obj` in the process-wide
|
|
31
|
+
// registry. The construction itself is compiler-generated (register the
|
|
32
|
+
// object, capture the slot's generation), so the body is a declaration.
|
|
33
|
+
#weak = () {
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The registry slot id and the generation captured at creation.
|
|
37
|
+
var uint64 id = 0
|
|
38
|
+
var uint64 gen = 0
|
|
39
|
+
|
|
40
|
+
// The checked read: the slot's live pointer, NULL when the instance was
|
|
41
|
+
// destroyed (or the slot was recycled). Bind to `T?` and nil-check.
|
|
42
|
+
// Offsets skip the leading `_vt` slot the auto-derived `to_string`
|
|
43
|
+
// (Stringable conformance) puts on every struct: id at +8, gen at +16.
|
|
44
|
+
pub func get = (self, out T) {
|
|
45
|
+
```
|
|
46
|
+
#arch: c
|
|
47
|
+
return __nomen_weak_get(self->id, self->gen);
|
|
48
|
+
```
|
|
49
|
+
```
|
|
50
|
+
#arch: aarch64
|
|
51
|
+
ldr x1, [x0, #16]
|
|
52
|
+
ldr x0, [x0, #8]
|
|
53
|
+
bl ___nomen_weak_get
|
|
54
|
+
```
|
|
55
|
+
}
|
|
56
|
+
}
|
package/core/System/bool.nm
CHANGED
|
@@ -12,7 +12,7 @@ pub struct bool: Stringable, Hashable, Equatable {
|
|
|
12
12
|
* @param self: the boolean
|
|
13
13
|
* @out string: the boolean as a string value (`"true"` or `"false"`)
|
|
14
14
|
**/
|
|
15
|
-
pub func to_string = (self,
|
|
15
|
+
pub func to_string = (self, mv out string) {
|
|
16
16
|
```
|
|
17
17
|
#arch: c
|
|
18
18
|
int length = snprintf(NULL, 0, "%s", self ? "true" : "false");
|
package/core/System/char.nm
CHANGED
package/core/System/float.nm
CHANGED
package/core/System/float32.nm
CHANGED
package/core/System/float64.nm
CHANGED
package/core/System/int.nm
CHANGED
package/core/System/int16.nm
CHANGED
package/core/System/int32.nm
CHANGED
package/core/System/int64.nm
CHANGED
package/core/System/int8.nm
CHANGED
package/core/System/ufloat.nm
CHANGED
package/core/System/ufloat32.nm
CHANGED
package/core/System/ufloat64.nm
CHANGED
package/core/System/uint.nm
CHANGED
package/core/System/uint16.nm
CHANGED
package/core/System/uint32.nm
CHANGED
package/core/System/uint64.nm
CHANGED