ticbuild 1.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/.attachments/support_me_on_kofi_beige.png +0 -0
- package/.env.example +3 -0
- package/.prettierignore +10 -0
- package/LICENSE +15 -0
- package/README.md +429 -0
- package/debug/obj/resolvedManifest.ticbuild.jsonc +108 -0
- package/dist/backend/ImportedResource.d.ts +11 -0
- package/dist/backend/ImportedResource.d.ts.map +1 -0
- package/dist/backend/ImportedResource.js +53 -0
- package/dist/backend/ImportedResource.js.map +1 -0
- package/dist/backend/ImportedResourceTypes.d.ts +24 -0
- package/dist/backend/ImportedResourceTypes.d.ts.map +1 -0
- package/dist/backend/ImportedResourceTypes.js +35 -0
- package/dist/backend/ImportedResourceTypes.js.map +1 -0
- package/dist/backend/codeBanking.test.d.ts +2 -0
- package/dist/backend/codeBanking.test.d.ts.map +1 -0
- package/dist/backend/codeBanking.test.js.map +1 -0
- package/dist/backend/importResources.d.ts +4 -0
- package/dist/backend/importResources.d.ts.map +1 -0
- package/dist/backend/importResources.js +58 -0
- package/dist/backend/importResources.js.map +1 -0
- package/dist/backend/importUtils.d.ts +14 -0
- package/dist/backend/importUtils.d.ts.map +1 -0
- package/dist/backend/importUtils.js +77 -0
- package/dist/backend/importUtils.js.map +1 -0
- package/dist/backend/importers/LuaCodeImporter.d.ts +47 -0
- package/dist/backend/importers/LuaCodeImporter.d.ts.map +1 -0
- package/dist/backend/importers/LuaCodeImporter.js +196 -0
- package/dist/backend/importers/LuaCodeImporter.js.map +1 -0
- package/dist/backend/importers/LuaCodeImporter.test.d.ts +2 -0
- package/dist/backend/importers/LuaCodeImporter.test.d.ts.map +1 -0
- package/dist/backend/importers/LuaCodeImporter.test.js.map +1 -0
- package/dist/backend/importers/binaryResourceImporter.d.ts +22 -0
- package/dist/backend/importers/binaryResourceImporter.d.ts.map +1 -0
- package/dist/backend/importers/binaryResourceImporter.js +53 -0
- package/dist/backend/importers/binaryResourceImporter.js.map +1 -0
- package/dist/backend/importers/luaImporter.d.ts +1 -0
- package/dist/backend/importers/luaImporter.d.ts.map +1 -0
- package/dist/backend/importers/luaImporter.js +3 -0
- package/dist/backend/importers/luaImporter.js.map +1 -0
- package/dist/backend/importers/textResourceImporter.d.ts +23 -0
- package/dist/backend/importers/textResourceImporter.d.ts.map +1 -0
- package/dist/backend/importers/textResourceImporter.js +55 -0
- package/dist/backend/importers/textResourceImporter.js.map +1 -0
- package/dist/backend/importers/tic80CartImporter.d.ts +21 -0
- package/dist/backend/importers/tic80CartImporter.d.ts.map +1 -0
- package/dist/backend/importers/tic80CartImporter.js +96 -0
- package/dist/backend/importers/tic80CartImporter.js.map +1 -0
- package/dist/backend/loadAllImports.d.ts +1 -0
- package/dist/backend/loadAllImports.d.ts.map +1 -0
- package/dist/backend/loadAllImports.js +3 -0
- package/dist/backend/loadAllImports.js.map +1 -0
- package/dist/backend/luaBinaryEncoding.d.ts +6 -0
- package/dist/backend/luaBinaryEncoding.d.ts.map +1 -0
- package/dist/backend/luaBinaryEncoding.js +94 -0
- package/dist/backend/luaBinaryEncoding.js.map +1 -0
- package/dist/backend/luaPreprocessor.d.ts +8 -0
- package/dist/backend/luaPreprocessor.d.ts.map +1 -0
- package/dist/backend/luaPreprocessor.js +862 -0
- package/dist/backend/luaPreprocessor.js.map +1 -0
- package/dist/backend/luaPreprocessor.test.d.ts +2 -0
- package/dist/backend/luaPreprocessor.test.d.ts.map +1 -0
- package/dist/backend/luaPreprocessor.test.js.map +1 -0
- package/dist/backend/manifestLoader.d.ts +19 -0
- package/dist/backend/manifestLoader.d.ts.map +1 -0
- package/dist/backend/manifestLoader.js +142 -0
- package/dist/backend/manifestLoader.js.map +1 -0
- package/dist/backend/manifestLoader.test.d.ts +2 -0
- package/dist/backend/manifestLoader.test.d.ts.map +1 -0
- package/dist/backend/manifestLoader.test.js.map +1 -0
- package/dist/backend/manifestTypes.d.ts +454 -0
- package/dist/backend/manifestTypes.d.ts.map +1 -0
- package/dist/backend/manifestTypes.js +28 -0
- package/dist/backend/manifestTypes.js.map +1 -0
- package/dist/backend/project.d.ts +24 -0
- package/dist/backend/project.d.ts.map +1 -0
- package/dist/backend/project.js +159 -0
- package/dist/backend/project.js.map +1 -0
- package/dist/backend/projectCore.d.ts +34 -0
- package/dist/backend/projectCore.d.ts.map +1 -0
- package/dist/backend/projectCore.js +226 -0
- package/dist/backend/projectCore.js.map +1 -0
- package/dist/backend/tic80Resolver.d.ts +6 -0
- package/dist/backend/tic80Resolver.d.ts.map +1 -0
- package/dist/backend/tic80Resolver.js +66 -0
- package/dist/backend/tic80Resolver.js.map +1 -0
- package/dist/buildInfo.d.ts +9 -0
- package/dist/buildInfo.d.ts.map +1 -0
- package/dist/buildInfo.js +13 -0
- package/dist/buildInfo.js.map +1 -0
- package/dist/frontend/build.d.ts +3 -0
- package/dist/frontend/build.d.ts.map +1 -0
- package/dist/frontend/build.js +8 -0
- package/dist/frontend/build.js.map +1 -0
- package/dist/frontend/codeBankWarnings.test.d.ts +2 -0
- package/dist/frontend/codeBankWarnings.test.d.ts.map +1 -0
- package/dist/frontend/codeBankWarnings.test.js.map +1 -0
- package/dist/frontend/core.d.ts +3 -0
- package/dist/frontend/core.d.ts.map +1 -0
- package/dist/frontend/core.js +259 -0
- package/dist/frontend/core.js.map +1 -0
- package/dist/frontend/init.d.ts +7 -0
- package/dist/frontend/init.d.ts.map +1 -0
- package/dist/frontend/init.js +95 -0
- package/dist/frontend/init.js.map +1 -0
- package/dist/frontend/parseOptions.d.ts +7 -0
- package/dist/frontend/parseOptions.d.ts.map +1 -0
- package/dist/frontend/parseOptions.js +68 -0
- package/dist/frontend/parseOptions.js.map +1 -0
- package/dist/frontend/run.d.ts +3 -0
- package/dist/frontend/run.d.ts.map +1 -0
- package/dist/frontend/run.js +63 -0
- package/dist/frontend/run.js.map +1 -0
- package/dist/frontend/watch.d.ts +3 -0
- package/dist/frontend/watch.d.ts.map +1 -0
- package/dist/frontend/watch.js +208 -0
- package/dist/frontend/watch.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +191 -0
- package/dist/index.js.map +1 -0
- package/dist/obj/resolvedManifest.ticbuild.jsonc +110 -0
- package/dist/obj/variables.json +19 -0
- package/dist/utils/algorithms.d.ts +4 -0
- package/dist/utils/algorithms.d.ts.map +1 -0
- package/dist/utils/algorithms.js +15 -0
- package/dist/utils/algorithms.js.map +1 -0
- package/dist/utils/algorithms.test.d.ts +2 -0
- package/dist/utils/algorithms.test.d.ts.map +1 -0
- package/dist/utils/algorithms.test.js.map +1 -0
- package/dist/utils/bin.d.ts +4 -0
- package/dist/utils/bin.d.ts.map +1 -0
- package/dist/utils/bin.js +16 -0
- package/dist/utils/bin.js.map +1 -0
- package/dist/utils/charMap.d.ts +28 -0
- package/dist/utils/charMap.d.ts.map +1 -0
- package/dist/utils/charMap.js +31 -0
- package/dist/utils/charMap.js.map +1 -0
- package/dist/utils/console.d.ts +10 -0
- package/dist/utils/console.d.ts.map +1 -0
- package/dist/utils/console.js +66 -0
- package/dist/utils/console.js.map +1 -0
- package/dist/utils/encoding/b85.d.ts +5 -0
- package/dist/utils/encoding/b85.d.ts.map +1 -0
- package/dist/utils/encoding/b85.js +136 -0
- package/dist/utils/encoding/b85.js.map +1 -0
- package/dist/utils/encoding/codecRegistry.d.ts +333 -0
- package/dist/utils/encoding/codecRegistry.d.ts.map +1 -0
- package/dist/utils/encoding/codecRegistry.js +81 -0
- package/dist/utils/encoding/codecRegistry.js.map +1 -0
- package/dist/utils/encoding/hex.d.ts +3 -0
- package/dist/utils/encoding/hex.d.ts.map +1 -0
- package/dist/utils/encoding/hex.js +30 -0
- package/dist/utils/encoding/hex.js.map +1 -0
- package/dist/utils/encoding/lz.d.ts +12 -0
- package/dist/utils/encoding/lz.d.ts.map +1 -0
- package/dist/utils/encoding/lz.js +271 -0
- package/dist/utils/encoding/lz.js.map +1 -0
- package/dist/utils/enum.d.ts +45 -0
- package/dist/utils/enum.d.ts.map +1 -0
- package/dist/utils/enum.js +135 -0
- package/dist/utils/enum.js.map +1 -0
- package/dist/utils/errorHandling.d.ts +13 -0
- package/dist/utils/errorHandling.d.ts.map +1 -0
- package/dist/utils/errorHandling.js +18 -0
- package/dist/utils/errorHandling.js.map +1 -0
- package/dist/utils/fileSystem.d.ts +16 -0
- package/dist/utils/fileSystem.d.ts.map +1 -0
- package/dist/utils/fileSystem.js +161 -0
- package/dist/utils/fileSystem.js.map +1 -0
- package/dist/utils/help.d.ts +7 -0
- package/dist/utils/help.d.ts.map +1 -0
- package/dist/utils/help.js +87 -0
- package/dist/utils/help.js.map +1 -0
- package/dist/utils/lua/luaUtils.d.ts +1 -0
- package/dist/utils/lua/luaUtils.d.ts.map +1 -0
- package/dist/utils/lua/luaUtils.js +3 -0
- package/dist/utils/lua/luaUtils.js.map +1 -0
- package/dist/utils/lua/lua_alias_expressions.d.ts +20 -0
- package/dist/utils/lua/lua_alias_expressions.d.ts.map +1 -0
- package/dist/utils/lua/lua_alias_expressions.js +233 -0
- package/dist/utils/lua/lua_alias_expressions.js.map +1 -0
- package/dist/utils/lua/lua_alias_literals.d.ts +20 -0
- package/dist/utils/lua/lua_alias_literals.d.ts.map +1 -0
- package/dist/utils/lua/lua_alias_literals.js +165 -0
- package/dist/utils/lua/lua_alias_literals.js.map +1 -0
- package/dist/utils/lua/lua_alias_shared.d.ts +31 -0
- package/dist/utils/lua/lua_alias_shared.d.ts.map +1 -0
- package/dist/utils/lua/lua_alias_shared.js +415 -0
- package/dist/utils/lua/lua_alias_shared.js.map +1 -0
- package/dist/utils/lua/lua_ast.d.ts +9 -0
- package/dist/utils/lua/lua_ast.d.ts.map +1 -0
- package/dist/utils/lua/lua_ast.js +90 -0
- package/dist/utils/lua/lua_ast.js.map +1 -0
- package/dist/utils/lua/lua_fundamentals.d.ts +14 -0
- package/dist/utils/lua/lua_fundamentals.d.ts.map +1 -0
- package/dist/utils/lua/lua_fundamentals.js +93 -0
- package/dist/utils/lua/lua_fundamentals.js.map +1 -0
- package/dist/utils/lua/lua_pack_locals.d.ts +3 -0
- package/dist/utils/lua/lua_pack_locals.d.ts.map +1 -0
- package/dist/utils/lua/lua_pack_locals.js +206 -0
- package/dist/utils/lua/lua_pack_locals.js.map +1 -0
- package/dist/utils/lua/lua_processor.d.ts +65 -0
- package/dist/utils/lua/lua_processor.d.ts.map +1 -0
- package/dist/utils/lua/lua_processor.js +1153 -0
- package/dist/utils/lua/lua_processor.js.map +1 -0
- package/dist/utils/lua/lua_processor.test.d.ts +2 -0
- package/dist/utils/lua/lua_processor.test.d.ts.map +1 -0
- package/dist/utils/lua/lua_processor.test.js.map +1 -0
- package/dist/utils/lua/lua_remove_unused_functions.d.ts +6 -0
- package/dist/utils/lua/lua_remove_unused_functions.d.ts.map +1 -0
- package/dist/utils/lua/lua_remove_unused_functions.js +474 -0
- package/dist/utils/lua/lua_remove_unused_functions.js.map +1 -0
- package/dist/utils/lua/lua_remove_unused_locals.d.ts +3 -0
- package/dist/utils/lua/lua_remove_unused_locals.d.ts.map +1 -0
- package/dist/utils/lua/lua_remove_unused_locals.js +303 -0
- package/dist/utils/lua/lua_remove_unused_locals.js.map +1 -0
- package/dist/utils/lua/lua_rename_allowed_table_keys.d.ts +3 -0
- package/dist/utils/lua/lua_rename_allowed_table_keys.d.ts.map +1 -0
- package/dist/utils/lua/lua_rename_allowed_table_keys.js +157 -0
- package/dist/utils/lua/lua_rename_allowed_table_keys.js.map +1 -0
- package/dist/utils/lua/lua_rename_table_fields.d.ts +3 -0
- package/dist/utils/lua/lua_rename_table_fields.d.ts.map +1 -0
- package/dist/utils/lua/lua_rename_table_fields.js +427 -0
- package/dist/utils/lua/lua_rename_table_fields.js.map +1 -0
- package/dist/utils/lua/lua_renamer.d.ts +3 -0
- package/dist/utils/lua/lua_renamer.d.ts.map +1 -0
- package/dist/utils/lua/lua_renamer.js +229 -0
- package/dist/utils/lua/lua_renamer.js.map +1 -0
- package/dist/utils/lua/lua_simplify.d.ts +3 -0
- package/dist/utils/lua/lua_simplify.d.ts.map +1 -0
- package/dist/utils/lua/lua_simplify.js +541 -0
- package/dist/utils/lua/lua_simplify.js.map +1 -0
- package/dist/utils/lua/lua_utils.d.ts +13 -0
- package/dist/utils/lua/lua_utils.d.ts.map +1 -0
- package/dist/utils/lua/lua_utils.js +58 -0
- package/dist/utils/lua/lua_utils.js.map +1 -0
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +7 -0
- package/dist/utils/math.js.map +1 -0
- package/dist/utils/math.test.d.ts +2 -0
- package/dist/utils/math.test.d.ts.map +1 -0
- package/dist/utils/math.test.js.map +1 -0
- package/dist/utils/templates.d.ts +3 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +57 -0
- package/dist/utils/templates.js.map +1 -0
- package/dist/utils/tic80/bankSupport.test.d.ts +2 -0
- package/dist/utils/tic80/bankSupport.test.d.ts.map +1 -0
- package/dist/utils/tic80/bankSupport.test.js.map +1 -0
- package/dist/utils/tic80/cartLoader.d.ts +3 -0
- package/dist/utils/tic80/cartLoader.d.ts.map +1 -0
- package/dist/utils/tic80/cartLoader.js +54 -0
- package/dist/utils/tic80/cartLoader.js.map +1 -0
- package/dist/utils/tic80/cartWriter.d.ts +5 -0
- package/dist/utils/tic80/cartWriter.d.ts.map +1 -0
- package/dist/utils/tic80/cartWriter.js +95 -0
- package/dist/utils/tic80/cartWriter.js.map +1 -0
- package/dist/utils/tic80/launch.d.ts +4 -0
- package/dist/utils/tic80/launch.d.ts.map +1 -0
- package/dist/utils/tic80/launch.js +36 -0
- package/dist/utils/tic80/launch.js.map +1 -0
- package/dist/utils/tic80/tic80.d.ts +1149 -0
- package/dist/utils/tic80/tic80.d.ts.map +1 -0
- package/dist/utils/tic80/tic80.js +114 -0
- package/dist/utils/tic80/tic80.js.map +1 -0
- package/dist/utils/utils.d.ts +13 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +109 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/utils/versionString.d.ts +12 -0
- package/dist/utils/versionString.d.ts.map +1 -0
- package/dist/utils/versionString.js +33 -0
- package/dist/utils/versionString.js.map +1 -0
- package/dist/utils/windowPosition.d.ts +10 -0
- package/dist/utils/windowPosition.d.ts.map +1 -0
- package/dist/utils/windowPosition.js +222 -0
- package/dist/utils/windowPosition.js.map +1 -0
- package/example.ticbuild.jsonc +94 -0
- package/package.json +51 -0
- package/templates/help/build.txt +23 -0
- package/templates/help/init.txt +23 -0
- package/templates/help/main.txt +41 -0
- package/templates/help/run.txt +22 -0
- package/templates/help/tic80.txt +8 -0
- package/templates/help/watch.txt +24 -0
- package/templates/minimal/project.ticbuild.jsonc +43 -0
- package/ticbuild-1.0.0.tgz +0 -0
- package/ticbuild.schema.json +327 -0
|
@@ -0,0 +1,1153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LuaPrinter = void 0;
|
|
37
|
+
exports.unparseLua = unparseLua;
|
|
38
|
+
exports.parseLua = parseLua;
|
|
39
|
+
exports.processLua = processLua;
|
|
40
|
+
const luaparse = __importStar(require("luaparse"));
|
|
41
|
+
const lua_renamer_1 = require("./lua_renamer");
|
|
42
|
+
const lua_alias_literals_1 = require("./lua_alias_literals");
|
|
43
|
+
const lua_alias_expressions_1 = require("./lua_alias_expressions");
|
|
44
|
+
const lua_pack_locals_1 = require("./lua_pack_locals");
|
|
45
|
+
const lua_simplify_1 = require("./lua_simplify");
|
|
46
|
+
const lua_remove_unused_locals_1 = require("./lua_remove_unused_locals");
|
|
47
|
+
const lua_remove_unused_functions_1 = require("./lua_remove_unused_functions");
|
|
48
|
+
const lua_rename_table_fields_1 = require("./lua_rename_table_fields");
|
|
49
|
+
const lua_rename_allowed_table_keys_1 = require("./lua_rename_allowed_table_keys");
|
|
50
|
+
const lua_fundamentals_1 = require("./lua_fundamentals");
|
|
51
|
+
// Precedence tables, low → high
|
|
52
|
+
const LOGICAL_PRECEDENCE = {
|
|
53
|
+
or: 1,
|
|
54
|
+
and: 2,
|
|
55
|
+
};
|
|
56
|
+
const BINARY_PRECEDENCE = {
|
|
57
|
+
"<": 3,
|
|
58
|
+
">": 3,
|
|
59
|
+
"<=": 3,
|
|
60
|
+
">=": 3,
|
|
61
|
+
"~=": 3,
|
|
62
|
+
"==": 3,
|
|
63
|
+
"|": 4,
|
|
64
|
+
"~": 5,
|
|
65
|
+
"&": 6,
|
|
66
|
+
"<<": 7,
|
|
67
|
+
">>": 7,
|
|
68
|
+
"..": 8, // right associative
|
|
69
|
+
"+": 9,
|
|
70
|
+
"-": 9,
|
|
71
|
+
"*": 10,
|
|
72
|
+
"/": 10,
|
|
73
|
+
"//": 10,
|
|
74
|
+
"%": 10,
|
|
75
|
+
};
|
|
76
|
+
const UNARY_PRECEDENCE = 11; // not, #, -, ~
|
|
77
|
+
const POW_PRECEDENCE = 12; // ^
|
|
78
|
+
function getPrecedence(node) {
|
|
79
|
+
switch (node.type) {
|
|
80
|
+
case "LogicalExpression":
|
|
81
|
+
return LOGICAL_PRECEDENCE[node.operator];
|
|
82
|
+
case "BinaryExpression": {
|
|
83
|
+
const op = node.operator;
|
|
84
|
+
if (op === "^")
|
|
85
|
+
return POW_PRECEDENCE;
|
|
86
|
+
return BINARY_PRECEDENCE[op];
|
|
87
|
+
}
|
|
88
|
+
case "UnaryExpression":
|
|
89
|
+
return UNARY_PRECEDENCE;
|
|
90
|
+
default:
|
|
91
|
+
// Primary expressions (literals, identifiers, calls, table ctors, etc.)
|
|
92
|
+
return 100;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
class LuaPrinter {
|
|
96
|
+
constructor(options, blockComments) {
|
|
97
|
+
this.buf = [];
|
|
98
|
+
this.indentLevel = 0;
|
|
99
|
+
this.indentUnit = " "; // only used if !minified
|
|
100
|
+
this.currentLine = "";
|
|
101
|
+
this.inlineMode = false; // When true, render everything on single lines without packing
|
|
102
|
+
this.options = options;
|
|
103
|
+
this.blockComments = blockComments || new Map();
|
|
104
|
+
}
|
|
105
|
+
print(chunk) {
|
|
106
|
+
const mode = this.options.lineBehavior || "pretty";
|
|
107
|
+
// For tight mode, use the token-stream approach
|
|
108
|
+
if (mode === "tight") {
|
|
109
|
+
return this.printTightMode(chunk);
|
|
110
|
+
}
|
|
111
|
+
// For pretty and single-line-blocks, use structured approach
|
|
112
|
+
this.buf = [];
|
|
113
|
+
this.currentLine = "";
|
|
114
|
+
this.indentLevel = 0;
|
|
115
|
+
this.printBlock(chunk.body);
|
|
116
|
+
if (this.currentLine.length > 0)
|
|
117
|
+
this.flushLine();
|
|
118
|
+
return this.buf.join("");
|
|
119
|
+
}
|
|
120
|
+
// ===== TIGHT MODE: Token-stream based packing =====
|
|
121
|
+
// Renders everything to space-separated tokens, then packs into lines
|
|
122
|
+
printTightMode(chunk) {
|
|
123
|
+
const tokens = this.collectTokens(chunk.body);
|
|
124
|
+
return this.packTokensIntoLines(tokens);
|
|
125
|
+
}
|
|
126
|
+
// Collect all tokens from a block of statements
|
|
127
|
+
collectTokens(body) {
|
|
128
|
+
const comments = [...(this.blockComments.get(body) || [])];
|
|
129
|
+
const items = [];
|
|
130
|
+
let ci = 0;
|
|
131
|
+
for (const stmt of body) {
|
|
132
|
+
while (ci < comments.length && this.startPos(comments[ci]) <= this.startPos(stmt)) {
|
|
133
|
+
items.push(comments[ci]);
|
|
134
|
+
ci++;
|
|
135
|
+
}
|
|
136
|
+
items.push(stmt);
|
|
137
|
+
}
|
|
138
|
+
while (ci < comments.length) {
|
|
139
|
+
items.push(comments[ci]);
|
|
140
|
+
ci++;
|
|
141
|
+
}
|
|
142
|
+
const tokens = [];
|
|
143
|
+
for (const node of items) {
|
|
144
|
+
if (node.type === "Comment") {
|
|
145
|
+
// Comments get special handling - they force a line break
|
|
146
|
+
tokens.push("\n" + this.renderComment(node));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const stmtTokens = this.statementToTokens(node);
|
|
150
|
+
tokens.push(...stmtTokens);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return tokens;
|
|
154
|
+
}
|
|
155
|
+
// Convert a statement to tokens (space-separated pieces)
|
|
156
|
+
// For maximum packing flexibility, we separate keywords from their arguments
|
|
157
|
+
statementToTokens(stmt) {
|
|
158
|
+
const tokens = [];
|
|
159
|
+
switch (stmt.type) {
|
|
160
|
+
case "AssignmentStatement": {
|
|
161
|
+
const st = stmt;
|
|
162
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
163
|
+
const vals = st.init.map((v) => this.expr(v)).join(",");
|
|
164
|
+
tokens.push(vars + "=" + vals);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case "LocalStatement": {
|
|
168
|
+
const st = stmt;
|
|
169
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
170
|
+
let s = "local " + vars;
|
|
171
|
+
if (st.init && st.init.length > 0) {
|
|
172
|
+
s += "=" + st.init.map((v) => this.expr(v)).join(",");
|
|
173
|
+
}
|
|
174
|
+
tokens.push(s);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case "CallStatement": {
|
|
178
|
+
const st = stmt;
|
|
179
|
+
tokens.push(this.expr(st.expression));
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "ReturnStatement": {
|
|
183
|
+
const st = stmt;
|
|
184
|
+
if (st.arguments.length > 0) {
|
|
185
|
+
// Keep return with all its comma-separated arguments as one token
|
|
186
|
+
// to preserve required commas between multiple return values
|
|
187
|
+
tokens.push("return " + st.arguments.map((a) => this.expr(a)).join(","));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
tokens.push("return");
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case "BreakStatement":
|
|
195
|
+
tokens.push("break");
|
|
196
|
+
break;
|
|
197
|
+
case "FunctionDeclaration": {
|
|
198
|
+
const fn = stmt;
|
|
199
|
+
let s = fn.isLocal ? "local function " : "function ";
|
|
200
|
+
if (fn.identifier) {
|
|
201
|
+
s += this.expr(fn.identifier);
|
|
202
|
+
}
|
|
203
|
+
s += "(" + fn.parameters.map((p) => this.expr(p)).join(",") + ")";
|
|
204
|
+
tokens.push(s);
|
|
205
|
+
tokens.push(...this.collectTokens(fn.body));
|
|
206
|
+
tokens.push("end");
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case "IfStatement": {
|
|
210
|
+
const ifs = stmt;
|
|
211
|
+
for (const clause of ifs.clauses) {
|
|
212
|
+
if (clause.type === "IfClause") {
|
|
213
|
+
tokens.push("if " + this.expr(clause.condition) + " then");
|
|
214
|
+
}
|
|
215
|
+
else if (clause.type === "ElseifClause") {
|
|
216
|
+
tokens.push("elseif " + this.expr(clause.condition) + " then");
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
tokens.push("else");
|
|
220
|
+
}
|
|
221
|
+
tokens.push(...this.collectTokens(clause.body));
|
|
222
|
+
}
|
|
223
|
+
tokens.push("end");
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case "WhileStatement": {
|
|
227
|
+
const st = stmt;
|
|
228
|
+
tokens.push("while " + this.expr(st.condition) + " do");
|
|
229
|
+
tokens.push(...this.collectTokens(st.body));
|
|
230
|
+
tokens.push("end");
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
case "RepeatStatement": {
|
|
234
|
+
const st = stmt;
|
|
235
|
+
tokens.push("repeat");
|
|
236
|
+
tokens.push(...this.collectTokens(st.body));
|
|
237
|
+
tokens.push("until " + this.expr(st.condition));
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
case "ForNumericStatement": {
|
|
241
|
+
const st = stmt;
|
|
242
|
+
let s = "for " + this.expr(st.variable) + "=" + this.expr(st.start) + "," + this.expr(st.end);
|
|
243
|
+
if (st.step) {
|
|
244
|
+
s += "," + this.expr(st.step);
|
|
245
|
+
}
|
|
246
|
+
s += " do";
|
|
247
|
+
tokens.push(s);
|
|
248
|
+
tokens.push(...this.collectTokens(st.body));
|
|
249
|
+
tokens.push("end");
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "ForGenericStatement": {
|
|
253
|
+
const st = stmt;
|
|
254
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
255
|
+
const iters = st.iterators.map((it) => this.expr(it)).join(",");
|
|
256
|
+
tokens.push("for " + vars + " in " + iters + " do");
|
|
257
|
+
tokens.push(...this.collectTokens(st.body));
|
|
258
|
+
tokens.push("end");
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case "DoStatement": {
|
|
262
|
+
const st = stmt;
|
|
263
|
+
tokens.push("do");
|
|
264
|
+
tokens.push(...this.collectTokens(st.body));
|
|
265
|
+
tokens.push("end");
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
default:
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
return tokens;
|
|
272
|
+
}
|
|
273
|
+
// Pack tokens into lines respecting maxLineLength
|
|
274
|
+
packTokensIntoLines(tokens) {
|
|
275
|
+
const maxLen = this.options.maxLineLength || 120;
|
|
276
|
+
const lines = [];
|
|
277
|
+
let currentLine = "";
|
|
278
|
+
for (const token of tokens) {
|
|
279
|
+
// Special case: comment tokens start with \n and force a new line
|
|
280
|
+
if (token.startsWith("\n")) {
|
|
281
|
+
if (currentLine.length > 0) {
|
|
282
|
+
lines.push(currentLine);
|
|
283
|
+
currentLine = "";
|
|
284
|
+
}
|
|
285
|
+
lines.push(token.slice(1)); // Remove the leading \n marker
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (currentLine.length === 0) {
|
|
289
|
+
currentLine = token;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
const candidate = currentLine + " " + token;
|
|
293
|
+
// Use <= to allow filling lines up to exactly maxLen
|
|
294
|
+
// EXCEPT: if the token is 'end', use < to prefer wrapping
|
|
295
|
+
// This avoids packing 'end' to fill exactly maxLen
|
|
296
|
+
const isEndToken = token === "end";
|
|
297
|
+
const fits = isEndToken ? candidate.length < maxLen : candidate.length <= maxLen;
|
|
298
|
+
if (fits) {
|
|
299
|
+
currentLine = candidate;
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
lines.push(currentLine);
|
|
303
|
+
currentLine = token;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (currentLine.length > 0) {
|
|
308
|
+
lines.push(currentLine);
|
|
309
|
+
}
|
|
310
|
+
return lines.join("\n") + (lines.length > 0 ? "\n" : "");
|
|
311
|
+
}
|
|
312
|
+
// Render a comment for tight mode
|
|
313
|
+
renderComment(comment) {
|
|
314
|
+
if (comment.raw) {
|
|
315
|
+
return comment.raw.trim();
|
|
316
|
+
}
|
|
317
|
+
return "--" + comment.value;
|
|
318
|
+
}
|
|
319
|
+
// --- low-level emit helpers ---
|
|
320
|
+
emit(s) {
|
|
321
|
+
this.currentLine += s;
|
|
322
|
+
}
|
|
323
|
+
newline() {
|
|
324
|
+
this.flushLine();
|
|
325
|
+
}
|
|
326
|
+
flushLine() {
|
|
327
|
+
this.buf.push(this.currentLine + "\n");
|
|
328
|
+
this.currentLine = "";
|
|
329
|
+
}
|
|
330
|
+
emitKeyword(s) {
|
|
331
|
+
this.emit(s);
|
|
332
|
+
}
|
|
333
|
+
startPos(node) {
|
|
334
|
+
if (node && Array.isArray(node.range) && node.range.length > 0) {
|
|
335
|
+
return node.range[0];
|
|
336
|
+
}
|
|
337
|
+
return 0;
|
|
338
|
+
}
|
|
339
|
+
printIndent() {
|
|
340
|
+
const indentLevel = Math.min(this.indentLevel, this.options.maxIndentLevel);
|
|
341
|
+
this.buf.push(this.indentUnit.repeat(indentLevel));
|
|
342
|
+
// if (!this.options.stripWhitespace) {
|
|
343
|
+
// this.buf.push(this.indentUnit.repeat(this.indentLevel));
|
|
344
|
+
// }
|
|
345
|
+
}
|
|
346
|
+
printBlock(body) {
|
|
347
|
+
const comments = [...(this.blockComments.get(body) || [])];
|
|
348
|
+
const items = [];
|
|
349
|
+
let ci = 0;
|
|
350
|
+
for (const stmt of body) {
|
|
351
|
+
while (ci < comments.length && this.startPos(comments[ci]) <= this.startPos(stmt)) {
|
|
352
|
+
items.push(comments[ci]);
|
|
353
|
+
ci++;
|
|
354
|
+
}
|
|
355
|
+
items.push(stmt);
|
|
356
|
+
}
|
|
357
|
+
while (ci < comments.length) {
|
|
358
|
+
items.push(comments[ci]);
|
|
359
|
+
ci++;
|
|
360
|
+
}
|
|
361
|
+
const mode = this.options.lineBehavior || "pretty";
|
|
362
|
+
const maxLen = this.options.maxLineLength || 120;
|
|
363
|
+
// In inline mode, render all statements space-separated on one line (no newlines)
|
|
364
|
+
if (this.inlineMode) {
|
|
365
|
+
for (let i = 0; i < items.length; i++) {
|
|
366
|
+
const node = items[i];
|
|
367
|
+
if (i > 0)
|
|
368
|
+
this.emit(" ");
|
|
369
|
+
this.printStatementInline(node);
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
// In pretty mode, print each statement on its own line
|
|
374
|
+
if (mode === "pretty") {
|
|
375
|
+
for (const node of items) {
|
|
376
|
+
this.printIndent();
|
|
377
|
+
this.printStatement(node);
|
|
378
|
+
}
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// single-line-blocks mode: blocks are either entirely single-line or multi-line
|
|
382
|
+
// (tight mode is handled separately via printTightMode)
|
|
383
|
+
const flushLineIfAny = () => {
|
|
384
|
+
if (this.currentLine.length > 0)
|
|
385
|
+
this.flushLine();
|
|
386
|
+
};
|
|
387
|
+
for (const node of items) {
|
|
388
|
+
// Comments always get their own line
|
|
389
|
+
if (node.type === "Comment") {
|
|
390
|
+
flushLineIfAny();
|
|
391
|
+
this.printIndent();
|
|
392
|
+
this.printStatement(node);
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const stmt = node;
|
|
396
|
+
const inline = this.renderInlineStatement(stmt, maxLen);
|
|
397
|
+
const indent = this.indentUnit.repeat(Math.min(this.indentLevel, this.options.maxIndentLevel));
|
|
398
|
+
// Check if inline version fits on its own line (with indent)
|
|
399
|
+
const inlineWithIndent = inline !== null ? indent + inline : null;
|
|
400
|
+
const inlineFits = inlineWithIndent !== null && inlineWithIndent.length < maxLen;
|
|
401
|
+
if (inlineFits) {
|
|
402
|
+
// Try to pack onto current line
|
|
403
|
+
const sep = this.currentLine.length === 0 ? "" : " ";
|
|
404
|
+
const prefix = this.currentLine.length === 0 ? indent : this.currentLine;
|
|
405
|
+
const candidate = prefix + sep + inline;
|
|
406
|
+
if (candidate.length < maxLen || this.currentLine.length === 0) {
|
|
407
|
+
if (this.currentLine.length === 0) {
|
|
408
|
+
this.currentLine = indent + inline;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
this.currentLine = this.currentLine + " " + inline;
|
|
412
|
+
}
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
// Doesn't fit on current line, but inline exists - start new line with inline
|
|
416
|
+
flushLineIfAny();
|
|
417
|
+
this.currentLine = indent + inline;
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
// Fallback to normal multi-line printing for this statement
|
|
421
|
+
flushLineIfAny();
|
|
422
|
+
this.printIndent();
|
|
423
|
+
this.printStatement(node);
|
|
424
|
+
}
|
|
425
|
+
// Ensure any buffered inline statements inside this block are flushed before exiting it.
|
|
426
|
+
flushLineIfAny();
|
|
427
|
+
}
|
|
428
|
+
// Print a statement without any newline at the end (for inline mode)
|
|
429
|
+
printStatementInline(node) {
|
|
430
|
+
switch (node.type) {
|
|
431
|
+
case "AssignmentStatement": {
|
|
432
|
+
const st = node;
|
|
433
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
434
|
+
const vals = st.init.map((v) => this.expr(v)).join(",");
|
|
435
|
+
this.emit(vars + "=" + vals);
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
case "LocalStatement": {
|
|
439
|
+
const st = node;
|
|
440
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
441
|
+
let s = "local " + vars;
|
|
442
|
+
if (st.init && st.init.length > 0) {
|
|
443
|
+
s += "=" + st.init.map((v) => this.expr(v)).join(",");
|
|
444
|
+
}
|
|
445
|
+
this.emit(s);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
case "CallStatement": {
|
|
449
|
+
const st = node;
|
|
450
|
+
this.emit(this.expr(st.expression));
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case "FunctionDeclaration": {
|
|
454
|
+
const fn = node;
|
|
455
|
+
let s = fn.isLocal ? "local function " : "function ";
|
|
456
|
+
if (fn.identifier) {
|
|
457
|
+
s += this.expr(fn.identifier);
|
|
458
|
+
}
|
|
459
|
+
s += "(" + fn.parameters.map((p) => this.expr(p)).join(",") + ") ";
|
|
460
|
+
this.emit(s);
|
|
461
|
+
this.printBlock(fn.body);
|
|
462
|
+
this.emit(" end");
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
case "IfStatement": {
|
|
466
|
+
const ifs = node;
|
|
467
|
+
for (let i = 0; i < ifs.clauses.length; i++) {
|
|
468
|
+
const clause = ifs.clauses[i];
|
|
469
|
+
if (clause.type === "IfClause") {
|
|
470
|
+
this.emit("if " + this.expr(clause.condition) + " then ");
|
|
471
|
+
}
|
|
472
|
+
else if (clause.type === "ElseifClause") {
|
|
473
|
+
this.emit(" elseif " + this.expr(clause.condition) + " then ");
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
this.emit(" else ");
|
|
477
|
+
}
|
|
478
|
+
this.printBlock(clause.body);
|
|
479
|
+
}
|
|
480
|
+
this.emit(" end");
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
case "WhileStatement": {
|
|
484
|
+
const st = node;
|
|
485
|
+
this.emit("while " + this.expr(st.condition) + " do ");
|
|
486
|
+
this.printBlock(st.body);
|
|
487
|
+
this.emit(" end");
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
case "RepeatStatement": {
|
|
491
|
+
const st = node;
|
|
492
|
+
this.emit("repeat ");
|
|
493
|
+
this.printBlock(st.body);
|
|
494
|
+
this.emit(" until " + this.expr(st.condition));
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
case "ForNumericStatement": {
|
|
498
|
+
const st = node;
|
|
499
|
+
let s = "for " + this.expr(st.variable) + "=" + this.expr(st.start) + "," + this.expr(st.end);
|
|
500
|
+
if (st.step) {
|
|
501
|
+
s += "," + this.expr(st.step);
|
|
502
|
+
}
|
|
503
|
+
s += " do ";
|
|
504
|
+
this.emit(s);
|
|
505
|
+
this.printBlock(st.body);
|
|
506
|
+
this.emit(" end");
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
case "ForGenericStatement": {
|
|
510
|
+
const st = node;
|
|
511
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
512
|
+
const iters = st.iterators.map((it) => this.expr(it)).join(",");
|
|
513
|
+
this.emit("for " + vars + " in " + iters + " do ");
|
|
514
|
+
this.printBlock(st.body);
|
|
515
|
+
this.emit(" end");
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
case "ReturnStatement": {
|
|
519
|
+
const st = node;
|
|
520
|
+
if (st.arguments.length > 0) {
|
|
521
|
+
this.emit("return " + st.arguments.map((a) => this.expr(a)).join(","));
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
this.emit("return");
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
case "BreakStatement":
|
|
529
|
+
this.emit("break");
|
|
530
|
+
break;
|
|
531
|
+
case "DoStatement": {
|
|
532
|
+
const st = node;
|
|
533
|
+
this.emit("do ");
|
|
534
|
+
this.printBlock(st.body);
|
|
535
|
+
this.emit(" end");
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
case "Comment":
|
|
539
|
+
// Skip comments in inline mode
|
|
540
|
+
break;
|
|
541
|
+
default:
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
// --- statement printer ---
|
|
546
|
+
printStatement(node) {
|
|
547
|
+
switch (node.type) {
|
|
548
|
+
case "AssignmentStatement": {
|
|
549
|
+
const st = node;
|
|
550
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
551
|
+
const vals = st.init.map((v) => this.expr(v)).join(",");
|
|
552
|
+
this.emit(vars);
|
|
553
|
+
this.emit("=");
|
|
554
|
+
this.emit(vals);
|
|
555
|
+
this.newline();
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
case "LocalStatement": {
|
|
559
|
+
const st = node;
|
|
560
|
+
const vars = st.variables.map((v) => this.expr(v)).join(",");
|
|
561
|
+
this.emitKeyword("local");
|
|
562
|
+
this.emit(" ");
|
|
563
|
+
this.emit(vars);
|
|
564
|
+
if (st.init && st.init.length > 0) {
|
|
565
|
+
const vals = st.init.map((v) => this.expr(v)).join(",");
|
|
566
|
+
this.emit("=");
|
|
567
|
+
this.emit(vals);
|
|
568
|
+
}
|
|
569
|
+
this.newline();
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
case "CallStatement": {
|
|
573
|
+
const st = node;
|
|
574
|
+
this.emit(this.expr(st.expression));
|
|
575
|
+
this.newline();
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
case "FunctionDeclaration": {
|
|
579
|
+
const fn = node;
|
|
580
|
+
if (fn.isLocal) {
|
|
581
|
+
this.emitKeyword("local");
|
|
582
|
+
this.emit(" ");
|
|
583
|
+
}
|
|
584
|
+
this.emitKeyword("function");
|
|
585
|
+
this.emit(" ");
|
|
586
|
+
if (fn.identifier) {
|
|
587
|
+
this.emit(this.expr(fn.identifier));
|
|
588
|
+
}
|
|
589
|
+
this.emit("(");
|
|
590
|
+
this.emit(fn.parameters.map((p) => this.expr(p)).join(","));
|
|
591
|
+
this.emit(")");
|
|
592
|
+
this.newline();
|
|
593
|
+
this.indentLevel++;
|
|
594
|
+
this.printBlock(fn.body);
|
|
595
|
+
this.indentLevel--;
|
|
596
|
+
this.printIndent();
|
|
597
|
+
this.emitKeyword("end");
|
|
598
|
+
this.newline();
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
case "IfStatement": {
|
|
602
|
+
const ifs = node;
|
|
603
|
+
ifs.clauses.forEach((clause, idx) => {
|
|
604
|
+
// The enclosing block printer (`printBlock`) emits indentation only once for the
|
|
605
|
+
// top-level statement. Subsequent clauses need to re-emit indentation explicitly,
|
|
606
|
+
// otherwise `elseif`/`else` start at column 0.
|
|
607
|
+
if (idx > 0) {
|
|
608
|
+
this.printIndent();
|
|
609
|
+
}
|
|
610
|
+
if (clause.type === "IfClause") {
|
|
611
|
+
this.emitKeyword("if");
|
|
612
|
+
this.emit(" ");
|
|
613
|
+
this.emit(this.expr(clause.condition));
|
|
614
|
+
this.emitKeyword(" then");
|
|
615
|
+
}
|
|
616
|
+
else if (clause.type === "ElseifClause") {
|
|
617
|
+
this.emitKeyword("elseif");
|
|
618
|
+
this.emit(" ");
|
|
619
|
+
this.emit(this.expr(clause.condition));
|
|
620
|
+
this.emitKeyword(" then");
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
this.emitKeyword("else");
|
|
624
|
+
}
|
|
625
|
+
this.newline();
|
|
626
|
+
this.indentLevel++;
|
|
627
|
+
this.printBlock(clause.body);
|
|
628
|
+
this.indentLevel--;
|
|
629
|
+
});
|
|
630
|
+
this.printIndent();
|
|
631
|
+
this.emitKeyword("end");
|
|
632
|
+
this.newline();
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
case "WhileStatement": {
|
|
636
|
+
const st = node;
|
|
637
|
+
this.emitKeyword("while");
|
|
638
|
+
this.emit(" ");
|
|
639
|
+
this.emit(this.expr(st.condition));
|
|
640
|
+
this.emitKeyword(" do");
|
|
641
|
+
this.newline();
|
|
642
|
+
this.indentLevel++;
|
|
643
|
+
this.printBlock(st.body);
|
|
644
|
+
this.indentLevel--;
|
|
645
|
+
this.printIndent();
|
|
646
|
+
this.emitKeyword("end");
|
|
647
|
+
this.newline();
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
case "RepeatStatement": {
|
|
651
|
+
const st = node;
|
|
652
|
+
this.emitKeyword("repeat");
|
|
653
|
+
this.newline();
|
|
654
|
+
this.indentLevel++;
|
|
655
|
+
this.printBlock(st.body);
|
|
656
|
+
this.indentLevel--;
|
|
657
|
+
this.emitKeyword("until");
|
|
658
|
+
this.emit(" ");
|
|
659
|
+
this.emit(this.expr(st.condition));
|
|
660
|
+
this.newline();
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
case "ForNumericStatement": {
|
|
664
|
+
const st = node;
|
|
665
|
+
this.emitKeyword("for");
|
|
666
|
+
this.emit(" ");
|
|
667
|
+
this.emit(this.expr(st.variable));
|
|
668
|
+
this.emit("=");
|
|
669
|
+
this.emit(this.expr(st.start));
|
|
670
|
+
this.emit(",");
|
|
671
|
+
this.emit(this.expr(st.end));
|
|
672
|
+
if (st.step) {
|
|
673
|
+
this.emit(",");
|
|
674
|
+
this.emit(this.expr(st.step));
|
|
675
|
+
}
|
|
676
|
+
this.emitKeyword(" do");
|
|
677
|
+
this.newline();
|
|
678
|
+
this.indentLevel++;
|
|
679
|
+
this.printBlock(st.body);
|
|
680
|
+
this.indentLevel--;
|
|
681
|
+
this.printIndent();
|
|
682
|
+
this.emitKeyword("end");
|
|
683
|
+
this.newline();
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
case "ForGenericStatement": {
|
|
687
|
+
const st = node;
|
|
688
|
+
this.emitKeyword("for");
|
|
689
|
+
this.emit(" ");
|
|
690
|
+
this.emit(st.variables.map((v) => this.expr(v)).join(","));
|
|
691
|
+
this.emitKeyword(" in ");
|
|
692
|
+
this.emit(st.iterators.map((it) => this.expr(it)).join(","));
|
|
693
|
+
this.emitKeyword(" do");
|
|
694
|
+
this.newline();
|
|
695
|
+
this.indentLevel++;
|
|
696
|
+
this.printBlock(st.body);
|
|
697
|
+
this.indentLevel--;
|
|
698
|
+
this.printIndent();
|
|
699
|
+
this.emitKeyword("end");
|
|
700
|
+
this.newline();
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
case "ReturnStatement": {
|
|
704
|
+
const st = node;
|
|
705
|
+
this.emitKeyword("return");
|
|
706
|
+
if (st.arguments.length > 0) {
|
|
707
|
+
this.emit(" ");
|
|
708
|
+
this.emit(st.arguments.map((a) => this.expr(a)).join(","));
|
|
709
|
+
}
|
|
710
|
+
this.newline();
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
case "BreakStatement": {
|
|
714
|
+
this.emitKeyword("break");
|
|
715
|
+
this.newline();
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
case "DoStatement": {
|
|
719
|
+
const st = node;
|
|
720
|
+
this.emitKeyword("do");
|
|
721
|
+
this.newline();
|
|
722
|
+
this.indentLevel++;
|
|
723
|
+
this.printBlock(st.body);
|
|
724
|
+
this.indentLevel--;
|
|
725
|
+
this.printIndent();
|
|
726
|
+
this.emitKeyword("end");
|
|
727
|
+
this.newline();
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
case "Comment":
|
|
731
|
+
this.printComment(node);
|
|
732
|
+
break;
|
|
733
|
+
default:
|
|
734
|
+
// console.warn("Unimplemented statement type:", node.type);
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
// Try to render a statement as a single-line string.
|
|
739
|
+
// For single-line-blocks mode: only return non-null if the entire statement (including nested blocks) fits on one line.
|
|
740
|
+
// Returns null if the statement cannot be rendered inline under the given constraints.
|
|
741
|
+
renderInlineStatement(stmt, maxLen) {
|
|
742
|
+
// Use a temporary printer in inline mode to render everything on one line
|
|
743
|
+
const temp = new LuaPrinter(this.options, this.blockComments);
|
|
744
|
+
temp.inlineMode = true;
|
|
745
|
+
temp.buf = [];
|
|
746
|
+
temp.currentLine = "";
|
|
747
|
+
temp.printStatementInline(stmt);
|
|
748
|
+
const out = temp.currentLine.trim();
|
|
749
|
+
// If it exceeds maxLen, cannot inline
|
|
750
|
+
if (out.length > maxLen) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
return out;
|
|
754
|
+
}
|
|
755
|
+
// Check if statement contains nested blocks
|
|
756
|
+
isBlockStatement(stmt) {
|
|
757
|
+
switch (stmt.type) {
|
|
758
|
+
case "IfStatement":
|
|
759
|
+
case "WhileStatement":
|
|
760
|
+
case "RepeatStatement":
|
|
761
|
+
case "ForNumericStatement":
|
|
762
|
+
case "ForGenericStatement":
|
|
763
|
+
case "FunctionDeclaration":
|
|
764
|
+
case "DoStatement":
|
|
765
|
+
return true;
|
|
766
|
+
default:
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
// --- expression printer ---
|
|
771
|
+
expr(node, parentPrec = 0) {
|
|
772
|
+
if (!node)
|
|
773
|
+
return "";
|
|
774
|
+
switch (node.type) {
|
|
775
|
+
case "Identifier":
|
|
776
|
+
return node.name;
|
|
777
|
+
case "StringLiteral":
|
|
778
|
+
return this.stringLiteral(node);
|
|
779
|
+
case "NumericLiteral":
|
|
780
|
+
return this.numericLiteral(node);
|
|
781
|
+
case "BooleanLiteral":
|
|
782
|
+
return node.value ? "true" : "false";
|
|
783
|
+
case "NilLiteral":
|
|
784
|
+
return "nil";
|
|
785
|
+
case "VarargLiteral":
|
|
786
|
+
return "...";
|
|
787
|
+
case "TableConstructorExpression":
|
|
788
|
+
return this.tableConstructor(node);
|
|
789
|
+
case "UnaryExpression":
|
|
790
|
+
return this.unaryExpr(node, parentPrec);
|
|
791
|
+
case "BinaryExpression":
|
|
792
|
+
return this.binaryExpr(node, parentPrec);
|
|
793
|
+
case "LogicalExpression":
|
|
794
|
+
return this.logicalExpr(node, parentPrec);
|
|
795
|
+
case "MemberExpression":
|
|
796
|
+
return this.memberExpr(node);
|
|
797
|
+
case "IndexExpression":
|
|
798
|
+
return this.indexExpr(node);
|
|
799
|
+
case "CallExpression":
|
|
800
|
+
return this.callExpr(node);
|
|
801
|
+
case "TableCallExpression":
|
|
802
|
+
return this.tableCallExpr(node);
|
|
803
|
+
case "StringCallExpression":
|
|
804
|
+
return this.stringCallExpr(node);
|
|
805
|
+
case "FunctionDeclaration":
|
|
806
|
+
return this.functionExpr(node);
|
|
807
|
+
default:
|
|
808
|
+
return `<${node.type}>`;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
stringLiteral(node) {
|
|
812
|
+
if (node.raw)
|
|
813
|
+
return node.raw;
|
|
814
|
+
return (0, lua_fundamentals_1.toLuaStringLiteral)(node.value);
|
|
815
|
+
}
|
|
816
|
+
numericLiteral(node, options) {
|
|
817
|
+
const value = node.value;
|
|
818
|
+
const decimalStr = Number.isFinite(value) ? value.toString(10) : String(value);
|
|
819
|
+
if (/^-?0\.\d/.test(decimalStr)) {
|
|
820
|
+
const compact = decimalStr.replace(/^(-?)0\./, "$1.");
|
|
821
|
+
if (options?.forceLeadingZero && /^-?\./.test(compact)) {
|
|
822
|
+
return compact.replace(/^(-?)\./, "$10.");
|
|
823
|
+
}
|
|
824
|
+
return compact;
|
|
825
|
+
}
|
|
826
|
+
if (options?.forceLeadingZero && /^-?\./.test(decimalStr)) {
|
|
827
|
+
return decimalStr.replace(/^(-?)\./, "$10.");
|
|
828
|
+
}
|
|
829
|
+
return decimalStr;
|
|
830
|
+
}
|
|
831
|
+
tableConstructor(node) {
|
|
832
|
+
if (node.fields.length === 0)
|
|
833
|
+
return "{}";
|
|
834
|
+
const parts = [];
|
|
835
|
+
for (const f of node.fields) {
|
|
836
|
+
if (f.type === "TableKey") {
|
|
837
|
+
parts.push(`[${this.expr(f.key)}]=${this.expr(f.value)}`);
|
|
838
|
+
}
|
|
839
|
+
else if (f.type === "TableKeyString") {
|
|
840
|
+
// luaparse gives key as an Identifier or StringLiteral
|
|
841
|
+
parts.push(`${this.expr(f.key)}=${this.expr(f.value)}`);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
// TableValue
|
|
845
|
+
parts.push(this.expr(f.value));
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return `{${parts.join(",")}}`;
|
|
849
|
+
}
|
|
850
|
+
unaryExpr(node, parentPrec) {
|
|
851
|
+
const prec = getPrecedence(node);
|
|
852
|
+
const arg = this.expr(node.argument, prec);
|
|
853
|
+
const op = node.operator;
|
|
854
|
+
let s;
|
|
855
|
+
if (op === "not") {
|
|
856
|
+
s = `not ${arg}`;
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
s = op + arg;
|
|
860
|
+
}
|
|
861
|
+
if (prec < parentPrec)
|
|
862
|
+
s = `(${s})`;
|
|
863
|
+
return s;
|
|
864
|
+
}
|
|
865
|
+
binaryExpr(node, parentPrec) {
|
|
866
|
+
const prec = getPrecedence(node);
|
|
867
|
+
const left = node.operator === ".." ? this.concatLeftExpr(node.left, prec) : this.expr(node.left, prec);
|
|
868
|
+
const rightRaw = node.operator === ".." ? this.concatRightExpr(node.right, prec) : this.expr(node.right, prec);
|
|
869
|
+
const right = node.operator === ".." ? this.ensureConcatSafeRight(rightRaw) : rightRaw;
|
|
870
|
+
let s = `${left}${node.operator}${right}`;
|
|
871
|
+
if (prec < parentPrec)
|
|
872
|
+
s = `(${s})`;
|
|
873
|
+
return s;
|
|
874
|
+
}
|
|
875
|
+
concatLeftExpr(node, parentPrec) {
|
|
876
|
+
if (node.type === "NumericLiteral") {
|
|
877
|
+
return `(${this.numericLiteral(node)})`;
|
|
878
|
+
}
|
|
879
|
+
if (node.type === "UnaryExpression") {
|
|
880
|
+
const unary = node;
|
|
881
|
+
if (unary.operator === "-" && unary.argument.type === "NumericLiteral") {
|
|
882
|
+
const arg = this.numericLiteral(unary.argument);
|
|
883
|
+
return `(-${arg})`;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return this.expr(node, parentPrec);
|
|
887
|
+
}
|
|
888
|
+
concatRightExpr(node, parentPrec) {
|
|
889
|
+
if (node.type === "NumericLiteral") {
|
|
890
|
+
return this.numericLiteral(node, { forceLeadingZero: true });
|
|
891
|
+
}
|
|
892
|
+
if (node.type === "UnaryExpression") {
|
|
893
|
+
const unary = node;
|
|
894
|
+
if (unary.operator === "-" && unary.argument.type === "NumericLiteral") {
|
|
895
|
+
const arg = this.numericLiteral(unary.argument, { forceLeadingZero: true });
|
|
896
|
+
let s = `-${arg}`;
|
|
897
|
+
if (getPrecedence(unary) < parentPrec)
|
|
898
|
+
s = `(${s})`;
|
|
899
|
+
return s;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return this.expr(node, parentPrec);
|
|
903
|
+
}
|
|
904
|
+
ensureConcatSafeRight(text) {
|
|
905
|
+
if (text.startsWith("-.")) {
|
|
906
|
+
return "-0" + text.slice(1);
|
|
907
|
+
}
|
|
908
|
+
if (text.startsWith(".")) {
|
|
909
|
+
return "0" + text;
|
|
910
|
+
}
|
|
911
|
+
return text;
|
|
912
|
+
}
|
|
913
|
+
logicalExpr(node, parentPrec) {
|
|
914
|
+
const prec = getPrecedence(node);
|
|
915
|
+
const left = this.expr(node.left, prec);
|
|
916
|
+
const right = this.expr(node.right, prec);
|
|
917
|
+
let s = `${left} ${node.operator} ${right}`;
|
|
918
|
+
if (prec < parentPrec)
|
|
919
|
+
s = `(${s})`;
|
|
920
|
+
return s;
|
|
921
|
+
}
|
|
922
|
+
memberExpr(node) {
|
|
923
|
+
// luaparse usually gives . or : in node.indexer
|
|
924
|
+
const base = this.expr(node.base, 100); // force parens if non-primary
|
|
925
|
+
const id = this.expr(node.identifier);
|
|
926
|
+
const indexer = node.indexer || ".";
|
|
927
|
+
return `${base}${indexer}${id}`;
|
|
928
|
+
}
|
|
929
|
+
indexExpr(node) {
|
|
930
|
+
const base = this.expr(node.base, 100);
|
|
931
|
+
return `${base}[${this.expr(node.index)}]`;
|
|
932
|
+
}
|
|
933
|
+
callExpr(node) {
|
|
934
|
+
const base = this.expr(node.base, 100);
|
|
935
|
+
const args = node.arguments.map((a) => this.expr(a)).join(",");
|
|
936
|
+
return `${base}(${args})`;
|
|
937
|
+
}
|
|
938
|
+
tableCallExpr(node) {
|
|
939
|
+
// sugar: f{...} → f({ ... })
|
|
940
|
+
const base = this.expr(node.base, 100);
|
|
941
|
+
const arg = this.expr(node.arguments);
|
|
942
|
+
return `${base}(${arg})`;
|
|
943
|
+
}
|
|
944
|
+
stringCallExpr(node) {
|
|
945
|
+
// sugar: f"str" → f("str")
|
|
946
|
+
const base = this.expr(node.base, 100);
|
|
947
|
+
const arg = this.stringLiteral(node.argument);
|
|
948
|
+
return `${base}(${arg})`;
|
|
949
|
+
}
|
|
950
|
+
functionExpr(node) {
|
|
951
|
+
// function used as expression: "function(a,b) ... end"
|
|
952
|
+
const params = node.parameters.map((p) => this.expr(p)).join(",");
|
|
953
|
+
const bodyPrinter = new LuaPrinter(this.options, this.blockComments);
|
|
954
|
+
// reuse statement printer but avoid duplicating indent handling:
|
|
955
|
+
const innerChunk = {
|
|
956
|
+
type: "Chunk",
|
|
957
|
+
body: node.body,
|
|
958
|
+
comments: [],
|
|
959
|
+
//globals: [],
|
|
960
|
+
};
|
|
961
|
+
const bodyCode = bodyPrinter.print(innerChunk).trimEnd();
|
|
962
|
+
return `function(${params})\n${bodyCode}\nend`;
|
|
963
|
+
}
|
|
964
|
+
printComment(node) {
|
|
965
|
+
if (node.raw) {
|
|
966
|
+
this.emit(node.raw);
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
this.emit("--" + node.value);
|
|
970
|
+
}
|
|
971
|
+
this.newline();
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
exports.LuaPrinter = LuaPrinter;
|
|
975
|
+
function nodeRange(node) {
|
|
976
|
+
if (node && Array.isArray(node.range) && node.range.length > 1) {
|
|
977
|
+
return node.range;
|
|
978
|
+
}
|
|
979
|
+
return [0, Number.MAX_SAFE_INTEGER];
|
|
980
|
+
}
|
|
981
|
+
function rangeContains(outer, inner) {
|
|
982
|
+
return inner[0] >= outer[0] && inner[1] <= outer[1];
|
|
983
|
+
}
|
|
984
|
+
// Collect all statement blocks (function bodies, if/else bodies, loops, etc.)
|
|
985
|
+
function collectBlocksFromStatement(node, blocks) {
|
|
986
|
+
switch (node.type) {
|
|
987
|
+
case "FunctionDeclaration": {
|
|
988
|
+
const fn = node;
|
|
989
|
+
blocks.push({ body: fn.body, range: nodeRange(fn) });
|
|
990
|
+
fn.body.forEach((st) => collectBlocksFromStatement(st, blocks));
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
case "IfStatement": {
|
|
994
|
+
const ifs = node;
|
|
995
|
+
ifs.clauses.forEach((clause) => {
|
|
996
|
+
blocks.push({ body: clause.body, range: nodeRange(clause) });
|
|
997
|
+
clause.body.forEach((st) => collectBlocksFromStatement(st, blocks));
|
|
998
|
+
});
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
case "WhileStatement":
|
|
1002
|
+
case "RepeatStatement":
|
|
1003
|
+
case "ForNumericStatement":
|
|
1004
|
+
case "ForGenericStatement":
|
|
1005
|
+
case "DoStatement": {
|
|
1006
|
+
const body = node.body;
|
|
1007
|
+
blocks.push({ body, range: nodeRange(node) });
|
|
1008
|
+
body.forEach((st) => collectBlocksFromStatement(st, blocks));
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
default:
|
|
1012
|
+
break;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
function collectAllStatementBlocks(chunk) {
|
|
1016
|
+
const blocks = [
|
|
1017
|
+
{ body: chunk.body, range: nodeRange(chunk) },
|
|
1018
|
+
];
|
|
1019
|
+
for (const st of chunk.body) {
|
|
1020
|
+
collectBlocksFromStatement(st, blocks);
|
|
1021
|
+
}
|
|
1022
|
+
return blocks;
|
|
1023
|
+
}
|
|
1024
|
+
// Build a map from statement blocks to comments contained within them
|
|
1025
|
+
// why is this needed?
|
|
1026
|
+
// luaparse gives comments attached to the root chunk only, not to inner blocks
|
|
1027
|
+
// so we have to manually assign them to the correct blocks
|
|
1028
|
+
function buildCommentMap(ast) {
|
|
1029
|
+
const blocks = collectAllStatementBlocks(ast);
|
|
1030
|
+
const map = new Map();
|
|
1031
|
+
blocks.forEach((b) => map.set(b.body, []));
|
|
1032
|
+
const comments = ast.comments || [];
|
|
1033
|
+
for (const c of comments) {
|
|
1034
|
+
const cr = nodeRange(c);
|
|
1035
|
+
let target = blocks[0];
|
|
1036
|
+
for (const blk of blocks) {
|
|
1037
|
+
if (rangeContains(blk.range, cr)) {
|
|
1038
|
+
const widthCurrent = target ? target.range[1] - target.range[0] : Number.MAX_SAFE_INTEGER;
|
|
1039
|
+
const widthCandidate = blk.range[1] - blk.range[0];
|
|
1040
|
+
if (widthCandidate <= widthCurrent) {
|
|
1041
|
+
target = blk;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
const list = map.get(target.body) || [];
|
|
1046
|
+
list.push(c);
|
|
1047
|
+
map.set(target.body, list);
|
|
1048
|
+
}
|
|
1049
|
+
for (const [body, list] of map.entries()) {
|
|
1050
|
+
list.sort((a, b) => nodeRange(a)[0] - nodeRange(b)[0]);
|
|
1051
|
+
}
|
|
1052
|
+
return map;
|
|
1053
|
+
}
|
|
1054
|
+
// Generate Lua code from an AST
|
|
1055
|
+
function unparseLua(ast, ruleOptions) {
|
|
1056
|
+
const generator = new LuaPrinter(ruleOptions, buildCommentMap(ast));
|
|
1057
|
+
return generator.print(ast);
|
|
1058
|
+
}
|
|
1059
|
+
function parseLua(code) {
|
|
1060
|
+
//console.log(code);
|
|
1061
|
+
try {
|
|
1062
|
+
const ast = luaparse.parse(code, {
|
|
1063
|
+
luaVersion: "5.3", // TIC-80 is 5.3-ish
|
|
1064
|
+
comments: true,
|
|
1065
|
+
locations: true,
|
|
1066
|
+
ranges: true,
|
|
1067
|
+
});
|
|
1068
|
+
return ast;
|
|
1069
|
+
}
|
|
1070
|
+
catch (error) {
|
|
1071
|
+
console.error("Error parsing Lua code:", error);
|
|
1072
|
+
console.log("Lua code:\n", code);
|
|
1073
|
+
}
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
function processLua(code, ruleOptions) {
|
|
1077
|
+
// Apply optimization rules
|
|
1078
|
+
//const options = {...DEFAULT_OPTIMIZATION_RULES, ...ruleOptions};
|
|
1079
|
+
// Strip debug blocks and lines before parsing (line-based string matching)
|
|
1080
|
+
let processedCode = code;
|
|
1081
|
+
// if (ruleOptions.stripDebugBlocks) {
|
|
1082
|
+
// // Strip debug blocks
|
|
1083
|
+
// processedCode = replaceLuaBlock(processedCode, "-- BEGIN_DEBUG_ONLY", "-- END_DEBUG_ONLY", "");
|
|
1084
|
+
// // Strip individual lines marked with -- DEBUG_ONLY
|
|
1085
|
+
// const eol = processedCode.includes("\r\n") ? "\r\n" : "\n";
|
|
1086
|
+
// const lines = processedCode.split(eol);
|
|
1087
|
+
// const filteredLines = lines.filter(line => !line.includes("-- DEBUG_ONLY"));
|
|
1088
|
+
// processedCode = filteredLines.join(eol);
|
|
1089
|
+
// }
|
|
1090
|
+
// Honor explicit directives to keep certain regions verbatim
|
|
1091
|
+
// doing this at text level for simplification and because the printer can reformat everything.
|
|
1092
|
+
const disableMinify = (0, lua_fundamentals_1.extractLuaBlocks)(processedCode, "-- MINIFICATION OFF", "-- MINIFICATION ON", (i) => `__SOMATIC_DISABLED_MINIFICATION_BLOCK_${i}__()`, { strict: false });
|
|
1093
|
+
processedCode = disableMinify.code;
|
|
1094
|
+
let ast = parseLua(processedCode);
|
|
1095
|
+
if (!ast) {
|
|
1096
|
+
console.error("Failed to parse Lua code; returning original code.");
|
|
1097
|
+
return code;
|
|
1098
|
+
}
|
|
1099
|
+
//console.log("Parsed Lua AST:", ast);
|
|
1100
|
+
if (ruleOptions.stripComments) {
|
|
1101
|
+
ast.comments = [];
|
|
1102
|
+
}
|
|
1103
|
+
if (ruleOptions.simplifyExpressions) {
|
|
1104
|
+
ast = (0, lua_simplify_1.simplifyExpressionsInAST)(ast);
|
|
1105
|
+
}
|
|
1106
|
+
if (ruleOptions.removeUnusedLocals) {
|
|
1107
|
+
ast = (0, lua_remove_unused_locals_1.removeUnusedLocalsInAST)(ast);
|
|
1108
|
+
}
|
|
1109
|
+
if (ruleOptions.removeUnusedFunctions) {
|
|
1110
|
+
ast = (0, lua_remove_unused_functions_1.removeUnusedFunctionsInAST)(ast, {
|
|
1111
|
+
functionNamesToKeep: ruleOptions.functionNamesToKeep,
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
if (ruleOptions.aliasLiterals) {
|
|
1115
|
+
ast = (0, lua_alias_literals_1.aliasLiteralsInAST)(ast);
|
|
1116
|
+
}
|
|
1117
|
+
if (ruleOptions.aliasRepeatedExpressions) {
|
|
1118
|
+
ast = (0, lua_alias_expressions_1.aliasRepeatedExpressionsInAST)(ast);
|
|
1119
|
+
}
|
|
1120
|
+
if (ruleOptions.packLocalDeclarations) {
|
|
1121
|
+
ast = (0, lua_pack_locals_1.packLocalDeclarationsInAST)(ast);
|
|
1122
|
+
}
|
|
1123
|
+
if (ruleOptions.renameLocalVariables) {
|
|
1124
|
+
ast = (0, lua_renamer_1.renameLocalVariablesInAST)(ast);
|
|
1125
|
+
}
|
|
1126
|
+
if (ruleOptions.tableEntryKeysToRename && ruleOptions.tableEntryKeysToRename.length > 0) {
|
|
1127
|
+
ast = (0, lua_rename_allowed_table_keys_1.renameAllowedTableKeysInAST)(ast, ruleOptions.tableEntryKeysToRename);
|
|
1128
|
+
}
|
|
1129
|
+
if (ruleOptions.renameTableFields) {
|
|
1130
|
+
ast = (0, lua_rename_table_fields_1.renameTableFieldsInAST)(ast);
|
|
1131
|
+
}
|
|
1132
|
+
const minified = unparseLua(ast, ruleOptions);
|
|
1133
|
+
return reinsertDisableMinificationBlocks(minified, disableMinify.blocks);
|
|
1134
|
+
}
|
|
1135
|
+
// Escape special characters in a string for use in a RegExp
|
|
1136
|
+
function escapeRegExp(s) {
|
|
1137
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1138
|
+
}
|
|
1139
|
+
function reinsertDisableMinificationBlocks(src, blocks) {
|
|
1140
|
+
if (blocks.length === 0)
|
|
1141
|
+
return src;
|
|
1142
|
+
let out = src;
|
|
1143
|
+
for (const b of blocks) {
|
|
1144
|
+
// normalize line endings and trim trailing newlines from the block content
|
|
1145
|
+
const normalized = b.content.replace(/\r?\n/g, "\n").replace(/\n+$/g, "");
|
|
1146
|
+
const replacement = `\n${normalized}\n`;
|
|
1147
|
+
// remove surrounding whitespace introduced by tight packing.
|
|
1148
|
+
const re = new RegExp(`[\\t ]*${escapeRegExp(b.placeholder)}[\\t ]*`, "g");
|
|
1149
|
+
out = out.replace(re, replacement);
|
|
1150
|
+
}
|
|
1151
|
+
return out;
|
|
1152
|
+
}
|
|
1153
|
+
//# sourceMappingURL=lua_processor.js.map
|