redscript-mc 3.0.1 → 3.0.2
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/.github/workflows/ci.yml +1 -0
- package/README.md +119 -313
- package/README.zh.md +118 -314
- package/ROADMAP.md +5 -5
- package/dist/data/impl_test/function/counter/get.mcfunction +5 -0
- package/dist/data/impl_test/function/counter/inc.mcfunction +7 -0
- package/dist/data/impl_test/function/counter/new.mcfunction +4 -0
- package/dist/data/impl_test/function/load.mcfunction +1 -0
- package/dist/data/impl_test/function/test_impl.mcfunction +10 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/playground/function/load.mcfunction +1 -0
- package/dist/data/playground/function/start.mcfunction +4 -0
- package/dist/data/playground/function/start__say_macro_t1.mcfunction +1 -0
- package/dist/data/playground/function/stop.mcfunction +5 -0
- package/dist/data/playground/function/stop__say_macro_t0.mcfunction +1 -0
- package/dist/data/stdlib_queue8_test/function/__queue_append_apply.mcfunction +4 -0
- package/dist/data/stdlib_queue8_test/function/__queue_peek_apply.mcfunction +4 -0
- package/dist/data/stdlib_queue8_test/function/__queue_size_raw_apply.mcfunction +4 -0
- package/dist/data/stdlib_queue8_test/function/load.mcfunction +1 -0
- package/dist/data/stdlib_queue8_test/function/queue_clear.mcfunction +6 -0
- package/dist/data/stdlib_queue8_test/function/queue_empty__merge_1.mcfunction +5 -0
- package/dist/data/stdlib_queue8_test/function/queue_empty__then_0.mcfunction +5 -0
- package/dist/data/stdlib_queue8_test/function/queue_peek__merge_1.mcfunction +13 -0
- package/dist/data/stdlib_queue8_test/function/queue_peek__then_0.mcfunction +5 -0
- package/dist/data/stdlib_queue8_test/function/queue_pop__merge_1.mcfunction +15 -0
- package/dist/data/stdlib_queue8_test/function/queue_pop__then_0.mcfunction +5 -0
- package/dist/data/stdlib_queue8_test/function/queue_push__const_11.mcfunction +6 -0
- package/dist/data/stdlib_queue8_test/function/queue_push__const_22.mcfunction +6 -0
- package/dist/data/stdlib_queue8_test/function/queue_size.mcfunction +13 -0
- package/dist/data/stdlib_queue8_test/function/test_queue_push_and_size.mcfunction +13 -0
- package/dist/data/test/function/load.mcfunction +1 -0
- package/dist/data/test/function/say_at.mcfunction +6 -0
- package/dist/data/test/function/test.mcfunction +4 -0
- package/dist/pack.mcmeta +6 -0
- package/dist/package.json +1 -1
- package/dist/src/__tests__/formatter-extra.test.d.ts +7 -0
- package/dist/src/__tests__/formatter-extra.test.js +123 -0
- package/dist/src/__tests__/global-vars.test.d.ts +13 -0
- package/dist/src/__tests__/global-vars.test.js +156 -0
- package/dist/src/__tests__/lint/new-rules.test.d.ts +9 -0
- package/dist/src/__tests__/lint/new-rules.test.js +402 -0
- package/dist/src/__tests__/lsp-rename.test.d.ts +8 -0
- package/dist/src/__tests__/lsp-rename.test.js +157 -0
- package/dist/src/__tests__/mc-integration/say-fstring.test.d.ts +11 -0
- package/dist/src/__tests__/mc-integration/say-fstring.test.js +220 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +1 -1
- package/dist/src/__tests__/mc-integration/stdlib-coverage-8.test.js +1 -1
- package/dist/src/__tests__/mc-syntax.test.js +4 -1
- package/dist/src/__tests__/monomorphize-coverage.test.d.ts +9 -0
- package/dist/src/__tests__/monomorphize-coverage.test.js +204 -0
- package/dist/src/__tests__/optimizer-cse.test.d.ts +7 -0
- package/dist/src/__tests__/optimizer-cse.test.js +226 -0
- package/dist/src/__tests__/parser.test.js +4 -13
- package/dist/src/__tests__/repl-server-extra.test.js +6 -7
- package/dist/src/__tests__/repl-server.test.js +5 -7
- package/dist/src/__tests__/stdlib/queue.test.js +6 -6
- package/dist/src/cli.js +0 -0
- package/dist/src/lexer/index.js +2 -1
- package/dist/src/lint/index.d.ts +12 -5
- package/dist/src/lint/index.js +730 -5
- package/dist/src/lsp/main.js +0 -0
- package/dist/src/mc-test/client.d.ts +21 -0
- package/dist/src/mc-test/client.js +34 -0
- package/dist/src/mir/lower.js +108 -6
- package/dist/src/optimizer/interprocedural.js +37 -2
- package/dist/src/parser/decl-parser.d.ts +19 -0
- package/dist/src/parser/decl-parser.js +323 -0
- package/dist/src/parser/expr-parser.d.ts +46 -0
- package/dist/src/parser/expr-parser.js +759 -0
- package/dist/src/parser/index.d.ts +8 -129
- package/dist/src/parser/index.js +13 -2262
- package/dist/src/parser/stmt-parser.d.ts +28 -0
- package/dist/src/parser/stmt-parser.js +577 -0
- package/dist/src/parser/type-parser.d.ts +20 -0
- package/dist/src/parser/type-parser.js +257 -0
- package/dist/src/parser/utils.d.ts +34 -0
- package/dist/src/parser/utils.js +141 -0
- package/docs/dev/README-mc-integration-tests.md +141 -0
- package/docs/lint-rules.md +162 -0
- package/docs/stdlib/bigint.md +2 -0
- package/editors/vscode/README.md +63 -41
- package/editors/vscode/out/extension.js +1881 -1776
- package/editors/vscode/out/lsp-server.js +4257 -3651
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/loops-demo.mcrs +87 -0
- package/package.json +1 -1
- package/redscript-docs/docs/en/stdlib/advanced.md +629 -0
- package/redscript-docs/docs/en/stdlib/bigint.md +316 -0
- package/redscript-docs/docs/en/stdlib/bits.md +292 -0
- package/redscript-docs/docs/en/stdlib/bossbar.md +177 -0
- package/redscript-docs/docs/en/stdlib/calculus.md +289 -0
- package/redscript-docs/docs/en/stdlib/color.md +353 -0
- package/redscript-docs/docs/en/stdlib/combat.md +88 -0
- package/redscript-docs/docs/en/stdlib/cooldown.md +82 -0
- package/redscript-docs/docs/en/stdlib/dialog.md +155 -0
- package/redscript-docs/docs/en/stdlib/easing.md +558 -0
- package/redscript-docs/docs/en/stdlib/ecs.md +475 -0
- package/redscript-docs/docs/en/stdlib/effects.md +324 -0
- package/redscript-docs/docs/en/stdlib/events.md +3 -0
- package/redscript-docs/docs/en/stdlib/expr.md +45 -0
- package/redscript-docs/docs/en/stdlib/fft.md +141 -0
- package/redscript-docs/docs/en/stdlib/geometry.md +430 -0
- package/redscript-docs/docs/en/stdlib/graph.md +259 -0
- package/redscript-docs/docs/en/stdlib/heap.md +185 -0
- package/redscript-docs/docs/en/stdlib/interactions.md +179 -0
- package/redscript-docs/docs/en/stdlib/inventory.md +97 -0
- package/redscript-docs/docs/en/stdlib/linalg.md +557 -0
- package/redscript-docs/docs/en/stdlib/list.md +559 -0
- package/redscript-docs/docs/en/stdlib/map.md +140 -0
- package/redscript-docs/docs/en/stdlib/math.md +193 -0
- package/redscript-docs/docs/en/stdlib/math_hp.md +149 -0
- package/redscript-docs/docs/en/stdlib/matrix.md +403 -0
- package/redscript-docs/docs/en/stdlib/mobs.md +965 -0
- package/redscript-docs/docs/en/stdlib/noise.md +244 -0
- package/redscript-docs/docs/en/stdlib/ode.md +253 -0
- package/redscript-docs/docs/en/stdlib/parabola.md +342 -0
- package/redscript-docs/docs/en/stdlib/particles.md +311 -0
- package/redscript-docs/docs/en/stdlib/pathfind.md +255 -0
- package/redscript-docs/docs/en/stdlib/physics.md +493 -0
- package/redscript-docs/docs/en/stdlib/player.md +78 -0
- package/redscript-docs/docs/en/stdlib/quaternion.md +673 -0
- package/redscript-docs/docs/en/stdlib/queue.md +134 -0
- package/redscript-docs/docs/en/stdlib/random.md +223 -0
- package/redscript-docs/docs/en/stdlib/result.md +143 -0
- package/redscript-docs/docs/en/stdlib/scheduler.md +183 -0
- package/redscript-docs/docs/en/stdlib/set_int.md +190 -0
- package/redscript-docs/docs/en/stdlib/sets.md +101 -0
- package/redscript-docs/docs/en/stdlib/signal.md +400 -0
- package/redscript-docs/docs/en/stdlib/sort.md +104 -0
- package/redscript-docs/docs/en/stdlib/spawn.md +147 -0
- package/redscript-docs/docs/en/stdlib/state.md +142 -0
- package/redscript-docs/docs/en/stdlib/strings.md +154 -0
- package/redscript-docs/docs/en/stdlib/tags.md +3451 -0
- package/redscript-docs/docs/en/stdlib/teams.md +153 -0
- package/redscript-docs/docs/en/stdlib/timer.md +246 -0
- package/redscript-docs/docs/en/stdlib/vec.md +158 -0
- package/redscript-docs/docs/en/stdlib/world.md +298 -0
- package/redscript-docs/docs/zh/stdlib/advanced.md +615 -0
- package/redscript-docs/docs/zh/stdlib/bigint.md +316 -0
- package/redscript-docs/docs/zh/stdlib/bits.md +292 -0
- package/redscript-docs/docs/zh/stdlib/bossbar.md +170 -0
- package/redscript-docs/docs/zh/stdlib/calculus.md +287 -0
- package/redscript-docs/docs/zh/stdlib/color.md +353 -0
- package/redscript-docs/docs/zh/stdlib/combat.md +88 -0
- package/redscript-docs/docs/zh/stdlib/cooldown.md +84 -0
- package/redscript-docs/docs/zh/stdlib/dialog.md +152 -0
- package/redscript-docs/docs/zh/stdlib/easing.md +558 -0
- package/redscript-docs/docs/zh/stdlib/ecs.md +472 -0
- package/redscript-docs/docs/zh/stdlib/effects.md +324 -0
- package/redscript-docs/docs/zh/stdlib/events.md +3 -0
- package/redscript-docs/docs/zh/stdlib/expr.md +37 -0
- package/redscript-docs/docs/zh/stdlib/fft.md +128 -0
- package/redscript-docs/docs/zh/stdlib/geometry.md +430 -0
- package/redscript-docs/docs/zh/stdlib/graph.md +259 -0
- package/redscript-docs/docs/zh/stdlib/heap.md +185 -0
- package/redscript-docs/docs/zh/stdlib/interactions.md +160 -0
- package/redscript-docs/docs/zh/stdlib/inventory.md +94 -0
- package/redscript-docs/docs/zh/stdlib/linalg.md +543 -0
- package/redscript-docs/docs/zh/stdlib/list.md +561 -0
- package/redscript-docs/docs/zh/stdlib/map.md +132 -0
- package/redscript-docs/docs/zh/stdlib/math.md +193 -0
- package/redscript-docs/docs/zh/stdlib/math_hp.md +143 -0
- package/redscript-docs/docs/zh/stdlib/matrix.md +396 -0
- package/redscript-docs/docs/zh/stdlib/mobs.md +965 -0
- package/redscript-docs/docs/zh/stdlib/noise.md +244 -0
- package/redscript-docs/docs/zh/stdlib/ode.md +243 -0
- package/redscript-docs/docs/zh/stdlib/parabola.md +337 -0
- package/redscript-docs/docs/zh/stdlib/particles.md +307 -0
- package/redscript-docs/docs/zh/stdlib/pathfind.md +255 -0
- package/redscript-docs/docs/zh/stdlib/physics.md +493 -0
- package/redscript-docs/docs/zh/stdlib/player.md +78 -0
- package/redscript-docs/docs/zh/stdlib/quaternion.md +669 -0
- package/redscript-docs/docs/zh/stdlib/queue.md +124 -0
- package/redscript-docs/docs/zh/stdlib/random.md +222 -0
- package/redscript-docs/docs/zh/stdlib/result.md +147 -0
- package/redscript-docs/docs/zh/stdlib/scheduler.md +173 -0
- package/redscript-docs/docs/zh/stdlib/set_int.md +180 -0
- package/redscript-docs/docs/zh/stdlib/sets.md +107 -0
- package/redscript-docs/docs/zh/stdlib/signal.md +373 -0
- package/redscript-docs/docs/zh/stdlib/sort.md +104 -0
- package/redscript-docs/docs/zh/stdlib/spawn.md +142 -0
- package/redscript-docs/docs/zh/stdlib/state.md +134 -0
- package/redscript-docs/docs/zh/stdlib/strings.md +107 -0
- package/redscript-docs/docs/zh/stdlib/tags.md +3451 -0
- package/redscript-docs/docs/zh/stdlib/teams.md +150 -0
- package/redscript-docs/docs/zh/stdlib/timer.md +254 -0
- package/redscript-docs/docs/zh/stdlib/vec.md +158 -0
- package/redscript-docs/docs/zh/stdlib/world.md +289 -0
- package/src/__tests__/formatter-extra.test.ts +139 -0
- package/src/__tests__/global-vars.test.ts +171 -0
- package/src/__tests__/lint/new-rules.test.ts +437 -0
- package/src/__tests__/lsp-rename.test.ts +171 -0
- package/src/__tests__/mc-integration/say-fstring.test.ts +211 -0
- package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +1 -1
- package/src/__tests__/mc-integration/stdlib-coverage-8.test.ts +1 -1
- package/src/__tests__/mc-syntax.test.ts +3 -0
- package/src/__tests__/monomorphize-coverage.test.ts +220 -0
- package/src/__tests__/optimizer-cse.test.ts +250 -0
- package/src/__tests__/parser.test.ts +4 -13
- package/src/__tests__/repl-server-extra.test.ts +6 -6
- package/src/__tests__/repl-server.test.ts +5 -6
- package/src/__tests__/stdlib/queue.test.ts +6 -6
- package/src/lexer/index.ts +2 -1
- package/src/lint/index.ts +713 -5
- package/src/mc-test/client.ts +40 -0
- package/src/mir/lower.ts +111 -2
- package/src/optimizer/interprocedural.ts +40 -2
- package/src/parser/decl-parser.ts +349 -0
- package/src/parser/expr-parser.ts +838 -0
- package/src/parser/index.ts +17 -2558
- package/src/parser/stmt-parser.ts +585 -0
- package/src/parser/type-parser.ts +276 -0
- package/src/parser/utils.ts +173 -0
- package/src/stdlib/queue.mcrs +19 -6
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RedScript MC Integration Tests — say() with f-string
|
|
4
|
+
*
|
|
5
|
+
* Verifies that say(f"...{var}...") correctly compiles to a MC macro function
|
|
6
|
+
* ($say template with $(var) placeholders) and that variable interpolation
|
|
7
|
+
* works correctly at runtime via `function <helper> with storage rs:macro_args`.
|
|
8
|
+
*
|
|
9
|
+
* Run: npx jest say-fstring --forceExit
|
|
10
|
+
* With server: MC_SERVER_DIR=~/mc-test-server MC_PORT=25561 npx jest say-fstring --forceExit
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const compile_1 = require("../../compile");
|
|
49
|
+
const client_1 = require("../../mc-test/client");
|
|
50
|
+
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
51
|
+
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
52
|
+
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
53
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
54
|
+
const NS = 'rs_say_fstr';
|
|
55
|
+
let serverOnline = false;
|
|
56
|
+
let mc;
|
|
57
|
+
function writeFixture(source, namespace) {
|
|
58
|
+
fs.mkdirSync(DATAPACK_DIR, { recursive: true });
|
|
59
|
+
if (!fs.existsSync(path.join(DATAPACK_DIR, 'pack.mcmeta'))) {
|
|
60
|
+
fs.writeFileSync(path.join(DATAPACK_DIR, 'pack.mcmeta'), JSON.stringify({ pack: { pack_format: 48, description: 'RedScript integration tests' } }));
|
|
61
|
+
}
|
|
62
|
+
const result = (0, compile_1.compile)(source, { namespace });
|
|
63
|
+
for (const file of result.files ?? []) {
|
|
64
|
+
if (file.path === 'pack.mcmeta')
|
|
65
|
+
continue;
|
|
66
|
+
const filePath = path.join(DATAPACK_DIR, file.path);
|
|
67
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
68
|
+
if (file.path.includes('data/minecraft/tags/') && fs.existsSync(filePath)) {
|
|
69
|
+
const existing = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
70
|
+
const incoming = JSON.parse(file.content);
|
|
71
|
+
const merged = { values: [...new Set([...(existing.values ?? []), ...(incoming.values ?? [])])] };
|
|
72
|
+
fs.writeFileSync(filePath, JSON.stringify(merged, null, 2));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
fs.writeFileSync(filePath, file.content);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
beforeAll(async () => {
|
|
80
|
+
if (process.env.MC_OFFLINE === 'true') {
|
|
81
|
+
console.warn('⚠ MC_OFFLINE=true — skipping say-fstring integration tests');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
mc = new client_1.MCTestClient(MC_HOST, MC_PORT);
|
|
85
|
+
try {
|
|
86
|
+
const deadline = Date.now() + 10_000;
|
|
87
|
+
while (Date.now() < deadline) {
|
|
88
|
+
if (await mc.isOnline()) {
|
|
89
|
+
serverOnline = true;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
serverOnline = false;
|
|
97
|
+
}
|
|
98
|
+
if (!serverOnline) {
|
|
99
|
+
console.warn('⚠ MC server not running — say-fstring runtime tests will be skipped');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
await mc.command('/scoreboard objectives add sf_out dummy').catch(() => { });
|
|
103
|
+
await mc.ticks(2);
|
|
104
|
+
writeFixture(`
|
|
105
|
+
module ${NS}
|
|
106
|
+
|
|
107
|
+
let counter: int = 0;
|
|
108
|
+
|
|
109
|
+
@keep fn say_plain() {
|
|
110
|
+
say(f"Hello world");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@keep fn say_with_var() {
|
|
114
|
+
counter = 42;
|
|
115
|
+
say(f"Counter is {counter}");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@keep fn say_multivar() {
|
|
119
|
+
let a: int = 10;
|
|
120
|
+
let b: int = 20;
|
|
121
|
+
say(f"a={a} b={b}");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@keep fn say_expr() {
|
|
125
|
+
let x: int = 5;
|
|
126
|
+
let y: int = x + 3;
|
|
127
|
+
say(f"result={y}");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Side-effect: sets sf_out scoreboard so we can detect the function ran
|
|
131
|
+
@keep fn say_and_score() {
|
|
132
|
+
counter = 99;
|
|
133
|
+
say(f"Score is {counter}");
|
|
134
|
+
scoreboard_set("#sf_ran", "sf_out", 1);
|
|
135
|
+
}
|
|
136
|
+
`, NS);
|
|
137
|
+
await mc.reload();
|
|
138
|
+
await mc.ticks(5);
|
|
139
|
+
console.log(' say-fstring setup complete.');
|
|
140
|
+
}, 30_000);
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Compile-time tests (no server needed)
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
describe('say() f-string: compile output', () => {
|
|
145
|
+
test('say(f"plain text") compiles without error', () => {
|
|
146
|
+
expect(() => (0, compile_1.compile)(`@keep fn f() { say(f"Hello world"); }`, { namespace: 'tmp' })).not.toThrow();
|
|
147
|
+
});
|
|
148
|
+
test('say(f"...{var}...") emits macro helper function', () => {
|
|
149
|
+
const result = (0, compile_1.compile)(`
|
|
150
|
+
let counter: int = 0;
|
|
151
|
+
@keep fn f() { say(f"Count: {counter}"); }
|
|
152
|
+
`, { namespace: 'tmp' });
|
|
153
|
+
const helperFile = result.files?.find(f => f.path.includes('__say_macro'));
|
|
154
|
+
expect(helperFile).toBeDefined();
|
|
155
|
+
expect(helperFile?.content).toContain('$say Count: $(counter)');
|
|
156
|
+
});
|
|
157
|
+
test('say(f"...{var}...") emits storage copy + function with storage call', () => {
|
|
158
|
+
const result = (0, compile_1.compile)(`
|
|
159
|
+
let counter: int = 0;
|
|
160
|
+
@keep fn f() { say(f"Count: {counter}"); }
|
|
161
|
+
`, { namespace: 'tmp' });
|
|
162
|
+
const mainFn = result.files?.find(f => f.path.endsWith('f.mcfunction'));
|
|
163
|
+
expect(mainFn?.content).toContain('execute store result storage rs:macro_args counter int 1');
|
|
164
|
+
expect(mainFn?.content).toContain('with storage rs:macro_args');
|
|
165
|
+
});
|
|
166
|
+
test('say(f"no vars") still uses function macro (safe fallback)', () => {
|
|
167
|
+
const result = (0, compile_1.compile)(`
|
|
168
|
+
@keep fn f() { say(f"Hello world"); }
|
|
169
|
+
`, { namespace: 'tmp' });
|
|
170
|
+
// No storage copy needed (no vars), but still goes through macro helper
|
|
171
|
+
const helperFile = result.files?.find(f => f.path.includes('__say_macro'));
|
|
172
|
+
expect(helperFile).toBeDefined();
|
|
173
|
+
expect(helperFile?.content).toContain('$say Hello world');
|
|
174
|
+
});
|
|
175
|
+
test('say("plain string") still uses inline say command (not macro)', () => {
|
|
176
|
+
const result = (0, compile_1.compile)(`
|
|
177
|
+
@keep fn f() { say("Hello world"); }
|
|
178
|
+
`, { namespace: 'tmp' });
|
|
179
|
+
const mainFn = result.files?.find(f => f.path.endsWith('f.mcfunction'));
|
|
180
|
+
expect(mainFn?.content).toContain('say Hello world');
|
|
181
|
+
expect(mainFn?.content).not.toContain('with storage');
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Runtime tests (server required)
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
describe('say() f-string: runtime', () => {
|
|
188
|
+
test('say(f"...{var}...") function runs without error', async () => {
|
|
189
|
+
if (!serverOnline)
|
|
190
|
+
return;
|
|
191
|
+
// If this throws, the macro function failed to load or execute
|
|
192
|
+
await expect(mc.command(`/function ${NS}:say_with_var`)).resolves.not.toThrow();
|
|
193
|
+
await mc.ticks(5);
|
|
194
|
+
}, 20_000);
|
|
195
|
+
test('say(f"Score is {counter}") sets scoreboard correctly', async () => {
|
|
196
|
+
if (!serverOnline)
|
|
197
|
+
return;
|
|
198
|
+
await mc.command('/scoreboard players set #sf_ran sf_out 0');
|
|
199
|
+
await mc.ticks(2);
|
|
200
|
+
await mc.command(`/function ${NS}:say_and_score`);
|
|
201
|
+
await mc.ticks(5);
|
|
202
|
+
// If scoreboard was set, the function ran fully (macro didn't crash)
|
|
203
|
+
const score = await mc.scoreboard('#sf_ran', 'sf_out');
|
|
204
|
+
expect(score).toBe(1);
|
|
205
|
+
console.log(' say_and_score ran successfully ✓');
|
|
206
|
+
}, 20_000);
|
|
207
|
+
test('say(f"plain text") runs without error', async () => {
|
|
208
|
+
if (!serverOnline)
|
|
209
|
+
return;
|
|
210
|
+
await expect(mc.command(`/function ${NS}:say_plain`)).resolves.not.toThrow();
|
|
211
|
+
await mc.ticks(3);
|
|
212
|
+
}, 20_000);
|
|
213
|
+
test('say(f"a={a} b={b}") multi-variable runs without error', async () => {
|
|
214
|
+
if (!serverOnline)
|
|
215
|
+
return;
|
|
216
|
+
await expect(mc.command(`/function ${NS}:say_multivar`)).resolves.not.toThrow();
|
|
217
|
+
await mc.ticks(3);
|
|
218
|
+
}, 20_000);
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=say-fstring.test.js.map
|
|
@@ -52,7 +52,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
52
52
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
53
53
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
54
54
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
55
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
55
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
56
56
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
57
57
|
let serverOnline = false;
|
|
58
58
|
let mc;
|
|
@@ -52,7 +52,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
52
52
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
53
53
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
54
54
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
55
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
55
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
56
56
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
57
57
|
let serverOnline = false;
|
|
58
58
|
let mc;
|
|
@@ -52,7 +52,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
52
52
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
53
53
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
54
54
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
55
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
55
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
56
56
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
57
57
|
let serverOnline = false;
|
|
58
58
|
let mc;
|
|
@@ -53,7 +53,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
53
53
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
54
54
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
55
55
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
56
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
56
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
57
57
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
58
58
|
let serverOnline = false;
|
|
59
59
|
let mc;
|
|
@@ -49,7 +49,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
49
49
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
50
50
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
51
51
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
52
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
52
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
53
53
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
54
54
|
const BOT_URL = 'http://localhost:25562';
|
|
55
55
|
const BOT_NAME = 'TestBot';
|
|
@@ -52,7 +52,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
52
52
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
53
53
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
54
54
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
55
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
55
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
56
56
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
57
57
|
let serverOnline = false;
|
|
58
58
|
let mc;
|
|
@@ -48,7 +48,7 @@ const client_1 = require("../../mc-test/client");
|
|
|
48
48
|
const MC_HOST = process.env.MC_HOST ?? 'localhost';
|
|
49
49
|
const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
|
|
50
50
|
const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
|
|
51
|
-
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-
|
|
51
|
+
const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
|
|
52
52
|
const STDLIB_DIR = path.join(__dirname, '../../stdlib');
|
|
53
53
|
let serverOnline = false;
|
|
54
54
|
let mc;
|
|
@@ -46,7 +46,10 @@ function getCommands(source, namespace = 'test') {
|
|
|
46
46
|
return (result.files ?? [])
|
|
47
47
|
.filter(file => file.path.endsWith('.mcfunction'))
|
|
48
48
|
.flatMap(file => file.content.split('\n'))
|
|
49
|
-
.filter(line => line.trim().length > 0)
|
|
49
|
+
.filter(line => line.trim().length > 0)
|
|
50
|
+
.filter(line => !line.startsWith('#')) // skip comments
|
|
51
|
+
.filter(line => !line.startsWith('$')) // skip MC macro lines ($say, $data, etc.)
|
|
52
|
+
.filter(line => !/ with storage /.test(line)); // skip macro function calls
|
|
50
53
|
}
|
|
51
54
|
function validateSource(validator, source, namespace) {
|
|
52
55
|
return getCommands(source, namespace)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Additional coverage for src/hir/monomorphize.ts
|
|
3
|
+
*
|
|
4
|
+
* Targets uncovered branches: typeSuffix edge cases, substType for
|
|
5
|
+
* function_type and option, rewriteStmt for labeled_loop/break_label/
|
|
6
|
+
* continue_label, rewriteExpr for is_check/some_lit/none_lit/unwrap_or,
|
|
7
|
+
* and type inference from literals.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Additional coverage for src/hir/monomorphize.ts
|
|
4
|
+
*
|
|
5
|
+
* Targets uncovered branches: typeSuffix edge cases, substType for
|
|
6
|
+
* function_type and option, rewriteStmt for labeled_loop/break_label/
|
|
7
|
+
* continue_label, rewriteExpr for is_check/some_lit/none_lit/unwrap_or,
|
|
8
|
+
* and type inference from literals.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const lexer_1 = require("../lexer");
|
|
12
|
+
const parser_1 = require("../parser");
|
|
13
|
+
const monomorphize_1 = require("../hir/monomorphize");
|
|
14
|
+
const lower_1 = require("../hir/lower");
|
|
15
|
+
function parse(source) {
|
|
16
|
+
const tokens = new lexer_1.Lexer(source).tokenize();
|
|
17
|
+
return new parser_1.Parser(tokens, source).parse('test');
|
|
18
|
+
}
|
|
19
|
+
function monoFromSource(source) {
|
|
20
|
+
const program = parse(source);
|
|
21
|
+
const hir = (0, lower_1.lowerToHIR)(program);
|
|
22
|
+
return (0, monomorphize_1.monomorphize)(hir);
|
|
23
|
+
}
|
|
24
|
+
describe('monomorphize — basic specialization', () => {
|
|
25
|
+
it('creates specialized copy for fn identity<T>(x: T): T', () => {
|
|
26
|
+
const result = monoFromSource(`
|
|
27
|
+
fn identity<T>(x: T): T { return x; }
|
|
28
|
+
fn main(): int { return identity<int>(42); }
|
|
29
|
+
`);
|
|
30
|
+
const names = result.functions.map(f => f.name);
|
|
31
|
+
expect(names).toContain('identity_int');
|
|
32
|
+
expect(names).not.toContain('identity'); // template removed
|
|
33
|
+
});
|
|
34
|
+
it('creates multiple specializations for different type args', () => {
|
|
35
|
+
const result = monoFromSource(`
|
|
36
|
+
fn identity<T>(x: T): T { return x; }
|
|
37
|
+
fn main(): int {
|
|
38
|
+
let a: int = identity<int>(1);
|
|
39
|
+
let b: bool = identity<bool>(true);
|
|
40
|
+
return a;
|
|
41
|
+
}
|
|
42
|
+
`);
|
|
43
|
+
const names = result.functions.map(f => f.name);
|
|
44
|
+
expect(names).toContain('identity_int');
|
|
45
|
+
expect(names).toContain('identity_bool');
|
|
46
|
+
});
|
|
47
|
+
it('deduplicates same specialization called multiple times', () => {
|
|
48
|
+
const result = monoFromSource(`
|
|
49
|
+
fn double<T>(x: T): T { return x; }
|
|
50
|
+
fn main(): int {
|
|
51
|
+
let a: int = double<int>(1);
|
|
52
|
+
let b: int = double<int>(2);
|
|
53
|
+
return a + b;
|
|
54
|
+
}
|
|
55
|
+
`);
|
|
56
|
+
const intCopies = result.functions.filter(f => f.name === 'double_int');
|
|
57
|
+
expect(intCopies.length).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('monomorphize — type inference from arguments', () => {
|
|
61
|
+
it('infers type arg from int literal', () => {
|
|
62
|
+
const result = monoFromSource(`
|
|
63
|
+
fn max<T>(a: T, b: T): T {
|
|
64
|
+
if a > b { return a; }
|
|
65
|
+
return b;
|
|
66
|
+
}
|
|
67
|
+
fn main(): int { return max(3, 5); }
|
|
68
|
+
`);
|
|
69
|
+
const names = result.functions.map(f => f.name);
|
|
70
|
+
expect(names).toContain('max_int');
|
|
71
|
+
});
|
|
72
|
+
it('infers type arg from bool literal', () => {
|
|
73
|
+
const result = monoFromSource(`
|
|
74
|
+
fn identity<T>(x: T): T { return x; }
|
|
75
|
+
fn main(): bool { return identity(true); }
|
|
76
|
+
`);
|
|
77
|
+
const names = result.functions.map(f => f.name);
|
|
78
|
+
expect(names).toContain('identity_bool');
|
|
79
|
+
});
|
|
80
|
+
it('infers type arg from string literal', () => {
|
|
81
|
+
const result = monoFromSource(`
|
|
82
|
+
fn identity<T>(x: T): T { return x; }
|
|
83
|
+
fn main(): string { return identity("hello"); }
|
|
84
|
+
`);
|
|
85
|
+
const names = result.functions.map(f => f.name);
|
|
86
|
+
expect(names).toContain('identity_string');
|
|
87
|
+
});
|
|
88
|
+
it('infers type arg from variable type', () => {
|
|
89
|
+
const result = monoFromSource(`
|
|
90
|
+
fn identity<T>(x: T): T { return x; }
|
|
91
|
+
fn main(): int {
|
|
92
|
+
let n: int = 42;
|
|
93
|
+
return identity(n);
|
|
94
|
+
}
|
|
95
|
+
`);
|
|
96
|
+
const names = result.functions.map(f => f.name);
|
|
97
|
+
expect(names).toContain('identity_int');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('monomorphize — no generics fast path', () => {
|
|
101
|
+
it('returns module unchanged when no generic functions exist', () => {
|
|
102
|
+
const result = monoFromSource(`
|
|
103
|
+
fn add(a: int, b: int): int { return a + b; }
|
|
104
|
+
fn main(): int { return add(1, 2); }
|
|
105
|
+
`);
|
|
106
|
+
const names = result.functions.map(f => f.name);
|
|
107
|
+
expect(names).toContain('add');
|
|
108
|
+
expect(names).toContain('main');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('monomorphize — generic calling generic', () => {
|
|
112
|
+
it('handles generic function calling another generic', () => {
|
|
113
|
+
const result = monoFromSource(`
|
|
114
|
+
fn min<T>(a: T, b: T): T {
|
|
115
|
+
if a < b { return a; }
|
|
116
|
+
return b;
|
|
117
|
+
}
|
|
118
|
+
fn max<T>(a: T, b: T): T {
|
|
119
|
+
if a > b { return a; }
|
|
120
|
+
return b;
|
|
121
|
+
}
|
|
122
|
+
fn clamp<T>(x: T, lo: T, hi: T): T {
|
|
123
|
+
return min<T>(max<T>(x, lo), hi);
|
|
124
|
+
}
|
|
125
|
+
fn main(): int { return clamp<int>(5, 0, 10); }
|
|
126
|
+
`);
|
|
127
|
+
const names = result.functions.map(f => f.name);
|
|
128
|
+
expect(names).toContain('clamp_int');
|
|
129
|
+
expect(names).toContain('min_int');
|
|
130
|
+
expect(names).toContain('max_int');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('monomorphize — statement rewriting', () => {
|
|
134
|
+
it('rewrites let statements inside generic functions', () => {
|
|
135
|
+
const result = monoFromSource(`
|
|
136
|
+
fn wrap<T>(x: T): T {
|
|
137
|
+
let temp: T = x;
|
|
138
|
+
return temp;
|
|
139
|
+
}
|
|
140
|
+
fn main(): int { return wrap<int>(42); }
|
|
141
|
+
`);
|
|
142
|
+
const wrapInt = result.functions.find(f => f.name === 'wrap_int');
|
|
143
|
+
expect(wrapInt).toBeDefined();
|
|
144
|
+
// The let statement's type should be substituted
|
|
145
|
+
const letStmt = wrapInt.body[0];
|
|
146
|
+
if (letStmt.kind === 'let' && letStmt.type) {
|
|
147
|
+
expect(letStmt.type.kind).toBe('named');
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
it('rewrites if statements inside generic functions', () => {
|
|
151
|
+
const result = monoFromSource(`
|
|
152
|
+
fn abs<T>(x: T): T {
|
|
153
|
+
if x < 0 { return 0 - x; }
|
|
154
|
+
return x;
|
|
155
|
+
}
|
|
156
|
+
fn main(): int { return abs<int>(-5); }
|
|
157
|
+
`);
|
|
158
|
+
const absInt = result.functions.find(f => f.name === 'abs_int');
|
|
159
|
+
expect(absInt).toBeDefined();
|
|
160
|
+
});
|
|
161
|
+
it('rewrites return statements', () => {
|
|
162
|
+
const result = monoFromSource(`
|
|
163
|
+
fn first<T>(a: T, b: T): T {
|
|
164
|
+
return a;
|
|
165
|
+
}
|
|
166
|
+
fn main(): int { return first<int>(1, 2); }
|
|
167
|
+
`);
|
|
168
|
+
const fn = result.functions.find(f => f.name === 'first_int');
|
|
169
|
+
expect(fn).toBeDefined();
|
|
170
|
+
expect(fn.returnType).toEqual({ kind: 'named', name: 'int' });
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('monomorphize — expression rewriting', () => {
|
|
174
|
+
it('rewrites binary expressions inside generic body', () => {
|
|
175
|
+
const result = monoFromSource(`
|
|
176
|
+
fn add<T>(a: T, b: T): T { return a + b; }
|
|
177
|
+
fn main(): int { return add<int>(1, 2); }
|
|
178
|
+
`);
|
|
179
|
+
const fn = result.functions.find(f => f.name === 'add_int');
|
|
180
|
+
expect(fn).toBeDefined();
|
|
181
|
+
});
|
|
182
|
+
it('rewrites array literal expressions', () => {
|
|
183
|
+
const result = monoFromSource(`
|
|
184
|
+
fn first<T>(a: T): T { return a; }
|
|
185
|
+
fn main(): int {
|
|
186
|
+
let arr: int[] = [1, 2, 3];
|
|
187
|
+
return first<int>(arr[0]);
|
|
188
|
+
}
|
|
189
|
+
`);
|
|
190
|
+
const fn = result.functions.find(f => f.name === 'first_int');
|
|
191
|
+
expect(fn).toBeDefined();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('monomorphize — type suffix', () => {
|
|
195
|
+
it('produces correct suffix for named types', () => {
|
|
196
|
+
const result = monoFromSource(`
|
|
197
|
+
fn id<T>(x: T): T { return x; }
|
|
198
|
+
fn main(): float { return id<float>(1.0); }
|
|
199
|
+
`);
|
|
200
|
+
const names = result.functions.map(f => f.name);
|
|
201
|
+
expect(names).toContain('id_float');
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=monomorphize-coverage.test.js.map
|