nomen-lang 0.2.3 → 0.3.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.
@@ -1,6 +1,7 @@
1
1
  // Buffer<T>: a flat buffer of value slots of type T. The value counterpart to
2
2
  // ClassBuffer<T>: no per-element freeing, store_int unconstrained. When T is a
3
3
  // class, the monomorphizer rewrites a Buffer<T> field to ClassBuffer<T>.
4
+
4
5
  /**
5
6
  * A flat, low-level buffer of value slots of type T — the backing store for arrays and collections
6
7
  **/
@@ -8,84 +9,33 @@ pub struct Buffer<T> {
8
9
  var uint64 data = 0
9
10
  var cap = 0
10
11
 
12
+ // Allocation / sizing primitives are `unsafe` Nomen single-sourced for
13
+ // both backends. They run once per container op (never per element), so
14
+ // the aarch64 inline-method ABI cost that keeps the per-limb load/store
15
+ // primitives raw (see BigInt.nm) doesn't apply here.
11
16
  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
- ```
17
+ self.cap = size
18
+ self.data = calloc(size, 4)
19
+ return self.cap
27
20
  }
28
21
 
29
22
  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
- ```
23
+ if self.cap >= needed {
24
+ return self.cap
25
+ }
26
+ var int new_cap = self.cap
27
+ if new_cap == 0 {
28
+ new_cap = 8
29
+ }
30
+ while new_cap < needed; new_cap *= 2 {}
31
+ self.data = realloc(self.data, new_cap * 4)
32
+ memset(self.data + self.cap * 4, 0, (new_cap - self.cap) * 4)
33
+ self.cap = new_cap
34
+ return self.cap
75
35
  }
76
36
 
77
37
  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
- ```
38
+ memset(self.data, 0, len * 4)
89
39
  }
90
40
 
91
41
  inline func load = (self, int i: i >= 0 && i < self.cap, out uint32) {
@@ -134,69 +84,24 @@ pub struct Buffer<T> {
134
84
  }
135
85
 
136
86
  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
- ```
87
+ self.cap = size
88
+ self.data = calloc(size, 8)
89
+ return self.cap
152
90
  }
153
91
 
154
92
  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
- ```
93
+ if self.cap >= needed {
94
+ return self.cap
95
+ }
96
+ var int new_cap = self.cap
97
+ if new_cap == 0 {
98
+ new_cap = 4
99
+ }
100
+ while new_cap < needed; new_cap *= 2 {}
101
+ self.data = realloc(self.data, new_cap * 8)
102
+ memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
103
+ self.cap = new_cap
104
+ return self.cap
200
105
  }
201
106
 
202
107
  inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
@@ -267,17 +172,7 @@ pub struct Buffer<T> {
267
172
  }
268
173
 
269
174
  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
- ```
175
+ memset(self.data, 0, len * 8)
281
176
  }
282
177
 
283
178
  // T_SIZE-aware primitives for value-struct elements. Slab is sized in
@@ -286,74 +181,24 @@ pub struct Buffer<T> {
286
181
  // reaching here is always a value type (primitive or struct).
287
182
 
288
183
  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
- ```
184
+ self.cap = size
185
+ self.data = calloc(size, T_SIZE)
186
+ return self.cap
304
187
  }
305
188
 
306
189
  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
- ```
190
+ if self.cap >= needed {
191
+ return self.cap
192
+ }
193
+ var int new_cap = self.cap
194
+ if new_cap == 0 {
195
+ new_cap = 4
196
+ }
197
+ while new_cap < needed; new_cap *= 2 {}
198
+ self.data = realloc(self.data, new_cap * T_SIZE)
199
+ memset(self.data + self.cap * T_SIZE, 0, (new_cap - self.cap) * T_SIZE)
200
+ self.cap = new_cap
201
+ return self.cap
357
202
  }
358
203
 
359
204
  // `inline` splices the (width-folded at monomorphization) raw body at
@@ -403,6 +248,12 @@ pub struct Buffer<T> {
403
248
  ```
404
249
  }
405
250
 
251
+ // Store `val` into slot `i`, which MUST be fresh (calloc'd, or zeroed by
252
+ // move_T). For an owning T (string, or a struct with string fields) the
253
+ // specialised body deep-copies the incoming value but does NOT free the
254
+ // slot's previous occupant — a second `store_T` at an occupied index
255
+ // leaks it. To overwrite a live slot use replace_T (frees the displaced
256
+ // value) — this is the primitive every container's `set` uses.
406
257
  inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
407
258
  ```
408
259
  #arch: c
@@ -650,18 +501,7 @@ pub struct Buffer<T> {
650
501
  }
651
502
 
652
503
  inline func zero_T = (ref self, int len) {
653
- ```
654
- #arch: c
655
- memset((T*)(unsigned long long)self->data, 0, len * T_SIZE);
656
- ```
657
- ```
658
- #arch: aarch64
659
- ldr x0, [x19, #8]
660
- mov x2, #T_SIZE
661
- mul x2, x1, x2
662
- mov x1, #0
663
- bl _memset
664
- ```
504
+ memset(self.data, 0, len * T_SIZE)
665
505
  }
666
506
 
667
507
  inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
@@ -681,21 +521,9 @@ pub struct Buffer<T> {
681
521
  }
682
522
 
683
523
  func alloc_float = (ref self, int size, out int: out >= size) {
684
- ```
685
- #arch: c
686
- self->cap = size;
687
- self->data = (unsigned long long)(double*)calloc(size, sizeof(double));
688
- return self->cap;
689
- ```
690
- ```
691
- #arch: aarch64
692
- str x1, [x19, #16]
693
- mov x0, x1
694
- mov x1, #8
695
- bl _calloc
696
- str x0, [x19, #8]
697
- ldr x0, [x19, #16]
698
- ```
524
+ self.cap = size
525
+ self.data = calloc(size, 8)
526
+ return self.cap
699
527
  }
700
528
 
701
529
  inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
@@ -727,20 +555,10 @@ pub struct Buffer<T> {
727
555
  }
728
556
 
729
557
  func #destroy = () {
730
- ```
731
- #arch: c
732
- if (self->data) free((unsigned int*)(unsigned long long)self->data);
733
- self->data = 0;
734
- self->cap = 0;
735
- ```
736
- ```
737
- #arch: aarch64
738
- ldr x0, [x19, #8]
739
- cbz x0, .Lbuffer_destroy_end
740
- bl _free
741
- .Lbuffer_destroy_end:
742
- str xzr, [x19, #8]
743
- str xzr, [x19, #16]
744
- ```
558
+ if self.data != 0 {
559
+ free(self.data)
560
+ }
561
+ self.data = 0
562
+ self.cap = 0
745
563
  }
746
564
  }
@@ -12,69 +12,35 @@ pub struct ClassBuffer<T> {
12
12
  var cap = 0
13
13
 
14
14
  func alloc_int = (ref self, int size, out int: out >= size) {
15
- ```
16
- #arch: c
17
- self->cap = size;
18
- self->data = (unsigned long long)(long*)calloc(size, sizeof(long));
19
- return self->cap;
20
- ```
21
- ```
22
- #arch: aarch64
23
- str x1, [x19, #16]
24
- mov x0, x1
25
- mov x1, #8
26
- bl _calloc
27
- str x0, [x19, #8]
28
- ldr x0, [x19, #16]
29
- ```
15
+ self.cap = size
16
+ self.data = calloc(size, 8)
17
+ return self.cap
18
+ }
19
+
20
+ // Semantic parity with Buffer<T>.alloc_T: generic code (e.g. Map#init's
21
+ // `self.values.alloc_T(N)`) forwards to either Buffer — where alloc_T is
22
+ // T_SIZE-aware (string slots are 16 bytes) — or this ClassBuffer, whose
23
+ // slots are always one pointer wide. The compiler routes value-struct
24
+ // element types to Buffer and class/trait elements to ClassBuffer
25
+ // (monomorphize's field rewrite), so a call arriving HERE is always
26
+ // pointer-sized: delegate to alloc_int.
27
+ func alloc_T = (ref self, int size, out int: out >= size) {
28
+ return self.alloc_int(size)
30
29
  }
31
30
 
32
31
  func grow_int = (ref self, int needed, out int: out >= needed) {
33
- ```
34
- #arch: c
35
- if (self->cap >= needed) return self->cap;
36
- int new_cap = self->cap;
37
- if (new_cap == 0) new_cap = 4;
38
- while (new_cap < needed) new_cap *= 2;
39
- self->data = (unsigned long long)(long*)realloc((long*)(unsigned long long)self->data, new_cap * sizeof(long));
40
- memset((long*)(unsigned long long)self->data + self->cap, 0, (new_cap - self->cap) * sizeof(long));
41
- self->cap = new_cap;
42
- return self->cap;
43
- ```
44
- ```
45
- #arch: aarch64
46
- ldr x2, [x19, #16]
47
- cmp x2, x1
48
- b.ge .Lcb_grow_end
49
- mov x3, #4
50
- cmp x2, #0
51
- csel x3, x3, x2, eq
52
- cmp x3, x1
53
- b.ge .Lcb_grow_got
54
- .Lcb_grow_loop:
55
- lsl x3, x3, #1
56
- cmp x3, x1
57
- b.lt .Lcb_grow_loop
58
- .Lcb_grow_got:
59
- sub sp, sp, #16
60
- str x2, [sp, #0]
61
- str x3, [sp, #8]
62
- ldr x0, [x19, #8]
63
- lsl x1, x3, #3
64
- bl _realloc
65
- str x0, [x19, #8]
66
- ldr x2, [sp, #0]
67
- ldr x3, [sp, #8]
68
- add sp, sp, #16
69
- str x3, [x19, #16]
70
- add x0, x0, x2, lsl #3
71
- mov x1, #0
72
- sub x2, x3, x2
73
- lsl x2, x2, #3
74
- bl _memset
75
- .Lcb_grow_end:
76
- ldr x0, [x19, #16]
77
- ```
32
+ if self.cap >= needed {
33
+ return self.cap
34
+ }
35
+ var int new_cap = self.cap
36
+ if new_cap == 0 {
37
+ new_cap = 4
38
+ }
39
+ while new_cap < needed; new_cap *= 2 {}
40
+ self.data = realloc(self.data, new_cap * 8)
41
+ memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
42
+ self.cap = new_cap
43
+ return self.cap
78
44
  }
79
45
 
80
46
  inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
@@ -99,51 +65,18 @@ pub struct ClassBuffer<T> {
99
65
  // slots, matching _int.
100
66
 
101
67
  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
- ```
68
+ if self.cap >= needed {
69
+ return self.cap
70
+ }
71
+ var int new_cap = self.cap
72
+ if new_cap == 0 {
73
+ new_cap = 4
74
+ }
75
+ while new_cap < needed; new_cap *= 2 {}
76
+ self.data = realloc(self.data, new_cap * 8)
77
+ memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
78
+ self.cap = new_cap
79
+ return self.cap
147
80
  }
148
81
 
149
82
  inline func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
@@ -160,6 +93,11 @@ pub struct ClassBuffer<T> {
160
93
  ```
161
94
  }
162
95
 
96
+ // Store the owned class pointer `val` into slot `i`, which MUST be fresh
97
+ // (calloc'd, or zeroed by move_T/move_int). This is a plain pointer
98
+ // store — it does NOT destroy/free the slot's previous occupant, so a
99
+ // second `store_T` at an occupied index leaks that instance. Use
100
+ // replace_T (or replace_int) to overwrite a live slot.
163
101
  inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val: val != 0) {
164
102
  ```
165
103
  #arch: c
@@ -41,7 +41,7 @@ pub struct LayoutParams {
41
41
  }
42
42
 
43
43
  // Sensible defaults so most children just work
44
- const LayoutParams DEFAULT_PARAMS = LayoutParams() + [
44
+ const LayoutParams DEFAULT_PARAMS = [ .. LayoutParams(),
45
45
  width = .auto,
46
46
  height = .auto,
47
47
  grow = 0,
@@ -27,6 +27,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
27
27
  pub func set = (ref self, move TK key, move TV value) {
28
28
  var int cap = self.keys.cap
29
29
  if cap == 0 {
30
+ // alloc_T: for Buffer<TK> it is T_SIZE-aware (string keys are
31
+ // 16-byte slots); for ClassBuffer<TV> it delegates to alloc_int
32
+ // (one pointer per slot). Both have it for generic parity.
30
33
  cap = self.keys.alloc_T(8)
31
34
  self.values.alloc_T(8)
32
35
  self.used.alloc(8)