2018-02-02 03:07:54 +01:00
|
|
|
const fs = require("fs");
|
|
|
|
const path = require("path");
|
|
|
|
const chalk = require("chalk");
|
|
|
|
const glob = require("glob");
|
|
|
|
const diff = require("./util/diff");
|
2017-12-02 01:14:15 +01:00
|
|
|
|
2017-12-11 02:03:15 +01:00
|
|
|
require("ts-node").register({ project: require("path").join(__dirname, "..", "src") });
|
|
|
|
require("../src/glue/js");
|
2017-09-29 17:25:02 +02:00
|
|
|
|
2018-02-02 03:07:54 +01:00
|
|
|
const { Compiler, Options } = require("../src/compiler");
|
|
|
|
const { Module } = require("../src/module");
|
|
|
|
const { Parser } = require("../src/parser");
|
|
|
|
const { ElementKind, LIBRARY_PREFIX } = require("../src/program");
|
2017-12-11 02:03:15 +01:00
|
|
|
|
|
|
|
var isCreate = process.argv[2] === "--create";
|
2017-12-16 02:27:39 +01:00
|
|
|
var filter = process.argv.length > 2 && !isCreate ? "**/" + process.argv[2] + ".ts" : "**/*.ts";
|
|
|
|
|
2018-02-02 03:07:54 +01:00
|
|
|
var stdDir = path.join(__dirname, "..", "std", "assembly");
|
2018-01-28 15:30:49 +01:00
|
|
|
var stdFiles = glob.sync("*.ts", { cwd: stdDir });
|
2017-10-11 17:03:22 +02:00
|
|
|
|
2018-01-10 13:09:05 +01:00
|
|
|
var success = 0;
|
|
|
|
var failures = 0;
|
|
|
|
|
2018-02-02 03:07:54 +01:00
|
|
|
glob.sync(filter, { cwd: path.join(__dirname, "compiler") }).forEach(filename => {
|
|
|
|
if (filename.charAt(0) == "_") return;
|
2018-01-10 13:09:05 +01:00
|
|
|
console.log(chalk.whiteBright("Testing compiler/" + filename));
|
2017-10-11 17:03:22 +02:00
|
|
|
|
2017-12-16 02:27:39 +01:00
|
|
|
var fixture = path.basename(filename, ".ts");
|
2018-01-10 13:09:05 +01:00
|
|
|
var startTime = process.hrtime();
|
2017-12-11 02:03:15 +01:00
|
|
|
var parser = new Parser();
|
2018-02-02 03:07:54 +01:00
|
|
|
var cwd = path.join(__dirname, "compiler");
|
|
|
|
|
|
|
|
// include stdlib in std/ tests only. doing this to reduce the sheer amount of
|
|
|
|
// program elements listed at the bottom of the basic fixtures.
|
2017-12-16 02:27:39 +01:00
|
|
|
if (filename.startsWith("std/")) {
|
2018-02-02 03:07:54 +01:00
|
|
|
stdFiles.forEach(file => parser.parseFile(fs.readFileSync(path.join(stdDir, file), { encoding: "utf8" }), LIBRARY_PREFIX + path.basename(file), false));
|
2017-12-16 02:27:39 +01:00
|
|
|
fixture = "std/" + fixture;
|
|
|
|
}
|
|
|
|
|
2018-02-02 03:07:54 +01:00
|
|
|
var sourceText = fs.readFileSync(path.join(cwd, filename), { encoding: "utf8" });
|
2017-12-02 01:14:15 +01:00
|
|
|
parser.parseFile(sourceText, filename, true);
|
2017-12-11 02:03:15 +01:00
|
|
|
var nextFile;
|
2017-12-02 01:14:15 +01:00
|
|
|
while ((nextFile = parser.nextFile()) !== null) {
|
2018-02-02 03:07:54 +01:00
|
|
|
if (nextFile.startsWith(LIBRARY_PREFIX)) {
|
|
|
|
sourceText = fs.readFileSync(path.join(stdDir, nextFile.substring(LIBRARY_PREFIX.length) + ".ts"), { encoding: "utf8" });
|
|
|
|
nextFile = nextFile + ".ts";
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
sourceText = fs.readFileSync(path.join(cwd, nextFile + ".ts"), { encoding: "utf8" });
|
|
|
|
nextFile += ".ts";
|
|
|
|
} catch (e) {
|
|
|
|
try {
|
|
|
|
sourceText = fs.readFileSync(path.join(cwd, nextFile, "index.ts"), { encoding: "utf8" });
|
|
|
|
nextFile += "/index.ts";
|
|
|
|
} catch (e) {
|
|
|
|
sourceText = fs.readFileSync(path.join(stdDir, nextFile + ".ts"), { encoding: "utf8" });
|
|
|
|
nextFile = LIBRARY_PREFIX + nextFile + ".ts";
|
|
|
|
// FIXME: what exactly is swallowing the error here?
|
|
|
|
}
|
|
|
|
}
|
2017-12-02 01:14:15 +01:00
|
|
|
}
|
2018-02-02 03:07:54 +01:00
|
|
|
parser.parseFile(sourceText, nextFile, false);
|
2017-12-02 01:14:15 +01:00
|
|
|
}
|
2017-12-11 02:03:15 +01:00
|
|
|
var program = parser.finish();
|
2018-02-02 03:07:54 +01:00
|
|
|
var options = new Options();
|
|
|
|
options.sourceMap = true;
|
2018-01-10 13:09:05 +01:00
|
|
|
var parseTime = process.hrtime(startTime);
|
|
|
|
startTime = process.hrtime();
|
2018-01-18 23:34:12 +01:00
|
|
|
var module;
|
|
|
|
try {
|
2018-02-02 03:07:54 +01:00
|
|
|
module = Compiler.compile(program, options);
|
2018-01-18 23:34:12 +01:00
|
|
|
} catch (e) {
|
|
|
|
failed = true;
|
|
|
|
module = Module.create();
|
|
|
|
console.log(chalk.red("compile ERROR: ") + e.stack);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
var compileTime = process.hrtime(startTime);
|
2017-12-27 02:37:53 +01:00
|
|
|
var actual = module.toText() + "(;\n[program.elements]\n " + elements(program.elements)
|
|
|
|
+ "\n[program.exports]\n " + elements(program.exports)
|
|
|
|
+ "\n;)\n";
|
2017-12-11 02:03:15 +01:00
|
|
|
var actualOptimized = null;
|
2017-12-02 01:14:15 +01:00
|
|
|
|
2018-01-10 13:09:05 +01:00
|
|
|
console.log("parse incl. I/O: " + ((parseTime[0] * 1e9 + parseTime[1]) / 1e6).toFixed(3) + "ms / compile: " + ((compileTime[0] * 1e9 + compileTime[1]) / 1e6).toFixed(3) + "ms");
|
|
|
|
|
|
|
|
var failed = false;
|
2017-12-03 23:04:33 +01:00
|
|
|
if (module.validate()) {
|
2018-01-10 13:09:05 +01:00
|
|
|
console.log(chalk.green("validate OK"));
|
2017-12-03 23:04:33 +01:00
|
|
|
try {
|
2018-02-02 03:07:54 +01:00
|
|
|
var binary = module.toBinary();
|
|
|
|
var wasmModule = new WebAssembly.Module(binary.output);
|
|
|
|
var wasmInstance = new WebAssembly.Instance(wasmModule, {
|
|
|
|
env: {
|
|
|
|
abort: function(msg, file, line, column) {
|
|
|
|
throw new Error("Assertion failed");
|
|
|
|
},
|
|
|
|
externalFunc: function(arg0, arg1, arg2) {
|
|
|
|
console.log("env.externalFunc called with: " + arg0 + ", " + arg1 + ", " + arg2);
|
2017-12-27 22:38:32 +01:00
|
|
|
},
|
2018-02-02 03:07:54 +01:00
|
|
|
externalConst: 1,
|
|
|
|
allocate_memory: function(size) {
|
|
|
|
console.log("env.allocate_memory called with: " + size);
|
|
|
|
return 0;
|
|
|
|
},
|
|
|
|
free_memory: function(ptr) {
|
|
|
|
console.log("env.free_memory called with: " + ptr);
|
2017-12-27 02:37:53 +01:00
|
|
|
}
|
2018-02-02 03:07:54 +01:00
|
|
|
},
|
|
|
|
external: {
|
|
|
|
externalFunc: function(arg0, arg1, arg2) {
|
|
|
|
console.log("external.externalFunc called with: " + arg0 + ", " + arg1 + ", " + arg2);
|
|
|
|
},
|
|
|
|
externalConst: 2
|
|
|
|
}
|
|
|
|
});
|
|
|
|
console.log(chalk.green("instantiate OK"));
|
2017-12-03 23:04:33 +01:00
|
|
|
} catch (e) {
|
2018-01-10 13:09:05 +01:00
|
|
|
failed = true;
|
2018-02-02 03:07:54 +01:00
|
|
|
console.log(chalk.red("instantiate ERROR: ") + e.stack);
|
2017-12-03 23:04:33 +01:00
|
|
|
}
|
2017-12-04 16:26:34 +01:00
|
|
|
module.optimize();
|
|
|
|
actualOptimized = module.toText();
|
2018-02-02 03:07:54 +01:00
|
|
|
if (isCreate) {
|
|
|
|
var binary = module.toBinary(fixture + ".optimized.wasm.map");
|
|
|
|
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wasm", binary.output);
|
|
|
|
if (binary.sourceMap != null)
|
|
|
|
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wasm.map", binary.sourceMap, { encoding: "utf8" });
|
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
} else {
|
2018-01-10 13:09:05 +01:00
|
|
|
failed = true;
|
|
|
|
console.log(chalk.red("validate ERROR"));
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2017-12-02 18:37:59 +01:00
|
|
|
|
2017-12-02 01:14:15 +01:00
|
|
|
if (isCreate) {
|
2017-12-16 02:27:39 +01:00
|
|
|
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".wast", actual, { encoding: "utf8" });
|
2017-12-02 18:37:59 +01:00
|
|
|
console.log("Created");
|
2017-12-04 16:26:34 +01:00
|
|
|
if (actualOptimized != null) {
|
2017-12-16 02:27:39 +01:00
|
|
|
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wast", actualOptimized, { encoding: "utf8" });
|
2017-12-04 16:26:34 +01:00
|
|
|
console.log("Created optimized");
|
|
|
|
}
|
2017-12-02 01:14:15 +01:00
|
|
|
} else {
|
2018-01-10 13:09:05 +01:00
|
|
|
var expected;
|
2017-12-15 02:50:55 +01:00
|
|
|
try {
|
2018-01-10 13:09:05 +01:00
|
|
|
expected = fs.readFileSync(__dirname + "/compiler/" + fixture + ".wast", { encoding: "utf8" });
|
2017-12-15 02:50:55 +01:00
|
|
|
} catch (e) {
|
2018-01-10 13:09:05 +01:00
|
|
|
expected = e.message + "\n";
|
2017-12-02 01:14:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
var diffs = diff(filename + ".wast", expected, actual);
|
|
|
|
if (diffs !== null) {
|
|
|
|
console.log(diffs);
|
|
|
|
console.log(chalk.red("diff ERROR"));
|
|
|
|
failed = true;
|
|
|
|
} else
|
|
|
|
console.log(chalk.green("diff OK"));
|
2017-12-02 01:14:15 +01:00
|
|
|
}
|
2017-12-02 18:37:59 +01:00
|
|
|
|
2017-12-03 23:04:33 +01:00
|
|
|
module.dispose();
|
2017-12-02 18:37:59 +01:00
|
|
|
console.log();
|
2018-01-10 13:09:05 +01:00
|
|
|
if (failed)
|
|
|
|
++failures;
|
2017-12-02 01:14:15 +01:00
|
|
|
});
|
2017-09-29 17:25:02 +02:00
|
|
|
|
2017-12-27 02:37:53 +01:00
|
|
|
function elements(map) {
|
2017-12-11 02:03:15 +01:00
|
|
|
var arr = [];
|
2017-12-27 02:37:53 +01:00
|
|
|
map.forEach((value, key) => {
|
|
|
|
arr.push(ElementKind[value.kind] + ": " + key);
|
|
|
|
});
|
|
|
|
return arr.join("\n ");
|
2017-12-11 02:03:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
|
|
|
|
if (failures) {
|
|
|
|
process.exitCode = 1;
|
|
|
|
console.log(chalk.red("ERROR: ") + failures + " compiler tests failed");
|
|
|
|
} else
|
2018-01-12 05:03:25 +01:00
|
|
|
console.log("[ " + chalk.whiteBright("SUCCESS") + " ]");
|