mirror of
https://github.com/remko/waforth
synced 2024-12-27 09:59:29 +01:00
webpack -> esbuild
This commit is contained in:
parent
e50fbe7e1c
commit
6b9de10002
34 changed files with 2568 additions and 5149 deletions
|
@ -1 +1 @@
|
|||
dist
|
||||
public/waforth/dist
|
||||
|
|
14
.eslintrc
14
.eslintrc
|
@ -1,14 +0,0 @@
|
|||
env:
|
||||
browser: true
|
||||
es6: true
|
||||
extends: eslint:recommended
|
||||
parserOptions:
|
||||
sourceType: module
|
||||
globals:
|
||||
WebAssembly: true
|
||||
require: true
|
||||
rules:
|
||||
no-console: 0
|
||||
settings:
|
||||
react:
|
||||
version: "16.0"
|
23
.eslintrc.yml
Normal file
23
.eslintrc.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
env:
|
||||
browser: true
|
||||
es2021: true
|
||||
node: true
|
||||
extends:
|
||||
- 'eslint:recommended'
|
||||
- 'plugin:react/recommended'
|
||||
- "plugin:react-hooks/recommended"
|
||||
parserOptions:
|
||||
ecmaFeatures:
|
||||
jsx: true
|
||||
ecmaVersion: 12
|
||||
sourceType: module
|
||||
plugins:
|
||||
- prettier
|
||||
- react
|
||||
settings:
|
||||
react:
|
||||
version: detect
|
||||
rules:
|
||||
"prettier/prettier": "error"
|
||||
react/display-name: 0
|
||||
react/prop-types: 0
|
20
.github/workflows/build.yml
vendored
Normal file
20
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
cache: 'yarn'
|
||||
- run: sudo apt-get install wabt
|
||||
- run: yarnpkg --pure-lockfile
|
||||
- run: yarnpkg build
|
||||
- run: yarnpkg lint
|
||||
- run: yarnpkg test --coverage
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,7 +1,6 @@
|
|||
.DS_Store
|
||||
.cache/
|
||||
node_modules/
|
||||
dist/
|
||||
public/waforth/
|
||||
src/waforth.bulkmem.wat
|
||||
src/waforth.vanilla.wat
|
||||
*.wasm
|
||||
|
|
36
.vscode/settings.json
vendored
Normal file
36
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"editor.tabSize": 2,
|
||||
"files.exclude": {
|
||||
"bin/": true,
|
||||
"build/": true,
|
||||
"**/node_modules/": true,
|
||||
"coverage/": true
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/node_modules": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
}
|
24
Makefile
24
Makefile
|
@ -5,15 +5,19 @@ ifeq ($(DEBUG),1)
|
|||
WAT2WASM_FLAGS:=$(WAT2WASM_FLAGS) --debug-names
|
||||
endif
|
||||
|
||||
WASM_FILES=src/waforth.wasm src/waforth.bulkmem.wasm tests/benchmarks/sieve-vanilla.wasm
|
||||
|
||||
all: $(WASM_FILES)
|
||||
all:
|
||||
yarn -s build
|
||||
|
||||
dev-server: $(WASM_FILES)
|
||||
yarn -s dev-server
|
||||
dev:
|
||||
yarn -s dev
|
||||
|
||||
wasm: $(WASM_FILES) src/waforth.assembled.wat src/tools/quadruple.wasm.hex
|
||||
check: src/waforth.wasm
|
||||
yarn -s test
|
||||
|
||||
check-watch: src/waforth.wasm
|
||||
yarn -s test-watch
|
||||
|
||||
wasm: src/waforth.assembled.wat src/tools/quadruple.wasm.hex
|
||||
|
||||
process: src/waforth.vanilla.wat
|
||||
cp $< src/waforth.wat
|
||||
|
@ -30,7 +34,7 @@ src/waforth.bulkmem.wasm: src/waforth.bulkmem.wat
|
|||
src/waforth.bulkmem.wat: src/waforth.wat
|
||||
./src/tools/process.js --enable-bulk-memory $< > $@
|
||||
|
||||
tests/benchmarks/sieve-vanilla.wasm: tests/benchmarks/sieve-vanilla.wat
|
||||
src/benchmarks/sieve-vanilla.wasm: src/benchmarks/sieve-vanilla.wat
|
||||
$(WAT2WASM) $(WAT2WASM_FLAGS) -o $@ $<
|
||||
|
||||
src/tools/quadruple.wasm: src/tools/quadruple.wat
|
||||
|
@ -42,11 +46,5 @@ src/tools/quadruple.wasm.hex: src/tools/quadruple.wasm
|
|||
clean:
|
||||
-rm -rf $(WASM_FILES) src/tools/quadruple.wasm src/tools/quadruple.wasm.hex src/waforth.wat.tmp dist
|
||||
|
||||
check: $(WASM_FILES)
|
||||
yarn -s test
|
||||
|
||||
check-watch: $(WASM_FILES)
|
||||
yarn -s test-watch
|
||||
|
||||
lint:
|
||||
yarn -s lint
|
||||
|
|
|
@ -40,7 +40,7 @@ To build everything:
|
|||
|
||||
To run the development server:
|
||||
|
||||
make dev-server
|
||||
make dev
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
161
build.js
Executable file
161
build.js
Executable file
|
@ -0,0 +1,161 @@
|
|||
#!/usr/bin/env node
|
||||
/* eslint-env node */
|
||||
|
||||
const esbuild = require("esbuild");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { createServer } = require("http");
|
||||
const nstatic = require("node-static");
|
||||
const { promisify } = require("util");
|
||||
const exec = promisify(require("child_process").exec);
|
||||
|
||||
function withWatcher(config, handleBuildFinished = () => {}, port = 8880) {
|
||||
const watchClients = [];
|
||||
createServer((req, res) => {
|
||||
return watchClients.push(
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Connection: "keep-alive",
|
||||
})
|
||||
);
|
||||
}).listen(port);
|
||||
return {
|
||||
...config,
|
||||
banner: {
|
||||
js: `(function () { new EventSource("http://localhost:${port}").onmessage = function() { location.reload();};})();`,
|
||||
},
|
||||
watch: {
|
||||
async onRebuild(error, result) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
} else {
|
||||
// Doing this first, because this may do some ES5 transformations
|
||||
await handleBuildFinished(result);
|
||||
|
||||
watchClients.forEach((res) => res.write("data: update\n\n"));
|
||||
watchClients.length = 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let dev = false;
|
||||
let watch = false;
|
||||
for (const arg of process.argv.slice(2)) {
|
||||
switch (arg) {
|
||||
case "--development":
|
||||
dev = true;
|
||||
break;
|
||||
case "--watch":
|
||||
watch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let buildConfig = {
|
||||
bundle: true,
|
||||
logLevel: "info",
|
||||
entryPoints: [
|
||||
path.join(__dirname, "src", "shell", "shell"),
|
||||
path.join(__dirname, "src", "tests", "tests"),
|
||||
path.join(__dirname, "src", "benchmarks", "benchmarks"),
|
||||
],
|
||||
entryNames: dev ? "[name]" : "[name]-c$[hash]",
|
||||
assetNames: "[name]-c$[hash]",
|
||||
// target: "es6",
|
||||
outdir: path.join(__dirname, "public/waforth/dist"),
|
||||
external: ["fs", "stream", "util", "events"],
|
||||
minify: !dev,
|
||||
loader: {
|
||||
".wasm": "binary",
|
||||
".js": "jsx",
|
||||
".png": "file",
|
||||
".m4a": "file",
|
||||
".woff2": "file",
|
||||
".svg": "file",
|
||||
".woff": "file",
|
||||
".ttf": "file",
|
||||
".eot": "file",
|
||||
".md": "text",
|
||||
},
|
||||
sourcemap: true,
|
||||
metafile: true,
|
||||
plugins: [
|
||||
{
|
||||
name: "wat",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /.\.wat$/ }, async (args) => {
|
||||
if (args.resolveDir === "") {
|
||||
return;
|
||||
}
|
||||
const watPath = path.isAbsolute(args.path)
|
||||
? args.path
|
||||
: path.join(args.resolveDir, args.path);
|
||||
return {
|
||||
path: watPath,
|
||||
namespace: "wat",
|
||||
watchFiles: [watPath],
|
||||
};
|
||||
});
|
||||
build.onLoad({ filter: /.*/, namespace: "wat" }, async (args) => {
|
||||
// Would be handy if we could get output from stdout without going through file
|
||||
const out = args.path.replace(".wat", ".wasm");
|
||||
const flags = "";
|
||||
// flags = --debug-names
|
||||
// console.log("wat: compiling %s", args.path);
|
||||
await exec(`wat2wasm ${flags} --output=${out} ${args.path}`);
|
||||
return {
|
||||
contents: await fs.promises.readFile(out),
|
||||
loader: "binary",
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const INDEX_TEMPLATE = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="/waforth/dist/$BASE.css" rel="stylesheet" />
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="/waforth/dist/$BASE.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
async function handleBuildFinished(result) {
|
||||
let index = INDEX_TEMPLATE.replace(/\$BASE/g, "shell");
|
||||
let testIndex = INDEX_TEMPLATE.replace(/\$BASE/g, "tests");
|
||||
let benchmarksIndex = INDEX_TEMPLATE.replace(/\$BASE/g, "benchmarks");
|
||||
// console.log(JSON.stringify(result.metafile.outputs, undefined, 2));
|
||||
for (const [out] of Object.entries(result.metafile.outputs)) {
|
||||
const outfile = path.basename(out);
|
||||
const sourcefile = outfile.replace(/-c\$[^.]+\./, ".");
|
||||
// console.log("%s -> %s", sourcefile, outfile);
|
||||
index = index.replace(`/${sourcefile}`, `/${outfile}`);
|
||||
testIndex = testIndex.replace(`/${sourcefile}`, `/${outfile}`);
|
||||
benchmarksIndex = benchmarksIndex.replace(`/${sourcefile}`, `/${outfile}`);
|
||||
}
|
||||
fs.writeFileSync("public/waforth/index.html", index);
|
||||
fs.mkdirSync("public/waforth/tests", { recursive: true });
|
||||
fs.writeFileSync("public/waforth/tests/index.html", testIndex);
|
||||
fs.mkdirSync("public/waforth/benchmarks", { recursive: true });
|
||||
fs.writeFileSync("public/waforth/benchmarks/index.html", benchmarksIndex);
|
||||
}
|
||||
|
||||
if (watch) {
|
||||
const file = new nstatic.Server(path.join(__dirname, "public"));
|
||||
createServer(function (req, res) {
|
||||
file.serve(req, res);
|
||||
}).listen(8080);
|
||||
console.log("listening on port 8080");
|
||||
buildConfig = withWatcher(buildConfig, handleBuildFinished, 8081);
|
||||
}
|
||||
esbuild.build(buildConfig).then(handleBuildFinished, () => process.exit(1));
|
|
@ -40,7 +40,7 @@ function here() {
|
|||
|
||||
WebAssembly.instantiate(coreWasm, {
|
||||
shell: {
|
||||
emit: c => {
|
||||
emit: (c) => {
|
||||
process.stdout.write(String.fromCharCode(c));
|
||||
},
|
||||
|
||||
|
@ -51,7 +51,7 @@ WebAssembly.instantiate(coreWasm, {
|
|||
return buffer.pop();
|
||||
},
|
||||
|
||||
debug: c => {
|
||||
debug: (c) => {
|
||||
process.stderr.write(String.fromCharCode(c));
|
||||
},
|
||||
|
||||
|
@ -64,11 +64,11 @@ WebAssembly.instantiate(coreWasm, {
|
|||
var module = new WebAssembly.Module(data);
|
||||
modules.push(new Uint8Array(Array.from(data)));
|
||||
new WebAssembly.Instance(module, {
|
||||
env: { table, memory, tos: -1 }
|
||||
env: { table, memory, tos: -1 },
|
||||
});
|
||||
}
|
||||
}
|
||||
}).then(instance => {
|
||||
},
|
||||
},
|
||||
}).then((instance) => {
|
||||
core = instance.instance;
|
||||
table = core.exports.table;
|
||||
memory = core.exports.memory;
|
||||
|
@ -99,7 +99,7 @@ WebAssembly.instantiate(coreWasm, {
|
|||
"#define WAFORTH_HERE " + savedHere + "\n",
|
||||
"#define WAFORTH_TABLE_SIZE " + tableSize + "\n",
|
||||
"void waforth_modules_init();",
|
||||
"#undef WASM_RT_MODULE_PREFIX"
|
||||
"#undef WASM_RT_MODULE_PREFIX",
|
||||
];
|
||||
const init = [
|
||||
"#include <memory.h>",
|
||||
|
@ -112,7 +112,7 @@ WebAssembly.instantiate(coreWasm, {
|
|||
dictionaryStart +
|
||||
"], dictionary, " +
|
||||
(savedHere - dictionaryStart) +
|
||||
");"
|
||||
");",
|
||||
];
|
||||
const moduleFiles = [];
|
||||
for (let i = 0; i < modules.length; ++i) {
|
||||
|
|
45
package.json
45
package.json
|
@ -2,37 +2,34 @@
|
|||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"immutability-helper": "^3.0.0",
|
||||
"jq-console": "^2.13.2",
|
||||
"jquery": "^3.5.0",
|
||||
"preact": "^8.2.9",
|
||||
"promise-polyfill": "^7.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.4",
|
||||
"@babel/preset-env": "^7.3.4",
|
||||
"@babel/register": "^7.0.0",
|
||||
"babel-loader": "^8.0.5",
|
||||
"babel-preset-preact": "^2.0.0",
|
||||
"bin-loader": "^0.1.0",
|
||||
"chai": "^4.2.0",
|
||||
"commander": "^4.0.0",
|
||||
"css-loader": "^2.1.1",
|
||||
"eslint": "5.15.1",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"@babel/core": "^7.17.9",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/register": "^7.17.7",
|
||||
"chai": "^4.3.6",
|
||||
"commander": "^9.1.0",
|
||||
"esbuild": "^0.14.36",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.4.0",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mocha": "^6.1.4",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.2.3",
|
||||
"webpack-dev-server": "^3.2.1"
|
||||
"mocha": "^9.2.2",
|
||||
"node-static": "^0.7.11",
|
||||
"prettier": "^2.6.2",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --mode=production",
|
||||
"test": "mocha tests/index-node.js",
|
||||
"test-watch": "mocha --watch tests/index-node.js",
|
||||
"lint": "eslint .",
|
||||
"dev-server": "webpack-dev-server --open --openPage waforth --content-base public"
|
||||
"build": "./build.js",
|
||||
"dev": "./build.js --watch --development",
|
||||
"test": "mocha src/tests/tests.node.js",
|
||||
"test-watch": "mocha --watch src/tests/tests.node.js",
|
||||
"lint": "eslint ."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import WAForth from "../../src/shell/WAForth";
|
||||
import sieve from "../../src/shell/sieve";
|
||||
import sieveVanillaModule from "./sieve-vanilla.wasm";
|
||||
import { Component, render, h } from "preact";
|
||||
import sieveVanillaModule from "./sieve-vanilla.wat";
|
||||
import update from "immutability-helper";
|
||||
import "./index.css";
|
||||
import "./benchmarks.css";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initial setup
|
||||
|
@ -13,7 +14,7 @@ const setup = [];
|
|||
|
||||
const forth = new WAForth();
|
||||
let outputBuffer = [];
|
||||
forth.onEmit = c => {
|
||||
forth.onEmit = (c) => {
|
||||
outputBuffer.push(String.fromCharCode(c));
|
||||
};
|
||||
setup.push(
|
||||
|
@ -26,9 +27,9 @@ let sieveVanilla;
|
|||
setup.push(
|
||||
WebAssembly.instantiate(sieveVanillaModule, {
|
||||
js: {
|
||||
print: x => console.log(x)
|
||||
}
|
||||
}).then(instance => {
|
||||
print: (x) => console.log(x),
|
||||
},
|
||||
}).then((instance) => {
|
||||
sieveVanilla = instance.instance.exports.sieve;
|
||||
})
|
||||
);
|
||||
|
@ -44,7 +45,7 @@ const benchmarks = [
|
|||
outputBuffer = [];
|
||||
forth.run(`${LIMIT} sieve`);
|
||||
return outputBuffer.join("");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sieve-direct",
|
||||
|
@ -52,21 +53,21 @@ const benchmarks = [
|
|||
outputBuffer = [];
|
||||
forth.run(`${LIMIT} sieve_direct .`);
|
||||
return outputBuffer.join("");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sieve-vanilla",
|
||||
fn: () => {
|
||||
return sieveVanilla(LIMIT);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const iterations = Array.from(Array(ITERATIONS).keys());
|
||||
|
||||
class Benchmarks extends Component {
|
||||
class Benchmarks extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const results = {};
|
||||
|
@ -74,7 +75,7 @@ class Benchmarks extends Component {
|
|||
this.state = {
|
||||
initialized: false,
|
||||
done: false,
|
||||
results
|
||||
results,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -91,10 +92,10 @@ class Benchmarks extends Component {
|
|||
results: update(this.state.results, {
|
||||
[benchmarks[benchmarkIndex].name]: {
|
||||
[benchmarkIteration]: {
|
||||
$set: { time: (t2 - t1) / 1000.0, output }
|
||||
}
|
||||
}
|
||||
})
|
||||
$set: { time: (t2 - t1) / 1000.0, output },
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (benchmarkIteration < ITERATIONS - 1) {
|
||||
benchmarkIteration += 1;
|
||||
|
@ -122,7 +123,9 @@ class Benchmarks extends Component {
|
|||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
{iterations.map(i => <th key={i}>{i}</th>)}
|
||||
{iterations.map((i) => (
|
||||
<th key={i}>{i}</th>
|
||||
))}
|
||||
<th>Avg</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -133,7 +136,7 @@ class Benchmarks extends Component {
|
|||
return [
|
||||
<tr key={`${name}-time`}>
|
||||
<th>{name}</th>
|
||||
{iterations.map(i => (
|
||||
{iterations.map((i) => (
|
||||
<td key={i}>
|
||||
{benchmark[i] == null ? null : (
|
||||
<span>{benchmark[i].time.toFixed(2)}s</span>
|
||||
|
@ -150,14 +153,14 @@ class Benchmarks extends Component {
|
|||
</tr>,
|
||||
<tr key={`${name}-output`}>
|
||||
<th />
|
||||
{iterations.map(i => (
|
||||
{iterations.map((i) => (
|
||||
<td key={i}>
|
||||
<pre className="output">
|
||||
{benchmark[i] == null ? null : benchmark[i].output}
|
||||
</pre>
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
</tr>,
|
||||
];
|
||||
})}
|
||||
</tbody>
|
||||
|
@ -166,4 +169,7 @@ class Benchmarks extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
render(<Benchmarks />, document.body);
|
||||
|
||||
const rootEl = document.createElement("div");
|
||||
document.body.appendChild(rootEl);
|
||||
createRoot(rootEl).render(<Benchmarks />);
|
|
@ -5,7 +5,7 @@ const isSafari =
|
|||
class WAForth {
|
||||
constructor(wasmModule, arrayToBase64) {
|
||||
if (wasmModule == null) {
|
||||
this.wasmModule = require("../waforth.wasm");
|
||||
this.wasmModule = require("../waforth.wat");
|
||||
} else {
|
||||
this.wasmModule = wasmModule;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class WAForth {
|
|||
return buffer.pop();
|
||||
},
|
||||
|
||||
debug: d => {
|
||||
debug: (d) => {
|
||||
console.log("DEBUG: ", d, String.fromCharCode(d));
|
||||
},
|
||||
|
||||
|
@ -88,11 +88,11 @@ class WAForth {
|
|||
// console.log("Load", index, this.arrayToBase64(data));
|
||||
var module = new WebAssembly.Module(data);
|
||||
new WebAssembly.Instance(module, {
|
||||
env: { table, memory, tos: -1 }
|
||||
env: { table, memory, tos: -1 },
|
||||
});
|
||||
}
|
||||
}
|
||||
}).then(instance => {
|
||||
},
|
||||
},
|
||||
}).then((instance) => {
|
||||
this.core = instance.instance;
|
||||
table = this.core.exports.table;
|
||||
memory = this.core.exports.memory;
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="console"></div>
|
||||
<div class="messageContainer">
|
||||
<div class="message" id="message"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -20,15 +20,15 @@ body {
|
|||
}
|
||||
|
||||
.message.error {
|
||||
color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* The console container element */
|
||||
#console {
|
||||
/* The console container element */
|
||||
.console {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color:black;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
/* The inner console element. */
|
||||
|
@ -49,31 +49,31 @@ body {
|
|||
|
||||
/* The cursor. */
|
||||
.jqconsole-cursor {
|
||||
background-color: gray;
|
||||
background-color: gray;
|
||||
}
|
||||
/* The cursor color when the console looses focus. */
|
||||
.jqconsole-blurred .jqconsole-cursor {
|
||||
background-color: #666;
|
||||
background-color: #666;
|
||||
}
|
||||
/* The current prompt text color */
|
||||
.jqconsole-prompt {
|
||||
color: #dd0;
|
||||
color: #dd0;
|
||||
}
|
||||
/* The command history */
|
||||
.jqconsole-old-prompt {
|
||||
color: #bb0;
|
||||
font-weight: normal;
|
||||
color: #bb0;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* The text color when in input mode. */
|
||||
.jqconsole-input {
|
||||
color: #0d0;
|
||||
color: #0d0;
|
||||
}
|
||||
/* Previously entered input. */
|
||||
.jqconsole-old-input {
|
||||
color: #0b0;
|
||||
font-weight: normal;
|
||||
color: #0b0;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* The text color of the output. */
|
||||
.jqconsole-output {
|
||||
color: white;
|
||||
color: white;
|
||||
}
|
|
@ -2,25 +2,38 @@ import "promise-polyfill/src/polyfill";
|
|||
import $ from "jquery";
|
||||
import WAForth from "./WAForth";
|
||||
import sieve from "./sieve";
|
||||
import "./index.css";
|
||||
import "./shell.css";
|
||||
|
||||
window.jQuery = $;
|
||||
require("jq-console");
|
||||
|
||||
document.title = "WAForth";
|
||||
|
||||
const forth = new WAForth();
|
||||
|
||||
let jqconsole = $("#console").jqconsole("WAForth\n", "");
|
||||
$("#console").hide();
|
||||
const consoleEl = document.createElement("div");
|
||||
consoleEl.className = "console";
|
||||
document.body.appendChild(consoleEl);
|
||||
|
||||
const messageContainerEl = document.createElement("div");
|
||||
messageContainerEl.className = "messageContainer";
|
||||
const messageEl = document.createElement("div");
|
||||
messageEl.className = "message";
|
||||
messageContainerEl.appendChild(messageEl);
|
||||
document.body.appendChild(messageContainerEl);
|
||||
|
||||
let jqconsole = $(consoleEl).jqconsole("WAForth\n", "");
|
||||
$(consoleEl).hide();
|
||||
$(".jqconsole-header").html(
|
||||
"<span><a target='_blank' href='https://github.com/remko/waforth'>WAForth</a>\n</span>"
|
||||
);
|
||||
let outputBuffer = [];
|
||||
forth.onEmit = c => {
|
||||
forth.onEmit = (c) => {
|
||||
outputBuffer.push(String.fromCharCode(c));
|
||||
};
|
||||
|
||||
function prompt() {
|
||||
jqconsole.Prompt(false, input => {
|
||||
jqconsole.Prompt(false, (input) => {
|
||||
jqconsole.Write(" ");
|
||||
|
||||
// Avoid console inserting a newline
|
||||
|
@ -38,18 +51,16 @@ function prompt() {
|
|||
});
|
||||
}
|
||||
|
||||
$("#message").text("Loading...");
|
||||
$(messageEl).text("Loading...");
|
||||
forth.start().then(
|
||||
() => {
|
||||
forth.run(sieve);
|
||||
outputBuffer = [];
|
||||
$("#message").hide();
|
||||
$("#console").show();
|
||||
$(messageEl).hide();
|
||||
$(consoleEl).show();
|
||||
prompt();
|
||||
},
|
||||
() => {
|
||||
$("#message")
|
||||
.addClass("error")
|
||||
.text("Error");
|
||||
$(messageEl).addClass("error").text("Error");
|
||||
}
|
||||
);
|
|
@ -1,5 +1,5 @@
|
|||
import WAForth from "../src/shell/WAForth";
|
||||
import sieve from "../src/shell/sieve";
|
||||
import WAForth from "../shell/WAForth";
|
||||
import sieve from "../shell/sieve";
|
||||
import standardTestSuiteTester from "./standard-testsuite/tester.f";
|
||||
import standardCoreWordsTestSuite from "./standard-testsuite/core.f";
|
||||
import { expect, assert } from "chai";
|
||||
|
@ -10,7 +10,7 @@ function loadTests(wasmModule, arrayToBase64) {
|
|||
|
||||
beforeEach(() => {
|
||||
forth = new WAForth(wasmModule, arrayToBase64);
|
||||
forth.onEmit = c => {
|
||||
forth.onEmit = (c) => {
|
||||
output = output + String.fromCharCode(c);
|
||||
// console.log(output);
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ function loadTests(wasmModule, arrayToBase64) {
|
|||
stack = new Int32Array(core.memory.buffer, core.tos(), 0x100);
|
||||
initialTOS = core.tos();
|
||||
},
|
||||
err => {
|
||||
(err) => {
|
||||
console.error(err);
|
||||
}
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ function loadTests(wasmModule, arrayToBase64) {
|
|||
}
|
||||
|
||||
function run(ss, expectErrors = false) {
|
||||
ss.split("\n").forEach(s => {
|
||||
ss.split("\n").forEach((s) => {
|
||||
// console.log("Running: ", s);
|
||||
const r = forth.run(s);
|
||||
if (expectErrors) {
|
18
src/tests/tests.js
Normal file
18
src/tests/tests.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import mocha from "mocha/mocha.js";
|
||||
import loadTests from "./suite";
|
||||
import "mocha/mocha.css";
|
||||
|
||||
const h1El = document.createElement("h1");
|
||||
h1El.style = "font-family: sans-serif; margin: 1rem;";
|
||||
h1El.appendChild(document.createTextNode("WAForth Unit Tests"));
|
||||
document.body.appendChild(h1El);
|
||||
|
||||
const mochaEl = document.createElement("div");
|
||||
mochaEl.id = "mocha";
|
||||
document.body.appendChild(mochaEl);
|
||||
|
||||
mocha.setup("bdd");
|
||||
loadTests();
|
||||
// mocha.checkLeaks();
|
||||
mocha.globals(["jQuery"]);
|
||||
mocha.run();
|
10
src/tests/tests.node.js
Normal file
10
src/tests/tests.node.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
require("@babel/register")({
|
||||
presets: ["@babel/preset-env"],
|
||||
});
|
||||
const loadTests = require("./suite.js").default;
|
||||
const wasmModule = fs.readFileSync(path.join(__dirname, "../waforth.wasm"));
|
||||
loadTests(wasmModule, (s) => {
|
||||
return Buffer.from(s).toString("base64");
|
||||
});
|
|
@ -26,7 +26,7 @@ const dictionaryEntry = [
|
|||
encodeLE(latest, 4),
|
||||
encodeLE(name.length | flags, 1),
|
||||
_.padEnd(name, 4 * Math.floor((name.length + 4) / 4) - 1, "0"),
|
||||
encodeLE(nextTableIndex, 4)
|
||||
encodeLE(nextTableIndex, 4),
|
||||
];
|
||||
console.log(
|
||||
"(data (i32.const 0x" +
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
TODO
|
||||
;;; !moduleHeaderSize := (string-length !moduleHeader))
|
||||
;;; !moduleHeaderCodeSizeOffset := (char-index (string->list !moduleHeader) \FF 0))
|
||||
;;; !moduleHeaderBodySizeOffset := (char-index (string->list !moduleHeader) \FE 0))
|
||||
;;; !moduleHeaderLocalCountOffset := (char-index (string->list !moduleHeader) \FD 0))
|
||||
;;; !moduleHeaderTableIndexOffset := (char-index (string->list !moduleHeader) \FC 0))
|
||||
;;; !moduleHeaderTableInitialSizeOffset := (char-index (string->list !moduleHeader) \FB 0))
|
||||
;;; !moduleHeaderFunctionTypeOffset := (char-index (string->list !moduleHeader) \FA 0))
|
||||
// TODO
|
||||
// ;;; !moduleHeaderSize := (string-length !moduleHeader))
|
||||
// ;;; !moduleHeaderCodeSizeOffset := (char-index (string->list !moduleHeader) \FF 0))
|
||||
// ;;; !moduleHeaderBodySizeOffset := (char-index (string->list !moduleHeader) \FE 0))
|
||||
// ;;; !moduleHeaderLocalCountOffset := (char-index (string->list !moduleHeader) \FD 0))
|
||||
// ;;; !moduleHeaderTableIndexOffset := (char-index (string->list !moduleHeader) \FC 0))
|
||||
// ;;; !moduleHeaderTableInitialSizeOffset := (char-index (string->list !moduleHeader) \FB 0))
|
||||
// ;;; !moduleHeaderFunctionTypeOffset := (char-index (string->list !moduleHeader) \FA 0))
|
||||
|
|
|
@ -12,22 +12,19 @@ program
|
|||
"--enable-bulk-memory",
|
||||
"use bulk memory operations instead of own implementation"
|
||||
)
|
||||
.action(f => {
|
||||
.action((f) => {
|
||||
file = f;
|
||||
});
|
||||
program.parse(process.argv);
|
||||
|
||||
const lines = fs
|
||||
.readFileSync(file)
|
||||
.toString()
|
||||
.split("\n");
|
||||
const lines = fs.readFileSync(file).toString().split("\n");
|
||||
|
||||
const definitions = {};
|
||||
let skipLevel = 0;
|
||||
let skippingDefinition = false;
|
||||
lines.forEach(line => {
|
||||
lines.forEach((line) => {
|
||||
// Constants
|
||||
Object.keys(definitions).forEach(k => {
|
||||
Object.keys(definitions).forEach((k) => {
|
||||
line = line.replace(
|
||||
new RegExp(
|
||||
"(\\s)([^\\s])+(\\s)+\\(; = " + _.escapeRegExp(k) + " ;\\)",
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
/* global __dirname, Buffer */
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
require("@babel/register")({
|
||||
presets: ["@babel/preset-env"]
|
||||
});
|
||||
const loadTests = require("./tests.js").default;
|
||||
const wasmModule = fs.readFileSync(path.join(__dirname, "../src/waforth.wasm"));
|
||||
loadTests(wasmModule, s => {
|
||||
return Buffer.from(s).toString("base64");
|
||||
});
|
|
@ -1,14 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link href="https://cdn.jsdelivr.net/gh/mochajs/mocha@2.2.5/mocha.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: sans-serif; margin: 1rem; ">
|
||||
<%= htmlWebpackPlugin.options.title %>
|
||||
</h1>
|
||||
<div style="margin-top: 30px;" id="mocha"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
import { mocha } from "mocha";
|
||||
import loadTests from "./tests";
|
||||
|
||||
mocha.setup("bdd");
|
||||
loadTests();
|
||||
// mocha.checkLeaks();
|
||||
mocha.globals(["jQuery"]);
|
||||
mocha.run();
|
|
@ -1,91 +0,0 @@
|
|||
/*eslint-env node*/
|
||||
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const webpack = require("webpack");
|
||||
|
||||
function config({ entry, outputDir, title, template, mode }) {
|
||||
mode = mode || "development";
|
||||
const result = {
|
||||
mode,
|
||||
entry,
|
||||
output: {
|
||||
filename: "index.js",
|
||||
path: path.resolve(__dirname, "dist", outputDir),
|
||||
publicPath: "/" + outputDir
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$|\.jsx$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [["@babel/preset-env", { modules: false }], "preact"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [{ loader: "style-loader" }, { loader: "css-loader" }]
|
||||
},
|
||||
{
|
||||
test: /\.wasm$/,
|
||||
exclude: /node_modules/,
|
||||
type: "javascript/auto",
|
||||
use: { loader: "bin-loader" }
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ContextReplacementPlugin(/mocha\/lib/, "", false),
|
||||
new HtmlWebpackPlugin(
|
||||
Object.assign(
|
||||
{
|
||||
title,
|
||||
meta: {
|
||||
viewport: "width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
}
|
||||
},
|
||||
template ? { template } : {}
|
||||
)
|
||||
)
|
||||
],
|
||||
// Mocha requires this
|
||||
node: {
|
||||
fs: "empty"
|
||||
},
|
||||
// Mocha requires this
|
||||
performance: { hints: false }
|
||||
};
|
||||
if (mode === "development") {
|
||||
result.devtool = "cheap-module-eval-source-map";
|
||||
} else {
|
||||
result.devtool = "source-map";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = (env, argv) => [
|
||||
config({
|
||||
title: "WAForth",
|
||||
template: "./src/shell/index.html",
|
||||
entry: "./src/shell/index.js",
|
||||
outputDir: "waforth",
|
||||
mode: argv.mode
|
||||
}),
|
||||
config({
|
||||
title: "WAForth Unit Tests",
|
||||
template: "./tests/index.html",
|
||||
entry: "./tests/index.js",
|
||||
outputDir: "tests",
|
||||
mode: argv.mode
|
||||
}),
|
||||
config({
|
||||
title: "Benchmarks",
|
||||
entry: "./tests/benchmarks/index.js",
|
||||
outputDir: "benchmarks",
|
||||
mode: argv.mode
|
||||
})
|
||||
];
|
Loading…
Reference in a new issue