@live-codes/ocaml 0.0.0-stage → 0.1.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 (130) hide show
  1. package/LICENSE +220 -0
  2. package/README.md +165 -2
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/assets/compiler/compile_stdout.browser.js +27856 -0
  5. package/assets/compiler/jsoo.js +12631 -0
  6. package/assets/compiler/package.json +3 -0
  7. package/assets/compiler/runtime/bigarray.js +1072 -0
  8. package/assets/compiler/runtime/bigstring.js +137 -0
  9. package/assets/compiler/runtime/domain.js +393 -0
  10. package/assets/compiler/runtime/dynlink.js +91 -0
  11. package/assets/compiler/runtime/float32.js +486 -0
  12. package/assets/compiler/runtime/fs.js +416 -0
  13. package/assets/compiler/runtime/fs_fake.js +600 -0
  14. package/assets/compiler/runtime/fs_node.js +609 -0
  15. package/assets/compiler/runtime/fs_quickjs.js +532 -0
  16. package/assets/compiler/runtime/gc.js +201 -0
  17. package/assets/compiler/runtime/graphics.js +1053 -0
  18. package/assets/compiler/runtime/ieee_754.js +621 -0
  19. package/assets/compiler/runtime/int64.js +516 -0
  20. package/assets/compiler/runtime/io.js +739 -0
  21. package/assets/compiler/runtime/jslib.js +553 -0
  22. package/assets/compiler/runtime/jslib_js_of_ocaml.js +81 -0
  23. package/assets/compiler/runtime/lexing.js +240 -0
  24. package/assets/compiler/runtime/manifest.txt +31 -0
  25. package/assets/compiler/runtime/marshal.js +863 -0
  26. package/assets/compiler/runtime/md5.js +236 -0
  27. package/assets/compiler/runtime/mlBytes.js +1007 -0
  28. package/assets/compiler/runtime/nat.js +469 -0
  29. package/assets/compiler/runtime/parsing.js +317 -0
  30. package/assets/compiler/runtime/prng.js +84 -0
  31. package/assets/compiler/runtime/promise.js +45 -0
  32. package/assets/compiler/runtime/runtime.js +16688 -0
  33. package/assets/compiler/runtime/runtime_events.js +90 -0
  34. package/assets/compiler/runtime/stdlib.js +363 -0
  35. package/assets/compiler/runtime/sync.js +35 -0
  36. package/assets/compiler/runtime/toplevel.js +150 -0
  37. package/assets/compiler/runtime/unix.js +914 -0
  38. package/assets/compiler/runtime/weak.js +247 -0
  39. package/assets/compiler/stdlib.js +254 -0
  40. package/assets/compiler/worker.js +46 -0
  41. package/assets/interpreter/libs/greet.cma +0 -0
  42. package/assets/interpreter/libs/greet.cmi +0 -0
  43. package/assets/interpreter/libs/manifest.txt +1 -0
  44. package/assets/interpreter/package.json +3 -0
  45. package/assets/interpreter/stdlib/camlinternalFormat.cmi +0 -0
  46. package/assets/interpreter/stdlib/camlinternalFormatBasics.cmi +0 -0
  47. package/assets/interpreter/stdlib/camlinternalLazy.cmi +0 -0
  48. package/assets/interpreter/stdlib/camlinternalMod.cmi +0 -0
  49. package/assets/interpreter/stdlib/camlinternalOO.cmi +0 -0
  50. package/assets/interpreter/stdlib/std_exit.cmi +0 -0
  51. package/assets/interpreter/stdlib/stdlib.cmi +0 -0
  52. package/assets/interpreter/stdlib/stdlib__Arg.cmi +0 -0
  53. package/assets/interpreter/stdlib/stdlib__Array.cmi +0 -0
  54. package/assets/interpreter/stdlib/stdlib__ArrayLabels.cmi +0 -0
  55. package/assets/interpreter/stdlib/stdlib__Atomic.cmi +0 -0
  56. package/assets/interpreter/stdlib/stdlib__Bigarray.cmi +0 -0
  57. package/assets/interpreter/stdlib/stdlib__Bool.cmi +0 -0
  58. package/assets/interpreter/stdlib/stdlib__Buffer.cmi +0 -0
  59. package/assets/interpreter/stdlib/stdlib__Bytes.cmi +0 -0
  60. package/assets/interpreter/stdlib/stdlib__BytesLabels.cmi +0 -0
  61. package/assets/interpreter/stdlib/stdlib__Callback.cmi +0 -0
  62. package/assets/interpreter/stdlib/stdlib__Char.cmi +0 -0
  63. package/assets/interpreter/stdlib/stdlib__Complex.cmi +0 -0
  64. package/assets/interpreter/stdlib/stdlib__Condition.cmi +0 -0
  65. package/assets/interpreter/stdlib/stdlib__Digest.cmi +0 -0
  66. package/assets/interpreter/stdlib/stdlib__Domain.cmi +0 -0
  67. package/assets/interpreter/stdlib/stdlib__Dynarray.cmi +0 -0
  68. package/assets/interpreter/stdlib/stdlib__Effect.cmi +0 -0
  69. package/assets/interpreter/stdlib/stdlib__Either.cmi +0 -0
  70. package/assets/interpreter/stdlib/stdlib__Ephemeron.cmi +0 -0
  71. package/assets/interpreter/stdlib/stdlib__Filename.cmi +0 -0
  72. package/assets/interpreter/stdlib/stdlib__Float.cmi +0 -0
  73. package/assets/interpreter/stdlib/stdlib__Format.cmi +0 -0
  74. package/assets/interpreter/stdlib/stdlib__Fun.cmi +0 -0
  75. package/assets/interpreter/stdlib/stdlib__Gc.cmi +0 -0
  76. package/assets/interpreter/stdlib/stdlib__Hashtbl.cmi +0 -0
  77. package/assets/interpreter/stdlib/stdlib__Iarray.cmi +0 -0
  78. package/assets/interpreter/stdlib/stdlib__In_channel.cmi +0 -0
  79. package/assets/interpreter/stdlib/stdlib__Int.cmi +0 -0
  80. package/assets/interpreter/stdlib/stdlib__Int32.cmi +0 -0
  81. package/assets/interpreter/stdlib/stdlib__Int64.cmi +0 -0
  82. package/assets/interpreter/stdlib/stdlib__Lazy.cmi +0 -0
  83. package/assets/interpreter/stdlib/stdlib__Lexing.cmi +0 -0
  84. package/assets/interpreter/stdlib/stdlib__List.cmi +0 -0
  85. package/assets/interpreter/stdlib/stdlib__ListLabels.cmi +0 -0
  86. package/assets/interpreter/stdlib/stdlib__Map.cmi +0 -0
  87. package/assets/interpreter/stdlib/stdlib__Marshal.cmi +0 -0
  88. package/assets/interpreter/stdlib/stdlib__MoreLabels.cmi +0 -0
  89. package/assets/interpreter/stdlib/stdlib__Mutex.cmi +0 -0
  90. package/assets/interpreter/stdlib/stdlib__Nativeint.cmi +0 -0
  91. package/assets/interpreter/stdlib/stdlib__Obj.cmi +0 -0
  92. package/assets/interpreter/stdlib/stdlib__Oo.cmi +0 -0
  93. package/assets/interpreter/stdlib/stdlib__Option.cmi +0 -0
  94. package/assets/interpreter/stdlib/stdlib__Out_channel.cmi +0 -0
  95. package/assets/interpreter/stdlib/stdlib__Pair.cmi +0 -0
  96. package/assets/interpreter/stdlib/stdlib__Parsing.cmi +0 -0
  97. package/assets/interpreter/stdlib/stdlib__Pqueue.cmi +0 -0
  98. package/assets/interpreter/stdlib/stdlib__Printexc.cmi +0 -0
  99. package/assets/interpreter/stdlib/stdlib__Printf.cmi +0 -0
  100. package/assets/interpreter/stdlib/stdlib__Queue.cmi +0 -0
  101. package/assets/interpreter/stdlib/stdlib__Random.cmi +0 -0
  102. package/assets/interpreter/stdlib/stdlib__Repr.cmi +0 -0
  103. package/assets/interpreter/stdlib/stdlib__Result.cmi +0 -0
  104. package/assets/interpreter/stdlib/stdlib__Scanf.cmi +0 -0
  105. package/assets/interpreter/stdlib/stdlib__Semaphore.cmi +0 -0
  106. package/assets/interpreter/stdlib/stdlib__Seq.cmi +0 -0
  107. package/assets/interpreter/stdlib/stdlib__Set.cmi +0 -0
  108. package/assets/interpreter/stdlib/stdlib__Stack.cmi +0 -0
  109. package/assets/interpreter/stdlib/stdlib__StdLabels.cmi +0 -0
  110. package/assets/interpreter/stdlib/stdlib__String.cmi +0 -0
  111. package/assets/interpreter/stdlib/stdlib__StringLabels.cmi +0 -0
  112. package/assets/interpreter/stdlib/stdlib__Sys.cmi +0 -0
  113. package/assets/interpreter/stdlib/stdlib__Type.cmi +0 -0
  114. package/assets/interpreter/stdlib/stdlib__Uchar.cmi +0 -0
  115. package/assets/interpreter/stdlib/stdlib__Unit.cmi +0 -0
  116. package/assets/interpreter/stdlib/stdlib__Weak.cmi +0 -0
  117. package/assets/interpreter/stdlib/topdirs.cmi +0 -0
  118. package/assets/interpreter/stdlib/units.txt +75 -0
  119. package/assets/interpreter/stdlib/unix.cmi +0 -0
  120. package/assets/interpreter/stdlib/unixLabels.cmi +0 -0
  121. package/assets/interpreter/worker-entry.js +39 -0
  122. package/assets/interpreter/worker.js +42356 -0
  123. package/bin/copy-assets.mjs +75 -0
  124. package/package.json +41 -4
  125. package/src/compiler/compile.js +170 -0
  126. package/src/compiler/index.js +46 -0
  127. package/src/compiler/worker.js +46 -0
  128. package/src/index.js +12 -0
  129. package/src/interpreter/api.js +182 -0
  130. package/src/interpreter/index.js +5 -0
@@ -0,0 +1,532 @@
1
+ // Js_of_ocaml runtime support
2
+ // http://www.ocsigen.org/js_of_ocaml/
3
+ //
4
+ // This program is free software; you can redistribute it and/or modify
5
+ // it under the terms of the GNU Lesser General Public License as published by
6
+ // the Free Software Foundation, with linking exception;
7
+ // either version 2.1 of the License, or (at your option) any later version.
8
+ //
9
+ // This program is distributed in the hope that it will be useful,
10
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ // GNU Lesser General Public License for more details.
13
+ //
14
+ // You should have received a copy of the GNU Lesser General Public License
15
+ // along with this program; if not, write to the Free Software
16
+ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
+
18
+ // Real-disk device backed by QuickJS-NG's [os] / [std] modules. Active
19
+ // when the runtime detects a qjs host (no `process`, but `os.open` is
20
+ // available). Mirrors the [MlNodeDevice] interface; primitives qjs
21
+ // does not expose ([access], [chmod], [truncate], [link]) raise
22
+ // "not implemented".
23
+
24
+ //Provides: fs_quickjs_supported
25
+ function fs_quickjs_supported() {
26
+ return (
27
+ globalThis.process?.versions?.node === undefined &&
28
+ typeof globalThis.os?.open === "function"
29
+ );
30
+ }
31
+ //Provides: fs_quickjs_supported
32
+ //If: browser
33
+ function fs_quickjs_supported() {
34
+ return false;
35
+ }
36
+
37
+ // POSIX errno -> Unix-error-code string. Linux values; CI runs on
38
+ // Ubuntu so this is the only platform we rely on for now.
39
+ //Provides: caml_qjs_errno_code
40
+ function caml_qjs_errno_code(errno) {
41
+ switch (-errno) {
42
+ case 1:
43
+ return "EPERM";
44
+ case 2:
45
+ return "ENOENT";
46
+ case 5:
47
+ return "EIO";
48
+ case 9:
49
+ return "EBADF";
50
+ case 11:
51
+ return "EAGAIN";
52
+ case 13:
53
+ return "EACCES";
54
+ case 17:
55
+ return "EEXIST";
56
+ case 20:
57
+ return "ENOTDIR";
58
+ case 21:
59
+ return "EISDIR";
60
+ case 22:
61
+ return "EINVAL";
62
+ case 24:
63
+ return "EMFILE";
64
+ case 28:
65
+ return "ENOSPC";
66
+ case 29:
67
+ return "ESPIPE";
68
+ case 30:
69
+ return "EROFS";
70
+ case 32:
71
+ return "EPIPE";
72
+ case 36:
73
+ return "ENAMETOOLONG";
74
+ case 39:
75
+ return "ENOTEMPTY";
76
+ case 40:
77
+ return "ELOOP";
78
+ default:
79
+ return "EUNKNOWN";
80
+ }
81
+ }
82
+
83
+ //Provides: caml_raise_qjs_error
84
+ //Requires: caml_raise_system_error, caml_qjs_errno_code
85
+ function caml_raise_qjs_error(errno, syscall, path, raise_unix) {
86
+ var code = caml_qjs_errno_code(errno);
87
+ caml_raise_system_error(raise_unix, code, syscall, "qjs " + syscall, path);
88
+ }
89
+
90
+ //Provides: ocaml_stats_from_qjs_stats
91
+ //Requires: caml_int64_of_float
92
+ function ocaml_stats_from_qjs_stats(s, large) {
93
+ var os = globalThis.os;
94
+ var kind_bits = s.mode & (os.S_IFMT || 0o170000);
95
+ var file_kind = 0;
96
+ if (kind_bits === os.S_IFREG) file_kind = 0;
97
+ else if (kind_bits === os.S_IFDIR) file_kind = 1;
98
+ else if (kind_bits === os.S_IFCHR) file_kind = 2;
99
+ else if (kind_bits === os.S_IFBLK) file_kind = 3;
100
+ else if (kind_bits === os.S_IFLNK) file_kind = 4;
101
+ else if (kind_bits === os.S_IFIFO) file_kind = 5;
102
+ else if (kind_bits === os.S_IFSOCK) file_kind = 6;
103
+ return BLOCK(
104
+ 0,
105
+ s.dev | 0,
106
+ s.ino | 0,
107
+ file_kind,
108
+ s.mode & 0o7777,
109
+ s.nlink | 0,
110
+ s.uid | 0,
111
+ s.gid | 0,
112
+ s.rdev | 0,
113
+ large ? caml_int64_of_float(s.size) : s.size | 0,
114
+ s.atime / 1000,
115
+ s.mtime / 1000,
116
+ s.ctime / 1000,
117
+ );
118
+ }
119
+
120
+ //Provides: MlQuickJSDevice
121
+ //Requires: MlQuickJSFd, caml_raise_qjs_error, caml_raise_sys_error
122
+ //Requires: caml_raise_system_error
123
+ //Requires: caml_string_of_jsstring, caml_failwith
124
+ //Requires: ocaml_stats_from_qjs_stats
125
+ class MlQuickJSDevice {
126
+ constructor(root) {
127
+ this.os = globalThis.os;
128
+ this.root = root;
129
+ }
130
+
131
+ nm(name) {
132
+ return this.root + name;
133
+ }
134
+
135
+ exists(name) {
136
+ var r = this.os.stat(this.nm(name));
137
+ return r[1] === 0 ? 1 : 0;
138
+ }
139
+
140
+ isFile(name) {
141
+ var r = this.os.stat(this.nm(name));
142
+ if (r[1] !== 0) caml_raise_sys_error("stat " + this.nm(name));
143
+ return (r[0].mode & this.os.S_IFMT) === this.os.S_IFREG ? 1 : 0;
144
+ }
145
+
146
+ is_dir(name) {
147
+ var r = this.os.stat(this.nm(name));
148
+ if (r[1] !== 0) caml_raise_sys_error("stat " + this.nm(name));
149
+ return (r[0].mode & this.os.S_IFMT) === this.os.S_IFDIR ? 1 : 0;
150
+ }
151
+
152
+ mkdir(name, mode, raise_unix) {
153
+ var err = this.os.mkdir(this.nm(name), mode);
154
+ if (err !== 0)
155
+ caml_raise_qjs_error(err, "mkdir", this.nm(name), raise_unix);
156
+ return 0;
157
+ }
158
+
159
+ // qjs has no rmdir; os.remove handles directories (fails if non-empty),
160
+ // but it also removes files, so check the type first.
161
+ rmdir(name, raise_unix) {
162
+ var r = this.os.stat(this.nm(name));
163
+ if (
164
+ r[1] === 0 &&
165
+ (r[0].mode & (this.os.S_IFMT || 0o170000)) !== this.os.S_IFDIR
166
+ )
167
+ caml_raise_system_error(
168
+ raise_unix,
169
+ "ENOTDIR",
170
+ "rmdir",
171
+ "not a directory",
172
+ this.nm(name),
173
+ );
174
+ var err = this.os.remove(this.nm(name));
175
+ if (err !== 0)
176
+ caml_raise_qjs_error(err, "rmdir", this.nm(name), raise_unix);
177
+ return 0;
178
+ }
179
+
180
+ readdir(name, raise_unix) {
181
+ var r = this.os.readdir(this.nm(name));
182
+ if (r[1] !== 0)
183
+ caml_raise_qjs_error(r[1], "readdir", this.nm(name), raise_unix);
184
+ // qjs includes "." and ".." — strip to match Node.
185
+ return r[0].filter(function (x) {
186
+ return x !== "." && x !== "..";
187
+ });
188
+ }
189
+
190
+ // os.remove also removes directories; refuse them like unlink(2)
191
+ unlink(name, raise_unix) {
192
+ var r = this.os.stat(this.nm(name));
193
+ if (
194
+ r[1] === 0 &&
195
+ (r[0].mode & (this.os.S_IFMT || 0o170000)) === this.os.S_IFDIR
196
+ )
197
+ caml_raise_system_error(
198
+ raise_unix,
199
+ "EISDIR",
200
+ "unlink",
201
+ "is a directory",
202
+ this.nm(name),
203
+ );
204
+ var err = this.os.remove(this.nm(name));
205
+ if (err !== 0)
206
+ caml_raise_qjs_error(err, "unlink", this.nm(name), raise_unix);
207
+ return 0;
208
+ }
209
+
210
+ utimes(name, atime, mtime, raise_unix) {
211
+ if (atime === 0 && mtime === 0) {
212
+ atime = Date.now() / 1000;
213
+ mtime = atime;
214
+ }
215
+ var err = this.os.utimes(
216
+ this.nm(name),
217
+ Math.round(atime * 1000),
218
+ Math.round(mtime * 1000),
219
+ );
220
+ if (err !== 0)
221
+ caml_raise_qjs_error(err, "utimes", this.nm(name), raise_unix);
222
+ return 0;
223
+ }
224
+
225
+ truncate(_name, _len, _raise_unix) {
226
+ caml_failwith("MlQuickJSDevice.truncate: not implemented");
227
+ }
228
+
229
+ // qjs has no access(); fall back to stat for "f" (existence) only.
230
+ access(name, _f, raise_unix) {
231
+ var r = this.os.stat(this.nm(name));
232
+ if (r[1] !== 0)
233
+ caml_raise_qjs_error(r[1], "access", this.nm(name), raise_unix);
234
+ return 0;
235
+ }
236
+
237
+ open(name, f, perms, raise_unix) {
238
+ var os = this.os;
239
+ var flags = 0;
240
+ for (var key in f) {
241
+ switch (key) {
242
+ case "rdonly":
243
+ flags |= os.O_RDONLY;
244
+ break;
245
+ case "wronly":
246
+ flags |= os.O_WRONLY;
247
+ break;
248
+ case "rdwr":
249
+ flags |= os.O_RDWR;
250
+ break;
251
+ case "append":
252
+ flags |= os.O_APPEND;
253
+ break;
254
+ case "create":
255
+ flags |= os.O_CREAT;
256
+ break;
257
+ case "truncate":
258
+ flags |= os.O_TRUNC;
259
+ break;
260
+ case "excl":
261
+ flags |= os.O_EXCL;
262
+ break;
263
+ // binary/text/nonblock/noctty/dsync/sync: not in qjs, ignored.
264
+ }
265
+ }
266
+ var fd = os.open(this.nm(name), flags, perms === undefined ? 0o666 : perms);
267
+ if (fd < 0) caml_raise_qjs_error(fd, "open", this.nm(name), raise_unix);
268
+ return new MlQuickJSFd(fd, f, this.nm(name));
269
+ }
270
+
271
+ rename(o, n, raise_unix) {
272
+ var err = this.os.rename(this.nm(o), this.nm(n));
273
+ if (err !== 0) caml_raise_qjs_error(err, "rename", this.nm(o), raise_unix);
274
+ }
275
+
276
+ stat(name, large, raise_unix) {
277
+ var r = this.os.stat(this.nm(name));
278
+ if (r[1] !== 0)
279
+ caml_raise_qjs_error(r[1], "stat", this.nm(name), raise_unix);
280
+ return ocaml_stats_from_qjs_stats(r[0], large);
281
+ }
282
+
283
+ lstat(name, large, raise_unix) {
284
+ var r = this.os.lstat(this.nm(name));
285
+ if (r[1] !== 0)
286
+ caml_raise_qjs_error(r[1], "lstat", this.nm(name), raise_unix);
287
+ return ocaml_stats_from_qjs_stats(r[0], large);
288
+ }
289
+
290
+ chmod(_name, _perms, _raise_unix) {
291
+ caml_failwith("MlQuickJSDevice.chmod: not implemented");
292
+ }
293
+
294
+ link(_target, _path, _raise_unix) {
295
+ caml_failwith("MlQuickJSDevice.link: not implemented");
296
+ }
297
+
298
+ symlink(_to_dir, target, path, raise_unix) {
299
+ var err = this.os.symlink(target, this.nm(path));
300
+ if (err !== 0)
301
+ caml_raise_qjs_error(err, "symlink", this.nm(path), raise_unix);
302
+ return 0;
303
+ }
304
+
305
+ readlink(name, raise_unix) {
306
+ var r = this.os.readlink(this.nm(name));
307
+ if (r[1] !== 0)
308
+ caml_raise_qjs_error(r[1], "readlink", this.nm(name), raise_unix);
309
+ return caml_string_of_jsstring(r[0]);
310
+ }
311
+
312
+ opendir(_name, _raise_unix) {
313
+ caml_failwith("MlQuickJSDevice.opendir: not implemented");
314
+ }
315
+ }
316
+
317
+ //Provides: MlQuickJSDevice
318
+ //If: browser
319
+ class MlQuickJSDevice {}
320
+
321
+ //Provides: MlQuickJSFd
322
+ //Requires: MlFile, caml_failwith, caml_raise_qjs_error, caml_raise_system_error
323
+ //Requires: ocaml_stats_from_qjs_stats
324
+ class MlQuickJSFd extends MlFile {
325
+ constructor(fd, flags, path) {
326
+ super();
327
+ this.os = globalThis.os;
328
+ this.fd = fd;
329
+ this.flags = flags;
330
+ this.path = path;
331
+ // Like native [O_APPEND], the offset starts at the beginning of the file;
332
+ // each [write] repositions to the end (see [write] below).
333
+ this.offset = 0;
334
+ this.seeked = false;
335
+ flags.noSeek = false;
336
+ }
337
+
338
+ isatty() {
339
+ return this.os.isatty(this.fd) ? 1 : 0;
340
+ }
341
+
342
+ length() {
343
+ var cur = this.offset;
344
+ var end = this.os.seek(this.fd, 0, 2 /* SEEK_END */);
345
+ this.os.seek(this.fd, cur, 0 /* SEEK_SET */);
346
+ return end;
347
+ }
348
+
349
+ // qjs's os.read/os.write take an ArrayBuffer + byte offset.
350
+ // The runtime hands us either a Uint8Array view or a raw buffer.
351
+
352
+ read(a, buf_offset, len, raise_unix) {
353
+ if (this.seeked) this.os.seek(this.fd, this.offset, 0);
354
+ var ab = a.buffer || a;
355
+ var base = a.byteOffset || 0;
356
+ var n = this.os.read(this.fd, ab, base + buf_offset, len);
357
+ if (n < 0) caml_raise_qjs_error(n, "read", this.path, raise_unix);
358
+ this.offset += n;
359
+ return n;
360
+ }
361
+
362
+ write(buf, buf_offset, len, raise_unix) {
363
+ // [O_APPEND]: every write goes to the end of the file. The OS already
364
+ // enforces this for the bytes (the fd was opened with O_APPEND); we
365
+ // refresh the tracked offset so [pos]/[lseek] report the native value.
366
+ if (this.flags.append) this.offset = this.length();
367
+ if (this.seeked) this.os.seek(this.fd, this.offset, 0);
368
+ var ab = buf.buffer || buf;
369
+ var base = buf.byteOffset || 0;
370
+ var n = this.os.write(this.fd, ab, base + buf_offset, len);
371
+ if (n < 0) caml_raise_qjs_error(n, "write", this.path, raise_unix);
372
+ this.offset += n;
373
+ return n;
374
+ }
375
+
376
+ seek(offset, whence, raise_unix) {
377
+ switch (whence) {
378
+ case 0:
379
+ break;
380
+ case 1:
381
+ offset += this.offset;
382
+ break;
383
+ case 2:
384
+ offset += this.length();
385
+ break;
386
+ }
387
+ if (offset < 0)
388
+ caml_raise_system_error(
389
+ raise_unix,
390
+ "EINVAL",
391
+ "lseek",
392
+ "invalid argument",
393
+ );
394
+ this.offset = offset;
395
+ this.seeked = true;
396
+ return this.offset;
397
+ }
398
+
399
+ pos() {
400
+ return this.offset;
401
+ }
402
+
403
+ truncate(_len, _raise_unix) {
404
+ caml_failwith("MlQuickJSFd.truncate: not implemented");
405
+ }
406
+
407
+ stat(large) {
408
+ var r = this.os.stat(this.path);
409
+ if (r[1] !== 0) caml_raise_qjs_error(r[1], "fstat", this.path, 1);
410
+ return ocaml_stats_from_qjs_stats(r[0], large);
411
+ }
412
+
413
+ chmod(_perms) {
414
+ caml_failwith("MlQuickJSFd.chmod: not implemented");
415
+ }
416
+
417
+ sync() {
418
+ return 0;
419
+ }
420
+
421
+ close(raise_unix) {
422
+ var err = this.os.close(this.fd);
423
+ if (err !== 0) caml_raise_qjs_error(err, "close", this.path, raise_unix);
424
+ return 0;
425
+ }
426
+
427
+ check_stream_semantics(_cmd) {
428
+ return 0;
429
+ }
430
+ }
431
+
432
+ //Provides: MlQuickJSFd
433
+ //If: browser
434
+ class MlQuickJSFd {}
435
+
436
+ // Stream FD wrapping the host's stdin / stdout / stderr (qjs fd 0 / 1 /
437
+ // 2) via os.read / os.write. Used as the qjs counterpart of MlNodeFd
438
+ // for the standard streams; opt-in like the rest of fs_quickjs.
439
+
440
+ //Provides: MlQuickJSStdFd
441
+ //Requires: MlFile, caml_raise_system_error, caml_raise_qjs_error
442
+ class MlQuickJSStdFd extends MlFile {
443
+ constructor(fd, flags) {
444
+ super();
445
+ this.os = globalThis.os;
446
+ this.fd = fd;
447
+ this.flags = flags;
448
+ flags.noSeek = true;
449
+ }
450
+
451
+ isatty() {
452
+ return this.os.isatty(this.fd) ? 1 : 0;
453
+ }
454
+
455
+ length() {
456
+ return 0;
457
+ }
458
+
459
+ read(a, buf_offset, len, raise_unix) {
460
+ if (this.fd !== 0)
461
+ caml_raise_system_error(
462
+ raise_unix,
463
+ "EBADF",
464
+ "read",
465
+ "bad file descriptor",
466
+ );
467
+ var ab = a.buffer || a;
468
+ var base = a.byteOffset || 0;
469
+ var n = this.os.read(this.fd, ab, base + buf_offset, len);
470
+ // a negative return is an error, not EOF
471
+ if (n < 0) caml_raise_qjs_error(n, "read", "", raise_unix);
472
+ return n;
473
+ }
474
+
475
+ write(buf, buf_offset, len, raise_unix) {
476
+ if (this.fd !== 1 && this.fd !== 2)
477
+ caml_raise_system_error(
478
+ raise_unix,
479
+ "EBADF",
480
+ "write",
481
+ "bad file descriptor",
482
+ );
483
+ var ab = buf.buffer || buf;
484
+ var base = buf.byteOffset || 0;
485
+ var n = this.os.write(this.fd, ab, base + buf_offset, len);
486
+ // a negative return is an error; returning 0 would make the
487
+ // flush/write loop spin forever
488
+ if (n < 0) caml_raise_qjs_error(n, "write", "", raise_unix);
489
+ return n;
490
+ }
491
+
492
+ seek(_offset, _whence, raise_unix) {
493
+ caml_raise_system_error(raise_unix, "ESPIPE", "lseek", "illegal seek");
494
+ }
495
+
496
+ pos() {
497
+ return -1;
498
+ }
499
+
500
+ truncate(_len, raise_unix) {
501
+ caml_raise_system_error(
502
+ raise_unix,
503
+ "EINVAL",
504
+ "ftruncate",
505
+ "invalid argument",
506
+ );
507
+ }
508
+
509
+ close(_raise_unix) {
510
+ return 0;
511
+ }
512
+
513
+ check_stream_semantics(_cmd) {
514
+ return 0;
515
+ }
516
+ }
517
+
518
+ //Provides: MlQuickJSStdFd
519
+ //If: browser
520
+ class MlQuickJSStdFd {}
521
+
522
+ //Provides: caml_sys_open_for_quickjs
523
+ //Requires: MlQuickJSStdFd
524
+ function caml_sys_open_for_quickjs(fd, flags) {
525
+ return new MlQuickJSStdFd(fd, flags);
526
+ }
527
+
528
+ //Provides: caml_sys_open_for_quickjs
529
+ //If: browser
530
+ function caml_sys_open_for_quickjs(_fd, _flags) {
531
+ return null;
532
+ }