@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.
- package/analisador-semantico/analisador-semantico.d.ts +14 -0
- package/analisador-semantico/analisador-semantico.d.ts.map +1 -1
- package/analisador-semantico/analisador-semantico.js +20 -12
- package/analisador-semantico/analisador-semantico.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts +5 -0
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
- package/bin/package.json +1 -1
- package/estilizador/estilizador-delegua.d.ts.map +1 -1
- package/estilizador/estilizador-delegua.js +10 -2
- package/estilizador/estilizador-delegua.js.map +1 -1
- package/estilizador/index.d.ts +1 -0
- package/estilizador/index.d.ts.map +1 -1
- package/estilizador/index.js +1 -0
- package/estilizador/index.js.map +1 -1
- package/estilizador/quebrador-linha.d.ts +18 -0
- package/estilizador/quebrador-linha.d.ts.map +1 -0
- package/estilizador/quebrador-linha.js +184 -0
- package/estilizador/quebrador-linha.js.map +1 -0
- package/estilizador/regras/index.d.ts +3 -3
- package/estilizador/regras/index.d.ts.map +1 -1
- package/estilizador/regras/index.js +3 -3
- package/estilizador/regras/index.js.map +1 -1
- package/estilizador/regras/{convencao-nomenclatura.d.ts → regra-convencao-nomenclatura.d.ts} +3 -28
- package/estilizador/regras/regra-convencao-nomenclatura.d.ts.map +1 -0
- package/estilizador/regras/{convencao-nomenclatura.js → regra-convencao-nomenclatura.js} +1 -1
- package/estilizador/regras/regra-convencao-nomenclatura.js.map +1 -0
- package/estilizador/regras/{fortalecer-tipos.d.ts → regra-fortalecer-tipos.d.ts} +1 -1
- package/estilizador/regras/regra-fortalecer-tipos.d.ts.map +1 -0
- package/estilizador/regras/{fortalecer-tipos.js → regra-fortalecer-tipos.js} +1 -1
- package/estilizador/regras/regra-fortalecer-tipos.js.map +1 -0
- package/estilizador/regras/{paradigma-consistente.d.ts → regra-paradigma-consistente.d.ts} +1 -1
- package/estilizador/regras/regra-paradigma-consistente.d.ts.map +1 -0
- package/estilizador/regras/{paradigma-consistente.js → regra-paradigma-consistente.js} +1 -1
- package/estilizador/regras/regra-paradigma-consistente.js.map +1 -0
- package/interfaces/estilizador/estilizador-interface.d.ts +1 -6
- package/interfaces/estilizador/estilizador-interface.d.ts.map +1 -1
- package/interfaces/estilizador/index.d.ts +2 -0
- package/interfaces/estilizador/index.d.ts.map +1 -1
- package/interfaces/estilizador/index.js +2 -0
- package/interfaces/estilizador/index.js.map +1 -1
- package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.d.ts +26 -0
- package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.d.ts.map +1 -0
- package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.js +3 -0
- package/interfaces/estilizador/opcoes-convencao-nomenclatura-interface.js.map +1 -0
- package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.d.ts +8 -0
- package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.d.ts.map +1 -0
- package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.js +3 -0
- package/interfaces/estilizador/opcoes-formatacao-estilizador-interface.js.map +1 -0
- package/interpretador/dialetos/pitugues/interpretador-pitugues.js +3 -3
- package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
- package/interpretador/interpretador-base.d.ts +1 -0
- package/interpretador/interpretador-base.d.ts.map +1 -1
- package/interpretador/interpretador-base.js +2 -0
- package/interpretador/interpretador-base.js.map +1 -1
- package/interpretador/interpretador.d.ts.map +1 -1
- package/interpretador/interpretador.js +12 -0
- package/interpretador/interpretador.js.map +1 -1
- package/package.json +1 -1
- package/tradutores/index.d.ts +1 -1
- package/tradutores/index.d.ts.map +1 -1
- package/tradutores/index.js +1 -1
- package/tradutores/index.js.map +1 -1
- package/tradutores/tradutor-reverso-calango.d.ts +45 -0
- package/tradutores/tradutor-reverso-calango.d.ts.map +1 -0
- package/tradutores/tradutor-reverso-calango.js +351 -0
- package/tradutores/tradutor-reverso-calango.js.map +1 -0
- package/tradutores/tradutor-reverso-python.d.ts +58 -26
- package/tradutores/tradutor-reverso-python.d.ts.map +1 -1
- package/tradutores/tradutor-reverso-python.js +609 -52
- package/tradutores/tradutor-reverso-python.js.map +1 -1
- package/umd/delegua.js +1716 -606
- package/estilizador/regras/convencao-nomenclatura.d.ts.map +0 -1
- package/estilizador/regras/convencao-nomenclatura.js.map +0 -1
- package/estilizador/regras/fortalecer-tipos.d.ts.map +0 -1
- package/estilizador/regras/fortalecer-tipos.js.map +0 -1
- package/estilizador/regras/paradigma-consistente.d.ts.map +0 -1
- package/estilizador/regras/paradigma-consistente.js.map +0 -1
- package/tradutores/tradutor-calango.d.ts +0 -23
- package/tradutores/tradutor-calango.d.ts.map +0 -1
- package/tradutores/tradutor-calango.js +0 -54
- 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
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|