nomen-lang 0.0.19 → 0.2.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/NOMEN_AGENTS.md +57 -12
- package/core/System/Array.nm +11 -11
- package/core/System/Buffer.nm +2 -2
- package/core/System/Channel.nm +146 -12
- package/core/System/ClassBuffer.nm +2 -2
- package/core/System/Console.nm +28 -17
- package/core/System/Controls/Button.nm +96 -8
- package/core/System/Controls/CheckBox.nm +117 -12
- package/core/System/Controls/Container.nm +114 -8
- package/core/System/Controls/Text.nm +98 -8
- package/core/System/Controls/TextBox.nm +120 -10
- package/core/System/Controls/Window.nm +231 -23
- package/core/System/Graph.nm +1 -1
- package/core/System/Init.nm +4 -8
- package/core/System/LinkedList.nm +1 -1
- package/core/System/List.nm +3 -3
- package/core/System/Map.nm +5 -5
- package/core/System/Math.nm +10 -32
- package/core/System/Result.nm +1 -1
- package/core/System/Set.nm +4 -4
- package/core/System/Stream/Directory.nm +189 -63
- package/core/System/Stream/DirectoryError.nm +21 -0
- package/core/System/Stream/File.nm +339 -141
- package/core/System/Stream/FileError.nm +21 -0
- package/core/System/Stream/Http.nm +109 -44
- package/core/System/Stream/HttpError.nm +20 -0
- package/core/System/String.nm +83 -69
- package/core/System/StringBuilder.nm +11 -13
- package/core/System/Task.nm +46 -12
- package/core/System/Test.nm +1 -1
- package/core/System/Text/Json.nm +5 -3
- package/core/System/Text/JsonTree.nm +23 -14
- package/core/System/Text/Regex.nm +124 -64
- package/core/System/Tree.nm +1 -1
- package/core/System/bool.nm +4 -9
- package/core/System/char.nm +3 -9
- package/core/System/float.nm +2 -1
- package/core/System/float32.nm +44 -0
- package/core/System/float64.nm +44 -0
- package/core/System/int.nm +3 -9
- package/core/System/int16.nm +47 -0
- package/core/System/int32.nm +47 -0
- package/core/System/int64.nm +3 -9
- package/core/System/int8.nm +3 -9
- package/core/System/ufloat.nm +44 -0
- package/core/System/ufloat32.nm +44 -0
- package/core/System/ufloat64.nm +44 -0
- package/core/System/uint.nm +3 -9
- package/core/System/uint16.nm +47 -0
- package/core/System/uint32.nm +47 -0
- package/core/System/uint64.nm +3 -9
- package/core/System/uint8.nm +3 -9
- package/core/docs/System/Channel.md +2 -0
- package/core/docs/System/Result.md +5 -1
- package/core/docs/System/Task.md +1 -1
- package/dist/index.mjs +38794 -21299
- package/package.json +38 -34
- package/src/args.ts +11 -0
- package/src/index.ts +21 -3
- package/src/init.ts +1 -1
- package/src/test.ts +48 -4
- package/src/types/Config.ts +2 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The failure mode of a file operation.
|
|
3
|
+
*
|
|
4
|
+
* File.write_all("out.txt", "payload")
|
|
5
|
+
* var Result<string, FileError> body = File.read_all("out.txt")
|
|
6
|
+
* match body {
|
|
7
|
+
* case .ok(text) -> Console.write(text)
|
|
8
|
+
* case .error(e) -> Console.write("failed")
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Cases map from the underlying errno: `not_found` (ENOENT), `access_denied`
|
|
12
|
+
* (EACCES), `already_exists` (EEXIST), `not_open` (operating on a `File`
|
|
13
|
+
* whose open failed or that was already closed), `other` (anything else).
|
|
14
|
+
**/
|
|
15
|
+
pub enum FileError {
|
|
16
|
+
case not_found
|
|
17
|
+
case access_denied
|
|
18
|
+
case already_exists
|
|
19
|
+
case not_open
|
|
20
|
+
case other
|
|
21
|
+
}
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Plain `http://` only — no TLS (an `https://` URL cannot be served; use a
|
|
5
5
|
* TLS proxy or wait for a TLS-capable transport). Construct an instance,
|
|
6
6
|
* call `get`/`post` (which block until the full response is received), then
|
|
7
|
-
* read the `status` field for the response's status code.
|
|
7
|
+
* read the `status` field for the response's status code. Fallible calls
|
|
8
|
+
* return a `Result` whose error side is an `HttpError`; `status` is 0 when
|
|
8
9
|
* DNS resolution or the connection fails.
|
|
9
10
|
*
|
|
10
11
|
* URLs may carry an explicit port (`http://host:8080/path`); the default is
|
|
@@ -14,20 +15,47 @@
|
|
|
14
15
|
* separator line) is returned.
|
|
15
16
|
*
|
|
16
17
|
* var Http h = Http()
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* match h.get("http://example.com/") {
|
|
19
|
+
* case .ok(body) -> Console.write(body)
|
|
20
|
+
* case .error(e) -> Console.write("request failed")
|
|
21
|
+
* }
|
|
22
|
+
* var int code = h.status
|
|
20
23
|
**/
|
|
21
24
|
pub struct Http {
|
|
22
|
-
// HTTP status code from the most recent request (e.g. 200). 0
|
|
23
|
-
// the
|
|
25
|
+
// HTTP status code from the most recent request (e.g. 200). 0 when the
|
|
26
|
+
// request failed (the `error` side of the get/post Result says why).
|
|
24
27
|
pub var int status = 0
|
|
25
28
|
|
|
29
|
+
// Internal failure code from the most recent request: 0 = success,
|
|
30
|
+
// 1 = DNS resolution, 2 = socket creation, 3 = connect. Raw #arch bodies
|
|
31
|
+
// set it, the Result-returning wrappers map it to HttpError.
|
|
32
|
+
var int error = 0
|
|
33
|
+
|
|
34
|
+
// Maps the raw failure code to its HttpError case.
|
|
35
|
+
func error_of = (int err, out HttpError) {
|
|
36
|
+
switch {
|
|
37
|
+
case err == 1 {
|
|
38
|
+
return HttpError.dns
|
|
39
|
+
}
|
|
40
|
+
case err == 2 {
|
|
41
|
+
return HttpError.socket
|
|
42
|
+
}
|
|
43
|
+
case err == 3 {
|
|
44
|
+
return HttpError.connect
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
return HttpError.other
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
26
52
|
// Shared socket round-trip used by get/post. `method` is the request
|
|
27
53
|
// method string ("GET" / "POST"); a leading 'P' selects POST semantics
|
|
28
|
-
// (sends `body` and the Content-* headers). Sets self->status
|
|
29
|
-
// the response body (empty string
|
|
30
|
-
|
|
54
|
+
// (sends `body` and the Content-* headers). Sets self->status (0 on
|
|
55
|
+
// failure) and self->error, and returns the response body (empty string
|
|
56
|
+
// on failure). The raw body mallocs the response — `move out string`
|
|
57
|
+
// transfers ownership to the caller.
|
|
58
|
+
func raw_exchange = (ref self, string method, string url, string body, move out string) {
|
|
31
59
|
```
|
|
32
60
|
#arch: c
|
|
33
61
|
#scope: file
|
|
@@ -39,8 +67,10 @@ pub struct Http {
|
|
|
39
67
|
```
|
|
40
68
|
```
|
|
41
69
|
#arch: c
|
|
42
|
-
|
|
43
|
-
|
|
70
|
+
// Fat-string ABI: params are (ptr, len) pairs; consume the .ptr
|
|
71
|
+
// halves at each FFI boundary.
|
|
72
|
+
const char *scheme = strstr(url.ptr, "://");
|
|
73
|
+
const char *hp = scheme ? scheme + 3 : url.ptr;
|
|
44
74
|
const char *colon = strchr(hp, ':');
|
|
45
75
|
const char *slash = strchr(hp, '/');
|
|
46
76
|
char host[256];
|
|
@@ -70,33 +100,36 @@ pub struct Http {
|
|
|
70
100
|
snprintf(portstr, sizeof(portstr), "%d", port);
|
|
71
101
|
if (getaddrinfo(host, portstr, &hints, &res) != 0) {
|
|
72
102
|
self->status = 0;
|
|
73
|
-
|
|
103
|
+
self->error = 1;
|
|
104
|
+
return (nomen_string){ strdup(""), 0 };
|
|
74
105
|
}
|
|
75
106
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
76
107
|
if (sock < 0) {
|
|
77
108
|
freeaddrinfo(res);
|
|
78
109
|
self->status = 0;
|
|
79
|
-
|
|
110
|
+
self->error = 2;
|
|
111
|
+
return (nomen_string){ strdup(""), 0 };
|
|
80
112
|
}
|
|
81
113
|
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
|
82
114
|
freeaddrinfo(res);
|
|
83
115
|
close(sock);
|
|
84
116
|
self->status = 0;
|
|
85
|
-
|
|
117
|
+
self->error = 3;
|
|
118
|
+
return (nomen_string){ strdup(""), 0 };
|
|
86
119
|
}
|
|
87
120
|
freeaddrinfo(res);
|
|
88
121
|
|
|
89
122
|
char req[1600];
|
|
90
123
|
int off = snprintf(req, sizeof(req),
|
|
91
124
|
"%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n",
|
|
92
|
-
method, path, host);
|
|
93
|
-
if (method[0] == 'P') {
|
|
94
|
-
int blen = (int)
|
|
125
|
+
method.ptr, path, host);
|
|
126
|
+
if (method.ptr[0] == 'P') {
|
|
127
|
+
int blen = (int)body.len;
|
|
95
128
|
off += snprintf(req + off, sizeof(req) - off,
|
|
96
129
|
"Content-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n\r\n",
|
|
97
130
|
blen);
|
|
98
131
|
send(sock, req, off, 0);
|
|
99
|
-
send(sock, body, blen, 0);
|
|
132
|
+
send(sock, body.ptr, blen, 0);
|
|
100
133
|
} else {
|
|
101
134
|
off += snprintf(req + off, sizeof(req) - off, "\r\n");
|
|
102
135
|
send(sock, req, off, 0);
|
|
@@ -120,18 +153,24 @@ pub struct Http {
|
|
|
120
153
|
code = atoi(buf + 9);
|
|
121
154
|
}
|
|
122
155
|
self->status = code;
|
|
156
|
+
self->error = 0;
|
|
123
157
|
|
|
124
158
|
char *body_start = strstr(buf, "\r\n\r\n");
|
|
125
159
|
if (body_start) {
|
|
126
160
|
char *result = strdup(body_start + 4);
|
|
161
|
+
long rlen = (long)len - (long)(body_start + 4 - buf);
|
|
127
162
|
free(buf);
|
|
128
|
-
return result;
|
|
163
|
+
return (nomen_string){ result, rlen };
|
|
129
164
|
}
|
|
130
|
-
return buf;
|
|
165
|
+
return (nomen_string){ buf, len };
|
|
131
166
|
```
|
|
132
167
|
```
|
|
133
168
|
#arch: aarch64
|
|
134
|
-
// x0=self(->x19)
|
|
169
|
+
// Fat-string ABI: x0=self(->x19); method=(x1,x2), url=(x3,x4),
|
|
170
|
+
// body=(x5,x6) — only the ptr halves are consumed below, plus
|
|
171
|
+
// body.len (stashed at #200) for Content-Length/send.
|
|
172
|
+
// Struct layout: self->status at [x19, #8], self->error at
|
|
173
|
+
// [x19, #16] (1 = dns, 2 = socket, 3 = connect; cleared on success).
|
|
135
174
|
// macOS arm64 passes variadic args on the caller stack at [sp+0..], so
|
|
136
175
|
// [sp+0..47] is reserved scratch for snprintf variadic args and the
|
|
137
176
|
// addrinfo hints live above it. Stack frame (2048 bytes):
|
|
@@ -146,8 +185,9 @@ pub struct Http {
|
|
|
146
185
|
// #208 host buffer (256) #464 request buffer (1584)
|
|
147
186
|
sub sp, sp, #2048
|
|
148
187
|
str x1, [sp, #128]
|
|
149
|
-
str
|
|
150
|
-
str
|
|
188
|
+
str x3, [sp, #136]
|
|
189
|
+
str x5, [sp, #144]
|
|
190
|
+
str x6, [sp, #200] // body len
|
|
151
191
|
mov x0, #80
|
|
152
192
|
str x0, [sp, #112]
|
|
153
193
|
adr x0, .Lhttp_slash
|
|
@@ -245,7 +285,7 @@ pub struct Http {
|
|
|
245
285
|
add x2, sp, #48
|
|
246
286
|
add x3, sp, #96
|
|
247
287
|
bl _getaddrinfo
|
|
248
|
-
cbnz w0, .
|
|
288
|
+
cbnz w0, .Lhttp_dnsfail
|
|
249
289
|
|
|
250
290
|
// sock = socket(AF_INET, SOCK_STREAM, 0)
|
|
251
291
|
mov x0, #2
|
|
@@ -256,6 +296,8 @@ pub struct Http {
|
|
|
256
296
|
b.ge .Lhttp_sockok
|
|
257
297
|
ldr x0, [sp, #96]
|
|
258
298
|
bl _freeaddrinfo
|
|
299
|
+
mov x9, #2
|
|
300
|
+
str x9, [x19, #16]
|
|
259
301
|
b .Lhttp_fail
|
|
260
302
|
.Lhttp_sockok:
|
|
261
303
|
str w0, [sp, #104]
|
|
@@ -271,6 +313,8 @@ pub struct Http {
|
|
|
271
313
|
bl _freeaddrinfo
|
|
272
314
|
ldr w0, [sp, #104]
|
|
273
315
|
bl _close
|
|
316
|
+
mov x9, #3
|
|
317
|
+
str x9, [x19, #16]
|
|
274
318
|
b .Lhttp_fail
|
|
275
319
|
.Lhttp_connected:
|
|
276
320
|
ldr x0, [sp, #96]
|
|
@@ -297,10 +341,9 @@ pub struct Http {
|
|
|
297
341
|
cmp w0, #0x50
|
|
298
342
|
b.ne .Lhttp_getsend
|
|
299
343
|
|
|
300
|
-
// POST: blen =
|
|
301
|
-
ldr
|
|
302
|
-
|
|
303
|
-
str x0, [sp, #160]
|
|
344
|
+
// POST: blen = body.len (fat half); append Content-Length; send both
|
|
345
|
+
ldr x9, [sp, #200]
|
|
346
|
+
str x9, [sp, #160]
|
|
304
347
|
// snprintf(req+off, 1584-off, reqpost, blen) — blen on stack at [sp+0]
|
|
305
348
|
ldr x9, [sp, #160]
|
|
306
349
|
str x9, [sp, #0]
|
|
@@ -321,11 +364,9 @@ pub struct Http {
|
|
|
321
364
|
ldr x2, [sp, #176]
|
|
322
365
|
mov x3, xzr
|
|
323
366
|
bl _send
|
|
324
|
-
ldr x0, [sp, #144]
|
|
325
|
-
bl _strlen
|
|
326
|
-
mov x2, x0
|
|
327
367
|
ldr w0, [sp, #104]
|
|
328
368
|
ldr x1, [sp, #144]
|
|
369
|
+
ldr x2, [sp, #200]
|
|
329
370
|
mov x3, xzr
|
|
330
371
|
bl _send
|
|
331
372
|
b .Lhttp_recv
|
|
@@ -394,36 +435,51 @@ pub struct Http {
|
|
|
394
435
|
strb wzr, [x0, x1]
|
|
395
436
|
ldr w0, [sp, #104]
|
|
396
437
|
bl _close
|
|
438
|
+
// success: clear error before storing the status code
|
|
439
|
+
str xzr, [x19, #16]
|
|
397
440
|
// self->status = atoi(buf + 9)
|
|
398
441
|
ldr x0, [sp, #160]
|
|
399
442
|
add x0, x0, #9
|
|
400
443
|
bl _atoi
|
|
401
444
|
sxtw x0, w0
|
|
402
445
|
str x0, [x19, #8]
|
|
403
|
-
// body_start = strstr(buf, "\r\n\r\n")
|
|
446
|
+
// body_start = strstr(buf, "\r\n\r\n"); fat returns carry lens.
|
|
404
447
|
ldr x0, [sp, #160]
|
|
405
448
|
adr x1, .Lhttp_hdrsep
|
|
406
449
|
bl _strstr
|
|
407
450
|
cbz x0, .Lhttp_retbuf
|
|
408
|
-
// result = strdup(body_start + 4);
|
|
451
|
+
// result = strdup(body_start + 4); rlen = len - (body_start+4-buf)
|
|
452
|
+
add x9, x0, #4
|
|
453
|
+
ldr x10, [sp, #160]
|
|
454
|
+
sub x9, x9, x10
|
|
455
|
+
ldr x10, [sp, #96]
|
|
456
|
+
sub x9, x10, x9 // rlen
|
|
457
|
+
str x9, [sp, #168]
|
|
409
458
|
add x0, x0, #4
|
|
410
459
|
bl _strdup
|
|
460
|
+
ldr x1, [sp, #168]
|
|
411
461
|
str x0, [sp, #112]
|
|
412
462
|
ldr x0, [sp, #160]
|
|
413
463
|
bl _free
|
|
414
464
|
ldr x0, [sp, #112]
|
|
415
465
|
add sp, sp, #2048
|
|
416
|
-
b .
|
|
466
|
+
b .return_Http_raw_exchange
|
|
417
467
|
.Lhttp_retbuf:
|
|
418
468
|
ldr x0, [sp, #160]
|
|
469
|
+
ldr x1, [sp, #96]
|
|
419
470
|
add sp, sp, #2048
|
|
420
|
-
b .
|
|
471
|
+
b .return_Http_raw_exchange
|
|
472
|
+
.Lhttp_dnsfail:
|
|
473
|
+
mov x9, #1
|
|
474
|
+
str x9, [x19, #16]
|
|
475
|
+
b .Lhttp_fail
|
|
421
476
|
.Lhttp_fail:
|
|
422
477
|
str xzr, [x19, #8]
|
|
423
478
|
adr x0, .Lhttp_empty
|
|
424
479
|
bl _strdup
|
|
480
|
+
mov x1, #0
|
|
425
481
|
add sp, sp, #2048
|
|
426
|
-
b .
|
|
482
|
+
b .return_Http_raw_exchange
|
|
427
483
|
|
|
428
484
|
.Lhttp_scheme: .asciz "://"
|
|
429
485
|
.Lhttp_slash: .asciz "/"
|
|
@@ -438,16 +494,25 @@ pub struct Http {
|
|
|
438
494
|
return ""
|
|
439
495
|
}
|
|
440
496
|
|
|
441
|
-
// Issue a blocking GET request to `url`.
|
|
442
|
-
//
|
|
443
|
-
|
|
444
|
-
|
|
497
|
+
// Issue a blocking GET request to `url`. `.ok(body)` with the response
|
|
498
|
+
// body and `self.status` set to the response's status code, or
|
|
499
|
+
// `.error(HttpError)` (`status` is 0).
|
|
500
|
+
pub func get = (ref self, string url, out Result<string, HttpError>) {
|
|
501
|
+
const string response = self.raw_exchange("GET", url, "")
|
|
502
|
+
if self.error == 0 {
|
|
503
|
+
return Result.ok(response)
|
|
504
|
+
}
|
|
505
|
+
return Result.error(Http.error_of(self.error))
|
|
445
506
|
}
|
|
446
507
|
|
|
447
508
|
// Issue a blocking POST request to `url` with `body` as the payload.
|
|
448
|
-
//
|
|
449
|
-
// status code (
|
|
450
|
-
pub func post = (ref self, string url, string body, out string) {
|
|
451
|
-
|
|
509
|
+
// `.ok(body)` with the response body and `self.status` set to the
|
|
510
|
+
// response's status code, or `.error(HttpError)` (`status` is 0).
|
|
511
|
+
pub func post = (ref self, string url, string body, out Result<string, HttpError>) {
|
|
512
|
+
const string response = self.raw_exchange("POST", url, body)
|
|
513
|
+
if self.error == 0 {
|
|
514
|
+
return Result.ok(response)
|
|
515
|
+
}
|
|
516
|
+
return Result.error(Http.error_of(self.error))
|
|
452
517
|
}
|
|
453
518
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The failure mode of an HTTP request.
|
|
3
|
+
*
|
|
4
|
+
* var Http h = Http()
|
|
5
|
+
* var Result<string, HttpError> body = h.get("http://example.com/")
|
|
6
|
+
* match body {
|
|
7
|
+
* case .ok(text) -> Console.write(text)
|
|
8
|
+
* case .error(e) -> Console.write("failed")
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Cases map from the request lifecycle: `dns` (hostname resolution failed),
|
|
12
|
+
* `socket` (the socket could not be created), `connect` (the connection was
|
|
13
|
+
* refused or timed out), `other` (anything else).
|
|
14
|
+
**/
|
|
15
|
+
pub enum HttpError {
|
|
16
|
+
case dns
|
|
17
|
+
case socket
|
|
18
|
+
case connect
|
|
19
|
+
case other
|
|
20
|
+
}
|
package/core/System/String.nm
CHANGED
|
@@ -1,42 +1,31 @@
|
|
|
1
|
+
// FFI: the C library's heap-copy entry point (string.h). The adapter
|
|
2
|
+
// marshals the fat string to the thin char* the C ABI expects; the string
|
|
3
|
+
// result is re-wrapped with its length.
|
|
4
|
+
extern func strdup = (string s, move out string)
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* A UTF-8 text string — a heap-owned, length-tracked sequence of bytes
|
|
3
8
|
**/
|
|
4
9
|
pub struct string: Stringable, Hashable, Equatable {
|
|
5
10
|
pub func hash = (self, out uint) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
// djb2 over exactly self.length bytes — matches the byte count of
|
|
12
|
+
// owned strings and literals (views hash the viewed bytes only).
|
|
13
|
+
var uint h = 5381
|
|
14
|
+
var i = 0
|
|
15
|
+
while i < self.length; i += 1 {
|
|
16
|
+
h = h * 33 + (self.at(i) as uint)
|
|
11
17
|
}
|
|
12
|
-
return h
|
|
13
|
-
```
|
|
14
|
-
```
|
|
15
|
-
#arch: aarch64
|
|
16
|
-
// x19 = self (char*), result in x0 (djb2 hash)
|
|
17
|
-
mov x0, #5381
|
|
18
|
-
mov x3, x19
|
|
19
|
-
.Lstring_hash_loop:
|
|
20
|
-
ldrb w1, [x3]
|
|
21
|
-
cbz w1, .Lstring_hash_done
|
|
22
|
-
mov x2, #33
|
|
23
|
-
mul x0, x0, x2
|
|
24
|
-
add x0, x0, x1
|
|
25
|
-
add x3, x3, #1
|
|
26
|
-
b .Lstring_hash_loop
|
|
27
|
-
.Lstring_hash_done:
|
|
28
|
-
```
|
|
18
|
+
return h
|
|
29
19
|
}
|
|
30
20
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
21
|
+
// Returns an OWNED copy of self (`move out string`). Both backends hand
|
|
22
|
+
// back a fresh allocation the caller frees — never an alias of self's
|
|
23
|
+
// storage — so the result can outlive the receiver (e.g. escape a match
|
|
24
|
+
// branch that reclaims the scrutinee temp). Goes through the `strdup`
|
|
25
|
+
// extern: the adapter marshals self.ptr to libc and re-wraps the copy
|
|
26
|
+
// with its length.
|
|
27
|
+
pub func to_string = (self, move out string) {
|
|
28
|
+
return strdup(self)
|
|
40
29
|
}
|
|
41
30
|
|
|
42
31
|
pub func at = (self, int index: index >= 0 && index < self.length, out char) {
|
|
@@ -46,8 +35,9 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
46
35
|
```
|
|
47
36
|
```
|
|
48
37
|
#arch: aarch64
|
|
49
|
-
// x19 = self
|
|
50
|
-
|
|
38
|
+
// Fat-string ABI: x19 = self ptr, x20 = self len; index in x2
|
|
39
|
+
// (self's pair occupies slots 0-1).
|
|
40
|
+
ldrb w0, [x19, x2]
|
|
51
41
|
```
|
|
52
42
|
}
|
|
53
43
|
|
|
@@ -89,9 +79,10 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
89
79
|
```
|
|
90
80
|
#arch: aarch64
|
|
91
81
|
// view string is (ptr, len), returned in the x0/x1 register pair.
|
|
92
|
-
// x19 = self
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
// Fat-string ABI: x19 = self ptr, x20 = self len; start in x2,
|
|
83
|
+
// end in x3 (self's pair occupies slots 0-1).
|
|
84
|
+
add x0, x19, x2 // ptr = self + start
|
|
85
|
+
sub x1, x3, x2 // len = end - start
|
|
95
86
|
```
|
|
96
87
|
}
|
|
97
88
|
|
|
@@ -114,10 +105,22 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
114
105
|
```
|
|
115
106
|
```
|
|
116
107
|
#arch: aarch64
|
|
117
|
-
//
|
|
118
|
-
|
|
108
|
+
// Fat-string ABI: x19/x20 = self (ptr, len); other = (x2 ptr, x3
|
|
109
|
+
// len). Equal lengths + equal bytes — no NUL scan.
|
|
110
|
+
stp x20, x21, [sp, #-16]!
|
|
111
|
+
cmp x20, x3
|
|
112
|
+
b.ne .Lstring_eq_len_ne
|
|
113
|
+
mov x0, x19
|
|
114
|
+
mov x1, x2
|
|
115
|
+
mov x2, x20
|
|
116
|
+
bl _memcmp
|
|
119
117
|
cmp x0, #0
|
|
120
118
|
cset x0, eq
|
|
119
|
+
b .Lstring_eq_done
|
|
120
|
+
.Lstring_eq_len_ne:
|
|
121
|
+
mov x0, #0
|
|
122
|
+
.Lstring_eq_done:
|
|
123
|
+
ldp x20, x21, [sp], #16
|
|
121
124
|
```
|
|
122
125
|
}
|
|
123
126
|
|
|
@@ -133,23 +136,29 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
133
136
|
```
|
|
134
137
|
```
|
|
135
138
|
#arch: aarch64
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
add x0, x21, x0
|
|
139
|
+
// Fat-string ABI: x19/x20 = self (ptr, len); other = (x2 ptr, x3
|
|
140
|
+
// len). Two memcpys of known length — no strlen/strcpy/strcat.
|
|
141
|
+
// Returns the (buf, total) pair.
|
|
142
|
+
stp x21, x22, [sp, #-16]!
|
|
143
|
+
stp x2, x3, [sp, #-16]! // other (ptr, len)
|
|
144
|
+
add x0, x20, x3
|
|
143
145
|
add x0, x0, #1
|
|
144
146
|
bl _malloc
|
|
145
|
-
mov x21, x0
|
|
146
|
-
mov x1, x19
|
|
147
|
-
bl _strcpy
|
|
147
|
+
mov x21, x0 // buf (callee-saved across memcpys)
|
|
148
148
|
mov x0, x21
|
|
149
|
-
mov x1,
|
|
150
|
-
|
|
149
|
+
mov x1, x19
|
|
150
|
+
mov x2, x20
|
|
151
|
+
bl _memcpy // left half
|
|
152
|
+
ldp x1, x2, [sp] // other ptr, len
|
|
153
|
+
add x0, x21, x20
|
|
154
|
+
bl _memcpy // right half
|
|
155
|
+
ldp x1, x2, [sp], #16 // reload other len; pop
|
|
156
|
+
add x3, x20, x2 // total bytes
|
|
157
|
+
add x0, x21, x3
|
|
158
|
+
strb wzr, [x0] // NUL-terminate for libc consumers
|
|
159
|
+
mov x1, x3
|
|
151
160
|
mov x0, x21
|
|
152
|
-
ldp
|
|
161
|
+
ldp x21, x22, [sp], #16
|
|
153
162
|
```
|
|
154
163
|
}
|
|
155
164
|
|
|
@@ -169,29 +178,34 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
169
178
|
```
|
|
170
179
|
```
|
|
171
180
|
#arch: aarch64
|
|
181
|
+
// Fat-string ABI: x19/x20 = self (ptr, len); count in x2. memcpy
|
|
182
|
+
// loop of known stride; returns the (buf, total) pair.
|
|
172
183
|
stp x20, x21, [sp, #-16]!
|
|
173
|
-
stp x22,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
mov
|
|
177
|
-
mul
|
|
178
|
-
add x0,
|
|
184
|
+
stp x22, x23, [sp, #-16]!
|
|
185
|
+
stp x24, x25, [sp, #-16]!
|
|
186
|
+
mov x21, x20 // self len (stride)
|
|
187
|
+
mov x22, x2 // count
|
|
188
|
+
mul x23, x21, x22 // total bytes
|
|
189
|
+
add x0, x23, #1
|
|
179
190
|
bl _malloc
|
|
180
|
-
|
|
181
|
-
mov
|
|
182
|
-
.
|
|
183
|
-
cbz
|
|
184
|
-
mov x0,
|
|
191
|
+
mov x24, x0 // buf
|
|
192
|
+
mov x25, x0 // cursor
|
|
193
|
+
.Lstring_mul_loop:
|
|
194
|
+
cbz x22, .Lstring_mul_done
|
|
195
|
+
mov x0, x25
|
|
185
196
|
mov x1, x19
|
|
186
197
|
mov x2, x21
|
|
187
198
|
bl _memcpy
|
|
188
|
-
add
|
|
189
|
-
sub
|
|
190
|
-
b .
|
|
191
|
-
.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
199
|
+
add x25, x25, x21
|
|
200
|
+
sub x22, x22, #1
|
|
201
|
+
b .Lstring_mul_loop
|
|
202
|
+
.Lstring_mul_done:
|
|
203
|
+
add x0, x24, x23
|
|
204
|
+
strb wzr, [x0] // NUL-terminate for libc consumers
|
|
205
|
+
mov x1, x23
|
|
206
|
+
mov x0, x24
|
|
207
|
+
ldp x24, x25, [sp], #16
|
|
208
|
+
ldp x22, x23, [sp], #16
|
|
195
209
|
ldp x20, x21, [sp], #16
|
|
196
210
|
```
|
|
197
211
|
}
|
|
@@ -59,7 +59,7 @@ pub struct StringBuilder {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Append a single byte (char).
|
|
62
|
-
func append_char = (ref self, char c) {
|
|
62
|
+
pub inline func append_char = (ref self, char c) {
|
|
63
63
|
```
|
|
64
64
|
#arch: c
|
|
65
65
|
int idx = self->len;
|
|
@@ -128,15 +128,13 @@ pub struct StringBuilder {
|
|
|
128
128
|
```
|
|
129
129
|
```
|
|
130
130
|
#arch: aarch64
|
|
131
|
-
// x19 = self
|
|
132
|
-
//
|
|
133
|
-
mov x0, x1
|
|
131
|
+
// Fat-string ABI: x19 = self; s = (x1 ptr, x2 len). The length is
|
|
132
|
+
// already in a register — no strlen.
|
|
134
133
|
sub sp, sp, #32
|
|
135
|
-
str
|
|
136
|
-
|
|
137
|
-
str x0, [sp, #8] // sl
|
|
134
|
+
str x1, [sp, #0] // s ptr
|
|
135
|
+
str x2, [sp, #8] // sl
|
|
138
136
|
ldr x1, [x19, #16] // len
|
|
139
|
-
add x1, x1,
|
|
137
|
+
add x1, x1, x2 // len + sl
|
|
140
138
|
add x1, x1, #1 // +1 for null room
|
|
141
139
|
// inline ensure(x1)
|
|
142
140
|
ldr x2, [x19, #24]
|
|
@@ -157,12 +155,11 @@ pub struct StringBuilder {
|
|
|
157
155
|
bl _realloc
|
|
158
156
|
str x0, [x19, #8]
|
|
159
157
|
.Lsb_as_copy:
|
|
160
|
-
// memcpy(data + len, s, sl)
|
|
161
|
-
ldr x1, [sp, #8] // sl
|
|
158
|
+
// memcpy(data + len, s.ptr, sl)
|
|
162
159
|
ldr x0, [x19, #8] // data
|
|
163
|
-
ldr
|
|
164
|
-
add x0, x0,
|
|
165
|
-
ldr x1, [sp, #0] // src = s
|
|
160
|
+
ldr x1, [x19, #16] // len
|
|
161
|
+
add x0, x0, x1 // dest = data + len
|
|
162
|
+
ldr x1, [sp, #0] // src = s ptr
|
|
166
163
|
ldr x2, [sp, #8] // n = sl
|
|
167
164
|
bl _memcpy
|
|
168
165
|
// len = len + sl
|
|
@@ -221,6 +218,7 @@ pub struct StringBuilder {
|
|
|
221
218
|
strb wzr, [x0, x1] // data[len] = 0
|
|
222
219
|
// transfer ownership: clear self->data. x0 retains the old ptr.
|
|
223
220
|
str xzr, [x19, #8]
|
|
221
|
+
// Fat-string ABI: (x0 = data, x1 = len) is already the return pair.
|
|
224
222
|
```
|
|
225
223
|
}
|
|
226
224
|
|