@designliquido/delegua 1.16.1 → 1.16.3

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 (82) hide show
  1. package/analisador-semantico/analisador-semantico.d.ts +14 -0
  2. package/analisador-semantico/analisador-semantico.d.ts.map +1 -1
  3. package/analisador-semantico/analisador-semantico.js +20 -12
  4. package/analisador-semantico/analisador-semantico.js.map +1 -1
  5. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts +5 -0
  6. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
  7. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
  8. package/bin/package.json +1 -1
  9. package/estilizador/estilizador-delegua.d.ts.map +1 -1
  10. package/estilizador/estilizador-delegua.js +10 -2
  11. package/estilizador/estilizador-delegua.js.map +1 -1
  12. package/estilizador/index.d.ts +1 -0
  13. package/estilizador/index.d.ts.map +1 -1
  14. package/estilizador/index.js +1 -0
  15. package/estilizador/index.js.map +1 -1
  16. package/estilizador/quebrador-linha.d.ts +18 -0
  17. package/estilizador/quebrador-linha.d.ts.map +1 -0
  18. package/estilizador/quebrador-linha.js +184 -0
  19. package/estilizador/quebrador-linha.js.map +1 -0
  20. package/estilizador/regras/index.d.ts +3 -3
  21. package/estilizador/regras/index.d.ts.map +1 -1
  22. package/estilizador/regras/index.js +3 -3
  23. package/estilizador/regras/index.js.map +1 -1
  24. package/estilizador/regras/{convencao-nomenclatura.d.ts → regra-convencao-nomenclatura.d.ts} +3 -28
  25. package/estilizador/regras/regra-convencao-nomenclatura.d.ts.map +1 -0
  26. package/estilizador/regras/{convencao-nomenclatura.js → regra-convencao-nomenclatura.js} +1 -1
  27. package/estilizador/regras/regra-convencao-nomenclatura.js.map +1 -0
  28. package/estilizador/regras/{fortalecer-tipos.d.ts → regra-fortalecer-tipos.d.ts} +1 -1
  29. package/estilizador/regras/regra-fortalecer-tipos.d.ts.map +1 -0
  30. package/estilizador/regras/{fortalecer-tipos.js → regra-fortalecer-tipos.js} +1 -1
  31. package/estilizador/regras/regra-fortalecer-tipos.js.map +1 -0
  32. package/estilizador/regras/{paradigma-consistente.d.ts → regra-paradigma-consistente.d.ts} +1 -1
  33. package/estilizador/regras/regra-paradigma-consistente.d.ts.map +1 -0
  34. package/estilizador/regras/{paradigma-consistente.js → regra-paradigma-consistente.js} +1 -1
  35. package/estilizador/regras/regra-paradigma-consistente.js.map +1 -0
  36. package/interfaces/estilizador/estilizador-interface.d.ts +1 -6
  37. package/interfaces/estilizador/estilizador-interface.d.ts.map +1 -1
  38. package/interfaces/estilizador/index.d.ts +2 -0
  39. package/interfaces/estilizador/index.d.ts.map +1 -1
  40. package/interfaces/estilizador/index.js +2 -0
  41. package/interfaces/estilizador/index.js.map +1 -1
  42. package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.d.ts +26 -0
  43. package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.d.ts.map +1 -0
  44. package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.js +3 -0
  45. package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.js.map +1 -0
  46. package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.d.ts +8 -0
  47. package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.d.ts.map +1 -0
  48. package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.js +3 -0
  49. package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.js.map +1 -0
  50. package/interpretador/dialetos/pitugues/interpretador-pitugues.js +3 -3
  51. package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
  52. package/interpretador/interpretador-base.d.ts +1 -0
  53. package/interpretador/interpretador-base.d.ts.map +1 -1
  54. package/interpretador/interpretador-base.js +2 -0
  55. package/interpretador/interpretador-base.js.map +1 -1
  56. package/interpretador/interpretador.d.ts.map +1 -1
  57. package/interpretador/interpretador.js +12 -0
  58. package/interpretador/interpretador.js.map +1 -1
  59. package/package.json +1 -1
  60. package/tradutores/index.d.ts +1 -1
  61. package/tradutores/index.d.ts.map +1 -1
  62. package/tradutores/index.js +1 -1
  63. package/tradutores/index.js.map +1 -1
  64. package/tradutores/tradutor-reverso-calango.d.ts +45 -0
  65. package/tradutores/tradutor-reverso-calango.d.ts.map +1 -0
  66. package/tradutores/tradutor-reverso-calango.js +351 -0
  67. package/tradutores/tradutor-reverso-calango.js.map +1 -0
  68. package/tradutores/tradutor-reverso-python.d.ts +58 -26
  69. package/tradutores/tradutor-reverso-python.d.ts.map +1 -1
  70. package/tradutores/tradutor-reverso-python.js +609 -52
  71. package/tradutores/tradutor-reverso-python.js.map +1 -1
  72. package/umd/delegua.js +1716 -606
  73. package/estilizador/regras/convencao-nomenclatura.d.ts.map +0 -1
  74. package/estilizador/regras/convencao-nomenclatura.js.map +0 -1
  75. package/estilizador/regras/fortalecer-tipos.d.ts.map +0 -1
  76. package/estilizador/regras/fortalecer-tipos.js.map +0 -1
  77. package/estilizador/regras/paradigma-consistente.d.ts.map +0 -1
  78. package/estilizador/regras/paradigma-consistente.js.map +0 -1
  79. package/tradutores/tradutor-calango.d.ts +0 -23
  80. package/tradutores/tradutor-calango.d.ts.map +0 -1
  81. package/tradutores/tradutor-calango.js +0 -54
  82. package/tradutores/tradutor-calango.js.map +0 -1
@@ -2,70 +2,627 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TradutorReversoPython = void 0;
4
4
  const antlr4ts_1 = require("antlr4ts");
5
- const python3_parser_1 = require("./python/python3-parser");
6
- const ParseTreeWalker_1 = require("antlr4ts/tree/ParseTreeWalker");
5
+ const AbstractParseTreeVisitor_1 = require("antlr4ts/tree/AbstractParseTreeVisitor");
7
6
  const python3_lexer_1 = require("./python/python3-lexer");
7
+ const python3_parser_1 = require("./python/python3-parser");
8
8
  /**
9
9
  * Tradutor reverso de Python para Delégua.
10
- * Utiliza o ecossistema do ANTLR para percorrer código em
10
+ * Utiliza o visitor do ANTLR para percorrer a árvore sintática em
11
11
  * Python e traduzir para Delégua.
12
12
  */
13
- class TradutorReversoPython {
14
- /**
15
- * Aqui é preciso contar se o contexto tem filhos.
16
- * alguns casos em que este código é executado mais
17
- * de uma vez por algum motivo.
18
- * @param ctx O contexto da atribuição.
19
- */
20
- enterSimple_assign(ctx) {
21
- if (ctx.childCount > 0) {
22
- this.resultado += ' = ';
23
- }
24
- }
25
- /**
26
- * Aparentemente é o melhor lugar para escrever quebras de linha.
27
- * @param ctx Contexto da instrução.
28
- */
29
- exitStmt(ctx) {
30
- this.resultado += ctx.stop.text;
31
- }
32
- enterExpr_stmt(ctx) {
33
- // console.log(ctx.start.text);
34
- }
35
- enterExpr(ctx) {
36
- switch (ctx.start.text) {
37
- case 'input':
38
- this.resultado += 'leia(';
39
- break;
40
- case 'print':
41
- this.resultado += 'escreva(';
42
- break;
43
- default:
44
- this.resultado += ctx.start.text;
45
- break;
13
+ class TradutorReversoPython extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
14
+ constructor() {
15
+ super(...arguments);
16
+ // Funções globais Python Delégua
17
+ this.mapeamentoFuncoes = {
18
+ print: 'escreva',
19
+ input: 'leia',
20
+ len: 'tamanho',
21
+ int: 'inteiro',
22
+ float: 'real',
23
+ str: 'texto',
24
+ bool: 'logico',
25
+ type: 'tipoDe',
26
+ range: 'intervalo',
27
+ abs: 'absoluto',
28
+ round: 'arredondar',
29
+ min: 'minimo',
30
+ max: 'maximo',
31
+ sum: 'somar',
32
+ };
33
+ // Métodos de instância Python → Delégua
34
+ this.mapeamentoMetodos = {
35
+ // Lista / vetor
36
+ append: 'adicionar',
37
+ pop: 'removerUltimo',
38
+ reverse: 'inverter',
39
+ sort: 'ordenar',
40
+ clear: 'limpar',
41
+ // Texto / string
42
+ upper: 'maiusculo',
43
+ lower: 'minusculo',
44
+ strip: 'aparar',
45
+ lstrip: 'aparar',
46
+ rstrip: 'aparar',
47
+ split: 'dividir',
48
+ join: 'juntar',
49
+ startswith: 'iniciaCom',
50
+ endswith: 'terminaCom',
51
+ replace: 'substituir',
52
+ find: 'encontrar',
53
+ count: 'contar',
54
+ // Dicionário
55
+ keys: 'chaves',
56
+ values: 'valores',
57
+ items: 'itens',
58
+ };
59
+ }
60
+ defaultResult() {
61
+ return '';
62
+ }
63
+ aggregateResult(aggregate, nextResult) {
64
+ return aggregate + nextResult;
65
+ }
66
+ visitTerminal(node) {
67
+ return node.text;
68
+ }
69
+ visitFile_input(ctx) {
70
+ return ctx.stmt().map((s) => this.visit(s)).join('\n');
71
+ }
72
+ visitSimple_stmt(ctx) {
73
+ return ctx.small_stmt().map((s) => this.visit(s)).join('; ');
74
+ }
75
+ visitExpr_stmt(ctx) {
76
+ const lhs = this.visit(ctx.testlist_star_expr());
77
+ const simpleAssign = ctx.simple_assign();
78
+ if (simpleAssign && simpleAssign.childCount > 0) {
79
+ const rhs = this.visitSimple_assign(simpleAssign);
80
+ // Atribuições a atributos (a.b = x) ou índices (a[i] = x) não usam 'var'
81
+ const prefixo = lhs.includes('.') || lhs.includes('[') ? '' : 'var ';
82
+ return `${prefixo}${lhs} = ${rhs}`;
83
+ }
84
+ if (ctx.augassign()) {
85
+ const op = this.visitAugassign(ctx.augassign());
86
+ const testlist = ctx.testlist();
87
+ const yieldExpr = ctx.yield_expr();
88
+ const rhs = testlist
89
+ ? this.visit(testlist)
90
+ : yieldExpr
91
+ ? this.visit(yieldExpr)
92
+ : '';
93
+ return `${lhs} ${op} ${rhs}`;
94
+ }
95
+ return lhs;
96
+ }
97
+ visitSimple_assign(ctx) {
98
+ const exprs = ctx.testlist_star_expr();
99
+ return this.visit(exprs[exprs.length - 1]);
100
+ }
101
+ visitAugassign(ctx) {
102
+ if (ctx.ADD_ASSIGN())
103
+ return '+=';
104
+ if (ctx.SUB_ASSIGN())
105
+ return '-=';
106
+ if (ctx.MULT_ASSIGN())
107
+ return '*=';
108
+ if (ctx.DIV_ASSIGN())
109
+ return '/=';
110
+ if (ctx.MOD_ASSIGN())
111
+ return '%=';
112
+ if (ctx.AND_ASSIGN())
113
+ return '&=';
114
+ if (ctx.OR_ASSIGN())
115
+ return '|=';
116
+ if (ctx.XOR_ASSIGN())
117
+ return '^=';
118
+ if (ctx.LEFT_SHIFT_ASSIGN())
119
+ return '<<=';
120
+ if (ctx.RIGHT_SHIFT_ASSIGN())
121
+ return '>>=';
122
+ if (ctx.POWER_ASSIGN())
123
+ return '**=';
124
+ if (ctx.IDIV_ASSIGN())
125
+ return '//=';
126
+ return ctx.text;
127
+ }
128
+ visitTestlist_star_expr(ctx) {
129
+ return ctx.test().map((t) => this.visit(t)).join(', ');
130
+ }
131
+ visitTestlist(ctx) {
132
+ return ctx.test().map((t) => this.visit(t)).join(', ');
133
+ }
134
+ visitTest(ctx) {
135
+ const orTests = ctx.or_test();
136
+ if (orTests.length === 1)
137
+ return this.visit(orTests[0]);
138
+ const lambdef = ctx.lambdef();
139
+ if (lambdef)
140
+ return this.visit(lambdef);
141
+ // Expressão ternária (a if cond else b) — implementada em fase futura
142
+ return this.visitChildren(ctx);
143
+ }
144
+ visitOr_test(ctx) {
145
+ return ctx.and_test().map((t) => this.visit(t)).join(' ou ');
146
+ }
147
+ visitAnd_test(ctx) {
148
+ return ctx.not_test().map((t) => this.visit(t)).join(' e ');
149
+ }
150
+ visitNot_test(ctx) {
151
+ if (ctx.NOT()) {
152
+ return `nao ${this.visit(ctx.not_test())}`;
153
+ }
154
+ const comp = ctx.comparison();
155
+ if (comp)
156
+ return this.visit(comp);
157
+ return this.visitChildren(ctx);
158
+ }
159
+ visitComparison(ctx) {
160
+ const exprs = ctx.expr();
161
+ if (exprs.length === 1)
162
+ return this.visit(exprs[0]);
163
+ const ops = ctx.comp_op();
164
+ let resultado = this.visit(exprs[0]);
165
+ for (let i = 0; i < ops.length; i++) {
166
+ resultado += ` ${this.visitComp_op(ops[i])} ${this.visit(exprs[i + 1])}`;
46
167
  }
168
+ return resultado;
47
169
  }
48
- exitExpr(ctx) {
49
- switch (ctx.start.text) {
50
- case 'input':
51
- case 'print':
52
- this.resultado += ')';
170
+ visitComp_op(ctx) {
171
+ if (ctx.LESS_THAN())
172
+ return '<';
173
+ if (ctx.GREATER_THAN())
174
+ return '>';
175
+ if (ctx.EQUALS())
176
+ return '==';
177
+ if (ctx.GT_EQ())
178
+ return '>=';
179
+ if (ctx.LT_EQ())
180
+ return '<=';
181
+ if (ctx.NOT_EQ_1() || ctx.NOT_EQ_2())
182
+ return '!=';
183
+ if (ctx.NOT() && ctx.IN())
184
+ return 'nao em';
185
+ if (ctx.IN())
186
+ return 'em';
187
+ if (ctx.NOT() && ctx.IS())
188
+ return '!=';
189
+ if (ctx.IS())
190
+ return '==';
191
+ return ctx.text;
192
+ }
193
+ visitArith_expr(ctx) {
194
+ const termos = ctx.term();
195
+ if (termos.length === 1)
196
+ return this.visit(termos[0]);
197
+ let resultado = this.visit(termos[0]);
198
+ let idx = 1;
199
+ for (let i = 1; i < ctx.childCount; i++) {
200
+ const texto = ctx.getChild(i).text;
201
+ if (texto === '+' || texto === '-') {
202
+ resultado += ` ${texto} ${this.visit(termos[idx++])}`;
203
+ }
204
+ }
205
+ return resultado;
206
+ }
207
+ visitTerm(ctx) {
208
+ const fatores = ctx.factor();
209
+ if (fatores.length === 1)
210
+ return this.visit(fatores[0]);
211
+ let resultado = this.visit(fatores[0]);
212
+ let idx = 1;
213
+ for (let i = 1; i < ctx.childCount; i++) {
214
+ const texto = ctx.getChild(i).text;
215
+ if (['*', '/', '%', '//', '@'].includes(texto)) {
216
+ resultado += ` ${texto} ${this.visit(fatores[idx++])}`;
217
+ }
218
+ }
219
+ return resultado;
220
+ }
221
+ visitFactor(ctx) {
222
+ if (ctx.ADD())
223
+ return `+${this.visit(ctx.factor())}`;
224
+ if (ctx.MINUS())
225
+ return `-${this.visit(ctx.factor())}`;
226
+ if (ctx.NOT_OP())
227
+ return `~${this.visit(ctx.factor())}`;
228
+ return this.visit(ctx.power());
229
+ }
230
+ visitPower(ctx) {
231
+ const base = this.visit(ctx.atom_expr());
232
+ if (ctx.POWER()) {
233
+ return `${base} ** ${this.visit(ctx.factor())}`;
234
+ }
235
+ return base;
236
+ }
237
+ visitAtom_expr(ctx) {
238
+ const textoAtomo = this.visit(ctx.atom());
239
+ const trailers = ctx.trailer();
240
+ if (trailers.length === 0)
241
+ return textoAtomo;
242
+ // Chamada de função simples: nome(args)
243
+ if (trailers.length === 1 && trailers[0].OPEN_PAREN()) {
244
+ const nomeFuncao = this.mapeamentoFuncoes[textoAtomo] ?? textoAtomo;
245
+ const arglist = trailers[0].arglist();
246
+ const args = arglist ? this.visit(arglist) : '';
247
+ return `${nomeFuncao}(${args})`;
248
+ }
249
+ // Chamada de método: obj.metodo(args) → dois trailers: .nome e (args)
250
+ if (trailers.length === 2 &&
251
+ trailers[0].DOT() &&
252
+ trailers[0].NAME() &&
253
+ trailers[1].OPEN_PAREN()) {
254
+ const nomeMetodoPython = trailers[0].NAME().text;
255
+ const arglist = trailers[1].arglist();
256
+ const args = arglist ? this.visit(arglist) : '';
257
+ // join é invertido: sep.join(iteravel) → iteravel.juntar(sep)
258
+ if (nomeMetodoPython === 'join') {
259
+ return `${args}.juntar(${textoAtomo})`;
260
+ }
261
+ const nomeMetodoDelégua = this.mapeamentoMetodos[nomeMetodoPython] ?? nomeMetodoPython;
262
+ return `${textoAtomo}.${nomeMetodoDelégua}(${args})`;
263
+ }
264
+ // Fallback: acesso a atributo, índice ou chamadas encadeadas
265
+ let resultado = textoAtomo;
266
+ for (const trailer of trailers) {
267
+ resultado += this.visitTrailer(trailer);
268
+ }
269
+ return resultado;
270
+ }
271
+ visitTrailer(ctx) {
272
+ if (ctx.DOT() && ctx.NAME()) {
273
+ return `.${ctx.NAME().text}`;
274
+ }
275
+ if (ctx.OPEN_BRACK()) {
276
+ const subscriptlist = ctx.subscriptlist();
277
+ const conteudo = subscriptlist ? this.visit(subscriptlist) : '';
278
+ return `[${conteudo}]`;
279
+ }
280
+ if (ctx.OPEN_PAREN()) {
281
+ const arglist = ctx.arglist();
282
+ const args = arglist ? this.visit(arglist) : '';
283
+ return `(${args})`;
284
+ }
285
+ return ctx.text;
286
+ }
287
+ visitAtom(ctx) {
288
+ const nome = ctx.NAME();
289
+ if (nome)
290
+ return nome.text === 'self' ? 'isto' : nome.text;
291
+ const numero = ctx.NUMBER();
292
+ if (numero)
293
+ return numero.text;
294
+ if (ctx.TRUE())
295
+ return 'verdadeiro';
296
+ if (ctx.FALSE())
297
+ return 'falso';
298
+ if (ctx.NONE())
299
+ return 'nulo';
300
+ const strings = ctx.STRING();
301
+ if (strings.length > 0)
302
+ return strings.map((s) => s.text).join(' ');
303
+ if (ctx.OPEN_PAREN()) {
304
+ const testlistComp = ctx.testlist_comp();
305
+ if (testlistComp) {
306
+ // Tupla com vírgula → vetor em Delégua
307
+ if (testlistComp.COMMA().length > 0) {
308
+ return `[${this.visitTestlist_comp(testlistComp)}]`;
309
+ }
310
+ return `(${this.visitTestlist_comp(testlistComp)})`;
311
+ }
312
+ return '()';
313
+ }
314
+ if (ctx.OPEN_BRACK()) {
315
+ const testlistComp = ctx.testlist_comp();
316
+ if (testlistComp) {
317
+ // Compreensão de lista: resultado já é um vetor, não envolve em []
318
+ if (testlistComp.comp_for()) {
319
+ return this.visitTestlist_comp(testlistComp);
320
+ }
321
+ return `[${this.visitTestlist_comp(testlistComp)}]`;
322
+ }
323
+ return '[]';
324
+ }
325
+ if (ctx.OPEN_BRACE()) {
326
+ const dictorsetmaker = ctx.dictorsetmaker();
327
+ if (dictorsetmaker)
328
+ return `{${this.visitDictorsetmaker(dictorsetmaker)}}`;
329
+ return '{}';
330
+ }
331
+ return ctx.text;
332
+ }
333
+ visitArglist(ctx) {
334
+ return ctx.argument().map((a) => this.visit(a)).join(', ');
335
+ }
336
+ visitArgument(ctx) {
337
+ const testes = ctx.test();
338
+ if (testes.length === 1 && !ctx.ASSIGN()) {
339
+ return this.visit(testes[0]);
340
+ }
341
+ // Argumento nomeado: nome=valor
342
+ if (testes.length === 2 && ctx.ASSIGN()) {
343
+ return `${this.visit(testes[0])} = ${this.visit(testes[1])}`;
344
+ }
345
+ return this.visitChildren(ctx);
346
+ }
347
+ visitTestlist_comp(ctx) {
348
+ const compFor = ctx.comp_for();
349
+ if (compFor) {
350
+ return this.traduzirCompreensao(ctx.test(0), compFor);
351
+ }
352
+ return ctx.test().map((t) => this.visit(t)).join(', ');
353
+ }
354
+ traduzirCompreensao(exprCtx, compFor) {
355
+ const variavel = this.visit(compFor.exprlist());
356
+ const iteravel = this.visit(compFor.or_test());
357
+ const expr = this.visit(exprCtx);
358
+ const compIter = compFor.comp_iter();
359
+ const compIf = compIter?.comp_if();
360
+ if (compIf) {
361
+ const cond = this.visitChildren(compIf.test_nocond());
362
+ return `filtrarPor(${iteravel}, funcao(${variavel}) { retorna ${cond} }).mapear(funcao(${variavel}) { retorna ${expr} })`;
363
+ }
364
+ return `${iteravel}.mapear(funcao(${variavel}) { retorna ${expr} })`;
365
+ }
366
+ visitLambdef(ctx) {
367
+ const varargslist = ctx.varargslist();
368
+ const params = varargslist ? this.visitVarargslist(varargslist) : '';
369
+ const corpo = this.visit(ctx.test());
370
+ return `funcao(${params}) { retorna ${corpo} }`;
371
+ }
372
+ visitVarargslist(ctx) {
373
+ const params = [];
374
+ for (let i = 0; i < ctx.childCount;) {
375
+ const texto = ctx.getChild(i).text;
376
+ if (texto === ',') {
377
+ i++;
378
+ continue;
379
+ }
380
+ if (texto === '*' || texto === '**')
53
381
  break;
54
- default:
382
+ const nomeParam = texto;
383
+ if (i + 1 < ctx.childCount && ctx.getChild(i + 1).text === '=') {
384
+ const valorPadrao = this.visit(ctx.getChild(i + 2));
385
+ params.push(`${nomeParam} = ${valorPadrao}`);
386
+ i += 3;
387
+ }
388
+ else {
389
+ params.push(nomeParam);
390
+ i++;
391
+ }
392
+ }
393
+ return params.join(', ');
394
+ }
395
+ visitDictorsetmaker(ctx) {
396
+ const tests = ctx.test();
397
+ if (ctx.COLON().length > 0) {
398
+ // Dicionário: testes alternados como chave/valor
399
+ const pares = [];
400
+ for (let i = 0; i + 1 < tests.length; i += 2) {
401
+ pares.push(`${this.visit(tests[i])}: ${this.visit(tests[i + 1])}`);
402
+ }
403
+ return pares.join(', ');
404
+ }
405
+ // Conjunto (set) — representado como lista em Delégua
406
+ return tests.map((t) => this.visit(t)).join(', ');
407
+ }
408
+ visitSubscriptlist(ctx) {
409
+ return ctx.subscript().map((s) => this.visitSubscript(s)).join(', ');
410
+ }
411
+ visitSubscript(ctx) {
412
+ const tests = ctx.test();
413
+ if (!ctx.COLON()) {
414
+ // Índice simples
415
+ return tests.length > 0 ? this.visit(tests[0]) : '';
416
+ }
417
+ // Fatia: [inicio]:fim → inicio..fim
418
+ // Se o primeiro filho é ':', não há início (ex: texto[:3])
419
+ const temInicio = ctx.childCount > 0 && ctx.getChild(0).text !== ':';
420
+ const inicio = temInicio ? this.visit(tests[0]) : '';
421
+ const fimIdx = temInicio ? 1 : 0;
422
+ const fim = tests.length > fimIdx ? this.visit(tests[fimIdx]) : '';
423
+ return `${inicio}..${fim}`;
424
+ }
425
+ // Retorna as linhas já indentadas de um bloco, sem os colchetes externos.
426
+ visitLinhasCorpo(ctx) {
427
+ const linhas = [];
428
+ const simpleStmt = ctx.simple_stmt();
429
+ if (simpleStmt) {
430
+ linhas.push(` ${this.visit(simpleStmt)}`);
431
+ }
432
+ else {
433
+ for (const stmt of ctx.stmt()) {
434
+ const traduzido = this.visit(stmt);
435
+ for (const linha of traduzido.split('\n')) {
436
+ linhas.push(` ${linha}`);
437
+ }
438
+ }
439
+ }
440
+ return linhas;
441
+ }
442
+ // Traduz um bloco indentado (suite) para o corpo entre chaves de Delégua.
443
+ visitCorpo(ctx) {
444
+ return `{\n${this.visitLinhasCorpo(ctx).join('\n')}\n}`;
445
+ }
446
+ visitTry_stmt(ctx) {
447
+ const corpoTente = this.visitCorpo(ctx.suite(0));
448
+ let resultado = `tente ${corpoTente}`;
449
+ const excepts = ctx.except_clause();
450
+ if (excepts.length > 0) {
451
+ // Detecta alias do erro na primeira cláusula except com `as nome`
452
+ const alias = excepts.find((e) => e.NAME())?.NAME()?.text;
453
+ // Junta todos os corpos except num único bloco pegue
454
+ const todasLinhas = [];
455
+ for (let i = 0; i < excepts.length; i++) {
456
+ todasLinhas.push(...this.visitLinhasCorpo(ctx.suite(i + 1)));
457
+ }
458
+ const corpoPegue = `{\n${todasLinhas.join('\n')}\n}`;
459
+ resultado += alias ? ` pegue (${alias}) ${corpoPegue}` : ` pegue ${corpoPegue}`;
460
+ }
461
+ // Índice da suite do else/finally começa após as suites de except
462
+ let suiteIdx = 1 + excepts.length;
463
+ if (ctx.ELSE()) {
464
+ suiteIdx++; // else não tem equivalente em Delégua — ignora
465
+ }
466
+ if (ctx.FINALLY()) {
467
+ resultado += ` finalmente ${this.visitCorpo(ctx.suite(suiteIdx))}`;
468
+ }
469
+ return resultado;
470
+ }
471
+ visitRaise_stmt(ctx) {
472
+ const tests = ctx.test();
473
+ if (tests.length === 0)
474
+ return 'levante';
475
+ return `levante ${this.visit(tests[0])}`;
476
+ }
477
+ visitWith_stmt(ctx) {
478
+ const linhasCorpo = this.visitLinhasCorpo(ctx.suite());
479
+ // Apenas itens com `as` podem ser traduzidos para `tendo...como`
480
+ const itemsComAs = ctx.with_item().filter((item) => item.expr());
481
+ if (itemsComAs.length === 0) {
482
+ // Nenhum item com `as`: traduz apenas o corpo, sem tendo
483
+ return linhasCorpo.map((l) => l.trimStart()).join('\n');
484
+ }
485
+ return this.construirTendo(itemsComAs, 0, linhasCorpo);
486
+ }
487
+ // Constrói blocos `tendo` aninhados para cada item do `with`.
488
+ // Items sem `as` são ignorados (Delégua exige um identificador).
489
+ construirTendo(items, i, linhas) {
490
+ if (i >= items.length) {
491
+ return `{\n${linhas.join('\n')}\n}`;
492
+ }
493
+ const item = items[i];
494
+ const varExpr = item.expr();
495
+ const expr = this.visit(item.test());
496
+ if (!varExpr) {
497
+ // Sem `as`: sem variável para ligar — pula este item
498
+ return this.construirTendo(items, i + 1, linhas);
499
+ }
500
+ const nomeVar = this.visit(varExpr);
501
+ // Para múltiplos itens, o próximo nível é indentado dentro deste bloco
502
+ let linhasInternas;
503
+ if (i + 1 < items.length) {
504
+ const blocoInterno = this.construirTendo(items, i + 1, linhas);
505
+ linhasInternas = blocoInterno.split('\n').map((l) => ` ${l}`);
506
+ }
507
+ else {
508
+ linhasInternas = linhas;
509
+ }
510
+ return `tendo ${expr} como ${nomeVar} {\n${linhasInternas.join('\n')}\n}`;
511
+ }
512
+ visitIf_stmt(ctx) {
513
+ const testes = ctx.test();
514
+ const suites = ctx.suite();
515
+ const elifs = ctx.ELIF();
516
+ // Primeiro bloco: se (cond) { ... }
517
+ let resultado = `se (${this.visit(testes[0])}) ${this.visitCorpo(suites[0])}`;
518
+ // Blocos elif: senão se (cond) { ... }
519
+ for (let i = 0; i < elifs.length; i++) {
520
+ resultado += ` senão se (${this.visit(testes[i + 1])}) ${this.visitCorpo(suites[i + 1])}`;
521
+ }
522
+ // Bloco else: senão { ... }
523
+ if (ctx.ELSE()) {
524
+ resultado += ` senão ${this.visitCorpo(suites[suites.length - 1])}`;
525
+ }
526
+ return resultado;
527
+ }
528
+ visitWhile_stmt(ctx) {
529
+ const cond = this.visit(ctx.test());
530
+ const corpo = this.visitCorpo(ctx.suite(0));
531
+ return `enquanto (${cond}) ${corpo}`;
532
+ }
533
+ visitFor_stmt(ctx) {
534
+ const variavel = this.visit(ctx.exprlist());
535
+ const iteravel = this.visit(ctx.testlist());
536
+ const corpo = this.visitCorpo(ctx.suite(0));
537
+ return `para cada ${variavel} em ${iteravel} ${corpo}`;
538
+ }
539
+ visitBreak_stmt(_ctx) {
540
+ return 'sustar';
541
+ }
542
+ visitContinue_stmt(_ctx) {
543
+ return 'continua';
544
+ }
545
+ visitReturn_stmt(ctx) {
546
+ const testlist = ctx.testlist();
547
+ if (testlist)
548
+ return `retorna ${this.visit(testlist)}`;
549
+ return 'retorna';
550
+ }
551
+ visitTfpdef(ctx) {
552
+ // Ignora anotação de tipo (: Tipo) — retorna apenas o nome
553
+ return ctx.NAME().text;
554
+ }
555
+ visitTypedargslist(ctx) {
556
+ const params = [];
557
+ for (let i = 0; i < ctx.childCount;) {
558
+ const filho = ctx.getChild(i);
559
+ const texto = filho.text;
560
+ if (texto === ',') {
561
+ i++;
562
+ continue;
563
+ }
564
+ // Para em *args ou **kwargs — suporte básico suficiente para fase 4
565
+ if (texto === '*' || texto === '**')
55
566
  break;
567
+ const nomeParam = this.visit(filho); // → visitTfpdef → NAME
568
+ if (nomeParam === 'self') {
569
+ i++;
570
+ continue;
571
+ } // Remove self
572
+ // Verifica se há valor padrão: tfpdef '=' test
573
+ if (i + 1 < ctx.childCount && ctx.getChild(i + 1).text === '=') {
574
+ const valorPadrao = this.visit(ctx.getChild(i + 2));
575
+ params.push(`${nomeParam} = ${valorPadrao}`);
576
+ i += 3;
577
+ }
578
+ else {
579
+ params.push(nomeParam);
580
+ i++;
581
+ }
56
582
  }
583
+ return params.join(', ');
584
+ }
585
+ visitParameters(ctx) {
586
+ const argslist = ctx.typedargslist();
587
+ if (!argslist)
588
+ return '';
589
+ return this.visitTypedargslist(argslist);
590
+ }
591
+ visitFuncdef(ctx) {
592
+ const nomePython = ctx.NAME().text;
593
+ const params = this.visitParameters(ctx.parameters());
594
+ const corpo = this.visitCorpo(ctx.suite());
595
+ if (nomePython === '__init__') {
596
+ return `construtor(${params}) ${corpo}`;
597
+ }
598
+ return `funcao ${nomePython}(${params}) ${corpo}`;
599
+ }
600
+ visitClassdef(ctx) {
601
+ const nome = ctx.NAME().text;
602
+ const arglist = ctx.arglist();
603
+ const heranca = arglist ? ` herda ${this.visit(arglist)}` : '';
604
+ const corpo = this.visitCorpo(ctx.suite());
605
+ return `classe ${nome}${heranca} ${corpo}`;
606
+ }
607
+ visitDecorated(ctx) {
608
+ // Ignora decoradores — traduz apenas o funcdef ou classdef subjacente
609
+ const funcdef = ctx.funcdef();
610
+ if (funcdef)
611
+ return this.visitFuncdef(funcdef);
612
+ const classdef = ctx.classdef();
613
+ if (classdef)
614
+ return this.visitClassdef(classdef);
615
+ return this.visitChildren(ctx);
57
616
  }
58
617
  traduzir(codigo) {
59
- this.inputStream = antlr4ts_1.CharStreams.fromString(codigo);
60
- this.lexer = new python3_lexer_1.Python3Lexer(this.inputStream);
61
- this.tokenStream = new antlr4ts_1.CommonTokenStream(this.lexer);
62
- this.parser = new python3_parser_1.Python3Parser(this.tokenStream);
63
- this.resultado = '';
64
- // Aqui achei três bons pontos de entrada:
65
- // single_input, file_input e eval_input. O que funcionou melhor foi o file_input.
66
- let tree = this.parser.file_input();
67
- ParseTreeWalker_1.ParseTreeWalker.DEFAULT.walk(this, tree);
68
- return this.resultado;
618
+ // O lexer Python3 do ANTLR exige NEWLINE ao final de cada instrução.
619
+ const codigoNormalizado = codigo.endsWith('\n') ? codigo : codigo + '\n';
620
+ const inputStream = antlr4ts_1.CharStreams.fromString(codigoNormalizado);
621
+ const lexer = new python3_lexer_1.Python3Lexer(inputStream);
622
+ const tokenStream = new antlr4ts_1.CommonTokenStream(lexer);
623
+ const parser = new python3_parser_1.Python3Parser(tokenStream);
624
+ const tree = parser.file_input();
625
+ return this.visit(tree);
69
626
  }
70
627
  }
71
628
  exports.TradutorReversoPython = TradutorReversoPython;