substrate-lang 0.10.0 → 0.10.2
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/build/compiler/{checker.4dd4556dd421@0+0.wasm → checker.1d67e1d4e91a@0+0.wasm} +0 -0
- package/build/compiler/{expander.967ce443d379@0+0.wasm → expander.34110a31a949@0+0.wasm} +0 -0
- package/build/compiler/{main.4fc52f204d54@0+0.wasm → main.ca9b5089c24d@0+0.wasm} +0 -0
- package/build/compiler/program +4 -4
- package/build/compiler/{roots.cefd10e93684@0+0.wasm → roots.2f1ad1a79459@0+0.wasm} +0 -0
- package/build/sub/{build.459c5b9412bd@0+0.wasm → build.eef7dfa467ec@0+0.wasm} +0 -0
- package/build/sub/{common.1edc613607a0@0+0.wasm → common.7617940db2dc@0+0.wasm} +0 -0
- package/build/sub/deflate.23f7c4679260@0+0.wasm +0 -0
- package/build/sub/{doc.0775df5de6fe@0+0.wasm → doc.92d6d82d99c1@0+0.wasm} +0 -0
- package/build/sub/{doc.ef9965d5d402@0+0.wasm → doc.dab689b811ca@0+0.wasm} +0 -0
- package/build/sub/{fetch.96b2d10f025e@0+0.wasm → fetch.3367ff4f88c0@0+0.wasm} +0 -0
- package/build/sub/{files.ad0469fdf6fa@0+0.wasm → files.5ae9d3cebeca@0+0.wasm} +0 -0
- package/build/sub/gzip.16e372eda1cf@0+0.wasm +0 -0
- package/build/sub/{hash.660682e4f491@0+0.wasm → hash.c57c141b4862@0+0.wasm} +0 -0
- package/build/sub/{html.a23126eb949a@0+0.wasm → html.803f73c35c4a@0+0.wasm} +0 -0
- package/build/sub/{manifest.ef317480deb0@0+0.wasm → manifest.da52a88c7af7@0+0.wasm} +0 -0
- package/build/sub/{map.f455cca6a42a@0+0.wasm → map.5c8084999550@0+0.wasm} +0 -0
- package/build/sub/program +22 -22
- package/build/sub/{root.f10a4906f460@0+0.wasm → root.78253db36643@0+0.wasm} +0 -0
- package/build/sub/{roots.cefd10e93684@0+0.wasm → roots.2f1ad1a79459@0+0.wasm} +0 -0
- package/build/sub/sha256.a6c32b04d799@0+0.wasm +0 -0
- package/build/sub/site.47fd989be8fb@0+0.wasm +0 -0
- package/build/sub/site.c908b1f6db12@0+0.wasm +0 -0
- package/build/sub/{store.a24d7a25daa6@0+0.wasm → store.048c77bb124d@0+0.wasm} +0 -0
- package/build/sub/sub.a618f89f2ec8@0+0.wasm +0 -0
- package/build/sub/{test.9bd59c73f65e@0+0.wasm → test.b529bf52ba3e@0+0.wasm} +0 -0
- package/build/sub/{text.1bc90482bd43@0+0.wasm → text.b214933a4984@0+0.wasm} +0 -0
- package/build/sub/{upgrade.39ee449b00d5@0+0.wasm → upgrade.7ec5651ed2e9@0+0.wasm} +0 -0
- package/package.json +1 -1
- package/std/http/server.sub +7 -7
- package/std/http/static.sub +66 -30
- package/std/package/manifest.sub +9 -4
- package/std/package/site.sub +209 -15
- package/std/package.sub +4 -3
- package/std/test/browser.sub +20 -14
- package/std/test/build.sub +8 -6
- package/std/test/page/agent.mjs +8 -2
- package/std/web/canvas.sub +4 -4
- package/std/web/dom.sub +45 -11
- package/std/web/gpu-commands.sub +439 -0
- package/std/web/gpu.sub +17 -424
- package/std/web/patches.sub +53 -18
- package/substrate/VERSION +1 -1
- package/substrate/compiler/expander.sub +2 -3
- package/substrate/compiler/roots.sub +12 -5
- package/substrate/host/grants.mjs +3 -3
- package/substrate/host/node/net.mjs +17 -2
- package/substrate/host/node/worker.mjs +3 -1
- package/substrate/host/subhost.mjs +4 -1
- package/substrate/host/web/audio.mjs +18 -10
- package/substrate/host/web/audio.sub +9 -3
- package/substrate/host/web/dom.mjs +167 -66
- package/substrate/host/web/dom.sub +9 -27
- package/substrate/host/web/fs.mjs +3 -3
- package/substrate/host/web/gpu.mjs +65 -27
- package/substrate/host/web/gpu.sub +18 -4
- package/substrate/host/web/location.mjs +15 -1
- package/substrate/host/web/location.sub +11 -3
- package/substrate/host/web/start.mjs +11 -7
- package/substrate/host/web/subhost-web.mjs +54 -33
- package/substrate/host/web/worker-script.mjs +4 -4
- package/substrate/host/web/worker.mjs +4 -4
- package/substrate/host/worker.mjs +1 -1
- package/build/sub/site.1732b58ec0e8@0+0.wasm +0 -0
- package/build/sub/site.ae3913b0b0f4@0+0.wasm +0 -0
- package/build/sub/sub.2e3092140706@0+0.wasm +0 -0
|
@@ -42,7 +42,10 @@ try {
|
|
|
42
42
|
if (request.inherit.size > 0) fail('inherit is only for workers');
|
|
43
43
|
setup.grants = joinedGrants(setup.grants, request.grants);
|
|
44
44
|
for (const [name, at] of request.fakes) setup.fakes.set(name, at);
|
|
45
|
-
if (request.tls)
|
|
45
|
+
if (request.tls) {
|
|
46
|
+
const files = [request.tls.cert, request.tls.key];
|
|
47
|
+
setup.tls = { cert: read(files[0]), key: read(files[1]), files };
|
|
48
|
+
}
|
|
46
49
|
} catch (e) {
|
|
47
50
|
fail(e.message);
|
|
48
51
|
}
|
|
@@ -14,7 +14,13 @@ export function audio() {
|
|
|
14
14
|
let started = 0;
|
|
15
15
|
|
|
16
16
|
const sounds = new Map();
|
|
17
|
-
let
|
|
17
|
+
let nextSound = 1;
|
|
18
|
+
const loading = new Map();
|
|
19
|
+
const counted = (tag, n) => {
|
|
20
|
+
const k = (loading.get(tag) || 0) + n;
|
|
21
|
+
if (k === 0) loading.delete(tag);
|
|
22
|
+
else loading.set(tag, k);
|
|
23
|
+
};
|
|
18
24
|
let decoder = null;
|
|
19
25
|
|
|
20
26
|
const voices = new Map();
|
|
@@ -60,35 +66,37 @@ export function audio() {
|
|
|
60
66
|
|
|
61
67
|
const module = (caller, app) => ({
|
|
62
68
|
source: SOURCE,
|
|
63
|
-
load(
|
|
69
|
+
load(ptr, length, tag) {
|
|
70
|
+
const id = nextSound++;
|
|
64
71
|
const name = caller.string(ptr, length);
|
|
65
72
|
const bytes = app.files.get(resolvePath(app.cwd, name));
|
|
66
73
|
if (!decoder) decoder = new OfflineAudioContext(1, 1, 44100);
|
|
67
|
-
|
|
74
|
+
counted(tag, 1);
|
|
68
75
|
const data = bytes
|
|
69
76
|
? Promise.resolve(bytes.slice().buffer)
|
|
70
|
-
: fetch(name).then((response) => {
|
|
77
|
+
: fetch(app.url(name)).then((response) => {
|
|
71
78
|
if (!response.ok) throw new Error(`the server answered ${response.status}`);
|
|
72
79
|
return response.arrayBuffer();
|
|
73
80
|
});
|
|
74
81
|
data.then((buffer) => decoder.decodeAudioData(buffer)).then(
|
|
75
82
|
(decoded) => {
|
|
76
83
|
sounds.set(id, decoded);
|
|
77
|
-
|
|
84
|
+
counted(tag, -1);
|
|
78
85
|
startWaiting();
|
|
79
|
-
caller.event(LOADED, id,
|
|
86
|
+
caller.event(LOADED, id, tag, 0);
|
|
80
87
|
},
|
|
81
88
|
(e) => {
|
|
82
89
|
console.error(`audio: cannot load the sound ${name}: ${e.message}`);
|
|
83
|
-
|
|
90
|
+
counted(tag, -1);
|
|
84
91
|
startWaiting();
|
|
85
|
-
caller.event(FAILED, id,
|
|
92
|
+
caller.event(FAILED, id, tag, e.name === 'EncodingError' ? errors.invalid : errors.missing,
|
|
86
93
|
utf8.encode(`cannot load the sound ${name}: ${e.message}`));
|
|
87
94
|
},
|
|
88
95
|
);
|
|
96
|
+
return id;
|
|
89
97
|
},
|
|
90
|
-
loading() {
|
|
91
|
-
return loading;
|
|
98
|
+
loading(tag) {
|
|
99
|
+
return loading.get(tag) || 0;
|
|
92
100
|
},
|
|
93
101
|
play(id, volume, rate, loop) {
|
|
94
102
|
played++;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
;; Sound: the host module "audio".
|
|
1
|
+
;; Sound: the host module "audio". audio-load gives the sound's number, and its loaded or failed event goes to tag.
|
|
2
|
+
;; audio-loading counts the sounds loading for a tag.
|
|
2
3
|
(provide audio-source audio-loaded audio-failed audio-tone audio-load audio-loading audio-play audio-stop)
|
|
3
4
|
|
|
4
5
|
(const audio-source u32 4)
|
|
@@ -6,7 +7,12 @@
|
|
|
6
7
|
(const audio-failed u32 2)
|
|
7
8
|
|
|
8
9
|
(import audio-tone "audio" "tone" (i32 f64 f64 f64 f64 ->))
|
|
9
|
-
(import
|
|
10
|
-
(import
|
|
10
|
+
(import load "audio" "load" (i32 i32 i32 -> i32))
|
|
11
|
+
(import loading "audio" "loading" (i32 -> i32))
|
|
11
12
|
(import audio-play "audio" "play" (i32 f64 f64 i32 -> i32))
|
|
12
13
|
(import audio-stop "audio" "stop" (i32 ->))
|
|
14
|
+
|
|
15
|
+
(define (audio-load [path string] [tag (ptr void)]) -> u32
|
|
16
|
+
(cast u32 (load (cast i32 (-> path bytes)) (cast i32 (-> path length)) (cast i32 tag))))
|
|
17
|
+
|
|
18
|
+
(define (audio-loading [tag (ptr void)]) -> u32 (cast u32 (loading (cast i32 tag))))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The host module "dom": applies a program's patches to the
|
|
1
|
+
// The host module "dom": applies a program's patches to the document, and sends it the document's events.
|
|
2
2
|
import { resolvePath } from './fs.mjs';
|
|
3
3
|
import { errors } from '../errors.mjs';
|
|
4
4
|
|
|
@@ -10,6 +10,9 @@ const HEARD = 1;
|
|
|
10
10
|
const IMAGE_LOADED = 2;
|
|
11
11
|
const IMAGE_FAILED = 3;
|
|
12
12
|
|
|
13
|
+
// The document's node number (std/web/patches.sub).
|
|
14
|
+
const DOCUMENT = 1;
|
|
15
|
+
|
|
13
16
|
const imageTypes = {
|
|
14
17
|
png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp',
|
|
15
18
|
avif: 'image/avif', bmp: 'image/bmp', svg: 'image/svg+xml',
|
|
@@ -17,9 +20,14 @@ const imageTypes = {
|
|
|
17
20
|
|
|
18
21
|
export function dom(root) {
|
|
19
22
|
const templates = new Map();
|
|
20
|
-
const nodes = new Map([[0, root]]);
|
|
23
|
+
const nodes = new Map([[0, root], [DOCUMENT, root.ownerDocument]]);
|
|
21
24
|
const images = new Map();
|
|
22
|
-
|
|
25
|
+
const loading = new Map();
|
|
26
|
+
const counted = (tag, n) => {
|
|
27
|
+
const k = (loading.get(tag) || 0) + n;
|
|
28
|
+
if (k === 0) loading.delete(tag);
|
|
29
|
+
else loading.set(tag, k);
|
|
30
|
+
};
|
|
23
31
|
let app = null;
|
|
24
32
|
let caller = null;
|
|
25
33
|
|
|
@@ -30,6 +38,73 @@ export function dom(root) {
|
|
|
30
38
|
return e && e.source === SOURCE ? e.data : null;
|
|
31
39
|
};
|
|
32
40
|
|
|
41
|
+
const kinds = ['Node', 'Event', 'NodeList', 'HTMLCollection', 'DOMRectReadOnly', 'DOMTokenList',
|
|
42
|
+
'CSSStyleDeclaration', 'DOMStringMap', 'ValidityState', 'FileList', 'Blob', 'DataTransfer', 'TouchList', 'Touch',
|
|
43
|
+
'IntersectionObserverEntry'].map((name) => globalThis[name]).filter((kind) => kind !== undefined);
|
|
44
|
+
const reachable = (x) => kinds.some((kind) => x instanceof kind);
|
|
45
|
+
|
|
46
|
+
function guarded(path, f) {
|
|
47
|
+
try {
|
|
48
|
+
return f();
|
|
49
|
+
} catch (e) {
|
|
50
|
+
caller.trap(`dom: ${path}: ${e.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function step(x, name, path) {
|
|
55
|
+
if (!(name in Object(x))) caller.trap(`dom: ${path}: there is no ${name}`);
|
|
56
|
+
return guarded(path, () => x[name]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function owner(root, path) {
|
|
60
|
+
const parts = path.split('.');
|
|
61
|
+
const last = parts.pop();
|
|
62
|
+
let x = root;
|
|
63
|
+
for (let k = 0; k < parts.length; k++) {
|
|
64
|
+
x = step(x, parts[k], path);
|
|
65
|
+
if (x === null || x === undefined) return [null, last];
|
|
66
|
+
if (!reachable(x)) {
|
|
67
|
+
caller.trap(`dom: ${path}: ${parts.slice(0, k + 1).join('.')} is not one of the document's objects`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [x, last];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function walk(root, path) {
|
|
74
|
+
const [x, last] = owner(root, path);
|
|
75
|
+
return x === null ? null : step(x, last, path);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function read(root, path) {
|
|
79
|
+
const v = walk(root, path);
|
|
80
|
+
const plain = v === null || v === undefined || ['number', 'string', 'boolean'].includes(typeof v);
|
|
81
|
+
if (!plain) caller.trap(`dom: ${path} is not a number, text, or true or false`);
|
|
82
|
+
return v;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function write(root, path, value) {
|
|
86
|
+
const [x, last] = owner(root, path);
|
|
87
|
+
if (x === null || !(last in x)) caller.trap(`dom: ${path}: there is no ${last} to set`);
|
|
88
|
+
guarded(path, () => { x[last] = value; });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function call(root, path, args) {
|
|
92
|
+
const [x, last] = owner(root, path);
|
|
93
|
+
if (x === null || typeof x[last] !== 'function') caller.trap(`dom: ${path} is not a method`);
|
|
94
|
+
const result = guarded(path, () => x[last](...args));
|
|
95
|
+
if (result && typeof result.catch === 'function') result.catch(() => {});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const numberOf = (v) => (v === null || v === undefined ? 0 : Number(v));
|
|
99
|
+
const textOf = (v) => (v === null || v === undefined ? '' : String(v));
|
|
100
|
+
|
|
101
|
+
const bits = new DataView(new ArrayBuffer(8));
|
|
102
|
+
const float64 = (low, high) => {
|
|
103
|
+
bits.setUint32(0, low, true);
|
|
104
|
+
bits.setUint32(4, high, true);
|
|
105
|
+
return bits.getFloat64(0, true);
|
|
106
|
+
};
|
|
107
|
+
|
|
33
108
|
const listener = (e) => {
|
|
34
109
|
const messages = e.currentTarget.subListeners;
|
|
35
110
|
if (messages && e.type in messages) give(e, messages[e.type]);
|
|
@@ -66,12 +141,27 @@ export function dom(root) {
|
|
|
66
141
|
|
|
67
142
|
const windowTarget = (type) => (type === 'pointerlockchange' || type === 'pointerlockerror' ? document : window);
|
|
68
143
|
|
|
144
|
+
const watched = new Map();
|
|
145
|
+
let observer = null;
|
|
146
|
+
|
|
147
|
+
function watch(node, message) {
|
|
148
|
+
observer ||= new IntersectionObserver((entries) => {
|
|
149
|
+
for (const entry of entries) if (watched.has(entry.target)) give(entry, watched.get(entry.target));
|
|
150
|
+
});
|
|
151
|
+
watched.set(node, message);
|
|
152
|
+
observer.observe(node);
|
|
153
|
+
}
|
|
154
|
+
|
|
69
155
|
const unlisten = (id) => {
|
|
70
156
|
const n = nodes.get(id);
|
|
71
157
|
if (n instanceof Node && n.subListeners) {
|
|
72
158
|
for (const message of Object.values(n.subListeners)) caller.forget(message);
|
|
73
159
|
n.subListeners = null;
|
|
74
160
|
}
|
|
161
|
+
if (watched.has(n)) {
|
|
162
|
+
observer.unobserve(n);
|
|
163
|
+
watched.delete(n);
|
|
164
|
+
}
|
|
75
165
|
for (const { type, message, handler } of windowListeners.get(id) || []) {
|
|
76
166
|
windowTarget(type).removeEventListener(type, handler);
|
|
77
167
|
caller.forget(message);
|
|
@@ -260,68 +350,75 @@ export function dom(root) {
|
|
|
260
350
|
const node = nodes.get(w[i + 1]);
|
|
261
351
|
const type = string(i + 2);
|
|
262
352
|
(node.subListeners ||= {})[type] = w[i + 4];
|
|
263
|
-
|
|
353
|
+
if (type === 'visibility') watch(node, w[i + 4]);
|
|
354
|
+
else node.addEventListener(type, listener);
|
|
264
355
|
i += 5;
|
|
265
356
|
break;
|
|
266
357
|
}
|
|
267
|
-
case 10:
|
|
268
|
-
const node = nodes.get(w[i + 1]);
|
|
269
|
-
after.push(() => node.focus());
|
|
270
|
-
i += 2;
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
case 11: {
|
|
274
|
-
const node = nodes.get(w[i + 1]);
|
|
275
|
-
after.push(() => { node.scrollTop = node.scrollHeight; });
|
|
276
|
-
i += 2;
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
case 12:
|
|
358
|
+
case 10:
|
|
280
359
|
listenWindow(w[i + 1], string(i + 2), w[i + 4]);
|
|
281
360
|
i += 5;
|
|
282
361
|
break;
|
|
283
|
-
case
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
i += 3;
|
|
362
|
+
case 11: {
|
|
363
|
+
const canvas = nodes.get(w[i + 1]);
|
|
364
|
+
const count = w[i + 2];
|
|
365
|
+
const f = new Float32Array(w.buffer, w.byteOffset, w.length);
|
|
366
|
+
draw(canvas.getContext('2d'), w, f, i + 3, i + 3 + count, string);
|
|
367
|
+
i += 3 + count;
|
|
291
368
|
break;
|
|
292
369
|
}
|
|
293
|
-
case
|
|
370
|
+
case 12: {
|
|
294
371
|
const name = string(i + 2);
|
|
295
372
|
const image = new Image();
|
|
296
373
|
const bytes = app.files.get(resolvePath(app.cwd, name));
|
|
297
374
|
const type = imageTypes[name.slice(name.lastIndexOf('.') + 1).toLowerCase()] || '';
|
|
298
|
-
const url = bytes ? URL.createObjectURL(new Blob([bytes], { type })) : name;
|
|
375
|
+
const url = bytes ? URL.createObjectURL(new Blob([bytes], { type })) : app.url(name);
|
|
299
376
|
const id = w[i + 1];
|
|
377
|
+
const tag = w[i + 4];
|
|
300
378
|
const finished = () => {
|
|
301
|
-
|
|
379
|
+
counted(tag, -1);
|
|
302
380
|
if (bytes) URL.revokeObjectURL(url);
|
|
303
381
|
};
|
|
304
|
-
|
|
382
|
+
counted(tag, 1);
|
|
305
383
|
image.onload = () => {
|
|
306
384
|
finished();
|
|
307
|
-
caller.event(IMAGE_LOADED, id,
|
|
385
|
+
caller.event(IMAGE_LOADED, id, tag, 0);
|
|
308
386
|
};
|
|
309
387
|
image.onerror = () => {
|
|
310
388
|
finished();
|
|
311
389
|
console.error(`dom: cannot load the image ${name}`);
|
|
312
|
-
caller.event(IMAGE_FAILED, id,
|
|
390
|
+
caller.event(IMAGE_FAILED, id, tag, errors.missing, utf8.encode(`cannot load the image ${name}`));
|
|
313
391
|
};
|
|
314
392
|
image.src = url;
|
|
315
393
|
images.set(w[i + 1], image);
|
|
316
|
-
i +=
|
|
394
|
+
i += 5;
|
|
317
395
|
break;
|
|
318
396
|
}
|
|
319
397
|
case 13: {
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
398
|
+
const style = document.createElement('style');
|
|
399
|
+
style.textContent = string(i + 1);
|
|
400
|
+
root.ownerDocument.head.appendChild(style);
|
|
401
|
+
i += 3;
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
case 14: {
|
|
405
|
+
const node = nodeOf(w[i + 1]);
|
|
406
|
+
const path = string(i + 2);
|
|
407
|
+
const value = w[i + 4] === 0 ? float64(w[i + 5], w[i + 6]) : string(i + 5);
|
|
408
|
+
after.push(() => write(node, path, value));
|
|
409
|
+
i += 7;
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
case 15: {
|
|
413
|
+
const node = nodeOf(w[i + 1]);
|
|
414
|
+
const path = string(i + 2);
|
|
415
|
+
const args = [];
|
|
416
|
+
for (let k = 0; k < w[i + 4]; k++) {
|
|
417
|
+
const at = i + 5 + 3 * k;
|
|
418
|
+
args.push(w[at] === 0 ? float64(w[at + 1], w[at + 2]) : string(at + 1));
|
|
419
|
+
}
|
|
420
|
+
after.push(() => call(node, path, args));
|
|
421
|
+
i += 5 + 3 * w[i + 4];
|
|
325
422
|
break;
|
|
326
423
|
}
|
|
327
424
|
default:
|
|
@@ -340,45 +437,49 @@ export function dom(root) {
|
|
|
340
437
|
caller = theCaller;
|
|
341
438
|
app = theApp;
|
|
342
439
|
const given = (s, out) => caller.give(utf8.encode(s), out);
|
|
440
|
+
const current = () => {
|
|
441
|
+
const e = event();
|
|
442
|
+
if (!e) caller.trap('dom: there is no current event');
|
|
443
|
+
return e;
|
|
444
|
+
};
|
|
445
|
+
const known = (id) => {
|
|
446
|
+
if (!nodes.has(id)) caller.trap(`dom: there is no node ${id}`);
|
|
447
|
+
return nodeOf(id);
|
|
448
|
+
};
|
|
343
449
|
return {
|
|
344
450
|
source: SOURCE,
|
|
345
451
|
apply(ptr, length) {
|
|
346
452
|
apply(caller.memory(), caller.u(ptr), length);
|
|
347
453
|
},
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const target = e && e.target;
|
|
351
|
-
return given(target && typeof target.value === 'string' ? target.value : '', out);
|
|
454
|
+
event_number(ptr, length) {
|
|
455
|
+
return numberOf(read(current(), caller.string(ptr, length)));
|
|
352
456
|
},
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return given(e && typeof e.key === 'string' ? e.key : '', out);
|
|
457
|
+
event_text(ptr, length, out) {
|
|
458
|
+
return given(textOf(read(current(), caller.string(ptr, length))), out);
|
|
356
459
|
},
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (!e) return 0;
|
|
360
|
-
return (e.shiftKey ? 1 : 0) | (e.ctrlKey ? 2 : 0) | (e.altKey ? 4 : 0) | (e.metaKey ? 8 : 0) |
|
|
361
|
-
(e.target && e.target.checked === true ? 16 : 0) | (document.pointerLockElement ? 32 : 0);
|
|
460
|
+
event_call(ptr, length) {
|
|
461
|
+
call(current(), caller.string(ptr, length), []);
|
|
362
462
|
},
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
463
|
+
event_is(node, ptr, length) {
|
|
464
|
+
return walk(current(), caller.string(ptr, length)) === known(node) ? 1 : 0;
|
|
465
|
+
},
|
|
466
|
+
read_number(node, ptr, length) {
|
|
467
|
+
return numberOf(read(known(node), caller.string(ptr, length)));
|
|
468
|
+
},
|
|
469
|
+
read_text(node, ptr, length, out) {
|
|
470
|
+
return given(textOf(read(known(node), caller.string(ptr, length))), out);
|
|
471
|
+
},
|
|
472
|
+
is(node, from, ptr, length) {
|
|
473
|
+
return walk(known(from), caller.string(ptr, length)) === known(node) ? 1 : 0;
|
|
375
474
|
},
|
|
376
|
-
images_loading() {
|
|
377
|
-
return loading;
|
|
475
|
+
images_loading(tag) {
|
|
476
|
+
return loading.get(tag) || 0;
|
|
378
477
|
},
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
if (
|
|
478
|
+
element(ptr, length, node) {
|
|
479
|
+
const found = root.ownerDocument.getElementById(caller.string(ptr, length));
|
|
480
|
+
if (!found) return 0;
|
|
481
|
+
nodes.set(node, found);
|
|
482
|
+
return 1;
|
|
382
483
|
},
|
|
383
484
|
};
|
|
384
485
|
};
|
|
@@ -1,34 +1,16 @@
|
|
|
1
|
-
;; The
|
|
2
|
-
;; the
|
|
3
|
-
;;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
dom-time dom-x dom-y dom-movement-x dom-movement-y dom-button
|
|
7
|
-
dom-apply dom-event-value dom-event-key dom-event-flags dom-event-number dom-prevent-default dom-images-loading)
|
|
1
|
+
;; The document: the host module "dom". A heard event carries the id and tag its listener was given. A visibility
|
|
2
|
+
;; listener hears when its element comes into the viewport or leaves it. dom-bind-element gives the element with an id a
|
|
3
|
+
;; node number, for dom-element (std/web/dom.sub). The reads of the document are in std/web/dom.sub too.
|
|
4
|
+
;; dom-images-loading counts the images loading for a tag.
|
|
5
|
+
(provide dom-source dom-heard dom-image-loaded dom-image-failed dom-apply dom-bind-element dom-images-loading)
|
|
8
6
|
|
|
9
7
|
(const dom-source u32 1)
|
|
10
8
|
(const dom-heard u32 1)
|
|
11
9
|
(const dom-image-loaded u32 2)
|
|
12
10
|
(const dom-image-failed u32 3)
|
|
13
11
|
|
|
14
|
-
(const dom-shift u32 1)
|
|
15
|
-
(const dom-control u32 2)
|
|
16
|
-
(const dom-alt u32 4)
|
|
17
|
-
(const dom-meta u32 8)
|
|
18
|
-
(const dom-checked u32 16)
|
|
19
|
-
(const dom-locked u32 32)
|
|
20
|
-
|
|
21
|
-
(const dom-time i32 0)
|
|
22
|
-
(const dom-x i32 1)
|
|
23
|
-
(const dom-y i32 2)
|
|
24
|
-
(const dom-movement-x i32 3)
|
|
25
|
-
(const dom-movement-y i32 4)
|
|
26
|
-
(const dom-button i32 5)
|
|
27
|
-
|
|
28
12
|
(import dom-apply "dom" "apply" (i32 i32 ->))
|
|
29
|
-
(import
|
|
30
|
-
(import dom-
|
|
31
|
-
|
|
32
|
-
(
|
|
33
|
-
(import dom-prevent-default "dom" "prevent_default" (->))
|
|
34
|
-
(import dom-images-loading "dom" "images_loading" (-> i32))
|
|
13
|
+
(import images-loading "dom" "images_loading" (i32 -> i32))
|
|
14
|
+
(import dom-bind-element "dom" "element" (i32 i32 i32 -> i32))
|
|
15
|
+
|
|
16
|
+
(define (dom-images-loading [tag (ptr void)]) -> u32 (cast u32 (images-loading (cast i32 tag))))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// A
|
|
2
|
-
// grants. A directory exists as long as it has a file in it, and there are no links or modes.
|
|
1
|
+
// A web program's files for fs.mjs, kept in memory under the program's working directory and checked against the
|
|
2
|
+
// program's grants. A directory exists as long as it has a file in it, and there are no links or modes.
|
|
3
3
|
import { mayPath, mayTree, pathDenied, unlimited } from '../grants.mjs';
|
|
4
4
|
import { sameFile, tempName } from '../fs.mjs';
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ const missing = () => Object.assign(new Error('No such file or directory'), { co
|
|
|
17
17
|
const unsupported = () => new Error('Operation not supported');
|
|
18
18
|
const under = (dir) => (dir === '/' ? '/' : `${dir}/`);
|
|
19
19
|
|
|
20
|
-
export function
|
|
20
|
+
export function memoryFiles(files, cwd, grants) {
|
|
21
21
|
const times = new Map();
|
|
22
22
|
const at = (k, p, tree = false) => {
|
|
23
23
|
const key = resolvePath(cwd, p);
|