mirror of
https://github.com/remko/waforth
synced 2024-12-27 09:59:29 +01:00
Implement DOES>
This commit is contained in:
parent
f7a1ab2aa2
commit
2a7322cfa5
4 changed files with 62 additions and 39 deletions
|
@ -2,23 +2,23 @@ const isSafari =
|
|||
typeof navigator != "undefined" &&
|
||||
/^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function arrayToBase64(bytes) {
|
||||
var binary = "";
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
class WAForth {
|
||||
constructor(wasmModule) {
|
||||
constructor(wasmModule, arrayToBase64) {
|
||||
if (wasmModule == null) {
|
||||
this.wasmModule = require("../waforth.wasm");
|
||||
} else {
|
||||
this.wasmModule = wasmModule;
|
||||
}
|
||||
this.arrayToBase64 =
|
||||
arrayToBase64 ||
|
||||
function arrayToBase64(bytes) {
|
||||
var binary = "";
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
};
|
||||
}
|
||||
|
||||
start(options = {}) {
|
||||
|
@ -68,7 +68,7 @@ class WAForth {
|
|||
if (index >= table.length) {
|
||||
table.grow(table.length); // Double size
|
||||
}
|
||||
// console.log("Load", index, new Uint8Array(data), arrayToBase64(data));
|
||||
// console.log("Load", index, this.arrayToBase64(data));
|
||||
var module = new WebAssembly.Module(data);
|
||||
new WebAssembly.Instance(module, {
|
||||
env: { table, memory, tos: -1 }
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
"\u0003" "\u0002" ;; Function section
|
||||
"\u0001" ;; #Entries
|
||||
"\u0000" ;; Type 0
|
||||
"\u00FA" ;; Type 0
|
||||
|
||||
"\u0009" "\u000a" ;; Element section
|
||||
"\u0001" ;; #Entries
|
||||
|
@ -82,6 +82,7 @@
|
|||
(define !moduleHeaderLocalCountOffset (char-index (string->list !moduleHeader) #\u00FD 0))
|
||||
(define !moduleHeaderTableIndexOffset (char-index (string->list !moduleHeader) #\u00FC 0))
|
||||
(define !moduleHeaderTableInitialSizeOffset (char-index (string->list !moduleHeader) #\u00FB 0))
|
||||
(define !moduleHeaderFunctionTypeOffset (char-index (string->list !moduleHeader) #\u00FA 0))
|
||||
|
||||
(define !moduleBodyBase (+ !moduleHeaderBase !moduleHeaderSize))
|
||||
(define !moduleHeaderCodeSizeBase (+ !moduleHeaderBase !moduleHeaderCodeSizeOffset))
|
||||
|
@ -89,6 +90,7 @@
|
|||
(define !moduleHeaderLocalCountBase (+ !moduleHeaderBase !moduleHeaderLocalCountOffset))
|
||||
(define !moduleHeaderTableIndexBase (+ !moduleHeaderBase !moduleHeaderTableIndexOffset))
|
||||
(define !moduleHeaderTableInitialSizeBase (+ !moduleHeaderBase !moduleHeaderTableInitialSizeOffset))
|
||||
(define !moduleHeaderFunctionTypeBase (+ !moduleHeaderBase !moduleHeaderFunctionTypeOffset))
|
||||
|
||||
|
||||
(define !fNone #x0)
|
||||
|
@ -103,7 +105,8 @@
|
|||
(define !typeIndex 3)
|
||||
(define !pushDataAddressIndex 4)
|
||||
(define !pushDataValueIndex 5)
|
||||
(define !tableStartIndex 6)
|
||||
(define !setLatestBodyIndex 6)
|
||||
(define !tableStartIndex 7)
|
||||
|
||||
(define !dictionaryLatest 0)
|
||||
(define !dictionaryTop !dictionaryBase)
|
||||
|
@ -399,14 +402,27 @@
|
|||
;; agnostic about whether it is compiling a word or a DOES>.
|
||||
(i32.store (call $body (get_global $latest)) (get_global $nextTableIndex))
|
||||
|
||||
(set_global $cp (i32.const !moduleBodyBase))
|
||||
(set_global $currentLocal (i32.const -1))
|
||||
(set_global $lastLocal (i32.const -1))
|
||||
(call $startColon (i32.const 0))
|
||||
(call $right-bracket))
|
||||
(!def_word ":" "$colon")
|
||||
|
||||
;; 6.1.0460
|
||||
(func $semicolon
|
||||
(call $endColon)
|
||||
(call $hidden)
|
||||
(call $left-bracket))
|
||||
(!def_word ";" "$semicolon" !fImmediate)
|
||||
|
||||
;; Initializes compilation.
|
||||
;; Parameter indicates the type of code we're compiling: type 0 (no params),
|
||||
;; or type 1 (1 param)
|
||||
(func $startColon (param $params i32)
|
||||
(i32.store8 (i32.const !moduleHeaderFunctionTypeBase) (get_local $params))
|
||||
(set_global $cp (i32.const !moduleBodyBase))
|
||||
(set_global $currentLocal (i32.add (i32.const -1) (get_local $params)))
|
||||
(set_global $lastLocal (i32.add (i32.const -1) (get_local $params))))
|
||||
|
||||
(func $endColon
|
||||
(local $bodySize i32)
|
||||
(local $nameLength i32)
|
||||
|
||||
|
@ -484,11 +500,7 @@
|
|||
(i32.sub (get_global $cp) (i32.const !moduleHeaderBase))
|
||||
(get_global $nextTableIndex))
|
||||
|
||||
(set_global $nextTableIndex (i32.add (get_global $nextTableIndex) (i32.const 1)))
|
||||
|
||||
(call $hidden)
|
||||
(call $left-bracket))
|
||||
(!def_word ";" "$semicolon" !fImmediate)
|
||||
(set_global $nextTableIndex (i32.add (get_global $nextTableIndex) (i32.const 1))))
|
||||
|
||||
;; 6.1.0480
|
||||
(func $less-than
|
||||
|
@ -710,8 +722,13 @@
|
|||
(!def_word "DO" "$do" !fImmediate)
|
||||
|
||||
;; 6.1.1250
|
||||
; (func $DOES>)
|
||||
; (!def_word "DOES>" "$DOES>")
|
||||
(func $DOES>
|
||||
(call $emitConst (i32.add (get_global $nextTableIndex) (i32.const 1)))
|
||||
(call $emitICall (i32.const 1) (i32.const !setLatestBodyIndex))
|
||||
(call $endColon)
|
||||
(call $startColon (i32.const 1))
|
||||
(call $compilePushLocal (i32.const 0)))
|
||||
(!def_word "DOES>" "$DOES>" !fImmediate)
|
||||
|
||||
;; 6.1.1260
|
||||
(func $drop
|
||||
|
@ -1669,6 +1686,10 @@ EOF
|
|||
(call $push (i32.load (get_local $d))))
|
||||
(elem (i32.const !pushDataValueIndex) $pushDataValue)
|
||||
|
||||
(func $setLatestBody (param $v i32)
|
||||
(i32.store (call $body (get_global $latest)) (get_local $v)))
|
||||
(elem (i32.const !setLatestBodyIndex) $setLatestBody)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Helper functions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global __dirname */
|
||||
/* global __dirname, Buffer */
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
require("@babel/register")({
|
||||
|
@ -6,4 +6,6 @@ require("@babel/register")({
|
|||
});
|
||||
const loadTests = require("./tests.js").default;
|
||||
const wasmModule = fs.readFileSync(path.join(__dirname, "../src/waforth.wasm"));
|
||||
loadTests(wasmModule);
|
||||
loadTests(wasmModule, s => {
|
||||
return Buffer.from(s).toString("base64");
|
||||
});
|
||||
|
|
|
@ -2,12 +2,12 @@ import WAForth from "../src/shell/WAForth";
|
|||
import sieve from "../src/shell/sieve";
|
||||
import { expect } from "chai";
|
||||
|
||||
function loadTests(wasmModule) {
|
||||
function loadTests(wasmModule, arrayToBase64) {
|
||||
describe("WAForth", () => {
|
||||
let forth, stack, output, core, memory, memory8;
|
||||
|
||||
beforeEach(() => {
|
||||
forth = new WAForth(wasmModule);
|
||||
forth = new WAForth(wasmModule, arrayToBase64);
|
||||
forth.onEmit = c => {
|
||||
output = output + String.fromCharCode(c);
|
||||
};
|
||||
|
@ -827,7 +827,7 @@ function loadTests(wasmModule) {
|
|||
it("should find a word", () => {
|
||||
loadString("DUP");
|
||||
run("FIND");
|
||||
expect(stack[0]).to.eql(131768);
|
||||
expect(stack[0]).to.eql(131784);
|
||||
expect(stack[1]).to.eql(-1);
|
||||
});
|
||||
|
||||
|
@ -1211,16 +1211,16 @@ function loadTests(wasmModule) {
|
|||
});
|
||||
});
|
||||
|
||||
// describe.only("DOES>", () => {
|
||||
// it("should work", () => {
|
||||
// run(": ID CREATE 23 , DOES> @ ;");
|
||||
// run("CREATE boo");
|
||||
// run("boo boo 44");
|
||||
// expect(stack[0]).to.eql(23);
|
||||
// expect(stack[1]).to.eql(23);
|
||||
// expect(stack[2]).to.eql(44);
|
||||
// });
|
||||
// });
|
||||
describe("DOES>", () => {
|
||||
it("should work", () => {
|
||||
run(": ID CREATE 23 , DOES> @ ;");
|
||||
run("ID boo");
|
||||
run("boo boo 44");
|
||||
expect(stack[0]).to.eql(23);
|
||||
expect(stack[1]).to.eql(23);
|
||||
expect(stack[2]).to.eql(44);
|
||||
});
|
||||
});
|
||||
|
||||
describe("UWIDTH", () => {
|
||||
beforeEach(() => {
|
||||
|
|
Loading…
Reference in a new issue