diff --git a/src/standalone/main.c b/src/standalone/main.c index 9884b74..0e6c2ad 100644 --- a/src/standalone/main.c +++ b/src/standalone/main.c @@ -11,7 +11,7 @@ #define CORE_TABLE_EXPORT_INDEX 0 #define CORE_MEMORY_EXPORT_INDEX 1 #define CORE_ERROR_EXPORT_INDEX 6 -#define CORE_INTERPRET_EXPORT_INDEX 7 +#define CORE_RUN_EXPORT_INDEX 7 #define ERR_UNKNOWN 0x1 #define ERR_QUIT 0x2 @@ -172,8 +172,8 @@ int main(int argc, char *argv_main[]) { return -1; } - const wasm_func_t *interpret_fn = wasm_extern_as_func(exports.data[CORE_INTERPRET_EXPORT_INDEX]); - if (interpret_fn == NULL) { + const wasm_func_t *run_fn = wasm_extern_as_func(exports.data[CORE_RUN_EXPORT_INDEX]); + if (run_fn == NULL) { printf("error accessing `interpret` export\n"); return -1; } @@ -185,16 +185,16 @@ int main(int argc, char *argv_main[]) { } printf("WAForth (" VERSION ")\n"); - wasm_val_t interpret_as[1] = {WASM_I32_VAL(0)}; - wasm_val_vec_t interpret_args = WASM_ARRAY_VEC(interpret_as); - wasm_val_vec_t interpret_results = WASM_EMPTY_VEC; + wasm_val_t run_as[1] = {WASM_I32_VAL(0)}; + wasm_val_vec_t run_args = WASM_ARRAY_VEC(run_as); + wasm_val_vec_t run_results = WASM_EMPTY_VEC; wasm_val_vec_t err_args = WASM_EMPTY_VEC; wasm_val_t err_results_vs[] = {WASM_INIT_VAL}; wasm_val_vec_t err_results = WASM_ARRAY_VEC(err_results_vs); for (int stopped = 0; !stopped;) { - trap = wasm_func_call(interpret_fn, &interpret_args, &interpret_results); + trap = wasm_func_call(run_fn, &run_args, &run_results); wasm_trap_t *etrap = wasm_func_call(error_fn, &err_args, &err_results); assert(etrap == NULL); switch (err_results.data[0].of.i32) { diff --git a/src/waforth.wat b/src/waforth.wat index ad64b04..c43bff2 100644 --- a/src/waforth.wat +++ b/src/waforth.wat @@ -2829,24 +2829,31 @@ ;; API Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (func (export "tos") (result i32) - (global.get $tos)) - - (func (export "here") (result i32) - (global.get $here)) - - (func (export "error") (result i32) - (global.get $error)) - - (func (export "interpret") (param $silent i32) + ;; Run the interpreter loop, until no more user input is available (or until + ;; execution is aborted using QUIT) + (func $run (export "run") (param $silent i32) (local $state i32) (local $tos i32) + + ;; Load the top-of-stack (TOS) pointer as a local, and thread it through the execution. + ;; The global TOS pointer will not be accurate until it is reset at the end of the loop, + ;; at abort time, or at shell `call` time. + ;; + ;; Put the local value on the WASM operand stack, so it is threaded through the loop. (local.tee $tos (global.get $tos)) + + ;; In case a trap occurs, make sure the error is set to an unknown error. + ;; We'll reset the error to a real value later if no trap occurs. (global.set $error (i32.const 0x1 (; = ERR_UNKNOWN ;))) + + ;; Start looping until there is no more input (block $endLoop (param i32) (result i32) (loop $loop (param i32) (result i32) + ;; Fill the input buffer with user input (call $REFILL) (br_if $endLoop (i32.eqz (call $pop))) + + ;; Run the interpreter loop on the entire input buffer (local.set $tos (call $interpret)) ;; Check for stack underflow @@ -2871,7 +2878,11 @@ (call $shell_emit (i32.const 10)))) (local.get $tos) (br $loop))) + + ;; Reset the global TOS pointer to the current local value (still on the WASM operand stack) (global.set $tos) + + ;; End of input was reached (global.set $error (i32.const 0x4 (; = ERR_EOI ;)))) (func (export "push") (param $v i32) @@ -2883,6 +2894,10 @@ (global.set $tos) (local.get $result)) + (func (export "tos") (result i32) (global.get $tos)) + (func (export "here") (result i32) (global.get $here)) + (func (export "error") (result i32) (global.get $error)) + ;; Used for experiments (func (export "set_state") (param $latest i32) (param $here i32) (global.set $latest (local.get $latest)) diff --git a/src/waforth2c/waforth2c.js b/src/waforth2c/waforth2c.js index a0d9406..f1372e0 100755 --- a/src/waforth2c/waforth2c.js +++ b/src/waforth2c/waforth2c.js @@ -21,7 +21,7 @@ function run(s) { for (let i = data.length - 1; i >= 0; --i) { buffer.push(data[i]); } - return core.exports.interpret(); + return core.exports.run(); } function latest() { diff --git a/src/web/tests/suite.js b/src/web/tests/suite.js index 0f63089..063977d 100644 --- a/src/web/tests/suite.js +++ b/src/web/tests/suite.js @@ -192,38 +192,38 @@ function loadTests() { describe("interpret", () => { it("should return an error when word is not found", () => { forth.read("BADWORD"); - expect(() => core.interpret()).to.throw(); + expect(() => core.run()).to.throw(); expect(output.trim()).to.eql("undefined word: BADWORD"); }); it("should interpret a positive number", () => { forth.read("123"); - core.interpret(); + core.run(); expect(core.error()).to.eql(4); expect(stackValues()[0]).to.eql(123); }); it("should interpret a negative number", () => { forth.read("-123"); - core.interpret(); + core.run(); expect(core.error()).to.eql(4); expect(stackValues()[0]).to.eql(-123); }); it("should interpret a hex", () => { forth.read("16 BASE ! DF"); - core.interpret(); + core.run(); expect(core.error()).to.eql(4); expect(stackValues()[0]).to.eql(223); }); it("should not interpret hex in decimal mode", () => { forth.read("DF"); - expect(() => core.interpret()).to.throw(); + expect(() => core.run()).to.throw(); expect(output.trim()).to.eql("undefined word: DF"); }); it("should fail on half a word", () => { forth.read("23FOO"); - expect(() => core.interpret()).to.throw(); + expect(() => core.run()).to.throw(); expect(output.trim()).to.eql("undefined word: 23FOO"); }); diff --git a/src/web/waforth.ts b/src/web/waforth.ts index f43ccad..7908c8a 100644 --- a/src/web/waforth.ts +++ b/src/web/waforth.ts @@ -239,7 +239,7 @@ class WAForth { } this.read(s); try { - return (this.core!.exports.interpret as any)(silent); + return (this.core!.exports.run as any)(silent); } catch (e) { // Exceptions thrown from the core means QUIT or ABORT is called, or an error // has occurred.