vladx 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 (42) hide show
  1. package/README.md +256 -0
  2. package/bin/cli.js +486 -0
  3. package/bin/vlad.js +539 -0
  4. package/bin/vladpm.js +710 -0
  5. package/bin/vladx.js +491 -0
  6. package/package.json +57 -0
  7. package/src/engine/jit-compiler.js +285 -0
  8. package/src/engine/vladx-engine.js +941 -0
  9. package/src/index.js +44 -0
  10. package/src/interpreter/interpreter.js +2114 -0
  11. package/src/lexer/lexer.js +658 -0
  12. package/src/lexer/optimized-lexer.js +106 -0
  13. package/src/lexer/regex-cache.js +83 -0
  14. package/src/parser/ast-nodes.js +472 -0
  15. package/src/parser/parser.js +1408 -0
  16. package/src/runtime/advanced-type-system.js +209 -0
  17. package/src/runtime/async-manager.js +252 -0
  18. package/src/runtime/builtins.js +143 -0
  19. package/src/runtime/bundler.js +422 -0
  20. package/src/runtime/cache-manager.js +126 -0
  21. package/src/runtime/data-structures.js +612 -0
  22. package/src/runtime/debugger.js +260 -0
  23. package/src/runtime/enhanced-module-system.js +196 -0
  24. package/src/runtime/environment-enhanced.js +272 -0
  25. package/src/runtime/environment.js +140 -0
  26. package/src/runtime/event-emitter.js +232 -0
  27. package/src/runtime/formatter.js +280 -0
  28. package/src/runtime/functional.js +359 -0
  29. package/src/runtime/io-operations.js +390 -0
  30. package/src/runtime/linter.js +374 -0
  31. package/src/runtime/logging.js +314 -0
  32. package/src/runtime/minifier.js +242 -0
  33. package/src/runtime/module-system.js +377 -0
  34. package/src/runtime/network-operations.js +373 -0
  35. package/src/runtime/profiler.js +295 -0
  36. package/src/runtime/repl.js +336 -0
  37. package/src/runtime/security-manager.js +244 -0
  38. package/src/runtime/source-map-generator.js +208 -0
  39. package/src/runtime/test-runner.js +394 -0
  40. package/src/runtime/transformer.js +277 -0
  41. package/src/runtime/type-system.js +244 -0
  42. package/src/runtime/vladx-object.js +250 -0
package/bin/cli.js ADDED
@@ -0,0 +1,486 @@
1
+ /**
2
+ * CLI — Интерфейс командной строки для VladX
3
+ */
4
+
5
+ import { VladXEngine } from './vladx-engine.js';
6
+ import { Linter } from './runtime/linter.js';
7
+ import { Formatter } from './runtime/formatter.js';
8
+ import { Logging } from './runtime/logging.js';
9
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
10
+ import { resolve, dirname, join, basename } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const logger = new Logging({ level: 'info' });
15
+
16
+ export class CLI {
17
+ constructor() {
18
+ this.engine = null;
19
+ this.commands = new Map();
20
+ this.registerCommands();
21
+ }
22
+
23
+ /**
24
+ * Регистрация команд
25
+ */
26
+ registerCommands() {
27
+ this.commands.set('run', this.run.bind(this));
28
+ this.commands.set('repl', this.repl.bind(this));
29
+ this.commands.set('compile', this.compile.bind(this));
30
+ this.commands.set('lint', this.lint.bind(this));
31
+ this.commands.set('format', this.format.bind(this));
32
+ this.commands.set('test', this.test.bind(this));
33
+ this.commands.set('bundle', this.bundle.bind(this));
34
+ this.commands.set('watch', this.watch.bind(this));
35
+ this.commands.set('debug', this.debug.bind(this));
36
+ this.commands.set('help', this.help.bind(this));
37
+ }
38
+
39
+ /**
40
+ * Запуск CLI
41
+ */
42
+ async runCLI(argv = process.argv) {
43
+ const command = argv[2];
44
+ const args = argv.slice(3);
45
+
46
+ if (!command || !this.commands.has(command)) {
47
+ this.help();
48
+ return;
49
+ }
50
+
51
+ const cmd = this.commands.get(command);
52
+
53
+ try {
54
+ await cmd(args);
55
+ } catch (error) {
56
+ logger.error(`Ошибка: ${error.message}`);
57
+ process.exit(1);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Выполнить файл
63
+ */
64
+ async run(args) {
65
+ if (args.length === 0) {
66
+ logger.error('Укажите файл для выполнения');
67
+ return;
68
+ }
69
+
70
+ const filepath = resolve(args[0]);
71
+ const options = this.parseOptions(args.slice(1));
72
+
73
+ if (!existsSync(filepath)) {
74
+ throw new Error(`Файл не найден: ${filepath}`);
75
+ }
76
+
77
+ const startTime = Date.now();
78
+ this.engine = new VladXEngine({
79
+ debug: options.debug || false,
80
+ strictMode: options.strict || false,
81
+ maxExecutionTime: options.timeout || 30000,
82
+ cache: options.cache,
83
+ security: options.security
84
+ });
85
+
86
+ try {
87
+ const result = await this.engine.executeFile(filepath);
88
+
89
+ if (options.time) {
90
+ const duration = Date.now() - startTime;
91
+ logger.info(`Время выполнения: ${duration}ms`);
92
+ }
93
+
94
+ if (result !== undefined && !options.silent) {
95
+ logger.info('Результат:', result);
96
+ }
97
+
98
+ process.exit(0);
99
+ } catch (error) {
100
+ logger.error(error.message);
101
+ process.exit(1);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * REPL режим
107
+ */
108
+ async repl(args) {
109
+ const options = this.parseOptions(args);
110
+
111
+ this.engine = new VladXEngine({
112
+ debug: options.debug || false,
113
+ cache: options.cache,
114
+ security: options.security
115
+ });
116
+
117
+ await this.engine.repl();
118
+ }
119
+
120
+ /**
121
+ * Компиляция
122
+ */
123
+ async compile(args) {
124
+ if (args.length === 0) {
125
+ logger.error('Укажите файл для компиляции');
126
+ return;
127
+ }
128
+
129
+ const filepath = resolve(args[0]);
130
+ const options = this.parseOptions(args.slice(1));
131
+
132
+ if (!existsSync(filepath)) {
133
+ throw new Error(`Файл не найден: ${filepath}`);
134
+ }
135
+
136
+ this.engine = new VladXEngine();
137
+
138
+ const jsCode = this.engine.compile(readFileSync(filepath, 'utf-8'));
139
+
140
+ let output = options.output || filepath.replace(/\.vx$/, '.js');
141
+
142
+ if (options.format === 'cjs') {
143
+ jsCode = `"use strict";\n${jsCode}`;
144
+ }
145
+
146
+ writeFileSync(output, jsCode, 'utf-8');
147
+ logger.info(`Скомпилировано: ${filepath} -> ${output}`);
148
+ }
149
+
150
+ /**
151
+ * Линтинг
152
+ */
153
+ async lint(args) {
154
+ if (args.length === 0) {
155
+ logger.error('Укажите файл для линтинга');
156
+ return;
157
+ }
158
+
159
+ const filepath = resolve(args[0]);
160
+ const options = this.parseOptions(args.slice(1));
161
+
162
+ if (!existsSync(filepath)) {
163
+ throw new Error(`Файл не найден: ${filepath}`);
164
+ }
165
+
166
+ const linter = new Linter({
167
+ autoFix: options.fix || false,
168
+ config: options.config
169
+ });
170
+
171
+ const source = readFileSync(filepath, 'utf-8');
172
+ const results = linter.lint(source, filepath);
173
+
174
+ if (options.fix && results.all.length > 0) {
175
+ const fixed = linter.fix(source, filepath);
176
+ if (fixed.fixed) {
177
+ writeFileSync(filepath, fixed.source, 'utf-8');
178
+ logger.info('Автофикс применен');
179
+ }
180
+ }
181
+
182
+ if (results.hasErrors) {
183
+ logger.error('Найдены ошибки:');
184
+ results.errors.forEach(err => {
185
+ logger.error(` ${filepath}:${err.line}:${err.column} - ${err.message}`);
186
+ });
187
+ process.exit(1);
188
+ }
189
+
190
+ if (results.warnings.length > 0) {
191
+ logger.warn('Предупреждения:');
192
+ results.warnings.forEach(warn => {
193
+ logger.warn(` ${filepath}:${warn.line}:${warn.column} - ${warn.message}`);
194
+ });
195
+ }
196
+
197
+ if (results.all.length === 0) {
198
+ logger.info('Проблем не найдено');
199
+ }
200
+
201
+ process.exit(0);
202
+ }
203
+
204
+ /**
205
+ * Форматирование
206
+ */
207
+ async format(args) {
208
+ if (args.length === 0) {
209
+ logger.error('Укажите файл для форматирования');
210
+ return;
211
+ }
212
+
213
+ const filepath = resolve(args[0]);
214
+ const options = this.parseOptions(args.slice(1));
215
+
216
+ if (!existsSync(filepath)) {
217
+ throw new Error(`Файл не найден: ${filepath}`);
218
+ }
219
+
220
+ const formatter = new Formatter({
221
+ indentSize: options.indent || 4,
222
+ useTabs: options.tabs || false,
223
+ printWidth: options.width || 100
224
+ });
225
+
226
+ const source = readFileSync(filepath, 'utf-8');
227
+ const formatted = formatter.format(source, filepath);
228
+
229
+ writeFileSync(filepath, formatted, 'utf-8');
230
+ logger.info(`Отформатировано: ${filepath}`);
231
+ }
232
+
233
+ /**
234
+ * Тесты
235
+ */
236
+ async test(args) {
237
+ const TestRunner = await import('./runtime/test-runner.js');
238
+ const runner = new TestRunner.default();
239
+
240
+ const filepath = args[0] ? resolve(args[0]) : null;
241
+
242
+ if (filepath) {
243
+ if (!existsSync(filepath)) {
244
+ throw new Error(`Файл не найден: ${filepath}`);
245
+ }
246
+
247
+ const source = readFileSync(filepath, 'utf-8');
248
+ await this.engine.execute(source, { filename: filepath });
249
+ } else {
250
+ const files = this.findTestFiles();
251
+
252
+ for (const file of files) {
253
+ const source = readFileSync(file, 'utf-8');
254
+ await this.engine.execute(source, { filename: file });
255
+ }
256
+ }
257
+
258
+ const results = await runner.run();
259
+
260
+ if (results.failed > 0) {
261
+ logger.error(`Тесты провалены: ${results.failed}/${results.total}`);
262
+ process.exit(1);
263
+ }
264
+
265
+ logger.info(`Тесты пройдены: ${results.passed}/${results.total}`);
266
+ process.exit(0);
267
+ }
268
+
269
+ /**
270
+ * Сборка модулей
271
+ */
272
+ async bundle(args) {
273
+ if (args.length === 0) {
274
+ logger.error('Укажите точку входа');
275
+ return;
276
+ }
277
+
278
+ const entry = resolve(args[0]);
279
+ const options = this.parseOptions(args.slice(1));
280
+
281
+ if (!existsSync(entry)) {
282
+ throw new Error(`Файл не найден: ${entry}`);
283
+ }
284
+
285
+ const { Bundle } = await import('./runtime/bundler.js');
286
+ const bundler = new Bundle({
287
+ entry,
288
+ output: options.output || 'bundle.vx',
289
+ format: options.format || 'esm',
290
+ minify: options.minify || false,
291
+ sourceMap: options.sourcemap || false
292
+ });
293
+
294
+ const bundled = await bundler.build();
295
+ await bundler.write(bundled);
296
+
297
+ logger.info(`Собрано: ${bundled.modules} модулей -> ${bundler.output}`);
298
+ }
299
+
300
+ /**
301
+ * Watch режим
302
+ */
303
+ async watch(args) {
304
+ if (args.length === 0) {
305
+ logger.error('Укажите файл для слежения');
306
+ return;
307
+ }
308
+
309
+ const filepath = resolve(args[0]);
310
+ const options = this.parseOptions(args.slice(1));
311
+
312
+ if (!existsSync(filepath)) {
313
+ throw new Error(`Файл не найден: ${filepath}`);
314
+ }
315
+
316
+ logger.info(`Слежение за: ${filepath}`);
317
+
318
+ this.engine = new VladXEngine({
319
+ debug: options.debug || false
320
+ });
321
+
322
+ const runFile = async () => {
323
+ try {
324
+ await this.engine.executeFile(filepath);
325
+ } catch (error) {
326
+ logger.error(error.message);
327
+ }
328
+ };
329
+
330
+ await runFile();
331
+
332
+ const fs = await import('fs');
333
+ fs.watchFile(filepath, { interval: options.interval || 1000 }, async () => {
334
+ logger.info('Файл изменен, перезапуск...');
335
+ await runFile();
336
+ });
337
+ }
338
+
339
+ /**
340
+ * Отладка
341
+ */
342
+ async debug(args) {
343
+ if (args.length === 0) {
344
+ logger.error('Укажите файл для отладки');
345
+ return;
346
+ }
347
+
348
+ const filepath = resolve(args[0]);
349
+
350
+ if (!existsSync(filepath)) {
351
+ throw new Error(`Файл не найден: ${filepath}`);
352
+ }
353
+
354
+ this.engine = new VladXEngine({
355
+ debug: true
356
+ });
357
+
358
+ logger.info('Отладочный режим включен');
359
+ logger.info('Команды: точкаОстанова, пошаговыйРежим, продолжить');
360
+
361
+ await this.engine.executeFile(filepath);
362
+ }
363
+
364
+ /**
365
+ * Справка
366
+ */
367
+ help() {
368
+ console.log(`
369
+ VladX - Мощный интерпретируемый язык программирования
370
+
371
+ Использование:
372
+ vladx <команда> [опции] [аргументы]
373
+
374
+ Команды:
375
+ run <файл> Выполнить файл
376
+ repl Интерактивная консоль
377
+ compile <файл> Скомпилировать в JavaScript
378
+ lint <файл> Проверить код на ошибки
379
+ format <файл> Отформатировать код
380
+ test [файл] Запустить тесты
381
+ bundle <entry> Собрать модули
382
+ watch <файл> Смотреть за изменениями файла
383
+ debug <файл> Отладочный режим
384
+ help Показать эту справку
385
+
386
+ Опции:
387
+ --debug Режим отладки
388
+ --strict Строгий режим
389
+ --timeout <ms> Таймаут выполнения
390
+ --output <file> Файл вывода
391
+ --format <format> Формат (esm, cjs, iife, umd)
392
+ --minify Минифицировать
393
+ --fix Автофикс для линтера
394
+ --watch Смотреть за изменениями
395
+ --time Показать время выполнения
396
+ --silent Без вывода результатов
397
+ --indent <n> Размер отступа
398
+ --tabs Использовать табы
399
+ --width <n> Максимальная ширина строки
400
+
401
+ Примеры:
402
+ vladx run main.vx
403
+ vladx repl
404
+ vladx compile main.vx --output main.js
405
+ vladx lint main.vx --fix
406
+ vladx format main.vx --indent 2
407
+ vladx bundle main.vx --format iife --minify
408
+ vladx watch main.vx
409
+ vladx debug main.vx
410
+
411
+ Документация: https://vladx.dev
412
+ `.trim());
413
+ }
414
+
415
+ /**
416
+ * Парсинг опций
417
+ */
418
+ parseOptions(args) {
419
+ const options = {};
420
+
421
+ for (let i = 0; i < args.length; i++) {
422
+ const arg = args[i];
423
+
424
+ if (arg === '--debug') {
425
+ options.debug = true;
426
+ } else if (arg === '--strict') {
427
+ options.strict = true;
428
+ } else if (arg === '--timeout' && args[i + 1]) {
429
+ options.timeout = parseInt(args[++i]);
430
+ } else if (arg === '--output' && args[i + 1]) {
431
+ options.output = args[++i];
432
+ } else if (arg === '--format' && args[i + 1]) {
433
+ options.format = args[++i];
434
+ } else if (arg === '--minify') {
435
+ options.minify = true;
436
+ } else if (arg === '--fix') {
437
+ options.fix = true;
438
+ } else if (arg === '--watch') {
439
+ options.watch = true;
440
+ } else if (arg === '--time') {
441
+ options.time = true;
442
+ } else if (arg === '--silent') {
443
+ options.silent = true;
444
+ } else if (arg === '--indent' && args[i + 1]) {
445
+ options.indent = parseInt(args[++i]);
446
+ } else if (arg === '--tabs') {
447
+ options.tabs = true;
448
+ } else if (arg === '--width' && args[i + 1]) {
449
+ options.width = parseInt(args[++i]);
450
+ }
451
+ }
452
+
453
+ return options;
454
+ }
455
+
456
+ /**
457
+ * Найти тестовые файлы
458
+ */
459
+ findTestFiles() {
460
+ const fs = require('fs');
461
+ const path = require('path');
462
+
463
+ const testFiles = [];
464
+
465
+ const findFiles = (dir) => {
466
+ const files = fs.readdirSync(dir);
467
+
468
+ for (const file of files) {
469
+ const filepath = path.join(dir, file);
470
+ const stat = fs.statSync(filepath);
471
+
472
+ if (stat.isDirectory()) {
473
+ if (file === 'node_modules' || file.startsWith('.')) continue;
474
+ findFiles(filepath);
475
+ } else if (file.endsWith('.test.vx') || file.endsWith('.spec.vx')) {
476
+ testFiles.push(filepath);
477
+ }
478
+ }
479
+ };
480
+
481
+ findFiles(process.cwd());
482
+ return testFiles;
483
+ }
484
+ }
485
+
486
+ export default CLI;