Documentation

This commit is contained in:
Remko Tronçon 2022-06-01 22:01:21 +02:00
parent 71ec9e341a
commit 5a4efef6c8
5 changed files with 40 additions and 25 deletions

View file

@ -11,7 +11,7 @@
#define CORE_TABLE_EXPORT_INDEX 0 #define CORE_TABLE_EXPORT_INDEX 0
#define CORE_MEMORY_EXPORT_INDEX 1 #define CORE_MEMORY_EXPORT_INDEX 1
#define CORE_ERROR_EXPORT_INDEX 6 #define CORE_ERROR_EXPORT_INDEX 6
#define CORE_INTERPRET_EXPORT_INDEX 7 #define CORE_RUN_EXPORT_INDEX 7
#define ERR_UNKNOWN 0x1 #define ERR_UNKNOWN 0x1
#define ERR_QUIT 0x2 #define ERR_QUIT 0x2
@ -172,8 +172,8 @@ int main(int argc, char *argv_main[]) {
return -1; return -1;
} }
const wasm_func_t *interpret_fn = wasm_extern_as_func(exports.data[CORE_INTERPRET_EXPORT_INDEX]); const wasm_func_t *run_fn = wasm_extern_as_func(exports.data[CORE_RUN_EXPORT_INDEX]);
if (interpret_fn == NULL) { if (run_fn == NULL) {
printf("error accessing `interpret` export\n"); printf("error accessing `interpret` export\n");
return -1; return -1;
} }
@ -185,16 +185,16 @@ int main(int argc, char *argv_main[]) {
} }
printf("WAForth (" VERSION ")\n"); printf("WAForth (" VERSION ")\n");
wasm_val_t interpret_as[1] = {WASM_I32_VAL(0)}; wasm_val_t run_as[1] = {WASM_I32_VAL(0)};
wasm_val_vec_t interpret_args = WASM_ARRAY_VEC(interpret_as); wasm_val_vec_t run_args = WASM_ARRAY_VEC(run_as);
wasm_val_vec_t interpret_results = WASM_EMPTY_VEC; wasm_val_vec_t run_results = WASM_EMPTY_VEC;
wasm_val_vec_t err_args = WASM_EMPTY_VEC; wasm_val_vec_t err_args = WASM_EMPTY_VEC;
wasm_val_t err_results_vs[] = {WASM_INIT_VAL}; wasm_val_t err_results_vs[] = {WASM_INIT_VAL};
wasm_val_vec_t err_results = WASM_ARRAY_VEC(err_results_vs); wasm_val_vec_t err_results = WASM_ARRAY_VEC(err_results_vs);
for (int stopped = 0; !stopped;) { 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); wasm_trap_t *etrap = wasm_func_call(error_fn, &err_args, &err_results);
assert(etrap == NULL); assert(etrap == NULL);
switch (err_results.data[0].of.i32) { switch (err_results.data[0].of.i32) {

View file

@ -2829,24 +2829,31 @@
;; API Functions ;; API Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(func (export "tos") (result i32) ;; Run the interpreter loop, until no more user input is available (or until
(global.get $tos)) ;; execution is aborted using QUIT)
(func $run (export "run") (param $silent i32)
(func (export "here") (result i32)
(global.get $here))
(func (export "error") (result i32)
(global.get $error))
(func (export "interpret") (param $silent i32)
(local $state i32) (local $state i32)
(local $tos 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)) (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 ;))) (global.set $error (i32.const 0x1 (; = ERR_UNKNOWN ;)))
;; Start looping until there is no more input
(block $endLoop (param i32) (result i32) (block $endLoop (param i32) (result i32)
(loop $loop (param i32) (result i32) (loop $loop (param i32) (result i32)
;; Fill the input buffer with user input
(call $REFILL) (call $REFILL)
(br_if $endLoop (i32.eqz (call $pop))) (br_if $endLoop (i32.eqz (call $pop)))
;; Run the interpreter loop on the entire input buffer
(local.set $tos (call $interpret)) (local.set $tos (call $interpret))
;; Check for stack underflow ;; Check for stack underflow
@ -2871,7 +2878,11 @@
(call $shell_emit (i32.const 10)))) (call $shell_emit (i32.const 10))))
(local.get $tos) (local.get $tos)
(br $loop))) (br $loop)))
;; Reset the global TOS pointer to the current local value (still on the WASM operand stack)
(global.set $tos) (global.set $tos)
;; End of input was reached
(global.set $error (i32.const 0x4 (; = ERR_EOI ;)))) (global.set $error (i32.const 0x4 (; = ERR_EOI ;))))
(func (export "push") (param $v i32) (func (export "push") (param $v i32)
@ -2883,6 +2894,10 @@
(global.set $tos) (global.set $tos)
(local.get $result)) (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 ;; Used for experiments
(func (export "set_state") (param $latest i32) (param $here i32) (func (export "set_state") (param $latest i32) (param $here i32)
(global.set $latest (local.get $latest)) (global.set $latest (local.get $latest))

View file

@ -21,7 +21,7 @@ function run(s) {
for (let i = data.length - 1; i >= 0; --i) { for (let i = data.length - 1; i >= 0; --i) {
buffer.push(data[i]); buffer.push(data[i]);
} }
return core.exports.interpret(); return core.exports.run();
} }
function latest() { function latest() {

View file

@ -192,38 +192,38 @@ function loadTests() {
describe("interpret", () => { describe("interpret", () => {
it("should return an error when word is not found", () => { it("should return an error when word is not found", () => {
forth.read("BADWORD"); forth.read("BADWORD");
expect(() => core.interpret()).to.throw(); expect(() => core.run()).to.throw();
expect(output.trim()).to.eql("undefined word: BADWORD"); expect(output.trim()).to.eql("undefined word: BADWORD");
}); });
it("should interpret a positive number", () => { it("should interpret a positive number", () => {
forth.read("123"); forth.read("123");
core.interpret(); core.run();
expect(core.error()).to.eql(4); expect(core.error()).to.eql(4);
expect(stackValues()[0]).to.eql(123); expect(stackValues()[0]).to.eql(123);
}); });
it("should interpret a negative number", () => { it("should interpret a negative number", () => {
forth.read("-123"); forth.read("-123");
core.interpret(); core.run();
expect(core.error()).to.eql(4); expect(core.error()).to.eql(4);
expect(stackValues()[0]).to.eql(-123); expect(stackValues()[0]).to.eql(-123);
}); });
it("should interpret a hex", () => { it("should interpret a hex", () => {
forth.read("16 BASE ! DF"); forth.read("16 BASE ! DF");
core.interpret(); core.run();
expect(core.error()).to.eql(4); expect(core.error()).to.eql(4);
expect(stackValues()[0]).to.eql(223); expect(stackValues()[0]).to.eql(223);
}); });
it("should not interpret hex in decimal mode", () => { it("should not interpret hex in decimal mode", () => {
forth.read("DF"); forth.read("DF");
expect(() => core.interpret()).to.throw(); expect(() => core.run()).to.throw();
expect(output.trim()).to.eql("undefined word: DF"); expect(output.trim()).to.eql("undefined word: DF");
}); });
it("should fail on half a word", () => { it("should fail on half a word", () => {
forth.read("23FOO"); forth.read("23FOO");
expect(() => core.interpret()).to.throw(); expect(() => core.run()).to.throw();
expect(output.trim()).to.eql("undefined word: 23FOO"); expect(output.trim()).to.eql("undefined word: 23FOO");
}); });

View file

@ -239,7 +239,7 @@ class WAForth {
} }
this.read(s); this.read(s);
try { try {
return (this.core!.exports.interpret as any)(silent); return (this.core!.exports.run as any)(silent);
} catch (e) { } catch (e) {
// Exceptions thrown from the core means QUIT or ABORT is called, or an error // Exceptions thrown from the core means QUIT or ABORT is called, or an error
// has occurred. // has occurred.