@designliquido/delegua 0.0.1
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/.vscode/launch.json +29 -0
- package/.vscode/settings.json +3 -0
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/babel.config.js +1 -0
- package/bin/delegua +3 -0
- package/index.html +43 -0
- package/index.js +14 -0
- package/package.json +37 -0
- package/src/egua.js +102 -0
- package/src/environment.js +53 -0
- package/src/errors.js +17 -0
- package/src/expr.js +228 -0
- package/src/interpreter.js +798 -0
- package/src/lexer.js +315 -0
- package/src/lib/__tests__/eguamat.test.js +101 -0
- package/src/lib/eguamat.js +725 -0
- package/src/lib/globalLib.js +171 -0
- package/src/lib/importStdlib.js +41 -0
- package/src/lib/tempo.js +50 -0
- package/src/parser.js +826 -0
- package/src/resolver.js +425 -0
- package/src/stmt.js +215 -0
- package/src/structures/callable.js +5 -0
- package/src/structures/class.js +43 -0
- package/src/structures/function.js +62 -0
- package/src/structures/instance.js +27 -0
- package/src/structures/module.js +9 -0
- package/src/structures/standardFn.js +18 -0
- package/src/tokenTypes.js +67 -0
- package/src/web.js +70 -0
- package/testes/testes.egua +631 -0
package/src/lexer.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
const tokenTypes = require("./tokenTypes.js");
|
|
2
|
+
|
|
3
|
+
const palavrasReservadas = {
|
|
4
|
+
e: tokenTypes.E,
|
|
5
|
+
em: tokenTypes.EM,
|
|
6
|
+
classe: tokenTypes.CLASSE,
|
|
7
|
+
senao: tokenTypes.SENAO,
|
|
8
|
+
falso: tokenTypes.FALSO,
|
|
9
|
+
para: tokenTypes.PARA,
|
|
10
|
+
funcao: tokenTypes.FUNCAO,
|
|
11
|
+
se: tokenTypes.SE,
|
|
12
|
+
senaose: tokenTypes.SENAOSE,
|
|
13
|
+
nulo: tokenTypes.NULO,
|
|
14
|
+
ou: tokenTypes.OU,
|
|
15
|
+
escreva: tokenTypes.ESCREVA,
|
|
16
|
+
retorna: tokenTypes.RETORNA,
|
|
17
|
+
super: tokenTypes.SUPER,
|
|
18
|
+
isto: tokenTypes.ISTO,
|
|
19
|
+
verdadeiro: tokenTypes.VERDADEIRO,
|
|
20
|
+
var: tokenTypes.VAR,
|
|
21
|
+
fazer: tokenTypes.FAZER,
|
|
22
|
+
enquanto: tokenTypes.ENQUANTO,
|
|
23
|
+
pausa: tokenTypes.PAUSA,
|
|
24
|
+
continua: tokenTypes.CONTINUA,
|
|
25
|
+
escolha: tokenTypes.ESCOLHA,
|
|
26
|
+
caso: tokenTypes.CASO,
|
|
27
|
+
padrao: tokenTypes.PADRAO,
|
|
28
|
+
importar: tokenTypes.IMPORTAR,
|
|
29
|
+
tente: tokenTypes.TENTE,
|
|
30
|
+
pegue: tokenTypes.PEGUE,
|
|
31
|
+
finalmente: tokenTypes.FINALMENTE,
|
|
32
|
+
herda: tokenTypes.HERDA
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
class Token {
|
|
36
|
+
constructor(tipo, lexeme, literal, linha) {
|
|
37
|
+
this.tipo = tipo;
|
|
38
|
+
this.lexeme = lexeme;
|
|
39
|
+
this.literal = literal;
|
|
40
|
+
this.linha = linha;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toString() {
|
|
44
|
+
return this.tipo + " " + this.lexeme + " " + this.literal;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* O Lexador é responsável por transformar o código em uma coleção de tokens de linguagem.
|
|
50
|
+
* Cada token de linguagem é representado por um tipo, um lexema e informações da linha de código em que foi expresso.
|
|
51
|
+
* Também é responsável por mapear as palavras reservadas da linguagem, que não podem ser usadas por outras
|
|
52
|
+
* estruturas, tais como nomes de variáveis, funções, literais, classes e assim por diante.
|
|
53
|
+
*/
|
|
54
|
+
module.exports = class Lexer {
|
|
55
|
+
constructor(codigo, Egua) {
|
|
56
|
+
this.Egua = Egua;
|
|
57
|
+
this.codigo = codigo;
|
|
58
|
+
|
|
59
|
+
this.simbolos = [];
|
|
60
|
+
|
|
61
|
+
this.inicio = 0;
|
|
62
|
+
this.atual = 0;
|
|
63
|
+
this.linha = 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
eDigito(c) {
|
|
67
|
+
return c >= "0" && c <= "9";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
eAlfabeto(c) {
|
|
71
|
+
return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c == "_";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
eAlfabetoOuDigito(c) {
|
|
75
|
+
return this.eDigito(c) || this.eAlfabeto(c);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
endOfCode() {
|
|
79
|
+
return this.atual >= this.codigo.length;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
avancar() {
|
|
83
|
+
this.atual += 1;
|
|
84
|
+
return this.codigo[this.atual - 1];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
adicionarSimbolo(tipo, literal = null) {
|
|
88
|
+
const texto = this.codigo.substring(this.inicio, this.atual);
|
|
89
|
+
this.simbolos.push(new Token(tipo, texto, literal, this.linha));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
match(esperado) {
|
|
93
|
+
if (this.endOfCode()) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (this.codigo[this.atual] !== esperado) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.atual += 1;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
peek() {
|
|
106
|
+
if (this.endOfCode()) return "\0";
|
|
107
|
+
return this.codigo.charAt(this.atual);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
peekNext() {
|
|
111
|
+
if (this.atual + 1 >= this.codigo.length) return "\0";
|
|
112
|
+
return this.codigo.charAt(this.atual + 1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
voltar() {
|
|
116
|
+
return this.codigo.charAt(this.atual - 1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
analisarTexto(stringChar = '"') {
|
|
120
|
+
while (this.peek() !== stringChar && !this.endOfCode()) {
|
|
121
|
+
if (this.peek() === "\n") this.linha = +1;
|
|
122
|
+
this.avancar();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (this.endOfCode()) {
|
|
126
|
+
this.Egua.lexerError(
|
|
127
|
+
this.linha,
|
|
128
|
+
this.voltar(),
|
|
129
|
+
"Texto não finalizado."
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.avancar();
|
|
135
|
+
|
|
136
|
+
const valor = this.codigo.substring(this.inicio + 1, this.atual - 1);
|
|
137
|
+
this.adicionarSimbolo(tokenTypes.STRING, valor);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
analisarNumero() {
|
|
141
|
+
while (this.eDigito(this.peek())) {
|
|
142
|
+
this.avancar();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (this.peek() == "." && this.eDigito(this.peekNext())) {
|
|
146
|
+
this.avancar();
|
|
147
|
+
|
|
148
|
+
while (this.eDigito(this.peek())) {
|
|
149
|
+
this.avancar();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const numeroCompleto = this.codigo.substring(this.inicio, this.atual);
|
|
154
|
+
this.adicionarSimbolo(tokenTypes.NUMBER, parseFloat(numeroCompleto));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
identificarPalavraChave() {
|
|
158
|
+
while (this.eAlfabetoOuDigito(this.peek())) {
|
|
159
|
+
this.avancar();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const c = this.codigo.substring(this.inicio, this.atual);
|
|
163
|
+
const tipo = c in palavrasReservadas ? palavrasReservadas[c] : tokenTypes.IDENTIFIER;
|
|
164
|
+
|
|
165
|
+
this.adicionarSimbolo(tipo);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
scanToken() {
|
|
169
|
+
const char = this.avancar();
|
|
170
|
+
|
|
171
|
+
switch (char) {
|
|
172
|
+
case "[":
|
|
173
|
+
this.adicionarSimbolo(tokenTypes.LEFT_SQUARE_BRACKET);
|
|
174
|
+
break;
|
|
175
|
+
case "]":
|
|
176
|
+
this.adicionarSimbolo(tokenTypes.RIGHT_SQUARE_BRACKET);
|
|
177
|
+
break;
|
|
178
|
+
case "(":
|
|
179
|
+
this.adicionarSimbolo(tokenTypes.LEFT_PAREN);
|
|
180
|
+
break;
|
|
181
|
+
case ")":
|
|
182
|
+
this.adicionarSimbolo(tokenTypes.RIGHT_PAREN);
|
|
183
|
+
break;
|
|
184
|
+
case "{":
|
|
185
|
+
this.adicionarSimbolo(tokenTypes.LEFT_BRACE);
|
|
186
|
+
break;
|
|
187
|
+
case "}":
|
|
188
|
+
this.adicionarSimbolo(tokenTypes.RIGHT_BRACE);
|
|
189
|
+
break;
|
|
190
|
+
case ",":
|
|
191
|
+
this.adicionarSimbolo(tokenTypes.COMMA);
|
|
192
|
+
break;
|
|
193
|
+
case ".":
|
|
194
|
+
this.adicionarSimbolo(tokenTypes.DOT);
|
|
195
|
+
break;
|
|
196
|
+
case "-":
|
|
197
|
+
if (this.match("=")) {
|
|
198
|
+
this.adicionarSimbolo(tokenTypes.MENOR_IGUAL);
|
|
199
|
+
}
|
|
200
|
+
this.adicionarSimbolo(tokenTypes.MINUS);
|
|
201
|
+
break;
|
|
202
|
+
case "+":
|
|
203
|
+
if (this.match("=")) {
|
|
204
|
+
this.adicionarSimbolo(tokenTypes.MAIS_IGUAL);
|
|
205
|
+
}
|
|
206
|
+
this.adicionarSimbolo(tokenTypes.PLUS);
|
|
207
|
+
break;
|
|
208
|
+
case ":":
|
|
209
|
+
this.adicionarSimbolo(tokenTypes.COLON);
|
|
210
|
+
break;
|
|
211
|
+
case ";":
|
|
212
|
+
this.adicionarSimbolo(tokenTypes.SEMICOLON);
|
|
213
|
+
break;
|
|
214
|
+
case "%":
|
|
215
|
+
this.adicionarSimbolo(tokenTypes.MODULUS);
|
|
216
|
+
break;
|
|
217
|
+
case "*":
|
|
218
|
+
if (this.peek() === "*") {
|
|
219
|
+
this.avancar();
|
|
220
|
+
this.adicionarSimbolo(tokenTypes.STAR_STAR);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
this.adicionarSimbolo(tokenTypes.STAR);
|
|
224
|
+
break;
|
|
225
|
+
case "!":
|
|
226
|
+
this.adicionarSimbolo(
|
|
227
|
+
this.match("=") ? tokenTypes.BANG_EQUAL : tokenTypes.BANG
|
|
228
|
+
);
|
|
229
|
+
break;
|
|
230
|
+
case "=":
|
|
231
|
+
this.adicionarSimbolo(
|
|
232
|
+
this.match("=") ? tokenTypes.EQUAL_EQUAL : tokenTypes.EQUAL
|
|
233
|
+
);
|
|
234
|
+
break;
|
|
235
|
+
|
|
236
|
+
case "&":
|
|
237
|
+
this.adicionarSimbolo(tokenTypes.BIT_AND);
|
|
238
|
+
break;
|
|
239
|
+
|
|
240
|
+
case "~":
|
|
241
|
+
this.adicionarSimbolo(tokenTypes.BIT_NOT);
|
|
242
|
+
break;
|
|
243
|
+
|
|
244
|
+
case "|":
|
|
245
|
+
this.adicionarSimbolo(tokenTypes.BIT_OR);
|
|
246
|
+
break;
|
|
247
|
+
|
|
248
|
+
case "^":
|
|
249
|
+
this.adicionarSimbolo(tokenTypes.BIT_XOR);
|
|
250
|
+
break;
|
|
251
|
+
|
|
252
|
+
case "<":
|
|
253
|
+
if (this.match("=")) {
|
|
254
|
+
this.adicionarSimbolo(tokenTypes.LESS_EQUAL);
|
|
255
|
+
} else if (this.match("<")) {
|
|
256
|
+
this.adicionarSimbolo(tokenTypes.LESSER_LESSER);
|
|
257
|
+
} else {
|
|
258
|
+
this.adicionarSimbolo(tokenTypes.LESS);
|
|
259
|
+
}
|
|
260
|
+
break;
|
|
261
|
+
|
|
262
|
+
case ">":
|
|
263
|
+
if (this.match("=")) {
|
|
264
|
+
this.adicionarSimbolo(tokenTypes.GREATER_EQUAL);
|
|
265
|
+
} else if (this.match(">")) {
|
|
266
|
+
this.adicionarSimbolo(tokenTypes.GREATER_GREATER);
|
|
267
|
+
} else {
|
|
268
|
+
this.adicionarSimbolo(tokenTypes.GREATER);
|
|
269
|
+
}
|
|
270
|
+
break;
|
|
271
|
+
|
|
272
|
+
case "/":
|
|
273
|
+
if (this.match("/")) {
|
|
274
|
+
while (this.peek() != "\n" && !this.endOfCode()) this.avancar();
|
|
275
|
+
} else {
|
|
276
|
+
this.adicionarSimbolo(tokenTypes.SLASH);
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
// Esta sessão ignora espaços em branco na tokenização
|
|
281
|
+
case " ":
|
|
282
|
+
case "\r":
|
|
283
|
+
case "\t":
|
|
284
|
+
break;
|
|
285
|
+
|
|
286
|
+
// tentativa de pulhar linha com \n que ainda não funciona
|
|
287
|
+
case "\n":
|
|
288
|
+
this.linha += 1;
|
|
289
|
+
break;
|
|
290
|
+
|
|
291
|
+
case '"':
|
|
292
|
+
this.analisarTexto('"');
|
|
293
|
+
break;
|
|
294
|
+
|
|
295
|
+
case "'":
|
|
296
|
+
this.analisarTexto("'");
|
|
297
|
+
break;
|
|
298
|
+
|
|
299
|
+
default:
|
|
300
|
+
if (this.eDigito(char)) this.analisarNumero();
|
|
301
|
+
else if (this.eAlfabeto(char)) this.identificarPalavraChave();
|
|
302
|
+
else this.Egua.lexerError(this.linha, char, "Caractere inesperado.");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
scan() {
|
|
307
|
+
while (!this.endOfCode()) {
|
|
308
|
+
this.inicio = this.atual;
|
|
309
|
+
this.scanToken();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
this.simbolos.push(new Token(tokenTypes.EOF, "", null, this.linha));
|
|
313
|
+
return this.simbolos;
|
|
314
|
+
}
|
|
315
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { aprox, raizq, sen, cos, tan, radiano, graus, pi, raiz } from '../eguamat';
|
|
4
|
+
|
|
5
|
+
describe('aprox', () => {
|
|
6
|
+
it('atira exceção se num for nulo', () => {
|
|
7
|
+
expect(() => aprox()).toThrow();
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('atira exceção se num é NaN', () => {
|
|
11
|
+
expect(() => aprox('egua', 'outro-NaN')).toThrow();
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('arredonda um número', () => {
|
|
15
|
+
expect(aprox(2.9999999999, 0)).toBe("3");
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('raizq', () => {
|
|
20
|
+
it('atira exceção se num for nulo', () => {
|
|
21
|
+
expect(() => raizq()).toThrow();
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('atira exceção se num é NaN', () => {
|
|
25
|
+
expect(() => raizq('egua')).toThrow();
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('calcula a raiz quadrada', () => {
|
|
29
|
+
expect(raizq(4)).toBe(2);
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('sen', () => {
|
|
34
|
+
it('atira exceção se num for nulo', () => {
|
|
35
|
+
expect(() => sen()).toThrow();
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('atira exceção se num é NaN', () => {
|
|
39
|
+
expect(() => sen('egua')).toThrow();
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('calcula o seno', () => {
|
|
43
|
+
expect(sen(90)).toBe(0.8939966636005579);
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('cos', () => {
|
|
48
|
+
it('atira exceção se num for nulo', () => {
|
|
49
|
+
expect(() => cos()).toThrow();
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('atira exceção se num é NaN', () => {
|
|
53
|
+
expect(() => cos('egua')).toThrow();
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('calcula o cosseno', () => {
|
|
57
|
+
expect(cos(90)).toBe(-0.4480736161291702);
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('radiano', () => {
|
|
62
|
+
it('atira exceção se num for nulo', () => {
|
|
63
|
+
expect(() => radiano()).toThrow();
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('atira exceção se num é NaN', () => {
|
|
67
|
+
expect(() => radiano('egua')).toThrow();
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('calcula o radiano', () => {
|
|
71
|
+
expect(radiano(180)).toBe(pi);
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('graus', () => {
|
|
76
|
+
it('atira exceção se num for nulo', () => {
|
|
77
|
+
expect(() => graus()).toThrow();
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('atira exceção se num é NaN', () => {
|
|
81
|
+
expect(() => graus('egua')).toThrow();
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('calcula o ângulo', () => {
|
|
85
|
+
expect(graus(pi)).toBe(180);
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
describe('raizq', () => {
|
|
90
|
+
it('atira exceção se num for nulo', () => {
|
|
91
|
+
expect(() => raizq()).toThrow();
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('atira exceção se num é NaN', () => {
|
|
95
|
+
expect(() => raizq('egua')).toThrow();
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('calcula a raiz', () => {
|
|
99
|
+
expect(raizq(25)).toBeCloseTo(5, 2);
|
|
100
|
+
})
|
|
101
|
+
})
|