@designliquido/delegua 0.11.14 → 0.12.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.
Files changed (61) hide show
  1. package/bin/package.json +1 -1
  2. package/fontes/construtos/atribuir.js +1 -1
  3. package/fontes/construtos/atribuir.js.map +1 -1
  4. package/fontes/construtos/chamada.d.ts +2 -0
  5. package/fontes/construtos/chamada.js +20 -0
  6. package/fontes/construtos/chamada.js.map +1 -1
  7. package/fontes/declaracoes/classe.js +1 -1
  8. package/fontes/declaracoes/classe.js.map +1 -1
  9. package/fontes/declaracoes/enquanto.js +1 -1
  10. package/fontes/declaracoes/enquanto.js.map +1 -1
  11. package/fontes/declaracoes/escolha.js +1 -1
  12. package/fontes/declaracoes/escolha.js.map +1 -1
  13. package/fontes/declaracoes/escreva.js +1 -1
  14. package/fontes/declaracoes/escreva.js.map +1 -1
  15. package/fontes/declaracoes/fazer.js +1 -1
  16. package/fontes/declaracoes/fazer.js.map +1 -1
  17. package/fontes/declaracoes/funcao.js +1 -1
  18. package/fontes/declaracoes/funcao.js.map +1 -1
  19. package/fontes/declaracoes/importar.js +1 -1
  20. package/fontes/declaracoes/importar.js.map +1 -1
  21. package/fontes/declaracoes/para.js +1 -1
  22. package/fontes/declaracoes/para.js.map +1 -1
  23. package/fontes/declaracoes/se.js +1 -1
  24. package/fontes/declaracoes/se.js.map +1 -1
  25. package/fontes/declaracoes/tente.js +1 -1
  26. package/fontes/declaracoes/tente.js.map +1 -1
  27. package/fontes/declaracoes/var.js +1 -1
  28. package/fontes/declaracoes/var.js.map +1 -1
  29. package/fontes/depuracao/servidor-depuracao.d.ts +2 -1
  30. package/fontes/depuracao/servidor-depuracao.js +43 -13
  31. package/fontes/depuracao/servidor-depuracao.js.map +1 -1
  32. package/fontes/espaco-variaveis.d.ts +12 -0
  33. package/fontes/espaco-variaveis.js +10 -0
  34. package/fontes/espaco-variaveis.js.map +1 -1
  35. package/fontes/estruturas/delegua-funcao.d.ts +3 -0
  36. package/fontes/estruturas/delegua-funcao.js +3 -0
  37. package/fontes/estruturas/delegua-funcao.js.map +1 -1
  38. package/fontes/interfaces/escopo-execucao.d.ts +4 -0
  39. package/fontes/interfaces/interpretador-com-depuracao-interface.d.ts +7 -5
  40. package/fontes/interfaces/interpretador-interface.d.ts +12 -18
  41. package/fontes/interfaces/pilha-escopos-execucao-interface.d.ts +2 -1
  42. package/fontes/interfaces/resolvedor-interface.d.ts +0 -12
  43. package/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.d.ts +12 -12
  44. package/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.js +19 -13
  45. package/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.js.map +1 -1
  46. package/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.d.ts +12 -12
  47. package/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.js +12 -12
  48. package/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.js.map +1 -1
  49. package/fontes/interpretador/dialetos/visualg.d.ts +1 -1
  50. package/fontes/interpretador/dialetos/visualg.js +1 -1
  51. package/fontes/interpretador/dialetos/visualg.js.map +1 -1
  52. package/fontes/interpretador/interpretador-com-depuracao.d.ts +83 -12
  53. package/fontes/interpretador/interpretador-com-depuracao.js +238 -111
  54. package/fontes/interpretador/interpretador-com-depuracao.js.map +1 -1
  55. package/fontes/interpretador/interpretador.d.ts +25 -24
  56. package/fontes/interpretador/interpretador.js +35 -21
  57. package/fontes/interpretador/interpretador.js.map +1 -1
  58. package/fontes/interpretador/pilha-escopos-execucao.d.ts +2 -1
  59. package/fontes/interpretador/pilha-escopos-execucao.js +10 -1
  60. package/fontes/interpretador/pilha-escopos-execucao.js.map +1 -1
  61. package/package.json +1 -1
@@ -1,9 +1,12 @@
1
1
  import { EspacoVariaveis } from '../espaco-variaveis';
2
- import { Declaracao } from '../declaracoes';
2
+ import { Declaracao, Retorna, Var } from '../declaracoes';
3
3
  import { PontoParada } from '../depuracao';
4
- import { ImportadorInterface, InterpretadorComDepuracaoInterface } from '../interfaces';
4
+ import { ComandoDepurador, ImportadorInterface, InterpretadorComDepuracaoInterface } from '../interfaces';
5
+ import { TipoEscopoExecucao } from '../interfaces/escopo-execucao';
6
+ import { RetornoQuebra } from '../quebras';
5
7
  import { Interpretador } from './interpretador';
6
8
  import { RetornoInterpretador } from '../interfaces/retornos/retorno-interpretador';
9
+ import { Atribuir, Chamada } from '../construtos';
7
10
  /**
8
11
  * Implementação do Interpretador com suporte a depuração.
9
12
  * Herda o Interpretador padrão de Delégua e implementa métodos a mais, que são
@@ -29,9 +32,42 @@ export declare class InterpretadorComDepuracao extends Interpretador implements
29
32
  finalizacaoDaExecucao: Function;
30
33
  pontoDeParadaAtivo: boolean;
31
34
  escopoAtual: number;
32
- comandoAdentrarEscopo: boolean;
33
- comandoProximo: boolean;
35
+ comando?: ComandoDepurador;
36
+ executandoChamada: boolean;
37
+ proximoEscopo?: TipoEscopoExecucao;
38
+ idChamadaAtual?: string;
39
+ passos: number;
34
40
  constructor(importador: ImportadorInterface, diretorioBase: string, funcaoDeRetorno: Function);
41
+ private gerarIdResolucaoChamada;
42
+ visitarExpressaoDeChamada(expressao: Chamada): Promise<any>;
43
+ /**
44
+ * A execução de uma atribuição de variável no interpretador com depuração pode ser em duas etapas.
45
+ * O desenvolvedor pode inspecionar o lado direito e ir parando a execução usando
46
+ * F10, por exemplo. Neste caso, a instrução aqui é executada duas vezes:
47
+ * A primeira para armazenar o valor do lado direito em `this.valorRetornoEscopoAnterior`, e a
48
+ * segunda para efetivamente atribuir o valor da variável.
49
+ * @param expressao
50
+ * @returns
51
+ */
52
+ visitarDeclaracaoDeAtribuicao(expressao: Atribuir): Promise<any>;
53
+ /**
54
+ * A execução de `var` no interpretador com depuração pode ser em duas etapas.
55
+ * O desenvolvedor pode inspecionar o lado direito e ir parando a execução usando
56
+ * F10, por exemplo. Neste caso, a instrução aqui é executada duas vezes:
57
+ * A primeira para armazenar o valor do lado direito em `this.valorRetornoEscopoAnterior`, e a
58
+ * segunda para efetivamente atribuir o valor da variável.
59
+ * @param declaracao A declaração Var
60
+ * @returns O valor do resultado resolvido, se a declaração resolveu.
61
+ * Nulo ou indefinido em caso contrário.
62
+ */
63
+ visitarDeclaracaoVar(declaracao: Var): Promise<any>;
64
+ /**
65
+ * Ao executar um retorno, manter o valor retornado no Interpretador para
66
+ * uso por linhas que foram executadas com o comando `próximo` do depurador.
67
+ * @param declaracao Uma declaracao Retorna
68
+ * @returns O resultado da execução da visita.
69
+ */
70
+ visitarExpressaoRetornar(declaracao: Retorna): Promise<RetornoQuebra>;
35
71
  /**
36
72
  * Se bloco de execução já foi instanciado antes (por exemplo, quando há um ponto de parada e a
37
73
  * execução do código é retomada pelo depurador), retoma a execução do bloco do ponto em que havia parado.
@@ -48,7 +84,21 @@ export declare class InterpretadorComDepuracao extends Interpretador implements
48
84
  * @param declaracao A declaração a ser executada.
49
85
  * @returns True quando execução deve parar. False caso contrário.
50
86
  */
51
- verificarPontoParada(declaracao: Declaracao): boolean;
87
+ private verificarPontoParada;
88
+ /**
89
+ * No interpretador com depuração, este método é dividido em dois outros métodos privados:
90
+ * - `this.executarUmPassoNoEscopo`, que executa apenas uma instrução e nada mais;
91
+ * - `this.executarUltimoEscopoComandoContinuar`, que é a execução trivial de um escopo inteiro,
92
+ * ou com todas as instruções, ou até encontrar um ponto de parada.
93
+ * @param manterAmbiente Se verdadeiro, junta elementos do último escopo com o escopo
94
+ * imediatamente abaixo.
95
+ * @param naoVerificarPrimeiraExecucao Booleano que pede ao Interpretador para não
96
+ * verificar o ponto de parada na primeira execução.
97
+ * Normalmente usado pelo Servidor de Depuração para continuar uma linha.
98
+ * @returns O retorno da execução.
99
+ */
100
+ executarUltimoEscopo(manterAmbiente?: boolean, naoVerificarPrimeiraExecucao?: boolean): Promise<any>;
101
+ private executarUmPassoNoEscopo;
52
102
  /**
53
103
  * Continua a interpretação parcial do último ponto em que parou.
54
104
  * Pode ser tanto o começo da execução inteira, ou pós comando do depurador
@@ -60,7 +110,7 @@ export declare class InterpretadorComDepuracao extends Interpretador implements
60
110
  * Normalmente usado pelo Servidor de Depuração para continuar uma linha.
61
111
  * @returns Um objeto de retorno, com erros encontrados se houverem.
62
112
  */
63
- executarUltimoEscopo(manterAmbiente?: boolean, naoVerificarPrimeiraExecucao?: boolean): Promise<any>;
113
+ private executarUltimoEscopoComandoContinuar;
64
114
  /**
65
115
  * Continua a interpretação, conforme comando do depurador.
66
116
  * Quando um ponto de parada é ativado, a pilha de execução do TypeScript é perdida.
@@ -69,34 +119,55 @@ export declare class InterpretadorComDepuracao extends Interpretador implements
69
119
  * Diferentemente de `executarUltimoEscopo`, este método descarta apenas um escopo (o que foi chamado).
70
120
  * @see executarBloco
71
121
  */
72
- continuarInterpretacao(): Promise<any>;
73
- private descartarEscoposFinalizados;
122
+ instrucaoContinuarInterpretacao(): Promise<any>;
123
+ /**
124
+ * Empilha um escopo se for possível.
125
+ * Se não for, apenas executa a instrução corrente.
126
+ */
127
+ adentrarEscopo(): Promise<any>;
74
128
  /**
75
129
  * Interpreta apenas uma instrução a partir do ponto de parada ativo, conforme comando do depurador.
76
130
  * Esse método cria uma nova pilha de execução do lado do JS, começando do último elemento executado do
77
131
  * primeiro escopo, subindo até o último elemento executado do último escopo.
78
132
  * @param escopo Indica o escopo a ser visitado. Usado para construir uma pilha de chamadas do lado JS.
79
133
  */
80
- interpretarApenasUmaInstrucao(escopo?: number): Promise<void>;
134
+ instrucaoPasso(escopo?: number): Promise<any>;
81
135
  /**
82
136
  * Interpreta restante do bloco de execução em que o ponto de parada está, conforme comando do depurador.
83
137
  * Se houver outros pontos de parada no mesmo escopo à frente da instrução atual, todos são ignorados.
84
138
  * @param escopo Indica o escopo a ser visitado. Usado para construir uma pilha de chamadas do lado JS.
85
139
  */
86
- proximoESair(escopo?: number): Promise<void>;
140
+ instrucaoProximoESair(): Promise<void>;
87
141
  /**
88
142
  * Prepara a pilha de escopos para uma situação de depuração.
89
143
  * Não há execução de código neste caso.
90
144
  * @param declaracoes Um vetor de declarações.
91
145
  */
92
146
  prepararParaDepuracao(declaracoes: Declaracao[]): void;
147
+ private abrirNovoBlocoEscopo;
148
+ /**
149
+ * Reimplementando este método aqui porque a execução por depuração não requer
150
+ * mostrar o resultado em momento algum, ou lidar com o retorno.
151
+ * @param declaracao A declaracao a ser executada.
152
+ * @param mostrarResultado Sempre falso.
153
+ * @returns O resultado da execução.
154
+ */
155
+ executar(declaracao: Declaracao, mostrarResultado?: boolean): Promise<any>;
93
156
  /**
94
- * Interpretação utilizada pelo depurador. Pode encerrar ao encontrar um
95
- * ponto de parada ou não.
157
+ * Interpretação utilizada pelo depurador para avaliar valores de variáveis.
96
158
  * Diferentemente da interpretação tradicional, não possui indicadores
97
159
  * de performance porque eles não fazem sentido aqui.
98
160
  * @param declaracoes Um vetor de declarações.
99
161
  * @returns Um objeto de retorno, com erros encontrados se houverem.
100
162
  */
101
163
  interpretar(declaracoes: Declaracao[], manterAmbiente?: boolean): Promise<RetornoInterpretador>;
164
+ /**
165
+ * Obtém o valor de uma variável por nome.
166
+ * Em versões anteriores, o mecanismo de avaliação fazia toda a avaliação tradicional,
167
+ * passando por Lexador, Avaliador Sintático e Interpretador.
168
+ * Isso tem sua cota de problemas, sobretudo porque a avaliação insere e descarta escopos,
169
+ * entrando em condição de corrida com a interpretação com depuração.
170
+ * @param nome O nome da variável.
171
+ */
172
+ obterVariavel(nome: string): any;
102
173
  }
@@ -4,6 +4,8 @@ exports.InterpretadorComDepuracao = void 0;
4
4
  const espaco_variaveis_1 = require("../espaco-variaveis");
5
5
  const quebras_1 = require("../quebras");
6
6
  const interpretador_1 = require("./interpretador");
7
+ const construtos_1 = require("../construtos");
8
+ const inferenciador_1 = require("./inferenciador");
7
9
  /**
8
10
  * Implementação do Interpretador com suporte a depuração.
9
11
  * Herda o Interpretador padrão de Delégua e implementa métodos a mais, que são
@@ -30,8 +32,101 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
30
32
  this.pontosParada = [];
31
33
  this.pontoDeParadaAtivo = false;
32
34
  this.escopoAtual = 0;
33
- this.comandoAdentrarEscopo = false;
34
- this.comandoProximo = false;
35
+ this.executandoChamada = false;
36
+ this.passos = 0;
37
+ }
38
+ async gerarIdResolucaoChamada(expressao) {
39
+ const argumentosResolvidos = [];
40
+ for (let argumento of expressao.argumentos) {
41
+ argumentosResolvidos.push(await this.avaliar(argumento));
42
+ }
43
+ return argumentosResolvidos.reduce((acumulador, argumento) => acumulador += `,${argumento.hasOwnProperty('valor') ? argumento.valor : argumento}`, expressao.id);
44
+ }
45
+ async visitarExpressaoDeChamada(expressao) {
46
+ const _idChamadaComArgumentos = await this.gerarIdResolucaoChamada(expressao);
47
+ // Usado na abertura do bloco de escopo da chamada.
48
+ this.idChamadaAtual = _idChamadaComArgumentos;
49
+ this.executandoChamada = true;
50
+ this.proximoEscopo = 'funcao';
51
+ const retorno = await super.visitarExpressaoDeChamada(expressao);
52
+ this.executandoChamada = false;
53
+ const escopoAtual = this.pilhaEscoposExecucao.topoDaPilha();
54
+ escopoAtual.ambiente.resolucoesChamadas[_idChamadaComArgumentos] = retorno;
55
+ return retorno;
56
+ }
57
+ /**
58
+ * A execução de uma atribuição de variável no interpretador com depuração pode ser em duas etapas.
59
+ * O desenvolvedor pode inspecionar o lado direito e ir parando a execução usando
60
+ * F10, por exemplo. Neste caso, a instrução aqui é executada duas vezes:
61
+ * A primeira para armazenar o valor do lado direito em `this.valorRetornoEscopoAnterior`, e a
62
+ * segunda para efetivamente atribuir o valor da variável.
63
+ * @param expressao
64
+ * @returns
65
+ */
66
+ async visitarDeclaracaoDeAtribuicao(expressao) {
67
+ if (expressao.valor instanceof construtos_1.Chamada) {
68
+ const escopoAtual = this.pilhaEscoposExecucao.topoDaPilha();
69
+ const idChamadaComArgumentos = await this.gerarIdResolucaoChamada(expressao.valor);
70
+ if (escopoAtual.ambiente.resolucoesChamadas.hasOwnProperty(idChamadaComArgumentos)) {
71
+ const retornar = escopoAtual.ambiente.resolucoesChamadas[idChamadaComArgumentos];
72
+ this.pilhaEscoposExecucao.atribuirVariavel(expressao.simbolo, retornar);
73
+ delete escopoAtual.ambiente.resolucoesChamadas[idChamadaComArgumentos];
74
+ return retornar;
75
+ }
76
+ }
77
+ const valor = await this.avaliar(expressao.valor);
78
+ this.pilhaEscoposExecucao.atribuirVariavel(expressao.simbolo, valor);
79
+ return valor;
80
+ }
81
+ /**
82
+ * A execução de `var` no interpretador com depuração pode ser em duas etapas.
83
+ * O desenvolvedor pode inspecionar o lado direito e ir parando a execução usando
84
+ * F10, por exemplo. Neste caso, a instrução aqui é executada duas vezes:
85
+ * A primeira para armazenar o valor do lado direito em `this.valorRetornoEscopoAnterior`, e a
86
+ * segunda para efetivamente atribuir o valor da variável.
87
+ * @param declaracao A declaração Var
88
+ * @returns O valor do resultado resolvido, se a declaração resolveu.
89
+ * Nulo ou indefinido em caso contrário.
90
+ */
91
+ async visitarDeclaracaoVar(declaracao) {
92
+ if (declaracao.inicializador instanceof construtos_1.Chamada) {
93
+ const escopoAtual = this.pilhaEscoposExecucao.topoDaPilha();
94
+ const idChamadaComArgumentos = await this.gerarIdResolucaoChamada(declaracao.inicializador);
95
+ if (escopoAtual.ambiente.resolucoesChamadas.hasOwnProperty(idChamadaComArgumentos)) {
96
+ const retornar = escopoAtual.ambiente.resolucoesChamadas[idChamadaComArgumentos];
97
+ this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, retornar);
98
+ delete escopoAtual.ambiente.resolucoesChamadas[idChamadaComArgumentos];
99
+ return retornar;
100
+ }
101
+ }
102
+ const valorFinal = await this.avaliacaoDeclaracaoVar(declaracao);
103
+ if (valorFinal !== null && valorFinal !== undefined) {
104
+ this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, valorFinal);
105
+ }
106
+ return valorFinal;
107
+ }
108
+ /**
109
+ * Ao executar um retorno, manter o valor retornado no Interpretador para
110
+ * uso por linhas que foram executadas com o comando `próximo` do depurador.
111
+ * @param declaracao Uma declaracao Retorna
112
+ * @returns O resultado da execução da visita.
113
+ */
114
+ async visitarExpressaoRetornar(declaracao) {
115
+ const retorno = await super.visitarExpressaoRetornar(declaracao);
116
+ // O escopo atual é marcado como finalizado, para notificar a
117
+ // instrução de que deve ser descartado.
118
+ const escopoAtual = this.pilhaEscoposExecucao.topoDaPilha();
119
+ escopoAtual.finalizado = true;
120
+ // Acha o primeiro escopo de função.
121
+ const escopoFuncao = this.pilhaEscoposExecucao.obterEscopoPorTipo('funcao');
122
+ if (escopoFuncao === undefined) {
123
+ return Promise.reject('retorna() chamado fora de execução de função.');
124
+ }
125
+ if (escopoFuncao.idChamada !== undefined) {
126
+ escopoAtual.ambiente.resolucoesChamadas[escopoFuncao.idChamada] =
127
+ retorno && retorno.hasOwnProperty('valor') ? retorno.valor : retorno;
128
+ }
129
+ return retorno;
35
130
  }
36
131
  /**
37
132
  * Se bloco de execução já foi instanciado antes (por exemplo, quando há um ponto de parada e a
@@ -44,6 +139,7 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
44
139
  * @param ambiente O ambiente de execução quando houver, como parâmetros, argumentos, etc.
45
140
  */
46
141
  async executarBloco(declaracoes, ambiente) {
142
+ // Se o escopo atual não é o último.
47
143
  if (this.escopoAtual < this.pilhaEscoposExecucao.elementos() - 1) {
48
144
  this.escopoAtual++;
49
145
  const proximoEscopo = this.pilhaEscoposExecucao.naPosicao(this.escopoAtual);
@@ -59,25 +155,26 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
59
155
  break;
60
156
  }
61
157
  retornoExecucao = await this.executar(proximoEscopo.declaracoes[proximoEscopo.declaracaoAtual]);
158
+ // Um ponto de parada ativo pode ter vindo de um escopo mais interno.
159
+ // Por isso verificamos outra parada aqui para evitar que
160
+ // `this.declaracaoAtual` seja incrementado.
161
+ if (this.pontoDeParadaAtivo) {
162
+ break;
163
+ }
62
164
  }
63
165
  this.pilhaEscoposExecucao.removerUltimo();
64
166
  this.escopoAtual--;
65
167
  return retornoExecucao;
66
168
  }
67
169
  else {
68
- const escopoExecucao = {
69
- declaracoes: declaracoes,
70
- declaracaoAtual: 0,
71
- ambiente: ambiente || new espaco_variaveis_1.EspacoVariaveis(),
72
- };
73
- this.pilhaEscoposExecucao.empilhar(escopoExecucao);
74
- this.escopoAtual++;
75
- if (this.comandoProximo) {
76
- // Quando o comando for 'próximo', não executa.
77
- // Aguarda o usuário com a próxima instrução vinda do depurador.
78
- return null;
170
+ this.abrirNovoBlocoEscopo(declaracoes, ambiente, this.proximoEscopo || 'outro');
171
+ const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
172
+ if (this.idChamadaAtual) {
173
+ ultimoEscopo.idChamada = this.idChamadaAtual;
174
+ this.idChamadaAtual = undefined;
79
175
  }
80
- if (!this.comandoAdentrarEscopo) {
176
+ this.proximoEscopo = undefined;
177
+ if (this.comando !== 'adentrarEscopo') {
81
178
  return await this.executarUltimoEscopo();
82
179
  }
83
180
  }
@@ -91,11 +188,68 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
91
188
  const buscaPontoParada = this.pontosParada.filter((p) => p.hashArquivo === declaracao.hashArquivo &&
92
189
  p.linha === declaracao.linha);
93
190
  if (buscaPontoParada.length > 0) {
94
- console.log('Ponto de parada encontrado.');
191
+ console.log(`Ponto de parada encontrado. Linha: ${declaracao.linha}.`);
95
192
  return true;
96
193
  }
97
194
  return false;
98
195
  }
196
+ /**
197
+ * No interpretador com depuração, este método é dividido em dois outros métodos privados:
198
+ * - `this.executarUmPassoNoEscopo`, que executa apenas uma instrução e nada mais;
199
+ * - `this.executarUltimoEscopoComandoContinuar`, que é a execução trivial de um escopo inteiro,
200
+ * ou com todas as instruções, ou até encontrar um ponto de parada.
201
+ * @param manterAmbiente Se verdadeiro, junta elementos do último escopo com o escopo
202
+ * imediatamente abaixo.
203
+ * @param naoVerificarPrimeiraExecucao Booleano que pede ao Interpretador para não
204
+ * verificar o ponto de parada na primeira execução.
205
+ * Normalmente usado pelo Servidor de Depuração para continuar uma linha.
206
+ * @returns O retorno da execução.
207
+ */
208
+ async executarUltimoEscopo(manterAmbiente = false, naoVerificarPrimeiraExecucao = false) {
209
+ switch (this.comando) {
210
+ case 'adentrarEscopo':
211
+ case 'proximo':
212
+ if (!this.executandoChamada) {
213
+ return this.executarUmPassoNoEscopo();
214
+ }
215
+ else {
216
+ return this.executarUltimoEscopoComandoContinuar(manterAmbiente, naoVerificarPrimeiraExecucao);
217
+ }
218
+ default:
219
+ return this.executarUltimoEscopoComandoContinuar(manterAmbiente, naoVerificarPrimeiraExecucao);
220
+ }
221
+ }
222
+ async executarUmPassoNoEscopo() {
223
+ const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
224
+ let retornoExecucao;
225
+ if (this.passos > 0) {
226
+ this.passos--;
227
+ retornoExecucao = await this.executar(ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual]);
228
+ if (!this.pontoDeParadaAtivo) {
229
+ ultimoEscopo.declaracaoAtual++;
230
+ }
231
+ if (ultimoEscopo.declaracaoAtual >= ultimoEscopo.declaracoes.length || ultimoEscopo.finalizado) {
232
+ let outroEscopo = this.pilhaEscoposExecucao.topoDaPilha();
233
+ if (retornoExecucao instanceof quebras_1.RetornoQuebra) {
234
+ while (outroEscopo.tipo !== 'funcao') {
235
+ this.pilhaEscoposExecucao.removerUltimo();
236
+ const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
237
+ escopoAnterior.ambiente.resolucoesChamadas = Object.assign(escopoAnterior.ambiente.resolucoesChamadas, outroEscopo.ambiente.resolucoesChamadas);
238
+ this.escopoAtual--;
239
+ outroEscopo = this.pilhaEscoposExecucao.topoDaPilha();
240
+ }
241
+ }
242
+ this.pilhaEscoposExecucao.removerUltimo();
243
+ const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
244
+ escopoAnterior.ambiente.resolucoesChamadas = Object.assign(escopoAnterior.ambiente.resolucoesChamadas, outroEscopo.ambiente.resolucoesChamadas);
245
+ this.escopoAtual--;
246
+ }
247
+ if (this.pilhaEscoposExecucao.elementos() === 1) {
248
+ this.finalizacaoDaExecucao();
249
+ }
250
+ }
251
+ return retornoExecucao;
252
+ }
99
253
  /**
100
254
  * Continua a interpretação parcial do último ponto em que parou.
101
255
  * Pode ser tanto o começo da execução inteira, ou pós comando do depurador
@@ -107,10 +261,10 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
107
261
  * Normalmente usado pelo Servidor de Depuração para continuar uma linha.
108
262
  * @returns Um objeto de retorno, com erros encontrados se houverem.
109
263
  */
110
- async executarUltimoEscopo(manterAmbiente = false, naoVerificarPrimeiraExecucao = false) {
264
+ async executarUltimoEscopoComandoContinuar(manterAmbiente = false, naoVerificarPrimeiraExecucao = false) {
111
265
  const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
266
+ let retornoExecucao;
112
267
  try {
113
- let retornoExecucao;
114
268
  for (; !(retornoExecucao instanceof quebras_1.Quebra) &&
115
269
  ultimoEscopo.declaracaoAtual < ultimoEscopo.declaracoes.length; ultimoEscopo.declaracaoAtual++) {
116
270
  if (naoVerificarPrimeiraExecucao) {
@@ -123,14 +277,21 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
123
277
  }
124
278
  }
125
279
  retornoExecucao = await this.executar(ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual]);
280
+ // Um ponto de parada ativo pode ter vindo de um escopo mais interno.
281
+ // Por isso verificamos outra parada aqui para evitar que
282
+ // `this.declaracaoAtual` seja incrementado.
283
+ if (this.pontoDeParadaAtivo) {
284
+ break;
285
+ }
126
286
  }
127
287
  return retornoExecucao;
128
288
  }
129
289
  finally {
130
- if (!this.pontoDeParadaAtivo) {
290
+ if (!this.pontoDeParadaAtivo && this.comando !== 'adentrarEscopo') {
131
291
  this.pilhaEscoposExecucao.removerUltimo();
292
+ const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
293
+ escopoAnterior.ambiente.resolucoesChamadas = Object.assign(escopoAnterior.ambiente.resolucoesChamadas, ultimoEscopo.ambiente.resolucoesChamadas);
132
294
  if (manterAmbiente) {
133
- const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha();
134
295
  escopoAnterior.ambiente.valores = Object.assign(escopoAnterior.ambiente.valores, ultimoEscopo.ambiente.valores);
135
296
  }
136
297
  this.escopoAtual--;
@@ -148,45 +309,15 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
148
309
  * Diferentemente de `executarUltimoEscopo`, este método descarta apenas um escopo (o que foi chamado).
149
310
  * @see executarBloco
150
311
  */
151
- async continuarInterpretacao() {
152
- this.escopoAtual = 1;
153
- const primeiroEscopo = this.pilhaEscoposExecucao.naPosicao(1);
154
- let retornoExecucao;
155
- // Primeira execução sempre ocorre, independente de pontos de parada.
156
- retornoExecucao = await this.executar(primeiroEscopo.declaracoes[primeiroEscopo.declaracaoAtual]);
157
- primeiroEscopo.declaracaoAtual++;
158
- for (; !(retornoExecucao instanceof quebras_1.Quebra) &&
159
- primeiroEscopo.declaracaoAtual < primeiroEscopo.declaracoes.length; primeiroEscopo.declaracaoAtual++) {
160
- this.pontoDeParadaAtivo = this.verificarPontoParada(primeiroEscopo.declaracoes[primeiroEscopo.declaracaoAtual]);
161
- if (this.pontoDeParadaAtivo) {
162
- break;
163
- }
164
- retornoExecucao = await this.executar(primeiroEscopo.declaracoes[primeiroEscopo.declaracaoAtual]);
165
- }
166
- if (primeiroEscopo.declaracaoAtual >= primeiroEscopo.declaracoes.length) {
167
- this.pilhaEscoposExecucao.removerUltimo();
168
- }
169
- if (this.pilhaEscoposExecucao.elementos() === 1) {
170
- this.finalizacaoDaExecucao();
171
- }
312
+ async instrucaoContinuarInterpretacao() {
313
+ this.executarUltimoEscopoComandoContinuar(false, true);
172
314
  }
173
- descartarEscoposFinalizados(numeroEscopo, escopoVisitado) {
174
- // Se última instrução do escopo atual foi executada, e
175
- // escopos adicionais não foram criados com a última execução,
176
- // descartar este e todos os escopos abaixo deste que também estejam na última instrução.
177
- if (escopoVisitado.declaracoes.length ==
178
- escopoVisitado.declaracaoAtual &&
179
- numeroEscopo == this.pilhaEscoposExecucao.pilha.length - 1) {
180
- let numeroEscopoAtual = numeroEscopo;
181
- while (numeroEscopoAtual > 0) {
182
- const escopo = this.pilhaEscoposExecucao.pilha[numeroEscopoAtual];
183
- if (escopo.declaracoes.length == escopo.declaracaoAtual) {
184
- this.pilhaEscoposExecucao.removerUltimo();
185
- this.escopoAtual--;
186
- }
187
- numeroEscopoAtual--;
188
- }
189
- }
315
+ /**
316
+ * Empilha um escopo se for possível.
317
+ * Se não for, apenas executa a instrução corrente.
318
+ */
319
+ async adentrarEscopo() {
320
+ throw new Error('Método não implementado.');
190
321
  }
191
322
  /**
192
323
  * Interpreta apenas uma instrução a partir do ponto de parada ativo, conforme comando do depurador.
@@ -194,28 +325,20 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
194
325
  * primeiro escopo, subindo até o último elemento executado do último escopo.
195
326
  * @param escopo Indica o escopo a ser visitado. Usado para construir uma pilha de chamadas do lado JS.
196
327
  */
197
- async interpretarApenasUmaInstrucao(escopo = 1) {
328
+ async instrucaoPasso(escopo = 1) {
329
+ this.passos = 1;
198
330
  const escopoVisitado = this.pilhaEscoposExecucao.naPosicao(escopo);
331
+ if (escopoVisitado.declaracaoAtual >= escopoVisitado.declaracoes.length || escopoVisitado.finalizado) {
332
+ this.pilhaEscoposExecucao.removerUltimo();
333
+ }
334
+ if (this.pilhaEscoposExecucao.elementos() === 1) {
335
+ return this.finalizacaoDaExecucao();
336
+ }
199
337
  if (escopo < this.escopoAtual) {
200
- this.interpretarApenasUmaInstrucao(escopo + 1);
338
+ this.instrucaoPasso(escopo + 1);
201
339
  }
202
340
  else {
203
- const declaracaoAtual = escopoVisitado.declaracoes[escopoVisitado.declaracaoAtual];
204
- await this.executar(declaracaoAtual);
205
- if (this.comandoAdentrarEscopo) {
206
- // Depurador comandou instrução 'adentrar-escopo', ou bloco de escopo
207
- // não é de uma função.
208
- // Instrução só foi realmente executada se não abriu novo bloco de escopo.
209
- // Por isso, `declaracaoAtual` não deve ser incrementada aqui.
210
- this.comandoAdentrarEscopo = false;
211
- }
212
- else {
213
- escopoVisitado.declaracaoAtual++;
214
- }
215
- this.descartarEscoposFinalizados(escopo, escopoVisitado);
216
- }
217
- if (this.pilhaEscoposExecucao.elementos() === 1) {
218
- this.finalizacaoDaExecucao();
341
+ await this.executarUmPassoNoEscopo();
219
342
  }
220
343
  }
221
344
  /**
@@ -223,30 +346,8 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
223
346
  * Se houver outros pontos de parada no mesmo escopo à frente da instrução atual, todos são ignorados.
224
347
  * @param escopo Indica o escopo a ser visitado. Usado para construir uma pilha de chamadas do lado JS.
225
348
  */
226
- async proximoESair(escopo = 1) {
227
- const escopoVisitado = this.pilhaEscoposExecucao.naPosicao(escopo);
228
- if (escopo < this.escopoAtual - 1) {
229
- this.proximoESair(escopo + 1);
230
- }
231
- else {
232
- const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha();
233
- let retornoExecucao;
234
- for (; !(retornoExecucao instanceof quebras_1.Quebra) &&
235
- ultimoEscopo.declaracaoAtual < ultimoEscopo.declaracoes.length; ultimoEscopo.declaracaoAtual++) {
236
- retornoExecucao = await this.executar(ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual]);
237
- }
238
- this.pilhaEscoposExecucao.removerUltimo();
239
- this.escopoAtual--;
240
- escopoVisitado.declaracaoAtual++;
241
- }
242
- // Se última instrução do escopo atual foi executada, descartar escopo.
243
- if (escopoVisitado.declaracoes.length <= escopoVisitado.declaracaoAtual) {
244
- this.pilhaEscoposExecucao.removerUltimo();
245
- this.escopoAtual--;
246
- }
247
- if (this.pilhaEscoposExecucao.elementos() === 1) {
248
- this.finalizacaoDaExecucao();
249
- }
349
+ async instrucaoProximoESair() {
350
+ this.executarUltimoEscopoComandoContinuar(false, true);
250
351
  }
251
352
  /**
252
353
  * Prepara a pilha de escopos para uma situação de depuração.
@@ -255,17 +356,31 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
255
356
  */
256
357
  prepararParaDepuracao(declaracoes) {
257
358
  this.declaracoes = declaracoes;
359
+ this.abrirNovoBlocoEscopo(declaracoes);
360
+ }
361
+ abrirNovoBlocoEscopo(declaracoes, ambiente, tipoEscopo = 'outro') {
258
362
  const escopoExecucao = {
259
363
  declaracoes: declaracoes,
260
364
  declaracaoAtual: 0,
261
- ambiente: new espaco_variaveis_1.EspacoVariaveis(),
365
+ ambiente: ambiente || new espaco_variaveis_1.EspacoVariaveis(),
366
+ finalizado: false,
367
+ tipo: tipoEscopo
262
368
  };
263
369
  this.pilhaEscoposExecucao.empilhar(escopoExecucao);
264
370
  this.escopoAtual++;
265
371
  }
266
372
  /**
267
- * Interpretação utilizada pelo depurador. Pode encerrar ao encontrar um
268
- * ponto de parada ou não.
373
+ * Reimplementando este método aqui porque a execução por depuração não requer
374
+ * mostrar o resultado em momento algum, ou lidar com o retorno.
375
+ * @param declaracao A declaracao a ser executada.
376
+ * @param mostrarResultado Sempre falso.
377
+ * @returns O resultado da execução.
378
+ */
379
+ async executar(declaracao, mostrarResultado = false) {
380
+ return await declaracao.aceitar(this);
381
+ }
382
+ /**
383
+ * Interpretação utilizada pelo depurador para avaliar valores de variáveis.
269
384
  * Diferentemente da interpretação tradicional, não possui indicadores
270
385
  * de performance porque eles não fazem sentido aqui.
271
386
  * @param declaracoes Um vetor de declarações.
@@ -274,21 +389,33 @@ class InterpretadorComDepuracao extends interpretador_1.Interpretador {
274
389
  async interpretar(declaracoes, manterAmbiente = false) {
275
390
  this.erros = [];
276
391
  this.declaracoes = declaracoes;
277
- const escopoExecucao = {
278
- declaracoes: declaracoes,
279
- declaracaoAtual: 0,
280
- ambiente: new espaco_variaveis_1.EspacoVariaveis(),
281
- };
282
- this.pilhaEscoposExecucao.empilhar(escopoExecucao);
283
- this.escopoAtual++;
284
- await this.executarUltimoEscopo(manterAmbiente);
392
+ this.abrirNovoBlocoEscopo(declaracoes);
393
+ const resultado = await super.executarUltimoEscopo(manterAmbiente);
394
+ // Corrigir contador de escopos
395
+ this.escopoAtual--;
285
396
  const retorno = {
286
397
  erros: this.erros,
287
- resultado: this.resultadoInterpretador,
398
+ // resultado: this.resultadoInterpretador // Removido para simplificar `this.executar()`.
399
+ resultado: [resultado]
288
400
  };
289
401
  this.resultadoInterpretador = [];
290
402
  return retorno;
291
403
  }
404
+ /**
405
+ * Obtém o valor de uma variável por nome.
406
+ * Em versões anteriores, o mecanismo de avaliação fazia toda a avaliação tradicional,
407
+ * passando por Lexador, Avaliador Sintático e Interpretador.
408
+ * Isso tem sua cota de problemas, sobretudo porque a avaliação insere e descarta escopos,
409
+ * entrando em condição de corrida com a interpretação com depuração.
410
+ * @param nome O nome da variável.
411
+ */
412
+ obterVariavel(nome) {
413
+ const valorOuVariavel = this.pilhaEscoposExecucao.obterValorVariavel({ lexema: nome });
414
+ return valorOuVariavel.hasOwnProperty('valor') ? valorOuVariavel : {
415
+ valor: valorOuVariavel,
416
+ tipo: (0, inferenciador_1.inferirTipoVariavel)(valorOuVariavel)
417
+ };
418
+ }
292
419
  }
293
420
  exports.InterpretadorComDepuracao = InterpretadorComDepuracao;
294
421
  //# sourceMappingURL=interpretador-com-depuracao.js.map