diff --git a/fontes/analisador-semantico/analisador-semantico.ts b/fontes/analisador-semantico/analisador-semantico.ts index 01a07166..0bf13bf3 100644 --- a/fontes/analisador-semantico/analisador-semantico.ts +++ b/fontes/analisador-semantico/analisador-semantico.ts @@ -59,6 +59,12 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface { this.atual = 0; this.diagnosticos = []; } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + return Promise.resolve(); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + return Promise.resolve(); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { return Promise.resolve(); } diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-birl.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-birl.ts index b208b063..a342584e 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-birl.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-birl.ts @@ -60,6 +60,12 @@ export class AnalisadorSemanticoBirl implements AnalisadorSemanticoInterface { this.atual = 0; this.diagnosticos = []; } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + return Promise.resolve(); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + return Promise.resolve(); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { return Promise.resolve(); } diff --git a/fontes/analisador-semantico/dialetos/analisador-semantico-mapler.ts b/fontes/analisador-semantico/dialetos/analisador-semantico-mapler.ts index fcc07304..eebd1256 100644 --- a/fontes/analisador-semantico/dialetos/analisador-semantico-mapler.ts +++ b/fontes/analisador-semantico/dialetos/analisador-semantico-mapler.ts @@ -59,6 +59,12 @@ export class AnalisadorSemanticoMapler implements AnalisadorSemanticoInterface { this.atual = 0; this.diagnosticos = []; } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + return Promise.resolve(); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + return Promise.resolve(); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { return Promise.resolve(); } diff --git a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts index 7176038f..7d0b3548 100644 --- a/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts +++ b/fontes/avaliador-sintatico/dialetos/visualg/avaliador-sintatico-visualg.ts @@ -38,6 +38,8 @@ import { Simbolo } from '../../../lexador'; import tiposDeSimbolos from '../../../tipos-de-simbolos/visualg'; import { ParametroVisuAlg } from './parametro-visualg'; +import { AcessoElementoMatriz } from '../../../construtos/acesso-elemento-matriz'; +import { AtribuicaoPorIndicesMatriz } from '../../../construtos/atribuicao-por-indices-matriz'; export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { blocoPrincipalIniciado: boolean; @@ -384,6 +386,15 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { expressao.indice, valor ); + } else if (expressao instanceof AcessoElementoMatriz) { + return new AtribuicaoPorIndicesMatriz( + this.hashArquivo, + expressao.linha, + expressao.entidadeChamada, + expressao.indicePrimario, + expressao.indiceSecundario, + valor + ); } this.erro(setaAtribuicao, 'Tarefa de atribuição inválida'); @@ -427,12 +438,15 @@ export class AvaliadorSintaticoVisuAlg extends AvaliadorSintaticoBase { indices.push(this.expressao()); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); - const indice = indices[0]; const simboloFechamento = this.consumir( tiposDeSimbolos.COLCHETE_DIREITO, "Esperado ']' após escrita do indice." ); - expressao = new AcessoIndiceVariavel(this.hashArquivo, expressao, indice, simboloFechamento); + if (!indices[1]) { + expressao = new AcessoIndiceVariavel(this.hashArquivo, expressao, indices[0], simboloFechamento); + } else { + expressao = new AcessoElementoMatriz(this.hashArquivo, expressao, indices[0], indices[1], simboloFechamento); + } } else { break; } diff --git a/fontes/construtos/acesso-elemento-matriz.ts b/fontes/construtos/acesso-elemento-matriz.ts new file mode 100644 index 00000000..45cf438d --- /dev/null +++ b/fontes/construtos/acesso-elemento-matriz.ts @@ -0,0 +1,26 @@ +import { VisitanteComumInterface, SimboloInterface } from '../interfaces'; +import { Construto } from './construto'; + +export class AcessoElementoMatriz implements Construto { + linha: number; + hashArquivo: number; + + entidadeChamada: Construto; + simboloFechamento: SimboloInterface; + indicePrimario: any; + indiceSecundario: any; + + constructor(hashArquivo: number, entidadeChamada: Construto, indicePrimario: any, indiceSegundario: any, simboloFechamento: SimboloInterface) { + this.linha = entidadeChamada.linha; + this.hashArquivo = hashArquivo; + + this.entidadeChamada = entidadeChamada; + this.indicePrimario = indicePrimario; + this.indiceSecundario = indiceSegundario; + this.simboloFechamento = simboloFechamento; + } + + async aceitar(visitante: VisitanteComumInterface): Promise { + return await visitante.visitarExpressaoAcessoElementoMatriz(this); + } +} diff --git a/fontes/construtos/atribuicao-por-indices-matriz.ts b/fontes/construtos/atribuicao-por-indices-matriz.ts new file mode 100644 index 00000000..fc86a5b7 --- /dev/null +++ b/fontes/construtos/atribuicao-por-indices-matriz.ts @@ -0,0 +1,26 @@ +import { VisitanteComumInterface } from '../interfaces'; +import { Construto } from './construto'; + +export class AtribuicaoPorIndicesMatriz implements Construto { + linha: number; + hashArquivo: number; + + objeto: any; + valor: any; + indicePrimario: any; + indiceSecundario: any; + + constructor(hashArquivo: number, linha: number, objeto: any, indicePrimario: any, indiceSecundario: any, valor: any) { + this.linha = linha; + this.hashArquivo = hashArquivo; + + this.objeto = objeto; + this.indicePrimario = indicePrimario; + this.indiceSecundario = indiceSecundario; + this.valor = valor; + } + + async aceitar(visitante: VisitanteComumInterface): Promise { + return await visitante.visitarExpressaoAtribuicaoPorIndicesMatriz(this); + } +} diff --git a/fontes/interfaces/visitante-comum-interface.ts b/fontes/interfaces/visitante-comum-interface.ts index 0c35e65b..2a475509 100644 --- a/fontes/interfaces/visitante-comum-interface.ts +++ b/fontes/interfaces/visitante-comum-interface.ts @@ -47,9 +47,11 @@ export interface VisitanteComumInterface { visitarDeclaracaoVar(declaracao: Var): Promise; visitarDeclaracaoVarMultiplo(declaracao: VarMultiplo): Promise; visitarExpressaoAcessoIndiceVariavel(expressao: any): any; + visitarExpressaoAcessoElementoMatriz(expressao: any): any; visitarExpressaoAcessoMetodo(expressao: any): any; visitarExpressaoAgrupamento(expressao: any): Promise; visitarExpressaoAtribuicaoPorIndice(expressao: any): Promise; + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise; visitarExpressaoBinaria(expressao: any): any; visitarExpressaoBloco(declaracao: Bloco): Promise; visitarExpressaoContinua(declaracao?: Continua): ContinuarQuebra; diff --git a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts index bbdebea1..5e5967c7 100644 --- a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts +++ b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts @@ -97,6 +97,12 @@ export class InterpretadorEguaClassico implements InterpretadorInterface { carregarBibliotecaGlobal(this, this.pilhaEscoposExecucao); } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + throw new Error('Método não implementado.'); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + throw new Error('Método não implementado.'); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { throw new Error('Método não implementado.'); } diff --git a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts index f4221962..c8216a25 100644 --- a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts +++ b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts @@ -75,6 +75,12 @@ export class ResolvedorEguaClassico implements ResolvedorInterface, Interpretado this.classeAtual = TipoClasse.NENHUM; this.cicloAtual = TipoClasse.NENHUM; } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + throw new Error('Método não implementado.'); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + throw new Error('Método não implementado.'); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { throw new Error('Método não implementado.'); diff --git a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts index 0221a9e9..61e36978 100644 --- a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts +++ b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts @@ -73,6 +73,12 @@ export class InterpretadorPortugolIpt implements InterpretadorInterface { }; this.pilhaEscoposExecucao.empilhar(escopoExecucao); } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + throw new Error('Método não implementado.'); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + throw new Error('Método não implementado.'); + } visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { throw new Error('Método não implementado.'); } diff --git a/fontes/interpretador/dialetos/visualg/interpretador-visualg.ts b/fontes/interpretador/dialetos/visualg/interpretador-visualg.ts index 8dc4dac5..739d38dd 100644 --- a/fontes/interpretador/dialetos/visualg/interpretador-visualg.ts +++ b/fontes/interpretador/dialetos/visualg/interpretador-visualg.ts @@ -6,6 +6,11 @@ import { registrarBibliotecaNumericaVisuAlg } from '../../../bibliotecas/dialeto import { registrarBibliotecaCaracteresVisuAlg } from '../../../bibliotecas/dialetos/visualg'; import * as comum from './comum'; +import { ErroEmTempoDeExecucao } from '../../../excecoes'; +import { DeleguaClasse, DeleguaFuncao, DeleguaModulo, ObjetoDeleguaClasse } from '../../../estruturas'; +import { VariavelInterface } from '../../../interfaces'; +import { AtribuicaoPorIndicesMatriz } from '../../../construtos/atribuicao-por-indices-matriz'; +import { AcessoElementoMatriz } from '../../../construtos/acesso-elemento-matriz'; /** * O Interpretador VisuAlg possui algumas diferenças em relação ao @@ -33,6 +38,108 @@ export class InterpretadorVisuAlg extends InterpretadorBase { throw new Error('Método não implementado.'); } + async visitarExpressaoAcessoElementoMatriz(expressao: AcessoElementoMatriz): Promise { + const promises = await Promise.all([ + this.avaliar(expressao.entidadeChamada), + this.avaliar(expressao.indicePrimario), + this.avaliar(expressao.indiceSecundario), + ]); + + const variavelObjeto: VariavelInterface = promises[0]; + const indicePrimario = promises[1]; + const indiceSecundario = promises[2]; + + const objeto = variavelObjeto.hasOwnProperty('valor') ? variavelObjeto.valor : variavelObjeto; + let valorIndicePrimario = indicePrimario.hasOwnProperty('valor') ? indicePrimario.valor : indicePrimario; + let valorIndiceSecundario = indiceSecundario.hasOwnProperty('valor') ? indiceSecundario.valor : indiceSecundario; + + if (Array.isArray(objeto)) { + if (!Number.isInteger(valorIndicePrimario) || !Number.isInteger(valorIndiceSecundario)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + expressao.simboloFechamento, + 'Somente inteiros podem ser usados para indexar um vetor.', + expressao.linha + ) + ); + } + + if (valorIndicePrimario < 0 && objeto.length !== 0) { + while (valorIndicePrimario < 0) { + valorIndicePrimario += objeto.length; + } + } + if (valorIndiceSecundario < 0 && objeto.length !== 0) { + while (valorIndiceSecundario < 0) { + valorIndiceSecundario += objeto.length; + } + } + + if (valorIndicePrimario >= objeto.length || valorIndiceSecundario >= objeto.length) { + return Promise.reject( + new ErroEmTempoDeExecucao( + expressao.simboloFechamento, + 'Índice do vetor fora do intervalo.', + expressao.linha + ) + ); + } + return objeto[valorIndicePrimario][valorIndiceSecundario]; + } + return Promise.reject( + new ErroEmTempoDeExecucao( + expressao.entidadeChamada.valor, + 'Somente listas, dicionários, classes e objetos podem ser mudados por sobrescrita.', + expressao.linha + ) + ); + } + + async visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: AtribuicaoPorIndicesMatriz): Promise { + const promises = await Promise.all([ + this.avaliar(expressao.objeto), + this.avaliar(expressao.indicePrimario), + this.avaliar(expressao.indiceSecundario), + this.avaliar(expressao.valor), + ]); + + let objeto = promises[0]; + let indicePrimario = promises[1]; + let indiceSecundario = promises[2]; + const valor = promises[3]; + + objeto = objeto.hasOwnProperty('valor') ? objeto.valor : objeto; + indicePrimario = indicePrimario.hasOwnProperty('valor') ? indicePrimario.valor : indicePrimario; + indiceSecundario = indiceSecundario.hasOwnProperty('valor') ? indiceSecundario.valor : indiceSecundario; + + if (Array.isArray(objeto)) { + if (indicePrimario < 0 && objeto.length !== 0) { + while (indicePrimario < 0) { + indicePrimario += objeto.length; + } + } + if (indiceSecundario < 0 && objeto.length !== 0) { + while (indiceSecundario < 0) { + indiceSecundario += objeto.length; + } + } + + while (objeto.length < indicePrimario || objeto.length < indiceSecundario) { + objeto.push(null); + } + + objeto[indicePrimario][indiceSecundario] = valor; + return Promise.resolve(); + } + return Promise.reject( + new ErroEmTempoDeExecucao( + expressao.objeto.nome, + 'Somente listas, dicionários, classes e objetos podem ser mudados por sobrescrita.', + expressao.linha + ) + ); + } + private async avaliarArgumentosEscrevaVisuAlg(argumentos: Construto[]): Promise { let formatoTexto: string = ''; diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts index e84daaae..2db4648d 100644 --- a/fontes/interpretador/interpretador-base.ts +++ b/fontes/interpretador/interpretador-base.ts @@ -154,6 +154,12 @@ export class InterpretadorBase implements InterpretadorInterface { carregarBibliotecasGlobais(this, this.pilhaEscoposExecucao); } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + throw new Error('Método não implementado.'); + } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + throw new Error('Método não implementado.'); + } //https://stackoverflow.com/a/66751666/9043143 textoParaRegex(texto): any { diff --git a/testes/visualg/interpretador.test.ts b/testes/visualg/interpretador.test.ts index f119408f..85e518d6 100644 --- a/testes/visualg/interpretador.test.ts +++ b/testes/visualg/interpretador.test.ts @@ -363,8 +363,7 @@ describe('Interpretador', () => { expect(retornoInterpretador.erros).toHaveLength(0); }); - //TODO: https://github.com/DesignLiquido/delegua/issues/503 - it.skip("Sucesso - Matriz - Jogo da Velha", async () => { + it("Sucesso - Matriz - Jogo da Velha", async () => { const retornoLexador = lexador.mapear([ 'Algoritmo "Jogo da Velha"', 'Var',