cluaupp 0.2.2 → 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/CHANGELOG.md +14 -75
- package/README.md +42 -88
- package/docs/README.md +25 -21
- package/docs/architecture.md +13 -76
- package/docs/cli.md +12 -64
- package/docs/comparison.md +6 -24
- package/docs/config.md +6 -7
- package/docs/cpp-advanced.md +6 -3
- package/docs/cpp-types.md +2 -0
- package/docs/examples/combat.md +19 -227
- package/docs/examples/hud.md +13 -81
- package/docs/examples/index.md +9 -16
- package/docs/examples/leaderstats.md +44 -115
- package/docs/getting-started.md +20 -135
- package/docs/intellisense.md +5 -42
- package/docs/intro.md +16 -15
- package/docs/libraries/dataservice.md +4 -1
- package/docs/libraries/index.md +2 -1
- package/docs/libraries/more.md +3 -1
- package/docs/libraries/ui.md +76 -0
- package/docs/migration.md +38 -0
- package/docs/oop/file-tags.md +12 -36
- package/docs/oop/index.md +18 -11
- package/docs/roblox-api.md +4 -56
- package/docs/syntax.md +54 -179
- package/editors/vscode/extension.js +1 -1
- package/editors/vscode/package.json +4 -4
- package/examples/README.md +5 -7
- package/examples/game/.vscode/extensions.json +2 -2
- package/examples/game/.vscode/settings.json +6 -23
- package/examples/game/src/client/hud.client.clpp +54 -0
- package/examples/game/src/client/init.client.clpp +6 -0
- package/examples/game/src/server/combat.server.clpp +85 -0
- package/examples/game/src/server/leaderstats.server.clpp +28 -0
- package/examples/game/src/shared/PlayerData.clh +20 -0
- package/examples/game/src/shared/config.clp +6 -0
- package/examples/game/src/shared/features.clp +88 -0
- package/generated/api.js +15 -1
- package/generated/cli.js +40 -24
- package/generated/clpp/contract.js +5 -0
- package/generated/clpp/index.js +27 -0
- package/generated/clpp/paths.js +121 -0
- package/generated/clpp/postprocess.js +78 -0
- package/generated/clpp/runner.js +102 -0
- package/generated/compile.js +26 -138
- package/generated/emit.js +79 -3
- package/generated/intellisense.js +83 -207
- package/generated/lex.js +3 -0
- package/generated/libs.js +1 -1
- package/generated/lsp.js +1 -8
- package/generated/parse.js +119 -24
- package/generated/preprocess.js +8 -179
- package/generated/system-understander.js +1 -1
- package/generated/transpile.js +3 -50
- package/generated/utils/project.js +13 -28
- package/include/{cluaupp/datatypes.hpp → clpp/datatypes.clh} +5 -1
- package/include/{cluaupp/generated/instances.hpp → clpp/generated/instances.clh} +1 -1
- package/include/{cluaupp/libs/chrono.hpp → clpp/libs/chrono.clh} +9 -9
- package/include/{cluaupp/libs/cmdr.hpp → clpp/libs/cmdr.clh} +4 -4
- package/include/{cluaupp/libs/dataservice.hpp → clpp/libs/dataservice.clh} +8 -15
- package/include/{cluaupp/libs/display.hpp → clpp/libs/display.clh} +1 -2
- package/include/{cluaupp/libs/ezvisual.hpp → clpp/libs/ezvisual.clh} +1 -3
- package/include/{cluaupp/libs/formatnumber.hpp → clpp/libs/formatnumber.clh} +2 -3
- package/include/{cluaupp/libs/fusion.hpp → clpp/libs/fusion.clh} +5 -5
- package/include/{cluaupp/libs/iris.hpp → clpp/libs/iris.clh} +2 -2
- package/include/{cluaupp/libs/janitor.hpp → clpp/libs/janitor.clh} +1 -2
- package/include/{cluaupp/libs/module3d.hpp → clpp/libs/module3d.clh} +2 -4
- package/include/{cluaupp/libs/net.hpp → clpp/libs/net.clh} +2 -4
- package/include/{cluaupp/libs/promise.hpp → clpp/libs/promise.clh} +1 -4
- package/include/{cluaupp/libs/spring.hpp → clpp/libs/spring.clh} +1 -2
- package/include/{cluaupp/libs/statemachine.hpp → clpp/libs/statemachine.clh} +2 -3
- package/include/{cluaupp/libs/stickybillboard.hpp → clpp/libs/stickybillboard.clh} +1 -2
- package/include/{cluaupp/libs/topbarplus.hpp → clpp/libs/topbarplus.clh} +3 -4
- package/include/clpp/libs.clh +24 -0
- package/include/clpp/roblox.clh +31 -0
- package/package.json +20 -16
- package/src/api.ts +15 -1
- package/src/cli.ts +39 -25
- package/src/clpp/contract.ts +39 -0
- package/src/clpp/index.ts +18 -0
- package/src/clpp/paths.ts +117 -0
- package/src/clpp/postprocess.ts +93 -0
- package/src/clpp/runner.ts +102 -0
- package/src/compile.ts +26 -149
- package/src/intellisense.ts +82 -211
- package/src/libs.ts +1 -1
- package/src/lsp.ts +1 -5
- package/src/preprocess.ts +8 -180
- package/src/system-understander.ts +1 -1
- package/src/transpile.ts +9 -52
- package/src/utils/project.ts +12 -28
- package/templates/game/.vscode/extensions.json +2 -2
- package/templates/game/.vscode/settings.json +6 -23
- package/templates/game/src/client/init.client.clpp +6 -0
- package/templates/game/src/server/leaderstats.server.clpp +29 -0
- package/templates/game/src/shared/config.clp +6 -0
- package/examples/game/.clangd +0 -25
- package/examples/game/.vscode/c_cpp_properties.json +0 -27
- package/examples/game/compile_flags.txt +0 -6
- package/examples/game/src/client/hud.client.cpp +0 -12
- package/examples/game/src/client/init.client.cpp +0 -6
- package/examples/game/src/server/combat.server.cpp +0 -23
- package/examples/game/src/server/leaderstats.server.cpp +0 -29
- package/examples/game/src/shared/config.cpp +0 -5
- package/examples/game/src/shared/config.h +0 -5
- package/include/cluaupp/libs.hpp +0 -25
- package/include/cluaupp/roblox.hpp +0 -47
- package/src/architecture.ts +0 -500
- package/src/ast.ts +0 -37
- package/src/emit.ts +0 -531
- package/src/emitter/luau-codegen.ts +0 -187
- package/src/emitter/translators.ts +0 -168
- package/src/headers.ts +0 -233
- package/src/layout.ts +0 -114
- package/src/lex.ts +0 -155
- package/src/parse.ts +0 -630
- package/src/parser/collector.ts +0 -148
- package/src/parser/index.ts +0 -27
- package/src/tree-sitter-cpp.d.ts +0 -4
- package/src/understand.ts +0 -322
- package/templates/game/.vscode/c_cpp_properties.json +0 -27
- package/templates/game/src/client/init.client.cpp +0 -6
- package/templates/game/src/server/leaderstats.server.cpp +0 -29
- package/templates/game/src/shared/config.cpp +0 -5
- package/templates/game/src/shared/config.h +0 -5
- /package/include/{cluaupp/generated/enums.hpp → clpp/generated/enums.clh} +0 -0
- /package/include/{cluaupp/libs/math.hpp → clpp/libs/math.clh} +0 -0
- /package/include/{cluaupp/libs/twinkle.hpp → clpp/libs/twinkle.clh} +0 -0
- /package/include/{cluaupp/libs/vfx.hpp → clpp/libs/vfx.clh} +0 -0
package/generated/compile.js
CHANGED
|
@@ -5,149 +5,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.compileSource = compileSource;
|
|
7
7
|
exports.compileService = compileService;
|
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const libs_js_1 = require("./libs.js");
|
|
14
|
-
const architecture_js_1 = require("./architecture.js");
|
|
15
|
-
const headers_js_1 = require("./headers.js");
|
|
16
|
-
function shouldAttachRequires(name, contents) {
|
|
17
|
-
const file = String(name || "").replace(/\\/g, "/");
|
|
18
|
-
if (/\.json$/i.test(file) || /\.meta\.json$/i.test(file)) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
const trimmed = String(contents || "").trim();
|
|
22
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
function attachRequires(contents, source, ast, options, outName) {
|
|
28
|
-
if (!shouldAttachRequires(outName, contents)) {
|
|
29
|
-
return contents;
|
|
30
|
-
}
|
|
31
|
-
const libraries = String(contents).includes("CluauppLibs") ? [] : (0, libs_js_1.collectLibraries)(source, ast);
|
|
32
|
-
return (0, libs_js_1.insertPreamble)(contents, options.moduleIncludes || [], libraries, outName);
|
|
33
|
-
}
|
|
34
|
-
function posixRel(from, file) {
|
|
35
|
-
return node_path_1.default.relative(from, file).replace(/\\/g, "/");
|
|
36
|
-
}
|
|
37
|
-
function declKey(decl) {
|
|
38
|
-
return `${decl.owner || ""}::${decl.name}`;
|
|
39
|
-
}
|
|
40
|
-
function mergeSiblingImpl(ast, implPath, options) {
|
|
41
|
-
const implOptions = {
|
|
42
|
-
...options,
|
|
43
|
-
moduleIncludes: [],
|
|
44
|
-
seen: new Set(),
|
|
45
|
-
pragmaResolved: false,
|
|
46
|
-
};
|
|
47
|
-
const prepared = (0, preprocess_js_1.preprocess)(node_fs_1.default.readFileSync(implPath, "utf8"), implPath, implOptions);
|
|
48
|
-
const implAst = (0, parse_js_1.parse)(prepared, node_path_1.default.basename(implPath));
|
|
49
|
-
if (!Array.isArray(ast.body)) {
|
|
50
|
-
ast.body = [];
|
|
51
|
-
}
|
|
52
|
-
const existing = new Set((ast.body || [])
|
|
53
|
-
.filter((decl) => decl && (decl.type === "function" || decl.type === "proto") && decl.name)
|
|
54
|
-
.map(declKey));
|
|
55
|
-
for (const decl of implAst.body || []) {
|
|
56
|
-
if ((decl.type !== "function" && decl.type !== "proto") || !decl.name) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const key = declKey(decl);
|
|
60
|
-
if (existing.has(key)) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
existing.add(key);
|
|
64
|
-
ast.body.push({
|
|
65
|
-
type: "proto",
|
|
66
|
-
name: decl.name,
|
|
67
|
-
owner: decl.owner,
|
|
68
|
-
returnType: decl.returnType,
|
|
69
|
-
params: decl.params,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function wireHeaderImpl(ast, fileName, options) {
|
|
74
|
-
const headerPath = options.filePath || null;
|
|
75
|
-
const impl = headerPath ? (0, preprocess_js_1.siblingImplementation)(headerPath) : null;
|
|
76
|
-
if (!impl) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
mergeSiblingImpl(ast, impl, options);
|
|
80
|
-
const typeName = (0, headers_js_1.primaryHeaderName)(ast, options.relativeName || fileName);
|
|
81
|
-
const implRel = options.srcDir ? posixRel(options.srcDir, impl) : node_path_1.default.basename(impl).replace(/\\/g, "/");
|
|
82
|
-
const implOut = (0, preprocess_js_1.implOutName)(implRel);
|
|
83
|
-
options.headerImplName = `${typeName}Module`;
|
|
84
|
-
options.moduleIncludes = options.moduleIncludes || [];
|
|
85
|
-
if (!options.moduleIncludes.some((spec) => spec.name === options.headerImplName)) {
|
|
86
|
-
options.moduleIncludes.push({
|
|
87
|
-
name: options.headerImplName,
|
|
88
|
-
outRel: implOut,
|
|
89
|
-
exports: { consts: [], structs: [] },
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function compileHeader(source, fileName, options, ast) {
|
|
94
|
-
wireHeaderImpl(ast, fileName, options);
|
|
95
|
-
const rel = (options.relativeName || fileName || "header.h").replace(/\\/g, "/");
|
|
96
|
-
const outName = (0, preprocess_js_1.toLuauPath)(rel);
|
|
97
|
-
const luau = attachRequires((0, headers_js_1.emitHeaderModule)(ast, options), source, ast, options, outName);
|
|
98
|
-
return {
|
|
99
|
-
kind: "module",
|
|
100
|
-
plan: { kind: "module", strict: options.strict === true },
|
|
101
|
-
files: [{ name: outName, contents: luau }],
|
|
102
|
-
stale: [],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
9
|
+
const runner_js_1 = require("./clpp/runner.js");
|
|
10
|
+
const postprocess_js_1 = require("./clpp/postprocess.js");
|
|
11
|
+
const paths_js_1 = require("./clpp/paths.js");
|
|
105
12
|
function compileSource(source, fileName, options = {}) {
|
|
106
|
-
|
|
107
|
-
opts.moduleIncludes = opts.moduleIncludes || [];
|
|
108
|
-
const prepared = (0, preprocess_js_1.preprocess)(source, opts.filePath || null, opts);
|
|
109
|
-
const ast = (0, parse_js_1.parse)(prepared, fileName || "input.cpp");
|
|
110
|
-
if ((0, preprocess_js_1.isHeaderFile)(fileName || "") || (0, preprocess_js_1.isHeaderFile)(opts.filePath || "")) {
|
|
111
|
-
return compileHeader(source, fileName || "header.h", opts, ast).files[0].contents;
|
|
112
|
-
}
|
|
113
|
-
const luau = (0, emit_js_1.emit)(ast, opts);
|
|
114
|
-
return attachRequires(luau, source, ast, opts, opts.outName || fileName || "input.cpp");
|
|
13
|
+
return compileService(source, fileName, options).files[0]?.contents ?? "";
|
|
115
14
|
}
|
|
116
15
|
function compileService(source, fileName, options = {}) {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
16
|
+
const relative = (options.relativeName || fileName || "input.clpp").replace(/\\/g, "/");
|
|
17
|
+
const outName = options.outName || (0, paths_js_1.toLuauPath)(relative);
|
|
18
|
+
const header = options.filePath ? (0, paths_js_1.siblingHeader)(options.filePath) : null;
|
|
19
|
+
const skipInit = options.skipInit === true || (0, postprocess_js_1.shouldSkipInit)(relative, Boolean(header));
|
|
20
|
+
const diskPath = options.filePath ? node_path_1.default.resolve(options.filePath) : null;
|
|
21
|
+
const artifact = (0, runner_js_1.compileViaClpp)({
|
|
22
|
+
source,
|
|
23
|
+
fileName: diskPath ? diskPath.replace(/\\/g, "/") : relative,
|
|
24
|
+
strict: options.strict,
|
|
25
|
+
cwd: diskPath ? node_path_1.default.dirname(diskPath) : options.srcDir,
|
|
26
|
+
});
|
|
27
|
+
const luau = (0, postprocess_js_1.clppLuauToGame)(artifact, {
|
|
28
|
+
relativeName: relative,
|
|
29
|
+
outName,
|
|
30
|
+
srcDir: options.srcDir,
|
|
31
|
+
rootDir: options.rootDir,
|
|
32
|
+
strict: options.strict,
|
|
33
|
+
skipInit,
|
|
133
34
|
});
|
|
134
|
-
if (planned.files) {
|
|
135
|
-
return {
|
|
136
|
-
...planned,
|
|
137
|
-
files: planned.files.map((file) => ({
|
|
138
|
-
...file,
|
|
139
|
-
contents: attachRequires(file.contents, source, ast, opts, file.name),
|
|
140
|
-
})),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const luau = attachRequires((0, emit_js_1.emit)(ast, opts), source, ast, opts, planned.outName || opts.outName || fileName || "input.cpp");
|
|
144
|
-
const name = planned.outName ||
|
|
145
|
-
opts.outName ||
|
|
146
|
-
String(fileName || "input.cpp").replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau");
|
|
147
35
|
return {
|
|
148
|
-
kind:
|
|
149
|
-
plan:
|
|
150
|
-
files: [{ name, contents: luau }],
|
|
151
|
-
stale:
|
|
36
|
+
kind: (0, paths_js_1.emitKind)(relative),
|
|
37
|
+
plan: { kind: (0, paths_js_1.emitKind)(relative), strict: options.strict === true },
|
|
38
|
+
files: [{ name: outName, contents: luau }],
|
|
39
|
+
stale: [],
|
|
152
40
|
};
|
|
153
41
|
}
|
package/generated/emit.js
CHANGED
|
@@ -31,6 +31,7 @@ function emit(ast, options = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
const ownedFns = (ast.body || []).filter((decl) => decl.type === "function");
|
|
34
|
+
const hasOwnedMethods = ownedFns.some((decl) => Boolean(decl.owner));
|
|
34
35
|
const classModule = ownedFns.length > 0 && ownedFns.every((decl) => Boolean(decl.owner));
|
|
35
36
|
const nestedTypes = new Set();
|
|
36
37
|
for (const decl of ast.body || []) {
|
|
@@ -131,6 +132,35 @@ function emit(ast, options = {}) {
|
|
|
131
132
|
}
|
|
132
133
|
return linesOut;
|
|
133
134
|
};
|
|
135
|
+
const isStringConcatCall = (node) => node && node.type === "call" && !node.object && node.name === "string_concat";
|
|
136
|
+
const emitStringConcat = (args) => {
|
|
137
|
+
const parts = (args || []).map(emitExpr);
|
|
138
|
+
if (parts.length === 0) {
|
|
139
|
+
return `""`;
|
|
140
|
+
}
|
|
141
|
+
if (parts.length === 1) {
|
|
142
|
+
return parts[0];
|
|
143
|
+
}
|
|
144
|
+
return `(${parts.join(" .. ")})`;
|
|
145
|
+
};
|
|
146
|
+
const isStringExpr = (node) => {
|
|
147
|
+
if (!node) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (node.type === "string") {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (isStringConcatCall(node)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
if (node.type === "binary" && node.op === "+" && (isStringExpr(node.left) || isStringExpr(node.right))) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
if (node.type === "member" && (node.name === "Name" || node.name === "Text" || node.name === "DisplayName")) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
};
|
|
134
164
|
const emitExpr = (node) => {
|
|
135
165
|
if (!node) {
|
|
136
166
|
return "nil";
|
|
@@ -153,6 +183,28 @@ function emit(ast, options = {}) {
|
|
|
153
183
|
}
|
|
154
184
|
return `{ ${entries.join(", ")} }`;
|
|
155
185
|
}
|
|
186
|
+
case "cast":
|
|
187
|
+
if (node.valueType === "void") {
|
|
188
|
+
return emitExpr(node.argument);
|
|
189
|
+
}
|
|
190
|
+
return emitExpr(node.argument);
|
|
191
|
+
case "lambda": {
|
|
192
|
+
const params = (node.params || [])
|
|
193
|
+
.map((param) => {
|
|
194
|
+
if (typeof param === "string") {
|
|
195
|
+
return param;
|
|
196
|
+
}
|
|
197
|
+
const typeAnn = (0, api_js_1.luauType)(param.valueType);
|
|
198
|
+
return typeAnn ? `${param.name}: ${typeAnn}` : param.name;
|
|
199
|
+
})
|
|
200
|
+
.join(", ");
|
|
201
|
+
const inner = [];
|
|
202
|
+
for (const stmt of node.body || []) {
|
|
203
|
+
inner.push(...emitStmt(stmt, 1));
|
|
204
|
+
}
|
|
205
|
+
const body = inner.length > 0 ? `\n${inner.join("\n")}\n` : "\n";
|
|
206
|
+
return `function(${params})${body}end`;
|
|
207
|
+
}
|
|
156
208
|
case "unary": {
|
|
157
209
|
const inner = emitExpr(node.argument);
|
|
158
210
|
if (node.op === "!") {
|
|
@@ -172,6 +224,9 @@ function emit(ast, options = {}) {
|
|
|
172
224
|
case "member":
|
|
173
225
|
return `${emitExpr(node.object)}.${node.name}`;
|
|
174
226
|
case "call": {
|
|
227
|
+
if (isStringConcatCall(node)) {
|
|
228
|
+
return emitStringConcat(node.args);
|
|
229
|
+
}
|
|
175
230
|
const args = node.args.map(emitMethodArg).join(", ");
|
|
176
231
|
if (!node.object) {
|
|
177
232
|
if ((0, api_js_1.isDatatype)(node.name)) {
|
|
@@ -183,6 +238,9 @@ function emit(ast, options = {}) {
|
|
|
183
238
|
return `${node.name}(${args})`;
|
|
184
239
|
}
|
|
185
240
|
const obj = emitExpr(node.object);
|
|
241
|
+
if (classMethods.has(node.name) && !localNames.has(node.name)) {
|
|
242
|
+
return `${obj}:${node.name}(${args})`;
|
|
243
|
+
}
|
|
186
244
|
if (node.access === "::" && node.object.type === "ident" && node.object.name === "cout") {
|
|
187
245
|
if (node.name === "endl") {
|
|
188
246
|
return "print()";
|
|
@@ -220,6 +278,9 @@ function emit(ast, options = {}) {
|
|
|
220
278
|
return printed.join("; ");
|
|
221
279
|
}
|
|
222
280
|
}
|
|
281
|
+
if (node.op === "+" && (isStringExpr(node.left) || isStringExpr(node.right))) {
|
|
282
|
+
return `${emitExpr(node.left)} .. ${emitExpr(node.right)}`;
|
|
283
|
+
}
|
|
223
284
|
const ops = { "!=": "~=", "&&": "and", "||": "or" };
|
|
224
285
|
const op = ops[node.op] || node.op;
|
|
225
286
|
return `${emitExpr(node.left)} ${op} ${emitExpr(node.right)}`;
|
|
@@ -278,6 +339,9 @@ function emit(ast, options = {}) {
|
|
|
278
339
|
return [`${prefix}${kind} ${node.name}${typed} = ${created.className}.new(${args})`];
|
|
279
340
|
}
|
|
280
341
|
const value = node.value ? emitExpr(node.value) : "nil";
|
|
342
|
+
if (!node.value && node.valueType && classOwners.has(node.valueType)) {
|
|
343
|
+
return [`${prefix}${kind} ${node.name}${typed} = ${node.valueType}`];
|
|
344
|
+
}
|
|
281
345
|
return [`${prefix}${kind} ${node.name}${typed} = ${value}`];
|
|
282
346
|
};
|
|
283
347
|
const emitStmt = (node, indent) => {
|
|
@@ -290,6 +354,9 @@ function emit(ast, options = {}) {
|
|
|
290
354
|
return emitNewDecl(node, indent);
|
|
291
355
|
case "expr": {
|
|
292
356
|
const expr = node.expr;
|
|
357
|
+
if (expr && expr.type === "cast" && expr.valueType === "void") {
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
293
360
|
if (expr && expr.type === "binary" && expr.op === "<<") {
|
|
294
361
|
const printed = emitCout(expr);
|
|
295
362
|
if (printed) {
|
|
@@ -433,10 +500,8 @@ function emit(ast, options = {}) {
|
|
|
433
500
|
lines.push(" }");
|
|
434
501
|
lines.push("end");
|
|
435
502
|
lines.push("");
|
|
436
|
-
lines.push(`return ${root}`);
|
|
437
|
-
lines.push("");
|
|
438
503
|
};
|
|
439
|
-
if (
|
|
504
|
+
if (hasOwnedMethods) {
|
|
440
505
|
for (const owner of classOwners) {
|
|
441
506
|
lines.push(`local ${owner} = {}`);
|
|
442
507
|
lines.push("");
|
|
@@ -446,6 +511,17 @@ function emit(ast, options = {}) {
|
|
|
446
511
|
for (const root of structRoots) {
|
|
447
512
|
emitStructConstructor(root);
|
|
448
513
|
}
|
|
514
|
+
if (structRoots.length === 1) {
|
|
515
|
+
lines.push(`return ${structRoots[0]}`);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
lines.push("return {");
|
|
519
|
+
for (const root of structRoots) {
|
|
520
|
+
lines.push(` ${root} = ${root},`);
|
|
521
|
+
}
|
|
522
|
+
lines.push("}");
|
|
523
|
+
}
|
|
524
|
+
lines.push("");
|
|
449
525
|
return lines.join("\n");
|
|
450
526
|
}
|
|
451
527
|
for (const decl of ast.body) {
|
|
@@ -3,10 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
exports.clangPath = clangPath;
|
|
8
|
-
exports.writeCompileCommands = writeCompileCommands;
|
|
9
|
-
exports.writeClangd = writeClangd;
|
|
6
|
+
exports.isClppSource = void 0;
|
|
10
7
|
exports.diagnosticsFor = diagnosticsFor;
|
|
11
8
|
exports.syncEditorSupport = syncEditorSupport;
|
|
12
9
|
exports.installEditorExtension = installEditorExtension;
|
|
@@ -14,83 +11,11 @@ exports.installEditorSupport = installEditorSupport;
|
|
|
14
11
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
12
|
const node_os_1 = __importDefault(require("node:os"));
|
|
16
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
-
const
|
|
18
|
-
const preprocess_js_1 = require("./preprocess.js");
|
|
19
|
-
const editor_install_js_1 = require("./editor-install.js");
|
|
14
|
+
const node_child_process_1 = require("node:child_process");
|
|
20
15
|
const package_info_js_1 = require("./package-info.js");
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
}
|
|
16
|
+
const contract_js_1 = require("./clpp/contract.js");
|
|
17
|
+
const runner_js_1 = require("./clpp/runner.js");
|
|
18
|
+
const paths_js_1 = require("./clpp/paths.js");
|
|
94
19
|
function copyDir(from, to) {
|
|
95
20
|
node_fs_1.default.mkdirSync(to, { recursive: true });
|
|
96
21
|
for (const entry of node_fs_1.default.readdirSync(from, { withFileTypes: true })) {
|
|
@@ -104,147 +29,90 @@ function copyDir(from, to) {
|
|
|
104
29
|
}
|
|
105
30
|
}
|
|
106
31
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
32
|
+
function uniqueStrings(...lists) {
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
const out = [];
|
|
35
|
+
for (const list of lists) {
|
|
36
|
+
if (!Array.isArray(list)) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
for (const item of list) {
|
|
40
|
+
if (typeof item === "string" && item && !seen.has(item)) {
|
|
41
|
+
seen.add(item);
|
|
42
|
+
out.push(item);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
113
47
|
}
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return `windows-clang-${arch}`;
|
|
48
|
+
function readJsonObject(file) {
|
|
49
|
+
if (!node_fs_1.default.existsSync(file)) {
|
|
50
|
+
return {};
|
|
118
51
|
}
|
|
119
|
-
|
|
120
|
-
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
|
|
54
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
55
|
+
return parsed;
|
|
56
|
+
}
|
|
121
57
|
}
|
|
122
|
-
|
|
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;
|
|
58
|
+
catch {
|
|
59
|
+
// ignore
|
|
133
60
|
}
|
|
134
|
-
|
|
135
|
-
return true;
|
|
61
|
+
return {};
|
|
136
62
|
}
|
|
137
|
-
function
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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;
|
|
63
|
+
function writeJson(file, value) {
|
|
64
|
+
const json = `${JSON.stringify(value, null, "\t")}\n`;
|
|
65
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(file), { recursive: true });
|
|
66
|
+
if (node_fs_1.default.existsSync(file) && node_fs_1.default.readFileSync(file, "utf8") === json) {
|
|
67
|
+
return;
|
|
165
68
|
}
|
|
166
|
-
node_fs_1.default.writeFileSync(
|
|
167
|
-
return true;
|
|
69
|
+
node_fs_1.default.writeFileSync(file, json, "utf8");
|
|
168
70
|
}
|
|
169
71
|
function writeVscode(root) {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"*.legacy.cpp": "cpp",
|
|
187
|
-
"*.legacy.server.cpp": "cpp",
|
|
188
|
-
"*.legacy.client.cpp": "cpp",
|
|
189
|
-
},
|
|
72
|
+
const settingsPath = node_path_1.default.join(root, ".vscode", "settings.json");
|
|
73
|
+
const current = readJsonObject(settingsPath);
|
|
74
|
+
const associations = {
|
|
75
|
+
...((current["files.associations"] && typeof current["files.associations"] === "object" && !Array.isArray(current["files.associations"]))
|
|
76
|
+
? current["files.associations"]
|
|
77
|
+
: {}),
|
|
78
|
+
"*.clpp": "clpp",
|
|
79
|
+
"*.clp": "clpp",
|
|
80
|
+
"*.clh": "clpp",
|
|
81
|
+
"*.server.clpp": "clpp",
|
|
82
|
+
"*.client.clpp": "clpp",
|
|
83
|
+
"*.plugin.clpp": "clpp",
|
|
84
|
+
};
|
|
85
|
+
writeJson(settingsPath, {
|
|
86
|
+
...current,
|
|
87
|
+
"files.associations": associations,
|
|
190
88
|
});
|
|
191
|
-
|
|
192
|
-
|
|
89
|
+
const extensionsPath = node_path_1.default.join(root, ".vscode", "extensions.json");
|
|
90
|
+
const extensions = readJsonObject(extensionsPath);
|
|
91
|
+
writeJson(extensionsPath, {
|
|
92
|
+
...extensions,
|
|
93
|
+
recommendations: uniqueStrings(extensions.recommendations),
|
|
94
|
+
unwantedRecommendations: uniqueStrings(extensions.unwantedRecommendations, ["ms-vscode.cpptools"]),
|
|
193
95
|
});
|
|
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
96
|
}
|
|
220
|
-
function diagnosticsFor(source, fileName
|
|
97
|
+
function diagnosticsFor(source, fileName) {
|
|
98
|
+
if (!(0, runner_js_1.hasClpp)()) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
221
101
|
try {
|
|
222
|
-
|
|
223
|
-
(0, parse_js_1.parse)(prepared, fileName || "input.cpp");
|
|
102
|
+
(0, runner_js_1.compileViaClpp)({ source, fileName: fileName || "input.clpp" });
|
|
224
103
|
return [];
|
|
225
104
|
}
|
|
226
105
|
catch (err) {
|
|
227
|
-
const
|
|
228
|
-
const message = error.message ? String(error.message) : "parse error";
|
|
106
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
229
107
|
const match = message.match(/:(\d+):(\d+):\s*(.*)$/);
|
|
230
108
|
if (match) {
|
|
231
109
|
return [{ line: Number(match[1]), col: Number(match[2]), message: match[3], severity: "error" }];
|
|
232
110
|
}
|
|
233
|
-
return [{ line:
|
|
111
|
+
return [{ line: 1, col: 1, message, severity: "error" }];
|
|
234
112
|
}
|
|
235
113
|
}
|
|
236
|
-
function syncEditorSupport(root,
|
|
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);
|
|
114
|
+
function syncEditorSupport(root, _config = {}) {
|
|
242
115
|
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
116
|
}
|
|
249
117
|
function installEditorExtension(cluauppRoot = package_info_js_1.projectRoot) {
|
|
250
118
|
const from = node_path_1.default.join(cluauppRoot, "editors", "vscode");
|
|
@@ -266,12 +134,20 @@ function installEditorExtension(cluauppRoot = package_info_js_1.projectRoot) {
|
|
|
266
134
|
}
|
|
267
135
|
return installed;
|
|
268
136
|
}
|
|
269
|
-
async function installEditorSupport(
|
|
270
|
-
const local = installEditorExtension(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
137
|
+
async function installEditorSupport() {
|
|
138
|
+
const local = installEditorExtension();
|
|
139
|
+
if ((0, runner_js_1.hasClpp)()) {
|
|
140
|
+
const result = (0, node_child_process_1.spawnSync)("clpp", ["install"], { encoding: "utf8", windowsHide: true });
|
|
141
|
+
if (result.status === 0) {
|
|
142
|
+
console.log(String(result.stderr || result.stdout || "clpp install ok").trim());
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log("cluaupp:", contract_js_1.CLPP_INSTALL_HINT);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
console.log("cluaupp:", contract_js_1.CLPP_INSTALL_HINT);
|
|
150
|
+
}
|
|
151
|
+
return { local };
|
|
277
152
|
}
|
|
153
|
+
exports.isClppSource = paths_js_1.isSourceFile;
|