Use latest hoot.

This commit is contained in:
David Thompson 2024-05-17 15:39:29 -04:00
parent 0279623e2a
commit 7d728559d0
5 changed files with 74 additions and 27 deletions

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script type="text/javascript" src="js-runtime/reflect.js"></script> <script type="text/javascript" src="reflect.js"></script>
<script type="text/javascript" src="game.js"></script> <script type="text/javascript" src="game.js"></script>
<link rel="stylesheet" href="game.css" /> <link rel="stylesheet" href="game.css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

View file

@ -1,7 +1,28 @@
(use-modules (guix packages) (use-modules (guix git-download)
(guix packages)
(gnu packages autotools)
(gnu packages base) (gnu packages base)
(gnu packages compression) (gnu packages compression)
(gnu packages guile) (gnu packages guile)
(gnu packages guile-xyz)) (gnu packages guile-xyz)
(gnu packages pkg-config)
(gnu packages texinfo))
(packages->manifest (list guile-next guile-hoot gnu-make zip)) (define guile-hoot-next
(let ((commit "bdc355d97a88b1337c14d3155ce83fe699b405ac")
(revision "1"))
(package
(inherit guile-hoot)
(version (git-version "0.4.1" revision commit))
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://gitlab.com/spritely/guile-hoot.git")
(commit commit)))
(file-name (git-file-name "guile-hoot" version))
(sha256
(base32 "0p18zy505flacvqi4r2xp42gljnpq86fydvw2k154aw89chhkc32"))))
(native-inputs
(list autoconf automake pkg-config texinfo)))))
(packages->manifest (list guile-next guile-hoot-next gnu-make zip))

View file

@ -115,6 +115,9 @@ class Procedure extends HeapObject {
call(...arg) { call(...arg) {
return this.reflector.call(this, ...arg); return this.reflector.call(this, ...arg);
} }
async call_async(...arg) {
return await this.reflector.call_async(this, ...arg);
}
} }
class Sym extends HeapObject { class Sym extends HeapObject {
@ -160,7 +163,7 @@ class Scheme {
this.#abi = abi; this.#abi = abi;
} }
static async reflect(abi) { static async reflect(abi, {reflect_wasm_dir = '.'}) {
let debug = { let debug = {
debug_str(x) { console.log(`reflect debug: ${x}`); }, debug_str(x) { console.log(`reflect debug: ${x}`); },
debug_str_i32(x, y) { console.log(`reflect debug: ${x}: ${y}`); }, debug_str_i32(x, y) { console.log(`reflect debug: ${x}: ${y}`); },
@ -168,16 +171,14 @@ class Scheme {
console.log(`reflect debug: ${x}: #<scm>`); console.log(`reflect debug: ${x}: #<scm>`);
}, },
}; };
let reflect_wasm = reflect_wasm_dir + '/reflect.wasm';
let rt = {
die(tag, data) { throw new SchemeTrapError(tag, data); },
wtf8_to_string(wtf8) { return wtf8_to_string(wtf8); },
string_to_wtf8(str) { return string_to_wtf8(str); },
};
let { module, instance } = let { module, instance } =
await instantiate_streaming('js-runtime/reflect.wasm', { await instantiate_streaming(reflect_wasm, { abi, debug, rt });
abi,
debug,
rt: {
die(tag, data) { throw new SchemeTrapError(tag, data); },
wtf8_to_string(wtf8) { return wtf8_to_string(wtf8); },
string_to_wtf8(str) { return string_to_wtf8(str); },
}
});
return new Scheme(instance, abi); return new Scheme(instance, abi);
} }
@ -200,13 +201,14 @@ class Scheme {
let proc = new Procedure(this, mod.get_export('$load').value); let proc = new Procedure(this, mod.get_export('$load').value);
return proc.call(); return proc.call();
} }
static async load_main(path, abi, user_imports = {}) { static async load_main(path, opts = {}) {
let mod = await SchemeModule.fetch_and_instantiate(path, abi, user_imports); let mod = await SchemeModule.fetch_and_instantiate(path, opts);
let reflect = await mod.reflect(); let reflect = await mod.reflect(opts);
return reflect.#init_module(mod); return reflect.#init_module(mod);
} }
async load_extension(path, user_imports = {}) { async load_extension(path, opts = {}) {
let mod = await SchemeModule.fetch_and_instantiate(path, this.#abi, user_imports); opts = Object.assign({ abi: this.#abi }, opts);
let mod = await SchemeModule.fetch_and_instantiate(path, opts);
return this.#init_module(mod); return this.#init_module(mod);
} }
@ -236,6 +238,8 @@ class Scheme {
if (js instanceof Complex) if (js instanceof Complex)
return api.scm_from_complex(js.real, js.imag); return api.scm_from_complex(js.real, js.imag);
return api.scm_from_extern(js); return api.scm_from_extern(js);
} else if (typeof(js) == 'function') {
return api.scm_from_extern(js);
} else { } else {
throw new Error(`unexpected; ${typeof(js)}`); throw new Error(`unexpected; ${typeof(js)}`);
} }
@ -301,6 +305,15 @@ class Scheme {
return results; return results;
} }
call_async(func, ...args) {
return new Promise((resolve, reject) => {
this.call(func,
val => resolve(this.#to_js(val)),
err => reject(this.#to_js(err)),
...args);
})
}
car(x) { return this.#to_js(this.#instance.exports.car(x.obj)); } car(x) { return this.#to_js(this.#instance.exports.car(x.obj)); }
cdr(x) { return this.#to_js(this.#instance.exports.cdr(x.obj)); } cdr(x) { return this.#to_js(this.#instance.exports.cdr(x.obj)); }
@ -353,6 +366,13 @@ function flonum_to_string(f64) {
} }
} }
let async_invoke = typeof queueMicrotask !== 'undefined'
? queueMicrotask
: thunk => setTimeout(thunk, 0);
function async_invoke_later(thunk, jiffies) {
setTimeout(thunk, jiffies / 1000);
}
let wtf8_helper; let wtf8_helper;
function wtf8_to_string(wtf8) { function wtf8_to_string(wtf8) {
@ -388,9 +408,10 @@ function string_to_wtf8(str) {
return finish_builder(builder); return finish_builder(builder);
} }
async function load_wtf8_helper_module() { async function load_wtf8_helper_module(reflect_wasm_dir = '') {
if (wtf8_helper) return; if (wtf8_helper) return;
let { module, instance } = await instantiate_streaming("js-runtime/wtf8.wasm"); let wtf8_wasm = reflect_wasm_dir + "/wtf8.wasm";
let { module, instance } = await instantiate_streaming(wtf8_wasm);
wtf8_helper = instance; wtf8_helper = instance;
} }
@ -487,6 +508,11 @@ class SchemeModule {
current_jiffy() { return performance.now() * 1000; }, current_jiffy() { return performance.now() * 1000; },
current_second() { return Date.now() / 1000; }, current_second() { return Date.now() / 1000; },
async_invoke,
async_invoke_later,
promise_on_completed(p, kt, kf) { p.then(kt, kf); },
promise_complete(callback, val) { callback(val); },
// Wrap in functions to allow for lazy loading of the wtf8 // Wrap in functions to allow for lazy loading of the wtf8
// module. // module.
wtf8_to_string(wtf8) { return wtf8_to_string(wtf8); }, wtf8_to_string(wtf8) { return wtf8_to_string(wtf8); },
@ -629,8 +655,9 @@ class SchemeModule {
debug_str_scm(x, y) { console.log(`debug: ${x}: #<scm>`); }, debug_str_scm(x, y) { console.log(`debug: ${x}: #<scm>`); },
}; };
} }
static async fetch_and_instantiate(path, imported_abi, user_imports = {}) { static async fetch_and_instantiate(path, { abi, reflect_wasm_dir = '.',
await load_wtf8_helper_module(); user_imports = {} }) {
await load_wtf8_helper_module(reflect_wasm_dir);
let io = { let io = {
write_stdout(str) { mod.#io_handler.write_stdout(str); }, write_stdout(str) { mod.#io_handler.write_stdout(str); },
write_stderr(str) { mod.#io_handler.write_stderr(str); }, write_stderr(str) { mod.#io_handler.write_stderr(str); },
@ -660,8 +687,7 @@ class SchemeModule {
}; };
let imports = { let imports = {
rt: SchemeModule.#rt, rt: SchemeModule.#rt,
abi: imported_abi, abi, debug, io, ffi, ...user_imports
debug, io, ffi, ...user_imports
}; };
let { module, instance } = await instantiate_streaming(path, imports); let { module, instance } = await instantiate_streaming(path, imports);
let mod = new SchemeModule(instance); let mod = new SchemeModule(instance);
@ -692,8 +718,8 @@ class SchemeModule {
return this.all_exports()[name]; return this.all_exports()[name];
throw new Error(`unknown export: ${name}`) throw new Error(`unknown export: ${name}`)
} }
async reflect() { async reflect(opts = {}) {
return await Scheme.reflect(this.exported_abi()); return await Scheme.reflect(this.exported_abi(), opts);
} }
} }