@designliquido/delegua 1.27.2 → 1.28.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 (114) hide show
  1. package/avaliador-sintatico/avaliador-sintatico.d.ts +1 -0
  2. package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
  3. package/avaliador-sintatico/avaliador-sintatico.js +15 -6
  4. package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
  5. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
  6. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js +0 -1
  7. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
  8. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts.map +1 -1
  9. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js +0 -1
  10. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js.map +1 -1
  11. package/bibliotecas/biblioteca-global.js +1 -1
  12. package/bibliotecas/biblioteca-global.js.map +1 -1
  13. package/bibliotecas/primitivas-vetor.d.ts.map +1 -1
  14. package/bibliotecas/primitivas-vetor.js +2 -1
  15. package/bibliotecas/primitivas-vetor.js.map +1 -1
  16. package/bin/package.json +3 -2
  17. package/construtos/agrupamento.d.ts +1 -1
  18. package/construtos/agrupamento.d.ts.map +1 -1
  19. package/construtos/agrupamento.js +2 -2
  20. package/construtos/agrupamento.js.map +1 -1
  21. package/construtos/atribuir.d.ts +1 -1
  22. package/construtos/atribuir.d.ts.map +1 -1
  23. package/construtos/atribuir.js +2 -2
  24. package/construtos/atribuir.js.map +1 -1
  25. package/construtos/binario.d.ts +1 -1
  26. package/construtos/binario.d.ts.map +1 -1
  27. package/construtos/binario.js +2 -2
  28. package/construtos/binario.js.map +1 -1
  29. package/construtos/literal.d.ts +1 -1
  30. package/construtos/literal.d.ts.map +1 -1
  31. package/construtos/literal.js +2 -2
  32. package/construtos/literal.js.map +1 -1
  33. package/construtos/logico.d.ts +1 -1
  34. package/construtos/logico.d.ts.map +1 -1
  35. package/construtos/logico.js +2 -2
  36. package/construtos/logico.js.map +1 -1
  37. package/construtos/para-como-construto.d.ts +2 -1
  38. package/construtos/para-como-construto.d.ts.map +1 -1
  39. package/construtos/para-como-construto.js +2 -1
  40. package/construtos/para-como-construto.js.map +1 -1
  41. package/construtos/unario.d.ts +1 -1
  42. package/construtos/unario.d.ts.map +1 -1
  43. package/construtos/unario.js +2 -2
  44. package/construtos/unario.js.map +1 -1
  45. package/construtos/variavel.d.ts +2 -2
  46. package/construtos/variavel.d.ts.map +1 -1
  47. package/construtos/variavel.js +2 -2
  48. package/construtos/variavel.js.map +1 -1
  49. package/declaracoes/para.d.ts +2 -1
  50. package/declaracoes/para.d.ts.map +1 -1
  51. package/declaracoes/para.js +2 -1
  52. package/declaracoes/para.js.map +1 -1
  53. package/formatadores/formatador-delegua.d.ts.map +1 -1
  54. package/formatadores/formatador-delegua.js +11 -7
  55. package/formatadores/formatador-delegua.js.map +1 -1
  56. package/formatadores/formatador-pitugues.d.ts.map +1 -1
  57. package/formatadores/formatador-pitugues.js +2 -1
  58. package/formatadores/formatador-pitugues.js.map +1 -1
  59. package/interfaces/construtos/construto-interface.d.ts +6 -1
  60. package/interfaces/construtos/construto-interface.d.ts.map +1 -1
  61. package/interfaces/delegua/para-interface.d.ts +7 -0
  62. package/interfaces/delegua/para-interface.d.ts.map +1 -1
  63. package/interfaces/interpretador-interface.d.ts +13 -1
  64. package/interfaces/interpretador-interface.d.ts.map +1 -1
  65. package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts +1 -0
  66. package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts.map +1 -1
  67. package/interpretador/depuracao/interpretador-base-com-depuracao.js +1 -0
  68. package/interpretador/depuracao/interpretador-base-com-depuracao.js.map +1 -1
  69. package/interpretador/depuracao/interpretador-com-depuracao.d.ts +1 -0
  70. package/interpretador/depuracao/interpretador-com-depuracao.d.ts.map +1 -1
  71. package/interpretador/depuracao/interpretador-com-depuracao.js +1 -0
  72. package/interpretador/depuracao/interpretador-com-depuracao.js.map +1 -1
  73. package/interpretador/dialetos/calango/interpretador-calango.d.ts +1 -1
  74. package/interpretador/dialetos/calango/interpretador-calango.d.ts.map +1 -1
  75. package/interpretador/dialetos/calango/interpretador-calango.js +14 -10
  76. package/interpretador/dialetos/calango/interpretador-calango.js.map +1 -1
  77. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.d.ts.map +1 -1
  78. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js +3 -3
  79. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js.map +1 -1
  80. package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts +1 -1
  81. package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts.map +1 -1
  82. package/interpretador/dialetos/pitugues/interpretador-pitugues.js +8 -6
  83. package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
  84. package/interpretador/dialetos/prisma/interpretador-prisma.d.ts +2 -2
  85. package/interpretador/dialetos/prisma/interpretador-prisma.d.ts.map +1 -1
  86. package/interpretador/dialetos/prisma/interpretador-prisma.js +26 -19
  87. package/interpretador/dialetos/prisma/interpretador-prisma.js.map +1 -1
  88. package/interpretador/encadear.d.ts +36 -0
  89. package/interpretador/encadear.d.ts.map +1 -0
  90. package/interpretador/encadear.js +43 -0
  91. package/interpretador/encadear.js.map +1 -0
  92. package/interpretador/estruturas/delegua-funcao.d.ts +25 -0
  93. package/interpretador/estruturas/delegua-funcao.d.ts.map +1 -1
  94. package/interpretador/estruturas/delegua-funcao.js +90 -23
  95. package/interpretador/estruturas/delegua-funcao.js.map +1 -1
  96. package/interpretador/interpretador-base.d.ts +34 -22
  97. package/interpretador/interpretador-base.d.ts.map +1 -1
  98. package/interpretador/interpretador-base.js +630 -557
  99. package/interpretador/interpretador-base.js.map +1 -1
  100. package/interpretador/interpretador.d.ts +8 -11
  101. package/interpretador/interpretador.d.ts.map +1 -1
  102. package/interpretador/interpretador.js +170 -116
  103. package/interpretador/interpretador.js.map +1 -1
  104. package/lexador/dialetos/lexador-pitugues.d.ts.map +1 -1
  105. package/lexador/dialetos/lexador-pitugues.js +0 -1
  106. package/lexador/dialetos/lexador-pitugues.js.map +1 -1
  107. package/lexador/dialetos/lexador-tenda.d.ts.map +1 -1
  108. package/lexador/dialetos/lexador-tenda.js +0 -1
  109. package/lexador/dialetos/lexador-tenda.js.map +1 -1
  110. package/lexador/lexador.d.ts.map +1 -1
  111. package/lexador/lexador.js +0 -1
  112. package/lexador/lexador.js.map +1 -1
  113. package/package.json +3 -2
  114. package/umd/delegua.js +1377 -1105
@@ -15,6 +15,7 @@ const lexador_1 = require("../lexador");
15
15
  const avaliador_sintatico_1 = require("../avaliador-sintatico");
16
16
  const espaco_memoria_1 = require("./espaco-memoria");
17
17
  const excecoes_1 = require("../excecoes");
18
+ const encadear_1 = require("./encadear");
18
19
  const primitivas_dicionario_1 = __importDefault(require("../bibliotecas/primitivas-dicionario"));
19
20
  const delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua"));
20
21
  const primitivos_1 = __importDefault(require("../tipos-de-dados/primitivos"));
@@ -92,13 +93,14 @@ class InterpretadorBase {
92
93
  this.pilhaEscoposExecucao.definirVariavel('Excecao', estruturas_1.EXCECAO_BASE);
93
94
  }
94
95
  /**
95
- * Cede o controle ao loop de eventos do JavaScript.
96
- * Usado em laços de repetição para evitar bloqueio do loop de eventos
97
- * em iterações longas ou infinitas.
96
+ * Cede o controle ao loop de eventos do JavaScript, mas só de fato a cada
97
+ * `iteracoesParaCederControle` chamadas nos outros casos retorna `undefined` diretamente,
98
+ * sem alocar Promise nem agendar microtarefa, já que isto é chamado em toda iteração de todo
99
+ * laço (`enquanto`, `para`) e o custo de um `await` "inútil" 999 em 1000 vezes se acumula.
98
100
  */
99
- async cederControle(iteracoes) {
101
+ cederControle(iteracoes) {
100
102
  if (iteracoes % this.iteracoesParaCederControle === 0) {
101
- await new Promise((resolve) => {
103
+ return new Promise((resolve) => {
102
104
  const _setImmediate = globalThis.setImmediate;
103
105
  if (_setImmediate) {
104
106
  _setImmediate(resolve);
@@ -108,6 +110,7 @@ class InterpretadorBase {
108
110
  }
109
111
  });
110
112
  }
113
+ return undefined;
111
114
  }
112
115
  visitarDeclaracaoTextoDocumentacao(declaracao) {
113
116
  throw new Error('Método não implementado.');
@@ -331,7 +334,7 @@ class InterpretadorBase {
331
334
  * @param expressao A expressão, que pode ser um construto ou declaração.
332
335
  * @returns O retorno da execução do método de visita chamado.
333
336
  */
334
- async avaliar(expressao) {
337
+ avaliar(expressao) {
335
338
  // Descomente o código abaixo quando precisar detectar expressões undefined ou nulas.
336
339
  // Por algum motivo o depurador do VSCode não funciona direito aqui
337
340
  // com breakpoint condicional.
@@ -341,7 +344,7 @@ class InterpretadorBase {
341
344
  if (expressao.hashArquivo >= 0 && expressao.linha >= 0) {
342
345
  this.registrarExpressao?.(expressao.hashArquivo, expressao.linha);
343
346
  }
344
- return await expressao.aceitar(this);
347
+ return expressao.aceitar(this);
345
348
  }
346
349
  /**
347
350
  * Execução da leitura de valores da entrada configurada no
@@ -427,11 +430,10 @@ class InterpretadorBase {
427
430
  return { expressaoInterpolacao, valor };
428
431
  }));
429
432
  }
430
- async visitarExpressaoLiteral(expressao) {
433
+ visitarExpressaoLiteral(expressao) {
431
434
  if (this.regexInterpolacao.test(String(expressao.valor))) {
432
435
  const valorComoTexto = String(expressao.valor);
433
- const interpolacoes = await this.resolverInterpolacoes(valorComoTexto, expressao.linha);
434
- return this.retirarInterpolacao(valorComoTexto, interpolacoes);
436
+ return (0, encadear_1.encadear)(this.resolverInterpolacoes(valorComoTexto, expressao.linha), (interpolacoes) => this.retirarInterpolacao(valorComoTexto, interpolacoes));
435
437
  }
436
438
  return expressao.valor;
437
439
  }
@@ -443,12 +445,13 @@ class InterpretadorBase {
443
445
  * @returns O resultado da avaliação.
444
446
  * @see this.visitarExpressaoDeChamada
445
447
  */
446
- async visitarExpressaoAgrupamento(expressao) {
447
- const avaliacaoAgrupamento = await this.avaliar(expressao.expressao);
448
- if (avaliacaoAgrupamento !== null && avaliacaoAgrupamento.declaracao) {
449
- return avaliacaoAgrupamento.declaracao;
450
- }
451
- return avaliacaoAgrupamento;
448
+ visitarExpressaoAgrupamento(expressao) {
449
+ return (0, encadear_1.encadear)(this.avaliar(expressao.expressao), (avaliacaoAgrupamento) => {
450
+ if (avaliacaoAgrupamento !== null && avaliacaoAgrupamento.declaracao) {
451
+ return avaliacaoAgrupamento.declaracao;
452
+ }
453
+ return avaliacaoAgrupamento;
454
+ });
452
455
  }
453
456
  eVerdadeiro(objeto) {
454
457
  if (objeto === null || objeto === undefined)
@@ -469,63 +472,87 @@ class InterpretadorBase {
469
472
  return;
470
473
  throw new excecoes_1.ErroEmTempoDeExecucao(operador, 'Operando precisa ser um número.', Number(operador.linha));
471
474
  }
472
- async visitarExpressaoUnaria(expressao) {
473
- const operando = await this.avaliar(expressao.operando);
474
- let valor = this.resolverValor(operando);
475
- switch (expressao.operador.tipo) {
476
- case delegua_1.default.ADICAO:
477
- this.verificarOperandoNumero(expressao.operador, valor);
478
- return +valor;
479
- case delegua_1.default.SUBTRACAO:
480
- this.verificarOperandoNumero(expressao.operador, valor);
481
- return -valor;
482
- case delegua_1.default.NEGACAO:
483
- case delegua_1.default.NAO:
484
- return !this.eVerdadeiro(valor);
485
- case delegua_1.default.BIT_NOT:
486
- if (typeof valor === 'bigint') {
487
- return ~valor;
488
- }
489
- this.verificarOperandoNumero(expressao.operador, valor);
490
- return ~Number(valor);
491
- // Para incrementar e decrementar, primeiro precisamos saber se o operador
492
- // veio antes do literal ou variável.
493
- // Se veio antes e o operando é uma variável, precisamos incrementar/decrementar,
494
- // armazenar o valor da variável pra só então devolver o valor.
495
- case delegua_1.default.INCREMENTAR:
496
- if (typeof valor === 'string') {
497
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
498
- }
499
- if (expressao.incidenciaOperador === 'ANTES') {
500
- valor++;
501
- if (expressao.operando instanceof construtos_1.Variavel) {
502
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, valor);
475
+ /**
476
+ * Atribui `valor` de volta ao operando de um unário de incremento/decremento
477
+ * (`++operando` / `operando++` / `--operando` / `operando--`).
478
+ * Suporta variáveis simples e elementos de vetor/dicionário acessados por índice
479
+ * (ex.: `x[0]++`). Outros tipos de operando (literais, chamadas, etc.) apenas
480
+ * devolvem o valor, sem persistir a mudança em lugar nenhum.
481
+ * @param operando O construto à esquerda/direita do operador de incremento/decremento.
482
+ * @param valor O novo valor a ser armazenado.
483
+ * @returns {any} O próprio `valor`, possivelmente encadeado numa `Promise`.
484
+ */
485
+ atribuirValorAoOperandoUnario(operando, valor) {
486
+ if (operando instanceof construtos_1.Variavel) {
487
+ this.pilhaEscoposExecucao.atribuirVariavel(operando.simbolo, valor);
488
+ return valor;
489
+ }
490
+ if (operando instanceof construtos_1.AcessoIndiceVariavel) {
491
+ return (0, encadear_1.encadear)(this.avaliar(operando.entidadeChamada), (entidadeBruta) => {
492
+ const entidade = this.resolverValor(entidadeBruta);
493
+ return (0, encadear_1.encadear)(this.avaliar(operando.indice), (indiceBruto) => {
494
+ let indice = this.resolverValor(indiceBruto);
495
+ if (Array.isArray(entidade)) {
496
+ if (indice < 0 && entidade.length !== 0) {
497
+ while (indice < 0) {
498
+ indice += entidade.length;
499
+ }
500
+ }
501
+ entidade[indice] = valor;
503
502
  }
504
- return valor;
505
- }
506
- const valorAnteriorIncremento = valor;
507
- if (expressao.operando instanceof construtos_1.Variavel) {
508
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, ++valor);
509
- }
510
- return valorAnteriorIncremento;
511
- case delegua_1.default.DECREMENTAR:
512
- if (typeof valor === 'string') {
513
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
514
- }
515
- if (expressao.incidenciaOperador === 'ANTES') {
516
- valor--;
517
- if (expressao.operando instanceof construtos_1.Variavel) {
518
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, valor);
503
+ else if (entidade && typeof entidade === 'object') {
504
+ entidade[indice] = valor;
519
505
  }
520
506
  return valor;
521
- }
522
- const valorAnteriorDecremento = valor;
523
- if (expressao.operando instanceof construtos_1.Variavel) {
524
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, --valor);
525
- }
526
- return valorAnteriorDecremento;
507
+ });
508
+ });
527
509
  }
528
- return null;
510
+ return valor;
511
+ }
512
+ visitarExpressaoUnaria(expressao) {
513
+ return (0, encadear_1.encadear)(this.avaliar(expressao.operando), (operando) => {
514
+ let valor = this.resolverValor(operando);
515
+ switch (expressao.operador.tipo) {
516
+ case delegua_1.default.ADICAO:
517
+ this.verificarOperandoNumero(expressao.operador, valor);
518
+ return +valor;
519
+ case delegua_1.default.SUBTRACAO:
520
+ this.verificarOperandoNumero(expressao.operador, valor);
521
+ return -valor;
522
+ case delegua_1.default.NEGACAO:
523
+ case delegua_1.default.NAO:
524
+ return !this.eVerdadeiro(valor);
525
+ case delegua_1.default.BIT_NOT:
526
+ if (typeof valor === 'bigint') {
527
+ return ~valor;
528
+ }
529
+ this.verificarOperandoNumero(expressao.operador, valor);
530
+ return ~Number(valor);
531
+ // Para incrementar e decrementar, primeiro precisamos saber se o operador
532
+ // veio antes do literal ou variável.
533
+ // Se veio antes e o operando é uma variável, precisamos incrementar/decrementar,
534
+ // armazenar o valor da variável pra só então devolver o valor.
535
+ case delegua_1.default.INCREMENTAR:
536
+ if (typeof valor === 'string') {
537
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
538
+ }
539
+ if (expressao.incidenciaOperador === 'ANTES') {
540
+ return this.atribuirValorAoOperandoUnario(expressao.operando, valor + 1);
541
+ }
542
+ const valorAnteriorIncremento = valor;
543
+ return (0, encadear_1.encadear)(this.atribuirValorAoOperandoUnario(expressao.operando, valor + 1), () => valorAnteriorIncremento);
544
+ case delegua_1.default.DECREMENTAR:
545
+ if (typeof valor === 'string') {
546
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
547
+ }
548
+ if (expressao.incidenciaOperador === 'ANTES') {
549
+ return this.atribuirValorAoOperandoUnario(expressao.operando, valor - 1);
550
+ }
551
+ const valorAnteriorDecremento = valor;
552
+ return (0, encadear_1.encadear)(this.atribuirValorAoOperandoUnario(expressao.operando, valor - 1), () => valorAnteriorDecremento);
553
+ }
554
+ return null;
555
+ });
529
556
  }
530
557
  /**
531
558
  * Formata uma saída de acordo com o número e espaços e casas decimais solicitados.
@@ -604,270 +631,276 @@ class InterpretadorBase {
604
631
  return;
605
632
  if (this.tiposNumericos.includes(tipoDireita) && tipoEsquerda === 'nulo')
606
633
  return;
607
- // Se operador é subtração, os dois tipos são `qualquer`, mas ambos podem ser convertidos
608
- // para número, a operação é válida.
609
- if (operador.tipo === delegua_1.default.SUBTRACAO) {
610
- if (typeof esquerda.valor === 'number' && typeof direita.valor === 'number') {
611
- return;
612
- }
634
+ // A inferência estática de tipos (feita em tempo de análise sintática) é otimista e pode
635
+ // marcar variáveis como `qualquer` quando não consegue deduzir o tipo real (por exemplo,
636
+ // resultado de operação bit a bit ou acesso a índice de vetor com parâmetro sem tipo
637
+ // explícito). Se os dois operandos não bateram nas checagens de tipo acima, mas os
638
+ // valores em tempo de execução são efetivamente números, a operação é válida.
639
+ const valorEsquerda = esquerda && esquerda.hasOwnProperty('valor') ? esquerda.valor : esquerda;
640
+ const valorDireita = direita && direita.hasOwnProperty('valor') ? direita.valor : direita;
641
+ if ((typeof valorEsquerda === 'number' || typeof valorEsquerda === 'bigint') &&
642
+ (typeof valorDireita === 'number' || typeof valorDireita === 'bigint')) {
643
+ return;
613
644
  }
614
645
  throw new excecoes_1.ErroEmTempoDeExecucao(operador, 'Operadores precisam ser números.', operador.linha);
615
646
  }
616
647
  converterParaBigInt(valor) {
617
648
  return typeof valor === 'bigint' ? valor : BigInt(Math.floor(Number(valor)));
618
649
  }
619
- async visitarExpressaoBinaria(expressao) {
620
- const esquerda = await this.avaliar(expressao.esquerda);
621
- const direita = await this.avaliar(expressao.direita);
622
- const valorEsquerdo = this.resolverValor(esquerda);
623
- const valorDireito = this.resolverValor(direita);
624
- // Verificar sobrecarga de operador: se o operando esquerdo é uma instância de classe,
625
- // procurar método `operador<símbolo>` (ex: `operador+`, `operador==`).
626
- if (valorEsquerdo instanceof estruturas_1.ObjetoDeleguaClasse) {
627
- const nomeOperador = 'operador' + expressao.operador.lexema;
628
- const metodoOperador = valorEsquerdo.classe.encontrarMetodo(nomeOperador);
629
- if (metodoOperador) {
630
- const metodoASerChamado = metodoOperador.funcaoPorMetodoDeClasse(valorEsquerdo);
631
- const argumentoOperador = direita && Object.prototype.hasOwnProperty.call(direita, 'tipo')
632
- ? direita
633
- : {
634
- tipo: (0, inferenciador_1.inferirTipoVariavel)(valorDireito),
635
- valor: valorDireito,
636
- imutavel: false,
637
- };
638
- return await metodoASerChamado.chamar(this, [
639
- { nome: null, valor: argumentoOperador },
640
- ]);
641
- }
642
- }
643
- const tipoEsquerdo = esquerda?.hasOwnProperty('tipo')
644
- ? esquerda.tipo
645
- : (0, inferenciador_1.inferirTipoVariavel)(esquerda);
646
- const tipoDireito = direita?.hasOwnProperty('tipo')
647
- ? direita.tipo
648
- : (0, inferenciador_1.inferirTipoVariavel)(direita);
649
- switch (expressao.operador.tipo) {
650
- case delegua_1.default.EXPONENCIACAO:
651
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
652
- // Auto-promove para BigInt se qualquer operando for BigInt
653
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
654
- return (this.converterParaBigInt(valorEsquerdo) **
655
- this.converterParaBigInt(valorDireito));
656
- }
657
- const resultadoExponenciacao = Math.pow(valorEsquerdo, valorDireito);
658
- return resultadoExponenciacao;
659
- case delegua_1.default.MAIOR:
660
- if (typeof valorEsquerdo === 'string' &&
661
- typeof valorDireito === 'string') {
662
- return valorEsquerdo > valorDireito;
663
- }
664
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
665
- return Number(valorEsquerdo) > Number(valorDireito);
666
- case delegua_1.default.MAIOR_IGUAL:
667
- if (typeof valorEsquerdo === 'string' &&
668
- typeof valorDireito === 'string') {
669
- return valorEsquerdo >= valorDireito;
670
- }
671
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
672
- return Number(valorEsquerdo) >= Number(valorDireito);
673
- case delegua_1.default.MENOR:
674
- if (typeof valorEsquerdo === 'string' &&
675
- typeof valorDireito === 'string') {
676
- return valorEsquerdo < valorDireito;
677
- }
678
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
679
- return Number(valorEsquerdo) < Number(valorDireito);
680
- case delegua_1.default.MENOR_IGUAL:
681
- if (typeof valorEsquerdo === 'string' &&
682
- typeof valorDireito === 'string') {
683
- return valorEsquerdo <= valorDireito;
684
- }
685
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
686
- return Number(valorEsquerdo) <= Number(valorDireito);
687
- case delegua_1.default.SUBTRACAO:
688
- case delegua_1.default.MENOS_IGUAL:
689
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
690
- // Auto-promove para BigInt se qualquer operando for BigInt
691
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
692
- return (this.converterParaBigInt(valorEsquerdo) -
693
- this.converterParaBigInt(valorDireito));
694
- }
695
- return Number(valorEsquerdo) - Number(valorDireito);
696
- case delegua_1.default.ADICAO:
697
- case delegua_1.default.MAIS_IGUAL:
698
- // Se ambos os operandos são vetores, concatená-los
699
- if (Array.isArray(valorEsquerdo) && Array.isArray(valorDireito)) {
700
- return valorEsquerdo.concat(valorDireito);
701
- }
702
- // Se ambos os operandos são dicionários, mescla-os.
703
- // Em caso de chaves duplicadas, valores à direita sobrescrevem os da esquerda.
704
- if (valorEsquerdo &&
705
- valorDireito &&
706
- !Array.isArray(valorEsquerdo) &&
707
- !Array.isArray(valorDireito) &&
708
- valorEsquerdo.constructor === Object &&
709
- valorDireito.constructor === Object) {
710
- return Object.assign({}, valorEsquerdo, valorDireito);
711
- }
712
- // Auto-promove para BigInt se qualquer operando for BigInt
713
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
714
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
715
- ? valorEsquerdo
716
- : BigInt(Math.floor(Number(valorEsquerdo)));
717
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
718
- ? valorDireito
719
- : BigInt(Math.floor(Number(valorDireito)));
720
- return valorResolvidoEsquerdo + valorResolvidoDireito;
721
- }
722
- if (this.tiposNumericos.includes(tipoEsquerdo) &&
723
- this.tiposNumericos.includes(tipoDireito)) {
724
- return Number(valorEsquerdo) + Number(valorDireito);
725
- }
726
- if (valorEsquerdo === null || valorDireito === null) {
650
+ // Corpo original mantido com a indentação de antes da conversão ( o cabeçalho e o
651
+ // fechamento mudaram) para manter este diff revisável — ver `encadear` para o porquê.
652
+ visitarExpressaoBinaria(expressao) {
653
+ return (0, encadear_1.encadear)(this.avaliar(expressao.esquerda), (esquerda) => (0, encadear_1.encadear)(this.avaliar(expressao.direita), (direita) => {
654
+ const valorEsquerdo = this.resolverValor(esquerda);
655
+ const valorDireito = this.resolverValor(direita);
656
+ // Verificar sobrecarga de operador: se o operando esquerdo é uma instância de classe,
657
+ // procurar método `operador<símbolo>` (ex: `operador+`, `operador==`).
658
+ if (valorEsquerdo instanceof estruturas_1.ObjetoDeleguaClasse) {
659
+ const nomeOperador = 'operador' + expressao.operador.lexema;
660
+ const metodoOperador = valorEsquerdo.classe.encontrarMetodo(nomeOperador);
661
+ if (metodoOperador) {
662
+ const metodoASerChamado = metodoOperador.funcaoPorMetodoDeClasse(valorEsquerdo);
663
+ const argumentoOperador = direita && Object.prototype.hasOwnProperty.call(direita, 'tipo')
664
+ ? direita
665
+ : {
666
+ tipo: (0, inferenciador_1.inferirTipoVariavel)(valorDireito),
667
+ valor: valorDireito,
668
+ imutavel: false,
669
+ };
670
+ return metodoASerChamado.chamar(this, [
671
+ { nome: null, valor: argumentoOperador },
672
+ ]);
673
+ }
674
+ }
675
+ const tipoEsquerdo = esquerda?.hasOwnProperty('tipo')
676
+ ? esquerda.tipo
677
+ : (0, inferenciador_1.inferirTipoVariavel)(esquerda);
678
+ const tipoDireito = direita?.hasOwnProperty('tipo')
679
+ ? direita.tipo
680
+ : (0, inferenciador_1.inferirTipoVariavel)(direita);
681
+ switch (expressao.operador.tipo) {
682
+ case delegua_1.default.EXPONENCIACAO:
683
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
684
+ // Auto-promove para BigInt se qualquer operando for BigInt
685
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
686
+ return (this.converterParaBigInt(valorEsquerdo) **
687
+ this.converterParaBigInt(valorDireito));
688
+ }
689
+ const resultadoExponenciacao = Math.pow(valorEsquerdo, valorDireito);
690
+ return resultadoExponenciacao;
691
+ case delegua_1.default.MAIOR:
692
+ if (typeof valorEsquerdo === 'string' &&
693
+ typeof valorDireito === 'string') {
694
+ return valorEsquerdo > valorDireito;
695
+ }
696
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
697
+ return Number(valorEsquerdo) > Number(valorDireito);
698
+ case delegua_1.default.MAIOR_IGUAL:
699
+ if (typeof valorEsquerdo === 'string' &&
700
+ typeof valorDireito === 'string') {
701
+ return valorEsquerdo >= valorDireito;
702
+ }
703
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
704
+ return Number(valorEsquerdo) >= Number(valorDireito);
705
+ case delegua_1.default.MENOR:
706
+ if (typeof valorEsquerdo === 'string' &&
707
+ typeof valorDireito === 'string') {
708
+ return valorEsquerdo < valorDireito;
709
+ }
710
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
711
+ return Number(valorEsquerdo) < Number(valorDireito);
712
+ case delegua_1.default.MENOR_IGUAL:
713
+ if (typeof valorEsquerdo === 'string' &&
714
+ typeof valorDireito === 'string') {
715
+ return valorEsquerdo <= valorDireito;
716
+ }
717
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
718
+ return Number(valorEsquerdo) <= Number(valorDireito);
719
+ case delegua_1.default.SUBTRACAO:
720
+ case delegua_1.default.MENOS_IGUAL:
721
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
722
+ // Auto-promove para BigInt se qualquer operando for BigInt
723
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
724
+ return (this.converterParaBigInt(valorEsquerdo) -
725
+ this.converterParaBigInt(valorDireito));
726
+ }
727
+ return Number(valorEsquerdo) - Number(valorDireito);
728
+ case delegua_1.default.ADICAO:
729
+ case delegua_1.default.MAIS_IGUAL:
730
+ // Se ambos os operandos são vetores, concatená-los
731
+ if (Array.isArray(valorEsquerdo) && Array.isArray(valorDireito)) {
732
+ return valorEsquerdo.concat(valorDireito);
733
+ }
734
+ // Se ambos os operandos são dicionários, mescla-os.
735
+ // Em caso de chaves duplicadas, valores à direita sobrescrevem os da esquerda.
736
+ if (valorEsquerdo &&
737
+ valorDireito &&
738
+ !Array.isArray(valorEsquerdo) &&
739
+ !Array.isArray(valorDireito) &&
740
+ valorEsquerdo.constructor === Object &&
741
+ valorDireito.constructor === Object) {
742
+ return Object.assign({}, valorEsquerdo, valorDireito);
743
+ }
744
+ // Auto-promove para BigInt se qualquer operando for BigInt
745
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
746
+ const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
747
+ ? valorEsquerdo
748
+ : BigInt(Math.floor(Number(valorEsquerdo)));
749
+ const valorResolvidoDireito = typeof valorDireito === 'bigint'
750
+ ? valorDireito
751
+ : BigInt(Math.floor(Number(valorDireito)));
752
+ return valorResolvidoEsquerdo + valorResolvidoDireito;
753
+ }
754
+ if (this.tiposNumericos.includes(tipoEsquerdo) &&
755
+ this.tiposNumericos.includes(tipoDireito)) {
756
+ return Number(valorEsquerdo) + Number(valorDireito);
757
+ }
758
+ if (valorEsquerdo === null || valorDireito === null) {
759
+ return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
760
+ }
761
+ // Para tipos 'qualquer', delegamos ao operador nativo do JavaScript,
762
+ // que resolve concatenação ou soma dependendo dos valores em tempo de execução.
763
+ if (tipoEsquerdo === 'qualquer' || tipoDireito === 'qualquer') {
764
+ return valorEsquerdo + valorDireito;
765
+ }
727
766
  return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
728
- }
729
- // Para tipos 'qualquer', delegamos ao operador nativo do JavaScript,
730
- // que resolve concatenação ou soma dependendo dos valores em tempo de execução.
731
- if (tipoEsquerdo === 'qualquer' || tipoDireito === 'qualquer') {
732
- return valorEsquerdo + valorDireito;
733
- }
734
- return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
735
- case delegua_1.default.DIVISAO:
736
- case delegua_1.default.DIVISAO_IGUAL:
737
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
738
- if (this.lancarErroPorDivisaoPorZero && Number(valorDireito) === 0) {
739
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
740
- }
741
- // SEMPRE retorna Number para precisão decimal (preferência do usuário)
742
- // Mesmo se operandos forem BigInt, converte para Number
743
- return Number(valorEsquerdo) / Number(valorDireito);
744
- case delegua_1.default.DIVISAO_INTEIRA:
745
- case delegua_1.default.DIVISAO_INTEIRA_IGUAL:
746
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
747
- if (this.lancarErroPorDivisaoPorZero && valorDireito === 0) {
748
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
749
- }
750
- // Retorna BigInt se qualquer operando for BigInt
751
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
752
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
753
- ? valorEsquerdo
754
- : BigInt(Math.floor(Number(valorEsquerdo)));
755
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
756
- ? valorDireito
757
- : BigInt(Math.floor(Number(valorDireito)));
758
- return valorResolvidoEsquerdo / valorResolvidoDireito; // Trunca automaticamente
759
- }
760
- return Math.floor(Number(valorEsquerdo) / Number(valorDireito));
761
- case delegua_1.default.MULTIPLICACAO:
762
- case delegua_1.default.MULTIPLICACAO_IGUAL:
763
- // Auto-promove para BigInt se qualquer operando for BigInt (e não for texto)
764
- if ((typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') &&
765
- tipoEsquerdo !== delegua_2.default.TEXTO &&
766
- tipoDireito !== delegua_2.default.TEXTO) {
767
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
768
- ? valorEsquerdo
769
- : BigInt(Math.floor(Number(valorEsquerdo)));
770
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
771
- ? valorDireito
772
- : BigInt(Math.floor(Number(valorDireito)));
773
- return valorResolvidoEsquerdo * valorResolvidoDireito;
774
- }
775
- if (tipoEsquerdo === delegua_2.default.TEXTO ||
776
- tipoDireito === delegua_2.default.TEXTO) {
777
- // Sem ambos os valores resolvem como texto, multiplica normal.
778
- // Se apenas um resolve como texto, o outro repete o
779
- // texto n vezes, sendo n o valor do outro.
780
- if (tipoEsquerdo === delegua_2.default.TEXTO &&
767
+ case delegua_1.default.DIVISAO:
768
+ case delegua_1.default.DIVISAO_IGUAL:
769
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
770
+ if (this.lancarErroPorDivisaoPorZero && Number(valorDireito) === 0) {
771
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
772
+ }
773
+ // SEMPRE retorna Number para precisão decimal (preferência do usuário)
774
+ // Mesmo se operandos forem BigInt, converte para Number
775
+ return Number(valorEsquerdo) / Number(valorDireito);
776
+ case delegua_1.default.DIVISAO_INTEIRA:
777
+ case delegua_1.default.DIVISAO_INTEIRA_IGUAL:
778
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
779
+ if (this.lancarErroPorDivisaoPorZero && valorDireito === 0) {
780
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
781
+ }
782
+ // Retorna BigInt se qualquer operando for BigInt
783
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
784
+ const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
785
+ ? valorEsquerdo
786
+ : BigInt(Math.floor(Number(valorEsquerdo)));
787
+ const valorResolvidoDireito = typeof valorDireito === 'bigint'
788
+ ? valorDireito
789
+ : BigInt(Math.floor(Number(valorDireito)));
790
+ return valorResolvidoEsquerdo / valorResolvidoDireito; // Trunca automaticamente
791
+ }
792
+ return Math.floor(Number(valorEsquerdo) / Number(valorDireito));
793
+ case delegua_1.default.MULTIPLICACAO:
794
+ case delegua_1.default.MULTIPLICACAO_IGUAL:
795
+ // Auto-promove para BigInt se qualquer operando for BigInt (e não for texto)
796
+ if ((typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') &&
797
+ tipoEsquerdo !== delegua_2.default.TEXTO &&
798
+ tipoDireito !== delegua_2.default.TEXTO) {
799
+ const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
800
+ ? valorEsquerdo
801
+ : BigInt(Math.floor(Number(valorEsquerdo)));
802
+ const valorResolvidoDireito = typeof valorDireito === 'bigint'
803
+ ? valorDireito
804
+ : BigInt(Math.floor(Number(valorDireito)));
805
+ return valorResolvidoEsquerdo * valorResolvidoDireito;
806
+ }
807
+ if (tipoEsquerdo === delegua_2.default.TEXTO ||
781
808
  tipoDireito === delegua_2.default.TEXTO) {
782
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Não é possível multiplicar dois textos.', expressao.linha);
809
+ // Sem ambos os valores resolvem como texto, multiplica normal.
810
+ // Se apenas um resolve como texto, o outro repete o
811
+ // texto n vezes, sendo n o valor do outro.
812
+ if (tipoEsquerdo === delegua_2.default.TEXTO &&
813
+ tipoDireito === delegua_2.default.TEXTO) {
814
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Não é possível multiplicar dois textos.', expressao.linha);
815
+ }
816
+ const valorTexto = tipoEsquerdo === delegua_2.default.TEXTO ? valorEsquerdo : valorDireito;
817
+ const valorQuantidade = tipoEsquerdo === delegua_2.default.TEXTO ? valorDireito : valorEsquerdo;
818
+ if (typeof valorQuantidade !== 'number') {
819
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Para multiplicar um texto, o outro operando deve ser um número.', expressao.linha);
820
+ }
821
+ const textoParaNumero = Number(valorTexto);
822
+ if (!isNaN(textoParaNumero)) {
823
+ return textoParaNumero * valorQuantidade;
824
+ }
825
+ if (!Number.isInteger(valorQuantidade)) {
826
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'A multiplicação de texto exige um número inteiro.', expressao.linha);
827
+ }
828
+ if (valorQuantidade < 0) {
829
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Não é possível multiplicar texto por número negativo.', expressao.linha);
830
+ }
831
+ return valorTexto.repeat(valorQuantidade);
783
832
  }
784
- const valorTexto = tipoEsquerdo === delegua_2.default.TEXTO ? valorEsquerdo : valorDireito;
785
- const valorQuantidade = tipoEsquerdo === delegua_2.default.TEXTO ? valorDireito : valorEsquerdo;
786
- if (typeof valorQuantidade !== 'number') {
787
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Para multiplicar um texto, o outro operando deve ser um número.', expressao.linha);
833
+ return Number(valorEsquerdo) * Number(valorDireito);
834
+ case delegua_1.default.MODULO:
835
+ case delegua_1.default.MODULO_IGUAL:
836
+ // Se o operando esquerdo é uma string, usar formatação de string
837
+ if (tipoEsquerdo === delegua_2.default.TEXTO ||
838
+ typeof valorEsquerdo === 'string') {
839
+ return this.formatarStringComOperadorPorcentagem(String(valorEsquerdo), direita, // Passar 'direita' ao invés de 'valorDireito' para preservar arrays de tuplas
840
+ expressao.operador);
788
841
  }
789
- const textoParaNumero = Number(valorTexto);
790
- if (!isNaN(textoParaNumero)) {
791
- return textoParaNumero * valorQuantidade;
842
+ // Caso contrário, operação matemática normal
843
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
844
+ return Number(valorEsquerdo) % Number(valorDireito);
845
+ case delegua_1.default.BIT_AND:
846
+ if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
847
+ return valorEsquerdo && valorDireito;
792
848
  }
793
- if (!Number.isInteger(valorQuantidade)) {
794
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'A multiplicação de texto exige um número inteiro.', expressao.linha);
849
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
850
+ // Auto-promove para BigInt se qualquer operando for BigInt
851
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
852
+ return (this.converterParaBigInt(valorEsquerdo) &
853
+ this.converterParaBigInt(valorDireito));
795
854
  }
796
- if (valorQuantidade < 0) {
797
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Não é possível multiplicar texto por número negativo.', expressao.linha);
855
+ return Number(valorEsquerdo) & Number(valorDireito);
856
+ case delegua_1.default.CIRCUMFLEXO:
857
+ if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
858
+ return valorEsquerdo !== valorDireito;
798
859
  }
799
- return valorTexto.repeat(valorQuantidade);
800
- }
801
- return Number(valorEsquerdo) * Number(valorDireito);
802
- case delegua_1.default.MODULO:
803
- case delegua_1.default.MODULO_IGUAL:
804
- // Se o operando esquerdo é uma string, usar formatação de string
805
- if (tipoEsquerdo === delegua_2.default.TEXTO ||
806
- typeof valorEsquerdo === 'string') {
807
- return this.formatarStringComOperadorPorcentagem(String(valorEsquerdo), direita, // Passar 'direita' ao invés de 'valorDireito' para preservar arrays de tuplas
808
- expressao.operador);
809
- }
810
- // Caso contrário, operação matemática normal
811
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
812
- return Number(valorEsquerdo) % Number(valorDireito);
813
- case delegua_1.default.BIT_AND:
814
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
815
- return valorEsquerdo && valorDireito;
816
- }
817
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
818
- // Auto-promove para BigInt se qualquer operando for BigInt
819
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
820
- return (this.converterParaBigInt(valorEsquerdo) &
821
- this.converterParaBigInt(valorDireito));
822
- }
823
- return Number(valorEsquerdo) & Number(valorDireito);
824
- case delegua_1.default.CIRCUMFLEXO:
825
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
826
- return valorEsquerdo !== valorDireito;
827
- }
828
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
829
- // Auto-promove para BigInt se qualquer operando for BigInt
830
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
831
- return (this.converterParaBigInt(valorEsquerdo) ^
832
- this.converterParaBigInt(valorDireito));
833
- }
834
- return Number(valorEsquerdo) ^ Number(valorDireito);
835
- case delegua_1.default.BIT_OR:
836
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
837
- return valorEsquerdo || valorDireito;
838
- }
839
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
840
- // Auto-promove para BigInt se qualquer operando for BigInt
841
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
842
- return (this.converterParaBigInt(valorEsquerdo) |
843
- this.converterParaBigInt(valorDireito));
844
- }
845
- return Number(valorEsquerdo) | Number(valorDireito);
846
- case delegua_1.default.MENOR_MENOR:
847
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
848
- // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
849
- if (typeof valorEsquerdo === 'bigint' ||
850
- typeof valorDireito === 'bigint' ||
851
- Number(valorDireito) >= 32) {
852
- return (this.converterParaBigInt(valorEsquerdo) <<
853
- this.converterParaBigInt(valorDireito));
854
- }
855
- return Number(valorEsquerdo) << Number(valorDireito);
856
- case delegua_1.default.MAIOR_MAIOR:
857
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
858
- // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
859
- if (typeof valorEsquerdo === 'bigint' ||
860
- typeof valorDireito === 'bigint' ||
861
- Number(valorDireito) >= 32) {
862
- return (this.converterParaBigInt(valorEsquerdo) >>
863
- this.converterParaBigInt(valorDireito));
864
- }
865
- return Number(valorEsquerdo) >> Number(valorDireito);
866
- case delegua_1.default.DIFERENTE:
867
- return !this.eIgual(valorEsquerdo, valorDireito);
868
- case delegua_1.default.IGUAL_IGUAL:
869
- return this.eIgual(valorEsquerdo, valorDireito);
870
- }
860
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
861
+ // Auto-promove para BigInt se qualquer operando for BigInt
862
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
863
+ return (this.converterParaBigInt(valorEsquerdo) ^
864
+ this.converterParaBigInt(valorDireito));
865
+ }
866
+ return Number(valorEsquerdo) ^ Number(valorDireito);
867
+ case delegua_1.default.BIT_OR:
868
+ if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
869
+ return valorEsquerdo || valorDireito;
870
+ }
871
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
872
+ // Auto-promove para BigInt se qualquer operando for BigInt
873
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
874
+ return (this.converterParaBigInt(valorEsquerdo) |
875
+ this.converterParaBigInt(valorDireito));
876
+ }
877
+ return Number(valorEsquerdo) | Number(valorDireito);
878
+ case delegua_1.default.MENOR_MENOR:
879
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
880
+ // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
881
+ if (typeof valorEsquerdo === 'bigint' ||
882
+ typeof valorDireito === 'bigint' ||
883
+ Number(valorDireito) >= 32) {
884
+ return (this.converterParaBigInt(valorEsquerdo) <<
885
+ this.converterParaBigInt(valorDireito));
886
+ }
887
+ return Number(valorEsquerdo) << Number(valorDireito);
888
+ case delegua_1.default.MAIOR_MAIOR:
889
+ this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
890
+ // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
891
+ if (typeof valorEsquerdo === 'bigint' ||
892
+ typeof valorDireito === 'bigint' ||
893
+ Number(valorDireito) >= 32) {
894
+ return (this.converterParaBigInt(valorEsquerdo) >>
895
+ this.converterParaBigInt(valorDireito));
896
+ }
897
+ return Number(valorEsquerdo) >> Number(valorDireito);
898
+ case delegua_1.default.DIFERENTE:
899
+ return !this.eIgual(valorEsquerdo, valorDireito);
900
+ case delegua_1.default.IGUAL_IGUAL:
901
+ return this.eIgual(valorEsquerdo, valorDireito);
902
+ }
903
+ }));
871
904
  }
872
905
  /**
873
906
  * Faz a chamada do método de uma primitiva (por exemplo, número, texto, etc.) com seus
@@ -919,7 +952,7 @@ class InterpretadorBase {
919
952
  let entidadeChamada = this.resolverValor(variavelEntidadeChamada);
920
953
  // Funções anônimas
921
954
  if (entidadeChamada instanceof construtos_1.FuncaoConstruto) {
922
- entidadeChamada = new estruturas_1.DeleguaFuncao(null, entidadeChamada);
955
+ entidadeChamada = new estruturas_1.DeleguaFuncao(null, entidadeChamada).capturarEscopo(this.pilhaEscoposExecucao);
923
956
  }
924
957
  if (entidadeChamada instanceof estruturas_1.DeleguaModulo) {
925
958
  return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.parentese, 'Entidade chamada é um módulo de Delégua. Provavelmente você quer chamar um de seus componentes?', expressao.linha));
@@ -1041,57 +1074,63 @@ class InterpretadorBase {
1041
1074
  * @param expressao A expressão.
1042
1075
  * @returns O valor atribuído.
1043
1076
  */
1044
- async visitarExpressaoDeAtribuicao(expressao) {
1045
- let valor = await this.avaliar(expressao.valor);
1046
- if (valor && valor.hasOwnProperty('valorRetornado')) {
1047
- valor = valor.valorRetornado;
1048
- }
1049
- const valorResolvido = this.resolverValor(valor);
1050
- let indice = null;
1051
- if (expressao.indice) {
1052
- indice = this.resolverValor(await this.avaliar(expressao.indice));
1053
- }
1054
- switch (expressao.alvo.constructor) {
1055
- case construtos_1.AcessoMetodoOuPropriedade:
1056
- const alvoPropriedade = expressao.alvo;
1057
- const variavelObjeto = await this.avaliar(alvoPropriedade.objeto);
1058
- const objeto = this.resolverValor(variavelObjeto);
1059
- const valorProp = await this.avaliar(expressao.valor);
1060
- await this.definirPropriedadeObjeto(objeto, alvoPropriedade.simbolo, valorProp);
1061
- break;
1062
- case construtos_1.Variavel:
1063
- const alvoVariavel = expressao.alvo;
1064
- if (expressao.simboloOperador) {
1065
- let valorAtual;
1066
- valorAtual = this.resolverValor(this.pilhaEscoposExecucao.obterValorVariavel(alvoVariavel.simbolo));
1067
- if (typeof valorAtual === 'string') {
1068
- let valorDireito;
1069
- if (expressao.valor instanceof construtos_1.Binario) {
1070
- valorDireito = this.resolverValor(await this.avaliar(expressao.valor.direita));
1071
- }
1072
- else {
1073
- valorDireito = valorResolvido;
1074
- }
1075
- if (expressao.simboloOperador.tipo === delegua_1.default.MAIS_IGUAL) {
1076
- if (typeof valorDireito !== 'string') {
1077
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, `Operador '+=' não pode concatenar texto com ${typeof valorDireito}. Use conversão explícita.`, expressao.linha);
1077
+ visitarExpressaoDeAtribuicao(expressao) {
1078
+ return (0, encadear_1.encadear)(this.avaliar(expressao.valor), (valorBruto) => {
1079
+ let valor = valorBruto;
1080
+ if (valor && valor.hasOwnProperty('valorRetornado')) {
1081
+ valor = valor.valorRetornado;
1082
+ }
1083
+ const valorResolvido = this.resolverValor(valor);
1084
+ const continuarComIndice = (indice) => {
1085
+ switch (expressao.alvo.constructor) {
1086
+ case construtos_1.AcessoMetodoOuPropriedade: {
1087
+ const alvoPropriedade = expressao.alvo;
1088
+ return (0, encadear_1.encadear)(this.avaliar(alvoPropriedade.objeto), (variavelObjeto) => {
1089
+ const objeto = this.resolverValor(variavelObjeto);
1090
+ return (0, encadear_1.encadear)(this.avaliar(expressao.valor), (valorProp) => (0, encadear_1.encadear)(this.definirPropriedadeObjeto(objeto, alvoPropriedade.simbolo, valorProp), () => valorResolvido));
1091
+ });
1092
+ }
1093
+ case construtos_1.Variavel: {
1094
+ const alvoVariavel = expressao.alvo;
1095
+ const finalizarAtribuicaoVariavel = () => {
1096
+ this.atribuirVariavel(alvoVariavel, valorResolvido, indice);
1097
+ return valorResolvido;
1098
+ };
1099
+ if (expressao.simboloOperador) {
1100
+ const valorAtual = this.resolverValor(this.pilhaEscoposExecucao.obterValorVariavel(alvoVariavel.simbolo));
1101
+ if (typeof valorAtual === 'string') {
1102
+ const continuarComValorDireito = (valorDireito) => {
1103
+ if (expressao.simboloOperador.tipo === delegua_1.default.MAIS_IGUAL) {
1104
+ if (typeof valorDireito !== 'string') {
1105
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, `Operador '+=' não pode concatenar texto com ${typeof valorDireito}. Use conversão explícita.`, expressao.linha);
1106
+ }
1107
+ }
1108
+ else if ([delegua_1.default.MENOS_IGUAL,
1109
+ delegua_1.default.MULTIPLICACAO_IGUAL,
1110
+ delegua_1.default.DIVISAO_IGUAL,
1111
+ delegua_1.default.MODULO_IGUAL]
1112
+ .includes(expressao.simboloOperador.tipo)) {
1113
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, `Operador '${expressao.simboloOperador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
1114
+ }
1115
+ return finalizarAtribuicaoVariavel();
1116
+ };
1117
+ if (expressao.valor instanceof construtos_1.Binario) {
1118
+ return (0, encadear_1.encadear)(this.avaliar(expressao.valor.direita), (direitaBruta) => continuarComValorDireito(this.resolverValor(direitaBruta)));
1119
+ }
1120
+ return continuarComValorDireito(valorResolvido);
1078
1121
  }
1079
1122
  }
1080
- else if ([delegua_1.default.MENOS_IGUAL,
1081
- delegua_1.default.MULTIPLICACAO_IGUAL,
1082
- delegua_1.default.DIVISAO_IGUAL,
1083
- delegua_1.default.MODULO_IGUAL]
1084
- .includes(expressao.simboloOperador.tipo)) {
1085
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, `Operador '${expressao.simboloOperador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
1086
- }
1123
+ return finalizarAtribuicaoVariavel();
1087
1124
  }
1125
+ default:
1126
+ throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, "Alvo da atribuição inválido. O lado esquerdo de uma atribuição deve ser uma variável, propriedade ou índice.");
1088
1127
  }
1089
- this.atribuirVariavel(alvoVariavel, valorResolvido, indice);
1090
- break;
1091
- default:
1092
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, "Alvo da atribuição inválido. O lado esquerdo de uma atribuição deve ser uma variável, propriedade ou índice.");
1093
- }
1094
- return valorResolvido;
1128
+ };
1129
+ if (expressao.indice) {
1130
+ return (0, encadear_1.encadear)(this.avaliar(expressao.indice), (indiceBruto) => continuarComIndice(this.resolverValor(indiceBruto)));
1131
+ }
1132
+ return continuarComIndice(null);
1133
+ });
1095
1134
  }
1096
1135
  procurarVariavel(simbolo) {
1097
1136
  return this.pilhaEscoposExecucao.obterValorVariavel(simbolo);
@@ -1099,8 +1138,8 @@ class InterpretadorBase {
1099
1138
  visitarExpressaoDeVariavel(expressao) {
1100
1139
  return this.procurarVariavel(expressao.simbolo);
1101
1140
  }
1102
- async visitarDeclaracaoDeExpressao(declaracao) {
1103
- return await this.avaliar(declaracao.expressao);
1141
+ visitarDeclaracaoDeExpressao(declaracao) {
1142
+ return this.avaliar(declaracao.expressao);
1104
1143
  }
1105
1144
  logicaContemOuEm(esquerda, direita, expressao) {
1106
1145
  const valorEsquerdoResolvido = this.resolverValor(esquerda);
@@ -1116,66 +1155,69 @@ class InterpretadorBase {
1116
1155
  }
1117
1156
  throw new excecoes_1.ErroEmTempoDeExecucao(esquerda, `Tipo de chamada inválida com '${expressao.operador.tipo}'.`, expressao.linha);
1118
1157
  }
1119
- async visitarExpressaoLogica(expressao) {
1120
- const esquerda = await this.avaliar(expressao.esquerda);
1121
- if ([delegua_1.default.EM, delegua_1.default.CONTEM].includes(expressao.operador.tipo)) {
1122
- const direita = await this.avaliar(expressao.direita);
1123
- // `3 em lista` é igual a `lista contém 3`.
1124
- // Portanto, precisamos inverter os operandos de acordo com a
1125
- // palavra reservada usada.
1126
- switch (expressao.operador.tipo) {
1127
- case delegua_1.default.EM:
1128
- return this.logicaContemOuEm(esquerda, direita, expressao);
1129
- case delegua_1.default.CONTEM:
1130
- return this.logicaContemOuEm(direita, esquerda, expressao);
1131
- }
1132
- }
1133
- // E/OU como bitwise quando ambos operandos são numéricos
1134
- if ([delegua_1.default.E, delegua_1.default.OU].includes(expressao.operador.tipo)) {
1135
- const valorEsquerdo = this.resolverValor(esquerda);
1136
- if (typeof valorEsquerdo === 'number' || typeof valorEsquerdo === 'bigint') {
1137
- const direita = await this.avaliar(expressao.direita);
1138
- const valorDireito = this.resolverValor(direita);
1139
- if (typeof valorDireito === 'number' || typeof valorDireito === 'bigint') {
1140
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
1141
- const esq = typeof valorEsquerdo === 'bigint'
1142
- ? valorEsquerdo
1143
- : BigInt(Math.floor(Number(valorEsquerdo)));
1144
- const dir = typeof valorDireito === 'bigint'
1145
- ? valorDireito
1146
- : BigInt(Math.floor(Number(valorDireito)));
1147
- return expressao.operador.tipo === delegua_1.default.E
1148
- ? esq & dir
1149
- : esq | dir;
1158
+ visitarExpressaoLogica(expressao) {
1159
+ return (0, encadear_1.encadear)(this.avaliar(expressao.esquerda), (esquerda) => {
1160
+ if ([delegua_1.default.EM, delegua_1.default.CONTEM].includes(expressao.operador.tipo)) {
1161
+ return (0, encadear_1.encadear)(this.avaliar(expressao.direita), (direita) => {
1162
+ // `3 em lista` é igual a `lista contém 3`.
1163
+ // Portanto, precisamos inverter os operandos de acordo com a
1164
+ // palavra reservada usada.
1165
+ switch (expressao.operador.tipo) {
1166
+ case delegua_1.default.EM:
1167
+ return this.logicaContemOuEm(esquerda, direita, expressao);
1168
+ case delegua_1.default.CONTEM:
1169
+ return this.logicaContemOuEm(direita, esquerda, expressao);
1150
1170
  }
1151
- return expressao.operador.tipo === delegua_1.default.E
1152
- ? Number(valorEsquerdo) & Number(valorDireito)
1153
- : Number(valorEsquerdo) | Number(valorDireito);
1154
- }
1155
- // Demais casos sem diferença de tipos
1156
- if (expressao.operador.tipo === delegua_1.default.OU) {
1157
- if (this.eVerdadeiro(esquerda))
1158
- return esquerda;
1159
- return direita;
1160
- }
1161
- if (expressao.operador.tipo === delegua_1.default.E) {
1162
- if (!this.eVerdadeiro(esquerda))
1163
- return esquerda;
1164
- return direita;
1171
+ });
1172
+ }
1173
+ // E/OU como bitwise quando ambos operandos são numéricos
1174
+ if ([delegua_1.default.E, delegua_1.default.OU].includes(expressao.operador.tipo)) {
1175
+ const valorEsquerdo = this.resolverValor(esquerda);
1176
+ if (typeof valorEsquerdo === 'number' || typeof valorEsquerdo === 'bigint') {
1177
+ return (0, encadear_1.encadear)(this.avaliar(expressao.direita), (direita) => {
1178
+ const valorDireito = this.resolverValor(direita);
1179
+ if (typeof valorDireito === 'number' || typeof valorDireito === 'bigint') {
1180
+ if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
1181
+ const esq = typeof valorEsquerdo === 'bigint'
1182
+ ? valorEsquerdo
1183
+ : BigInt(Math.floor(Number(valorEsquerdo)));
1184
+ const dir = typeof valorDireito === 'bigint'
1185
+ ? valorDireito
1186
+ : BigInt(Math.floor(Number(valorDireito)));
1187
+ return expressao.operador.tipo === delegua_1.default.E
1188
+ ? esq & dir
1189
+ : esq | dir;
1190
+ }
1191
+ return expressao.operador.tipo === delegua_1.default.E
1192
+ ? Number(valorEsquerdo) & Number(valorDireito)
1193
+ : Number(valorEsquerdo) | Number(valorDireito);
1194
+ }
1195
+ // Demais casos sem diferença de tipos
1196
+ if (expressao.operador.tipo === delegua_1.default.OU) {
1197
+ if (this.eVerdadeiro(esquerda))
1198
+ return esquerda;
1199
+ return direita;
1200
+ }
1201
+ if (expressao.operador.tipo === delegua_1.default.E) {
1202
+ if (!this.eVerdadeiro(esquerda))
1203
+ return esquerda;
1204
+ return direita;
1205
+ }
1206
+ });
1165
1207
  }
1166
1208
  }
1167
- }
1168
- // se um estado for verdadeiro, retorna verdadeiro
1169
- if (expressao.operador.tipo === delegua_1.default.OU) {
1170
- if (this.eVerdadeiro(esquerda))
1171
- return esquerda;
1172
- }
1173
- // se um estado for falso, retorna falso
1174
- if (expressao.operador.tipo === delegua_1.default.E) {
1175
- if (!this.eVerdadeiro(esquerda))
1176
- return esquerda;
1177
- }
1178
- return await this.avaliar(expressao.direita);
1209
+ // se um estado for verdadeiro, retorna verdadeiro
1210
+ if (expressao.operador.tipo === delegua_1.default.OU) {
1211
+ if (this.eVerdadeiro(esquerda))
1212
+ return esquerda;
1213
+ }
1214
+ // se um estado for falso, retorna falso
1215
+ if (expressao.operador.tipo === delegua_1.default.E) {
1216
+ if (!this.eVerdadeiro(esquerda))
1217
+ return esquerda;
1218
+ }
1219
+ return this.avaliar(expressao.direita);
1220
+ });
1179
1221
  }
1180
1222
  async visitarDeclaracaoPara(declaracao) {
1181
1223
  const declaracaoInicializador = Array.isArray(declaracao.inicializador)
@@ -1279,26 +1321,33 @@ class InterpretadorBase {
1279
1321
  * @param declaracao A declaração Se.
1280
1322
  * @returns O resultado da avaliação do bloco cuja condição é verdadeira.
1281
1323
  */
1282
- async visitarDeclaracaoSe(declaracao) {
1283
- const avaliacaoCondicaoSe = await this.avaliar(declaracao.condicao);
1284
- if (this.eVerdadeiro(avaliacaoCondicaoSe)) {
1285
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'verdadeiro');
1286
- return await this.executar(declaracao.caminhoEntao);
1287
- }
1324
+ visitarDeclaracaoSe(declaracao) {
1288
1325
  const declaracaoCaminhosSeSenao = declaracao.caminhosSeSenao || [];
1289
- for (let i = 0; i < declaracaoCaminhosSeSenao.length; i++) {
1326
+ const proximoCaminhoSeSenao = (i) => {
1327
+ if (i >= declaracaoCaminhosSeSenao.length) {
1328
+ if (declaracao.caminhoSenao) {
1329
+ this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'senao');
1330
+ return this.executar(declaracao.caminhoSenao);
1331
+ }
1332
+ this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'falso');
1333
+ return null;
1334
+ }
1290
1335
  const atual = declaracaoCaminhosSeSenao[i];
1291
- if (this.eVerdadeiro(await this.avaliar(atual.condicao))) {
1336
+ return (0, encadear_1.encadear)(this.avaliar(atual.condicao), (condicaoAtual) => {
1337
+ if (this.eVerdadeiro(condicaoAtual)) {
1338
+ this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'verdadeiro');
1339
+ return this.executar(atual.caminho);
1340
+ }
1341
+ return proximoCaminhoSeSenao(i + 1);
1342
+ });
1343
+ };
1344
+ return (0, encadear_1.encadear)(this.avaliar(declaracao.condicao), (avaliacaoCondicaoSe) => {
1345
+ if (this.eVerdadeiro(avaliacaoCondicaoSe)) {
1292
1346
  this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'verdadeiro');
1293
- return await this.executar(atual.caminho);
1347
+ return this.executar(declaracao.caminhoEntao);
1294
1348
  }
1295
- }
1296
- if (declaracao.caminhoSenao) {
1297
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'senao');
1298
- return await this.executar(declaracao.caminhoSenao);
1299
- }
1300
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'falso');
1301
- return null;
1349
+ return proximoCaminhoSeSenao(0);
1350
+ });
1302
1351
  }
1303
1352
  async visitarDeclaracaoEnquanto(declaracao) {
1304
1353
  let retornoExecucao = undefined;
@@ -1473,10 +1522,7 @@ class InterpretadorBase {
1473
1522
  try {
1474
1523
  const formatoTexto = await this.avaliarArgumentosEscreva(declaracao.argumentos);
1475
1524
  this.funcaoDeRetornoMesmaLinha?.(formatoTexto);
1476
- return {
1477
- tipo: 'vazio',
1478
- tipoExplicito: false,
1479
- };
1525
+ return null;
1480
1526
  }
1481
1527
  catch (erro) {
1482
1528
  this.erros.push({
@@ -1496,10 +1542,7 @@ class InterpretadorBase {
1496
1542
  try {
1497
1543
  const formatoTexto = await this.avaliarArgumentosEscreva(declaracao.argumentos);
1498
1544
  this.funcaoDeRetorno?.(formatoTexto);
1499
- return {
1500
- tipo: 'vazio',
1501
- tipoExplicito: false,
1502
- };
1545
+ return null;
1503
1546
  }
1504
1547
  catch (erro) {
1505
1548
  this.erros.push({
@@ -1518,7 +1561,7 @@ class InterpretadorBase {
1518
1561
  * @param declaracoes Um vetor de declaracoes a ser executado.
1519
1562
  * @param ambiente O ambiente de execução quando houver, como parâmetros, argumentos, etc.
1520
1563
  */
1521
- async executarBloco(declaracoes, ambiente) {
1564
+ executarBloco(declaracoes, ambiente) {
1522
1565
  const escopoExecucao = {
1523
1566
  declaracoes: declaracoes,
1524
1567
  declaracaoAtual: 0,
@@ -1528,51 +1571,54 @@ class InterpretadorBase {
1528
1571
  emLacoRepeticao: false,
1529
1572
  };
1530
1573
  this.pilhaEscoposExecucao.empilhar(escopoExecucao);
1531
- const retornoUltimoEscopo = await this.executarUltimoEscopo();
1532
- if (retornoUltimoEscopo instanceof excecoes_1.ErroEmTempoDeExecucao) {
1533
- return Promise.reject(retornoUltimoEscopo);
1534
- }
1535
- return retornoUltimoEscopo;
1574
+ return (0, encadear_1.encadear)(this.executarUltimoEscopo(), (retornoUltimoEscopo) => {
1575
+ if (retornoUltimoEscopo instanceof excecoes_1.ErroEmTempoDeExecucao) {
1576
+ return Promise.reject(retornoUltimoEscopo);
1577
+ }
1578
+ return retornoUltimoEscopo;
1579
+ });
1536
1580
  }
1537
- async visitarExpressaoBloco(declaracao) {
1538
- return await this.executarBloco(declaracao.declaracoes);
1581
+ visitarExpressaoBloco(declaracao) {
1582
+ return this.executarBloco(declaracao.declaracoes);
1539
1583
  }
1540
- async avaliacaoDeclaracaoVarOuConst(declaracao) {
1541
- let valorOuOutraVariavel = null;
1542
- if (declaracao.inicializador != null) {
1543
- valorOuOutraVariavel = await this.avaliar(declaracao.inicializador);
1544
- }
1545
- let valorFinal = null;
1546
- if (valorOuOutraVariavel !== null && valorOuOutraVariavel !== undefined) {
1547
- valorFinal = this.resolverValor(valorOuOutraVariavel);
1584
+ avaliacaoDeclaracaoVarOuConst(declaracao) {
1585
+ if (declaracao.inicializador == null) {
1586
+ return null;
1548
1587
  }
1549
- return valorFinal;
1588
+ return (0, encadear_1.encadear)(this.avaliar(declaracao.inicializador), (valorOuOutraVariavel) => {
1589
+ if (valorOuOutraVariavel !== null && valorOuOutraVariavel !== undefined) {
1590
+ return this.resolverValor(valorOuOutraVariavel);
1591
+ }
1592
+ return null;
1593
+ });
1550
1594
  }
1551
1595
  /**
1552
1596
  * Executa expressão de definição de constante.
1553
1597
  * @param declaracao A declaração `Const`.
1554
1598
  * @returns Um descritor de informações importantes para o retorno externo.
1555
1599
  */
1556
- async visitarDeclaracaoConst(declaracao) {
1557
- const valorFinal = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1558
- this.pilhaEscoposExecucao.definirConstante(declaracao.simbolo.lexema, valorFinal, declaracao.tipo);
1559
- return {
1560
- tipo: declaracao.tipo,
1561
- tipoExplicito: declaracao.tipoExplicito,
1562
- };
1600
+ visitarDeclaracaoConst(declaracao) {
1601
+ return (0, encadear_1.encadear)(this.avaliacaoDeclaracaoVarOuConst(declaracao), (valorFinal) => {
1602
+ this.pilhaEscoposExecucao.definirConstante(declaracao.simbolo.lexema, valorFinal, declaracao.tipo);
1603
+ return {
1604
+ tipo: declaracao.tipo,
1605
+ tipoExplicito: declaracao.tipoExplicito,
1606
+ };
1607
+ });
1563
1608
  }
1564
1609
  /**
1565
1610
  * Executa expressão de definição de múltiplas constantes.
1566
1611
  * @param declaracao A declaração `ConstMultiplo`.
1567
1612
  * @returns Sempre retorna nulo.
1568
1613
  */
1569
- async visitarDeclaracaoConstMultiplo(declaracao) {
1570
- const valoresFinais = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1571
- const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
1572
- for (let [indice, valor] of valoresFinais.entries()) {
1573
- this.pilhaEscoposExecucao.definirConstante(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
1574
- }
1575
- return null;
1614
+ visitarDeclaracaoConstMultiplo(declaracao) {
1615
+ return (0, encadear_1.encadear)(this.avaliacaoDeclaracaoVarOuConst(declaracao), (valoresFinais) => {
1616
+ const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
1617
+ for (let [indice, valor] of valoresFinais.entries()) {
1618
+ this.pilhaEscoposExecucao.definirConstante(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
1619
+ }
1620
+ return null;
1621
+ });
1576
1622
  }
1577
1623
  visitarExpressaoContinua(_) {
1578
1624
  return new quebras_1.ContinuarQuebra();
@@ -1587,7 +1633,7 @@ class InterpretadorBase {
1587
1633
  return new quebras_1.RetornoQuebra(valor);
1588
1634
  }
1589
1635
  async visitarExpressaoFuncaoConstruto(funcaoConstruto) {
1590
- return new estruturas_1.DeleguaFuncao(null, funcaoConstruto);
1636
+ return new estruturas_1.DeleguaFuncao(null, funcaoConstruto).capturarEscopo(this.pilhaEscoposExecucao);
1591
1637
  }
1592
1638
  async visitarExpressaoAtribuicaoPorIndice(expressao) {
1593
1639
  const promises = await Promise.all([
@@ -1724,7 +1770,7 @@ class InterpretadorBase {
1724
1770
  }
1725
1771
  }
1726
1772
  async visitarDeclaracaoDefinicaoFuncao(declaracao) {
1727
- const funcao = new estruturas_1.DeleguaFuncao(declaracao.simbolo.lexema, declaracao.funcao);
1773
+ const funcao = new estruturas_1.DeleguaFuncao(declaracao.simbolo.lexema, declaracao.funcao).capturarEscopo(this.pilhaEscoposExecucao);
1728
1774
  funcao.documentacao = declaracao.documentacao;
1729
1775
  this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, funcao);
1730
1776
  this.pilhaEscoposExecucao.registrarReferenciaFuncao(declaracao.id, funcao);
@@ -1782,7 +1828,7 @@ class InterpretadorBase {
1782
1828
  for (const metodoAtual of declaracao.metodos) {
1783
1829
  const nomeMetodo = metodoAtual.simbolo.lexema;
1784
1830
  const eInicializador = nomeMetodo === 'construtor';
1785
- const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoAtual.funcao, undefined, eInicializador);
1831
+ const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoAtual.funcao, undefined, eInicializador).capturarEscopo(this.pilhaEscoposExecucao);
1786
1832
  funcao.documentacao = metodoAtual.documentacao;
1787
1833
  metodos[nomeMetodo] = funcao;
1788
1834
  }
@@ -1837,7 +1883,7 @@ class InterpretadorBase {
1837
1883
  const tipoNome = declaracao.simboloTipo.lexema;
1838
1884
  for (const metodoDeclarado of declaracao.metodos) {
1839
1885
  const nomeMetodo = metodoDeclarado.simbolo.lexema;
1840
- const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoDeclarado.funcao);
1886
+ const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoDeclarado.funcao).capturarEscopo(this.pilhaEscoposExecucao);
1841
1887
  if (declaracao.ehGlobal) {
1842
1888
  if (!this.extensoesGlobais.has(tipoNome)) {
1843
1889
  this.extensoesGlobais.set(tipoNome, new Map());
@@ -1986,30 +2032,32 @@ class InterpretadorBase {
1986
2032
  * @param declaracao A declaração Var
1987
2033
  * @returns Um descritor de informações importantes para o retorno externo.
1988
2034
  */
1989
- async visitarDeclaracaoVar(declaracao) {
1990
- const valorFinal = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1991
- let tipoResolvido = declaracao.tipo;
1992
- if (tipoResolvido.startsWith('função<')) {
1993
- tipoResolvido = tipoResolvido.replace('função<', '').replace('>', '');
1994
- }
1995
- if (!declaracao.tipoExplicito && tipoResolvido === delegua_2.default.QUALQUER && valorFinal instanceof Array) {
1996
- tipoResolvido = (0, inferenciador_1.inferirTipoVariavel)(valorFinal);
1997
- }
1998
- this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, valorFinal, tipoResolvido, declaracao.tipoExplicito && declaracao.tipoOriginal !== 'qualquer');
1999
- return null;
2035
+ visitarDeclaracaoVar(declaracao) {
2036
+ return (0, encadear_1.encadear)(this.avaliacaoDeclaracaoVarOuConst(declaracao), (valorFinal) => {
2037
+ let tipoResolvido = declaracao.tipo;
2038
+ if (tipoResolvido.startsWith('função<') && tipoResolvido.endsWith('>')) {
2039
+ tipoResolvido = tipoResolvido.slice('função<'.length, -1);
2040
+ }
2041
+ if (!declaracao.tipoExplicito && tipoResolvido === delegua_2.default.QUALQUER && valorFinal instanceof Array) {
2042
+ tipoResolvido = (0, inferenciador_1.inferirTipoVariavel)(valorFinal);
2043
+ }
2044
+ this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, valorFinal, tipoResolvido, declaracao.tipoExplicito && declaracao.tipoOriginal !== 'qualquer');
2045
+ return null;
2046
+ });
2000
2047
  }
2001
2048
  /**
2002
2049
  * Executa expressão de definição de múltiplas variáveis.
2003
2050
  * @param declaracao A declaração `VarMultiplo`.
2004
2051
  * @returns Sempre retorna nulo.
2005
2052
  */
2006
- async visitarDeclaracaoVarMultiplo(declaracao) {
2007
- const valoresFinais = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
2008
- const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
2009
- for (let [indice, valor] of valoresFinais.entries()) {
2010
- this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
2011
- }
2012
- return null;
2053
+ visitarDeclaracaoVarMultiplo(declaracao) {
2054
+ return (0, encadear_1.encadear)(this.avaliacaoDeclaracaoVarOuConst(declaracao), (valoresFinais) => {
2055
+ const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
2056
+ for (let [indice, valor] of valoresFinais.entries()) {
2057
+ this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
2058
+ }
2059
+ return null;
2060
+ });
2013
2061
  }
2014
2062
  /**
2015
2063
  * Formata uma string usando o operador % (similar ao Python).
@@ -2226,34 +2274,35 @@ class InterpretadorBase {
2226
2274
  * @returns O resultado parcial da execução, normalmente usado por
2227
2275
  * ferramentas externas.
2228
2276
  */
2229
- async executar(declaracao) {
2230
- const resultado = await declaracao.aceitar(this);
2231
- // Alguns casos não possuem retorno, como declarações `se`, `enquanto`, etc.,
2232
- // que não satisfazem suas respectivas condições.
2233
- if (resultado === null || resultado === undefined) {
2234
- return null;
2235
- }
2236
- // Se o retorno já possui um `valorRetornado`, apenas retorna o resultado.
2237
- if (resultado.hasOwnProperty('valorRetornado')) {
2238
- return resultado;
2239
- }
2240
- let tipoResultado = resultado.tipo;
2241
- switch (resultado.constructor) {
2242
- case estruturas_1.DescritorTipoClasse:
2243
- tipoResultado = resultado.simboloOriginal.lexema;
2244
- break;
2245
- default:
2246
- if (!tipoResultado) {
2247
- tipoResultado = (0, inferenciador_1.inferirTipoVariavel)(resultado);
2248
- }
2249
- break;
2250
- }
2251
- return {
2252
- hashArquivo: declaracao.hashArquivo,
2253
- linha: declaracao.linha,
2254
- valorRetornado: resultado,
2255
- tipo: tipoResultado,
2256
- };
2277
+ executar(declaracao) {
2278
+ return (0, encadear_1.encadear)(declaracao.aceitar(this), (resultado) => {
2279
+ // Alguns casos não possuem retorno, como declarações `se`, `enquanto`, etc.,
2280
+ // que não satisfazem suas respectivas condições.
2281
+ if (resultado === null || resultado === undefined) {
2282
+ return null;
2283
+ }
2284
+ // Se o retorno já possui um `valorRetornado`, apenas retorna o resultado.
2285
+ if (resultado.hasOwnProperty('valorRetornado')) {
2286
+ return resultado;
2287
+ }
2288
+ let tipoResultado = resultado.tipo;
2289
+ switch (resultado.constructor) {
2290
+ case estruturas_1.DescritorTipoClasse:
2291
+ tipoResultado = resultado.simboloOriginal.lexema;
2292
+ break;
2293
+ default:
2294
+ if (!tipoResultado) {
2295
+ tipoResultado = (0, inferenciador_1.inferirTipoVariavel)(resultado);
2296
+ }
2297
+ break;
2298
+ }
2299
+ return {
2300
+ hashArquivo: declaracao.hashArquivo,
2301
+ linha: declaracao.linha,
2302
+ valorRetornado: resultado,
2303
+ tipo: tipoResultado,
2304
+ };
2305
+ });
2257
2306
  }
2258
2307
  /**
2259
2308
  * Executa o último escopo empilhado no topo na pilha de escopos do interpretador.
@@ -2265,38 +2314,62 @@ class InterpretadorBase {
2265
2314
  * @param manterAmbiente Se verdadeiro, ambiente do topo da pilha de escopo é copiado para o ambiente imediatamente abaixo.
2266
2315
  * @returns O resultado da execução do escopo, se houver.
2267
2316
  */
2268
- async executarUltimoEscopo(manterAmbiente = false) {
2317
+ executarUltimoEscopo(manterAmbiente = false) {
2269
2318
  const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
2270
2319
  let retornoExecucao;
2271
- try {
2272
- for (; !(retornoExecucao && retornoExecucao.valorRetornado instanceof quebras_1.Quebra) &&
2273
- ultimoEscopo.declaracaoAtual < ultimoEscopo.declaracoes.length; ultimoEscopo.declaracaoAtual++) {
2274
- const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2275
- this.linhaDeclaracaoAtual = declaracaoAtual.linha;
2276
- this.hashArquivoDeclaracaoAtual = declaracaoAtual.hashArquivo;
2277
- retornoExecucao = await this.executar(declaracaoAtual);
2278
- }
2279
- return retornoExecucao;
2280
- }
2281
- catch (erro) {
2282
- const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2283
- if (!this.emDeclaracaoTente) {
2284
- this.erros.push({
2285
- erroInterno: erro,
2286
- linha: declaracaoAtual.linha,
2287
- hashArquivo: declaracaoAtual.hashArquivo,
2288
- });
2289
- }
2290
- else {
2291
- return Promise.reject(erro);
2292
- }
2293
- }
2294
- finally {
2320
+ // Substitui o `finally` original: precisa rodar em toda saída (sucesso, erro síncrono
2321
+ // ou rejeição assíncrona), então é chamado explicitamente em cada um desses três casos
2322
+ // abaixo, nunca implicitamente — não há `finally` de verdade quando não se usa `await`.
2323
+ const finalizar = () => {
2295
2324
  this.pilhaEscoposExecucao.removerUltimo();
2296
2325
  const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
2297
2326
  if (manterAmbiente || (retornoExecucao && retornoExecucao.preservarEscopo === true)) {
2298
2327
  escopoAnterior.espacoMemoria.valores = Object.assign(escopoAnterior.espacoMemoria.valores, ultimoEscopo.espacoMemoria.valores);
2299
2328
  }
2329
+ };
2330
+ const tratarErro = (erro) => {
2331
+ try {
2332
+ const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2333
+ if (!this.emDeclaracaoTente) {
2334
+ this.erros.push({
2335
+ erroInterno: erro,
2336
+ linha: declaracaoAtual.linha,
2337
+ hashArquivo: declaracaoAtual.hashArquivo,
2338
+ });
2339
+ return undefined;
2340
+ }
2341
+ return Promise.reject(erro);
2342
+ }
2343
+ finally {
2344
+ finalizar();
2345
+ }
2346
+ };
2347
+ const proximaDeclaracao = () => {
2348
+ if ((retornoExecucao && retornoExecucao.valorRetornado instanceof quebras_1.Quebra) ||
2349
+ ultimoEscopo.declaracaoAtual >= ultimoEscopo.declaracoes.length) {
2350
+ finalizar();
2351
+ return retornoExecucao;
2352
+ }
2353
+ const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2354
+ this.linhaDeclaracaoAtual = declaracaoAtual.linha;
2355
+ this.hashArquivoDeclaracaoAtual = declaracaoAtual.hashArquivo;
2356
+ return (0, encadear_1.encadear)(this.executar(declaracaoAtual), (resultado) => {
2357
+ retornoExecucao = resultado;
2358
+ ultimoEscopo.declaracaoAtual++;
2359
+ return proximaDeclaracao();
2360
+ });
2361
+ };
2362
+ try {
2363
+ const resultadoOuPromise = proximaDeclaracao();
2364
+ // Um throw síncrono em qualquer passo da recursão é pego pelo catch abaixo; um
2365
+ // erro que só aparece depois de a cadeia já ter virado uma Promise (algum passo
2366
+ // realmente assíncrono no meio) vira uma rejeição, pega aqui.
2367
+ return resultadoOuPromise instanceof Promise
2368
+ ? resultadoOuPromise.catch(tratarErro)
2369
+ : resultadoOuPromise;
2370
+ }
2371
+ catch (erro) {
2372
+ return tratarErro(erro);
2300
2373
  }
2301
2374
  }
2302
2375
  /**