cluaupp 0.1.4 → 0.2.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/CHANGELOG.md +21 -0
- package/README.md +12 -7
- package/bin/cluau.js +1 -1
- package/bin/cluaupp.js +1 -1
- package/docs/README.md +1 -1
- package/docs/architecture.md +52 -77
- package/docs/cli.md +29 -9
- package/docs/comparison.md +3 -3
- package/docs/config.md +6 -6
- package/docs/cpp-organization.md +2 -2
- package/docs/examples/index.md +2 -0
- package/docs/getting-started.md +7 -5
- package/docs/intellisense.md +49 -31
- package/docs/intro.md +2 -2
- package/docs/oop/file-tags.md +16 -17
- package/docs/oop/index.md +2 -2
- package/docs/oop/modules.md +3 -1
- package/docs/oop/services.md +7 -14
- package/docs/syntax.md +6 -5
- package/editors/vscode/extension.js +97 -146
- package/editors/vscode/package.json +6 -6
- package/examples/README.md +18 -0
- package/examples/game/.clangd +25 -0
- package/examples/game/.vscode/c_cpp_properties.json +27 -0
- package/examples/game/.vscode/extensions.json +5 -0
- package/examples/game/.vscode/settings.json +27 -0
- package/examples/game/Packages/.gitkeep +0 -0
- package/examples/game/cluaupp.config.json +6 -0
- package/examples/game/compile_flags.txt +6 -0
- package/examples/game/default.project.json +39 -0
- package/examples/game/package.json +9 -0
- package/examples/game/rokit.toml +5 -0
- package/examples/game/src/client/hud.client.cpp +12 -0
- package/{src → examples/game/src}/client/init.client.cpp +1 -0
- package/examples/game/src/server/combat.server.cpp +23 -0
- package/{src → examples/game/src}/server/leaderstats.server.cpp +1 -0
- package/examples/game/wally.toml +11 -0
- package/generated/api.js +51 -0
- package/generated/architecture.js +473 -0
- package/generated/ast.js +2 -0
- package/generated/cli.js +191 -0
- package/generated/compile.js +115 -0
- package/generated/editor-install.js +170 -0
- package/generated/emit.js +503 -0
- package/generated/emitter/luau-codegen.js +167 -0
- package/generated/emitter/translators.js +164 -0
- package/generated/headers.js +220 -0
- package/generated/index.html +49 -0
- package/generated/intellisense.js +277 -0
- package/generated/layout.js +112 -0
- package/generated/lex.js +146 -0
- package/generated/libs.js +484 -0
- package/generated/lsp.js +55 -0
- package/generated/package-info.js +11 -0
- package/generated/parse.js +607 -0
- package/generated/parser/collector.js +100 -0
- package/generated/parser/index.js +30 -0
- package/generated/preprocess.js +181 -0
- package/generated/system-understander.js +443 -0
- package/generated/transpile.js +66 -0
- package/generated/types.js +2 -0
- package/generated/understand.js +298 -0
- package/generated/utils/process-orchestrator.js +63 -0
- package/generated/utils/project.js +491 -0
- package/generated/utils/rojo-mapper.js +181 -0
- package/generated/utils/safe-paths.js +104 -0
- package/package.json +25 -8
- package/src/api.ts +53 -0
- package/src/{architecture.js → architecture.ts} +80 -33
- package/src/ast.ts +37 -0
- package/src/cli.ts +214 -0
- package/src/compile.ts +118 -0
- package/src/editor-install.ts +182 -0
- package/src/{emit.js → emit.ts} +5 -6
- package/src/emitter/luau-codegen.ts +187 -0
- package/src/emitter/translators.ts +168 -0
- package/src/headers.ts +233 -0
- package/src/intellisense.ts +286 -0
- package/src/{layout.js → layout.ts} +114 -129
- package/src/{lex.js → lex.ts} +4 -6
- package/src/{libs.js → libs.ts} +119 -46
- package/src/lsp.ts +60 -0
- package/src/package-info.ts +7 -0
- package/src/{parse.js → parse.ts} +3 -4
- package/src/parser/collector.ts +115 -0
- package/src/parser/index.ts +27 -0
- package/src/{preprocess.js → preprocess.ts} +64 -32
- package/src/system-understander.ts +501 -0
- package/src/transpile.ts +64 -0
- package/src/tree-sitter-cpp.d.ts +4 -0
- package/src/types.ts +81 -0
- package/src/{understand.js → understand.ts} +24 -213
- package/src/utils/process-orchestrator.ts +72 -0
- package/src/utils/project.ts +506 -0
- package/src/utils/rojo-mapper.ts +190 -0
- package/src/utils/safe-paths.ts +98 -0
- package/templates/game/.clangd +9 -0
- package/templates/game/.vscode/c_cpp_properties.json +1 -1
- package/templates/game/.vscode/extensions.json +5 -6
- package/templates/game/.vscode/settings.json +7 -6
- package/templates/game/cluaupp.config.json +2 -2
- package/templates/game/compile_flags.txt +1 -0
- package/templates/game/rokit.toml +5 -0
- package/templates/game/src/client/init.client.cpp +1 -0
- package/templates/game/src/server/leaderstats.server.cpp +1 -0
- package/src/api.js +0 -57
- package/src/cli.js +0 -481
- package/src/compile.js +0 -56
- package/src/editor-install.js +0 -218
- package/src/intellisense.js +0 -1368
- package/src/lsp.js +0 -227
- /package/{src → examples/game/src}/shared/config.cpp +0 -0
- /package/{src → examples/game/src}/shared/config.h +0 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.intelliSenseMode = intelliSenseMode;
|
|
7
|
+
exports.clangPath = clangPath;
|
|
8
|
+
exports.writeCompileCommands = writeCompileCommands;
|
|
9
|
+
exports.writeClangd = writeClangd;
|
|
10
|
+
exports.diagnosticsFor = diagnosticsFor;
|
|
11
|
+
exports.syncEditorSupport = syncEditorSupport;
|
|
12
|
+
exports.installEditorExtension = installEditorExtension;
|
|
13
|
+
exports.installEditorSupport = installEditorSupport;
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
16
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const parse_js_1 = require("./parse.js");
|
|
18
|
+
const preprocess_js_1 = require("./preprocess.js");
|
|
19
|
+
const editor_install_js_1 = require("./editor-install.js");
|
|
20
|
+
const package_info_js_1 = require("./package-info.js");
|
|
21
|
+
function posix(file) {
|
|
22
|
+
return String(file).replace(/\\/g, "/");
|
|
23
|
+
}
|
|
24
|
+
function collectFiles(dir, files = []) {
|
|
25
|
+
if (!node_fs_1.default.existsSync(dir)) {
|
|
26
|
+
return files;
|
|
27
|
+
}
|
|
28
|
+
for (const entry of node_fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
29
|
+
const full = node_path_1.default.join(dir, entry.name);
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
collectFiles(full, files);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
files.push(full);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return files;
|
|
38
|
+
}
|
|
39
|
+
function isCppFile(file) {
|
|
40
|
+
return /\.(cpp|cc|cxx|c|h|hpp|hh)$/i.test(file);
|
|
41
|
+
}
|
|
42
|
+
function clangCompileArgs(root) {
|
|
43
|
+
const absRoot = posix(node_path_1.default.resolve(root));
|
|
44
|
+
const absInclude = posix(node_path_1.default.join(absRoot, "include"));
|
|
45
|
+
const absSrc = posix(node_path_1.default.join(absRoot, "src"));
|
|
46
|
+
const roblox = posix(node_path_1.default.join(absInclude, "cluaupp", "roblox.hpp"));
|
|
47
|
+
return [
|
|
48
|
+
"-xc++",
|
|
49
|
+
"-std=c++20",
|
|
50
|
+
"-ferror-limit=0",
|
|
51
|
+
"-I" + absInclude,
|
|
52
|
+
"-I" + absSrc,
|
|
53
|
+
"-Iinclude",
|
|
54
|
+
"-Isrc",
|
|
55
|
+
"-include",
|
|
56
|
+
roblox,
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
function compileCommandEntry(root, file) {
|
|
60
|
+
const absRoot = posix(node_path_1.default.resolve(root));
|
|
61
|
+
const absFile = posix(node_path_1.default.resolve(file));
|
|
62
|
+
return {
|
|
63
|
+
directory: absRoot,
|
|
64
|
+
file: absFile,
|
|
65
|
+
arguments: [clangPath(), ...clangCompileArgs(root), "-c", absFile],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function mergeJson(file, patch) {
|
|
69
|
+
let current = {};
|
|
70
|
+
if (node_fs_1.default.existsSync(file)) {
|
|
71
|
+
try {
|
|
72
|
+
current = JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
current = {};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const next = { ...current, ...patch };
|
|
79
|
+
for (const key of Object.keys(patch)) {
|
|
80
|
+
const value = patch[key];
|
|
81
|
+
const existing = current[key];
|
|
82
|
+
if (value && typeof value === "object" && !Array.isArray(value) && existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
83
|
+
next[key] = { ...existing, ...value };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const json = `${JSON.stringify(next, null, "\t")}\n`;
|
|
87
|
+
if (node_fs_1.default.existsSync(file) && node_fs_1.default.readFileSync(file, "utf8") === json) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(file), { recursive: true });
|
|
91
|
+
node_fs_1.default.writeFileSync(file, json, "utf8");
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
function copyDir(from, to) {
|
|
95
|
+
node_fs_1.default.mkdirSync(to, { recursive: true });
|
|
96
|
+
for (const entry of node_fs_1.default.readdirSync(from, { withFileTypes: true })) {
|
|
97
|
+
const src = node_path_1.default.join(from, entry.name);
|
|
98
|
+
const dest = node_path_1.default.join(to, entry.name);
|
|
99
|
+
if (entry.isDirectory()) {
|
|
100
|
+
copyDir(src, dest);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
node_fs_1.default.copyFileSync(src, dest);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function clangdEditorArgs() {
|
|
108
|
+
return [
|
|
109
|
+
"--compile-commands-dir=${workspaceFolder}",
|
|
110
|
+
"--header-insertion=never",
|
|
111
|
+
"--query-driver=**/clang++*,**/clang++.exe,**/g++*,**/g++.exe",
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
function intelliSenseMode() {
|
|
115
|
+
const arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
116
|
+
if (process.platform === "win32") {
|
|
117
|
+
return `windows-clang-${arch}`;
|
|
118
|
+
}
|
|
119
|
+
if (process.platform === "darwin") {
|
|
120
|
+
return `macos-clang-${arch}`;
|
|
121
|
+
}
|
|
122
|
+
return `linux-clang-${arch}`;
|
|
123
|
+
}
|
|
124
|
+
function clangPath() {
|
|
125
|
+
return (0, editor_install_js_1.findClangPlusPlus)() || "clang++";
|
|
126
|
+
}
|
|
127
|
+
function writeCompileCommands(root, srcDir) {
|
|
128
|
+
const files = collectFiles(srcDir).filter((file) => isCppFile(file)).sort();
|
|
129
|
+
const json = `${JSON.stringify(files.map((file) => compileCommandEntry(root, file)), null, "\t")}\n`;
|
|
130
|
+
const dest = node_path_1.default.join(root, "compile_commands.json");
|
|
131
|
+
if (node_fs_1.default.existsSync(dest) && node_fs_1.default.readFileSync(dest, "utf8") === json) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
node_fs_1.default.writeFileSync(dest, json, "utf8");
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
function writeClangd(root) {
|
|
138
|
+
const flags = clangCompileArgs(root)
|
|
139
|
+
.map((flag) => ` - ${flag}`)
|
|
140
|
+
.join("\n");
|
|
141
|
+
const contents = `CompileFlags:
|
|
142
|
+
CompilationDatabase: .
|
|
143
|
+
Add:
|
|
144
|
+
${flags}
|
|
145
|
+
|
|
146
|
+
Diagnostics:
|
|
147
|
+
Suppress: '*'
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
If:
|
|
151
|
+
PathMatch: .*\\.(cpp|cc|cxx|c|h|hpp|hh)$
|
|
152
|
+
CompileFlags:
|
|
153
|
+
Add:
|
|
154
|
+
- -xc++
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
If:
|
|
158
|
+
PathMatch: (out|libs)/.*
|
|
159
|
+
Index:
|
|
160
|
+
Background: Skip
|
|
161
|
+
`;
|
|
162
|
+
const dest = node_path_1.default.join(root, ".clangd");
|
|
163
|
+
if (node_fs_1.default.existsSync(dest) && node_fs_1.default.readFileSync(dest, "utf8") === contents) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
node_fs_1.default.writeFileSync(dest, contents, "utf8");
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
function writeVscode(root) {
|
|
170
|
+
const settings = node_path_1.default.join(root, ".vscode", "settings.json");
|
|
171
|
+
mergeJson(settings, {
|
|
172
|
+
"C_Cpp.intelliSenseEngine": "Disabled",
|
|
173
|
+
"C_Cpp.default.cppStandard": "c++20",
|
|
174
|
+
"C_Cpp.default.cStandard": "c17",
|
|
175
|
+
"C_Cpp.default.compilerPath": clangPath(),
|
|
176
|
+
"C_Cpp.default.intelliSenseMode": intelliSenseMode(),
|
|
177
|
+
"C_Cpp.default.includePath": ["${workspaceFolder}/include", "${workspaceFolder}/src"],
|
|
178
|
+
"clangd.enable": true,
|
|
179
|
+
"clangd.arguments": clangdEditorArgs(),
|
|
180
|
+
"files.associations": {
|
|
181
|
+
"*.hpp": "cpp",
|
|
182
|
+
"*.h": "cpp",
|
|
183
|
+
"*.server.cpp": "cpp",
|
|
184
|
+
"*.client.cpp": "cpp",
|
|
185
|
+
"*.plugin.cpp": "cpp",
|
|
186
|
+
"*.legacy.cpp": "cpp",
|
|
187
|
+
"*.legacy.server.cpp": "cpp",
|
|
188
|
+
"*.legacy.client.cpp": "cpp",
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
mergeJson(node_path_1.default.join(root, ".vscode", "extensions.json"), {
|
|
192
|
+
recommendations: ["llvm-vs-code-extensions.vscode-clangd"],
|
|
193
|
+
});
|
|
194
|
+
const props = node_path_1.default.join(root, ".vscode", "c_cpp_properties.json");
|
|
195
|
+
const nextProps = {
|
|
196
|
+
configurations: [
|
|
197
|
+
{
|
|
198
|
+
name: "Cluaupp",
|
|
199
|
+
compilerPath: clangPath(),
|
|
200
|
+
cStandard: "c17",
|
|
201
|
+
cppStandard: "c++20",
|
|
202
|
+
intelliSenseMode: intelliSenseMode(),
|
|
203
|
+
includePath: ["${workspaceFolder}/include", "${workspaceFolder}/src"],
|
|
204
|
+
forcedInclude: ["${workspaceFolder}/include/cluaupp/roblox.hpp"],
|
|
205
|
+
compileCommands: "${workspaceFolder}/compile_commands.json",
|
|
206
|
+
browse: {
|
|
207
|
+
path: ["${workspaceFolder}/include", "${workspaceFolder}/src"],
|
|
208
|
+
limitSymbolsToIncludedHeaders: true,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
version: 4,
|
|
213
|
+
};
|
|
214
|
+
const json = `${JSON.stringify(nextProps, null, "\t")}\n`;
|
|
215
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(props), { recursive: true });
|
|
216
|
+
if (!node_fs_1.default.existsSync(props) || node_fs_1.default.readFileSync(props, "utf8") !== json) {
|
|
217
|
+
node_fs_1.default.writeFileSync(props, json, "utf8");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function diagnosticsFor(source, fileName, options = {}) {
|
|
221
|
+
try {
|
|
222
|
+
const prepared = options.filePath ? (0, preprocess_js_1.preprocess)(source, options.filePath, options) : source;
|
|
223
|
+
(0, parse_js_1.parse)(prepared, fileName || "input.cpp");
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
const error = err;
|
|
228
|
+
const message = error.message ? String(error.message) : "parse error";
|
|
229
|
+
const match = message.match(/:(\d+):(\d+):\s*(.*)$/);
|
|
230
|
+
if (match) {
|
|
231
|
+
return [{ line: Number(match[1]), col: Number(match[2]), message: match[3], severity: "error" }];
|
|
232
|
+
}
|
|
233
|
+
return [{ line: error.line || 1, col: error.col || 1, message, severity: "error" }];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function syncEditorSupport(root, config = {}) {
|
|
237
|
+
const srcDir = node_path_1.default.join(root, config.rootDir || "src");
|
|
238
|
+
if (node_fs_1.default.existsSync(srcDir)) {
|
|
239
|
+
writeCompileCommands(root, srcDir);
|
|
240
|
+
}
|
|
241
|
+
writeClangd(root);
|
|
242
|
+
writeVscode(root);
|
|
243
|
+
const flags = ["-xc++", "-std=c++20", "-ferror-limit=0", "-Iinclude", "-Isrc", "-include", "include/cluaupp/roblox.hpp"].join("\n") + "\n";
|
|
244
|
+
const flagsFile = node_path_1.default.join(root, "compile_flags.txt");
|
|
245
|
+
if (!node_fs_1.default.existsSync(flagsFile) || node_fs_1.default.readFileSync(flagsFile, "utf8") !== flags) {
|
|
246
|
+
node_fs_1.default.writeFileSync(flagsFile, flags, "utf8");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function installEditorExtension(cluauppRoot = package_info_js_1.projectRoot) {
|
|
250
|
+
const from = node_path_1.default.join(cluauppRoot, "editors", "vscode");
|
|
251
|
+
if (!node_fs_1.default.existsSync(from)) {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
const id = `kartzdev.cluaupp-diagnostics-${package_info_js_1.pkg.version}`;
|
|
255
|
+
const homes = [node_path_1.default.join(node_os_1.default.homedir(), ".cursor", "extensions"), node_path_1.default.join(node_os_1.default.homedir(), ".vscode", "extensions")];
|
|
256
|
+
const installed = [];
|
|
257
|
+
for (const home of homes) {
|
|
258
|
+
if (!node_fs_1.default.existsSync(node_path_1.default.dirname(home))) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
node_fs_1.default.mkdirSync(home, { recursive: true });
|
|
262
|
+
const dest = node_path_1.default.join(home, id);
|
|
263
|
+
copyDir(from, dest);
|
|
264
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(dest, "cluaupp.root"), node_path_1.default.resolve(cluauppRoot), "utf8");
|
|
265
|
+
installed.push(dest);
|
|
266
|
+
}
|
|
267
|
+
return installed;
|
|
268
|
+
}
|
|
269
|
+
async function installEditorSupport(cluauppRoot = package_info_js_1.projectRoot) {
|
|
270
|
+
const local = installEditorExtension(cluauppRoot);
|
|
271
|
+
const llvm = (0, editor_install_js_1.ensureLlvm)();
|
|
272
|
+
(0, editor_install_js_1.reportInstall)(llvm, "LLVM clang++");
|
|
273
|
+
const clangd = await (0, editor_install_js_1.installMarketplaceExtension)(editor_install_js_1.CLANGD_ID, "clangd (LLVM)");
|
|
274
|
+
(0, editor_install_js_1.reportInstall)(clangd, "clangd");
|
|
275
|
+
console.log("cluaupp: C++ completion is clangd — reload the editor (Ctrl+Shift+P → Developer: Reload Window)");
|
|
276
|
+
return { local, llvm, clangd };
|
|
277
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ENTRY_FN = exports.PRINCIPAL_FN = exports.CLEANUP_FN = exports.SECTION = void 0;
|
|
4
|
+
exports.isJanitorDecl = isJanitorDecl;
|
|
5
|
+
exports.isApiDecl = isApiDecl;
|
|
6
|
+
exports.classifyDecl = classifyDecl;
|
|
7
|
+
exports.organizeDecls = organizeDecls;
|
|
8
|
+
exports.janitorNames = janitorNames;
|
|
9
|
+
exports.emitSection = emitSection;
|
|
10
|
+
exports.joinBlocks = joinBlocks;
|
|
11
|
+
exports.commentLine = commentLine;
|
|
12
|
+
exports.SECTION = {
|
|
13
|
+
api: "API",
|
|
14
|
+
constants: "CONSTANTS",
|
|
15
|
+
variables: "VARIABLES",
|
|
16
|
+
types: "TYPES",
|
|
17
|
+
support: "HELPERS FUNCTIONS",
|
|
18
|
+
principal: "MAIN FUNCTIONS",
|
|
19
|
+
cleanup: "JANITOR",
|
|
20
|
+
returns: "RETURN",
|
|
21
|
+
};
|
|
22
|
+
exports.CLEANUP_FN = /^(OnClose|OnPlayerRemoving|Cleanup|Shutdown|OnDestroy)$/i;
|
|
23
|
+
exports.PRINCIPAL_FN = /^(init|start|main|setup)/i;
|
|
24
|
+
exports.ENTRY_FN = /^(init|main)$/i;
|
|
25
|
+
function isGetService(node) {
|
|
26
|
+
return Boolean(node && node.type === "getService");
|
|
27
|
+
}
|
|
28
|
+
function isDataServiceAlias(node) {
|
|
29
|
+
let current = node || undefined;
|
|
30
|
+
while (current && current.type === "member") {
|
|
31
|
+
if (current.object && current.object.type === "ident" && current.object.name === "DataService") {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
current = current.object;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
function isJanitorDecl(decl) {
|
|
39
|
+
if (!decl || decl.type !== "decl") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const name = String(decl.name || "").toLowerCase();
|
|
43
|
+
const typeName = String(decl.valueType || "").toLowerCase();
|
|
44
|
+
const created = decl.value && decl.value.type === "new" && decl.value.className === "Janitor";
|
|
45
|
+
return name.includes("janitor") || typeName.includes("janitor") || created;
|
|
46
|
+
}
|
|
47
|
+
function isApiDecl(decl) {
|
|
48
|
+
if (!decl || decl.type !== "decl") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return isGetService(decl.value) || isDataServiceAlias(decl.value);
|
|
52
|
+
}
|
|
53
|
+
function classifyDecl(decl) {
|
|
54
|
+
if (!decl || decl.type === "proto") {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (decl.type === "decl") {
|
|
58
|
+
if (isApiDecl(decl)) {
|
|
59
|
+
return "api";
|
|
60
|
+
}
|
|
61
|
+
if (isJanitorDecl(decl)) {
|
|
62
|
+
return "variables";
|
|
63
|
+
}
|
|
64
|
+
if (decl.isConst) {
|
|
65
|
+
return "constants";
|
|
66
|
+
}
|
|
67
|
+
return "variables";
|
|
68
|
+
}
|
|
69
|
+
if (decl.type === "function") {
|
|
70
|
+
if (exports.CLEANUP_FN.test(decl.name || "")) {
|
|
71
|
+
return "cleanup";
|
|
72
|
+
}
|
|
73
|
+
if (exports.PRINCIPAL_FN.test(decl.name || "")) {
|
|
74
|
+
return "principal";
|
|
75
|
+
}
|
|
76
|
+
return "support";
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function organizeDecls(keep) {
|
|
81
|
+
const groups = {
|
|
82
|
+
api: [],
|
|
83
|
+
constants: [],
|
|
84
|
+
variables: [],
|
|
85
|
+
support: [],
|
|
86
|
+
principal: [],
|
|
87
|
+
cleanup: [],
|
|
88
|
+
};
|
|
89
|
+
for (const decl of keep) {
|
|
90
|
+
const bucket = classifyDecl(decl);
|
|
91
|
+
if (bucket && groups[bucket]) {
|
|
92
|
+
groups[bucket].push(decl);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return groups;
|
|
96
|
+
}
|
|
97
|
+
function janitorNames(keep) {
|
|
98
|
+
return (keep || []).filter(isJanitorDecl).map((decl) => decl.name);
|
|
99
|
+
}
|
|
100
|
+
function emitSection(_title, body) {
|
|
101
|
+
const text = String(body || "").trimEnd();
|
|
102
|
+
if (!text) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
return `${text}\n\n`;
|
|
106
|
+
}
|
|
107
|
+
function joinBlocks(parts) {
|
|
108
|
+
return parts.filter((part) => Boolean(part && String(part).trim())).join("\n\n");
|
|
109
|
+
}
|
|
110
|
+
function commentLine(title) {
|
|
111
|
+
return `-- ${title}`;
|
|
112
|
+
}
|
package/generated/lex.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tokenize = tokenize;
|
|
4
|
+
const KEYWORDS = new Set([
|
|
5
|
+
"if",
|
|
6
|
+
"else",
|
|
7
|
+
"for",
|
|
8
|
+
"while",
|
|
9
|
+
"return",
|
|
10
|
+
"new",
|
|
11
|
+
"auto",
|
|
12
|
+
"const",
|
|
13
|
+
"void",
|
|
14
|
+
"int",
|
|
15
|
+
"bool",
|
|
16
|
+
"float",
|
|
17
|
+
"double",
|
|
18
|
+
"true",
|
|
19
|
+
"false",
|
|
20
|
+
"nullptr",
|
|
21
|
+
"class",
|
|
22
|
+
"struct",
|
|
23
|
+
"public",
|
|
24
|
+
"private",
|
|
25
|
+
"protected",
|
|
26
|
+
"namespace",
|
|
27
|
+
"using",
|
|
28
|
+
"template",
|
|
29
|
+
"typedef",
|
|
30
|
+
"extern",
|
|
31
|
+
"enum",
|
|
32
|
+
"switch",
|
|
33
|
+
"case",
|
|
34
|
+
"default",
|
|
35
|
+
"break",
|
|
36
|
+
]);
|
|
37
|
+
function tokenize(source) {
|
|
38
|
+
const tokens = [];
|
|
39
|
+
let i = 0;
|
|
40
|
+
let line = 1;
|
|
41
|
+
let col = 1;
|
|
42
|
+
const push = (type, value, startLine, startCol, start, end) => {
|
|
43
|
+
tokens.push({ type, value, line: startLine, col: startCol, start, end });
|
|
44
|
+
};
|
|
45
|
+
while (i < source.length) {
|
|
46
|
+
const c = source[i];
|
|
47
|
+
if (c === "\n") {
|
|
48
|
+
i += 1;
|
|
49
|
+
line += 1;
|
|
50
|
+
col = 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (c === " " || c === "\t" || c === "\r") {
|
|
54
|
+
i += 1;
|
|
55
|
+
col += 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (c === "#") {
|
|
59
|
+
while (i < source.length && source[i] !== "\n") {
|
|
60
|
+
i += 1;
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (c === "/" && source[i + 1] === "/") {
|
|
65
|
+
while (i < source.length && source[i] !== "\n") {
|
|
66
|
+
i += 1;
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (c === "/" && source[i + 1] === "*") {
|
|
71
|
+
i += 2;
|
|
72
|
+
col += 2;
|
|
73
|
+
while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) {
|
|
74
|
+
if (source[i] === "\n") {
|
|
75
|
+
line += 1;
|
|
76
|
+
col = 1;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
col += 1;
|
|
80
|
+
}
|
|
81
|
+
i += 1;
|
|
82
|
+
}
|
|
83
|
+
i += 2;
|
|
84
|
+
col += 2;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const startLine = line;
|
|
88
|
+
const startCol = col;
|
|
89
|
+
if (c === '"') {
|
|
90
|
+
const start = i;
|
|
91
|
+
i += 1;
|
|
92
|
+
col += 1;
|
|
93
|
+
let value = "";
|
|
94
|
+
while (i < source.length && source[i] !== '"') {
|
|
95
|
+
if (source[i] === "\\" && i + 1 < source.length) {
|
|
96
|
+
value += source[i] + source[i + 1];
|
|
97
|
+
i += 2;
|
|
98
|
+
col += 2;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
value += source[i];
|
|
102
|
+
i += 1;
|
|
103
|
+
col += 1;
|
|
104
|
+
}
|
|
105
|
+
i += 1;
|
|
106
|
+
col += 1;
|
|
107
|
+
push("string", value, startLine, startCol, start, i);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (/[0-9]/.test(c)) {
|
|
111
|
+
const start = i;
|
|
112
|
+
let value = "";
|
|
113
|
+
while (i < source.length && /[0-9.]/.test(source[i])) {
|
|
114
|
+
value += source[i];
|
|
115
|
+
i += 1;
|
|
116
|
+
col += 1;
|
|
117
|
+
}
|
|
118
|
+
push("number", value, startLine, startCol, start, i);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (/[A-Za-z_]/.test(c)) {
|
|
122
|
+
const start = i;
|
|
123
|
+
let value = "";
|
|
124
|
+
while (i < source.length && /[A-Za-z0-9_]/.test(source[i])) {
|
|
125
|
+
value += source[i];
|
|
126
|
+
i += 1;
|
|
127
|
+
col += 1;
|
|
128
|
+
}
|
|
129
|
+
push(KEYWORDS.has(value) ? "kw" : "ident", value, startLine, startCol, start, i);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const two = source.slice(i, i + 2);
|
|
133
|
+
const start = i;
|
|
134
|
+
if (["->", "==", "!=", "<=", ">=", "&&", "||", "::", "<<", ">>"].includes(two)) {
|
|
135
|
+
push("op", two, startLine, startCol, start, i + 2);
|
|
136
|
+
i += 2;
|
|
137
|
+
col += 2;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
push("op", c, startLine, startCol, start, i + 1);
|
|
141
|
+
i += 1;
|
|
142
|
+
col += 1;
|
|
143
|
+
}
|
|
144
|
+
push("eof", "", line, col, source.length, source.length);
|
|
145
|
+
return tokens;
|
|
146
|
+
}
|