@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.
@@ -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 pragma.
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
- declaracaoFuncaoPotigolIniciadaPorIgual(simboloPrimario, parametros, tipoRetorno) {
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 pragma.
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, simboloPragma, parametros) {
103
+ corpoDaFuncao(nomeFuncao, simboloLocalizacao, parametros) {
105
104
  const corpo = this.blocoEscopo();
106
- return new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simboloPragma.linha), parametros, corpo);
105
+ return new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simboloLocalizacao.linha), parametros, corpo);
107
106
  }
108
- declaracaoDeFuncaoOuMetodo(construtoPrimario) {
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 pragma.
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.declaracaoFuncaoPotigolIniciadaPorIgual(construtoPrimario.simbolo, resolucaoParametros.parametros, tipoRetorno);
135
+ return this.declaracaoFuncaoPotigolIniciadaPorIgualOuSeta(simboloNomeFuncao, resolucaoParametros.parametros, tipoRetorno);
130
136
  }
131
- return this.declaracaoFuncaoPotigolTerminadaPorFim(construtoPrimario.simbolo, parenteseEsquerdo, resolucaoParametros.parametros, tipoRetorno);
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
- indice++;
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
- // Tupla
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
- * Em Potigol, uma definição de função normalmente começa com um
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: