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