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.
Files changed (62) hide show
  1. package/NOMEN_AGENTS.md +57 -12
  2. package/core/System/Array.nm +11 -11
  3. package/core/System/Buffer.nm +2 -2
  4. package/core/System/Channel.nm +146 -12
  5. package/core/System/ClassBuffer.nm +2 -2
  6. package/core/System/Console.nm +28 -17
  7. package/core/System/Controls/Button.nm +96 -8
  8. package/core/System/Controls/CheckBox.nm +117 -12
  9. package/core/System/Controls/Container.nm +114 -8
  10. package/core/System/Controls/Text.nm +98 -8
  11. package/core/System/Controls/TextBox.nm +120 -10
  12. package/core/System/Controls/Window.nm +231 -23
  13. package/core/System/Graph.nm +1 -1
  14. package/core/System/Init.nm +4 -8
  15. package/core/System/LinkedList.nm +1 -1
  16. package/core/System/List.nm +3 -3
  17. package/core/System/Map.nm +5 -5
  18. package/core/System/Math.nm +10 -32
  19. package/core/System/Result.nm +1 -1
  20. package/core/System/Set.nm +4 -4
  21. package/core/System/Stream/Directory.nm +189 -63
  22. package/core/System/Stream/DirectoryError.nm +21 -0
  23. package/core/System/Stream/File.nm +339 -141
  24. package/core/System/Stream/FileError.nm +21 -0
  25. package/core/System/Stream/Http.nm +109 -44
  26. package/core/System/Stream/HttpError.nm +20 -0
  27. package/core/System/String.nm +83 -69
  28. package/core/System/StringBuilder.nm +11 -13
  29. package/core/System/Task.nm +46 -12
  30. package/core/System/Test.nm +1 -1
  31. package/core/System/Text/Json.nm +5 -3
  32. package/core/System/Text/JsonTree.nm +23 -14
  33. package/core/System/Text/Regex.nm +124 -64
  34. package/core/System/Tree.nm +1 -1
  35. package/core/System/bool.nm +4 -9
  36. package/core/System/char.nm +3 -9
  37. package/core/System/float.nm +2 -1
  38. package/core/System/float32.nm +44 -0
  39. package/core/System/float64.nm +44 -0
  40. package/core/System/int.nm +3 -9
  41. package/core/System/int16.nm +47 -0
  42. package/core/System/int32.nm +47 -0
  43. package/core/System/int64.nm +3 -9
  44. package/core/System/int8.nm +3 -9
  45. package/core/System/ufloat.nm +44 -0
  46. package/core/System/ufloat32.nm +44 -0
  47. package/core/System/ufloat64.nm +44 -0
  48. package/core/System/uint.nm +3 -9
  49. package/core/System/uint16.nm +47 -0
  50. package/core/System/uint32.nm +47 -0
  51. package/core/System/uint64.nm +3 -9
  52. package/core/System/uint8.nm +3 -9
  53. package/core/docs/System/Channel.md +2 -0
  54. package/core/docs/System/Result.md +5 -1
  55. package/core/docs/System/Task.md +1 -1
  56. package/dist/index.mjs +38794 -21299
  57. package/package.json +38 -34
  58. package/src/args.ts +11 -0
  59. package/src/index.ts +21 -3
  60. package/src/init.ts +1 -1
  61. package/src/test.ts +48 -4
  62. 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
- * const string names = Directory.list("scratch")
8
- * const bool has = Directory.exists("scratch")
9
- * Directory.remove("scratch")
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
- // (static) Create a directory at `path`.
13
- pub func create = (string path) {
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
- pub func remove = (string path) {
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) Whether a directory exists at `path`.
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
- // Returns the directory's entry names as a single newline-separated
58
- // string. The `.` and `..` entries are skipped. Returns an empty string
59
- // if the path cannot be opened.
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
- // On macOS/iOS the entry length is read from `dirent.d_namlen`, so this
62
- // is currently macOS-specific aarch64 asm (the C backend is portable).
63
- pub func list = (string path, out string) {
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) return strdup("");
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 *e;
77
- while ((e = readdir(d)) != NULL) {
78
- if (e->d_name[0] == '.' && e->d_name[1] == 0) continue;
79
- if (e->d_name[0] == '.' && e->d_name[1] == '.' && e->d_name[2] == 0) continue;
80
- int nl = (int)strlen(e->d_name);
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, e->d_name, nl);
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
- return buf;
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
- sub sp, sp, #64
96
- str x0, [sp, #0]
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, #8]
99
- cbz x0, .Ldir_list_empty
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, #16]
103
- str xzr, [sp, #24]
104
- mov x0, #4096
105
- str x0, [sp, #32]
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, #8]
226
+ ldr x0, [sp, #0]
108
227
  bl _readdir
109
- str x0, [sp, #40]
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
- ldr x0, [sp, #40]
122
- ldrh w0, [x0, #18]
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, #48]
244
+ ldr x2, [sp, #40]
127
245
  add x1, x1, x2
128
246
  add x1, x1, #2
129
- ldr x2, [sp, #32]
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, #32]
134
- ldr x0, [sp, #16]
251
+ str x2, [sp, #48]
252
+ ldr x0, [sp, #56]
135
253
  bl _realloc
136
- str x0, [sp, #16]
254
+ str x0, [sp, #56]
137
255
  b .Ldir_list_grow
138
256
  .Ldir_list_grow_ok:
139
- ldr x0, [sp, #16]
257
+ ldr x0, [sp, #56]
140
258
  ldr x1, [sp, #24]
141
- add x0, x0, x1
142
- ldr x1, [sp, #40]
143
- add x1, x1, #21
144
- ldr x2, [sp, #48]
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
- add x1, x1, x0
149
- str x1, [sp, #24]
150
- ldr x0, [sp, #16]
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, #16]
276
+ ldr x0, [sp, #56]
159
277
  ldr x1, [sp, #24]
160
278
  strb wzr, [x0, x1]
161
- ldr x0, [sp, #8]
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
- add sp, sp, #64
165
- b .return_Directory_list
166
- .Ldir_list_empty:
167
- adr x0, .Ldir_list_empty_str
168
- bl _strdup
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
+ }