vladx 1.3.2 → 1.5.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 (43) hide show
  1. package/bin/vladx +4 -1
  2. package/examples/stdlib/ambiente.vx +8 -0
  3. package/examples/stdlib/archivio_extra.vx +11 -0
  4. package/examples/stdlib/asserzione.vx +11 -0
  5. package/examples/stdlib/client_web.vx +7 -0
  6. package/examples/stdlib/codifica.vx +8 -0
  7. package/examples/stdlib/collezioni.vx +11 -0
  8. package/examples/stdlib/compressione.vx +10 -0
  9. package/examples/stdlib/console.vx +14 -0
  10. package/examples/stdlib/cripto.vx +8 -0
  11. package/examples/stdlib/dati.vx +21 -0
  12. package/examples/stdlib/eventi.vx +10 -0
  13. package/examples/stdlib/json_extra.vx +7 -0
  14. package/examples/stdlib/matematica.vx +9 -0
  15. package/examples/stdlib/percorso.vx +9 -0
  16. package/examples/stdlib/processo.vx +9 -0
  17. package/examples/stdlib/server_web.vx +10 -0
  18. package/examples/stdlib/sql_helper.vx +7 -0
  19. package/examples/stdlib/tempo.vx +9 -0
  20. package/examples/stdlib/testo.vx +10 -0
  21. package/examples/stdlib/url.vx +11 -0
  22. package/examples/stdlib/validazione.vx +5 -0
  23. package/package.json +6 -2
  24. package/programs/1/index.vx +16 -4
  25. package/programs/main/index.vx +11 -8
  26. package/programs/main/passports/Alina.json +1 -0
  27. package/programs/main/passports/Tanya.json +1 -0
  28. package/programs/main/passports/vlad.json +1 -0
  29. package/programs/main/test_async.vx +25 -0
  30. package/programs/main/test_async_advanced.vx +35 -0
  31. package/programs/main/test_backend.vx +33 -0
  32. package/programs/tests/test_new_features.vx +53 -0
  33. package/programs/tests/test_stdlib.vx +26 -0
  34. package/programs/tests/test_templates.vx +8 -0
  35. package/src/cli/cli.js +8 -6
  36. package/src/interpreter/interpreter.js +388 -170
  37. package/src/lexer/lexer.js +5 -1
  38. package/src/lexer/tokens.js +9 -1
  39. package/src/parser/ast.js +59 -4
  40. package/src/parser/parser.js +152 -18
  41. package/src/repl/repl.js +5 -5
  42. package/src/stdlib/registry.js +301 -0
  43. /package/programs/main/passports/{Vlad.txt → Vlad.json} +0 -0
@@ -59,20 +59,31 @@ class ReturnValue {
59
59
  class BreakSignal { }
60
60
  class ContinueSignal { }
61
61
 
62
+ class VladXPromise {
63
+ constructor(promise) {
64
+ this.promise = promise;
65
+ }
66
+
67
+ async wait() {
68
+ return await this.promise;
69
+ }
70
+ }
71
+
62
72
  class VladXFunction {
63
- constructor(declaration, closure) {
73
+ constructor(declaration, closure, isAsync = false) {
64
74
  this.declaration = declaration;
65
75
  this.closure = closure;
76
+ this.isAsync = isAsync;
66
77
  }
67
78
 
68
- call(interpreter, args) {
79
+ async call(interpreter, args) {
69
80
  const env = new Environment(this.closure);
70
81
  for (let i = 0; i < this.declaration.params.length; i++) {
71
82
  env.define(this.declaration.params[i], args[i] !== undefined ? args[i] : null);
72
83
  }
73
84
 
74
85
  try {
75
- interpreter.executeBlock(this.declaration.body.body, env);
86
+ await interpreter.executeBlock(this.declaration.body.body, env);
76
87
  } catch (e) {
77
88
  if (e instanceof ReturnValue) {
78
89
  return e.value;
@@ -84,13 +95,15 @@ class VladXFunction {
84
95
  }
85
96
 
86
97
  class ArrowFunc {
87
- constructor(params, body, closure) {
98
+ constructor(params, body, closure, isAsync = false) {
88
99
  this.params = params;
89
100
  this.body = body;
90
101
  this.closure = closure;
102
+ this.isAsync = isAsync;
91
103
  }
104
+ // ... call unchanged except it returns result ...
92
105
 
93
- call(interpreter, args) {
106
+ async call(interpreter, args) {
94
107
  const env = new Environment(this.closure);
95
108
  for (let i = 0; i < this.params.length; i++) {
96
109
  env.define(this.params[i], args[i] !== undefined ? args[i] : null);
@@ -98,7 +111,7 @@ class ArrowFunc {
98
111
 
99
112
  if (this.body.type === 'BlockStatement') {
100
113
  try {
101
- interpreter.executeBlock(this.body.body, env);
114
+ await interpreter.executeBlock(this.body.body, env);
102
115
  } catch (e) {
103
116
  if (e instanceof ReturnValue) {
104
117
  return e.value;
@@ -107,11 +120,7 @@ class ArrowFunc {
107
120
  }
108
121
  return null;
109
122
  } else {
110
- const previousEnv = interpreter.environment;
111
- interpreter.environment = env;
112
- const result = interpreter.evaluate(this.body);
113
- interpreter.environment = previousEnv;
114
- return result;
123
+ return await interpreter.evaluate(this.body, env);
115
124
  }
116
125
  }
117
126
  }
@@ -163,7 +172,11 @@ class BoundMethod {
163
172
  this.instance = instance;
164
173
  }
165
174
 
166
- call(interpreter, args) {
175
+ get isAsync() {
176
+ return this.method.isAsync;
177
+ }
178
+
179
+ async call(interpreter, args) {
167
180
  const env = new Environment(this.method.closure);
168
181
  env.define('questo', this.instance);
169
182
  for (let i = 0; i < this.method.declaration.params.length; i++) {
@@ -171,7 +184,7 @@ class BoundMethod {
171
184
  }
172
185
 
173
186
  try {
174
- interpreter.executeBlock(this.method.declaration.body.body, env);
187
+ await interpreter.executeBlock(this.method.declaration.body.body, env);
175
188
  } catch (e) {
176
189
  if (e instanceof ReturnValue) {
177
190
  return e.value;
@@ -187,8 +200,11 @@ const path = require('path');
187
200
  const http = require('http');
188
201
  const https = require('https');
189
202
  const { execSync } = require('child_process');
203
+ const sqlite3 = require('better-sqlite3');
204
+ const mysql = require('mysql2/promise');
190
205
  const { Lexer } = require('../lexer/lexer.js');
191
206
  const { Parser } = require('../parser/parser.js');
207
+ const stdRegistry = require('../stdlib/registry.js');
192
208
 
193
209
  class Interpreter {
194
210
  constructor() {
@@ -210,7 +226,11 @@ class Interpreter {
210
226
  });
211
227
 
212
228
  this.globals.define('tipo', {
213
- call: (_, args) => typeof args[0]
229
+ call: (_, args) => {
230
+ const val = args[0];
231
+ if (val instanceof VladXPromise) return 'promessa';
232
+ return typeof val;
233
+ }
214
234
  });
215
235
 
216
236
  this.globals.define('numero', {
@@ -242,6 +262,21 @@ class Interpreter {
242
262
  }
243
263
  });
244
264
 
265
+ this.globals.define('Buffer', {
266
+ alloc: { call: (_, args) => Buffer.alloc(args[0]) },
267
+ from: { call: (_, args) => Buffer.from(args[0], args[1]) },
268
+ isBuffer: { call: (_, args) => Buffer.isBuffer(args[0]) }
269
+ });
270
+
271
+ this.globals.define('Base64', {
272
+ codifica: {
273
+ call: (_, args) => Buffer.from(String(args[0])).toString('base64')
274
+ },
275
+ decodifica: {
276
+ call: (_, args) => Buffer.from(String(args[0]), 'base64').toString('utf8')
277
+ }
278
+ });
279
+
245
280
  this.globals.define('aspetta', {
246
281
  call: (_, args) => {
247
282
  const ms = args[0];
@@ -306,6 +341,68 @@ class Interpreter {
306
341
  };
307
342
  this.globals.define('Archivio', Archivio);
308
343
 
344
+ // --- DATABASE (SQLite) ---
345
+ const SQLite = {
346
+ apri: {
347
+ call: (_, args) => {
348
+ const db = new sqlite3(args[0]);
349
+ return {
350
+ interroga: {
351
+ call: (_, qArgs) => {
352
+ try {
353
+ return db.prepare(qArgs[0]).all(qArgs.slice(1));
354
+ } catch (e) {
355
+ throw new Error(`Errore query SQLite: ${e.message}`);
356
+ }
357
+ }
358
+ },
359
+ esegui: {
360
+ call: (_, qArgs) => {
361
+ try {
362
+ const result = db.prepare(qArgs[0]).run(qArgs.slice(1));
363
+ return {
364
+ modifiche: result.changes,
365
+ ultimoId: result.lastInsertRowid
366
+ };
367
+ } catch (e) {
368
+ throw new Error(`Errore esecuzione SQLite: ${e.message}`);
369
+ }
370
+ }
371
+ },
372
+ chiudi: { call: () => db.close() }
373
+ };
374
+ }
375
+ }
376
+ };
377
+ this.globals.define('SQLite', SQLite);
378
+
379
+ // --- DATABASE (MySQL) ---
380
+ const MySQL = {
381
+ connetti: {
382
+ call: async (_, args) => {
383
+ try {
384
+ const conn = await mysql.createConnection(args[0]);
385
+ return {
386
+ interroga: {
387
+ call: async (_, qArgs) => {
388
+ try {
389
+ const [rows] = await conn.execute(qArgs[0], qArgs.slice(1));
390
+ return rows;
391
+ } catch (e) {
392
+ throw new Error(`Errore query MySQL: ${e.message}`);
393
+ }
394
+ }
395
+ },
396
+ chiudi: { call: async () => await conn.end() }
397
+ };
398
+ } catch (e) {
399
+ throw new Error(`Errore connessione MySQL: ${e.message}`);
400
+ }
401
+ }
402
+ }
403
+ };
404
+ this.globals.define('MySQL', MySQL);
405
+
309
406
  // --- SISTEMA (Process/OS) ---
310
407
  const Sistema = {
311
408
  esegui: {
@@ -374,13 +471,34 @@ class Interpreter {
374
471
  }
375
472
  };
376
473
  this.globals.define('Rete', Rete);
474
+
475
+ // --- MATEMATICA ---
476
+ const Matematica = {
477
+ casuale: { call: () => Math.random() },
478
+ rotonda: { call: (_, args) => Math.round(args[0]) },
479
+ radice: { call: (_, args) => Math.sqrt(args[0]) },
480
+ min: { call: (_, args) => Math.min(...args) },
481
+ max: { call: (_, args) => Math.max(...args) },
482
+ piGreco: Math.PI,
483
+ E: Math.E
484
+ };
485
+ this.globals.define('Matematica', Matematica);
486
+
487
+ // --- TEMPO ---
488
+ const Tempo = {
489
+ ora: { call: () => new Date().toLocaleTimeString() },
490
+ data: { call: () => new Date().toLocaleDateString() },
491
+ timestamp: { call: () => Date.now() },
492
+ pausa: { call: async (_, args) => new Promise(res => setTimeout(res, args[0])) }
493
+ };
494
+ this.globals.define('Tempo', Tempo);
377
495
  }
378
496
 
379
- interpret(program) {
497
+ async interpret(program) {
380
498
  this.output = [];
381
499
  try {
382
500
  for (const statement of program.body) {
383
- this.execute(statement);
501
+ await this.execute(statement, this.globals);
384
502
  }
385
503
  } catch (error) {
386
504
  if (error instanceof ReturnValue) {
@@ -391,59 +509,102 @@ class Interpreter {
391
509
  return this.output;
392
510
  }
393
511
 
394
- execute(node) {
512
+ async execute(node, env) {
395
513
  switch (node.type) {
396
514
  case 'VariableDeclaration':
397
- return this.executeVariableDeclaration(node);
515
+ return await this.executeVariableDeclaration(node, env);
398
516
  case 'FunctionDeclaration':
399
- return this.executeFunctionDeclaration(node);
517
+ return this.executeFunctionDeclaration(node, env);
400
518
  case 'ClassDeclaration':
401
- return this.executeClassDeclaration(node);
519
+ return this.executeClassDeclaration(node, env);
402
520
  case 'BlockStatement':
403
- return this.executeBlock(node.body, new Environment(this.environment));
521
+ return await this.executeBlock(node.body, new Environment(env));
404
522
  case 'IfStatement':
405
- return this.executeIfStatement(node);
523
+ return await this.executeIfStatement(node, env);
406
524
  case 'WhileStatement':
407
- return this.executeWhileStatement(node);
525
+ return await this.executeWhileStatement(node, env);
408
526
  case 'ForStatement':
409
- return this.executeForStatement(node);
527
+ return await this.executeForStatement(node, env);
528
+ case 'SwitchStatement':
529
+ return await this.executeSwitchStatement(node, env);
410
530
  case 'ReturnStatement':
411
- throw new ReturnValue(node.argument ? this.evaluate(node.argument) : null);
531
+ throw new ReturnValue(node.argument ? await this.evaluate(node.argument, env) : null);
412
532
  case 'BreakStatement':
413
533
  throw new BreakSignal();
414
534
  case 'ContinueStatement':
415
535
  throw new ContinueSignal();
416
536
  case 'TryStatement':
417
- return this.executeTryStatement(node);
537
+ return await this.executeTryStatement(node, env);
418
538
  case 'ThrowStatement':
419
- return this.executeThrowStatement(node);
539
+ return await this.executeThrowStatement(node, env);
420
540
  case 'ExportNamedDeclaration':
421
- return this.executeExportNamedDeclaration(node);
541
+ return await this.executeExportNamedDeclaration(node, env);
422
542
  case 'ImportDeclaration':
423
- return this.executeImportDeclaration(node);
543
+ return await this.executeImportDeclaration(node, env);
424
544
  case 'PrintStatement':
425
- return this.executePrintStatement(node);
545
+ return await this.executePrintStatement(node, env);
426
546
  case 'ExpressionStatement':
427
- return this.evaluate(node.expression);
547
+ return await this.evaluate(node.expression, env);
428
548
  default:
429
549
  throw new Error(`Tipo statement sconosciuto: ${node.type}`);
430
550
  }
431
551
  }
432
552
 
433
- executeVariableDeclaration(node) {
434
- const value = node.value ? this.evaluate(node.value) : null;
435
- this.environment.define(node.name, value, node.isConstant);
553
+ async executeVariableDeclaration(node, env) {
554
+ const value = node.value ? await this.evaluate(node.value, env) : null;
555
+
556
+ if (typeof node.name === 'string') {
557
+ env.define(node.name, value, node.isConstant);
558
+ } else if (node.name.type === 'ArrayPattern') {
559
+ if (!Array.isArray(value)) throw new Error('Destrutturazione array fallita: il valore non è un array');
560
+ for (let i = 0; i < node.name.elements.length; i++) {
561
+ env.define(node.name.elements[i], value[i] !== undefined ? value[i] : null, node.isConstant);
562
+ }
563
+ } else if (node.name.type === 'ObjectPattern') {
564
+ if (typeof value !== 'object' || value === null) throw new Error('Destrutturazione oggetto fallita: il valore non è un oggetto');
565
+ for (const prop of node.name.properties) {
566
+ env.define(prop, value[prop] !== undefined ? value[prop] : null, node.isConstant);
567
+ }
568
+ }
436
569
  }
437
570
 
438
- executeFunctionDeclaration(node) {
439
- const func = new VladXFunction(node, this.environment);
440
- this.environment.define(node.name, func);
571
+ async executeSwitchStatement(node, env) {
572
+ const discriminant = await this.evaluate(node.discriminant, env);
573
+ let matched = false;
574
+ let defaultCase = null;
575
+
576
+ for (const switchCase of node.cases) {
577
+ if (switchCase.test === null) {
578
+ defaultCase = switchCase;
579
+ continue;
580
+ }
581
+
582
+ const testValue = await this.evaluate(switchCase.test, env);
583
+ if (matched || discriminant === testValue) {
584
+ matched = true;
585
+ try {
586
+ await this.executeBlock(switchCase.consequent, env);
587
+ } catch (e) {
588
+ if (e instanceof BreakSignal) return;
589
+ throw e;
590
+ }
591
+ }
592
+ }
593
+
594
+ if (!matched && defaultCase) {
595
+ await this.executeBlock(defaultCase.consequent, env);
596
+ }
597
+ }
598
+
599
+ executeFunctionDeclaration(node, env) {
600
+ const func = new VladXFunction(node, env, node.isAsync);
601
+ env.define(node.name, func);
441
602
  }
442
603
 
443
- executeClassDeclaration(node) {
604
+ executeClassDeclaration(node, env) {
444
605
  let superclass = null;
445
606
  if (node.superclass) {
446
- const superclassValue = this.environment.get(node.superclass);
607
+ const superclassValue = env.get(node.superclass);
447
608
  if (!(superclassValue instanceof VladXClass)) {
448
609
  throw new Error(`"${node.superclass}" non è una classe`);
449
610
  }
@@ -452,40 +613,34 @@ class Interpreter {
452
613
 
453
614
  const methods = new Map();
454
615
  if (node.constructor) {
455
- methods.set('costruttore', new VladXFunction(node.constructor, this.environment));
616
+ methods.set('costruttore', new VladXFunction(node.constructor, env, false));
456
617
  }
457
618
  for (const method of node.methods) {
458
- methods.set(method.name, new VladXFunction(method, this.environment));
619
+ methods.set(method.name, new VladXFunction(method, env, method.isAsync));
459
620
  }
460
621
 
461
622
  const klass = new VladXClass(node.name, superclass, node.constructor, methods);
462
- this.environment.define(node.name, klass);
623
+ env.define(node.name, klass);
463
624
  }
464
625
 
465
- executeBlock(statements, env) {
466
- const previousEnv = this.environment;
467
- this.environment = env;
468
- try {
469
- for (const statement of statements) {
470
- this.execute(statement);
471
- }
472
- } finally {
473
- this.environment = previousEnv;
626
+ async executeBlock(statements, env) {
627
+ for (const statement of statements) {
628
+ await this.execute(statement, env);
474
629
  }
475
630
  }
476
631
 
477
- executeIfStatement(node) {
478
- if (this.isTruthy(this.evaluate(node.condition))) {
479
- this.execute(node.consequent);
632
+ async executeIfStatement(node, env) {
633
+ if (this.isTruthy(await this.evaluate(node.condition, env))) {
634
+ await this.execute(node.consequent, env);
480
635
  } else if (node.alternate) {
481
- this.execute(node.alternate);
636
+ await this.execute(node.alternate, env);
482
637
  }
483
638
  }
484
639
 
485
- executeWhileStatement(node) {
486
- while (this.isTruthy(this.evaluate(node.condition))) {
640
+ async executeWhileStatement(node, env) {
641
+ while (this.isTruthy(await this.evaluate(node.condition, env))) {
487
642
  try {
488
- this.execute(node.body);
643
+ await this.execute(node.body, env);
489
644
  } catch (e) {
490
645
  if (e instanceof BreakSignal) break;
491
646
  if (e instanceof ContinueSignal) continue;
@@ -494,35 +649,33 @@ class Interpreter {
494
649
  }
495
650
  }
496
651
 
497
- executeForStatement(node) {
498
- const forEnv = new Environment(this.environment);
499
- const previousEnv = this.environment;
500
- this.environment = forEnv;
652
+ async executeForStatement(node, env) {
653
+ const forEnv = new Environment(env);
501
654
 
502
655
  try {
503
- if (node.init) this.execute(node.init);
656
+ if (node.init) await this.execute(node.init, forEnv);
504
657
 
505
- while (!node.condition || this.isTruthy(this.evaluate(node.condition))) {
658
+ while (!node.condition || this.isTruthy(await this.evaluate(node.condition, forEnv))) {
506
659
  try {
507
- this.execute(node.body);
660
+ await this.execute(node.body, forEnv);
508
661
  } catch (e) {
509
662
  if (e instanceof BreakSignal) break;
510
663
  if (e instanceof ContinueSignal) {
511
- if (node.update) this.evaluate(node.update);
664
+ if (node.update) await this.evaluate(node.update, forEnv);
512
665
  continue;
513
666
  }
514
667
  throw e;
515
668
  }
516
- if (node.update) this.evaluate(node.update);
669
+ if (node.update) await this.evaluate(node.update, forEnv);
517
670
  }
518
671
  } finally {
519
- this.environment = previousEnv;
672
+ // No need to restore since we didn't mutate this.environment
520
673
  }
521
674
  }
522
675
 
523
- executeTryStatement(node) {
676
+ async executeTryStatement(node, env) {
524
677
  try {
525
- this.execute(node.block);
678
+ await this.execute(node.block, env);
526
679
  } catch (error) {
527
680
  // Se è un ReturnValue o Break/Continue Signal, non catturarlo qui
528
681
  if (error instanceof ReturnValue || error instanceof BreakSignal || error instanceof ContinueSignal) {
@@ -530,100 +683,105 @@ class Interpreter {
530
683
  }
531
684
 
532
685
  if (node.handler) {
533
- const catchEnv = new Environment(this.environment);
686
+ const catchEnv = new Environment(env);
534
687
  // Il valore errore può essere quello lanciato da LANCIA o un errore JS
688
+ // Se è un errore JS, potrebbe essere un Error object o stringa
535
689
  const errorValue = error instanceof Error ? error.message : error;
536
690
  catchEnv.define(node.handler.param, errorValue);
537
691
 
538
- const previousEnv = this.environment;
539
- this.environment = catchEnv;
540
- try {
541
- this.execute(node.handler.body);
542
- } finally {
543
- this.environment = previousEnv;
544
- }
692
+ await this.execute(node.handler.body, catchEnv);
545
693
  } else if (!node.finalizer) {
546
694
  throw error;
547
695
  }
548
696
  } finally {
549
697
  if (node.finalizer) {
550
- this.execute(node.finalizer);
698
+ await this.execute(node.finalizer, env);
551
699
  }
552
700
  }
553
701
  }
554
702
 
555
- executeThrowStatement(node) {
556
- const value = this.evaluate(node.argument);
703
+ async executeThrowStatement(node, env) {
704
+ const value = await this.evaluate(node.argument, env);
557
705
  throw value;
558
706
  }
559
707
 
560
- executeExportNamedDeclaration(node) {
561
- this.execute(node.declaration);
708
+ async executeExportNamedDeclaration(node, env) {
709
+ await this.execute(node.declaration, env);
562
710
  const name = node.declaration.name;
563
- const value = this.environment.get(name);
711
+ const value = env.get(name);
564
712
  this.exportedSymbols.set(name, value);
565
713
  }
566
714
 
567
- executeImportDeclaration(node) {
715
+ async executeImportDeclaration(node, env) {
568
716
  const sourcePath = node.source;
569
- let fullPath;
717
+ let moduleExports;
570
718
 
571
- if (sourcePath.startsWith('./') || sourcePath.startsWith('../')) {
572
- fullPath = path.resolve(path.dirname(this.currentPath), sourcePath);
573
- } else {
574
- // Check vladx_modules
575
- fullPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
576
- if (!fullPath.endsWith('.vx')) fullPath += '.vx';
577
- if (!fs.existsSync(fullPath)) {
578
- // Try index.vx inside the module folder
579
- const folderPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
580
- fullPath = path.join(folderPath, 'index.vx');
719
+ // Check if it's a standard library module
720
+ if (sourcePath.startsWith('@std/')) {
721
+ if (stdRegistry[sourcePath]) {
722
+ moduleExports = stdRegistry[sourcePath];
723
+ } else {
724
+ throw new Error(`Modulo standard non trovato: ${sourcePath}`);
581
725
  }
582
- }
583
-
584
- if (!fs.existsSync(fullPath)) {
585
- throw new Error(`Modulo non trovato: ${sourcePath}`);
586
- }
587
-
588
- let moduleExports;
589
- if (this.modules.has(fullPath)) {
590
- moduleExports = this.modules.get(fullPath);
591
726
  } else {
592
- // Load and execute module
593
- const content = fs.readFileSync(fullPath, 'utf8');
594
- const lexer = new Lexer(content);
595
- const tokens = lexer.tokenize();
596
- const parser = new Parser(tokens);
597
- const program = parser.parse();
727
+ let fullPath;
598
728
 
599
- const subInterpreter = new Interpreter();
600
- // Sharing the same modules cache
601
- subInterpreter.modules = this.modules;
602
- subInterpreter.currentPath = fullPath;
729
+ if (sourcePath.startsWith('./') || sourcePath.startsWith('../')) {
730
+ fullPath = path.resolve(path.dirname(this.currentPath), sourcePath);
731
+ } else {
732
+ // Check vladx_modules
733
+ fullPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
734
+ if (!fullPath.endsWith('.vx')) fullPath += '.vx';
735
+ if (!fs.existsSync(fullPath)) {
736
+ // Try index.vx inside the module folder
737
+ const folderPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
738
+ fullPath = path.join(folderPath, 'index.vx');
739
+ }
740
+ }
741
+
742
+ if (!fs.existsSync(fullPath)) {
743
+ throw new Error(`Modulo non trovato: ${sourcePath}`);
744
+ }
603
745
 
604
- subInterpreter.interpret(program);
605
- moduleExports = subInterpreter.exportedSymbols;
606
- this.modules.set(fullPath, moduleExports);
746
+ if (this.modules.has(fullPath)) {
747
+ moduleExports = this.modules.get(fullPath);
748
+ } else {
749
+ // Load and execute module
750
+ const content = fs.readFileSync(fullPath, 'utf8');
751
+ const lexer = new Lexer(content);
752
+ const tokens = lexer.tokenize();
753
+ const parser = new Parser(tokens);
754
+ const program = parser.parse();
755
+
756
+ const subInterpreter = new Interpreter();
757
+ // Sharing the same modules cache
758
+ subInterpreter.modules = this.modules;
759
+ subInterpreter.currentPath = fullPath;
760
+
761
+ await subInterpreter.interpret(program);
762
+ moduleExports = subInterpreter.exportedSymbols;
763
+ this.modules.set(fullPath, moduleExports);
764
+ }
607
765
  }
608
766
 
609
767
  // Import specified symbols
610
768
  for (const specifier of node.specifiers) {
611
769
  if (moduleExports.has(specifier)) {
612
- this.environment.define(specifier, moduleExports.get(specifier));
770
+ env.define(specifier, moduleExports.get(specifier));
613
771
  } else {
614
772
  throw new Error(`Il modulo "${sourcePath}" non esporta "${specifier}"`);
615
773
  }
616
774
  }
617
775
  }
618
776
 
619
- executePrintStatement(node) {
620
- const value = this.evaluate(node.argument);
777
+ async executePrintStatement(node, env) {
778
+ const value = await this.evaluate(node.argument, env);
621
779
  const output = this.stringify(value);
622
780
  console.log(output);
623
781
  this.output.push(output);
624
782
  }
625
783
 
626
- evaluate(node) {
784
+ async evaluate(node, env) {
627
785
  switch (node.type) {
628
786
  case 'NumericLiteral':
629
787
  return node.value;
@@ -634,47 +792,59 @@ class Interpreter {
634
792
  case 'NullLiteral':
635
793
  return null;
636
794
  case 'Identifier':
637
- return this.environment.get(node.name);
795
+ return env.get(node.name);
638
796
  case 'ThisExpression':
639
- return this.environment.get('questo');
797
+ return env.get('questo');
640
798
  case 'ArrayLiteral':
641
- return node.elements.map(el => this.evaluate(el));
799
+ return await Promise.all(node.elements.map(el => this.evaluate(el, env)));
642
800
  case 'ObjectLiteral':
643
801
  const obj = {};
644
802
  for (const prop of node.properties) {
645
- obj[prop.key] = this.evaluate(prop.value);
803
+ obj[prop.key] = await this.evaluate(prop.value, env);
646
804
  }
647
805
  return obj;
648
806
  case 'BinaryExpression':
649
- return this.evaluateBinaryExpression(node);
807
+ return await this.evaluateBinaryExpression(node, env);
650
808
  case 'LogicalExpression':
651
- return this.evaluateLogicalExpression(node);
809
+ return await this.evaluateLogicalExpression(node, env);
652
810
  case 'UnaryExpression':
653
- return this.evaluateUnaryExpression(node);
811
+ return await this.evaluateUnaryExpression(node, env);
654
812
  case 'AssignmentExpression':
655
- return this.evaluateAssignment(node);
813
+ return await this.evaluateAssignment(node, env);
656
814
  case 'UpdateExpression':
657
- return this.evaluateUpdateExpression(node);
815
+ return await this.evaluateUpdateExpression(node, env);
658
816
  case 'CallExpression':
659
- return this.evaluateCallExpression(node);
817
+ return await this.evaluateCallExpression(node, env);
660
818
  case 'NewExpression':
661
- return this.evaluateNewExpression(node);
819
+ return await this.evaluateNewExpression(node, env);
662
820
  case 'MemberExpression':
663
- return this.evaluateMemberExpression(node);
821
+ return await this.evaluateMemberExpression(node, env);
664
822
  case 'ArrowFunction':
665
- return new ArrowFunc(node.params, node.body, this.environment);
823
+ return new ArrowFunc(node.params, node.body, env, node.isAsync);
824
+ case 'ConditionalExpression':
825
+ return await this.evaluateConditionalExpression(node, env);
666
826
  case 'TemplateLiteral':
667
- return this.evaluateTemplateLiteral(node);
827
+ return await this.evaluateTemplateLiteral(node, env);
828
+ case 'AwaitExpression':
829
+ return await this.evaluateAwaitExpression(node, env);
668
830
  default:
669
831
  throw new Error(`Tipo espressione sconosciuto: ${node.type}`);
670
832
  }
671
833
  }
672
834
 
673
- evaluateTemplateLiteral(node) {
835
+ async evaluateAwaitExpression(node, env) {
836
+ const value = await this.evaluate(node.argument, env);
837
+ if (value instanceof VladXPromise) {
838
+ return await value.wait();
839
+ }
840
+ return value;
841
+ }
842
+
843
+ async evaluateTemplateLiteral(node, env) {
674
844
  let result = node.quasis[0];
675
845
 
676
846
  for (let i = 0; i < node.expressions.length; i++) {
677
- const value = this.evaluate(node.expressions[i]);
847
+ const value = await this.evaluate(node.expressions[i], env);
678
848
  result += this.stringify(value);
679
849
  result += node.quasis[i + 1];
680
850
  }
@@ -682,9 +852,9 @@ class Interpreter {
682
852
  return result;
683
853
  }
684
854
 
685
- evaluateBinaryExpression(node) {
686
- const left = this.evaluate(node.left);
687
- const right = this.evaluate(node.right);
855
+ async evaluateBinaryExpression(node, env) {
856
+ const left = await this.evaluate(node.left, env);
857
+ const right = await this.evaluate(node.right, env);
688
858
 
689
859
  switch (node.operator) {
690
860
  case '+':
@@ -709,17 +879,27 @@ class Interpreter {
709
879
  }
710
880
  }
711
881
 
712
- evaluateLogicalExpression(node) {
713
- const left = this.evaluate(node.left);
882
+ async evaluateLogicalExpression(node, env) {
883
+ const left = await this.evaluate(node.left, env);
714
884
  if (node.operator === '||') {
715
- return this.isTruthy(left) ? left : this.evaluate(node.right);
885
+ return this.isTruthy(left) ? left : await this.evaluate(node.right, env);
886
+ } else if (node.operator === '&&') {
887
+ return !this.isTruthy(left) ? left : await this.evaluate(node.right, env);
888
+ } else if (node.operator === '??') {
889
+ return (left !== null && left !== undefined) ? left : await this.evaluate(node.right, env);
890
+ }
891
+ }
892
+
893
+ async evaluateConditionalExpression(node, env) {
894
+ if (this.isTruthy(await this.evaluate(node.test, env))) {
895
+ return await this.evaluate(node.consequent, env);
716
896
  } else {
717
- return !this.isTruthy(left) ? left : this.evaluate(node.right);
897
+ return await this.evaluate(node.alternate, env);
718
898
  }
719
899
  }
720
900
 
721
- evaluateUnaryExpression(node) {
722
- const argument = this.evaluate(node.argument);
901
+ async evaluateUnaryExpression(node, env) {
902
+ const argument = await this.evaluate(node.argument, env);
723
903
  switch (node.operator) {
724
904
  case '-': return -argument;
725
905
  case '!': return !this.isTruthy(argument);
@@ -728,20 +908,20 @@ class Interpreter {
728
908
  }
729
909
  }
730
910
 
731
- evaluateAssignment(node) {
732
- let value = this.evaluate(node.right);
911
+ async evaluateAssignment(node, env) {
912
+ let value = await this.evaluate(node.right, env);
733
913
 
734
914
  if (node.operator === '+=' || node.operator === '-=') {
735
- const current = this.evaluate(node.left);
915
+ const current = await this.evaluate(node.left, env);
736
916
  value = node.operator === '+=' ? current + value : current - value;
737
917
  }
738
918
 
739
919
  if (node.left.type === 'Identifier') {
740
- this.environment.set(node.left.name, value);
920
+ env.set(node.left.name, value);
741
921
  } else if (node.left.type === 'MemberExpression') {
742
- const obj = this.evaluate(node.left.object);
922
+ const obj = await this.evaluate(node.left.object, env);
743
923
  const prop = node.left.computed
744
- ? this.evaluate(node.left.property)
924
+ ? await this.evaluate(node.left.property, env)
745
925
  : node.left.property.name;
746
926
 
747
927
  // Handle class instances
@@ -755,30 +935,36 @@ class Interpreter {
755
935
  return value;
756
936
  }
757
937
 
758
- evaluateUpdateExpression(node) {
759
- const current = this.evaluate(node.argument);
938
+ async evaluateUpdateExpression(node, env) {
939
+ const current = await this.evaluate(node.argument, env);
760
940
  const newValue = node.operator === '++' ? current + 1 : current - 1;
761
941
 
762
942
  if (node.argument.type === 'Identifier') {
763
- this.environment.set(node.argument.name, newValue);
943
+ env.set(node.argument.name, newValue);
764
944
  }
765
945
 
766
946
  return node.prefix ? newValue : current;
767
947
  }
768
948
 
769
- evaluateCallExpression(node) {
770
- const callee = this.evaluate(node.callee);
771
- const args = node.arguments.map(arg => this.evaluate(arg));
949
+ async evaluateCallExpression(node, env) {
950
+ const callee = await this.evaluate(node.callee, env);
951
+ const args = await Promise.all(node.arguments.map(el => this.evaluate(el, env)));
772
952
 
773
953
  if (callee && typeof callee.call === 'function') {
774
- return callee.call(this, args);
954
+ const result = callee.call(this, args);
955
+ if (callee.isAsync) {
956
+ // If async, return the Promise wrapped in a box
957
+ // to prevent the interpreter's automatic await
958
+ return new VladXPromise(result);
959
+ }
960
+ return await result;
775
961
  }
776
962
 
777
963
  throw new Error(`"${node.callee.name || 'valore'}" non è una funzione`);
778
964
  }
779
965
 
780
- evaluateNewExpression(node) {
781
- const klass = this.evaluate(node.callee);
966
+ async evaluateNewExpression(node, env) {
967
+ const klass = await this.evaluate(node.callee, env);
782
968
 
783
969
  if (!(klass instanceof VladXClass)) {
784
970
  throw new Error(`"${node.callee.name || 'valore'}" non è una classe`);
@@ -789,23 +975,28 @@ class Interpreter {
789
975
 
790
976
  if (constructor) {
791
977
  const boundConstructor = new BoundMethod(constructor, instance);
792
- const args = node.arguments.map(arg => this.evaluate(arg));
793
- boundConstructor.call(this, args);
978
+ const args = await Promise.all(node.arguments.map(el => this.evaluate(el, env)));
979
+ await boundConstructor.call(this, args);
794
980
  }
795
981
 
796
982
  return instance;
797
983
  }
798
984
 
799
- evaluateMemberExpression(node) {
800
- const obj = this.evaluate(node.object);
801
- if (obj === null || obj === undefined) {
802
- throw new Error('Impossibile accedere a proprietà di null/undefined');
985
+ async evaluateMemberExpression(node, env) {
986
+ const obj = await this.evaluate(node.object, env);
987
+
988
+ if (node.optional && (obj === undefined || obj === null)) {
989
+ return null;
803
990
  }
804
991
 
805
992
  const prop = node.computed
806
- ? this.evaluate(node.property)
993
+ ? await this.evaluate(node.property, env)
807
994
  : node.property.name;
808
995
 
996
+ if (obj === undefined || obj === null) {
997
+ throw new Error(`Impossibile leggere proprietà "${prop}" di ${obj}`);
998
+ }
999
+
809
1000
  // Handle array methods
810
1001
  if (Array.isArray(obj)) {
811
1002
  if (prop === 'aggiungi' || prop === 'push') {
@@ -817,9 +1008,36 @@ class Interpreter {
817
1008
  if (prop === 'lunghezza' || prop === 'length') {
818
1009
  return obj.length;
819
1010
  }
1011
+ if (prop === 'mappa' || prop === 'map') {
1012
+ return {
1013
+ isAsync: true,
1014
+ call: async (interpreter, args) => {
1015
+ const callback = args[0];
1016
+ const results = [];
1017
+ for (let i = 0; i < obj.length; i++) {
1018
+ results.push(await callback.call(interpreter, [obj[i], i, obj]));
1019
+ }
1020
+ return results;
1021
+ }
1022
+ };
1023
+ }
1024
+ if (prop === 'filtra' || prop === 'filter') {
1025
+ return {
1026
+ isAsync: true,
1027
+ call: async (interpreter, args) => {
1028
+ const callback = args[0];
1029
+ const results = [];
1030
+ for (let i = 0; i < obj.length; i++) {
1031
+ if (interpreter.isTruthy(await callback.call(interpreter, [obj[i], i, obj]))) {
1032
+ results.push(obj[i]);
1033
+ }
1034
+ }
1035
+ return results;
1036
+ }
1037
+ };
1038
+ }
820
1039
  }
821
1040
 
822
- // Handle class instances
823
1041
  if (obj instanceof VladXInstance) {
824
1042
  return obj.get(prop);
825
1043
  }