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,29 +2758,34 @@
(local $result i32)
(local $tos i32)
(local.tee $tos (global.get $tos))
(call $REFILL)
(drop (call $pop))
(local.set $result (call $interpret))
(global.set $tos)
(block $endLoop (param i32) (result i32)
(loop $loop (param i32) (result i32)
(call $REFILL)
(br_if $endLoop (i32.eqz (call $pop)))
(local.set $result (call $interpret))
(local.set $tos)
;; Check for stack underflow
(if (i32.lt_s (global.get $tos) (i32.const 0x10000 (; = STACK_BASE ;)))
(drop (call $fail (global.get $tos) (i32.const 0x200B2 (; stack empty ;)))))
;; Check for stack underflow
(if (i32.lt_s (local.get $tos) (i32.const 0x10000 (; = STACK_BASE ;)))
(drop (call $fail (local.get $tos) (i32.const 0x200B2 (; stack empty ;)))))
(if (i32.ge_s (local.get $result) (i32.const 0))
(then
;; Write ok
(call $shell_emit (i32.const 111))
(call $shell_emit (i32.const 107)))
(else
;; Write error
(call $shell_emit (i32.const 101))
(call $shell_emit (i32.const 114))
(call $shell_emit (i32.const 114))
(call $shell_emit (i32.const 111))
(call $shell_emit (i32.const 114))))
(call $shell_emit (i32.const 10))
(local.get $result))
(if (i32.ge_s (local.get $result) (i32.const 0))
(then
;; Write ok
(call $shell_emit (i32.const 111))
(call $shell_emit (i32.const 107)))
(else
;; Write error
(call $shell_emit (i32.const 101))
(call $shell_emit (i32.const 114))
(call $shell_emit (i32.const 114))
(call $shell_emit (i32.const 111))
(call $shell_emit (i32.const 114))))
(call $shell_emit (i32.const 10))
(local.get $tos)
(br $loop)))
(global.set $tos)
(local.get $result))
(func (export "push") (param $v i32)
(global.set $tos (call $push (global.get $tos) (local.get $v))))

View file

@ -222,6 +222,15 @@ function loadTests() {
expect(() => core.interpret()).to.throw();
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", () => {

View file

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