Support reading long strings

This commit is contained in:
Remko Tronçon 2022-05-24 20:16:23 +02:00
parent ff84035919
commit 236ad04aa5
3 changed files with 57 additions and 38 deletions

View file

@ -2758,14 +2758,16 @@
(local $result i32) (local $result i32)
(local $tos i32) (local $tos i32)
(local.tee $tos (global.get $tos)) (local.tee $tos (global.get $tos))
(block $endLoop (param i32) (result i32)
(loop $loop (param i32) (result i32)
(call $REFILL) (call $REFILL)
(drop (call $pop)) (br_if $endLoop (i32.eqz (call $pop)))
(local.set $result (call $interpret)) (local.set $result (call $interpret))
(global.set $tos) (local.set $tos)
;; Check for stack underflow ;; Check for stack underflow
(if (i32.lt_s (global.get $tos) (i32.const 0x10000 (; = STACK_BASE ;))) (if (i32.lt_s (local.get $tos) (i32.const 0x10000 (; = STACK_BASE ;)))
(drop (call $fail (global.get $tos) (i32.const 0x200B2 (; stack empty ;))))) (drop (call $fail (local.get $tos) (i32.const 0x200B2 (; stack empty ;)))))
(if (i32.ge_s (local.get $result) (i32.const 0)) (if (i32.ge_s (local.get $result) (i32.const 0))
(then (then
@ -2780,6 +2782,9 @@
(call $shell_emit (i32.const 111)) (call $shell_emit (i32.const 111))
(call $shell_emit (i32.const 114)))) (call $shell_emit (i32.const 114))))
(call $shell_emit (i32.const 10)) (call $shell_emit (i32.const 10))
(local.get $tos)
(br $loop)))
(global.set $tos)
(local.get $result)) (local.get $result))
(func (export "push") (param $v i32) (func (export "push") (param $v i32)

View file

@ -222,6 +222,15 @@ function loadTests() {
expect(() => core.interpret()).to.throw(); expect(() => core.interpret()).to.throw();
expect(output.trim()).to.eql("undefined word: 23FOO"); expect(output.trim()).to.eql("undefined word: 23FOO");
}); });
it("should interpret a long string", () => {
const p = ["1"];
for (let i = 0; i < 1000; i++) {
p.push(`${1} +`);
}
forth.interpret(p.join("\n"));
expect(stackValues()).to.eql([1001]);
});
}); });
describe("DUP", () => { describe("DUP", () => {

View file

@ -46,7 +46,7 @@ function saveString(s: string, memory: WebAssembly.Memory, addr: number) {
* */ * */
class WAForth { class WAForth {
core?: WebAssembly.Instance; core?: WebAssembly.Instance;
#buffer?: number[]; #buffer?: string;
#fns: Record<string, (f: WAForth) => void>; #fns: Record<string, (f: WAForth) => void>;
/** /**
@ -96,7 +96,7 @@ class WAForth {
async load() { async load() {
let table: WebAssembly.Table; let table: WebAssembly.Table;
let memory: WebAssembly.Memory; let memory: WebAssembly.Memory;
this.#buffer = []; this.#buffer = "";
const instance = await WebAssembly.instantiate(wasmModule, { const instance = await WebAssembly.instantiate(wasmModule, {
shell: { shell: {
@ -111,17 +111,22 @@ class WAForth {
}, },
read: (addr: number, length: number): number => { read: (addr: number, length: number): number => {
let data = new Uint8Array( let input: string;
(this.core!.exports.memory as WebAssembly.Memory).buffer, if (this.#buffer!.length <= length) {
addr, input = this.#buffer!;
length this.#buffer = "";
); } else {
let n = 0; const i = this.#buffer!.lastIndexOf("\n", length - 1);
while (this.#buffer!.length > 0 && n < length) { input = this.#buffer!.substring(0, i + 1);
data[n] = this.#buffer!.shift()!; this.#buffer = this.#buffer!.substring(i + 1);
n += 1;
} }
return n; // console.log("read: %s (%d remaining)", input, this.#buffer!.length);
saveString(
input,
this.core!.exports.memory as WebAssembly.Memory,
addr
);
return input.length;
}, },
key: () => { key: () => {
@ -215,16 +220,16 @@ class WAForth {
* Read data `s` into the input buffer without interpreting it. * Read data `s` into the input buffer without interpreting it.
*/ */
read(s: string) { read(s: string) {
const data = new TextEncoder().encode(s); this.#buffer = this.#buffer + s;
for (let i = 0, len = data.length; i < len; ++i) {
this.#buffer!.push(data[i]);
}
} }
/** /**
* Read data `s` into the input buffer, and interpret. * Read data `s` into the input buffer, and interpret.
*/ */
interpret(s: string) { interpret(s: string) {
if (!s.endsWith("\n")) {
s = s + "\n";
}
this.read(s); this.read(s);
try { try {
return (this.core!.exports.interpret as any)(); return (this.core!.exports.interpret as any)();