nomen-lang 0.5.0 → 0.6.1
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/Arena.nm +6 -6
- package/core/System/Buffer.nm +15 -6
- package/core/System/Channel.nm +2 -0
- package/core/System/ClassBuffer.nm +14 -5
- package/core/System/Controls/Button.nm +2 -2
- package/core/System/Controls/CheckBox.nm +2 -2
- package/core/System/Controls/Container.nm +3 -3
- package/core/System/Controls/TextBox.nm +2 -2
- package/core/System/Fiber.nm +85 -5
- package/core/System/Graph.nm +1 -1
- package/core/System/LinkedList.nm +1 -1
- package/core/System/List.nm +3 -3
- package/core/System/Map.nm +2 -2
- package/core/System/Mutex.nm +8 -8
- package/core/System/Option.nm +2 -2
- package/core/System/Random.nm +67 -0
- package/core/System/Result.nm +2 -2
- package/core/System/Set.nm +1 -1
- package/core/System/Spawnable.nm +18 -0
- package/core/System/Stream/File.nm +3 -3
- package/core/System/Stream/Http.nm +5 -5
- package/core/System/Stream/Tcp.nm +6 -6
- package/core/System/String.nm +7 -7
- package/core/System/StringBuilder.nm +116 -1
- package/core/System/Task.nm +42 -8
- package/core/System/Test.nm +20 -11
- package/core/System/Text/CharIndex.nm +8 -8
- package/core/System/Text/Chars.nm +1 -1
- package/core/System/Text/JsonTree.nm +1 -1
- package/core/System/Text/Regex.nm +176 -58
- package/core/System/Text/Utf8.nm +6 -6
- package/core/System/Thread.nm +118 -2
- package/core/System/Tree.nm +1 -1
- package/dist/index.mjs +1201 -1101
- package/package.json +1 -1
- package/src/test.ts +22 -4
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
/**
|
|
27
27
|
* A non-blocking TCP socket whose waits park the calling fiber
|
|
28
28
|
**/
|
|
29
|
-
pub class Tcp
|
|
29
|
+
pub class Tcp: Sendable {
|
|
30
30
|
// The underlying file descriptor, -1 when closed/failed.
|
|
31
31
|
pub var int fd = -1
|
|
32
32
|
// 0 = ok; 1 = DNS, 2 = socket, 3 = connect, 4 = listen, 5 = closed.
|
|
33
|
-
pub var
|
|
33
|
+
pub var error = 0
|
|
34
34
|
|
|
35
35
|
pub func #init = (self, int handle) {
|
|
36
36
|
self.fd = handle
|
|
@@ -66,7 +66,7 @@ pub class Tcp : Sendable {
|
|
|
66
66
|
// Create a listening socket bound to `port` on all interfaces.
|
|
67
67
|
pub func listen = (int port, int backlog, move out Tcp) {
|
|
68
68
|
var int handle = Tcp.listen_fd(port, backlog)
|
|
69
|
-
var
|
|
69
|
+
var t = Tcp(handle)
|
|
70
70
|
if handle < 0 {
|
|
71
71
|
t.error = 4
|
|
72
72
|
}
|
|
@@ -78,7 +78,7 @@ pub class Tcp : Sendable {
|
|
|
78
78
|
// failed.
|
|
79
79
|
pub func accept = (ref self, move out Tcp) {
|
|
80
80
|
var int handle = Tcp.accept_fd(self.fd)
|
|
81
|
-
var
|
|
81
|
+
var t = Tcp(handle)
|
|
82
82
|
if handle < 0 {
|
|
83
83
|
t.error = 5
|
|
84
84
|
}
|
|
@@ -91,14 +91,14 @@ pub class Tcp : Sendable {
|
|
|
91
91
|
pub func connect = (string host, int port, move out Tcp) {
|
|
92
92
|
var int handle = Tcp.socket_fd()
|
|
93
93
|
if handle < 0 {
|
|
94
|
-
var
|
|
94
|
+
var bad = Tcp(-1)
|
|
95
95
|
bad.error = 2
|
|
96
96
|
return bad
|
|
97
97
|
}
|
|
98
98
|
var int err = Tcp.connect_to(handle, host, port)
|
|
99
99
|
if err != 0 {
|
|
100
100
|
Tcp.close_fd(handle)
|
|
101
|
-
var
|
|
101
|
+
var bad = Tcp(-1)
|
|
102
102
|
bad.error = err
|
|
103
103
|
return bad
|
|
104
104
|
}
|
package/core/System/String.nm
CHANGED
|
@@ -248,7 +248,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
248
248
|
// are only ever read.
|
|
249
249
|
pub func replace_first = (self, view string needle, view string replacement, out string) {
|
|
250
250
|
var sb = StringBuilder()
|
|
251
|
-
var
|
|
251
|
+
var i = 0
|
|
252
252
|
var int n = self.length
|
|
253
253
|
var int nlen = needle.length
|
|
254
254
|
var bool replaced = nlen == 0
|
|
@@ -269,7 +269,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
269
269
|
// left to right. Same edge behavior as replace_first.
|
|
270
270
|
pub func replace_all = (self, view string needle, view string replacement, out string) {
|
|
271
271
|
var sb = StringBuilder()
|
|
272
|
-
var
|
|
272
|
+
var i = 0
|
|
273
273
|
var int n = self.length
|
|
274
274
|
var int nlen = needle.length
|
|
275
275
|
while i < n {
|
|
@@ -391,7 +391,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
391
391
|
// Owned copy of self with leading and trailing ASCII whitespace
|
|
392
392
|
// (tab, LF, VT, FF, CR, space) removed. All-whitespace yields "".
|
|
393
393
|
pub func trim = (self, out string) {
|
|
394
|
-
var
|
|
394
|
+
var start = 0
|
|
395
395
|
while start < self.length; start += 1 {
|
|
396
396
|
if !self.at(start).is_ascii_space() {
|
|
397
397
|
break
|
|
@@ -421,7 +421,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
421
421
|
|
|
422
422
|
// Owned copy of self with leading ASCII whitespace removed.
|
|
423
423
|
pub func trim_start = (self, out string) {
|
|
424
|
-
var
|
|
424
|
+
var start = 0
|
|
425
425
|
while start < self.length; start += 1 {
|
|
426
426
|
if !self.at(start).is_ascii_space() {
|
|
427
427
|
break
|
|
@@ -435,7 +435,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
435
435
|
// bytes — including UTF-8 sequences — pass through unchanged).
|
|
436
436
|
pub func to_lowercase = (self, out string) {
|
|
437
437
|
var sb = StringBuilder()
|
|
438
|
-
var
|
|
438
|
+
var i = 0
|
|
439
439
|
while i < self.length; i += 1 {
|
|
440
440
|
var int code = self.at(i) as int
|
|
441
441
|
if code > 64 && code < 91 {
|
|
@@ -450,7 +450,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
450
450
|
// bytes — including UTF-8 sequences — pass through unchanged).
|
|
451
451
|
pub func to_uppercase = (self, out string) {
|
|
452
452
|
var sb = StringBuilder()
|
|
453
|
-
var
|
|
453
|
+
var i = 0
|
|
454
454
|
while i < self.length; i += 1 {
|
|
455
455
|
var int code = self.at(i) as int
|
|
456
456
|
if code > 96 && code < 123 {
|
|
@@ -465,7 +465,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
465
465
|
// needle matches text at byte offset pos (caller guarantees pos + len fits;
|
|
466
466
|
// the trailing guard makes the bound explicit so `.at` verifies).
|
|
467
467
|
func match_at = (view string text, view string needle, int pos, out bool) {
|
|
468
|
-
var
|
|
468
|
+
var i = 0
|
|
469
469
|
var int nlen = needle.length
|
|
470
470
|
var int n = text.length
|
|
471
471
|
while i < nlen && pos + i < n {
|
|
@@ -24,7 +24,7 @@ pub struct StringBuilder {
|
|
|
24
24
|
if new_cap == 0 {
|
|
25
25
|
new_cap = 16
|
|
26
26
|
}
|
|
27
|
-
while new_cap < needed; new_cap *= 2 {}
|
|
27
|
+
while new_cap < needed; new_cap *= 2 { }
|
|
28
28
|
self.data = realloc(self.data, new_cap)
|
|
29
29
|
self.cap = new_cap
|
|
30
30
|
}
|
|
@@ -120,6 +120,121 @@ pub struct StringBuilder {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// Read-back: how many bytes the buffer currently holds. (The `len` field
|
|
124
|
+
// is private; this is the O(1) peek the incremental-builder flow needs —
|
|
125
|
+
// e.g. recording a mark before appending a section.)
|
|
126
|
+
pub func length = (self, out int) {
|
|
127
|
+
return self.len
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Whether the buffer's current bytes end with `suffix` (an empty suffix
|
|
131
|
+
// is always true). Reads the buffer tail in place — no copy of either
|
|
132
|
+
// side (`view string` avoids materializing the checked suffix).
|
|
133
|
+
pub func ends_with = (ref self, view string suffix, out bool) {
|
|
134
|
+
unsafe {
|
|
135
|
+
var int sl = suffix.length
|
|
136
|
+
if sl > self.len {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
var int start = self.len - sl
|
|
140
|
+
var int i = 0
|
|
141
|
+
while i < sl; i += 1 {
|
|
142
|
+
if (self.data as ptr char)[start + i] != (suffix as ptr char)[i] {
|
|
143
|
+
return false
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Truncate the buffer to `new_len` bytes (clamped to [0, len]). Capacity
|
|
151
|
+
// is kept, so a subsequent append reuses the storage without a realloc.
|
|
152
|
+
pub func truncate = (ref self, int new_len) {
|
|
153
|
+
var int n = new_len
|
|
154
|
+
if n < 0 {
|
|
155
|
+
n = 0
|
|
156
|
+
}
|
|
157
|
+
if n > self.len {
|
|
158
|
+
n = self.len
|
|
159
|
+
}
|
|
160
|
+
self.len = n
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Drop the last byte (a no-op when the buffer is empty). The common
|
|
164
|
+
// chomp-the-trailing-separator shape.
|
|
165
|
+
pub func chomp = (ref self) {
|
|
166
|
+
if self.len > 0 {
|
|
167
|
+
self.len = self.len - 1
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Extract the bytes from `mark` to the end as a fresh owned string and
|
|
172
|
+
// rewind the buffer to `mark` bytes (capacity kept). The mid-render
|
|
173
|
+
// measure-and-restart shape: record `length()`, append a section, then
|
|
174
|
+
// `take_since(mark)` to measure it and re-emit decorated. `mark` clamps
|
|
175
|
+
// to [0, len]; the returned string is always an independent allocation.
|
|
176
|
+
// (`move out string` — the raw body mallocs the result, so the caller
|
|
177
|
+
// owns it by signature, like `Console.read_line`.)
|
|
178
|
+
func take_since = (ref self, int mark, move out string) {
|
|
179
|
+
```
|
|
180
|
+
#arch: c
|
|
181
|
+
int start = mark;
|
|
182
|
+
if (start < 0) start = 0;
|
|
183
|
+
if (start > self->len) start = self->len;
|
|
184
|
+
int n = self->len - start;
|
|
185
|
+
char* buf = (char*)malloc((size_t)n + 1);
|
|
186
|
+
if (n > 0) memcpy(buf, (void*)(unsigned long long)(self->data + start), n);
|
|
187
|
+
buf[n] = 0;
|
|
188
|
+
self->len = start;
|
|
189
|
+
// Fat-string ABI: return the (ptr, len) pair — no strlen.
|
|
190
|
+
return (nomen_string){ buf, n };
|
|
191
|
+
```
|
|
192
|
+
```
|
|
193
|
+
#arch: aarch64
|
|
194
|
+
// x19 = self, x1 = mark. Clamp start to [0, len]; malloc(n+1),
|
|
195
|
+
// copy the tail, null-terminate, rewind len. Live values live in a
|
|
196
|
+
// 32-byte (16-aligned) frame across the calls (x0-x18 are
|
|
197
|
+
// caller-saved): [sp]=start, [sp+8]=n, [sp+16]=buf.
|
|
198
|
+
ldr x2, [x19, #16] // len
|
|
199
|
+
mov x3, x1 // start = mark
|
|
200
|
+
cmp x3, #0
|
|
201
|
+
b.ge .Lsb_tk_hi
|
|
202
|
+
mov x3, #0
|
|
203
|
+
.Lsb_tk_hi:
|
|
204
|
+
cmp x3, x2
|
|
205
|
+
b.le .Lsb_tk_ok
|
|
206
|
+
mov x3, x2 // start = min(start, len)
|
|
207
|
+
.Lsb_tk_ok:
|
|
208
|
+
sub x4, x2, x3 // n = len - start
|
|
209
|
+
sub sp, sp, #32
|
|
210
|
+
str x3, [sp, #0] // start
|
|
211
|
+
str x4, [sp, #8] // n
|
|
212
|
+
add x0, x4, #1
|
|
213
|
+
// buf = malloc(n + 1) — bare call line: the audit pass rewrites
|
|
214
|
+
// `bl _malloc` (line-exact) to the counter-wrapped allocator.
|
|
215
|
+
bl _malloc
|
|
216
|
+
str x0, [sp, #16]
|
|
217
|
+
ldr x1, [sp, #8] // n
|
|
218
|
+
cbz x1, .Lsb_tk_copied
|
|
219
|
+
ldr x0, [sp, #16] // dst = buf
|
|
220
|
+
ldr x3, [x19, #8] // data
|
|
221
|
+
ldr x4, [sp, #0] // start
|
|
222
|
+
add x1, x3, x4 // src = data + start
|
|
223
|
+
ldr x2, [sp, #8] // n
|
|
224
|
+
bl _memcpy
|
|
225
|
+
.Lsb_tk_copied:
|
|
226
|
+
ldr x0, [sp, #16] // buf
|
|
227
|
+
ldr x1, [sp, #8] // n
|
|
228
|
+
add x2, x0, x1
|
|
229
|
+
strb wzr, [x2] // buf[n] = 0
|
|
230
|
+
ldr x3, [sp, #0] // start
|
|
231
|
+
str x3, [x19, #16] // len = start
|
|
232
|
+
ldr x0, [sp, #16] // return pair: (buf, n)
|
|
233
|
+
ldr x1, [sp, #8]
|
|
234
|
+
add sp, sp, #32
|
|
235
|
+
```
|
|
236
|
+
}
|
|
237
|
+
|
|
123
238
|
// Finalize: null-terminate, return the byte buffer as a string, and
|
|
124
239
|
// release ownership (sets `data` to 0 so the destructor won't free it).
|
|
125
240
|
func to_string = (ref self, out string) {
|
package/core/System/Task.nm
CHANGED
|
@@ -24,6 +24,14 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
24
24
|
pub var uint64 cancel_flag = 0
|
|
25
25
|
pub var uint64 future = 0
|
|
26
26
|
|
|
27
|
+
// INTERNAL (library-only): constructs a zeroed handle. `Thread.start` /
|
|
28
|
+
// `Fiber.start` build the Task they return through this — a user can
|
|
29
|
+
// wait/result/cancel a handle, but never constructs a bare one (it would
|
|
30
|
+
// reference no task at all). The auto-free pass reclaims the returned
|
|
31
|
+
// handle via #destroy, exactly like a spawn-yielded Task.
|
|
32
|
+
internal #init = () {
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
// Block until the task finishes. Idempotent — calling twice is safe, and
|
|
28
36
|
// a Task captured from a nursery spawn can be waited on here AND joined
|
|
29
37
|
// by the nursery at block exit (both wait on the same shared future).
|
|
@@ -160,6 +168,24 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
160
168
|
```
|
|
161
169
|
}
|
|
162
170
|
|
|
171
|
+
// Has the task finished? A poll — never blocks. True once the task's
|
|
172
|
+
// future has completed; false while it may still be running (and for a
|
|
173
|
+
// handle whose machinery was already consumed). The missing peek
|
|
174
|
+
// between wait (blocking) and cancel (cooperative): event loops use it
|
|
175
|
+
// to notice a finished task without parking the UI thread.
|
|
176
|
+
pub func is_done = (ref self, out bool) {
|
|
177
|
+
```
|
|
178
|
+
#arch: c
|
|
179
|
+
return __nomen_future_is_done((struct nomen_future *)self->future);
|
|
180
|
+
```
|
|
181
|
+
```
|
|
182
|
+
#arch: aarch64
|
|
183
|
+
// x0 = self->future; result in x0.
|
|
184
|
+
ldr x0, [x19, #40]
|
|
185
|
+
bl ___nomen_future_is_done
|
|
186
|
+
```
|
|
187
|
+
}
|
|
188
|
+
|
|
163
189
|
// Request that the task stop. Cooperative — the task observes this via
|
|
164
190
|
// `Task.current_cancelled()` at its own checkpoints. No preemption.
|
|
165
191
|
pub func cancel = (ref self) {
|
|
@@ -354,14 +380,18 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
354
380
|
```
|
|
355
381
|
#arch: c
|
|
356
382
|
if (self->future) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
383
|
+
#if T_NEEDS_STRDUP
|
|
384
|
+
// T is the fat nomen_string here (the guard is 0 for every other
|
|
385
|
+
// T, and the preprocessor removes this region before parsing).
|
|
386
|
+
if (self->result_slot) {
|
|
387
|
+
T _s = *(T *)self->result_slot;
|
|
388
|
+
if (_s.ptr) free(_s.ptr);
|
|
389
|
+
// Zero the cell: the future's last release also frees an
|
|
390
|
+
// unconsumed fat result, keyed on a non-NULL ptr (see
|
|
391
|
+
// __nomen_future_release) — this free must be the only one.
|
|
392
|
+
memset((void *)self->result_slot, 0, sizeof(T));
|
|
393
|
+
}
|
|
394
|
+
#endif
|
|
365
395
|
__nomen_future_release((struct nomen_future *)self->future);
|
|
366
396
|
self->future = 0;
|
|
367
397
|
self->result_slot = 0;
|
|
@@ -383,6 +413,10 @@ pub class Task<T> : Sendable, Awaitable {
|
|
|
383
413
|
cbz x8, .Ldestroy_nofree
|
|
384
414
|
ldr x0, [x8]
|
|
385
415
|
cbz x0, .Ldestroy_nofree
|
|
416
|
+
// Mark consumed BEFORE the free (x8 is caller-saved and dead after
|
|
417
|
+
// the call): the future's last release also frees an unconsumed
|
|
418
|
+
// fat result, keyed on a non-NULL cell (see __nomen_future_release).
|
|
419
|
+
stp xzr, xzr, [x8]
|
|
386
420
|
bl _free
|
|
387
421
|
.Ldestroy_nofree:
|
|
388
422
|
ldr x0, [x19, #40]
|
package/core/System/Test.nm
CHANGED
|
@@ -48,17 +48,17 @@
|
|
|
48
48
|
**/
|
|
49
49
|
pub class Tester {
|
|
50
50
|
// Has the *current* test recorded a failure? Reset by `begin_test`.
|
|
51
|
-
pub var
|
|
51
|
+
pub var has_failed = false
|
|
52
52
|
|
|
53
53
|
// Assertion tallies for the current test.
|
|
54
|
-
var
|
|
55
|
-
var
|
|
54
|
+
var passed = 0
|
|
55
|
+
var failed = 0
|
|
56
56
|
|
|
57
57
|
// Tallies for the whole file, so `done` records stay per-test while the
|
|
58
58
|
// process still knows whether anything failed overall.
|
|
59
|
-
var
|
|
59
|
+
var total_failed = 0
|
|
60
60
|
|
|
61
|
-
var
|
|
61
|
+
var current = ""
|
|
62
62
|
var uint64 started = 0
|
|
63
63
|
|
|
64
64
|
// Benchmark capture state. `bench`/`bench_n` record the label and sample
|
|
@@ -66,9 +66,9 @@ pub class Tester {
|
|
|
66
66
|
// function and drives the actual timing loop (Nomen can't store or call a
|
|
67
67
|
// function pointer, so the harness measures `bench_fn` itself). `bench_fn`
|
|
68
68
|
// is reconstructed by the harness from the call site, not stored here.
|
|
69
|
-
var
|
|
70
|
-
var
|
|
71
|
-
var
|
|
69
|
+
var bench_pending = false
|
|
70
|
+
var bench_label = ""
|
|
71
|
+
var bench_samples = 1000
|
|
72
72
|
|
|
73
73
|
// (harness) Start timing `name` and clear the per-test state. Called by
|
|
74
74
|
// the `main` that `nomen test` generates — not by test code.
|
|
@@ -188,7 +188,7 @@ pub class Tester {
|
|
|
188
188
|
* (default 1000, override with `bench_n`) and computes min / median /
|
|
189
189
|
* mean / max / stddev over the per-iteration durations.
|
|
190
190
|
**/
|
|
191
|
-
pub func bench = (ref self, string label, func
|
|
191
|
+
pub func bench = (ref self, string label, func() body) {
|
|
192
192
|
if self.has_failed {
|
|
193
193
|
return
|
|
194
194
|
}
|
|
@@ -202,7 +202,7 @@ pub class Tester {
|
|
|
202
202
|
* for slow functions (where the default 1000 would dominate the suite) or
|
|
203
203
|
* for reproducible sample counts.
|
|
204
204
|
**/
|
|
205
|
-
pub func bench_n = (ref self, string label, func
|
|
205
|
+
pub func bench_n = (ref self, string label, func() body, int samples) {
|
|
206
206
|
if self.has_failed {
|
|
207
207
|
return
|
|
208
208
|
}
|
|
@@ -219,7 +219,16 @@ pub class Tester {
|
|
|
219
219
|
* If a test has already recorded a failure, benchmarks are skipped and
|
|
220
220
|
* this is a no-op.
|
|
221
221
|
**/
|
|
222
|
-
pub func record_bench = (
|
|
222
|
+
pub func record_bench = (
|
|
223
|
+
ref self,
|
|
224
|
+
string label,
|
|
225
|
+
int n,
|
|
226
|
+
int min,
|
|
227
|
+
int median,
|
|
228
|
+
int max,
|
|
229
|
+
float mean,
|
|
230
|
+
float stddev
|
|
231
|
+
) {
|
|
223
232
|
if self.has_failed {
|
|
224
233
|
return
|
|
225
234
|
}
|
|
@@ -22,18 +22,18 @@ pub struct CharRun {
|
|
|
22
22
|
**/
|
|
23
23
|
pub struct CharIndex {
|
|
24
24
|
var view string source
|
|
25
|
-
var
|
|
26
|
-
var
|
|
25
|
+
var runs = List<CharRun>()
|
|
26
|
+
var char_count = 0
|
|
27
27
|
|
|
28
28
|
pub func #init = (self, view string source) {
|
|
29
29
|
self.source = source
|
|
30
|
-
var
|
|
30
|
+
var pos = 0
|
|
31
31
|
var int len = source.length
|
|
32
|
-
var
|
|
32
|
+
var chars = 0
|
|
33
33
|
var int open_at = -1
|
|
34
|
-
var
|
|
35
|
-
var
|
|
36
|
-
var
|
|
34
|
+
var open_width = 0
|
|
35
|
+
var open_start = 0
|
|
36
|
+
var open_count = 0
|
|
37
37
|
while pos < len {
|
|
38
38
|
var int w = Utf8.width_at(source, pos)
|
|
39
39
|
switch {
|
|
@@ -122,7 +122,7 @@ pub struct CharIndex {
|
|
|
122
122
|
// Rightmost run whose key (char_start when by_char, else byte_index) is
|
|
123
123
|
// <= target, or -1 when all runs start after it.
|
|
124
124
|
func rightmost_run = (self, int target, bool by_char, out int) {
|
|
125
|
-
var
|
|
125
|
+
var lo = 0
|
|
126
126
|
var int hi = self.runs.length - 1
|
|
127
127
|
var int found = -1
|
|
128
128
|
while lo <= hi {
|
|
@@ -23,7 +23,7 @@ struct JsonNode {
|
|
|
23
23
|
* A flat, buffer-backed pool of JSON tree nodes — the parsed representation `Json.parse` produces
|
|
24
24
|
**/
|
|
25
25
|
pub struct JsonTree {
|
|
26
|
-
var
|
|
26
|
+
var nodes = Buffer<JsonNode>()
|
|
27
27
|
var count = 0
|
|
28
28
|
|
|
29
29
|
func alloc_node = (ref self, out int) {
|