ether-code 0.1.5 → 0.1.7

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.
Files changed (44) hide show
  1. package/cli/ether.js +1 -1
  2. package/generators/css-generator.js +42 -55
  3. package/generators/graphql-generator.js +19 -22
  4. package/generators/html-generator.js +51 -182
  5. package/generators/js-generator.js +76 -157
  6. package/generators/node-generator.js +49 -93
  7. package/generators/php-generator.js +46 -68
  8. package/generators/python-generator.js +35 -54
  9. package/generators/react-generator.js +37 -47
  10. package/generators/ruby-generator.js +59 -119
  11. package/generators/sql-generator.js +42 -63
  12. package/generators/ts-generator.js +59 -133
  13. package/i18n/i18n-css.json +147 -147
  14. package/i18n/i18n-graphql.json +6 -6
  15. package/i18n/i18n-html.json +135 -135
  16. package/i18n/i18n-js.json +107 -107
  17. package/i18n/i18n-node.json +14 -14
  18. package/i18n/i18n-php.json +177 -177
  19. package/i18n/i18n-python.json +16 -16
  20. package/i18n/i18n-react.json +97 -97
  21. package/i18n/i18n-ruby.json +22 -22
  22. package/i18n/i18n-sql.json +153 -153
  23. package/i18n/i18n-ts.json +10 -10
  24. package/lexer/ether-lexer.js +175 -34
  25. package/lexer/tokens.js +6 -6
  26. package/package.json +1 -1
  27. package/parsers/ast-css.js +0 -545
  28. package/parsers/ast-graphql.js +0 -424
  29. package/parsers/ast-html.js +0 -886
  30. package/parsers/ast-js.js +0 -750
  31. package/parsers/ast-node.js +0 -2440
  32. package/parsers/ast-php.js +0 -957
  33. package/parsers/ast-react.js +0 -580
  34. package/parsers/ast-ruby.js +0 -895
  35. package/parsers/ast-ts.js +0 -1352
  36. package/parsers/css-parser.js +0 -1981
  37. package/parsers/graphql-parser.js +0 -2011
  38. package/parsers/html-parser.js +0 -1182
  39. package/parsers/js-parser.js +0 -2564
  40. package/parsers/node-parser.js +0 -2644
  41. package/parsers/php-parser.js +0 -3037
  42. package/parsers/react-parser.js +0 -1035
  43. package/parsers/ruby-parser.js +0 -2680
  44. package/parsers/ts-parser.js +0 -3881
@@ -1,2564 +0,0 @@
1
- const fs = require('fs')
2
- const AST = require('./ast-js')
3
-
4
- const KEYWORDS = new Set([
5
- 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'default', 'break',
6
- 'continue', 'return', 'throw', 'try', 'catch', 'finally', 'function',
7
- 'class', 'extends', 'new', 'this', 'super', 'import', 'export', 'from',
8
- 'as', 'const', 'let', 'var', 'async', 'await', 'yield', 'typeof',
9
- 'instanceof', 'in', 'of', 'delete', 'void', 'debugger', 'with', 'static',
10
- 'get', 'set', 'true', 'false', 'null', 'undefined', 'using'
11
- ])
12
-
13
- const OPERATORS = {
14
- '+': 'PLUS', '-': 'MINUS', '*': 'STAR', '/': 'SLASH', '%': 'PERCENT',
15
- '**': 'POWER', '++': 'INCREMENT', '--': 'DECREMENT',
16
- '=': 'ASSIGN', '+=': 'PLUS_ASSIGN', '-=': 'MINUS_ASSIGN',
17
- '*=': 'STAR_ASSIGN', '/=': 'SLASH_ASSIGN', '%=': 'PERCENT_ASSIGN',
18
- '**=': 'POWER_ASSIGN', '&&=': 'AND_ASSIGN', '||=': 'OR_ASSIGN',
19
- '??=': 'NULLISH_ASSIGN', '&=': 'BIT_AND_ASSIGN', '|=': 'BIT_OR_ASSIGN',
20
- '^=': 'BIT_XOR_ASSIGN', '<<=': 'LEFT_SHIFT_ASSIGN', '>>=': 'RIGHT_SHIFT_ASSIGN',
21
- '>>>=': 'UNSIGNED_RIGHT_SHIFT_ASSIGN',
22
- '==': 'EQUAL', '===': 'STRICT_EQUAL', '!=': 'NOT_EQUAL', '!==': 'STRICT_NOT_EQUAL',
23
- '<': 'LT', '>': 'GT', '<=': 'LTE', '>=': 'GTE',
24
- '&&': 'AND', '||': 'OR', '!': 'NOT', '??': 'NULLISH',
25
- '&': 'BIT_AND', '|': 'BIT_OR', '^': 'BIT_XOR', '~': 'BIT_NOT',
26
- '<<': 'LEFT_SHIFT', '>>': 'RIGHT_SHIFT', '>>>': 'UNSIGNED_RIGHT_SHIFT',
27
- '?': 'QUESTION', ':': 'COLON', '.': 'DOT', '?.': 'OPTIONAL_CHAIN',
28
- '...': 'SPREAD', '=>': 'ARROW', ',': 'COMMA', ';': 'SEMICOLON'
29
- }
30
-
31
- class JSLexer {
32
- constructor(source, i18n) {
33
- this.source = source
34
- this.i18n = i18n
35
- this.pos = 0
36
- this.line = 1
37
- this.column = 1
38
- this.tokens = []
39
- }
40
-
41
- peek(offset = 0) {
42
- return this.source[this.pos + offset] || ''
43
- }
44
-
45
- advance() {
46
- const char = this.source[this.pos]
47
- this.pos++
48
- if (char === '\n') {
49
- this.line++
50
- this.column = 1
51
- } else {
52
- this.column++
53
- }
54
- return char
55
- }
56
-
57
- skipWhitespace() {
58
- while (this.pos < this.source.length) {
59
- const char = this.peek()
60
- if (char === ' ' || char === '\t' || char === '\r') {
61
- this.advance()
62
- } else if (char === '\n') {
63
- this.advance()
64
- } else if (char === '/' && this.peek(1) === '/') {
65
- this.skipLineComment()
66
- } else if (char === '/' && this.peek(1) === '*') {
67
- this.skipBlockComment()
68
- } else if (char === '-' && this.peek(1) === '-' && this.peek(2) !== '-') {
69
- this.skipLineComment()
70
- } else if (char === '{' && this.peek(1) === '-') {
71
- this.skipEtherBlockComment()
72
- } else {
73
- break
74
- }
75
- }
76
- }
77
-
78
- skipLineComment() {
79
- while (this.pos < this.source.length && this.peek() !== '\n') {
80
- this.advance()
81
- }
82
- }
83
-
84
- skipBlockComment() {
85
- this.advance()
86
- this.advance()
87
- while (this.pos < this.source.length) {
88
- if (this.peek() === '*' && this.peek(1) === '/') {
89
- this.advance()
90
- this.advance()
91
- break
92
- }
93
- this.advance()
94
- }
95
- }
96
-
97
- skipEtherBlockComment() {
98
- this.advance()
99
- this.advance()
100
- while (this.pos < this.source.length) {
101
- if (this.peek() === '-' && this.peek(1) === '}') {
102
- this.advance()
103
- this.advance()
104
- break
105
- }
106
- this.advance()
107
- }
108
- }
109
-
110
- readString(quote) {
111
- let value = ''
112
- const loc = { line: this.line, column: this.column }
113
- this.advance()
114
- while (this.pos < this.source.length) {
115
- const char = this.peek()
116
- if (char === quote) {
117
- this.advance()
118
- break
119
- }
120
- if (char === '\\') {
121
- this.advance()
122
- const escaped = this.advance()
123
- switch (escaped) {
124
- case 'n': value += '\n'; break
125
- case 't': value += '\t'; break
126
- case 'r': value += '\r'; break
127
- case '\\': value += '\\'; break
128
- case "'": value += "'"; break
129
- case '"': value += '"'; break
130
- case '`': value += '`'; break
131
- case '0': value += '\0'; break
132
- default: value += escaped
133
- }
134
- } else {
135
- value += this.advance()
136
- }
137
- }
138
- return { type: 'STRING', value, quote, loc }
139
- }
140
-
141
- readTemplateLiteral() {
142
- const loc = { line: this.line, column: this.column }
143
- this.advance()
144
- let value = ''
145
- const quasis = []
146
- const expressions = []
147
-
148
- while (this.pos < this.source.length) {
149
- const char = this.peek()
150
- if (char === '`') {
151
- this.advance()
152
- quasis.push({ value, tail: true })
153
- break
154
- }
155
- if (char === '$' && this.peek(1) === '{') {
156
- quasis.push({ value, tail: false })
157
- value = ''
158
- this.advance()
159
- this.advance()
160
- let braceCount = 1
161
- let expr = ''
162
- while (this.pos < this.source.length && braceCount > 0) {
163
- const c = this.peek()
164
- if (c === '{') braceCount++
165
- if (c === '}') braceCount--
166
- if (braceCount > 0) expr += this.advance()
167
- else this.advance()
168
- }
169
- expressions.push(expr.trim())
170
- } else if (char === '\\') {
171
- this.advance()
172
- const escaped = this.advance()
173
- switch (escaped) {
174
- case 'n': value += '\n'; break
175
- case 't': value += '\t'; break
176
- default: value += escaped
177
- }
178
- } else {
179
- value += this.advance()
180
- }
181
- }
182
-
183
- return { type: 'TEMPLATE', quasis, expressions, loc }
184
- }
185
-
186
- readNumber() {
187
- const loc = { line: this.line, column: this.column }
188
- let value = ''
189
- let isFloat = false
190
- let isBigInt = false
191
-
192
- if (this.peek() === '0' && (this.peek(1) === 'x' || this.peek(1) === 'X')) {
193
- value += this.advance() + this.advance()
194
- while (/[0-9a-fA-F_]/.test(this.peek())) {
195
- if (this.peek() !== '_') value += this.advance()
196
- else this.advance()
197
- }
198
- } else if (this.peek() === '0' && (this.peek(1) === 'b' || this.peek(1) === 'B')) {
199
- value += this.advance() + this.advance()
200
- while (/[01_]/.test(this.peek())) {
201
- if (this.peek() !== '_') value += this.advance()
202
- else this.advance()
203
- }
204
- } else if (this.peek() === '0' && (this.peek(1) === 'o' || this.peek(1) === 'O')) {
205
- value += this.advance() + this.advance()
206
- while (/[0-7_]/.test(this.peek())) {
207
- if (this.peek() !== '_') value += this.advance()
208
- else this.advance()
209
- }
210
- } else {
211
- while (/[0-9_]/.test(this.peek())) {
212
- if (this.peek() !== '_') value += this.advance()
213
- else this.advance()
214
- }
215
- if (this.peek() === '.' && /[0-9]/.test(this.peek(1))) {
216
- isFloat = true
217
- value += this.advance()
218
- while (/[0-9_]/.test(this.peek())) {
219
- if (this.peek() !== '_') value += this.advance()
220
- else this.advance()
221
- }
222
- }
223
- if (this.peek() === 'e' || this.peek() === 'E') {
224
- isFloat = true
225
- value += this.advance()
226
- if (this.peek() === '+' || this.peek() === '-') {
227
- value += this.advance()
228
- }
229
- while (/[0-9_]/.test(this.peek())) {
230
- if (this.peek() !== '_') value += this.advance()
231
- else this.advance()
232
- }
233
- }
234
- }
235
-
236
- if (this.peek() === 'n') {
237
- isBigInt = true
238
- this.advance()
239
- }
240
-
241
- return { type: isBigInt ? 'BIGINT' : 'NUMBER', value, loc }
242
- }
243
-
244
- readWord() {
245
- const loc = { line: this.line, column: this.column }
246
- let word = ''
247
-
248
- while (this.pos < this.source.length) {
249
- const char = this.peek()
250
- if (/[a-zA-ZÀ-ÿА-яぁ-ゟァ-ヿ一-龯0-9_$]/.test(char)) {
251
- word += this.advance()
252
- } else {
253
- break
254
- }
255
- }
256
-
257
- const nextWords = this.peekMultiWord()
258
- if (nextWords) {
259
- const fullWord = word + ' ' + nextWords
260
- if (this.isMultiWordKeyword(fullWord)) {
261
- for (let i = 0; i < nextWords.length + 1; i++) {
262
- this.advance()
263
- }
264
- word = fullWord
265
- }
266
- }
267
-
268
- return { word, loc }
269
- }
270
-
271
- peekMultiWord() {
272
- let tempPos = this.pos
273
- while (tempPos < this.source.length && this.source[tempPos] === ' ') {
274
- tempPos++
275
- }
276
- let nextWord = ''
277
- while (tempPos < this.source.length && /[a-zA-ZÀ-ÿА-яぁ-ゟァ-ヿ一-龯0-9_$]/.test(this.source[tempPos])) {
278
- nextWord += this.source[tempPos]
279
- tempPos++
280
- }
281
- return nextWord || null
282
- }
283
-
284
- isMultiWordKeyword(text) {
285
- const patterns = [
286
- 'sinon si', 'else if', 'sino si', 'иначе если', '否则如果', 'そうでなければもし',
287
- 'tant que', 'while', 'mientras', 'пока', '当', 'ながら',
288
- 'faire tant que', 'do while', 'hacer mientras', 'делать пока', '做当', 'する間',
289
- 'pour de', 'for of', 'para de', 'для из', '为的', 'のために',
290
- 'pour dans', 'for in', 'para en', 'для в', '为在', 'の中で',
291
- 'type de', 'typeof', 'tipo de', 'тип', '类型', 'タイプ',
292
- 'instance de', 'instanceof', 'instancia de', 'экземпляр', '实例', 'インスタンス',
293
- 'fonction asynchrone', 'async function', 'función asíncrona', 'асинхронная функция', '异步函数', '非同期関数',
294
- 'fonction génératrice', 'generator function', 'función generadora', 'функция генератор', '生成器函数', 'ジェネレータ関数',
295
- 'variable globale', 'global variable', 'variable global', 'глобальная переменная', '全局变量', 'グローバル変数',
296
- 'grand entier', 'big integer', 'entero grande', 'большое целое', '大整数', '大きな整数'
297
- ]
298
- return patterns.includes(text.toLowerCase())
299
- }
300
-
301
- readRegExp() {
302
- const loc = { line: this.line, column: this.column }
303
- this.advance()
304
- let pattern = ''
305
- let inClass = false
306
-
307
- while (this.pos < this.source.length) {
308
- const char = this.peek()
309
- if (char === '\\') {
310
- pattern += this.advance() + this.advance()
311
- } else if (char === '[') {
312
- inClass = true
313
- pattern += this.advance()
314
- } else if (char === ']') {
315
- inClass = false
316
- pattern += this.advance()
317
- } else if (char === '/' && !inClass) {
318
- this.advance()
319
- break
320
- } else {
321
- pattern += this.advance()
322
- }
323
- }
324
-
325
- let flags = ''
326
- while (/[gimsuy]/.test(this.peek())) {
327
- flags += this.advance()
328
- }
329
-
330
- return { type: 'REGEXP', pattern, flags, loc }
331
- }
332
-
333
- tokenize() {
334
- while (this.pos < this.source.length) {
335
- this.skipWhitespace()
336
- if (this.pos >= this.source.length) break
337
-
338
- const loc = { line: this.line, column: this.column }
339
- const char = this.peek()
340
-
341
- if (char === '"' || char === "'") {
342
- this.tokens.push(this.readString(char))
343
- continue
344
- }
345
-
346
- if (char === '`') {
347
- this.tokens.push(this.readTemplateLiteral())
348
- continue
349
- }
350
-
351
- if (/[0-9]/.test(char) || (char === '.' && /[0-9]/.test(this.peek(1)))) {
352
- this.tokens.push(this.readNumber())
353
- continue
354
- }
355
-
356
- if (/[a-zA-ZÀ-ÿА-яぁ-ゟァ-ヿ一-龯_$]/.test(char)) {
357
- const { word, loc: wordLoc } = this.readWord()
358
- const tokenType = this.classifyWord(word)
359
- this.tokens.push({ type: tokenType, value: word, loc: wordLoc })
360
- continue
361
- }
362
-
363
- if (char === '#') {
364
- this.advance()
365
- const { word, loc: wordLoc } = this.readWord()
366
- this.tokens.push({ type: 'PRIVATE_ID', value: word, loc })
367
- continue
368
- }
369
-
370
- const threeChar = this.source.slice(this.pos, this.pos + 3)
371
- if (OPERATORS[threeChar]) {
372
- this.tokens.push({ type: OPERATORS[threeChar], value: threeChar, loc })
373
- this.advance(); this.advance(); this.advance()
374
- continue
375
- }
376
-
377
- const twoChar = this.source.slice(this.pos, this.pos + 2)
378
- if (OPERATORS[twoChar]) {
379
- this.tokens.push({ type: OPERATORS[twoChar], value: twoChar, loc })
380
- this.advance(); this.advance()
381
- continue
382
- }
383
-
384
- if (OPERATORS[char]) {
385
- this.tokens.push({ type: OPERATORS[char], value: char, loc })
386
- this.advance()
387
- continue
388
- }
389
-
390
- if (char === '(') {
391
- this.tokens.push({ type: 'LPAREN', loc })
392
- this.advance()
393
- continue
394
- }
395
- if (char === ')') {
396
- this.tokens.push({ type: 'RPAREN', loc })
397
- this.advance()
398
- continue
399
- }
400
- if (char === '{') {
401
- this.tokens.push({ type: 'LBRACE', loc })
402
- this.advance()
403
- continue
404
- }
405
- if (char === '}') {
406
- this.tokens.push({ type: 'RBRACE', loc })
407
- this.advance()
408
- continue
409
- }
410
- if (char === '[') {
411
- this.tokens.push({ type: 'LBRACKET', loc })
412
- this.advance()
413
- continue
414
- }
415
- if (char === ']') {
416
- this.tokens.push({ type: 'RBRACKET', loc })
417
- this.advance()
418
- continue
419
- }
420
-
421
- this.advance()
422
- }
423
-
424
- this.tokens.push({ type: 'EOF', loc: { line: this.line, column: this.column } })
425
- return this.tokens
426
- }
427
-
428
- classifyWord(word) {
429
- const lowerWord = word.toLowerCase()
430
-
431
- if (KEYWORDS.has(lowerWord)) return 'KEYWORD'
432
- if (this.isEtherKeyword(lowerWord)) return 'ETHER_KEYWORD'
433
-
434
- return 'IDENTIFIER'
435
- }
436
-
437
- isEtherKeyword(word) {
438
- const etherKeywords = this.getEtherKeywords()
439
- return etherKeywords.has(word.toLowerCase())
440
- }
441
-
442
- getEtherKeywords() {
443
- const keywords = new Set()
444
-
445
- const categories = [
446
- 'variables', 'conditions', 'boucles', 'fonctions', 'classes',
447
- 'gestionErreurs', 'operateursLogiques', 'valeursSpeciales'
448
- ]
449
-
450
- for (const cat of categories) {
451
- const items = this.i18n[cat]
452
- if (!items) continue
453
- for (const item of Object.values(items)) {
454
- if (typeof item === 'object') {
455
- for (const translation of Object.values(item)) {
456
- if (typeof translation === 'string') {
457
- keywords.add(translation.toLowerCase())
458
- }
459
- }
460
- }
461
- }
462
- }
463
-
464
- return keywords
465
- }
466
- }
467
-
468
- class JSParser {
469
- constructor(i18nPath = null) {
470
- this.i18n = {}
471
- this.tokens = []
472
- this.pos = 0
473
-
474
- if (i18nPath) {
475
- this.loadI18n(i18nPath)
476
- }
477
- }
478
-
479
- loadI18n(filePath) {
480
- try {
481
- const content = fs.readFileSync(filePath, 'utf-8')
482
- this.i18n = JSON.parse(content)
483
- } catch (e) {
484
- console.error(`Erreur chargement i18n: ${e.message}`)
485
- this.i18n = {}
486
- }
487
- }
488
-
489
- setI18n(i18nData) {
490
- this.i18n = i18nData
491
- }
492
-
493
- parse(source) {
494
- const lexer = new JSLexer(source, this.i18n)
495
- this.tokens = lexer.tokenize()
496
- this.pos = 0
497
- return this.parseProgram()
498
- }
499
-
500
- peek(offset = 0) {
501
- const idx = this.pos + offset
502
- return idx < this.tokens.length ? this.tokens[idx] : { type: 'EOF' }
503
- }
504
-
505
- advance() {
506
- const token = this.tokens[this.pos]
507
- this.pos++
508
- return token
509
- }
510
-
511
- expect(type) {
512
- const token = this.peek()
513
- if (token.type !== type) {
514
- throw new Error(`Attendu ${type}, reçu ${token.type} à ligne ${token.loc?.line}`)
515
- }
516
- return this.advance()
517
- }
518
-
519
- match(...types) {
520
- return types.includes(this.peek().type)
521
- }
522
-
523
- matchValue(...values) {
524
- const token = this.peek()
525
- return values.includes(token.value?.toLowerCase())
526
- }
527
-
528
- parseProgram() {
529
- const body = []
530
- const loc = this.peek().loc
531
-
532
- while (!this.match('EOF')) {
533
- const stmt = this.parseStatement()
534
- if (stmt) body.push(stmt)
535
- }
536
-
537
- return new AST.Program(body, 'module', loc)
538
- }
539
-
540
- parseStatement() {
541
- const token = this.peek()
542
-
543
- if (token.type === 'KEYWORD' || token.type === 'ETHER_KEYWORD') {
544
- const keyword = this.translateKeyword(token.value)
545
-
546
- switch (keyword) {
547
- case 'let':
548
- case 'const':
549
- case 'var':
550
- return this.parseVariableDeclaration()
551
- case 'function':
552
- return this.parseFunctionDeclaration()
553
- case 'class':
554
- return this.parseClassDeclaration()
555
- case 'if':
556
- return this.parseIfStatement()
557
- case 'switch':
558
- return this.parseSwitchStatement()
559
- case 'for':
560
- return this.parseForStatement()
561
- case 'while':
562
- return this.parseWhileStatement()
563
- case 'do':
564
- return this.parseDoWhileStatement()
565
- case 'try':
566
- return this.parseTryStatement()
567
- case 'throw':
568
- return this.parseThrowStatement()
569
- case 'return':
570
- return this.parseReturnStatement()
571
- case 'break':
572
- return this.parseBreakStatement()
573
- case 'continue':
574
- return this.parseContinueStatement()
575
- case 'import':
576
- return this.parseImportDeclaration()
577
- case 'export':
578
- return this.parseExportDeclaration()
579
- case 'debugger':
580
- this.advance()
581
- this.consumeSemicolon()
582
- return new AST.DebuggerStatement(token.loc)
583
- case 'using':
584
- return this.parseUsingDeclaration()
585
- }
586
- }
587
-
588
- if (this.match('LBRACE')) {
589
- return this.parseBlockStatement()
590
- }
591
-
592
- if (this.match('SEMICOLON')) {
593
- this.advance()
594
- return new AST.EmptyStatement(token.loc)
595
- }
596
-
597
- return this.parseExpressionStatement()
598
- }
599
-
600
- parseVariableDeclaration() {
601
- const token = this.advance()
602
- const kind = this.translateKeyword(token.value)
603
- const declarations = []
604
-
605
- do {
606
- const id = this.parseBindingPattern()
607
- let init = null
608
-
609
- if (this.match('ASSIGN')) {
610
- this.advance()
611
- init = this.parseExpression()
612
- }
613
-
614
- declarations.push(new AST.VariableDeclarator(id, init, id.loc))
615
- } while (this.match('COMMA') && this.advance())
616
-
617
- this.consumeSemicolon()
618
-
619
- return new AST.VariableDeclaration(kind, declarations, token.loc)
620
- }
621
-
622
- parseFunctionDeclaration() {
623
- const loc = this.peek().loc
624
- let async = false
625
- let generator = false
626
-
627
- if (this.matchValue('async', 'asynchrone', 'asíncrona', 'асинхронный')) {
628
- async = true
629
- this.advance()
630
- }
631
-
632
- this.advance()
633
-
634
- if (this.match('STAR')) {
635
- generator = true
636
- this.advance()
637
- }
638
-
639
- const id = this.parseIdentifier()
640
- const params = this.parseParameters()
641
- const body = this.parseBlockStatement()
642
-
643
- return new AST.FunctionDeclaration(id, params, body, async, generator, loc)
644
- }
645
-
646
- parseClassDeclaration() {
647
- const loc = this.peek().loc
648
- this.advance()
649
-
650
- const id = this.parseIdentifier()
651
- let superClass = null
652
-
653
- if (this.matchValue('extends', 'étend', 'extiende', 'расширяет')) {
654
- this.advance()
655
- superClass = this.parseExpression()
656
- }
657
-
658
- const body = this.parseClassBody()
659
-
660
- return new AST.ClassDeclaration(id, superClass, body, loc)
661
- }
662
-
663
- parseClassBody() {
664
- const loc = this.peek().loc
665
- this.expect('LBRACE')
666
- const body = []
667
-
668
- while (!this.match('RBRACE', 'EOF')) {
669
- const member = this.parseClassMember()
670
- if (member) body.push(member)
671
- }
672
-
673
- this.expect('RBRACE')
674
- return new AST.ClassBody(body, loc)
675
- }
676
-
677
- parseClassMember() {
678
- let isStatic = false
679
- const loc = this.peek().loc
680
-
681
- if (this.matchValue('static', 'statique', 'estático', 'статический')) {
682
- isStatic = true
683
- this.advance()
684
-
685
- if (this.match('LBRACE')) {
686
- return this.parseStaticBlock()
687
- }
688
- }
689
-
690
- let kind = 'method'
691
- if (this.matchValue('get', 'obtenir', 'получить')) {
692
- kind = 'get'
693
- this.advance()
694
- } else if (this.matchValue('set', 'définir', 'establecer', 'установить')) {
695
- kind = 'set'
696
- this.advance()
697
- }
698
-
699
- let key
700
- let computed = false
701
-
702
- if (this.match('PRIVATE_ID')) {
703
- const token = this.advance()
704
- key = new AST.PrivateIdentifier(token.value, token.loc)
705
- } else if (this.match('LBRACKET')) {
706
- computed = true
707
- this.advance()
708
- key = this.parseExpression()
709
- this.expect('RBRACKET')
710
- } else {
711
- key = this.parseIdentifier()
712
- }
713
-
714
- if (this.match('LPAREN')) {
715
- const params = this.parseParameters()
716
- const body = this.parseBlockStatement()
717
- const value = new AST.FunctionExpression(null, params, body, false, false, loc)
718
- return new AST.MethodDefinition(key, value, kind, computed, isStatic, loc)
719
- } else {
720
- let value = null
721
- if (this.match('ASSIGN')) {
722
- this.advance()
723
- value = this.parseExpression()
724
- }
725
- this.consumeSemicolon()
726
- return new AST.PropertyDefinition(key, value, computed, isStatic, loc)
727
- }
728
- }
729
-
730
- parseStaticBlock() {
731
- const loc = this.peek().loc
732
- const block = this.parseBlockStatement()
733
- return new AST.StaticBlock(block.body, loc)
734
- }
735
-
736
- parseIfStatement() {
737
- const loc = this.peek().loc
738
- this.advance()
739
-
740
- this.expect('LPAREN')
741
- const test = this.parseExpression()
742
- this.expect('RPAREN')
743
-
744
- const consequent = this.parseStatement()
745
- let alternate = null
746
-
747
- if (this.matchValue('else', 'sinon', 'sino', 'иначе')) {
748
- this.advance()
749
- alternate = this.parseStatement()
750
- }
751
-
752
- return new AST.IfStatement(test, consequent, alternate, loc)
753
- }
754
-
755
- parseSwitchStatement() {
756
- const loc = this.peek().loc
757
- this.advance()
758
-
759
- this.expect('LPAREN')
760
- const discriminant = this.parseExpression()
761
- this.expect('RPAREN')
762
-
763
- this.expect('LBRACE')
764
- const cases = []
765
-
766
- while (!this.match('RBRACE', 'EOF')) {
767
- cases.push(this.parseSwitchCase())
768
- }
769
-
770
- this.expect('RBRACE')
771
-
772
- return new AST.SwitchStatement(discriminant, cases, loc)
773
- }
774
-
775
- parseSwitchCase() {
776
- const loc = this.peek().loc
777
- let test = null
778
-
779
- if (this.matchValue('case', 'cas', 'caso', 'случай')) {
780
- this.advance()
781
- test = this.parseExpression()
782
- } else if (this.matchValue('default', 'défaut', 'predeterminado', 'по умолчанию')) {
783
- this.advance()
784
- }
785
-
786
- this.expect('COLON')
787
-
788
- const consequent = []
789
- while (!this.matchValue('case', 'cas', 'caso', 'случай', 'default', 'défaut', 'predeterminado') && !this.match('RBRACE', 'EOF')) {
790
- consequent.push(this.parseStatement())
791
- }
792
-
793
- return new AST.SwitchCase(test, consequent, loc)
794
- }
795
-
796
- parseForStatement() {
797
- const loc = this.peek().loc
798
- this.advance()
799
-
800
- this.expect('LPAREN')
801
-
802
- let init = null
803
- if (!this.match('SEMICOLON')) {
804
- if (this.matchValue('let', 'const', 'var', 'variable', 'constante')) {
805
- init = this.parseVariableDeclarationNoSemi()
806
- } else {
807
- init = this.parseExpression()
808
- }
809
- }
810
-
811
- if (this.matchValue('in', 'dans', 'en', 'в')) {
812
- this.advance()
813
- const right = this.parseExpression()
814
- this.expect('RPAREN')
815
- const body = this.parseStatement()
816
- return new AST.ForInStatement(init, right, body, loc)
817
- }
818
-
819
- if (this.matchValue('of', 'de')) {
820
- this.advance()
821
- const right = this.parseExpression()
822
- this.expect('RPAREN')
823
- const body = this.parseStatement()
824
- return new AST.ForOfStatement(init, right, body, false, loc)
825
- }
826
-
827
- this.expect('SEMICOLON')
828
-
829
- let test = null
830
- if (!this.match('SEMICOLON')) {
831
- test = this.parseExpression()
832
- }
833
-
834
- this.expect('SEMICOLON')
835
-
836
- let update = null
837
- if (!this.match('RPAREN')) {
838
- update = this.parseExpression()
839
- }
840
-
841
- this.expect('RPAREN')
842
- const body = this.parseStatement()
843
-
844
- return new AST.ForStatement(init, test, update, body, loc)
845
- }
846
-
847
- parseVariableDeclarationNoSemi() {
848
- const token = this.advance()
849
- const kind = this.translateKeyword(token.value)
850
- const declarations = []
851
-
852
- const id = this.parseBindingPattern()
853
- let init = null
854
-
855
- if (this.match('ASSIGN')) {
856
- this.advance()
857
- init = this.parseExpression()
858
- }
859
-
860
- declarations.push(new AST.VariableDeclarator(id, init, id.loc))
861
-
862
- return new AST.VariableDeclaration(kind, declarations, token.loc)
863
- }
864
-
865
- parseWhileStatement() {
866
- const loc = this.peek().loc
867
- this.advance()
868
-
869
- this.expect('LPAREN')
870
- const test = this.parseExpression()
871
- this.expect('RPAREN')
872
-
873
- const body = this.parseStatement()
874
-
875
- return new AST.WhileStatement(test, body, loc)
876
- }
877
-
878
- parseDoWhileStatement() {
879
- const loc = this.peek().loc
880
- this.advance()
881
-
882
- const body = this.parseStatement()
883
-
884
- if (!this.matchValue('while', 'tant que', 'mientras', 'пока')) {
885
- throw new Error('Attendu while après do')
886
- }
887
- this.advance()
888
-
889
- this.expect('LPAREN')
890
- const test = this.parseExpression()
891
- this.expect('RPAREN')
892
-
893
- this.consumeSemicolon()
894
-
895
- return new AST.DoWhileStatement(body, test, loc)
896
- }
897
-
898
- parseTryStatement() {
899
- const loc = this.peek().loc
900
- this.advance()
901
-
902
- const block = this.parseBlockStatement()
903
- let handler = null
904
- let finalizer = null
905
-
906
- if (this.matchValue('catch', 'attraper', 'capturar', 'поймать')) {
907
- const catchLoc = this.peek().loc
908
- this.advance()
909
-
910
- let param = null
911
- if (this.match('LPAREN')) {
912
- this.advance()
913
- param = this.parseBindingPattern()
914
- this.expect('RPAREN')
915
- }
916
-
917
- const catchBody = this.parseBlockStatement()
918
- handler = new AST.CatchClause(param, catchBody, catchLoc)
919
- }
920
-
921
- if (this.matchValue('finally', 'finalement', 'finalmente', 'наконец')) {
922
- this.advance()
923
- finalizer = this.parseBlockStatement()
924
- }
925
-
926
- return new AST.TryStatement(block, handler, finalizer, loc)
927
- }
928
-
929
- parseThrowStatement() {
930
- const loc = this.peek().loc
931
- this.advance()
932
-
933
- const argument = this.parseExpression()
934
- this.consumeSemicolon()
935
-
936
- return new AST.ThrowStatement(argument, loc)
937
- }
938
-
939
- parseReturnStatement() {
940
- const loc = this.peek().loc
941
- this.advance()
942
-
943
- let argument = null
944
- if (!this.match('SEMICOLON', 'RBRACE', 'EOF')) {
945
- argument = this.parseExpression()
946
- }
947
-
948
- this.consumeSemicolon()
949
-
950
- return new AST.ReturnStatement(argument, loc)
951
- }
952
-
953
- parseBreakStatement() {
954
- const loc = this.peek().loc
955
- this.advance()
956
-
957
- let label = null
958
- if (this.match('IDENTIFIER')) {
959
- label = this.parseIdentifier()
960
- }
961
-
962
- this.consumeSemicolon()
963
-
964
- return new AST.BreakStatement(label, loc)
965
- }
966
-
967
- parseContinueStatement() {
968
- const loc = this.peek().loc
969
- this.advance()
970
-
971
- let label = null
972
- if (this.match('IDENTIFIER')) {
973
- label = this.parseIdentifier()
974
- }
975
-
976
- this.consumeSemicolon()
977
-
978
- return new AST.ContinueStatement(label, loc)
979
- }
980
-
981
- parseImportDeclaration() {
982
- const loc = this.peek().loc
983
- this.advance()
984
-
985
- const specifiers = []
986
-
987
- if (this.match('STRING')) {
988
- const source = this.parseStringLiteral()
989
- this.consumeSemicolon()
990
- return new AST.ImportDeclaration(specifiers, source, loc)
991
- }
992
-
993
- if (this.match('IDENTIFIER')) {
994
- const local = this.parseIdentifier()
995
- specifiers.push(new AST.ImportDefaultSpecifier(local, local.loc))
996
-
997
- if (this.match('COMMA')) {
998
- this.advance()
999
- }
1000
- }
1001
-
1002
- if (this.match('STAR')) {
1003
- this.advance()
1004
- this.expectValue('as', 'comme', 'como', 'как')
1005
- const local = this.parseIdentifier()
1006
- specifiers.push(new AST.ImportNamespaceSpecifier(local, local.loc))
1007
- } else if (this.match('LBRACE')) {
1008
- this.advance()
1009
- while (!this.match('RBRACE', 'EOF')) {
1010
- const imported = this.parseIdentifier()
1011
- let local = imported
1012
-
1013
- if (this.matchValue('as', 'comme', 'como', 'как')) {
1014
- this.advance()
1015
- local = this.parseIdentifier()
1016
- }
1017
-
1018
- specifiers.push(new AST.ImportSpecifier(imported, local, imported.loc))
1019
-
1020
- if (!this.match('RBRACE')) {
1021
- this.expect('COMMA')
1022
- }
1023
- }
1024
- this.expect('RBRACE')
1025
- }
1026
-
1027
- this.expectValue('from', 'depuis', 'de', 'из')
1028
- const source = this.parseStringLiteral()
1029
- this.consumeSemicolon()
1030
-
1031
- return new AST.ImportDeclaration(specifiers, source, loc)
1032
- }
1033
-
1034
- parseExportDeclaration() {
1035
- const loc = this.peek().loc
1036
- this.advance()
1037
-
1038
- if (this.matchValue('default', 'défaut', 'predeterminado', 'по умолчанию')) {
1039
- this.advance()
1040
- let declaration
1041
-
1042
- if (this.matchValue('function', 'fonction', 'función', 'функция')) {
1043
- declaration = this.parseFunctionDeclaration()
1044
- } else if (this.matchValue('class', 'classe', 'clase', 'класс')) {
1045
- declaration = this.parseClassDeclaration()
1046
- } else {
1047
- declaration = this.parseExpression()
1048
- this.consumeSemicolon()
1049
- }
1050
-
1051
- return new AST.ExportDefaultDeclaration(declaration, loc)
1052
- }
1053
-
1054
- if (this.match('STAR')) {
1055
- this.advance()
1056
- let exported = null
1057
-
1058
- if (this.matchValue('as', 'comme', 'como', 'как')) {
1059
- this.advance()
1060
- exported = this.parseIdentifier()
1061
- }
1062
-
1063
- this.expectValue('from', 'depuis', 'de', 'из')
1064
- const source = this.parseStringLiteral()
1065
- this.consumeSemicolon()
1066
-
1067
- return new AST.ExportAllDeclaration(source, exported, loc)
1068
- }
1069
-
1070
- if (this.match('LBRACE')) {
1071
- this.advance()
1072
- const specifiers = []
1073
-
1074
- while (!this.match('RBRACE', 'EOF')) {
1075
- const local = this.parseIdentifier()
1076
- let exported = local
1077
-
1078
- if (this.matchValue('as', 'comme', 'como', 'как')) {
1079
- this.advance()
1080
- exported = this.parseIdentifier()
1081
- }
1082
-
1083
- specifiers.push(new AST.ExportSpecifier(local, exported, local.loc))
1084
-
1085
- if (!this.match('RBRACE')) {
1086
- this.expect('COMMA')
1087
- }
1088
- }
1089
- this.expect('RBRACE')
1090
-
1091
- let source = null
1092
- if (this.matchValue('from', 'depuis', 'de', 'из')) {
1093
- this.advance()
1094
- source = this.parseStringLiteral()
1095
- }
1096
-
1097
- this.consumeSemicolon()
1098
- return new AST.ExportNamedDeclaration(null, specifiers, source, loc)
1099
- }
1100
-
1101
- const declaration = this.parseStatement()
1102
- return new AST.ExportNamedDeclaration(declaration, [], null, loc)
1103
- }
1104
-
1105
- parseUsingDeclaration() {
1106
- const loc = this.peek().loc
1107
- let await_ = false
1108
-
1109
- if (this.matchValue('await', 'attendre', 'esperar', 'ждать')) {
1110
- await_ = true
1111
- this.advance()
1112
- }
1113
-
1114
- this.advance()
1115
-
1116
- const declarations = []
1117
- do {
1118
- const id = this.parseBindingPattern()
1119
- let init = null
1120
-
1121
- if (this.match('ASSIGN')) {
1122
- this.advance()
1123
- init = this.parseExpression()
1124
- }
1125
-
1126
- declarations.push(new AST.VariableDeclarator(id, init, id.loc))
1127
- } while (this.match('COMMA') && this.advance())
1128
-
1129
- this.consumeSemicolon()
1130
-
1131
- return new AST.UsingDeclaration(declarations, await_, loc)
1132
- }
1133
-
1134
- parseBlockStatement() {
1135
- const loc = this.peek().loc
1136
- this.expect('LBRACE')
1137
- const body = []
1138
-
1139
- while (!this.match('RBRACE', 'EOF')) {
1140
- const stmt = this.parseStatement()
1141
- if (stmt) body.push(stmt)
1142
- }
1143
-
1144
- this.expect('RBRACE')
1145
- return new AST.BlockStatement(body, loc)
1146
- }
1147
-
1148
- parseExpressionStatement() {
1149
- const loc = this.peek().loc
1150
- const expression = this.parseExpression()
1151
- this.consumeSemicolon()
1152
- return new AST.ExpressionStatement(expression, loc)
1153
- }
1154
-
1155
- parseExpression() {
1156
- return this.parseAssignmentExpression()
1157
- }
1158
-
1159
- parseAssignmentExpression() {
1160
- const left = this.parseConditionalExpression()
1161
-
1162
- if (this.match('ASSIGN', 'PLUS_ASSIGN', 'MINUS_ASSIGN', 'STAR_ASSIGN',
1163
- 'SLASH_ASSIGN', 'PERCENT_ASSIGN', 'POWER_ASSIGN', 'AND_ASSIGN',
1164
- 'OR_ASSIGN', 'NULLISH_ASSIGN', 'BIT_AND_ASSIGN', 'BIT_OR_ASSIGN',
1165
- 'BIT_XOR_ASSIGN', 'LEFT_SHIFT_ASSIGN', 'RIGHT_SHIFT_ASSIGN',
1166
- 'UNSIGNED_RIGHT_SHIFT_ASSIGN')) {
1167
- const op = this.advance()
1168
- const right = this.parseAssignmentExpression()
1169
- return new AST.AssignmentExpression(op.value, left, right, left.loc)
1170
- }
1171
-
1172
- return left
1173
- }
1174
-
1175
- parseConditionalExpression() {
1176
- const test = this.parseLogicalOrExpression()
1177
-
1178
- if (this.match('QUESTION')) {
1179
- this.advance()
1180
- const consequent = this.parseAssignmentExpression()
1181
- this.expect('COLON')
1182
- const alternate = this.parseAssignmentExpression()
1183
- return new AST.ConditionalExpression(test, consequent, alternate, test.loc)
1184
- }
1185
-
1186
- return test
1187
- }
1188
-
1189
- parseLogicalOrExpression() {
1190
- let left = this.parseLogicalAndExpression()
1191
-
1192
- while (this.match('OR', 'NULLISH')) {
1193
- const op = this.advance()
1194
- const right = this.parseLogicalAndExpression()
1195
- left = new AST.LogicalExpression(op.value, left, right, left.loc)
1196
- }
1197
-
1198
- return left
1199
- }
1200
-
1201
- parseLogicalAndExpression() {
1202
- let left = this.parseBitwiseOrExpression()
1203
-
1204
- while (this.match('AND')) {
1205
- const op = this.advance()
1206
- const right = this.parseBitwiseOrExpression()
1207
- left = new AST.LogicalExpression(op.value, left, right, left.loc)
1208
- }
1209
-
1210
- return left
1211
- }
1212
-
1213
- parseBitwiseOrExpression() {
1214
- let left = this.parseBitwiseXorExpression()
1215
-
1216
- while (this.match('BIT_OR')) {
1217
- const op = this.advance()
1218
- const right = this.parseBitwiseXorExpression()
1219
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1220
- }
1221
-
1222
- return left
1223
- }
1224
-
1225
- parseBitwiseXorExpression() {
1226
- let left = this.parseBitwiseAndExpression()
1227
-
1228
- while (this.match('BIT_XOR')) {
1229
- const op = this.advance()
1230
- const right = this.parseBitwiseAndExpression()
1231
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1232
- }
1233
-
1234
- return left
1235
- }
1236
-
1237
- parseBitwiseAndExpression() {
1238
- let left = this.parseEqualityExpression()
1239
-
1240
- while (this.match('BIT_AND')) {
1241
- const op = this.advance()
1242
- const right = this.parseEqualityExpression()
1243
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1244
- }
1245
-
1246
- return left
1247
- }
1248
-
1249
- parseEqualityExpression() {
1250
- let left = this.parseRelationalExpression()
1251
-
1252
- while (this.match('EQUAL', 'NOT_EQUAL', 'STRICT_EQUAL', 'STRICT_NOT_EQUAL')) {
1253
- const op = this.advance()
1254
- const right = this.parseRelationalExpression()
1255
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1256
- }
1257
-
1258
- return left
1259
- }
1260
-
1261
- parseRelationalExpression() {
1262
- let left = this.parseShiftExpression()
1263
-
1264
- while (this.match('LT', 'GT', 'LTE', 'GTE') ||
1265
- this.matchValue('instanceof', 'instance de', 'instancia de', 'экземпляр') ||
1266
- this.matchValue('in', 'dans', 'en', 'в')) {
1267
- const op = this.advance()
1268
- const right = this.parseShiftExpression()
1269
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1270
- }
1271
-
1272
- return left
1273
- }
1274
-
1275
- parseShiftExpression() {
1276
- let left = this.parseAdditiveExpression()
1277
-
1278
- while (this.match('LEFT_SHIFT', 'RIGHT_SHIFT', 'UNSIGNED_RIGHT_SHIFT')) {
1279
- const op = this.advance()
1280
- const right = this.parseAdditiveExpression()
1281
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1282
- }
1283
-
1284
- return left
1285
- }
1286
-
1287
- parseAdditiveExpression() {
1288
- let left = this.parseMultiplicativeExpression()
1289
-
1290
- while (this.match('PLUS', 'MINUS')) {
1291
- const op = this.advance()
1292
- const right = this.parseMultiplicativeExpression()
1293
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1294
- }
1295
-
1296
- return left
1297
- }
1298
-
1299
- parseMultiplicativeExpression() {
1300
- let left = this.parseExponentiationExpression()
1301
-
1302
- while (this.match('STAR', 'SLASH', 'PERCENT')) {
1303
- const op = this.advance()
1304
- const right = this.parseExponentiationExpression()
1305
- left = new AST.BinaryExpression(op.value, left, right, left.loc)
1306
- }
1307
-
1308
- return left
1309
- }
1310
-
1311
- parseExponentiationExpression() {
1312
- const left = this.parseUnaryExpression()
1313
-
1314
- if (this.match('POWER')) {
1315
- const op = this.advance()
1316
- const right = this.parseExponentiationExpression()
1317
- return new AST.BinaryExpression(op.value, left, right, left.loc)
1318
- }
1319
-
1320
- return left
1321
- }
1322
-
1323
- parseUnaryExpression() {
1324
- if (this.match('NOT', 'BIT_NOT', 'PLUS', 'MINUS') ||
1325
- this.matchValue('typeof', 'type de', 'tipo de', 'тип') ||
1326
- this.matchValue('void', 'vide', 'vacío', 'пустой') ||
1327
- this.matchValue('delete', 'supprimer', 'eliminar', 'удалить')) {
1328
- const op = this.advance()
1329
- const argument = this.parseUnaryExpression()
1330
- return new AST.UnaryExpression(op.value, argument, true, op.loc)
1331
- }
1332
-
1333
- if (this.match('INCREMENT', 'DECREMENT')) {
1334
- const op = this.advance()
1335
- const argument = this.parseUnaryExpression()
1336
- return new AST.UpdateExpression(op.value, argument, true, op.loc)
1337
- }
1338
-
1339
- if (this.matchValue('await', 'attendre', 'esperar', 'ждать')) {
1340
- const loc = this.peek().loc
1341
- this.advance()
1342
- const argument = this.parseUnaryExpression()
1343
- return new AST.AwaitExpression(argument, loc)
1344
- }
1345
-
1346
- return this.parseUpdateExpression()
1347
- }
1348
-
1349
- parseUpdateExpression() {
1350
- const argument = this.parseLeftHandSideExpression()
1351
-
1352
- if (this.match('INCREMENT', 'DECREMENT')) {
1353
- const op = this.advance()
1354
- return new AST.UpdateExpression(op.value, argument, false, argument.loc)
1355
- }
1356
-
1357
- return argument
1358
- }
1359
-
1360
- parseLeftHandSideExpression() {
1361
- let expr
1362
-
1363
- if (this.matchValue('new', 'nouveau', 'nuevo', 'новый')) {
1364
- expr = this.parseNewExpression()
1365
- } else {
1366
- expr = this.parsePrimaryExpression()
1367
- }
1368
-
1369
- while (true) {
1370
- if (this.match('DOT')) {
1371
- this.advance()
1372
- const property = this.parseIdentifier()
1373
- expr = new AST.MemberExpression(expr, property, false, false, expr.loc)
1374
- } else if (this.match('OPTIONAL_CHAIN')) {
1375
- this.advance()
1376
- if (this.match('LPAREN')) {
1377
- const args = this.parseArguments()
1378
- expr = new AST.CallExpression(expr, args, true, expr.loc)
1379
- } else if (this.match('LBRACKET')) {
1380
- this.advance()
1381
- const property = this.parseExpression()
1382
- this.expect('RBRACKET')
1383
- expr = new AST.MemberExpression(expr, property, true, true, expr.loc)
1384
- } else {
1385
- const property = this.parseIdentifier()
1386
- expr = new AST.MemberExpression(expr, property, false, true, expr.loc)
1387
- }
1388
- } else if (this.match('LBRACKET')) {
1389
- this.advance()
1390
- const property = this.parseExpression()
1391
- this.expect('RBRACKET')
1392
- expr = new AST.MemberExpression(expr, property, true, false, expr.loc)
1393
- } else if (this.match('LPAREN')) {
1394
- const args = this.parseArguments()
1395
- expr = new AST.CallExpression(expr, args, false, expr.loc)
1396
- } else if (this.match('TEMPLATE')) {
1397
- const quasi = this.parseTemplateLiteral()
1398
- expr = new AST.TaggedTemplateExpression(expr, quasi, expr.loc)
1399
- } else {
1400
- break
1401
- }
1402
- }
1403
-
1404
- return expr
1405
- }
1406
-
1407
- parseNewExpression() {
1408
- const loc = this.peek().loc
1409
- this.advance()
1410
-
1411
- if (this.match('DOT')) {
1412
- this.advance()
1413
- const property = this.parseIdentifier()
1414
- return new AST.MetaProperty(new AST.Identifier('new', loc), property, loc)
1415
- }
1416
-
1417
- const callee = this.parseLeftHandSideExpression()
1418
- let args = []
1419
-
1420
- if (this.match('LPAREN')) {
1421
- args = this.parseArguments()
1422
- }
1423
-
1424
- return new AST.NewExpression(callee, args, loc)
1425
- }
1426
-
1427
- parsePrimaryExpression() {
1428
- const token = this.peek()
1429
-
1430
- if (this.matchValue('this', 'ceci', 'esto', 'это')) {
1431
- this.advance()
1432
- return new AST.ThisExpression(token.loc)
1433
- }
1434
-
1435
- if (this.matchValue('super')) {
1436
- this.advance()
1437
- return new AST.Super(token.loc)
1438
- }
1439
-
1440
- if (this.matchValue('true', 'vrai', 'verdadero', 'истина')) {
1441
- this.advance()
1442
- return new AST.BooleanLiteral(true, token.loc)
1443
- }
1444
-
1445
- if (this.matchValue('false', 'faux', 'falso', 'ложь')) {
1446
- this.advance()
1447
- return new AST.BooleanLiteral(false, token.loc)
1448
- }
1449
-
1450
- if (this.matchValue('null', 'nul', 'nulo', 'нуль')) {
1451
- this.advance()
1452
- return new AST.NullLiteral(token.loc)
1453
- }
1454
-
1455
- if (this.matchValue('undefined', 'indéfini', 'indefinido', 'неопределённый')) {
1456
- this.advance()
1457
- return new AST.Identifier('undefined', token.loc)
1458
- }
1459
-
1460
- if (this.match('NUMBER')) {
1461
- return this.parseNumericLiteral()
1462
- }
1463
-
1464
- if (this.match('BIGINT')) {
1465
- return this.parseBigIntLiteral()
1466
- }
1467
-
1468
- if (this.match('STRING')) {
1469
- return this.parseStringLiteral()
1470
- }
1471
-
1472
- if (this.match('TEMPLATE')) {
1473
- return this.parseTemplateLiteral()
1474
- }
1475
-
1476
- if (this.match('REGEXP')) {
1477
- return this.parseRegExpLiteral()
1478
- }
1479
-
1480
- if (this.match('LBRACKET')) {
1481
- return this.parseArrayExpression()
1482
- }
1483
-
1484
- if (this.match('LBRACE')) {
1485
- return this.parseObjectExpression()
1486
- }
1487
-
1488
- if (this.match('LPAREN')) {
1489
- return this.parseParenthesizedOrArrow()
1490
- }
1491
-
1492
- if (this.matchValue('function', 'fonction', 'función', 'функция')) {
1493
- return this.parseFunctionExpression()
1494
- }
1495
-
1496
- if (this.matchValue('class', 'classe', 'clase', 'класс')) {
1497
- return this.parseClassExpression()
1498
- }
1499
-
1500
- if (this.matchValue('async', 'asynchrone', 'asíncrona', 'асинхронный')) {
1501
- return this.parseAsyncFunctionOrArrow()
1502
- }
1503
-
1504
- if (this.match('IDENTIFIER', 'KEYWORD', 'ETHER_KEYWORD')) {
1505
- return this.parseIdentifier()
1506
- }
1507
-
1508
- throw new Error(`Token inattendu: ${token.type} à ligne ${token.loc?.line}`)
1509
- }
1510
-
1511
- parseIdentifier() {
1512
- const token = this.advance()
1513
- return new AST.Identifier(token.value, token.loc)
1514
- }
1515
-
1516
- parseNumericLiteral() {
1517
- const token = this.advance()
1518
- return new AST.NumericLiteral(parseFloat(token.value), token.value, token.loc)
1519
- }
1520
-
1521
- parseBigIntLiteral() {
1522
- const token = this.advance()
1523
- return new AST.BigIntLiteral(BigInt(token.value), token.value + 'n', token.loc)
1524
- }
1525
-
1526
- parseStringLiteral() {
1527
- const token = this.advance()
1528
- return new AST.StringLiteral(token.value, `${token.quote}${token.value}${token.quote}`, token.loc)
1529
- }
1530
-
1531
- parseTemplateLiteral() {
1532
- const token = this.advance()
1533
- const quasis = token.quasis.map((q, i) =>
1534
- new AST.TemplateElement({ raw: q.value, cooked: q.value }, q.tail, token.loc)
1535
- )
1536
- const expressions = token.expressions.map(e => {
1537
- const parser = new JSParser()
1538
- parser.setI18n(this.i18n)
1539
- const ast = parser.parse(e)
1540
- return ast.body[0]?.expression || new AST.Identifier(e, token.loc)
1541
- })
1542
- return new AST.TemplateLiteral(quasis, expressions, token.loc)
1543
- }
1544
-
1545
- parseRegExpLiteral() {
1546
- const token = this.advance()
1547
- return new AST.RegExpLiteral(token.pattern, token.flags, token.loc)
1548
- }
1549
-
1550
- parseArrayExpression() {
1551
- const loc = this.peek().loc
1552
- this.expect('LBRACKET')
1553
- const elements = []
1554
-
1555
- while (!this.match('RBRACKET', 'EOF')) {
1556
- if (this.match('COMMA')) {
1557
- elements.push(null)
1558
- this.advance()
1559
- continue
1560
- }
1561
-
1562
- if (this.match('SPREAD')) {
1563
- this.advance()
1564
- const argument = this.parseAssignmentExpression()
1565
- elements.push(new AST.SpreadElement(argument, argument.loc))
1566
- } else {
1567
- elements.push(this.parseAssignmentExpression())
1568
- }
1569
-
1570
- if (!this.match('RBRACKET')) {
1571
- this.expect('COMMA')
1572
- }
1573
- }
1574
-
1575
- this.expect('RBRACKET')
1576
- return new AST.ArrayExpression(elements, loc)
1577
- }
1578
-
1579
- parseObjectExpression() {
1580
- const loc = this.peek().loc
1581
- this.expect('LBRACE')
1582
- const properties = []
1583
-
1584
- while (!this.match('RBRACE', 'EOF')) {
1585
- properties.push(this.parseProperty())
1586
-
1587
- if (!this.match('RBRACE')) {
1588
- this.expect('COMMA')
1589
- }
1590
- }
1591
-
1592
- this.expect('RBRACE')
1593
- return new AST.ObjectExpression(properties, loc)
1594
- }
1595
-
1596
- parseProperty() {
1597
- const loc = this.peek().loc
1598
-
1599
- if (this.match('SPREAD')) {
1600
- this.advance()
1601
- const argument = this.parseAssignmentExpression()
1602
- return new AST.SpreadElement(argument, loc)
1603
- }
1604
-
1605
- let kind = 'init'
1606
- let method = false
1607
- let shorthand = false
1608
- let computed = false
1609
- let key
1610
- let value
1611
-
1612
- if (this.matchValue('get', 'obtenir', 'получить')) {
1613
- const next = this.peek(1)
1614
- if (next.type !== 'COLON' && next.type !== 'COMMA' && next.type !== 'RBRACE') {
1615
- kind = 'get'
1616
- this.advance()
1617
- }
1618
- } else if (this.matchValue('set', 'définir', 'establecer', 'установить')) {
1619
- const next = this.peek(1)
1620
- if (next.type !== 'COLON' && next.type !== 'COMMA' && next.type !== 'RBRACE') {
1621
- kind = 'set'
1622
- this.advance()
1623
- }
1624
- }
1625
-
1626
- if (this.match('LBRACKET')) {
1627
- computed = true
1628
- this.advance()
1629
- key = this.parseAssignmentExpression()
1630
- this.expect('RBRACKET')
1631
- } else if (this.match('STRING')) {
1632
- key = this.parseStringLiteral()
1633
- } else if (this.match('NUMBER')) {
1634
- key = this.parseNumericLiteral()
1635
- } else {
1636
- key = this.parseIdentifier()
1637
- }
1638
-
1639
- if (this.match('LPAREN')) {
1640
- method = true
1641
- const params = this.parseParameters()
1642
- const body = this.parseBlockStatement()
1643
- value = new AST.FunctionExpression(null, params, body, false, false, loc)
1644
- } else if (this.match('COLON')) {
1645
- this.advance()
1646
- value = this.parseAssignmentExpression()
1647
- } else if (this.match('ASSIGN')) {
1648
- this.advance()
1649
- const defaultValue = this.parseAssignmentExpression()
1650
- value = new AST.AssignmentPattern(key, defaultValue, loc)
1651
- shorthand = true
1652
- } else {
1653
- value = key
1654
- shorthand = true
1655
- }
1656
-
1657
- return new AST.Property(key, value, kind, method, shorthand, computed, loc)
1658
- }
1659
-
1660
- parseParenthesizedOrArrow() {
1661
- const loc = this.peek().loc
1662
- this.expect('LPAREN')
1663
-
1664
- if (this.match('RPAREN')) {
1665
- this.advance()
1666
- if (this.match('ARROW')) {
1667
- this.advance()
1668
- return this.parseArrowFunctionBody([], false, loc)
1669
- }
1670
- throw new Error('Attendu => après ()')
1671
- }
1672
-
1673
- const first = this.parseAssignmentExpression()
1674
-
1675
- if (this.match('COMMA')) {
1676
- const expressions = [first]
1677
- while (this.match('COMMA')) {
1678
- this.advance()
1679
- if (this.match('RPAREN')) break
1680
- expressions.push(this.parseAssignmentExpression())
1681
- }
1682
- this.expect('RPAREN')
1683
-
1684
- if (this.match('ARROW')) {
1685
- this.advance()
1686
- return this.parseArrowFunctionBody(expressions, false, loc)
1687
- }
1688
-
1689
- return new AST.SequenceExpression(expressions, loc)
1690
- }
1691
-
1692
- this.expect('RPAREN')
1693
-
1694
- if (this.match('ARROW')) {
1695
- this.advance()
1696
- return this.parseArrowFunctionBody([first], false, loc)
1697
- }
1698
-
1699
- return first
1700
- }
1701
-
1702
- parseArrowFunctionBody(params, async, loc) {
1703
- let body
1704
- let expression = false
1705
-
1706
- if (this.match('LBRACE')) {
1707
- body = this.parseBlockStatement()
1708
- } else {
1709
- body = this.parseAssignmentExpression()
1710
- expression = true
1711
- }
1712
-
1713
- return new AST.ArrowFunctionExpression(params, body, async, expression, loc)
1714
- }
1715
-
1716
- parseFunctionExpression() {
1717
- const loc = this.peek().loc
1718
- let async = false
1719
- let generator = false
1720
-
1721
- if (this.matchValue('async', 'asynchrone', 'asíncrona', 'асинхронный')) {
1722
- async = true
1723
- this.advance()
1724
- }
1725
-
1726
- this.advance()
1727
-
1728
- if (this.match('STAR')) {
1729
- generator = true
1730
- this.advance()
1731
- }
1732
-
1733
- let id = null
1734
- if (this.match('IDENTIFIER')) {
1735
- id = this.parseIdentifier()
1736
- }
1737
-
1738
- const params = this.parseParameters()
1739
- const body = this.parseBlockStatement()
1740
-
1741
- return new AST.FunctionExpression(id, params, body, async, generator, loc)
1742
- }
1743
-
1744
- parseClassExpression() {
1745
- const loc = this.peek().loc
1746
- this.advance()
1747
-
1748
- let id = null
1749
- if (this.match('IDENTIFIER')) {
1750
- id = this.parseIdentifier()
1751
- }
1752
-
1753
- let superClass = null
1754
- if (this.matchValue('extends', 'étend', 'extiende', 'расширяет')) {
1755
- this.advance()
1756
- superClass = this.parseExpression()
1757
- }
1758
-
1759
- const body = this.parseClassBody()
1760
-
1761
- return new AST.ClassExpression(id, superClass, body, loc)
1762
- }
1763
-
1764
- parseAsyncFunctionOrArrow() {
1765
- const loc = this.peek().loc
1766
- this.advance()
1767
-
1768
- if (this.matchValue('function', 'fonction', 'función', 'функция')) {
1769
- this.advance()
1770
- let generator = false
1771
- if (this.match('STAR')) {
1772
- generator = true
1773
- this.advance()
1774
- }
1775
-
1776
- let id = null
1777
- if (this.match('IDENTIFIER')) {
1778
- id = this.parseIdentifier()
1779
- }
1780
-
1781
- const params = this.parseParameters()
1782
- const body = this.parseBlockStatement()
1783
-
1784
- return new AST.FunctionExpression(id, params, body, true, generator, loc)
1785
- }
1786
-
1787
- if (this.match('LPAREN')) {
1788
- const params = this.parseParameters()
1789
- this.expect('ARROW')
1790
- return this.parseArrowFunctionBody(params, true, loc)
1791
- }
1792
-
1793
- if (this.match('IDENTIFIER')) {
1794
- const param = this.parseIdentifier()
1795
- this.expect('ARROW')
1796
- return this.parseArrowFunctionBody([param], true, loc)
1797
- }
1798
-
1799
- throw new Error('Syntaxe async invalide')
1800
- }
1801
-
1802
- parseParameters() {
1803
- this.expect('LPAREN')
1804
- const params = []
1805
-
1806
- while (!this.match('RPAREN', 'EOF')) {
1807
- if (this.match('SPREAD')) {
1808
- this.advance()
1809
- const argument = this.parseBindingPattern()
1810
- params.push(new AST.RestElement(argument, argument.loc))
1811
- break
1812
- }
1813
-
1814
- const param = this.parseBindingPattern()
1815
-
1816
- if (this.match('ASSIGN')) {
1817
- this.advance()
1818
- const defaultValue = this.parseAssignmentExpression()
1819
- params.push(new AST.AssignmentPattern(param, defaultValue, param.loc))
1820
- } else {
1821
- params.push(param)
1822
- }
1823
-
1824
- if (!this.match('RPAREN')) {
1825
- this.expect('COMMA')
1826
- }
1827
- }
1828
-
1829
- this.expect('RPAREN')
1830
- return params
1831
- }
1832
-
1833
- parseBindingPattern() {
1834
- if (this.match('LBRACKET')) {
1835
- return this.parseArrayPattern()
1836
- }
1837
-
1838
- if (this.match('LBRACE')) {
1839
- return this.parseObjectPattern()
1840
- }
1841
-
1842
- return this.parseIdentifier()
1843
- }
1844
-
1845
- parseArrayPattern() {
1846
- const loc = this.peek().loc
1847
- this.expect('LBRACKET')
1848
- const elements = []
1849
-
1850
- while (!this.match('RBRACKET', 'EOF')) {
1851
- if (this.match('COMMA')) {
1852
- elements.push(null)
1853
- this.advance()
1854
- continue
1855
- }
1856
-
1857
- if (this.match('SPREAD')) {
1858
- this.advance()
1859
- const argument = this.parseBindingPattern()
1860
- elements.push(new AST.RestElement(argument, argument.loc))
1861
- break
1862
- }
1863
-
1864
- let element = this.parseBindingPattern()
1865
-
1866
- if (this.match('ASSIGN')) {
1867
- this.advance()
1868
- const defaultValue = this.parseAssignmentExpression()
1869
- element = new AST.AssignmentPattern(element, defaultValue, element.loc)
1870
- }
1871
-
1872
- elements.push(element)
1873
-
1874
- if (!this.match('RBRACKET')) {
1875
- this.expect('COMMA')
1876
- }
1877
- }
1878
-
1879
- this.expect('RBRACKET')
1880
- return new AST.ArrayPattern(elements, loc)
1881
- }
1882
-
1883
- parseObjectPattern() {
1884
- const loc = this.peek().loc
1885
- this.expect('LBRACE')
1886
- const properties = []
1887
-
1888
- while (!this.match('RBRACE', 'EOF')) {
1889
- if (this.match('SPREAD')) {
1890
- this.advance()
1891
- const argument = this.parseBindingPattern()
1892
- properties.push(new AST.RestElement(argument, argument.loc))
1893
- break
1894
- }
1895
-
1896
- let key
1897
- let value
1898
- let computed = false
1899
- let shorthand = false
1900
-
1901
- if (this.match('LBRACKET')) {
1902
- computed = true
1903
- this.advance()
1904
- key = this.parseAssignmentExpression()
1905
- this.expect('RBRACKET')
1906
- } else {
1907
- key = this.parseIdentifier()
1908
- }
1909
-
1910
- if (this.match('COLON')) {
1911
- this.advance()
1912
- value = this.parseBindingPattern()
1913
- } else {
1914
- value = key
1915
- shorthand = true
1916
- }
1917
-
1918
- if (this.match('ASSIGN')) {
1919
- this.advance()
1920
- const defaultValue = this.parseAssignmentExpression()
1921
- value = new AST.AssignmentPattern(value, defaultValue, value.loc)
1922
- }
1923
-
1924
- properties.push(new AST.Property(key, value, 'init', false, shorthand, computed, key.loc))
1925
-
1926
- if (!this.match('RBRACE')) {
1927
- this.expect('COMMA')
1928
- }
1929
- }
1930
-
1931
- this.expect('RBRACE')
1932
- return new AST.ObjectPattern(properties, loc)
1933
- }
1934
-
1935
- parseArguments() {
1936
- this.expect('LPAREN')
1937
- const args = []
1938
-
1939
- while (!this.match('RPAREN', 'EOF')) {
1940
- if (this.match('SPREAD')) {
1941
- this.advance()
1942
- const argument = this.parseAssignmentExpression()
1943
- args.push(new AST.SpreadElement(argument, argument.loc))
1944
- } else {
1945
- args.push(this.parseAssignmentExpression())
1946
- }
1947
-
1948
- if (!this.match('RPAREN')) {
1949
- this.expect('COMMA')
1950
- }
1951
- }
1952
-
1953
- this.expect('RPAREN')
1954
- return args
1955
- }
1956
-
1957
- consumeSemicolon() {
1958
- if (this.match('SEMICOLON')) {
1959
- this.advance()
1960
- }
1961
- }
1962
-
1963
- expectValue(...values) {
1964
- const token = this.peek()
1965
- if (!values.includes(token.value?.toLowerCase())) {
1966
- throw new Error(`Attendu un de ${values.join(', ')}, reçu ${token.value} à ligne ${token.loc?.line}`)
1967
- }
1968
- return this.advance()
1969
- }
1970
-
1971
- translateKeyword(word) {
1972
- const lowerWord = word.toLowerCase()
1973
-
1974
- const translations = {
1975
- 'variable': 'let', 'let': 'let', 'переменная': 'let', '变量': 'let', '変数': 'let',
1976
- 'constante': 'const', 'constant': 'const', 'const': 'const', 'константа': 'const', '常量': 'const', '定数': 'const',
1977
- 'variable globale': 'var', 'global variable': 'var', 'var': 'var', 'variable global': 'var', 'глобальная переменная': 'var', '全局变量': 'var', 'グローバル変数': 'var',
1978
- 'fonction': 'function', 'function': 'function', 'función': 'function', 'функция': 'function', '函数': 'function', '関数': 'function',
1979
- 'classe': 'class', 'class': 'class', 'clase': 'class', 'класс': 'class', '类': 'class', 'クラス': 'class',
1980
- 'si': 'if', 'if': 'if', 'если': 'if', '如果': 'if', 'もし': 'if',
1981
- 'sinon': 'else', 'else': 'else', 'sino': 'else', 'иначе': 'else', '否则': 'else', 'そうでなければ': 'else',
1982
- 'sinon si': 'else if', 'else if': 'else if', 'sino si': 'else if', 'иначе если': 'else if', '否则如果': 'else if', 'そうでなければもし': 'else if',
1983
- 'pour': 'for', 'for': 'for', 'para': 'for', 'для': 'for', '为': 'for', 'ために': 'for',
1984
- 'tant que': 'while', 'while': 'while', 'mientras': 'while', 'пока': 'while', '当': 'while', 'ながら': 'while',
1985
- 'faire': 'do', 'do': 'do', 'hacer': 'do', 'делать': 'do', '做': 'do', 'する': 'do',
1986
- 'selon': 'switch', 'switch': 'switch', 'según': 'switch', 'segun': 'switch', 'переключатель': 'switch', '开关': 'switch', 'スイッチ': 'switch',
1987
- 'cas': 'case', 'case': 'case', 'caso': 'case', 'случай': 'case', '情况': 'case', 'ケース': 'case',
1988
- 'defaut': 'default', 'défaut': 'default', 'default': 'default', 'predeterminado': 'default', 'по умолчанию': 'default', '默认': 'default', 'デフォルト': 'default',
1989
- 'sortir': 'break', 'break': 'break', 'romper': 'break', 'прервать': 'break', '跳出': 'break', 'ブレーク': 'break',
1990
- 'continuer': 'continue', 'continue': 'continue', 'continuar': 'continue', 'продолжить': 'continue', '继续': 'continue', 'コンティニュー': 'continue',
1991
- 'retourner': 'return', 'return': 'return', 'retornar': 'return', 'вернуть': 'return', '返回': 'return', 'リターン': 'return',
1992
- 'lancer': 'throw', 'throw': 'throw', 'lanzar': 'throw', 'бросить': 'throw', '抛出': 'throw', 'スロー': 'throw',
1993
- 'essayer': 'try', 'try': 'try', 'intentar': 'try', 'попробовать': 'try', '尝试': 'try', 'トライ': 'try',
1994
- 'attraper': 'catch', 'catch': 'catch', 'capturar': 'catch', 'поймать': 'catch', '捕获': 'catch', 'キャッチ': 'catch',
1995
- 'finalement': 'finally', 'finally': 'finally', 'finalmente': 'finally', 'наконец': 'finally', '最终': 'finally', 'ファイナリー': 'finally',
1996
- 'importer': 'import', 'import': 'import', 'importar': 'import', 'импортировать': 'import', '导入': 'import', 'インポート': 'import',
1997
- 'exporter': 'export', 'export': 'export', 'exportar': 'export', 'экспортировать': 'export', '导出': 'export', 'エクスポート': 'export',
1998
- 'depuis': 'from', 'from': 'from', 'de': 'from', 'desde': 'from', 'из': 'from', '从': 'from', 'から': 'from',
1999
- 'comme': 'as', 'as': 'as', 'como': 'as', 'как': 'as', '作为': 'as', 'として': 'as',
2000
- 'nouveau': 'new', 'new': 'new', 'nuevo': 'new', 'новый': 'new', '新建': 'new', '新規': 'new',
2001
- 'ceci': 'this', 'this': 'this', 'esto': 'this', 'это': 'this', '这个': 'this', 'これ': 'this',
2002
- 'parent': 'super', 'super': 'super', 'padre': 'super', 'родитель': 'super', '父类': 'super', 'スーパー': 'super',
2003
- 'etend': 'extends', 'étend': 'extends', 'extends': 'extends', 'extiende': 'extends', 'расширяет': 'extends', '扩展': 'extends', '拡張': 'extends',
2004
- 'statique': 'static', 'static': 'static', 'estático': 'static', 'estatico': 'static', 'статический': 'static', '静态': 'static', '静的': 'static',
2005
- 'obtenir': 'get', 'get': 'get', 'получить': 'get', '获取': 'get', 'ゲット': 'get',
2006
- 'definir': 'set', 'définir': 'set', 'set': 'set', 'establecer': 'set', 'установить': 'set', '设置': 'set', 'セット': 'set',
2007
- 'asynchrone': 'async', 'async': 'async', 'asíncrona': 'async', 'asincrona': 'async', 'асинхронный': 'async', '异步': 'async', '非同期': 'async',
2008
- 'attendre': 'await', 'await': 'await', 'esperar': 'await', 'ждать': 'await', '等待': 'await', 'アウェイト': 'await',
2009
- 'ceder': 'yield', 'céder': 'yield', 'yield': 'yield', 'уступить': 'yield', '产出': 'yield', 'イールド': 'yield',
2010
- 'utilisant': 'using', 'using': 'using', 'usando': 'using', 'используя': 'using', '使用': 'using', '使用中': 'using',
2011
- 'vrai': 'true', 'true': 'true', 'verdadero': 'true', 'истина': 'true', '真': 'true', '真実': 'true',
2012
- 'faux': 'false', 'false': 'false', 'falso': 'false', 'ложь': 'false', '假': 'false', '偽': 'false',
2013
- 'nul': 'null', 'null': 'null', 'nulo': 'null', 'ноль': 'null', '空': 'null', 'ヌル': 'null',
2014
- 'indefini': 'undefined', 'indéfini': 'undefined', 'undefined': 'undefined', 'indefinido': 'undefined', 'неопределено': 'undefined', '未定义': 'undefined', '未定義': 'undefined',
2015
- 'type de': 'typeof', 'typeof': 'typeof', 'tipo de': 'typeof', 'тип': 'typeof', '类型': 'typeof', 'タイプ': 'typeof',
2016
- 'instance de': 'instanceof', 'instanceof': 'instanceof', 'instancia de': 'instanceof', 'экземпляр': 'instanceof', '实例': 'instanceof', 'インスタンス': 'instanceof',
2017
- 'dans': 'in', 'in': 'in', 'en': 'in', 'в': 'in', '在': 'in', '中': 'in',
2018
- 'de': 'of', 'of': 'of', 'из': 'of', '的': 'of', 'の': 'of',
2019
- 'supprimer': 'delete', 'delete': 'delete', 'eliminar': 'delete', 'удалить': 'delete', '删除': 'delete', '削除': 'delete',
2020
- 'vide': 'void', 'void': 'void', 'vacío': 'void', 'vacio': 'void', 'пустой': 'void', '空值': 'void', 'ボイド': 'void',
2021
- 'debogueur': 'debugger', 'débogueur': 'debugger', 'debugger': 'debugger', 'depurador': 'debugger', 'отладчик': 'debugger', '调试器': 'debugger', 'デバッガー': 'debugger',
2022
- 'avec': 'with', 'with': 'with', 'con': 'with', 'с': 'with', '与': 'with', 'と': 'with'
2023
- }
2024
-
2025
- return translations[lowerWord] || word
2026
- }
2027
- }
2028
-
2029
- class JSCodeGenerator {
2030
- constructor(options = {}) {
2031
- this.indent = 0
2032
- this.indentStr = options.indentStr || ' '
2033
- }
2034
-
2035
- generate(ast) {
2036
- if (!ast) return ''
2037
-
2038
- const method = `generate${ast.type}`
2039
- if (this[method]) {
2040
- return this[method](ast)
2041
- }
2042
-
2043
- return ''
2044
- }
2045
-
2046
- generateProgram(node) {
2047
- return node.body.map(stmt => this.generate(stmt)).join('\n')
2048
- }
2049
-
2050
- generateIdentifier(node) {
2051
- return node.name
2052
- }
2053
-
2054
- generateLiteral(node) {
2055
- return node.raw || String(node.value)
2056
- }
2057
-
2058
- generateStringLiteral(node) {
2059
- return node.raw || `"${node.value}"`
2060
- }
2061
-
2062
- generateNumericLiteral(node) {
2063
- return node.raw || String(node.value)
2064
- }
2065
-
2066
- generateBooleanLiteral(node) {
2067
- return String(node.value)
2068
- }
2069
-
2070
- generateNullLiteral() {
2071
- return 'null'
2072
- }
2073
-
2074
- generateBigIntLiteral(node) {
2075
- return node.raw || `${node.value}n`
2076
- }
2077
-
2078
- generateRegExpLiteral(node) {
2079
- return `/${node.pattern}/${node.flags}`
2080
- }
2081
-
2082
- generateTemplateLiteral(node) {
2083
- let result = '`'
2084
- for (let i = 0; i < node.quasis.length; i++) {
2085
- result += node.quasis[i].value.raw || node.quasis[i].value
2086
- if (i < node.expressions.length) {
2087
- result += '${' + this.generate(node.expressions[i]) + '}'
2088
- }
2089
- }
2090
- result += '`'
2091
- return result
2092
- }
2093
-
2094
- generateVariableDeclaration(node) {
2095
- const declarations = node.declarations.map(d => this.generate(d)).join(', ')
2096
- return `${node.kind} ${declarations};`
2097
- }
2098
-
2099
- generateVariableDeclarator(node) {
2100
- let result = this.generate(node.id)
2101
- if (node.init) {
2102
- result += ' = ' + this.generate(node.init)
2103
- }
2104
- return result
2105
- }
2106
-
2107
- generateFunctionDeclaration(node) {
2108
- let result = ''
2109
- if (node.async) result += 'async '
2110
- result += 'function'
2111
- if (node.generator) result += '*'
2112
- result += ' ' + this.generate(node.id)
2113
- result += '(' + node.params.map(p => this.generate(p)).join(', ') + ') '
2114
- result += this.generate(node.body)
2115
- return result
2116
- }
2117
-
2118
- generateFunctionExpression(node) {
2119
- let result = ''
2120
- if (node.async) result += 'async '
2121
- result += 'function'
2122
- if (node.generator) result += '*'
2123
- if (node.id) result += ' ' + this.generate(node.id)
2124
- result += '(' + node.params.map(p => this.generate(p)).join(', ') + ') '
2125
- result += this.generate(node.body)
2126
- return result
2127
- }
2128
-
2129
- generateArrowFunctionExpression(node) {
2130
- let result = ''
2131
- if (node.async) result += 'async '
2132
-
2133
- if (node.params.length === 1 && node.params[0].type === 'Identifier') {
2134
- result += this.generate(node.params[0])
2135
- } else {
2136
- result += '(' + node.params.map(p => this.generate(p)).join(', ') + ')'
2137
- }
2138
-
2139
- result += ' => '
2140
-
2141
- if (node.expression) {
2142
- result += this.generate(node.body)
2143
- } else {
2144
- result += this.generate(node.body)
2145
- }
2146
-
2147
- return result
2148
- }
2149
-
2150
- generateClassDeclaration(node) {
2151
- let result = 'class ' + this.generate(node.id)
2152
- if (node.superClass) {
2153
- result += ' extends ' + this.generate(node.superClass)
2154
- }
2155
- result += ' ' + this.generate(node.body)
2156
- return result
2157
- }
2158
-
2159
- generateClassBody(node) {
2160
- this.indent++
2161
- const body = node.body.map(m => this.getIndent() + this.generate(m)).join('\n')
2162
- this.indent--
2163
- return '{\n' + body + '\n' + this.getIndent() + '}'
2164
- }
2165
-
2166
- generateMethodDefinition(node) {
2167
- let result = ''
2168
- if (node.static) result += 'static '
2169
- if (node.kind === 'get') result += 'get '
2170
- if (node.kind === 'set') result += 'set '
2171
- if (node.value.async) result += 'async '
2172
- if (node.value.generator) result += '*'
2173
-
2174
- if (node.computed) {
2175
- result += '[' + this.generate(node.key) + ']'
2176
- } else {
2177
- result += this.generate(node.key)
2178
- }
2179
-
2180
- result += '(' + node.value.params.map(p => this.generate(p)).join(', ') + ') '
2181
- result += this.generate(node.value.body)
2182
-
2183
- return result
2184
- }
2185
-
2186
- generatePropertyDefinition(node) {
2187
- let result = ''
2188
- if (node.static) result += 'static '
2189
-
2190
- if (node.computed) {
2191
- result += '[' + this.generate(node.key) + ']'
2192
- } else {
2193
- result += this.generate(node.key)
2194
- }
2195
-
2196
- if (node.value) {
2197
- result += ' = ' + this.generate(node.value)
2198
- }
2199
-
2200
- return result + ';'
2201
- }
2202
-
2203
- generatePrivateIdentifier(node) {
2204
- return '#' + node.name
2205
- }
2206
-
2207
- generateBlockStatement(node) {
2208
- this.indent++
2209
- const body = node.body.map(s => this.getIndent() + this.generate(s)).join('\n')
2210
- this.indent--
2211
- return '{\n' + body + '\n' + this.getIndent() + '}'
2212
- }
2213
-
2214
- generateExpressionStatement(node) {
2215
- return this.generate(node.expression) + ';'
2216
- }
2217
-
2218
- generateEmptyStatement() {
2219
- return ';'
2220
- }
2221
-
2222
- generateReturnStatement(node) {
2223
- if (node.argument) {
2224
- return 'return ' + this.generate(node.argument) + ';'
2225
- }
2226
- return 'return;'
2227
- }
2228
-
2229
- generateBreakStatement(node) {
2230
- if (node.label) {
2231
- return 'break ' + this.generate(node.label) + ';'
2232
- }
2233
- return 'break;'
2234
- }
2235
-
2236
- generateContinueStatement(node) {
2237
- if (node.label) {
2238
- return 'continue ' + this.generate(node.label) + ';'
2239
- }
2240
- return 'continue;'
2241
- }
2242
-
2243
- generateIfStatement(node) {
2244
- let result = 'if (' + this.generate(node.test) + ') ' + this.generate(node.consequent)
2245
- if (node.alternate) {
2246
- result += ' else ' + this.generate(node.alternate)
2247
- }
2248
- return result
2249
- }
2250
-
2251
- generateSwitchStatement(node) {
2252
- let result = 'switch (' + this.generate(node.discriminant) + ') {\n'
2253
- this.indent++
2254
- result += node.cases.map(c => this.getIndent() + this.generate(c)).join('\n')
2255
- this.indent--
2256
- result += '\n' + this.getIndent() + '}'
2257
- return result
2258
- }
2259
-
2260
- generateSwitchCase(node) {
2261
- let result = node.test ? 'case ' + this.generate(node.test) + ':' : 'default:'
2262
- if (node.consequent.length > 0) {
2263
- this.indent++
2264
- result += '\n' + node.consequent.map(s => this.getIndent() + this.generate(s)).join('\n')
2265
- this.indent--
2266
- }
2267
- return result
2268
- }
2269
-
2270
- generateWhileStatement(node) {
2271
- return 'while (' + this.generate(node.test) + ') ' + this.generate(node.body)
2272
- }
2273
-
2274
- generateDoWhileStatement(node) {
2275
- return 'do ' + this.generate(node.body) + ' while (' + this.generate(node.test) + ');'
2276
- }
2277
-
2278
- generateForStatement(node) {
2279
- let result = 'for ('
2280
- if (node.init) {
2281
- if (node.init.type === 'VariableDeclaration') {
2282
- result += node.init.kind + ' ' + node.init.declarations.map(d => this.generate(d)).join(', ')
2283
- } else {
2284
- result += this.generate(node.init)
2285
- }
2286
- }
2287
- result += '; '
2288
- if (node.test) result += this.generate(node.test)
2289
- result += '; '
2290
- if (node.update) result += this.generate(node.update)
2291
- result += ') ' + this.generate(node.body)
2292
- return result
2293
- }
2294
-
2295
- generateForInStatement(node) {
2296
- let left
2297
- if (node.left.type === 'VariableDeclaration') {
2298
- left = node.left.kind + ' ' + this.generate(node.left.declarations[0].id)
2299
- } else {
2300
- left = this.generate(node.left)
2301
- }
2302
- return 'for (' + left + ' in ' + this.generate(node.right) + ') ' + this.generate(node.body)
2303
- }
2304
-
2305
- generateForOfStatement(node) {
2306
- let left
2307
- if (node.left.type === 'VariableDeclaration') {
2308
- left = node.left.kind + ' ' + this.generate(node.left.declarations[0].id)
2309
- } else {
2310
- left = this.generate(node.left)
2311
- }
2312
- const await_ = node.await ? 'await ' : ''
2313
- return 'for ' + await_ + '(' + left + ' of ' + this.generate(node.right) + ') ' + this.generate(node.body)
2314
- }
2315
-
2316
- generateTryStatement(node) {
2317
- let result = 'try ' + this.generate(node.block)
2318
- if (node.handler) {
2319
- result += ' ' + this.generate(node.handler)
2320
- }
2321
- if (node.finalizer) {
2322
- result += ' finally ' + this.generate(node.finalizer)
2323
- }
2324
- return result
2325
- }
2326
-
2327
- generateCatchClause(node) {
2328
- let result = 'catch'
2329
- if (node.param) {
2330
- result += ' (' + this.generate(node.param) + ')'
2331
- }
2332
- result += ' ' + this.generate(node.body)
2333
- return result
2334
- }
2335
-
2336
- generateThrowStatement(node) {
2337
- return 'throw ' + this.generate(node.argument) + ';'
2338
- }
2339
-
2340
- generateDebuggerStatement() {
2341
- return 'debugger;'
2342
- }
2343
-
2344
- generateBinaryExpression(node) {
2345
- return '(' + this.generate(node.left) + ' ' + node.operator + ' ' + this.generate(node.right) + ')'
2346
- }
2347
-
2348
- generateLogicalExpression(node) {
2349
- return '(' + this.generate(node.left) + ' ' + node.operator + ' ' + this.generate(node.right) + ')'
2350
- }
2351
-
2352
- generateUnaryExpression(node) {
2353
- if (node.prefix) {
2354
- const space = /[a-z]/i.test(node.operator) ? ' ' : ''
2355
- return node.operator + space + this.generate(node.argument)
2356
- }
2357
- return this.generate(node.argument) + node.operator
2358
- }
2359
-
2360
- generateUpdateExpression(node) {
2361
- if (node.prefix) {
2362
- return node.operator + this.generate(node.argument)
2363
- }
2364
- return this.generate(node.argument) + node.operator
2365
- }
2366
-
2367
- generateAssignmentExpression(node) {
2368
- return this.generate(node.left) + ' ' + node.operator + ' ' + this.generate(node.right)
2369
- }
2370
-
2371
- generateConditionalExpression(node) {
2372
- return '(' + this.generate(node.test) + ' ? ' + this.generate(node.consequent) + ' : ' + this.generate(node.alternate) + ')'
2373
- }
2374
-
2375
- generateCallExpression(node) {
2376
- const callee = this.generate(node.callee)
2377
- const args = node.arguments.map(a => this.generate(a)).join(', ')
2378
- const opt = node.optional ? '?.' : ''
2379
- return callee + opt + '(' + args + ')'
2380
- }
2381
-
2382
- generateNewExpression(node) {
2383
- const callee = this.generate(node.callee)
2384
- const args = node.arguments.map(a => this.generate(a)).join(', ')
2385
- return 'new ' + callee + '(' + args + ')'
2386
- }
2387
-
2388
- generateMemberExpression(node) {
2389
- const obj = this.generate(node.object)
2390
- const prop = this.generate(node.property)
2391
- const opt = node.optional ? '?' : ''
2392
-
2393
- if (node.computed) {
2394
- return obj + opt + '[' + prop + ']'
2395
- }
2396
- return obj + opt + '.' + prop
2397
- }
2398
-
2399
- generateThisExpression() {
2400
- return 'this'
2401
- }
2402
-
2403
- generateSuper() {
2404
- return 'super'
2405
- }
2406
-
2407
- generateSpreadElement(node) {
2408
- return '...' + this.generate(node.argument)
2409
- }
2410
-
2411
- generateRestElement(node) {
2412
- return '...' + this.generate(node.argument)
2413
- }
2414
-
2415
- generateYieldExpression(node) {
2416
- let result = 'yield'
2417
- if (node.delegate) result += '*'
2418
- if (node.argument) result += ' ' + this.generate(node.argument)
2419
- return result
2420
- }
2421
-
2422
- generateAwaitExpression(node) {
2423
- return 'await ' + this.generate(node.argument)
2424
- }
2425
-
2426
- generateArrayExpression(node) {
2427
- const elements = node.elements.map(e => e ? this.generate(e) : '').join(', ')
2428
- return '[' + elements + ']'
2429
- }
2430
-
2431
- generateObjectExpression(node) {
2432
- if (node.properties.length === 0) return '{}'
2433
-
2434
- this.indent++
2435
- const props = node.properties.map(p => this.getIndent() + this.generate(p)).join(',\n')
2436
- this.indent--
2437
- return '{\n' + props + '\n' + this.getIndent() + '}'
2438
- }
2439
-
2440
- generateProperty(node) {
2441
- if (node.type === 'SpreadElement') {
2442
- return this.generate(node)
2443
- }
2444
-
2445
- if (node.shorthand) {
2446
- return this.generate(node.key)
2447
- }
2448
-
2449
- let result = ''
2450
- if (node.kind === 'get') result += 'get '
2451
- if (node.kind === 'set') result += 'set '
2452
-
2453
- if (node.computed) {
2454
- result += '[' + this.generate(node.key) + ']'
2455
- } else {
2456
- result += this.generate(node.key)
2457
- }
2458
-
2459
- if (node.method) {
2460
- result += '(' + node.value.params.map(p => this.generate(p)).join(', ') + ') '
2461
- result += this.generate(node.value.body)
2462
- } else {
2463
- result += ': ' + this.generate(node.value)
2464
- }
2465
-
2466
- return result
2467
- }
2468
-
2469
- generateArrayPattern(node) {
2470
- const elements = node.elements.map(e => e ? this.generate(e) : '').join(', ')
2471
- return '[' + elements + ']'
2472
- }
2473
-
2474
- generateObjectPattern(node) {
2475
- const props = node.properties.map(p => this.generate(p)).join(', ')
2476
- return '{ ' + props + ' }'
2477
- }
2478
-
2479
- generateAssignmentPattern(node) {
2480
- return this.generate(node.left) + ' = ' + this.generate(node.right)
2481
- }
2482
-
2483
- generateImportDeclaration(node) {
2484
- if (node.specifiers.length === 0) {
2485
- return 'import ' + this.generate(node.source) + ';'
2486
- }
2487
-
2488
- const specifiers = []
2489
- let defaultSpec = null
2490
- let namespaceSpec = null
2491
- const namedSpecs = []
2492
-
2493
- for (const spec of node.specifiers) {
2494
- if (spec.type === 'ImportDefaultSpecifier') {
2495
- defaultSpec = this.generate(spec.local)
2496
- } else if (spec.type === 'ImportNamespaceSpecifier') {
2497
- namespaceSpec = '* as ' + this.generate(spec.local)
2498
- } else {
2499
- const imported = this.generate(spec.imported)
2500
- const local = this.generate(spec.local)
2501
- if (imported === local) {
2502
- namedSpecs.push(imported)
2503
- } else {
2504
- namedSpecs.push(imported + ' as ' + local)
2505
- }
2506
- }
2507
- }
2508
-
2509
- if (defaultSpec) specifiers.push(defaultSpec)
2510
- if (namespaceSpec) specifiers.push(namespaceSpec)
2511
- if (namedSpecs.length > 0) specifiers.push('{ ' + namedSpecs.join(', ') + ' }')
2512
-
2513
- return 'import ' + specifiers.join(', ') + ' from ' + this.generate(node.source) + ';'
2514
- }
2515
-
2516
- generateExportNamedDeclaration(node) {
2517
- if (node.declaration) {
2518
- return 'export ' + this.generate(node.declaration)
2519
- }
2520
-
2521
- const specifiers = node.specifiers.map(s => {
2522
- const local = this.generate(s.local)
2523
- const exported = this.generate(s.exported)
2524
- return local === exported ? local : local + ' as ' + exported
2525
- }).join(', ')
2526
-
2527
- let result = 'export { ' + specifiers + ' }'
2528
- if (node.source) {
2529
- result += ' from ' + this.generate(node.source)
2530
- }
2531
- return result + ';'
2532
- }
2533
-
2534
- generateExportDefaultDeclaration(node) {
2535
- return 'export default ' + this.generate(node.declaration) + (node.declaration.type?.includes('Declaration') ? '' : ';')
2536
- }
2537
-
2538
- generateExportAllDeclaration(node) {
2539
- let result = 'export *'
2540
- if (node.exported) {
2541
- result += ' as ' + this.generate(node.exported)
2542
- }
2543
- result += ' from ' + this.generate(node.source) + ';'
2544
- return result
2545
- }
2546
-
2547
- generateUsingDeclaration(node) {
2548
- let result = ''
2549
- if (node.await) result += 'await '
2550
- result += 'using '
2551
- result += node.declarations.map(d => this.generate(d)).join(', ')
2552
- return result + ';'
2553
- }
2554
-
2555
- getIndent() {
2556
- return this.indentStr.repeat(this.indent)
2557
- }
2558
- }
2559
-
2560
- module.exports = {
2561
- JSLexer,
2562
- JSParser,
2563
- JSCodeGenerator
2564
- }