diff --git a/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts b/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts index e65224a..99dd7f9 100644 --- a/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts +++ b/fontes/avaliador-sintatico/avaliador-sintatico-portugol-studio.ts @@ -11,7 +11,6 @@ import { Literal, Unario, Variavel, - Vetor, } from '@designliquido/delegua/construtos'; import { Escreva, @@ -40,6 +39,7 @@ import { RetornoDeclaracao } from '@designliquido/delegua/avaliador-sintatico/re import { ErroAvaliadorSintatico } from '@designliquido/delegua/avaliador-sintatico/erro-avaliador-sintatico'; import { TipoDadosElementar } from '@designliquido/delegua/tipo-dados-elementar'; +import { Matriz, Limpa } from '../construtos'; import tiposDeSimbolos from '../tipos-de-simbolos/lexico-regular'; /** @@ -48,13 +48,13 @@ import tiposDeSimbolos from '../tipos-de-simbolos/lexico-regular'; * Há dois grupos de estruturas de alto nível: Construtos e Declarações. */ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { - private declaracoes: Declaracao[] = [] + private declaracoes: Declaracao[] = []; declaracaoEscreva(): Escreva { throw new Error('Método não implementado.'); } - private validarEscopoPrograma(): void { + private validarEscopoProgramaEAvaliacaoSintatica(): void { this.consumir(tiposDeSimbolos.PROGRAMA, "Esperada expressão 'programa' para inicializar programa."); this.consumir( @@ -138,6 +138,14 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { case tiposDeSimbolos.REAL: const simboloVariavel: SimboloInterface = this.avancarEDevolverAnterior(); return new Literal(this.hashArquivo, Number(simboloVariavel.linha), simboloVariavel.literal); + case tiposDeSimbolos.FALSO: + this.avancarEDevolverAnterior(); + return new Literal(this.hashArquivo, Number(simboloAtual.linha), false); + case tiposDeSimbolos.VERDADEIRO: + this.avancarEDevolverAnterior(); + return new Literal(this.hashArquivo, Number(simboloAtual.linha), true); + default: + throw this.erro(simboloAtual, 'Não deveria cair aqui.'); } } @@ -213,17 +221,28 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } /** - * Declaração para inclusão de uma biblioteca. + * Declaração para inclusão de uma biblioteca. * Exemplo: `inclua biblioteca Matematica --> mat` seria o mesmo que - * `const mat = importar('matematica')` em Delégua. + * `const mat = importar('Matematica')` em Delégua, ou + * `inclua biblioteca Matematica` (sem o nome da variável) seria o + * mesmo que `const Matematica = importar('Matematica')` * @returns Uma declaração do tipo `Importar`. */ declaracaoInclua(): Const { this.avancarEDevolverAnterior(); this.consumir(tiposDeSimbolos.BIBLIOTECA, 'Esperado palavra reservada "biblioteca" após "inclua".'); - const nomeBiblioteca = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado identificador com nome de biblioteca após palavra reservada "biblioteca"'); - this.consumir(tiposDeSimbolos.SETA, 'Esperado seta de atribuição após nome de biblioteca.'); - const constanteBiblioteca = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado identificador com nome de constante de biblioteca após seta de atribuição em declaração "inclua".'); + const nomeBiblioteca = this.consumir( + tiposDeSimbolos.IDENTIFICADOR, + 'Esperado identificador com nome de biblioteca após palavra reservada "biblioteca"' + ); + let constanteBiblioteca = nomeBiblioteca; + if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.SETA)) { + constanteBiblioteca = this.consumir( + tiposDeSimbolos.IDENTIFICADOR, + 'Esperado identificador com nome de constante de biblioteca após seta de atribuição em declaração "inclua".' + ); + } + return new Const( constanteBiblioteca, new Importar(new Literal(this.hashArquivo, nomeBiblioteca.linha, nomeBiblioteca.lexema), null) @@ -292,7 +311,6 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { let caminhoPadrao = null; while (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA) && !this.estaNoFinal()) { if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CASO)) { - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONTRARIO)) { if (caminhoPadrao !== null) { const excecao = new ErroAvaliadorSintatico( @@ -309,7 +327,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { do { declaracoes.push(this.resolverDeclaracaoForaDeBloco()); - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE); } while ( !this.verificarTipoSimboloAtual(tiposDeSimbolos.CASO) && !this.verificarTipoSimboloAtual(tiposDeSimbolos.CONTRARIO) && @@ -339,7 +357,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } else { declaracoes.push(retornoDeclaracao as Declaracao); } - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARE); } while ( !this.verificarTipoSimboloAtual(tiposDeSimbolos.CASO) && !this.verificarTipoSimboloAtual(tiposDeSimbolos.CONTRARIO) && @@ -475,7 +493,10 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } declaracaoCadeiasCaracteres(): Var[] { - const simboloCadeia = this.consumir(tiposDeSimbolos.CADEIA, ''); + const simboloCadeia = this.consumir( + tiposDeSimbolos.CADEIA, + 'Esse erro nunca deve acontecer (declaracaoCadeiasCaracteres).' + ); const inicializacoes = []; do { @@ -484,19 +505,13 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'cadeia'." ); - // Inicializações de variáveis podem ter valores definidos. - let valorInicializacao = ''; - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - const literalInicializacao = this.consumir( - tiposDeSimbolos.CADEIA, - 'Esperado literal de cadeia de caracteres após símbolo de igual em declaração de variável.' - ); - valorInicializacao = literalInicializacao.literal; - } + const dimensoes = this.logicaComumDimensoesMatrizes(); - inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloCadeia.linha), valorInicializacao), "caracter") - ); + if (dimensoes.length > 0) { + inicializacoes.push(this.declaracaoVetorOuMatriz(simboloCadeia, identificador, dimensoes, 'texto')); + } else { + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloCadeia, identificador, 'texto')); + } } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); return inicializacoes; @@ -512,19 +527,15 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'caracter'." ); - // Inicializações de variáveis podem ter valores definidos. - let valorInicializacao = ''; - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - const literalInicializacao = this.consumir( - tiposDeSimbolos.CARACTER, - 'Esperado literal de caracter após símbolo de igual em declaração de variável.' + const dimensoes = this.logicaComumDimensoesMatrizes(); + + if (dimensoes.length > 0) { + inicializacoes.push( + this.declaracaoVetorOuMatriz(simboloCaracter, identificador, dimensoes, 'caracter') ); - valorInicializacao = literalInicializacao.literal; + } else { + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloCaracter, identificador, 'caracter')); } - - inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloCaracter.linha), valorInicializacao), "caracter") - ); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); return inicializacoes; @@ -541,48 +552,91 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { return new Expressao(expressao); } - protected declaracaoVetorInteiros( - simboloInteiro: SimboloInterface, - identificador: SimboloInterface, - posicoes: number - ) { - let valorInicializacao: Vetor = new Vetor(this.hashArquivo, Number(simboloInteiro.linha), []); - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - this.consumir( - tiposDeSimbolos.CHAVE_ESQUERDA, - 'Esperado chave esquerda após sinal de igual em lado direito da atribuição de vetor.' - ); + /** + * Método recursivo que lê os valores de inicialização de uma matriz de N dimensões. + * @param {number[]} dimensoes O número de dimensões faltantes. + * Cada passo recursivo usa o primeiro valor e chama a função passando esse vetor, mas sem + * o primeiro valor. + */ + protected lerValoresAtribuicaoMatriz(dimensoes: number[]) { + this.consumir( + tiposDeSimbolos.CHAVE_ESQUERDA, + 'Esperado chave esquerda após sinal de igual em lado direito da atribuição de vetor.' + ); - const valores = []; - do { + const valores = []; + do { + if (dimensoes.length === 1) { valores.push(this.primario()); - } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); + } else { + const valoresProximaDimensao = this.lerValoresAtribuicaoMatriz(dimensoes.slice(1)); + valores.push(valoresProximaDimensao); + } + } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); - this.consumir( - tiposDeSimbolos.CHAVE_DIREITA, - 'Esperado chave direita após valores de vetor em lado direito da atribuição de vetor.' + this.consumir( + tiposDeSimbolos.CHAVE_DIREITA, + 'Esperado chave direita após valores de vetor em lado direito da atribuição de vetor.' + ); + + // TODO: Recolocar. + /* if (dimensoes !== valores.length) { + throw this.erro( + simboloInteiro, + `Esperado ${dimensoes} números, mas foram fornecidos ${valores.length} valores do lado direito da atribuição.` ); + } */ - if (posicoes !== valores.length) { - throw this.erro( - simboloInteiro, - `Esperado ${posicoes} números, mas foram fornecidos ${valores.length} valores do lado direito da atribuição.` - ); - } + return valores; + } - valorInicializacao.valores = valores; + protected declaracaoVetorOuMatriz( + simboloTipo: SimboloInterface, + identificador: SimboloInterface, + dimensoes: number[], + tipoDados: string = 'inteiro' + ) { + let valorInicializacao: Matriz = new Matriz(this.hashArquivo, Number(simboloTipo.linha), dimensoes, null); + if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { + valorInicializacao.valores = this.lerValoresAtribuicaoMatriz(dimensoes); } - return new Var(identificador, valorInicializacao, "inteiro[]"); + return new Var(identificador, valorInicializacao, `${tipoDados}[]` as any); } - protected declaracaoTrivialInteiro(simboloInteiro: SimboloInterface, identificador: SimboloInterface) { + protected declaracaoVariavelSemDimensoes( + simboloInteiro: SimboloInterface, + identificador: SimboloInterface, + tipoDados: string = 'inteiro' + ) { // Inicializações de variáveis podem ter valores definidos. let valorInicializacao: Construto = new Literal(this.hashArquivo, Number(simboloInteiro.linha), 0); if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { valorInicializacao = this.expressao(); } - return new Var(identificador, valorInicializacao, 'inteiro'); + return new Var(identificador, valorInicializacao, tipoDados as any); + } + + protected logicaComumDimensoesMatrizes(): number[] { + let dimensoes = []; + while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) { + let simboloNumeroPosicoes: SimboloInterface; + if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INTEIRO)) { + simboloNumeroPosicoes = this.simboloAnterior(); + } + + this.consumir( + tiposDeSimbolos.COLCHETE_DIREITO, + 'Esperado fechamento de identificação de número de posições de uma dimensão de vetor ou matriz.' + ); + + // Portugol Studio permite declarar vetores sem posições definidas. + // Quando isso acontece, definimos a quantidade de posições de uma dimensão como -1. + const numeroPosicoes = simboloNumeroPosicoes ? Number(simboloNumeroPosicoes.literal) : -1; + dimensoes.push(numeroPosicoes); + } + + return dimensoes; } declaracaoInteiros(): Var[] { @@ -595,25 +649,15 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'inteiro'." ); - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) { - // TODO - const numeroPosicoes = this.consumir( - tiposDeSimbolos.INTEIRO, - 'Esperado número inteiro para definir quantas posições terá o vetor.' - ); - - this.consumir( - tiposDeSimbolos.COLCHETE_DIREITO, - 'Esperado fechamento de identificação de número de posições de uma declaração de vetor.' - ); + const dimensoes = this.logicaComumDimensoesMatrizes(); - inicializacoes.push( - this.declaracaoVetorInteiros(simboloInteiro, identificador, Number(numeroPosicoes.literal)) - ); + if (dimensoes.length > 0) { + inicializacoes.push(this.declaracaoVetorOuMatriz(simboloInteiro, identificador, dimensoes)); } else { - inicializacoes.push(this.declaracaoTrivialInteiro(simboloInteiro, identificador)); + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloInteiro, identificador)); } } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); + return inicializacoes; } @@ -660,7 +704,11 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloLogico.linha), valorInicializacao), 'lógico') + new Var( + identificador, + new Literal(this.hashArquivo, Number(simboloLogico.linha), valorInicializacao), + 'lógico' + ) ); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); @@ -668,7 +716,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { } declaracaoRetorne(): Retorna { - this.avancarEDevolverAnterior() + this.avancarEDevolverAnterior(); const simboloChave = this.simbolos[this.atual]; let valor = null; @@ -714,7 +762,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { let incrementar = null; if (!this.verificarTipoSimboloAtual(tiposDeSimbolos.PARENTESE_DIREITO)) { incrementar = this.expressao(); - this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR) + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.INCREMENTAR, tiposDeSimbolos.DECREMENTAR); } this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após cláusulas"); @@ -737,29 +785,29 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { "Esperado identificador após palavra reservada 'real'." ); - // Inicializações de variáveis podem ter valores definidos. - let valorInicializacao = 0; - if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) { - const literalInicializacao = this.consumir( - tiposDeSimbolos.REAL, - 'Esperado literal real após símbolo de igual em declaração de variável.' - ); - valorInicializacao = Number(literalInicializacao.literal); - } + const dimensoes = this.logicaComumDimensoesMatrizes(); - inicializacoes.push( - new Var(identificador, new Literal(this.hashArquivo, Number(simboloReal.linha), valorInicializacao), 'real') - ); + if (dimensoes.length > 0) { + inicializacoes.push(this.declaracaoVetorOuMatriz(simboloReal, identificador, dimensoes, 'real')); + } else { + inicializacoes.push(this.declaracaoVariavelSemDimensoes(simboloReal, identificador, 'real')); + } } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); return inicializacoes; } - expressao(): Construto { return this.atribuir(); } + expressaoLimpa(): Limpa { + const simboloLimpa = this.avancarEDevolverAnterior(); + this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO, 'Esperado parêntese esquerdo após palavra reservada "limpa".'); + this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, 'Esperado parêntese direito após parêntese esquerdo que acompanha palavra reservada "limpa".'); + return new Limpa(simboloLimpa.hashArquivo, simboloLimpa.linha); + } + funcao(tipo: string): FuncaoDeclaracao { const simboloFuncao: SimboloInterface = this.avancarEDevolverAnterior(); @@ -837,6 +885,8 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { return this.declaracaoInteiros(); case tiposDeSimbolos.LEIA: return this.declaracaoLeia(); + case tiposDeSimbolos.LIMPA: + return this.expressaoLimpa(); case tiposDeSimbolos.LOGICO: return this.declaracaoLogicos(); case tiposDeSimbolos.PARA: @@ -866,9 +916,9 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase { this.hashArquivo = hashArquivo || 0; this.simbolos = retornoLexador?.simbolos || []; - this.declaracoes = [] + this.declaracoes = []; - this.validarEscopoPrograma(); + this.validarEscopoProgramaEAvaliacaoSintatica(); return { declaracoes: this.declaracoes.filter((d) => d), diff --git a/fontes/bibliotecas/calendario.ts b/fontes/bibliotecas/calendario.ts index 88621e5..8161edd 100644 --- a/fontes/bibliotecas/calendario.ts +++ b/fontes/bibliotecas/calendario.ts @@ -24,13 +24,13 @@ export async function hora_atual(formato_12h: boolean): Promise { const data = new Date(); if (!formato_12h) { return data.getHours(); - } else { - let hora = data.getHours() % 12; - if (hora === 0) { - hora = 12; - } - return hora; } + + let hora = data.getHours() % 12; + if (hora === 0) { + hora = 12; + } + return hora; } export async function minuto_atual(): Promise { @@ -73,9 +73,9 @@ export async function dia_semana_completo( } return dia; - } else { - throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); - } + } + + throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); } export async function dia_semana_curto(numero_dia: number, caixa_alta: boolean, caixa_baixa: boolean): Promise { @@ -91,9 +91,9 @@ export async function dia_semana_curto(numero_dia: number, caixa_alta: boolean, } return dia; - } else { - throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); - } + } + + throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); } export async function dia_semana_abreviado( @@ -113,7 +113,7 @@ export async function dia_semana_abreviado( } return dia; - } else { - throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); } + + throw new Error(`'${numero_dia}' não corresponde a um dia da semana válido.`); } diff --git a/fontes/construtos/index.ts b/fontes/construtos/index.ts new file mode 100644 index 0000000..f572713 --- /dev/null +++ b/fontes/construtos/index.ts @@ -0,0 +1,2 @@ +export * from './limpa'; +export * from './matriz'; diff --git a/fontes/construtos/limpa.ts b/fontes/construtos/limpa.ts new file mode 100644 index 0000000..fe4d238 --- /dev/null +++ b/fontes/construtos/limpa.ts @@ -0,0 +1,17 @@ +import { Construto } from "@designliquido/delegua"; + +import { VisitantePortugolStudioInterface } from "../interfaces"; + +export class Limpa implements Construto { + linha: number; + hashArquivo: number; + + constructor(hashArquivo: number, linha: number) { + this.hashArquivo = hashArquivo; + this.linha = linha; + } + + async aceitar(visitante: VisitantePortugolStudioInterface): Promise { + return await visitante.visitarExpressaoLimpa(this); + } +} diff --git a/fontes/construtos/matriz.ts b/fontes/construtos/matriz.ts new file mode 100644 index 0000000..8925d4c --- /dev/null +++ b/fontes/construtos/matriz.ts @@ -0,0 +1,22 @@ +import { VisitanteComumInterface } from "@designliquido/delegua"; +import { Construto } from "@designliquido/delegua/construtos"; + +import { InterpretadorPortugolStudio } from "../interpretador"; + +export class Matriz implements Construto { + linha: number; + hashArquivo: number; + dimensoes: number[]; + valores: any; + + constructor(hashArquivo: number, linha: number, dimensoes: number[], valores: any) { + this.linha = linha; + this.hashArquivo = hashArquivo; + this.dimensoes = dimensoes; + this.valores = valores; + } + + async aceitar(visitante: VisitanteComumInterface): Promise { + return await (visitante as InterpretadorPortugolStudio).visitarExpressaoMatriz(this); + } +} diff --git a/fontes/formatador/formatador-portugol-studio.ts b/fontes/formatador/formatador-portugol-studio.ts index d0fdef6..5821b0c 100644 --- a/fontes/formatador/formatador-portugol-studio.ts +++ b/fontes/formatador/formatador-portugol-studio.ts @@ -38,6 +38,7 @@ import { Atribuir, Binario, Chamada, + Comentario, Construto, DefinirValor, Dicionario, @@ -77,6 +78,22 @@ export class FormatadorPortugolStudio implements VisitanteComumInterface { this.deveIndentar = true; } + visitarDeclaracaoComentario(declaracao: Comentario): void | Promise { + if (declaracao.multilinha) { + this.codigoFormatado += `${' '.repeat(this.indentacaoAtual)}/`; + + for (let linhaConteudo of (declaracao.conteudo as string[])) { + this.codigoFormatado += `${' '.repeat(this.indentacaoAtual)}* ${linhaConteudo.replace(/\s+/g, " ")}${this.quebraLinha}`; + } + + this.codigoFormatado += `${' '.repeat(this.indentacaoAtual)} */${this.quebraLinha}`; + } else { + this.codigoFormatado += `${' '.repeat(this.indentacaoAtual)}// `; + this.codigoFormatado += (declaracao.conteudo as string).replace(/\s+/g, " "); + this.codigoFormatado += `${this.quebraLinha}`; + } + } + visitarDeclaracaoTendoComo(declaracao: TendoComo): void | Promise { throw new Error('Método não implementado.'); } @@ -92,9 +109,11 @@ export class FormatadorPortugolStudio implements VisitanteComumInterface { visitarExpressaoTupla(expressao: Tupla): Promise { throw new Error('Método não implementado'); } + visitarDeclaracaoClasse(declaracao: Classe) { throw new Error('Método não implementado'); } + visitarDeclaracaoConst(declaracao: Const): any { this.codigoFormatado += `${' '.repeat(this.indentacaoAtual)}const ${declaracao.tipo} ${ declaracao.simbolo.lexema diff --git a/fontes/interfaces/index.ts b/fontes/interfaces/index.ts new file mode 100644 index 0000000..46fb5c4 --- /dev/null +++ b/fontes/interfaces/index.ts @@ -0,0 +1 @@ +export * from './visitante-portugol-studio-interface'; diff --git a/fontes/interfaces/visitante-portugol-studio-interface.ts b/fontes/interfaces/visitante-portugol-studio-interface.ts new file mode 100644 index 0000000..ee292d3 --- /dev/null +++ b/fontes/interfaces/visitante-portugol-studio-interface.ts @@ -0,0 +1,7 @@ +import { VisitanteComumInterface } from "@designliquido/delegua"; + +import { Limpa } from "../construtos/limpa"; + +export interface VisitantePortugolStudioInterface extends VisitanteComumInterface { + visitarExpressaoLimpa(expressao: Limpa): void | Promise; +} \ No newline at end of file diff --git a/fontes/interpretador/comum.ts b/fontes/interpretador/comum.ts index b98c38c..16e452b 100644 --- a/fontes/interpretador/comum.ts +++ b/fontes/interpretador/comum.ts @@ -1,13 +1,36 @@ -import { Variavel } from '@designliquido/delegua/construtos'; +import { Construto, Variavel } from '@designliquido/delegua/construtos'; import { Expressao, Importar, Leia } from '@designliquido/delegua/declaracoes'; import { PilhaEscoposExecucaoInterface } from '@designliquido/delegua/interfaces/pilha-escopos-execucao-interface'; import { DeleguaModulo, FuncaoPadrao } from '@designliquido/delegua/estruturas'; import { ErroEmTempoDeExecucao } from '@designliquido/delegua/excecoes'; +import { InterpretadorBase } from '@designliquido/delegua'; +import { Matriz } from '../construtos/matriz'; + +import * as calendario from '../bibliotecas/calendario'; import * as matematica from '../bibliotecas/matematica'; import * as texto from '../bibliotecas/texto'; import * as util from '../bibliotecas/util'; +function carregarBibliotecaCalendario(): DeleguaModulo { + const metodos: { [nome: string]: FuncaoPadrao } = { + dia_mes_atual: new FuncaoPadrao(0, calendario.dia_mes_atual), + dia_semana_atual: new FuncaoPadrao(0, calendario.dia_semana_atual), + mes_atual: new FuncaoPadrao(0, calendario.mes_atual), + ano_atual: new FuncaoPadrao(0, calendario.ano_atual), + hora_atual: new FuncaoPadrao(0, calendario.hora_atual), + minuto_atual: new FuncaoPadrao(0, calendario.minuto_atual), + segundo_atual: new FuncaoPadrao(0, calendario.segundo_atual), + milisegundo_atual: new FuncaoPadrao(0, calendario.milisegundo_atual), + dia_semana_completo: new FuncaoPadrao(0, calendario.dia_semana_completo), + dia_semana_curto: new FuncaoPadrao(0, calendario.dia_semana_completo), + }; + + const objetoCalendario = new DeleguaModulo('Calendario'); + objetoCalendario.componentes = metodos; + return objetoCalendario; +} + function carregarBibliotecaMatematica(): DeleguaModulo { const metodos: { [nome: string]: FuncaoPadrao } = { potencia: new FuncaoPadrao(2, matematica.potencia), @@ -60,8 +83,29 @@ function carregarBibliotecaUtil(): DeleguaModulo { return objetoUtil; } +/** + * Avaliação de argumentos para `escreva`. Diferentemente de outros dialetos, aqui não ocorre `trimEnd`, já que `\n` + * É significativo para Portugol Studio. + * @param interpretador A instância do interpretador. + * @param argumentos Os argumentos. + * @returns {string} O texto formatado. + */ +export async function avaliarArgumentosEscreva(interpretador: InterpretadorBase, argumentos: Construto[]): Promise { + let formatoTexto: string = ''; + + for (const argumento of argumentos) { + const resultadoAvaliacao = await interpretador.avaliar(argumento); + let valor = resultadoAvaliacao?.hasOwnProperty('valor') ? resultadoAvaliacao.valor : resultadoAvaliacao; + formatoTexto += `${interpretador.paraTexto(valor)} `; + } + + return formatoTexto; +} + export async function visitarExpressaoImportarComum(expressao: Importar): Promise { switch (expressao.caminho.valor) { + case 'Calendario': + return carregarBibliotecaCalendario(); case 'Matematica': return carregarBibliotecaMatematica(); case 'Texto': @@ -101,3 +145,30 @@ export async function visitarExpressaoLeiaComum( pilhaEscoposExecucao.definirVariavel(simbolo.lexema, valorLido); } } + +export async function visitarExpressaoMatrizComum( + interpretador: InterpretadorBase, + expressao: Matriz +): Promise { + return await resolverValoresMatriz(interpretador, expressao.valores); +} + +/** + * Função recursiva que visita todos os valores de uma matriz. + * @param interpretador A instância do interpretador. + * @param valores A matriz de valores das dimensões ainda não resolvidas. + */ +async function resolverValoresMatriz(interpretador: InterpretadorBase, valores: any[]) { + const valoresResolvidos = []; + if (valores && valores.length > 0) { + for (let i = 0; i < valores.length; i++) { + if (Array.isArray(valores[i])) { + valoresResolvidos.push(await resolverValoresMatriz(interpretador, valores[i])); + } else { + valoresResolvidos.push(await interpretador.avaliar(valores[i])); + } + } + } + + return valoresResolvidos; +} \ No newline at end of file diff --git a/fontes/interpretador/interpretador-portugol-studio-com-depuracao.ts b/fontes/interpretador/interpretador-portugol-studio-com-depuracao.ts index 984b7c5..e88b181 100644 --- a/fontes/interpretador/interpretador-portugol-studio-com-depuracao.ts +++ b/fontes/interpretador/interpretador-portugol-studio-com-depuracao.ts @@ -1,19 +1,34 @@ import { Importar, Leia } from '@designliquido/delegua/declaracoes'; import { InterpretadorComDepuracao } from '@designliquido/delegua/interpretador/interpretador-com-depuracao'; -import { PilhaEscoposExecucaoPortugolStudio } from './pilha-escopos-execucao-portugol-studio'; import { DeleguaModulo } from '@designliquido/delegua/estruturas'; +import { PilhaEscoposExecucaoPortugolStudio } from './pilha-escopos-execucao-portugol-studio'; +import { Matriz } from '../construtos/matriz'; +import { VisitantePortugolStudioInterface } from '../interfaces'; +import { Limpa } from '../construtos'; + import * as comum from './comum'; -export class InterpretadorPortugolStudioComDepuracao extends InterpretadorComDepuracao { +export class InterpretadorPortugolStudioComDepuracao extends InterpretadorComDepuracao implements VisitantePortugolStudioInterface { mensagemPrompt: string; + funcaoLimpa: Function = () => { console.log('Função "limpa()" não está ligada a uma interface de entrada e saída.') }; - constructor(diretorioBase: string, funcaoDeRetorno: Function = null, funcaoDeRetornoMesmaLinha: Function = null) { + constructor(diretorioBase: string, funcaoDeRetorno: Function = null, funcaoDeRetornoMesmaLinha: Function = null, funcaoLimpa: Function = null) { super(diretorioBase, funcaoDeRetorno, funcaoDeRetornoMesmaLinha); + + if (funcaoLimpa !== null) { + this.funcaoLimpa = funcaoLimpa; + } + this.mensagemPrompt = '> '; this.pilhaEscoposExecucao = new PilhaEscoposExecucaoPortugolStudio(); } + async visitarExpressaoLimpa(expressao: Limpa): Promise { + this.funcaoLimpa(); + return Promise.resolve(); + } + async visitarDeclaracaoImportar(declaracao: Importar): Promise { return comum.visitarExpressaoImportarComum(declaracao); } @@ -28,6 +43,10 @@ export class InterpretadorPortugolStudioComDepuracao extends InterpretadorComDep return comum.visitarExpressaoLeiaComum(this.interfaceEntradaSaida, this.pilhaEscoposExecucao, expressao); } + async visitarExpressaoMatriz(expressao: Matriz): Promise { + return comum.visitarExpressaoMatrizComum(this, expressao); + } + /** * No Portugol Studio, como o bloco de execução da função `inicio` é criado * pelo avaliador sintático, precisamos ter uma forma aqui de avançar o diff --git a/fontes/interpretador/interpretador-portugol-studio.ts b/fontes/interpretador/interpretador-portugol-studio.ts index e2612b4..0c388fb 100644 --- a/fontes/interpretador/interpretador-portugol-studio.ts +++ b/fontes/interpretador/interpretador-portugol-studio.ts @@ -1,15 +1,26 @@ -import { Importar, Leia } from '@designliquido/delegua/declaracoes'; +import { EscrevaMesmaLinha, Importar, Leia } from '@designliquido/delegua/declaracoes'; import { InterpretadorBase } from '@designliquido/delegua/interpretador/interpretador-base'; import { EscopoExecucao } from '@designliquido/delegua/interfaces/escopo-execucao'; import { EspacoVariaveis } from '@designliquido/delegua/espaco-variaveis'; import { DeleguaModulo } from '@designliquido/delegua/estruturas'; +import { Matriz } from '../construtos/matriz'; import { PilhaEscoposExecucaoPortugolStudio } from './pilha-escopos-execucao-portugol-studio'; +import { VisitantePortugolStudioInterface } from '../interfaces'; +import { Limpa } from '../construtos'; + import * as comum from './comum'; -export class InterpretadorPortugolStudio extends InterpretadorBase { - constructor(diretorioBase: string, performance = false, funcaoDeRetorno: Function = null) { +export class InterpretadorPortugolStudio extends InterpretadorBase implements VisitantePortugolStudioInterface { + funcaoLimpa: Function = () => { console.log('Função "limpa()" não está ligada a uma interface de entrada e saída.') }; + + constructor(diretorioBase: string, performance = false, funcaoDeRetorno: Function = null, funcaoLimpa: Function = null) { super(diretorioBase, performance, funcaoDeRetorno); + + if (funcaoLimpa !== null) { + this.funcaoLimpa = funcaoLimpa; + } + this.pilhaEscoposExecucao = new PilhaEscoposExecucaoPortugolStudio(); const escopoExecucao: EscopoExecucao = { declaracoes: [], @@ -21,6 +32,11 @@ export class InterpretadorPortugolStudio extends InterpretadorBase { }; this.pilhaEscoposExecucao.empilhar(escopoExecucao); } + + async visitarExpressaoLimpa(expressao: Limpa): Promise { + this.funcaoLimpa(); + return Promise.resolve(); + } async visitarDeclaracaoImportar(declaracao: Importar): Promise { return comum.visitarExpressaoImportarComum(declaracao); @@ -35,4 +51,28 @@ export class InterpretadorPortugolStudio extends InterpretadorBase { async visitarExpressaoLeia(expressao: Leia): Promise { return comum.visitarExpressaoLeiaComum(this.interfaceEntradaSaida, this.pilhaEscoposExecucao, expressao); } + + async visitarExpressaoMatriz(expressao: Matriz): Promise { + return comum.visitarExpressaoMatrizComum(this, expressao); + } + + /** + * Execução de uma escrita na saída padrão, sem quebras de linha. + * Implementada para alguns dialetos, como VisuAlg. + * @param declaracao A declaração. + * @returns Sempre nulo, por convenção de visita. + */ + async visitarDeclaracaoEscrevaMesmaLinha(declaracao: EscrevaMesmaLinha): Promise { + try { + const formatoTexto: string = await comum.avaliarArgumentosEscreva(this, declaracao.argumentos); + this.funcaoDeRetornoMesmaLinha(formatoTexto); + return null; + } catch (erro: any) { + this.erros.push({ + erroInterno: erro, + linha: declaracao.linha, + hashArquivo: declaracao.hashArquivo, + }); + } + } } diff --git a/fontes/lexador/palavras-reservadas.ts b/fontes/lexador/palavras-reservadas.ts index ef8401a..64f6f2f 100644 --- a/fontes/lexador/palavras-reservadas.ts +++ b/fontes/lexador/palavras-reservadas.ts @@ -17,6 +17,7 @@ export const palavrasReservadas = { inclua: tiposDeSimbolos.INCLUA, inteiro: tiposDeSimbolos.INTEIRO, leia: tiposDeSimbolos.LEIA, + limpa: tiposDeSimbolos.LIMPA, logico: tiposDeSimbolos.LOGICO, nao: tiposDeSimbolos.NEGACAO, ou: tiposDeSimbolos.OU, diff --git a/fontes/tipos-de-simbolos/lexico-regular.ts b/fontes/tipos-de-simbolos/lexico-regular.ts index 20ad126..9c4b40c 100644 --- a/fontes/tipos-de-simbolos/lexico-regular.ts +++ b/fontes/tipos-de-simbolos/lexico-regular.ts @@ -30,6 +30,7 @@ export default { INCLUA: 'INCLUA', INTEIRO: 'INTEIRO', LEIA: 'LEIA', + LIMPA: 'LIMPA', LOGICO: 'LOGICO', MAIOR: 'MAIOR', MAIOR_IGUAL: 'MAIOR_IGUAL', diff --git a/package.json b/package.json index 2492ea9..8aa115e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@designliquido/portugol-studio", "description": "Dialeto de Portugol Studio baseado em Delégua e TypeScript", - "version": "0.1.0", + "version": "0.2.1", "license": "MIT", "bugs": { "url": "https://github.com/DesignLiquido/portugol-studio/issues" @@ -24,7 +24,8 @@ "deixar-codigo-bonito": "prettier --config .prettierrc --write fontes/**/*.ts" }, "dependencies": { - "@designliquido/delegua": "^0.33.15", + "@designliquido/delegua": "^0.34.0", + "lodash": "^4.17.21", "node-fetch": "2" }, "devDependencies": { diff --git a/testes/avaliador-sintatico.test.ts b/testes/avaliador-sintatico.test.ts index fbbf38a..b608932 100644 --- a/testes/avaliador-sintatico.test.ts +++ b/testes/avaliador-sintatico.test.ts @@ -1,7 +1,9 @@ import { ErroAvaliadorSintatico } from "@designliquido/delegua/avaliador-sintatico"; +import { FuncaoDeclaracao } from "@designliquido/delegua"; import { AvaliadorSintaticoPortugolStudio } from "../fontes"; import { LexadorPortugolStudio } from "../fontes/lexador/lexador-portugol-studio"; +import { Limpa } from "../fontes/construtos"; describe('Avaliador sintático (Portugol Studio)', () => { @@ -57,7 +59,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThanOrEqual(2); }); it('Sucesso - Agrupamento', async () => { @@ -82,7 +84,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Sucesso - Leia', () => { @@ -104,7 +106,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Sucesso - Funções', () => { @@ -181,7 +183,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Estruturas de repetição - Enquanto', () => { @@ -209,7 +211,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Estruturas de repetição - Faca ... Enquanto', () => { @@ -235,7 +237,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Estruturas de repetição - Para', () => { @@ -252,7 +254,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Atribuição de Variáveis', () => { @@ -269,7 +271,7 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Atribuição de Vetores', () => { @@ -285,10 +287,28 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); }); it('Importação de bibliotecas', () => { + const resultado = lexador.mapear([ + 'programa', + '{', + ' inclua biblioteca Matematica', + ' funcao inicio()', + ' {', + ' escreva(Matematica.raiz(4.0, 2.0))', + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); + + expect(retornoAvaliadorSintatico).toBeTruthy(); + expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThanOrEqual(2); + }); + + it('Importação de bibliotecas, com nome de constante definido', () => { const resultado = lexador.mapear([ 'programa', '{', @@ -303,7 +323,49 @@ describe('Avaliador sintático (Portugol Studio)', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(resultado, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0); + expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThanOrEqual(2); + }); + + it('Matrizes', () => { + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' funcao inicio()', + ' {', + ' //Declaração de uma matriz de inteiros', + ' // de duas linhas e duas colunas já inicializado.', + ' inteiro matriz[2][2] = {{15,22},{10,11}}', + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + + expect(retornoAvaliadorSintatico).toBeTruthy(); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); + }); + + it('limpa()', () => { + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' funcao inicio()', + ' {', + ` escreva('1, 2, 3')`, + ' limpa()', + ` escreva('4, 5, 6')`, + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + + expect(retornoAvaliadorSintatico).toBeTruthy(); + expect(retornoAvaliadorSintatico.declaracoes.length).toBe(2); + const declaracaoFuncao = retornoAvaliadorSintatico.declaracoes[0]; + expect(declaracaoFuncao).toBeInstanceOf(FuncaoDeclaracao); + expect((declaracaoFuncao as FuncaoDeclaracao).funcao.corpo.length).toBe(3); + expect((declaracaoFuncao as FuncaoDeclaracao).funcao.corpo[1]).toBeInstanceOf(Limpa); }); }); diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts index 7928959..f592f63 100644 --- a/testes/interpretador.test.ts +++ b/testes/interpretador.test.ts @@ -398,6 +398,30 @@ describe('Interpretador (Portugol Studio)', () => { _saidas += saida; } + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' inclua biblioteca Matematica', + ' funcao inicio()', + ' {', + ' escreva(Matematica.raiz(81.0, 2.0))', + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(retornoInterpretador.erros).toHaveLength(0); + expect(_saidas).toContain('9'); + }); + + it('Biblioteca matemática, com nome de variável', async () => { + let _saidas = ""; + interpretador.funcaoDeRetornoMesmaLinha = (saida: string) => { + _saidas += saida; + } + const retornoLexador = lexador.mapear([ 'programa', '{', @@ -413,7 +437,114 @@ describe('Interpretador (Portugol Studio)', () => { const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); expect(retornoInterpretador.erros).toHaveLength(0); - expect(_saidas).toBe('9'); + expect(_saidas).toContain('9'); + }); + + describe('Matrizes', () => { + it('Operações Básicas', async () => { + let _saidas = ""; + interpretador.funcaoDeRetornoMesmaLinha = (saida: string) => { + _saidas += saida; + } + + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' funcao inicio()', + ' {', + ' //Declaração de uma matriz de inteiros', + ' // de duas linhas e duas colunas já inicializado.', + ' inteiro matriz[2][2] = {{15,22},{10,11}}', + + ' //Atribui -1 na primeira linha e segunda', + ' // coluna da matriz.', + ' matriz[0][1] = -1', + + ' //Imprime o valor 15 correspondente ', + ' // a primeira linha e primeira coluna da matriz.', + ' inteiro i = 0', + ' escreva(matriz[i][0])', + ' escreva("\n")', + + ' //Imprime o valor 11 correspondente ', + ' // a última linha e última coluna da matriz.', + ' escreva(matriz[1][1])', + + ' //Declaração de uma matriz de reais de ', + ' // duas linhas e quatro colunas.', + ' real outra_matriz[2][4]', + + ' //Declaração de uma matriz de caracteres onde o tamanho', + ' // de linhas e colunas são definidos pela inicialização', + ` caracter jogo_velha[][] = {{'X','O','X'}`, + ` ,{'O','X','O'}`, + ` ,{' ',' ','X'}}`, + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(retornoInterpretador.erros).toHaveLength(0); + expect(_saidas.length).toBeGreaterThanOrEqual(4); + }); + + it('Matrizes com Para', async () => { + let _saidas = ""; + interpretador.funcaoDeRetornoMesmaLinha = (saida: string) => { + _saidas += saida; + } + + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' funcao inicio()', + ' {', + ' cadeia nome[] = { "João", "Ana" , "Tiago", "Luiz", "Carlos" }', + ' real altura[] = { 5.7, 8.8, 9.75, 1.32, 9.93 }', + ' // Cria o cabeçalho da tabela', + ' escreva ("--------------------\n")', + ' escreva (" TABELA \n")', + ' escreva ("--------------------\n")', + ' para (inteiro posicao = 0; posicao < 5; posicao++)', + ' {', + ' escreva (nome[posicao], "\t\t", altura [posicao], "\n")', + ' }', + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(retornoInterpretador.erros).toHaveLength(0); + expect(_saidas.length).toBeGreaterThan(0); + }); + }); + + describe('Função limpa()', () => { + it('Trivial', async () => { + const metodoVisitarExpressaoLimpa = jest.spyOn(interpretador, 'visitarExpressaoLimpa'); + + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' funcao inicio()', + ' {', + ` escreva('1, 2, 3')`, + ' limpa()', + ` escreva('4, 5, 6')`, + ' }', + '}' + ], -1); + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(retornoInterpretador.erros).toHaveLength(0); + expect(metodoVisitarExpressaoLimpa).toHaveBeenCalledTimes(1); + }); }); }); }); diff --git a/yarn.lock b/yarn.lock index c4a84e3..3e85ae2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@designliquido/delegua@^0.33.15": - version "0.33.15" - resolved "https://registry.yarnpkg.com/@designliquido/delegua/-/delegua-0.33.15.tgz#c7ab793e4931fbaea51ab671e47e1924078914d7" - integrity sha512-5Tv8qxVcnYOPA+MZ8Y7HyobxZOsWM1/bOkwcbdgrGenL4iUMucRmwx3DILbIrg5uPWVtNibWUlMxrEGYf3+jTQ== +"@designliquido/delegua@^0.34.0": + version "0.34.0" + resolved "https://registry.yarnpkg.com/@designliquido/delegua/-/delegua-0.34.0.tgz#6a24460194eac7caf411c65115bb065b1c9d8960" + integrity sha512-5vF/5x2jLaDN8NrX/xZ2PRaDbD4JhulmjtUeKBUUM1P15V9GAiF7D51+dEufM9i/OZtX32IJV7zDVexM/9NuwA== dependencies: antlr4ts "^0.5.0-alpha.4" browser-process-hrtime "^1.0.0" @@ -1878,6 +1878,11 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"