nomen-lang 0.0.7 → 0.0.8

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 (118) hide show
  1. package/NOMEN_AGENTS.md +235 -0
  2. package/core/System/Ansi.nm +150 -0
  3. package/core/System/Array.nm +358 -0
  4. package/core/System/BigInt.nm +887 -0
  5. package/core/System/Buffer.nm +526 -0
  6. package/core/System/Channel.nm +198 -0
  7. package/core/System/ClassBuffer.nm +229 -0
  8. package/core/System/Console.nm +211 -0
  9. package/core/System/Controls/Button.nm +138 -0
  10. package/core/System/Controls/CheckBox.nm +158 -0
  11. package/core/System/Controls/Container.nm +1562 -0
  12. package/core/System/Controls/Control.nm +28 -0
  13. package/core/System/Controls/Geometry.nm +101 -0
  14. package/core/System/Controls/Layout.nm +228 -0
  15. package/core/System/Controls/LayoutParams.nm +50 -0
  16. package/core/System/Controls/Text.nm +129 -0
  17. package/core/System/Controls/TextBox.nm +157 -0
  18. package/core/System/Controls/Window.nm +280 -0
  19. package/core/System/Disposable.nm +8 -0
  20. package/core/System/Enumerable.nm +10 -0
  21. package/core/System/Equatable.nm +10 -0
  22. package/core/System/Graph.nm +68 -0
  23. package/core/System/Hashable.nm +13 -0
  24. package/core/System/Init.nm +21 -0
  25. package/core/System/LinkedList.nm +64 -0
  26. package/core/System/List.nm +44 -0
  27. package/core/System/Map.nm +153 -0
  28. package/core/System/Math.nm +54 -0
  29. package/core/System/Mutex.nm +78 -0
  30. package/core/System/Nursery.nm +27 -0
  31. package/core/System/Sendable.nm +9 -0
  32. package/core/System/Set.nm +97 -0
  33. package/core/System/Stream/Directory.nm +176 -0
  34. package/core/System/Stream/File.nm +432 -0
  35. package/core/System/Stream/Http.nm +453 -0
  36. package/core/System/String.nm +154 -0
  37. package/core/System/StringBuilder.nm +249 -0
  38. package/core/System/Stringable.nm +8 -0
  39. package/core/System/Task.nm +263 -0
  40. package/core/System/Test.nm +241 -0
  41. package/core/System/Text/Json.nm +377 -0
  42. package/core/System/Text/JsonTree.nm +187 -0
  43. package/core/System/Text/Regex.nm +655 -0
  44. package/core/System/Time.nm +112 -0
  45. package/core/System/Tree.nm +70 -0
  46. package/core/System/Viewable.nm +27 -0
  47. package/core/System/bool.nm +66 -0
  48. package/core/System/char.nm +42 -0
  49. package/core/System/float.nm +43 -0
  50. package/core/System/int.nm +54 -0
  51. package/core/System/int64.nm +42 -0
  52. package/core/System/int8.nm +42 -0
  53. package/core/System/uint.nm +42 -0
  54. package/core/System/uint64.nm +42 -0
  55. package/core/System/uint8.nm +42 -0
  56. package/core/docs/System/Ansi.md +40 -0
  57. package/core/docs/System/Array.md +16 -0
  58. package/core/docs/System/BigInt.md +30 -0
  59. package/core/docs/System/Buffer.md +31 -0
  60. package/core/docs/System/Channel.md +10 -0
  61. package/core/docs/System/ClassBuffer.md +15 -0
  62. package/core/docs/System/Console.md +13 -0
  63. package/core/docs/System/Controls/Button.md +12 -0
  64. package/core/docs/System/Controls/CheckBox.md +15 -0
  65. package/core/docs/System/Controls/Container.md +82 -0
  66. package/core/docs/System/Controls/Control.md +5 -0
  67. package/core/docs/System/Controls/Geometry.md +26 -0
  68. package/core/docs/System/Controls/Layout.md +37 -0
  69. package/core/docs/System/Controls/LayoutParams.md +13 -0
  70. package/core/docs/System/Controls/Text.md +12 -0
  71. package/core/docs/System/Controls/TextBox.md +13 -0
  72. package/core/docs/System/Controls/Window.md +20 -0
  73. package/core/docs/System/Disposable.md +5 -0
  74. package/core/docs/System/Enumerable.md +5 -0
  75. package/core/docs/System/Graph.md +17 -0
  76. package/core/docs/System/Init.md +9 -0
  77. package/core/docs/System/LinkedList.md +16 -0
  78. package/core/docs/System/List.md +13 -0
  79. package/core/docs/System/Map.md +14 -0
  80. package/core/docs/System/Math.md +11 -0
  81. package/core/docs/System/Mutex.md +10 -0
  82. package/core/docs/System/Nursery.md +5 -0
  83. package/core/docs/System/Sendable.md +5 -0
  84. package/core/docs/System/Set.md +14 -0
  85. package/core/docs/System/Stream/Directory.md +12 -0
  86. package/core/docs/System/Stream/File.md +21 -0
  87. package/core/docs/System/String.md +14 -0
  88. package/core/docs/System/StringBuilder.md +12 -0
  89. package/core/docs/System/Stringable.md +5 -0
  90. package/core/docs/System/Task.md +15 -0
  91. package/core/docs/System/Text/Json.md +12 -0
  92. package/core/docs/System/Text/JsonTree.md +21 -0
  93. package/core/docs/System/Text/Regex.md +12 -0
  94. package/core/docs/System/Time.md +11 -0
  95. package/core/docs/System/Tree.md +18 -0
  96. package/core/docs/System/Viewable.md +5 -0
  97. package/core/docs/System/bool.md +9 -0
  98. package/core/docs/System/char.md +9 -0
  99. package/core/docs/System/float.md +9 -0
  100. package/core/docs/System/int.md +10 -0
  101. package/core/docs/System/int64.md +9 -0
  102. package/core/docs/System/int8.md +9 -0
  103. package/core/docs/System/uint.md +9 -0
  104. package/core/docs/System/uint64.md +9 -0
  105. package/core/docs/System/uint8.md +9 -0
  106. package/core/package.jsonc +4 -0
  107. package/dist/index.mjs +417 -5490
  108. package/package.json +33 -30
  109. package/src/args.ts +171 -0
  110. package/src/index.ts +53 -104
  111. package/src/init.ts +128 -0
  112. package/src/test.ts +6 -2
  113. package/test/fixtures/build/calc.test +0 -0
  114. package/test/fixtures/build/calc.test.c +0 -969
  115. package/test/fixtures/build/main.h +0 -170
  116. package/test/fixtures/calc.test.nm +0 -32
  117. package/tsconfig.json +0 -21
  118. package/vite.config.ts +0 -7
@@ -0,0 +1,526 @@
1
+ // Buffer<T>: a flat buffer of value slots of type T. The value counterpart to
2
+ // ClassBuffer<T>: no per-element freeing, store_int unconstrained. When T is a
3
+ // class, the monomorphizer rewrites a Buffer<T> field to ClassBuffer<T>.
4
+ /**
5
+ * A flat, low-level buffer of value slots of type T — the backing store for arrays and collections
6
+ **/
7
+ pub struct Buffer<T> {
8
+ var uint64 data = 0
9
+ var cap = 0
10
+
11
+ func alloc = (ref self, int size, out int: out >= size) {
12
+ ```
13
+ #arch: c
14
+ self->cap = size;
15
+ self->data = (unsigned long long)(unsigned int*)calloc(size, sizeof(unsigned int));
16
+ return self->cap;
17
+ ```
18
+ ```
19
+ #arch: aarch64
20
+ str x1, [x19, #16]
21
+ mov x0, x1
22
+ mov x1, #4
23
+ bl _calloc
24
+ str x0, [x19, #8]
25
+ ldr x0, [x19, #16]
26
+ ```
27
+ }
28
+
29
+ func grow = (ref self, int needed, out int: out >= needed) {
30
+ ```
31
+ #arch: c
32
+ if (self->cap >= needed) return self->cap;
33
+ int new_cap = self->cap;
34
+ if (new_cap == 0) new_cap = 8;
35
+ while (new_cap < needed) new_cap *= 2;
36
+ self->data = (unsigned long long)(unsigned int*)realloc((unsigned int*)(unsigned long long)self->data, new_cap * sizeof(unsigned int));
37
+ memset((unsigned int*)(unsigned long long)self->data + self->cap, 0, (new_cap - self->cap) * sizeof(unsigned int));
38
+ self->cap = new_cap;
39
+ return self->cap;
40
+ ```
41
+ ```
42
+ #arch: aarch64
43
+ ldr x2, [x19, #16]
44
+ cmp x2, x1
45
+ b.ge .Lbuffer_grow_end
46
+ mov x3, #8
47
+ cmp x2, #0
48
+ csel x3, x3, x2, eq
49
+ cmp x3, x1
50
+ b.ge .Lbuffer_grow_got
51
+ .Lbuffer_grow_loop:
52
+ lsl x3, x3, #1
53
+ cmp x3, x1
54
+ b.lt .Lbuffer_grow_loop
55
+ .Lbuffer_grow_got:
56
+ sub sp, sp, #16
57
+ str x2, [sp, #0]
58
+ str x3, [sp, #8]
59
+ ldr x0, [x19, #8]
60
+ lsl x1, x3, #2
61
+ bl _realloc
62
+ str x0, [x19, #8]
63
+ ldr x2, [sp, #0]
64
+ ldr x3, [sp, #8]
65
+ add sp, sp, #16
66
+ str x3, [x19, #16]
67
+ add x0, x0, x2, lsl #2
68
+ mov x1, #0
69
+ sub x2, x3, x2
70
+ lsl x2, x2, #2
71
+ bl _memset
72
+ .Lbuffer_grow_end:
73
+ ldr x0, [x19, #16]
74
+ ```
75
+ }
76
+
77
+ func zero = (ref self, int len) {
78
+ ```
79
+ #arch: c
80
+ memset((unsigned int*)(unsigned long long)self->data, 0, len * sizeof(unsigned int));
81
+ ```
82
+ ```
83
+ #arch: aarch64
84
+ ldr x0, [x19, #8]
85
+ lsl x2, x1, #2
86
+ mov x1, #0
87
+ bl _memset
88
+ ```
89
+ }
90
+
91
+ inline func load = (self, int i: i >= 0 && i < self.cap, out uint32) {
92
+ ```
93
+ #arch: c
94
+ return ((unsigned int*)(unsigned long long)self->data)[i];
95
+ ```
96
+ ```
97
+ #arch: aarch64
98
+ ldr x0, [x19, #8]
99
+ lsl x1, x1, #2
100
+ add x0, x0, x1
101
+ ldr w0, [x0]
102
+ and x0, x0, #0xFFFFFFFF
103
+ ```
104
+ }
105
+
106
+ inline func store = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
107
+ ```
108
+ #arch: c
109
+ ((unsigned int*)(unsigned long long)self->data)[i] = val;
110
+ ```
111
+ ```
112
+ #arch: aarch64
113
+ ldr x0, [x19, #8]
114
+ lsl x3, x1, #2
115
+ add x0, x0, x3
116
+ str w2, [x0]
117
+ ```
118
+ }
119
+
120
+ inline func store_or = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
121
+ ```
122
+ #arch: c
123
+ ((unsigned int*)(unsigned long long)self->data)[i] |= val;
124
+ ```
125
+ ```
126
+ #arch: aarch64
127
+ ldr x0, [x19, #8]
128
+ lsl x3, x1, #2
129
+ add x0, x0, x3
130
+ ldr w3, [x0]
131
+ orr w3, w3, w2
132
+ str w3, [x0]
133
+ ```
134
+ }
135
+
136
+ func alloc_int = (ref self, int size, out int: out >= size) {
137
+ ```
138
+ #arch: c
139
+ self->cap = size;
140
+ self->data = (unsigned long long)(long*)calloc(size, sizeof(long));
141
+ return self->cap;
142
+ ```
143
+ ```
144
+ #arch: aarch64
145
+ str x1, [x19, #16]
146
+ mov x0, x1
147
+ mov x1, #8
148
+ bl _calloc
149
+ str x0, [x19, #8]
150
+ ldr x0, [x19, #16]
151
+ ```
152
+ }
153
+
154
+ func grow_int = (ref self, int needed, out int: out >= needed) {
155
+ ```
156
+ #arch: c
157
+ if (self->cap >= needed) return self->cap;
158
+ int new_cap = self->cap;
159
+ if (new_cap == 0) new_cap = 4;
160
+ while (new_cap < needed) new_cap *= 2;
161
+ self->data = (unsigned long long)(long*)realloc((long*)(unsigned long long)self->data, new_cap * sizeof(long));
162
+ memset((long*)(unsigned long long)self->data + self->cap, 0, (new_cap - self->cap) * sizeof(long));
163
+ self->cap = new_cap;
164
+ return self->cap;
165
+ ```
166
+ ```
167
+ #arch: aarch64
168
+ ldr x2, [x19, #16]
169
+ cmp x2, x1
170
+ b.ge .Lbuffer_grow_int_end
171
+ mov x3, #4
172
+ cmp x2, #0
173
+ csel x3, x3, x2, eq
174
+ cmp x3, x1
175
+ b.ge .Lbuffer_grow_int_got
176
+ .Lbuffer_grow_int_loop:
177
+ lsl x3, x3, #1
178
+ cmp x3, x1
179
+ b.lt .Lbuffer_grow_int_loop
180
+ .Lbuffer_grow_int_got:
181
+ sub sp, sp, #16
182
+ str x2, [sp, #0]
183
+ str x3, [sp, #8]
184
+ ldr x0, [x19, #8]
185
+ lsl x1, x3, #3
186
+ bl _realloc
187
+ str x0, [x19, #8]
188
+ ldr x2, [sp, #0]
189
+ ldr x3, [sp, #8]
190
+ add sp, sp, #16
191
+ str x3, [x19, #16]
192
+ add x0, x0, x2, lsl #3
193
+ mov x1, #0
194
+ sub x2, x3, x2
195
+ lsl x2, x2, #3
196
+ bl _memset
197
+ .Lbuffer_grow_int_end:
198
+ ldr x0, [x19, #16]
199
+ ```
200
+ }
201
+
202
+ inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
203
+ ```
204
+ #arch: c
205
+ return ((long*)(unsigned long long)self->data)[i];
206
+ ```
207
+ ```
208
+ #arch: aarch64
209
+ ldr x0, [x19, #8]
210
+ lsl x1, x1, #3
211
+ add x0, x0, x1
212
+ ldr x0, [x0]
213
+ ```
214
+ }
215
+
216
+ inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
217
+ ```
218
+ #arch: c
219
+ ((long*)(unsigned long long)self->data)[i] = val;
220
+ ```
221
+ ```
222
+ #arch: aarch64
223
+ ldr x0, [x19, #8]
224
+ lsl x3, x1, #3
225
+ add x0, x0, x3
226
+ str x2, [x0]
227
+ ```
228
+ }
229
+
230
+ // Move a value out of a slot: return it and clear the slot to 0. This is
231
+ // the ownership-extracting primitive (used by e.g. List.pop) — unlike
232
+ // load_int (a borrow read), it relinquishes the slot so the buffer no
233
+ // longer owns the value.
234
+ inline func move_int = (ref self, int i: i >= 0 && i < self.cap, out int) {
235
+ ```
236
+ #arch: c
237
+ long *slots = (long*)(unsigned long long)self->data;
238
+ long val = slots[i];
239
+ slots[i] = 0;
240
+ return val;
241
+ ```
242
+ ```
243
+ #arch: aarch64
244
+ ldr x0, [x19, #8]
245
+ lsl x3, x1, #3
246
+ add x3, x0, x3
247
+ ldr x0, [x3]
248
+ str xzr, [x3]
249
+ ```
250
+ }
251
+
252
+ // Store into a slot, freeing the previous value when the buffer holds
253
+ // owned class pointers (has_class_refs). For non-class buffers this is a
254
+ // plain store, so it is safe to use anywhere store_int would be.
255
+ inline func replace_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
256
+ ```
257
+ #arch: c
258
+ ((long*)(unsigned long long)self->data)[i] = val;
259
+ ```
260
+ ```
261
+ #arch: aarch64
262
+ ldr x0, [x19, #8]
263
+ lsl x3, x1, #3
264
+ add x0, x0, x3
265
+ str x2, [x0]
266
+ ```
267
+ }
268
+
269
+ inline func zero_int = (ref self, int len) {
270
+ ```
271
+ #arch: c
272
+ memset((long*)(unsigned long long)self->data, 0, len * sizeof(long));
273
+ ```
274
+ ```
275
+ #arch: aarch64
276
+ ldr x0, [x19, #8]
277
+ lsl x2, x1, #3
278
+ mov x1, #0
279
+ bl _memset
280
+ ```
281
+ }
282
+
283
+ // T_SIZE-aware primitives for value-struct elements. Slab is sized in
284
+ // multiples of T_SIZE; load/store use memcpy so multi-word structs work
285
+ // correctly. Classes route to ClassBuffer<T> (per-element destroy), so T
286
+ // reaching here is always a value type (primitive or struct).
287
+
288
+ func alloc_T = (ref self, int size, out int: out >= size) {
289
+ ```
290
+ #arch: c
291
+ self->cap = size;
292
+ self->data = (unsigned long long)(T*)calloc(size, T_SIZE);
293
+ return self->cap;
294
+ ```
295
+ ```
296
+ #arch: aarch64
297
+ str x1, [x19, #16]
298
+ mov x0, x1
299
+ mov x1, #T_SIZE
300
+ bl _calloc
301
+ str x0, [x19, #8]
302
+ ldr x0, [x19, #16]
303
+ ```
304
+ }
305
+
306
+ func grow_T = (ref self, int needed, out int: out >= needed) {
307
+ ```
308
+ #arch: c
309
+ if (self->cap >= needed) return self->cap;
310
+ int new_cap = self->cap;
311
+ if (new_cap == 0) new_cap = 4;
312
+ while (new_cap < needed) new_cap *= 2;
313
+ self->data = (unsigned long long)(T*)realloc((T*)(unsigned long long)self->data, new_cap * T_SIZE);
314
+ memset((char*)(unsigned long long)self->data + self->cap * T_SIZE, 0, (new_cap - self->cap) * T_SIZE);
315
+ self->cap = new_cap;
316
+ return self->cap;
317
+ ```
318
+ ```
319
+ #arch: aarch64
320
+ ldr x2, [x19, #16]
321
+ cmp x2, x1
322
+ b.ge .Lbuffer_grow_T_end
323
+ mov x3, #4
324
+ cmp x2, #0
325
+ csel x3, x3, x2, eq
326
+ cmp x3, x1
327
+ b.ge .Lbuffer_grow_T_got
328
+ .Lbuffer_grow_T_loop:
329
+ lsl x3, x3, #1
330
+ cmp x3, x1
331
+ b.lt .Lbuffer_grow_T_loop
332
+ .Lbuffer_grow_T_got:
333
+ sub sp, sp, #32
334
+ str x2, [sp, #0]
335
+ str x3, [sp, #8]
336
+ mov x4, #T_SIZE
337
+ str x4, [sp, #16]
338
+ ldr x0, [x19, #8]
339
+ madd x1, x3, x4, xzr
340
+ bl _realloc
341
+ str x0, [x19, #8]
342
+ ldr x2, [sp, #0]
343
+ ldr x3, [sp, #8]
344
+ ldr x4, [sp, #16]
345
+ add sp, sp, #32
346
+ str x3, [x19, #16]
347
+ ldr x0, [x19, #8]
348
+ mul x5, x2, x4
349
+ add x0, x0, x5
350
+ sub x2, x3, x2
351
+ mul x2, x2, x4
352
+ mov x1, #0
353
+ bl _memset
354
+ .Lbuffer_grow_T_end:
355
+ ldr x0, [x19, #16]
356
+ ```
357
+ }
358
+
359
+ func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
360
+ ```
361
+ #arch: c
362
+ return ((T*)(unsigned long long)self->data)[i];
363
+ ```
364
+ ```
365
+ #arch: aarch64
366
+ // x19 = self, x1 = i, x8 = return buf for structs
367
+ ldr x0, [x19, #8]
368
+ mov x3, #T_SIZE
369
+ madd x1, x1, x3, xzr
370
+ add x0, x0, x1
371
+ cmp x3, #8
372
+ b.gt .Lbuffer_load_T_copy
373
+ ldr x0, [x0]
374
+ b .Lbuffer_load_T_end
375
+ .Lbuffer_load_T_copy:
376
+ mov x1, x0
377
+ mov x0, x8
378
+ mov x2, x3
379
+ bl _memcpy
380
+ .Lbuffer_load_T_end:
381
+ ```
382
+ }
383
+
384
+ func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
385
+ ```
386
+ #arch: c
387
+ ((T*)(unsigned long long)self->data)[i] = val;
388
+ ```
389
+ ```
390
+ #arch: aarch64
391
+ // x19 = self, x1 = i, x2 = val (value if T_SIZE<=8, address if struct)
392
+ ldr x0, [x19, #8]
393
+ mov x3, #T_SIZE
394
+ madd x1, x1, x3, xzr
395
+ add x0, x0, x1
396
+ cmp x3, #8
397
+ b.gt .Lbuffer_store_T_copy
398
+ str x2, [x0]
399
+ b .Lbuffer_store_T_end
400
+ .Lbuffer_store_T_copy:
401
+ mov x1, x2
402
+ mov x2, x3
403
+ bl _memcpy
404
+ .Lbuffer_store_T_end:
405
+ ```
406
+ }
407
+
408
+ // A non-owning (ptr, len) slice [start, end) over this buffer's element
409
+ // storage, returned as a `view T`. It borrows from self: it may not outlive
410
+ // self's scope and is invalidated if self is reassigned. This is the single
411
+ // primitive every other slice (Array<T>, List<T>, user containers) builds
412
+ // on — higher layers just `return self.items.slice(start, end)`.
413
+ func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
414
+ ```
415
+ #arch: c
416
+ nomen_view _r;
417
+ _r.ptr = (void*)((T*)(unsigned long long)self->data + start);
418
+ _r.len = (long)(end - start);
419
+ return _r;
420
+ ```
421
+ ```
422
+ #arch: aarch64
423
+ // x19 = self (Buffer struct ptr), x1 = start, x2 = end.
424
+ // self->data lives at [x19, #8]. Return (ptr, len) in x0/x1.
425
+ ldr x0, [x19, #8]
426
+ mov x3, #T_SIZE
427
+ madd x0, x1, x3, x0
428
+ sub x1, x2, x1
429
+ ```
430
+ }
431
+
432
+ inline func zero_T = (ref self, int len) {
433
+ ```
434
+ #arch: c
435
+ memset((T*)(unsigned long long)self->data, 0, len * T_SIZE);
436
+ ```
437
+ ```
438
+ #arch: aarch64
439
+ ldr x0, [x19, #8]
440
+ mov x2, #T_SIZE
441
+ mul x2, x1, x2
442
+ mov x1, #0
443
+ bl _memset
444
+ ```
445
+ }
446
+
447
+ inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
448
+ ```
449
+ #arch: c
450
+ ((long*)(unsigned long long)self->data)[i] |= val;
451
+ ```
452
+ ```
453
+ #arch: aarch64
454
+ ldr x0, [x19, #8]
455
+ lsl x3, x1, #3
456
+ add x0, x0, x3
457
+ ldr x3, [x0]
458
+ orr x3, x3, x2
459
+ str x3, [x0]
460
+ ```
461
+ }
462
+
463
+ func alloc_float = (ref self, int size, out int: out >= size) {
464
+ ```
465
+ #arch: c
466
+ self->cap = size;
467
+ self->data = (unsigned long long)(double*)calloc(size, sizeof(double));
468
+ return self->cap;
469
+ ```
470
+ ```
471
+ #arch: aarch64
472
+ str x1, [x19, #16]
473
+ mov x0, x1
474
+ mov x1, #8
475
+ bl _calloc
476
+ str x0, [x19, #8]
477
+ ldr x0, [x19, #16]
478
+ ```
479
+ }
480
+
481
+ inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
482
+ ```
483
+ #arch: c
484
+ return ((double*)(unsigned long long)self->data)[i];
485
+ ```
486
+ ```
487
+ #arch: aarch64
488
+ ldr x0, [x19, #8]
489
+ lsl x1, x1, #3
490
+ add x0, x0, x1
491
+ ldr x0, [x0]
492
+ ```
493
+ }
494
+
495
+ inline func store_float = (ref self, int i: i >= 0 && i < self.cap, float val) {
496
+ ```
497
+ #arch: c
498
+ ((double*)(unsigned long long)self->data)[i] = val;
499
+ ```
500
+ ```
501
+ #arch: aarch64
502
+ ldr x0, [x19, #8]
503
+ lsl x3, x1, #3
504
+ add x0, x0, x3
505
+ str x2, [x0]
506
+ ```
507
+ }
508
+
509
+ func #destroy = () {
510
+ ```
511
+ #arch: c
512
+ if (self->data) free((unsigned int*)(unsigned long long)self->data);
513
+ self->data = 0;
514
+ self->cap = 0;
515
+ ```
516
+ ```
517
+ #arch: aarch64
518
+ ldr x0, [x19, #8]
519
+ cbz x0, .Lbuffer_destroy_end
520
+ bl _free
521
+ .Lbuffer_destroy_end:
522
+ str xzr, [x19, #8]
523
+ str xzr, [x19, #16]
524
+ ```
525
+ }
526
+ }
@@ -0,0 +1,198 @@
1
+ // Channel — thread-safe single-direction queue for passing values between
2
+ // tasks. Unbounded, FIFO, blocking receive.
3
+ //
4
+ // Stores uint64 values (Nomen values are pointer-sized on every target we
5
+ // care about). A typed Channel<T> wrapper can come later — the storage story
6
+ // is identical, only the call-site types change.
7
+ //
8
+ // Default stance in Nomen is "no shared mutable state" — channels are the
9
+ // preferred way for tasks to communicate. See ASYNC.md.
10
+
11
+ /**
12
+ * A thread-safe, blocking FIFO queue for passing values between tasks
13
+ **/
14
+ pub class Channel: Sendable {
15
+ pub var uint64 mu = 0
16
+ pub var uint64 not_empty_cv = 0
17
+ pub var uint64 head = 0
18
+ pub var uint64 tail = 0
19
+
20
+ pub func #init = (self) {
21
+ ```
22
+ #arch: c
23
+ #scope: file
24
+ #include <pthread.h>
25
+ struct nomen_channel_node {
26
+ unsigned long long value;
27
+ struct nomen_channel_node *next;
28
+ };
29
+ ```
30
+ ```
31
+ #arch: c
32
+ self->mu = (unsigned long long)malloc(sizeof(pthread_mutex_t));
33
+ self->not_empty_cv = (unsigned long long)malloc(sizeof(pthread_cond_t));
34
+ pthread_mutex_init((pthread_mutex_t *)self->mu, NULL);
35
+ pthread_cond_init((pthread_cond_t *)self->not_empty_cv, NULL);
36
+ self->head = 0;
37
+ self->tail = 0;
38
+ ```
39
+ ```
40
+ #arch: aarch64
41
+ mov x0, #64
42
+ bl _malloc
43
+ str x0, [x19, #8]
44
+ mov x1, #0
45
+ bl _pthread_mutex_init
46
+ mov x0, #64
47
+ bl _malloc
48
+ str x0, [x19, #16]
49
+ mov x1, #0
50
+ bl _pthread_cond_init
51
+ str xzr, [x19, #24]
52
+ str xzr, [x19, #32]
53
+ ```
54
+ }
55
+
56
+ pub func send = (self, uint64 value) {
57
+ ```
58
+ #arch: c
59
+ struct nomen_channel_node *n = (struct nomen_channel_node *)malloc(sizeof(struct nomen_channel_node));
60
+ n->value = value;
61
+ n->next = NULL;
62
+ pthread_mutex_lock((pthread_mutex_t *)self->mu);
63
+ if (self->tail) {
64
+ ((struct nomen_channel_node *)self->tail)->next = n;
65
+ } else {
66
+ self->head = (unsigned long long)n;
67
+ }
68
+ self->tail = (unsigned long long)n;
69
+ pthread_cond_signal((pthread_cond_t *)self->not_empty_cv);
70
+ pthread_mutex_unlock((pthread_mutex_t *)self->mu);
71
+ ```
72
+ ```
73
+ #arch: aarch64
74
+ // x19 = self (set by prologue), x1 = value
75
+ str x1, [sp, #-16]! // save value on stack
76
+ mov x0, #16
77
+ bl _malloc // x0 = node
78
+ ldr x1, [sp], #16 // restore value
79
+ str x1, [x0, #0] // node->value = value
80
+ str xzr, [x0, #8] // node->next = NULL
81
+ str x0, [sp, #-16]! // save node on stack
82
+ ldr x0, [x19, #8] // self->mu
83
+ bl _pthread_mutex_lock
84
+ ldr x2, [sp], #16 // restore node
85
+ ldr x1, [x19, #32] // tail
86
+ cbz x1, .Lchannel_send_empty
87
+ str x2, [x1, #8] // tail->next = node
88
+ b .Lchannel_send_enqueued
89
+ .Lchannel_send_empty:
90
+ str x2, [x19, #24] // head = node
91
+ .Lchannel_send_enqueued:
92
+ str x2, [x19, #32] // tail = node
93
+ ldr x0, [x19, #16] // not_empty_cv
94
+ bl _pthread_cond_signal
95
+ ldr x0, [x19, #8] // self->mu
96
+ bl _pthread_mutex_unlock
97
+ ```
98
+ }
99
+
100
+ pub func receive = (self, out uint64) {
101
+ ```
102
+ #arch: c
103
+ pthread_mutex_lock((pthread_mutex_t *)self->mu);
104
+ while (!self->head) {
105
+ pthread_cond_wait((pthread_cond_t *)self->not_empty_cv, (pthread_mutex_t *)self->mu);
106
+ }
107
+ struct nomen_channel_node *n = (struct nomen_channel_node *)self->head;
108
+ self->head = (unsigned long long)n->next;
109
+ if (!self->head) self->tail = 0;
110
+ unsigned long long v = n->value;
111
+ free(n);
112
+ pthread_mutex_unlock((pthread_mutex_t *)self->mu);
113
+ return v;
114
+ ```
115
+ ```
116
+ #arch: aarch64
117
+ // x19 = self (set by prologue)
118
+ ldr x0, [x19, #8] // self->mu
119
+ bl _pthread_mutex_lock
120
+ .Lchannel_receive_wait:
121
+ ldr x1, [x19, #24] // head
122
+ cbnz x1, .Lchannel_receive_got
123
+ ldr x0, [x19, #16] // not_empty_cv
124
+ ldr x1, [x19, #8] // mu
125
+ bl _pthread_cond_wait
126
+ b .Lchannel_receive_wait
127
+ .Lchannel_receive_got:
128
+ // x1 = node
129
+ ldr x2, [x1, #8] // node->next
130
+ str x2, [x19, #24] // head = node->next
131
+ cbnz x2, .Lchannel_receive_not_empty
132
+ str xzr, [x19, #32] // tail = 0
133
+ .Lchannel_receive_not_empty:
134
+ ldr x0, [x1, #0] // x0 = value
135
+ str x0, [sp, #-16]! // push value
136
+ mov x0, x1 // x0 = node (for free)
137
+ bl _free
138
+ ldr x0, [x19, #8] // self->mu
139
+ bl _pthread_mutex_unlock
140
+ ldr x0, [sp], #16 // pop value → x0 (return)
141
+ ```
142
+ }
143
+
144
+ pub func #destroy = () {
145
+ ```
146
+ #arch: c
147
+ if (self->mu) {
148
+ // Drain any pending nodes.
149
+ struct nomen_channel_node *n = (struct nomen_channel_node *)self->head;
150
+ while (n) {
151
+ struct nomen_channel_node *next = n->next;
152
+ free(n);
153
+ n = next;
154
+ }
155
+ pthread_mutex_destroy((pthread_mutex_t *)self->mu);
156
+ pthread_cond_destroy((pthread_cond_t *)self->not_empty_cv);
157
+ free((void *)self->mu);
158
+ free((void *)self->not_empty_cv);
159
+ self->mu = 0;
160
+ self->not_empty_cv = 0;
161
+ self->head = 0;
162
+ self->tail = 0;
163
+ }
164
+ ```
165
+ ```
166
+ #arch: aarch64
167
+ // x19 = self (set by prologue)
168
+ ldr x0, [x19, #8] // self->mu
169
+ cbz x0, .Lchannel_destroy_done
170
+ // Drain nodes
171
+ ldr x1, [x19, #24] // head
172
+ .Lchannel_destroy_drain:
173
+ cbz x1, .Lchannel_destroy_drained
174
+ ldr x2, [x1, #8] // next (before free clobbers it)
175
+ str x2, [sp, #-16]! // save next on stack
176
+ bl _free
177
+ ldr x1, [sp], #16 // restore next
178
+ b .Lchannel_destroy_drain
179
+ .Lchannel_destroy_drained:
180
+ // Destroy mutex and condvar
181
+ ldr x0, [x19, #8]
182
+ bl _pthread_mutex_destroy
183
+ ldr x0, [x19, #16]
184
+ bl _pthread_cond_destroy
185
+ // Free mutex and condvar allocations
186
+ ldr x0, [x19, #8]
187
+ bl _free
188
+ ldr x0, [x19, #16]
189
+ bl _free
190
+ // Zero all fields
191
+ str xzr, [x19, #8]
192
+ str xzr, [x19, #16]
193
+ str xzr, [x19, #24]
194
+ str xzr, [x19, #32]
195
+ .Lchannel_destroy_done:
196
+ ```
197
+ }
198
+ }