@live-codes/ocaml 0.0.0-stage → 0.1.1
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/LICENSE +220 -0
- package/README.md +165 -2
- package/THIRD-PARTY-NOTICES.md +52 -0
- package/assets/compiler/compile_stdout.browser.js +27856 -0
- package/assets/compiler/jsoo.js +12631 -0
- package/assets/compiler/package.json +3 -0
- package/assets/compiler/runtime/bigarray.js +1072 -0
- package/assets/compiler/runtime/bigstring.js +137 -0
- package/assets/compiler/runtime/domain.js +393 -0
- package/assets/compiler/runtime/dynlink.js +91 -0
- package/assets/compiler/runtime/float32.js +486 -0
- package/assets/compiler/runtime/fs.js +416 -0
- package/assets/compiler/runtime/fs_fake.js +600 -0
- package/assets/compiler/runtime/fs_node.js +609 -0
- package/assets/compiler/runtime/fs_quickjs.js +532 -0
- package/assets/compiler/runtime/gc.js +201 -0
- package/assets/compiler/runtime/graphics.js +1053 -0
- package/assets/compiler/runtime/ieee_754.js +621 -0
- package/assets/compiler/runtime/int64.js +516 -0
- package/assets/compiler/runtime/io.js +739 -0
- package/assets/compiler/runtime/jslib.js +553 -0
- package/assets/compiler/runtime/jslib_js_of_ocaml.js +81 -0
- package/assets/compiler/runtime/lexing.js +240 -0
- package/assets/compiler/runtime/manifest.txt +31 -0
- package/assets/compiler/runtime/marshal.js +863 -0
- package/assets/compiler/runtime/md5.js +236 -0
- package/assets/compiler/runtime/mlBytes.js +1007 -0
- package/assets/compiler/runtime/nat.js +469 -0
- package/assets/compiler/runtime/parsing.js +317 -0
- package/assets/compiler/runtime/prng.js +84 -0
- package/assets/compiler/runtime/promise.js +45 -0
- package/assets/compiler/runtime/runtime.js +16688 -0
- package/assets/compiler/runtime/runtime_events.js +90 -0
- package/assets/compiler/runtime/stdlib.js +363 -0
- package/assets/compiler/runtime/sync.js +35 -0
- package/assets/compiler/runtime/toplevel.js +150 -0
- package/assets/compiler/runtime/unix.js +914 -0
- package/assets/compiler/runtime/weak.js +247 -0
- package/assets/compiler/stdlib.js +254 -0
- package/assets/compiler/worker.js +46 -0
- package/assets/interpreter/libs/greet.cma +0 -0
- package/assets/interpreter/libs/greet.cmi +0 -0
- package/assets/interpreter/libs/manifest.txt +1 -0
- package/assets/interpreter/package.json +3 -0
- package/assets/interpreter/stdlib/camlinternalFormat.cmi +0 -0
- package/assets/interpreter/stdlib/camlinternalFormatBasics.cmi +0 -0
- package/assets/interpreter/stdlib/camlinternalLazy.cmi +0 -0
- package/assets/interpreter/stdlib/camlinternalMod.cmi +0 -0
- package/assets/interpreter/stdlib/camlinternalOO.cmi +0 -0
- package/assets/interpreter/stdlib/std_exit.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Arg.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Array.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__ArrayLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Atomic.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Bigarray.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Bool.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Buffer.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Bytes.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__BytesLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Callback.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Char.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Complex.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Condition.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Digest.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Domain.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Dynarray.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Effect.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Either.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Ephemeron.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Filename.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Float.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Format.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Fun.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Gc.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Hashtbl.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Iarray.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__In_channel.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Int.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Int32.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Int64.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Lazy.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Lexing.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__List.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__ListLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Map.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Marshal.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__MoreLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Mutex.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Nativeint.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Obj.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Oo.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Option.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Out_channel.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Pair.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Parsing.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Pqueue.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Printexc.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Printf.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Queue.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Random.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Repr.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Result.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Scanf.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Semaphore.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Seq.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Set.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Stack.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__StdLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__String.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__StringLabels.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Sys.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Type.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Uchar.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Unit.cmi +0 -0
- package/assets/interpreter/stdlib/stdlib__Weak.cmi +0 -0
- package/assets/interpreter/stdlib/topdirs.cmi +0 -0
- package/assets/interpreter/stdlib/units.txt +75 -0
- package/assets/interpreter/stdlib/unix.cmi +0 -0
- package/assets/interpreter/stdlib/unixLabels.cmi +0 -0
- package/assets/interpreter/worker-entry.js +39 -0
- package/assets/interpreter/worker.js +42356 -0
- package/bin/copy-assets.mjs +75 -0
- package/package.json +41 -4
- package/src/compiler/compile.js +195 -0
- package/src/compiler/index.js +46 -0
- package/src/compiler/worker.js +46 -0
- package/src/index.js +12 -0
- package/src/interpreter/api.js +182 -0
- package/src/interpreter/index.js +5 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
// Js_of_ocaml runtime support
|
|
2
|
+
// http://www.ocsigen.org/js_of_ocaml/
|
|
3
|
+
// Copyright (C) 2014 Jérôme Vouillon, Hugo Heuzard
|
|
4
|
+
// Laboratoire PPS - CNRS Université Paris Diderot
|
|
5
|
+
//
|
|
6
|
+
// This program is free software; you can redistribute it and/or modify
|
|
7
|
+
// it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
// the Free Software Foundation, with linking exception;
|
|
9
|
+
// either version 2.1 of the License, or (at your option) any later version.
|
|
10
|
+
//
|
|
11
|
+
// This program is distributed in the hope that it will be useful,
|
|
12
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
// GNU Lesser General Public License for more details.
|
|
15
|
+
//
|
|
16
|
+
// You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
// along with this program; if not, write to the Free Software
|
|
18
|
+
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
19
|
+
|
|
20
|
+
//Provides: MlFakeDevice
|
|
21
|
+
//Requires: MlFakeFile, MlFakeFd, caml_create_bytes
|
|
22
|
+
//Requires: caml_raise_sys_error, caml_raise_no_such_file
|
|
23
|
+
//Requires: caml_string_of_jsbytes, caml_string_of_jsstring
|
|
24
|
+
//Requires: caml_bytes_of_array, caml_bytes_of_string, caml_bytes_of_jsbytes
|
|
25
|
+
//Requires: caml_is_ml_bytes, caml_is_ml_string
|
|
26
|
+
//Requires: caml_raise_system_error
|
|
27
|
+
class MlFakeDevice {
|
|
28
|
+
constructor(root, f) {
|
|
29
|
+
this.content = {};
|
|
30
|
+
this.root = root;
|
|
31
|
+
this.lookupFun = f;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
nm(name) {
|
|
35
|
+
return this.root + name;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
create_dir_if_needed(name) {
|
|
39
|
+
var comp = name.split("/");
|
|
40
|
+
var res = "";
|
|
41
|
+
for (var i = 0; i < comp.length - 1; i++) {
|
|
42
|
+
res += comp[i] + "/";
|
|
43
|
+
if (this.content[res]) continue;
|
|
44
|
+
this.content[res] = Symbol("directory");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
slash(name) {
|
|
49
|
+
return /\/$/.test(name) ? name : name + "/";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
lookup(name) {
|
|
53
|
+
if (!this.content[name] && this.lookupFun) {
|
|
54
|
+
var res = this.lookupFun(
|
|
55
|
+
caml_string_of_jsstring(this.root),
|
|
56
|
+
caml_string_of_jsstring(name),
|
|
57
|
+
);
|
|
58
|
+
if (res !== 0) {
|
|
59
|
+
this.create_dir_if_needed(name);
|
|
60
|
+
this.content[name] = new MlFakeFile(caml_bytes_of_string(res[1]));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exists(name, do_not_lookup) {
|
|
66
|
+
// The root of the device exists
|
|
67
|
+
if (name === "") return 1;
|
|
68
|
+
// Check if a directory exists
|
|
69
|
+
var name_slash = this.slash(name);
|
|
70
|
+
if (this.content[name_slash]) return 1;
|
|
71
|
+
// Check if a file exists
|
|
72
|
+
if (!do_not_lookup) this.lookup(name);
|
|
73
|
+
return this.content[name] ? 1 : 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
isFile(name) {
|
|
77
|
+
if (this.exists(name) && !this.is_dir(name)) {
|
|
78
|
+
return 1;
|
|
79
|
+
} else {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
rename_dir(oldname, newname, raise_unix) {
|
|
85
|
+
var old_slash = this.slash(oldname);
|
|
86
|
+
var new_slash = this.slash(newname);
|
|
87
|
+
if (newname !== oldname && new_slash.startsWith(old_slash))
|
|
88
|
+
// renaming a directory into its own subtree would recurse forever
|
|
89
|
+
caml_raise_system_error(
|
|
90
|
+
raise_unix,
|
|
91
|
+
"EINVAL",
|
|
92
|
+
"rename",
|
|
93
|
+
"invalid argument",
|
|
94
|
+
this.nm(newname),
|
|
95
|
+
);
|
|
96
|
+
if (this.exists(newname)) {
|
|
97
|
+
if (!this.is_dir(newname)) {
|
|
98
|
+
caml_raise_system_error(
|
|
99
|
+
raise_unix,
|
|
100
|
+
"ENOTDIR",
|
|
101
|
+
"rename",
|
|
102
|
+
"not a directory",
|
|
103
|
+
this.nm(newname),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (this.readdir(newname).length > 0) {
|
|
107
|
+
caml_raise_system_error(
|
|
108
|
+
raise_unix,
|
|
109
|
+
"ENOTEMPTY",
|
|
110
|
+
"rename",
|
|
111
|
+
"directory not empty",
|
|
112
|
+
this.nm(newname),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.create_dir_if_needed(new_slash);
|
|
117
|
+
for (const f of this.readdir(oldname)) {
|
|
118
|
+
this.rename(old_slash + f, new_slash + f, raise_unix);
|
|
119
|
+
}
|
|
120
|
+
delete this.content[old_slash];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
rename(oldname, newname, raise_unix) {
|
|
124
|
+
if (!this.exists(oldname))
|
|
125
|
+
caml_raise_no_such_file(this.nm(oldname), raise_unix, "rename");
|
|
126
|
+
if (this.is_dir(oldname)) {
|
|
127
|
+
this.rename_dir(oldname, newname, raise_unix);
|
|
128
|
+
} else {
|
|
129
|
+
if (this.exists(newname) && this.is_dir(newname)) {
|
|
130
|
+
caml_raise_system_error(
|
|
131
|
+
raise_unix,
|
|
132
|
+
"EISDIR",
|
|
133
|
+
"rename",
|
|
134
|
+
"is a directory",
|
|
135
|
+
this.nm(newname),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (newname !== oldname) {
|
|
139
|
+
this.content[newname] = this.content[oldname];
|
|
140
|
+
delete this.content[oldname];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
mkdir(name, _mode, raise_unix) {
|
|
146
|
+
if (this.exists(name))
|
|
147
|
+
caml_raise_system_error(
|
|
148
|
+
raise_unix,
|
|
149
|
+
"EEXIST",
|
|
150
|
+
"mkdir",
|
|
151
|
+
"file already exists",
|
|
152
|
+
this.nm(name),
|
|
153
|
+
);
|
|
154
|
+
var parent = /^(.*)\/[^/]+/.exec(name);
|
|
155
|
+
parent = parent?.[1] || "";
|
|
156
|
+
if (!this.exists(parent))
|
|
157
|
+
caml_raise_system_error(
|
|
158
|
+
raise_unix,
|
|
159
|
+
"ENOENT",
|
|
160
|
+
"mkdir",
|
|
161
|
+
"no such file or directory",
|
|
162
|
+
this.nm(name),
|
|
163
|
+
);
|
|
164
|
+
if (!this.is_dir(parent))
|
|
165
|
+
caml_raise_system_error(
|
|
166
|
+
raise_unix,
|
|
167
|
+
"ENOTDIR",
|
|
168
|
+
"mkdir",
|
|
169
|
+
"not a directory",
|
|
170
|
+
this.nm(name),
|
|
171
|
+
);
|
|
172
|
+
this.create_dir_if_needed(this.slash(name));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
rmdir(name, raise_unix) {
|
|
176
|
+
var name_slash = name === "" ? "" : this.slash(name);
|
|
177
|
+
if (!this.exists(name))
|
|
178
|
+
caml_raise_system_error(
|
|
179
|
+
raise_unix,
|
|
180
|
+
"ENOENT",
|
|
181
|
+
"rmdir",
|
|
182
|
+
"no such file or directory",
|
|
183
|
+
this.nm(name),
|
|
184
|
+
);
|
|
185
|
+
if (!this.is_dir(name))
|
|
186
|
+
caml_raise_system_error(
|
|
187
|
+
raise_unix,
|
|
188
|
+
"ENOTDIR",
|
|
189
|
+
"rmdir",
|
|
190
|
+
"not a directory",
|
|
191
|
+
this.nm(name),
|
|
192
|
+
);
|
|
193
|
+
for (var n in this.content) {
|
|
194
|
+
if (n.startsWith(name_slash) && n !== name_slash)
|
|
195
|
+
caml_raise_system_error(
|
|
196
|
+
raise_unix,
|
|
197
|
+
"ENOTEMPTY",
|
|
198
|
+
"rmdir",
|
|
199
|
+
"directory not empty",
|
|
200
|
+
this.nm(name),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
delete this.content[name_slash];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
readdir(name, raise_unix) {
|
|
207
|
+
var name_slash = name === "" ? "" : this.slash(name);
|
|
208
|
+
if (!this.exists(name)) {
|
|
209
|
+
caml_raise_no_such_file(this.nm(name), raise_unix, "readdir");
|
|
210
|
+
}
|
|
211
|
+
if (!this.is_dir(name)) {
|
|
212
|
+
caml_raise_system_error(
|
|
213
|
+
raise_unix,
|
|
214
|
+
"ENOTDIR",
|
|
215
|
+
"readdir",
|
|
216
|
+
"not a directory",
|
|
217
|
+
this.nm(name),
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
var seen = {};
|
|
221
|
+
var a = [];
|
|
222
|
+
for (var n in this.content) {
|
|
223
|
+
if (n.startsWith(name_slash) && n !== name_slash) {
|
|
224
|
+
var last = n.indexOf("/", name_slash.length);
|
|
225
|
+
if (last < 0) last = undefined;
|
|
226
|
+
var m = n.slice(name_slash.length, last);
|
|
227
|
+
if (m && !seen[m]) {
|
|
228
|
+
seen[m] = true;
|
|
229
|
+
a.push(m);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return a;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
opendir(name, raise_unix) {
|
|
237
|
+
var a = this.readdir(name, raise_unix);
|
|
238
|
+
var c = false;
|
|
239
|
+
var i = 0;
|
|
240
|
+
return {
|
|
241
|
+
readSync: function () {
|
|
242
|
+
if (c)
|
|
243
|
+
caml_raise_system_error(
|
|
244
|
+
raise_unix,
|
|
245
|
+
"EBADF",
|
|
246
|
+
"readdir",
|
|
247
|
+
"bad file descriptor",
|
|
248
|
+
);
|
|
249
|
+
if (i === a.length) return null;
|
|
250
|
+
var entry = a[i];
|
|
251
|
+
i++;
|
|
252
|
+
return { name: entry };
|
|
253
|
+
},
|
|
254
|
+
closeSync: function () {
|
|
255
|
+
if (c)
|
|
256
|
+
caml_raise_system_error(
|
|
257
|
+
raise_unix,
|
|
258
|
+
"EBADF",
|
|
259
|
+
"readdir",
|
|
260
|
+
"bad file descriptor",
|
|
261
|
+
);
|
|
262
|
+
c = true;
|
|
263
|
+
a = [];
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
is_dir(name) {
|
|
269
|
+
if (name === "") return true;
|
|
270
|
+
var name_slash = this.slash(name);
|
|
271
|
+
return this.content[name_slash] ? 1 : 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
unlink(name, raise_unix) {
|
|
275
|
+
if (!this.exists(name, true)) {
|
|
276
|
+
// [true] means no "lookup" if not found.
|
|
277
|
+
caml_raise_system_error(
|
|
278
|
+
raise_unix,
|
|
279
|
+
"ENOENT",
|
|
280
|
+
"unlink",
|
|
281
|
+
"no such file or directory",
|
|
282
|
+
name,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
if (this.is_dir(name))
|
|
286
|
+
caml_raise_system_error(
|
|
287
|
+
raise_unix,
|
|
288
|
+
"EISDIR",
|
|
289
|
+
"unlink",
|
|
290
|
+
"is a directory",
|
|
291
|
+
this.nm(name),
|
|
292
|
+
);
|
|
293
|
+
delete this.content[name];
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
access(name, _flags, raise_unix) {
|
|
298
|
+
this.lookup(name);
|
|
299
|
+
if (!this.exists(name))
|
|
300
|
+
caml_raise_no_such_file(this.nm(name), raise_unix, "access");
|
|
301
|
+
return 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
open(name, f, _perms, raise_unix) {
|
|
305
|
+
var file;
|
|
306
|
+
this.lookup(name);
|
|
307
|
+
if (this.content[name]) {
|
|
308
|
+
if (this.is_dir(name))
|
|
309
|
+
caml_raise_system_error(
|
|
310
|
+
raise_unix,
|
|
311
|
+
"EISDIR",
|
|
312
|
+
"open",
|
|
313
|
+
"illegal operation on a directory",
|
|
314
|
+
this.nm(name),
|
|
315
|
+
);
|
|
316
|
+
if (f.create && f.excl)
|
|
317
|
+
caml_raise_system_error(
|
|
318
|
+
raise_unix,
|
|
319
|
+
"EEXIST",
|
|
320
|
+
"open",
|
|
321
|
+
"file already exists",
|
|
322
|
+
this.nm(name),
|
|
323
|
+
);
|
|
324
|
+
file = this.content[name];
|
|
325
|
+
if (f.truncate) file.truncate(0);
|
|
326
|
+
} else if (f.create) {
|
|
327
|
+
this.create_dir_if_needed(name);
|
|
328
|
+
this.content[name] = new MlFakeFile(caml_create_bytes(0));
|
|
329
|
+
file = this.content[name];
|
|
330
|
+
} else {
|
|
331
|
+
caml_raise_no_such_file(this.nm(name), raise_unix, "open");
|
|
332
|
+
}
|
|
333
|
+
return new MlFakeFd(this.nm(name), file, f);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
truncate(name, len, raise_unix) {
|
|
337
|
+
var file;
|
|
338
|
+
this.lookup(name);
|
|
339
|
+
if (this.content[name]) {
|
|
340
|
+
if (this.is_dir(name))
|
|
341
|
+
caml_raise_system_error(
|
|
342
|
+
raise_unix,
|
|
343
|
+
"EISDIR",
|
|
344
|
+
"open",
|
|
345
|
+
"illegal operation on a directory",
|
|
346
|
+
this.nm(name),
|
|
347
|
+
);
|
|
348
|
+
file = this.content[name];
|
|
349
|
+
file.truncate(len);
|
|
350
|
+
} else {
|
|
351
|
+
caml_raise_no_such_file(this.nm(name), raise_unix, "truncate");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
register(name, content) {
|
|
356
|
+
var file;
|
|
357
|
+
if (this.content[name])
|
|
358
|
+
caml_raise_sys_error(this.nm(name) + " : file already exists");
|
|
359
|
+
if (caml_is_ml_bytes(content)) file = new MlFakeFile(content);
|
|
360
|
+
else if (caml_is_ml_string(content))
|
|
361
|
+
file = new MlFakeFile(caml_bytes_of_string(content));
|
|
362
|
+
else if (Array.isArray(content))
|
|
363
|
+
file = new MlFakeFile(caml_bytes_of_array(content));
|
|
364
|
+
else if (typeof content === "string")
|
|
365
|
+
file = new MlFakeFile(caml_bytes_of_jsbytes(content));
|
|
366
|
+
else if (content.toString) {
|
|
367
|
+
var bytes = caml_bytes_of_string(
|
|
368
|
+
caml_string_of_jsstring(content.toString()),
|
|
369
|
+
);
|
|
370
|
+
file = new MlFakeFile(bytes);
|
|
371
|
+
}
|
|
372
|
+
if (file) {
|
|
373
|
+
this.create_dir_if_needed(name);
|
|
374
|
+
this.content[name] = file;
|
|
375
|
+
} else
|
|
376
|
+
caml_raise_sys_error(
|
|
377
|
+
this.nm(name) + " : registering file with invalid content type",
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
//Provides: MlFakeFile
|
|
383
|
+
//Requires: MlFile
|
|
384
|
+
//Requires: caml_create_bytes, caml_ml_bytes_length, caml_blit_bytes
|
|
385
|
+
//Requires: caml_uint8_array_of_bytes, caml_bytes_of_uint8_array
|
|
386
|
+
class MlFakeFile extends MlFile {
|
|
387
|
+
constructor(content) {
|
|
388
|
+
super();
|
|
389
|
+
this.data = content;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
truncate(len) {
|
|
393
|
+
var old = this.data;
|
|
394
|
+
var old_len = caml_ml_bytes_length(old);
|
|
395
|
+
this.data = caml_create_bytes(len | 0);
|
|
396
|
+
caml_blit_bytes(old, 0, this.data, 0, Math.min(len, old_len));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
length() {
|
|
400
|
+
return caml_ml_bytes_length(this.data);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
write(offset, buf, pos, len) {
|
|
404
|
+
var clen = this.length();
|
|
405
|
+
if (offset + len >= clen) {
|
|
406
|
+
var new_str = caml_create_bytes(offset + len);
|
|
407
|
+
var old_data = this.data;
|
|
408
|
+
this.data = new_str;
|
|
409
|
+
caml_blit_bytes(old_data, 0, this.data, 0, clen);
|
|
410
|
+
}
|
|
411
|
+
caml_blit_bytes(
|
|
412
|
+
caml_bytes_of_uint8_array(buf),
|
|
413
|
+
pos,
|
|
414
|
+
this.data,
|
|
415
|
+
offset,
|
|
416
|
+
len,
|
|
417
|
+
);
|
|
418
|
+
return len;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
read(offset, buf, pos, len) {
|
|
422
|
+
var clen = this.length();
|
|
423
|
+
if (offset + len >= clen) {
|
|
424
|
+
len = clen - offset;
|
|
425
|
+
}
|
|
426
|
+
if (len > 0) {
|
|
427
|
+
var data = caml_create_bytes(len | 0);
|
|
428
|
+
caml_blit_bytes(this.data, offset, data, 0, len);
|
|
429
|
+
buf.set(caml_uint8_array_of_bytes(data), pos);
|
|
430
|
+
return len;
|
|
431
|
+
}
|
|
432
|
+
return 0;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
//Provides: MlFakeFd_out
|
|
437
|
+
//Requires: MlFakeFile, caml_create_bytes, caml_blit_bytes, caml_bytes_of_uint8_array
|
|
438
|
+
//Requires: caml_raise_system_error
|
|
439
|
+
class MlFakeFd_out extends MlFakeFile {
|
|
440
|
+
constructor(fd, flags) {
|
|
441
|
+
super(caml_create_bytes(0));
|
|
442
|
+
// Pick a stdout / stderr sink. console.log / console.error always
|
|
443
|
+
// append a newline, so wrap them to drop at most one trailing \n
|
|
444
|
+
// (otherwise OCaml's own newline doubles up).
|
|
445
|
+
var via_console = (sink) => (s) =>
|
|
446
|
+
sink(
|
|
447
|
+
s.length > 0 && s.charCodeAt(s.length - 1) === 10 ? s.slice(0, -1) : s,
|
|
448
|
+
);
|
|
449
|
+
if (fd === 1 && typeof console.log === "function")
|
|
450
|
+
this.log = via_console(console.log);
|
|
451
|
+
else if (fd === 2 && typeof console.error === "function")
|
|
452
|
+
this.log = via_console(console.error);
|
|
453
|
+
else if (typeof console.log === "function")
|
|
454
|
+
this.log = via_console(console.log);
|
|
455
|
+
else this.log = (_s) => 0;
|
|
456
|
+
this.flags = flags;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
length() {
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
truncate(_len, raise_unix) {
|
|
464
|
+
caml_raise_system_error(
|
|
465
|
+
raise_unix,
|
|
466
|
+
"EINVAL",
|
|
467
|
+
"ftruncate",
|
|
468
|
+
"invalid argument",
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
write(buf, pos, len, raise_unix) {
|
|
473
|
+
if (this.log) {
|
|
474
|
+
var src = caml_create_bytes(len);
|
|
475
|
+
caml_blit_bytes(caml_bytes_of_uint8_array(buf), pos, src, 0, len);
|
|
476
|
+
this.log(src.toUtf16());
|
|
477
|
+
return len;
|
|
478
|
+
}
|
|
479
|
+
caml_raise_system_error(
|
|
480
|
+
raise_unix,
|
|
481
|
+
"EBADF",
|
|
482
|
+
"write",
|
|
483
|
+
"bad file descriptor",
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
read(_buf, _pos, _len, raise_unix) {
|
|
488
|
+
caml_raise_system_error(raise_unix, "EBADF", "read", "bad file descriptor");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
seek(_len, _whence, raise_unix) {
|
|
492
|
+
caml_raise_system_error(raise_unix, "ESPIPE", "lseek", "illegal seek");
|
|
493
|
+
}
|
|
494
|
+
pos() {
|
|
495
|
+
return -1;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
close() {
|
|
499
|
+
this.log = undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
check_stream_semantics(_cmd) {}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
//Provides: MlFakeFd
|
|
506
|
+
//Requires: MlFakeFile
|
|
507
|
+
//Requires: caml_raise_system_error
|
|
508
|
+
class MlFakeFd {
|
|
509
|
+
constructor(name, file, flags) {
|
|
510
|
+
this.file = file;
|
|
511
|
+
this.name = name;
|
|
512
|
+
this.flags = flags;
|
|
513
|
+
// Like native [O_APPEND], the offset starts at the beginning of the file;
|
|
514
|
+
// it is each [write] that repositions to the end (see [write] below).
|
|
515
|
+
this.offset = 0;
|
|
516
|
+
this.seeked = false;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
err_closed(cmd, raise_unix) {
|
|
520
|
+
caml_raise_system_error(raise_unix, "EBADF", cmd, "bad file descriptor");
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
length(raise_unix) {
|
|
524
|
+
if (this.file) return this.file.length();
|
|
525
|
+
this.err_closed("length", raise_unix);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
truncate(len, raise_unix) {
|
|
529
|
+
if (this.file) {
|
|
530
|
+
if (!(this.flags.wronly || this.flags.rdwr))
|
|
531
|
+
caml_raise_system_error(
|
|
532
|
+
raise_unix,
|
|
533
|
+
"EINVAL",
|
|
534
|
+
"truncate",
|
|
535
|
+
"invalid argument",
|
|
536
|
+
);
|
|
537
|
+
return this.file.truncate(len);
|
|
538
|
+
}
|
|
539
|
+
this.err_closed("truncate", raise_unix);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
write(buf, pos, len, raise_unix) {
|
|
543
|
+
if (this.file && (this.flags.wronly || this.flags.rdwr)) {
|
|
544
|
+
// [O_APPEND]: every write goes to the end of the file, regardless of the
|
|
545
|
+
// current offset (which may have been moved by [seek]).
|
|
546
|
+
if (this.flags.append) this.offset = this.file.length();
|
|
547
|
+
var offset = this.offset;
|
|
548
|
+
len = this.file.write(offset, buf, pos, len);
|
|
549
|
+
this.offset += len;
|
|
550
|
+
return len;
|
|
551
|
+
}
|
|
552
|
+
this.err_closed("write", raise_unix);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
read(buf, pos, len, raise_unix) {
|
|
556
|
+
if (this.file && !this.flags.wronly) {
|
|
557
|
+
var offset = this.offset;
|
|
558
|
+
len = this.file.read(offset, buf, pos, len);
|
|
559
|
+
this.offset += len;
|
|
560
|
+
return len;
|
|
561
|
+
}
|
|
562
|
+
this.err_closed("read", raise_unix);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
seek(offset, whence, raise_unix) {
|
|
566
|
+
switch (whence) {
|
|
567
|
+
case 0:
|
|
568
|
+
break;
|
|
569
|
+
case 1:
|
|
570
|
+
offset += this.offset;
|
|
571
|
+
break;
|
|
572
|
+
case 2:
|
|
573
|
+
offset += this.length();
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
if (offset < 0)
|
|
577
|
+
caml_raise_system_error(
|
|
578
|
+
raise_unix,
|
|
579
|
+
"EINVAL",
|
|
580
|
+
"lseek",
|
|
581
|
+
"invalid argument",
|
|
582
|
+
);
|
|
583
|
+
this.offset = offset;
|
|
584
|
+
this.seeked = true;
|
|
585
|
+
return offset;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
pos() {
|
|
589
|
+
return this.offset;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
close(raise_unix) {
|
|
593
|
+
if (!this.file) this.err_closed("close", raise_unix);
|
|
594
|
+
this.file = undefined;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
check_stream_semantics(cmd) {
|
|
598
|
+
if (!this.file) return this.err_closed(cmd, /* raise Unix_error */ 1);
|
|
599
|
+
}
|
|
600
|
+
}
|