nomen-lang 0.9.0 → 0.10.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 (70) hide show
  1. package/core/System/Arena.nm +9 -7
  2. package/core/System/Array.nm +1 -1
  3. package/core/System/Atomic.nm +3 -3
  4. package/core/System/BigInt.nm +182 -23
  5. package/core/System/Buffer.nm +37 -35
  6. package/core/System/ClassBuffer.nm +18 -18
  7. package/core/System/Controls/Alert.nm +1 -1
  8. package/core/System/Controls/App.nm +5 -5
  9. package/core/System/Controls/Button.nm +1 -1
  10. package/core/System/Controls/CheckBox.nm +1 -1
  11. package/core/System/Controls/ColorPicker.nm +1 -1
  12. package/core/System/Controls/ComboBox.nm +1 -1
  13. package/core/System/Controls/Container.nm +34 -34
  14. package/core/System/Controls/DatePicker.nm +1 -1
  15. package/core/System/Controls/Form.nm +2 -2
  16. package/core/System/Controls/GroupBox.nm +1 -1
  17. package/core/System/Controls/ImageView.nm +1 -1
  18. package/core/System/Controls/Layout.nm +5 -5
  19. package/core/System/Controls/LevelIndicator.nm +1 -1
  20. package/core/System/Controls/ListView.nm +1 -1
  21. package/core/System/Controls/Menu.nm +1 -1
  22. package/core/System/Controls/NumberInput.nm +3 -3
  23. package/core/System/Controls/OtpInput.nm +2 -2
  24. package/core/System/Controls/OutlineView.nm +1 -1
  25. package/core/System/Controls/Pagination.nm +6 -6
  26. package/core/System/Controls/Popover.nm +1 -1
  27. package/core/System/Controls/Progress.nm +1 -1
  28. package/core/System/Controls/Radio.nm +1 -1
  29. package/core/System/Controls/Scrollable.nm +1 -1
  30. package/core/System/Controls/SearchField.nm +1 -1
  31. package/core/System/Controls/SecureField.nm +1 -1
  32. package/core/System/Controls/Segmented.nm +1 -1
  33. package/core/System/Controls/Select.nm +1 -1
  34. package/core/System/Controls/Separator.nm +1 -1
  35. package/core/System/Controls/Sheet.nm +1 -1
  36. package/core/System/Controls/Slider.nm +1 -1
  37. package/core/System/Controls/Spinner.nm +3 -3
  38. package/core/System/Controls/SplitView.nm +2 -2
  39. package/core/System/Controls/Stepper.nm +1 -1
  40. package/core/System/Controls/Switch.nm +1 -1
  41. package/core/System/Controls/Table.nm +1 -1
  42. package/core/System/Controls/Tabs.nm +1 -1
  43. package/core/System/Controls/Text.nm +1 -1
  44. package/core/System/Controls/TextBox.nm +1 -1
  45. package/core/System/Controls/TextView.nm +1 -1
  46. package/core/System/Controls/Toggle.nm +1 -1
  47. package/core/System/Controls/Toolbar.nm +1 -1
  48. package/core/System/Controls/Window.nm +11 -3
  49. package/core/System/Fiber.nm +16 -3
  50. package/core/System/Graph.nm +2 -2
  51. package/core/System/LinkedList.nm +8 -6
  52. package/core/System/List.nm +16 -13
  53. package/core/System/Map.nm +11 -9
  54. package/core/System/Random.nm +3 -3
  55. package/core/System/Set.nm +9 -7
  56. package/core/System/StableList.nm +7 -7
  57. package/core/System/Stream/File.nm +16 -16
  58. package/core/System/Stream/Http.nm +3 -3
  59. package/core/System/Stream/Tcp.nm +5 -5
  60. package/core/System/StringBuilder.nm +16 -16
  61. package/core/System/Task.nm +56 -64
  62. package/core/System/Test.nm +18 -18
  63. package/core/System/Text/Chars.nm +1 -1
  64. package/core/System/Text/Json.nm +12 -12
  65. package/core/System/Text/JsonTree.nm +8 -8
  66. package/core/System/Text/Regex.nm +20 -20
  67. package/core/System/Thread.nm +26 -3
  68. package/core/System/Tree.nm +19 -3
  69. package/dist/index.mjs +3036 -1845
  70. package/package.json +1 -1
@@ -96,7 +96,7 @@ pub mv struct Tester {
96
96
 
97
97
  // (harness) Start timing `name` and clear the per-test state. Called by
98
98
  // the `main` that `nomen test` generates — not by test code.
99
- pub func begin_test = (ref self, string name) {
99
+ pub func begin_test = (ref self { current }, string name) {
100
100
  self.has_failed = false
101
101
  self.passed = 0
102
102
  self.failed = 0
@@ -106,7 +106,7 @@ pub mv struct Tester {
106
106
  }
107
107
 
108
108
  // (harness) Close the current test and emit its `done` record.
109
- pub func end_test = (ref self) {
109
+ pub func end_test = (ref self {}) {
110
110
  const uint64 elapsed = Time.now_ns() - self.started
111
111
  Console.write_line(
112
112
  "\\nomen|done|" + self.current + "|\{self.passed}|\{self.failed}|\{elapsed}",
@@ -124,7 +124,7 @@ pub mv struct Tester {
124
124
  *
125
125
  * t.expect(result == 2, "add(1, 1) should be 2")
126
126
  **/
127
- pub func expect = (ref self, bool condition, string message) {
127
+ pub func expect = (ref self {}, bool condition, string message) {
128
128
  if self.has_failed {
129
129
  return
130
130
  }
@@ -143,7 +143,7 @@ pub mv struct Tester {
143
143
  * t.fail("expected to find the key")
144
144
  * }
145
145
  **/
146
- pub func fail = (ref self, string message) {
146
+ pub func fail = (ref self {}, string message) {
147
147
  if self.has_failed {
148
148
  return
149
149
  }
@@ -154,43 +154,43 @@ pub mv struct Tester {
154
154
  //
155
155
  // Nomen has no generic methods, so there is one overload per nullable
156
156
  // type the compiler can compare against `null`.
157
- pub func assert = (ref self, int? value, string message) {
157
+ pub func assert = (ref self {}, int? value, string message) {
158
158
  self.expect(value != null, message)
159
159
  }
160
160
 
161
- pub func assert = (ref self, uint? value, string message) {
161
+ pub func assert = (ref self {}, uint? value, string message) {
162
162
  self.expect(value != null, message)
163
163
  }
164
164
 
165
- pub func assert = (ref self, int64? value, string message) {
165
+ pub func assert = (ref self {}, int64? value, string message) {
166
166
  self.expect(value != null, message)
167
167
  }
168
168
 
169
- pub func assert = (ref self, uint64? value, string message) {
169
+ pub func assert = (ref self {}, uint64? value, string message) {
170
170
  self.expect(value != null, message)
171
171
  }
172
172
 
173
- pub func assert = (ref self, int8? value, string message) {
173
+ pub func assert = (ref self {}, int8? value, string message) {
174
174
  self.expect(value != null, message)
175
175
  }
176
176
 
177
- pub func assert = (ref self, uint8? value, string message) {
177
+ pub func assert = (ref self {}, uint8? value, string message) {
178
178
  self.expect(value != null, message)
179
179
  }
180
180
 
181
- pub func assert = (ref self, float? value, string message) {
181
+ pub func assert = (ref self {}, float? value, string message) {
182
182
  self.expect(value != null, message)
183
183
  }
184
184
 
185
- pub func assert = (ref self, bool? value, string message) {
185
+ pub func assert = (ref self {}, bool? value, string message) {
186
186
  self.expect(value != null, message)
187
187
  }
188
188
 
189
- pub func assert = (ref self, char? value, string message) {
189
+ pub func assert = (ref self {}, char? value, string message) {
190
190
  self.expect(value != null, message)
191
191
  }
192
192
 
193
- pub func assert = (ref self, string? value, string message) {
193
+ pub func assert = (ref self {}, string? value, string message) {
194
194
  self.expect(value != null, message)
195
195
  }
196
196
 
@@ -212,7 +212,7 @@ pub mv struct Tester {
212
212
  * (default 1000, override with `bench_n`) and computes min / median /
213
213
  * mean / max / stddev over the per-iteration durations.
214
214
  **/
215
- pub func bench = (ref self, string label, func() body) {
215
+ pub func bench = (ref self { bench_label }, string label, func() body) {
216
216
  if self.has_failed {
217
217
  return
218
218
  }
@@ -226,7 +226,7 @@ pub mv struct Tester {
226
226
  * for slow functions (where the default 1000 would dominate the suite) or
227
227
  * for reproducible sample counts.
228
228
  **/
229
- pub func bench_n = (ref self, string label, func() body, int samples) {
229
+ pub func bench_n = (ref self { bench_label }, string label, func() body, int samples) {
230
230
  if self.has_failed {
231
231
  return
232
232
  }
@@ -244,7 +244,7 @@ pub mv struct Tester {
244
244
  * this is a no-op.
245
245
  **/
246
246
  pub func record_bench = (
247
- ref self,
247
+ ref self {},
248
248
  string label,
249
249
  int n,
250
250
  int min,
@@ -263,7 +263,7 @@ pub mv struct Tester {
263
263
  )
264
264
  }
265
265
 
266
- func record_failure = (ref self, string message) {
266
+ func record_failure = (ref self {}, string message) {
267
267
  self.failed += 1
268
268
  self.total_failed += 1
269
269
  self.has_failed = true
@@ -21,7 +21,7 @@ pub struct Chars {
21
21
 
22
22
  // The code point at the cursor, advancing past it. Malformed sequences
23
23
  // yield U+FFFD. Panics when exhausted — check has_next first.
24
- pub func next = (ref self, out int) {
24
+ pub func next = (ref self {}, out int) {
25
25
  if self.byte_pos >= self.source.length {
26
26
  panic("Chars exhausted; check has_next first")
27
27
  }
@@ -102,7 +102,7 @@ pub struct Json {
102
102
 
103
103
  // Parse a JSON document into tree. The caller provides a JsonTree pool
104
104
  // which is reset and filled. Returns the index of the root node.
105
- pub func parse = (string s, ref JsonTree tree, out int) {
105
+ pub func parse = (string s, ref JsonTree tree { nodes }, out int) {
106
106
  tree.reset()
107
107
  var pos = Buffer<int>()
108
108
  pos.alloc_int(1)
@@ -112,14 +112,14 @@ pub struct Json {
112
112
  }
113
113
 
114
114
  // Serialize a node in the tree back to a JSON string.
115
- pub func stringify = (ref JsonTree tree, int root, out string) {
115
+ pub func stringify = (ref JsonTree tree { nodes }, int root, out string) {
116
116
  var sb = StringBuilder()
117
117
  json_ser_value(ref tree, root, ref sb)
118
118
  return sb.to_string()
119
119
  }
120
120
  }
121
121
 
122
- func json_skip_ws = (string s, ref Buffer<int> pos, int len) {
122
+ func json_skip_ws = (string s, ref Buffer<int> pos {}, int len) {
123
123
  while pos.load_int(0) < len {
124
124
  var int i = pos.load_int(0)
125
125
  var int code = s.at(i) as int
@@ -131,7 +131,7 @@ func json_skip_ws = (string s, ref Buffer<int> pos, int len) {
131
131
  }
132
132
  }
133
133
 
134
- func json_parse_string = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
134
+ func json_parse_string = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
135
135
  var int i = pos.load_int(0)
136
136
  i += 1
137
137
  var sb = StringBuilder()
@@ -193,7 +193,7 @@ func json_parse_string = (string s, ref Buffer<int> pos, int len, ref JsonTree t
193
193
  return n
194
194
  }
195
195
 
196
- func json_parse_number = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
196
+ func json_parse_number = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
197
197
  var int i = pos.load_int(0)
198
198
  var int start = i
199
199
  while i < len {
@@ -215,7 +215,7 @@ func json_parse_number = (string s, ref Buffer<int> pos, int len, ref JsonTree t
215
215
  return n
216
216
  }
217
217
 
218
- func json_parse_literal = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
218
+ func json_parse_literal = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
219
219
  var int i = pos.load_int(0)
220
220
  var int code = s.at(i) as int
221
221
  var int n = tree.alloc_node()
@@ -237,7 +237,7 @@ func json_parse_literal = (string s, ref Buffer<int> pos, int len, ref JsonTree
237
237
  return n
238
238
  }
239
239
 
240
- func json_parse_value = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
240
+ func json_parse_value = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
241
241
  json_skip_ws(s, ref pos, len)
242
242
  var int i = pos.load_int(0)
243
243
  if i >= len {
@@ -267,7 +267,7 @@ func json_parse_value = (string s, ref Buffer<int> pos, int len, ref JsonTree tr
267
267
  return json_parse_number(s, ref pos, len, ref tree)
268
268
  }
269
269
 
270
- func json_parse_elements = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
270
+ func json_parse_elements = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
271
271
  json_skip_ws(s, ref pos, len)
272
272
  var int i = pos.load_int(0)
273
273
  if i >= len {
@@ -289,7 +289,7 @@ func json_parse_elements = (string s, ref Buffer<int> pos, int len, ref JsonTree
289
289
  return elem
290
290
  }
291
291
 
292
- func json_parse_pairs = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
292
+ func json_parse_pairs = (string s, ref Buffer<int> pos {}, int len, ref JsonTree tree { nodes }, out int) {
293
293
  json_skip_ws(s, ref pos, len)
294
294
  var int i = pos.load_int(0)
295
295
  if i >= len {
@@ -321,7 +321,7 @@ func json_parse_pairs = (string s, ref Buffer<int> pos, int len, ref JsonTree tr
321
321
  return key
322
322
  }
323
323
 
324
- func json_ser_list = (ref JsonTree tree, int first, ref StringBuilder sb) {
324
+ func json_ser_list = (ref JsonTree tree { nodes }, int first, ref StringBuilder sb {}) {
325
325
  json_ser_value(ref tree, first, ref sb)
326
326
  var int next = tree.get_next(first)
327
327
  if next >= 0 {
@@ -330,7 +330,7 @@ func json_ser_list = (ref JsonTree tree, int first, ref StringBuilder sb) {
330
330
  }
331
331
  }
332
332
 
333
- func json_ser_pairs = (ref JsonTree tree, int first, ref StringBuilder sb) {
333
+ func json_ser_pairs = (ref JsonTree tree { nodes }, int first, ref StringBuilder sb {}) {
334
334
  sb.append_char('"')
335
335
  sb.append_string_view(tree.get_text_view(first))
336
336
  sb.append_string("\":")
@@ -347,7 +347,7 @@ func json_ser_pairs = (ref JsonTree tree, int first, ref StringBuilder sb) {
347
347
  }
348
348
  }
349
349
 
350
- func json_ser_value = (ref JsonTree tree, int n, ref StringBuilder sb) {
350
+ func json_ser_value = (ref JsonTree tree { nodes }, int n, ref StringBuilder sb {}) {
351
351
  var int k = tree.get_kind(n)
352
352
  if k == 0 {
353
353
  sb.append_string("null")
@@ -37,7 +37,7 @@ pub mv struct JsonTree {
37
37
  var nodes = StableList<JsonNode>()
38
38
 
39
39
  // Append a fresh node and return its index.
40
- func alloc_node = (ref self, out int) {
40
+ func alloc_node = (ref self { nodes }, out int) {
41
41
  self.nodes.push(JsonNode())
42
42
  return self.nodes.length - 1
43
43
  }
@@ -45,7 +45,7 @@ pub mv struct JsonTree {
45
45
  // Drop the current document: the fresh StableList displaces the old one,
46
46
  // whose destroy frees every node (texts included) and its slabs. The
47
47
  // next parse starts from a clean pool.
48
- func reset = (ref self) {
48
+ func reset = (ref self { nodes }) {
49
49
  self.nodes = StableList<JsonNode>()
50
50
  }
51
51
 
@@ -58,7 +58,7 @@ pub mv struct JsonTree {
58
58
  // once, by the list's destroy or the next text store. For strings
59
59
  // produced by a StringBuilder, `take_text` installs the builder's
60
60
  // buffer with no copy at all.
61
- func set_text = (ref self, int idx, mv string text) {
61
+ func set_text = (ref self {}, int idx, mv string text) {
62
62
  if idx < 0 || idx >= self.nodes.length {
63
63
  panic("index out of range")
64
64
  }
@@ -75,7 +75,7 @@ pub mv struct JsonTree {
75
75
  // temp free. (A `mv string` parameter cannot do this: the string-arg
76
76
  // ownership convention makes mv string arguments caller-owned
77
77
  // borrows, forcing the callee-side copy this method exists to skip.)
78
- func take_text = (ref self, int idx, ref StringBuilder sb) {
78
+ func take_text = (ref self {}, int idx, ref StringBuilder sb {}) {
79
79
  if idx < 0 || idx >= self.nodes.length {
80
80
  panic("index out of range")
81
81
  }
@@ -83,7 +83,7 @@ pub mv struct JsonTree {
83
83
  n.text = sb.to_string()
84
84
  }
85
85
 
86
- func set_kind = (ref self, int idx, int val) {
86
+ func set_kind = (ref self {}, int idx, int val) {
87
87
  if idx < 0 || idx >= self.nodes.length {
88
88
  panic("index out of range")
89
89
  }
@@ -91,7 +91,7 @@ pub mv struct JsonTree {
91
91
  n.kind = val
92
92
  }
93
93
 
94
- func set_child = (ref self, int idx, int val) {
94
+ func set_child = (ref self {}, int idx, int val) {
95
95
  if idx < 0 || idx >= self.nodes.length {
96
96
  panic("index out of range")
97
97
  }
@@ -99,7 +99,7 @@ pub mv struct JsonTree {
99
99
  n.child = val
100
100
  }
101
101
 
102
- func set_next = (ref self, int idx, int val) {
102
+ func set_next = (ref self {}, int idx, int val) {
103
103
  if idx < 0 || idx >= self.nodes.length {
104
104
  panic("index out of range")
105
105
  }
@@ -107,7 +107,7 @@ pub mv struct JsonTree {
107
107
  n.next = val
108
108
  }
109
109
 
110
- func set_val = (ref self, int idx, int val) {
110
+ func set_val = (ref self {}, int idx, int val) {
111
111
  if idx < 0 || idx >= self.nodes.length {
112
112
  panic("index out of range")
113
113
  }
@@ -69,7 +69,7 @@ pub struct Regex {
69
69
  pub func captures = (
70
70
  string pattern,
71
71
  string input,
72
- ref List<string> dst,
72
+ ref List<string> dst { items },
73
73
  out bool
74
74
  ) { var int pat_len = pattern.length
75
75
  var int len = input.length
@@ -117,7 +117,7 @@ pub struct Regex {
117
117
  // first, so a reused RegexMatch carries nothing over. Scans every
118
118
  // position: the first-byte prefilter would skip nullable patterns'
119
119
  // empty matches at skipped positions, reporting a wrong .start.
120
- pub func find = (string pattern, string input, ref RegexMatch dst) {
120
+ pub func find = (string pattern, string input, ref RegexMatch dst { text }) {
121
121
  dst.found = false
122
122
  dst.start = 0
123
123
  dst.end = 0
@@ -232,13 +232,13 @@ pub struct Regex {
232
232
  }
233
233
 
234
234
  // find, ignoring ASCII case.
235
- pub func find_ci = (string pattern, string input, ref RegexMatch dst) {
235
+ pub func find_ci = (string pattern, string input, ref RegexMatch dst { text }) {
236
236
  var string folded = fold_pattern(pattern)
237
237
  Regex.find(folded, input, ref dst)
238
238
  }
239
239
 
240
240
  // captures, ignoring ASCII case.
241
- pub func captures_ci = (string pattern, string input, ref List<string> dst, out bool) {
241
+ pub func captures_ci = (string pattern, string input, ref List<string> dst { items }, out bool) {
242
242
  var string folded = fold_pattern(pattern)
243
243
  return Regex.captures(folded, input, ref dst)
244
244
  }
@@ -308,7 +308,7 @@ func fold_pattern = (string pattern, mv out string) {
308
308
 
309
309
  // fold a character class [cs..ce): copy its contents, adding the case
310
310
  // counterpart of every letter member and mirroring letter ranges.
311
- func fold_class = (string pattern, int cs, int ce, ref StringBuilder dst) {
311
+ func fold_class = (string pattern, int cs, int ce, ref StringBuilder dst {}) {
312
312
  dst.append_char('[')
313
313
  var int i = cs + 1
314
314
  if i < ce - 1 {
@@ -435,7 +435,7 @@ func collect_first_bytes = (
435
435
  string pattern,
436
436
  int pat_pos,
437
437
  int pat_end,
438
- ref StringBuilder sb,
438
+ ref StringBuilder sb {},
439
439
  out int
440
440
  ) {
441
441
  var depth = 0
@@ -482,7 +482,7 @@ func collect_first_bytes = (
482
482
  // atom — literal, escaped, class, or group — quantified with '?'/'*' is
483
483
  // nullable: what FOLLOWS it can also be first, so the scan continues past it.
484
484
  // A wildcard '.' or an empty alternative makes the set indeterminable.
485
- func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb, out int) {
485
+ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb {}, out int) {
486
486
  var int i = start
487
487
  while i < end {
488
488
  var char c = pattern.at(i)
@@ -722,7 +722,7 @@ func add_class_chars = (
722
722
  string pattern,
723
723
  int start,
724
724
  int end,
725
- ref StringBuilder sb
725
+ ref StringBuilder sb {}
726
726
  ) { var int cs = start
727
727
  if cs < end {
728
728
  if pattern.at(cs) == '^' {
@@ -777,7 +777,7 @@ func match_here = (
777
777
  string input,
778
778
  int in_pos,
779
779
  int in_len,
780
- ref List<int> caps,
780
+ ref List<int> caps { items },
781
781
  out int: out <= in_len
782
782
  ) {
783
783
  // Handle top-level alternation: a '|' at bracket/paren depth 0 splits the
@@ -1036,7 +1036,7 @@ func match_group_then_rest = (
1036
1036
  string input,
1037
1037
  int in_pos,
1038
1038
  int in_len,
1039
- ref List<int> caps,
1039
+ ref List<int> caps { items },
1040
1040
  out int
1041
1041
  ) {
1042
1042
  var int g = group_index_at(pattern, atom_start)
@@ -1127,7 +1127,7 @@ func match_single_atom = (
1127
1127
  string input,
1128
1128
  int in_pos,
1129
1129
  int in_len,
1130
- ref List<int> caps,
1130
+ ref List<int> caps { items },
1131
1131
  out int
1132
1132
  ) {
1133
1133
  var char pc = pattern.at(atom_start)
@@ -1309,7 +1309,7 @@ func match_counted = (
1309
1309
  int lazy,
1310
1310
  int count,
1311
1311
  int in_len,
1312
- ref List<int> caps,
1312
+ ref List<int> caps { items },
1313
1313
  out int
1314
1314
  ) {
1315
1315
  var can_stop = count >= min_count
@@ -1407,7 +1407,7 @@ func match_star = (
1407
1407
  int min_count,
1408
1408
  int lazy,
1409
1409
  int in_len,
1410
- ref List<int> caps,
1410
+ ref List<int> caps { items },
1411
1411
  out int
1412
1412
  ) {
1413
1413
  var char pc = pattern.at(atom_start)
@@ -1490,7 +1490,7 @@ func match_star_group = (
1490
1490
  int min_count,
1491
1491
  int lazy,
1492
1492
  int in_len,
1493
- ref List<int> caps,
1493
+ ref List<int> caps { items },
1494
1494
  out int
1495
1495
  ) {
1496
1496
  if lazy > 0 {
@@ -1559,7 +1559,7 @@ func match_group_iteration = (
1559
1559
  int min_count,
1560
1560
  int lazy,
1561
1561
  int in_len,
1562
- ref List<int> caps,
1562
+ ref List<int> caps { items },
1563
1563
  out int
1564
1564
  ) {
1565
1565
  var int g = group_index_at(pattern, atom_start)
@@ -1626,7 +1626,7 @@ func match_optional = (
1626
1626
  int in_pos,
1627
1627
  int lazy,
1628
1628
  int in_len,
1629
- ref List<int> caps,
1629
+ ref List<int> caps { items },
1630
1630
  out int
1631
1631
  ) {
1632
1632
  if lazy > 0 {
@@ -1899,7 +1899,7 @@ func group_index_at = (string pattern, int open_pos, out int) {
1899
1899
  // group_pos. A later span for the same group supersedes the earlier one, so
1900
1900
  // a repeated group reports its last iteration; a failed group records
1901
1901
  // (-1, -1) so stale spans from an abandoned attempt never surface.
1902
- func record_capture = (ref List<int> caps, int group, int start, int end) {
1902
+ func record_capture = (ref List<int> caps { items }, int group, int start, int end) {
1903
1903
  if group <= 0 {
1904
1904
  return
1905
1905
  }
@@ -1958,7 +1958,7 @@ func match_backref = (
1958
1958
  int group,
1959
1959
  int in_pos,
1960
1960
  int in_len,
1961
- ref List<int> caps,
1961
+ ref List<int> caps {},
1962
1962
  out int
1963
1963
  ) {
1964
1964
  var int at = last_capture_index(caps, group)
@@ -1994,7 +1994,7 @@ func match_star_backref = (
1994
1994
  int min_count,
1995
1995
  int lazy,
1996
1996
  int in_len,
1997
- ref List<int> caps,
1997
+ ref List<int> caps { items },
1998
1998
  out int
1999
1999
  ) {
2000
2000
  var int group = backref_group(pattern.at(atom_start + 1))
@@ -2116,7 +2116,7 @@ func matches_shorthand = (char c, char b, out bool) {
2116
2116
  // first-byte charset. Complement shorthands (S/D/W) match "anything else" —
2117
2117
  // not expressible as an inclusion set — so they return -1, which disables
2118
2118
  // the caller's prefilter.
2119
- func shorthand_members = (char c, ref StringBuilder sb, out int) {
2119
+ func shorthand_members = (char c, ref StringBuilder sb {}, out int) {
2120
2120
  var int kind = c as int
2121
2121
  if kind == 83 || kind == 68 || kind == 87 {
2122
2122
  return -1
@@ -82,9 +82,13 @@ pub mv struct Thread<T> : Spawnable<T> {
82
82
  // fields, so #destroy becomes a no-op afterwards. The future's refs
83
83
  // account for the trampoline, the returned handle, and the nursery (when
84
84
  // captured).
85
- pub func start = (ref self, mv out Task<T>) {
85
+ pub func start = (ref self {}, mv out Task<T>) {
86
86
  ```
87
87
  #arch: c
88
+ // Single-launch contract: a consumed construction (started) owns
89
+ // nothing — the handles below are zeroed, and writing the ref count
90
+ // through the null future would fault. Abort with the reason.
91
+ if (self->started) __nomen_spawn_double_start_abort();
88
92
  struct nomen_future *_f = (struct nomen_future *)self->future;
89
93
  _f->refs = self->nursery_futures ? 3 : 2;
90
94
  __nomen_pool_submit((struct nomen_closure *)self->task);
@@ -94,7 +98,12 @@ pub mv struct Thread<T> : Spawnable<T> {
94
98
  ```
95
99
  ```
96
100
  #arch: aarch64
97
- // x19 = self. f = self->future (#32); nursery_futures at #48.
101
+ // x19 = self. started at #40; f = self->future (#32); nursery_futures
102
+ // at #48. Single-launch contract first: a consumed construction has
103
+ // zeroed handles, and the ref-store below would write through null.
104
+ ldrb w9, [x19, #40]
105
+ cbnz w9, .Lnomen_start_double
106
+ // f = self->future (#32); nursery_futures at #48.
98
107
  ldr x0, [x19, #32]
99
108
  ldr x1, [x19, #48]
100
109
  mov w2, #2
@@ -113,6 +122,10 @@ pub mv struct Thread<T> : Spawnable<T> {
113
122
  ldr x3, [x19, #32]
114
123
  bl ___nomen_nursery_track
115
124
  .Lnomen_start_notrack:
125
+ b .Lnomen_start_done
126
+ .Lnomen_start_double:
127
+ bl ___nomen_spawn_double_start_abort
128
+ .Lnomen_start_done:
116
129
  ```
117
130
  // The handle is a fresh heap Task built through the internal #init;
118
131
  // the caller owns it (a discarded statement form is reclaimed at
@@ -136,9 +149,12 @@ pub mv struct Thread<T> : Spawnable<T> {
136
149
  // mid-execution BY DESIGN. The unused future (a Thread always carries
137
150
  // the full machinery) is released — first detaching the closure from it,
138
151
  // so the daemon runner owns the closure now.
139
- pub func detach = (ref self) {
152
+ pub func detach = (ref self {}) {
140
153
  ```
141
154
  #arch: c
155
+ // Single-launch contract (see .start): a consumed construction has
156
+ // zeroed handles, and detaching the null closure would crash a worker.
157
+ if (self->started) __nomen_spawn_double_start_abort();
142
158
  struct nomen_future *_uf = (struct nomen_future *)self->future;
143
159
  if (_uf) {
144
160
  _uf->owner_args = NULL;
@@ -148,6 +164,9 @@ pub mv struct Thread<T> : Spawnable<T> {
148
164
  ```
149
165
  ```
150
166
  #arch: aarch64
167
+ // Single-launch contract first (see .start): started at #40.
168
+ ldrb w9, [x19, #40]
169
+ cbnz w9, .Lnomen_detach_double
151
170
  // if (self->future) { owner_args = NULL; release it }
152
171
  ldr x0, [x19, #32]
153
172
  cbz x0, .Lnomen_detach_nofut
@@ -157,6 +176,10 @@ pub mv struct Thread<T> : Spawnable<T> {
157
176
  // __nomen_task_detach(self->task)
158
177
  ldr x0, [x19, #8]
159
178
  bl ___nomen_task_detach
179
+ b .Lnomen_detach_done
180
+ .Lnomen_detach_double:
181
+ bl ___nomen_spawn_double_start_abort
182
+ .Lnomen_detach_done:
160
183
  ```
161
184
  self.task = 0
162
185
  self.future = 0
@@ -13,7 +13,7 @@ pub mv struct Tree<T>: Enumerable {
13
13
  var parents = Buffer<int>()
14
14
  var count = 0
15
15
 
16
- pub func add = (ref self, mv T value) {
16
+ pub func add = (ref self { lefts, parents, rights, values }, mv T value) {
17
17
  const int idx = self.count
18
18
  self.values.grow_int(idx + 1)
19
19
  const int v = value
@@ -27,12 +27,12 @@ pub mv struct Tree<T>: Enumerable {
27
27
  self.count = self.count + 1
28
28
  }
29
29
 
30
- pub func set_left = (ref self, int idx, int left) {
30
+ pub func set_left = (ref self { lefts, parents }, int idx, int left) {
31
31
  self.lefts.store_int(idx, left)
32
32
  self.parents.store_int(left, idx)
33
33
  }
34
34
 
35
- pub func set_right = (ref self, int idx, int right) {
35
+ pub func set_right = (ref self { parents, rights }, int idx, int right) {
36
36
  self.rights.store_int(idx, right)
37
37
  self.parents.store_int(right, idx)
38
38
  }
@@ -57,6 +57,22 @@ pub mv struct Tree<T>: Enumerable {
57
57
  return self.values.load_int(idx)
58
58
  }
59
59
 
60
+ // Bounds-checked access: `fallback` when idx is outside [0, self.count).
61
+ pub func at_or = (self, int idx, T fallback, out T) {
62
+ if idx >= 0 && idx < self.count {
63
+ return self.at(idx)
64
+ }
65
+ return fallback
66
+ }
67
+
68
+ // Bounds-checked access that traps when idx is outside [0, self.count).
69
+ pub func at_or_panic = (self, int idx, out T) {
70
+ if idx >= 0 && idx < self.count {
71
+ return self.at(idx)
72
+ }
73
+ panic("index out of range")
74
+ }
75
+
60
76
  pub func count_nodes = (self, int idx, out int) {
61
77
  if idx == -1 {
62
78
  return 0