waforth/src/shell/WAForth.js

111 lines
3 KiB
JavaScript
Raw Normal View History

2018-05-12 21:09:19 +02:00
let wasmModule;
2018-05-13 17:07:54 +02:00
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
2018-05-12 21:09:19 +02:00
// eslint-disable-next-line no-unused-vars
function arrayToBase64(bytes) {
var binary = "";
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
class WAForth {
2018-05-13 17:07:54 +02:00
start(options = {}) {
const { skipPrelude } = options;
2018-05-12 21:09:19 +02:00
let table;
const buffer = (this.buffer = []);
// TODO: Try to bundle this. See https://github.com/parcel-bundler/parcel/issues/647
const initialize =
wasmModule != null
? Promise.resolve(wasmModule)
: fetch("waforth.wasm")
.then(resp => resp.arrayBuffer())
.then(module => {
wasmModule = module;
return wasmModule;
});
return initialize
.then(m =>
WebAssembly.instantiate(m, {
shell: {
2018-05-13 17:07:54 +02:00
////////////////////////////////////////
// I/O
////////////////////////////////////////
2018-05-12 21:09:19 +02:00
emit: this.onEmit,
2018-05-13 17:07:54 +02:00
2018-05-12 21:09:19 +02:00
key: () => {
if (buffer.length === 0) {
return -1;
}
return buffer.pop();
},
2018-05-13 17:07:54 +02:00
debug: d => {
console.log("DEBUG: ", d);
},
////////////////////////////////////////
// Loader
////////////////////////////////////////
load: (offset, length, index) => {
2018-05-13 17:07:54 +02:00
let data = new Uint8Array(
this.core.exports.memory.buffer,
offset,
length
);
if (isSafari) {
// On Safari, using the original Uint8Array triggers a bug.
// Taking an element-by-element copy of the data first.
let dataCopy = [];
for (let i = 0; i < length; ++i) {
dataCopy.push(data[i]);
}
data = new Uint8Array(dataCopy);
}
if (index >= table.length) {
2018-05-12 21:09:19 +02:00
table.grow(table.length); // Double size
}
2018-05-19 14:17:16 +02:00
// console.log(
// "Load",
// index,
2018-05-19 14:17:16 +02:00
// new Uint8Array(data),
// arrayToBase64(data)
// );
2018-05-27 16:40:47 +02:00
var module = new WebAssembly.Module(data);
2018-05-12 21:09:19 +02:00
new WebAssembly.Instance(module, {
env: { table, tableBase: index }
2018-05-12 21:09:19 +02:00
});
}
}
})
)
.then(instance => {
this.core = instance.instance;
table = this.core.exports.table;
2018-05-13 17:07:54 +02:00
if (!skipPrelude) {
this.core.exports.loadPrelude();
}
2018-05-12 21:09:19 +02:00
});
}
read(s) {
const data = new TextEncoder().encode(s);
for (let i = data.length - 1; i >= 0; --i) {
this.buffer.push(data[i]);
}
}
2018-05-13 17:07:54 +02:00
run(s) {
this.read(s);
return this.core.exports.interpret();
}
2018-05-12 21:09:19 +02:00
}
export default WAForth;