vladx 1.0.1 → 1.1.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * main.vx - Applicazione che usa i moduli
3
+ */
4
+
5
+ importa { somma, sottrai, PI } da "./math.vx";
6
+
7
+ stampa("Test Moduli VladX");
8
+ stampa("-----------------");
9
+
10
+ variabile r1 = somma(10, 5);
11
+ stampa("10 + 5 = " + r1);
12
+
13
+ variabile r2 = sottrai(20, 8);
14
+ stampa("20 - 8 = " + r2);
15
+
16
+ stampa("Valore di PI: " + PI);
17
+
18
+
19
+ stampa("Fine del test.");
@@ -0,0 +1,13 @@
1
+ /**
2
+ * math.vx - Modulo di esempio
3
+ */
4
+
5
+ esporta funzione somma(a, b) {
6
+ ritorna a + b;
7
+ }
8
+
9
+ esporta funzione sottrai(a, b) {
10
+ ritorna a - b;
11
+ }
12
+
13
+ esporta costante PI = 3.14159;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vladx",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "VladX - Linguaggio di programmazione con sintassi italiana",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
package/src/cli/cli.js CHANGED
@@ -69,6 +69,7 @@ function runFile(filePath) {
69
69
  const ast = parser.parse();
70
70
 
71
71
  const interpreter = new Interpreter();
72
+ interpreter.currentPath = absolutePath;
72
73
  interpreter.interpret(ast);
73
74
  } catch (error) {
74
75
  console.error(colorize(`✗ Errore: ${error.message}`, 'red'));
@@ -116,11 +116,19 @@ class ArrowFunc {
116
116
  }
117
117
  }
118
118
 
119
+ const fs = require('fs');
120
+ const path = require('path');
121
+ const { Lexer } = require('../lexer/lexer.js');
122
+ const { Parser } = require('../parser/parser.js');
123
+
119
124
  class Interpreter {
120
125
  constructor() {
121
126
  this.globals = new Environment();
122
127
  this.environment = this.globals;
123
128
  this.output = [];
129
+ this.modules = new Map(); // path -> exports
130
+ this.currentPath = process.cwd();
131
+ this.exportedSymbols = new Map(); // symbols exported by the current module
124
132
 
125
133
  // Built-in functions
126
134
  this.globals.define('lunghezza', {
@@ -184,6 +192,10 @@ class Interpreter {
184
192
  throw new BreakSignal();
185
193
  case 'ContinueStatement':
186
194
  throw new ContinueSignal();
195
+ case 'ExportNamedDeclaration':
196
+ return this.executeExportNamedDeclaration(node);
197
+ case 'ImportDeclaration':
198
+ return this.executeImportDeclaration(node);
187
199
  case 'PrintStatement':
188
200
  return this.executePrintStatement(node);
189
201
  case 'ExpressionStatement':
@@ -261,6 +273,65 @@ class Interpreter {
261
273
  }
262
274
  }
263
275
 
276
+ executeExportNamedDeclaration(node) {
277
+ this.execute(node.declaration);
278
+ const name = node.declaration.name;
279
+ const value = this.environment.get(name);
280
+ this.exportedSymbols.set(name, value);
281
+ }
282
+
283
+ executeImportDeclaration(node) {
284
+ const sourcePath = node.source;
285
+ let fullPath;
286
+
287
+ if (sourcePath.startsWith('./') || sourcePath.startsWith('../')) {
288
+ fullPath = path.resolve(path.dirname(this.currentPath), sourcePath);
289
+ } else {
290
+ // Check vladx_modules
291
+ fullPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
292
+ if (!fullPath.endsWith('.vx')) fullPath += '.vx';
293
+ if (!fs.existsSync(fullPath)) {
294
+ // Try index.vx inside the module folder
295
+ const folderPath = path.resolve(process.cwd(), 'vladx_modules', sourcePath);
296
+ fullPath = path.join(folderPath, 'index.vx');
297
+ }
298
+ }
299
+
300
+ if (!fs.existsSync(fullPath)) {
301
+ throw new Error(`Modulo non trovato: ${sourcePath}`);
302
+ }
303
+
304
+ let moduleExports;
305
+ if (this.modules.has(fullPath)) {
306
+ moduleExports = this.modules.get(fullPath);
307
+ } else {
308
+ // Load and execute module
309
+ const content = fs.readFileSync(fullPath, 'utf8');
310
+ const lexer = new Lexer(content);
311
+ const tokens = lexer.tokenize();
312
+ const parser = new Parser(tokens);
313
+ const program = parser.parse();
314
+
315
+ const subInterpreter = new Interpreter();
316
+ // Sharing the same modules cache
317
+ subInterpreter.modules = this.modules;
318
+ subInterpreter.currentPath = fullPath;
319
+
320
+ subInterpreter.interpret(program);
321
+ moduleExports = subInterpreter.exportedSymbols;
322
+ this.modules.set(fullPath, moduleExports);
323
+ }
324
+
325
+ // Import specified symbols
326
+ for (const specifier of node.specifiers) {
327
+ if (moduleExports.has(specifier)) {
328
+ this.environment.define(specifier, moduleExports.get(specifier));
329
+ } else {
330
+ throw new Error(`Il modulo "${sourcePath}" non esporta "${specifier}"`);
331
+ }
332
+ }
333
+ }
334
+
264
335
  executePrintStatement(node) {
265
336
  const value = this.evaluate(node.argument);
266
337
  const output = this.stringify(value);
package/src/parser/ast.js CHANGED
@@ -232,6 +232,29 @@ class LogicalExpression extends ASTNode {
232
232
  }
233
233
  }
234
234
 
235
+ class ExportNamedDeclaration {
236
+ constructor(declaration) {
237
+ this.type = 'ExportNamedDeclaration';
238
+ this.declaration = declaration;
239
+ }
240
+ }
241
+
242
+ class ImportDeclaration {
243
+ constructor(specifiers, source) {
244
+ this.type = 'ImportDeclaration';
245
+ this.specifiers = specifiers; // Array di nomi
246
+ this.source = source; // StringLiteral path
247
+ }
248
+ }
249
+
250
+ class ImportSpecifier {
251
+ constructor(imported, local) {
252
+ this.type = 'ImportSpecifier';
253
+ this.imported = imported;
254
+ this.local = local;
255
+ }
256
+ }
257
+
235
258
  module.exports = {
236
259
  ASTNode,
237
260
  Program,
@@ -246,6 +269,9 @@ module.exports = {
246
269
  ContinueStatement,
247
270
  ExpressionStatement,
248
271
  PrintStatement,
272
+ ExportNamedDeclaration,
273
+ ImportDeclaration,
274
+ ImportSpecifier,
249
275
  Identifier,
250
276
  NumericLiteral,
251
277
  StringLiteral,
@@ -69,6 +69,8 @@ class Parser {
69
69
 
70
70
  declaration() {
71
71
  try {
72
+ if (this.match(TokenType.IMPORTA)) return this.importDeclaration();
73
+ if (this.match(TokenType.ESPORTA)) return this.exportDeclaration();
72
74
  if (this.match(TokenType.VARIABILE)) return this.variableDeclaration(false);
73
75
  if (this.match(TokenType.COSTANTE)) return this.variableDeclaration(true);
74
76
  if (this.match(TokenType.FUNZIONE)) return this.functionDeclaration();
@@ -89,6 +91,38 @@ class Parser {
89
91
  return new AST.VariableDeclaration(name, value, isConstant);
90
92
  }
91
93
 
94
+ importDeclaration() {
95
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo "importa"');
96
+ const specifiers = [];
97
+ if (!this.check(TokenType.GRAFFA_CHIUSA)) {
98
+ do {
99
+ const name = this.consume(TokenType.IDENTIFICATORE, 'Nome import atteso').value;
100
+ specifiers.push(name);
101
+ } while (this.match(TokenType.VIRGOLA));
102
+ }
103
+ this.consume(TokenType.GRAFFA_CHIUSA, 'Atteso "}" dopo i nomi importati');
104
+ this.consume(TokenType.DA, 'Attesa parola chiave "da" dopo gli import');
105
+ const source = this.consume(TokenType.STRINGA, 'Percorso modulo atteso come stringa').value;
106
+ this.match(TokenType.PUNTO_VIRGOLA);
107
+ return new AST.ImportDeclaration(specifiers, source);
108
+ }
109
+
110
+ exportDeclaration() {
111
+ if (this.match(TokenType.FUNZIONE)) {
112
+ const decl = this.functionDeclaration();
113
+ return new AST.ExportNamedDeclaration(decl);
114
+ }
115
+ if (this.match(TokenType.VARIABILE)) {
116
+ const decl = this.variableDeclaration(false);
117
+ return new AST.ExportNamedDeclaration(decl);
118
+ }
119
+ if (this.match(TokenType.COSTANTE)) {
120
+ const decl = this.variableDeclaration(true);
121
+ return new AST.ExportNamedDeclaration(decl);
122
+ }
123
+ throw new ParserError('Atteso funzione o variabile dopo "esporta"', this.peek());
124
+ }
125
+
92
126
  functionDeclaration() {
93
127
  const name = this.consume(TokenType.IDENTIFICATORE, 'Nome funzione atteso').value;
94
128
  this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo nome funzione');