@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.
- package/avaliador-sintatico/avaliador-sintatico-base.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico-base.js +11 -0
- package/avaliador-sintatico/avaliador-sintatico-base.js.map +1 -1
- 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 +30 -7
- 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/interfaces/parametro-interface.d.ts +4 -0
- package/interfaces/parametro-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 +137 -24
- 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 +634 -558
- 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 +173 -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-portugol-ipt.d.ts.map +1 -1
- package/lexador/dialetos/lexador-portugol-ipt.js +3 -2
- package/lexador/dialetos/lexador-portugol-ipt.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-base-linha-unica.d.ts.map +1 -1
- package/lexador/lexador-base-linha-unica.js +3 -2
- package/lexador/lexador-base-linha-unica.js.map +1 -1
- package/lexador/lexador-base.d.ts.map +1 -1
- package/lexador/lexador-base.js +9 -2
- package/lexador/lexador-base.js.map +1 -1
- package/lexador/lexador.d.ts.map +1 -1
- package/lexador/lexador.js +3 -3
- package/lexador/lexador.js.map +1 -1
- package/lexador/micro-lexador-pitugues.d.ts.map +1 -1
- package/lexador/micro-lexador-pitugues.js +3 -2
- package/lexador/micro-lexador-pitugues.js.map +1 -1
- package/lexador/micro-lexador.d.ts.map +1 -1
- package/lexador/micro-lexador.js +3 -2
- package/lexador/micro-lexador.js.map +1 -1
- package/package.json +3 -2
- 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
|
-
*
|
|
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,18 +445,22 @@ 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
|
-
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
this.
|
|
487
|
-
return
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
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
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
this.converterParaBigInt(
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
typeof
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
typeof
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
typeof
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
typeof
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
this.converterParaBigInt(
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
-
this.tiposNumericos.includes(
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
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
|
+
}
|
|
724
766
|
return this.paraTexto(valorEsquerdo) + this.paraTexto(valorDireito);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
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
|
-
: 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
|
-
|
|
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
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
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
|
-
|
|
787
|
-
|
|
788
|
-
|
|
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
|
-
|
|
791
|
-
|
|
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
|
-
|
|
794
|
-
|
|
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
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
return valorEsquerdo
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
valor
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
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
|
-
|
|
1100
|
-
return
|
|
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
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
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
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
if (
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
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
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1347
|
+
return this.executar(declaracao.caminhoEntao);
|
|
1291
1348
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
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
|
-
|
|
1535
|
-
return
|
|
1581
|
+
visitarExpressaoBloco(declaracao) {
|
|
1582
|
+
return this.executarBloco(declaracao.declaracoes);
|
|
1536
1583
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
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
|
|
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
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
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
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
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
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
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
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2317
|
+
executarUltimoEscopo(manterAmbiente = false) {
|
|
2266
2318
|
const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
|
|
2267
2319
|
let retornoExecucao;
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
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
|
/**
|