vladx 1.2.4 → 1.2.5

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,68 @@
1
+ // vladx-logger - Logger per VladX
2
+ //
3
+ // API:
4
+ // - esporta funzione info(messaggio)
5
+ // - esporta funzione avviso(messaggio)
6
+ // - esporta funzione errore(messaggio)
7
+ // - esporta funzione debug(messaggio)
8
+ // - esporta funzione creaLogger(nome) -> oggetto con i 4 metodi sopra
9
+ //
10
+ // Ogni messaggio viene stampato con timestamp e livello.
11
+
12
+ funzione _oraIso() {
13
+ variabile ms = Sistema.esegui("date -u +\"%Y-%m-%dT%H:%M:%SZ\"");
14
+ ritorna ms;
15
+ }
16
+
17
+ funzione _formattaMessaggio(livello, nome, messaggio) {
18
+ variabile prefissoNome = "";
19
+
20
+ se (nome && tipo(nome) === "string" && nome !== "") {
21
+ prefissoNome = "[" + nome + "] ";
22
+ }
23
+
24
+ ritorna "[" + _oraIso().trim() + "]" + "[" + livello + "] " + prefissoNome + messaggio;
25
+ }
26
+
27
+ funzione _logGenerico(livello, nome, messaggio) {
28
+ // Se il messaggio non è stringa, proviamo a convertirlo
29
+ se (tipo(messaggio) !== "string") {
30
+ messaggio = stringa(messaggio);
31
+ }
32
+ stampa(_formattaMessaggio(livello, nome, messaggio));
33
+ }
34
+
35
+ esporta funzione info(messaggio) {
36
+ _logGenerico("INFO", "", messaggio);
37
+ }
38
+
39
+ esporta funzione avviso(messaggio) {
40
+ _logGenerico("AVVISO", "", messaggio);
41
+ }
42
+
43
+ esporta funzione errore(messaggio) {
44
+ _logGenerico("ERRORE", "", messaggio);
45
+ }
46
+
47
+ esporta funzione debug(messaggio) {
48
+ _logGenerico("DEBUG", "", messaggio);
49
+ }
50
+
51
+ // Logger con nome (es. modulo, servizio, contesto)
52
+ esporta funzione creaLogger(nome) {
53
+ ritorna {
54
+ info: (messaggio) => _logGenerico("INFO", nome, messaggio),
55
+ avviso: (messaggio) => _logGenerico("AVVISO", nome, messaggio),
56
+ errore: (messaggio) => _logGenerico("ERRORE", nome, messaggio),
57
+ debug: (messaggio) => _logGenerico("DEBUG", nome, messaggio)
58
+ };
59
+ }
60
+
61
+ // Esempio rapido se eseguito direttamente
62
+ se (Sistema.argomenti && Sistema.argomenti.length > 0) {
63
+ variabile log = creaLogger("esempio-logger");
64
+ info("Logger globale attivo");
65
+ log.debug("Messaggio di debug");
66
+ log.info("Informazione di esempio");
67
+ log.errore("Errore di esempio");
68
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "requires": true,
4
+ "dependencies": {}
5
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "vladx-logger",
3
+ "version": "1.0.0",
4
+ "description": "Logger semplice per VladX con livelli e prefissi",
5
+ "main": "index.vx",
6
+ "scripts": {
7
+ "start": "vladx index.vx",
8
+ "test": "vladx test.vx"
9
+ },
10
+ "keywords": [
11
+ "logger",
12
+ "logging",
13
+ "vladx"
14
+ ],
15
+ "author": "VladX Team",
16
+ "license": "MIT",
17
+ "dependencies": {}
18
+ }
@@ -0,0 +1,248 @@
1
+ // vladx-stringhe - Utility per stringhe in VladX
2
+ //
3
+ // API principale (tutte esportate):
4
+ // - trim(testo)
5
+ // - minuscolo(testo)
6
+ // - maiuscolo(testo)
7
+ // - iniziaCon(testo, prefisso)
8
+ // - finisceCon(testo, suffisso)
9
+ // - contiene(testo, parte)
10
+ // - sostituisciTutto(testo, cerca, sostituisci)
11
+ // - slug(testo)
12
+ // - ripeti(testo, volte)
13
+ // - unisci(separatore, elementiArray)
14
+
15
+ funzione _assicuratiStringa(valore) {
16
+ se (tipo(valore) === "string") {
17
+ ritorna valore;
18
+ }
19
+ ritorna stringa(valore);
20
+ }
21
+
22
+ esporta funzione trim(testo) {
23
+ testo = _assicuratiStringa(testo);
24
+
25
+ // rimuove spazi iniziali
26
+ mentre (lunghezza(testo) > 0 && (
27
+ testo[0] === " " ||
28
+ testo[0] === "\n" ||
29
+ testo[0] === "\t" ||
30
+ testo[0] === "\r"
31
+ )) {
32
+ testo = testo.substring(1);
33
+ }
34
+
35
+ // rimuove spazi finali
36
+ mentre (lunghezza(testo) > 0) {
37
+ variabile ultimo = testo[lunghezza(testo) - 1];
38
+ se (ultimo === " " || ultimo === "\n" || ultimo === "\t" || ultimo === "\r") {
39
+ testo = testo.substring(0, lunghezza(testo) - 1);
40
+ } altrimenti {
41
+ interrompi;
42
+ }
43
+ }
44
+
45
+ ritorna testo;
46
+ }
47
+
48
+ esporta funzione minuscolo(testo) {
49
+ testo = _assicuratiStringa(testo);
50
+ ritorna testo.toLowerCase();
51
+ }
52
+
53
+ esporta funzione maiuscolo(testo) {
54
+ testo = _assicuratiStringa(testo);
55
+ ritorna testo.toUpperCase();
56
+ }
57
+
58
+ esporta funzione iniziaCon(testo, prefisso) {
59
+ testo = _assicuratiStringa(testo);
60
+ prefisso = _assicuratiStringa(prefisso);
61
+
62
+ se (lunghezza(prefisso) > lunghezza(testo)) {
63
+ ritorna falso;
64
+ }
65
+
66
+ variabile i = 0;
67
+ mentre (i < lunghezza(prefisso)) {
68
+ se (testo[i] !== prefisso[i]) {
69
+ ritorna falso;
70
+ }
71
+ i++;
72
+ }
73
+
74
+ ritorna vero;
75
+ }
76
+
77
+ esporta funzione finisceCon(testo, suffisso) {
78
+ testo = _assicuratiStringa(testo);
79
+ suffisso = _assicuratiStringa(suffisso);
80
+
81
+ se (lunghezza(suffisso) > lunghezza(testo)) {
82
+ ritorna falso;
83
+ }
84
+
85
+ variabile offset = lunghezza(testo) - lunghezza(suffisso);
86
+ variabile i = 0;
87
+ mentre (i < lunghezza(suffisso)) {
88
+ se (testo[offset + i] !== suffisso[i]) {
89
+ ritorna falso;
90
+ }
91
+ i++;
92
+ }
93
+
94
+ ritorna vero;
95
+ }
96
+
97
+ esporta funzione contiene(testo, parte) {
98
+ testo = _assicuratiStringa(testo);
99
+ parte = _assicuratiStringa(parte);
100
+
101
+ se (lunghezza(parte) === 0) {
102
+ ritorna vero;
103
+ }
104
+
105
+ variabile i = 0;
106
+ mentre (i <= lunghezza(testo) - lunghezza(parte)) {
107
+ variabile j = 0;
108
+ variabile match = vero;
109
+
110
+ mentre (j < lunghezza(parte)) {
111
+ se (testo[i + j] !== parte[j]) {
112
+ match = falso;
113
+ interrompi;
114
+ }
115
+ j++;
116
+ }
117
+
118
+ se (match) {
119
+ ritorna vero;
120
+ }
121
+
122
+ i++;
123
+ }
124
+
125
+ ritorna falso;
126
+ }
127
+
128
+ esporta funzione sostituisciTutto(testo, cerca, sostituisci) {
129
+ testo = _assicuratiStringa(testo);
130
+ cerca = _assicuratiStringa(cerca);
131
+ sostituisci = _assicuratiStringa(sostituisci);
132
+
133
+ se (lunghezza(cerca) === 0) {
134
+ ritorna testo;
135
+ }
136
+
137
+ variabile risultato = "";
138
+ variabile i = 0;
139
+
140
+ mentre (i < lunghezza(testo)) {
141
+ variabile j = 0;
142
+ variabile match = vero;
143
+
144
+ mentre (j < lunghezza(cerca) && i + j < lunghezza(testo)) {
145
+ se (testo[i + j] !== cerca[j]) {
146
+ match = falso;
147
+ interrompi;
148
+ }
149
+ j++;
150
+ }
151
+
152
+ se (match && j === lunghezza(cerca)) {
153
+ risultato = risultato + sostituisci;
154
+ i = i + lunghezza(cerca);
155
+ } altrimenti {
156
+ risultato = risultato + testo[i];
157
+ i = i + 1;
158
+ }
159
+ }
160
+
161
+ ritorna risultato;
162
+ }
163
+
164
+ esporta funzione slug(testo) {
165
+ testo = _assicuratiStringa(testo);
166
+
167
+ // minuscolo
168
+ testo = testo.toLowerCase();
169
+
170
+ // sostituisci spazi con -
171
+ testo = sostituisciTutto(testo, " ", "-");
172
+
173
+ // rimuovi caratteri non alfanumerici (mantieni -)
174
+ variabile risultato = "";
175
+ variabile i = 0;
176
+ mentre (i < lunghezza(testo)) {
177
+ variabile c = testo[i];
178
+
179
+ se (
180
+ (c >= "a" && c <= "z") ||
181
+ (c >= "0" && c <= "9") ||
182
+ c === "-"
183
+ ) {
184
+ risultato = risultato + c;
185
+ }
186
+
187
+ i++;
188
+ }
189
+
190
+ // rimuovi eventuali -- doppi
191
+ mentre (contiene(risultato, "--")) {
192
+ risultato = sostituisciTutto(risultato, "--", "-");
193
+ }
194
+
195
+ // togli - iniziali e finali
196
+ risultato = trim(risultato);
197
+ mentre (lunghezza(risultato) > 0 && risultato[0] === "-") {
198
+ risultato = risultato.substring(1);
199
+ }
200
+ mentre (lunghezza(risultato) > 0 && risultato[lunghezza(risultato) - 1] === "-") {
201
+ risultato = risultato.substring(0, lunghezza(risultato) - 1);
202
+ }
203
+
204
+ ritorna risultato;
205
+ }
206
+
207
+ esporta funzione ripeti(testo, volte) {
208
+ testo = _assicuratiStringa(testo);
209
+ se (tipo(volte) !== "number" || volte <= 0) {
210
+ ritorna "";
211
+ }
212
+
213
+ variabile risultato = "";
214
+ variabile i = 0;
215
+ mentre (i < volte) {
216
+ risultato = risultato + testo;
217
+ i++;
218
+ }
219
+
220
+ ritorna risultato;
221
+ }
222
+
223
+ esporta funzione unisci(separatore, elementi) {
224
+ separatore = _assicuratiStringa(separatore);
225
+
226
+ se (!array(elementi)) {
227
+ ritorna "";
228
+ }
229
+
230
+ se (lunghezza(elementi) === 0) {
231
+ ritorna "";
232
+ }
233
+
234
+ variabile risultato = _assicuratiStringa(elementi[0]);
235
+ variabile i = 1;
236
+
237
+ mentre (i < lunghezza(elementi)) {
238
+ risultato = risultato + separatore + _assicuratiStringa(elementi[i]);
239
+ i++;
240
+ }
241
+
242
+ ritorna risultato;
243
+ }
244
+
245
+ // Esempio rapido se eseguito direttamente
246
+ se (Sistema.argomenti && Sistema.argomenti.length > 0) {
247
+ stampa(slug("Ciao Mondo da VladX Stringhe!"));
248
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "requires": true,
4
+ "dependencies": {}
5
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "vladx-stringhe",
3
+ "version": "1.0.0",
4
+ "description": "Utility per la manipolazione di stringhe in VladX",
5
+ "main": "index.vx",
6
+ "scripts": {
7
+ "start": "vladx index.vx",
8
+ "test": "vladx test.vx"
9
+ },
10
+ "keywords": [
11
+ "string",
12
+ "stringhe",
13
+ "vladx",
14
+ "utility"
15
+ ],
16
+ "author": "VladX Team",
17
+ "license": "MIT",
18
+ "dependencies": {}
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vladx",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "description": "VladX - Linguaggio di programmazione con sintassi italiana",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -620,11 +620,25 @@ class Interpreter {
620
620
  return this.evaluateMemberExpression(node);
621
621
  case 'ArrowFunction':
622
622
  return new ArrowFunc(node.params, node.body, this.environment);
623
+ case 'TemplateLiteral':
624
+ return this.evaluateTemplateLiteral(node);
623
625
  default:
624
626
  throw new Error(`Tipo espressione sconosciuto: ${node.type}`);
625
627
  }
626
628
  }
627
629
 
630
+ evaluateTemplateLiteral(node) {
631
+ let result = node.quasis[0];
632
+
633
+ for (let i = 0; i < node.expressions.length; i++) {
634
+ const value = this.evaluate(node.expressions[i]);
635
+ result += this.stringify(value);
636
+ result += node.quasis[i + 1];
637
+ }
638
+
639
+ return result;
640
+ }
641
+
628
642
  evaluateBinaryExpression(node) {
629
643
  const left = this.evaluate(node.left);
630
644
  const right = this.evaluate(node.right);
@@ -686,7 +700,7 @@ class Interpreter {
686
700
  const prop = node.left.computed
687
701
  ? this.evaluate(node.left.property)
688
702
  : node.left.property.name;
689
-
703
+
690
704
  // Handle class instances
691
705
  if (obj instanceof VladXInstance) {
692
706
  obj.set(prop, value);
@@ -722,14 +736,14 @@ class Interpreter {
722
736
 
723
737
  evaluateNewExpression(node) {
724
738
  const klass = this.evaluate(node.callee);
725
-
739
+
726
740
  if (!(klass instanceof VladXClass)) {
727
741
  throw new Error(`"${node.callee.name || 'valore'}" non è una classe`);
728
742
  }
729
743
 
730
744
  const instance = new VladXInstance(klass);
731
745
  const constructor = klass.findMethod('costruttore');
732
-
746
+
733
747
  if (constructor) {
734
748
  const boundConstructor = new BoundMethod(constructor, instance);
735
749
  const args = node.arguments.map(arg => this.evaluate(arg));
@@ -25,6 +25,8 @@ class Lexer {
25
25
  this.current = 0;
26
26
  this.line = 1;
27
27
  this.column = 1;
28
+ this.braceDepth = 0;
29
+ this.templateStack = [];
28
30
  }
29
31
 
30
32
  peek() {
@@ -149,6 +151,70 @@ class Lexer {
149
151
  this.tokens.push(new Token(TokenType.STRINGA, value, startLine, startColumn));
150
152
  }
151
153
 
154
+ readTemplateString(isRestart) {
155
+ // If not restarting (fresh backtick), consume the backtick
156
+ if (!isRestart) {
157
+ this.advance();
158
+ }
159
+
160
+ let value = '';
161
+ const startLine = this.line;
162
+ const startColumn = this.column;
163
+
164
+ while (!this.isAtEnd()) {
165
+ // Check for end of template string
166
+ if (this.peek() === '`') {
167
+ this.advance(); // consume backtick
168
+ if (isRestart) {
169
+ this.tokens.push(new Token(TokenType.TEMPLATE_FINE, value, startLine, startColumn));
170
+ } else {
171
+ this.tokens.push(new Token(TokenType.TEMPLATE_COMPLETO, value, startLine, startColumn));
172
+ }
173
+ return;
174
+ }
175
+
176
+ // Check for start of interpolation
177
+ if (this.peek() === '$' && this.peekNext() === '{') {
178
+ this.advance(); // consume $
179
+ this.advance(); // consume {
180
+
181
+ if (isRestart) {
182
+ this.tokens.push(new Token(TokenType.TEMPLATE_CENTRO, value, startLine, startColumn));
183
+ } else {
184
+ this.tokens.push(new Token(TokenType.TEMPLATE_INIZIO, value, startLine, startColumn));
185
+ }
186
+
187
+ // Track brace depth for this interpolation
188
+ this.templateStack.push(this.braceDepth);
189
+ return;
190
+ }
191
+
192
+ // Handle escapes
193
+ if (this.peek() === '\\') {
194
+ this.advance();
195
+ if (this.isAtEnd()) break;
196
+
197
+ const escaped = this.peek();
198
+ switch (escaped) {
199
+ case 'n': value += '\n'; break;
200
+ case 't': value += '\t'; break;
201
+ case 'r': value += '\r'; break;
202
+ case '\\': value += '\\'; break;
203
+ case '"': value += '"'; break;
204
+ case "'": value += "'"; break;
205
+ case '`': value += '`'; break;
206
+ case '$': value += '$'; break;
207
+ default: value += escaped;
208
+ }
209
+ this.advance();
210
+ } else {
211
+ value += this.advance();
212
+ }
213
+ }
214
+
215
+ throw new Error(`Template string non terminata alla riga ${startLine}`);
216
+ }
217
+
152
218
  readIdentifier() {
153
219
  const startColumn = this.column;
154
220
  let value = '';
@@ -182,8 +248,22 @@ class Lexer {
182
248
  switch (char) {
183
249
  case '(': this.addToken(TokenType.PARENTESI_APERTA, '('); break;
184
250
  case ')': this.addToken(TokenType.PARENTESI_CHIUSA, ')'); break;
185
- case '{': this.addToken(TokenType.GRAFFA_APERTA, '{'); break;
186
- case '}': this.addToken(TokenType.GRAFFA_CHIUSA, '}'); break;
251
+
252
+ case '{':
253
+ this.braceDepth++;
254
+ this.addToken(TokenType.GRAFFA_APERTA, '{');
255
+ break;
256
+
257
+ case '}':
258
+ if (this.templateStack.length > 0 && this.braceDepth === this.templateStack[this.templateStack.length - 1]) {
259
+ this.templateStack.pop();
260
+ this.readTemplateString(true);
261
+ } else {
262
+ this.braceDepth--;
263
+ this.addToken(TokenType.GRAFFA_CHIUSA, '}');
264
+ }
265
+ break;
266
+
187
267
  case '[': this.addToken(TokenType.QUADRA_APERTA, '['); break;
188
268
  case ']': this.addToken(TokenType.QUADRA_CHIUSA, ']'); break;
189
269
  case ',': this.addToken(TokenType.VIRGOLA, ','); break;
@@ -253,6 +333,12 @@ class Lexer {
253
333
  this.readString(char);
254
334
  break;
255
335
 
336
+ case '`':
337
+ this.current--;
338
+ this.column--;
339
+ this.readTemplateString(false);
340
+ break;
341
+
256
342
  default:
257
343
  if (this.isDigit(char)) {
258
344
  this.current--;
@@ -78,7 +78,13 @@ const TokenType = {
78
78
 
79
79
  // Special
80
80
  FINE: 'FINE',
81
- SCONOSCIUTO: 'SCONOSCIUTO'
81
+ SCONOSCIUTO: 'SCONOSCIUTO',
82
+
83
+ // Template Strings
84
+ TEMPLATE_COMPLETO: 'TEMPLATE_COMPLETO', // `stringa`
85
+ TEMPLATE_INIZIO: 'TEMPLATE_INIZIO', // `str${
86
+ TEMPLATE_CENTRO: 'TEMPLATE_CENTRO', // }str${
87
+ TEMPLATE_FINE: 'TEMPLATE_FINE' // }str`
82
88
  };
83
89
 
84
90
  const KEYWORDS = {
package/src/parser/ast.js CHANGED
@@ -174,6 +174,14 @@ class StringLiteral extends ASTNode {
174
174
  }
175
175
  }
176
176
 
177
+ class TemplateLiteral extends ASTNode {
178
+ constructor(quasis, expressions) {
179
+ super('TemplateLiteral');
180
+ this.quasis = quasis;
181
+ this.expressions = expressions;
182
+ }
183
+ }
184
+
177
185
  class BooleanLiteral extends ASTNode {
178
186
  constructor(value) {
179
187
  super('BooleanLiteral');
@@ -341,5 +349,6 @@ module.exports = {
341
349
  UpdateExpression,
342
350
  LogicalExpression,
343
351
  ThisExpression,
344
- NewExpression
352
+ NewExpression,
353
+ TemplateLiteral
345
354
  };
@@ -152,7 +152,7 @@ class Parser {
152
152
  }
153
153
  }
154
154
  const name = this.consume(TokenType.IDENTIFICATORE, 'Nome classe atteso').value;
155
-
155
+
156
156
  let superclass = null;
157
157
  if (this.match(TokenType.DA)) {
158
158
  superclass = this.consume(TokenType.IDENTIFICATORE, 'Nome classe padre atteso').value;
@@ -504,6 +504,30 @@ class Parser {
504
504
  return new AST.StringLiteral(this.previous().value);
505
505
  }
506
506
 
507
+ if (this.match(TokenType.TEMPLATE_COMPLETO)) {
508
+ return new AST.TemplateLiteral([this.previous().value], []);
509
+ }
510
+
511
+ if (this.match(TokenType.TEMPLATE_INIZIO)) {
512
+ const quasis = [this.previous().value];
513
+ const expressions = [];
514
+
515
+ while (true) {
516
+ expressions.push(this.expression());
517
+
518
+ if (this.match(TokenType.TEMPLATE_CENTRO)) {
519
+ quasis.push(this.previous().value);
520
+ } else if (this.match(TokenType.TEMPLATE_FINE)) {
521
+ quasis.push(this.previous().value);
522
+ break;
523
+ } else {
524
+ throw new ParserError('Atteso parte centrale o finale della template string', this.peek());
525
+ }
526
+ }
527
+
528
+ return new AST.TemplateLiteral(quasis, expressions);
529
+ }
530
+
507
531
  if (this.match(TokenType.NUOVO)) {
508
532
  return this.newExpression();
509
533
  }