nomen-lang 0.6.0 → 0.6.2

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.
@@ -61,6 +61,18 @@ pub struct List<T>: Viewable {
61
61
  self.items.replace(i, value)
62
62
  }
63
63
 
64
+ // Bounds-checked write that traps when i is outside [0, self.length) —
65
+ // for indices that can't be proven at compile time (cross-module calls
66
+ // can never discharge `set`'s parameter constraint) and out-of-range is
67
+ // a bug, not a case.
68
+ pub func set_or_panic = (ref self, int i, move T value) {
69
+ if i >= 0 && i < self.length {
70
+ self.set(i, value)
71
+ return
72
+ }
73
+ panic("index out of range")
74
+ }
75
+
64
76
  // A deep copy: a fresh List<T> with an independent copy of every element.
65
77
  // For owning element types (strings, owning value structs) each slot in the
66
78
  // copy owns its own heap data (Buffer deep-copies on store), so the source
@@ -16,7 +16,9 @@ pub struct StringBuilder {
16
16
  // Ensure capacity for at least `needed` bytes. Grows geometrically.
17
17
  // Plain Nomen + the memory externs — no pointer arithmetic needed, so
18
18
  // this doesn't even require an unsafe context.
19
- func ensure = (ref self, int needed) {
19
+ // `internal`: capacity plumbing for the builder's own appenders; not
20
+ // part of the user surface.
21
+ internal func ensure = (ref self, int needed) {
20
22
  if self.cap >= needed {
21
23
  return
22
24
  }
@@ -84,7 +86,10 @@ pub struct StringBuilder {
84
86
  // Append a null-terminated string. `unsafe` Nomen single-sourced for
85
87
  // both backends: the fat pair's pointer half feeds memcpy directly, and
86
88
  // the tracked length replaces the strlen the old C body paid.
87
- func append_string = (ref self, string s) {
89
+ // `internal`: a library-implementation append — user code appends with
90
+ // `append_char` / `append_string_view`; the library's own structs (Json,
91
+ // Regex) are on the trusted side of the boundary.
92
+ internal func append_string = (ref self, string s) {
88
93
  unsafe {
89
94
  var int sl = s.length
90
95
  self.ensure(self.len + sl + 1)
@@ -120,9 +125,127 @@ pub struct StringBuilder {
120
125
  }
121
126
  }
122
127
 
128
+ // Read-back: how many bytes the buffer currently holds. (The `len` field
129
+ // is private; this is the O(1) peek the incremental-builder flow needs —
130
+ // e.g. recording a mark before appending a section.)
131
+ pub func length = (self, out int) {
132
+ return self.len
133
+ }
134
+
135
+ // Whether the buffer's current bytes end with `suffix` (an empty suffix
136
+ // is always true). Reads the buffer tail in place — no copy of either
137
+ // side (`view string` avoids materializing the checked suffix).
138
+ pub func ends_with = (ref self, view string suffix, out bool) {
139
+ unsafe {
140
+ var int sl = suffix.length
141
+ if sl > self.len {
142
+ return false
143
+ }
144
+ var int start = self.len - sl
145
+ var int i = 0
146
+ while i < sl; i += 1 {
147
+ if (self.data as ptr char)[start + i] != (suffix as ptr char)[i] {
148
+ return false
149
+ }
150
+ }
151
+ }
152
+ return true
153
+ }
154
+
155
+ // Truncate the buffer to `new_len` bytes (clamped to [0, len]). Capacity
156
+ // is kept, so a subsequent append reuses the storage without a realloc.
157
+ pub func truncate = (ref self, int new_len) {
158
+ var int n = new_len
159
+ if n < 0 {
160
+ n = 0
161
+ }
162
+ if n > self.len {
163
+ n = self.len
164
+ }
165
+ self.len = n
166
+ }
167
+
168
+ // Drop the last byte (a no-op when the buffer is empty). The common
169
+ // chomp-the-trailing-separator shape.
170
+ pub func chomp = (ref self) {
171
+ if self.len > 0 {
172
+ self.len = self.len - 1
173
+ }
174
+ }
175
+
176
+ // Extract the bytes from `mark` to the end as a fresh owned string and
177
+ // rewind the buffer to `mark` bytes (capacity kept). The mid-render
178
+ // measure-and-restart shape: record `length()`, append a section, then
179
+ // `take_since(mark)` to measure it and re-emit decorated. `mark` clamps
180
+ // to [0, len]; the returned string is always an independent allocation.
181
+ // (`move out string` — the raw body mallocs the result, so the caller
182
+ // owns it by signature, like `Console.read_line`.)
183
+ pub func take_since = (ref self, int mark, move out string) {
184
+ ```
185
+ #arch: c
186
+ int start = mark;
187
+ if (start < 0) start = 0;
188
+ if (start > self->len) start = self->len;
189
+ int n = self->len - start;
190
+ char* buf = (char*)malloc((size_t)n + 1);
191
+ if (n > 0) memcpy(buf, (void*)(unsigned long long)(self->data + start), n);
192
+ buf[n] = 0;
193
+ self->len = start;
194
+ // Fat-string ABI: return the (ptr, len) pair — no strlen.
195
+ return (nomen_string){ buf, n };
196
+ ```
197
+ ```
198
+ #arch: aarch64
199
+ // x19 = self, x1 = mark. Clamp start to [0, len]; malloc(n+1),
200
+ // copy the tail, null-terminate, rewind len. Live values live in a
201
+ // 32-byte (16-aligned) frame across the calls (x0-x18 are
202
+ // caller-saved): [sp]=start, [sp+8]=n, [sp+16]=buf.
203
+ ldr x2, [x19, #16] // len
204
+ mov x3, x1 // start = mark
205
+ cmp x3, #0
206
+ b.ge .Lsb_tk_hi
207
+ mov x3, #0
208
+ .Lsb_tk_hi:
209
+ cmp x3, x2
210
+ b.le .Lsb_tk_ok
211
+ mov x3, x2 // start = min(start, len)
212
+ .Lsb_tk_ok:
213
+ sub x4, x2, x3 // n = len - start
214
+ sub sp, sp, #32
215
+ str x3, [sp, #0] // start
216
+ str x4, [sp, #8] // n
217
+ add x0, x4, #1
218
+ // buf = malloc(n + 1) — bare call line: the audit pass rewrites
219
+ // `bl _malloc` (line-exact) to the counter-wrapped allocator.
220
+ bl _malloc
221
+ str x0, [sp, #16]
222
+ ldr x1, [sp, #8] // n
223
+ cbz x1, .Lsb_tk_copied
224
+ ldr x0, [sp, #16] // dst = buf
225
+ ldr x3, [x19, #8] // data
226
+ ldr x4, [sp, #0] // start
227
+ add x1, x3, x4 // src = data + start
228
+ ldr x2, [sp, #8] // n
229
+ bl _memcpy
230
+ .Lsb_tk_copied:
231
+ ldr x0, [sp, #16] // buf
232
+ ldr x1, [sp, #8] // n
233
+ add x2, x0, x1
234
+ strb wzr, [x2] // buf[n] = 0
235
+ ldr x3, [sp, #0] // start
236
+ str x3, [x19, #16] // len = start
237
+ ldr x0, [sp, #16] // return pair: (buf, n)
238
+ ldr x1, [sp, #8]
239
+ add sp, sp, #32
240
+ ```
241
+ }
242
+
123
243
  // Finalize: null-terminate, return the byte buffer as a string, and
124
244
  // release ownership (sets `data` to 0 so the destructor won't free it).
125
- func to_string = (ref self, out string) {
245
+ // Explicitly `pub`: struct members default to pub, but this is the
246
+ // builder's primary read-back — the contract should not depend on the
247
+ // default.
248
+ pub func to_string = (ref self, out string) {
126
249
  ```
127
250
  #arch: c
128
251
  int idx = self->len;