diff --git a/manifest.scm b/manifest.scm index 21af7ff..1049c6d 100644 --- a/manifest.scm +++ b/manifest.scm @@ -5,4 +5,21 @@ (gnu packages guile) (gnu packages guile-xyz)) -(packages->manifest (list guile-next guile-hoot gnu-make zip)) +(define guile-hoot* + (let ((commit "61c072433020d7669c7edaf18803d790bf984a03")) + (package + (inherit guile-hoot) + (version (string-append (package-version guile-hoot) + "-1." (string-take commit 7))) + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://gitlab.com/spritely/guile-hoot.git") + (commit commit))) + (sha256 + (base32 + "0isx20rk92xlhcc5spbbxzs2dgmqcsjzsm82iri195894ir59f4f")))) + (arguments + '(#:tests? #f))))) + +(packages->manifest (list guile-next guile-hoot* gnu-make zip)) diff --git a/reflect.js b/reflect.js index af6b0da..24a92fe 100644 --- a/reflect.js +++ b/reflect.js @@ -5,6 +5,8 @@ class Char { } toString() { let ch = String.fromCodePoint(this.codepoint); + if (ch == '\n') return '#\\newline'; + if (ch == '\r') return '#\\return'; if (ch.match(/[a-zA-Z0-9$[\]().]/)) return `#\\${ch}`; return `#\\x${this.codepoint.toString(16)}`; } @@ -137,6 +139,7 @@ class WeakTable extends HeapObject { toString() { return "#"; } } class Fluid extends HeapObject { toString() { return "#"; } } class DynamicState extends HeapObject { toString() { return "#"; } } class Syntax extends HeapObject { toString() { return "#"; } } +class SyntaxTransformer extends HeapObject { toString() { return "#"; } } class Port extends HeapObject { toString() { return "#"; } } class Struct extends HeapObject { toString() { return "#"; } } @@ -200,123 +203,6 @@ class IterableWeakSet { } } -// See: -// https://github.com/tc39/proposal-weakrefs?tab=readme-ov-file#iterable-weakmaps -class IterableWeakMap { - #weakMap = new WeakMap(); - #refSet = new Set(); - #finalizationGroup = new FinalizationRegistry(IterableWeakMap.#cleanup); - - static #cleanup({ set, ref }) { - set.delete(ref); - } - - constructor(iterable) { - for (const [key, value] of iterable) { - this.set(key, value); - } - } - - set(key, value) { - const ref = new WeakRef(key); - - this.#weakMap.set(key, { value, ref }); - this.#refSet.add(ref); - this.#finalizationGroup.register(key, { - set: this.#refSet, - ref - }, ref); - } - - get(key) { - const entry = this.#weakMap.get(key); - return entry && entry.value; - } - - delete(key) { - const entry = this.#weakMap.get(key); - if (!entry) { - return false; - } - - this.#weakMap.delete(key); - this.#refSet.delete(entry.ref); - this.#finalizationGroup.unregister(entry.ref); - return true; - } - - *[Symbol.iterator]() { - for (const ref of this.#refSet) { - const key = ref.deref(); - if (!key) continue; - const { value } = this.#weakMap.get(key); - yield [key, value]; - } - } - - entries() { - return this[Symbol.iterator](); - } - - *keys() { - for (const [key, value] of this) { - yield key; - } - } - - *values() { - for (const [key, value] of this) { - yield value; - } - } -} -// class IterableWeakMap { -// #array; -// #map; -// constructor() { this.#array = []; this.#map = new WeakMap; } -// #kill(i) { -// let tail = this.#array.pop(); -// if (i < this.#array.length) -// this.#array[i] = tail; -// } -// #geti(i) { -// // If a dead weak ref is at i then kill it and try again with -// // the next weak ref. -// while (true) { -// if (i >= this.#array.length) -// return null; -// let obj = this.#array[i].deref(); -// if (obj) -// return obj; -// this.#kill(i); -// } -// } -// #cleanup() { -// let i = 0; -// while (this.#get(i)) i++; -// } -// has(k) { return this.#map.has(k); } -// get(k) { return this.#map.get(k); } -// set(k, v) { -// if (this.#array.length % 32 == 0) -// this.#cleanup(); -// this.#map.set(k, v); -// this.#array.push(new WeakRef(k)); -// } -// delete(k) { -// if (!this.has(k)) -// return; -// this.#map.delete(k); -// let i = 0; -// while (this.#geti(i) != k) i++; -// this.#kill(i); -// } -// *[Symbol.iterator]() { -// for (let i = 0, k; k = this.#geti(i); i++) -// yield [k, this.get(k)]; -// } -// } - class Scheme { #instance; #abi; @@ -362,6 +248,22 @@ class Scheme { }; } }); + mod.set_finalization_handler({ + make_finalization_registry: (f) => new FinalizationRegistry(f), + finalization_registry_register: (registry, target, heldValue) => { + // heldValue is a Wasm struct and needs to be wrapped + // so that when it goes back to Scheme via the + // finalizer callback it is seen as a Scheme value and + // not an external one. + registry.register(target, this.#to_js(heldValue)); + }, + finalization_registry_register_with_token: (registry, target, heldValue, unregisterToken) => { + registry.register(target, this.#to_js(heldValue), unregisterToken); + }, + finalization_registry_unregister: (registry, unregisterToken) => { + return registry.unregister(unregisterToken); + } + }); let proc = new Procedure(this, mod.get_export('$load').value); return proc.call(); } @@ -447,6 +349,7 @@ class Scheme { fluid: () => new Fluid(this, scm), 'dynamic-state': () => new DynamicState(this, scm), syntax: () => new Syntax(this, scm), + 'syntax-transformer': () => new SyntaxTransformer(this, scm), port: () => new Port(this, scm), struct: () => new Struct(this, scm), 'extern-ref': () => api.extern_value(scm) @@ -601,6 +504,7 @@ class SchemeModule { #io_handler; #debug_handler; #ffi_handler; + #finalization_handler; static #rt = { bignum_from_string(str) { return BigInt(str); }, bignum_from_i32(n) { return BigInt(n); }, @@ -676,14 +580,6 @@ class SchemeModule { weak_map_set(map, k, v) { return map.set(k, v); }, weak_map_delete(map, k) { return map.delete(k); }, - make_finalization_registry(f) { return new FinalizationRegistry(f); }, - finalization_registry_register(registry, target, heldValue, unregisterToken) { - registry.register(target, heldValue, unregisterToken); - }, - finalization_registry_unregister(registry, unregisterToken) { - registry.unregister(unregisterToken); - }, - fsqrt: Math.sqrt, fsin: Math.sin, fcos: Math.cos, @@ -979,9 +875,23 @@ class SchemeModule { return mod.#ffi_handler.procedure_to_extern(proc); } }; + let finalization = { + make_finalization_registry(f) { + return mod.#finalization_handler.make_finalization_registry(f); + }, + finalization_registry_register(registry, target, heldValue) { + mod.#finalization_handler.finalization_registry_register(registry, target, heldValue); + }, + finalization_registry_register_with_token(registry, target, heldValue, unregisterToken) { + mod.#finalization_handler.finalization_registry_register_with_token(registry, target, heldValue, unregisterToken); + }, + finalization_registry_unregister(registry, unregisterToken) { + return mod.#finalization_handler.finalization_registry_unregister(registry, unregisterToken); + } + }; let imports = { rt: SchemeModule.#rt, - abi, debug, io, ffi, ...user_imports + abi, debug, io, ffi, finalization, ...user_imports }; let { module, instance } = await instantiate_streaming(path, imports); let mod = new SchemeModule(instance); @@ -990,6 +900,7 @@ class SchemeModule { set_io_handler(h) { this.#io_handler = h; } set_debug_handler(h) { this.#debug_handler = h; } set_ffi_handler(h) { this.#ffi_handler = h; } + set_finalization_handler(h) { this.#finalization_handler = h; } all_exports() { return this.#instance.exports; } exported_abi() { let abi = {} diff --git a/reflect.wasm b/reflect.wasm index 2513e8c..a4d85c5 100644 Binary files a/reflect.wasm and b/reflect.wasm differ