@designliquido/delegua 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/CONTRIBUTING.md +37 -0
- package/.github/workflows/principal.yml +3 -1
- package/.release-it.json +2 -1
- package/.vscode/launch.json +43 -8
- package/README.md +9 -1
- package/bin/delegua +2 -2
- package/bin/delegua.cmd +1 -1
- package/index.ts +29 -0
- package/package.json +9 -4
- package/src/ambiente.ts +56 -0
- package/src/avaliador-sintatico/dialetos/egua-classico.ts +983 -0
- package/src/avaliador-sintatico/dialetos/index.ts +1 -0
- package/src/avaliador-sintatico/index.ts +983 -0
- package/src/avaliador-sintatico/parser-error.ts +1 -0
- package/src/{lib/globalLib.js → bibliotecas/bibliotecaGlobal.ts} +34 -34
- package/src/{lib/importStdlib.js → bibliotecas/importarBiblioteca.ts} +9 -9
- package/src/construtos/assign-subscript.ts +19 -0
- package/src/construtos/atribuir.ts +17 -0
- package/src/construtos/binario.ts +19 -0
- package/src/construtos/call.ts +19 -0
- package/src/construtos/conjunto.ts +19 -0
- package/src/construtos/dicionario.ts +17 -0
- package/src/construtos/expr.ts +3 -0
- package/src/construtos/funcao.ts +17 -0
- package/src/construtos/get.ts +17 -0
- package/src/construtos/grouping.ts +15 -0
- package/src/construtos/index.ts +18 -0
- package/src/construtos/isto.ts +15 -0
- package/src/construtos/literal.ts +15 -0
- package/src/construtos/logical.ts +19 -0
- package/src/construtos/subscript.ts +19 -0
- package/src/construtos/super.ts +17 -0
- package/src/construtos/unario.ts +17 -0
- package/src/construtos/variavel.ts +15 -0
- package/src/construtos/vetor.ts +15 -0
- package/src/{stmt.js → declaracoes/index.ts} +79 -51
- package/src/delegua.ts +156 -0
- package/src/estruturas/callable.ts +11 -0
- package/src/estruturas/{classe.js → classe.ts} +11 -7
- package/src/estruturas/{funcaoPadrao.js → funcao-padrao.ts} +8 -4
- package/src/estruturas/funcao.ts +70 -0
- package/src/estruturas/index.ts +6 -0
- package/src/estruturas/{instancia.js → instancia.ts} +12 -9
- package/src/estruturas/modulo.ts +11 -0
- package/src/excecoes/break-exception.ts +1 -0
- package/src/excecoes/continue-exception.ts +1 -0
- package/src/excecoes/erro-em-tempo-de-execucao.ts +11 -0
- package/src/excecoes/index.ts +4 -0
- package/src/excecoes/return-exception.ts +10 -0
- package/src/interfaces/avaliador-sintatico-interface.ts +58 -0
- package/src/interfaces/index.ts +6 -0
- package/src/interfaces/interpretador-interface.ts +52 -0
- package/src/interfaces/lexador-interface.ts +24 -0
- package/src/interfaces/pilha-interface.ts +7 -0
- package/src/interfaces/resolvedor-interface.ts +49 -0
- package/src/interfaces/simbolo-interface.ts +6 -0
- package/src/interpretador/dialetos/egua-classico.ts +825 -0
- package/src/interpretador/dialetos/index.ts +1 -0
- package/src/interpretador/index.ts +825 -0
- package/src/lexador/dialetos/egua-classico.ts +333 -0
- package/src/lexador/dialetos/index.ts +1 -0
- package/src/{lexer.js → lexador/index.ts} +38 -21
- package/src/resolvedor/Pilha.ts +29 -0
- package/src/resolvedor/ResolverError.ts +8 -0
- package/src/resolvedor/dialetos/egua-classico.ts +412 -0
- package/src/resolvedor/dialetos/index.ts +1 -0
- package/src/{resolver.js → resolvedor/index.ts} +101 -114
- package/src/{tiposDeSimbolos.js → tiposDeSimbolos.ts} +21 -22
- package/src/web.ts +75 -0
- package/tsconfig.json +11 -0
- package/indice.js +0 -14
- package/src/ambiente.js +0 -53
- package/src/delegua.js +0 -102
- package/src/erro.js +0 -18
- package/src/estruturas/callable.js +0 -5
- package/src/estruturas/funcao.js +0 -62
- package/src/estruturas/modulo.js +0 -9
- package/src/expr.js +0 -228
- package/src/interpretador.js +0 -802
- package/src/parser.js +0 -822
- package/src/web.js +0 -70
package/src/interpretador.js
DELETED
|
@@ -1,802 +0,0 @@
|
|
|
1
|
-
const tiposDeSimbolos = require("./tiposDeSimbolos.js"),
|
|
2
|
-
Ambiente = require("./ambiente.js"),
|
|
3
|
-
Delegua = require("./delegua.js"),
|
|
4
|
-
loadGlobalLib = require("./lib/globalLib.js"),
|
|
5
|
-
caminho = require("path"),
|
|
6
|
-
fs = require("fs"),
|
|
7
|
-
checkStdLib = require("./lib/importStdlib.js");
|
|
8
|
-
|
|
9
|
-
const Callable = require("./estruturas/callable.js"),
|
|
10
|
-
FuncaoPadrao = require("./estruturas/funcaoPadrao.js"),
|
|
11
|
-
DeleguaClasse = require("./estruturas/classe.js"),
|
|
12
|
-
DeleguaFuncao = require("./estruturas/funcao.js"),
|
|
13
|
-
DeleguaInstancia = require("./estruturas/instancia.js"),
|
|
14
|
-
DeleguaModulo = require("./estruturas/modulo.js");
|
|
15
|
-
|
|
16
|
-
const {
|
|
17
|
-
ErroEmTempoDeExecucao,
|
|
18
|
-
ContinueException,
|
|
19
|
-
BreakException,
|
|
20
|
-
ReturnException
|
|
21
|
-
} = require("./erro.js");
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* O Interpretador visita todos os elementos complexos gerados pelo analisador sintático (Parser)
|
|
25
|
-
* e de fato executa a lógica de programação descrita no código.
|
|
26
|
-
*/
|
|
27
|
-
module.exports = class Interpretador {
|
|
28
|
-
constructor(Delegua, diretorioBase) {
|
|
29
|
-
this.Delegua = Delegua;
|
|
30
|
-
this.diretorioBase = diretorioBase;
|
|
31
|
-
|
|
32
|
-
this.globals = new Ambiente();
|
|
33
|
-
this.ambiente = this.globals;
|
|
34
|
-
this.locais = new Map();
|
|
35
|
-
|
|
36
|
-
this.globals = loadGlobalLib(this, this.globals);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
resolver(expr, depth) {
|
|
40
|
-
this.locais.set(expr, depth);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
visitLiteralExpr(expr) {
|
|
44
|
-
return expr.valor;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
avaliar(expr) {
|
|
48
|
-
return expr.aceitar(this);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
visitGroupingExpr(expr) {
|
|
52
|
-
return this.avaliar(expr.expressao);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
eVerdadeiro(objeto) {
|
|
56
|
-
if (objeto === null)
|
|
57
|
-
return false;
|
|
58
|
-
if (typeof objeto === "boolean")
|
|
59
|
-
return Boolean(objeto);
|
|
60
|
-
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
checkNumberOperand(operador, operand) {
|
|
65
|
-
if (typeof operand === "number") return;
|
|
66
|
-
throw new ErroEmTempoDeExecucao(operador, "Operador precisa ser um número.");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
visitUnaryExpr(expr) {
|
|
70
|
-
const direita = this.avaliar(expr.direita);
|
|
71
|
-
|
|
72
|
-
switch (expr.operador.tipo) {
|
|
73
|
-
case tiposDeSimbolos.SUBTRACAO:
|
|
74
|
-
this.checkNumberOperand(expr.operador, direita);
|
|
75
|
-
return -direita;
|
|
76
|
-
case tiposDeSimbolos.NEGACAO:
|
|
77
|
-
return !this.eVerdadeiro(direita);
|
|
78
|
-
case tiposDeSimbolos.BIT_NOT:
|
|
79
|
-
return ~direita;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
eIgual(esquerda, direita) {
|
|
86
|
-
if (esquerda === null && direita === null)
|
|
87
|
-
return true;
|
|
88
|
-
if (esquerda === null)
|
|
89
|
-
return false;
|
|
90
|
-
|
|
91
|
-
return esquerda === direita;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
checkNumberOperands(operador, direita, esquerda) {
|
|
95
|
-
if (typeof direita === "number" && typeof esquerda === "number") return;
|
|
96
|
-
throw new ErroEmTempoDeExecucao(operador, "Operadores precisam ser números.");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
visitBinaryExpr(expr) {
|
|
100
|
-
let esquerda = this.avaliar(expr.esquerda);
|
|
101
|
-
let direita = this.avaliar(expr.direita);
|
|
102
|
-
|
|
103
|
-
switch (expr.operador.tipo) {
|
|
104
|
-
case tiposDeSimbolos.STAR_STAR:
|
|
105
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
106
|
-
return Math.pow(esquerda, direita);
|
|
107
|
-
|
|
108
|
-
case tiposDeSimbolos.MAIOR:
|
|
109
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
110
|
-
return Number(esquerda) > Number(direita);
|
|
111
|
-
|
|
112
|
-
case tiposDeSimbolos.MAIOR_IGUAL:
|
|
113
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
114
|
-
return Number(esquerda) >= Number(direita);
|
|
115
|
-
|
|
116
|
-
case tiposDeSimbolos.MENOR:
|
|
117
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
118
|
-
return Number(esquerda) < Number(direita);
|
|
119
|
-
|
|
120
|
-
case tiposDeSimbolos.MENOR_IGUAL:
|
|
121
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
122
|
-
return Number(esquerda) <= Number(direita);
|
|
123
|
-
|
|
124
|
-
case tiposDeSimbolos.SUBTRACAO:
|
|
125
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
126
|
-
return Number(esquerda) - Number(direita);
|
|
127
|
-
|
|
128
|
-
case tiposDeSimbolos.ADICAO:
|
|
129
|
-
if (typeof esquerda === "number" && typeof direita === "number") {
|
|
130
|
-
return Number(esquerda) + Number(direita);
|
|
131
|
-
} else if (typeof esquerda === "string" && typeof direita === "string") {
|
|
132
|
-
return String(esquerda) + String(direita);
|
|
133
|
-
} else{
|
|
134
|
-
return String(esquerda) + String(direita);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
case tiposDeSimbolos.SLASH:
|
|
138
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
139
|
-
return Number(esquerda) / Number(direita);
|
|
140
|
-
|
|
141
|
-
case tiposDeSimbolos.STAR:
|
|
142
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
143
|
-
return Number(esquerda) * Number(direita);
|
|
144
|
-
|
|
145
|
-
case tiposDeSimbolos.MODULUS:
|
|
146
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
147
|
-
return Number(esquerda) % Number(direita);
|
|
148
|
-
|
|
149
|
-
case tiposDeSimbolos.BIT_AND:
|
|
150
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
151
|
-
return Number(esquerda) & Number(direita);
|
|
152
|
-
|
|
153
|
-
case tiposDeSimbolos.BIT_XOR:
|
|
154
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
155
|
-
return Number(esquerda) ^ Number(direita);
|
|
156
|
-
|
|
157
|
-
case tiposDeSimbolos.BIT_OR:
|
|
158
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
159
|
-
return Number(esquerda) | Number(direita);
|
|
160
|
-
|
|
161
|
-
case tiposDeSimbolos.MENOR_MENOR:
|
|
162
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
163
|
-
return Number(esquerda) << Number(direita);
|
|
164
|
-
|
|
165
|
-
case tiposDeSimbolos.MAIOR_MAIOR:
|
|
166
|
-
this.checkNumberOperands(expr.operador, esquerda, direita);
|
|
167
|
-
return Number(esquerda) >> Number(direita);
|
|
168
|
-
|
|
169
|
-
case tiposDeSimbolos.DIFERENTE:
|
|
170
|
-
return !this.eIgual(esquerda, direita);
|
|
171
|
-
|
|
172
|
-
case tiposDeSimbolos.IGUAL_IGUAL:
|
|
173
|
-
return this.eIgual(esquerda, direita);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
visitCallExpr(expr) {
|
|
180
|
-
let callee = this.avaliar(expr.callee);
|
|
181
|
-
|
|
182
|
-
let argumentos = [];
|
|
183
|
-
for (let i = 0; i < expr.argumentos.length; i++) {
|
|
184
|
-
argumentos.push(this.avaliar(expr.argumentos[i]));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (!(callee instanceof Callable)) {
|
|
188
|
-
throw new ErroEmTempoDeExecucao(
|
|
189
|
-
expr.paren,
|
|
190
|
-
"Só pode chamar função ou classe."
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
let parametros;
|
|
195
|
-
if (callee instanceof DeleguaFuncao) {
|
|
196
|
-
parametros = callee.declaracao.parametros;
|
|
197
|
-
} else if (callee instanceof DeleguaClasse) {
|
|
198
|
-
parametros = callee.metodos.init
|
|
199
|
-
? callee.metodos.init.declaracao.parametros
|
|
200
|
-
: [];
|
|
201
|
-
} else {
|
|
202
|
-
parametros = [];
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (argumentos.length < callee.aridade()) {
|
|
206
|
-
let diferenca = callee.aridade() - argumentos.length;
|
|
207
|
-
for (let i = 0; i < diferenca; i++) {
|
|
208
|
-
argumentos.push(null);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
else if (argumentos.length >= callee.aridade()) {
|
|
213
|
-
if (
|
|
214
|
-
parametros.length > 0 &&
|
|
215
|
-
parametros[parametros.length - 1]["tipo"] === "wildcard"
|
|
216
|
-
) {
|
|
217
|
-
let novosArgumentos = argumentos.slice(0, parametros.length - 1);
|
|
218
|
-
novosArgumentos.push(argumentos.slice(parametros.length - 1, argumentos.length));
|
|
219
|
-
argumentos = novosArgumentos;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (callee instanceof FuncaoPadrao) {
|
|
224
|
-
return callee.chamar(this, argumentos, expr.callee.nome);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return callee.call(this, argumentos);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
visitAssignExpr(expr) {
|
|
231
|
-
const valor = this.avaliar(expr.valor);
|
|
232
|
-
|
|
233
|
-
const distancia = this.locais.get(expr);
|
|
234
|
-
if (distancia !== undefined) {
|
|
235
|
-
this.ambiente.atribuirVariavelEm(distancia, expr.nome, valor);
|
|
236
|
-
} else {
|
|
237
|
-
this.ambiente.atribuirVariavel(expr.nome, valor);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return valor;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
procurarVariavel(nome, expr) {
|
|
244
|
-
const distancia = this.locais.get(expr);
|
|
245
|
-
if (distancia !== undefined) {
|
|
246
|
-
return this.ambiente.obterVariavelEm(distancia, nome.lexeme);
|
|
247
|
-
} else {
|
|
248
|
-
return this.globals.obterVariavel(nome);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
visitVariableExpr(expr) {
|
|
253
|
-
return this.procurarVariavel(expr.nome, expr);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
visitExpressionStmt(stmt) {
|
|
257
|
-
return this.avaliar(stmt.expressao);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
visitLogicalExpr(expr) {
|
|
261
|
-
let esquerda = this.avaliar(expr.esquerda);
|
|
262
|
-
|
|
263
|
-
if (expr.operador.tipo === tiposDeSimbolos.EM) {
|
|
264
|
-
let direita = this.avaliar(expr.direita);
|
|
265
|
-
|
|
266
|
-
if (Array.isArray(direita) || typeof direita === "string") {
|
|
267
|
-
return direita.includes(esquerda);
|
|
268
|
-
} else if (direita.constructor === Object) {
|
|
269
|
-
return esquerda in direita;
|
|
270
|
-
} else {
|
|
271
|
-
throw new ErroEmTempoDeExecucao("Tipo de chamada inválida com 'em'.");
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// se um estado for verdadeiro, retorna verdadeiro
|
|
276
|
-
if (expr.operador.tipo === tiposDeSimbolos.OU) {
|
|
277
|
-
if (this.eVerdadeiro(esquerda)) return esquerda;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// se um estado for falso, retorna falso
|
|
281
|
-
if (expr.operador.tipo === tiposDeSimbolos.E) {
|
|
282
|
-
if (!this.eVerdadeiro(esquerda)) return esquerda;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return this.avaliar(expr.direita);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
visitIfStmt(stmt) {
|
|
289
|
-
if (this.eVerdadeiro(this.avaliar(stmt.condicao))) {
|
|
290
|
-
this.executar(stmt.thenBranch);
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
for (let i = 0; i < stmt.elifBranches.length; i++) {
|
|
295
|
-
const atual = stmt.elifBranches[i];
|
|
296
|
-
|
|
297
|
-
if (this.eVerdadeiro(this.avaliar(atual.condicao))) {
|
|
298
|
-
this.executar(atual.branch);
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (stmt.elseBranch !== null) {
|
|
304
|
-
this.executar(stmt.elseBranch);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
visitForStmt(stmt) {
|
|
311
|
-
if (stmt.inicializador !== null) {
|
|
312
|
-
this.avaliar(stmt.inicializador);
|
|
313
|
-
}
|
|
314
|
-
while (true) {
|
|
315
|
-
if (stmt.condicao !== null) {
|
|
316
|
-
if (!this.eVerdadeiro(this.avaliar(stmt.condicao))) {
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
try {
|
|
322
|
-
this.executar(stmt.corpo);
|
|
323
|
-
} catch (erro) {
|
|
324
|
-
if (erro instanceof BreakException) {
|
|
325
|
-
break;
|
|
326
|
-
} else if (erro instanceof ContinueException) {
|
|
327
|
-
} else {
|
|
328
|
-
throw erro;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (stmt.incrementar !== null) {
|
|
333
|
-
this.avaliar(stmt.incrementar);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
visitDoStmt(stmt) {
|
|
340
|
-
do {
|
|
341
|
-
try {
|
|
342
|
-
this.executar(stmt.doBranch);
|
|
343
|
-
} catch (erro) {
|
|
344
|
-
if (erro instanceof BreakException) {
|
|
345
|
-
break;
|
|
346
|
-
} else if (erro instanceof ContinueException) {
|
|
347
|
-
} else {
|
|
348
|
-
throw erro;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
} while (this.eVerdadeiro(this.avaliar(stmt.whileCondition)));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
visitSwitchStmt(stmt) {
|
|
355
|
-
let switchCondition = this.avaliar(stmt.condicao);
|
|
356
|
-
let branches = stmt.branches;
|
|
357
|
-
let defaultBranch = stmt.defaultBranch;
|
|
358
|
-
|
|
359
|
-
let matched = false;
|
|
360
|
-
try {
|
|
361
|
-
for (let i = 0; i < branches.length; i++) {
|
|
362
|
-
let branch = branches[i];
|
|
363
|
-
|
|
364
|
-
for (let j = 0; j < branch.conditions.length; j++) {
|
|
365
|
-
if (this.avaliar(branch.conditions[j]) === switchCondition) {
|
|
366
|
-
matched = true;
|
|
367
|
-
|
|
368
|
-
try {
|
|
369
|
-
for (let k = 0; k < branch.stmts.length; k++) {
|
|
370
|
-
this.executar(branch.stmts[k]);
|
|
371
|
-
}
|
|
372
|
-
} catch (erro) {
|
|
373
|
-
if (erro instanceof ContinueException) {
|
|
374
|
-
} else {
|
|
375
|
-
throw erro;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (defaultBranch !== null && matched === false) {
|
|
383
|
-
for (let i = 0; i < defaultBranch.stmts.length; i++) {
|
|
384
|
-
this.executar(defaultBranch["stmts"][i]);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
} catch (erro) {
|
|
388
|
-
if (erro instanceof BreakException) {
|
|
389
|
-
} else {
|
|
390
|
-
throw erro;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
visitTryStmt(stmt) {
|
|
396
|
-
try {
|
|
397
|
-
let sucesso = true;
|
|
398
|
-
try {
|
|
399
|
-
this.executeBlock(stmt.tryBranch, new Ambiente(this.ambiente));
|
|
400
|
-
} catch (erro) {
|
|
401
|
-
sucesso = false;
|
|
402
|
-
|
|
403
|
-
if (stmt.catchBranch !== null) {
|
|
404
|
-
this.executeBlock(
|
|
405
|
-
stmt.catchBranch,
|
|
406
|
-
new Ambiente(this.ambiente)
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (sucesso && stmt.elseBranch !== null) {
|
|
412
|
-
this.executeBlock(stmt.elseBranch, new Ambiente(this.ambiente));
|
|
413
|
-
}
|
|
414
|
-
} finally {
|
|
415
|
-
if (stmt.finallyBranch !== null)
|
|
416
|
-
this.executeBlock(
|
|
417
|
-
stmt.finallyBranch,
|
|
418
|
-
new Ambiente(this.ambiente)
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
visitWhileStmt(stmt) {
|
|
424
|
-
while (this.eVerdadeiro(this.avaliar(stmt.condicao))) {
|
|
425
|
-
try {
|
|
426
|
-
this.executar(stmt.corpo);
|
|
427
|
-
} catch (erro) {
|
|
428
|
-
if (erro instanceof BreakException) {
|
|
429
|
-
break;
|
|
430
|
-
} else if (erro instanceof ContinueException) {
|
|
431
|
-
} else {
|
|
432
|
-
throw erro;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
visitImportStmt(stmt) {
|
|
441
|
-
const caminhoRelativo = this.avaliar(stmt.caminho);
|
|
442
|
-
const caminhoTotal = caminho.join(this.diretorioBase, caminhoRelativo);
|
|
443
|
-
const pastaTotal = caminho.dirname(caminhoTotal);
|
|
444
|
-
const nomeArquivo = caminho.basename(caminhoTotal);
|
|
445
|
-
|
|
446
|
-
let dados = checkStdLib(caminhoRelativo);
|
|
447
|
-
if (dados !== null) return dados;
|
|
448
|
-
|
|
449
|
-
try {
|
|
450
|
-
if (!fs.existsSync(caminhoTotal)) {
|
|
451
|
-
throw new ErroEmTempoDeExecucao(
|
|
452
|
-
stmt.closeBracket,
|
|
453
|
-
"Não foi possível encontrar arquivo importado."
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
} catch (erro) {
|
|
457
|
-
throw new ErroEmTempoDeExecucao(stmt.closeBracket, "Não foi possível ler o arquivo.");
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
dados = fs.readFileSync(caminhoTotal).toString();
|
|
461
|
-
|
|
462
|
-
const delegua = new Delegua.Delegua(nomeArquivo);
|
|
463
|
-
const interpretador = new Interpretador(delegua, pastaTotal);
|
|
464
|
-
|
|
465
|
-
delegua.run(dados, interpretador);
|
|
466
|
-
|
|
467
|
-
let exportar = interpretador.globals.valores.exports;
|
|
468
|
-
|
|
469
|
-
const eDicionario = objeto => objeto.constructor === Object;
|
|
470
|
-
|
|
471
|
-
if (eDicionario(exportar)) {
|
|
472
|
-
let novoModulo = new DeleguaModulo();
|
|
473
|
-
|
|
474
|
-
let chaves = Object.keys(exportar);
|
|
475
|
-
for (let i = 0; i < chaves.length; i++) {
|
|
476
|
-
novoModulo[chaves[i]] = exportar[chaves[i]];
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return novoModulo;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
return exportar;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
visitPrintStmt(stmt) {
|
|
486
|
-
const valor = this.avaliar(stmt.expressao);
|
|
487
|
-
console.log(this.stringify(valor));
|
|
488
|
-
return null;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
executeBlock(declaracoes, ambiente) {
|
|
492
|
-
let anterior = this.ambiente;
|
|
493
|
-
try {
|
|
494
|
-
this.ambiente = ambiente;
|
|
495
|
-
|
|
496
|
-
for (let i = 0; i < declaracoes.length; i++) {
|
|
497
|
-
this.executar(declaracoes[i]);
|
|
498
|
-
}
|
|
499
|
-
} finally {
|
|
500
|
-
this.ambiente = anterior;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
visitBlockStmt(stmt) {
|
|
505
|
-
this.executeBlock(stmt.declaracoes, new Ambiente(this.ambiente));
|
|
506
|
-
return null;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
visitVarStmt(stmt) {
|
|
510
|
-
let valor = null;
|
|
511
|
-
if (stmt.inicializador !== null) {
|
|
512
|
-
valor = this.avaliar(stmt.inicializador);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
this.ambiente.definirVariavel(stmt.nome.lexeme, valor);
|
|
516
|
-
return null;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
visitContinueStmt(stmt) {
|
|
520
|
-
throw new ContinueException();
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
visitBreakStmt(stmt) {
|
|
524
|
-
throw new BreakException();
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
visitReturnStmt(stmt) {
|
|
528
|
-
let valor = null;
|
|
529
|
-
if (stmt.valor != null) valor = this.avaliar(stmt.valor);
|
|
530
|
-
|
|
531
|
-
throw new ReturnException(valor);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
visitFunctionExpr(expr) {
|
|
535
|
-
return new DeleguaFuncao(null, expr, this.ambiente, false);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
visitAssignsubscriptExpr(expr) {
|
|
539
|
-
let objeto = this.avaliar(expr.objeto);
|
|
540
|
-
let indice = this.avaliar(expr.indice);
|
|
541
|
-
let valor = this.avaliar(expr.valor);
|
|
542
|
-
|
|
543
|
-
if (Array.isArray(objeto)) {
|
|
544
|
-
if (indice < 0 && objeto.length !== 0) {
|
|
545
|
-
while (indice < 0) {
|
|
546
|
-
indice += objeto.length;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
while (objeto.length < indice) {
|
|
551
|
-
objeto.push(null);
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
objeto[indice] = valor;
|
|
555
|
-
} else if (
|
|
556
|
-
objeto.constructor === Object ||
|
|
557
|
-
objeto instanceof DeleguaInstancia ||
|
|
558
|
-
objeto instanceof DeleguaFuncao ||
|
|
559
|
-
objeto instanceof DeleguaClasse ||
|
|
560
|
-
objeto instanceof DeleguaModulo
|
|
561
|
-
) {
|
|
562
|
-
objeto[indice] = valor;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
else {
|
|
566
|
-
throw new ErroEmTempoDeExecucao(
|
|
567
|
-
expr.objeto.nome,
|
|
568
|
-
"Somente listas, dicionários, classes e objetos podem ser mudados por sobrescrita."
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
visitSubscriptExpr(expressao) {
|
|
574
|
-
const objeto = this.avaliar(expressao.callee);
|
|
575
|
-
|
|
576
|
-
let indice = this.avaliar(expressao.indice);
|
|
577
|
-
if (Array.isArray(objeto)) {
|
|
578
|
-
if (!Number.isInteger(indice)) {
|
|
579
|
-
throw new ErroEmTempoDeExecucao(
|
|
580
|
-
expressao.closeBracket,
|
|
581
|
-
"Somente inteiros podem ser usados para indexar um vetor."
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (indice < 0 && objeto.length !== 0) {
|
|
586
|
-
while (indice < 0) {
|
|
587
|
-
indice += objeto.length;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (indice >= objeto.length) {
|
|
592
|
-
throw new ErroEmTempoDeExecucao(expressao.closeBracket, "Índice do vetor fora do intervalo.");
|
|
593
|
-
}
|
|
594
|
-
return objeto[indice];
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
else if (
|
|
598
|
-
objeto.constructor === Object ||
|
|
599
|
-
objeto instanceof DeleguaInstancia ||
|
|
600
|
-
objeto instanceof DeleguaFuncao ||
|
|
601
|
-
objeto instanceof DeleguaClasse ||
|
|
602
|
-
objeto instanceof DeleguaModulo
|
|
603
|
-
) {
|
|
604
|
-
return objeto[indice] || null;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
else if (typeof objeto === "string") {
|
|
608
|
-
if (!Number.isInteger(indice)) {
|
|
609
|
-
throw new ErroEmTempoDeExecucao(
|
|
610
|
-
expressao.closeBracket,
|
|
611
|
-
"Somente inteiros podem ser usados para indexar um vetor."
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (indice < 0 && objeto.length !== 0) {
|
|
616
|
-
while (indice < 0) {
|
|
617
|
-
indice += obj.length;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
if (indice >= objeto.length) {
|
|
622
|
-
throw new ErroEmTempoDeExecucao(expressao.closeBracket, "Índice fora do tamanho.");
|
|
623
|
-
}
|
|
624
|
-
return objeto.charAt(indice);
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
else {
|
|
628
|
-
throw new ErroEmTempoDeExecucao(
|
|
629
|
-
expressao.callee.nome,
|
|
630
|
-
"Somente listas, dicionários, classes e objetos podem ser mudados por sobrescrita."
|
|
631
|
-
);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
visitSetExpr(expr) {
|
|
636
|
-
const objeto = this.avaliar(expr.objeto);
|
|
637
|
-
|
|
638
|
-
if (!(objeto instanceof DeleguaInstancia) && objeto.constructor !== Object) {
|
|
639
|
-
throw new ErroEmTempoDeExecucao(
|
|
640
|
-
expr.objeto.nome,
|
|
641
|
-
"Somente instâncias e dicionários podem possuir campos."
|
|
642
|
-
);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const valor = this.avaliar(expr.valor);
|
|
646
|
-
if (objeto instanceof DeleguaInstancia) {
|
|
647
|
-
objeto.set(expr.nome, valor);
|
|
648
|
-
return valor;
|
|
649
|
-
} else if (objeto.constructor === Object) {
|
|
650
|
-
objeto[expr.nome.lexeme] = valor;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
visitFunctionStmt(stmt) {
|
|
655
|
-
const funcao = new DeleguaFuncao(
|
|
656
|
-
stmt.nome.lexeme,
|
|
657
|
-
stmt.funcao,
|
|
658
|
-
this.ambiente,
|
|
659
|
-
false
|
|
660
|
-
);
|
|
661
|
-
this.ambiente.definirVariavel(stmt.nome.lexeme, funcao);
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
visitClassStmt(stmt) {
|
|
665
|
-
let superClasse = null;
|
|
666
|
-
if (stmt.superClasse !== null) {
|
|
667
|
-
superClasse = this.avaliar(stmt.superClasse);
|
|
668
|
-
if (!(superClasse instanceof DeleguaClasse)) {
|
|
669
|
-
throw new ErroEmTempoDeExecucao(
|
|
670
|
-
stmt.superClasse.nome,
|
|
671
|
-
"SuperClasse precisa ser uma classe."
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
this.ambiente.definirVariavel(stmt.nome.lexeme, null);
|
|
677
|
-
|
|
678
|
-
if (stmt.superClasse !== null) {
|
|
679
|
-
this.ambiente = new Ambiente(this.ambiente);
|
|
680
|
-
this.ambiente.definirVariavel("super", superClasse);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
let metodos = {};
|
|
684
|
-
let definirMetodos = stmt.metodos;
|
|
685
|
-
for (let i = 0; i < stmt.metodos.length; i++) {
|
|
686
|
-
let metodoAtual = definirMetodos[i];
|
|
687
|
-
let eInicializado = metodoAtual.nome.lexeme === "construtor";
|
|
688
|
-
const funcao = new DeleguaFuncao(
|
|
689
|
-
metodoAtual.nome.lexeme,
|
|
690
|
-
metodoAtual.funcao,
|
|
691
|
-
this.ambiente,
|
|
692
|
-
eInicializado
|
|
693
|
-
);
|
|
694
|
-
metodos[metodoAtual.nome.lexeme] = funcao;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
const criado = new DeleguaClasse(stmt.nome.lexeme, superClasse, metodos);
|
|
698
|
-
|
|
699
|
-
if (superClasse !== null) {
|
|
700
|
-
this.ambiente = this.ambiente.enclosing;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
this.ambiente.atribuirVariavel(stmt.nome, criado);
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
visitGetExpr(expr) {
|
|
708
|
-
let objeto = this.avaliar(expr.objeto);
|
|
709
|
-
if (objeto instanceof DeleguaInstancia) {
|
|
710
|
-
return objeto.get(expr.nome) || null;
|
|
711
|
-
} else if (objeto.constructor === Object) {
|
|
712
|
-
return objeto[expr.nome.lexeme] || null;
|
|
713
|
-
} else if (objeto instanceof DeleguaModulo) {
|
|
714
|
-
return objeto[expr.nome.lexeme] || null;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
throw new ErroEmTempoDeExecucao(
|
|
718
|
-
expr.nome,
|
|
719
|
-
"Você só pode acessar métodos do objeto e dicionários."
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
visitThisExpr(expr) {
|
|
724
|
-
return this.procurarVariavel(expr.palavraChave, expr);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
visitDictionaryExpr(expr) {
|
|
728
|
-
let dicionario = {};
|
|
729
|
-
for (let i = 0; i < expr.chaves.length; i++) {
|
|
730
|
-
dicionario[this.avaliar(expr.chaves[i])] = this.avaliar(expr.valores[i]);
|
|
731
|
-
}
|
|
732
|
-
return dicionario;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
visitArrayExpr(expr) {
|
|
736
|
-
let valores = [];
|
|
737
|
-
for (let i = 0; i < expr.valores.length; i++) {
|
|
738
|
-
valores.push(this.avaliar(expr.valores[i]));
|
|
739
|
-
}
|
|
740
|
-
return valores;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
visitSuperExpr(expr) {
|
|
744
|
-
const distancia = this.locais.get(expr);
|
|
745
|
-
const superClasse = this.ambiente.obterVariavelEm(distancia, "super");
|
|
746
|
-
|
|
747
|
-
const objeto = this.ambiente.obterVariavelEm(distancia - 1, "isto");
|
|
748
|
-
|
|
749
|
-
let metodo = superClasse.encontrarMetodo(expr.metodo.lexeme);
|
|
750
|
-
|
|
751
|
-
if (metodo === undefined) {
|
|
752
|
-
throw new ErroEmTempoDeExecucao(
|
|
753
|
-
expr.metodo,
|
|
754
|
-
"Método chamado indefinido."
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
return metodo.bind(objeto);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
stringify(objeto) {
|
|
762
|
-
if (objeto === null) return "nulo";
|
|
763
|
-
if (typeof objeto === "boolean") {
|
|
764
|
-
return objeto ? "verdadeiro" : "falso";
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (objeto instanceof Date) {
|
|
768
|
-
const formato = Intl.DateTimeFormat('pt', { dateStyle: 'full', timeStyle: 'full' });
|
|
769
|
-
return formato.format(objeto);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (Array.isArray(objeto)) return objeto;
|
|
773
|
-
|
|
774
|
-
if (typeof objeto === 'object') return JSON.stringify(objeto);
|
|
775
|
-
|
|
776
|
-
return objeto.toString();
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
executar(stmt, imprimirResultado = false) {
|
|
780
|
-
const resultado = stmt.aceitar(this);
|
|
781
|
-
if(imprimirResultado){
|
|
782
|
-
console.log(this.stringify(resultado));
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
interpretar(declaracoes) {
|
|
787
|
-
try {
|
|
788
|
-
if(declaracoes.length === 1){
|
|
789
|
-
const eObjetoExpressao = declaracoes[0].constructor.name === 'Expressao'
|
|
790
|
-
if(eObjetoExpressao){
|
|
791
|
-
this.executar(declaracoes[0], eObjetoExpressao);
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
for (let i = 0; i < declaracoes.length; i++) {
|
|
796
|
-
this.executar(declaracoes[i]);
|
|
797
|
-
}
|
|
798
|
-
} catch (erro) {
|
|
799
|
-
this.Delegua.erroEmTempoDeExecucao(erro);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
};
|