redscript-mc 1.2.29 → 2.0.0
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/.claude/commands/build-test.md +10 -0
- package/.claude/commands/deploy-demo.md +12 -0
- package/.claude/commands/stage-status.md +13 -0
- package/.claude/settings.json +12 -0
- package/.github/workflows/ci.yml +1 -0
- package/CLAUDE.md +231 -0
- package/README.md +29 -28
- package/README.zh.md +28 -28
- package/demo.gif +0 -0
- package/dist/cli.js +2 -554
- package/dist/compile.js +2 -266
- package/dist/index.js +2 -159
- package/dist/lexer/index.js +9 -1
- package/dist/lowering/index.js +22 -5
- package/dist/src/__tests__/cli.test.d.ts +1 -0
- package/dist/src/__tests__/cli.test.js +104 -0
- package/dist/src/__tests__/codegen.test.d.ts +1 -0
- package/dist/src/__tests__/codegen.test.js +152 -0
- package/dist/src/__tests__/compile-all.test.d.ts +10 -0
- package/dist/src/__tests__/compile-all.test.js +108 -0
- package/dist/src/__tests__/dce.test.d.ts +1 -0
- package/dist/src/__tests__/dce.test.js +102 -0
- package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
- package/dist/src/__tests__/diagnostics.test.js +177 -0
- package/dist/src/__tests__/e2e.test.d.ts +6 -0
- package/dist/src/__tests__/e2e.test.js +1789 -0
- package/dist/src/__tests__/entity-types.test.d.ts +1 -0
- package/dist/src/__tests__/entity-types.test.js +203 -0
- package/dist/src/__tests__/formatter.test.d.ts +1 -0
- package/dist/src/__tests__/formatter.test.js +40 -0
- package/dist/src/__tests__/lexer.test.d.ts +1 -0
- package/dist/src/__tests__/lexer.test.js +343 -0
- package/dist/src/__tests__/lowering.test.d.ts +1 -0
- package/dist/src/__tests__/lowering.test.js +1015 -0
- package/dist/src/__tests__/macro.test.d.ts +8 -0
- package/dist/src/__tests__/macro.test.js +306 -0
- package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
- package/dist/src/__tests__/mc-integration.test.js +817 -0
- package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
- package/dist/src/__tests__/mc-syntax.test.js +124 -0
- package/dist/src/__tests__/nbt.test.d.ts +1 -0
- package/dist/src/__tests__/nbt.test.js +82 -0
- package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
- package/dist/src/__tests__/optimizer.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer.test.js +149 -0
- package/dist/src/__tests__/parser.test.d.ts +1 -0
- package/dist/src/__tests__/parser.test.js +807 -0
- package/dist/src/__tests__/repl.test.d.ts +1 -0
- package/dist/src/__tests__/repl.test.js +27 -0
- package/dist/src/__tests__/runtime.test.d.ts +1 -0
- package/dist/src/__tests__/runtime.test.js +289 -0
- package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
- package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
- package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
- package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
- package/dist/src/__tests__/stdlib-math.test.js +351 -0
- package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib-vec.test.js +263 -0
- package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
- package/dist/src/__tests__/structure-optimizer.test.js +33 -0
- package/dist/src/__tests__/typechecker.test.d.ts +1 -0
- package/dist/src/__tests__/typechecker.test.js +552 -0
- package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
- package/dist/src/__tests__/var-allocator.test.js +69 -0
- package/dist/src/ast/types.d.ts +515 -0
- package/dist/src/ast/types.js +9 -0
- package/dist/src/builtins/metadata.d.ts +36 -0
- package/dist/src/builtins/metadata.js +1014 -0
- package/dist/src/cli.d.ts +11 -0
- package/dist/src/cli.js +443 -0
- package/dist/src/codegen/cmdblock/index.d.ts +26 -0
- package/dist/src/codegen/cmdblock/index.js +45 -0
- package/dist/src/codegen/mcfunction/index.d.ts +40 -0
- package/dist/src/codegen/mcfunction/index.js +606 -0
- package/dist/src/codegen/structure/index.d.ts +24 -0
- package/dist/src/codegen/structure/index.js +279 -0
- package/dist/src/codegen/var-allocator.d.ts +45 -0
- package/dist/src/codegen/var-allocator.js +104 -0
- package/dist/src/compile.d.ts +37 -0
- package/dist/src/compile.js +165 -0
- package/dist/src/diagnostics/index.d.ts +44 -0
- package/dist/src/diagnostics/index.js +140 -0
- package/dist/src/events/types.d.ts +35 -0
- package/dist/src/events/types.js +59 -0
- package/dist/src/formatter/index.d.ts +1 -0
- package/dist/src/formatter/index.js +26 -0
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.js +45 -0
- package/dist/src/ir/builder.d.ts +33 -0
- package/dist/src/ir/builder.js +99 -0
- package/dist/src/ir/types.d.ts +132 -0
- package/dist/src/ir/types.js +15 -0
- package/dist/src/lexer/index.d.ts +37 -0
- package/dist/src/lexer/index.js +569 -0
- package/dist/src/lowering/index.d.ts +188 -0
- package/dist/src/lowering/index.js +3405 -0
- package/dist/src/mc-test/client.d.ts +128 -0
- package/dist/src/mc-test/client.js +174 -0
- package/dist/src/mc-test/runner.d.ts +28 -0
- package/dist/src/mc-test/runner.js +151 -0
- package/dist/src/mc-test/setup.d.ts +11 -0
- package/dist/src/mc-test/setup.js +98 -0
- package/dist/src/mc-validator/index.d.ts +17 -0
- package/dist/src/mc-validator/index.js +322 -0
- package/dist/src/nbt/index.d.ts +86 -0
- package/dist/src/nbt/index.js +250 -0
- package/dist/src/optimizer/commands.d.ts +38 -0
- package/dist/src/optimizer/commands.js +451 -0
- package/dist/src/optimizer/dce.d.ts +34 -0
- package/dist/src/optimizer/dce.js +639 -0
- package/dist/src/optimizer/passes.d.ts +34 -0
- package/dist/src/optimizer/passes.js +243 -0
- package/dist/src/optimizer/structure.d.ts +9 -0
- package/dist/src/optimizer/structure.js +356 -0
- package/dist/src/parser/index.d.ts +93 -0
- package/dist/src/parser/index.js +1687 -0
- package/dist/src/repl.d.ts +16 -0
- package/dist/src/repl.js +165 -0
- package/dist/src/runtime/index.d.ts +107 -0
- package/dist/src/runtime/index.js +1409 -0
- package/dist/src/typechecker/index.d.ts +61 -0
- package/dist/src/typechecker/index.js +1034 -0
- package/dist/src/types/entity-hierarchy.d.ts +29 -0
- package/dist/src/types/entity-hierarchy.js +107 -0
- package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
- package/dist/src2/__tests__/e2e/basic.test.js +140 -0
- package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
- package/dist/src2/__tests__/e2e/macros.test.js +182 -0
- package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
- package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
- package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
- package/dist/src2/__tests__/hir/desugar.test.js +234 -0
- package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/lower.test.js +559 -0
- package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/types.test.js +185 -0
- package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
- package/dist/src2/__tests__/lir/verify.test.js +221 -0
- package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
- package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
- package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
- package/dist/src2/__tests__/mir/verify.test.js +223 -0
- package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
- package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
- package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
- package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
- package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
- package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
- package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
- package/dist/src2/emit/compile.d.ts +19 -0
- package/dist/src2/emit/compile.js +80 -0
- package/dist/src2/emit/index.d.ts +17 -0
- package/dist/src2/emit/index.js +172 -0
- package/dist/src2/hir/lower.d.ts +15 -0
- package/dist/src2/hir/lower.js +378 -0
- package/dist/src2/hir/types.d.ts +373 -0
- package/dist/src2/hir/types.js +16 -0
- package/dist/src2/lir/lower.d.ts +15 -0
- package/dist/src2/lir/lower.js +453 -0
- package/dist/src2/lir/types.d.ts +136 -0
- package/dist/src2/lir/types.js +11 -0
- package/dist/src2/lir/verify.d.ts +14 -0
- package/dist/src2/lir/verify.js +113 -0
- package/dist/src2/mir/lower.d.ts +9 -0
- package/dist/src2/mir/lower.js +1030 -0
- package/dist/src2/mir/macro.d.ts +22 -0
- package/dist/src2/mir/macro.js +168 -0
- package/dist/src2/mir/types.d.ts +183 -0
- package/dist/src2/mir/types.js +11 -0
- package/dist/src2/mir/verify.d.ts +16 -0
- package/dist/src2/mir/verify.js +216 -0
- package/dist/src2/optimizer/block_merge.d.ts +12 -0
- package/dist/src2/optimizer/block_merge.js +84 -0
- package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
- package/dist/src2/optimizer/branch_simplify.js +28 -0
- package/dist/src2/optimizer/constant_fold.d.ts +10 -0
- package/dist/src2/optimizer/constant_fold.js +85 -0
- package/dist/src2/optimizer/copy_prop.d.ts +9 -0
- package/dist/src2/optimizer/copy_prop.js +113 -0
- package/dist/src2/optimizer/dce.d.ts +8 -0
- package/dist/src2/optimizer/dce.js +155 -0
- package/dist/src2/optimizer/pipeline.d.ts +10 -0
- package/dist/src2/optimizer/pipeline.js +42 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/compiler-pipeline-redesign.md +2243 -0
- package/docs/optimization-ideas.md +1076 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/readme-demo.mcrs +44 -66
- package/jest.config.js +1 -1
- package/package.json +6 -5
- package/scripts/postbuild.js +15 -0
- package/src/__tests__/cli.test.ts +8 -220
- package/src/__tests__/dce.test.ts +11 -56
- package/src/__tests__/diagnostics.test.ts +59 -38
- package/src/__tests__/mc-integration.test.ts +1 -2
- package/src/ast/types.ts +6 -1
- package/src/cli.ts +29 -156
- package/src/compile.ts +6 -162
- package/src/index.ts +14 -178
- package/src/lexer/index.ts +9 -1
- package/src/mc-test/runner.ts +4 -3
- package/src/parser/index.ts +1 -1
- package/src/repl.ts +1 -1
- package/src/runtime/index.ts +1 -1
- package/src2/__tests__/e2e/basic.test.ts +154 -0
- package/src2/__tests__/e2e/macros.test.ts +199 -0
- package/src2/__tests__/e2e/migrate.test.ts +3008 -0
- package/src2/__tests__/hir/desugar.test.ts +263 -0
- package/src2/__tests__/lir/lower.test.ts +619 -0
- package/src2/__tests__/lir/types.test.ts +207 -0
- package/src2/__tests__/lir/verify.test.ts +249 -0
- package/src2/__tests__/mir/arithmetic.test.ts +156 -0
- package/src2/__tests__/mir/control-flow.test.ts +242 -0
- package/src2/__tests__/mir/verify.test.ts +254 -0
- package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
- package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
- package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
- package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
- package/src2/__tests__/optimizer/dce.test.ts +83 -0
- package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
- package/src2/emit/compile.ts +99 -0
- package/src2/emit/index.ts +222 -0
- package/src2/hir/lower.ts +428 -0
- package/src2/hir/types.ts +216 -0
- package/src2/lir/lower.ts +556 -0
- package/src2/lir/types.ts +109 -0
- package/src2/lir/verify.ts +129 -0
- package/src2/mir/lower.ts +1160 -0
- package/src2/mir/macro.ts +167 -0
- package/src2/mir/types.ts +106 -0
- package/src2/mir/verify.ts +218 -0
- package/src2/optimizer/block_merge.ts +93 -0
- package/src2/optimizer/branch_simplify.ts +27 -0
- package/src2/optimizer/constant_fold.ts +88 -0
- package/src2/optimizer/copy_prop.ts +106 -0
- package/src2/optimizer/dce.ts +133 -0
- package/src2/optimizer/pipeline.ts +44 -0
- package/tsconfig.json +2 -2
- package/src/__tests__/codegen.test.ts +0 -161
- package/src/__tests__/e2e.test.ts +0 -2039
- package/src/__tests__/entity-types.test.ts +0 -236
- package/src/__tests__/lowering.test.ts +0 -1185
- package/src/__tests__/macro.test.ts +0 -343
- package/src/__tests__/nbt.test.ts +0 -58
- package/src/__tests__/optimizer-advanced.test.ts +0 -144
- package/src/__tests__/optimizer.test.ts +0 -162
- package/src/__tests__/runtime.test.ts +0 -305
- package/src/__tests__/stdlib-advanced.test.ts +0 -379
- package/src/__tests__/stdlib-bigint.test.ts +0 -427
- package/src/__tests__/stdlib-math.test.ts +0 -374
- package/src/__tests__/stdlib-vec.test.ts +0 -259
- package/src/__tests__/structure-optimizer.test.ts +0 -38
- package/src/__tests__/var-allocator.test.ts +0 -75
- package/src/codegen/cmdblock/index.ts +0 -63
- package/src/codegen/mcfunction/index.ts +0 -662
- package/src/codegen/structure/index.ts +0 -346
- package/src/codegen/var-allocator.ts +0 -104
- package/src/ir/builder.ts +0 -116
- package/src/ir/types.ts +0 -134
- package/src/lowering/index.ts +0 -3860
- package/src/optimizer/commands.ts +0 -534
- package/src/optimizer/dce.ts +0 -679
- package/src/optimizer/passes.ts +0 -250
- package/src/optimizer/structure.ts +0 -450
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Type Hierarchy
|
|
3
|
+
*
|
|
4
|
+
* Closed inheritance tree mapping to Minecraft's entity registry.
|
|
5
|
+
* Used for type narrowing (is checks), selector<T> annotations,
|
|
6
|
+
* and W_IMPOSSIBLE_AS warnings.
|
|
7
|
+
*/
|
|
8
|
+
export interface EntityTypeNode {
|
|
9
|
+
name: string;
|
|
10
|
+
mcId: string | null;
|
|
11
|
+
abstract: boolean;
|
|
12
|
+
parent: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare const ENTITY_TYPES: EntityTypeNode[];
|
|
15
|
+
/** Map from lowercase name → EntityTypeNode */
|
|
16
|
+
export declare const ENTITY_TYPE_MAP: Map<string, EntityTypeNode>;
|
|
17
|
+
/** Map from mcId (without namespace) → EntityTypeNode */
|
|
18
|
+
export declare const ENTITY_TYPE_BY_MCID: Map<string, EntityTypeNode>;
|
|
19
|
+
/** Check if typeA is a subtype of typeB (recursive ancestry) */
|
|
20
|
+
export declare function isSubtype(typeA: string, typeB: string): boolean;
|
|
21
|
+
/** True if one type is a subtype of the other (in either direction) */
|
|
22
|
+
export declare function areCompatibleTypes(outerType: string, innerType: string): boolean;
|
|
23
|
+
/** Get all non-abstract leaf types under a given node */
|
|
24
|
+
export declare function getConcreteSubtypes(typeName: string): EntityTypeNode[];
|
|
25
|
+
/** Parse "type=zombie" from a selector string, return the entity type name or null */
|
|
26
|
+
export declare function getSelectorEntityType(selector: string): string | null;
|
|
27
|
+
/** Determine the base entity type from a selector kind:
|
|
28
|
+
* @a/@p/@r → "Player", @e → "Entity" or from type filter, @s → null */
|
|
29
|
+
export declare function getBaseSelectorType(selector: string): string | null;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Entity Type Hierarchy
|
|
4
|
+
*
|
|
5
|
+
* Closed inheritance tree mapping to Minecraft's entity registry.
|
|
6
|
+
* Used for type narrowing (is checks), selector<T> annotations,
|
|
7
|
+
* and W_IMPOSSIBLE_AS warnings.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ENTITY_TYPE_BY_MCID = exports.ENTITY_TYPE_MAP = exports.ENTITY_TYPES = void 0;
|
|
11
|
+
exports.isSubtype = isSubtype;
|
|
12
|
+
exports.areCompatibleTypes = areCompatibleTypes;
|
|
13
|
+
exports.getConcreteSubtypes = getConcreteSubtypes;
|
|
14
|
+
exports.getSelectorEntityType = getSelectorEntityType;
|
|
15
|
+
exports.getBaseSelectorType = getBaseSelectorType;
|
|
16
|
+
exports.ENTITY_TYPES = [
|
|
17
|
+
// Root
|
|
18
|
+
{ name: 'Entity', mcId: null, abstract: true, parent: null },
|
|
19
|
+
// Direct children of Entity
|
|
20
|
+
{ name: 'Player', mcId: 'minecraft:player', abstract: false, parent: 'Entity' },
|
|
21
|
+
{ name: 'ArmorStand', mcId: 'minecraft:armor_stand', abstract: false, parent: 'Entity' },
|
|
22
|
+
{ name: 'Item', mcId: 'minecraft:item', abstract: false, parent: 'Entity' },
|
|
23
|
+
{ name: 'Arrow', mcId: 'minecraft:arrow', abstract: false, parent: 'Entity' },
|
|
24
|
+
// Mob hierarchy
|
|
25
|
+
{ name: 'Mob', mcId: null, abstract: true, parent: 'Entity' },
|
|
26
|
+
// Hostile mobs
|
|
27
|
+
{ name: 'HostileMob', mcId: null, abstract: true, parent: 'Mob' },
|
|
28
|
+
{ name: 'Zombie', mcId: 'minecraft:zombie', abstract: false, parent: 'HostileMob' },
|
|
29
|
+
{ name: 'Skeleton', mcId: 'minecraft:skeleton', abstract: false, parent: 'HostileMob' },
|
|
30
|
+
{ name: 'Creeper', mcId: 'minecraft:creeper', abstract: false, parent: 'HostileMob' },
|
|
31
|
+
{ name: 'Spider', mcId: 'minecraft:spider', abstract: false, parent: 'HostileMob' },
|
|
32
|
+
{ name: 'Enderman', mcId: 'minecraft:enderman', abstract: false, parent: 'HostileMob' },
|
|
33
|
+
{ name: 'Blaze', mcId: 'minecraft:blaze', abstract: false, parent: 'HostileMob' },
|
|
34
|
+
{ name: 'Witch', mcId: 'minecraft:witch', abstract: false, parent: 'HostileMob' },
|
|
35
|
+
{ name: 'Slime', mcId: 'minecraft:slime', abstract: false, parent: 'HostileMob' },
|
|
36
|
+
{ name: 'ZombieVillager', mcId: 'minecraft:zombie_villager', abstract: false, parent: 'HostileMob' },
|
|
37
|
+
{ name: 'Husk', mcId: 'minecraft:husk', abstract: false, parent: 'HostileMob' },
|
|
38
|
+
{ name: 'Drowned', mcId: 'minecraft:drowned', abstract: false, parent: 'HostileMob' },
|
|
39
|
+
{ name: 'Stray', mcId: 'minecraft:stray', abstract: false, parent: 'HostileMob' },
|
|
40
|
+
{ name: 'WitherSkeleton', mcId: 'minecraft:wither_skeleton', abstract: false, parent: 'HostileMob' },
|
|
41
|
+
{ name: 'CaveSpider', mcId: 'minecraft:cave_spider', abstract: false, parent: 'HostileMob' },
|
|
42
|
+
// Passive mobs
|
|
43
|
+
{ name: 'PassiveMob', mcId: null, abstract: true, parent: 'Mob' },
|
|
44
|
+
{ name: 'Pig', mcId: 'minecraft:pig', abstract: false, parent: 'PassiveMob' },
|
|
45
|
+
{ name: 'Cow', mcId: 'minecraft:cow', abstract: false, parent: 'PassiveMob' },
|
|
46
|
+
{ name: 'Sheep', mcId: 'minecraft:sheep', abstract: false, parent: 'PassiveMob' },
|
|
47
|
+
{ name: 'Chicken', mcId: 'minecraft:chicken', abstract: false, parent: 'PassiveMob' },
|
|
48
|
+
{ name: 'Villager', mcId: 'minecraft:villager', abstract: false, parent: 'PassiveMob' },
|
|
49
|
+
{ name: 'WanderingTrader', mcId: 'minecraft:wandering_trader', abstract: false, parent: 'PassiveMob' },
|
|
50
|
+
];
|
|
51
|
+
/** Map from lowercase name → EntityTypeNode */
|
|
52
|
+
exports.ENTITY_TYPE_MAP = new Map(exports.ENTITY_TYPES.map(t => [t.name.toLowerCase(), t]));
|
|
53
|
+
/** Map from mcId (without namespace) → EntityTypeNode */
|
|
54
|
+
exports.ENTITY_TYPE_BY_MCID = new Map(exports.ENTITY_TYPES
|
|
55
|
+
.filter(t => t.mcId !== null)
|
|
56
|
+
.map(t => [t.mcId.replace('minecraft:', ''), t]));
|
|
57
|
+
/** Check if typeA is a subtype of typeB (recursive ancestry) */
|
|
58
|
+
function isSubtype(typeA, typeB) {
|
|
59
|
+
if (typeA === typeB)
|
|
60
|
+
return true;
|
|
61
|
+
const node = exports.ENTITY_TYPE_MAP.get(typeA.toLowerCase());
|
|
62
|
+
if (!node || !node.parent)
|
|
63
|
+
return false;
|
|
64
|
+
return isSubtype(node.parent, typeB);
|
|
65
|
+
}
|
|
66
|
+
/** True if one type is a subtype of the other (in either direction) */
|
|
67
|
+
function areCompatibleTypes(outerType, innerType) {
|
|
68
|
+
return isSubtype(outerType, innerType) || isSubtype(innerType, outerType);
|
|
69
|
+
}
|
|
70
|
+
/** Get all non-abstract leaf types under a given node */
|
|
71
|
+
function getConcreteSubtypes(typeName) {
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const node of exports.ENTITY_TYPES) {
|
|
74
|
+
if (!node.abstract && isSubtype(node.name, typeName)) {
|
|
75
|
+
results.push(node);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
}
|
|
80
|
+
/** Parse "type=zombie" from a selector string, return the entity type name or null */
|
|
81
|
+
function getSelectorEntityType(selector) {
|
|
82
|
+
const match = selector.match(/type=(?:minecraft:)?([a-z_]+)/);
|
|
83
|
+
if (!match)
|
|
84
|
+
return null;
|
|
85
|
+
const mcId = match[1];
|
|
86
|
+
const node = exports.ENTITY_TYPE_BY_MCID.get(mcId);
|
|
87
|
+
return node ? node.name : null;
|
|
88
|
+
}
|
|
89
|
+
/** Determine the base entity type from a selector kind:
|
|
90
|
+
* @a/@p/@r → "Player", @e → "Entity" or from type filter, @s → null */
|
|
91
|
+
function getBaseSelectorType(selector) {
|
|
92
|
+
const trimmed = selector.trim();
|
|
93
|
+
// Check for type filter first (works for any selector)
|
|
94
|
+
const typeFromFilter = getSelectorEntityType(trimmed);
|
|
95
|
+
if (trimmed.startsWith('@a') || trimmed.startsWith('@p') || trimmed.startsWith('@r')) {
|
|
96
|
+
return typeFromFilter ?? 'Player';
|
|
97
|
+
}
|
|
98
|
+
if (trimmed.startsWith('@e')) {
|
|
99
|
+
return typeFromFilter ?? 'Entity';
|
|
100
|
+
}
|
|
101
|
+
// @s — context-dependent, we don't know unless there's a type filter
|
|
102
|
+
if (trimmed.startsWith('@s')) {
|
|
103
|
+
return typeFromFilter ?? null;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=entity-hierarchy.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the v2 compiler pipeline.
|
|
3
|
+
*
|
|
4
|
+
* These tests compile RedScript source through the full pipeline
|
|
5
|
+
* (Lexer → Parser → HIR → MIR → optimize → LIR → emit) and verify
|
|
6
|
+
* the generated .mcfunction output contains expected MC commands.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* End-to-end tests for the v2 compiler pipeline.
|
|
4
|
+
*
|
|
5
|
+
* These tests compile RedScript source through the full pipeline
|
|
6
|
+
* (Lexer → Parser → HIR → MIR → optimize → LIR → emit) and verify
|
|
7
|
+
* the generated .mcfunction output contains expected MC commands.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const compile_1 = require("../../emit/compile");
|
|
11
|
+
function getFile(files, pathSubstr) {
|
|
12
|
+
const f = files.find(f => f.path.includes(pathSubstr));
|
|
13
|
+
return f?.content;
|
|
14
|
+
}
|
|
15
|
+
describe('e2e: basic compilation', () => {
|
|
16
|
+
test('simple arithmetic function produces scoreboard commands', () => {
|
|
17
|
+
const source = `
|
|
18
|
+
fn add(a: int, b: int): int {
|
|
19
|
+
return a + b;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
23
|
+
expect(result.files.length).toBeGreaterThan(0);
|
|
24
|
+
const addFn = getFile(result.files, 'add.mcfunction');
|
|
25
|
+
expect(addFn).toBeDefined();
|
|
26
|
+
expect(addFn).toContain('scoreboard players operation');
|
|
27
|
+
expect(addFn).toContain('__test');
|
|
28
|
+
});
|
|
29
|
+
test('pack.mcmeta is generated with pack_format 26', () => {
|
|
30
|
+
const source = `fn noop(): void {}`;
|
|
31
|
+
const result = (0, compile_1.compile)(source, { namespace: 'demo' });
|
|
32
|
+
const meta = getFile(result.files, 'pack.mcmeta');
|
|
33
|
+
expect(meta).toBeDefined();
|
|
34
|
+
const parsed = JSON.parse(meta);
|
|
35
|
+
expect(parsed.pack.pack_format).toBe(26);
|
|
36
|
+
});
|
|
37
|
+
test('load.mcfunction creates scoreboard objective', () => {
|
|
38
|
+
const source = `fn noop(): void {}`;
|
|
39
|
+
const result = (0, compile_1.compile)(source, { namespace: 'mypack' });
|
|
40
|
+
const load = getFile(result.files, 'load.mcfunction');
|
|
41
|
+
expect(load).toBeDefined();
|
|
42
|
+
expect(load).toContain('scoreboard objectives add __mypack dummy');
|
|
43
|
+
});
|
|
44
|
+
test('@tick function appears in tick.json', () => {
|
|
45
|
+
const source = `
|
|
46
|
+
@tick fn game_tick(): void {
|
|
47
|
+
let x: int = 1;
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
const result = (0, compile_1.compile)(source, { namespace: 'ticktest' });
|
|
51
|
+
const tickJson = getFile(result.files, 'tick.json');
|
|
52
|
+
expect(tickJson).toBeDefined();
|
|
53
|
+
const parsed = JSON.parse(tickJson);
|
|
54
|
+
expect(parsed.values).toContain('ticktest:game_tick');
|
|
55
|
+
});
|
|
56
|
+
test('@load function appears in load.json', () => {
|
|
57
|
+
const source = `
|
|
58
|
+
@load fn setup(): void {
|
|
59
|
+
let x: int = 42;
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const result = (0, compile_1.compile)(source, { namespace: 'loadtest' });
|
|
63
|
+
const loadJson = getFile(result.files, 'load.json');
|
|
64
|
+
expect(loadJson).toBeDefined();
|
|
65
|
+
const parsed = JSON.parse(loadJson);
|
|
66
|
+
expect(parsed.values).toContain('loadtest:setup');
|
|
67
|
+
// load.json should also reference the objective-init load function
|
|
68
|
+
expect(parsed.values).toContain('loadtest:load');
|
|
69
|
+
});
|
|
70
|
+
test('if/else produces conditional call pattern', () => {
|
|
71
|
+
const source = `
|
|
72
|
+
fn check(x: int): int {
|
|
73
|
+
if (x > 0) {
|
|
74
|
+
return 1;
|
|
75
|
+
} else {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
const result = (0, compile_1.compile)(source, { namespace: 'cond' });
|
|
81
|
+
// The main function should contain call_if_matches / call_unless_matches
|
|
82
|
+
const checkFn = getFile(result.files, 'check.mcfunction');
|
|
83
|
+
expect(checkFn).toBeDefined();
|
|
84
|
+
expect(checkFn).toContain('execute if score');
|
|
85
|
+
expect(checkFn).toContain('matches');
|
|
86
|
+
expect(checkFn).toContain('run function');
|
|
87
|
+
});
|
|
88
|
+
test('while loop produces loop structure with recursive call', () => {
|
|
89
|
+
const source = `
|
|
90
|
+
fn count(): void {
|
|
91
|
+
let i: int = 0;
|
|
92
|
+
while (i < 10) {
|
|
93
|
+
i = i + 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
const result = (0, compile_1.compile)(source, { namespace: 'loop' });
|
|
98
|
+
// There should be a loop body function that calls itself (or a header)
|
|
99
|
+
const fnFiles = result.files.filter(f => f.path.endsWith('.mcfunction'));
|
|
100
|
+
expect(fnFiles.length).toBeGreaterThan(1); // main + at least one extracted block
|
|
101
|
+
// At least one file should have a conditional call pattern for the loop
|
|
102
|
+
const allContent = fnFiles.map(f => f.content).join('\n');
|
|
103
|
+
expect(allContent).toContain('execute if score');
|
|
104
|
+
expect(allContent).toContain('run function');
|
|
105
|
+
});
|
|
106
|
+
test('function names are lowercased in output paths', () => {
|
|
107
|
+
const source = `fn MyFunc(): void {}`;
|
|
108
|
+
const result = (0, compile_1.compile)(source, { namespace: 'ns' });
|
|
109
|
+
const fn = result.files.find(f => f.path.includes('myfunc.mcfunction'));
|
|
110
|
+
expect(fn).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
test('constant assignment produces score_set', () => {
|
|
113
|
+
const source = `
|
|
114
|
+
fn init(): int {
|
|
115
|
+
let x: int = 42;
|
|
116
|
+
return x;
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
const result = (0, compile_1.compile)(source, { namespace: 'cst' });
|
|
120
|
+
const fn = getFile(result.files, 'init.mcfunction');
|
|
121
|
+
expect(fn).toBeDefined();
|
|
122
|
+
expect(fn).toContain('scoreboard players set');
|
|
123
|
+
expect(fn).toContain('42');
|
|
124
|
+
});
|
|
125
|
+
test('load.json always includes namespace:load', () => {
|
|
126
|
+
const source = `fn noop(): void {}`;
|
|
127
|
+
const result = (0, compile_1.compile)(source, { namespace: 'abc' });
|
|
128
|
+
const loadJson = getFile(result.files, 'load.json');
|
|
129
|
+
expect(loadJson).toBeDefined();
|
|
130
|
+
const parsed = JSON.parse(loadJson);
|
|
131
|
+
expect(parsed.values).toContain('abc:load');
|
|
132
|
+
});
|
|
133
|
+
test('no tick.json when no @tick functions', () => {
|
|
134
|
+
const source = `fn noop(): void {}`;
|
|
135
|
+
const result = (0, compile_1.compile)(source, { namespace: 'notick' });
|
|
136
|
+
const tickJson = getFile(result.files, 'tick.json');
|
|
137
|
+
expect(tickJson).toBeUndefined();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=basic.test.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for MC 1.20.2+ macro function support in the v2 pipeline.
|
|
3
|
+
*
|
|
4
|
+
* When a function uses runtime parameters in positions that require literal
|
|
5
|
+
* values in MC commands (coordinates, entity types, etc.), the compiler should
|
|
6
|
+
* automatically compile it as a macro function using $-prefixed syntax and
|
|
7
|
+
* call it via `function ns:fn with storage rs:macro_args`.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* End-to-end tests for MC 1.20.2+ macro function support in the v2 pipeline.
|
|
4
|
+
*
|
|
5
|
+
* When a function uses runtime parameters in positions that require literal
|
|
6
|
+
* values in MC commands (coordinates, entity types, etc.), the compiler should
|
|
7
|
+
* automatically compile it as a macro function using $-prefixed syntax and
|
|
8
|
+
* call it via `function ns:fn with storage rs:macro_args`.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const compile_1 = require("../../emit/compile");
|
|
12
|
+
function getFile(files, pathSubstr) {
|
|
13
|
+
const f = files.find(f => f.path.includes(pathSubstr));
|
|
14
|
+
return f?.content;
|
|
15
|
+
}
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Macro function detection
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
describe('e2e: macro function detection', () => {
|
|
20
|
+
test('function with int params in summon coords emits $-prefixed command', () => {
|
|
21
|
+
const source = `
|
|
22
|
+
fn spawn_zombie(x: int, y: int, z: int) {
|
|
23
|
+
summon("minecraft:zombie", x, y, z);
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
27
|
+
const fn = getFile(result.files, 'spawn_zombie.mcfunction');
|
|
28
|
+
expect(fn).toBeDefined();
|
|
29
|
+
// The function body should have a $summon macro line
|
|
30
|
+
expect(fn).toContain('$summon minecraft:zombie $(x) $(y) $(z)');
|
|
31
|
+
});
|
|
32
|
+
test('function with all constant args does NOT produce macro line', () => {
|
|
33
|
+
const source = `
|
|
34
|
+
fn spawn_fixed() {
|
|
35
|
+
summon("minecraft:zombie", 100, 64, 200);
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
39
|
+
const fn = getFile(result.files, 'spawn_fixed.mcfunction');
|
|
40
|
+
expect(fn).toBeDefined();
|
|
41
|
+
expect(fn).toContain('summon minecraft:zombie 100 64 200');
|
|
42
|
+
// No $ prefix
|
|
43
|
+
expect(fn).not.toMatch(/^\$summon/m);
|
|
44
|
+
});
|
|
45
|
+
test('function with int params in particle coords emits $-prefixed command', () => {
|
|
46
|
+
const source = `
|
|
47
|
+
fn show_particle(x: int, y: int, z: int) {
|
|
48
|
+
particle("minecraft:flame", x, y, z);
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
52
|
+
const fn = getFile(result.files, 'show_particle.mcfunction');
|
|
53
|
+
expect(fn).toBeDefined();
|
|
54
|
+
expect(fn).toContain('$particle minecraft:flame $(x) $(y) $(z)');
|
|
55
|
+
});
|
|
56
|
+
test('function with int params in setblock coords emits $-prefixed command', () => {
|
|
57
|
+
const source = `
|
|
58
|
+
fn place_block(x: int, y: int, z: int) {
|
|
59
|
+
setblock(x, y, z, "minecraft:stone");
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
63
|
+
const fn = getFile(result.files, 'place_block.mcfunction');
|
|
64
|
+
expect(fn).toBeDefined();
|
|
65
|
+
expect(fn).toContain('$setblock $(x) $(y) $(z) minecraft:stone');
|
|
66
|
+
});
|
|
67
|
+
test('mixed literal and variable args: only variable args get $()', () => {
|
|
68
|
+
const source = `
|
|
69
|
+
fn teleport_y(y: int) {
|
|
70
|
+
summon("minecraft:zombie", 100, y, 200);
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
74
|
+
const fn = getFile(result.files, 'teleport_y.mcfunction');
|
|
75
|
+
expect(fn).toBeDefined();
|
|
76
|
+
expect(fn).toContain('$summon minecraft:zombie 100 $(y) 200');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Macro call site generation
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
describe('e2e: macro call site generation', () => {
|
|
83
|
+
test('call site emits store_score_to_nbt + function with storage', () => {
|
|
84
|
+
const source = `
|
|
85
|
+
fn spawn_zombie(x: int, y: int, z: int) {
|
|
86
|
+
summon("minecraft:zombie", x, y, z);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fn caller(px: int, pz: int) {
|
|
90
|
+
spawn_zombie(px, 64, pz);
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
94
|
+
const callerFn = getFile(result.files, 'caller.mcfunction');
|
|
95
|
+
expect(callerFn).toBeDefined();
|
|
96
|
+
// Should have 'function test:spawn_zombie with storage rs:macro_args'
|
|
97
|
+
expect(callerFn).toContain('with storage rs:macro_args');
|
|
98
|
+
expect(callerFn).toContain('spawn_zombie');
|
|
99
|
+
});
|
|
100
|
+
test('call site stores args to rs:macro_args NBT', () => {
|
|
101
|
+
const source = `
|
|
102
|
+
fn spawn_zombie(x: int, y: int, z: int) {
|
|
103
|
+
summon("minecraft:zombie", x, y, z);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fn caller(my_x: int) {
|
|
107
|
+
spawn_zombie(my_x, 64, 0);
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
111
|
+
const callerFn = getFile(result.files, 'caller.mcfunction');
|
|
112
|
+
expect(callerFn).toBeDefined();
|
|
113
|
+
// Should have NBT storage setup for macro args
|
|
114
|
+
expect(callerFn).toContain('rs:macro_args');
|
|
115
|
+
expect(callerFn).toContain('with storage');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Float macro params (local coords)
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
describe('e2e: float macro params with local coords', () => {
|
|
122
|
+
test('float params in ^coord positions produce macro function', () => {
|
|
123
|
+
const source = `
|
|
124
|
+
fn draw_pt(px: float, py: float) {
|
|
125
|
+
particle("minecraft:end_rod", ^px, ^py, ^5, 0.02, 0.02, 0.02, 0.0, 10);
|
|
126
|
+
}
|
|
127
|
+
`;
|
|
128
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
129
|
+
const fn = getFile(result.files, 'draw_pt.mcfunction');
|
|
130
|
+
expect(fn).toBeDefined();
|
|
131
|
+
// Should have $particle with ^$(px) and ^$(py)
|
|
132
|
+
expect(fn).toContain('$particle minecraft:end_rod ^$(px) ^$(py) ^5');
|
|
133
|
+
});
|
|
134
|
+
test('float macro call site uses double 0.01 scale for NBT storage', () => {
|
|
135
|
+
const source = `
|
|
136
|
+
fn draw_pt(px: float, py: float) {
|
|
137
|
+
particle("minecraft:end_rod", ^px, ^py, ^5, 0.02, 0.02, 0.02, 0.0, 10);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn caller() {
|
|
141
|
+
draw_pt(100, 200);
|
|
142
|
+
}
|
|
143
|
+
`;
|
|
144
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
145
|
+
const callerFn = getFile(result.files, 'caller.mcfunction');
|
|
146
|
+
expect(callerFn).toBeDefined();
|
|
147
|
+
// Should store to NBT with double type and 0.01 scale
|
|
148
|
+
expect(callerFn).toContain('rs:macro_args');
|
|
149
|
+
expect(callerFn).toContain('double 0.01');
|
|
150
|
+
expect(callerFn).toContain('with storage rs:macro_args');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Non-macro functions still work
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
describe('e2e: non-macro functions', () => {
|
|
157
|
+
test('say builtin emits normal (non-macro) command', () => {
|
|
158
|
+
const source = `
|
|
159
|
+
fn greet() {
|
|
160
|
+
say("hello world");
|
|
161
|
+
}
|
|
162
|
+
`;
|
|
163
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
164
|
+
const fn = getFile(result.files, 'greet.mcfunction');
|
|
165
|
+
expect(fn).toBeDefined();
|
|
166
|
+
expect(fn).toContain('say hello world');
|
|
167
|
+
// No $ prefix
|
|
168
|
+
expect(fn).not.toMatch(/^\$/m);
|
|
169
|
+
});
|
|
170
|
+
test('kill builtin emits normal command', () => {
|
|
171
|
+
const source = `
|
|
172
|
+
fn cleanup() {
|
|
173
|
+
kill(@e[tag=temp]);
|
|
174
|
+
}
|
|
175
|
+
`;
|
|
176
|
+
const result = (0, compile_1.compile)(source, { namespace: 'test' });
|
|
177
|
+
const fn = getFile(result.files, 'cleanup.mcfunction');
|
|
178
|
+
expect(fn).toBeDefined();
|
|
179
|
+
expect(fn).toContain('kill @e[tag=temp]');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=macros.test.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration tests — representative cases from the existing 920-test suite
|
|
3
|
+
* run through the NEW v2 compiler pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Pattern:
|
|
6
|
+
* 1. Compile source with src2/emit/compile.ts
|
|
7
|
+
* 2. Load .mcfunction files into MCRuntime
|
|
8
|
+
* 3. Execute functions and assert scoreboard state
|
|
9
|
+
*
|
|
10
|
+
* NOTE: v2 uses objective `__<ns>` (not `rs`), load function is `ns:load`
|
|
11
|
+
* (not `ns:__load`), and return values go to `$ret` on the objective.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|