Refactor I/O

This commit is contained in:
Remko Tronçon 2018-06-03 09:15:21 +02:00
parent c5453432f3
commit 692e0ea288
3 changed files with 53 additions and 41 deletions

View file

@ -17,7 +17,6 @@ class WAForth {
const { skipPrelude } = options;
let table;
let memory;
const buffer = (this.buffer = []);
return WebAssembly.instantiate(wasmModule, {
shell: {
@ -27,13 +26,6 @@ class WAForth {
emit: this.onEmit,
key: () => {
if (buffer.length === 0) {
return -1;
}
return buffer.pop();
},
debug: d => {
console.log("DEBUG: ", d);
},
@ -79,8 +71,8 @@ class WAForth {
read(s) {
const data = new TextEncoder().encode(s);
for (let i = data.length - 1; i >= 0; --i) {
this.buffer.push(data[i]);
for (let i = 0; i < data.length; ++i) {
this.core.exports.read(data[i]);
}
}

View file

@ -26,6 +26,7 @@
(define !baseBase #x100)
(define !stateBase #x104)
(define !wordBase #x200)
(define !inputBufferBase #x300)
;; Compiled modules are limited to 4096 bytes until Chrome refuses to load
;; them synchronously
(define !moduleHeaderBase #x1000)
@ -140,7 +141,6 @@
(module
(import "shell" "emit" (func $shell_emit (param i32)))
(import "shell" "key" (func $shell_key (result i32)))
(import "shell" "load" (func $shell_load (param i32 i32 i32)))
(import "shell" "debug" (func $shell_debug (param i32)))
@ -150,6 +150,8 @@
(global $tos (mut i32) (i32.const !stackBase))
(global $tors (mut i32) (i32.const !returnStackBase))
(global $inputBufferEnd (mut i32) (i32.const !inputBufferBase))
(global $inputBufferP (mut i32) (i32.const !inputBufferBase))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Built-in words
@ -719,7 +721,7 @@
(!def_word "FILL" "$FILL")
;; 6.1.1550
(func $find (export "FIND") (param i32)
(func $find (param i32)
(local $entryP i32)
(local $entryNameP i32)
(local $entryLF i32)
@ -1299,6 +1301,9 @@ EOF
(local $findResult i32)
(local $findToken i32)
(local $body i32)
(local $error i32)
(set_local $error (i32.const 0))
(set_global $inputBufferP (i32.const !inputBufferBase))
(block $endLoop
(loop $loop
(call $word (i32.const -1))
@ -1317,9 +1322,9 @@ EOF
(call $compilePushConst (call $pop)))))
;; We're not compiling. Leave the number on the stack.
(else ;; It's not a number.
(drop (call $pop))
;; TODO: Give error
(return (i32.const -1)))))
(set_local $error (i32.const -1))
(br $endLoop))))
(else ;; Found the word.
(set_local $body (call $body (get_local $findToken)))
;; Are we compiling?
@ -1344,7 +1349,13 @@ EOF
(br $loop)))
;; 'WORD' left the address on the stack
(drop (call $pop))
(set_global $inputBufferEnd (i32.const !inputBufferBase))
(if (i32.eqz (get_local $error))
(then
(return (i32.load (i32.const !stateBase))))
(else
(return (get_local $error))))
(unreachable))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Compiler functions
@ -1672,7 +1683,13 @@ EOF
(local $n i32)
(if (i32.eq (get_global $preludeDataP) (get_global $preludeDataEnd))
(then
(return (call $shell_key)))
(if (i32.ge_u (get_global $inputBufferP) (get_global $inputBufferEnd))
(then
(return (i32.const -1)))
(else
(set_local $n (i32.load8_s (get_global $inputBufferP)))
(set_global $inputBufferP (i32.add (get_global $inputBufferP) (i32.const 1)))
(return (get_local $n)))))
(else
(set_local $n (i32.load8_s (get_global $preludeDataP)))
(set_global $preludeDataP (i32.add (get_global $preludeDataP) (i32.const 1)))
@ -1784,6 +1801,10 @@ EOF
(call $shell_emit (i32.const 10))
(get_local $result))
(func (export "read") (param $char i32)
(i32.store8 (get_global $inputBufferEnd) (get_local $char))
(set_global $inputBufferEnd (i32.add (get_global $inputBufferEnd) (i32.const 1))))
(table (export "table") !tableStartIndex anyfunc)
(global $latest (mut i32) (i32.const !dictionaryLatest))
(global $here (mut i32) (i32.const !dictionaryTop))

View file

@ -47,6 +47,14 @@ describe("WAForth", () => {
return getString(p + 4, memory[p / 4]);
}
function loadString(s) {
run("HERE");
run(`${s.length} ,`);
for (let i = 0; i < s.length; ++i) {
run(`${s.charCodeAt(i)} C,`);
}
}
// eslint-disable-next-line no-unused-vars
function dumpWord(w) {
let end = here();
@ -808,40 +816,35 @@ describe("WAForth", () => {
describe("FIND", () => {
it("should find a word", () => {
forth.read("DUP");
core.WORD();
core.FIND();
loadString("DUP");
run("FIND");
expect(stack[0]).to.eql(131756);
expect(stack[1]).to.eql(-1);
});
it("should find a short word", () => {
forth.read("!");
core.WORD();
core.FIND();
loadString("!");
run("FIND");
expect(stack[0]).to.eql(131072);
expect(stack[1]).to.eql(-1);
});
it("should find an immediate word", () => {
forth.read("+LOOP");
core.WORD();
core.FIND();
loadString("+LOOP");
run("FIND");
expect(stack[0]).to.eql(131160);
expect(stack[1]).to.eql(1);
});
it("should not find an unexisting word", () => {
forth.read("BADWORD");
core.WORD();
core.FIND();
loadString("BADWORD");
run("FIND");
expect(stack[1]).to.eql(0);
});
it("should not find a very long unexisting word", () => {
forth.read("VERYVERYVERYBADWORD");
core.WORD();
core.FIND();
loadString("VERYVERYVERYBADWORD");
run("FIND");
expect(stack[1]).to.eql(0);
});
});
@ -1079,10 +1082,8 @@ describe("WAForth", () => {
run("CREATE FOOBAR");
run("LATEST");
run("CREATE BAM");
forth.read("FOOBAR");
core.WORD();
core.FIND();
loadString("FOOBAR");
run("FIND");
expect(stack[1]).to.eql(stack[0]);
expect(stack[2]).to.eql(-1);
});
@ -1103,10 +1104,8 @@ describe("WAForth", () => {
describe("IMMEDIATE", () => {
it("should make words immediate", () => {
run("CREATE FOOBAR IMMEDIATE");
forth.read("FOOBAR");
core.WORD();
core.FIND();
loadString("FOOBAR");
run("FIND");
expect(stack[1]).to.eql(1);
});
});