@designliquido/delegua 1.24.2 → 1.24.3

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.
@@ -6,366 +6,117 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Lexador = void 0;
7
7
  const browser_process_hrtime_1 = __importDefault(require("browser-process-hrtime"));
8
8
  const simbolo_1 = require("./simbolo");
9
+ const lexador_base_1 = require("./lexador-base");
9
10
  const palavras_reservadas_1 = require("./palavras-reservadas");
10
11
  const delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua"));
11
- /**
12
- * O Lexador é responsável por transformar o código em uma coleção de tokens de linguagem.
13
- * Cada token de linguagem é representado por um tipo, um lexema e informações da linha de código em que foi expresso.
14
- * Também é responsável por mapear as palavras reservadas da linguagem, que não podem ser usadas por outras
15
- * estruturas, tais como nomes de variáveis, funções, literais, classes e assim por diante.
16
- */
17
- class Lexador {
12
+ const tokensSimples = {
13
+ '@': delegua_1.default.ARROBA,
14
+ '[': delegua_1.default.COLCHETE_ESQUERDO,
15
+ ']': delegua_1.default.COLCHETE_DIREITO,
16
+ '(': delegua_1.default.PARENTESE_ESQUERDO,
17
+ ')': delegua_1.default.PARENTESE_DIREITO,
18
+ '{': delegua_1.default.CHAVE_ESQUERDA,
19
+ '}': delegua_1.default.CHAVE_DIREITA,
20
+ ',': delegua_1.default.VIRGULA,
21
+ ':': delegua_1.default.DOIS_PONTOS,
22
+ // Ponto-e-vírgula é opcional em Delégua, mas em alguns casos pode ser
23
+ // necessário. Por exemplo, declaração de `para` sem inicializador.
24
+ ';': delegua_1.default.PONTO_E_VIRGULA,
25
+ '^': delegua_1.default.CIRCUMFLEXO,
26
+ '~': delegua_1.default.BIT_NOT,
27
+ '&': delegua_1.default.BIT_AND
28
+ };
29
+ /*
30
+ * O Lexador é responsável por transformar o código em uma coleção de tokens de linguagem.
31
+ * Cada token de linguagem é representado por um tipo, um lexema e informações da linha de código em que foi expresso.
32
+ * Também é responsável por mapear as palavras reservadas da linguagem, que não podem ser usadas por outras
33
+ * estruturas, tais como nomes de variáveis, funções, literais, classes e assim por diante.
34
+ */
35
+ class Lexador extends lexador_base_1.LexadorBase {
18
36
  constructor(performance = false) {
19
- this.codigo = [];
37
+ super();
38
+ this.regexAlfabeto = /[a-zA-Z_áàâãéèêíïóôõöúçñÁÀÂÃÉÈÊÍÏÓÔÕÖÚÇÑ]/;
39
+ this.regexEmoji = /\p{Extended_Pictographic}(?:\uFE0F|\u200D\p{Extended_Pictographic})*/u;
20
40
  this.performance = performance;
21
- this.simbolos = [];
22
- this.erros = [];
23
- this.hashArquivo = -1;
24
- this.inicioSimbolo = 0;
25
- this.atual = 0;
26
- this.linha = 0;
27
- }
28
- eDigito(caractere) {
29
- return caractere >= '0' && caractere <= '9';
30
- }
31
- eAlfabeto(caractere) {
32
- const acentuacoes = [
33
- 'á',
34
- 'Á',
35
- 'ã',
36
- 'Ã',
37
- 'â',
38
- 'Â',
39
- 'à',
40
- 'À',
41
- 'é',
42
- 'É',
43
- 'ê',
44
- 'Ê',
45
- 'í',
46
- 'Í',
47
- 'ó',
48
- 'Ó',
49
- 'õ',
50
- 'Õ',
51
- 'ô',
52
- 'Ô',
53
- 'ú',
54
- 'Ú',
55
- 'ç',
56
- 'Ç',
57
- '_',
58
- ];
59
- return ((caractere >= 'a' && caractere <= 'z') ||
60
- (caractere >= 'A' && caractere <= 'Z') ||
61
- acentuacoes.includes(caractere));
62
- }
63
- eAlfabetoOuDigito(caractere) {
64
- return this.eDigito(caractere) || this.eAlfabeto(caractere);
65
41
  }
66
- eHexDigito(caractere) {
67
- return ((caractere >= '0' && caractere <= '9') ||
68
- (caractere >= 'a' && caractere <= 'f') ||
69
- (caractere >= 'A' && caractere <= 'F'));
42
+ eAlfabeto(c) {
43
+ return this.regexAlfabeto.test(c);
70
44
  }
71
- eBinarioDigito(caractere) {
72
- return caractere === '0' || caractere === '1';
73
- }
74
- eOctalDigito(caractere) {
75
- return caractere >= '0' && caractere <= '7';
76
- }
77
- eFinalDaLinha() {
78
- if (this.codigo.length === this.linha) {
79
- return true;
80
- }
81
- return this.atual >= this.codigo[this.linha].length;
82
- }
83
- /**
84
- * Indica se o código está na última linha.
85
- * @returns Verdadeiro se contador de linhas está na última linha.
86
- * Falso caso contrário.
87
- */
88
- eUltimaLinha() {
89
- return this.linha >= this.codigo.length - 1;
90
- }
91
- eFinalDoCodigo() {
92
- return this.eUltimaLinha() && this.codigo[this.codigo.length - 1].length <= this.atual;
45
+ eEmoji(c) {
46
+ return this.regexEmoji.test(c);
93
47
  }
94
48
  avancar() {
95
- const linha = this.codigo[this.linha];
96
- const codePoint = linha.codePointAt(this.atual);
49
+ const codePoint = this.codigo[this.linha].codePointAt(this.atual);
97
50
  this.atual += codePoint && codePoint > 0xffff ? 2 : 1;
98
51
  if (this.eFinalDaLinha() && !this.eUltimaLinha()) {
99
52
  this.linha++;
100
53
  this.atual = 0;
101
54
  }
102
55
  }
103
- adicionarSimbolo(tipo, literal = null) {
104
- const texto = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
105
- const lexema = literal || texto;
106
- const comprimentoLexema = typeof lexema === 'string' ? lexema.length : 0;
107
- const comprimento = Math.max(comprimentoLexema, texto.length) || 1;
108
- const colunaInicio = this.inicioSimbolo + 1;
109
- const colunaFim = this.inicioSimbolo + comprimento;
110
- this.simbolos.push(new simbolo_1.Simbolo(tipo, lexema, literal, this.linha + 1, this.hashArquivo, colunaInicio, colunaFim));
111
- }
112
56
  simboloAtual() {
113
57
  if (this.eFinalDaLinha())
114
58
  return '\0';
115
- const linha = this.codigo[this.linha];
116
- const codePoint = linha.codePointAt(this.atual);
117
- if (codePoint === undefined) {
118
- return '\0';
119
- }
120
- return String.fromCodePoint(codePoint);
121
- }
122
- comentarioMultilinha() {
123
- let conteudo = '';
124
- while (!this.eFinalDoCodigo()) {
125
- this.avancar();
126
- conteudo += this.codigo[this.linha].charAt(this.atual);
127
- if (this.simboloAtual() === '*' && this.proximoSimbolo() === '/') {
128
- const linhas = conteudo.split('\0');
129
- for (let linha of linhas) {
130
- this.adicionarSimbolo(delegua_1.default.LINHA_COMENTARIO, linha.trim());
131
- }
132
- // Remove o asterisco da última linha
133
- let lexemaUltimaLinha = this.simbolos[this.simbolos.length - 1].lexema;
134
- lexemaUltimaLinha = lexemaUltimaLinha.substring(0, lexemaUltimaLinha.length - 1);
135
- this.simbolos[this.simbolos.length - 1].lexema = lexemaUltimaLinha;
136
- this.simbolos[this.simbolos.length - 1].literal = lexemaUltimaLinha;
137
- this.avancar();
138
- this.avancar();
139
- break;
140
- }
141
- }
142
- }
143
- /**
144
- * Lê um comentário documentário (iniciado com `/**`), agregando o conteúdo
145
- * em um único token DOCUMENTARIO. Linhas com `*` inicial (convenção JSDoc)
146
- * têm o asterisco removido.
147
- */
148
- comentarioDocumentario() {
149
- // Cursor está no primeiro '*' de '/**'. Avança para pular o segundo '*'.
150
- this.avancar();
151
- let conteudo = '';
152
- while (!this.eFinalDoCodigo()) {
153
- this.avancar();
154
- if (this.simboloAtual() === '*' && this.proximoSimbolo() === '/') {
155
- // Fecha o documentário sem adicionar o '*' ao conteúdo.
156
- this.avancar(); // pula '*'
157
- this.avancar(); // pula '/'
158
- break;
159
- }
160
- conteudo += this.codigo[this.linha].charAt(this.atual);
161
- }
162
- // Divide por '\0' (separador de linha), remove asteriscos iniciais e filtra vazios.
163
- const conteudoLimpo = conteudo
164
- .split('\0')
165
- .map((l) => {
166
- const trimmed = l.trim();
167
- return trimmed.startsWith('*') ? trimmed.substring(1).trim() : trimmed;
168
- })
169
- .filter((l) => l.length > 0)
170
- .join('\n');
171
- this.adicionarSimbolo(delegua_1.default.DOCUMENTARIO, conteudoLimpo || '');
172
- }
173
- comentarioUmaLinha() {
174
- this.avancar();
175
- const linhaAtual = this.linha;
176
- let ultimoAtual = this.atual;
177
- while (linhaAtual === this.linha && !this.eFinalDoCodigo()) {
178
- ultimoAtual = this.atual;
179
- this.avancar();
180
- }
181
- const conteudo = this.codigo[linhaAtual].substring(this.inicioSimbolo + 2, ultimoAtual);
182
- this.adicionarSimbolo(delegua_1.default.COMENTARIO, conteudo.trim());
59
+ const codePoint = this.codigo[this.linha].codePointAt(this.atual);
60
+ return codePoint === undefined ? '\0' : String.fromCodePoint(codePoint);
183
61
  }
184
62
  proximoSimbolo() {
185
- const linha = this.codigo[this.linha];
186
- const atual = this.simboloAtual();
187
- const incremento = atual.length;
188
- const codePoint = linha.codePointAt(this.atual + incremento);
189
- if (codePoint === undefined) {
190
- return '\0';
191
- }
192
- return String.fromCodePoint(codePoint);
63
+ const atualStr = this.simboloAtual();
64
+ const codePoint = this.codigo[this.linha].codePointAt(this.atual + atualStr.length);
65
+ return codePoint === undefined ? '\0' : String.fromCodePoint(codePoint);
193
66
  }
194
67
  simboloAnterior() {
195
68
  const linha = this.codigo[this.linha];
196
- const indiceAnterior = this.atual -
197
- (linha.codePointAt(this.atual - 2) > 0xffff ? 2 : 1);
69
+ const indiceAnterior = this.atual - (linha.codePointAt(this.atual - 2) > 0xffff ? 2 : 1);
198
70
  const codePoint = linha.codePointAt(indiceAnterior);
199
- if (codePoint === undefined) {
200
- return '\0';
201
- }
71
+ return codePoint === undefined ? '\0' : String.fromCodePoint(codePoint);
202
72
  }
203
- analisarTexto(delimitador = '"') {
204
- let valor = '';
205
- this.avancar();
206
- while (!this.eFinalDoCodigo()) {
207
- const caractere = this.simboloAtual();
208
- if (caractere === delimitador) {
209
- this.avancar();
210
- this.adicionarSimbolo(delegua_1.default.TEXTO, valor);
211
- const ultimoSimbolo = this.simbolos[this.simbolos.length - 1];
212
- ultimoSimbolo.delimitadorTexto = delimitador;
213
- return;
214
- }
215
- if (caractere === '\0' && this.eUltimaLinha()) {
216
- this.erros.push({
217
- linha: this.linha + 1,
218
- caractere: this.simboloAnterior(),
219
- mensagem: 'Texto não finalizado.',
220
- });
221
- return;
222
- }
223
- if (caractere === '\0') {
224
- valor += '\n';
225
- this.avancar();
226
- continue;
227
- }
228
- if (caractere === '\\') {
229
- this.avancar();
230
- const proximoCaractere = this.simboloAtual();
231
- switch (proximoCaractere) {
232
- case 'n':
233
- valor += '\n';
234
- break;
235
- case 't':
236
- valor += '\t';
237
- break;
238
- case 'r':
239
- valor += '\r';
240
- break;
241
- case 'b':
242
- valor += '\b';
243
- break;
244
- case "'":
245
- valor += "'";
246
- break;
247
- case '"':
248
- valor += '"';
249
- break;
250
- case '\\':
251
- valor += '\\';
252
- break;
253
- case 'e':
254
- valor += '\x1B';
255
- break;
256
- case 'x': {
257
- let hex = '';
258
- for (let i = 0; i < 2; i++) {
259
- const c = this.proximoSimbolo();
260
- if (/[0-9a-fA-F]/.test(c)) {
261
- this.avancar();
262
- hex += c;
263
- }
264
- else {
265
- break;
266
- }
267
- }
268
- valor +=
269
- hex.length === 2 ? String.fromCharCode(parseInt(hex, 16)) : '\\x' + hex;
270
- break;
271
- }
272
- case '\0':
273
- break; // barra invertida no fim de linha: ignora e continua na próxima linha
274
- default:
275
- valor += '\\' + proximoCaractere;
276
- break;
277
- }
278
- }
279
- else {
280
- valor += caractere;
281
- }
282
- this.avancar();
283
- }
284
- this.erros.push({
285
- linha: this.linha + 1,
286
- caractere: this.simboloAnterior(),
287
- mensagem: 'Texto não finalizado.',
288
- });
289
- }
290
- analisarHexadecimal() {
291
- this.avancar(); // Pula '0'
292
- this.avancar(); // Pula 'x' ou 'X'
293
- while (this.eHexDigito(this.simboloAtual())) {
294
- this.avancar();
295
- }
296
- const hexString = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
297
- try {
298
- const bigintValue = BigInt(hexString);
299
- this.adicionarSimbolo(delegua_1.default.NUMERO, bigintValue);
300
- }
301
- catch (e) {
302
- this.erros.push({
303
- linha: this.linha + 1,
304
- caractere: this.simboloAnterior(),
305
- mensagem: `Literal hexadecimal inválido: ${hexString}`,
306
- });
307
- }
73
+ adicionarSimbolo(tipo, literal = null) {
74
+ const texto = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
75
+ const lexema = literal !== null ? literal : texto;
76
+ const comprimento = Math.max(typeof lexema === 'string' ? lexema.length : 0, texto.length) || 1;
77
+ this.simbolos.push(new simbolo_1.Simbolo(tipo, lexema, literal, this.linha + 1, this.hashArquivo, this.inicioSimbolo + 1, this.inicioSimbolo + comprimento));
308
78
  }
309
- analisarBinario() {
310
- this.avancar(); // Pula '0'
311
- this.avancar(); // Pula 'b' ou 'B'
312
- while (this.eBinarioDigito(this.simboloAtual())) {
313
- this.avancar();
314
- }
315
- const binaryString = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
316
- try {
317
- const bigintValue = BigInt(binaryString);
318
- this.adicionarSimbolo(delegua_1.default.NUMERO, bigintValue);
319
- }
320
- catch (e) {
321
- this.erros.push({
322
- linha: this.linha + 1,
323
- caractere: this.simboloAnterior(),
324
- mensagem: `Literal binário inválido: ${binaryString}`,
325
- });
326
- }
79
+ verificarEAvancar(esperado) {
80
+ if (this.eFinalDaLinha() || this.simboloAtual() !== esperado)
81
+ return false;
82
+ this.avancar();
83
+ return true;
327
84
  }
328
- analisarOctal() {
85
+ analisarBaseNumerica(validadorDigito, tipoErro) {
329
86
  this.avancar(); // Pula '0'
330
- this.avancar(); // Pula 'o' ou 'O'
331
- while (this.eOctalDigito(this.simboloAtual())) {
87
+ this.avancar(); // Pula 'x', 'b' ou 'o'
88
+ while (validadorDigito.call(this, this.simboloAtual())) {
332
89
  this.avancar();
333
90
  }
334
- const octalString = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
91
+ const texto = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
335
92
  try {
336
- const bigintValue = BigInt(octalString);
337
- this.adicionarSimbolo(delegua_1.default.NUMERO, bigintValue);
93
+ this.adicionarSimbolo(delegua_1.default.NUMERO, BigInt(texto));
338
94
  }
339
95
  catch (e) {
340
96
  this.erros.push({
341
97
  linha: this.linha + 1,
342
98
  caractere: this.simboloAnterior(),
343
- mensagem: `Literal octal inválido: ${octalString}`,
99
+ mensagem: `Literal ${tipoErro} inválido: ${texto}`
344
100
  });
345
101
  }
346
102
  }
347
103
  analisarNumero() {
348
- // Verifica se é um literal especial (hexadecimal, binário ou octal)
349
104
  if (this.simboloAtual() === '0') {
350
- const proximoChar = this.proximoSimbolo();
351
- if (proximoChar === 'x' || proximoChar === 'X') {
352
- this.analisarHexadecimal();
353
- return;
105
+ const prox = this.proximoSimbolo().toLowerCase();
106
+ if (prox === 'x') {
107
+ return this.analisarBaseNumerica(this.eHexDigito, 'hexadecimal');
354
108
  }
355
- else if (proximoChar === 'b' || proximoChar === 'B') {
356
- this.analisarBinario();
357
- return;
109
+ if (prox === 'b') {
110
+ return this.analisarBaseNumerica(this.eBinarioDigito, 'binário');
358
111
  }
359
- else if (proximoChar === 'o' || proximoChar === 'O') {
360
- this.analisarOctal();
361
- return;
112
+ if (prox === 'o') {
113
+ return this.analisarBaseNumerica(this.eOctalDigito, 'octal');
362
114
  }
363
115
  }
364
- // Análise de número decimal normal
365
116
  while (this.eDigito(this.simboloAtual())) {
366
117
  this.avancar();
367
118
  }
368
- if (this.simboloAtual() == '.' && this.eDigito(this.proximoSimbolo())) {
119
+ if (this.simboloAtual() === '.' && this.eDigito(this.proximoSimbolo())) {
369
120
  this.avancar();
370
121
  while (this.eDigito(this.simboloAtual())) {
371
122
  this.avancar();
@@ -374,155 +125,222 @@ class Lexador {
374
125
  const numeroCompleto = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
375
126
  this.adicionarSimbolo(delegua_1.default.NUMERO, parseFloat(numeroCompleto));
376
127
  }
128
+ analisarTexto(delimitador = '"') {
129
+ let valor = '';
130
+ this.avancar();
131
+ while (!this.eFinalDoCodigo()) {
132
+ const c = this.simboloAtual();
133
+ if (c === delimitador) {
134
+ this.avancar();
135
+ this.adicionarSimbolo(delegua_1.default.TEXTO, valor);
136
+ this.simbolos[this.simbolos.length - 1].delimitadorTexto = delimitador;
137
+ return;
138
+ }
139
+ if (c === '\0' && this.eUltimaLinha())
140
+ break;
141
+ if (c === '\0') {
142
+ valor += '\n';
143
+ this.avancar();
144
+ continue;
145
+ }
146
+ if (c === '\\') {
147
+ this.avancar();
148
+ const prox = this.simboloAtual();
149
+ const escapes = {
150
+ 'n': '\n',
151
+ 't': '\t',
152
+ 'r': '\r',
153
+ 'b': '\b',
154
+ "'": "'",
155
+ '"': '"',
156
+ '\\': '\\',
157
+ 'e': '\x1B'
158
+ };
159
+ if (escapes[prox]) {
160
+ valor += escapes[prox];
161
+ }
162
+ else if (prox === 'x') {
163
+ let hex = '';
164
+ for (let i = 0; i < 2; i++) {
165
+ const h = this.proximoSimbolo();
166
+ if (/[0-9a-fA-F]/.test(h)) {
167
+ this.avancar();
168
+ hex += h;
169
+ }
170
+ else
171
+ break;
172
+ }
173
+ valor += hex.length === 2
174
+ ? String.fromCharCode(parseInt(hex, 16))
175
+ : '\\x' + hex;
176
+ }
177
+ else if (prox !== '\0') {
178
+ valor += '\\' + prox;
179
+ }
180
+ }
181
+ else {
182
+ valor += c;
183
+ }
184
+ this.avancar();
185
+ }
186
+ this.erros.push({
187
+ linha: this.linha + 1,
188
+ caractere: this.simboloAnterior(),
189
+ mensagem: 'Texto não finalizado.'
190
+ });
191
+ }
377
192
  identificarPalavraChave() {
378
193
  while (this.eAlfabetoOuDigito(this.simboloAtual())) {
379
194
  this.avancar();
380
195
  }
381
196
  const codigo = this.codigo[this.linha].substring(this.inicioSimbolo, this.atual);
382
- const tipo = codigo in palavras_reservadas_1.palavrasReservadasDelegua
197
+ this.adicionarSimbolo(codigo in palavras_reservadas_1.palavrasReservadasDelegua
383
198
  ? palavras_reservadas_1.palavrasReservadasDelegua[codigo]
384
- : delegua_1.default.IDENTIFICADOR;
385
- this.adicionarSimbolo(tipo);
386
- }
387
- eEmoji(caractere) {
388
- const emojiRegex = /\p{Extended_Pictographic}(?:\uFE0F|\u200D\p{Extended_Pictographic})*/u;
389
- return emojiRegex.test(caractere);
199
+ : delegua_1.default.IDENTIFICADOR);
390
200
  }
391
201
  analisarEmoji() {
392
- const simboloAtual = this.simboloAtual();
393
202
  this.erros.push({
394
203
  linha: this.linha + 1,
395
- caractere: simboloAtual,
396
- mensagem: 'Emojis devem estar envoltos por aspas.',
204
+ caractere: this.simboloAtual(),
205
+ mensagem: 'Emojis devem estar envoltos por aspas.'
397
206
  });
398
207
  this.avancar();
399
208
  }
400
- analisarToken() {
401
- const caractere = this.simboloAtual();
402
- switch (caractere) {
403
- case '@':
404
- this.adicionarSimbolo(delegua_1.default.ARROBA, '@');
405
- this.avancar();
406
- break;
407
- case '[':
408
- this.adicionarSimbolo(delegua_1.default.COLCHETE_ESQUERDO, '[');
409
- this.avancar();
410
- break;
411
- case ']':
412
- this.adicionarSimbolo(delegua_1.default.COLCHETE_DIREITO, ']');
413
- this.avancar();
414
- break;
415
- case '(':
416
- this.adicionarSimbolo(delegua_1.default.PARENTESE_ESQUERDO, '(');
417
- this.avancar();
418
- break;
419
- case ')':
420
- this.adicionarSimbolo(delegua_1.default.PARENTESE_DIREITO, ')');
421
- this.avancar();
422
- break;
423
- case '{':
424
- this.adicionarSimbolo(delegua_1.default.CHAVE_ESQUERDA, '{');
425
- this.avancar();
426
- break;
427
- case '}':
428
- this.adicionarSimbolo(delegua_1.default.CHAVE_DIREITA, '}');
429
- this.avancar();
209
+ comentarioUmaLinha() {
210
+ const linhaAtual = this.linha;
211
+ let ultimoAtual = this.atual;
212
+ while (linhaAtual === this.linha && !this.eFinalDoCodigo()) {
213
+ ultimoAtual = this.atual;
214
+ this.avancar();
215
+ }
216
+ const conteudo = this.codigo[linhaAtual].substring(this.inicioSimbolo + 2, ultimoAtual);
217
+ this.adicionarSimbolo(delegua_1.default.COMENTARIO, conteudo.trim());
218
+ }
219
+ comentarioMultilinha() {
220
+ let conteudo = '';
221
+ while (!this.eFinalDoCodigo()) {
222
+ if (this.simboloAtual() === '*' && this.proximoSimbolo() === '/') {
223
+ this.avancar(); // pula o '*'
224
+ this.avancar(); // pula o '/'
225
+ conteudo
226
+ .split('\0')
227
+ .forEach(l => this.adicionarSimbolo(delegua_1.default.LINHA_COMENTARIO, l.trim()));
430
228
  break;
431
- case ',':
432
- this.adicionarSimbolo(delegua_1.default.VIRGULA, ',');
433
- this.avancar();
229
+ }
230
+ conteudo += this.simboloAtual();
231
+ this.avancar();
232
+ }
233
+ }
234
+ /**
235
+ * Lê um comentário documentário (iniciado com `/**`), agregando o conteúdo
236
+ * em um único token DOCUMENTARIO. Linhas com `*` inicial (convenção JSDoc)
237
+ * têm o asterisco removido.
238
+ */
239
+ comentarioDocumentario() {
240
+ let conteudo = '';
241
+ while (!this.eFinalDoCodigo()) {
242
+ if (this.simboloAtual() === '*' && this.proximoSimbolo() === '/') {
243
+ this.avancar(); // pula '*'
244
+ this.avancar(); // pula '/'
434
245
  break;
246
+ }
247
+ conteudo += this.simboloAtual();
248
+ this.avancar();
249
+ }
250
+ const conteudoLimpo = conteudo
251
+ .split('\0')
252
+ .map(l => l.trim().startsWith('*')
253
+ ? l.trim().substring(1).trim()
254
+ : l.trim())
255
+ .filter(l => l.length > 0)
256
+ .join('\n');
257
+ this.adicionarSimbolo(delegua_1.default.DOCUMENTARIO, conteudoLimpo || '');
258
+ }
259
+ analisarToken() {
260
+ const c = this.simboloAtual();
261
+ if (tokensSimples[c]) {
262
+ this.adicionarSimbolo(tokensSimples[c], c);
263
+ this.avancar();
264
+ return;
265
+ }
266
+ if (c === ' ' || c === '\0' || c === '\r' || c === '\t') {
267
+ this.avancar();
268
+ return;
269
+ }
270
+ this.inicioSimbolo = this.atual;
271
+ if (c === '"' || c === "'") {
272
+ this.analisarTexto(c);
273
+ return;
274
+ }
275
+ switch (c) {
435
276
  case '.':
436
- this.inicioSimbolo = this.atual;
437
277
  this.avancar();
438
- if (this.simboloAtual() === '.') {
439
- this.avancar();
440
- if (this.simboloAtual() !== '.') {
278
+ if (this.verificarEAvancar('.')) {
279
+ if (this.verificarEAvancar('.')) {
280
+ this.adicionarSimbolo(delegua_1.default.RETICENCIAS, '...');
281
+ }
282
+ else {
441
283
  this.erros.push({
442
284
  linha: this.linha + 1,
443
285
  caractere: this.simboloAtual(),
444
- mensagem: 'Esperado ou apenas um ponto, ou três pontos em sequência.',
286
+ mensagem: 'Esperado ou apenas um ponto, ou três pontos em sequência.'
445
287
  });
446
288
  this.adicionarSimbolo(delegua_1.default.PONTO, '.');
447
289
  }
448
- else {
449
- this.avancar();
450
- this.adicionarSimbolo(delegua_1.default.RETICENCIAS, '...');
451
- }
452
290
  }
453
291
  else {
454
292
  this.adicionarSimbolo(delegua_1.default.PONTO, '.');
455
293
  }
456
294
  break;
457
295
  case '-':
458
- this.inicioSimbolo = this.atual;
459
296
  this.avancar();
460
- if (this.simboloAtual() === '=') {
297
+ if (this.verificarEAvancar('=')) {
461
298
  this.adicionarSimbolo(delegua_1.default.MENOS_IGUAL, '-=');
462
- this.avancar();
463
299
  }
464
- else if (this.simboloAtual() === '-') {
300
+ else if (this.verificarEAvancar('-')) {
465
301
  this.adicionarSimbolo(delegua_1.default.DECREMENTAR, '--');
466
- this.avancar();
467
302
  }
468
303
  else {
469
304
  this.adicionarSimbolo(delegua_1.default.SUBTRACAO);
470
305
  }
471
306
  break;
472
307
  case '+':
473
- this.inicioSimbolo = this.atual;
474
308
  this.avancar();
475
- if (this.simboloAtual() === '=') {
309
+ if (this.verificarEAvancar('=')) {
476
310
  this.adicionarSimbolo(delegua_1.default.MAIS_IGUAL, '+=');
477
- this.avancar();
478
311
  }
479
- else if (this.simboloAtual() === '+') {
312
+ else if (this.verificarEAvancar('+')) {
480
313
  this.adicionarSimbolo(delegua_1.default.INCREMENTAR, '++');
481
- this.avancar();
482
314
  }
483
315
  else {
484
316
  this.adicionarSimbolo(delegua_1.default.ADICAO);
485
317
  }
486
318
  break;
487
- case ':':
488
- this.adicionarSimbolo(delegua_1.default.DOIS_PONTOS);
489
- this.avancar();
490
- break;
491
319
  case '%':
492
- this.inicioSimbolo = this.atual;
493
320
  this.avancar();
494
- switch (this.simboloAtual()) {
495
- case '=':
496
- this.avancar();
497
- this.adicionarSimbolo(delegua_1.default.MODULO_IGUAL, '%=');
498
- break;
499
- default:
500
- this.adicionarSimbolo(delegua_1.default.MODULO);
501
- break;
321
+ if (this.verificarEAvancar('=')) {
322
+ this.adicionarSimbolo(delegua_1.default.MODULO_IGUAL, '%=');
323
+ }
324
+ else {
325
+ this.adicionarSimbolo(delegua_1.default.MODULO);
502
326
  }
503
327
  break;
504
328
  case '*':
505
- this.inicioSimbolo = this.atual;
506
329
  this.avancar();
507
- switch (this.simboloAtual()) {
508
- case '*':
509
- this.avancar();
510
- this.adicionarSimbolo(delegua_1.default.EXPONENCIACAO, '**');
511
- break;
512
- case '=':
513
- this.avancar();
514
- this.adicionarSimbolo(delegua_1.default.MULTIPLICACAO_IGUAL, '*=');
515
- break;
516
- default:
517
- this.adicionarSimbolo(delegua_1.default.MULTIPLICACAO);
518
- break;
330
+ if (this.verificarEAvancar('*')) {
331
+ this.adicionarSimbolo(delegua_1.default.EXPONENCIACAO, '**');
332
+ }
333
+ else if (this.verificarEAvancar('=')) {
334
+ this.adicionarSimbolo(delegua_1.default.MULTIPLICACAO_IGUAL, '*=');
335
+ }
336
+ else {
337
+ this.adicionarSimbolo(delegua_1.default.MULTIPLICACAO);
519
338
  }
520
339
  break;
521
340
  case '!':
522
341
  this.avancar();
523
- if (this.simboloAtual() === '=') {
342
+ if (this.verificarEAvancar('=')) {
524
343
  this.adicionarSimbolo(delegua_1.default.DIFERENTE, '!=');
525
- this.avancar();
526
344
  }
527
345
  else {
528
346
  this.adicionarSimbolo(delegua_1.default.NEGACAO);
@@ -530,49 +348,32 @@ class Lexador {
530
348
  break;
531
349
  case '=':
532
350
  this.avancar();
533
- if (this.simboloAtual() === '=') {
351
+ if (this.verificarEAvancar('=')) {
534
352
  this.adicionarSimbolo(delegua_1.default.IGUAL_IGUAL, '==');
535
- this.avancar();
536
353
  }
537
354
  else {
538
355
  this.adicionarSimbolo(delegua_1.default.IGUAL);
539
356
  }
540
357
  break;
541
- case '&':
542
- this.adicionarSimbolo(delegua_1.default.BIT_AND);
543
- this.avancar();
544
- break;
545
- case '~':
546
- this.adicionarSimbolo(delegua_1.default.BIT_NOT);
547
- this.avancar();
548
- break;
549
358
  case '|':
550
359
  this.avancar();
551
- if (this.simboloAtual() === '|') {
360
+ if (this.verificarEAvancar('|')) {
552
361
  this.adicionarSimbolo(delegua_1.default.EXPRESSAO_REGULAR, '||');
553
- this.avancar();
554
362
  }
555
363
  else {
556
364
  this.adicionarSimbolo(delegua_1.default.BIT_OR);
557
365
  }
558
366
  break;
559
- case '^':
560
- this.adicionarSimbolo(delegua_1.default.CIRCUMFLEXO);
561
- this.avancar();
562
- break;
563
367
  case '<':
564
368
  this.avancar();
565
- if (this.simboloAtual() === '=') {
369
+ if (this.verificarEAvancar('=')) {
566
370
  this.adicionarSimbolo(delegua_1.default.MENOR_IGUAL, '<=');
567
- this.avancar();
568
371
  }
569
- else if (this.simboloAtual() === '<') {
372
+ else if (this.verificarEAvancar('<')) {
570
373
  this.adicionarSimbolo(delegua_1.default.MENOR_MENOR, '<<');
571
- this.avancar();
572
374
  }
573
- else if (this.simboloAtual() === '-') {
375
+ else if (this.verificarEAvancar('-')) {
574
376
  this.adicionarSimbolo(delegua_1.default.SETA_ESQUERDA, '<-');
575
- this.avancar();
576
377
  }
577
378
  else {
578
379
  this.adicionarSimbolo(delegua_1.default.MENOR);
@@ -580,13 +381,11 @@ class Lexador {
580
381
  break;
581
382
  case '>':
582
383
  this.avancar();
583
- if (this.simboloAtual() === '=') {
384
+ if (this.verificarEAvancar('=')) {
584
385
  this.adicionarSimbolo(delegua_1.default.MAIOR_IGUAL, '>=');
585
- this.avancar();
586
386
  }
587
- else if (this.simboloAtual() === '>') {
387
+ else if (this.verificarEAvancar('>')) {
588
388
  this.adicionarSimbolo(delegua_1.default.MAIOR_MAIOR, '>>');
589
- this.avancar();
590
389
  }
591
390
  else {
592
391
  this.adicionarSimbolo(delegua_1.default.MAIOR);
@@ -594,81 +393,57 @@ class Lexador {
594
393
  break;
595
394
  case '/':
596
395
  this.avancar();
597
- switch (this.simboloAtual()) {
598
- case '/':
599
- this.comentarioUmaLinha();
600
- break;
601
- case '*':
602
- if (this.proximoSimbolo() === '*') {
603
- this.comentarioDocumentario();
604
- }
605
- else {
606
- this.comentarioMultilinha();
607
- }
608
- break;
609
- case '=':
610
- this.adicionarSimbolo(delegua_1.default.DIVISAO_IGUAL, '/=');
611
- this.avancar();
612
- break;
613
- default:
614
- this.adicionarSimbolo(delegua_1.default.DIVISAO);
615
- break;
396
+ if (this.verificarEAvancar('/')) {
397
+ this.comentarioUmaLinha();
398
+ }
399
+ else if (this.verificarEAvancar('*')) {
400
+ if (this.verificarEAvancar('*')) {
401
+ this.comentarioDocumentario();
402
+ }
403
+ else {
404
+ this.comentarioMultilinha();
405
+ }
406
+ }
407
+ else if (this.verificarEAvancar('=')) {
408
+ this.adicionarSimbolo(delegua_1.default.DIVISAO_IGUAL, '/=');
409
+ }
410
+ else {
411
+ this.adicionarSimbolo(delegua_1.default.DIVISAO);
616
412
  }
617
413
  break;
618
414
  case '\\':
619
- this.inicioSimbolo = this.atual;
620
415
  this.avancar();
621
- switch (this.simboloAtual()) {
622
- case '=':
623
- this.adicionarSimbolo(delegua_1.default.DIVISAO_INTEIRA_IGUAL, '\\=');
624
- this.avancar();
625
- break;
626
- default:
627
- this.adicionarSimbolo(delegua_1.default.DIVISAO_INTEIRA);
628
- break;
416
+ if (this.verificarEAvancar('=')) {
417
+ this.adicionarSimbolo(delegua_1.default.DIVISAO_INTEIRA_IGUAL, '\\=');
418
+ }
419
+ else {
420
+ this.adicionarSimbolo(delegua_1.default.DIVISAO_INTEIRA);
629
421
  }
630
422
  break;
631
423
  case '?':
632
424
  this.avancar();
633
- if (this.simboloAtual() === ':') {
425
+ if (this.verificarEAvancar(':')) {
634
426
  this.adicionarSimbolo(delegua_1.default.ELVIS, '?:');
635
- this.avancar();
636
427
  }
637
428
  else {
638
429
  this.adicionarSimbolo(delegua_1.default.INTERROGACAO);
639
430
  }
640
431
  break;
641
- // Esta sessão ignora espaços em branco (ou similares) na tokenização.
642
- case ' ':
643
- case '\0':
644
- case '\r':
645
- case '\t':
646
- this.avancar();
647
- break;
648
- // Ponto-e-vírgula é opcional em Delégua, mas em alguns casos pode ser
649
- // necessário. Por exemplo, declaração de `para` sem inicializador.
650
- case ';':
651
- this.adicionarSimbolo(delegua_1.default.PONTO_E_VIRGULA);
652
- this.avancar();
653
- break;
654
- case '"':
655
- this.analisarTexto('"');
656
- break;
657
- case "'":
658
- this.analisarTexto("'");
659
- break;
660
432
  default:
661
- if (this.eDigito(caractere))
433
+ if (this.eDigito(c)) {
662
434
  this.analisarNumero();
663
- else if (this.eEmoji(caractere))
435
+ }
436
+ else if (this.eEmoji(c)) {
664
437
  this.analisarEmoji();
665
- else if (this.eAlfabeto(caractere))
438
+ }
439
+ else if (this.eAlfabeto(c)) {
666
440
  this.identificarPalavraChave();
441
+ }
667
442
  else {
668
443
  this.erros.push({
669
444
  linha: this.linha + 1,
670
- caractere: caractere,
671
- mensagem: 'Caractere inesperado.',
445
+ caractere: c,
446
+ mensagem: 'Caractere inesperado.'
672
447
  });
673
448
  this.avancar();
674
449
  }
@@ -681,16 +456,12 @@ class Lexador {
681
456
  this.inicioSimbolo = 0;
682
457
  this.atual = 0;
683
458
  this.linha = 0;
684
- this.codigo = codigo || [''];
685
- if (codigo.length === 0) {
686
- this.codigo = [''];
687
- }
459
+ this.codigo = codigo && codigo.length > 0 ? codigo : [''];
688
460
  this.hashArquivo = hashArquivo;
689
461
  for (let iterador = 0; iterador < this.codigo.length; iterador++) {
690
462
  this.codigo[iterador] += '\0';
691
463
  }
692
464
  while (!this.eFinalDoCodigo()) {
693
- this.inicioSimbolo = this.atual;
694
465
  this.analisarToken();
695
466
  }
696
467
  if (this.performance) {
@@ -700,7 +471,7 @@ class Lexador {
700
471
  }
701
472
  return {
702
473
  simbolos: this.simbolos,
703
- erros: this.erros,
474
+ erros: this.erros
704
475
  };
705
476
  }
706
477
  }