nomen-lang 0.5.0 → 0.6.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.
- 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 +1 -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 +122 -32
- 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 +1166 -1097
- package/package.json +1 -1
|
@@ -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 {
|
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) {
|
|
@@ -65,7 +65,12 @@ pub struct Regex {
|
|
|
65
65
|
// group that did not participate in the match) and return true. Return
|
|
66
66
|
// false with `out` untouched when nothing matches. A group that repeats
|
|
67
67
|
// (`(a)+`) reports its LAST iteration.
|
|
68
|
-
pub func captures = (
|
|
68
|
+
pub func captures = (
|
|
69
|
+
string pattern,
|
|
70
|
+
string input,
|
|
71
|
+
ref List<string> dst,
|
|
72
|
+
out bool
|
|
73
|
+
) { var int pat_len = pattern.length
|
|
69
74
|
var int len = input.length
|
|
70
75
|
var string charset = first_byte_set(pattern, pat_len)
|
|
71
76
|
var int clen = charset.length
|
|
@@ -83,7 +88,7 @@ pub struct Regex {
|
|
|
83
88
|
if end >= 0 {
|
|
84
89
|
var string whole = input.substring(i, end)
|
|
85
90
|
dst.push(whole)
|
|
86
|
-
var
|
|
91
|
+
var g = 1
|
|
87
92
|
while g <= groups; g += 1 {
|
|
88
93
|
var int at = last_capture_index(caps, g)
|
|
89
94
|
if at >= 0 {
|
|
@@ -166,7 +171,12 @@ pub struct Regex {
|
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
// Replace all non-overlapping occurrences of pattern in input with replacement.
|
|
169
|
-
pub func replace_all = (
|
|
174
|
+
pub func replace_all = (
|
|
175
|
+
string pattern,
|
|
176
|
+
string input,
|
|
177
|
+
string replacement,
|
|
178
|
+
out string
|
|
179
|
+
) { var sb = StringBuilder()
|
|
170
180
|
var int pat_len = pattern.length
|
|
171
181
|
var int len = input.length
|
|
172
182
|
var string charset = first_byte_set(pattern, pat_len)
|
|
@@ -241,7 +251,7 @@ pub struct Regex {
|
|
|
241
251
|
func fold_pattern = (string pattern, move out string) {
|
|
242
252
|
var int n = pattern.length
|
|
243
253
|
var sb = StringBuilder()
|
|
244
|
-
var
|
|
254
|
+
var i = 0
|
|
245
255
|
while i < n; i += 1 {
|
|
246
256
|
var char c = pattern.at(i)
|
|
247
257
|
if (c as int) == 92 {
|
|
@@ -412,7 +422,13 @@ func first_byte_set = (string pattern, int pat_len, out string) {
|
|
|
412
422
|
// byte(s) of each alternative to sb. Alternations at depth 0 are split on '|'.
|
|
413
423
|
// Returns -1 when any alternative's first-byte set can't be determined (the
|
|
414
424
|
// caller must then disable the prefilter), 0 otherwise.
|
|
415
|
-
func collect_first_bytes = (
|
|
425
|
+
func collect_first_bytes = (
|
|
426
|
+
string pattern,
|
|
427
|
+
int pat_pos,
|
|
428
|
+
int pat_end,
|
|
429
|
+
ref StringBuilder sb,
|
|
430
|
+
out int
|
|
431
|
+
) {
|
|
416
432
|
var depth = 0
|
|
417
433
|
var int i = pat_pos
|
|
418
434
|
var int alt_start = pat_pos
|
|
@@ -506,7 +522,7 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
506
522
|
// can also come from whatever follows it. A second '?' marks the
|
|
507
523
|
// quantifier lazy and is skipped either way.
|
|
508
524
|
var int after = a_end
|
|
509
|
-
var
|
|
525
|
+
var nullable = 0
|
|
510
526
|
if after < end {
|
|
511
527
|
var char q = pattern.at(after)
|
|
512
528
|
if q == '?' || q == '*' {
|
|
@@ -568,7 +584,7 @@ func add_class_chars = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
568
584
|
}
|
|
569
585
|
} else {
|
|
570
586
|
sb.append_char(pattern.at(i))
|
|
571
|
-
|
|
587
|
+
i += 1
|
|
572
588
|
}
|
|
573
589
|
}
|
|
574
590
|
}
|
|
@@ -613,7 +629,15 @@ func match_here = (
|
|
|
613
629
|
}
|
|
614
630
|
if (c as int) == 124 {
|
|
615
631
|
if depth == 0 {
|
|
616
|
-
var int left = match_here(
|
|
632
|
+
var int left = match_here(
|
|
633
|
+
pattern,
|
|
634
|
+
pat_pos,
|
|
635
|
+
i,
|
|
636
|
+
input,
|
|
637
|
+
in_pos,
|
|
638
|
+
in_len,
|
|
639
|
+
ref caps,
|
|
640
|
+
)
|
|
617
641
|
if left >= 0 {
|
|
618
642
|
return left
|
|
619
643
|
}
|
|
@@ -655,7 +679,7 @@ func match_here = (
|
|
|
655
679
|
if a_end < pat_end {
|
|
656
680
|
var char q = pattern.at(a_end)
|
|
657
681
|
if q == '*' || q == '+' || q == '?' {
|
|
658
|
-
var
|
|
682
|
+
var lazy = 0
|
|
659
683
|
var int rest = a_end + 1
|
|
660
684
|
if rest < pat_end {
|
|
661
685
|
if pattern.at(rest) == '?' {
|
|
@@ -664,12 +688,47 @@ func match_here = (
|
|
|
664
688
|
}
|
|
665
689
|
}
|
|
666
690
|
if q == '*' {
|
|
667
|
-
return match_star(
|
|
691
|
+
return match_star(
|
|
692
|
+
pattern,
|
|
693
|
+
pat_pos,
|
|
694
|
+
a_end,
|
|
695
|
+
rest,
|
|
696
|
+
pat_end,
|
|
697
|
+
input,
|
|
698
|
+
in_pos,
|
|
699
|
+
0,
|
|
700
|
+
lazy,
|
|
701
|
+
in_len,
|
|
702
|
+
ref caps,
|
|
703
|
+
)
|
|
668
704
|
}
|
|
669
705
|
if q == '+' {
|
|
670
|
-
return match_star(
|
|
706
|
+
return match_star(
|
|
707
|
+
pattern,
|
|
708
|
+
pat_pos,
|
|
709
|
+
a_end,
|
|
710
|
+
rest,
|
|
711
|
+
pat_end,
|
|
712
|
+
input,
|
|
713
|
+
in_pos,
|
|
714
|
+
1,
|
|
715
|
+
lazy,
|
|
716
|
+
in_len,
|
|
717
|
+
ref caps,
|
|
718
|
+
)
|
|
671
719
|
}
|
|
672
|
-
return match_optional(
|
|
720
|
+
return match_optional(
|
|
721
|
+
pattern,
|
|
722
|
+
pat_pos,
|
|
723
|
+
a_end,
|
|
724
|
+
rest,
|
|
725
|
+
pat_end,
|
|
726
|
+
input,
|
|
727
|
+
in_pos,
|
|
728
|
+
lazy,
|
|
729
|
+
in_len,
|
|
730
|
+
ref caps,
|
|
731
|
+
)
|
|
673
732
|
}
|
|
674
733
|
}
|
|
675
734
|
|
|
@@ -768,7 +827,15 @@ func match_single_atom = (
|
|
|
768
827
|
old_start = caps.at(at + 1)
|
|
769
828
|
old_end = caps.at(at + 2)
|
|
770
829
|
}
|
|
771
|
-
var int next = match_here(
|
|
830
|
+
var int next = match_here(
|
|
831
|
+
pattern,
|
|
832
|
+
atom_start + 1,
|
|
833
|
+
atom_end - 1,
|
|
834
|
+
input,
|
|
835
|
+
in_pos,
|
|
836
|
+
in_len,
|
|
837
|
+
ref caps,
|
|
838
|
+
)
|
|
772
839
|
if next >= 0 {
|
|
773
840
|
record_capture(ref caps, g, in_pos, next)
|
|
774
841
|
return next
|
|
@@ -958,7 +1025,15 @@ func match_star_group = (
|
|
|
958
1025
|
return stop
|
|
959
1026
|
}
|
|
960
1027
|
}
|
|
961
|
-
var int next = match_single_atom(
|
|
1028
|
+
var int next = match_single_atom(
|
|
1029
|
+
pattern,
|
|
1030
|
+
atom_start,
|
|
1031
|
+
atom_end,
|
|
1032
|
+
input,
|
|
1033
|
+
in_pos,
|
|
1034
|
+
in_len,
|
|
1035
|
+
ref caps,
|
|
1036
|
+
)
|
|
962
1037
|
if next >= 0 {
|
|
963
1038
|
if next != in_pos {
|
|
964
1039
|
var new_min = 0
|
|
@@ -1035,7 +1110,15 @@ func match_optional = (
|
|
|
1035
1110
|
if skip >= 0 {
|
|
1036
1111
|
return skip
|
|
1037
1112
|
}
|
|
1038
|
-
var int next = match_single_atom(
|
|
1113
|
+
var int next = match_single_atom(
|
|
1114
|
+
pattern,
|
|
1115
|
+
atom_start,
|
|
1116
|
+
atom_end,
|
|
1117
|
+
input,
|
|
1118
|
+
in_pos,
|
|
1119
|
+
in_len,
|
|
1120
|
+
ref caps,
|
|
1121
|
+
)
|
|
1039
1122
|
if next >= 0 {
|
|
1040
1123
|
return match_here(pattern, rest, pat_end, input, next, in_len, ref caps)
|
|
1041
1124
|
}
|
|
@@ -1136,8 +1219,8 @@ func char_in_class = (
|
|
|
1136
1219
|
// groups).
|
|
1137
1220
|
func capture_count = (string pattern, out int) {
|
|
1138
1221
|
var int n = pattern.length
|
|
1139
|
-
var
|
|
1140
|
-
var
|
|
1222
|
+
var count = 0
|
|
1223
|
+
var i = 0
|
|
1141
1224
|
while i < n; i += 1 {
|
|
1142
1225
|
var char c = pattern.at(i)
|
|
1143
1226
|
if (c as int) == 92 {
|
|
@@ -1159,8 +1242,8 @@ func capture_count = (string pattern, out int) {
|
|
|
1159
1242
|
// open_pos: one more than the number of capture opens before it in the
|
|
1160
1243
|
// pattern (the whole match is group 0).
|
|
1161
1244
|
func group_index_at = (string pattern, int open_pos, out int) {
|
|
1162
|
-
var
|
|
1163
|
-
var
|
|
1245
|
+
var count = 0
|
|
1246
|
+
var i = 0
|
|
1164
1247
|
while i < open_pos; i += 1 {
|
|
1165
1248
|
var char c = pattern.at(i)
|
|
1166
1249
|
if (c as int) == 92 {
|
|
@@ -1198,7 +1281,7 @@ func record_capture = (ref List<int> caps, int group, int start, int end) {
|
|
|
1198
1281
|
// has no entry. Entries are (group, start, end) triples.
|
|
1199
1282
|
func last_capture_index = (List<int> caps, int group, out int) {
|
|
1200
1283
|
var int best = -1
|
|
1201
|
-
var
|
|
1284
|
+
var i = 0
|
|
1202
1285
|
while i < caps.length; i += 3 {
|
|
1203
1286
|
if caps.at(i) == group {
|
|
1204
1287
|
best = i
|
|
@@ -1211,11 +1294,11 @@ func last_capture_index = (List<int> caps, int group, out int) {
|
|
|
1211
1294
|
* A Regex.find result: whether the pattern matched, where, and what
|
|
1212
1295
|
**/
|
|
1213
1296
|
pub struct RegexMatch {
|
|
1214
|
-
var
|
|
1215
|
-
var
|
|
1216
|
-
var
|
|
1217
|
-
var
|
|
1218
|
-
var
|
|
1297
|
+
var found = false
|
|
1298
|
+
var start = 0
|
|
1299
|
+
var end = 0
|
|
1300
|
+
var length = 0
|
|
1301
|
+
var text = ""
|
|
1219
1302
|
}
|
|
1220
1303
|
|
|
1221
1304
|
// Whether the escaped character c (the byte after a backslash) is a
|
|
@@ -1233,7 +1316,14 @@ func backref_group = (char c, out int) {
|
|
|
1233
1316
|
// Match the text capture group `group` last matched, at in_pos. Returns the
|
|
1234
1317
|
// position after the span, or -1 when the group has no span here (it did not
|
|
1235
1318
|
// participate) or the text differs.
|
|
1236
|
-
func match_backref = (
|
|
1319
|
+
func match_backref = (
|
|
1320
|
+
string input,
|
|
1321
|
+
int group,
|
|
1322
|
+
int in_pos,
|
|
1323
|
+
int in_len,
|
|
1324
|
+
ref List<int> caps,
|
|
1325
|
+
out int
|
|
1326
|
+
) {
|
|
1237
1327
|
var int at = last_capture_index(caps, group)
|
|
1238
1328
|
if at < 0 {
|
|
1239
1329
|
return -1
|
|
@@ -1246,7 +1336,7 @@ func match_backref = (string input, int group, int in_pos, int in_len, ref List<
|
|
|
1246
1336
|
if in_pos + len > in_len {
|
|
1247
1337
|
return -1
|
|
1248
1338
|
}
|
|
1249
|
-
var
|
|
1339
|
+
var i = 0
|
|
1250
1340
|
while i < len; i += 1 {
|
|
1251
1341
|
if input.at(in_pos + i) != input.at(s + i) {
|
|
1252
1342
|
return -1
|
|
@@ -1372,22 +1462,22 @@ func shorthand_members = (char c, ref StringBuilder sb, out int) {
|
|
|
1372
1462
|
return -1
|
|
1373
1463
|
}
|
|
1374
1464
|
if kind == 100 {
|
|
1375
|
-
var
|
|
1465
|
+
var code = 48
|
|
1376
1466
|
while code <= 57; code += 1 {
|
|
1377
1467
|
sb.append_char(code as char)
|
|
1378
1468
|
}
|
|
1379
1469
|
return 0
|
|
1380
1470
|
}
|
|
1381
1471
|
if kind == 119 {
|
|
1382
|
-
var
|
|
1472
|
+
var code = 48
|
|
1383
1473
|
while code <= 57; code += 1 {
|
|
1384
1474
|
sb.append_char(code as char)
|
|
1385
1475
|
}
|
|
1386
|
-
var
|
|
1476
|
+
var upper = 65
|
|
1387
1477
|
while upper <= 90; upper += 1 {
|
|
1388
1478
|
sb.append_char(upper as char)
|
|
1389
1479
|
}
|
|
1390
|
-
var
|
|
1480
|
+
var lower = 97
|
|
1391
1481
|
while lower <= 122; lower += 1 {
|
|
1392
1482
|
sb.append_char(lower as char)
|
|
1393
1483
|
}
|
|
@@ -1395,7 +1485,7 @@ func shorthand_members = (char c, ref StringBuilder sb, out int) {
|
|
|
1395
1485
|
return 0
|
|
1396
1486
|
}
|
|
1397
1487
|
// \s: tab, LF, VT, FF, CR, space
|
|
1398
|
-
var
|
|
1488
|
+
var w = 9
|
|
1399
1489
|
while w <= 13; w += 1 {
|
|
1400
1490
|
sb.append_char(w as char)
|
|
1401
1491
|
}
|
package/core/System/Text/Utf8.nm
CHANGED
|
@@ -45,8 +45,8 @@ pub struct Utf8 {
|
|
|
45
45
|
if b0 < 0xF0 {
|
|
46
46
|
// E0 forbids second bytes below A0 (overlong); ED forbids
|
|
47
47
|
// AA-BF (surrogate halves).
|
|
48
|
-
var
|
|
49
|
-
var
|
|
48
|
+
var lo = 0x80
|
|
49
|
+
var hi = 0xBF
|
|
50
50
|
if b0 == 0xE0 {
|
|
51
51
|
lo = 0xA0
|
|
52
52
|
}
|
|
@@ -68,8 +68,8 @@ pub struct Utf8 {
|
|
|
68
68
|
}
|
|
69
69
|
// F0 forbids second bytes below 90 (overlong); F4 forbids above 8F
|
|
70
70
|
// (past U+10FFFF).
|
|
71
|
-
var
|
|
72
|
-
var
|
|
71
|
+
var lo = 0x80
|
|
72
|
+
var hi = 0xBF
|
|
73
73
|
if b0 == 0xF0 {
|
|
74
74
|
lo = 0x90
|
|
75
75
|
}
|
|
@@ -138,8 +138,8 @@ pub struct Utf8 {
|
|
|
138
138
|
// Count the code points in text (one pass; malformed bytes each count
|
|
139
139
|
// as one U+FFFD).
|
|
140
140
|
pub func char_count = (view string text, out int) {
|
|
141
|
-
var
|
|
142
|
-
var
|
|
141
|
+
var n = 0
|
|
142
|
+
var pos = 0
|
|
143
143
|
var int len = text.length
|
|
144
144
|
while pos < len {
|
|
145
145
|
pos = pos + Utf8.width_at(text, pos)
|