nomen-lang 0.8.0 → 0.9.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.
Files changed (73) hide show
  1. package/audit_runtime.c +12 -2
  2. package/core/System/Arena.nm +8 -1
  3. package/core/System/Buffer.nm +366 -9
  4. package/core/System/ClassBuffer.nm +133 -1
  5. package/core/System/Controls/Alert.nm +2 -2
  6. package/core/System/Controls/App.nm +12 -12
  7. package/core/System/Controls/Button.nm +1 -1
  8. package/core/System/Controls/CheckBox.nm +2 -2
  9. package/core/System/Controls/ColorPicker.nm +1 -1
  10. package/core/System/Controls/ComboBox.nm +1 -1
  11. package/core/System/Controls/Container.nm +7 -1
  12. package/core/System/Controls/GroupBox.nm +1 -1
  13. package/core/System/Controls/ImageView.nm +1 -1
  14. package/core/System/Controls/LevelIndicator.nm +1 -1
  15. package/core/System/Controls/ListView.nm +1 -1
  16. package/core/System/Controls/Menu.nm +1 -1
  17. package/core/System/Controls/OutlineView.nm +1 -1
  18. package/core/System/Controls/Pagination.nm +8 -8
  19. package/core/System/Controls/Popover.nm +1 -1
  20. package/core/System/Controls/Progress.nm +1 -1
  21. package/core/System/Controls/Radio.nm +2 -2
  22. package/core/System/Controls/SearchField.nm +1 -1
  23. package/core/System/Controls/SecureField.nm +1 -1
  24. package/core/System/Controls/Segmented.nm +1 -1
  25. package/core/System/Controls/Select.nm +1 -1
  26. package/core/System/Controls/Separator.nm +1 -1
  27. package/core/System/Controls/Sheet.nm +1 -1
  28. package/core/System/Controls/Slider.nm +1 -1
  29. package/core/System/Controls/Spinner.nm +2 -2
  30. package/core/System/Controls/SplitView.nm +1 -1
  31. package/core/System/Controls/Stepper.nm +1 -1
  32. package/core/System/Controls/Switch.nm +1 -1
  33. package/core/System/Controls/Table.nm +1 -1
  34. package/core/System/Controls/Tabs.nm +1 -1
  35. package/core/System/Controls/Text.nm +1 -1
  36. package/core/System/Controls/TextBox.nm +2 -2
  37. package/core/System/Controls/TextView.nm +1 -1
  38. package/core/System/Controls/Toggle.nm +2 -2
  39. package/core/System/Controls/Toolbar.nm +1 -1
  40. package/core/System/Controls/Window.nm +1 -2
  41. package/core/System/LinkedList.nm +8 -1
  42. package/core/System/List.nm +68 -12
  43. package/core/System/Map.nm +174 -18
  44. package/core/System/Mutex.nm +4 -4
  45. package/core/System/Random.nm +3 -4
  46. package/core/System/Set.nm +94 -20
  47. package/core/System/StableList.nm +371 -0
  48. package/core/System/Stream/Directory.nm +2 -2
  49. package/core/System/Stream/File.nm +2 -2
  50. package/core/System/Stream/Http.nm +2 -2
  51. package/core/System/String.nm +10 -5
  52. package/core/System/StringBuilder.nm +213 -2
  53. package/core/System/Text/CharIndex.nm +9 -9
  54. package/core/System/Text/Json.nm +60 -46
  55. package/core/System/Text/JsonTree.nm +120 -92
  56. package/core/System/Text/Regex.nm +23 -18
  57. package/core/System/Text/Utf8.nm +5 -5
  58. package/core/System/float.nm +36 -22
  59. package/core/System/int.nm +80 -28
  60. package/core/System/int16.nm +11 -0
  61. package/core/System/int32.nm +11 -0
  62. package/core/System/int64.nm +11 -0
  63. package/core/System/int8.nm +11 -0
  64. package/core/System/uint.nm +11 -0
  65. package/core/System/uint16.nm +11 -0
  66. package/core/System/uint32.nm +11 -0
  67. package/core/System/uint64.nm +11 -0
  68. package/core/System/uint8.nm +11 -0
  69. package/core/docs/System/StringBuilder.md +6 -0
  70. package/core/docs/System/Text/JsonTree.md +3 -2
  71. package/dist/index.mjs +36575 -30747
  72. package/package.json +1 -1
  73. package/src/bench_loop.nm +9 -9
@@ -83,7 +83,218 @@ pub struct StringBuilder {
83
83
  ```
84
84
  }
85
85
 
86
- // Append a null-terminated string. `unsafe` Nomen single-sourced for
86
+ // Append a base-10 integer WITHOUT materializing a string: the digits are
87
+ // written straight into the buffer (one capacity check, no malloc and no
88
+ // snprintf). The `sb.append(i.to_string())` shape's two snprintf passes
89
+ // plus the intermediate string's malloc/free collapse to a few
90
+ // instructions against the buffer. The raw body is spliced per call site
91
+ // (labels renamed by the splicer), so the digit loop is truly inline.
92
+ pub inline func append_int = (ref self, int n) {
93
+ ```
94
+ #arch: c
95
+ long v = n;
96
+ char tmp[24];
97
+ int pos = 24;
98
+ // Magnitude via the two's-complement negate (u stays correct for
99
+ // INT64_MIN, whose positive counterpart is not representable).
100
+ unsigned long long u = v < 0 ? (unsigned long long)(-(v + 1)) + 1ULL : (unsigned long long)v;
101
+ do {
102
+ tmp[--pos] = (char)('0' + (int)(u % 10));
103
+ u /= 10;
104
+ } while (u != 0);
105
+ if (v < 0) tmp[--pos] = '-';
106
+ long sl = 24 - pos;
107
+ long idx = self->len;
108
+ if (idx + sl + 1 > self->cap) {
109
+ long nc = self->cap;
110
+ if (nc == 0) nc = 16;
111
+ while (nc < idx + sl + 1) nc *= 2;
112
+ self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, nc);
113
+ self->cap = nc;
114
+ }
115
+ memcpy((void*)((unsigned long long)self->data + (unsigned long long)idx), tmp + pos, (size_t)sl);
116
+ self->len = idx + sl;
117
+ ```
118
+ ```
119
+ #arch: aarch64
120
+ // x19 = self, x1 = n. Format into a 24-byte scratch at [sp+40..64)
121
+ // (20 chars for INT64_MIN), then copy into the buffer
122
+ // (capacity-checked inline, like append_char). Saves live below the
123
+ // scratch: [sp]=pos, [sp+8]=sl, [sp+16]=idx, [sp+24]=new_cap.
124
+ sub sp, sp, #64
125
+ mov x9, x1 // v = n
126
+ mov x10, x9
127
+ cmp x9, #0
128
+ b.ge .Lsb_ai_pos
129
+ neg x10, x10 // magnitude (wraps correctly for INT64_MIN)
130
+ .Lsb_ai_pos:
131
+ add x11, sp, #64 // pos = end of scratch
132
+ mov x12, x11
133
+ .Lsb_ai_digit:
134
+ mov x13, #10
135
+ udiv x14, x10, x13
136
+ msub x15, x14, x13, x10 // rem = v - q*10
137
+ add x15, x15, #48
138
+ sub x12, x12, #1
139
+ strb w15, [x12]
140
+ mov x10, x14
141
+ cbnz x10, .Lsb_ai_digit
142
+ cmp x9, #0
143
+ b.ge .Lsb_ai_store
144
+ sub x12, x12, #1
145
+ mov w15, #45 // '-'
146
+ strb w15, [x12]
147
+ .Lsb_ai_store:
148
+ sub x1, x11, x12 // sl = end - pos
149
+ ldr x2, [x19, #16] // len
150
+ add x3, x2, x1
151
+ add x3, x3, #1 // needed
152
+ ldr x4, [x19, #24] // cap
153
+ cmp x4, x3
154
+ b.ge .Lsb_ai_copy
155
+ mov x5, #16
156
+ cmp x4, #0
157
+ csel x5, x5, x4, eq
158
+ .Lsb_ai_grow:
159
+ cmp x5, x3
160
+ b.ge .Lsb_ai_realloc
161
+ lsl x5, x5, #1
162
+ b .Lsb_ai_grow
163
+ .Lsb_ai_realloc:
164
+ str x12, [sp, #0] // pos
165
+ str x1, [sp, #8] // sl
166
+ str x2, [sp, #16] // idx
167
+ str x5, [sp, #24] // new_cap
168
+ ldr x0, [x19, #8]
169
+ mov x1, x5
170
+ bl _realloc
171
+ str x0, [x19, #8]
172
+ ldr x5, [sp, #24]
173
+ str x5, [x19, #24]
174
+ ldr x12, [sp, #0]
175
+ ldr x1, [sp, #8]
176
+ ldr x2, [sp, #16]
177
+ .Lsb_ai_copy:
178
+ ldr x0, [x19, #8] // data
179
+ add x0, x0, x2 // dst = data + idx
180
+ mov x3, x1
181
+ .Lsb_ai_cl:
182
+ cbz x3, .Lsb_ai_done
183
+ ldrb w4, [x12]
184
+ strb w4, [x0]
185
+ add x12, x12, #1
186
+ add x0, x0, #1
187
+ sub x3, x3, #1
188
+ b .Lsb_ai_cl
189
+ .Lsb_ai_done:
190
+ add x2, x2, x1 // len += sl
191
+ str x2, [x19, #16]
192
+ add sp, sp, #64
193
+ ```
194
+ }
195
+
196
+ // Append a float with the SAME text `float.to_string` produces ("%f"):
197
+ // one snprintf into a stack scratch, then a bulk copy into the buffer —
198
+ // no sizing pass and no intermediate string allocation.
199
+ pub inline func append_float = (ref self, float f) {
200
+ ```
201
+ #arch: c
202
+ char tmp[360];
203
+ int sl = snprintf(tmp, sizeof(tmp), "%f", f);
204
+ long idx = self->len;
205
+ if (idx + sl + 1 > self->cap) {
206
+ long nc = self->cap;
207
+ if (nc == 0) nc = 16;
208
+ while (nc < idx + sl + 1) nc *= 2;
209
+ self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, nc);
210
+ self->cap = nc;
211
+ }
212
+ memcpy((void*)((unsigned long long)self->data + (unsigned long long)idx), tmp, (size_t)sl);
213
+ self->len = idx + sl;
214
+ ```
215
+ ```
216
+ #arch: aarch64
217
+ // x19 = self, x1 = f (raw bits — float params ride integer
218
+ // registers). Scratch [sp+16..sp+376); [sp+0] is snprintf's
219
+ // variadic slot, reused after the call for `sl`; [sp+8] = idx across
220
+ // the grow call; [sp+376] = new_cap.
221
+ sub sp, sp, #384
222
+ fmov d0, x1 // f bits (capture before x1 is reused)
223
+ str d0, [sp, #0] // variadic double slot
224
+ add x0, sp, #16
225
+ mov x1, #360
226
+ adr x2, .Lsb_af_fmt
227
+ bl _snprintf
228
+ str x0, [sp, #0] // sl
229
+ ldr x2, [x19, #16] // idx = len
230
+ add x3, x2, x0
231
+ add x3, x3, #1 // needed
232
+ ldr x4, [x19, #24] // cap
233
+ cmp x4, x3
234
+ b.ge .Lsb_af_copy
235
+ mov x5, #16
236
+ cmp x4, #0
237
+ csel x5, x5, x4, eq
238
+ .Lsb_af_grow:
239
+ cmp x5, x3
240
+ b.ge .Lsb_af_realloc
241
+ lsl x5, x5, #1
242
+ b .Lsb_af_grow
243
+ .Lsb_af_realloc:
244
+ str x2, [sp, #8] // idx
245
+ str x5, [sp, #376] // new_cap (above the scratch)
246
+ ldr x0, [x19, #8]
247
+ mov x1, x5
248
+ bl _realloc
249
+ str x0, [x19, #8]
250
+ ldr x5, [sp, #376]
251
+ str x5, [x19, #24]
252
+ ldr x2, [sp, #8]
253
+ .Lsb_af_copy:
254
+ ldr x0, [x19, #8] // data
255
+ add x0, x0, x2 // dst = data + idx
256
+ add x4, sp, #16 // src = scratch
257
+ ldr x1, [sp, #0] // sl
258
+ mov x3, x1
259
+ .Lsb_af_cl:
260
+ cbz x3, .Lsb_af_done
261
+ ldrb w5, [x4]
262
+ strb w5, [x0]
263
+ add x4, x4, #1
264
+ add x0, x0, #1
265
+ sub x3, x3, #1
266
+ b .Lsb_af_cl
267
+ .Lsb_af_done:
268
+ add x2, x2, x1 // len += sl
269
+ str x2, [x19, #16]
270
+ add sp, sp, #384
271
+ b .Lsb_af_after
272
+ .Lsb_af_fmt: .asciz "%f"
273
+ .p2align 2
274
+ .Lsb_af_after:
275
+ ```
276
+ }
277
+
278
+ // Append a borrowed view without materializing it.
279
+ pub func append = (ref self, view string s) {
280
+ self.append_string_view(s)
281
+ }
282
+
283
+ // Append an int without materializing a string (see `append_int`).
284
+ pub func append = (ref self, int n) {
285
+ self.append_int(n)
286
+ }
287
+
288
+ // Append a float without materializing a string (see `append_float`).
289
+ pub func append = (ref self, float f) {
290
+ self.append_float(f)
291
+ }
292
+
293
+ // Append a single byte. (Overload, so `sb.append(c)` works for chars.)
294
+ pub func append = (ref self, char c) {
295
+ self.append_char(c)
296
+ }
297
+
87
298
  // both backends: the fat pair's pointer half feeds memcpy directly, and
88
299
  // the tracked length replaces the strlen the old C body paid.
89
300
  // `internal`: a library-implementation append — user code appends with
@@ -142,7 +353,7 @@ pub struct StringBuilder {
142
353
  return false
143
354
  }
144
355
  var int start = self.len - sl
145
- var int i = 0
356
+ var i = 0
146
357
  while i < sl; i += 1 {
147
358
  if (self.data as ptr char)[start + i] != (suffix as ptr char)[i] {
148
359
  return false
@@ -51,16 +51,16 @@ pub mv struct CharIndex {
51
51
  chars = chars + 1
52
52
  }
53
53
  } else {
54
- if open_at >= 0 {
55
- self.runs.push(CharRun(open_at, open_start, open_width, open_count))
56
- }
57
- open_at = pos
58
- open_start = chars
59
- open_width = w
60
- open_count = 1
61
- pos = pos + w
62
- chars = chars + 1
54
+ if open_at >= 0 {
55
+ self.runs.push(CharRun(open_at, open_start, open_width, open_count))
63
56
  }
57
+ open_at = pos
58
+ open_start = chars
59
+ open_width = w
60
+ open_count = 1
61
+ pos = pos + w
62
+ chars = chars + 1
63
+ }
64
64
  }
65
65
  if open_at >= 0 {
66
66
  self.runs.push(CharRun(open_at, open_start, open_width, open_count))
@@ -5,7 +5,7 @@
5
5
  // Integer (de)serialization is handled by int.to_string() and int.parse()
6
6
  // (see int.nm), so this struct only deals with JSON strings.
7
7
  //
8
- // `parse` / `stringify` use a JsonTree pool (flat Buffer-backed slot array)
8
+ // `parse` / `stringify` use a JsonTree pool (a flat StableList of nodes)
9
9
  // instead of per-node heap allocation, avoiding O(nodes) malloc/free per
10
10
  // parse cycle. The caller creates a JsonTree once and resets it per document.
11
11
 
@@ -41,8 +41,8 @@ pub struct Json {
41
41
  sb.append_string("\x5cr")
42
42
  }
43
43
  } else {
44
- sb.append_char(c)
45
- }
44
+ sb.append_char(c)
45
+ }
46
46
  }
47
47
  sb.append_char('"')
48
48
  return sb.to_string()
@@ -90,8 +90,8 @@ pub struct Json {
90
90
  sb.append_string("\x5c")
91
91
  }
92
92
  } else {
93
- sb.append_char(e)
94
- }
93
+ sb.append_char(e)
94
+ }
95
95
  }
96
96
  } else {
97
97
  sb.append_char(c)
@@ -135,46 +135,61 @@ func json_parse_string = (string s, ref Buffer<int> pos, int len, ref JsonTree t
135
135
  var int i = pos.load_int(0)
136
136
  i += 1
137
137
  var sb = StringBuilder()
138
- while i < len; i += 1 {
139
- var char c = s.at(i)
140
- var int code = c as int
141
- if code == 34 {
138
+ while i < len {
139
+ // Scan-to-next-escape fast path: copy the run of plain bytes in ONE
140
+ // bulk append instead of a per-byte append_char (each of which pays
141
+ // the builder's capacity check and length bump).
142
+ var int run_start = i
143
+ var int code = 0
144
+ while i < len {
145
+ code = s.at(i) as int
146
+ if code == 34 || code == 92 {
147
+ break
148
+ }
142
149
  i += 1
150
+ }
151
+ if i > run_start {
152
+ sb.append_string_view(s.slice(run_start, i))
153
+ }
154
+ if i >= len {
143
155
  break
144
156
  }
145
- if code == 92 {
157
+ if code == 34 {
146
158
  i += 1
147
- if i < len {
148
- var char e = s.at(i)
149
- var int ec = e as int
150
- switch {
151
- case ec == 110 {
152
- sb.append_string("\n")
153
- }
154
- case ec == 116 {
155
- sb.append_string("\t")
156
- }
157
- case ec == 114 {
158
- sb.append_string("\r")
159
- }
160
- case ec == 34 {
161
- sb.append_char('"')
162
- }
163
- case ec == 92 {
164
- sb.append_string("\x5c")
165
- }
166
- } else {
167
- sb.append_char(e)
168
- }
159
+ break
160
+ }
161
+ // code == 92 — escape sequence: consume the backslash, append the
162
+ // decoded byte (an unknown escape appends the byte verbatim).
163
+ i += 1
164
+ if i < len {
165
+ var char e = s.at(i)
166
+ var int ec = e as int
167
+ switch {
168
+ case ec == 110 {
169
+ sb.append_string("\n")
170
+ }
171
+ case ec == 116 {
172
+ sb.append_string("\t")
173
+ }
174
+ case ec == 114 {
175
+ sb.append_string("\r")
176
+ }
177
+ case ec == 34 {
178
+ sb.append_char('"')
179
+ }
180
+ case ec == 92 {
181
+ sb.append_string("\x5c")
182
+ }
183
+ } else {
184
+ sb.append_char(e)
169
185
  }
170
- } else {
171
- sb.append_char(c)
186
+ i += 1
172
187
  }
173
188
  }
174
189
  pos.store_int(0, i)
175
190
  var int n = tree.alloc_node()
176
191
  tree.set_kind(n, 3)
177
- tree.set_text(n, sb.to_string())
192
+ tree.take_text(n, ref sb)
178
193
  return n
179
194
  }
180
195
 
@@ -191,13 +206,12 @@ func json_parse_number = (string s, ref Buffer<int> pos, int len, ref JsonTree t
191
206
  }
192
207
  pos.store_int(0, i)
193
208
  var sb = StringBuilder()
194
- var int j = start
195
- while j < i; j += 1 {
196
- sb.append_char(s.at(j))
197
- }
209
+ // One bulk append for the whole run of number bytes (the scan above
210
+ // already found its end) — no per-byte append_char.
211
+ sb.append_string_view(s.slice(start, i))
198
212
  var int n = tree.alloc_node()
199
213
  tree.set_kind(n, 2)
200
- tree.set_text(n, sb.to_string())
214
+ tree.take_text(n, ref sb)
201
215
  return n
202
216
  }
203
217
 
@@ -216,9 +230,9 @@ func json_parse_literal = (string s, ref Buffer<int> pos, int len, ref JsonTree
216
230
  adv = 5
217
231
  }
218
232
  } else {
219
- tree.set_kind(n, 0)
220
- adv = 4
221
- }
233
+ tree.set_kind(n, 0)
234
+ adv = 4
235
+ }
222
236
  pos.store_int(0, i + adv)
223
237
  return n
224
238
  }
@@ -318,7 +332,7 @@ func json_ser_list = (ref JsonTree tree, int first, ref StringBuilder sb) {
318
332
 
319
333
  func json_ser_pairs = (ref JsonTree tree, int first, ref StringBuilder sb) {
320
334
  sb.append_char('"')
321
- sb.append_string(tree.get_text(first))
335
+ sb.append_string_view(tree.get_text_view(first))
322
336
  sb.append_string("\":")
323
337
  var int v = tree.get_val(first)
324
338
  if v < 0 {
@@ -348,12 +362,12 @@ func json_ser_value = (ref JsonTree tree, int n, ref StringBuilder sb) {
348
362
  return
349
363
  }
350
364
  if k == 2 {
351
- sb.append_string(tree.get_text(n))
365
+ sb.append_string_view(tree.get_text_view(n))
352
366
  return
353
367
  }
354
368
  if k == 3 {
355
369
  sb.append_char('"')
356
- sb.append_string(tree.get_text(n))
370
+ sb.append_string_view(tree.get_text_view(n))
357
371
  sb.append_char('"')
358
372
  return
359
373
  }