vladx 1.0.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.
- package/bin/vladpm +9 -0
- package/bin/vladx +10 -0
- package/examples/esempio.vx +79 -0
- package/package.json +23 -0
- package/src/cli/cli.js +191 -0
- package/src/index.js +32 -0
- package/src/interpreter/interpreter.js +455 -0
- package/src/lexer/lexer.js +284 -0
- package/src/lexer/tokens.js +116 -0
- package/src/parser/ast.js +265 -0
- package/src/parser/parser.js +476 -0
- package/src/pm/cli.js +130 -0
- package/src/pm/commands/config.js +76 -0
- package/src/pm/commands/init.js +129 -0
- package/src/pm/commands/install.js +185 -0
- package/src/pm/commands/list.js +70 -0
- package/src/pm/commands/login.js +124 -0
- package/src/pm/commands/publish.js +115 -0
- package/src/pm/commands/search.js +55 -0
- package/src/pm/commands/uninstall.js +68 -0
- package/src/pm/utils/api.js +135 -0
- package/src/pm/utils/config.js +117 -0
- package/src/repl/repl.js +179 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VladX Parser
|
|
3
|
+
* Parser ricorsivo discendente per generare AST
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { TokenType } = require('../lexer/tokens.js');
|
|
7
|
+
const AST = require('./ast.js');
|
|
8
|
+
|
|
9
|
+
class ParserError extends Error {
|
|
10
|
+
constructor(message, token) {
|
|
11
|
+
super(`Errore alla riga ${token.line}, colonna ${token.column}: ${message}`);
|
|
12
|
+
this.token = token;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class Parser {
|
|
17
|
+
constructor(tokens) {
|
|
18
|
+
this.tokens = tokens;
|
|
19
|
+
this.current = 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// === Utility Methods ===
|
|
23
|
+
peek() {
|
|
24
|
+
return this.tokens[this.current];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
previous() {
|
|
28
|
+
return this.tokens[this.current - 1];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
isAtEnd() {
|
|
32
|
+
return this.peek().type === TokenType.FINE;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
advance() {
|
|
36
|
+
if (!this.isAtEnd()) this.current++;
|
|
37
|
+
return this.previous();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
check(type) {
|
|
41
|
+
if (this.isAtEnd()) return false;
|
|
42
|
+
return this.peek().type === type;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
match(...types) {
|
|
46
|
+
for (const type of types) {
|
|
47
|
+
if (this.check(type)) {
|
|
48
|
+
this.advance();
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
consume(type, message) {
|
|
56
|
+
if (this.check(type)) return this.advance();
|
|
57
|
+
throw new ParserError(message, this.peek());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// === Parsing Methods ===
|
|
61
|
+
parse() {
|
|
62
|
+
const statements = [];
|
|
63
|
+
while (!this.isAtEnd()) {
|
|
64
|
+
const stmt = this.declaration();
|
|
65
|
+
if (stmt) statements.push(stmt);
|
|
66
|
+
}
|
|
67
|
+
return new AST.Program(statements);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declaration() {
|
|
71
|
+
try {
|
|
72
|
+
if (this.match(TokenType.VARIABILE)) return this.variableDeclaration(false);
|
|
73
|
+
if (this.match(TokenType.COSTANTE)) return this.variableDeclaration(true);
|
|
74
|
+
if (this.match(TokenType.FUNZIONE)) return this.functionDeclaration();
|
|
75
|
+
return this.statement();
|
|
76
|
+
} catch (error) {
|
|
77
|
+
this.synchronize();
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
variableDeclaration(isConstant) {
|
|
83
|
+
const name = this.consume(TokenType.IDENTIFICATORE, 'Nome variabile atteso').value;
|
|
84
|
+
let value = null;
|
|
85
|
+
if (this.match(TokenType.ASSEGNA)) {
|
|
86
|
+
value = this.expression();
|
|
87
|
+
}
|
|
88
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
89
|
+
return new AST.VariableDeclaration(name, value, isConstant);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
functionDeclaration() {
|
|
93
|
+
const name = this.consume(TokenType.IDENTIFICATORE, 'Nome funzione atteso').value;
|
|
94
|
+
this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo nome funzione');
|
|
95
|
+
const params = [];
|
|
96
|
+
if (!this.check(TokenType.PARENTESI_CHIUSA)) {
|
|
97
|
+
do {
|
|
98
|
+
params.push(this.consume(TokenType.IDENTIFICATORE, 'Nome parametro atteso').value);
|
|
99
|
+
} while (this.match(TokenType.VIRGOLA));
|
|
100
|
+
}
|
|
101
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo parametri');
|
|
102
|
+
this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" prima del corpo funzione');
|
|
103
|
+
const body = this.blockStatement();
|
|
104
|
+
return new AST.FunctionDeclaration(name, params, body);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
statement() {
|
|
108
|
+
if (this.match(TokenType.SE)) return this.ifStatement();
|
|
109
|
+
if (this.match(TokenType.MENTRE)) return this.whileStatement();
|
|
110
|
+
if (this.match(TokenType.PER)) return this.forStatement();
|
|
111
|
+
if (this.match(TokenType.RITORNA)) return this.returnStatement();
|
|
112
|
+
if (this.match(TokenType.INTERROMPI)) return this.breakStatement();
|
|
113
|
+
if (this.match(TokenType.CONTINUA)) return this.continueStatement();
|
|
114
|
+
if (this.match(TokenType.STAMPA)) return this.printStatement();
|
|
115
|
+
if (this.match(TokenType.GRAFFA_APERTA)) return this.blockStatement();
|
|
116
|
+
return this.expressionStatement();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
blockStatement() {
|
|
120
|
+
const statements = [];
|
|
121
|
+
while (!this.check(TokenType.GRAFFA_CHIUSA) && !this.isAtEnd()) {
|
|
122
|
+
statements.push(this.declaration());
|
|
123
|
+
}
|
|
124
|
+
this.consume(TokenType.GRAFFA_CHIUSA, 'Atteso "}" alla fine del blocco');
|
|
125
|
+
return new AST.BlockStatement(statements);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
ifStatement() {
|
|
129
|
+
this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "se"');
|
|
130
|
+
const condition = this.expression();
|
|
131
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo condizione');
|
|
132
|
+
this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo condizione');
|
|
133
|
+
const consequent = this.blockStatement();
|
|
134
|
+
let alternate = null;
|
|
135
|
+
if (this.match(TokenType.ALTRIMENTI)) {
|
|
136
|
+
if (this.match(TokenType.SE)) {
|
|
137
|
+
alternate = this.ifStatement();
|
|
138
|
+
} else {
|
|
139
|
+
this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo "altrimenti"');
|
|
140
|
+
alternate = this.blockStatement();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return new AST.IfStatement(condition, consequent, alternate);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
whileStatement() {
|
|
147
|
+
this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "mentre"');
|
|
148
|
+
const condition = this.expression();
|
|
149
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo condizione');
|
|
150
|
+
this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo condizione');
|
|
151
|
+
const body = this.blockStatement();
|
|
152
|
+
return new AST.WhileStatement(condition, body);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
forStatement() {
|
|
156
|
+
this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "per"');
|
|
157
|
+
|
|
158
|
+
let init = null;
|
|
159
|
+
if (this.match(TokenType.VARIABILE)) {
|
|
160
|
+
init = this.variableDeclaration(false);
|
|
161
|
+
} else if (!this.check(TokenType.PUNTO_VIRGOLA)) {
|
|
162
|
+
init = this.expressionStatement();
|
|
163
|
+
} else {
|
|
164
|
+
this.advance();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let condition = null;
|
|
168
|
+
if (!this.check(TokenType.PUNTO_VIRGOLA)) {
|
|
169
|
+
condition = this.expression();
|
|
170
|
+
}
|
|
171
|
+
this.consume(TokenType.PUNTO_VIRGOLA, 'Atteso ";" dopo condizione del ciclo');
|
|
172
|
+
|
|
173
|
+
let update = null;
|
|
174
|
+
if (!this.check(TokenType.PARENTESI_CHIUSA)) {
|
|
175
|
+
update = this.expression();
|
|
176
|
+
}
|
|
177
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo clausole del ciclo');
|
|
178
|
+
|
|
179
|
+
this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo clausole del ciclo');
|
|
180
|
+
const body = this.blockStatement();
|
|
181
|
+
return new AST.ForStatement(init, condition, update, body);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
returnStatement() {
|
|
185
|
+
let argument = null;
|
|
186
|
+
if (!this.check(TokenType.PUNTO_VIRGOLA) && !this.check(TokenType.GRAFFA_CHIUSA)) {
|
|
187
|
+
argument = this.expression();
|
|
188
|
+
}
|
|
189
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
190
|
+
return new AST.ReturnStatement(argument);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
breakStatement() {
|
|
194
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
195
|
+
return new AST.BreakStatement();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
continueStatement() {
|
|
199
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
200
|
+
return new AST.ContinueStatement();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
printStatement() {
|
|
204
|
+
this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "stampa"');
|
|
205
|
+
const argument = this.expression();
|
|
206
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo argomento');
|
|
207
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
208
|
+
return new AST.PrintStatement(argument);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
expressionStatement() {
|
|
212
|
+
const expr = this.expression();
|
|
213
|
+
this.match(TokenType.PUNTO_VIRGOLA);
|
|
214
|
+
return new AST.ExpressionStatement(expr);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// === Expression Parsing (Precedence Climbing) ===
|
|
218
|
+
expression() {
|
|
219
|
+
return this.assignment();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
assignment() {
|
|
223
|
+
const expr = this.logicalOr();
|
|
224
|
+
|
|
225
|
+
if (this.match(TokenType.ASSEGNA, TokenType.PIU_ASSEGNA, TokenType.MENO_ASSEGNA)) {
|
|
226
|
+
const operator = this.previous().value;
|
|
227
|
+
const value = this.assignment();
|
|
228
|
+
return new AST.AssignmentExpression(operator, expr, value);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return expr;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
logicalOr() {
|
|
235
|
+
let expr = this.logicalAnd();
|
|
236
|
+
|
|
237
|
+
while (this.match(TokenType.O, TokenType.OR)) {
|
|
238
|
+
const operator = '||';
|
|
239
|
+
const right = this.logicalAnd();
|
|
240
|
+
expr = new AST.LogicalExpression(operator, expr, right);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return expr;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
logicalAnd() {
|
|
247
|
+
let expr = this.equality();
|
|
248
|
+
|
|
249
|
+
while (this.match(TokenType.E, TokenType.AND)) {
|
|
250
|
+
const operator = '&&';
|
|
251
|
+
const right = this.equality();
|
|
252
|
+
expr = new AST.LogicalExpression(operator, expr, right);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return expr;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
equality() {
|
|
259
|
+
let expr = this.comparison();
|
|
260
|
+
|
|
261
|
+
while (this.match(TokenType.UGUALE, TokenType.DIVERSO, TokenType.UGUALE_STRETTO, TokenType.DIVERSO_STRETTO)) {
|
|
262
|
+
const operator = this.previous().value;
|
|
263
|
+
const right = this.comparison();
|
|
264
|
+
expr = new AST.BinaryExpression(operator, expr, right);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return expr;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
comparison() {
|
|
271
|
+
let expr = this.term();
|
|
272
|
+
|
|
273
|
+
while (this.match(TokenType.MINORE, TokenType.MAGGIORE, TokenType.MINORE_UGUALE, TokenType.MAGGIORE_UGUALE)) {
|
|
274
|
+
const operator = this.previous().value;
|
|
275
|
+
const right = this.term();
|
|
276
|
+
expr = new AST.BinaryExpression(operator, expr, right);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return expr;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
term() {
|
|
283
|
+
let expr = this.factor();
|
|
284
|
+
|
|
285
|
+
while (this.match(TokenType.PIU, TokenType.MENO)) {
|
|
286
|
+
const operator = this.previous().value;
|
|
287
|
+
const right = this.factor();
|
|
288
|
+
expr = new AST.BinaryExpression(operator, expr, right);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return expr;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
factor() {
|
|
295
|
+
let expr = this.unary();
|
|
296
|
+
|
|
297
|
+
while (this.match(TokenType.MOLTIPLICA, TokenType.DIVIDI, TokenType.MODULO)) {
|
|
298
|
+
const operator = this.previous().value;
|
|
299
|
+
const right = this.unary();
|
|
300
|
+
expr = new AST.BinaryExpression(operator, expr, right);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return expr;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
unary() {
|
|
307
|
+
if (this.match(TokenType.NON, TokenType.MENO)) {
|
|
308
|
+
const operator = this.previous().value === 'non' ? '!' : this.previous().value;
|
|
309
|
+
const argument = this.unary();
|
|
310
|
+
return new AST.UnaryExpression(operator, argument);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return this.postfix();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
postfix() {
|
|
317
|
+
let expr = this.call();
|
|
318
|
+
|
|
319
|
+
while (this.match(TokenType.INCREMENTA, TokenType.DECREMENTA)) {
|
|
320
|
+
const operator = this.previous().value;
|
|
321
|
+
expr = new AST.UpdateExpression(operator, expr, false);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return expr;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
call() {
|
|
328
|
+
let expr = this.primary();
|
|
329
|
+
|
|
330
|
+
while (true) {
|
|
331
|
+
if (this.match(TokenType.PARENTESI_APERTA)) {
|
|
332
|
+
expr = this.finishCall(expr);
|
|
333
|
+
} else if (this.match(TokenType.PUNTO)) {
|
|
334
|
+
const property = this.consume(TokenType.IDENTIFICATORE, 'Nome proprietà atteso dopo "."');
|
|
335
|
+
expr = new AST.MemberExpression(expr, new AST.Identifier(property.value), false);
|
|
336
|
+
} else if (this.match(TokenType.QUADRA_APERTA)) {
|
|
337
|
+
const property = this.expression();
|
|
338
|
+
this.consume(TokenType.QUADRA_CHIUSA, 'Atteso "]" dopo indice');
|
|
339
|
+
expr = new AST.MemberExpression(expr, property, true);
|
|
340
|
+
} else {
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return expr;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
finishCall(callee) {
|
|
349
|
+
const args = [];
|
|
350
|
+
if (!this.check(TokenType.PARENTESI_CHIUSA)) {
|
|
351
|
+
do {
|
|
352
|
+
args.push(this.expression());
|
|
353
|
+
} while (this.match(TokenType.VIRGOLA));
|
|
354
|
+
}
|
|
355
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo argomenti');
|
|
356
|
+
return new AST.CallExpression(callee, args);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
primary() {
|
|
360
|
+
if (this.match(TokenType.VERO)) return new AST.BooleanLiteral(true);
|
|
361
|
+
if (this.match(TokenType.FALSO)) return new AST.BooleanLiteral(false);
|
|
362
|
+
if (this.match(TokenType.NULLO)) return new AST.NullLiteral();
|
|
363
|
+
|
|
364
|
+
if (this.match(TokenType.NUMERO)) {
|
|
365
|
+
return new AST.NumericLiteral(this.previous().value);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (this.match(TokenType.STRINGA)) {
|
|
369
|
+
return new AST.StringLiteral(this.previous().value);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (this.match(TokenType.IDENTIFICATORE)) {
|
|
373
|
+
return new AST.Identifier(this.previous().value);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (this.match(TokenType.QUESTO)) {
|
|
377
|
+
return new AST.Identifier('questo');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (this.match(TokenType.QUADRA_APERTA)) {
|
|
381
|
+
return this.arrayLiteral();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (this.match(TokenType.GRAFFA_APERTA)) {
|
|
385
|
+
return this.objectLiteral();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (this.match(TokenType.PARENTESI_APERTA)) {
|
|
389
|
+
// Potrebbe essere una arrow function o un'espressione raggruppata
|
|
390
|
+
const startPos = this.current - 1;
|
|
391
|
+
|
|
392
|
+
// Prova a parsare come arrow function
|
|
393
|
+
if (this.check(TokenType.PARENTESI_CHIUSA) || this.check(TokenType.IDENTIFICATORE)) {
|
|
394
|
+
const params = [];
|
|
395
|
+
if (!this.check(TokenType.PARENTESI_CHIUSA)) {
|
|
396
|
+
do {
|
|
397
|
+
if (this.match(TokenType.IDENTIFICATORE)) {
|
|
398
|
+
params.push(this.previous().value);
|
|
399
|
+
} else {
|
|
400
|
+
// Non è una arrow function, torna indietro
|
|
401
|
+
this.current = startPos + 1;
|
|
402
|
+
const expr = this.expression();
|
|
403
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo espressione');
|
|
404
|
+
return expr;
|
|
405
|
+
}
|
|
406
|
+
} while (this.match(TokenType.VIRGOLA));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (this.match(TokenType.PARENTESI_CHIUSA) && this.match(TokenType.FRECCIA)) {
|
|
410
|
+
// È una arrow function
|
|
411
|
+
if (this.match(TokenType.GRAFFA_APERTA)) {
|
|
412
|
+
const body = this.blockStatement();
|
|
413
|
+
return new AST.ArrowFunction(params, body);
|
|
414
|
+
} else {
|
|
415
|
+
const body = this.expression();
|
|
416
|
+
return new AST.ArrowFunction(params, body);
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
// Non è una arrow function, torna indietro
|
|
420
|
+
this.current = startPos + 1;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const expr = this.expression();
|
|
425
|
+
this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo espressione');
|
|
426
|
+
return expr;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
throw new ParserError(`Token inaspettato: ${this.peek().type}`, this.peek());
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
arrayLiteral() {
|
|
433
|
+
const elements = [];
|
|
434
|
+
if (!this.check(TokenType.QUADRA_CHIUSA)) {
|
|
435
|
+
do {
|
|
436
|
+
elements.push(this.expression());
|
|
437
|
+
} while (this.match(TokenType.VIRGOLA));
|
|
438
|
+
}
|
|
439
|
+
this.consume(TokenType.QUADRA_CHIUSA, 'Atteso "]" alla fine dell\'array');
|
|
440
|
+
return new AST.ArrayLiteral(elements);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
objectLiteral() {
|
|
444
|
+
const properties = [];
|
|
445
|
+
if (!this.check(TokenType.GRAFFA_CHIUSA)) {
|
|
446
|
+
do {
|
|
447
|
+
const key = this.consume(TokenType.IDENTIFICATORE, 'Nome proprietà atteso').value;
|
|
448
|
+
this.consume(TokenType.DUE_PUNTI, 'Atteso ":" dopo nome proprietà');
|
|
449
|
+
const value = this.expression();
|
|
450
|
+
properties.push(new AST.Property(key, value));
|
|
451
|
+
} while (this.match(TokenType.VIRGOLA));
|
|
452
|
+
}
|
|
453
|
+
this.consume(TokenType.GRAFFA_CHIUSA, 'Atteso "}" alla fine dell\'oggetto');
|
|
454
|
+
return new AST.ObjectLiteral(properties);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
synchronize() {
|
|
458
|
+
this.advance();
|
|
459
|
+
while (!this.isAtEnd()) {
|
|
460
|
+
if (this.previous().type === TokenType.PUNTO_VIRGOLA) return;
|
|
461
|
+
switch (this.peek().type) {
|
|
462
|
+
case TokenType.FUNZIONE:
|
|
463
|
+
case TokenType.VARIABILE:
|
|
464
|
+
case TokenType.COSTANTE:
|
|
465
|
+
case TokenType.PER:
|
|
466
|
+
case TokenType.SE:
|
|
467
|
+
case TokenType.MENTRE:
|
|
468
|
+
case TokenType.RITORNA:
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
this.advance();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
module.exports = { Parser, ParserError };
|
package/src/pm/cli.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VladPM CLI
|
|
3
|
+
* Package Manager per VladX
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const init = require('./commands/init.js');
|
|
7
|
+
const login = require('./commands/login.js');
|
|
8
|
+
const publish = require('./commands/publish.js');
|
|
9
|
+
const install = require('./commands/install.js');
|
|
10
|
+
const uninstall = require('./commands/uninstall.js');
|
|
11
|
+
const search = require('./commands/search.js');
|
|
12
|
+
const list = require('./commands/list.js');
|
|
13
|
+
const config = require('./commands/config.js');
|
|
14
|
+
|
|
15
|
+
const VERSION = '1.0.0';
|
|
16
|
+
|
|
17
|
+
const COLORS = {
|
|
18
|
+
reset: '\x1b[0m',
|
|
19
|
+
bright: '\x1b[1m',
|
|
20
|
+
red: '\x1b[31m',
|
|
21
|
+
green: '\x1b[32m',
|
|
22
|
+
yellow: '\x1b[33m',
|
|
23
|
+
cyan: '\x1b[36m'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function colorize(text, color) {
|
|
27
|
+
return `${COLORS[color]}${text}${COLORS.reset}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function showHelp() {
|
|
31
|
+
console.log(`
|
|
32
|
+
${colorize('VladPM', 'bright')} - Package Manager per VladX
|
|
33
|
+
|
|
34
|
+
${colorize('Uso:', 'cyan')}
|
|
35
|
+
vladpm init Inizializza un nuovo progetto
|
|
36
|
+
vladpm login Login al registry
|
|
37
|
+
vladpm logout Logout dal registry
|
|
38
|
+
vladpm publish Pubblica il pacchetto
|
|
39
|
+
vladpm install [pkg] Installa un pacchetto (o tutti da vladx.json)
|
|
40
|
+
vladpm uninstall <pkg> Rimuove un pacchetto
|
|
41
|
+
vladpm search <query> Cerca pacchetti
|
|
42
|
+
vladpm list Lista pacchetti installati
|
|
43
|
+
vladpm --help, -h Mostra questo aiuto
|
|
44
|
+
vladpm --version, -v Mostra la versione
|
|
45
|
+
|
|
46
|
+
${colorize('Esempi:', 'cyan')}
|
|
47
|
+
vladpm init
|
|
48
|
+
vladpm install mio-pacchetto
|
|
49
|
+
vladpm publish
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function showVersion() {
|
|
54
|
+
console.log(`VladPM v${VERSION}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function run(args) {
|
|
58
|
+
if (args.length === 0) {
|
|
59
|
+
showHelp();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const command = args[0];
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
switch (command) {
|
|
67
|
+
case '--help':
|
|
68
|
+
case '-h':
|
|
69
|
+
case 'help':
|
|
70
|
+
showHelp();
|
|
71
|
+
break;
|
|
72
|
+
|
|
73
|
+
case '--version':
|
|
74
|
+
case '-v':
|
|
75
|
+
case 'version':
|
|
76
|
+
showVersion();
|
|
77
|
+
break;
|
|
78
|
+
|
|
79
|
+
case 'init':
|
|
80
|
+
await init.execute(args.slice(1));
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
case 'login':
|
|
84
|
+
await login.execute(args.slice(1));
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case 'logout':
|
|
88
|
+
await login.logout();
|
|
89
|
+
break;
|
|
90
|
+
|
|
91
|
+
case 'publish':
|
|
92
|
+
await publish.execute(args.slice(1));
|
|
93
|
+
break;
|
|
94
|
+
|
|
95
|
+
case 'install':
|
|
96
|
+
case 'i':
|
|
97
|
+
await install.execute(args.slice(1));
|
|
98
|
+
break;
|
|
99
|
+
|
|
100
|
+
case 'uninstall':
|
|
101
|
+
case 'remove':
|
|
102
|
+
case 'rm':
|
|
103
|
+
await uninstall.execute(args.slice(1));
|
|
104
|
+
break;
|
|
105
|
+
|
|
106
|
+
case 'search':
|
|
107
|
+
await search.execute(args.slice(1));
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case 'list':
|
|
111
|
+
case 'ls':
|
|
112
|
+
await list.execute(args.slice(1));
|
|
113
|
+
break;
|
|
114
|
+
|
|
115
|
+
case 'config':
|
|
116
|
+
await config.execute(args.slice(1));
|
|
117
|
+
break;
|
|
118
|
+
|
|
119
|
+
default:
|
|
120
|
+
console.error(colorize(`✗ Comando sconosciuto: ${command}`, 'red'));
|
|
121
|
+
console.log('Usa "vladpm --help" per vedere i comandi disponibili.');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(colorize(`✗ Errore: ${error.message}`, 'red'));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = { run };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VladPM - config command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { getConfig, saveConfig, getRegistry } = require('../utils/config.js');
|
|
6
|
+
|
|
7
|
+
const COLORS = {
|
|
8
|
+
reset: '\x1b[0m',
|
|
9
|
+
bright: '\x1b[1m',
|
|
10
|
+
green: '\x1b[32m',
|
|
11
|
+
cyan: '\x1b[36m',
|
|
12
|
+
yellow: '\x1b[33m'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function colorize(text, color) {
|
|
16
|
+
return `${COLORS[color]}${text}${COLORS.reset}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function execute(args) {
|
|
20
|
+
if (args.length === 0) {
|
|
21
|
+
// Show current config
|
|
22
|
+
console.log(colorize('\n⚙️ Configurazione VladPM\n', 'bright'));
|
|
23
|
+
const config = getConfig();
|
|
24
|
+
console.log(` Registry: ${colorize(config.registry || 'default', 'cyan')}`);
|
|
25
|
+
if (config.username) {
|
|
26
|
+
console.log(` Utente: ${colorize(config.username, 'cyan')}`);
|
|
27
|
+
}
|
|
28
|
+
console.log();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const subcommand = args[0];
|
|
33
|
+
|
|
34
|
+
if (subcommand === 'set') {
|
|
35
|
+
const key = args[1];
|
|
36
|
+
const value = args[2];
|
|
37
|
+
|
|
38
|
+
if (!key || !value) {
|
|
39
|
+
console.log(colorize('Uso: vladpm config set <chiave> <valore>', 'yellow'));
|
|
40
|
+
console.log('\nChiavi disponibili:');
|
|
41
|
+
console.log(' registry URL del registry (es: http://localhost:3000)');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const config = getConfig();
|
|
46
|
+
|
|
47
|
+
if (key === 'registry') {
|
|
48
|
+
config.registry = value;
|
|
49
|
+
saveConfig(config);
|
|
50
|
+
console.log(colorize(`✓ Registry impostato a: ${value}`, 'green'));
|
|
51
|
+
} else {
|
|
52
|
+
console.log(colorize(`✗ Chiave sconosciuta: ${key}`, 'yellow'));
|
|
53
|
+
}
|
|
54
|
+
} else if (subcommand === 'get') {
|
|
55
|
+
const key = args[1];
|
|
56
|
+
const config = getConfig();
|
|
57
|
+
|
|
58
|
+
if (key === 'registry') {
|
|
59
|
+
console.log(getRegistry());
|
|
60
|
+
} else if (key) {
|
|
61
|
+
console.log(config[key] || '');
|
|
62
|
+
} else {
|
|
63
|
+
console.log(JSON.stringify(config, null, 2));
|
|
64
|
+
}
|
|
65
|
+
} else if (subcommand === 'reset') {
|
|
66
|
+
const config = getConfig();
|
|
67
|
+
delete config.registry;
|
|
68
|
+
saveConfig(config);
|
|
69
|
+
console.log(colorize('✓ Configurazione resettata ai valori di default', 'green'));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(colorize(`Sottocomando sconosciuto: ${subcommand}`, 'yellow'));
|
|
72
|
+
console.log('Usa: vladpm config [set|get|reset]');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { execute };
|