@designliquido/delegua 1.2.0 → 1.3.0

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 (45) hide show
  1. package/analisador-semantico/dialetos/analisador-semantico-pitugues.d.ts.map +1 -1
  2. package/analisador-semantico/dialetos/analisador-semantico-pitugues.js +5 -0
  3. package/analisador-semantico/dialetos/analisador-semantico-pitugues.js.map +1 -1
  4. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
  5. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js +11 -8
  6. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
  7. package/bibliotecas/biblioteca-global.d.ts +1 -1
  8. package/bibliotecas/biblioteca-global.d.ts.map +1 -1
  9. package/bibliotecas/biblioteca-global.js +3 -17
  10. package/bibliotecas/biblioteca-global.js.map +1 -1
  11. package/bibliotecas/dialetos/pitugues/biblioteca-global.d.ts.map +1 -1
  12. package/bibliotecas/dialetos/pitugues/biblioteca-global.js +8 -6
  13. package/bibliotecas/dialetos/pitugues/biblioteca-global.js.map +1 -1
  14. package/bin/package.json +1 -1
  15. package/interfaces/tradutor-interface.d.ts +1 -1
  16. package/interfaces/tradutor-interface.d.ts.map +1 -1
  17. package/interfaces/visitante-comum-interface.d.ts +2 -2
  18. package/interfaces/visitante-comum-interface.d.ts.map +1 -1
  19. package/interpretador/comum.d.ts.map +1 -1
  20. package/interpretador/comum.js +1 -0
  21. package/interpretador/comum.js.map +1 -1
  22. package/interpretador/dialetos/pitugues/comum.d.ts.map +1 -1
  23. package/interpretador/dialetos/pitugues/comum.js +13 -0
  24. package/interpretador/dialetos/pitugues/comum.js.map +1 -1
  25. package/interpretador/interpretador-base.d.ts.map +1 -1
  26. package/interpretador/interpretador-base.js +1 -12
  27. package/interpretador/interpretador-base.js.map +1 -1
  28. package/interpretador/interpretador.d.ts +2 -1
  29. package/interpretador/interpretador.d.ts.map +1 -1
  30. package/interpretador/interpretador.js +14 -0
  31. package/interpretador/interpretador.js.map +1 -1
  32. package/package.json +1 -1
  33. package/tradutores/index.d.ts +1 -0
  34. package/tradutores/index.d.ts.map +1 -1
  35. package/tradutores/index.js +1 -0
  36. package/tradutores/index.js.map +1 -1
  37. package/tradutores/tradutor-elixir.d.ts +141 -0
  38. package/tradutores/tradutor-elixir.d.ts.map +1 -0
  39. package/tradutores/tradutor-elixir.js +926 -0
  40. package/tradutores/tradutor-elixir.js.map +1 -0
  41. package/tradutores/tradutor-mermaidjs.d.ts +69 -78
  42. package/tradutores/tradutor-mermaidjs.d.ts.map +1 -1
  43. package/tradutores/tradutor-mermaidjs.js +440 -404
  44. package/tradutores/tradutor-mermaidjs.js.map +1 -1
  45. package/umd/delegua.js +1642 -685
@@ -0,0 +1,926 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TradutorElixir = void 0;
7
+ const delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua"));
8
+ /**
9
+ * Tradutor que converte código Delégua para Elixir.
10
+ *
11
+ * Elixir é uma linguagem funcional, então algumas conversões são necessárias:
12
+ * - Classes → Módulos com structs
13
+ * - Métodos → Funções que recebem structs como primeiro parâmetro
14
+ * - Loops imperativos → Funções recursivas ou Enum.each
15
+ * - Variables → Bindings imutáveis
16
+ */
17
+ class TradutorElixir {
18
+ constructor() {
19
+ this.indentacaoAtual = 0;
20
+ this.moduloAtual = null;
21
+ this.modulosConhecidos = new Set();
22
+ this.funcoesConhecidas = new Set();
23
+ this.atributosModulo = new Map();
24
+ this.dentroDeMetodo = false;
25
+ this.nomeParametroStruct = null;
26
+ this.contadorVariavelTemporaria = 0;
27
+ }
28
+ /**
29
+ * Adiciona a indentação atual (Elixir usa 2 espaços por convenção)
30
+ */
31
+ adicionarIndentacao() {
32
+ return ' '.repeat(this.indentacaoAtual);
33
+ }
34
+ /**
35
+ * Aumenta o nível de indentação em 2 espaços
36
+ */
37
+ aumentarIndentacao() {
38
+ this.indentacaoAtual += 2;
39
+ }
40
+ /**
41
+ * Diminui o nível de indentação em 2 espaços
42
+ */
43
+ diminuirIndentacao() {
44
+ this.indentacaoAtual -= 2;
45
+ if (this.indentacaoAtual < 0) {
46
+ this.indentacaoAtual = 0;
47
+ }
48
+ }
49
+ /**
50
+ * Converte identificadores de camelCase para snake_case (convenção Elixir)
51
+ */
52
+ converterIdentificador(nome) {
53
+ return nome
54
+ .replace(/([A-Z])/g, '_$1')
55
+ .toLowerCase()
56
+ .replace(/^_/, '');
57
+ }
58
+ /**
59
+ * Converte nomes de classes/módulos, preservando PascalCase
60
+ */
61
+ converterNomeModulo(nome) {
62
+ return nome.charAt(0).toUpperCase() + nome.slice(1);
63
+ }
64
+ /**
65
+ * Gera nome único para variável temporária
66
+ */
67
+ gerarVariavelTemporaria() {
68
+ return `_temp_${this.contadorVariavelTemporaria++}`;
69
+ }
70
+ /**
71
+ * Mapeia operadores Delégua para Elixir
72
+ */
73
+ traduzirOperador(simbolo) {
74
+ const tipoSimbolo = simbolo.tipo;
75
+ switch (tipoSimbolo) {
76
+ // Aritméticos
77
+ case delegua_1.default.ADICAO:
78
+ return '+';
79
+ case delegua_1.default.SUBTRACAO:
80
+ return '-';
81
+ case delegua_1.default.MULTIPLICACAO:
82
+ return '*';
83
+ case delegua_1.default.DIVISAO:
84
+ return '/';
85
+ case delegua_1.default.MODULO:
86
+ return 'rem';
87
+ case delegua_1.default.EXPONENCIACAO:
88
+ return '**';
89
+ // Comparação
90
+ case delegua_1.default.MAIOR:
91
+ return '>';
92
+ case delegua_1.default.MAIOR_IGUAL:
93
+ return '>=';
94
+ case delegua_1.default.MENOR:
95
+ return '<';
96
+ case delegua_1.default.MENOR_IGUAL:
97
+ return '<=';
98
+ case delegua_1.default.IGUAL_IGUAL:
99
+ return '==';
100
+ case delegua_1.default.DIFERENTE:
101
+ return '!=';
102
+ // Lógicos
103
+ case delegua_1.default.E:
104
+ return 'and';
105
+ case delegua_1.default.OU:
106
+ return 'or';
107
+ case delegua_1.default.NEGACAO:
108
+ return 'not';
109
+ // Bitwise
110
+ case delegua_1.default.BIT_AND:
111
+ return '&&&';
112
+ case delegua_1.default.BIT_OR:
113
+ return '|||';
114
+ case delegua_1.default.BIT_XOR:
115
+ return '^^^';
116
+ case delegua_1.default.BIT_NOT:
117
+ return '~~~';
118
+ default:
119
+ return simbolo.lexema;
120
+ }
121
+ }
122
+ /**
123
+ * Ponto de entrada para tradução
124
+ */
125
+ async traduzir(declaracoes) {
126
+ let resultado = '';
127
+ for (const declaracao of declaracoes) {
128
+ const traducao = await declaracao.aceitar(this);
129
+ if (traducao) {
130
+ resultado += traducao + '\n';
131
+ }
132
+ }
133
+ return resultado;
134
+ }
135
+ // ========== DECLARAÇÕES ==========
136
+ visitarDeclaracaoCabecalhoPrograma(declaracao) {
137
+ // Elixir não tem conceito de cabeçalho de programa
138
+ return Promise.resolve('');
139
+ }
140
+ async visitarDeclaracaoClasse(declaracao) {
141
+ const nomeModulo = this.converterNomeModulo(declaracao.simbolo.lexema);
142
+ this.modulosConhecidos.add(nomeModulo);
143
+ let resultado = this.adicionarIndentacao();
144
+ resultado += `defmodule ${nomeModulo} do\n`;
145
+ this.aumentarIndentacao();
146
+ const moduloAnterior = this.moduloAtual;
147
+ this.moduloAtual = nomeModulo;
148
+ // Extrair campos do struct do construtor
149
+ const camposStruct = await this.extrairCamposStruct(declaracao);
150
+ if (camposStruct.length > 0) {
151
+ resultado += this.adicionarIndentacao();
152
+ resultado += `defstruct [${camposStruct.join(', ')}]\n\n`;
153
+ }
154
+ // Traduzir métodos
155
+ for (const metodo of declaracao.metodos) {
156
+ const traducaoMetodo = await this.traduzirMetodoClasse(metodo, nomeModulo);
157
+ resultado += traducaoMetodo + '\n\n';
158
+ }
159
+ this.diminuirIndentacao();
160
+ resultado += this.adicionarIndentacao() + 'end';
161
+ this.moduloAtual = moduloAnterior;
162
+ return Promise.resolve(resultado);
163
+ }
164
+ /**
165
+ * Extrai nomes de campos do struct a partir do construtor da classe
166
+ */
167
+ async extrairCamposStruct(declaracao) {
168
+ const campos = new Set();
169
+ // Procurar pelo construtor
170
+ const construtor = declaracao.metodos.find(m => m.simbolo.lexema === 'construtor' || m.simbolo.lexema === 'inicializar');
171
+ if (!construtor) {
172
+ return [];
173
+ }
174
+ // Analisar corpo do construtor para encontrar atribuições a "isto.campo"
175
+ for (const declaracaoCorpo of construtor.funcao.corpo) {
176
+ this.extrairCamposDeDeclaracao(declaracaoCorpo, campos);
177
+ }
178
+ // Converter para atoms do Elixir
179
+ return Array.from(campos).map(c => `:${this.converterIdentificador(c)}`);
180
+ }
181
+ /**
182
+ * Extrai campos de uma declaração recursivamente
183
+ */
184
+ extrairCamposDeDeclaracao(declaracao, campos) {
185
+ // Se é uma expressão de atribuição com isto.campo
186
+ if (declaracao.constructor.name === 'Expressao' && declaracao.expressao) {
187
+ const expressao = declaracao.expressao;
188
+ // DefinirValor: usado para isto.campo = valor
189
+ if (expressao.constructor.name === 'DefinirValor') {
190
+ if (expressao.objeto && expressao.objeto.constructor.name === 'Isto') {
191
+ campos.add(expressao.nome.lexema);
192
+ }
193
+ }
194
+ // Atribuir: pode ser usado para isto.campo = valor
195
+ if (expressao.constructor.name === 'Atribuir') {
196
+ // Verificar se o alvo é um acesso a propriedade de isto
197
+ if (expressao.alvo && expressao.alvo.constructor.name === 'AcessoPropriedade') {
198
+ const acesso = expressao.alvo;
199
+ if (acesso.objeto && acesso.objeto.constructor.name === 'Isto') {
200
+ campos.add(acesso.nomePropriedade);
201
+ }
202
+ }
203
+ }
204
+ }
205
+ // Se é um bloco, processar declarações internas
206
+ if (declaracao.constructor.name === 'Bloco') {
207
+ for (const decl of declaracao.declaracoes) {
208
+ this.extrairCamposDeDeclaracao(decl, campos);
209
+ }
210
+ }
211
+ }
212
+ /**
213
+ * Traduz um método de classe para função de módulo
214
+ */
215
+ async traduzirMetodoClasse(metodo, nomeModulo) {
216
+ const nomeMetodo = this.converterIdentificador(metodo.simbolo.lexema);
217
+ let resultado = this.adicionarIndentacao();
218
+ // Construtor vira função new/N
219
+ if (metodo.simbolo.lexema === 'construtor' || metodo.simbolo.lexema === 'inicializar') {
220
+ resultado += `def new(`;
221
+ const parametros = metodo.funcao.parametros.map(p => this.converterIdentificador(p.nome.lexema));
222
+ resultado += parametros.join(', ');
223
+ resultado += ') do\n';
224
+ this.aumentarIndentacao();
225
+ resultado += this.adicionarIndentacao();
226
+ resultado += `%${nomeModulo}{`;
227
+ // Extrair inicializações do construtor
228
+ const inicializacoes = await this.extrairInicializacoesStruct(metodo.funcao.corpo, nomeModulo);
229
+ resultado += inicializacoes;
230
+ resultado += '}\n';
231
+ this.diminuirIndentacao();
232
+ resultado += this.adicionarIndentacao() + 'end';
233
+ }
234
+ else {
235
+ // Métodos normais recebem o struct como primeiro parâmetro
236
+ resultado += `def ${nomeMetodo}(`;
237
+ const nomeParametroStruct = this.converterIdentificador(nomeModulo.toLowerCase());
238
+ this.nomeParametroStruct = nomeParametroStruct;
239
+ const parametros = [nomeParametroStruct].concat(metodo.funcao.parametros.map(p => this.converterIdentificador(p.nome.lexema)));
240
+ resultado += parametros.join(', ');
241
+ resultado += ') do\n';
242
+ this.aumentarIndentacao();
243
+ this.dentroDeMetodo = true;
244
+ for (const declaracaoCorpo of metodo.funcao.corpo) {
245
+ const traducao = await declaracaoCorpo.aceitar(this);
246
+ if (traducao) {
247
+ resultado += traducao + '\n';
248
+ }
249
+ }
250
+ this.dentroDeMetodo = false;
251
+ this.nomeParametroStruct = null;
252
+ this.diminuirIndentacao();
253
+ resultado += this.adicionarIndentacao() + 'end';
254
+ }
255
+ return resultado;
256
+ }
257
+ /**
258
+ * Extrai inicializações de struct do corpo do construtor
259
+ */
260
+ async extrairInicializacoesStruct(corpo, nomeModulo) {
261
+ const inicializacoes = [];
262
+ for (const declaracao of corpo) {
263
+ if (declaracao.constructor.name === 'Expressao' && declaracao.expressao) {
264
+ const expressao = declaracao.expressao;
265
+ // DefinirValor: isto.campo = valor
266
+ if (expressao.constructor.name === 'DefinirValor') {
267
+ if (expressao.objeto && expressao.objeto.constructor.name === 'Isto') {
268
+ const campo = this.converterIdentificador(expressao.nome.lexema);
269
+ const valor = await expressao.valor.aceitar(this);
270
+ inicializacoes.push(`${campo}: ${valor}`);
271
+ }
272
+ }
273
+ // Atribuir: pode ser isto.campo = valor (se alvo é AcessoPropriedade)
274
+ if (expressao.constructor.name === 'Atribuir') {
275
+ if (expressao.alvo && expressao.alvo.constructor.name === 'AcessoPropriedade') {
276
+ const acesso = expressao.alvo;
277
+ if (acesso.objeto && acesso.objeto.constructor.name === 'Isto') {
278
+ const campo = this.converterIdentificador(acesso.nomePropriedade);
279
+ const valor = await expressao.valor.aceitar(this);
280
+ inicializacoes.push(`${campo}: ${valor}`);
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ return inicializacoes.length > 0 ? inicializacoes.join(', ') : '';
287
+ }
288
+ async visitarDeclaracaoComentario(declaracao) {
289
+ const conteudo = Array.isArray(declaracao.conteudo)
290
+ ? declaracao.conteudo.join('\n# ')
291
+ : declaracao.conteudo;
292
+ return Promise.resolve(`${this.adicionarIndentacao()}# ${conteudo}`);
293
+ }
294
+ async visitarDeclaracaoConst(declaracao) {
295
+ // Em Elixir, constantes em módulos são atributos de módulo (@constante)
296
+ // Fora de módulos, são apenas bindings normais (imutáveis por padrão)
297
+ let resultado = this.adicionarIndentacao();
298
+ if (this.moduloAtual) {
299
+ // Dentro de módulo, usar atributo de módulo
300
+ const nomeAtributo = this.converterIdentificador(declaracao.simbolo.lexema);
301
+ resultado += `@${nomeAtributo} `;
302
+ }
303
+ else {
304
+ // Fora de módulo, binding normal (mantem nome original em maiúsculas)
305
+ resultado += declaracao.simbolo.lexema;
306
+ resultado += ' = ';
307
+ }
308
+ if (declaracao.inicializador) {
309
+ resultado += await declaracao.inicializador.aceitar(this);
310
+ }
311
+ else {
312
+ resultado += 'nil';
313
+ }
314
+ return Promise.resolve(resultado);
315
+ }
316
+ visitarDeclaracaoConstMultiplo(declaracao) {
317
+ throw new Error('Método não implementado: visitarDeclaracaoConstMultiplo');
318
+ }
319
+ async visitarDeclaracaoDeExpressao(declaracao) {
320
+ const resultado = this.adicionarIndentacao() + (await declaracao.expressao.aceitar(this));
321
+ return Promise.resolve(resultado);
322
+ }
323
+ async visitarDeclaracaoDefinicaoFuncao(declaracao) {
324
+ const nomeFuncao = this.converterIdentificador(declaracao.simbolo.lexema);
325
+ this.funcoesConhecidas.add(nomeFuncao);
326
+ let resultado = this.adicionarIndentacao();
327
+ resultado += `def ${nomeFuncao}(`;
328
+ // Parâmetros
329
+ const parametros = declaracao.funcao.parametros.map(p => this.converterIdentificador(p.nome.lexema));
330
+ resultado += parametros.join(', ');
331
+ resultado += ') do\n';
332
+ // Corpo
333
+ this.aumentarIndentacao();
334
+ for (const declaracaoCorpo of declaracao.funcao.corpo) {
335
+ const traducao = await declaracaoCorpo.aceitar(this);
336
+ if (traducao) {
337
+ resultado += traducao + '\n';
338
+ }
339
+ }
340
+ this.diminuirIndentacao();
341
+ resultado += this.adicionarIndentacao() + 'end';
342
+ return Promise.resolve(resultado);
343
+ }
344
+ async visitarDeclaracaoEnquanto(declaracao) {
345
+ // Enquanto em Elixir vira função recursiva
346
+ // Padrão: (fn -> loop = fn when cond -> corpo; loop.() end; loop = fn -> :ok end; loop.() end).()
347
+ let resultado = this.adicionarIndentacao();
348
+ resultado += '(fn ->\n';
349
+ this.aumentarIndentacao();
350
+ // Função recursiva com guard
351
+ resultado += this.adicionarIndentacao();
352
+ resultado += 'loop = fn when ';
353
+ resultado += await declaracao.condicao.aceitar(this);
354
+ resultado += ' ->\n';
355
+ this.aumentarIndentacao();
356
+ const traducaoCorpo = await declaracao.corpo.aceitar(this);
357
+ resultado += traducaoCorpo;
358
+ // Chamada recursiva
359
+ resultado += this.adicionarIndentacao() + 'loop.()\n';
360
+ this.diminuirIndentacao();
361
+ resultado += this.adicionarIndentacao() + 'end\n';
362
+ // Caso base
363
+ resultado += this.adicionarIndentacao() + 'loop = fn -> :ok end\n';
364
+ resultado += this.adicionarIndentacao() + 'loop.()\n';
365
+ this.diminuirIndentacao();
366
+ resultado += this.adicionarIndentacao() + 'end).()';
367
+ return Promise.resolve(resultado);
368
+ }
369
+ async visitarDeclaracaoEscolha(declaracao) {
370
+ let resultado = this.adicionarIndentacao();
371
+ resultado += 'case ';
372
+ resultado += await declaracao.identificadorOuLiteral.aceitar(this);
373
+ resultado += ' do\n';
374
+ this.aumentarIndentacao();
375
+ // Processar cada caminho
376
+ for (const caminho of declaracao.caminhos) {
377
+ for (const condicao of caminho.condicoes) {
378
+ resultado += this.adicionarIndentacao();
379
+ resultado += await condicao.aceitar(this);
380
+ resultado += ' ->\n';
381
+ }
382
+ this.aumentarIndentacao();
383
+ for (const decl of caminho.declaracoes) {
384
+ resultado += await decl.aceitar(this);
385
+ resultado += '\n';
386
+ }
387
+ this.diminuirIndentacao();
388
+ }
389
+ // Caminho padrão
390
+ if (declaracao.caminhoPadrao && declaracao.caminhoPadrao.declaracoes.length > 0) {
391
+ resultado += this.adicionarIndentacao() + '_ ->\n';
392
+ this.aumentarIndentacao();
393
+ for (const decl of declaracao.caminhoPadrao.declaracoes) {
394
+ resultado += await decl.aceitar(this);
395
+ resultado += '\n';
396
+ }
397
+ this.diminuirIndentacao();
398
+ }
399
+ this.diminuirIndentacao();
400
+ resultado += this.adicionarIndentacao() + 'end';
401
+ return Promise.resolve(resultado);
402
+ }
403
+ async visitarDeclaracaoEscreva(declaracao) {
404
+ let resultado = this.adicionarIndentacao();
405
+ resultado += 'IO.puts(';
406
+ if (declaracao.argumentos.length === 0) {
407
+ resultado += '""';
408
+ }
409
+ else if (declaracao.argumentos.length === 1) {
410
+ resultado += await declaracao.argumentos[0].aceitar(this);
411
+ }
412
+ else {
413
+ // Múltiplos argumentos - concatenar
414
+ const argumentos = [];
415
+ for (const arg of declaracao.argumentos) {
416
+ argumentos.push(await arg.aceitar(this));
417
+ }
418
+ resultado += argumentos.join(' <> ');
419
+ }
420
+ resultado += ')';
421
+ return Promise.resolve(resultado);
422
+ }
423
+ visitarDeclaracaoEscrevaMesmaLinha(declaracao) {
424
+ throw new Error('Método não implementado: visitarDeclaracaoEscrevaMesmaLinha');
425
+ }
426
+ async visitarDeclaracaoFazer(declaracao) {
427
+ // Fazer...enquanto é similar a enquanto, mas executa o corpo pelo menos uma vez
428
+ let resultado = this.adicionarIndentacao();
429
+ resultado += '(fn ->\n';
430
+ this.aumentarIndentacao();
431
+ resultado += this.adicionarIndentacao();
432
+ resultado += 'loop = fn ->\n';
433
+ this.aumentarIndentacao();
434
+ // Corpo
435
+ const traducaoCorpo = await declaracao.caminhoFazer.aceitar(this);
436
+ resultado += traducaoCorpo;
437
+ // Verificar condição e decidir se continua
438
+ resultado += this.adicionarIndentacao() + 'if ';
439
+ resultado += await declaracao.condicaoEnquanto.aceitar(this);
440
+ resultado += ' do\n';
441
+ this.aumentarIndentacao();
442
+ resultado += this.adicionarIndentacao() + 'loop.()\n';
443
+ this.diminuirIndentacao();
444
+ resultado += this.adicionarIndentacao() + 'else\n';
445
+ this.aumentarIndentacao();
446
+ resultado += this.adicionarIndentacao() + ':ok\n';
447
+ this.diminuirIndentacao();
448
+ resultado += this.adicionarIndentacao() + 'end\n';
449
+ this.diminuirIndentacao();
450
+ resultado += this.adicionarIndentacao() + 'end\n';
451
+ resultado += this.adicionarIndentacao() + 'loop.()\n';
452
+ this.diminuirIndentacao();
453
+ resultado += this.adicionarIndentacao() + 'end).()';
454
+ return Promise.resolve(resultado);
455
+ }
456
+ visitarDeclaracaoInicioAlgoritmo(declaracao) {
457
+ // Elixir não tem conceito de início de algoritmo
458
+ return Promise.resolve('');
459
+ }
460
+ async visitarDeclaracaoPara(declaracao) {
461
+ // Para loop vira função recursiva com inicializador, condição e incremento
462
+ let resultado = this.adicionarIndentacao();
463
+ resultado += '(fn ->\n';
464
+ this.aumentarIndentacao();
465
+ // Extrair variável e valor inicial
466
+ let nomeVar = '';
467
+ let valorInicial = '';
468
+ if (declaracao.inicializador) {
469
+ const init = Array.isArray(declaracao.inicializador)
470
+ ? declaracao.inicializador[0]
471
+ : declaracao.inicializador;
472
+ if (init.constructor.name === 'Var') {
473
+ nomeVar = this.converterIdentificador(init.simbolo.lexema);
474
+ if (init.inicializador) {
475
+ valorInicial = await init.inicializador.aceitar(this);
476
+ }
477
+ else {
478
+ valorInicial = '0';
479
+ }
480
+ }
481
+ }
482
+ // Função recursiva com parâmetro e guard
483
+ resultado += this.adicionarIndentacao();
484
+ resultado += `loop = fn ${nomeVar} when `;
485
+ resultado += await declaracao.condicao.aceitar(this);
486
+ resultado += ' ->\n';
487
+ this.aumentarIndentacao();
488
+ const traducaoCorpo = await declaracao.corpo.aceitar(this);
489
+ resultado += traducaoCorpo;
490
+ // Incremento e chamada recursiva
491
+ const incremento = await declaracao.incrementar.aceitar(this);
492
+ resultado += this.adicionarIndentacao() + `loop.(${incremento})\n`;
493
+ this.diminuirIndentacao();
494
+ resultado += this.adicionarIndentacao() + 'end\n';
495
+ // Caso base
496
+ resultado += this.adicionarIndentacao() + `loop = fn _ -> :ok end\n`;
497
+ resultado += this.adicionarIndentacao() + `loop.(${valorInicial})\n`;
498
+ this.diminuirIndentacao();
499
+ resultado += this.adicionarIndentacao() + 'end).()';
500
+ return Promise.resolve(resultado);
501
+ }
502
+ async visitarDeclaracaoParaCada(declaracao) {
503
+ let resultado = this.adicionarIndentacao();
504
+ resultado += 'Enum.each(';
505
+ resultado += await declaracao.vetorOuDicionario.aceitar(this);
506
+ resultado += ', fn ';
507
+ resultado += await declaracao.variavelIteracao.aceitar(this);
508
+ resultado += ' ->\n';
509
+ this.aumentarIndentacao();
510
+ const traducaoCorpo = await declaracao.corpo.aceitar(this);
511
+ resultado += traducaoCorpo;
512
+ this.diminuirIndentacao();
513
+ resultado += this.adicionarIndentacao() + 'end)';
514
+ return Promise.resolve(resultado);
515
+ }
516
+ async visitarDeclaracaoSe(declaracao) {
517
+ let resultado = this.adicionarIndentacao();
518
+ resultado += 'if ';
519
+ resultado += await declaracao.condicao.aceitar(this);
520
+ resultado += ' do\n';
521
+ this.aumentarIndentacao();
522
+ const traducaoEntao = await declaracao.caminhoEntao.aceitar(this);
523
+ resultado += traducaoEntao;
524
+ this.diminuirIndentacao();
525
+ if (declaracao.caminhoSenao) {
526
+ resultado += this.adicionarIndentacao() + 'else\n';
527
+ this.aumentarIndentacao();
528
+ const traducaoSenao = await declaracao.caminhoSenao.aceitar(this);
529
+ resultado += traducaoSenao;
530
+ this.diminuirIndentacao();
531
+ }
532
+ resultado += this.adicionarIndentacao() + 'end';
533
+ return Promise.resolve(resultado);
534
+ }
535
+ async visitarDeclaracaoTendoComo(declaracao) {
536
+ throw new Error('Método não implementado: visitarDeclaracaoTendoComo');
537
+ }
538
+ visitarDeclaracaoTente(declaracao) {
539
+ throw new Error('Método não implementado: visitarDeclaracaoTente');
540
+ }
541
+ visitarDeclaracaoTextoDocumentacao(declaracao) {
542
+ throw new Error('Método não implementado: visitarDeclaracaoTextoDocumentacao');
543
+ }
544
+ async visitarDeclaracaoVar(declaracao) {
545
+ let resultado = this.adicionarIndentacao();
546
+ resultado += this.converterIdentificador(declaracao.simbolo.lexema);
547
+ resultado += ' = ';
548
+ if (declaracao.inicializador) {
549
+ resultado += await declaracao.inicializador.aceitar(this);
550
+ }
551
+ else {
552
+ resultado += 'nil';
553
+ }
554
+ return Promise.resolve(resultado);
555
+ }
556
+ visitarDeclaracaoVarMultiplo(declaracao) {
557
+ throw new Error('Método não implementado: visitarDeclaracaoVarMultiplo');
558
+ }
559
+ // ========== EXPRESSÕES ==========
560
+ async visitarExpressaoDeAtribuicao(expressao) {
561
+ const alvo = await expressao.alvo.aceitar(this);
562
+ const valor = await expressao.valor.aceitar(this);
563
+ return Promise.resolve(`${alvo} = ${valor}`);
564
+ }
565
+ async visitarExpressaoAcessoIndiceVariavel(expressao) {
566
+ const objeto = await expressao.entidadeChamada.aceitar(this);
567
+ const indice = await expressao.indice.aceitar(this);
568
+ // Em Elixir, acesso por índice usa Enum.at/2
569
+ return Promise.resolve(`Enum.at(${objeto}, ${indice})`);
570
+ }
571
+ visitarExpressaoAcessoIntervaloVariavel(expressao) {
572
+ throw new Error('Método não implementado: visitarExpressaoAcessoIntervaloVariavel');
573
+ }
574
+ visitarExpressaoAcessoElementoMatriz(expressao) {
575
+ throw new Error('Método não implementado: visitarExpressaoAcessoElementoMatriz');
576
+ }
577
+ async visitarExpressaoAcessoMetodo(expressao) {
578
+ const objeto = await expressao.objeto.aceitar(this);
579
+ const metodo = this.converterIdentificador(expressao.nomeMetodo);
580
+ // AcessoMetodo é apenas a referência ao método, não a chamada
581
+ // A chamada é feita por visitarExpressaoDeChamada
582
+ return Promise.resolve(`${objeto}.${metodo}`);
583
+ }
584
+ /**
585
+ * Mapeia métodos built-in de Delégua para Elixir
586
+ */
587
+ mapearMetodoBuiltIn(metodo, objeto, argumentos) {
588
+ switch (metodo) {
589
+ // Array/List methods
590
+ case 'adicionar':
591
+ case 'empilhar':
592
+ return argumentos.length > 0 ? `[${argumentos[0]} | ${objeto}]` : `${objeto}`;
593
+ case 'tamanho':
594
+ return `length(${objeto})`;
595
+ case 'inclui':
596
+ return argumentos.length > 0 ? `Enum.member?(${objeto}, ${argumentos[0]})` : null;
597
+ case 'inverter':
598
+ return `Enum.reverse(${objeto})`;
599
+ case 'mapear':
600
+ return argumentos.length > 0 ? `Enum.map(${objeto}, ${argumentos[0]})` : null;
601
+ case 'filtrar':
602
+ return argumentos.length > 0 ? `Enum.filter(${objeto}, ${argumentos[0]})` : null;
603
+ case 'ordenar':
604
+ return `Enum.sort(${objeto})`;
605
+ case 'juntar':
606
+ return argumentos.length > 0 ? `Enum.join(${objeto}, ${argumentos[0]})` : `Enum.join(${objeto})`;
607
+ case 'fatiar':
608
+ if (argumentos.length >= 2) {
609
+ return `Enum.slice(${objeto}, ${argumentos[0]}, ${argumentos[1]})`;
610
+ }
611
+ return null;
612
+ case 'remover':
613
+ return argumentos.length > 0 ? `List.delete(${objeto}, ${argumentos[0]})` : null;
614
+ case 'somar':
615
+ return `Enum.sum(${objeto})`;
616
+ // String methods
617
+ case 'maiusculo':
618
+ return `String.upcase(${objeto})`;
619
+ case 'minusculo':
620
+ return `String.downcase(${objeto})`;
621
+ case 'dividir':
622
+ return argumentos.length > 0 ? `String.split(${objeto}, ${argumentos[0]})` : null;
623
+ case 'substituir':
624
+ if (argumentos.length >= 2) {
625
+ return `String.replace(${objeto}, ${argumentos[0]}, ${argumentos[1]})`;
626
+ }
627
+ return null;
628
+ case 'aparar':
629
+ return `String.trim(${objeto})`;
630
+ default:
631
+ return null;
632
+ }
633
+ }
634
+ /**
635
+ * Tenta extrair o nome do módulo de uma expressão de objeto
636
+ */
637
+ obterNomeModulo(objetoStr) {
638
+ // Se o objeto é uma variável simples, assumir que o módulo tem o mesmo nome em PascalCase
639
+ // Isso é uma heurística; em casos reais, precisaríamos de análise semântica
640
+ const match = objetoStr.match(/^([a-z_][a-z0-9_]*)$/);
641
+ if (match) {
642
+ return this.converterNomeModulo(match[1]);
643
+ }
644
+ return objetoStr;
645
+ }
646
+ async visitarExpressaoAcessoMetodoOuPropriedade(expressao) {
647
+ const objeto = await expressao.objeto.aceitar(this);
648
+ const simbolo = this.converterIdentificador(expressao.simbolo.lexema);
649
+ // AcessoMetodoOuPropriedade é apenas a referência, não a chamada
650
+ // A chamada com argumentos é feita por visitarExpressaoDeChamada
651
+ return Promise.resolve(`${objeto}.${simbolo}`);
652
+ }
653
+ async visitarExpressaoAcessoPropriedade(expressao) {
654
+ const objeto = await expressao.objeto.aceitar(this);
655
+ const propriedade = this.converterIdentificador(expressao.nomePropriedade);
656
+ return Promise.resolve(`${objeto}.${propriedade}`);
657
+ }
658
+ async visitarExpressaoAgrupamento(expressao) {
659
+ const conteudo = await expressao.expressao.aceitar(this);
660
+ return Promise.resolve(`(${conteudo})`);
661
+ }
662
+ visitarExpressaoArgumentoReferenciaFuncao(expressao) {
663
+ throw new Error('Método não implementado: visitarExpressaoArgumentoReferenciaFuncao');
664
+ }
665
+ visitarExpressaoAtribuicaoPorIndice(expressao) {
666
+ throw new Error('Método não implementado: visitarExpressaoAtribuicaoPorIndice');
667
+ }
668
+ visitarExpressaoAtribuicaoPorIndicesMatriz(expressao) {
669
+ throw new Error('Método não implementado: visitarExpressaoAtribuicaoPorIndicesMatriz');
670
+ }
671
+ async visitarExpressaoBinaria(expressao) {
672
+ const esquerda = await expressao.esquerda.aceitar(this);
673
+ const direita = await expressao.direita.aceitar(this);
674
+ const operador = this.traduzirOperador(expressao.operador);
675
+ return Promise.resolve(`${esquerda} ${operador} ${direita}`);
676
+ }
677
+ async visitarExpressaoBloco(declaracao) {
678
+ let resultado = '';
679
+ for (const decl of declaracao.declaracoes) {
680
+ const traducao = await decl.aceitar(this);
681
+ if (traducao) {
682
+ resultado += traducao + '\n';
683
+ }
684
+ }
685
+ return Promise.resolve(resultado);
686
+ }
687
+ visitarExpressaoComentario(expressao) {
688
+ throw new Error('Método não implementado: visitarExpressaoComentario');
689
+ }
690
+ visitarExpressaoContinua(declaracao) {
691
+ throw new Error('Método não implementado: visitarExpressaoContinua');
692
+ }
693
+ async visitarExpressaoDeChamada(expressao) {
694
+ // Processar argumentos
695
+ const argumentos = [];
696
+ for (const arg of expressao.argumentos) {
697
+ const argTraduzido = await arg.aceitar(this);
698
+ if (argTraduzido && argTraduzido.trim() !== '') {
699
+ argumentos.push(argTraduzido);
700
+ }
701
+ }
702
+ // Verificar se é instanciação de módulo (classe)
703
+ if (expressao.entidadeChamada.constructor.name === 'Variavel') {
704
+ const nomeEntidade = expressao.entidadeChamada.simbolo.lexema;
705
+ if (this.modulosConhecidos.has(this.converterNomeModulo(nomeEntidade))) {
706
+ // Chamada de construtor de módulo
707
+ return Promise.resolve(`${this.converterNomeModulo(nomeEntidade)}.new(${argumentos.join(', ')})`);
708
+ }
709
+ }
710
+ // Verificar se é chamada de método (AcessoMetodo ou AcessoMetodoOuPropriedade)
711
+ if (expressao.entidadeChamada.constructor.name === 'AcessoMetodo') {
712
+ const acessoMetodo = expressao.entidadeChamada;
713
+ const objeto = await acessoMetodo.objeto.aceitar(this);
714
+ const metodo = this.converterIdentificador(acessoMetodo.nomeMetodo);
715
+ // Mapear métodos built-in
716
+ const metodoMapeado = this.mapearMetodoBuiltIn(metodo, objeto, argumentos);
717
+ if (metodoMapeado) {
718
+ return Promise.resolve(metodoMapeado);
719
+ }
720
+ // Método de módulo/struct - passar o struct como primeiro argumento
721
+ return Promise.resolve(`${this.obterNomeModulo(objeto)}.${metodo}(${objeto}${argumentos.length > 0 ? ', ' + argumentos.join(', ') : ''})`);
722
+ }
723
+ if (expressao.entidadeChamada.constructor.name === 'AcessoMetodoOuPropriedade') {
724
+ const acesso = expressao.entidadeChamada;
725
+ const objeto = await acesso.objeto.aceitar(this);
726
+ const simbolo = this.converterIdentificador(acesso.simbolo.lexema);
727
+ // Mapear métodos built-in
728
+ const metodoMapeado = this.mapearMetodoBuiltIn(simbolo, objeto, argumentos);
729
+ if (metodoMapeado) {
730
+ return Promise.resolve(metodoMapeado);
731
+ }
732
+ // Método de módulo/struct
733
+ return Promise.resolve(`${this.obterNomeModulo(objeto)}.${simbolo}(${objeto}${argumentos.length > 0 ? ', ' + argumentos.join(', ') : ''})`);
734
+ }
735
+ // Chamada normal de função
736
+ const entidadeChamada = await expressao.entidadeChamada.aceitar(this);
737
+ return Promise.resolve(`${entidadeChamada}(${argumentos.join(', ')})`);
738
+ }
739
+ visitarExpressaoDefinirValor(expressao) {
740
+ throw new Error('Método não implementado: visitarExpressaoDefinirValor');
741
+ }
742
+ async visitarExpressaoFuncaoConstruto(expressao) {
743
+ let resultado = 'fn ';
744
+ // Parâmetros
745
+ const parametros = expressao.parametros.map(p => this.converterIdentificador(p.nome.lexema));
746
+ resultado += parametros.join(', ');
747
+ resultado += ' ->';
748
+ // Corpo - se for uma única expressão, inline; se for bloco, multi-linha
749
+ if (expressao.corpo.length === 1) {
750
+ resultado += ' ';
751
+ const traducao = await expressao.corpo[0].aceitar(this);
752
+ resultado += traducao;
753
+ }
754
+ else {
755
+ resultado += '\n';
756
+ this.aumentarIndentacao();
757
+ for (const decl of expressao.corpo) {
758
+ const traducao = await decl.aceitar(this);
759
+ if (traducao) {
760
+ resultado += traducao + '\n';
761
+ }
762
+ }
763
+ this.diminuirIndentacao();
764
+ resultado += this.adicionarIndentacao();
765
+ }
766
+ resultado += ' end';
767
+ return Promise.resolve(resultado);
768
+ }
769
+ async visitarExpressaoDeVariavel(expressao) {
770
+ return Promise.resolve(this.converterIdentificador(expressao.simbolo.lexema));
771
+ }
772
+ async visitarExpressaoDicionario(expressao) {
773
+ if (expressao.chaves.length === 0) {
774
+ return Promise.resolve('%{}');
775
+ }
776
+ const pares = [];
777
+ for (let i = 0; i < expressao.chaves.length; i++) {
778
+ const chave = await expressao.chaves[i].aceitar(this);
779
+ const valor = await expressao.valores[i].aceitar(this);
780
+ // Ignorar pares vazios (separadores)
781
+ if (chave && chave.trim() !== '' && valor && valor.trim() !== '') {
782
+ // Em Elixir, usa-se atoms (:chave) quando possível ou string => valor
783
+ // Por simplicidade, vamos usar sempre a sintaxe de string
784
+ pares.push(`${chave} => ${valor}`);
785
+ }
786
+ }
787
+ return Promise.resolve(`%{${pares.join(', ')}}`);
788
+ }
789
+ visitarExpressaoExpressaoRegular(expressao) {
790
+ throw new Error('Método não implementado: visitarExpressaoExpressaoRegular');
791
+ }
792
+ visitarExpressaoFalhar(expressao) {
793
+ throw new Error('Método não implementado: visitarExpressaoFalhar');
794
+ }
795
+ visitarExpressaoFimPara(declaracao) {
796
+ throw new Error('Método não implementado: visitarExpressaoFimPara');
797
+ }
798
+ visitarExpressaoFormatacaoEscrita(declaracao) {
799
+ throw new Error('Método não implementado: visitarExpressaoFormatacaoEscrita');
800
+ }
801
+ async visitarExpressaoIsto(expressao) {
802
+ // "isto" em Elixir é substituído pelo nome do parâmetro do struct
803
+ if (this.nomeParametroStruct) {
804
+ return Promise.resolve(this.nomeParametroStruct);
805
+ }
806
+ // Se não estamos em contexto de método, usar nome genérico
807
+ return Promise.resolve('self');
808
+ }
809
+ async visitarExpressaoLeia(expressao) {
810
+ let resultado = 'IO.gets(';
811
+ if (expressao.argumentos && expressao.argumentos.length > 0) {
812
+ resultado += await expressao.argumentos[0].aceitar(this);
813
+ }
814
+ else {
815
+ resultado += '""';
816
+ }
817
+ resultado += ') |> String.trim()';
818
+ return Promise.resolve(resultado);
819
+ }
820
+ async visitarExpressaoLiteral(expressao) {
821
+ const valor = expressao.valor;
822
+ // Null/nulo
823
+ if (valor === null || valor === undefined) {
824
+ return Promise.resolve('nil');
825
+ }
826
+ // Boolean
827
+ if (typeof valor === 'boolean') {
828
+ return Promise.resolve(valor ? 'true' : 'false');
829
+ }
830
+ // Number
831
+ if (typeof valor === 'number') {
832
+ return Promise.resolve(String(valor));
833
+ }
834
+ // String
835
+ if (typeof valor === 'string') {
836
+ // Elixir suporta interpolação com #{}
837
+ return Promise.resolve(`"${valor}"`);
838
+ }
839
+ return Promise.resolve(String(valor));
840
+ }
841
+ async visitarExpressaoLogica(expressao) {
842
+ const esquerda = await expressao.esquerda.aceitar(this);
843
+ const direita = await expressao.direita.aceitar(this);
844
+ const operador = this.traduzirOperador(expressao.operador);
845
+ return Promise.resolve(`${esquerda} ${operador} ${direita}`);
846
+ }
847
+ visitarExpressaoReferenciaFuncao(expressao) {
848
+ throw new Error('Método não implementado: visitarExpressaoReferenciaFuncao');
849
+ }
850
+ async visitarExpressaoRetornar(expressao) {
851
+ // Em Elixir, o retorno é implícito (última expressão)
852
+ // Mas podemos usar explicitamente para clareza ou retorno antecipado
853
+ let resultado = this.adicionarIndentacao();
854
+ if (expressao.valor) {
855
+ // Apenas retornar o valor, pois em Elixir a última expressão é o retorno
856
+ resultado += await expressao.valor.aceitar(this);
857
+ }
858
+ else {
859
+ resultado += 'nil';
860
+ }
861
+ return Promise.resolve(resultado);
862
+ }
863
+ visitarExpressaoSeparador(expressao) {
864
+ return Promise.resolve('');
865
+ }
866
+ visitarExpressaoSuper(expressao) {
867
+ throw new Error('Método não implementado: visitarExpressaoSuper');
868
+ }
869
+ visitarExpressaoSustar(declaracao) {
870
+ throw new Error('Método não implementado: visitarExpressaoSustar');
871
+ }
872
+ async visitarExpressaoTupla(expressao) {
873
+ // Tupla pode ter apenas um valor (expressao.valor) ou ser TuplaN com elementos
874
+ // Por enquanto, apenas retornar o valor se houver
875
+ if (expressao.valor !== undefined) {
876
+ return Promise.resolve(`{${expressao.valor}}`);
877
+ }
878
+ // Se não houver valor, tupla vazia
879
+ return Promise.resolve('{}');
880
+ }
881
+ async visitarExpressaoTuplaN(expressao) {
882
+ const valores = [];
883
+ for (const elemento of expressao.elementos) {
884
+ const valorTraduzido = await elemento.aceitar(this);
885
+ valores.push(valorTraduzido);
886
+ }
887
+ return Promise.resolve(`{${valores.join(', ')}}`);
888
+ }
889
+ visitarExpressaoTipoDe(expressao) {
890
+ throw new Error('Método não implementado: visitarExpressaoTipoDe');
891
+ }
892
+ async visitarExpressaoUnaria(expressao) {
893
+ const operando = await expressao.operando.aceitar(this);
894
+ const operador = this.traduzirOperador(expressao.operador);
895
+ // Elixir não tem ++ ou --, então operações de incremento/decremento precisam ser convertidas
896
+ if (expressao.operador.tipo === delegua_1.default.INCREMENTAR) {
897
+ return Promise.resolve(`${operando} + 1`);
898
+ }
899
+ if (expressao.operador.tipo === delegua_1.default.DECREMENTAR) {
900
+ return Promise.resolve(`${operando} - 1`);
901
+ }
902
+ // Operações unárias normais (-, !, ~)
903
+ if (expressao.incidenciaOperador === 'ANTES') {
904
+ return Promise.resolve(`${operador} ${operando}`);
905
+ }
906
+ else {
907
+ return Promise.resolve(`${operando} ${operador}`);
908
+ }
909
+ }
910
+ async visitarExpressaoVetor(expressao) {
911
+ if (expressao.valores.length === 0) {
912
+ return Promise.resolve('[]');
913
+ }
914
+ const valores = [];
915
+ for (const valor of expressao.valores) {
916
+ const valorTraduzido = await valor.aceitar(this);
917
+ // Ignorar separadores vazios
918
+ if (valorTraduzido && valorTraduzido.trim() !== '') {
919
+ valores.push(valorTraduzido);
920
+ }
921
+ }
922
+ return Promise.resolve(`[${valores.join(', ')}]`);
923
+ }
924
+ }
925
+ exports.TradutorElixir = TradutorElixir;
926
+ //# sourceMappingURL=tradutor-elixir.js.map