thyscript 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.
Files changed (49) hide show
  1. package/bin/thy-node.js +332 -0
  2. package/bin/thy.js +828 -0
  3. package/bin/thys.js +25 -0
  4. package/examples/calculator.thy +274 -0
  5. package/examples/calculator.thy.js +628 -0
  6. package/examples/hello.thy +34 -0
  7. package/examples/login.thy +382 -0
  8. package/examples/login.thy.js +710 -0
  9. package/package.json +54 -0
  10. package/scripts/_class.js +18 -0
  11. package/scripts/_class2.js +11 -0
  12. package/scripts/_class3.js +21 -0
  13. package/scripts/_dstruct.js +20 -0
  14. package/scripts/_dstruct2.js +24 -0
  15. package/scripts/_scaffold.js +16 -0
  16. package/scripts/_scaffold2.js +16 -0
  17. package/scripts/_scaffold3.js +26 -0
  18. package/scripts/_tpl_compile.js +13 -0
  19. package/scripts/_tpl_test.js +9 -0
  20. package/scripts/_typeof.js +26 -0
  21. package/scripts/_typeof2.js +25 -0
  22. package/scripts/patch_genmethod.js +44 -0
  23. package/scripts/smoke_test.js +167 -0
  24. package/scripts/smoke_test2.js +151 -0
  25. package/scripts/test_control_panel.js +58 -0
  26. package/src/compiler/CodeGenerator.js +1449 -0
  27. package/src/compiler/JITCompiler.js +325 -0
  28. package/src/database/DatabaseEngine.js +931 -0
  29. package/src/errors/ErrorDetector.js +305 -0
  30. package/src/errors/ErrorMessages.js +497 -0
  31. package/src/index.js +169 -0
  32. package/src/lexer/Lexer.js +342 -0
  33. package/src/lexer/TokenTypes.js +1234 -0
  34. package/src/memory/MemoryManager.js +283 -0
  35. package/src/parser/AST.js +606 -0
  36. package/src/parser/Parser.js +1942 -0
  37. package/src/runtime/ThyRuntime.js +265 -0
  38. package/src/runtime/stdlib/ArrayLib.js +207 -0
  39. package/src/runtime/stdlib/FileLib.js +168 -0
  40. package/src/runtime/stdlib/MathLib.js +411 -0
  41. package/src/runtime/stdlib/StringLib.js +387 -0
  42. package/src/server/ControlPanel.js +1188 -0
  43. package/src/server/HTMLCSSEngine.js +866 -0
  44. package/src/server/SecurityEngine.js +714 -0
  45. package/src/server/ServerEngine.js +738 -0
  46. package/tests/test1_math.thy +82 -0
  47. package/tests/test2_oop.thy +133 -0
  48. package/tests/test3_server.thy +143 -0
  49. package/tests/test4_functions.thy +159 -0
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * thy-node - ThyScript direct execution command
6
+ * Usage: thy-node filename.thy
7
+ */
8
+
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+
12
+ // ─── Bootstrap: ensure chalk & ora are available ────────────────────────────
13
+ let chalk, ora;
14
+ try {
15
+ chalk = require('chalk');
16
+ } catch {
17
+ // Minimal fallback so the binary stays usable before deps are installed
18
+ chalk = {
19
+ cyan: s => s, green: s => s, red: s => s, yellow: s => s,
20
+ blue: s => s, magenta: s => s, white: s => s, gray: s => s,
21
+ bold: { cyan: s => s, red: s => s, green: s => s, yellow: s => s, white: s => s },
22
+ bgRed: { white: s => s }, bgCyan: { black: s => s },
23
+ dim: s => s,
24
+ };
25
+ chalk.bold = new Proxy(chalk, { get: (t, p) => t[p] || (s => s) });
26
+ }
27
+ try {
28
+ ora = require('ora');
29
+ } catch {
30
+ // Minimal fallback spinner
31
+ ora = (opts) => {
32
+ const text = typeof opts === 'object' && opts !== null ? opts.text : opts;
33
+ return {
34
+ text,
35
+ start() { process.stdout.write(` ⏳ ${this.text || ''}...\n`); return this; },
36
+ succeed(msg) { process.stdout.write(` ✅ ${msg || this.text}\n`); return this; },
37
+ fail(msg) { process.stdout.write(` ❌ ${msg || this.text}\n`); return this; },
38
+ info(msg) { process.stdout.write(` ℹ️ ${msg || this.text}\n`); return this; },
39
+ stop() { return this; },
40
+ };
41
+ };
42
+ }
43
+
44
+ // ─── ThyScript source modules ────────────────────────────────────────────────
45
+ const THYSCRIPT_ROOT = path.resolve(__dirname, '..');
46
+ function tryRequire(rel) {
47
+ const full = path.join(THYSCRIPT_ROOT, rel);
48
+ try { return require(full); } catch { return null; }
49
+ }
50
+
51
+ const ThyModule = tryRequire('src/index.js');
52
+ const ErrorDetect = tryRequire('src/errors/ErrorDetector.js');
53
+ const MemoryMgr = tryRequire('src/memory/MemoryManager.js');
54
+
55
+ // ─── ASCII Banner ────────────────────────────────────────────────────────────
56
+ function printBanner() {
57
+ const lines = [
58
+ '',
59
+ ' ████████╗██╗ ██╗██╗ ██╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗',
60
+ ' ██╔══╝██║ ██║╚██╗ ██╔╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝',
61
+ ' ██║ ███████║ ╚████╔╝ ███████╗██║ ██████╔╝██║██████╔╝ ██║ ',
62
+ ' ██║ ██╔══██║ ╚██╔╝ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ',
63
+ ' ██║ ██║ ██║ ██║ ███████║╚██████╗██║ ██║██║██║ ██║ ',
64
+ ' ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ',
65
+ '',
66
+ ];
67
+
68
+ const tagline = ' ⚡ High-Performance Language Built on Node.js ⚡';
69
+ const version = ThyModule ? ThyModule.VERSION : '1.0.0';
70
+ const verLine = ` v${version} • ThyScript Runtime • Node.js ${process.version}`;
71
+
72
+ console.log(chalk.cyan(lines.join('\n')));
73
+ console.log(chalk.bold.white(tagline));
74
+ console.log(chalk.gray(verLine));
75
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
76
+ console.log('');
77
+ }
78
+
79
+ // ─── Pretty error renderer ────────────────────────────────────────────────────
80
+ function renderError(err, sourceLines, filename) {
81
+ console.log('');
82
+ console.log(chalk.bgRed.white(` ✖ ${err.type || 'Error'} `), chalk.red(err.message));
83
+
84
+ if (err.line != null) {
85
+ const lineNo = err.line;
86
+ const colNo = err.column || 1;
87
+ const snippet = sourceLines[lineNo - 1] || '';
88
+ const pointer = ' '.repeat(colNo - 1) + '^';
89
+
90
+ console.log('');
91
+ console.log(chalk.gray(` ${filename}:${lineNo}:${colNo}`));
92
+ console.log('');
93
+ console.log(chalk.white(` ${String(lineNo).padStart(4)} │ `) + snippet);
94
+ console.log(chalk.red (` │ ${pointer}`));
95
+ }
96
+
97
+ if (err.suggestion) {
98
+ console.log('');
99
+ console.log(chalk.yellow(` 💡 Fix: ${err.suggestion}`));
100
+ }
101
+ if (err.didYouMean) {
102
+ console.log(chalk.blue(` 🔎 Did you mean: ${chalk.bold.white(err.didYouMean)}?`));
103
+ }
104
+ console.log('');
105
+ }
106
+
107
+ // ─── Argument parsing ────────────────────────────────────────────────────────
108
+ function parseArgs(argv) {
109
+ const args = argv.slice(2); // strip 'node' + script path
110
+ const opts = { filename: null, flags: {} };
111
+
112
+ for (let i = 0; i < args.length; i++) {
113
+ const a = args[i];
114
+ if (a.startsWith('--')) {
115
+ const key = a.slice(2);
116
+ opts.flags[key] = args[i + 1] && !args[i + 1].startsWith('--') ? args[++i] : true;
117
+ } else if (!opts.filename) {
118
+ opts.filename = a;
119
+ }
120
+ }
121
+ return opts;
122
+ }
123
+
124
+ // ─── Performance stats renderer ──────────────────────────────────────────────
125
+ function printStats({ lexMs, parseMs, compileMs, runMs, memBefore, memAfter }) {
126
+ const totalMs = lexMs + parseMs + compileMs + runMs;
127
+ const memDiff = memAfter - memBefore;
128
+
129
+ console.log('');
130
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
131
+ console.log(chalk.bold.cyan(' 📊 Performance Report'));
132
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
133
+
134
+ const row = (label, value, color = chalk.green) =>
135
+ console.log(` ${chalk.gray(label.padEnd(28))} ${color(value)}`);
136
+
137
+ row('Lex time:', `${lexMs.toFixed(2)} ms`);
138
+ row('Parse time:', `${parseMs.toFixed(2)} ms`);
139
+ row('Compile time:', `${compileMs.toFixed(2)} ms`);
140
+ row('Run time:', `${runMs.toFixed(2)} ms`);
141
+ row('Total time:', `${totalMs.toFixed(2)} ms`, chalk.bold.green);
142
+ row('Memory delta:', `${(memDiff / 1024).toFixed(1)} KB`,
143
+ memDiff > 1024 * 1024 ? chalk.yellow : chalk.green);
144
+
145
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
146
+ console.log('');
147
+ }
148
+
149
+ // ─── Main ────────────────────────────────────────────────────────────────────
150
+ async function main() {
151
+ printBanner();
152
+
153
+ const opts = parseArgs(process.argv);
154
+
155
+ // ── No filename ──
156
+ if (!opts.filename) {
157
+ console.log(chalk.yellow(' Usage: thy-node <filename.thy> [--no-stats] [--no-banner]'));
158
+ console.log('');
159
+ console.log(chalk.gray(' Options:'));
160
+ console.log(chalk.gray(' --no-stats Skip performance report'));
161
+ console.log(chalk.gray(' --no-banner Skip ASCII banner'));
162
+ console.log('');
163
+ process.exit(1);
164
+ }
165
+
166
+ // ── Resolve & read file ──
167
+ const filename = path.resolve(process.cwd(), opts.filename);
168
+ const displayName = path.basename(filename);
169
+
170
+ if (!fs.existsSync(filename)) {
171
+ console.log(chalk.red(` ✖ File not found: ${filename}`));
172
+ console.log(chalk.yellow(` 💡 Fix: Make sure the path is correct.`));
173
+ process.exit(1);
174
+ }
175
+
176
+ const ext = path.extname(filename);
177
+ if (ext !== '.thy') {
178
+ console.log(chalk.yellow(` ⚠️ Warning: Expected a .thy file, got '${ext}'.`));
179
+ }
180
+
181
+ let source;
182
+ try {
183
+ source = fs.readFileSync(filename, 'utf8');
184
+ } catch (err) {
185
+ console.log(chalk.red(` ✖ Cannot read file: ${err.message}`));
186
+ process.exit(1);
187
+ }
188
+
189
+ const sourceLines = source.split('\n');
190
+
191
+ // ── Memory tracking ──
192
+ const memMgr = MemoryMgr ? new MemoryMgr() : null;
193
+ const memBefore = process.memoryUsage().heapUsed;
194
+
195
+ // ── Check ThyScript modules loaded ──
196
+ if (!ThyModule) {
197
+ console.log(chalk.yellow(' ⚠️ ThyScript core modules not found. Running in stub mode.'));
198
+ console.log(chalk.gray(` Install ThyScript properly with: npm install`));
199
+ console.log('');
200
+ }
201
+
202
+ // ╔═══════════════╗
203
+ // ║ COMPILATION ║
204
+ // ╚═══════════════╝
205
+ const compilationSpinner = ora({
206
+ text: chalk.cyan(`Compiling ${displayName}...`),
207
+ color: 'cyan',
208
+ }).start();
209
+
210
+ const t0 = Date.now();
211
+ let lexMs = 0, parseMs = 0, compileMs = 0;
212
+ let tokens = [], ast = null, compiled = null;
213
+ let lexer, parser, compiler;
214
+
215
+ try {
216
+ // ── Lex ──
217
+ const t1 = Date.now();
218
+ if (ThyModule && ThyModule.Lexer) {
219
+ lexer = new ThyModule.Lexer(source, filename);
220
+ tokens = lexer.tokenize();
221
+ }
222
+ lexMs = Date.now() - t1;
223
+ compilationSpinner.text = chalk.cyan(`Parsing ${displayName}...`);
224
+
225
+ // ── Parse ──
226
+ const t2 = Date.now();
227
+ if (ThyModule && ThyModule.Parser) {
228
+ parser = new ThyModule.Parser(tokens, source, filename);
229
+ ast = parser.parse();
230
+ }
231
+ parseMs = Date.now() - t2;
232
+ compilationSpinner.text = chalk.cyan(`Compiling to bytecode...`);
233
+
234
+ // ── Compile ──
235
+ const t3 = Date.now();
236
+ if (ThyModule && ThyModule.JITCompiler) {
237
+ compiler = new ThyModule.JITCompiler(ast, source, filename);
238
+ compiled = compiler.compile();
239
+ }
240
+ compileMs = Date.now() - t3;
241
+
242
+ compilationSpinner.succeed(chalk.green(
243
+ `Compiled ${displayName} (lex ${lexMs}ms · parse ${parseMs}ms · compile ${compileMs}ms)`,
244
+ ));
245
+ } catch (err) {
246
+ compilationSpinner.fail(chalk.red(`Compilation failed: ${err.message}`));
247
+ renderError(
248
+ { type: err.type || 'CompileError', message: err.message,
249
+ line: err.line, column: err.column, suggestion: err.suggestion },
250
+ sourceLines, displayName,
251
+ );
252
+ process.exit(1);
253
+ }
254
+
255
+ // ── Error detection ──
256
+ if (ErrorDetect && (tokens.length || ast)) {
257
+ const detector = new ErrorDetect();
258
+ const { errors, warnings } = detector.scan(tokens, ast, source);
259
+
260
+ if (warnings.length) {
261
+ console.log(chalk.yellow(` ⚠️ ${warnings.length} warning(s):`));
262
+ warnings.forEach(w => console.log(chalk.yellow(` ${w.code} ${w.message}`)));
263
+ console.log('');
264
+ }
265
+ if (errors.length) {
266
+ console.log(chalk.red(` ✖ ${errors.length} error(s) detected:`));
267
+ errors.forEach(e => renderError(e, sourceLines, displayName));
268
+ process.exit(1);
269
+ }
270
+ }
271
+
272
+ // ╔═══════════════╗
273
+ // ║ EXECUTION ║
274
+ // ╚═══════════════╝
275
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
276
+ console.log(chalk.bold.cyan(` ▶ Executing ${displayName}`));
277
+ console.log(chalk.cyan(' ' + '─'.repeat(72)));
278
+ console.log('');
279
+
280
+ const runSpinner = ora({ text: chalk.cyan('Starting runtime...'), color: 'cyan' }).start();
281
+
282
+ const t4 = Date.now();
283
+ let runMs = 0;
284
+
285
+ try {
286
+ if (compiler && compiled) {
287
+ runSpinner.stop();
288
+ const runtime = new ThyModule.ThyRuntime({ filename });
289
+ await runtime.init();
290
+ const context = runtime.buildContext();
291
+ await compiler.execute(compiled, context);
292
+ } else if (ThyModule && typeof ThyModule.run === 'function') {
293
+ runSpinner.stop();
294
+ await ThyModule.run(filename);
295
+ } else {
296
+ runSpinner.info(chalk.yellow('No executable runtime available.'));
297
+ }
298
+ runMs = Date.now() - t4;
299
+ } catch (err) {
300
+ runMs = Date.now() - t4;
301
+ if (runSpinner) runSpinner.fail(chalk.red(`Runtime error: ${err.message}`));
302
+ renderError(
303
+ { type: err.type || 'RuntimeError', message: err.message,
304
+ line: err.line, column: err.column, suggestion: err.suggestion },
305
+ sourceLines, displayName,
306
+ );
307
+ process.exit(1);
308
+ }
309
+
310
+ // ── Final status ──
311
+ console.log('');
312
+ console.log(chalk.green(` ✔ ${displayName} finished successfully.`));
313
+
314
+ const memAfter = process.memoryUsage().heapUsed;
315
+
316
+ if (!opts.flags['no-stats']) {
317
+ printStats({ lexMs, parseMs, compileMs, runMs, memBefore, memAfter });
318
+ }
319
+
320
+ if (memMgr) {
321
+ const leak = memMgr.checkLeak();
322
+ if (leak) {
323
+ console.log(chalk.yellow(` ⚠️ Memory warning: ${leak}`));
324
+ }
325
+ }
326
+ }
327
+
328
+ main().catch(err => {
329
+ console.error(chalk.red(` ✖ Unexpected error: ${err.message}`));
330
+ if (process.env.THY_DEBUG) console.error(err.stack);
331
+ process.exit(1);
332
+ });