summaryrefslogtreecommitdiff
path: root/js-runtime/reflect.js
diff options
context:
space:
mode:
Diffstat (limited to 'js-runtime/reflect.js')
-rw-r--r--js-runtime/reflect.js150
1 files changed, 142 insertions, 8 deletions
diff --git a/js-runtime/reflect.js b/js-runtime/reflect.js
index 5ee2928..172f187 100644
--- a/js-runtime/reflect.js
+++ b/js-runtime/reflect.js
@@ -165,6 +165,7 @@ class Scheme {
await instantiate_streaming('js-runtime/reflect.wasm', {
abi,
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); },
}
@@ -352,7 +353,22 @@ function wtf8_to_string(wtf8) {
let iter = as_iter(wtf8);
for (let cp = iter_next(iter); cp != -1; cp = iter_next(iter))
codepoints.push(cp);
- return String.fromCodePoint(...codepoints);
+
+ // Passing too many codepoints can overflow the stack.
+ let maxcp = 100000;
+ if (codepoints.length <= maxcp) {
+ return String.fromCodePoint(...codepoints);
+ }
+
+ // For converting large strings, concatenate several smaller
+ // strings.
+ let substrings = [];
+ let end = 0;
+ for (let start = 0; start != codepoints.length; start = end) {
+ end = Math.min(start + maxcp, codepoints.length);
+ substrings.push(String.fromCodePoint(...codepoints.slice(start, end)));
+ }
+ return substrings.join('');
}
function string_to_wtf8(str) {
@@ -473,25 +489,131 @@ class SchemeModule {
constructor(instance) {
this.#instance = instance;
- let read_stdin = () => '';
- if (typeof printErr === 'function') {
+ if (typeof printErr === 'function') { // v8/sm dev console
// On the console, try to use 'write' (v8) or 'putstr' (sm),
// as these don't add an extraneous newline. Unfortunately
// JSC doesn't have a printer that doesn't add a newline.
let write_no_newline =
typeof write === 'function' ? write
: typeof putstr === 'function' ? putstr : print;
+ // Use readline when available. v8 strips newlines so
+ // we need to add them back.
+ let read_stdin =
+ typeof readline == 'function' ? () => {
+ let line = readline();
+ if (line) {
+ return `${line}\n`;
+ } else {
+ return '\n';
+ }
+ }: () => '';
+ let delete_file = (filename) => false;
this.#io_handler = {
write_stdout: write_no_newline,
write_stderr: printErr,
- read_stdin
+ read_stdin,
+ file_exists: (filename) => false,
+ open_input_file: (filename) => {},
+ open_output_file: (filename) => {},
+ close_file: () => undefined,
+ read_file: (handle, length) => 0,
+ write_file: (handle, length) => 0,
+ seek_file: (handle, offset, whence) => -1,
+ file_random_access: (handle) => false,
+ file_buffer_size: (handle) => 0,
+ file_buffer_ref: (handle, i) => 0,
+ file_buffer_set: (handle, i, x) => undefined,
+ delete_file: (filename) => undefined
};
- } else {
+ } else if (typeof window !== 'undefined') { // web browser
this.#io_handler = {
write_stdout: console.log,
write_stderr: console.error,
- read_stdin
- }
+ read_stdin: () => '',
+ file_exists: (filename) => false,
+ open_input_file: (filename) => {},
+ open_output_file: (filename) => {},
+ close_file: () => undefined,
+ read_file: (handle, length) => 0,
+ write_file: (handle, length) => 0,
+ seek_file: (handle, offset, whence) => -1,
+ file_random_access: (handle) => false,
+ file_buffer_size: (handle) => 0,
+ file_buffer_ref: (handle, i) => 0,
+ file_buffer_set: (handle, i, x) => undefined,
+ delete_file: (filename) => undefined
+ };
+ } else { // nodejs
+ const fs = require('fs');
+ const process = require('process');
+ const bufLength = 1024;
+ const stdinBuf = Buffer.alloc(bufLength);
+ const SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2;
+ this.#io_handler = {
+ write_stdout: console.log,
+ write_stderr: console.error,
+ read_stdin: () => {
+ let n = fs.readSync(process.stdin.fd, stdinBuf, 0, stdinBuf.length);
+ return stdinBuf.toString('utf8', 0, n);
+ },
+ file_exists: fs.existsSync.bind(fs),
+ open_input_file: (filename) => {
+ let fd = fs.openSync(filename, 'r');
+ return {
+ fd,
+ buf: Buffer.alloc(bufLength),
+ pos: 0
+ };
+ },
+ open_output_file: (filename) => {
+ let fd = fs.openSync(filename, 'w');
+ return {
+ fd,
+ buf: Buffer.alloc(bufLength),
+ pos: 0
+ };
+ },
+ close_file: (handle) => {
+ fs.closeSync(handle.fd);
+ },
+ read_file: (handle, count) => {
+ const n = fs.readSync(handle.fd, handle.buf, 0, count, handle.pos);
+ handle.pos += n;
+ return n;
+ },
+ write_file: (handle, count) => {
+ const n = fs.writeSync(handle.fd, handle.buf, 0, count, handle.pos);
+ handle.pos += n;
+ return n;
+ },
+ seek_file: (handle, offset, whence) => {
+ // There doesn't seem to be a way to ask NodeJS if
+ // a position is valid or not.
+ if (whence == SEEK_SET) {
+ handle.pos = offset;
+ return handle.pos;
+ } else if (whence == SEEK_CUR) {
+ handle.pos += offset;
+ return handle.pos;
+ }
+
+ // SEEK_END not supported.
+ return -1;
+ },
+ file_random_access: (handle) => {
+ return true;
+ },
+ file_buffer_size: (handle) => {
+ return handle.buf.length;
+ },
+ file_buffer_ref: (handle, i) => {
+ return handle.buf[i];
+ },
+ file_buffer_set: (handle, i, x) => {
+ handle.buf[i] = x;
+ },
+ delete_file: fs.rmSync.bind(fs)
+ };
}
this.#debug_handler = {
debug_str(x) { console.log(`debug: ${x}`); },
@@ -505,7 +627,19 @@ class SchemeModule {
write_stdout(str) { mod.#io_handler.write_stdout(str); },
write_stderr(str) { mod.#io_handler.write_stderr(str); },
read_stdin() { return mod.#io_handler.read_stdin(); },
- }
+ file_exists(filename) { return mod.#io_handler.file_exists(filename); },
+ open_input_file(filename) { return mod.#io_handler.open_input_file(filename); },
+ open_output_file(filename) { return mod.#io_handler.open_output_file(filename); },
+ close_file(handle) { mod.#io_handler.close_file(handle); },
+ read_file(handle, length) { return mod.#io_handler.read_file(handle, length); },
+ write_file(handle, length) { return mod.#io_handler.write_file(handle, length); },
+ seek_file(handle, offset, whence) { return mod.#io_handler.seek_file(handle, offset, whence); },
+ file_random_access(handle) { return mod.#io_handler.file_random_access(handle); },
+ file_buffer_size(handle) { return mod.#io_handler.file_buffer_size(handle); },
+ file_buffer_ref(handle, i) { return mod.#io_handler.file_buffer_ref(handle, i); },
+ file_buffer_set(handle, i, x) { return mod.#io_handler.file_buffer_set(handle, i, x); },
+ delete_file(filename) { mod.#io_handler.delete_file(filename); }
+ };
let debug = {
debug_str(x) { mod.#debug_handler.debug_str(x); },
debug_str_i32(x, y) { mod.#debug_handler.debug_str_i32(x, y); },