Implement DOES>

This commit is contained in:
Remko Tronçon 2019-03-10 14:32:41 +01:00
parent f7a1ab2aa2
commit 2a7322cfa5
4 changed files with 62 additions and 39 deletions

View file

@ -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 }

View file

@ -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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -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");
});

View file

@ -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(() => {