@designliquido/delegua 0.43.3 → 0.43.4
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-base.d.ts +1 -3
- package/avaliador-sintatico/avaliador-sintatico-base.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico-base.js.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.d.ts +2 -2
- package/avaliador-sintatico/avaliador-sintatico.d.ts.map +1 -1
- package/avaliador-sintatico/avaliador-sintatico.js +9 -3
- package/avaliador-sintatico/avaliador-sintatico.js.map +1 -1
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts +140 -0
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.d.ts.map +1 -0
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js +1087 -0
- package/avaliador-sintatico/dialetos/avaliador-sintatico-tenda.js.map +1 -0
- package/avaliador-sintatico/dialetos/index.d.ts +1 -0
- package/avaliador-sintatico/dialetos/index.d.ts.map +1 -1
- package/avaliador-sintatico/dialetos/index.js +1 -0
- package/avaliador-sintatico/dialetos/index.js.map +1 -1
- package/avaliador-sintatico/erro-avaliador-sintatico.d.ts +2 -0
- package/avaliador-sintatico/erro-avaliador-sintatico.d.ts.map +1 -1
- package/avaliador-sintatico/erro-avaliador-sintatico.js +2 -0
- package/avaliador-sintatico/erro-avaliador-sintatico.js.map +1 -1
- package/bin/package.json +1 -1
- package/lexador/dialetos/index.d.ts +1 -0
- package/lexador/dialetos/index.d.ts.map +1 -1
- package/lexador/dialetos/index.js +1 -0
- package/lexador/dialetos/index.js.map +1 -1
- package/lexador/dialetos/lexador-tenda.d.ts +52 -0
- package/lexador/dialetos/lexador-tenda.d.ts.map +1 -0
- package/lexador/dialetos/lexador-tenda.js +399 -0
- package/lexador/dialetos/lexador-tenda.js.map +1 -0
- package/lexador/dialetos/palavras-reservadas/tenda.d.ts +46 -0
- package/lexador/dialetos/palavras-reservadas/tenda.d.ts.map +1 -0
- package/lexador/dialetos/palavras-reservadas/tenda.js +53 -0
- package/lexador/dialetos/palavras-reservadas/tenda.js.map +1 -0
- package/package.json +1 -1
- package/tipos-de-simbolos/tenda.d.ts +100 -0
- package/tipos-de-simbolos/tenda.d.ts.map +1 -0
- package/tipos-de-simbolos/tenda.js +102 -0
- package/tipos-de-simbolos/tenda.js.map +1 -0
- package/tradutores/index.d.ts +1 -0
- package/tradutores/index.d.ts.map +1 -1
- package/tradutores/index.js +1 -0
- package/tradutores/index.js.map +1 -1
- package/tradutores/tradutor-reverso-tenda.d.ts +90 -0
- package/tradutores/tradutor-reverso-tenda.d.ts.map +1 -0
- package/tradutores/tradutor-reverso-tenda.js +584 -0
- package/tradutores/tradutor-reverso-tenda.js.map +1 -0
- package/umd/delegua.js +5741 -3500
|
@@ -0,0 +1,1087 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AvaliadorSintaticoTenda = void 0;
|
|
7
|
+
const browser_process_hrtime_1 = __importDefault(require("browser-process-hrtime"));
|
|
8
|
+
const construtos_1 = require("../../construtos");
|
|
9
|
+
const erro_avaliador_sintatico_1 = require("./../erro-avaliador-sintatico");
|
|
10
|
+
const tuplas_1 = require("../../construtos/tuplas");
|
|
11
|
+
const declaracoes_1 = require("../../declaracoes");
|
|
12
|
+
const avaliador_sintatico_base_1 = require("../avaliador-sintatico-base");
|
|
13
|
+
const inferenciador_1 = require("../../inferenciador");
|
|
14
|
+
const pilha_escopos_1 = require("./../pilha-escopos");
|
|
15
|
+
const informacao_escopo_1 = require("./../informacao-escopo");
|
|
16
|
+
const informacao_variavel_ou_constante_1 = require("../../informacao-variavel-ou-constante");
|
|
17
|
+
const simbolo_1 = require("../../lexador/simbolo");
|
|
18
|
+
const delegua_1 = __importDefault(require("../../tipos-de-dados/delegua"));
|
|
19
|
+
const tenda_1 = __importDefault(require("../../tipos-de-simbolos/tenda"));
|
|
20
|
+
const primitivas_dicionario_1 = __importDefault(require("../../bibliotecas/primitivas-dicionario"));
|
|
21
|
+
const primitivas_numero_1 = __importDefault(require("../../bibliotecas/primitivas-numero"));
|
|
22
|
+
const primitivas_texto_1 = __importDefault(require("../../bibliotecas/primitivas-texto"));
|
|
23
|
+
const primitivas_vetor_1 = __importDefault(require("../../bibliotecas/primitivas-vetor"));
|
|
24
|
+
/**
|
|
25
|
+
* Este avaliador sintático emite todos os símbolos de Tenda. No entanto, nem todo
|
|
26
|
+
* símbolo emitido aqui pode ser interpretado por este núcleo, já que Tenda tem
|
|
27
|
+
* Rust como base, e várias de suas funções requerem interface com um sistema operacional.
|
|
28
|
+
* Outros pacotes do ecossistema de Delégua, como `delegua-node` poderão lidar com
|
|
29
|
+
* todas as funcionalidades de Tenda.
|
|
30
|
+
*/
|
|
31
|
+
class AvaliadorSintaticoTenda extends avaliador_sintatico_base_1.AvaliadorSintaticoBase {
|
|
32
|
+
constructor(performance = false) {
|
|
33
|
+
super();
|
|
34
|
+
this.hashArquivo = 0;
|
|
35
|
+
this.atual = 0;
|
|
36
|
+
this.blocos = 0;
|
|
37
|
+
this.erros = [];
|
|
38
|
+
this.performance = performance;
|
|
39
|
+
this.tiposDefinidosEmCodigo = {};
|
|
40
|
+
this.tiposDeFerramentasExternas = {};
|
|
41
|
+
this.primitivasConhecidas = {};
|
|
42
|
+
for (const [nomePrimitivaDicionario, dadosPrimitiva] of Object.entries(primitivas_dicionario_1.default)) {
|
|
43
|
+
this.primitivasConhecidas[nomePrimitivaDicionario] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomePrimitivaDicionario, 'dicionário', dadosPrimitiva.argumentos);
|
|
44
|
+
}
|
|
45
|
+
for (const [nomePrimitivaNumero, dadosPrimitiva] of Object.entries(primitivas_numero_1.default)) {
|
|
46
|
+
this.primitivasConhecidas[nomePrimitivaNumero] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomePrimitivaNumero, 'número', dadosPrimitiva.argumentos);
|
|
47
|
+
}
|
|
48
|
+
for (const [nomePrimitivaTexto, dadosPrimitiva] of Object.entries(primitivas_texto_1.default)) {
|
|
49
|
+
this.primitivasConhecidas[nomePrimitivaTexto] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomePrimitivaTexto, 'texto', dadosPrimitiva.argumentos);
|
|
50
|
+
}
|
|
51
|
+
for (const [nomePrimitivaVetor, dadosPrimitiva] of Object.entries(primitivas_vetor_1.default)) {
|
|
52
|
+
this.primitivasConhecidas[nomePrimitivaVetor] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomePrimitivaVetor, 'vetor', dadosPrimitiva.argumentos);
|
|
53
|
+
}
|
|
54
|
+
// TODO: Por enquanto não há necessidade de validar argumentos aqui, mas isso pode mudar no futuro.
|
|
55
|
+
this.primitivasConhecidas['inteiro'] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('inteiro', 'inteiro');
|
|
56
|
+
this.primitivasConhecidas['numero'] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('numero', 'número');
|
|
57
|
+
this.primitivasConhecidas['número'] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número');
|
|
58
|
+
this.primitivasConhecidas['texto'] = new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('texto', 'texto');
|
|
59
|
+
this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos();
|
|
60
|
+
}
|
|
61
|
+
verificarDefinicaoTipoAtual() {
|
|
62
|
+
const tipos = [...Object.values(delegua_1.default)];
|
|
63
|
+
if (this.simbolos[this.atual].lexema in this.tiposDefinidosEmCodigo) {
|
|
64
|
+
return this.simbolos[this.atual].lexema;
|
|
65
|
+
}
|
|
66
|
+
const lexemaElementar = this.simbolos[this.atual].lexema.toLowerCase();
|
|
67
|
+
const tipoElementarResolvido = tipos.find((tipo) => tipo === lexemaElementar);
|
|
68
|
+
if (!tipoElementarResolvido) {
|
|
69
|
+
throw this.erro(this.simbolos[this.atual], `Tipo de dados desconhecido: '${this.simbolos[this.atual].lexema}'.`);
|
|
70
|
+
}
|
|
71
|
+
if (this.verificarTipoProximoSimbolo(tenda_1.default.COLCHETE_ESQUERDO)) {
|
|
72
|
+
const tiposVetores = ['inteiro[]', 'numero[]', 'número[]', 'qualquer[]', 'real[]', 'texto[]'];
|
|
73
|
+
this.avancarEDevolverAnterior();
|
|
74
|
+
if (!this.verificarTipoProximoSimbolo(tenda_1.default.COLCHETE_DIREITO)) {
|
|
75
|
+
throw this.erro(this.simbolos[this.atual], `Esperado símbolo de fechamento do vetor: ']'. Atual: ${this.simbolos[this.atual].lexema}`);
|
|
76
|
+
}
|
|
77
|
+
const tipoVetor = tiposVetores.find((tipo) => tipo === `${lexemaElementar}[]`);
|
|
78
|
+
this.avancarEDevolverAnterior();
|
|
79
|
+
return tipoVetor;
|
|
80
|
+
}
|
|
81
|
+
return tipoElementarResolvido;
|
|
82
|
+
}
|
|
83
|
+
obterChaveDicionario() {
|
|
84
|
+
switch (this.simbolos[this.atual].tipo) {
|
|
85
|
+
case tenda_1.default.NUMERO:
|
|
86
|
+
case tenda_1.default.TEXTO:
|
|
87
|
+
case tenda_1.default.FALSO:
|
|
88
|
+
case tenda_1.default.VERDADEIRO:
|
|
89
|
+
return this.primario();
|
|
90
|
+
case tenda_1.default.IDENTIFICADOR:
|
|
91
|
+
const simboloIdentificador = this.avancarEDevolverAnterior();
|
|
92
|
+
let tipoOperando;
|
|
93
|
+
if (simboloIdentificador.lexema in this.tiposDefinidosEmCodigo) {
|
|
94
|
+
tipoOperando = simboloIdentificador.lexema;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema);
|
|
98
|
+
}
|
|
99
|
+
if (!['numero', 'número', 'texto', 'lógico'].includes(tipoOperando)) {
|
|
100
|
+
throw this.erro(simboloIdentificador, `Tipo ${tipoOperando} de identificador ${simboloIdentificador.lexema} não é válido como chave de dicionário.`);
|
|
101
|
+
}
|
|
102
|
+
return new construtos_1.Variavel(this.hashArquivo, simboloIdentificador, tipoOperando);
|
|
103
|
+
case tenda_1.default.COLCHETE_ESQUERDO:
|
|
104
|
+
this.avancarEDevolverAnterior();
|
|
105
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.PARENTESE_ESQUERDO)) {
|
|
106
|
+
return this.construtoTupla();
|
|
107
|
+
}
|
|
108
|
+
throw this.erro(this.simbolos[this.atual], `Esperado parêntese esquerdo após colchete esquerdo para definição de chave de dicionário. Atual: ${this.simbolos[this.atual].tipo}.`);
|
|
109
|
+
default:
|
|
110
|
+
throw this.erro(this.simbolos[this.atual], `Símbolo ${this.simbolos[this.atual].tipo} inesperado ou inválido como chave de dicionário.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
construtoDicionario(simboloChaveEsquerda) {
|
|
114
|
+
this.avancarEDevolverAnterior();
|
|
115
|
+
const chaves = [];
|
|
116
|
+
const valores = [];
|
|
117
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.CHAVE_DIREITA)) {
|
|
118
|
+
return new construtos_1.Dicionario(this.hashArquivo, Number(simboloChaveEsquerda.linha), [], []);
|
|
119
|
+
}
|
|
120
|
+
while (!this.verificarSeSimboloAtualEIgualA(tenda_1.default.CHAVE_DIREITA)) {
|
|
121
|
+
const chave = this.obterChaveDicionario();
|
|
122
|
+
this.consumir(tenda_1.default.DOIS_PONTOS, "Esperado ':' entre chave e valor.");
|
|
123
|
+
const valor = this.atribuir();
|
|
124
|
+
chaves.push(chave);
|
|
125
|
+
valores.push(valor);
|
|
126
|
+
if (this.simbolos[this.atual].tipo !== tenda_1.default.CHAVE_DIREITA) {
|
|
127
|
+
this.consumir(tenda_1.default.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return new construtos_1.Dicionario(this.hashArquivo, Number(simboloChaveEsquerda.linha), chaves, valores);
|
|
131
|
+
}
|
|
132
|
+
construtoTupla() {
|
|
133
|
+
const expressao = this.expressao();
|
|
134
|
+
const argumentos = [expressao];
|
|
135
|
+
while (this.simbolos[this.atual].tipo === tenda_1.default.VIRGULA) {
|
|
136
|
+
this.avancarEDevolverAnterior();
|
|
137
|
+
argumentos.push(this.expressao());
|
|
138
|
+
}
|
|
139
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
|
|
140
|
+
this.consumir(tenda_1.default.COLCHETE_DIREITO, "Esperado ']' após a expressão.");
|
|
141
|
+
return new tuplas_1.SeletorTuplas(...argumentos);
|
|
142
|
+
}
|
|
143
|
+
primario() {
|
|
144
|
+
const simboloAtual = this.simbolos[this.atual];
|
|
145
|
+
let valores = [];
|
|
146
|
+
switch (simboloAtual.tipo) {
|
|
147
|
+
case tenda_1.default.CHAVE_ESQUERDA:
|
|
148
|
+
return this.construtoDicionario(simboloAtual);
|
|
149
|
+
case tenda_1.default.COLCHETE_ESQUERDO:
|
|
150
|
+
this.avancarEDevolverAnterior();
|
|
151
|
+
valores = [];
|
|
152
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.COLCHETE_DIREITO)) {
|
|
153
|
+
return new construtos_1.Vetor(this.hashArquivo, Number(simboloAtual.linha), [], 0, 'qualquer[]');
|
|
154
|
+
}
|
|
155
|
+
while (!this.verificarSeSimboloAtualEIgualA(tenda_1.default.COLCHETE_DIREITO)) {
|
|
156
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.PARENTESE_ESQUERDO)) {
|
|
157
|
+
return this.construtoTupla();
|
|
158
|
+
}
|
|
159
|
+
const valor = this.atribuir();
|
|
160
|
+
valores.push(valor);
|
|
161
|
+
if (this.simbolos[this.atual].tipo !== tenda_1.default.COLCHETE_DIREITO) {
|
|
162
|
+
this.consumir(tenda_1.default.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const tipoVetor = (0, inferenciador_1.inferirTipoVariavel)(valores);
|
|
166
|
+
return new construtos_1.Vetor(this.hashArquivo, Number(simboloAtual.linha), valores, valores.length, tipoVetor);
|
|
167
|
+
case tenda_1.default.EXPRESSAO_REGULAR:
|
|
168
|
+
let valor = '';
|
|
169
|
+
let linhaAtual = this.simbolos[this.atual].linha;
|
|
170
|
+
let eParExpressaoRegular = this.simbolos.filter((l) => l.linha === linhaAtual && l.tipo === tenda_1.default.EXPRESSAO_REGULAR)
|
|
171
|
+
.length %
|
|
172
|
+
2 ===
|
|
173
|
+
0;
|
|
174
|
+
if (eParExpressaoRegular) {
|
|
175
|
+
this.avancarEDevolverAnterior();
|
|
176
|
+
while (!this.verificarTipoSimboloAtual(tenda_1.default.EXPRESSAO_REGULAR)) {
|
|
177
|
+
valor += this.simbolos[this.atual].lexema || '';
|
|
178
|
+
this.avancarEDevolverAnterior();
|
|
179
|
+
}
|
|
180
|
+
this.avancarEDevolverAnterior();
|
|
181
|
+
return new construtos_1.ExpressaoRegular(this.hashArquivo, simboloAtual, valor);
|
|
182
|
+
}
|
|
183
|
+
case tenda_1.default.FALSO:
|
|
184
|
+
this.avancarEDevolverAnterior();
|
|
185
|
+
return new construtos_1.Literal(this.hashArquivo, Number(simboloAtual.linha), false, 'lógico');
|
|
186
|
+
case tenda_1.default.FUNCAO:
|
|
187
|
+
case tenda_1.default.FUNÇÃO:
|
|
188
|
+
const simboloFuncao = this.avancarEDevolverAnterior();
|
|
189
|
+
// Avançamos o parêntese esquerdo aqui, porque `corpoDaFuncao`
|
|
190
|
+
// espera que esse parêntese esquerdo já foi consumido.
|
|
191
|
+
this.consumir(tenda_1.default.PARENTESE_ESQUERDO, "Esperado parêntese esquerdo após palavra reservada 'função'.");
|
|
192
|
+
const corpoDaFuncao = this.corpoDaFuncao(simboloFuncao.lexema);
|
|
193
|
+
this.pilhaEscopos.definirInformacoesVariavel(simboloFuncao.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simboloFuncao.lexema, 'função'));
|
|
194
|
+
return corpoDaFuncao;
|
|
195
|
+
case tenda_1.default.IDENTIFICADOR:
|
|
196
|
+
const simboloIdentificador = this.avancarEDevolverAnterior();
|
|
197
|
+
let tipoOperando;
|
|
198
|
+
if (simboloIdentificador.lexema in this.tiposDefinidosEmCodigo) {
|
|
199
|
+
tipoOperando = simboloIdentificador.lexema;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema);
|
|
203
|
+
}
|
|
204
|
+
// Se o próximo símbolo é um incremento ou um decremento,
|
|
205
|
+
// aqui deve retornar um unário correspondente.
|
|
206
|
+
// Caso contrário, apenas retornar um construto de variável.
|
|
207
|
+
if (this.simbolos[this.atual] &&
|
|
208
|
+
[tenda_1.default.INCREMENTAR, tenda_1.default.DECREMENTAR].includes(this.simbolos[this.atual].tipo)) {
|
|
209
|
+
const simboloIncrementoDecremento = this.avancarEDevolverAnterior();
|
|
210
|
+
return new construtos_1.Unario(this.hashArquivo, simboloIncrementoDecremento, new construtos_1.Variavel(this.hashArquivo, simboloIdentificador, tipoOperando || 'qualquer'), 'DEPOIS');
|
|
211
|
+
}
|
|
212
|
+
return new construtos_1.Variavel(this.hashArquivo, simboloIdentificador, tipoOperando || 'qualquer');
|
|
213
|
+
case tenda_1.default.LEIA:
|
|
214
|
+
return this.expressaoLeia();
|
|
215
|
+
case tenda_1.default.NADA:
|
|
216
|
+
this.avancarEDevolverAnterior();
|
|
217
|
+
return new construtos_1.Literal(this.hashArquivo, Number(simboloAtual.linha), null, 'nulo');
|
|
218
|
+
case tenda_1.default.NUMERO:
|
|
219
|
+
case tenda_1.default.NÚMERO:
|
|
220
|
+
case tenda_1.default.TEXTO:
|
|
221
|
+
const simboloNumeroTexto = this.avancarEDevolverAnterior();
|
|
222
|
+
const tipoInferido = (0, inferenciador_1.inferirTipoVariavel)(simboloNumeroTexto.literal);
|
|
223
|
+
const tipoDadosElementar = (0, inferenciador_1.tipoInferenciaParaTipoDadosElementar)(tipoInferido);
|
|
224
|
+
return new construtos_1.Literal(this.hashArquivo, Number(simboloNumeroTexto.linha), simboloNumeroTexto.literal, tipoDadosElementar);
|
|
225
|
+
case tenda_1.default.PARENTESE_ESQUERDO:
|
|
226
|
+
this.avancarEDevolverAnterior();
|
|
227
|
+
const expressao = this.expressao();
|
|
228
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
|
|
229
|
+
return new construtos_1.Agrupamento(this.hashArquivo, Number(simboloAtual.linha), expressao);
|
|
230
|
+
case tenda_1.default.SUPER:
|
|
231
|
+
const simboloSuper = this.avancarEDevolverAnterior();
|
|
232
|
+
if (!this.superclasseAtual) {
|
|
233
|
+
throw this.erro(this.simbolos[this.atual], "'Super' usado fora de declaração de classe com herança.");
|
|
234
|
+
}
|
|
235
|
+
return new construtos_1.Super(this.hashArquivo, simboloSuper, this.superclasseAtual);
|
|
236
|
+
case tenda_1.default.VERDADEIRO:
|
|
237
|
+
this.avancarEDevolverAnterior();
|
|
238
|
+
return new construtos_1.Literal(this.hashArquivo, Number(simboloAtual.linha), true, 'lógico');
|
|
239
|
+
}
|
|
240
|
+
throw this.erro(this.simbolos[this.atual], 'Esperado expressão.');
|
|
241
|
+
}
|
|
242
|
+
chamar() {
|
|
243
|
+
let expressao = this.primario();
|
|
244
|
+
while (true) {
|
|
245
|
+
let tipoPrimitiva = undefined;
|
|
246
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.PARENTESE_ESQUERDO)) {
|
|
247
|
+
expressao = this.finalizarChamada(expressao, tipoPrimitiva);
|
|
248
|
+
}
|
|
249
|
+
else if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.PONTO)) {
|
|
250
|
+
const nome = this.consumir(tenda_1.default.IDENTIFICADOR, "Esperado nome de método ou propriedade após '.'.");
|
|
251
|
+
tipoPrimitiva = expressao.tipo;
|
|
252
|
+
expressao = new construtos_1.AcessoMetodoOuPropriedade(this.hashArquivo, expressao, nome);
|
|
253
|
+
}
|
|
254
|
+
else if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.COLCHETE_ESQUERDO)) {
|
|
255
|
+
const indice = this.expressao();
|
|
256
|
+
const simboloFechamento = this.consumir(tenda_1.default.COLCHETE_DIREITO, "Esperado ']' após escrita do indice.");
|
|
257
|
+
expressao = new construtos_1.AcessoIndiceVariavel(this.hashArquivo, expressao, indice, simboloFechamento);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return expressao;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* `AcessoMetodoOuPropriedade` é um construto intermediário em Delégua, e deve ser resolvido como outro
|
|
267
|
+
* construto antes de qualquer outra próxima etapa. Algumas validações adicionais também ocorrem aqui.
|
|
268
|
+
* @param {AcessoMetodoOuPropriedade} entidadeChamadaResolvida O construto original.
|
|
269
|
+
* @returns {Construto} O construto resolvido como um tipo mais específico.
|
|
270
|
+
* @see finalizarChamada
|
|
271
|
+
*/
|
|
272
|
+
resolverEntidadeChamadaAcessoMetodoOuPropriedade(entidadeChamadaResolvida) {
|
|
273
|
+
const construtoTipado = entidadeChamadaResolvida;
|
|
274
|
+
switch (entidadeChamadaResolvida.tipo) {
|
|
275
|
+
case delegua_1.default.DICIONARIO:
|
|
276
|
+
case delegua_1.default.DICIONÁRIO:
|
|
277
|
+
if (!(construtoTipado.simbolo.lexema in primitivas_dicionario_1.default)) {
|
|
278
|
+
throw this.erro(construtoTipado.simbolo, `${construtoTipado.simbolo.lexema} não é uma primitiva de dicionário.`);
|
|
279
|
+
}
|
|
280
|
+
const primitivaDicionarioSelecionada = primitivas_dicionario_1.default[construtoTipado.simbolo.lexema];
|
|
281
|
+
return new construtos_1.AcessoMetodo(construtoTipado.hashArquivo, construtoTipado.objeto, construtoTipado.simbolo.lexema, primitivaDicionarioSelecionada.tipoRetorno);
|
|
282
|
+
case delegua_1.default.INTEIRO:
|
|
283
|
+
case delegua_1.default.NUMERO:
|
|
284
|
+
case delegua_1.default.NÚMERO:
|
|
285
|
+
if (!(construtoTipado.simbolo.lexema in primitivas_numero_1.default)) {
|
|
286
|
+
throw this.erro(construtoTipado.simbolo, `${construtoTipado.simbolo.lexema} não é uma primitiva de número.`);
|
|
287
|
+
}
|
|
288
|
+
const primitivaNumeroSelecionada = primitivas_numero_1.default[construtoTipado.simbolo.lexema];
|
|
289
|
+
return new construtos_1.AcessoMetodo(construtoTipado.hashArquivo, construtoTipado.objeto, construtoTipado.simbolo.lexema, primitivaNumeroSelecionada.tipoRetorno);
|
|
290
|
+
case delegua_1.default.MODULO:
|
|
291
|
+
case delegua_1.default.MÓDULO:
|
|
292
|
+
if (construtoTipado.simbolo.lexema in this.tiposDefinidosEmCodigo) {
|
|
293
|
+
// Construtor de classe.
|
|
294
|
+
return new construtos_1.Variavel(construtoTipado.hashArquivo, construtoTipado.simbolo, construtoTipado.objeto.tipo);
|
|
295
|
+
}
|
|
296
|
+
return new construtos_1.AcessoMetodo(construtoTipado.hashArquivo, construtoTipado.objeto, construtoTipado.simbolo.lexema);
|
|
297
|
+
case delegua_1.default.TEXTO:
|
|
298
|
+
if (!(construtoTipado.simbolo.lexema in primitivas_texto_1.default)) {
|
|
299
|
+
throw this.erro(construtoTipado.simbolo, `${construtoTipado.simbolo.lexema} não é uma primitiva de texto.`);
|
|
300
|
+
}
|
|
301
|
+
const primitivaTextoSelecionada = primitivas_texto_1.default[construtoTipado.simbolo.lexema];
|
|
302
|
+
return new construtos_1.AcessoMetodo(construtoTipado.hashArquivo, construtoTipado.objeto, construtoTipado.simbolo.lexema, primitivaTextoSelecionada.tipoRetorno);
|
|
303
|
+
case delegua_1.default.VETOR:
|
|
304
|
+
case delegua_1.default.VETOR_NUMERO:
|
|
305
|
+
case delegua_1.default.VETOR_NÚMERO:
|
|
306
|
+
case delegua_1.default.VETOR_TEXTO:
|
|
307
|
+
if (!(construtoTipado.simbolo.lexema in primitivas_vetor_1.default)) {
|
|
308
|
+
throw this.erro(construtoTipado.simbolo, `${construtoTipado.simbolo.lexema} não é uma primitiva de vetor.`);
|
|
309
|
+
}
|
|
310
|
+
const primitivaVetorSelecionada = primitivas_vetor_1.default[construtoTipado.simbolo.lexema];
|
|
311
|
+
return new construtos_1.AcessoMetodo(construtoTipado.hashArquivo, construtoTipado.objeto, construtoTipado.simbolo.lexema, primitivaVetorSelecionada.tipoRetorno);
|
|
312
|
+
}
|
|
313
|
+
return entidadeChamadaResolvida;
|
|
314
|
+
}
|
|
315
|
+
validarArgumentosEntidadeChamada(argumentosEntidadeChamada, argumentosUtilizados) {
|
|
316
|
+
if (argumentosEntidadeChamada.length === 0) {
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
const possiveisErros = [];
|
|
320
|
+
for (const [indice, argumentoEntidadeChamada] of argumentosEntidadeChamada.entries()) {
|
|
321
|
+
const argumentoUtilizado = argumentosUtilizados[indice];
|
|
322
|
+
if (argumentoUtilizado.tipo === null || argumentoUtilizado.tipo === undefined) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const argumentoEntidadeChamadaVetor = argumentoEntidadeChamada.tipo.endsWith('[]');
|
|
326
|
+
const argumentoUtilizadoVetor = argumentoUtilizado.tipo.endsWith('[]');
|
|
327
|
+
if (argumentoEntidadeChamadaVetor !== argumentoUtilizadoVetor) {
|
|
328
|
+
possiveisErros.push(`Argumento: ${argumentoEntidadeChamada.nome}. Tipo esperado: ${argumentoEntidadeChamada.tipo}; Tipo utilizado: ${argumentoUtilizado.tipo}`);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const argumentoEntidadeChamadaQualquer = argumentoEntidadeChamada.tipo.startsWith('qualquer');
|
|
332
|
+
if (argumentoEntidadeChamadaQualquer) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (argumentoUtilizado.tipo !== argumentoEntidadeChamada.tipo) {
|
|
336
|
+
possiveisErros.push(`Argumento: ${argumentoEntidadeChamada.nome}. Tipo esperado: ${argumentoEntidadeChamada.tipo}; Tipo utilizado: ${argumentoUtilizado.tipo}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return possiveisErros;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Diversas verificações de resolução de entidade chamada, como resolver chamada da pilha ou usar referência, argumentos, etc.
|
|
343
|
+
* @param entidadeChamada O construto da entidade chamada.
|
|
344
|
+
* @param argumentos Os argumentos utilizados na chamada.
|
|
345
|
+
* @param tipoPrimitiva Se for uma primitiva, o tipo dela. Senão, `undefined`.
|
|
346
|
+
* @returns A entidade chamada resolvida, se as validações passarem.
|
|
347
|
+
*/
|
|
348
|
+
resolverEntidadeChamada(entidadeChamada, argumentos, tipoPrimitiva = undefined) {
|
|
349
|
+
if (entidadeChamada.constructor.name === 'Variavel') {
|
|
350
|
+
const entidadeChamadaResolvidaVariavel = entidadeChamada;
|
|
351
|
+
if (tipoPrimitiva === undefined) {
|
|
352
|
+
// Provavelmente uma chamada a alguma função da biblioteca global.
|
|
353
|
+
const informacoesPossivelFuncaoBibliotecaGlobal = this.pilhaEscopos.obterBibliotecaGlobal(entidadeChamadaResolvidaVariavel.simbolo.lexema);
|
|
354
|
+
if (informacoesPossivelFuncaoBibliotecaGlobal !== undefined) {
|
|
355
|
+
const erros = this.validarArgumentosEntidadeChamada(informacoesPossivelFuncaoBibliotecaGlobal.argumentos, argumentos);
|
|
356
|
+
if (erros.length > 0) {
|
|
357
|
+
throw new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(entidadeChamadaResolvidaVariavel.simbolo, `Erros ao resolver argumentos de chamada a ${entidadeChamadaResolvidaVariavel.simbolo.lexema}: \n${erros.reduce((mensagem, erro) => mensagem += `${erro}\n`, '')}`);
|
|
358
|
+
}
|
|
359
|
+
return entidadeChamadaResolvidaVariavel;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (tipoPrimitiva !== undefined && this.primitivasConhecidas.hasOwnProperty(entidadeChamadaResolvidaVariavel.simbolo.lexema)) {
|
|
363
|
+
var informacoesPrimitiva = this.primitivasConhecidas[entidadeChamadaResolvidaVariavel.simbolo.lexema];
|
|
364
|
+
const erros = this.validarArgumentosEntidadeChamada(informacoesPrimitiva.argumentos, argumentos);
|
|
365
|
+
if (erros.length > 0) {
|
|
366
|
+
throw new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(entidadeChamadaResolvidaVariavel.simbolo, `Erros ao resolver argumentos de chamada a ${entidadeChamadaResolvidaVariavel.simbolo.lexema}: \n${erros.reduce((mensagem, erro) => mensagem += `${erro}\n`, '')}`);
|
|
367
|
+
}
|
|
368
|
+
return entidadeChamadaResolvidaVariavel;
|
|
369
|
+
}
|
|
370
|
+
if (entidadeChamadaResolvidaVariavel.simbolo.lexema in this.tiposDefinidosEmCodigo) {
|
|
371
|
+
return entidadeChamadaResolvidaVariavel;
|
|
372
|
+
}
|
|
373
|
+
const possivelReferencia = this.pilhaEscopos.obterReferenciaFuncao(entidadeChamadaResolvidaVariavel.simbolo.lexema);
|
|
374
|
+
if (possivelReferencia !== null) {
|
|
375
|
+
return new construtos_1.ReferenciaFuncao(entidadeChamada.hashArquivo, entidadeChamada.linha, entidadeChamadaResolvidaVariavel.simbolo, entidadeChamadaResolvidaVariavel.tipo, possivelReferencia.id);
|
|
376
|
+
}
|
|
377
|
+
return new construtos_1.ArgumentoReferenciaFuncao(entidadeChamada.hashArquivo, entidadeChamada.linha, entidadeChamadaResolvidaVariavel.simbolo);
|
|
378
|
+
}
|
|
379
|
+
if (entidadeChamada.constructor.name === 'AcessoMetodoOuPropriedade') {
|
|
380
|
+
return this.resolverEntidadeChamadaAcessoMetodoOuPropriedade(entidadeChamada);
|
|
381
|
+
}
|
|
382
|
+
return entidadeChamada;
|
|
383
|
+
}
|
|
384
|
+
declaracaoDeFuncao(identificador) {
|
|
385
|
+
// Se houver chamadas recursivas à função, precisamos definir um tipo
|
|
386
|
+
// para ela. Vai ser atualizado após avaliação do corpo da função.
|
|
387
|
+
this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(identificador.lexema, 'qualquer'));
|
|
388
|
+
const corpoDaFuncao = this.corpoDaFuncao('implícita');
|
|
389
|
+
this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(identificador.lexema, corpoDaFuncao.tipo));
|
|
390
|
+
const funcaoDeclaracao = new declaracoes_1.FuncaoDeclaracao(identificador, corpoDaFuncao, corpoDaFuncao.tipo);
|
|
391
|
+
this.pilhaEscopos.registrarReferenciaFuncao(identificador.lexema, funcaoDeclaracao);
|
|
392
|
+
return funcaoDeclaracao;
|
|
393
|
+
}
|
|
394
|
+
finalizarChamada(entidadeChamada, tipoPrimitiva = undefined) {
|
|
395
|
+
const argumentos = [];
|
|
396
|
+
if (!this.verificarTipoSimboloAtual(tenda_1.default.PARENTESE_DIREITO)) {
|
|
397
|
+
do {
|
|
398
|
+
// `apply()` em JavaScript aceita até 255 parâmetros.
|
|
399
|
+
if (argumentos.length >= 255) {
|
|
400
|
+
throw this.erro(this.simbolos[this.atual], 'Não pode haver mais de 255 argumentos.');
|
|
401
|
+
}
|
|
402
|
+
argumentos.push(this.expressao());
|
|
403
|
+
} while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.VIRGULA));
|
|
404
|
+
}
|
|
405
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos.");
|
|
406
|
+
// Toda chamada precisa saber de antemão qual o tipo resolvido.
|
|
407
|
+
const entidadeChamadaResolvida = this.resolverEntidadeChamada(entidadeChamada, argumentos, tipoPrimitiva);
|
|
408
|
+
// TODO: Criar forma de validar tipos dos argumentos da entidade chamada.
|
|
409
|
+
const construtoChamada = new construtos_1.Chamada(this.hashArquivo, entidadeChamadaResolvida, argumentos);
|
|
410
|
+
construtoChamada.tipo = 'qualquer';
|
|
411
|
+
return construtoChamada;
|
|
412
|
+
}
|
|
413
|
+
unario() {
|
|
414
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.NÃO, tenda_1.default.SUBTRACAO, tenda_1.default.BIT_NOT, tenda_1.default.INCREMENTAR, tenda_1.default.DECREMENTAR)) {
|
|
415
|
+
const operador = this.simbolos[this.atual - 1];
|
|
416
|
+
const direito = this.unario();
|
|
417
|
+
return new construtos_1.Unario(this.hashArquivo, operador, direito, 'ANTES');
|
|
418
|
+
}
|
|
419
|
+
return this.chamar();
|
|
420
|
+
}
|
|
421
|
+
multiplicar() {
|
|
422
|
+
let expressao = this.exponenciacao();
|
|
423
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.DIVISAO, tenda_1.default.DIVISAO_IGUAL, tenda_1.default.DIVISAO_INTEIRA, tenda_1.default.DIVISAO_INTEIRA_IGUAL, tenda_1.default.MODULO, tenda_1.default.MODULO_IGUAL, tenda_1.default.MULTIPLICACAO, tenda_1.default.MULTIPLICACAO_IGUAL)) {
|
|
424
|
+
const operador = this.simbolos[this.atual - 1];
|
|
425
|
+
const direito = this.exponenciacao();
|
|
426
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
427
|
+
}
|
|
428
|
+
return expressao;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Se símbolo de operação é `+`, `-`, `+=` ou `-=`, monta objeto `Binario` para
|
|
432
|
+
* ser avaliado pelo Interpretador.
|
|
433
|
+
* @returns Um Construto, normalmente um `Binario`, ou `Unario` se houver alguma operação unária para ser avaliada.
|
|
434
|
+
*/
|
|
435
|
+
adicaoOuSubtracao() {
|
|
436
|
+
let expressao = this.multiplicar();
|
|
437
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.SUBTRACAO, tenda_1.default.ADICAO, tenda_1.default.MENOS_IGUAL)) {
|
|
438
|
+
const operador = this.simbolos[this.atual - 1];
|
|
439
|
+
const direito = this.multiplicar();
|
|
440
|
+
// const tipoInferido = inferirTipoParaBinario(expressao, operador, direito);
|
|
441
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
442
|
+
}
|
|
443
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.MAIS_IGUAL)) {
|
|
444
|
+
const operador = this.simbolos[this.atual - 1];
|
|
445
|
+
const direito = this.atribuir();
|
|
446
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
447
|
+
}
|
|
448
|
+
return expressao;
|
|
449
|
+
}
|
|
450
|
+
bitShift() {
|
|
451
|
+
let expressao = this.adicaoOuSubtracao();
|
|
452
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.MENOR_MENOR, tenda_1.default.MAIOR_MAIOR)) {
|
|
453
|
+
const operador = this.simbolos[this.atual - 1];
|
|
454
|
+
const direito = this.adicaoOuSubtracao();
|
|
455
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
456
|
+
}
|
|
457
|
+
return expressao;
|
|
458
|
+
}
|
|
459
|
+
bitE() {
|
|
460
|
+
let expressao = this.bitShift();
|
|
461
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.BIT_AND)) {
|
|
462
|
+
const operador = this.simbolos[this.atual - 1];
|
|
463
|
+
const direito = this.bitShift();
|
|
464
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
465
|
+
}
|
|
466
|
+
return expressao;
|
|
467
|
+
}
|
|
468
|
+
bitOu() {
|
|
469
|
+
let expressao = this.bitE();
|
|
470
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.BIT_OR, tenda_1.default.BIT_XOR)) {
|
|
471
|
+
const operador = this.simbolos[this.atual - 1];
|
|
472
|
+
const direito = this.bitE();
|
|
473
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
474
|
+
}
|
|
475
|
+
return expressao;
|
|
476
|
+
}
|
|
477
|
+
comparar() {
|
|
478
|
+
let expressao = this.bitOu();
|
|
479
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.MAIOR, tenda_1.default.MAIOR_IGUAL, tenda_1.default.MENOR, tenda_1.default.MENOR_IGUAL)) {
|
|
480
|
+
const operador = this.simbolos[this.atual - 1];
|
|
481
|
+
const direito = this.bitOu();
|
|
482
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
483
|
+
}
|
|
484
|
+
return expressao;
|
|
485
|
+
}
|
|
486
|
+
comparacaoIgualdade() {
|
|
487
|
+
let expressao = this.comparar();
|
|
488
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.NÃO, tenda_1.default.É)) {
|
|
489
|
+
const operador = this.simbolos[this.atual - 1];
|
|
490
|
+
if (operador.tipo === tenda_1.default.NÃO) {
|
|
491
|
+
this.consumir(tenda_1.default.É, `Esperado 'é' após 'não'.`);
|
|
492
|
+
operador.tipo = tenda_1.default.DIFERENTE;
|
|
493
|
+
operador.lexema = "não é";
|
|
494
|
+
operador.literal = "não é";
|
|
495
|
+
}
|
|
496
|
+
const direito = this.comparar();
|
|
497
|
+
expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
|
|
498
|
+
}
|
|
499
|
+
return expressao;
|
|
500
|
+
}
|
|
501
|
+
em() {
|
|
502
|
+
let expressao = this.comparacaoIgualdade();
|
|
503
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.TEM)) {
|
|
504
|
+
const operador = this.simbolos[this.atual - 1];
|
|
505
|
+
const direito = this.comparacaoIgualdade();
|
|
506
|
+
expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
|
|
507
|
+
}
|
|
508
|
+
return expressao;
|
|
509
|
+
}
|
|
510
|
+
e() {
|
|
511
|
+
let expressao = this.em();
|
|
512
|
+
while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.E)) {
|
|
513
|
+
const operador = this.simbolos[this.atual - 1];
|
|
514
|
+
const direito = this.em();
|
|
515
|
+
expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
|
|
516
|
+
}
|
|
517
|
+
return expressao;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Método que resolve atribuições.
|
|
521
|
+
* @returns Um construto do tipo `Atribuir`, `Conjunto` ou `AtribuicaoPorIndice`.
|
|
522
|
+
*/
|
|
523
|
+
atribuir() {
|
|
524
|
+
const expressao = this.ou();
|
|
525
|
+
if (expressao instanceof construtos_1.Binario &&
|
|
526
|
+
[
|
|
527
|
+
tenda_1.default.MAIS_IGUAL,
|
|
528
|
+
tenda_1.default.MENOS_IGUAL,
|
|
529
|
+
tenda_1.default.MULTIPLICACAO_IGUAL,
|
|
530
|
+
tenda_1.default.DIVISAO_IGUAL,
|
|
531
|
+
tenda_1.default.DIVISAO_INTEIRA_IGUAL,
|
|
532
|
+
tenda_1.default.MODULO_IGUAL,
|
|
533
|
+
].includes(expressao.operador.tipo)) {
|
|
534
|
+
if (expressao.esquerda instanceof construtos_1.AcessoIndiceVariavel) {
|
|
535
|
+
const entidade = expressao.esquerda;
|
|
536
|
+
return new construtos_1.Atribuir(this.hashArquivo, entidade.entidadeChamada, expressao, entidade.indice, expressao.operador);
|
|
537
|
+
}
|
|
538
|
+
return new construtos_1.Atribuir(this.hashArquivo, expressao.esquerda, expressao, undefined, expressao.operador);
|
|
539
|
+
}
|
|
540
|
+
else if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.IGUAL)) {
|
|
541
|
+
const igual = this.simbolos[this.atual - 1];
|
|
542
|
+
const valor = this.expressao();
|
|
543
|
+
switch (expressao.constructor.name) {
|
|
544
|
+
case 'Variavel':
|
|
545
|
+
return new construtos_1.Atribuir(this.hashArquivo, expressao, valor);
|
|
546
|
+
case 'AcessoMetodoOuPropriedade':
|
|
547
|
+
const expressaoAcessoMetodoOuPropriedade = expressao;
|
|
548
|
+
return new construtos_1.DefinirValor(this.hashArquivo, igual.linha, expressaoAcessoMetodoOuPropriedade.objeto, expressaoAcessoMetodoOuPropriedade.simbolo, valor);
|
|
549
|
+
case 'AcessoIndiceVariavel':
|
|
550
|
+
const expressaoAcessoIndiceVariavel = expressao;
|
|
551
|
+
return new construtos_1.AtribuicaoPorIndice(this.hashArquivo, expressaoAcessoIndiceVariavel.linha, expressaoAcessoIndiceVariavel.entidadeChamada, expressaoAcessoIndiceVariavel.indice, valor);
|
|
552
|
+
}
|
|
553
|
+
throw this.erro(igual, 'Tarefa de atribuição inválida');
|
|
554
|
+
}
|
|
555
|
+
return expressao;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Declaração para comando `leia`, para ler dados de entrada do usuário.
|
|
559
|
+
* @returns Um objeto da classe `Leia`.
|
|
560
|
+
*/
|
|
561
|
+
expressaoLeia() {
|
|
562
|
+
const simboloLeia = this.avancarEDevolverAnterior();
|
|
563
|
+
this.consumir(tenda_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos argumentos em instrução `leia`.");
|
|
564
|
+
const argumentos = [];
|
|
565
|
+
if (this.simbolos[this.atual].tipo !== tenda_1.default.PARENTESE_DIREITO) {
|
|
566
|
+
do {
|
|
567
|
+
argumentos.push(this.expressao());
|
|
568
|
+
} while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.VIRGULA));
|
|
569
|
+
}
|
|
570
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos em instrução `leia`.");
|
|
571
|
+
return new construtos_1.Leia(simboloLeia, argumentos);
|
|
572
|
+
}
|
|
573
|
+
// TODO: Depreciar.
|
|
574
|
+
expressao() {
|
|
575
|
+
return this.atribuir();
|
|
576
|
+
}
|
|
577
|
+
blocoEscopo(tipo) {
|
|
578
|
+
this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
|
|
579
|
+
let declaracoes = [];
|
|
580
|
+
while (!this.verificarTipoSimboloAtual(tenda_1.default.FIM) && !this.estaNoFinal()) {
|
|
581
|
+
const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
|
|
582
|
+
if (Array.isArray(retornoDeclaracao)) {
|
|
583
|
+
declaracoes = declaracoes.concat(retornoDeclaracao);
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
declaracoes.push(retornoDeclaracao);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
this.consumir(tenda_1.default.FIM, `Esperado 'fim' para concluir bloco de escopo ${tipo ? "de " + tipo : ''}.`);
|
|
590
|
+
this.pilhaEscopos.removerUltimo();
|
|
591
|
+
return declaracoes;
|
|
592
|
+
}
|
|
593
|
+
declaracaoComentarioUmaLinha() {
|
|
594
|
+
const simboloComentario = this.avancarEDevolverAnterior();
|
|
595
|
+
return new declaracoes_1.Comentario(simboloComentario.hashArquivo, simboloComentario.linha, simboloComentario.literal, false);
|
|
596
|
+
}
|
|
597
|
+
declaracaoContinua() {
|
|
598
|
+
if (this.blocos < 1) {
|
|
599
|
+
throw this.erro(this.simbolos[this.atual - 1], "'continua' precisa estar em um laço de repetição.");
|
|
600
|
+
}
|
|
601
|
+
// Ponto-e-vírgula é opcional aqui.
|
|
602
|
+
this.verificarSeSimboloAtualEIgualA(tenda_1.default.PONTO_E_VIRGULA);
|
|
603
|
+
return new declaracoes_1.Continua(this.simbolos[this.atual - 1]);
|
|
604
|
+
}
|
|
605
|
+
declaracaoEnquanto() {
|
|
606
|
+
try {
|
|
607
|
+
const simboloEnquanto = this.simbolos[this.atual - 1];
|
|
608
|
+
this.blocos += 1;
|
|
609
|
+
const condicao = this.expressao();
|
|
610
|
+
this.consumir(tenda_1.default.FAÇA, "Esperado 'faça' depois da condição.");
|
|
611
|
+
const blocoCorpo = this.blocoEscopo('enquanto');
|
|
612
|
+
return new declaracoes_1.Enquanto(condicao, new declaracoes_1.Bloco(simboloEnquanto.linha, simboloEnquanto.hashArquivo, blocoCorpo));
|
|
613
|
+
}
|
|
614
|
+
finally {
|
|
615
|
+
this.blocos -= 1;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
declaracaoEscreva() {
|
|
619
|
+
const simboloAtual = this.simbolos[this.atual];
|
|
620
|
+
this.consumir(tenda_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em escreva.");
|
|
621
|
+
const argumentos = [];
|
|
622
|
+
if (!this.verificarTipoSimboloAtual(tenda_1.default.PARENTESE_DIREITO)) {
|
|
623
|
+
do {
|
|
624
|
+
argumentos.push(this.expressao());
|
|
625
|
+
} while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.VIRGULA));
|
|
626
|
+
}
|
|
627
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em escreva.");
|
|
628
|
+
// Ponto-e-vírgula é opcional aqui.
|
|
629
|
+
// this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
|
|
630
|
+
return new declaracoes_1.Escreva(Number(simboloAtual.linha), simboloAtual.hashArquivo, argumentos);
|
|
631
|
+
}
|
|
632
|
+
declaracaoExpressao() {
|
|
633
|
+
const expressao = this.expressao();
|
|
634
|
+
// Ponto-e-vírgula é opcional aqui.
|
|
635
|
+
this.verificarSeSimboloAtualEIgualA(tenda_1.default.PONTO_E_VIRGULA);
|
|
636
|
+
return new declaracoes_1.Expressao(expressao);
|
|
637
|
+
}
|
|
638
|
+
declaracaoPara() {
|
|
639
|
+
const simboloPara = this.simbolos[this.atual - 1];
|
|
640
|
+
this.consumir(tenda_1.default.CADA, `Esperado palavra reservada 'cada' após 'para'.`);
|
|
641
|
+
this.blocos += 1;
|
|
642
|
+
const nomeVariavelIteracao = this.consumir(tenda_1.default.IDENTIFICADOR, "Esperado identificador de variável de iteração para instrução 'para cada'.");
|
|
643
|
+
this.consumir(tenda_1.default.EM, "Esperado palavra reservada 'em' após variável de iteração em instrução 'para cada'.");
|
|
644
|
+
// Se for um literal ou identificador numérico, segue um `para`
|
|
645
|
+
// tradicional de Delégua, com variável de controle e passo positivo, incrementado em 1.
|
|
646
|
+
const literalOuVariavelInicio = this.adicaoOuSubtracao();
|
|
647
|
+
this.blocos -= 1;
|
|
648
|
+
switch (literalOuVariavelInicio.constructor.name) {
|
|
649
|
+
case 'Literal':
|
|
650
|
+
return this.declaracaoParaTradicional(simboloPara, nomeVariavelIteracao, literalOuVariavelInicio);
|
|
651
|
+
// TODO: Terminar
|
|
652
|
+
case 'Variavel':
|
|
653
|
+
case 'Vetor':
|
|
654
|
+
default:
|
|
655
|
+
return this.declaracaoParaCada(simboloPara, nomeVariavelIteracao, literalOuVariavelInicio);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
declaracaoParaCada(simboloParaCada, simboloVariavelIteracao, literalOuVariavelIteravel) {
|
|
659
|
+
const tipoVetor = literalOuVariavelIteravel.tipo;
|
|
660
|
+
// TODO: Permitir 'qualquer' aqui é bastante frágil. Criar uma forma de validar o tipo
|
|
661
|
+
// antes dessa avaliação.
|
|
662
|
+
if (!tipoVetor.endsWith('[]') && !['qualquer', 'vetor'].includes(tipoVetor)) {
|
|
663
|
+
throw this.erro(simboloParaCada, `Variável ou constante em 'para cada' não é iterável. Tipo resolvido: ${tipoVetor}.`);
|
|
664
|
+
}
|
|
665
|
+
let tipoVariavelIteracao = 'qualquer';
|
|
666
|
+
if (tipoVetor.endsWith('[]')) {
|
|
667
|
+
tipoVariavelIteracao = tipoVetor.slice(0, -2);
|
|
668
|
+
}
|
|
669
|
+
this.pilhaEscopos.definirInformacoesVariavel(simboloVariavelIteracao.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simboloVariavelIteracao.lexema, tipoVariavelIteracao));
|
|
670
|
+
this.consumir(tenda_1.default.FAÇA, "Esperado palavra reservada 'faça' após literal ou variável de iteração em declaração 'para cada'.");
|
|
671
|
+
const corpo = this.blocoEscopo();
|
|
672
|
+
return new declaracoes_1.ParaCada(this.hashArquivo, Number(simboloParaCada.linha), simboloVariavelIteracao.lexema, literalOuVariavelIteravel, new declaracoes_1.Bloco(simboloParaCada.hashArquivo, simboloParaCada.linha, corpo));
|
|
673
|
+
}
|
|
674
|
+
declaracaoParaTradicional(simboloPara, simboloVariavelIteracao, literalOuVariavelInicio) {
|
|
675
|
+
this.consumir(tenda_1.default.ATÉ, "Esperado palavra reservada 'até' após literal ou identificador de início de declaração 'para cada'.");
|
|
676
|
+
const literalOuVariavelFim = this.adicaoOuSubtracao();
|
|
677
|
+
this.consumir(tenda_1.default.FAÇA, "Esperado palavra reservada 'faça' após literal ou variável de passo final em declaração 'para cada'.");
|
|
678
|
+
// A variável de iteração precisa ser definida aqui, para que o corpo de `para cada` (um escopo)
|
|
679
|
+
// seja capaz de reconhecer a variável e seu tipo.
|
|
680
|
+
this.pilhaEscopos.definirInformacoesVariavel(simboloVariavelIteracao.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simboloVariavelIteracao.lexema, 'inteiro'));
|
|
681
|
+
const corpo = this.blocoEscopo();
|
|
682
|
+
// `variavelIteracao <= valorFinal`
|
|
683
|
+
let operadorCondicao = new simbolo_1.Simbolo(tenda_1.default.MENOR_IGUAL, '<=', null, Number(simboloPara.linha), this.hashArquivo);
|
|
684
|
+
let operadorCondicaoIncremento = new simbolo_1.Simbolo(tenda_1.default.MENOR, '<', null, Number(simboloPara.linha), this.hashArquivo);
|
|
685
|
+
return new declaracoes_1.Para(this.hashArquivo, Number(simboloPara.linha),
|
|
686
|
+
// Inicialização.
|
|
687
|
+
new declaracoes_1.Expressao(new construtos_1.Atribuir(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'), literalOuVariavelInicio)),
|
|
688
|
+
// Condição.
|
|
689
|
+
new construtos_1.Binario(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'), operadorCondicao, literalOuVariavelFim),
|
|
690
|
+
// Incremento, feito em construto especial `FimPara`.
|
|
691
|
+
new construtos_1.FimPara(this.hashArquivo, Number(simboloPara.linha), new construtos_1.Binario(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'), operadorCondicaoIncremento, literalOuVariavelFim), new declaracoes_1.Expressao(new construtos_1.Atribuir(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'), new construtos_1.Binario(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, simboloVariavelIteracao, 'inteiro'), new simbolo_1.Simbolo(tenda_1.default.ADICAO, '+', null, Number(simboloPara.linha), this.hashArquivo), new construtos_1.Literal(this.hashArquivo, Number(simboloPara.linha), 1))))), new declaracoes_1.Bloco(simboloPara.hashArquivo, simboloPara.linha, corpo));
|
|
692
|
+
}
|
|
693
|
+
declaracaoRetorna() {
|
|
694
|
+
const simboloChave = this.simbolos[this.atual - 1];
|
|
695
|
+
let valor = null;
|
|
696
|
+
if ([
|
|
697
|
+
tenda_1.default.CHAVE_ESQUERDA,
|
|
698
|
+
tenda_1.default.COLCHETE_ESQUERDO,
|
|
699
|
+
tenda_1.default.FALSO,
|
|
700
|
+
tenda_1.default.FUNCAO,
|
|
701
|
+
tenda_1.default.FUNÇÃO,
|
|
702
|
+
tenda_1.default.IDENTIFICADOR,
|
|
703
|
+
tenda_1.default.ISTO,
|
|
704
|
+
tenda_1.default.NÃO,
|
|
705
|
+
tenda_1.default.NUMERO,
|
|
706
|
+
tenda_1.default.NADA,
|
|
707
|
+
tenda_1.default.PARENTESE_ESQUERDO,
|
|
708
|
+
tenda_1.default.SUPER,
|
|
709
|
+
tenda_1.default.TEXTO,
|
|
710
|
+
tenda_1.default.VERDADEIRO,
|
|
711
|
+
].includes(this.simbolos[this.atual].tipo)) {
|
|
712
|
+
valor = this.expressao();
|
|
713
|
+
}
|
|
714
|
+
// Ponto-e-vírgula é opcional aqui.
|
|
715
|
+
this.verificarSeSimboloAtualEIgualA(tenda_1.default.PONTO_E_VIRGULA);
|
|
716
|
+
return new declaracoes_1.Retorna(simboloChave, valor);
|
|
717
|
+
}
|
|
718
|
+
declaracaoSe() {
|
|
719
|
+
const condicao = this.expressao();
|
|
720
|
+
this.consumir(tenda_1.default.ENTÃO, "Esperado 'então' após a condição.");
|
|
721
|
+
const caminhoEntao = this.resolverDeclaracao();
|
|
722
|
+
let caminhoSenao = null;
|
|
723
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.SENÃO)) {
|
|
724
|
+
caminhoSenao = this.resolverDeclaracao();
|
|
725
|
+
}
|
|
726
|
+
return new declaracoes_1.Se(condicao, caminhoEntao, [], caminhoSenao);
|
|
727
|
+
}
|
|
728
|
+
declaracaoSustar() {
|
|
729
|
+
if (this.blocos < 1) {
|
|
730
|
+
throw this.erro(this.simbolos[this.atual - 1], "'sustar' ou 'pausa' deve estar dentro de um laço de repetição.");
|
|
731
|
+
}
|
|
732
|
+
// Ponto-e-vírgula é opcional aqui.
|
|
733
|
+
this.verificarSeSimboloAtualEIgualA(tenda_1.default.PONTO_E_VIRGULA);
|
|
734
|
+
return new declaracoes_1.Sustar(this.simbolos[this.atual - 1]);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Todas as resoluções triviais da linguagem, ou seja, todas as
|
|
738
|
+
* resoluções que podem ocorrer dentro ou fora de um bloco.
|
|
739
|
+
* @returns Normalmente uma `Declaracao`, mas há casos em que
|
|
740
|
+
* outros objetos podem ser retornados.
|
|
741
|
+
* @see resolverDeclaracaoForaDeBloco para as declarações que não podem
|
|
742
|
+
* ocorrer em blocos de escopo elementares.
|
|
743
|
+
*/
|
|
744
|
+
resolverDeclaracao() {
|
|
745
|
+
switch (this.simbolos[this.atual].tipo) {
|
|
746
|
+
case tenda_1.default.COMENTARIO:
|
|
747
|
+
return this.declaracaoComentarioUmaLinha();
|
|
748
|
+
case tenda_1.default.CONTINUA:
|
|
749
|
+
this.avancarEDevolverAnterior();
|
|
750
|
+
return this.declaracaoContinua();
|
|
751
|
+
case tenda_1.default.ENQUANTO:
|
|
752
|
+
this.avancarEDevolverAnterior();
|
|
753
|
+
return this.declaracaoEnquanto();
|
|
754
|
+
case tenda_1.default.EXIBA:
|
|
755
|
+
this.avancarEDevolverAnterior();
|
|
756
|
+
return this.declaracaoEscreva();
|
|
757
|
+
case tenda_1.default.FAÇA:
|
|
758
|
+
this.avancarEDevolverAnterior();
|
|
759
|
+
return this.blocoEscopo();
|
|
760
|
+
case tenda_1.default.PARA:
|
|
761
|
+
this.avancarEDevolverAnterior();
|
|
762
|
+
return this.declaracaoPara();
|
|
763
|
+
case tenda_1.default.PAUSA:
|
|
764
|
+
case tenda_1.default.SUSTAR:
|
|
765
|
+
this.avancarEDevolverAnterior();
|
|
766
|
+
return this.declaracaoSustar();
|
|
767
|
+
case tenda_1.default.SE:
|
|
768
|
+
this.avancarEDevolverAnterior();
|
|
769
|
+
return this.declaracaoSe();
|
|
770
|
+
case tenda_1.default.RETORNA:
|
|
771
|
+
this.avancarEDevolverAnterior();
|
|
772
|
+
return this.declaracaoRetorna();
|
|
773
|
+
case tenda_1.default.TENTE:
|
|
774
|
+
this.avancarEDevolverAnterior();
|
|
775
|
+
return this.declaracaoTente();
|
|
776
|
+
case tenda_1.default.SEJA:
|
|
777
|
+
this.avancarEDevolverAnterior();
|
|
778
|
+
return this.declaracaoDeVariaveisOuFuncoes();
|
|
779
|
+
}
|
|
780
|
+
const simboloAtual = this.simbolos[this.atual];
|
|
781
|
+
if (simboloAtual.tipo === tenda_1.default.IDENTIFICADOR) {
|
|
782
|
+
// Pela gramática, a seguinte situação não pode ocorrer:
|
|
783
|
+
// 1. O símbolo anterior ser um identificador; e
|
|
784
|
+
// 2. O símbolo anterior estar na mesma linha do identificador atual.
|
|
785
|
+
const simboloAnterior = this.simbolos[this.atual - 1];
|
|
786
|
+
if (!!simboloAnterior &&
|
|
787
|
+
simboloAnterior.tipo === tenda_1.default.IDENTIFICADOR &&
|
|
788
|
+
simboloAnterior.linha === simboloAtual.linha) {
|
|
789
|
+
throw this.erro(this.simbolos[this.atual], 'Não é permitido ter dois identificadores seguidos na mesma linha.');
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return this.declaracaoExpressao();
|
|
793
|
+
}
|
|
794
|
+
logicaComumInferenciaTiposVariaveis(inicializador) {
|
|
795
|
+
switch (inicializador.constructor.name) {
|
|
796
|
+
case 'AcessoIndiceVariavel':
|
|
797
|
+
const entidadeChamadaAcessoIndiceVariavel = inicializador.entidadeChamada;
|
|
798
|
+
return entidadeChamadaAcessoIndiceVariavel.tipo.slice(0, -2);
|
|
799
|
+
case 'Chamada':
|
|
800
|
+
const entidadeChamadaChamada = inicializador.entidadeChamada;
|
|
801
|
+
switch (entidadeChamadaChamada.constructor.name) {
|
|
802
|
+
case 'AcessoMetodo':
|
|
803
|
+
const entidadeChamadaAcessoMetodo = entidadeChamadaChamada;
|
|
804
|
+
return entidadeChamadaAcessoMetodo.tipoRetornoMetodo;
|
|
805
|
+
case 'AcessoMetodoOuPropriedade':
|
|
806
|
+
// Este caso ocorre quando a variável/constante é do tipo 'qualquer',
|
|
807
|
+
// e a chamada normalmente é feita para uma primitiva.
|
|
808
|
+
// A inferência, portanto, ocorre pelo uso da primitiva.
|
|
809
|
+
const entidadeChamadaAcessoMetodoOuPropriedade = entidadeChamadaChamada;
|
|
810
|
+
if (this.primitivasConhecidas.hasOwnProperty(entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema)) {
|
|
811
|
+
return this.primitivasConhecidas[entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema].tipo;
|
|
812
|
+
}
|
|
813
|
+
throw new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(entidadeChamadaAcessoMetodoOuPropriedade.simbolo, `Primitiva '${entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema}' não existe.`);
|
|
814
|
+
case 'AcessoPropriedade':
|
|
815
|
+
const entidadeChamadaAcessoPropriedade = entidadeChamadaChamada;
|
|
816
|
+
return entidadeChamadaAcessoPropriedade.tipoRetornoPropriedade;
|
|
817
|
+
case 'ArgumentoReferenciaFuncao':
|
|
818
|
+
// TODO: Voltar aqui se necessário.
|
|
819
|
+
return 'qualquer';
|
|
820
|
+
case 'ReferenciaFuncao':
|
|
821
|
+
const entidadeChamadaReferenciaFuncao = entidadeChamadaChamada;
|
|
822
|
+
return entidadeChamadaReferenciaFuncao.tipo;
|
|
823
|
+
case 'Variavel':
|
|
824
|
+
const entidadeChamadaVariavel = entidadeChamadaChamada;
|
|
825
|
+
return entidadeChamadaVariavel.tipo;
|
|
826
|
+
}
|
|
827
|
+
break;
|
|
828
|
+
case 'FuncaoConstruto':
|
|
829
|
+
const funcaoConstruto = inicializador;
|
|
830
|
+
return `função<${funcaoConstruto.tipo}>`;
|
|
831
|
+
case 'Leia':
|
|
832
|
+
return 'texto';
|
|
833
|
+
case 'Dupla':
|
|
834
|
+
case 'Trio':
|
|
835
|
+
case 'Quarteto':
|
|
836
|
+
case 'Quinteto':
|
|
837
|
+
case 'Sexteto':
|
|
838
|
+
case 'Septeto':
|
|
839
|
+
case 'Octeto':
|
|
840
|
+
case 'Noneto':
|
|
841
|
+
case 'Deceto':
|
|
842
|
+
return delegua_1.default.TUPLA;
|
|
843
|
+
case "ImportarBiblioteca":
|
|
844
|
+
case "ModuloDeclaracoes":
|
|
845
|
+
return "módulo";
|
|
846
|
+
default:
|
|
847
|
+
return inicializador.tipo;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Após palavra reservada `seja`, é esperado ou uma variável, ou uma função.
|
|
852
|
+
* @returns Um Construto, ou do tipo `Var` para variável, ou do tipo `FuncaoDeclaracao` se for
|
|
853
|
+
* declaração de função.
|
|
854
|
+
*/
|
|
855
|
+
declaracaoDeVariaveisOuFuncoes() {
|
|
856
|
+
const identificador = this.consumir(tenda_1.default.IDENTIFICADOR, 'Esperado nome da variável ou função.');
|
|
857
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.PARENTESE_ESQUERDO)) {
|
|
858
|
+
return this.declaracaoDeFuncao(identificador);
|
|
859
|
+
}
|
|
860
|
+
this.consumir(tenda_1.default.IGUAL, "Esperado símbolo de igual após nome de identificador em declaração 'seja'.");
|
|
861
|
+
const inicializador = this.expressao();
|
|
862
|
+
const tipo = this.logicaComumInferenciaTiposVariaveis(inicializador);
|
|
863
|
+
this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(identificador.lexema, tipo));
|
|
864
|
+
return new declaracoes_1.Var(identificador, inicializador, tipo);
|
|
865
|
+
}
|
|
866
|
+
logicaComumParametros() {
|
|
867
|
+
const parametros = [];
|
|
868
|
+
do {
|
|
869
|
+
const parametro = {};
|
|
870
|
+
parametro.nome = this.consumir(tenda_1.default.IDENTIFICADOR, 'Esperado nome do parâmetro.');
|
|
871
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.IGUAL)) {
|
|
872
|
+
const valorPadrao = this.primario();
|
|
873
|
+
parametro.valorPadrao = valorPadrao;
|
|
874
|
+
}
|
|
875
|
+
if (this.verificarSeSimboloAtualEIgualA(tenda_1.default.DOIS_PONTOS)) {
|
|
876
|
+
let tipoDadoParametro = this.verificarDefinicaoTipoAtual();
|
|
877
|
+
parametro.tipoDado = tipoDadoParametro;
|
|
878
|
+
this.avancarEDevolverAnterior();
|
|
879
|
+
}
|
|
880
|
+
this.pilhaEscopos.definirInformacoesVariavel(parametro.nome.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(parametro.nome.lexema, parametro.tipoDado || 'qualquer'));
|
|
881
|
+
parametros.push(parametro);
|
|
882
|
+
if (parametro.abrangencia === 'multiplo')
|
|
883
|
+
break;
|
|
884
|
+
} while (this.verificarSeSimboloAtualEIgualA(tenda_1.default.VIRGULA));
|
|
885
|
+
return parametros;
|
|
886
|
+
}
|
|
887
|
+
corpoDaFuncao(tipo) {
|
|
888
|
+
// O parêntese esquerdo aqui é o símbolo atual.
|
|
889
|
+
// Ele já foi lido neste ponto.
|
|
890
|
+
const parenteseEsquerdo = this.simbolos[this.atual];
|
|
891
|
+
let parametros = [];
|
|
892
|
+
if (!this.verificarTipoSimboloAtual(tenda_1.default.PARENTESE_DIREITO)) {
|
|
893
|
+
parametros = this.logicaComumParametros();
|
|
894
|
+
}
|
|
895
|
+
this.consumir(tenda_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros.");
|
|
896
|
+
switch (tipo) {
|
|
897
|
+
case 'função':
|
|
898
|
+
this.consumir(tenda_1.default.SUBTRACAO, "Esperado seta após fechamento de parênteses para declaração de função.");
|
|
899
|
+
this.consumir(tenda_1.default.MAIOR, "Esperado seta após fechamento de parênteses para declaração de função.");
|
|
900
|
+
break;
|
|
901
|
+
case 'implícita':
|
|
902
|
+
this.consumir(tenda_1.default.IGUAL, "Esperado sinal de igual após fechamento de parênteses para declaração de função.");
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
const corpo = this.resolverDeclaracao();
|
|
906
|
+
// Se o corpo for uma `Expressao`, corpo é convertido para `Retorna`.
|
|
907
|
+
// Tenda trabalha com retornos implícitos.
|
|
908
|
+
let corpoResolvido = [];
|
|
909
|
+
if (corpo.constructor.name === 'Expressao') {
|
|
910
|
+
const expressaoComoRetorna = new declaracoes_1.Retorna(new simbolo_1.Simbolo(tenda_1.default.RETORNA, 'retorna', 'retorna', parenteseEsquerdo.linha, this.hashArquivo), corpo.expressao);
|
|
911
|
+
corpoResolvido.push(expressaoComoRetorna);
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
// TODO: Verificar se `corpo` é sempre um Array aqui.
|
|
915
|
+
corpoResolvido = corpo;
|
|
916
|
+
}
|
|
917
|
+
// TODO: Inferir o tipo de retorno corretamente.
|
|
918
|
+
return new construtos_1.FuncaoConstruto(this.hashArquivo, Number(parenteseEsquerdo.linha), parametros, corpoResolvido, 'qualquer');
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Até então, Tenda não tem casos de declarações fora de blocos.
|
|
922
|
+
* Isso pode mudar futuramente. Portanto, esta seção será mantida.
|
|
923
|
+
* @returns Uma `Declaracao` ou várias, dependendo do retorno de `resolverDeclaracao`.
|
|
924
|
+
* @see resolverDeclaracao
|
|
925
|
+
*/
|
|
926
|
+
resolverDeclaracaoForaDeBloco() {
|
|
927
|
+
try {
|
|
928
|
+
return this.resolverDeclaracao();
|
|
929
|
+
}
|
|
930
|
+
catch (erro) {
|
|
931
|
+
this.sincronizar();
|
|
932
|
+
this.erros.push(erro);
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Usado quando há erros na avaliação sintática.
|
|
938
|
+
* Garante que o código não entre em loop infinito.
|
|
939
|
+
* @returns Sempre retorna `void`.
|
|
940
|
+
*/
|
|
941
|
+
sincronizar() {
|
|
942
|
+
this.avancarEDevolverAnterior();
|
|
943
|
+
while (!this.estaNoFinal()) {
|
|
944
|
+
const tipoSimboloAtual = this.simbolos[this.atual - 1].tipo;
|
|
945
|
+
switch (tipoSimboloAtual) {
|
|
946
|
+
case tenda_1.default.CLASSE:
|
|
947
|
+
case tenda_1.default.FUNCAO:
|
|
948
|
+
case tenda_1.default.FUNÇÃO:
|
|
949
|
+
case tenda_1.default.VARIAVEL:
|
|
950
|
+
case tenda_1.default.PARA:
|
|
951
|
+
case tenda_1.default.SE:
|
|
952
|
+
case tenda_1.default.ENQUANTO:
|
|
953
|
+
case tenda_1.default.EXIBA:
|
|
954
|
+
case tenda_1.default.RETORNA:
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
this.avancarEDevolverAnterior();
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Inicializa o primeiro nível da pilha de escopos, normalmente com ítens da biblioteca global.
|
|
962
|
+
* TODO: Esta abordagem deve ser depreciada, em favor do novo suporte a referências de funções.
|
|
963
|
+
*/
|
|
964
|
+
inicializarPilhaEscopos() {
|
|
965
|
+
this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos();
|
|
966
|
+
this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
|
|
967
|
+
// Funções nativas de Delégua
|
|
968
|
+
this.pilhaEscopos.definirInformacoesVariavel('aleatorio', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('aleatorio', 'inteiro', [
|
|
969
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número')
|
|
970
|
+
]));
|
|
971
|
+
this.pilhaEscopos.definirInformacoesVariavel('aleatorioEntre', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('aleatorioEntre', 'inteiro', [
|
|
972
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('minimo', 'número'),
|
|
973
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('maximo', 'número')
|
|
974
|
+
]));
|
|
975
|
+
this.pilhaEscopos.definirInformacoesVariavel('algum', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('algum', 'lógico', [
|
|
976
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
977
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
|
|
978
|
+
]));
|
|
979
|
+
this.pilhaEscopos.definirInformacoesVariavel('encontrar', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrar', 'qualquer', [
|
|
980
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
981
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
|
|
982
|
+
]));
|
|
983
|
+
this.pilhaEscopos.definirInformacoesVariavel('encontrarIndice', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarIndice', 'inteiro', [
|
|
984
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
985
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
|
|
986
|
+
]));
|
|
987
|
+
this.pilhaEscopos.definirInformacoesVariavel('encontrarUltimo', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarUltimo', 'inteiro', [
|
|
988
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
989
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
|
|
990
|
+
]));
|
|
991
|
+
this.pilhaEscopos.definirInformacoesVariavel('encontrarUltimoIndice', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarUltimoIndice', 'inteiro', [
|
|
992
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
993
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função')
|
|
994
|
+
]));
|
|
995
|
+
this.pilhaEscopos.definirInformacoesVariavel('filtrarPor', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('filtrarPor', 'qualquer[]', [
|
|
996
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
997
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
|
|
998
|
+
]));
|
|
999
|
+
this.pilhaEscopos.definirInformacoesVariavel('incluido', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('incluido', 'lógico', [
|
|
1000
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1001
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valor', 'qualquer')
|
|
1002
|
+
]));
|
|
1003
|
+
this.pilhaEscopos.definirInformacoesVariavel('inteiro', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('inteiro', 'inteiro', [
|
|
1004
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valor', 'qualquer')
|
|
1005
|
+
]));
|
|
1006
|
+
this.pilhaEscopos.definirInformacoesVariavel('mapear', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('mapear', 'qualquer[]', [
|
|
1007
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1008
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoMapeamento', 'função')
|
|
1009
|
+
]));
|
|
1010
|
+
this.pilhaEscopos.definirInformacoesVariavel('numero', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número', [
|
|
1011
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
|
|
1012
|
+
]));
|
|
1013
|
+
this.pilhaEscopos.definirInformacoesVariavel('número', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número', [
|
|
1014
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
|
|
1015
|
+
]));
|
|
1016
|
+
this.pilhaEscopos.definirInformacoesVariavel('ordenar', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('ordenar', 'qualquer[]', [
|
|
1017
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1018
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoOrdenacao', 'função')
|
|
1019
|
+
]));
|
|
1020
|
+
this.pilhaEscopos.definirInformacoesVariavel('paraCada', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('paraCada', 'qualquer[]', [
|
|
1021
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1022
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
|
|
1023
|
+
]));
|
|
1024
|
+
this.pilhaEscopos.definirInformacoesVariavel('primeiroEmCondicao', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('primeiroEmCondicao', 'qualquer', [
|
|
1025
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1026
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função')
|
|
1027
|
+
]));
|
|
1028
|
+
this.pilhaEscopos.definirInformacoesVariavel('real', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('real', 'número', [
|
|
1029
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
|
|
1030
|
+
]));
|
|
1031
|
+
this.pilhaEscopos.definirInformacoesVariavel('reduzir', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('reduzir', 'qualquer', [
|
|
1032
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1033
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoReducao', 'função'),
|
|
1034
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorInicial', 'qualquer')
|
|
1035
|
+
]));
|
|
1036
|
+
this.pilhaEscopos.definirInformacoesVariavel('tamanho', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('tamanho', 'inteiro', [
|
|
1037
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('objeto', 'qualquer')
|
|
1038
|
+
]));
|
|
1039
|
+
this.pilhaEscopos.definirInformacoesVariavel('texto', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('texto', 'texto', [
|
|
1040
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer')
|
|
1041
|
+
]));
|
|
1042
|
+
this.pilhaEscopos.definirInformacoesVariavel('todosEmCondicao', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('todosEmCondicao', 'lógico', [
|
|
1043
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
|
|
1044
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoCondicional', 'função')
|
|
1045
|
+
]));
|
|
1046
|
+
this.pilhaEscopos.definirInformacoesVariavel('tupla', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('tupla', 'tupla', [
|
|
1047
|
+
new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]')
|
|
1048
|
+
]));
|
|
1049
|
+
// TODO: Escrever algum tipo de validação aqui.
|
|
1050
|
+
for (const tipos of Object.values(this.tiposDeFerramentasExternas)) {
|
|
1051
|
+
for (const [nomeTipo, tipo] of Object.entries(tipos)) {
|
|
1052
|
+
this.pilhaEscopos.definirInformacoesVariavel(nomeTipo, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomeTipo, tipo));
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
analisar(retornoLexador, hashArquivo) {
|
|
1057
|
+
const inicioAnalise = (0, browser_process_hrtime_1.default)();
|
|
1058
|
+
this.erros = [];
|
|
1059
|
+
this.atual = 0;
|
|
1060
|
+
this.blocos = 0;
|
|
1061
|
+
this.hashArquivo = hashArquivo || 0;
|
|
1062
|
+
this.simbolos = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.simbolos) || [];
|
|
1063
|
+
this.tiposDefinidosEmCodigo = {};
|
|
1064
|
+
this.inicializarPilhaEscopos();
|
|
1065
|
+
let declaracoes = [];
|
|
1066
|
+
while (!this.estaNoFinal()) {
|
|
1067
|
+
const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
|
|
1068
|
+
if (Array.isArray(retornoDeclaracao)) {
|
|
1069
|
+
declaracoes = declaracoes.concat(retornoDeclaracao);
|
|
1070
|
+
}
|
|
1071
|
+
else if (retornoDeclaracao !== null) {
|
|
1072
|
+
declaracoes.push(retornoDeclaracao);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (this.performance) {
|
|
1076
|
+
const deltaAnalise = (0, browser_process_hrtime_1.default)(inicioAnalise);
|
|
1077
|
+
// eslint-disable-next-line no-undef
|
|
1078
|
+
console.log(`[Avaliador Sintático Tenda] Tempo para análise: ${deltaAnalise[0] * 1e9 + deltaAnalise[1]}ns`);
|
|
1079
|
+
}
|
|
1080
|
+
return {
|
|
1081
|
+
declaracoes: declaracoes,
|
|
1082
|
+
erros: this.erros,
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
exports.AvaliadorSintaticoTenda = AvaliadorSintaticoTenda;
|
|
1087
|
+
//# sourceMappingURL=avaliador-sintatico-tenda.js.map
|