@ugo-studio/jspp 0.2.9 → 0.3.1

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.
Files changed (97) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/analysis/scope.js +5 -3
  4. package/dist/analysis/typeAnalyzer.js +21 -25
  5. package/dist/cli/index.js +14 -4
  6. package/dist/cli/utils.js +61 -0
  7. package/dist/core/codegen/class-handlers.js +6 -6
  8. package/dist/core/codegen/control-flow-handlers.js +10 -9
  9. package/dist/core/codegen/declaration-handlers.js +10 -3
  10. package/dist/core/codegen/destructuring-handlers.js +9 -4
  11. package/dist/core/codegen/expression-handlers.js +40 -29
  12. package/dist/core/codegen/function-handlers.js +78 -12
  13. package/dist/core/codegen/helpers.js +91 -14
  14. package/dist/core/codegen/index.js +4 -2
  15. package/dist/core/codegen/statement-handlers.js +9 -7
  16. package/package.json +2 -2
  17. package/scripts/precompile-headers.ts +249 -50
  18. package/scripts/setup-compiler.ts +63 -63
  19. package/src/prelude/any_value.cpp +636 -0
  20. package/src/prelude/any_value.hpp +369 -362
  21. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  22. package/src/prelude/exception.hpp +27 -27
  23. package/src/prelude/iterator_instantiations.hpp +10 -0
  24. package/src/prelude/{index.hpp → jspp.hpp} +10 -16
  25. package/src/prelude/library/array.cpp +191 -0
  26. package/src/prelude/library/array.hpp +13 -186
  27. package/src/prelude/library/console.cpp +125 -0
  28. package/src/prelude/library/console.hpp +24 -112
  29. package/src/prelude/library/error.cpp +100 -0
  30. package/src/prelude/library/error.hpp +13 -113
  31. package/src/prelude/library/function.cpp +69 -0
  32. package/src/prelude/library/function.hpp +11 -10
  33. package/src/prelude/library/global.cpp +96 -0
  34. package/src/prelude/library/global.hpp +12 -28
  35. package/src/prelude/library/global_usings.hpp +15 -0
  36. package/src/prelude/library/math.cpp +258 -0
  37. package/src/prelude/library/math.hpp +26 -308
  38. package/src/prelude/library/object.cpp +379 -0
  39. package/src/prelude/library/object.hpp +14 -276
  40. package/src/prelude/library/performance.cpp +21 -0
  41. package/src/prelude/library/performance.hpp +5 -20
  42. package/src/prelude/library/process.cpp +38 -0
  43. package/src/prelude/library/process.hpp +11 -39
  44. package/src/prelude/library/promise.cpp +131 -0
  45. package/src/prelude/library/promise.hpp +12 -123
  46. package/src/prelude/library/symbol.cpp +56 -0
  47. package/src/prelude/library/symbol.hpp +11 -52
  48. package/src/prelude/library/timer.cpp +88 -0
  49. package/src/prelude/library/timer.hpp +16 -92
  50. package/src/prelude/runtime.cpp +19 -0
  51. package/src/prelude/types.hpp +184 -179
  52. package/src/prelude/utils/access.hpp +502 -411
  53. package/src/prelude/utils/assignment_operators.hpp +99 -99
  54. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  55. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  56. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  57. package/src/prelude/utils/operators.hpp +351 -336
  58. package/src/prelude/utils/operators_primitive.hpp +336 -336
  59. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  60. package/src/prelude/values/array.cpp +1399 -0
  61. package/src/prelude/values/array.hpp +4 -1
  62. package/src/prelude/values/async_iterator.cpp +251 -0
  63. package/src/prelude/values/async_iterator.hpp +111 -83
  64. package/src/prelude/values/function.cpp +262 -0
  65. package/src/prelude/values/function.hpp +62 -82
  66. package/src/prelude/values/iterator.cpp +309 -0
  67. package/src/prelude/values/iterator.hpp +33 -64
  68. package/src/prelude/values/number.cpp +176 -0
  69. package/src/prelude/values/object.cpp +159 -0
  70. package/src/prelude/values/object.hpp +4 -0
  71. package/src/prelude/values/promise.cpp +479 -0
  72. package/src/prelude/values/promise.hpp +79 -72
  73. package/src/prelude/values/prototypes/array.hpp +46 -1336
  74. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  75. package/src/prelude/values/prototypes/function.hpp +7 -46
  76. package/src/prelude/values/prototypes/iterator.hpp +25 -201
  77. package/src/prelude/values/prototypes/number.hpp +23 -210
  78. package/src/prelude/values/prototypes/object.hpp +7 -23
  79. package/src/prelude/values/prototypes/promise.hpp +18 -196
  80. package/src/prelude/values/prototypes/string.hpp +39 -542
  81. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  82. package/src/prelude/values/shape.hpp +52 -52
  83. package/src/prelude/values/string.cpp +485 -0
  84. package/src/prelude/values/string.hpp +25 -26
  85. package/src/prelude/values/symbol.cpp +89 -0
  86. package/src/prelude/values/symbol.hpp +101 -101
  87. package/src/prelude/any_value_access.hpp +0 -170
  88. package/src/prelude/any_value_defines.hpp +0 -190
  89. package/src/prelude/any_value_helpers.hpp +0 -374
  90. package/src/prelude/values/helpers/array.hpp +0 -209
  91. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  92. package/src/prelude/values/helpers/function.hpp +0 -109
  93. package/src/prelude/values/helpers/iterator.hpp +0 -145
  94. package/src/prelude/values/helpers/object.hpp +0 -104
  95. package/src/prelude/values/helpers/promise.hpp +0 -254
  96. package/src/prelude/values/helpers/string.hpp +0 -61
  97. package/src/prelude/values/helpers/symbol.hpp +0 -21
@@ -1,7 +1,82 @@
1
- import { spawnSync } from "child_process";
1
+ import { spawn, spawnSync } from "child_process";
2
2
  import fs from "fs/promises";
3
3
  import path from "path";
4
4
 
5
+ const COLORS = {
6
+ reset: "\x1b[0m",
7
+ cyan: "\x1b[36m",
8
+ green: "\x1b[32m",
9
+ yellow: "\x1b[33m",
10
+ red: "\x1b[31m",
11
+ dim: "\x1b[2m",
12
+ bold: "\x1b[1m",
13
+ };
14
+
15
+ export class Spinner {
16
+ private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
17
+ private interval: any = null;
18
+ private frameIndex = 0;
19
+ public text: string;
20
+
21
+ constructor(text: string) {
22
+ this.text = text;
23
+ }
24
+
25
+ start() {
26
+ process.stdout.write("\x1b[?25l"); // Hide cursor
27
+ this.frameIndex = 0;
28
+ this.render();
29
+ this.interval = setInterval(() => {
30
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
31
+ this.render();
32
+ }, 80);
33
+ }
34
+
35
+ update(text: string) {
36
+ this.text = text;
37
+ this.render();
38
+ }
39
+
40
+ stop(symbol: string = "", color: string = COLORS.reset) {
41
+ if (this.interval) {
42
+ clearInterval(this.interval);
43
+ this.interval = null;
44
+ }
45
+ this.clearLine();
46
+ process.stdout.write(
47
+ `${color}${symbol} ${COLORS.reset} ${this.text}\n`,
48
+ );
49
+ process.stdout.write("\x1b[?25h"); // Show cursor
50
+ }
51
+
52
+ succeed(text?: string) {
53
+ if (text) this.text = text;
54
+ this.stop("✔", COLORS.green);
55
+ }
56
+
57
+ fail(text?: string) {
58
+ if (text) this.text = text;
59
+ this.stop("✖", COLORS.red);
60
+ }
61
+
62
+ info(text?: string) {
63
+ if (text) this.text = text;
64
+ this.stop("ℹ", COLORS.cyan);
65
+ }
66
+
67
+ private render() {
68
+ this.clearLine();
69
+ const frame = this.frames[this.frameIndex];
70
+ process.stdout.write(
71
+ `${COLORS.cyan}${frame} ${COLORS.reset} ${this.text}`,
72
+ );
73
+ }
74
+
75
+ private clearLine() {
76
+ process.stdout.write("\r\x1b[K");
77
+ }
78
+ }
79
+
5
80
  const PRELUDE_DIR = path.resolve(process.cwd(), "src", "prelude");
6
81
  const PRECOMPILED_HEADER_BASE_DIR = path.resolve(
7
82
  process.cwd(),
@@ -11,7 +86,7 @@ const PRECOMPILED_HEADER_BASE_DIR = path.resolve(
11
86
  const MODES = [
12
87
  {
13
88
  name: "debug",
14
- flags: ["-O0"],
89
+ flags: ["-Og"],
15
90
  },
16
91
  {
17
92
  name: "release",
@@ -24,15 +99,19 @@ if (process.platform === "win32") {
24
99
  MODES[1].flags.push("-Wa,-mbig-obj");
25
100
  }
26
101
 
27
- async function getLatestMtime(dirPath: string): Promise<number> {
102
+ async function getLatestMtime(
103
+ dirPath: string,
104
+ filter?: (name: string) => boolean,
105
+ ): Promise<number> {
28
106
  let maxMtime = 0;
29
107
  const entries = await fs.readdir(dirPath, { withFileTypes: true });
30
108
  for (const entry of entries) {
31
109
  const fullPath = path.join(dirPath, entry.name);
32
110
  if (entry.isDirectory()) {
33
- const nestedMtime = await getLatestMtime(fullPath);
111
+ const nestedMtime = await getLatestMtime(fullPath, filter);
34
112
  if (nestedMtime > maxMtime) maxMtime = nestedMtime;
35
113
  } else {
114
+ if (filter && !filter(entry.name)) continue;
36
115
  const stats = await fs.stat(fullPath);
37
116
  if (stats.mtimeMs > maxMtime) maxMtime = stats.mtimeMs;
38
117
  }
@@ -40,53 +119,74 @@ async function getLatestMtime(dirPath: string): Promise<number> {
40
119
  return maxMtime;
41
120
  }
42
121
 
122
+ async function findCppFiles(dir: string): Promise<string[]> {
123
+ const entries = await fs.readdir(dir, { withFileTypes: true });
124
+ const files = await Promise.all(entries.map((entry) => {
125
+ const res = path.resolve(dir, entry.name);
126
+ if (entry.isDirectory()) {
127
+ return findCppFiles(res);
128
+ } else {
129
+ return res.endsWith(".cpp") ? [res] : [];
130
+ }
131
+ }));
132
+ return Array.prototype.concat(...files);
133
+ }
134
+
135
+ async function runCommand(cmd: string, args: string[]): Promise<boolean> {
136
+ return new Promise((resolve) => {
137
+ const proc = spawn(cmd, args, { stdio: "ignore" });
138
+ proc.on("close", (code) => resolve(code === 0));
139
+ });
140
+ }
141
+
43
142
  async function precompileHeaders() {
143
+ console.log(
144
+ `${COLORS.bold}${COLORS.cyan}JSPP: Precompiling headers and runtime...${COLORS.reset}\n`,
145
+ );
146
+
44
147
  const force = process.argv.includes("--force");
45
148
  try {
46
149
  await fs.mkdir(PRECOMPILED_HEADER_BASE_DIR, { recursive: true });
47
- const sourceMtime = await getLatestMtime(PRELUDE_DIR);
150
+
151
+ const latestHeaderMtime = await getLatestMtime(
152
+ PRELUDE_DIR,
153
+ (name) => name.endsWith(".hpp") || name.endsWith(".h"),
154
+ );
48
155
 
49
156
  for (const mode of MODES) {
50
157
  const modeDir = path.join(PRECOMPILED_HEADER_BASE_DIR, mode.name);
51
- const headerPath = path.join(modeDir, "index.hpp");
52
- const gchPath = path.join(modeDir, "index.hpp.gch");
158
+ const headerPath = path.join(modeDir, "jspp.hpp");
159
+ const gchPath = path.join(modeDir, "jspp.hpp.gch");
160
+
161
+ const modeLabel = `[${mode.name.toUpperCase()}]`;
162
+ const spinner = new Spinner(`${modeLabel} Checking headers...`);
163
+ spinner.start();
164
+
165
+ await fs.mkdir(modeDir, { recursive: true });
53
166
 
54
- if (!force) {
167
+ let gchRebuilt = false;
168
+ let shouldBuildGch = force;
169
+
170
+ if (!shouldBuildGch) {
55
171
  try {
56
172
  const gchStats = await fs.stat(gchPath);
57
- if (gchStats.mtimeMs >= sourceMtime) {
58
- console.log(
59
- `[${mode.name.toUpperCase()}] Headers are up-to-date. Skipping.`,
60
- );
61
- continue;
173
+ if (latestHeaderMtime > gchStats.mtimeMs) {
174
+ shouldBuildGch = true;
62
175
  }
63
176
  } catch (e) {
64
- // PCH doesn't exist, proceed to compile
177
+ shouldBuildGch = true;
65
178
  }
66
179
  }
67
180
 
68
- console.log(`\n[${mode.name.toUpperCase()}] Setting up...`);
69
- await fs.mkdir(modeDir, { recursive: true });
70
-
71
- // Copy index.hpp
72
- await fs.copyFile(path.join(PRELUDE_DIR, "index.hpp"), headerPath);
73
-
74
- // Remove existing gch if it exists
75
- if (
76
- await fs.stat(gchPath).then(
77
- () => true,
78
- () => false,
79
- )
80
- ) {
81
- await fs.unlink(gchPath);
82
- }
83
-
84
- console.log(`[${mode.name.toUpperCase()}] Compiling header...`);
85
- const tempGchPath = `${gchPath}.tmp`;
181
+ if (shouldBuildGch) {
182
+ spinner.update(`${modeLabel} Compiling header...`);
183
+ await fs.copyFile(
184
+ path.join(PRELUDE_DIR, "jspp.hpp"),
185
+ headerPath,
186
+ );
86
187
 
87
- const compile = spawnSync(
88
- "g++",
89
- [
188
+ const tempGchPath = `${gchPath}.tmp`;
189
+ const success = await runCommand("g++", [
90
190
  "-x",
91
191
  "c++-header",
92
192
  "-std=c++23",
@@ -95,31 +195,130 @@ async function precompileHeaders() {
95
195
  "-o",
96
196
  tempGchPath,
97
197
  "-I",
198
+ modeDir,
199
+ "-I",
98
200
  PRELUDE_DIR,
99
- ],
100
- {
101
- stdio: "inherit",
102
- },
201
+ ]);
202
+
203
+ if (!success) {
204
+ spinner.fail(`${modeLabel} Failed to precompile headers.`);
205
+ process.exit(1);
206
+ }
207
+
208
+ await fs.rename(tempGchPath, gchPath);
209
+ gchRebuilt = true;
210
+ spinner.succeed(`${modeLabel} PCH Success.`);
211
+ } else {
212
+ spinner.succeed(`${modeLabel} Headers are up-to-date.`);
213
+ }
214
+
215
+ // --- Incremental Compilation of .cpp files ---
216
+ const cppFiles = await findCppFiles(PRELUDE_DIR);
217
+ const objFiles: string[] = [];
218
+ let anyObjRebuilt = false;
219
+
220
+ const gchMtime = (await fs.stat(gchPath)).mtimeMs;
221
+
222
+ const libSpinner = new Spinner(
223
+ `${modeLabel} Checking runtime library...`,
103
224
  );
225
+ libSpinner.start();
226
+
227
+ for (let idx = 0; idx < cppFiles.length; idx++) {
228
+ const cppFile = cppFiles[idx];
229
+ const relativePath = path.relative(PRELUDE_DIR, cppFile);
230
+ const objFile = path.join(
231
+ modeDir,
232
+ relativePath.replace(/\.cpp$/, ".o"),
233
+ );
234
+ await fs.mkdir(path.dirname(objFile), { recursive: true });
235
+ objFiles.push(objFile);
236
+
237
+ let shouldCompile = force || gchRebuilt;
238
+ if (!shouldCompile) {
239
+ try {
240
+ const objStats = await fs.stat(objFile);
241
+ const cppStats = await fs.stat(cppFile);
242
+ if (
243
+ cppStats.mtimeMs > objStats.mtimeMs ||
244
+ gchMtime > objStats.mtimeMs
245
+ ) {
246
+ shouldCompile = true;
247
+ }
248
+ } catch (e) {
249
+ shouldCompile = true;
250
+ }
251
+ }
252
+
253
+ if (shouldCompile) {
254
+ libSpinner.update(
255
+ `${modeLabel} Compiling ${relativePath} ${COLORS.dim}[${
256
+ idx + 1
257
+ }/${cppFiles.length}]${COLORS.reset}`,
258
+ );
259
+ const success = await runCommand("g++", [
260
+ "-c",
261
+ "-std=c++23",
262
+ ...mode.flags,
263
+ cppFile,
264
+ "-o",
265
+ objFile,
266
+ "-I",
267
+ modeDir,
268
+ "-I",
269
+ PRELUDE_DIR,
270
+ ]);
104
271
 
105
- if (compile.status !== 0) {
272
+ if (!success) {
273
+ libSpinner.fail(
274
+ `${modeLabel} Failed to compile ${relativePath}`,
275
+ );
276
+ process.exit(1);
277
+ }
278
+ anyObjRebuilt = true;
279
+ }
280
+ }
281
+
282
+ const libPath = path.join(modeDir, "libjspp.a");
283
+ let shouldArchive = anyObjRebuilt;
284
+ if (!shouldArchive) {
106
285
  try {
107
- await fs.unlink(tempGchPath);
286
+ await fs.access(libPath);
108
287
  } catch (e) {
109
- // Ignore if temp file doesn't exist
288
+ shouldArchive = true;
110
289
  }
111
- console.error(
112
- `[${mode.name.toUpperCase()}] Failed to precompile headers.`,
113
- );
114
- process.exit(1);
115
290
  }
116
291
 
117
- // Atomically replace the old GCH with the new one
118
- await fs.rename(tempGchPath, gchPath);
119
- console.log(`[${mode.name.toUpperCase()}] Success.`);
292
+ if (shouldArchive) {
293
+ libSpinner.update(`${modeLabel} Updating runtime library...`);
294
+ const tempLibPath = `${libPath}.tmp`;
295
+
296
+ const success = await runCommand("ar", [
297
+ "rcs",
298
+ tempLibPath,
299
+ ...objFiles,
300
+ ]);
301
+
302
+ if (!success) {
303
+ libSpinner.fail(
304
+ `${modeLabel} Failed to create static library.`,
305
+ );
306
+ process.exit(1);
307
+ }
308
+
309
+ await fs.rename(tempLibPath, libPath);
310
+ libSpinner.succeed(`${modeLabel} Runtime Library Success.`);
311
+ } else {
312
+ libSpinner.succeed(
313
+ `${modeLabel} Runtime library is up-to-date.`,
314
+ );
315
+ }
120
316
  }
317
+ console.log(
318
+ `\n${COLORS.bold}${COLORS.green}JSPP: Environment ready.${COLORS.reset}\n`,
319
+ );
121
320
  } catch (error: any) {
122
- console.error(`Error: ${error.message}`);
321
+ console.error(`${COLORS.red}Error: ${error.message}${COLORS.reset}`);
123
322
  process.exit(1);
124
323
  }
125
324
  }
@@ -1,63 +1,63 @@
1
- import { spawnSync } from "child_process";
2
- import { platform } from "os";
3
-
4
- const COLORS = {
5
- reset: "\x1b[0m",
6
- green: "\x1b[32m",
7
- yellow: "\x1b[33m",
8
- red: "\x1b[31m",
9
- cyan: "\x1b[36m",
10
- bold: "\x1b[1m",
11
- };
12
-
13
- function checkGpp(): boolean {
14
- try {
15
- const result = spawnSync("g++", ["--version"], { encoding: "utf8" });
16
- return result.status === 0;
17
- } catch (e) {
18
- return false;
19
- }
20
- }
21
-
22
- function setup() {
23
- console.log(`${COLORS.bold}${COLORS.cyan}JSPP: Checking for C++ compiler...${COLORS.reset}`);
24
-
25
- if (checkGpp()) {
26
- console.log(`${COLORS.green}✔ g++ found.${COLORS.reset}`);
27
- return;
28
- }
29
-
30
- console.log(`${COLORS.yellow}⚠ g++ (GCC) not found in PATH. JSPP requires a C++23 compatible compiler.${COLORS.reset}`);
31
-
32
- const os = platform();
33
-
34
- if (os === "win32") {
35
- console.log(`\n${COLORS.bold}To install GCC on Windows:${COLORS.reset}`);
36
- console.log(`1. Install MinGW-w64 via MSYS2: ${COLORS.cyan}https://www.msys2.org/${COLORS.reset}`);
37
- console.log(`2. Or use winget: ${COLORS.cyan}winget install MSYS2.MSYS2${COLORS.reset}`);
38
- console.log(` Then run: ${COLORS.bold}pacman -S mingw-w64-x86_64-gcc${COLORS.reset}`);
39
- } else if (os === "linux") {
40
- console.log(`\n${COLORS.bold}To install GCC on Linux (Ubuntu/Debian):${COLORS.reset}`);
41
- console.log(`${COLORS.cyan}sudo apt update && sudo apt install g++-14 -y${COLORS.reset}`);
42
- console.log(`\nAttempting to install now (may require password)...`);
43
-
44
- // Try to install automatically on Linux if apt is found
45
- try {
46
- const install = spawnSync("sudo", ["apt-get", "install", "-y", "g++-14"], { stdio: "inherit" });
47
- if (install.status === 0) {
48
- console.log(`${COLORS.green}✔ g++-14 installed successfully.${COLORS.reset}`);
49
- // Try to set up symlink if needed or just inform user
50
- return;
51
- }
52
- } catch (e) {
53
- console.error(`${COLORS.red}Automatic installation failed. Please install manually.${COLORS.reset}`);
54
- }
55
- } else if (os === "darwin") {
56
- console.log(`\n${COLORS.bold}To install GCC on macOS:${COLORS.reset}`);
57
- console.log(`${COLORS.cyan}brew install gcc${COLORS.reset}`);
58
- }
59
-
60
- console.log(`\n${COLORS.bold}After installation, please ensure 'g++' is in your PATH and restart your terminal.${COLORS.reset}\n`);
61
- }
62
-
63
- setup();
1
+ import { spawnSync } from "child_process";
2
+ import { platform } from "os";
3
+
4
+ const COLORS = {
5
+ reset: "\x1b[0m",
6
+ green: "\x1b[32m",
7
+ yellow: "\x1b[33m",
8
+ red: "\x1b[31m",
9
+ cyan: "\x1b[36m",
10
+ bold: "\x1b[1m",
11
+ };
12
+
13
+ function checkGpp(): boolean {
14
+ try {
15
+ const result = spawnSync("g++", ["--version"], { encoding: "utf8" });
16
+ return result.status === 0;
17
+ } catch (e) {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ function setup() {
23
+ console.log(`${COLORS.bold}${COLORS.cyan}JSPP: Checking for C++ compiler...${COLORS.reset}`);
24
+
25
+ if (checkGpp()) {
26
+ console.log(`${COLORS.green}✔ g++ found.${COLORS.reset}`);
27
+ return;
28
+ }
29
+
30
+ console.log(`${COLORS.yellow}⚠ g++ (GCC) not found in PATH. JSPP requires a C++23 compatible compiler.${COLORS.reset}`);
31
+
32
+ const os = platform();
33
+
34
+ if (os === "win32") {
35
+ console.log(`\n${COLORS.bold}To install GCC on Windows:${COLORS.reset}`);
36
+ console.log(`1. Install MinGW-w64 via MSYS2: ${COLORS.cyan}https://www.msys2.org/${COLORS.reset}`);
37
+ console.log(`2. Or use winget: ${COLORS.cyan}winget install MSYS2.MSYS2${COLORS.reset}`);
38
+ console.log(` Then run: ${COLORS.bold}pacman -S mingw-w64-x86_64-gcc${COLORS.reset}`);
39
+ } else if (os === "linux") {
40
+ console.log(`\n${COLORS.bold}To install GCC on Linux (Ubuntu/Debian):${COLORS.reset}`);
41
+ console.log(`${COLORS.cyan}sudo apt update && sudo apt install g++-14 -y${COLORS.reset}`);
42
+ console.log(`\nAttempting to install now (may require password)...`);
43
+
44
+ // Try to install automatically on Linux if apt is found
45
+ try {
46
+ const install = spawnSync("sudo", ["apt-get", "install", "-y", "g++-14"], { stdio: "inherit" });
47
+ if (install.status === 0) {
48
+ console.log(`${COLORS.green}✔ g++-14 installed successfully.${COLORS.reset}`);
49
+ // Try to set up symlink if needed or just inform user
50
+ return;
51
+ }
52
+ } catch (e) {
53
+ console.error(`${COLORS.red}Automatic installation failed. Please install manually.${COLORS.reset}`);
54
+ }
55
+ } else if (os === "darwin") {
56
+ console.log(`\n${COLORS.bold}To install GCC on macOS:${COLORS.reset}`);
57
+ console.log(`${COLORS.cyan}brew install gcc${COLORS.reset}`);
58
+ }
59
+
60
+ console.log(`\n${COLORS.bold}After installation, please ensure 'g++' is in your PATH and restart your terminal.${COLORS.reset}\n`);
61
+ }
62
+
63
+ setup();