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
|
@@ -2,39 +2,109 @@
|
|
|
2
2
|
* Helpers for working with filesystem directories.
|
|
3
3
|
*
|
|
4
4
|
* `Directory` is a namespace of static helpers — no instance is constructed.
|
|
5
|
+
* Fallible operations return a `Result` whose error side is a
|
|
6
|
+
* `DirectoryError`.
|
|
5
7
|
*
|
|
6
8
|
* Directory.create("scratch")
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* var Result<string, DirectoryError> names = Directory.list("scratch")
|
|
10
|
+
* match names {
|
|
11
|
+
* case .ok(text) -> Console.write(text)
|
|
12
|
+
* case .error(e) -> Console.write("failed")
|
|
13
|
+
* }
|
|
10
14
|
**/
|
|
11
15
|
pub struct Directory {
|
|
12
|
-
//
|
|
13
|
-
|
|
16
|
+
// Maps an errno to its DirectoryError case.
|
|
17
|
+
func error_of = (int err, out DirectoryError) {
|
|
18
|
+
switch {
|
|
19
|
+
case err == 2 {
|
|
20
|
+
return DirectoryError.not_found
|
|
21
|
+
}
|
|
22
|
+
case err == 13 {
|
|
23
|
+
return DirectoryError.access_denied
|
|
24
|
+
}
|
|
25
|
+
case err == 17 {
|
|
26
|
+
return DirectoryError.already_exists
|
|
27
|
+
}
|
|
28
|
+
case err == 66 {
|
|
29
|
+
return DirectoryError.not_empty
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return DirectoryError.other
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// (static) Create a directory at `path`; returns errno (0 on success).
|
|
38
|
+
func raw_create = (string path, out int) {
|
|
39
|
+
```
|
|
40
|
+
#arch: c
|
|
41
|
+
#scope: file
|
|
42
|
+
#include <errno.h>
|
|
43
|
+
```
|
|
14
44
|
```
|
|
15
45
|
#arch: c
|
|
16
|
-
mkdir(path, 0777);
|
|
46
|
+
if (mkdir(path, 0777)) return errno;
|
|
47
|
+
return 0;
|
|
17
48
|
```
|
|
18
49
|
```
|
|
19
50
|
#arch: aarch64
|
|
20
51
|
mov x1, #0x1FF
|
|
21
52
|
bl _mkdir
|
|
53
|
+
cbz w0, .Ldir_create_ok
|
|
54
|
+
bl ___error
|
|
55
|
+
ldr w0, [x0]
|
|
56
|
+
b .return_Directory_raw_create
|
|
57
|
+
.Ldir_create_ok:
|
|
58
|
+
mov x0, #0
|
|
59
|
+
b .return_Directory_raw_create
|
|
22
60
|
```
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// (static) Create a directory at `path`. `.ok(true)`, or
|
|
65
|
+
// `.error(DirectoryError)` (`already_exists` when it is already there).
|
|
66
|
+
pub func create = (string path, out Result<bool, DirectoryError>) {
|
|
67
|
+
const int err = Directory.raw_create(path)
|
|
68
|
+
if err == 0 {
|
|
69
|
+
return Result.ok(true)
|
|
70
|
+
}
|
|
71
|
+
return Result.error(Directory.error_of(err))
|
|
23
72
|
}
|
|
24
73
|
|
|
25
|
-
// (static) Remove the (empty) directory at `path
|
|
26
|
-
|
|
74
|
+
// (static) Remove the (empty) directory at `path`; returns errno (0 on
|
|
75
|
+
// success).
|
|
76
|
+
func raw_remove = (string path, out int) {
|
|
27
77
|
```
|
|
28
78
|
#arch: c
|
|
29
|
-
rmdir(path);
|
|
79
|
+
if (rmdir(path)) return errno;
|
|
80
|
+
return 0;
|
|
30
81
|
```
|
|
31
82
|
```
|
|
32
83
|
#arch: aarch64
|
|
33
84
|
bl _rmdir
|
|
85
|
+
cbz w0, .Ldir_remove_ok
|
|
86
|
+
bl ___error
|
|
87
|
+
ldr w0, [x0]
|
|
88
|
+
b .return_Directory_raw_remove
|
|
89
|
+
.Ldir_remove_ok:
|
|
90
|
+
mov x0, #0
|
|
91
|
+
b .return_Directory_raw_remove
|
|
34
92
|
```
|
|
93
|
+
return 0
|
|
35
94
|
}
|
|
36
95
|
|
|
37
|
-
// (static)
|
|
96
|
+
// (static) Remove the (empty) directory at `path`. `.ok(true)`, or
|
|
97
|
+
// `.error(DirectoryError)` (`not_empty` when it still has entries).
|
|
98
|
+
pub func remove = (string path, out Result<bool, DirectoryError>) {
|
|
99
|
+
const int err = Directory.raw_remove(path)
|
|
100
|
+
if err == 0 {
|
|
101
|
+
return Result.ok(true)
|
|
102
|
+
}
|
|
103
|
+
return Result.error(Directory.error_of(err))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// (static) Whether a directory exists at `path`. A missing directory is
|
|
107
|
+
// `false`, not an error.
|
|
38
108
|
pub func exists = (string path, out bool) {
|
|
39
109
|
```
|
|
40
110
|
#arch: c
|
|
@@ -54,59 +124,108 @@ pub struct Directory {
|
|
|
54
124
|
return false
|
|
55
125
|
}
|
|
56
126
|
|
|
57
|
-
//
|
|
58
|
-
// string
|
|
59
|
-
//
|
|
127
|
+
// (static) The directory's entry names as a single newline-separated
|
|
128
|
+
// string (the `.` and `..` entries are skipped). `.ok(text)`, or
|
|
129
|
+
// `.error(DirectoryError)` when the directory cannot be opened.
|
|
60
130
|
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
131
|
+
// The whole operation is one raw body per backend: the listing must be
|
|
132
|
+
// built and any open failure mapped to its errno inside a single
|
|
133
|
+
// opendir/closedir lifetime, so the Result is constructed directly in
|
|
134
|
+
// `#arch` code. Case ordinals mirrored below come from
|
|
135
|
+
// System/Result.nm (ok=0, error=1) and DirectoryError.nm (not_found=0,
|
|
136
|
+
// access_denied=1, already_exists=2, not_empty=3, other=4).
|
|
137
|
+
//
|
|
138
|
+
// On macOS/iOS the entry length is read from `dirent.d_namlen`, so the
|
|
139
|
+
// aarch64 body is currently macOS-specific (the C backend is portable).
|
|
140
|
+
pub func list = (string path, out Result<string, DirectoryError>) {
|
|
64
141
|
```
|
|
65
142
|
#arch: c
|
|
66
143
|
#scope: file
|
|
144
|
+
#include <errno.h>
|
|
67
145
|
#include <dirent.h>
|
|
68
146
|
```
|
|
69
147
|
```
|
|
70
148
|
#arch: c
|
|
149
|
+
Result_string_DirectoryError r;
|
|
71
150
|
DIR *d = opendir(path);
|
|
72
|
-
if (!d)
|
|
151
|
+
if (!d) {
|
|
152
|
+
int e = errno;
|
|
153
|
+
long de = 4;
|
|
154
|
+
if (e == ENOENT) de = 0;
|
|
155
|
+
else if (e == EACCES) de = 1;
|
|
156
|
+
r.tag = 1;
|
|
157
|
+
r._data._error.error = (DirectoryError)de;
|
|
158
|
+
return r;
|
|
159
|
+
}
|
|
73
160
|
int cap = 4096;
|
|
74
161
|
int len = 0;
|
|
75
162
|
char *buf = (char*)malloc(cap);
|
|
76
|
-
struct dirent *
|
|
77
|
-
while ((
|
|
78
|
-
if (
|
|
79
|
-
if (
|
|
80
|
-
int nl = (int)strlen(
|
|
163
|
+
struct dirent *ent;
|
|
164
|
+
while ((ent = readdir(d)) != NULL) {
|
|
165
|
+
if (ent->d_name[0] == '.' && ent->d_name[1] == 0) continue;
|
|
166
|
+
if (ent->d_name[0] == '.' && ent->d_name[1] == '.' && ent->d_name[2] == 0) continue;
|
|
167
|
+
int nl = (int)strlen(ent->d_name);
|
|
81
168
|
if (len + nl + 2 > cap) {
|
|
82
169
|
while (len + nl + 2 > cap) cap *= 2;
|
|
83
170
|
buf = (char*)realloc(buf, cap);
|
|
84
171
|
}
|
|
85
|
-
memcpy(buf + len,
|
|
172
|
+
memcpy(buf + len, ent->d_name, nl);
|
|
86
173
|
len += nl;
|
|
87
174
|
buf[len++] = '\n';
|
|
88
175
|
}
|
|
89
176
|
buf[len] = 0;
|
|
90
177
|
closedir(d);
|
|
91
|
-
|
|
178
|
+
r.tag = 0;
|
|
179
|
+
r._data._ok.value.ptr = buf;
|
|
180
|
+
r._data._ok.value.len = len;
|
|
181
|
+
// len bytes were appended — the count is exact, no strlen.
|
|
182
|
+
return r;
|
|
92
183
|
```
|
|
93
184
|
```
|
|
94
185
|
#arch: aarch64
|
|
95
|
-
|
|
96
|
-
|
|
186
|
+
// Fat-string ABI: path = (x0, x1). Enum-with-data returns use the
|
|
187
|
+
// sret convention: x8 holds the caller-provided destination buffer
|
|
188
|
+
// on entry (the prologue spills it; this body re-saves it across the
|
|
189
|
+
// calls below). The final blob (tag+payload, 24 bytes) is copied
|
|
190
|
+
// through x8 and the buffer address returned in x0.
|
|
191
|
+
//
|
|
192
|
+
// Frame (sp-relative): #0 DIR*, #8 blob.tag, #16 blob.ptr,
|
|
193
|
+
// #24 blob.len, #32 readdir ent, #40 namlen, #48 cap, #56 buf,
|
|
194
|
+
// #64 saved sret pointer (x8).
|
|
195
|
+
sub sp, sp, #80
|
|
196
|
+
str x8, [sp, #64]
|
|
97
197
|
bl _opendir
|
|
98
|
-
str x0, [sp, #
|
|
99
|
-
|
|
198
|
+
str x0, [sp, #0]
|
|
199
|
+
cbnz x0, .Ldir_list_opened
|
|
200
|
+
bl ___error
|
|
201
|
+
ldr w0, [x0]
|
|
202
|
+
// Map errno -> DirectoryError ordinal (see header comment).
|
|
203
|
+
mov x9, #4
|
|
204
|
+
cmp w0, #2
|
|
205
|
+
b.ne .Ldir_list_nf_skip
|
|
206
|
+
mov x9, #0
|
|
207
|
+
b .Ldir_list_emap
|
|
208
|
+
.Ldir_list_nf_skip:
|
|
209
|
+
cmp w0, #13
|
|
210
|
+
b.ne .Ldir_list_emap
|
|
211
|
+
mov x9, #1
|
|
212
|
+
.Ldir_list_emap:
|
|
213
|
+
mov x10, #1
|
|
214
|
+
str x10, [sp, #8] // tag = error
|
|
215
|
+
str x9, [sp, #16] // payload = DirectoryError ordinal
|
|
216
|
+
b .Ldir_list_ret
|
|
217
|
+
.Ldir_list_opened:
|
|
100
218
|
mov x0, #4096
|
|
101
219
|
bl _malloc
|
|
102
|
-
str x0, [sp, #
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
220
|
+
str x0, [sp, #56] // buf
|
|
221
|
+
mov x1, #0
|
|
222
|
+
str x1, [sp, #24] // len
|
|
223
|
+
mov x1, #4096
|
|
224
|
+
str x1, [sp, #48] // cap
|
|
106
225
|
.Ldir_list_loop:
|
|
107
|
-
ldr x0, [sp, #
|
|
226
|
+
ldr x0, [sp, #0]
|
|
108
227
|
bl _readdir
|
|
109
|
-
str x0, [sp, #
|
|
228
|
+
str x0, [sp, #32]
|
|
110
229
|
cbz x0, .Ldir_list_done
|
|
111
230
|
ldrb w1, [x0, #21]
|
|
112
231
|
cmp w1, #46
|
|
@@ -118,59 +237,66 @@ pub struct Directory {
|
|
|
118
237
|
ldrb w1, [x0, #23]
|
|
119
238
|
cbz w1, .Ldir_list_loop
|
|
120
239
|
.Ldir_list_keep:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
str x0, [sp, #48]
|
|
240
|
+
ldrh w2, [x0, #18] // d_namlen (macOS dirent)
|
|
241
|
+
str x2, [sp, #40]
|
|
124
242
|
.Ldir_list_grow:
|
|
125
243
|
ldr x1, [sp, #24]
|
|
126
|
-
ldr x2, [sp, #
|
|
244
|
+
ldr x2, [sp, #40]
|
|
127
245
|
add x1, x1, x2
|
|
128
246
|
add x1, x1, #2
|
|
129
|
-
ldr x2, [sp, #
|
|
247
|
+
ldr x2, [sp, #48]
|
|
130
248
|
cmp x1, x2
|
|
131
249
|
ble .Ldir_list_grow_ok
|
|
132
250
|
lsl x2, x2, #1
|
|
133
|
-
str x2, [sp, #
|
|
134
|
-
ldr x0, [sp, #
|
|
251
|
+
str x2, [sp, #48]
|
|
252
|
+
ldr x0, [sp, #56]
|
|
135
253
|
bl _realloc
|
|
136
|
-
str x0, [sp, #
|
|
254
|
+
str x0, [sp, #56]
|
|
137
255
|
b .Ldir_list_grow
|
|
138
256
|
.Ldir_list_grow_ok:
|
|
139
|
-
ldr x0, [sp, #
|
|
257
|
+
ldr x0, [sp, #56]
|
|
140
258
|
ldr x1, [sp, #24]
|
|
141
|
-
add x0, x0, x1
|
|
142
|
-
ldr x1, [sp, #
|
|
143
|
-
add x1, x1, #21
|
|
144
|
-
ldr x2, [sp, #
|
|
259
|
+
add x0, x0, x1 // dst = buf + len
|
|
260
|
+
ldr x1, [sp, #32]
|
|
261
|
+
add x1, x1, #21 // src = ent->d_name
|
|
262
|
+
ldr x2, [sp, #40] // nl
|
|
145
263
|
bl _memcpy
|
|
146
|
-
ldr x0, [sp, #48]
|
|
147
264
|
ldr x1, [sp, #24]
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
265
|
+
ldr x2, [sp, #40]
|
|
266
|
+
add x1, x1, x2
|
|
267
|
+
str x1, [sp, #24] // len += nl
|
|
268
|
+
ldr x0, [sp, #56]
|
|
151
269
|
ldr x1, [sp, #24]
|
|
152
270
|
mov w2, #10
|
|
153
|
-
strb w2, [x0, x1]
|
|
271
|
+
strb w2, [x0, x1] // buf[len++] = '\n'
|
|
154
272
|
add x1, x1, #1
|
|
155
273
|
str x1, [sp, #24]
|
|
156
274
|
b .Ldir_list_loop
|
|
157
275
|
.Ldir_list_done:
|
|
158
|
-
ldr x0, [sp, #
|
|
276
|
+
ldr x0, [sp, #56]
|
|
159
277
|
ldr x1, [sp, #24]
|
|
160
278
|
strb wzr, [x0, x1]
|
|
161
|
-
ldr x0, [sp, #
|
|
279
|
+
ldr x0, [sp, #0]
|
|
162
280
|
bl _closedir
|
|
281
|
+
// ok: tag = 0, payload = (buf, len)
|
|
282
|
+
str xzr, [sp, #8]
|
|
283
|
+
ldr x0, [sp, #56]
|
|
284
|
+
ldr x1, [sp, #24]
|
|
285
|
+
stp x0, x1, [sp, #16]
|
|
286
|
+
.Ldir_list_ret:
|
|
287
|
+
// Copy the blob into the caller's sret buffer (x8), then hand the
|
|
288
|
+
// buffer address back in x0.
|
|
289
|
+
ldr x8, [sp, #64]
|
|
290
|
+
ldr x0, [sp, #8]
|
|
291
|
+
str x0, [x8]
|
|
163
292
|
ldr x0, [sp, #16]
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
add sp, sp, #64
|
|
293
|
+
str x0, [x8, #8]
|
|
294
|
+
ldr x0, [sp, #24]
|
|
295
|
+
str x0, [x8, #16]
|
|
296
|
+
mov x0, x8
|
|
297
|
+
add sp, sp, #80
|
|
170
298
|
b .return_Directory_list
|
|
171
|
-
.Ldir_list_empty_str: .asciz ""
|
|
172
|
-
.p2align 2
|
|
173
299
|
```
|
|
174
|
-
return
|
|
300
|
+
return Result.error(DirectoryError.other)
|
|
175
301
|
}
|
|
176
302
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The failure mode of a directory operation.
|
|
3
|
+
*
|
|
4
|
+
* Directory.create("scratch")
|
|
5
|
+
* var Result<string, DirectoryError> names = Directory.list("scratch")
|
|
6
|
+
* match names {
|
|
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_empty` (removing a directory
|
|
13
|
+
* that still has entries), `other` (anything else).
|
|
14
|
+
**/
|
|
15
|
+
pub enum DirectoryError {
|
|
16
|
+
case not_found
|
|
17
|
+
case access_denied
|
|
18
|
+
case already_exists
|
|
19
|
+
case not_empty
|
|
20
|
+
case other
|
|
21
|
+
}
|