@designliquido/delegua 1.27.1 → 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 (134) hide show
  1. package/avaliador-sintatico/avaliador-sintatico-base.d.ts.map +1 -1
  2. package/avaliador-sintatico/avaliador-sintatico-base.js +11 -0
  3. package/avaliador-sintatico/avaliador-sintatico-base.js.map +1 -1
  4. package/avaliador-sintatico/avaliador-sintatico.d.ts +1 -0
  5. package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
  6. package/avaliador-sintatico/avaliador-sintatico.js +30 -7
  7. package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
  8. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
  9. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js +0 -1
  10. package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
  11. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts.map +1 -1
  12. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js +0 -1
  13. package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js.map +1 -1
  14. package/bibliotecas/biblioteca-global.js +1 -1
  15. package/bibliotecas/biblioteca-global.js.map +1 -1
  16. package/bibliotecas/primitivas-vetor.d.ts.map +1 -1
  17. package/bibliotecas/primitivas-vetor.js +2 -1
  18. package/bibliotecas/primitivas-vetor.js.map +1 -1
  19. package/bin/package.json +3 -2
  20. package/construtos/agrupamento.d.ts +1 -1
  21. package/construtos/agrupamento.d.ts.map +1 -1
  22. package/construtos/agrupamento.js +2 -2
  23. package/construtos/agrupamento.js.map +1 -1
  24. package/construtos/atribuir.d.ts +1 -1
  25. package/construtos/atribuir.d.ts.map +1 -1
  26. package/construtos/atribuir.js +2 -2
  27. package/construtos/atribuir.js.map +1 -1
  28. package/construtos/binario.d.ts +1 -1
  29. package/construtos/binario.d.ts.map +1 -1
  30. package/construtos/binario.js +2 -2
  31. package/construtos/binario.js.map +1 -1
  32. package/construtos/literal.d.ts +1 -1
  33. package/construtos/literal.d.ts.map +1 -1
  34. package/construtos/literal.js +2 -2
  35. package/construtos/literal.js.map +1 -1
  36. package/construtos/logico.d.ts +1 -1
  37. package/construtos/logico.d.ts.map +1 -1
  38. package/construtos/logico.js +2 -2
  39. package/construtos/logico.js.map +1 -1
  40. package/construtos/para-como-construto.d.ts +2 -1
  41. package/construtos/para-como-construto.d.ts.map +1 -1
  42. package/construtos/para-como-construto.js +2 -1
  43. package/construtos/para-como-construto.js.map +1 -1
  44. package/construtos/unario.d.ts +1 -1
  45. package/construtos/unario.d.ts.map +1 -1
  46. package/construtos/unario.js +2 -2
  47. package/construtos/unario.js.map +1 -1
  48. package/construtos/variavel.d.ts +2 -2
  49. package/construtos/variavel.d.ts.map +1 -1
  50. package/construtos/variavel.js +2 -2
  51. package/construtos/variavel.js.map +1 -1
  52. package/declaracoes/para.d.ts +2 -1
  53. package/declaracoes/para.d.ts.map +1 -1
  54. package/declaracoes/para.js +2 -1
  55. package/declaracoes/para.js.map +1 -1
  56. package/formatadores/formatador-delegua.d.ts.map +1 -1
  57. package/formatadores/formatador-delegua.js +11 -7
  58. package/formatadores/formatador-delegua.js.map +1 -1
  59. package/formatadores/formatador-pitugues.d.ts.map +1 -1
  60. package/formatadores/formatador-pitugues.js +2 -1
  61. package/formatadores/formatador-pitugues.js.map +1 -1
  62. package/interfaces/construtos/construto-interface.d.ts +6 -1
  63. package/interfaces/construtos/construto-interface.d.ts.map +1 -1
  64. package/interfaces/delegua/para-interface.d.ts +7 -0
  65. package/interfaces/delegua/para-interface.d.ts.map +1 -1
  66. package/interfaces/interpretador-interface.d.ts +13 -1
  67. package/interfaces/interpretador-interface.d.ts.map +1 -1
  68. package/interfaces/parametro-interface.d.ts +4 -0
  69. package/interfaces/parametro-interface.d.ts.map +1 -1
  70. package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts +1 -0
  71. package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts.map +1 -1
  72. package/interpretador/depuracao/interpretador-base-com-depuracao.js +1 -0
  73. package/interpretador/depuracao/interpretador-base-com-depuracao.js.map +1 -1
  74. package/interpretador/depuracao/interpretador-com-depuracao.d.ts +1 -0
  75. package/interpretador/depuracao/interpretador-com-depuracao.d.ts.map +1 -1
  76. package/interpretador/depuracao/interpretador-com-depuracao.js +1 -0
  77. package/interpretador/depuracao/interpretador-com-depuracao.js.map +1 -1
  78. package/interpretador/dialetos/calango/interpretador-calango.d.ts +1 -1
  79. package/interpretador/dialetos/calango/interpretador-calango.d.ts.map +1 -1
  80. package/interpretador/dialetos/calango/interpretador-calango.js +14 -10
  81. package/interpretador/dialetos/calango/interpretador-calango.js.map +1 -1
  82. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.d.ts.map +1 -1
  83. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js +3 -3
  84. package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js.map +1 -1
  85. package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts +1 -1
  86. package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts.map +1 -1
  87. package/interpretador/dialetos/pitugues/interpretador-pitugues.js +8 -6
  88. package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
  89. package/interpretador/dialetos/prisma/interpretador-prisma.d.ts +2 -2
  90. package/interpretador/dialetos/prisma/interpretador-prisma.d.ts.map +1 -1
  91. package/interpretador/dialetos/prisma/interpretador-prisma.js +26 -19
  92. package/interpretador/dialetos/prisma/interpretador-prisma.js.map +1 -1
  93. package/interpretador/encadear.d.ts +36 -0
  94. package/interpretador/encadear.d.ts.map +1 -0
  95. package/interpretador/encadear.js +43 -0
  96. package/interpretador/encadear.js.map +1 -0
  97. package/interpretador/estruturas/delegua-funcao.d.ts +25 -0
  98. package/interpretador/estruturas/delegua-funcao.d.ts.map +1 -1
  99. package/interpretador/estruturas/delegua-funcao.js +137 -24
  100. package/interpretador/estruturas/delegua-funcao.js.map +1 -1
  101. package/interpretador/interpretador-base.d.ts +34 -22
  102. package/interpretador/interpretador-base.d.ts.map +1 -1
  103. package/interpretador/interpretador-base.js +634 -558
  104. package/interpretador/interpretador-base.js.map +1 -1
  105. package/interpretador/interpretador.d.ts +8 -11
  106. package/interpretador/interpretador.d.ts.map +1 -1
  107. package/interpretador/interpretador.js +173 -116
  108. package/interpretador/interpretador.js.map +1 -1
  109. package/lexador/dialetos/lexador-pitugues.d.ts.map +1 -1
  110. package/lexador/dialetos/lexador-pitugues.js +0 -1
  111. package/lexador/dialetos/lexador-pitugues.js.map +1 -1
  112. package/lexador/dialetos/lexador-portugol-ipt.d.ts.map +1 -1
  113. package/lexador/dialetos/lexador-portugol-ipt.js +3 -2
  114. package/lexador/dialetos/lexador-portugol-ipt.js.map +1 -1
  115. package/lexador/dialetos/lexador-tenda.d.ts.map +1 -1
  116. package/lexador/dialetos/lexador-tenda.js +0 -1
  117. package/lexador/dialetos/lexador-tenda.js.map +1 -1
  118. package/lexador/lexador-base-linha-unica.d.ts.map +1 -1
  119. package/lexador/lexador-base-linha-unica.js +3 -2
  120. package/lexador/lexador-base-linha-unica.js.map +1 -1
  121. package/lexador/lexador-base.d.ts.map +1 -1
  122. package/lexador/lexador-base.js +9 -2
  123. package/lexador/lexador-base.js.map +1 -1
  124. package/lexador/lexador.d.ts.map +1 -1
  125. package/lexador/lexador.js +3 -3
  126. package/lexador/lexador.js.map +1 -1
  127. package/lexador/micro-lexador-pitugues.d.ts.map +1 -1
  128. package/lexador/micro-lexador-pitugues.js +3 -2
  129. package/lexador/micro-lexador-pitugues.js.map +1 -1
  130. package/lexador/micro-lexador.d.ts.map +1 -1
  131. package/lexador/micro-lexador.js +3 -2
  132. package/lexador/micro-lexador.js.map +1 -1
  133. package/package.json +3 -2
  134. package/umd/delegua.js +1481 -1120
@@ -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,18 +445,22 @@ 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
- if (objeto === null)
457
+ if (objeto === null || objeto === undefined)
455
458
  return false;
456
459
  if (typeof objeto === primitivos_1.default.BOOLEANO)
457
460
  return Boolean(objeto);
461
+ if (typeof objeto === primitivos_1.default.NUMERO || typeof objeto === 'bigint') {
462
+ return Boolean(objeto);
463
+ }
458
464
  if (objeto.hasOwnProperty('valor')) {
459
465
  return Boolean(objeto.valor);
460
466
  }
@@ -466,63 +472,87 @@ class InterpretadorBase {
466
472
  return;
467
473
  throw new excecoes_1.ErroEmTempoDeExecucao(operador, 'Operando precisa ser um número.', Number(operador.linha));
468
474
  }
469
- async visitarExpressaoUnaria(expressao) {
470
- const operando = await this.avaliar(expressao.operando);
471
- let valor = this.resolverValor(operando);
472
- switch (expressao.operador.tipo) {
473
- case delegua_1.default.ADICAO:
474
- this.verificarOperandoNumero(expressao.operador, valor);
475
- return +valor;
476
- case delegua_1.default.SUBTRACAO:
477
- this.verificarOperandoNumero(expressao.operador, valor);
478
- return -valor;
479
- case delegua_1.default.NEGACAO:
480
- case delegua_1.default.NAO:
481
- return !this.eVerdadeiro(valor);
482
- case delegua_1.default.BIT_NOT:
483
- if (typeof valor === 'bigint') {
484
- return ~valor;
485
- }
486
- this.verificarOperandoNumero(expressao.operador, valor);
487
- return ~Number(valor);
488
- // Para incrementar e decrementar, primeiro precisamos saber se o operador
489
- // veio antes do literal ou variável.
490
- // Se veio antes e o operando é uma variável, precisamos incrementar/decrementar,
491
- // armazenar o valor da variável pra só então devolver o valor.
492
- case delegua_1.default.INCREMENTAR:
493
- if (typeof valor === 'string') {
494
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
495
- }
496
- if (expressao.incidenciaOperador === 'ANTES') {
497
- valor++;
498
- if (expressao.operando instanceof construtos_1.Variavel) {
499
- 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;
500
502
  }
501
- return valor;
502
- }
503
- const valorAnteriorIncremento = valor;
504
- if (expressao.operando instanceof construtos_1.Variavel) {
505
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, ++valor);
506
- }
507
- return valorAnteriorIncremento;
508
- case delegua_1.default.DECREMENTAR:
509
- if (typeof valor === 'string') {
510
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, `Operador '${expressao.operador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
511
- }
512
- if (expressao.incidenciaOperador === 'ANTES') {
513
- valor--;
514
- if (expressao.operando instanceof construtos_1.Variavel) {
515
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, valor);
503
+ else if (entidade && typeof entidade === 'object') {
504
+ entidade[indice] = valor;
516
505
  }
517
506
  return valor;
518
- }
519
- const valorAnteriorDecremento = valor;
520
- if (expressao.operando instanceof construtos_1.Variavel) {
521
- this.pilhaEscoposExecucao.atribuirVariavel(expressao.operando.simbolo, --valor);
522
- }
523
- return valorAnteriorDecremento;
507
+ });
508
+ });
524
509
  }
525
- 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
+ });
526
556
  }
527
557
  /**
528
558
  * Formata uma saída de acordo com o número e espaços e casas decimais solicitados.
@@ -601,270 +631,276 @@ class InterpretadorBase {
601
631
  return;
602
632
  if (this.tiposNumericos.includes(tipoDireita) && tipoEsquerda === 'nulo')
603
633
  return;
604
- // Se operador é subtração, os dois tipos são `qualquer`, mas ambos podem ser convertidos
605
- // para número, a operação é válida.
606
- if (operador.tipo === delegua_1.default.SUBTRACAO) {
607
- if (typeof esquerda.valor === 'number' && typeof direita.valor === 'number') {
608
- return;
609
- }
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;
610
644
  }
611
645
  throw new excecoes_1.ErroEmTempoDeExecucao(operador, 'Operadores precisam ser números.', operador.linha);
612
646
  }
613
647
  converterParaBigInt(valor) {
614
648
  return typeof valor === 'bigint' ? valor : BigInt(Math.floor(Number(valor)));
615
649
  }
616
- async visitarExpressaoBinaria(expressao) {
617
- const esquerda = await this.avaliar(expressao.esquerda);
618
- const direita = await this.avaliar(expressao.direita);
619
- const valorEsquerdo = this.resolverValor(esquerda);
620
- const valorDireito = this.resolverValor(direita);
621
- // Verificar sobrecarga de operador: se o operando esquerdo é uma instância de classe,
622
- // procurar método `operador<símbolo>` (ex: `operador+`, `operador==`).
623
- if (valorEsquerdo instanceof estruturas_1.ObjetoDeleguaClasse) {
624
- const nomeOperador = 'operador' + expressao.operador.lexema;
625
- const metodoOperador = valorEsquerdo.classe.encontrarMetodo(nomeOperador);
626
- if (metodoOperador) {
627
- const metodoASerChamado = metodoOperador.funcaoPorMetodoDeClasse(valorEsquerdo);
628
- const argumentoOperador = direita && Object.prototype.hasOwnProperty.call(direita, 'tipo')
629
- ? direita
630
- : {
631
- tipo: (0, inferenciador_1.inferirTipoVariavel)(valorDireito),
632
- valor: valorDireito,
633
- imutavel: false,
634
- };
635
- return await metodoASerChamado.chamar(this, [
636
- { nome: null, valor: argumentoOperador },
637
- ]);
638
- }
639
- }
640
- const tipoEsquerdo = esquerda?.hasOwnProperty('tipo')
641
- ? esquerda.tipo
642
- : (0, inferenciador_1.inferirTipoVariavel)(esquerda);
643
- const tipoDireito = direita?.hasOwnProperty('tipo')
644
- ? direita.tipo
645
- : (0, inferenciador_1.inferirTipoVariavel)(direita);
646
- switch (expressao.operador.tipo) {
647
- case delegua_1.default.EXPONENCIACAO:
648
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
649
- // Auto-promove para BigInt se qualquer operando for BigInt
650
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
651
- return (this.converterParaBigInt(valorEsquerdo) **
652
- this.converterParaBigInt(valorDireito));
653
- }
654
- const resultadoExponenciacao = Math.pow(valorEsquerdo, valorDireito);
655
- return resultadoExponenciacao;
656
- case delegua_1.default.MAIOR:
657
- if (typeof valorEsquerdo === 'string' &&
658
- typeof valorDireito === 'string') {
659
- return valorEsquerdo > valorDireito;
660
- }
661
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
662
- return Number(valorEsquerdo) > Number(valorDireito);
663
- case delegua_1.default.MAIOR_IGUAL:
664
- if (typeof valorEsquerdo === 'string' &&
665
- typeof valorDireito === 'string') {
666
- return valorEsquerdo >= valorDireito;
667
- }
668
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
669
- return Number(valorEsquerdo) >= Number(valorDireito);
670
- case delegua_1.default.MENOR:
671
- if (typeof valorEsquerdo === 'string' &&
672
- typeof valorDireito === 'string') {
673
- return valorEsquerdo < valorDireito;
674
- }
675
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
676
- return Number(valorEsquerdo) < Number(valorDireito);
677
- case delegua_1.default.MENOR_IGUAL:
678
- if (typeof valorEsquerdo === 'string' &&
679
- typeof valorDireito === 'string') {
680
- return valorEsquerdo <= valorDireito;
681
- }
682
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
683
- return Number(valorEsquerdo) <= Number(valorDireito);
684
- case delegua_1.default.SUBTRACAO:
685
- case delegua_1.default.MENOS_IGUAL:
686
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
687
- // Auto-promove para BigInt se qualquer operando for BigInt
688
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
689
- return (this.converterParaBigInt(valorEsquerdo) -
690
- this.converterParaBigInt(valorDireito));
691
- }
692
- return Number(valorEsquerdo) - Number(valorDireito);
693
- case delegua_1.default.ADICAO:
694
- case delegua_1.default.MAIS_IGUAL:
695
- // Se ambos os operandos são vetores, concatená-los
696
- if (Array.isArray(valorEsquerdo) && Array.isArray(valorDireito)) {
697
- return valorEsquerdo.concat(valorDireito);
698
- }
699
- // Se ambos os operandos são dicionários, mescla-os.
700
- // Em caso de chaves duplicadas, valores à direita sobrescrevem os da esquerda.
701
- if (valorEsquerdo &&
702
- valorDireito &&
703
- !Array.isArray(valorEsquerdo) &&
704
- !Array.isArray(valorDireito) &&
705
- valorEsquerdo.constructor === Object &&
706
- valorDireito.constructor === Object) {
707
- return Object.assign({}, valorEsquerdo, valorDireito);
708
- }
709
- // Auto-promove para BigInt se qualquer operando for BigInt
710
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
711
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
712
- ? valorEsquerdo
713
- : BigInt(Math.floor(Number(valorEsquerdo)));
714
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
715
- ? valorDireito
716
- : BigInt(Math.floor(Number(valorDireito)));
717
- return valorResolvidoEsquerdo + valorResolvidoDireito;
718
- }
719
- if (this.tiposNumericos.includes(tipoEsquerdo) &&
720
- this.tiposNumericos.includes(tipoDireito)) {
721
- return Number(valorEsquerdo) + Number(valorDireito);
722
- }
723
- 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
+ }
724
766
  return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
725
- }
726
- // Para tipos 'qualquer', delegamos ao operador nativo do JavaScript,
727
- // que resolve concatenação ou soma dependendo dos valores em tempo de execução.
728
- if (tipoEsquerdo === 'qualquer' || tipoDireito === 'qualquer') {
729
- return valorEsquerdo + valorDireito;
730
- }
731
- return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
732
- case delegua_1.default.DIVISAO:
733
- case delegua_1.default.DIVISAO_IGUAL:
734
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
735
- if (this.lancarErroPorDivisaoPorZero && Number(valorDireito) === 0) {
736
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
737
- }
738
- // SEMPRE retorna Number para precisão decimal (preferência do usuário)
739
- // Mesmo se operandos forem BigInt, converte para Number
740
- return Number(valorEsquerdo) / Number(valorDireito);
741
- case delegua_1.default.DIVISAO_INTEIRA:
742
- case delegua_1.default.DIVISAO_INTEIRA_IGUAL:
743
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
744
- if (this.lancarErroPorDivisaoPorZero && valorDireito === 0) {
745
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.operador, 'Divisão por zero não é permitida.', expressao.operador.linha);
746
- }
747
- // Retorna BigInt se qualquer operando for BigInt
748
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
749
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
750
- ? valorEsquerdo
751
- : BigInt(Math.floor(Number(valorEsquerdo)));
752
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
753
- ? valorDireito
754
- : BigInt(Math.floor(Number(valorDireito)));
755
- return valorResolvidoEsquerdo / valorResolvidoDireito; // Trunca automaticamente
756
- }
757
- return Math.floor(Number(valorEsquerdo) / Number(valorDireito));
758
- case delegua_1.default.MULTIPLICACAO:
759
- case delegua_1.default.MULTIPLICACAO_IGUAL:
760
- // Auto-promove para BigInt se qualquer operando for BigInt (e não for texto)
761
- if ((typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') &&
762
- tipoEsquerdo !== delegua_2.default.TEXTO &&
763
- tipoDireito !== delegua_2.default.TEXTO) {
764
- const valorResolvidoEsquerdo = typeof valorEsquerdo === 'bigint'
765
- ? valorEsquerdo
766
- : BigInt(Math.floor(Number(valorEsquerdo)));
767
- const valorResolvidoDireito = typeof valorDireito === 'bigint'
768
- ? valorDireito
769
- : BigInt(Math.floor(Number(valorDireito)));
770
- return valorResolvidoEsquerdo * valorResolvidoDireito;
771
- }
772
- if (tipoEsquerdo === delegua_2.default.TEXTO ||
773
- tipoDireito === delegua_2.default.TEXTO) {
774
- // Sem ambos os valores resolvem como texto, multiplica normal.
775
- // Se apenas um resolve como texto, o outro repete o
776
- // texto n vezes, sendo n o valor do outro.
777
- 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 ||
778
808
  tipoDireito === delegua_2.default.TEXTO) {
779
- 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);
780
832
  }
781
- const valorTexto = tipoEsquerdo === delegua_2.default.TEXTO ? valorEsquerdo : valorDireito;
782
- const valorQuantidade = tipoEsquerdo === delegua_2.default.TEXTO ? valorDireito : valorEsquerdo;
783
- if (typeof valorQuantidade !== 'number') {
784
- 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);
785
841
  }
786
- const textoParaNumero = Number(valorTexto);
787
- if (!isNaN(textoParaNumero)) {
788
- 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;
789
848
  }
790
- if (!Number.isInteger(valorQuantidade)) {
791
- 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));
792
854
  }
793
- if (valorQuantidade < 0) {
794
- 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;
795
859
  }
796
- return valorTexto.repeat(valorQuantidade);
797
- }
798
- return Number(valorEsquerdo) * Number(valorDireito);
799
- case delegua_1.default.MODULO:
800
- case delegua_1.default.MODULO_IGUAL:
801
- // Se o operando esquerdo é uma string, usar formatação de string
802
- if (tipoEsquerdo === delegua_2.default.TEXTO ||
803
- typeof valorEsquerdo === 'string') {
804
- return this.formatarStringComOperadorPorcentagem(String(valorEsquerdo), direita, // Passar 'direita' ao invés de 'valorDireito' para preservar arrays de tuplas
805
- expressao.operador);
806
- }
807
- // Caso contrário, operação matemática normal
808
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
809
- return Number(valorEsquerdo) % Number(valorDireito);
810
- case delegua_1.default.BIT_AND:
811
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
812
- return valorEsquerdo && valorDireito;
813
- }
814
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
815
- // Auto-promove para BigInt se qualquer operando for BigInt
816
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
817
- return (this.converterParaBigInt(valorEsquerdo) &
818
- this.converterParaBigInt(valorDireito));
819
- }
820
- return Number(valorEsquerdo) & Number(valorDireito);
821
- case delegua_1.default.CIRCUMFLEXO:
822
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
823
- return valorEsquerdo !== valorDireito;
824
- }
825
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
826
- // Auto-promove para BigInt se qualquer operando for BigInt
827
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
828
- return (this.converterParaBigInt(valorEsquerdo) ^
829
- this.converterParaBigInt(valorDireito));
830
- }
831
- return Number(valorEsquerdo) ^ Number(valorDireito);
832
- case delegua_1.default.BIT_OR:
833
- if (typeof valorEsquerdo === 'boolean' && typeof valorDireito === 'boolean') {
834
- return valorEsquerdo || valorDireito;
835
- }
836
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
837
- // Auto-promove para BigInt se qualquer operando for BigInt
838
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
839
- return (this.converterParaBigInt(valorEsquerdo) |
840
- this.converterParaBigInt(valorDireito));
841
- }
842
- return Number(valorEsquerdo) | Number(valorDireito);
843
- case delegua_1.default.MENOR_MENOR:
844
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
845
- // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
846
- if (typeof valorEsquerdo === 'bigint' ||
847
- typeof valorDireito === 'bigint' ||
848
- Number(valorDireito) >= 32) {
849
- return (this.converterParaBigInt(valorEsquerdo) <<
850
- this.converterParaBigInt(valorDireito));
851
- }
852
- return Number(valorEsquerdo) << Number(valorDireito);
853
- case delegua_1.default.MAIOR_MAIOR:
854
- this.verificarOperandosNumeros(expressao.operador, esquerda, direita);
855
- // Auto-promove para BigInt (interno para longo) se qualquer operando for BigInt ou se deslocamento >= 32
856
- if (typeof valorEsquerdo === 'bigint' ||
857
- typeof valorDireito === 'bigint' ||
858
- Number(valorDireito) >= 32) {
859
- return (this.converterParaBigInt(valorEsquerdo) >>
860
- this.converterParaBigInt(valorDireito));
861
- }
862
- return Number(valorEsquerdo) >> Number(valorDireito);
863
- case delegua_1.default.DIFERENTE:
864
- return !this.eIgual(valorEsquerdo, valorDireito);
865
- case delegua_1.default.IGUAL_IGUAL:
866
- return this.eIgual(valorEsquerdo, valorDireito);
867
- }
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
+ }));
868
904
  }
869
905
  /**
870
906
  * Faz a chamada do método de uma primitiva (por exemplo, número, texto, etc.) com seus
@@ -916,7 +952,7 @@ class InterpretadorBase {
916
952
  let entidadeChamada = this.resolverValor(variavelEntidadeChamada);
917
953
  // Funções anônimas
918
954
  if (entidadeChamada instanceof construtos_1.FuncaoConstruto) {
919
- entidadeChamada = new estruturas_1.DeleguaFuncao(null, entidadeChamada);
955
+ entidadeChamada = new estruturas_1.DeleguaFuncao(null, entidadeChamada).capturarEscopo(this.pilhaEscoposExecucao);
920
956
  }
921
957
  if (entidadeChamada instanceof estruturas_1.DeleguaModulo) {
922
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));
@@ -1038,57 +1074,63 @@ class InterpretadorBase {
1038
1074
  * @param expressao A expressão.
1039
1075
  * @returns O valor atribuído.
1040
1076
  */
1041
- async visitarExpressaoDeAtribuicao(expressao) {
1042
- let valor = await this.avaliar(expressao.valor);
1043
- if (valor && valor.hasOwnProperty('valorRetornado')) {
1044
- valor = valor.valorRetornado;
1045
- }
1046
- const valorResolvido = this.resolverValor(valor);
1047
- let indice = null;
1048
- if (expressao.indice) {
1049
- indice = this.resolverValor(await this.avaliar(expressao.indice));
1050
- }
1051
- switch (expressao.alvo.constructor) {
1052
- case construtos_1.AcessoMetodoOuPropriedade:
1053
- const alvoPropriedade = expressao.alvo;
1054
- const variavelObjeto = await this.avaliar(alvoPropriedade.objeto);
1055
- const objeto = this.resolverValor(variavelObjeto);
1056
- const valorProp = await this.avaliar(expressao.valor);
1057
- await this.definirPropriedadeObjeto(objeto, alvoPropriedade.simbolo, valorProp);
1058
- break;
1059
- case construtos_1.Variavel:
1060
- const alvoVariavel = expressao.alvo;
1061
- if (expressao.simboloOperador) {
1062
- let valorAtual;
1063
- valorAtual = this.resolverValor(this.pilhaEscoposExecucao.obterValorVariavel(alvoVariavel.simbolo));
1064
- if (typeof valorAtual === 'string') {
1065
- let valorDireito;
1066
- if (expressao.valor instanceof construtos_1.Binario) {
1067
- valorDireito = this.resolverValor(await this.avaliar(expressao.valor.direita));
1068
- }
1069
- else {
1070
- valorDireito = valorResolvido;
1071
- }
1072
- if (expressao.simboloOperador.tipo === delegua_1.default.MAIS_IGUAL) {
1073
- if (typeof valorDireito !== 'string') {
1074
- 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);
1075
1121
  }
1076
1122
  }
1077
- else if ([delegua_1.default.MENOS_IGUAL,
1078
- delegua_1.default.MULTIPLICACAO_IGUAL,
1079
- delegua_1.default.DIVISAO_IGUAL,
1080
- delegua_1.default.MODULO_IGUAL]
1081
- .includes(expressao.simboloOperador.tipo)) {
1082
- throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloOperador, `Operador '${expressao.simboloOperador.lexema}' não pode ser aplicado a um texto.`, expressao.linha);
1083
- }
1123
+ return finalizarAtribuicaoVariavel();
1084
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.");
1085
1127
  }
1086
- this.atribuirVariavel(alvoVariavel, valorResolvido, indice);
1087
- break;
1088
- default:
1089
- 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.");
1090
- }
1091
- 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
+ });
1092
1134
  }
1093
1135
  procurarVariavel(simbolo) {
1094
1136
  return this.pilhaEscoposExecucao.obterValorVariavel(simbolo);
@@ -1096,8 +1138,8 @@ class InterpretadorBase {
1096
1138
  visitarExpressaoDeVariavel(expressao) {
1097
1139
  return this.procurarVariavel(expressao.simbolo);
1098
1140
  }
1099
- async visitarDeclaracaoDeExpressao(declaracao) {
1100
- return await this.avaliar(declaracao.expressao);
1141
+ visitarDeclaracaoDeExpressao(declaracao) {
1142
+ return this.avaliar(declaracao.expressao);
1101
1143
  }
1102
1144
  logicaContemOuEm(esquerda, direita, expressao) {
1103
1145
  const valorEsquerdoResolvido = this.resolverValor(esquerda);
@@ -1113,66 +1155,69 @@ class InterpretadorBase {
1113
1155
  }
1114
1156
  throw new excecoes_1.ErroEmTempoDeExecucao(esquerda, `Tipo de chamada inválida com '${expressao.operador.tipo}'.`, expressao.linha);
1115
1157
  }
1116
- async visitarExpressaoLogica(expressao) {
1117
- const esquerda = await this.avaliar(expressao.esquerda);
1118
- if ([delegua_1.default.EM, delegua_1.default.CONTEM].includes(expressao.operador.tipo)) {
1119
- const direita = await this.avaliar(expressao.direita);
1120
- // `3 em lista` é igual a `lista contém 3`.
1121
- // Portanto, precisamos inverter os operandos de acordo com a
1122
- // palavra reservada usada.
1123
- switch (expressao.operador.tipo) {
1124
- case delegua_1.default.EM:
1125
- return this.logicaContemOuEm(esquerda, direita, expressao);
1126
- case delegua_1.default.CONTEM:
1127
- return this.logicaContemOuEm(direita, esquerda, expressao);
1128
- }
1129
- }
1130
- // E/OU como bitwise quando ambos operandos são numéricos
1131
- if ([delegua_1.default.E, delegua_1.default.OU].includes(expressao.operador.tipo)) {
1132
- const valorEsquerdo = this.resolverValor(esquerda);
1133
- if (typeof valorEsquerdo === 'number' || typeof valorEsquerdo === 'bigint') {
1134
- const direita = await this.avaliar(expressao.direita);
1135
- const valorDireito = this.resolverValor(direita);
1136
- if (typeof valorDireito === 'number' || typeof valorDireito === 'bigint') {
1137
- if (typeof valorEsquerdo === 'bigint' || typeof valorDireito === 'bigint') {
1138
- const esq = typeof valorEsquerdo === 'bigint'
1139
- ? valorEsquerdo
1140
- : BigInt(Math.floor(Number(valorEsquerdo)));
1141
- const dir = typeof valorDireito === 'bigint'
1142
- ? valorDireito
1143
- : BigInt(Math.floor(Number(valorDireito)));
1144
- return expressao.operador.tipo === delegua_1.default.E
1145
- ? esq & dir
1146
- : 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);
1147
1170
  }
1148
- return expressao.operador.tipo === delegua_1.default.E
1149
- ? Number(valorEsquerdo) & Number(valorDireito)
1150
- : Number(valorEsquerdo) | Number(valorDireito);
1151
- }
1152
- // Demais casos sem diferença de tipos
1153
- if (expressao.operador.tipo === delegua_1.default.OU) {
1154
- if (this.eVerdadeiro(esquerda))
1155
- return esquerda;
1156
- return direita;
1157
- }
1158
- if (expressao.operador.tipo === delegua_1.default.E) {
1159
- if (!this.eVerdadeiro(esquerda))
1160
- return esquerda;
1161
- 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
+ });
1162
1207
  }
1163
1208
  }
1164
- }
1165
- // se um estado for verdadeiro, retorna verdadeiro
1166
- if (expressao.operador.tipo === delegua_1.default.OU) {
1167
- if (this.eVerdadeiro(esquerda))
1168
- return esquerda;
1169
- }
1170
- // se um estado for falso, retorna falso
1171
- if (expressao.operador.tipo === delegua_1.default.E) {
1172
- if (!this.eVerdadeiro(esquerda))
1173
- return esquerda;
1174
- }
1175
- 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
+ });
1176
1221
  }
1177
1222
  async visitarDeclaracaoPara(declaracao) {
1178
1223
  const declaracaoInicializador = Array.isArray(declaracao.inicializador)
@@ -1276,26 +1321,33 @@ class InterpretadorBase {
1276
1321
  * @param declaracao A declaração Se.
1277
1322
  * @returns O resultado da avaliação do bloco cuja condição é verdadeira.
1278
1323
  */
1279
- async visitarDeclaracaoSe(declaracao) {
1280
- const avaliacaoCondicaoSe = await this.avaliar(declaracao.condicao);
1281
- if (this.eVerdadeiro(avaliacaoCondicaoSe)) {
1282
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'verdadeiro');
1283
- return await this.executar(declaracao.caminhoEntao);
1284
- }
1324
+ visitarDeclaracaoSe(declaracao) {
1285
1325
  const declaracaoCaminhosSeSenao = declaracao.caminhosSeSenao || [];
1286
- 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
+ }
1287
1335
  const atual = declaracaoCaminhosSeSenao[i];
1288
- 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)) {
1289
1346
  this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'verdadeiro');
1290
- return await this.executar(atual.caminho);
1347
+ return this.executar(declaracao.caminhoEntao);
1291
1348
  }
1292
- }
1293
- if (declaracao.caminhoSenao) {
1294
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'senao');
1295
- return await this.executar(declaracao.caminhoSenao);
1296
- }
1297
- this.registrarRamo?.(declaracao.hashArquivo, declaracao.linha, 'falso');
1298
- return null;
1349
+ return proximoCaminhoSeSenao(0);
1350
+ });
1299
1351
  }
1300
1352
  async visitarDeclaracaoEnquanto(declaracao) {
1301
1353
  let retornoExecucao = undefined;
@@ -1470,10 +1522,7 @@ class InterpretadorBase {
1470
1522
  try {
1471
1523
  const formatoTexto = await this.avaliarArgumentosEscreva(declaracao.argumentos);
1472
1524
  this.funcaoDeRetornoMesmaLinha?.(formatoTexto);
1473
- return {
1474
- tipo: 'vazio',
1475
- tipoExplicito: false,
1476
- };
1525
+ return null;
1477
1526
  }
1478
1527
  catch (erro) {
1479
1528
  this.erros.push({
@@ -1493,10 +1542,7 @@ class InterpretadorBase {
1493
1542
  try {
1494
1543
  const formatoTexto = await this.avaliarArgumentosEscreva(declaracao.argumentos);
1495
1544
  this.funcaoDeRetorno?.(formatoTexto);
1496
- return {
1497
- tipo: 'vazio',
1498
- tipoExplicito: false,
1499
- };
1545
+ return null;
1500
1546
  }
1501
1547
  catch (erro) {
1502
1548
  this.erros.push({
@@ -1515,7 +1561,7 @@ class InterpretadorBase {
1515
1561
  * @param declaracoes Um vetor de declaracoes a ser executado.
1516
1562
  * @param ambiente O ambiente de execução quando houver, como parâmetros, argumentos, etc.
1517
1563
  */
1518
- async executarBloco(declaracoes, ambiente) {
1564
+ executarBloco(declaracoes, ambiente) {
1519
1565
  const escopoExecucao = {
1520
1566
  declaracoes: declaracoes,
1521
1567
  declaracaoAtual: 0,
@@ -1525,51 +1571,54 @@ class InterpretadorBase {
1525
1571
  emLacoRepeticao: false,
1526
1572
  };
1527
1573
  this.pilhaEscoposExecucao.empilhar(escopoExecucao);
1528
- const retornoUltimoEscopo = await this.executarUltimoEscopo();
1529
- if (retornoUltimoEscopo instanceof excecoes_1.ErroEmTempoDeExecucao) {
1530
- return Promise.reject(retornoUltimoEscopo);
1531
- }
1532
- 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
+ });
1533
1580
  }
1534
- async visitarExpressaoBloco(declaracao) {
1535
- return await this.executarBloco(declaracao.declaracoes);
1581
+ visitarExpressaoBloco(declaracao) {
1582
+ return this.executarBloco(declaracao.declaracoes);
1536
1583
  }
1537
- async avaliacaoDeclaracaoVarOuConst(declaracao) {
1538
- let valorOuOutraVariavel = null;
1539
- if (declaracao.inicializador != null) {
1540
- valorOuOutraVariavel = await this.avaliar(declaracao.inicializador);
1541
- }
1542
- let valorFinal = null;
1543
- if (valorOuOutraVariavel !== null && valorOuOutraVariavel !== undefined) {
1544
- valorFinal = this.resolverValor(valorOuOutraVariavel);
1584
+ avaliacaoDeclaracaoVarOuConst(declaracao) {
1585
+ if (declaracao.inicializador == null) {
1586
+ return null;
1545
1587
  }
1546
- 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
+ });
1547
1594
  }
1548
1595
  /**
1549
1596
  * Executa expressão de definição de constante.
1550
1597
  * @param declaracao A declaração `Const`.
1551
1598
  * @returns Um descritor de informações importantes para o retorno externo.
1552
1599
  */
1553
- async visitarDeclaracaoConst(declaracao) {
1554
- const valorFinal = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1555
- this.pilhaEscoposExecucao.definirConstante(declaracao.simbolo.lexema, valorFinal, declaracao.tipo);
1556
- return {
1557
- tipo: declaracao.tipo,
1558
- tipoExplicito: declaracao.tipoExplicito,
1559
- };
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
+ });
1560
1608
  }
1561
1609
  /**
1562
1610
  * Executa expressão de definição de múltiplas constantes.
1563
1611
  * @param declaracao A declaração `ConstMultiplo`.
1564
1612
  * @returns Sempre retorna nulo.
1565
1613
  */
1566
- async visitarDeclaracaoConstMultiplo(declaracao) {
1567
- const valoresFinais = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1568
- const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
1569
- for (let [indice, valor] of valoresFinais.entries()) {
1570
- this.pilhaEscoposExecucao.definirConstante(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
1571
- }
1572
- 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
+ });
1573
1622
  }
1574
1623
  visitarExpressaoContinua(_) {
1575
1624
  return new quebras_1.ContinuarQuebra();
@@ -1584,7 +1633,7 @@ class InterpretadorBase {
1584
1633
  return new quebras_1.RetornoQuebra(valor);
1585
1634
  }
1586
1635
  async visitarExpressaoFuncaoConstruto(funcaoConstruto) {
1587
- return new estruturas_1.DeleguaFuncao(null, funcaoConstruto);
1636
+ return new estruturas_1.DeleguaFuncao(null, funcaoConstruto).capturarEscopo(this.pilhaEscoposExecucao);
1588
1637
  }
1589
1638
  async visitarExpressaoAtribuicaoPorIndice(expressao) {
1590
1639
  const promises = await Promise.all([
@@ -1721,7 +1770,7 @@ class InterpretadorBase {
1721
1770
  }
1722
1771
  }
1723
1772
  async visitarDeclaracaoDefinicaoFuncao(declaracao) {
1724
- 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);
1725
1774
  funcao.documentacao = declaracao.documentacao;
1726
1775
  this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, funcao);
1727
1776
  this.pilhaEscoposExecucao.registrarReferenciaFuncao(declaracao.id, funcao);
@@ -1779,7 +1828,7 @@ class InterpretadorBase {
1779
1828
  for (const metodoAtual of declaracao.metodos) {
1780
1829
  const nomeMetodo = metodoAtual.simbolo.lexema;
1781
1830
  const eInicializador = nomeMetodo === 'construtor';
1782
- 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);
1783
1832
  funcao.documentacao = metodoAtual.documentacao;
1784
1833
  metodos[nomeMetodo] = funcao;
1785
1834
  }
@@ -1834,7 +1883,7 @@ class InterpretadorBase {
1834
1883
  const tipoNome = declaracao.simboloTipo.lexema;
1835
1884
  for (const metodoDeclarado of declaracao.metodos) {
1836
1885
  const nomeMetodo = metodoDeclarado.simbolo.lexema;
1837
- const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoDeclarado.funcao);
1886
+ const funcao = new estruturas_1.DeleguaFuncao(nomeMetodo, metodoDeclarado.funcao).capturarEscopo(this.pilhaEscoposExecucao);
1838
1887
  if (declaracao.ehGlobal) {
1839
1888
  if (!this.extensoesGlobais.has(tipoNome)) {
1840
1889
  this.extensoesGlobais.set(tipoNome, new Map());
@@ -1983,30 +2032,32 @@ class InterpretadorBase {
1983
2032
  * @param declaracao A declaração Var
1984
2033
  * @returns Um descritor de informações importantes para o retorno externo.
1985
2034
  */
1986
- async visitarDeclaracaoVar(declaracao) {
1987
- const valorFinal = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
1988
- let tipoResolvido = declaracao.tipo;
1989
- if (tipoResolvido.startsWith('função<')) {
1990
- tipoResolvido = tipoResolvido.replace('função<', '').replace('>', '');
1991
- }
1992
- if (!declaracao.tipoExplicito && tipoResolvido === delegua_2.default.QUALQUER && valorFinal instanceof Array) {
1993
- tipoResolvido = (0, inferenciador_1.inferirTipoVariavel)(valorFinal);
1994
- }
1995
- this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, valorFinal, tipoResolvido, declaracao.tipoExplicito && declaracao.tipoOriginal !== 'qualquer');
1996
- 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
+ });
1997
2047
  }
1998
2048
  /**
1999
2049
  * Executa expressão de definição de múltiplas variáveis.
2000
2050
  * @param declaracao A declaração `VarMultiplo`.
2001
2051
  * @returns Sempre retorna nulo.
2002
2052
  */
2003
- async visitarDeclaracaoVarMultiplo(declaracao) {
2004
- const valoresFinais = await this.avaliacaoDeclaracaoVarOuConst(declaracao);
2005
- const tipoIndividual = (declaracao.tipo || '').replace('[]', '');
2006
- for (let [indice, valor] of valoresFinais.entries()) {
2007
- this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolos[indice].lexema, valor, tipoIndividual);
2008
- }
2009
- 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
+ });
2010
2061
  }
2011
2062
  /**
2012
2063
  * Formata uma string usando o operador % (similar ao Python).
@@ -2223,34 +2274,35 @@ class InterpretadorBase {
2223
2274
  * @returns O resultado parcial da execução, normalmente usado por
2224
2275
  * ferramentas externas.
2225
2276
  */
2226
- async executar(declaracao) {
2227
- const resultado = await declaracao.aceitar(this);
2228
- // Alguns casos não possuem retorno, como declarações `se`, `enquanto`, etc.,
2229
- // que não satisfazem suas respectivas condições.
2230
- if (resultado === null || resultado === undefined) {
2231
- return null;
2232
- }
2233
- // Se o retorno já possui um `valorRetornado`, apenas retorna o resultado.
2234
- if (resultado.hasOwnProperty('valorRetornado')) {
2235
- return resultado;
2236
- }
2237
- let tipoResultado = resultado.tipo;
2238
- switch (resultado.constructor) {
2239
- case estruturas_1.DescritorTipoClasse:
2240
- tipoResultado = resultado.simboloOriginal.lexema;
2241
- break;
2242
- default:
2243
- if (!tipoResultado) {
2244
- tipoResultado = (0, inferenciador_1.inferirTipoVariavel)(resultado);
2245
- }
2246
- break;
2247
- }
2248
- return {
2249
- hashArquivo: declaracao.hashArquivo,
2250
- linha: declaracao.linha,
2251
- valorRetornado: resultado,
2252
- tipo: tipoResultado,
2253
- };
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
+ });
2254
2306
  }
2255
2307
  /**
2256
2308
  * Executa o último escopo empilhado no topo na pilha de escopos do interpretador.
@@ -2262,38 +2314,62 @@ class InterpretadorBase {
2262
2314
  * @param manterAmbiente Se verdadeiro, ambiente do topo da pilha de escopo é copiado para o ambiente imediatamente abaixo.
2263
2315
  * @returns O resultado da execução do escopo, se houver.
2264
2316
  */
2265
- async executarUltimoEscopo(manterAmbiente = false) {
2317
+ executarUltimoEscopo(manterAmbiente = false) {
2266
2318
  const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
2267
2319
  let retornoExecucao;
2268
- try {
2269
- for (; !(retornoExecucao && retornoExecucao.valorRetornado instanceof quebras_1.Quebra) &&
2270
- ultimoEscopo.declaracaoAtual < ultimoEscopo.declaracoes.length; ultimoEscopo.declaracaoAtual++) {
2271
- const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2272
- this.linhaDeclaracaoAtual = declaracaoAtual.linha;
2273
- this.hashArquivoDeclaracaoAtual = declaracaoAtual.hashArquivo;
2274
- retornoExecucao = await this.executar(declaracaoAtual);
2275
- }
2276
- return retornoExecucao;
2277
- }
2278
- catch (erro) {
2279
- const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual];
2280
- if (!this.emDeclaracaoTente) {
2281
- this.erros.push({
2282
- erroInterno: erro,
2283
- linha: declaracaoAtual.linha,
2284
- hashArquivo: declaracaoAtual.hashArquivo,
2285
- });
2286
- }
2287
- else {
2288
- return Promise.reject(erro);
2289
- }
2290
- }
2291
- 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 = () => {
2292
2324
  this.pilhaEscoposExecucao.removerUltimo();
2293
2325
  const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
2294
2326
  if (manterAmbiente || (retornoExecucao && retornoExecucao.preservarEscopo === true)) {
2295
2327
  escopoAnterior.espacoMemoria.valores = Object.assign(escopoAnterior.espacoMemoria.valores, ultimoEscopo.espacoMemoria.valores);
2296
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);
2297
2373
  }
2298
2374
  }
2299
2375
  /**