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.
- package/modules/logger/index.vx +68 -0
- package/modules/logger/vladx-lock.json +5 -0
- package/modules/logger/vladx.json +18 -0
- package/modules/stringhe/index.vx +248 -0
- package/modules/stringhe/vladx-lock.json +5 -0
- package/modules/stringhe/vladx.json +19 -0
- package/package.json +1 -1
- package/src/interpreter/interpreter.js +17 -3
- package/src/lexer/lexer.js +88 -2
- package/src/lexer/tokens.js +7 -1
- package/src/parser/ast.js +10 -1
- package/src/parser/parser.js +25 -1
|
@@ -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,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,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
|
@@ -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));
|
package/src/lexer/lexer.js
CHANGED
|
@@ -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
|
-
|
|
186
|
-
case '
|
|
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--;
|
package/src/lexer/tokens.js
CHANGED
|
@@ -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
|
};
|
package/src/parser/parser.js
CHANGED
|
@@ -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
|
}
|