@fraczak/k 6.10.2 → 6.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/DOCS/BIG_PICTURE.md +174 -100
- package/DOCS/CODECS.md +74 -29
- package/DOCS/CODEC_ARCHITECTURE.md +87 -31
- package/DOCS/CONVERGENCE.md +42 -11
- package/DOCS/DICTIONARY.md +69 -2
- package/DOCS/FILE_FORMATS.md +420 -0
- package/DOCS/KIR_V1.md +53 -42
- package/DOCS/KVM_EXECUTION_MODEL.md +189 -147
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +35 -17
- package/DOCS/PATTERNS.md +10 -6
- package/DOCS/REPL.md +100 -60
- package/DOCS/TEXTUAL_VALUES.md +24 -19
- package/DOCS/TYPE_DERIVATION.md +68 -22
- package/Examples/karatsuba-mult.k +215 -0
- package/README.md +92 -58
- package/backends/arm64/scripts/run-tests.mjs +16 -0
- package/backends/llvm/bin/k-llvm-build.mjs +40 -14
- package/backends/llvm/bin/k-llvm-compile.mjs +29 -12
- package/backends/llvm/runtime/krt.c +10 -10
- package/backends/llvm/runtime/krt.h +6 -1
- package/backends/llvm/scripts/run-tests.mjs +16 -0
- package/backends/llvm/src/cli.mjs +1 -1
- package/backends/llvm/src/executable.mjs +36 -0
- package/backends/llvm/src/kvm2llvm.mjs +10 -4
- package/backends/llvm/tests/integration.sh +11 -0
- package/backends/llvm/tests/test-llvm.mjs +15 -1
- package/backends/wasm/scripts/run-tests.mjs +16 -0
- package/browser/vfs-data.mjs +1 -1
- package/codecs/README.md +78 -67
- package/core.k +5 -5
- package/objects/README.md +57 -37
- package/package.json +2 -1
- package/scripts/benchmark-idempotency.mjs +27 -0
- package/scripts/benchmark.mjs +51 -0
- package/scripts/build-repl-html.mjs +17 -0
- package/scripts/generate-dependency-graph.mjs +25 -1
- package/scripts/perf-ieee.mjs +75 -0
- package/scripts/perf-int.mjs +67 -0
- package/scripts/perf-multiplication.mjs +644 -0
- package/scripts/perf-poly.mjs +67 -0
- package/scripts/render-benchmark.mjs +25 -0
- package/scripts/run-tests.mjs +19 -0
- package/tests/README.md +28 -17
- package/tests/test-karatsuba.mjs +133 -0
|
@@ -7,17 +7,20 @@ import {
|
|
|
7
7
|
parseCompileOptions,
|
|
8
8
|
resolveProgramInput
|
|
9
9
|
} from "../src/cli.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
compileObjectToLLVM,
|
|
12
|
+
compileLLVMArtifactFromKVM
|
|
13
|
+
} from "../src/llvm.mjs";
|
|
11
14
|
import { inputPatternForObjectRelation } from "../src/executable.mjs";
|
|
12
15
|
|
|
13
16
|
function usage(stream = console.error) {
|
|
14
17
|
const prog = argv[1] || "k-llvm-compile.mjs";
|
|
15
18
|
stream(`Usage: node ${prog} [options] [source-snippet | input-file [output.ll]]`);
|
|
16
|
-
stream("Compile a k .ko/.klib object into prototype LLVM IR.");
|
|
19
|
+
stream("Compile a k .ko/.klib object, source, or .kvm input into prototype LLVM IR.");
|
|
17
20
|
stream("");
|
|
18
21
|
stream("Arguments:");
|
|
19
22
|
stream(" source-snippet Inline k source, in the same style as k.mjs.");
|
|
20
|
-
stream(" input-file Source .k, .ko, or .
|
|
23
|
+
stream(" input-file Source .k, .ko, .klib, or .kvm file. Reads UTF-8 source from stdin when omitted.");
|
|
21
24
|
stream(" output.ll Output LLVM IR path. Writes to stdout when omitted.");
|
|
22
25
|
stream("");
|
|
23
26
|
stream("Options:");
|
|
@@ -55,16 +58,30 @@ try {
|
|
|
55
58
|
|
|
56
59
|
const outputPath = explicitOutput || positionalOutput || null;
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
let llvm;
|
|
62
|
+
if (input.kind === "kvm") {
|
|
63
|
+
const kvm = JSON.parse(fs.readFileSync(input.path, "utf8"));
|
|
64
|
+
const entry = kvm.entry || kvm.relation || "__main__";
|
|
65
|
+
const mainFunc = kvm.functions?.[entry];
|
|
66
|
+
const artifact = compileLLVMArtifactFromKVM(kvm, {
|
|
67
|
+
relation: entry,
|
|
68
|
+
inputPattern: mainFunc?.inputPattern || kvm.inputPattern,
|
|
69
|
+
outputPattern: mainFunc?.outputPattern || kvm.outputPattern
|
|
70
|
+
});
|
|
71
|
+
llvm = typeof artifact === "string" ? artifact : artifact.llvm;
|
|
72
|
+
} else {
|
|
73
|
+
const object = await compileProgramInputToObject(input, {
|
|
74
|
+
libraries,
|
|
75
|
+
exportSpecs,
|
|
76
|
+
stdin
|
|
77
|
+
});
|
|
63
78
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
const res = compileObjectToLLVM(object, {
|
|
80
|
+
relation: object.main,
|
|
81
|
+
inputPattern: inputPatternForObjectRelation(object, object.main)
|
|
82
|
+
});
|
|
83
|
+
llvm = res.llvm;
|
|
84
|
+
}
|
|
68
85
|
|
|
69
86
|
if (outputPath == null) {
|
|
70
87
|
stdout.write(llvm);
|
|
@@ -553,17 +553,17 @@ static void rt_rewind_and_free(k_rt *rt, k_rt_checkpoint mark) {
|
|
|
553
553
|
rt->has_reusable_blocks = 0;
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
k_value *k_rt_compact(k_rt *rt, k_value *root,
|
|
557
|
-
if (rt == NULL || root == NULL ||
|
|
556
|
+
k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_tail_mark *tm) {
|
|
557
|
+
if (rt == NULL || root == NULL || tm == NULL) return root;
|
|
558
558
|
|
|
559
|
-
size_t bytes = bytes_since_mark(rt,
|
|
559
|
+
size_t bytes = bytes_since_mark(rt, tm->last_mark);
|
|
560
560
|
if (bytes < 4194304) {
|
|
561
561
|
return root;
|
|
562
562
|
}
|
|
563
563
|
|
|
564
|
-
if (!is_after_mark(rt, root,
|
|
565
|
-
rt_rewind_and_free(rt,
|
|
566
|
-
|
|
564
|
+
if (!is_after_mark(rt, root, tm->base_mark)) {
|
|
565
|
+
rt_rewind_and_free(rt, tm->base_mark);
|
|
566
|
+
tm->last_mark = tm->base_mark;
|
|
567
567
|
return root;
|
|
568
568
|
}
|
|
569
569
|
|
|
@@ -574,14 +574,14 @@ k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_checkpoint *mark_ptr) {
|
|
|
574
574
|
|
|
575
575
|
k_fixup_list fixups = {NULL, 0, 0};
|
|
576
576
|
|
|
577
|
-
k_value *staged_root = copy_value(rt, root, &staging, &staging_used, &staging_cap, &fixups,
|
|
577
|
+
k_value *staged_root = copy_value(rt, root, &staging, &staging_used, &staging_cap, &fixups, tm->base_mark);
|
|
578
578
|
|
|
579
|
-
rt_rewind_and_free(rt,
|
|
579
|
+
rt_rewind_and_free(rt, tm->base_mark);
|
|
580
580
|
|
|
581
581
|
if (staging_used == 0) {
|
|
582
582
|
free(staging);
|
|
583
583
|
if (fixups.offsets != NULL) free(fixups.offsets);
|
|
584
|
-
|
|
584
|
+
tm->last_mark = tm->base_mark;
|
|
585
585
|
return staged_root;
|
|
586
586
|
}
|
|
587
587
|
|
|
@@ -605,7 +605,7 @@ k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_checkpoint *mark_ptr) {
|
|
|
605
605
|
free(staging);
|
|
606
606
|
if (fixups.offsets != NULL) free(fixups.offsets);
|
|
607
607
|
|
|
608
|
-
|
|
608
|
+
tm->last_mark = k_rt_mark(rt);
|
|
609
609
|
|
|
610
610
|
return new_root;
|
|
611
611
|
}
|
|
@@ -13,6 +13,11 @@ typedef struct {
|
|
|
13
13
|
size_t used;
|
|
14
14
|
} k_rt_checkpoint;
|
|
15
15
|
|
|
16
|
+
typedef struct {
|
|
17
|
+
k_rt_checkpoint base_mark;
|
|
18
|
+
k_rt_checkpoint last_mark;
|
|
19
|
+
} k_rt_tail_mark;
|
|
20
|
+
|
|
16
21
|
typedef struct {
|
|
17
22
|
const char *label;
|
|
18
23
|
size_t label_length;
|
|
@@ -66,7 +71,7 @@ k_rt *k_rt_new(void);
|
|
|
66
71
|
void k_rt_reset(k_rt *rt);
|
|
67
72
|
k_rt_checkpoint k_rt_mark(k_rt *rt);
|
|
68
73
|
void k_rt_rewind(k_rt *rt, k_rt_checkpoint mark);
|
|
69
|
-
k_value *k_rt_compact(k_rt *rt, k_value *root,
|
|
74
|
+
k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_tail_mark *mark_ptr);
|
|
70
75
|
void *k_rt_alloc(k_rt *rt, size_t size);
|
|
71
76
|
void k_rt_free(k_rt *rt);
|
|
72
77
|
|
|
@@ -6,6 +6,22 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
|
|
7
7
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
8
|
const node = process.execPath;
|
|
9
|
+
|
|
10
|
+
function printHelp() {
|
|
11
|
+
console.log(`Usage: node backends/llvm/scripts/run-tests.mjs [options]
|
|
12
|
+
|
|
13
|
+
Runs LLVM backend test suite, integration tests, and conformance suite.
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-h, --help
|
|
17
|
+
Show this help message and exit.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (process.argv.includes("-h") || process.argv.includes("--help")) {
|
|
21
|
+
printHelp();
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
const tests = [
|
|
10
26
|
["tests/test-llvm.mjs", node, ["tests/test-llvm.mjs"]],
|
|
11
27
|
["tests/integration.sh", path.join(root, "tests/integration.sh"), []],
|
|
@@ -135,7 +135,7 @@ export async function compileProgramInputToObject(
|
|
|
135
135
|
} else if (input.kind === "ko" || input.kind === "klib") {
|
|
136
136
|
object = decodeObject(fs.readFileSync(input.path));
|
|
137
137
|
} else if (input.kind === "kvm") {
|
|
138
|
-
throw new Error("
|
|
138
|
+
throw new Error("Input is already lowered to .kvm bytecode; use compileLLVMArtifactFromKVM or compileKVMToExecutable.");
|
|
139
139
|
} else {
|
|
140
140
|
throw new Error(`Unsupported input kind: ${input.kind}`);
|
|
141
141
|
}
|
|
@@ -6,7 +6,9 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { isProduct, isVariant } from "@fraczak/k/Value.mjs";
|
|
7
7
|
import { exportPatternGraph } from "@fraczak/k/codecs/runtime/codec.mjs";
|
|
8
8
|
import { patternToPropertyList } from "@fraczak/k/codecs/runtime/pattern-json.mjs";
|
|
9
|
+
import { specializeKVM } from "@fraczak/k/kvm.mjs";
|
|
9
10
|
import { compileObjectToLLVM } from "./llvm.mjs";
|
|
11
|
+
import { compileKVMModuleToLLVM } from "./kvm2llvm.mjs";
|
|
10
12
|
|
|
11
13
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
14
|
|
|
@@ -553,6 +555,40 @@ export function compileObjectToExecutable(object, outputPath, { relation = objec
|
|
|
553
555
|
});
|
|
554
556
|
}
|
|
555
557
|
|
|
558
|
+
export function compileKVMToExecutable(kvmInput, outputPath, {
|
|
559
|
+
entry = null,
|
|
560
|
+
inputPattern = null,
|
|
561
|
+
runtimeMode = "fast",
|
|
562
|
+
clangOpt = "-O3"
|
|
563
|
+
} = {}) {
|
|
564
|
+
let kvm = kvmInput;
|
|
565
|
+
if (kvm?.format === "k-vm") {
|
|
566
|
+
if (kvm.layer === "KVM-P" && inputPattern) {
|
|
567
|
+
kvm = specializeKVM(kvm, inputPattern);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const functions = kvm.functions || (typeof kvm === "object" && !Array.isArray(kvm) ? kvm : null);
|
|
571
|
+
if (!functions) throw new Error("Expected .kvm input to contain a functions object");
|
|
572
|
+
const entryFunc = entry || kvm.entry || kvm.relation || "__main__";
|
|
573
|
+
const mainFunc = functions[entryFunc];
|
|
574
|
+
if (!mainFunc) throw new Error(`No kVM entry function '${entryFunc}' found`);
|
|
575
|
+
const compiledInputPattern = inputPattern || mainFunc?.inputPattern || kvm.inputPattern;
|
|
576
|
+
const outputPattern = mainFunc?.outputPattern || kvm.outputPattern;
|
|
577
|
+
const llvm = compileKVMModuleToLLVM(entryFunc, functions, {
|
|
578
|
+
relation: entryFunc,
|
|
579
|
+
inputPattern: compiledInputPattern,
|
|
580
|
+
outputPattern,
|
|
581
|
+
runtimeMode
|
|
582
|
+
});
|
|
583
|
+
compileLLVMToExecutable(llvm, outputPath, {
|
|
584
|
+
driver: stdioDriverSource({
|
|
585
|
+
inputPattern: compiledInputPattern,
|
|
586
|
+
outputPattern
|
|
587
|
+
}),
|
|
588
|
+
clangOpt
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
556
592
|
export function compileObjectAndRun(object, { relation = object.main, input, expected = null, inputPattern = null }) {
|
|
557
593
|
const { llvm } = compileObjectToLLVM(object, {
|
|
558
594
|
relation,
|
|
@@ -49,6 +49,7 @@ function cStringBytes(text) {
|
|
|
49
49
|
export function runtimeDeclarations() {
|
|
50
50
|
return [
|
|
51
51
|
"%k_rt_mark = type { ptr, i64 }",
|
|
52
|
+
"%k_rt_tail_mark = type { %k_rt_mark, %k_rt_mark }",
|
|
52
53
|
"%k_result = type { i32, ptr }",
|
|
53
54
|
"",
|
|
54
55
|
"declare %k_rt_mark @k_rt_mark(ptr)",
|
|
@@ -316,7 +317,7 @@ function lowerRtCompact(ctx, val, tailMarkSlot = "%tail_mark_slot") {
|
|
|
316
317
|
const hasBlock = ctx.tempName("has_block");
|
|
317
318
|
const markBlockPtr = ctx.tempName("mark_block_ptr");
|
|
318
319
|
ctx.lines.push(` ${hasBlock} = icmp ne ptr ${curBlock}, null`);
|
|
319
|
-
ctx.lines.push(` ${markBlockPtr} = getelementptr inbounds %
|
|
320
|
+
ctx.lines.push(` ${markBlockPtr} = getelementptr inbounds %k_rt_tail_mark, ptr ${tailMarkSlot}, i32 0, i32 1, i32 0`);
|
|
320
321
|
const markBlock = ctx.tempName("mark_block");
|
|
321
322
|
ctx.lines.push(` ${markBlock} = load ptr, ptr ${markBlockPtr}`);
|
|
322
323
|
|
|
@@ -340,7 +341,7 @@ function lowerRtCompact(ctx, val, tailMarkSlot = "%tail_mark_slot") {
|
|
|
340
341
|
ctx.lines.push(`${loadGrowthBlock}:`);
|
|
341
342
|
const curUsed = loadI64At(ctx, curBlock, K_ARENA_BLOCK_USED_OFFSET, "cur_used");
|
|
342
343
|
const markUsedPtr = ctx.tempName("mark_used_ptr");
|
|
343
|
-
ctx.lines.push(` ${markUsedPtr} = getelementptr inbounds %
|
|
344
|
+
ctx.lines.push(` ${markUsedPtr} = getelementptr inbounds %k_rt_tail_mark, ptr ${tailMarkSlot}, i32 0, i32 1, i32 1`);
|
|
344
345
|
const markUsed = ctx.tempName("mark_used");
|
|
345
346
|
ctx.lines.push(` ${markUsed} = load i64, ptr ${markUsedPtr}`);
|
|
346
347
|
const growth = ctx.tempName("arena_growth");
|
|
@@ -605,11 +606,16 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
605
606
|
|
|
606
607
|
if (isCatchTail) {
|
|
607
608
|
ctx.allocas.push(" %tail_input_slot = alloca ptr");
|
|
608
|
-
ctx.allocas.push(" %tail_mark_slot = alloca %
|
|
609
|
+
ctx.allocas.push(" %tail_mark_slot = alloca %k_rt_tail_mark");
|
|
609
610
|
ctx.lines.push(" store ptr %input, ptr %tail_input_slot");
|
|
610
611
|
const initMark = ctx.tempName("init_mark");
|
|
611
612
|
ctx.lines.push(` ${initMark} = call %k_rt_mark @k_rt_mark(ptr %rt)`);
|
|
612
|
-
ctx.
|
|
613
|
+
const baseMarkPtr = ctx.tempName("base_mark_ptr");
|
|
614
|
+
const lastMarkPtr = ctx.tempName("last_mark_ptr");
|
|
615
|
+
ctx.lines.push(` ${baseMarkPtr} = getelementptr inbounds %k_rt_tail_mark, ptr %tail_mark_slot, i32 0, i32 0`);
|
|
616
|
+
ctx.lines.push(` store %k_rt_mark ${initMark}, ptr ${baseMarkPtr}`);
|
|
617
|
+
ctx.lines.push(` ${lastMarkPtr} = getelementptr inbounds %k_rt_tail_mark, ptr %tail_mark_slot, i32 0, i32 1`);
|
|
618
|
+
ctx.lines.push(` store %k_rt_mark ${initMark}, ptr ${lastMarkPtr}`);
|
|
613
619
|
ctx.lines.push(" br label %tail_loop");
|
|
614
620
|
ctx.lines.push("tail_loop:");
|
|
615
621
|
ctx.lines.push(" %tail_input = load ptr, ptr %tail_input_slot");
|
|
@@ -95,6 +95,17 @@ printf '{"x":"left","y":"right"}' \
|
|
|
95
95
|
|
|
96
96
|
printf '{"x":"left"}' | node ../../codecs/k-parse.mjs | "$TMP_DIR/run-exe" && exit 1 || test "$?" -eq 5
|
|
97
97
|
|
|
98
|
+
node ../../objects/compile.mjs '?{<{}=X0 left, ...> x, <X0 right, ...> y} .x' "$TMP_DIR/run-proj.kvm"
|
|
99
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/run-proj.kvm" "$TMP_DIR/run-proj-kvm.ll"
|
|
100
|
+
grep -q '@k_llvm_metadata' "$TMP_DIR/run-proj-kvm.ll"
|
|
101
|
+
grep -q 'define %k_result @k_main' "$TMP_DIR/run-proj-kvm.ll"
|
|
102
|
+
node ./bin/k-llvm-build.mjs "$TMP_DIR/run-proj.kvm" -o "$TMP_DIR/run-kvm-exe"
|
|
103
|
+
printf '{"x":"left","y":"right"}' \
|
|
104
|
+
| node ../../codecs/k-parse.mjs \
|
|
105
|
+
| "$TMP_DIR/run-kvm-exe" \
|
|
106
|
+
| node ../../codecs/k-print.mjs \
|
|
107
|
+
| grep -qx '"left"'
|
|
108
|
+
|
|
98
109
|
node ./bin/k-llvm-build.mjs '?<{} left, {} right, ...>' -o "$TMP_DIR/id-exe"
|
|
99
110
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const pattern = [[\"open-union\",[[\"left\",1],[\"right\",1]]],[\"closed-product\",[]]]; stdout.write(encodeToWire(Value.variant(\"left\", Value.product({}), pattern), pattern));" \
|
|
100
111
|
| "$TMP_DIR/id-exe" \
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { compileObjectBuffer, decodeObject } from "@fraczak/k/object.mjs";
|
|
3
|
-
import { compileObjectToLLVM, emitLLVMModule, llvmIdentifier } from "../src/llvm.mjs";
|
|
3
|
+
import { compileObjectToLLVM, compileLLVMArtifactFromKVM, emitLLVMModule, llvmIdentifier } from "../src/llvm.mjs";
|
|
4
|
+
import { objectToKVMArtifact } from "@fraczak/k/kvm.mjs";
|
|
4
5
|
|
|
5
6
|
function kirP(body, { patternGraph = null } = {}) {
|
|
6
7
|
return {
|
|
@@ -256,4 +257,17 @@ const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {
|
|
|
256
257
|
// Calls inside product fields must not return tail status (i32 2)
|
|
257
258
|
assert.doesNotMatch(productRecurseLLVM, /insertvalue %k_result undef, i32 2, 0/);
|
|
258
259
|
|
|
260
|
+
const kvmArtifact = objectToKVMArtifact(productObject, "__main__");
|
|
261
|
+
assert.equal(kvmArtifact.format, "k-vm");
|
|
262
|
+
const kvmLLVM = compileLLVMArtifactFromKVM(kvmArtifact, {
|
|
263
|
+
inputPattern: [
|
|
264
|
+
["closed-product", [["x", 1], ["y", 2]]],
|
|
265
|
+
["closed-product", [["valA", 1]]],
|
|
266
|
+
["closed-product", [["valB", 2]]]
|
|
267
|
+
]
|
|
268
|
+
});
|
|
269
|
+
assert.match(kvmLLVM, /source_filename = "k-llvm:__main__"/);
|
|
270
|
+
assert.match(kvmLLVM, /define %k_result @k_main/);
|
|
271
|
+
assert.match(kvmLLVM, /store ptr %product_fields\d+, ptr %ptr_slot\d+/);
|
|
272
|
+
|
|
259
273
|
console.log("OK");
|
|
@@ -6,6 +6,22 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
|
|
7
7
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
8
|
const node = process.execPath;
|
|
9
|
+
|
|
10
|
+
function printHelp() {
|
|
11
|
+
console.log(`Usage: node backends/wasm/scripts/run-tests.mjs [options]
|
|
12
|
+
|
|
13
|
+
Runs WebAssembly backend test suite and integration tests.
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-h, --help
|
|
17
|
+
Show this help message and exit.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (process.argv.includes("-h") || process.argv.includes("--help")) {
|
|
21
|
+
printHelp();
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
const tests = [
|
|
10
26
|
["tests/test-wasm.mjs", node, ["tests/test-wasm.mjs"]],
|
|
11
27
|
["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
|