xbintsc 0.3.79 → 0.3.87
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/README.md +13 -5
- package/README.zh-CN.md +13 -6
- package/dist/src/ast/common.d.ts +23 -0
- package/dist/src/cli/main.js +68 -24
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +5 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +50 -0
- package/dist/src/codegen/generator/context.js +124 -13
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.d.ts +33 -0
- package/dist/src/codegen/generator/debug.js +97 -0
- package/dist/src/codegen/generator/debug.js.map +1 -0
- package/dist/src/codegen/generator/expressions/assignment.js +9 -5
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +35 -9
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -2
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.d.ts +3 -1
- package/dist/src/codegen/generator/generator.js +3 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +76 -6
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +26 -0
- package/dist/src/codegen/generator/numeric.js +127 -0
- package/dist/src/codegen/generator/numeric.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +17 -0
- package/dist/src/codegen/generator/state.js +5 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +3 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +8 -2
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +25 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +41 -5
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +22 -3
- package/dist/src/driver/compiler.js +49 -58
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.d.ts +27 -0
- package/dist/src/driver/fingerprint.js +88 -0
- package/dist/src/driver/fingerprint.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +9 -2
- package/dist/src/driver/toolchain-provider.js +15 -15
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +58 -1
- package/dist/src/driver/toolchain.js +169 -22
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/gui/index.js +10 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/parser/expressions.js +20 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/tests/cli/main.test.js +41 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/expressions.test.js +14 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +23 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +49 -2
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +62 -3
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.d.ts +10 -0
- package/dist/tests/e2e/child-process.test.js +59 -0
- package/dist/tests/e2e/child-process.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +47 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/error-stack.test.d.ts +9 -0
- package/dist/tests/e2e/error-stack.test.js +94 -0
- package/dist/tests/e2e/error-stack.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-svg.test.d.ts +21 -0
- package/dist/tests/e2e/gui-example-svg.test.js +105 -0
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.d.ts +7 -0
- package/dist/tests/e2e/gui-transform.test.js +198 -0
- package/dist/tests/e2e/gui-transform.test.js.map +1 -0
- package/dist/tests/e2e/string-concat.test.d.ts +9 -0
- package/dist/tests/e2e/string-concat.test.js +102 -0
- package/dist/tests/e2e/string-concat.test.js.map +1 -0
- package/dist/tests/helpers.d.ts +9 -0
- package/dist/tests/helpers.js +26 -3
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +7 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/version.test.d.ts +1 -0
- package/dist/tests/version.test.js +24 -0
- package/dist/tests/version.test.js.map +1 -0
- package/doc/DESIGN.md +20 -12
- package/doc/ai/cli.md +7 -0
- package/doc/ai/contributing.md +7 -1
- package/doc/ai/extensions.md +5 -1
- package/doc/ai/language-support.md +4 -4
- package/doc/ai/troubleshooting.md +39 -2
- package/doc/ai/zh-CN/cli.md +2 -0
- package/doc/ai/zh-CN/contributing.md +6 -2
- package/doc/ai/zh-CN/extensions.md +5 -1
- package/doc/ai/zh-CN/language-support.md +4 -4
- package/doc/ai/zh-CN/troubleshooting.md +35 -2
- package/doc/gui/animation.md +53 -2
- package/doc/gui/api.md +1 -1
- package/doc/gui/dom.md +6 -1
- package/doc/gui/input.md +4 -1
- package/doc/gui/known-issues.md +16 -4
- package/doc/gui/layout.md +36 -0
- package/doc/gui/rendering.md +15 -0
- package/doc/gui.md +32 -3
- package/doc/implemented.md +4 -4
- package/doc/requirements.md +13 -4
- package/doc/unimplemented.md +11 -10
- package/doc/zh-CN/DESIGN.md +15 -9
- package/doc/zh-CN/gui/animation.md +49 -2
- package/doc/zh-CN/gui/api.md +1 -1
- package/doc/zh-CN/gui/dom.md +6 -1
- package/doc/zh-CN/gui/input.md +2 -0
- package/doc/zh-CN/gui/known-issues.md +12 -2
- package/doc/zh-CN/gui/layout.md +31 -0
- package/doc/zh-CN/gui/rendering.md +11 -0
- package/doc/zh-CN/gui.md +28 -3
- package/doc/zh-CN/implemented.md +4 -4
- package/doc/zh-CN/requirements.md +12 -3
- package/doc/zh-CN/unimplemented.md +10 -9
- package/package.json +3 -1
- package/runtime/ext_gui/document.cpp +21 -3
- package/runtime/ext_gui/document.h +4 -1
- package/runtime/ext_gui/dom_api_node.cpp +6 -4
- package/runtime/ext_gui/layout.cpp +78 -1
- package/runtime/ext_gui/layout.h +21 -0
- package/runtime/ext_gui/paint.cpp +48 -15
- package/runtime/ext_gui/paint.h +8 -2
- package/runtime/ext_gui/renderer.cpp +4 -2
- package/runtime/ext_gui/renderer_image.cpp +2 -1
- package/runtime/ext_gui/renderer_internal.h +6 -1
- package/runtime/ext_gui/renderer_text.cpp +37 -15
- package/runtime/ext_gui/style.h +10 -0
- package/runtime/ext_gui/style_print.cpp +6 -0
- package/runtime/ext_gui/style_values.cpp +43 -0
- package/runtime/ext_gui/transform.cpp +412 -0
- package/runtime/ext_gui/transform.h +112 -0
- package/runtime/ext_gui/window.cpp +6 -4
- package/runtime/ext_node/buffer/parts/construction.inc +2 -2
- package/runtime/ext_node/buffer/parts/methods.inc +1 -1
- package/runtime/ext_node/buffer/parts/search.inc +1 -1
- package/runtime/ext_node/child_process/child_process.c +25 -0
- package/runtime/ext_node/fs/fd_ops.c +1 -1
- package/runtime/rt.h +17 -1
- package/runtime/rt_internal.h +47 -4
- package/runtime/xt_alloc.c +14 -2
- package/runtime/xt_bigint/conversions.inc +1 -1
- package/runtime/xt_builtins.c +136 -14
- package/runtime/xt_containers/access.inc +17 -16
- package/runtime/xt_containers/objects.inc +4 -3
- package/runtime/xt_io/exception.inc +171 -2
- package/runtime/xt_io/inspect.inc +15 -13
- package/runtime/xt_io.c +5 -0
- package/runtime/xt_stdlib/arrays.inc +2 -2
- package/runtime/xt_stdlib/dispatch.inc +2 -2
- package/runtime/xt_stdlib/strings.inc +33 -21
- package/runtime/xt_stdlib2/array-statics.inc +2 -1
- package/runtime/xt_stdlib2/arrays.inc +1 -1
- package/runtime/xt_stdlib2/error.inc +22 -6
- package/runtime/xt_stdlib2/json.inc +3 -2
- package/runtime/xt_stdlib2/number-string-statics.inc +3 -1
- package/runtime/xt_stdlib2/regexp-match.inc +48 -33
- package/runtime/xt_stdlib2/strings.inc +23 -14
- package/runtime/xt_symbol.c +1 -1
- package/runtime/xt_values/comparison.inc +2 -2
- package/runtime/xt_values/constructors.inc +10 -5
- package/runtime/xt_values/conversions.inc +4 -3
- package/runtime/xt_values/strings.inc +78 -4
- package/scripts/bench.ts +172 -0
- package/scripts/build-runtime.ts +2 -1
- package/scripts/check-version.ts +53 -0
- package/src/ast/common.ts +23 -0
- package/src/cli/main.ts +68 -26
- package/src/codegen/generator/calls/invocation.ts +5 -0
- package/src/codegen/generator/context.ts +129 -18
- package/src/codegen/generator/debug.ts +132 -0
- package/src/codegen/generator/expressions/assignment.ts +9 -5
- package/src/codegen/generator/expressions/operators.ts +47 -8
- package/src/codegen/generator/expressions/primary.ts +5 -2
- package/src/codegen/generator/generator.ts +18 -2
- package/src/codegen/generator/module.ts +78 -6
- package/src/codegen/generator/numeric.ts +158 -0
- package/src/codegen/generator/state.ts +22 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -1
- package/src/codegen/generator/statements/dispatch.ts +3 -0
- package/src/codegen/generator/statements/variables.ts +8 -2
- package/src/codegen/generator/tables.ts +26 -0
- package/src/driver/bundler/merge.ts +39 -5
- package/src/driver/compiler.ts +68 -56
- package/src/driver/fingerprint.ts +85 -0
- package/src/driver/toolchain-provider.ts +17 -16
- package/src/driver/toolchain.ts +210 -21
- package/src/extensions/gui/index.ts +10 -2
- package/src/parser/expressions.ts +20 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end test for `examples/gui/pelican-svg` — the SVG gallery page that
|
|
3
|
+
* animates a CSS `transform` from the frame loop.
|
|
4
|
+
*
|
|
5
|
+
* The example's own `main.ts` is compiled here together with its `index.html`
|
|
6
|
+
* (the `gui` extension compiles the document and the `<img>` path it points at),
|
|
7
|
+
* linked against the prebuilt `gui.a`, and run under the `XT_GUI_AUTOCLOSE_MS`
|
|
8
|
+
* hang guard. The assertions read the example's `label=value` report, which is
|
|
9
|
+
* printed from the first presented frame:
|
|
10
|
+
*
|
|
11
|
+
* - the document parsed, the SVG decoded and the image reached the paint list;
|
|
12
|
+
* - the artwork's *layout* box is the 720x520 box CSS asked for;
|
|
13
|
+
* - each frame's pose (a `transform` list parsed by the engine) composed into a
|
|
14
|
+
* matrix that reached the display list, and the reported bounding box moved
|
|
15
|
+
* with it — a paint-time transform does not touch layout;
|
|
16
|
+
* - hit testing still lands on the `<img>` through the transform.
|
|
17
|
+
*
|
|
18
|
+
* The pose values themselves are wall-clock dependent (`requestAnimationFrame`
|
|
19
|
+
* timestamps), so the test matches their *shape*, not their numbers.
|
|
20
|
+
*/
|
|
21
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
import { dirname, join, resolve } from "node:path";
|
|
24
|
+
import { spawnSync } from "node:child_process";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
27
|
+
import { build } from "../../src/driver/compiler.js";
|
|
28
|
+
import { createDefaultRegistry } from "../../src/extensions/registry.js";
|
|
29
|
+
import { guiExtension } from "../../src/extensions/gui/index.js";
|
|
30
|
+
import { nodeExtension } from "../../src/extensions/node/index.js";
|
|
31
|
+
import { guiAvailable } from "./gui-helpers.js";
|
|
32
|
+
/** The example lives at <repo>/examples/gui/pelican-svg. */
|
|
33
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
34
|
+
const exampleDir = join(repoRoot, "examples", "gui", "pelican-svg");
|
|
35
|
+
/** Windows reports an access violation as this NTSTATUS exit code; on POSIX the
|
|
36
|
+
* same documented teardown fault surfaces as a signal (see
|
|
37
|
+
* `doc/gui/known-issues.md`). */
|
|
38
|
+
const ACCESS_VIOLATION = 3221225477;
|
|
39
|
+
const CRASH_SIGNALS = new Set(["SIGSEGV", "SIGBUS", "SIGABRT", "SIGILL", "SIGFPE"]);
|
|
40
|
+
let workdir = "";
|
|
41
|
+
describe.skipIf(!guiAvailable)("gui example — pelican svg", () => {
|
|
42
|
+
beforeAll(() => {
|
|
43
|
+
workdir = mkdtempSync(join(tmpdir(), "xbintsc-pelican-svg-"));
|
|
44
|
+
writeFileSync(join(workdir, "index.html"), readFileSync(join(exampleDir, "index.html"), "utf8"));
|
|
45
|
+
writeFileSync(join(workdir, "pelican-svg.ts"), readFileSync(join(exampleDir, "main.ts"), "utf8"));
|
|
46
|
+
});
|
|
47
|
+
afterAll(() => {
|
|
48
|
+
rmSync(workdir, { recursive: true, force: true });
|
|
49
|
+
});
|
|
50
|
+
it("compiles the gallery and animates the artwork", () => {
|
|
51
|
+
const extensions = createDefaultRegistry().register(guiExtension).register(nodeExtension);
|
|
52
|
+
const result = build(join(workdir, "pelican-svg.ts"), {
|
|
53
|
+
emit: "exe",
|
|
54
|
+
outDir: join(workdir, "out"),
|
|
55
|
+
cacheDir: join(workdir, ".cache"),
|
|
56
|
+
extensions,
|
|
57
|
+
});
|
|
58
|
+
expect(result.diagnostics.filter((diagnostic) => diagnostic.category === "error")).toEqual([]);
|
|
59
|
+
/* The example finds the artwork relative to the working directory, so it is
|
|
60
|
+
spawned from the repository root — the same way the CLI runs it. */
|
|
61
|
+
const executed = spawnSync(result.outputPath, [], {
|
|
62
|
+
cwd: repoRoot,
|
|
63
|
+
encoding: "utf8",
|
|
64
|
+
env: { ...process.env, XT_GUI_AUTOCLOSE_MS: "4000" },
|
|
65
|
+
});
|
|
66
|
+
const crashed = executed.status === ACCESS_VIOLATION ||
|
|
67
|
+
(executed.status === null && executed.signal !== null && CRASH_SIGNALS.has(executed.signal));
|
|
68
|
+
const outcome = executed.signal !== null ? `signal ${executed.signal}` : `exit ${executed.status}`;
|
|
69
|
+
expect(executed.status === 0 || crashed, `unexpected ${outcome}\nstderr:\n${executed.stderr}`).toBe(true);
|
|
70
|
+
const stdout = executed.stdout ?? "";
|
|
71
|
+
const value = (label) => {
|
|
72
|
+
const found = stdout.split("\n").find((entry) => entry.startsWith(`${label}=`));
|
|
73
|
+
expect(found, `missing ${label} in stdout:\n${stdout}\nstderr:\n${executed.stderr}`).toBeDefined();
|
|
74
|
+
return found.slice(label.length + 1).trim();
|
|
75
|
+
};
|
|
76
|
+
// The window, the backend and the document: the artwork laid out at 720x520
|
|
77
|
+
// and the vector source decoded into a single painted image.
|
|
78
|
+
expect(value("window")).toBe("800x640 (gui extension, SDL_GPU)");
|
|
79
|
+
expect(value("art-box")).toBe("x=40 y=35 720x520");
|
|
80
|
+
expect(value("painted-images")).toBe("1");
|
|
81
|
+
expect(value("painted-image")).toMatch(/^image x=40\.0 y=35\.0 w=720\.0 h=520\.0 src=.*pelican-bike\.svg$/);
|
|
82
|
+
expect(value("svg-declares")).toBe("720x520");
|
|
83
|
+
expect(value("svg-has-viewbox")).toBe("true");
|
|
84
|
+
expect(value("svg-paths")).toBe("44");
|
|
85
|
+
// The SVG is `<img>` content, so it is hit-testable like any other element,
|
|
86
|
+
// and `transform-origin` came through the cascade unresolved (`%`), as CSS
|
|
87
|
+
// requires: layout resolves it against the border box.
|
|
88
|
+
expect(value("hit-test")).toBe("img#art");
|
|
89
|
+
expect(value("art-origin")).toBe("50% 92%");
|
|
90
|
+
// The frame loop applied a pose: a `transform` list the engine parsed into a
|
|
91
|
+
// matrix, which is what the renderer received for the image quad.
|
|
92
|
+
/* Match the *shape* only: the values follow the wall clock, and the engine's
|
|
93
|
+
canonical spelling trims trailing zeros (`rotate(0.8deg)`, not `0.80deg`). */
|
|
94
|
+
const pose = /^translateY\(-?[\d.]+px\) rotate\(-?[\d.]+deg\) scale\([\d.]+, [\d.]+\)$/;
|
|
95
|
+
expect(value("art-pose@1")).toMatch(pose);
|
|
96
|
+
expect(value("art-pose@2")).toMatch(pose);
|
|
97
|
+
expect(value("art-matrix")).toMatch(/^matrix\(/);
|
|
98
|
+
// ...and the geometry the DOM reports follows the transform, while the
|
|
99
|
+
// layout box above stayed at 720x520.
|
|
100
|
+
const moved = value("art-moved-box");
|
|
101
|
+
expect(moved).toMatch(/^x=-?\d+ y=-?\d+ \d+x\d+$/);
|
|
102
|
+
expect(moved).not.toBe("x=40 y=35 720x520");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=gui-example-svg.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui-example-svg.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-example-svg.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the `gui` extension — CSS `transform` and
|
|
3
|
+
* `transform-origin`: parsing/computed style, the matrix the paint list carries,
|
|
4
|
+
* transformed geometry (`getBoundingClientRect`), hit testing, and animating a
|
|
5
|
+
* transform through a CSS transition.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the `gui` extension — CSS `transform` and
|
|
3
|
+
* `transform-origin`: parsing/computed style, the matrix the paint list carries,
|
|
4
|
+
* transformed geometry (`getBoundingClientRect`), hit testing, and animating a
|
|
5
|
+
* transform through a CSS transition.
|
|
6
|
+
*/
|
|
7
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
8
|
+
import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
|
|
9
|
+
const harness = createGuiHarness();
|
|
10
|
+
describe.skipIf(!guiAvailable)("gui extension — transform", () => {
|
|
11
|
+
beforeAll(() => harness.setup());
|
|
12
|
+
afterAll(() => harness.cleanup());
|
|
13
|
+
it("composes translate/rotate/scale into one matrix", () => {
|
|
14
|
+
const { stdout, value } = harness.compileAndRun("transform-matrix", `
|
|
15
|
+
import { createWindow, run } from "gui";
|
|
16
|
+
|
|
17
|
+
const HTML = \`
|
|
18
|
+
<html><head><style>
|
|
19
|
+
body { margin: 0; }
|
|
20
|
+
#moved {
|
|
21
|
+
position: absolute; left: 100px; top: 100px; width: 100px; height: 50px;
|
|
22
|
+
background-color: #ff0000;
|
|
23
|
+
transform-origin: 0 0;
|
|
24
|
+
transform: rotate(90deg) translate(10px, 0px);
|
|
25
|
+
}
|
|
26
|
+
#grew {
|
|
27
|
+
position: absolute; left: 100px; top: 200px; width: 40px; height: 20px;
|
|
28
|
+
background-color: #00ff00;
|
|
29
|
+
transform: scale(2, 3);
|
|
30
|
+
}
|
|
31
|
+
</style></head><body>
|
|
32
|
+
<div id="moved"></div><div id="grew"></div>
|
|
33
|
+
</body></html>
|
|
34
|
+
\`;
|
|
35
|
+
|
|
36
|
+
const win = createWindow({ title: "transform", width: 400, height: 300 });
|
|
37
|
+
win.on("ready", () => {
|
|
38
|
+
console.log("computed=" + win.computedStyle("#moved", "transform"));
|
|
39
|
+
console.log("origin=" + win.computedStyle("#moved", "transform-origin"));
|
|
40
|
+
console.log("default-origin=" + win.computedStyle("#grew", "transform-origin"));
|
|
41
|
+
const moved = win.getBoundingClientRect("#moved");
|
|
42
|
+
console.log("moved=" + moved.x.toFixed(1) + "," + moved.y.toFixed(1) + "," +
|
|
43
|
+
moved.width.toFixed(1) + "," + moved.height.toFixed(1));
|
|
44
|
+
const grew = win.getBoundingClientRect("#grew");
|
|
45
|
+
console.log("grew=" + grew.x.toFixed(1) + "," + grew.y.toFixed(1) + "," +
|
|
46
|
+
grew.width.toFixed(1) + "," + grew.height.toFixed(1));
|
|
47
|
+
console.log(win.paintList().trim());
|
|
48
|
+
win.close();
|
|
49
|
+
});
|
|
50
|
+
win.loadHTML(HTML);
|
|
51
|
+
run();
|
|
52
|
+
`);
|
|
53
|
+
expect(value("computed")).toBe("rotate(90deg) translate(10px, 0px)");
|
|
54
|
+
expect(value("origin")).toBe("0px 0px");
|
|
55
|
+
// `transform-origin` defaults to the centre of the border box.
|
|
56
|
+
expect(value("default-origin")).toBe("50% 50%");
|
|
57
|
+
/* rotate(90deg) about the top-left corner turns the 100x50 box into a
|
|
58
|
+
* 50x100 one; the local `translate(10px, 0)` moves it 10px down. */
|
|
59
|
+
expect(value("moved")).toBe("50.0,110.0,50.0,100.0");
|
|
60
|
+
// `scale(2, 3)` about the centre: 40x20 -> 80x60, centred on the same point.
|
|
61
|
+
expect(value("grew")).toBe("80.0,180.0,80.0,60.0");
|
|
62
|
+
// Paint keeps the untransformed layout geometry and carries the matrix.
|
|
63
|
+
expect(stdout).toContain("rect x=100.0 y=100.0 w=100.0 h=50.0 r=0.0 color=#ff0000ff transform=matrix(");
|
|
64
|
+
expect(stdout).toContain("transform=matrix(2,0,0,3,-120,-420)");
|
|
65
|
+
});
|
|
66
|
+
it("parses the 3d spellings and drops unsupported functions", () => {
|
|
67
|
+
const { stdout, value } = harness.compileAndRun("transform-parse", `
|
|
68
|
+
import { createWindow, run } from "gui";
|
|
69
|
+
|
|
70
|
+
const HTML = \`
|
|
71
|
+
<html><head><style>
|
|
72
|
+
body { margin: 0; }
|
|
73
|
+
#a {
|
|
74
|
+
position: absolute; left: 0px; top: 0px; width: 40px; height: 20px;
|
|
75
|
+
background-color: #ff0000; transform-origin: 0 0;
|
|
76
|
+
transform: translate3d(10px, 4px, 0) scale3d(2, 3, 1) rotateZ(0.5turn);
|
|
77
|
+
}
|
|
78
|
+
#b {
|
|
79
|
+
position: absolute; left: 0px; top: 100px; width: 40px; height: 20px;
|
|
80
|
+
background-color: #00ff00; transform: skewX(10deg);
|
|
81
|
+
}
|
|
82
|
+
#c {
|
|
83
|
+
position: absolute; left: 100px; top: 100px; width: 100px; height: 50px;
|
|
84
|
+
background-color: #0000ff; transform-origin: 0 0;
|
|
85
|
+
transform: translate(50%, 50%);
|
|
86
|
+
}
|
|
87
|
+
#d { transform-origin: top; }
|
|
88
|
+
#e { transform-origin: bottom right; }
|
|
89
|
+
#f { transform-origin: 10px; }
|
|
90
|
+
</style></head><body><div id="a"></div><div id="b"></div><div id="c"></div>
|
|
91
|
+
<div id="d"></div><div id="e"></div><div id="f"></div></body></html>
|
|
92
|
+
\`;
|
|
93
|
+
|
|
94
|
+
const win = createWindow({ title: "parse", width: 400, height: 300 });
|
|
95
|
+
win.on("ready", () => {
|
|
96
|
+
console.log("a=" + win.computedStyle("#a", "transform"));
|
|
97
|
+
console.log("b=" + win.computedStyle("#b", "transform"));
|
|
98
|
+
console.log("c=" + win.computedStyle("#c", "transform"));
|
|
99
|
+
/* translate(50%, 50%) resolves against the box: 50px, 25px. */
|
|
100
|
+
console.log("c-rect=" + win.getBoundingClientRect("#c").x.toFixed(1) + "," +
|
|
101
|
+
win.getBoundingClientRect("#c").y.toFixed(1));
|
|
102
|
+
/* A vertical keyword keeps x centred; bottom-right is right-bottom. */
|
|
103
|
+
console.log("d-origin=" + win.computedStyle("#d", "transform-origin"));
|
|
104
|
+
console.log("e-origin=" + win.computedStyle("#e", "transform-origin"));
|
|
105
|
+
console.log("f-origin=" + win.computedStyle("#f", "transform-origin"));
|
|
106
|
+
console.log(win.paintList().trim());
|
|
107
|
+
win.close();
|
|
108
|
+
});
|
|
109
|
+
win.loadHTML(HTML);
|
|
110
|
+
run();
|
|
111
|
+
`);
|
|
112
|
+
// `translate3d`/`scale3d` keep their x/y and drop `z`; `rotateZ` is `rotate`.
|
|
113
|
+
expect(value("a")).toBe("translate(10px, 4px) scale(2, 3) rotate(180deg)");
|
|
114
|
+
// An unsupported function invalidates the whole declaration.
|
|
115
|
+
expect(value("b")).toBe("none");
|
|
116
|
+
// Percentages stay unresolved in the computed value and resolve in layout.
|
|
117
|
+
expect(value("c")).toBe("translate(50%, 50%)");
|
|
118
|
+
expect(value("c-rect")).toBe("150.0,125.0");
|
|
119
|
+
expect(value("d-origin")).toBe("50% 0%");
|
|
120
|
+
expect(value("e-origin")).toBe("100% 100%");
|
|
121
|
+
expect(value("f-origin")).toBe("10px 50%");
|
|
122
|
+
expect(stdout).toContain("transform=matrix(1,0,0,1,50,25)");
|
|
123
|
+
});
|
|
124
|
+
it("hit tests through the transform", () => {
|
|
125
|
+
const { value } = harness.compileAndRun("transform-hit", `
|
|
126
|
+
import { createWindow, run } from "gui";
|
|
127
|
+
|
|
128
|
+
const HTML = \`
|
|
129
|
+
<html><head><style>
|
|
130
|
+
body { margin: 0; }
|
|
131
|
+
#box {
|
|
132
|
+
position: absolute; left: 100px; top: 100px; width: 100px; height: 50px;
|
|
133
|
+
background-color: #ff0000;
|
|
134
|
+
transform-origin: 0 0;
|
|
135
|
+
transform: rotate(90deg);
|
|
136
|
+
}
|
|
137
|
+
</style></head><body><div id="box"></div></body></html>
|
|
138
|
+
\`;
|
|
139
|
+
|
|
140
|
+
const win = createWindow({ title: "hit", width: 400, height: 300 });
|
|
141
|
+
win.on("ready", () => {
|
|
142
|
+
/* The rotated box covers x 50..150, y 100..200 and no longer covers the
|
|
143
|
+
* area it occupied before the rotation (x 100..200). */
|
|
144
|
+
console.log("rotated=" + win.hitTest(60, 190));
|
|
145
|
+
console.log("vacated=" + win.hitTest(190, 110));
|
|
146
|
+
win.close();
|
|
147
|
+
});
|
|
148
|
+
win.loadHTML(HTML);
|
|
149
|
+
run();
|
|
150
|
+
`);
|
|
151
|
+
expect(value("rotated")).toBe("div#box");
|
|
152
|
+
expect(value("vacated")).toBe("");
|
|
153
|
+
});
|
|
154
|
+
it("animates `transform` through a CSS transition", () => {
|
|
155
|
+
const { value } = harness.compileAndRun("transform-transition", `
|
|
156
|
+
import { createWindow, run } from "gui";
|
|
157
|
+
|
|
158
|
+
const HTML = \`
|
|
159
|
+
<html><head><style>
|
|
160
|
+
body { margin: 0; }
|
|
161
|
+
#box {
|
|
162
|
+
position: absolute; left: 20px; top: 200px; width: 60px; height: 30px;
|
|
163
|
+
background-color: #0000ff;
|
|
164
|
+
transform: translateX(0px) rotate(0deg);
|
|
165
|
+
transition: transform 400ms linear;
|
|
166
|
+
}
|
|
167
|
+
#box:hover { transform: translateX(40px) rotate(90deg); }
|
|
168
|
+
</style></head><body><div id="box"></div></body></html>
|
|
169
|
+
\`;
|
|
170
|
+
|
|
171
|
+
const win = createWindow({ title: "transition", width: 400, height: 300 });
|
|
172
|
+
win.on("ready", () => {
|
|
173
|
+
console.log("start=" + win.computedStyle("#box", "transform"));
|
|
174
|
+
win.sendEvent("mousemove", { x: 50, y: 215 });
|
|
175
|
+
win.advance(100);
|
|
176
|
+
console.log("q1=" + win.computedStyle("#box", "transform"));
|
|
177
|
+
win.advance(200);
|
|
178
|
+
console.log("q3=" + win.computedStyle("#box", "transform"));
|
|
179
|
+
win.advance(200);
|
|
180
|
+
console.log("end=" + win.computedStyle("#box", "transform"));
|
|
181
|
+
const end = win.getBoundingClientRect("#box");
|
|
182
|
+
console.log("end-rect=" + end.x.toFixed(1) + "," + end.y.toFixed(1) + "," +
|
|
183
|
+
end.width.toFixed(1) + "," + end.height.toFixed(1));
|
|
184
|
+
win.close();
|
|
185
|
+
});
|
|
186
|
+
win.loadHTML(HTML);
|
|
187
|
+
run();
|
|
188
|
+
`);
|
|
189
|
+
expect(value("start")).toBe("translateX(0px) rotate(0deg)");
|
|
190
|
+
// 100/400 and 300/400 of the way between the two lists, linearly.
|
|
191
|
+
expect(value("q1")).toBe("translateX(10px) rotate(22.5deg)");
|
|
192
|
+
expect(value("q3")).toBe("translateX(30px) rotate(67.5deg)");
|
|
193
|
+
expect(value("end")).toBe("translateX(40px) rotate(90deg)");
|
|
194
|
+
// Moved 40px right and rotated a quarter turn about its centre.
|
|
195
|
+
expect(value("end-rect")).toBe("75.0,185.0,30.0,60.0");
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
//# sourceMappingURL=gui-transform.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui-transform.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-transform.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the lazy (rope/cons) string model.
|
|
3
|
+
*
|
|
4
|
+
* Concatenation above the eager-copy threshold produces an immutable cons node
|
|
5
|
+
* whose bytes are materialised on first observation. These tests exercise every
|
|
6
|
+
* kind of observation (length, slicing, searching, case changes, JSON, property
|
|
7
|
+
* keys) and keep chains reachable across a garbage collection.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the lazy (rope/cons) string model.
|
|
3
|
+
*
|
|
4
|
+
* Concatenation above the eager-copy threshold produces an immutable cons node
|
|
5
|
+
* whose bytes are materialised on first observation. These tests exercise every
|
|
6
|
+
* kind of observation (length, slicing, searching, case changes, JSON, property
|
|
7
|
+
* keys) and keep chains reachable across a garbage collection.
|
|
8
|
+
*/
|
|
9
|
+
import { expect, it } from "vitest";
|
|
10
|
+
import { describeE2E } from "./harness.js";
|
|
11
|
+
describeE2E("lazy string concatenation", (harness) => {
|
|
12
|
+
const { runProgram, runProgramFull } = harness;
|
|
13
|
+
it("matches Node for append and prepend chains", () => {
|
|
14
|
+
const source = `
|
|
15
|
+
function build(n: number): string {
|
|
16
|
+
let text = "";
|
|
17
|
+
for (let i = 0; i < n; i++) text = text + "abcdefghijklmnopqrstuvwxyz".charAt(i % 26);
|
|
18
|
+
return text;
|
|
19
|
+
}
|
|
20
|
+
const text = build(2000);
|
|
21
|
+
console.log(text.length);
|
|
22
|
+
console.log(text.slice(0, 26));
|
|
23
|
+
console.log(text.slice(-26));
|
|
24
|
+
console.log(text.indexOf("xyz"));
|
|
25
|
+
console.log(text.lastIndexOf("abc"));
|
|
26
|
+
console.log(text.includes("mnop"));
|
|
27
|
+
console.log(text.split("def").length);
|
|
28
|
+
console.log(text.toUpperCase().slice(0, 26));
|
|
29
|
+
console.log(text.replace("abc", "ABC").slice(0, 26));
|
|
30
|
+
console.log(text.replaceAll("a", "!").slice(0, 26));
|
|
31
|
+
console.log(text === build(2000));
|
|
32
|
+
console.log(text.startsWith("abc"), text.endsWith("xyz"));
|
|
33
|
+
console.log(JSON.stringify(text.slice(0, 10)));
|
|
34
|
+
console.log(text.charCodeAt(5), text.at(-1));
|
|
35
|
+
|
|
36
|
+
let prepended = "";
|
|
37
|
+
for (let i = 0; i < 2000; i++) prepended = "x" + prepended;
|
|
38
|
+
console.log(prepended.length, prepended.slice(0, 3), prepended.slice(-3));
|
|
39
|
+
|
|
40
|
+
let mixed = "";
|
|
41
|
+
for (let i = 0; i < 200; i++) mixed += i;
|
|
42
|
+
console.log(mixed.length, mixed.slice(0, 12));
|
|
43
|
+
|
|
44
|
+
let templated = "";
|
|
45
|
+
for (let i = 0; i < 2000; i++) templated = \`\${templated}\${i % 10}\`;
|
|
46
|
+
console.log(templated.length, templated.slice(0, 12));
|
|
47
|
+
|
|
48
|
+
let key = "";
|
|
49
|
+
for (let i = 0; i < 40; i++) key += "k";
|
|
50
|
+
const holder: any = {};
|
|
51
|
+
holder[key] = "v";
|
|
52
|
+
console.log(holder[key], Object.keys(holder)[0].length);
|
|
53
|
+
console.log([text, prepended].join("|").length);
|
|
54
|
+
`;
|
|
55
|
+
harness.expectSameOutputAsNode(source, { name: "string_concat_chains" });
|
|
56
|
+
});
|
|
57
|
+
it("keeps cons nodes reachable across collections", () => {
|
|
58
|
+
const source = `
|
|
59
|
+
let text = "";
|
|
60
|
+
for (let i = 0; i < 2000; i++) text += "z";
|
|
61
|
+
const holder: any = { text: text };
|
|
62
|
+
const list: any[] = [text];
|
|
63
|
+
text = "";
|
|
64
|
+
|
|
65
|
+
/* Allocate and drop many objects to force collections while the rope is
|
|
66
|
+
reachable only through the object property and the array element. */
|
|
67
|
+
let junk: any = {};
|
|
68
|
+
for (let i = 0; i < 40000; i++) junk = { value: i };
|
|
69
|
+
junk = {};
|
|
70
|
+
const trigger = "x" + "y";
|
|
71
|
+
|
|
72
|
+
/* Reuse the freed memory before the rope is ever flattened. */
|
|
73
|
+
const reuse: any[] = [];
|
|
74
|
+
for (let i = 0; i < 5000; i++) reuse.push("a" + "b");
|
|
75
|
+
|
|
76
|
+
console.log(holder.text.length, holder.text === "z".repeat(2000));
|
|
77
|
+
console.log(list[0].length, list[0] === holder.text, reuse.length, trigger);
|
|
78
|
+
console.log(holder.text.slice(0, 2), holder.text.slice(-2), holder.text.toUpperCase().slice(0, 3));
|
|
79
|
+
`;
|
|
80
|
+
const result = runProgramFull(source, {
|
|
81
|
+
name: "string_concat_gc",
|
|
82
|
+
env: { XT_GC_THRESHOLD: "1048576" },
|
|
83
|
+
timeout: 60000,
|
|
84
|
+
});
|
|
85
|
+
expect(result.status).toBe(0);
|
|
86
|
+
expect(result.stdout.trim()).toBe("2000 true\n2000 true 5000 xy\nzz zz ZZZ");
|
|
87
|
+
});
|
|
88
|
+
it("flattens reused chains without mutating earlier results", () => {
|
|
89
|
+
const source = `
|
|
90
|
+
let prefix = "start-";
|
|
91
|
+
for (let i = 0; i < 200; i++) prefix += "p";
|
|
92
|
+
const first = prefix + "-first";
|
|
93
|
+
const second = prefix + "-second";
|
|
94
|
+
const prefixCopy = prefix.slice(0);
|
|
95
|
+
console.log(first.slice(-6), second.slice(-7));
|
|
96
|
+
console.log(prefix.length, first.length, second.length);
|
|
97
|
+
console.log(prefix === prefixCopy, prefix === first.slice(0, prefix.length));
|
|
98
|
+
`;
|
|
99
|
+
expect(runProgram(source)).toBe("-first -second\n206 212 213\ntrue true");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=string-concat.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-concat.test.js","sourceRoot":"","sources":["../../../tests/e2e/string-concat.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,WAAW,CAAC,2BAA2B,EAAE,CAAC,OAAO,EAAE,EAAE;IACnD,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAE/C,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwClB,CAAC;QACE,OAAO,CAAC,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBlB,CAAC;QACE,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE;YACpC,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,EAAE,eAAe,EAAE,SAAS,EAAE;YACnC,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,MAAM,GAAG;;;;;;;;;CASlB,CAAC;QACE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/tests/helpers.d.ts
CHANGED
|
@@ -18,9 +18,18 @@ export declare function bindSource(text: string): {
|
|
|
18
18
|
export declare function compileToIr(text: string, extensions?: ExtensionRegistry, target?: {
|
|
19
19
|
platform: string;
|
|
20
20
|
arch: string;
|
|
21
|
+
}, options?: {
|
|
22
|
+
readonly debug?: boolean;
|
|
21
23
|
}): {
|
|
22
24
|
ir: string;
|
|
23
25
|
binding: BindResult;
|
|
24
26
|
diagnostics: readonly Diagnostic[];
|
|
25
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* True when a *supported* clang is available. The end-to-end suites really
|
|
30
|
+
* compile and link native binaries, and the emitted IR needs clang >= 16, so a
|
|
31
|
+
* missing or too-old toolchain skips them instead of failing every case with an
|
|
32
|
+
* opaque-pointer error. `resolveToolchain` applies the same selection (and
|
|
33
|
+
* version gate) the driver uses, so the tests and the compiler agree.
|
|
34
|
+
*/
|
|
26
35
|
export declare function hasClang(): boolean;
|
package/dist/tests/helpers.js
CHANGED
|
@@ -7,7 +7,8 @@ import { Parser } from "../src/parser/parser.js";
|
|
|
7
7
|
import { bind } from "../src/binder/binder.js";
|
|
8
8
|
import { generate } from "../src/codegen/llvm.js";
|
|
9
9
|
import { createDefaultRegistry } from "../src/extensions/registry.js";
|
|
10
|
-
import {
|
|
10
|
+
import { MINIMUM_CLANG_MAJOR } from "../src/driver/toolchain.js";
|
|
11
|
+
import { resolveToolchain } from "../src/driver/toolchain-provider.js";
|
|
11
12
|
export function lex(text) {
|
|
12
13
|
const source = new SourceFile("test.ts", sourceTextBytes(text));
|
|
13
14
|
const diagnostics = new DiagnosticBag();
|
|
@@ -28,7 +29,7 @@ export function bindSource(text) {
|
|
|
28
29
|
const result = bind(file);
|
|
29
30
|
return { result, diagnostics: bag.diagnostics };
|
|
30
31
|
}
|
|
31
|
-
export function compileToIr(text, extensions, target) {
|
|
32
|
+
export function compileToIr(text, extensions, target, options = {}) {
|
|
32
33
|
const { file, diagnostics: parseDiagnostics } = parse(text);
|
|
33
34
|
const diagnostics = new DiagnosticBag();
|
|
34
35
|
diagnostics.addAll(parseDiagnostics);
|
|
@@ -37,10 +38,32 @@ export function compileToIr(text, extensions, target) {
|
|
|
37
38
|
builtins: registry.builtins(),
|
|
38
39
|
modules: registry.modules(),
|
|
39
40
|
...(target ? { target } : {}),
|
|
41
|
+
debug: options.debug === true,
|
|
40
42
|
});
|
|
41
43
|
return { ir, binding, diagnostics: diagnostics.diagnostics };
|
|
42
44
|
}
|
|
45
|
+
let cachedClangSupport;
|
|
46
|
+
/**
|
|
47
|
+
* True when a *supported* clang is available. The end-to-end suites really
|
|
48
|
+
* compile and link native binaries, and the emitted IR needs clang >= 16, so a
|
|
49
|
+
* missing or too-old toolchain skips them instead of failing every case with an
|
|
50
|
+
* opaque-pointer error. `resolveToolchain` applies the same selection (and
|
|
51
|
+
* version gate) the driver uses, so the tests and the compiler agree.
|
|
52
|
+
*/
|
|
43
53
|
export function hasClang() {
|
|
44
|
-
|
|
54
|
+
if (cachedClangSupport === undefined) {
|
|
55
|
+
try {
|
|
56
|
+
const version = resolveToolchain().version;
|
|
57
|
+
cachedClangSupport = version === undefined || version.major >= MINIMUM_CLANG_MAJOR;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
cachedClangSupport = false;
|
|
61
|
+
}
|
|
62
|
+
if (!cachedClangSupport) {
|
|
63
|
+
console.warn(`xbintsc: skipping end-to-end tests — clang ${MINIMUM_CLANG_MAJOR}+ was not found ` +
|
|
64
|
+
"(see doc/requirements.md, or set xbintsc_CLANG)");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return cachedClangSupport;
|
|
45
68
|
}
|
|
46
69
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../tests/helpers.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAErD,OAAO,EAAE,aAAa,EAAmB,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAmB,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAA0B,MAAM,+BAA+B,CAAC;AAC9F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../tests/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,4 +44,11 @@ describe("assignment validation", () => {
|
|
|
44
44
|
expect(diagnostics.some((d) => d.code === DiagnosticCode.InvalidAssignmentTarget)).toBe(true);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
|
+
describe("unsupported syntax", () => {
|
|
48
|
+
it("reports new.target as an unsupported feature, not a syntax error", () => {
|
|
49
|
+
const { diagnostics } = parse("function F() { return new.target; }");
|
|
50
|
+
expect(diagnostics.map((d) => d.code)).toContain(DiagnosticCode.UnsupportedFeature);
|
|
51
|
+
expect(diagnostics.map((d) => d.code)).not.toContain(DiagnosticCode.UnexpectedToken);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
47
54
|
//# sourceMappingURL=expressions.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.test.js","sourceRoot":"","sources":["../../../tests/parser/expressions.test.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAErE,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAQ,CAAC;IACvC,OAAO,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1D,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,2BAA2B,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,+BAA+B,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,wBAAwB,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"expressions.test.js","sourceRoot":"","sources":["../../../tests/parser/expressions.test.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAErE,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAQ,CAAC;IACvC,OAAO,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1D,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,2BAA2B,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,+BAA+B,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,wBAAwB,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;QACpF,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { COMPILER_VERSION } from "../src/driver/compiler.js";
|
|
4
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
5
|
+
describe("compiler version", () => {
|
|
6
|
+
it("matches package.json", () => {
|
|
7
|
+
expect(COMPILER_VERSION).toBe(packageJson.version);
|
|
8
|
+
});
|
|
9
|
+
it("is part of the incremental cache key", () => {
|
|
10
|
+
const source = readFileSync(new URL("../src/driver/compiler.ts", import.meta.url), "utf8");
|
|
11
|
+
expect(source).toMatch(/hashParts\(\[\s*COMPILER_VERSION,/);
|
|
12
|
+
});
|
|
13
|
+
it("is printed by `xbintsc version`", async () => {
|
|
14
|
+
const { run } = await import("../src/cli/main.js");
|
|
15
|
+
const lines = [];
|
|
16
|
+
const code = run(["version"], {
|
|
17
|
+
stdout: (text) => lines.push(text),
|
|
18
|
+
stderr: (text) => lines.push(text),
|
|
19
|
+
});
|
|
20
|
+
expect(code).toBe(0);
|
|
21
|
+
expect(lines.join("")).toContain(COMPILER_VERSION);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=version.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../../tests/version.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC3C,CAAC;AAEzB,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACnD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE;YAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|