@designliquido/potigol 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/avaliador-sintatico/avaliador-sintatico-potigol.d.ts +51 -22
- package/avaliador-sintatico/avaliador-sintatico-potigol.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico-potigol.js +303 -163
- package/avaliador-sintatico/avaliador-sintatico-potigol.js.map +1 -1
- package/avaliador-sintatico/micro-avaliador-sintatico-potigol.d.ts.map +1 -1
- package/avaliador-sintatico/micro-avaliador-sintatico-potigol.js +2 -1
- package/avaliador-sintatico/micro-avaliador-sintatico-potigol.js.map +1 -1
- package/construtos/leia-inteiros.d.ts.map +1 -1
- package/construtos/leia-inteiros.js +2 -1
- package/construtos/leia-inteiros.js.map +1 -1
- package/construtos/leia-reais.d.ts.map +1 -1
- package/construtos/leia-reais.js +2 -1
- package/construtos/leia-reais.js.map +1 -1
- package/interpretador/comum.js +3 -3
- package/interpretador/comum.js.map +1 -1
- package/interpretador/inferenciador.d.ts +1 -1
- package/lexador/palavras-reservadas.d.ts +2 -0
- package/lexador/palavras-reservadas.d.ts.map +1 -1
- package/lexador/palavras-reservadas.js +2 -0
- package/lexador/palavras-reservadas.js.map +1 -1
- package/package.json +2 -2
- package/tipos-de-dados.d.ts +9 -0
- package/tipos-de-dados.d.ts.map +1 -0
- package/tipos-de-dados.js +10 -0
- package/tipos-de-dados.js.map +1 -0
- package/tipos-de-simbolos/lexico-regular.d.ts +3 -1
- package/tipos-de-simbolos/lexico-regular.d.ts.map +1 -1
- package/tipos-de-simbolos/lexico-regular.js +3 -1
- package/tipos-de-simbolos/lexico-regular.js.map +1 -1
|
@@ -14,15 +14,14 @@ const construtos_2 = require("../construtos");
|
|
|
14
14
|
const declaracoes_2 = require("../declaracoes");
|
|
15
15
|
const micro_avaliador_sintatico_potigol_1 = require("./micro-avaliador-sintatico-potigol");
|
|
16
16
|
const pilha_escopos_variaveis_conhecidas_1 = require("./pilha-escopos-variaveis-conhecidas");
|
|
17
|
+
const tipos_de_dados_1 = __importDefault(require("../tipos-de-dados"));
|
|
17
18
|
const lexico_regular_1 = __importDefault(require("../tipos-de-simbolos/lexico-regular"));
|
|
18
19
|
/**
|
|
20
|
+
*
|
|
19
21
|
* TODO: Pensar numa forma de avaliar múltiplas constantes sem
|
|
20
22
|
* transformar o retorno de `primario()` em um vetor.
|
|
21
23
|
*/
|
|
22
24
|
class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSintaticoBase {
|
|
23
|
-
expressaoLeia() {
|
|
24
|
-
throw new Error('Method not implemented.');
|
|
25
|
-
}
|
|
26
25
|
constructor() {
|
|
27
26
|
super();
|
|
28
27
|
this.tiposPotigolParaDelegua = {
|
|
@@ -68,15 +67,15 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
68
67
|
return true;
|
|
69
68
|
}
|
|
70
69
|
/**
|
|
71
|
-
* Retorna uma declaração de função iniciada por igual,
|
|
70
|
+
* Retorna uma declaração de função iniciada por igual ou seta,
|
|
72
71
|
* ou seja, com apenas uma instrução.
|
|
73
72
|
* @param simboloPrimario O símbolo que identifica a função (nome),
|
|
74
|
-
* também usado para fins de
|
|
73
|
+
* também usado para fins de localização.
|
|
75
74
|
* @param parametros A lista de parâmetros da função.
|
|
76
75
|
* @param tipoRetorno O tipo de retorno da função.
|
|
77
76
|
* @returns Um construto do tipo `FuncaoDeclaracao`.
|
|
78
77
|
*/
|
|
79
|
-
|
|
78
|
+
declaracaoFuncaoPotigolIniciadaPorIgualOuSeta(simboloPrimario, parametros, tipoRetorno) {
|
|
80
79
|
const corpo = new construtos_1.FuncaoConstruto(simboloPrimario.hashArquivo, simboloPrimario.linha, parametros, [
|
|
81
80
|
new declaracoes_1.Retorna(simboloPrimario, this.expressao()),
|
|
82
81
|
]);
|
|
@@ -86,10 +85,10 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
86
85
|
return new declaracoes_1.FuncaoDeclaracao(simboloPrimario, corpo, tipoRetorno ? tipoRetorno.lexema : 'qualquer');
|
|
87
86
|
}
|
|
88
87
|
/**
|
|
89
|
-
* Retorna uma declaração de função terminada por fim
|
|
88
|
+
* Retorna uma declaração de função terminada por `fim`,
|
|
90
89
|
* ou seja, com mais de uma instrução.
|
|
91
90
|
* @param simboloPrimario O símbolo que identifica a função (nome).
|
|
92
|
-
* @param parenteseEsquerdo O parêntese esquerdo, usado para fins de
|
|
91
|
+
* @param parenteseEsquerdo O parêntese esquerdo, usado para fins de localização.
|
|
93
92
|
* @param parametros A lista de parâmetros da função.
|
|
94
93
|
* @param tipoRetorno O tipo de retorno da função.
|
|
95
94
|
* @returns Um construto do tipo `FuncaoDeclaracao`.
|
|
@@ -101,13 +100,20 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
101
100
|
}
|
|
102
101
|
return new declaracoes_1.FuncaoDeclaracao(simboloPrimario, corpo, tipoRetorno.lexema);
|
|
103
102
|
}
|
|
104
|
-
corpoDaFuncao(nomeFuncao,
|
|
103
|
+
corpoDaFuncao(nomeFuncao, simboloLocalizacao, parametros) {
|
|
105
104
|
const corpo = this.blocoEscopo();
|
|
106
|
-
return new construtos_1.FuncaoConstruto(this.hashArquivo, Number(
|
|
105
|
+
return new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simboloLocalizacao.linha), parametros, corpo);
|
|
107
106
|
}
|
|
108
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Ponto comum entre declarações de funções com nome. Em Potigol, usar `def` para definir
|
|
109
|
+
* uma função é opcional. Essa lógica serve tanto para quando a palavra `def` é usada,
|
|
110
|
+
* como para casos em que a função começa pelo seu nome, seguida de parênteses.
|
|
111
|
+
* @param {SimboloInterface} simboloNomeFuncao Normalmente um `Simbolo` do tipo `IDENTIFICADOR`.
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
114
|
+
logicaComumDefinicaoFuncaoComNome(simboloNomeFuncao) {
|
|
109
115
|
// O parêntese esquerdo é considerado o símbolo inicial para
|
|
110
|
-
// fins de
|
|
116
|
+
// fins de localização.
|
|
111
117
|
const parenteseEsquerdo = this.avancarEDevolverAnterior();
|
|
112
118
|
const simbolosEntreParenteses = [];
|
|
113
119
|
while (!this.verificarTipoSimboloAtual(lexico_regular_1.default.PARENTESE_DIREITO)) {
|
|
@@ -126,9 +132,17 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
126
132
|
// seja após a dica de retorno, é uma declaração de função.
|
|
127
133
|
if (this.simbolos[this.atual].tipo === lexico_regular_1.default.IGUAL) {
|
|
128
134
|
this.avancarEDevolverAnterior();
|
|
129
|
-
return this.
|
|
135
|
+
return this.declaracaoFuncaoPotigolIniciadaPorIgualOuSeta(simboloNomeFuncao, resolucaoParametros.parametros, tipoRetorno);
|
|
130
136
|
}
|
|
131
|
-
return this.declaracaoFuncaoPotigolTerminadaPorFim(
|
|
137
|
+
return this.declaracaoFuncaoPotigolTerminadaPorFim(simboloNomeFuncao, parenteseEsquerdo, resolucaoParametros.parametros, tipoRetorno);
|
|
138
|
+
}
|
|
139
|
+
declaracaoDeFuncaoComDef() {
|
|
140
|
+
this.avancarEDevolverAnterior(); // `def`
|
|
141
|
+
const simboloNomeFuncao = this.consumir(lexico_regular_1.default.IDENTIFICADOR, `Esperado nome da função após palavra reservada 'def'. Atual: ${this.simbolos[this.atual].tipo}.`);
|
|
142
|
+
return this.logicaComumDefinicaoFuncaoComNome(simboloNomeFuncao);
|
|
143
|
+
}
|
|
144
|
+
declaracaoDeFuncaoOuMetodo(construtoPrimario) {
|
|
145
|
+
return this.logicaComumDefinicaoFuncaoComNome(construtoPrimario.simbolo);
|
|
132
146
|
}
|
|
133
147
|
finalizarChamada(entidadeChamada) {
|
|
134
148
|
const simbolosEntreParenteses = [];
|
|
@@ -179,6 +193,7 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
179
193
|
const resolucaoTipo = this.tiposPotigolParaDelegua[tipoParametro.lexema];
|
|
180
194
|
parametro.tipoDado = resolucaoTipo;
|
|
181
195
|
tipagemDefinida = true;
|
|
196
|
+
indice++;
|
|
182
197
|
}
|
|
183
198
|
// TODO: Verificar se Potigol trabalha com valores padrão em argumentos.
|
|
184
199
|
/* if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
|
|
@@ -186,7 +201,7 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
186
201
|
} */
|
|
187
202
|
parametros.push(parametro);
|
|
188
203
|
// if (parametro.abrangencia === 'multiplo') break;
|
|
189
|
-
|
|
204
|
+
//
|
|
190
205
|
if (indice < simbolos.length && simbolos[indice].tipo !== lexico_regular_1.default.VIRGULA) {
|
|
191
206
|
throw this.erro(simbolos[indice], 'Esperado vírgula entre parâmetros de função.');
|
|
192
207
|
}
|
|
@@ -211,6 +226,67 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
211
226
|
return new construtos_2.LeiaTextos(simboloLeiaMultiplo, argumento);
|
|
212
227
|
}
|
|
213
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Lógica para leitura de argumentos tipados de função. Ocorre em casos de leitura
|
|
231
|
+
* de funções anônimas.
|
|
232
|
+
* @param primeiroArgumento O primeiro argumento, já resolvido como construto.
|
|
233
|
+
*/
|
|
234
|
+
logicaArgumentosTipados(primeiroArgumento) {
|
|
235
|
+
// Quando esta função executa, já sabemos que o próximo símbolo será um
|
|
236
|
+
// dois-pontos.
|
|
237
|
+
}
|
|
238
|
+
logicaFuncaoAnonimaOuTupla(primeiroConstruto) {
|
|
239
|
+
const simbolosEntreParenteses = [];
|
|
240
|
+
while (!this.verificarTipoSimboloAtual(lexico_regular_1.default.PARENTESE_DIREITO)) {
|
|
241
|
+
simbolosEntreParenteses.push(this.avancarEDevolverAnterior());
|
|
242
|
+
}
|
|
243
|
+
// Se houver algum dois-pontos nos símbolos lidos, os símbolos devem ser parâmetros.
|
|
244
|
+
if (simbolosEntreParenteses.some(s => s.tipo === lexico_regular_1.default.DOIS_PONTOS)) {
|
|
245
|
+
// Colocamos o primeiro símbolo de volta porque se cada parâmetro possui um tipo
|
|
246
|
+
// definido, precisamos avaliar o primeiro símbolo novamente.
|
|
247
|
+
const simboloPrimeiroConstruto = primeiroConstruto.simbolo;
|
|
248
|
+
const todosOsSimbolos = [simboloPrimeiroConstruto, ...simbolosEntreParenteses];
|
|
249
|
+
const resolucaoParametros = this.logicaComumParametrosPotigol(todosOsSimbolos);
|
|
250
|
+
// Pelo menos o último símbolo precisa ter um tipo.
|
|
251
|
+
if (!resolucaoParametros.tipagemDefinida) {
|
|
252
|
+
throw this.erro(simboloPrimeiroConstruto, `Não foi encontrado um tipo válido na definição de parâmetros para função.`);
|
|
253
|
+
}
|
|
254
|
+
this.consumir(lexico_regular_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros ou argumentos.");
|
|
255
|
+
const tipoUltimoParametro = resolucaoParametros.parametros[resolucaoParametros.parametros.length - 1].tipoDado;
|
|
256
|
+
for (const parametro of resolucaoParametros.parametros) {
|
|
257
|
+
if (parametro.tipoDado === undefined) {
|
|
258
|
+
parametro.tipoDado = tipoUltimoParametro;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Pode haver uma dica do tipo de retorno ou não.
|
|
262
|
+
let tipoRetorno = undefined;
|
|
263
|
+
if (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.DOIS_PONTOS)) {
|
|
264
|
+
this.verificacaoTipo(this.simbolos[this.atual], 'Esperado tipo válido após dois-pontos como retorno de função.');
|
|
265
|
+
tipoRetorno = this.avancarEDevolverAnterior();
|
|
266
|
+
}
|
|
267
|
+
// Em funções anônimas, logo após o fechamento dos parênteses, e com ou sem dica de retorno,
|
|
268
|
+
// o próximo símbolo precisa ser uma seta.
|
|
269
|
+
this.consumir(lexico_regular_1.default.SETA, `Esperado seta para definição de corpo de função anônima após leitura de parâmetros. Atual: ${this.simbolos[this.atual].tipo}.`);
|
|
270
|
+
return this.declaracaoFuncaoPotigolIniciadaPorIgualOuSeta({ hashArquivo: primeiroConstruto.hashArquivo, linha: primeiroConstruto.linha }, resolucaoParametros.parametros, tipoRetorno);
|
|
271
|
+
}
|
|
272
|
+
else { // Senão, são tuplas.
|
|
273
|
+
// Remove a primeira vírgula
|
|
274
|
+
simbolosEntreParenteses.shift();
|
|
275
|
+
const retornoMicroAvaliadorSintatico = this.microAvaliadorSintatico.analisar({ simbolos: simbolosEntreParenteses }, primeiroConstruto.linha);
|
|
276
|
+
this.consumir(lexico_regular_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros ou argumentos.");
|
|
277
|
+
return new tuplas_1.SeletorTuplas(primeiroConstruto, ...retornoMicroAvaliadorSintatico.declaracoes);
|
|
278
|
+
}
|
|
279
|
+
// Se próximo símbolo for fechamento de parênteses, é uma tupla.
|
|
280
|
+
// Se for dois-pontos (ou seja, especificação de tipos de parâmetros), provavelmente é uma função anônima.
|
|
281
|
+
/* switch (this.simbolos[this.atual].tipo) {
|
|
282
|
+
case tiposDeSimbolos.DOIS_PONTOS:
|
|
283
|
+
// TODO: Terminar
|
|
284
|
+
throw this.erro(this.simbolos[this.atual], 'Terminar.');
|
|
285
|
+
case tiposDeSimbolos.PARENTESE_DIREITO:
|
|
286
|
+
this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
|
|
287
|
+
return new SeletorTuplas(...argumentos) as Tupla;
|
|
288
|
+
} */
|
|
289
|
+
}
|
|
214
290
|
primario() {
|
|
215
291
|
const simboloAtual = this.simbolos[this.atual];
|
|
216
292
|
switch (simboloAtual.tipo) {
|
|
@@ -218,15 +294,12 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
218
294
|
this.avancarEDevolverAnterior();
|
|
219
295
|
const expressao = this.ou();
|
|
220
296
|
switch (this.simbolos[this.atual].tipo) {
|
|
297
|
+
case lexico_regular_1.default.DOIS_PONTOS:
|
|
298
|
+
const argumentosFuncao = this.logicaArgumentosTipados(expressao);
|
|
299
|
+
console.log('argumentosFuncao', argumentosFuncao);
|
|
300
|
+
break;
|
|
221
301
|
case lexico_regular_1.default.VIRGULA:
|
|
222
|
-
|
|
223
|
-
const argumentos = [expressao];
|
|
224
|
-
while (this.simbolos[this.atual].tipo === lexico_regular_1.default.VIRGULA) {
|
|
225
|
-
this.avancarEDevolverAnterior();
|
|
226
|
-
argumentos.push(this.ou());
|
|
227
|
-
}
|
|
228
|
-
this.consumir(lexico_regular_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
|
|
229
|
-
return new tuplas_1.SeletorTuplas(...argumentos);
|
|
302
|
+
return this.logicaFuncaoAnonimaOuTupla(expressao);
|
|
230
303
|
default:
|
|
231
304
|
this.consumir(lexico_regular_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
|
|
232
305
|
return new construtos_1.Agrupamento(this.hashArquivo, Number(simboloAtual.linha), expressao);
|
|
@@ -385,6 +458,200 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
385
458
|
}
|
|
386
459
|
return expressao;
|
|
387
460
|
}
|
|
461
|
+
verificarDefinicaoTipoAtual() {
|
|
462
|
+
const tipos = [...Object.values(tipos_de_dados_1.default)];
|
|
463
|
+
// TODO: Habilitar isso no futuro.
|
|
464
|
+
/* if (this.simbolos[this.atual].lexema in this.tiposDefinidosEmCodigo) {
|
|
465
|
+
return this.simbolos[this.atual].lexema;
|
|
466
|
+
} */
|
|
467
|
+
const lexemaElementar = this.simbolos[this.atual].lexema.toLowerCase();
|
|
468
|
+
const tipoElementarResolvido = tipos.find((tipo) => tipo.toLowerCase() === lexemaElementar);
|
|
469
|
+
if (!tipoElementarResolvido) {
|
|
470
|
+
throw this.erro(this.simbolos[this.atual], `Tipo de dados desconhecido: '${this.simbolos[this.atual].lexema}'.`);
|
|
471
|
+
}
|
|
472
|
+
// TODO: Verificar se precisa de alguma avaliação de vetor.
|
|
473
|
+
/* if (this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO)) {
|
|
474
|
+
const tiposVetores = [
|
|
475
|
+
'inteiro[]',
|
|
476
|
+
'numero[]',
|
|
477
|
+
'número[]',
|
|
478
|
+
'qualquer[]',
|
|
479
|
+
'real[]',
|
|
480
|
+
'texto[]',
|
|
481
|
+
];
|
|
482
|
+
this.avancarEDevolverAnterior();
|
|
483
|
+
|
|
484
|
+
if (!this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_DIREITO)) {
|
|
485
|
+
throw this.erro(
|
|
486
|
+
this.simbolos[this.atual],
|
|
487
|
+
`Esperado símbolo de fechamento do vetor: ']'. Atual: ${this.simbolos[this.atual].lexema}`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const tipoVetor = tiposVetores.find((tipo) => tipo === `${lexemaElementar}[]`);
|
|
492
|
+
this.avancarEDevolverAnterior();
|
|
493
|
+
return tipoVetor as TipoDadosElementar;
|
|
494
|
+
} */
|
|
495
|
+
return tipoElementarResolvido;
|
|
496
|
+
}
|
|
497
|
+
logicaComumInicializadorLeia(inicializador, identificadores) {
|
|
498
|
+
switch (inicializador.constructor) {
|
|
499
|
+
case construtos_2.LeiaInteiro:
|
|
500
|
+
const inicializadorTipadoInteiro = inicializador;
|
|
501
|
+
return new construtos_2.LeiaInteiros(inicializadorTipadoInteiro.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoInteiro.simbolo.linha), identificadores.length));
|
|
502
|
+
case construtos_2.LeiaReal:
|
|
503
|
+
const inicializadorTipadoReal = inicializador;
|
|
504
|
+
return new construtos_2.LeiaReais(inicializadorTipadoReal.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoReal.simbolo.linha), identificadores.length));
|
|
505
|
+
case construtos_2.LeiaTexto:
|
|
506
|
+
const inicializadorTipadoTexto = inicializador;
|
|
507
|
+
return new construtos_2.LeiaTextos(inicializadorTipadoTexto.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoTexto.simbolo.linha), identificadores.length));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
logicaComumInferenciaTiposLeia(inicializador) {
|
|
511
|
+
// Por algum motivo (muito) estranho, `inicializador.constructor.name` não funciona aqui.
|
|
512
|
+
// O nome da classe vai parar numa propriedade `name`.
|
|
513
|
+
switch (inicializador.name) {
|
|
514
|
+
case 'LeiaInteiros':
|
|
515
|
+
return 'inteiro[]';
|
|
516
|
+
case 'LeiaInteiro':
|
|
517
|
+
return 'inteiro';
|
|
518
|
+
case 'LeiaReais':
|
|
519
|
+
return 'real[]';
|
|
520
|
+
case 'LeiaReal':
|
|
521
|
+
return 'real';
|
|
522
|
+
case 'LeiaTextos':
|
|
523
|
+
return 'texto[]';
|
|
524
|
+
case 'LeiaTexto':
|
|
525
|
+
return 'texto';
|
|
526
|
+
default:
|
|
527
|
+
return 'qualquer';
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Em Potigol, a palavra reservada `val` indica uma constante.
|
|
532
|
+
*/
|
|
533
|
+
declaracaoDeConstanteExplicita() {
|
|
534
|
+
this.avancarEDevolverAnterior(); // `val`
|
|
535
|
+
const nomeConstante = this.consumir(lexico_regular_1.default.IDENTIFICADOR, 'Esperado nome da constante.');
|
|
536
|
+
let tipo = null;
|
|
537
|
+
if (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.DOIS_PONTOS)) {
|
|
538
|
+
const tipoConstante = this.verificarDefinicaoTipoAtual();
|
|
539
|
+
if (!tipoConstante) {
|
|
540
|
+
throw this.erro(this.simbolos[this.atual], 'Tipo definido na constante não é válido.');
|
|
541
|
+
}
|
|
542
|
+
tipo = tipoConstante;
|
|
543
|
+
this.avancarEDevolverAnterior();
|
|
544
|
+
}
|
|
545
|
+
this.consumir(lexico_regular_1.default.IGUAL, "Esperado '=' após identificador em instrução 'val'.");
|
|
546
|
+
let inicializador = this.expressao();
|
|
547
|
+
if (['LeiaInteiro', 'LeiaReal', 'LeiaTexto'].includes(inicializador.constructor.name)) {
|
|
548
|
+
inicializador = this.logicaComumInicializadorLeia(inicializador, [nomeConstante]);
|
|
549
|
+
}
|
|
550
|
+
return new declaracoes_1.Const(nomeConstante, inicializador, tipo);
|
|
551
|
+
}
|
|
552
|
+
declaracaoDeConstantes(primeiroIdentificador) {
|
|
553
|
+
// Normalmente o símbolo atual aqui será uma vírgula.
|
|
554
|
+
this.avancarEDevolverAnterior();
|
|
555
|
+
const identificadores = [primeiroIdentificador.simbolo];
|
|
556
|
+
let tipo = null;
|
|
557
|
+
do {
|
|
558
|
+
identificadores.push(this.consumir(lexico_regular_1.default.IDENTIFICADOR, 'Esperado nome da constante.'));
|
|
559
|
+
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
560
|
+
// TODO: Aparentemente, não é possível definir tipo para atribuição
|
|
561
|
+
// múltipla de constantes. Se algo mudar nisso, o código abaixo poderá
|
|
562
|
+
// voltar a ser usado.
|
|
563
|
+
/* if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
|
|
564
|
+
const tipoConstante = this.verificarDefinicaoTipoAtual();
|
|
565
|
+
if (!tipoConstante) {
|
|
566
|
+
throw this.erro(this.simboloAtual(), 'Tipo definido na constante não é válido.');
|
|
567
|
+
}
|
|
568
|
+
tipo = tipoConstante;
|
|
569
|
+
this.avancarEDevolverAnterior();
|
|
570
|
+
} */
|
|
571
|
+
this.consumir(lexico_regular_1.default.IGUAL, "Esperado '=' após identificador em instrução 'constante'.");
|
|
572
|
+
const inicializadores = [];
|
|
573
|
+
do {
|
|
574
|
+
let inicializador = this.expressao();
|
|
575
|
+
if (identificadores.length > 1 &&
|
|
576
|
+
['LeiaInteiro', 'LeiaReal', 'LeiaTexto'].includes(inicializador.constructor.name)) {
|
|
577
|
+
inicializador = this.logicaComumInicializadorLeia(inicializador, identificadores);
|
|
578
|
+
}
|
|
579
|
+
inicializadores.push(inicializador);
|
|
580
|
+
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
581
|
+
if (identificadores.length !== inicializadores.length) {
|
|
582
|
+
// Pode ser que a inicialização seja feita por uma das
|
|
583
|
+
// funções `leia`, que podem ler vários valores. Neste caso, não deve dar erro.
|
|
584
|
+
if (!(inicializadores.length === 1 &&
|
|
585
|
+
['LeiaInteiros', 'LeiaReais', 'LeiaTextos'].includes(inicializadores[0].constructor.name))) {
|
|
586
|
+
throw this.erro(this.simbolos[this.atual], 'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.');
|
|
587
|
+
}
|
|
588
|
+
const tipoConversao = this.logicaComumInferenciaTiposLeia(inicializadores[0].constructor);
|
|
589
|
+
return new declaracoes_1.ConstMultiplo(identificadores, inicializadores[0], tipoConversao);
|
|
590
|
+
}
|
|
591
|
+
let retorno = [];
|
|
592
|
+
for (let [indice, identificador] of identificadores.entries()) {
|
|
593
|
+
retorno.push(new declaracoes_1.Const(identificador, inicializadores[indice], tipo));
|
|
594
|
+
}
|
|
595
|
+
return retorno;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Este método contempla dois cenários:
|
|
599
|
+
*
|
|
600
|
+
* - A atribuição de variáveis em si (o primeiro símbolo é a palavra reservada `var`);
|
|
601
|
+
* - Uma reatribuição de uma ou mais variáveis (o primeiro símbolo a ser lido é uma
|
|
602
|
+
* vírgula, e o primeiro identificador é passado como argumento). Neste caso, não há
|
|
603
|
+
* a palavra reservada `var`.
|
|
604
|
+
* @param primeiroIdentificador Um construto de variável. É defiido em reatribuições.
|
|
605
|
+
* @returns Um vetor de declarações `Var`.
|
|
606
|
+
*/
|
|
607
|
+
declaracaoDeVariaveisPotigol(primeiroIdentificador) {
|
|
608
|
+
const identificadores = [];
|
|
609
|
+
let simboloVar;
|
|
610
|
+
// Se houver primeiro identificador definido (reatribuição),
|
|
611
|
+
// o símbolo atual aqui será uma vírgula.
|
|
612
|
+
if (primeiroIdentificador) {
|
|
613
|
+
this.avancarEDevolverAnterior();
|
|
614
|
+
identificadores.push(primeiroIdentificador.simbolo);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
simboloVar = this.avancarEDevolverAnterior();
|
|
618
|
+
}
|
|
619
|
+
do {
|
|
620
|
+
identificadores.push(this.consumir(lexico_regular_1.default.IDENTIFICADOR, 'Esperado nome de variável.'));
|
|
621
|
+
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
622
|
+
this.consumir(lexico_regular_1.default.REATRIBUIR, "Esperado ':=' após identificador em instrução 'var'.");
|
|
623
|
+
const inicializadores = [];
|
|
624
|
+
do {
|
|
625
|
+
inicializadores.push(this.expressao());
|
|
626
|
+
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
627
|
+
if (identificadores.length !== inicializadores.length) {
|
|
628
|
+
throw this.erro(simboloVar, 'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.');
|
|
629
|
+
}
|
|
630
|
+
const retorno = [];
|
|
631
|
+
const escopoAtual = this.pilhaEscoposVariaveisConhecidas.topoDaPilha();
|
|
632
|
+
for (let [indice, identificador] of identificadores.entries()) {
|
|
633
|
+
retorno.push(new declaracoes_1.Var(identificador, inicializadores[indice]));
|
|
634
|
+
escopoAtual.push(identificador.lexema);
|
|
635
|
+
}
|
|
636
|
+
return retorno;
|
|
637
|
+
}
|
|
638
|
+
logicaAtribuicaoComDicaDeTipo(expressao) {
|
|
639
|
+
// A dica de tipo é opcional.
|
|
640
|
+
// Só que, se a avaliação entra na dica, só
|
|
641
|
+
// podemos ter uma constante apenas.
|
|
642
|
+
this.avancarEDevolverAnterior();
|
|
643
|
+
if (![
|
|
644
|
+
lexico_regular_1.default.CARACTERE,
|
|
645
|
+
lexico_regular_1.default.INTEIRO,
|
|
646
|
+
lexico_regular_1.default.LOGICO,
|
|
647
|
+
lexico_regular_1.default.LÓGICO,
|
|
648
|
+
lexico_regular_1.default.REAL,
|
|
649
|
+
lexico_regular_1.default.TEXTO,
|
|
650
|
+
].includes(this.simbolos[this.atual].tipo)) {
|
|
651
|
+
throw this.erro(this.simbolos[this.atual], 'Esperado tipo após dois-pontos e nome de identificador.');
|
|
652
|
+
}
|
|
653
|
+
return this.avancarEDevolverAnterior();
|
|
654
|
+
}
|
|
388
655
|
/**
|
|
389
656
|
* Em Potigol, `escreva` aceita apenas um argumento.
|
|
390
657
|
* @returns Uma declaração `Escreva`.
|
|
@@ -554,145 +821,6 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
554
821
|
}
|
|
555
822
|
return new declaracoes_1.Escolha(condicao, caminhos, caminhoPadrao);
|
|
556
823
|
}
|
|
557
|
-
declaracaoDeConstantes(primeiroIdentificador) {
|
|
558
|
-
// Normalmente o símbolo atual aqui será uma vírgula.
|
|
559
|
-
this.avancarEDevolverAnterior();
|
|
560
|
-
const identificadores = [primeiroIdentificador.simbolo];
|
|
561
|
-
let tipo = null;
|
|
562
|
-
do {
|
|
563
|
-
identificadores.push(this.consumir(lexico_regular_1.default.IDENTIFICADOR, 'Esperado nome da constante.'));
|
|
564
|
-
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
565
|
-
// TODO: Aparentemente, não é possível definir tipo para atribuição
|
|
566
|
-
// múltipla de constantes. Se algo mudar nisso, o código abaixo poderá
|
|
567
|
-
// voltar a ser usado.
|
|
568
|
-
/* if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
|
|
569
|
-
const tipoConstante = this.verificarDefinicaoTipoAtual();
|
|
570
|
-
if (!tipoConstante) {
|
|
571
|
-
throw this.erro(this.simboloAtual(), 'Tipo definido na constante não é válido.');
|
|
572
|
-
}
|
|
573
|
-
tipo = tipoConstante;
|
|
574
|
-
this.avancarEDevolverAnterior();
|
|
575
|
-
} */
|
|
576
|
-
this.consumir(lexico_regular_1.default.IGUAL, "Esperado '=' após identificador em instrução 'constante'.");
|
|
577
|
-
const inicializadores = [];
|
|
578
|
-
do {
|
|
579
|
-
let inicializador = this.expressao();
|
|
580
|
-
if (identificadores.length > 1 &&
|
|
581
|
-
['LeiaInteiro', 'LeiaReal', 'LeiaTexto'].includes(inicializador.constructor.name)) {
|
|
582
|
-
switch (inicializador.constructor.name) {
|
|
583
|
-
case 'LeiaInteiro':
|
|
584
|
-
const inicializadorTipadoInteiro = inicializador;
|
|
585
|
-
inicializador = new construtos_2.LeiaInteiros(inicializadorTipadoInteiro.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoInteiro.simbolo.linha), identificadores.length));
|
|
586
|
-
break;
|
|
587
|
-
case 'LeiaReal':
|
|
588
|
-
const inicializadorTipadoReal = inicializador;
|
|
589
|
-
inicializador = new construtos_2.LeiaReais(inicializadorTipadoReal.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoReal.simbolo.linha), identificadores.length));
|
|
590
|
-
break;
|
|
591
|
-
case 'LeiaTexto':
|
|
592
|
-
const inicializadorTipadoTexto = inicializador;
|
|
593
|
-
inicializador = new construtos_2.LeiaTextos(inicializadorTipadoTexto.simbolo, new construtos_1.Literal(this.hashArquivo, Number(inicializadorTipadoTexto.simbolo.linha), identificadores.length));
|
|
594
|
-
break;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
inicializadores.push(inicializador);
|
|
598
|
-
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
599
|
-
if (identificadores.length !== inicializadores.length) {
|
|
600
|
-
// Pode ser que a inicialização seja feita por uma das
|
|
601
|
-
// funções `leia`, que podem ler vários valores. Neste caso, não deve dar erro.
|
|
602
|
-
if (!(inicializadores.length === 1 &&
|
|
603
|
-
['LeiaInteiros', 'LeiaReais', 'LeiaTextos'].includes(inicializadores[0].constructor.name))) {
|
|
604
|
-
throw this.erro(this.simbolos[this.atual], 'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.');
|
|
605
|
-
}
|
|
606
|
-
let tipoConversao;
|
|
607
|
-
switch (inicializadores[0].constructor.name) {
|
|
608
|
-
case 'LeiaInteiros':
|
|
609
|
-
tipoConversao = 'inteiro[]';
|
|
610
|
-
break;
|
|
611
|
-
case 'LeiaInteiro':
|
|
612
|
-
tipoConversao = 'inteiro';
|
|
613
|
-
break;
|
|
614
|
-
case 'LeiaReais':
|
|
615
|
-
tipoConversao = 'real[]';
|
|
616
|
-
break;
|
|
617
|
-
case 'LeiaReal':
|
|
618
|
-
tipoConversao = 'real';
|
|
619
|
-
break;
|
|
620
|
-
case 'LeiaTextos':
|
|
621
|
-
tipoConversao = 'texto[]';
|
|
622
|
-
break;
|
|
623
|
-
case 'LeiaTexto':
|
|
624
|
-
tipoConversao = 'texto';
|
|
625
|
-
break;
|
|
626
|
-
default:
|
|
627
|
-
tipoConversao = 'qualquer';
|
|
628
|
-
break;
|
|
629
|
-
}
|
|
630
|
-
return new declaracoes_1.ConstMultiplo(identificadores, inicializadores[0], tipoConversao);
|
|
631
|
-
}
|
|
632
|
-
let retorno = [];
|
|
633
|
-
for (let [indice, identificador] of identificadores.entries()) {
|
|
634
|
-
retorno.push(new declaracoes_1.Const(identificador, inicializadores[indice], tipo));
|
|
635
|
-
}
|
|
636
|
-
return retorno;
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Este método contempla dois cenários:
|
|
640
|
-
*
|
|
641
|
-
* - A atribuição de variáveis em si (o primeiro símbolo é a palavra reservada `var`);
|
|
642
|
-
* - Uma reatribuição de uma ou mais variáveis (o primeiro símbolo a ser lido é uma
|
|
643
|
-
* vírgula, e o primeiro identificador é passado como argumento). Neste caso, não há
|
|
644
|
-
* a palavra reservada `var`.
|
|
645
|
-
* @param primeiroIdentificador Um construto de variável. É defiido em reatribuições.
|
|
646
|
-
* @returns Um vetor de declarações `Var`.
|
|
647
|
-
*/
|
|
648
|
-
declaracaoDeVariaveisPotigol(primeiroIdentificador) {
|
|
649
|
-
const identificadores = [];
|
|
650
|
-
let simboloVar;
|
|
651
|
-
// Se houver primeiro identificador definido (reatribuição),
|
|
652
|
-
// o símbolo atual aqui será uma vírgula.
|
|
653
|
-
if (primeiroIdentificador) {
|
|
654
|
-
this.avancarEDevolverAnterior();
|
|
655
|
-
identificadores.push(primeiroIdentificador.simbolo);
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
simboloVar = this.avancarEDevolverAnterior();
|
|
659
|
-
}
|
|
660
|
-
do {
|
|
661
|
-
identificadores.push(this.consumir(lexico_regular_1.default.IDENTIFICADOR, 'Esperado nome de variável.'));
|
|
662
|
-
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
663
|
-
this.consumir(lexico_regular_1.default.REATRIBUIR, "Esperado ':=' após identificador em instrução 'var'.");
|
|
664
|
-
const inicializadores = [];
|
|
665
|
-
do {
|
|
666
|
-
inicializadores.push(this.expressao());
|
|
667
|
-
} while (this.verificarSeSimboloAtualEIgualA(lexico_regular_1.default.VIRGULA));
|
|
668
|
-
if (identificadores.length !== inicializadores.length) {
|
|
669
|
-
throw this.erro(simboloVar, 'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.');
|
|
670
|
-
}
|
|
671
|
-
const retorno = [];
|
|
672
|
-
const escopoAtual = this.pilhaEscoposVariaveisConhecidas.topoDaPilha();
|
|
673
|
-
for (let [indice, identificador] of identificadores.entries()) {
|
|
674
|
-
retorno.push(new declaracoes_1.Var(identificador, inicializadores[indice]));
|
|
675
|
-
escopoAtual.push(identificador.lexema);
|
|
676
|
-
}
|
|
677
|
-
return retorno;
|
|
678
|
-
}
|
|
679
|
-
logicaAtribuicaoComDicaDeTipo(expressao) {
|
|
680
|
-
// A dica de tipo é opcional.
|
|
681
|
-
// Só que, se a avaliação entra na dica, só
|
|
682
|
-
// podemos ter uma constante apenas.
|
|
683
|
-
this.avancarEDevolverAnterior();
|
|
684
|
-
if (![
|
|
685
|
-
lexico_regular_1.default.CARACTERE,
|
|
686
|
-
lexico_regular_1.default.INTEIRO,
|
|
687
|
-
lexico_regular_1.default.LOGICO,
|
|
688
|
-
lexico_regular_1.default.LÓGICO,
|
|
689
|
-
lexico_regular_1.default.REAL,
|
|
690
|
-
lexico_regular_1.default.TEXTO,
|
|
691
|
-
].includes(this.simbolos[this.atual].tipo)) {
|
|
692
|
-
throw this.erro(this.simbolos[this.atual], 'Esperado tipo após dois-pontos e nome de identificador.');
|
|
693
|
-
}
|
|
694
|
-
return this.avancarEDevolverAnterior();
|
|
695
|
-
}
|
|
696
824
|
declaracaoFazer() {
|
|
697
825
|
throw new Error('Método não implementado.');
|
|
698
826
|
}
|
|
@@ -783,7 +911,15 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
783
911
|
return expressao;
|
|
784
912
|
}
|
|
785
913
|
/**
|
|
786
|
-
*
|
|
914
|
+
* Potigol não possui simplesmente um `leia`. Seus comandos `leia` são todos tipados.
|
|
915
|
+
* São eles: `leia_inteiro`, `leia_inteiros`, `leia_real`, `leia_reais`, `leia_texto` e
|
|
916
|
+
* `leia_textos`.
|
|
917
|
+
*/
|
|
918
|
+
expressaoLeia() {
|
|
919
|
+
throw new Error('Método não implementado.');
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Em Potigol, uma definição de função pode simplesmente começar com um
|
|
787
923
|
* identificador - que não é uma palavra reservada - seguido de parênteses.
|
|
788
924
|
* Este ponto de entrada verifica o símbolo atual e o próximo.
|
|
789
925
|
*
|
|
@@ -810,6 +946,8 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
810
946
|
resolverDeclaracaoForaDeBloco() {
|
|
811
947
|
const simboloAtual = this.simbolos[this.atual];
|
|
812
948
|
switch (simboloAtual.tipo) {
|
|
949
|
+
case lexico_regular_1.default.DEF:
|
|
950
|
+
return this.declaracaoDeFuncaoComDef();
|
|
813
951
|
case lexico_regular_1.default.ENQUANTO:
|
|
814
952
|
return this.declaracaoEnquanto();
|
|
815
953
|
case lexico_regular_1.default.ESCOLHA:
|
|
@@ -824,6 +962,8 @@ class AvaliadorSintaticoPotigol extends avaliador_sintatico_base_1.AvaliadorSint
|
|
|
824
962
|
return this.declaracaoSe();
|
|
825
963
|
case lexico_regular_1.default.TIPO:
|
|
826
964
|
return this.declaracaoTipo();
|
|
965
|
+
case lexico_regular_1.default.VAL:
|
|
966
|
+
return this.declaracaoDeConstanteExplicita();
|
|
827
967
|
case lexico_regular_1.default.VARIAVEL:
|
|
828
968
|
return this.declaracaoDeVariaveisPotigol();
|
|
829
969
|
default:
|