nomen-lang 0.0.10 → 0.0.12
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/core/System/Array.nm +104 -9
- package/core/System/Buffer.nm +144 -0
- package/core/System/ClassBuffer.nm +143 -0
- package/core/System/Graph.nm +4 -5
- package/core/System/Init.nm +3 -1
- package/core/System/LinkedList.nm +4 -5
- package/core/System/List.nm +25 -7
- package/core/System/Map.nm +29 -19
- package/core/System/Option.nm +4 -0
- package/core/System/Result.nm +4 -0
- package/core/System/Set.nm +59 -13
- package/core/System/String.nm +27 -1
- package/core/System/Test.nm +1 -3
- package/core/System/Text/JsonTree.nm +11 -3
- package/core/System/Text/Regex.nm +4 -1
- package/core/System/bool.nm +12 -1
- package/core/System/char.nm +12 -1
- package/core/System/int.nm +12 -1
- package/core/System/int64.nm +12 -1
- package/core/System/int8.nm +12 -1
- package/core/System/uint.nm +12 -1
- package/core/System/uint64.nm +12 -1
- package/core/System/uint8.nm +12 -1
- package/core/docs/System/Init.md +2 -1
- package/core/docs/System/Option.md +23 -0
- package/core/docs/System/Result.md +19 -0
- package/dist/index.mjs +7382 -5214
- package/package.json +34 -33
- package/src/args.ts +11 -9
- package/src/index.ts +22 -16
package/core/System/Array.nm
CHANGED
|
@@ -38,10 +38,35 @@ pub struct Array<T>: Viewable {
|
|
|
38
38
|
```
|
|
39
39
|
```
|
|
40
40
|
#arch: aarch64
|
|
41
|
-
// x19 = self (first elem), x1 = index
|
|
41
|
+
// x19 = self (first elem), x1 = index, x8 = return buf for structs
|
|
42
42
|
mov x2, #T_SIZE
|
|
43
43
|
mul x1, x1, x2
|
|
44
|
+
cmp x2, #8
|
|
45
|
+
b.eq .L_at_8
|
|
46
|
+
b.gt .L_at_copy
|
|
47
|
+
cmp x2, #1
|
|
48
|
+
b.eq .L_at_1
|
|
49
|
+
cmp x2, #2
|
|
50
|
+
b.eq .L_at_2
|
|
51
|
+
ldr w0, [x19, x1]
|
|
52
|
+
b .L_at_end
|
|
53
|
+
.L_at_8:
|
|
44
54
|
ldr x0, [x19, x1]
|
|
55
|
+
b .L_at_end
|
|
56
|
+
.L_at_1:
|
|
57
|
+
ldrb w0, [x19, x1]
|
|
58
|
+
b .L_at_end
|
|
59
|
+
.L_at_2:
|
|
60
|
+
ldrh w0, [x19, x1]
|
|
61
|
+
b .L_at_end
|
|
62
|
+
// Struct element (T_SIZE > 8): copy the slot bytes into the x8
|
|
63
|
+
// sret buffer and return its address (Buffer.load_T convention).
|
|
64
|
+
.L_at_copy:
|
|
65
|
+
mov x0, x8
|
|
66
|
+
add x1, x19, x1
|
|
67
|
+
bl _memcpy
|
|
68
|
+
mov x0, x8
|
|
69
|
+
.L_at_end:
|
|
45
70
|
```
|
|
46
71
|
}
|
|
47
72
|
|
|
@@ -53,8 +78,35 @@ pub struct Array<T>: Viewable {
|
|
|
53
78
|
```
|
|
54
79
|
```
|
|
55
80
|
#arch: aarch64
|
|
56
|
-
// x19 = self (first elem)
|
|
81
|
+
// x19 = self (first elem), x8 = return buf for structs
|
|
82
|
+
mov x3, #T_SIZE
|
|
83
|
+
cmp x3, #8
|
|
84
|
+
b.eq .L_first_8
|
|
85
|
+
b.gt .L_first_copy
|
|
86
|
+
cmp x3, #1
|
|
87
|
+
b.eq .L_first_1
|
|
88
|
+
cmp x3, #2
|
|
89
|
+
b.eq .L_first_2
|
|
90
|
+
ldr w0, [x19]
|
|
91
|
+
b .L_first_end
|
|
92
|
+
.L_first_8:
|
|
57
93
|
ldr x0, [x19]
|
|
94
|
+
b .L_first_end
|
|
95
|
+
.L_first_1:
|
|
96
|
+
ldrb w0, [x19]
|
|
97
|
+
b .L_first_end
|
|
98
|
+
.L_first_2:
|
|
99
|
+
ldrh w0, [x19]
|
|
100
|
+
b .L_first_end
|
|
101
|
+
// Struct element (T_SIZE > 8): copy the first slot's bytes into
|
|
102
|
+
// the x8 sret buffer and return its address.
|
|
103
|
+
.L_first_copy:
|
|
104
|
+
mov x0, x8
|
|
105
|
+
mov x1, x19
|
|
106
|
+
mov x2, x3
|
|
107
|
+
bl _memcpy
|
|
108
|
+
mov x0, x8
|
|
109
|
+
.L_first_end:
|
|
58
110
|
```
|
|
59
111
|
}
|
|
60
112
|
|
|
@@ -75,18 +127,35 @@ pub struct Array<T>: Viewable {
|
|
|
75
127
|
```
|
|
76
128
|
```
|
|
77
129
|
#arch: aarch64
|
|
78
|
-
// x19 = self (first elem), x1 = index, x2 = value
|
|
130
|
+
// x19 = self (first elem), x1 = index, x2 = value (address if struct)
|
|
79
131
|
mov x3, #T_SIZE
|
|
80
132
|
mul x1, x1, x3
|
|
81
|
-
// Only use the 8-byte store when T_SIZE is exactly 8 (int/string/ptr).
|
|
82
|
-
// For smaller types (char/bool/int8/etc.) strb/strh/str w/ would
|
|
83
|
-
// clobber adjacent slots, so fall through to a size-aware store.
|
|
84
133
|
cmp x3, #8
|
|
85
|
-
b.
|
|
134
|
+
b.eq .L_set_8
|
|
135
|
+
b.gt .L_set_copy
|
|
136
|
+
cmp x3, #1
|
|
137
|
+
b.eq .L_set_1
|
|
138
|
+
cmp x3, #2
|
|
139
|
+
b.eq .L_set_2
|
|
140
|
+
str w2, [x19, x1]
|
|
141
|
+
b .L_set_done
|
|
142
|
+
.L_set_8:
|
|
86
143
|
str x2, [x19, x1]
|
|
87
144
|
b .L_set_done
|
|
88
|
-
.
|
|
145
|
+
.L_set_1:
|
|
89
146
|
strb w2, [x19, x1]
|
|
147
|
+
b .L_set_done
|
|
148
|
+
.L_set_2:
|
|
149
|
+
strh w2, [x19, x1]
|
|
150
|
+
b .L_set_done
|
|
151
|
+
// Struct element (T_SIZE > 8): x2 holds the ADDRESS of the value
|
|
152
|
+
// bytes — memcpy them into the slot (Buffer.store_T convention).
|
|
153
|
+
.L_set_copy:
|
|
154
|
+
mov x0, x19
|
|
155
|
+
add x0, x0, x1
|
|
156
|
+
mov x1, x2
|
|
157
|
+
mov x2, x3
|
|
158
|
+
bl _memcpy
|
|
90
159
|
.L_set_done:
|
|
91
160
|
```
|
|
92
161
|
}
|
|
@@ -99,12 +168,38 @@ pub struct Array<T>: Viewable {
|
|
|
99
168
|
```
|
|
100
169
|
```
|
|
101
170
|
#arch: aarch64
|
|
102
|
-
// x19 = self (first elem), length at [x19 - 8]
|
|
171
|
+
// x19 = self (first elem), length at [x19 - 8], x8 = return buf for structs
|
|
103
172
|
ldr x0, [x19, #-8]
|
|
104
173
|
sub x0, x0, #1
|
|
105
174
|
mov x1, #T_SIZE
|
|
106
175
|
mul x0, x0, x1
|
|
176
|
+
cmp x1, #8
|
|
177
|
+
b.eq .L_at_end_8
|
|
178
|
+
b.gt .L_at_end_copy
|
|
179
|
+
cmp x1, #1
|
|
180
|
+
b.eq .L_at_end_1
|
|
181
|
+
cmp x1, #2
|
|
182
|
+
b.eq .L_at_end_2
|
|
183
|
+
ldr w0, [x19, x0]
|
|
184
|
+
b .L_at_end_done
|
|
185
|
+
.L_at_end_8:
|
|
107
186
|
ldr x0, [x19, x0]
|
|
187
|
+
b .L_at_end_done
|
|
188
|
+
.L_at_end_1:
|
|
189
|
+
ldrb w0, [x19, x0]
|
|
190
|
+
b .L_at_end_done
|
|
191
|
+
.L_at_end_2:
|
|
192
|
+
ldrh w0, [x19, x0]
|
|
193
|
+
b .L_at_end_done
|
|
194
|
+
// Struct element (T_SIZE > 8): x0 = byte offset of the last slot —
|
|
195
|
+
// copy its bytes into the x8 sret buffer and return its address.
|
|
196
|
+
.L_at_end_copy:
|
|
197
|
+
mov x2, x1
|
|
198
|
+
add x1, x19, x0
|
|
199
|
+
mov x0, x8
|
|
200
|
+
bl _memcpy
|
|
201
|
+
mov x0, x8
|
|
202
|
+
.L_at_end_done:
|
|
108
203
|
```
|
|
109
204
|
}
|
|
110
205
|
|
package/core/System/Buffer.nm
CHANGED
|
@@ -370,8 +370,26 @@ pub struct Buffer<T> {
|
|
|
370
370
|
add x0, x0, x1
|
|
371
371
|
cmp x3, #8
|
|
372
372
|
b.gt .Lbuffer_load_T_copy
|
|
373
|
+
// Width-matched load (zero-extends) — an 8-byte ldr on a sub-8
|
|
374
|
+
// element would read past the slab's end and leave garbage in the
|
|
375
|
+
// upper bits.
|
|
376
|
+
cmp x3, #1
|
|
377
|
+
b.eq .Lbuffer_load_T_1
|
|
378
|
+
cmp x3, #2
|
|
379
|
+
b.eq .Lbuffer_load_T_2
|
|
380
|
+
cmp x3, #4
|
|
381
|
+
b.eq .Lbuffer_load_T_4
|
|
373
382
|
ldr x0, [x0]
|
|
374
383
|
b .Lbuffer_load_T_end
|
|
384
|
+
.Lbuffer_load_T_1:
|
|
385
|
+
ldrb w0, [x0]
|
|
386
|
+
b .Lbuffer_load_T_end
|
|
387
|
+
.Lbuffer_load_T_2:
|
|
388
|
+
ldrh w0, [x0]
|
|
389
|
+
b .Lbuffer_load_T_end
|
|
390
|
+
.Lbuffer_load_T_4:
|
|
391
|
+
ldr w0, [x0]
|
|
392
|
+
b .Lbuffer_load_T_end
|
|
375
393
|
.Lbuffer_load_T_copy:
|
|
376
394
|
mov x1, x0
|
|
377
395
|
mov x0, x8
|
|
@@ -395,8 +413,25 @@ pub struct Buffer<T> {
|
|
|
395
413
|
add x0, x0, x1
|
|
396
414
|
cmp x3, #8
|
|
397
415
|
b.gt .Lbuffer_store_T_copy
|
|
416
|
+
// Sub-8 element types must use a width-matched store: an 8-byte str
|
|
417
|
+
// would clobber the following slots (and run past the slab's end).
|
|
418
|
+
cmp x3, #1
|
|
419
|
+
b.eq .Lbuffer_store_T_1
|
|
420
|
+
cmp x3, #2
|
|
421
|
+
b.eq .Lbuffer_store_T_2
|
|
422
|
+
cmp x3, #4
|
|
423
|
+
b.eq .Lbuffer_store_T_4
|
|
398
424
|
str x2, [x0]
|
|
399
425
|
b .Lbuffer_store_T_end
|
|
426
|
+
.Lbuffer_store_T_1:
|
|
427
|
+
strb w2, [x0]
|
|
428
|
+
b .Lbuffer_store_T_end
|
|
429
|
+
.Lbuffer_store_T_2:
|
|
430
|
+
strh w2, [x0]
|
|
431
|
+
b .Lbuffer_store_T_end
|
|
432
|
+
.Lbuffer_store_T_4:
|
|
433
|
+
str w2, [x0]
|
|
434
|
+
b .Lbuffer_store_T_end
|
|
400
435
|
.Lbuffer_store_T_copy:
|
|
401
436
|
mov x1, x2
|
|
402
437
|
mov x2, x3
|
|
@@ -405,6 +440,115 @@ pub struct Buffer<T> {
|
|
|
405
440
|
```
|
|
406
441
|
}
|
|
407
442
|
|
|
443
|
+
// Move a value out of a T_SIZE-sized slot: return it and zero the slot so the
|
|
444
|
+
// buffer no longer holds a (possibly owning) copy. Declared `mov out T` so
|
|
445
|
+
// the result is treated as OWNED by the borrow checker — the slot is
|
|
446
|
+
// relinquished, so the caller is the sole remaining owner. The value
|
|
447
|
+
// counterpart of ClassBuffer.move_int — used by List.pop for any value T.
|
|
448
|
+
inline func move_T = (ref self, int i: i >= 0 && i < self.cap, mov out T) {
|
|
449
|
+
```
|
|
450
|
+
#arch: c
|
|
451
|
+
T* _slots = (T*)(unsigned long long)self->data;
|
|
452
|
+
T _tmp = _slots[i];
|
|
453
|
+
memset((void*)&_slots[i], 0, T_SIZE);
|
|
454
|
+
return _tmp;
|
|
455
|
+
```
|
|
456
|
+
```
|
|
457
|
+
#arch: aarch64
|
|
458
|
+
// x19 = self, x1 = i, x8 = return buf when T_SIZE > 8
|
|
459
|
+
ldr x4, [x19, #8]
|
|
460
|
+
mov x3, #T_SIZE
|
|
461
|
+
madd x5, x1, x3, xzr
|
|
462
|
+
add x5, x4, x5
|
|
463
|
+
cmp x3, #8
|
|
464
|
+
b.gt .Lbuffer_move_T_copy
|
|
465
|
+
// Width-matched load + zero-clear: an 8-byte access on a sub-8
|
|
466
|
+
// element would zero the following slots and run past the slab.
|
|
467
|
+
cmp x3, #1
|
|
468
|
+
b.eq .Lbuffer_move_T_1
|
|
469
|
+
cmp x3, #2
|
|
470
|
+
b.eq .Lbuffer_move_T_2
|
|
471
|
+
cmp x3, #4
|
|
472
|
+
b.eq .Lbuffer_move_T_4
|
|
473
|
+
ldr x0, [x5]
|
|
474
|
+
str xzr, [x5]
|
|
475
|
+
b .Lbuffer_move_T_end
|
|
476
|
+
.Lbuffer_move_T_1:
|
|
477
|
+
ldrb w0, [x5]
|
|
478
|
+
strb wzr, [x5]
|
|
479
|
+
b .Lbuffer_move_T_end
|
|
480
|
+
.Lbuffer_move_T_2:
|
|
481
|
+
ldrh w0, [x5]
|
|
482
|
+
strh wzr, [x5]
|
|
483
|
+
b .Lbuffer_move_T_end
|
|
484
|
+
.Lbuffer_move_T_4:
|
|
485
|
+
ldr w0, [x5]
|
|
486
|
+
str wzr, [x5]
|
|
487
|
+
b .Lbuffer_move_T_end
|
|
488
|
+
.Lbuffer_move_T_copy:
|
|
489
|
+
mov x0, x8
|
|
490
|
+
mov x1, x5
|
|
491
|
+
mov x2, x3
|
|
492
|
+
stp x5, x3, [sp, #-16]!
|
|
493
|
+
bl _memcpy
|
|
494
|
+
ldp x5, x3, [sp], #16
|
|
495
|
+
mov x0, x5
|
|
496
|
+
mov x1, #0
|
|
497
|
+
mov x2, x3
|
|
498
|
+
bl _memset
|
|
499
|
+
mov x0, x8
|
|
500
|
+
.Lbuffer_move_T_end:
|
|
501
|
+
```
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Store into a T_SIZE-sized slot, overwriting the previous value. For
|
|
505
|
+
// trivially-destructible value structs this is a plain overwrite. For
|
|
506
|
+
// owning value structs (with string fields), the build phase replaces this
|
|
507
|
+
// body with a specialised version that calls T_destroy on the old slot
|
|
508
|
+
// value, then deep-copies (strdup per string field). See
|
|
509
|
+
// owning_buffer_specialize.ts (both backends). ClassBuffer.replace_T
|
|
510
|
+
// destroys+frees class slots soundly.
|
|
511
|
+
inline func replace_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
|
|
512
|
+
```
|
|
513
|
+
#arch: c
|
|
514
|
+
((T*)(unsigned long long)self->data)[i] = val;
|
|
515
|
+
```
|
|
516
|
+
```
|
|
517
|
+
#arch: aarch64
|
|
518
|
+
// x19 = self, x1 = i, x2 = val (value if T_SIZE<=8, address if struct)
|
|
519
|
+
ldr x0, [x19, #8]
|
|
520
|
+
mov x3, #T_SIZE
|
|
521
|
+
madd x1, x1, x3, xzr
|
|
522
|
+
add x0, x0, x1
|
|
523
|
+
cmp x3, #8
|
|
524
|
+
b.gt .Lbuffer_replace_T_copy
|
|
525
|
+
// Width-matched store: an 8-byte str on a sub-8 element would
|
|
526
|
+
// clobber the following slots and run past the slab's end.
|
|
527
|
+
cmp x3, #1
|
|
528
|
+
b.eq .Lbuffer_replace_T_1
|
|
529
|
+
cmp x3, #2
|
|
530
|
+
b.eq .Lbuffer_replace_T_2
|
|
531
|
+
cmp x3, #4
|
|
532
|
+
b.eq .Lbuffer_replace_T_4
|
|
533
|
+
str x2, [x0]
|
|
534
|
+
b .Lbuffer_replace_T_end
|
|
535
|
+
.Lbuffer_replace_T_1:
|
|
536
|
+
strb w2, [x0]
|
|
537
|
+
b .Lbuffer_replace_T_end
|
|
538
|
+
.Lbuffer_replace_T_2:
|
|
539
|
+
strh w2, [x0]
|
|
540
|
+
b .Lbuffer_replace_T_end
|
|
541
|
+
.Lbuffer_replace_T_4:
|
|
542
|
+
str w2, [x0]
|
|
543
|
+
b .Lbuffer_replace_T_end
|
|
544
|
+
.Lbuffer_replace_T_copy:
|
|
545
|
+
mov x1, x2
|
|
546
|
+
mov x2, x3
|
|
547
|
+
bl _memcpy
|
|
548
|
+
.Lbuffer_replace_T_end:
|
|
549
|
+
```
|
|
550
|
+
}
|
|
551
|
+
|
|
408
552
|
// A non-owning (ptr, len) slice [start, end) over this buffer's element
|
|
409
553
|
// storage, returned as a `view T`. It borrows from self: it may not outlive
|
|
410
554
|
// self's scope and is invalidated if self is reassigned. This is the single
|
|
@@ -91,6 +91,115 @@ pub struct ClassBuffer<T> {
|
|
|
91
91
|
```
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// T_SIZE-aware aliases of the _int primitives. ClassBuffer only ever holds
|
|
95
|
+
// 8-byte class pointers (T_SIZE is 8), so these are behaviorally identical
|
|
96
|
+
// to their _int counterparts — they exist so List<T> can call a single
|
|
97
|
+
// uniform `_T` API whether T is a value struct (Buffer) or a class
|
|
98
|
+
// (ClassBuffer, after the Buffer<T> field is rewritten). Bodies use 8-byte
|
|
99
|
+
// slots, matching _int.
|
|
100
|
+
|
|
101
|
+
func grow_T = (ref self, int needed, out int: out >= needed) {
|
|
102
|
+
```
|
|
103
|
+
#arch: c
|
|
104
|
+
if (self->cap >= needed) return self->cap;
|
|
105
|
+
int new_cap = self->cap;
|
|
106
|
+
if (new_cap == 0) new_cap = 4;
|
|
107
|
+
while (new_cap < needed) new_cap *= 2;
|
|
108
|
+
self->data = (unsigned long long)(long*)realloc((long*)(unsigned long long)self->data, new_cap * sizeof(long));
|
|
109
|
+
memset((long*)(unsigned long long)self->data + self->cap, 0, (new_cap - self->cap) * sizeof(long));
|
|
110
|
+
self->cap = new_cap;
|
|
111
|
+
return self->cap;
|
|
112
|
+
```
|
|
113
|
+
```
|
|
114
|
+
#arch: aarch64
|
|
115
|
+
ldr x2, [x19, #16]
|
|
116
|
+
cmp x2, x1
|
|
117
|
+
b.ge .Lcb_grow_T_end
|
|
118
|
+
mov x3, #4
|
|
119
|
+
cmp x2, #0
|
|
120
|
+
csel x3, x3, x2, eq
|
|
121
|
+
cmp x3, x1
|
|
122
|
+
b.ge .Lcb_grow_T_got
|
|
123
|
+
.Lcb_grow_T_loop:
|
|
124
|
+
lsl x3, x3, #1
|
|
125
|
+
cmp x3, x1
|
|
126
|
+
b.lt .Lcb_grow_T_loop
|
|
127
|
+
.Lcb_grow_T_got:
|
|
128
|
+
sub sp, sp, #16
|
|
129
|
+
str x2, [sp, #0]
|
|
130
|
+
str x3, [sp, #8]
|
|
131
|
+
ldr x0, [x19, #8]
|
|
132
|
+
lsl x1, x3, #3
|
|
133
|
+
bl _realloc
|
|
134
|
+
str x0, [x19, #8]
|
|
135
|
+
ldr x2, [sp, #0]
|
|
136
|
+
ldr x3, [sp, #8]
|
|
137
|
+
add sp, sp, #16
|
|
138
|
+
str x3, [x19, #16]
|
|
139
|
+
add x0, x0, x2, lsl #3
|
|
140
|
+
mov x1, #0
|
|
141
|
+
sub x2, x3, x2
|
|
142
|
+
lsl x2, x2, #3
|
|
143
|
+
bl _memset
|
|
144
|
+
.Lcb_grow_T_end:
|
|
145
|
+
ldr x0, [x19, #16]
|
|
146
|
+
```
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
inline func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
|
|
150
|
+
```
|
|
151
|
+
#arch: c
|
|
152
|
+
return (void*)((long*)(unsigned long long)self->data)[i];
|
|
153
|
+
```
|
|
154
|
+
```
|
|
155
|
+
#arch: aarch64
|
|
156
|
+
ldr x0, [x19, #8]
|
|
157
|
+
lsl x1, x1, #3
|
|
158
|
+
add x0, x0, x1
|
|
159
|
+
ldr x0, [x0]
|
|
160
|
+
```
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val: val != 0) {
|
|
164
|
+
```
|
|
165
|
+
#arch: c
|
|
166
|
+
((long*)(unsigned long long)self->data)[i] = (long)val;
|
|
167
|
+
```
|
|
168
|
+
```
|
|
169
|
+
#arch: aarch64
|
|
170
|
+
ldr x0, [x19, #8]
|
|
171
|
+
lsl x3, x1, #3
|
|
172
|
+
add x0, x0, x3
|
|
173
|
+
str x2, [x0]
|
|
174
|
+
```
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Move a class pointer out of a slot: return it and zero the slot so the
|
|
178
|
+
// buffer no longer references it. Declared `mov out T` so the borrow
|
|
179
|
+
// checker treats the result as OWNED — the slot is relinquished, so the
|
|
180
|
+
// caller is the sole remaining owner. This is the owning-extract primitive
|
|
181
|
+
// (parallel to List.pop); use it (not load_T) when transferring ownership
|
|
182
|
+
// out of a ClassBuffer slot, or moving a value into a fresh owning
|
|
183
|
+
// container — load_T returns a BORROW (the slot is unchanged) and storing
|
|
184
|
+
// it elsewhere would create shared ownership (double-free at destroy).
|
|
185
|
+
inline func move_T = (ref self, int i: i >= 0 && i < self.cap, mov out T) {
|
|
186
|
+
```
|
|
187
|
+
#arch: c
|
|
188
|
+
long *slots = (long*)(unsigned long long)self->data;
|
|
189
|
+
void *val = (void*)slots[i];
|
|
190
|
+
slots[i] = 0;
|
|
191
|
+
return val;
|
|
192
|
+
```
|
|
193
|
+
```
|
|
194
|
+
#arch: aarch64
|
|
195
|
+
ldr x0, [x19, #8]
|
|
196
|
+
lsl x3, x1, #3
|
|
197
|
+
add x3, x0, x3
|
|
198
|
+
ldr x0, [x3]
|
|
199
|
+
str xzr, [x3]
|
|
200
|
+
```
|
|
201
|
+
}
|
|
202
|
+
|
|
94
203
|
inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val: val != 0) {
|
|
95
204
|
```
|
|
96
205
|
#arch: c
|
|
@@ -156,6 +265,40 @@ pub struct ClassBuffer<T> {
|
|
|
156
265
|
```
|
|
157
266
|
}
|
|
158
267
|
|
|
268
|
+
// T-typed alias of replace_int: free the outgoing class pointer (destroy +
|
|
269
|
+
// free) then store the new one. Used by List.set so the uniform `_T` API
|
|
270
|
+
// preserves ownership for class elements.
|
|
271
|
+
func replace_T = (ref self, int i: i >= 0 && i < self.cap, T val: val != 0) {
|
|
272
|
+
```
|
|
273
|
+
#arch: c
|
|
274
|
+
long *slots = (long*)(unsigned long long)self->data;
|
|
275
|
+
if (slots[i]) {
|
|
276
|
+
T_destroy((void*)slots[i]);
|
|
277
|
+
free((void*)slots[i]);
|
|
278
|
+
}
|
|
279
|
+
slots[i] = (long)val;
|
|
280
|
+
```
|
|
281
|
+
```
|
|
282
|
+
#arch: aarch64
|
|
283
|
+
stp x20, x21, [sp, #-16]!
|
|
284
|
+
str x22, [sp, #-16]!
|
|
285
|
+
ldr x0, [x19, #8]
|
|
286
|
+
lsl x3, x1, #3
|
|
287
|
+
add x21, x0, x3
|
|
288
|
+
mov x20, x2
|
|
289
|
+
ldr x0, [x21]
|
|
290
|
+
cbz x0, .Lcb_replace_T_store
|
|
291
|
+
mov x22, x0
|
|
292
|
+
bl T_destroy
|
|
293
|
+
mov x0, x22
|
|
294
|
+
bl _free
|
|
295
|
+
.Lcb_replace_T_store:
|
|
296
|
+
str x20, [x21]
|
|
297
|
+
ldr x22, [sp], #16
|
|
298
|
+
ldp x20, x21, [sp], #16
|
|
299
|
+
```
|
|
300
|
+
}
|
|
301
|
+
|
|
159
302
|
// A non-owning (ptr, len) slice [start, end) over this buffer's class
|
|
160
303
|
// pointers, returned as a `view T` (T is a class, so each element is an
|
|
161
304
|
// 8-byte pointer). Borrows from self — invalidated on reassignment. Mirrors
|
package/core/System/Graph.nm
CHANGED
|
@@ -16,9 +16,8 @@ pub struct Graph<T>: Enumerable {
|
|
|
16
16
|
|
|
17
17
|
pub func add_node = (ref self, mov T value) {
|
|
18
18
|
var int idx = self.node_count
|
|
19
|
-
self.values.
|
|
20
|
-
|
|
21
|
-
self.values.store_int(idx, v)
|
|
19
|
+
self.values.grow_T(idx + 1)
|
|
20
|
+
self.values.store_T(idx, value)
|
|
22
21
|
self.head_edge.grow_int(idx + 1)
|
|
23
22
|
self.head_edge.store_int(idx, -1)
|
|
24
23
|
self.node_count = self.node_count + 1
|
|
@@ -51,11 +50,11 @@ pub struct Graph<T>: Enumerable {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
pub func first = (self: self.node_count > 0, out T) {
|
|
54
|
-
return self.values.
|
|
53
|
+
return self.values.load_T(0)
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
pub func at = (self, int idx: idx >= 0 && idx < self.node_count, out T) {
|
|
58
|
-
return self.values.
|
|
57
|
+
return self.values.load_T(idx)
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
pub func node_length = (self, out int) {
|
package/core/System/Init.nm
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Program startup state — the argument count and argument list passed to `main
|
|
2
|
+
* Program startup state — the argument count and argument list passed to `main`,
|
|
3
|
+
* plus whether stdout is a terminal (for renderer selection).
|
|
3
4
|
**/
|
|
4
5
|
pub struct Init {
|
|
5
6
|
var int argc
|
|
6
7
|
var string[16] args
|
|
8
|
+
var bool is_tty
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -15,9 +15,8 @@ pub struct LinkedList<T>: Enumerable {
|
|
|
15
15
|
|
|
16
16
|
pub func add = (ref self, mov T value) {
|
|
17
17
|
var int idx = self.count
|
|
18
|
-
self.values.
|
|
19
|
-
|
|
20
|
-
self.values.store_int(idx, v)
|
|
18
|
+
self.values.grow_T(idx + 1)
|
|
19
|
+
self.values.store_T(idx, value)
|
|
21
20
|
self.nexts.grow_int(idx + 1)
|
|
22
21
|
self.nexts.store_int(idx, -1)
|
|
23
22
|
self.prevs.grow_int(idx + 1)
|
|
@@ -51,11 +50,11 @@ pub struct LinkedList<T>: Enumerable {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
pub func first = (self: self.count > 0, out T) {
|
|
54
|
-
return self.values.
|
|
53
|
+
return self.values.load_T(0)
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
pub func at = (self, int idx: idx >= 0 && idx < self.count, out T) {
|
|
58
|
-
return self.values.
|
|
57
|
+
return self.values.load_T(idx)
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
pub func length = (self, out int) {
|
package/core/System/List.nm
CHANGED
|
@@ -12,23 +12,23 @@ pub struct List<T>: Viewable {
|
|
|
12
12
|
if old_cap >= 4 {
|
|
13
13
|
new_cap = old_cap * 2
|
|
14
14
|
}
|
|
15
|
-
self.items.
|
|
15
|
+
self.items.grow_T(new_cap)
|
|
16
16
|
}
|
|
17
|
-
self.items.
|
|
17
|
+
self.items.store_T(self.length, value)
|
|
18
18
|
self.length += 1
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
pub func pop = (ref self, mov out T) {
|
|
22
22
|
if self.length <= 0 {
|
|
23
|
-
return 0
|
|
23
|
+
return self.items.move_T(0)
|
|
24
24
|
}
|
|
25
25
|
var int idx = self.length - 1
|
|
26
26
|
self.length = idx
|
|
27
|
-
return self.items.
|
|
27
|
+
return self.items.move_T(idx)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
pub func at = (self, int i: i >= 0 && i < self.length, out T) {
|
|
31
|
-
return self.items.
|
|
31
|
+
return self.items.load_T(i)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// A non-owning `view T` over [start, end). Delegates to the backing Buffer's
|
|
@@ -38,7 +38,25 @@ pub struct List<T>: Viewable {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
pub func set = (ref self, int i: i >= 0 && i < self.length, mov T value) {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
self.items.replace_T(i, value)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// A deep copy: a fresh List<T> with an independent copy of every element.
|
|
45
|
+
// For owning element types (strings, owning value structs) each slot in the
|
|
46
|
+
// copy owns its own heap data (Buffer deep-copies on store), so the source
|
|
47
|
+
// and the copy share nothing. Not available for class/trait element types
|
|
48
|
+
// (the copy would share the stored instances — the checker rejects it).
|
|
49
|
+
// The element is bound to a local before push — the monomorphized body is
|
|
50
|
+
// never re-checked, so it can't rely on check-time call-arg hoisting for
|
|
51
|
+
// struct element types.
|
|
52
|
+
pub func copy = (self, out List<T>) {
|
|
53
|
+
var List<T> dst = List<T>()
|
|
54
|
+
var int i = 0
|
|
55
|
+
while i < self.length {
|
|
56
|
+
var T v = self.at(i)
|
|
57
|
+
dst.push(v)
|
|
58
|
+
i += 1
|
|
59
|
+
}
|
|
60
|
+
return dst
|
|
43
61
|
}
|
|
44
62
|
}
|