@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.
- package/avaliador-sintatico/avaliador-sintatico.d.ts +1 -0
- package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.js +15 -6
- package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js +0 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js +0 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js.map +1 -1
- package/bibliotecas/biblioteca-global.js +1 -1
- package/bibliotecas/biblioteca-global.js.map +1 -1
- package/bibliotecas/primitivas-vetor.d.ts.map +1 -1
- package/bibliotecas/primitivas-vetor.js +2 -1
- package/bibliotecas/primitivas-vetor.js.map +1 -1
- package/bin/package.json +3 -2
- package/construtos/agrupamento.d.ts +1 -1
- package/construtos/agrupamento.d.ts.map +1 -1
- package/construtos/agrupamento.js +2 -2
- package/construtos/agrupamento.js.map +1 -1
- package/construtos/atribuir.d.ts +1 -1
- package/construtos/atribuir.d.ts.map +1 -1
- package/construtos/atribuir.js +2 -2
- package/construtos/atribuir.js.map +1 -1
- package/construtos/binario.d.ts +1 -1
- package/construtos/binario.d.ts.map +1 -1
- package/construtos/binario.js +2 -2
- package/construtos/binario.js.map +1 -1
- package/construtos/literal.d.ts +1 -1
- package/construtos/literal.d.ts.map +1 -1
- package/construtos/literal.js +2 -2
- package/construtos/literal.js.map +1 -1
- package/construtos/logico.d.ts +1 -1
- package/construtos/logico.d.ts.map +1 -1
- package/construtos/logico.js +2 -2
- package/construtos/logico.js.map +1 -1
- package/construtos/para-como-construto.d.ts +2 -1
- package/construtos/para-como-construto.d.ts.map +1 -1
- package/construtos/para-como-construto.js +2 -1
- package/construtos/para-como-construto.js.map +1 -1
- package/construtos/unario.d.ts +1 -1
- package/construtos/unario.d.ts.map +1 -1
- package/construtos/unario.js +2 -2
- package/construtos/unario.js.map +1 -1
- package/construtos/variavel.d.ts +2 -2
- package/construtos/variavel.d.ts.map +1 -1
- package/construtos/variavel.js +2 -2
- package/construtos/variavel.js.map +1 -1
- package/declaracoes/para.d.ts +2 -1
- package/declaracoes/para.d.ts.map +1 -1
- package/declaracoes/para.js +2 -1
- package/declaracoes/para.js.map +1 -1
- package/formatadores/formatador-delegua.d.ts.map +1 -1
- package/formatadores/formatador-delegua.js +11 -7
- package/formatadores/formatador-delegua.js.map +1 -1
- package/formatadores/formatador-pitugues.d.ts.map +1 -1
- package/formatadores/formatador-pitugues.js +2 -1
- package/formatadores/formatador-pitugues.js.map +1 -1
- package/interfaces/construtos/construto-interface.d.ts +6 -1
- package/interfaces/construtos/construto-interface.d.ts.map +1 -1
- package/interfaces/delegua/para-interface.d.ts +7 -0
- package/interfaces/delegua/para-interface.d.ts.map +1 -1
- package/interfaces/interpretador-interface.d.ts +13 -1
- package/interfaces/interpretador-interface.d.ts.map +1 -1
- package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts +1 -0
- package/interpretador/depuracao/interpretador-base-com-depuracao.d.ts.map +1 -1
- package/interpretador/depuracao/interpretador-base-com-depuracao.js +1 -0
- package/interpretador/depuracao/interpretador-base-com-depuracao.js.map +1 -1
- package/interpretador/depuracao/interpretador-com-depuracao.d.ts +1 -0
- package/interpretador/depuracao/interpretador-com-depuracao.d.ts.map +1 -1
- package/interpretador/depuracao/interpretador-com-depuracao.js +1 -0
- package/interpretador/depuracao/interpretador-com-depuracao.js.map +1 -1
- package/interpretador/dialetos/calango/interpretador-calango.d.ts +1 -1
- package/interpretador/dialetos/calango/interpretador-calango.d.ts.map +1 -1
- package/interpretador/dialetos/calango/interpretador-calango.js +14 -10
- package/interpretador/dialetos/calango/interpretador-calango.js.map +1 -1
- package/interpretador/dialetos/egua-classico/interpretador-egua-classico.d.ts.map +1 -1
- package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js +3 -3
- package/interpretador/dialetos/egua-classico/interpretador-egua-classico.js.map +1 -1
- package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts +1 -1
- package/interpretador/dialetos/pitugues/interpretador-pitugues.d.ts.map +1 -1
- package/interpretador/dialetos/pitugues/interpretador-pitugues.js +8 -6
- package/interpretador/dialetos/pitugues/interpretador-pitugues.js.map +1 -1
- package/interpretador/dialetos/prisma/interpretador-prisma.d.ts +2 -2
- package/interpretador/dialetos/prisma/interpretador-prisma.d.ts.map +1 -1
- package/interpretador/dialetos/prisma/interpretador-prisma.js +26 -19
- package/interpretador/dialetos/prisma/interpretador-prisma.js.map +1 -1
- package/interpretador/encadear.d.ts +36 -0
- package/interpretador/encadear.d.ts.map +1 -0
- package/interpretador/encadear.js +43 -0
- package/interpretador/encadear.js.map +1 -0
- package/interpretador/estruturas/delegua-funcao.d.ts +25 -0
- package/interpretador/estruturas/delegua-funcao.d.ts.map +1 -1
- package/interpretador/estruturas/delegua-funcao.js +90 -23
- package/interpretador/estruturas/delegua-funcao.js.map +1 -1
- package/interpretador/interpretador-base.d.ts +34 -22
- package/interpretador/interpretador-base.d.ts.map +1 -1
- package/interpretador/interpretador-base.js +630 -557
- package/interpretador/interpretador-base.js.map +1 -1
- package/interpretador/interpretador.d.ts +8 -11
- package/interpretador/interpretador.d.ts.map +1 -1
- package/interpretador/interpretador.js +170 -116
- package/interpretador/interpretador.js.map +1 -1
- package/lexador/dialetos/lexador-pitugues.d.ts.map +1 -1
- package/lexador/dialetos/lexador-pitugues.js +0 -1
- package/lexador/dialetos/lexador-pitugues.js.map +1 -1
- package/lexador/dialetos/lexador-tenda.d.ts.map +1 -1
- package/lexador/dialetos/lexador-tenda.js +0 -1
- package/lexador/dialetos/lexador-tenda.js.map +1 -1
- package/lexador/lexador.d.ts.map +1 -1
- package/lexador/lexador.js +0 -1
- package/lexador/lexador.js.map +1 -1
- package/package.json +3 -2
- 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
|
-
*
|
|
97
|
-
* em
|
|
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
|
-
|
|
101
|
+
cederControle(iteracoes) {
|
|
100
102
|
if (iteracoes % this.iteracoesParaCederControle === 0) {
|
|
101
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
433
|
+
visitarExpressaoLiteral(expressao) {
|
|
431
434
|
if (this.regexInterpolacao.test(String(expressao.valor))) {
|
|
432
435
|
const valorComoTexto = String(expressao.valor);
|
|
433
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.
|
|
490
|
-
return
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
608
|
-
//
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
this.converterParaBigInt(
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
typeof
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
typeof
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
typeof
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
typeof
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
this.converterParaBigInt(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
this.tiposNumericos.includes(
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
650
|
+
// Corpo original mantido com a indentação de antes da conversão (só 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
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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
|
-
|
|
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
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
-
|
|
794
|
-
|
|
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
|
-
|
|
797
|
-
|
|
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
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
return valorEsquerdo
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
valor
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
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
|
-
|
|
1103
|
-
return
|
|
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
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
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
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
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
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1347
|
+
return this.executar(declaracao.caminhoEntao);
|
|
1294
1348
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
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
|
-
|
|
1538
|
-
return
|
|
1581
|
+
visitarExpressaoBloco(declaracao) {
|
|
1582
|
+
return this.executarBloco(declaracao.declaracoes);
|
|
1539
1583
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
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
|
|
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
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
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
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
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
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
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
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
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
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
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
|
-
|
|
2317
|
+
executarUltimoEscopo(manterAmbiente = false) {
|
|
2269
2318
|
const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
|
|
2270
2319
|
let retornoExecucao;
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
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
|
/**
|