@designliquido/delegua 0.71.0 → 0.72.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/analisador-semantico/analisador-semantico-base.d.ts.map +1 -1
- package/analisador-semantico/analisador-semantico-base.js +7 -9
- package/analisador-semantico/analisador-semantico-base.js.map +1 -1
- package/analisador-semantico/analisador-semantico.d.ts +5 -1
- package/analisador-semantico/analisador-semantico.d.ts.map +1 -1
- package/analisador-semantico/analisador-semantico.js +67 -4
- package/analisador-semantico/analisador-semantico.js.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.d.ts +5 -0
- package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.js +26 -1
- package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
- package/bibliotecas/dialetos/pitugues/primitivas-texto.d.ts.map +1 -1
- package/bibliotecas/dialetos/pitugues/primitivas-texto.js +25 -0
- package/bibliotecas/dialetos/pitugues/primitivas-texto.js.map +1 -1
- package/bibliotecas/primitivas-texto.d.ts +2 -0
- package/bibliotecas/primitivas-texto.d.ts.map +1 -1
- package/bibliotecas/primitivas-texto.js +58 -0
- package/bibliotecas/primitivas-texto.js.map +1 -1
- package/bin/package.json +1 -1
- package/interpretador/interpretador-base.d.ts.map +1 -1
- package/interpretador/interpretador-base.js +3 -0
- package/interpretador/interpretador-base.js.map +1 -1
- package/package.json +1 -1
- package/umd/delegua.js +162 -15
package/umd/delegua.js
CHANGED
|
@@ -58,20 +58,18 @@ class AnalisadorSemanticoBase {
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
if (expressao instanceof construtos_1.Chamada) {
|
|
61
|
-
|
|
62
|
-
this.gerenciadorEscopos.marcarComoUsada(expressao.entidadeChamada.simbolo.lexema);
|
|
63
|
-
}
|
|
64
|
-
if (expressao.entidadeChamada instanceof construtos_1.AcessoMetodo) {
|
|
65
|
-
this.marcarVariaveisUsadasEmExpressao(expressao.entidadeChamada.objeto);
|
|
66
|
-
}
|
|
67
|
-
if (expressao.entidadeChamada instanceof construtos_1.AcessoMetodoOuPropriedade) {
|
|
68
|
-
this.marcarVariaveisUsadasEmExpressao(expressao.entidadeChamada.objeto);
|
|
69
|
-
}
|
|
61
|
+
this.marcarVariaveisUsadasEmExpressao(expressao.entidadeChamada);
|
|
70
62
|
for (const arg of expressao.argumentos) {
|
|
71
63
|
this.marcarVariaveisUsadasEmExpressao(arg);
|
|
72
64
|
}
|
|
73
65
|
return;
|
|
74
66
|
}
|
|
67
|
+
if (expressao instanceof construtos_1.AcessoMetodo ||
|
|
68
|
+
expressao instanceof construtos_1.AcessoMetodoOuPropriedade ||
|
|
69
|
+
expressao instanceof construtos_1.AcessoPropriedade) {
|
|
70
|
+
this.marcarVariaveisUsadasEmExpressao(expressao.objeto);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
75
73
|
if (expressao instanceof construtos_1.Logico) {
|
|
76
74
|
this.marcarVariaveisUsadasEmExpressao(expressao.esquerda);
|
|
77
75
|
this.marcarVariaveisUsadasEmExpressao(expressao.direita);
|
|
@@ -661,6 +659,27 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
661
659
|
// Verifica a condição (incluindo validação de tipos para operadores lógicos)
|
|
662
660
|
return this.verificarCondicao(declaracao.condicao);
|
|
663
661
|
}
|
|
662
|
+
/**
|
|
663
|
+
* Verifica uma expressão recursivamente, incluindo operações binárias
|
|
664
|
+
*/
|
|
665
|
+
verificarExpressao(expressao) {
|
|
666
|
+
if (expressao instanceof construtos_1.Agrupamento) {
|
|
667
|
+
this.verificarExpressao(expressao.expressao);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
if (expressao instanceof construtos_1.Binario) {
|
|
671
|
+
this.verificarBinario(expressao);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (expressao instanceof construtos_1.Logico) {
|
|
675
|
+
this.verificarLogico(expressao);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (expressao instanceof construtos_1.Chamada) {
|
|
679
|
+
this.verificarChamada(expressao);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
664
683
|
verificarCondicao(condicao) {
|
|
665
684
|
if (condicao instanceof construtos_1.Agrupamento) {
|
|
666
685
|
return this.verificarCondicao(condicao.expressao);
|
|
@@ -730,9 +749,34 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
730
749
|
verificarTiposOperandos(binario) {
|
|
731
750
|
const tipoEsquerda = this.obterTipoExpressao(binario.esquerda);
|
|
732
751
|
const tipoDireita = this.obterTipoExpressao(binario.direita);
|
|
752
|
+
const tiposNumericos = ['inteiro', 'número', 'real'];
|
|
753
|
+
// Verifica se algum operando é do tipo texto em operação aritmética
|
|
754
|
+
if (tipoEsquerda === 'texto' || tipoDireita === 'texto') {
|
|
755
|
+
// Verifica se é uma operação que precisa de números (não concatenação)
|
|
756
|
+
const operadoresAritmeticos = ['SUBTRACAO', 'MULTIPLICACAO', 'DIVISAO', 'MODULO'];
|
|
757
|
+
if (operadoresAritmeticos.includes(binario.operador.tipo)) {
|
|
758
|
+
const ladoProblematico = tipoEsquerda === 'texto' ? 'esquerdo' : 'direito';
|
|
759
|
+
const expressaoProblematica = tipoEsquerda === 'texto' ? binario.esquerda : binario.direita;
|
|
760
|
+
// Verifica se a expressão problemática é um Leia ou uma variável inicializada com Leia
|
|
761
|
+
let mensagemAdicional = '';
|
|
762
|
+
if (expressaoProblematica instanceof construtos_1.Leia) {
|
|
763
|
+
mensagemAdicional = " Função 'leia()' retorna texto. Use 'inteiro(leia(...))' ou 'real(leia(...))' para converter.";
|
|
764
|
+
}
|
|
765
|
+
else if (expressaoProblematica instanceof construtos_1.Variavel) {
|
|
766
|
+
const variavel = this.gerenciadorEscopos.buscar(expressaoProblematica.simbolo.lexema);
|
|
767
|
+
if (variavel && variavel.valor instanceof construtos_1.Leia) {
|
|
768
|
+
mensagemAdicional = " A variável foi inicializada com 'leia()' que retorna texto. Use 'inteiro(leia(...))' ou 'real(leia(...))' para converter.";
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
mensagemAdicional = " Use 'inteiro(...)' ou 'real(...)' para converter texto em número.";
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
this.erro(binario.operador, `Operação aritmética com tipo incompatível: operando ${ladoProblematico} é do tipo 'texto', mas a operação requer número.${mensagemAdicional}`);
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
733
778
|
if (tipoEsquerda && tipoDireita && tipoEsquerda !== tipoDireita) {
|
|
734
779
|
// Verificar se são tipos numéricos compatíveis
|
|
735
|
-
const tiposNumericos = ['inteiro', 'número', 'real'];
|
|
736
780
|
const ambosNumericos = tiposNumericos.includes(tipoEsquerda) &&
|
|
737
781
|
tiposNumericos.includes(tipoDireita);
|
|
738
782
|
if (!ambosNumericos) {
|
|
@@ -819,7 +863,7 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
819
863
|
}
|
|
820
864
|
}
|
|
821
865
|
/**
|
|
822
|
-
* Obtém o tipo de uma expressão (pode ser Literal, Variavel,
|
|
866
|
+
* Obtém o tipo de uma expressão (pode ser Literal, Variavel, Binario, Leia, etc)
|
|
823
867
|
*/
|
|
824
868
|
obterTipoExpressao(expressao) {
|
|
825
869
|
if (expressao instanceof construtos_1.Literal) {
|
|
@@ -840,6 +884,10 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
840
884
|
if (expressao instanceof construtos_1.Agrupamento) {
|
|
841
885
|
return this.obterTipoExpressao(expressao.expressao);
|
|
842
886
|
}
|
|
887
|
+
if (expressao instanceof construtos_1.Leia) {
|
|
888
|
+
// leia() sempre retorna texto
|
|
889
|
+
return 'texto';
|
|
890
|
+
}
|
|
843
891
|
return null;
|
|
844
892
|
}
|
|
845
893
|
/**
|
|
@@ -895,8 +943,17 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
895
943
|
switch (chamada.entidadeChamada.constructor) {
|
|
896
944
|
case construtos_1.Variavel:
|
|
897
945
|
let entidadeChamadaVariavel = chamada.entidadeChamada;
|
|
898
|
-
|
|
899
|
-
|
|
946
|
+
const nomeFuncao = entidadeChamadaVariavel.simbolo.lexema;
|
|
947
|
+
// Lista de funções built-in que não precisam ser declaradas
|
|
948
|
+
const funcoesBuiltIn = ['inteiro', 'real', 'número', 'texto', 'leia', 'escreva', 'tipo'];
|
|
949
|
+
// Classes/construtores geralmente começam com letra maiúscula
|
|
950
|
+
const pareceSerClasse = nomeFuncao[0] === nomeFuncao[0].toUpperCase();
|
|
951
|
+
// Só verifica se a função existe se não for built-in e não parecer ser classe
|
|
952
|
+
if (!funcoesBuiltIn.includes(nomeFuncao) &&
|
|
953
|
+
!pareceSerClasse &&
|
|
954
|
+
!this.funcoes[nomeFuncao] &&
|
|
955
|
+
!this.gerenciadorEscopos.buscar(nomeFuncao)) {
|
|
956
|
+
this.erro(entidadeChamadaVariavel.simbolo, `Chamada da função '${nomeFuncao}' não existe.`);
|
|
900
957
|
}
|
|
901
958
|
break;
|
|
902
959
|
}
|
|
@@ -999,6 +1056,8 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
999
1056
|
this.verificarTipoAtribuido(declaracao);
|
|
1000
1057
|
if (declaracao.inicializador) {
|
|
1001
1058
|
this.marcarVariaveisUsadasEmExpressao(declaracao.inicializador);
|
|
1059
|
+
// Verifica operações binárias no inicializador
|
|
1060
|
+
this.verificarExpressao(declaracao.inicializador);
|
|
1002
1061
|
}
|
|
1003
1062
|
const constanteCorrespondente = this.gerenciadorEscopos.buscarNoEscopoAtual(declaracao.simbolo.lexema);
|
|
1004
1063
|
if (constanteCorrespondente) {
|
|
@@ -1022,6 +1081,8 @@ class AnalisadorSemantico extends analisador_semantico_base_1.AnalisadorSemantic
|
|
|
1022
1081
|
this.verificarTipoAtribuido(declaracao);
|
|
1023
1082
|
if (declaracao.inicializador) {
|
|
1024
1083
|
this.marcarVariaveisUsadasEmExpressao(declaracao.inicializador);
|
|
1084
|
+
// Verifica operações binárias no inicializador
|
|
1085
|
+
this.verificarExpressao(declaracao.inicializador);
|
|
1025
1086
|
switch (declaracao.inicializador.constructor) {
|
|
1026
1087
|
case construtos_1.FuncaoConstruto:
|
|
1027
1088
|
const funcaoConstruto = declaracao.inicializador;
|
|
@@ -2291,7 +2352,7 @@ class AvaliadorSintatico extends avaliador_sintatico_base_1.AvaliadorSintaticoBa
|
|
|
2291
2352
|
return construtoChamada;
|
|
2292
2353
|
}
|
|
2293
2354
|
unario() {
|
|
2294
|
-
if (this.verificarSeSimboloAtualEIgualA(delegua_2.default.NAO, delegua_2.default.NEGACAO, delegua_2.default.SUBTRACAO, delegua_2.default.BIT_NOT, delegua_2.default.INCREMENTAR, delegua_2.default.DECREMENTAR)) {
|
|
2355
|
+
if (this.verificarSeSimboloAtualEIgualA(delegua_2.default.NAO, delegua_2.default.NEGACAO, delegua_2.default.ADICAO, delegua_2.default.SUBTRACAO, delegua_2.default.BIT_NOT, delegua_2.default.INCREMENTAR, delegua_2.default.DECREMENTAR)) {
|
|
2295
2356
|
const operador = this.simbolos[this.atual - 1];
|
|
2296
2357
|
const direito = this.unario();
|
|
2297
2358
|
return new construtos_1.Unario(this.hashArquivo, operador, direito, 'ANTES');
|
|
@@ -2312,7 +2373,32 @@ class AvaliadorSintatico extends avaliador_sintatico_base_1.AvaliadorSintaticoBa
|
|
|
2312
2373
|
}
|
|
2313
2374
|
return expressao;
|
|
2314
2375
|
}
|
|
2376
|
+
/**
|
|
2377
|
+
* Verifica recursivamente se um construto é ou contém uma operação unária em um vetor.
|
|
2378
|
+
* Isso bloqueia padrões de ofuscação como !![] usado em operações aritméticas.
|
|
2379
|
+
*/
|
|
2380
|
+
verificarOperacaoUnariaEmVetor(construto) {
|
|
2381
|
+
if (construto instanceof construtos_1.Unario) {
|
|
2382
|
+
const operando = construto.operando;
|
|
2383
|
+
// Verifica se o operando é um vetor
|
|
2384
|
+
if (operando instanceof construtos_1.Vetor || operando.tipo === 'vetor' || operando.tipo.endsWith('[]')) {
|
|
2385
|
+
return true;
|
|
2386
|
+
}
|
|
2387
|
+
// Verifica recursivamente para casos como !![]
|
|
2388
|
+
if (operando instanceof construtos_1.Unario) {
|
|
2389
|
+
return this.verificarOperacaoUnariaEmVetor(operando);
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
return false;
|
|
2393
|
+
}
|
|
2315
2394
|
verificacaoOperacoesBinariasIlegais(esquerdo, direito, operador) {
|
|
2395
|
+
// Bloquear operações aritméticas com operações unárias em vetores (padrão de ofuscação tipo !![] * 1)
|
|
2396
|
+
if (this.verificarOperacaoUnariaEmVetor(esquerdo)) {
|
|
2397
|
+
throw this.erro(operador, `Operação inválida: não é possível realizar operação ${operador.lexema} com expressão unária aplicada a vetor.`);
|
|
2398
|
+
}
|
|
2399
|
+
if (this.verificarOperacaoUnariaEmVetor(direito)) {
|
|
2400
|
+
throw this.erro(operador, `Operação inválida: não é possível realizar operação ${operador.lexema} com expressão unária aplicada a vetor.`);
|
|
2401
|
+
}
|
|
2316
2402
|
if (esquerdo.tipo === 'vetor' || esquerdo.tipo.endsWith('[]')) {
|
|
2317
2403
|
if (['dicionario', 'dicionário', 'nulo'].includes(direito.tipo)) {
|
|
2318
2404
|
throw this.erro(operador, `Operação inválida: não é possível realizar operação ${operador.lexema} entre vetor e ${direito.tipo}.`);
|
|
@@ -9913,7 +9999,41 @@ exports.default = {
|
|
|
9913
9999
|
},{"../informacao-elemento-sintatico":135}],31:[function(require,module,exports){
|
|
9914
10000
|
"use strict";
|
|
9915
10001
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10002
|
+
exports.implementacaoParticao = void 0;
|
|
9916
10003
|
const informacao_elemento_sintatico_1 = require("../informacao-elemento-sintatico");
|
|
10004
|
+
const construtos_1 = require("../construtos");
|
|
10005
|
+
const excecoes_1 = require("../excecoes");
|
|
10006
|
+
const implementacaoParticao = (interpretador, nomePrimitiva, texto, separador, ...args) => {
|
|
10007
|
+
if (args.length > 0) {
|
|
10008
|
+
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `A função "${nomePrimitiva}" aceita apenas um argumento.`, interpretador.linhaDeclaracaoAtual));
|
|
10009
|
+
}
|
|
10010
|
+
if (typeof texto !== 'string') {
|
|
10011
|
+
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `A função "${nomePrimitiva}" só pode ser chamada em textos.`, interpretador.linhaDeclaracaoAtual));
|
|
10012
|
+
}
|
|
10013
|
+
if (separador === undefined) {
|
|
10014
|
+
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `A função "${nomePrimitiva}" requer um argumento separador.`, interpretador.linhaDeclaracaoAtual));
|
|
10015
|
+
}
|
|
10016
|
+
if (typeof separador !== 'string') {
|
|
10017
|
+
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, 'O separador deve ser do tipo texto.', interpretador.linhaDeclaracaoAtual));
|
|
10018
|
+
}
|
|
10019
|
+
if (separador === '') {
|
|
10020
|
+
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, 'O separador não pode ser uma string vazia.', interpretador.linhaDeclaracaoAtual));
|
|
10021
|
+
}
|
|
10022
|
+
const indice = texto.indexOf(separador);
|
|
10023
|
+
let partes;
|
|
10024
|
+
if (indice === -1) {
|
|
10025
|
+
partes = [texto, '', ''];
|
|
10026
|
+
}
|
|
10027
|
+
else {
|
|
10028
|
+
const antes = texto.substring(0, indice);
|
|
10029
|
+
const depois = texto.substring(indice + separador.length);
|
|
10030
|
+
partes = [antes, separador, depois];
|
|
10031
|
+
}
|
|
10032
|
+
const elementos = partes.map(p => new construtos_1.Literal(interpretador.hashArquivoDeclaracaoAtual, interpretador.linhaDeclaracaoAtual, p, 'texto'));
|
|
10033
|
+
const tupla = new construtos_1.TuplaN(interpretador.hashArquivoDeclaracaoAtual, interpretador.linhaDeclaracaoAtual, elementos);
|
|
10034
|
+
return Promise.resolve(tupla);
|
|
10035
|
+
};
|
|
10036
|
+
exports.implementacaoParticao = implementacaoParticao;
|
|
9917
10037
|
exports.default = {
|
|
9918
10038
|
aparar: {
|
|
9919
10039
|
tipoRetorno: 'texto',
|
|
@@ -10088,6 +10208,30 @@ exports.default = {
|
|
|
10088
10208
|
'\n\n ### Formas de uso \n',
|
|
10089
10209
|
exemploCodigo: 'texto.minusculo()',
|
|
10090
10210
|
},
|
|
10211
|
+
particao: {
|
|
10212
|
+
tipoRetorno: 'tupla',
|
|
10213
|
+
argumentos: [
|
|
10214
|
+
new informacao_elemento_sintatico_1.InformacaoElementoSintatico('separador', 'texto', true, [], 'O separador usado para partir o texto.'),
|
|
10215
|
+
],
|
|
10216
|
+
implementacao: exports.implementacaoParticao,
|
|
10217
|
+
assinaturaFormato: 'texto.particao(separador: texto)',
|
|
10218
|
+
documentacao: '# `texto.particao(separador)` \n \n' +
|
|
10219
|
+
'Divide o texto na primeira ocorrência do separador e retorna uma tupla com: ' +
|
|
10220
|
+
'o que vem antes, o separador e o que vem depois.',
|
|
10221
|
+
exemploCodigo: 'texto.particao(" ")',
|
|
10222
|
+
},
|
|
10223
|
+
partição: {
|
|
10224
|
+
tipoRetorno: 'tupla',
|
|
10225
|
+
argumentos: [
|
|
10226
|
+
new informacao_elemento_sintatico_1.InformacaoElementoSintatico('separador', 'texto', true, [], 'O separador usado para partir o texto.'),
|
|
10227
|
+
],
|
|
10228
|
+
implementacao: exports.implementacaoParticao,
|
|
10229
|
+
assinaturaFormato: 'texto.partição(separador: texto)',
|
|
10230
|
+
documentacao: '# `texto.partição(separador)` \n \n' +
|
|
10231
|
+
'Divide o texto na primeira ocorrência do separador e retorna uma tupla com: ' +
|
|
10232
|
+
'o que vem antes, o separador e o que vem depois.',
|
|
10233
|
+
exemploCodigo: 'texto.partição(" ")',
|
|
10234
|
+
},
|
|
10091
10235
|
substituir: {
|
|
10092
10236
|
tipoRetorno: 'texto',
|
|
10093
10237
|
argumentos: [
|
|
@@ -10182,7 +10326,7 @@ exports.default = {
|
|
|
10182
10326
|
},
|
|
10183
10327
|
};
|
|
10184
10328
|
|
|
10185
|
-
},{"../informacao-elemento-sintatico":135}],32:[function(require,module,exports){
|
|
10329
|
+
},{"../construtos":62,"../excecoes":128,"../informacao-elemento-sintatico":135}],32:[function(require,module,exports){
|
|
10186
10330
|
"use strict";
|
|
10187
10331
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10188
10332
|
const informacao_elemento_sintatico_1 = require("../informacao-elemento-sintatico");
|
|
@@ -16486,6 +16630,9 @@ class InterpretadorBase {
|
|
|
16486
16630
|
const operando = await this.avaliar(expressao.operando);
|
|
16487
16631
|
let valor = this.resolverValor(operando);
|
|
16488
16632
|
switch (expressao.operador.tipo) {
|
|
16633
|
+
case delegua_1.default.ADICAO:
|
|
16634
|
+
this.verificarOperandoNumero(expressao.operador, valor);
|
|
16635
|
+
return +valor;
|
|
16489
16636
|
case delegua_1.default.SUBTRACAO:
|
|
16490
16637
|
this.verificarOperandoNumero(expressao.operador, valor);
|
|
16491
16638
|
return -valor;
|