mirror of
https://github.com/remko/waforth
synced 2025-02-05 20:46:22 +01:00
Refactor I/O
This commit is contained in:
parent
c5453432f3
commit
692e0ea288
3 changed files with 53 additions and 41 deletions
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -811,8 +813,8 @@
|
|||
|
||||
;; 6.1.1750
|
||||
(func $key (param i32)
|
||||
(i32.store (get_global $tos) (call $readChar))
|
||||
(set_global $tos (i32.add (get_global $tos) (i32.const 4))))
|
||||
(i32.store (get_global $tos) (call $readChar))
|
||||
(set_global $tos (i32.add (get_global $tos) (i32.const 4))))
|
||||
(!def_word "KEY" "$key")
|
||||
|
||||
;; 6.1.1760
|
||||
|
@ -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))
|
||||
(return (i32.load (i32.const !stateBase))))
|
||||
(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))
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue