ether-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +130 -0
  3. package/cli/compiler.js +298 -0
  4. package/cli/ether.js +532 -0
  5. package/cli/watcher.js +106 -0
  6. package/generators/css-generator.js +583 -0
  7. package/generators/graphql-generator.js +868 -0
  8. package/generators/html-generator.js +745 -0
  9. package/generators/js-generator.js +909 -0
  10. package/generators/node-generator.js +467 -0
  11. package/generators/php-generator.js +706 -0
  12. package/generators/python-generator.js +913 -0
  13. package/generators/react-generator.js +599 -0
  14. package/generators/ruby-generator.js +904 -0
  15. package/generators/sql-generator.js +988 -0
  16. package/generators/ts-generator.js +569 -0
  17. package/i18n/i18n-css.json +743 -0
  18. package/i18n/i18n-graphql.json +1531 -0
  19. package/i18n/i18n-html.json +572 -0
  20. package/i18n/i18n-js.json +2790 -0
  21. package/i18n/i18n-node.json +2442 -0
  22. package/i18n/i18n-php.json +4306 -0
  23. package/i18n/i18n-python.json +3080 -0
  24. package/i18n/i18n-react.json +1784 -0
  25. package/i18n/i18n-ruby.json +1858 -0
  26. package/i18n/i18n-sql.json +3466 -0
  27. package/i18n/i18n-ts.json +442 -0
  28. package/lexer/ether-lexer.js +728 -0
  29. package/lexer/tokens.js +292 -0
  30. package/package.json +45 -0
  31. package/parsers/ast-css.js +545 -0
  32. package/parsers/ast-graphql.js +424 -0
  33. package/parsers/ast-html.js +886 -0
  34. package/parsers/ast-js.js +750 -0
  35. package/parsers/ast-node.js +2440 -0
  36. package/parsers/ast-php.js +957 -0
  37. package/parsers/ast-react.js +580 -0
  38. package/parsers/ast-ruby.js +895 -0
  39. package/parsers/ast-ts.js +1352 -0
  40. package/parsers/css-parser.js +1981 -0
  41. package/parsers/graphql-parser.js +2011 -0
  42. package/parsers/html-parser.js +1181 -0
  43. package/parsers/js-parser.js +2564 -0
  44. package/parsers/node-parser.js +2644 -0
  45. package/parsers/php-parser.js +3037 -0
  46. package/parsers/react-parser.js +1035 -0
  47. package/parsers/ruby-parser.js +2680 -0
  48. package/parsers/ts-parser.js +3881 -0
@@ -0,0 +1,913 @@
1
+ const fs = require('fs')
2
+
3
+ class PythonGenerator {
4
+ constructor(i18nPath = null) {
5
+ this.i18n = null
6
+ this.indent = 0
7
+ this.output = ''
8
+ this.keywordMap = {}
9
+ this.builtinMap = {}
10
+
11
+ if (i18nPath) {
12
+ this.loadI18n(i18nPath)
13
+ }
14
+ }
15
+
16
+ loadI18n(filePath) {
17
+ const content = fs.readFileSync(filePath, 'utf-8')
18
+ this.i18n = JSON.parse(content)
19
+ this.buildMaps()
20
+ }
21
+
22
+ buildMaps() {
23
+ this.keywordMap = {}
24
+ this.builtinMap = {}
25
+
26
+ if (!this.i18n) return
27
+
28
+ const addToMap = (map, section) => {
29
+ if (!section) return
30
+ for (const [key, translations] of Object.entries(section)) {
31
+ if (translations && translations.fr && translations.python) {
32
+ map[translations.fr.toLowerCase()] = translations.python
33
+ }
34
+ }
35
+ }
36
+
37
+ for (const sectionName of Object.keys(this.i18n)) {
38
+ addToMap(this.keywordMap, this.i18n[sectionName])
39
+ }
40
+ }
41
+
42
+ translate(word) {
43
+ if (!word) return ''
44
+ const lower = word.toLowerCase()
45
+ return this.keywordMap[lower] || this.translateGeneric(word)
46
+ }
47
+
48
+ translateGeneric(word) {
49
+ const translations = {
50
+ 'si': 'if',
51
+ 'sinon': 'else',
52
+ 'sinon si': 'elif',
53
+ 'pour': 'for',
54
+ 'dans': 'in',
55
+ 'tant que': 'while',
56
+ 'définir': 'def',
57
+ 'fonction': 'def',
58
+ 'classe': 'class',
59
+ 'retourner': 'return',
60
+ 'produire': 'yield',
61
+ 'passer': 'pass',
62
+ 'sortir': 'break',
63
+ 'continuer': 'continue',
64
+ 'essayer': 'try',
65
+ 'sauf': 'except',
66
+ 'finalement': 'finally',
67
+ 'lever': 'raise',
68
+ 'affirmer': 'assert',
69
+ 'avec': 'with',
70
+ 'comme': 'as',
71
+ 'importer': 'import',
72
+ 'depuis': 'from',
73
+ 'global': 'global',
74
+ 'non local': 'nonlocal',
75
+ 'lambda': 'lambda',
76
+ 'et': 'and',
77
+ 'ou': 'or',
78
+ 'non': 'not',
79
+ 'est': 'is',
80
+ 'vrai': 'True',
81
+ 'faux': 'False',
82
+ 'aucun': 'None',
83
+ 'soi': 'self',
84
+ 'cls': 'cls',
85
+ 'asynchrone': 'asynchrone',
86
+ 'attendre': 'await',
87
+ 'afficher': 'print',
88
+ 'saisir': 'input',
89
+ 'longueur': 'len',
90
+ 'type': 'type',
91
+ 'plage': 'range',
92
+ 'enumerer': 'enumerate',
93
+ 'zipper': 'zip',
94
+ 'mapper': 'map',
95
+ 'filtrer': 'filter',
96
+ 'trier': 'sorted',
97
+ 'inverser': 'reversed',
98
+ 'tout': 'all',
99
+ 'quelconque': 'any',
100
+ 'minimum': 'min',
101
+ 'maximum': 'max',
102
+ 'somme': 'sum',
103
+ 'absolu': 'abs',
104
+ 'arrondir': 'round',
105
+ 'entier': 'int',
106
+ 'flottant': 'float',
107
+ 'chaîne': 'str',
108
+ 'booléen': 'bool',
109
+ 'liste': 'list',
110
+ 'tuple': 'tuple',
111
+ 'ensemble': 'set',
112
+ 'dictionnaire': 'dict',
113
+ 'octets': 'bytes',
114
+ 'ouvrir': 'open',
115
+ 'fermer': 'close',
116
+ 'lire': 'read',
117
+ 'écrire': 'write',
118
+ 'ligne': 'readline',
119
+ 'lignes': 'readlines',
120
+ 'ajouter': 'append',
121
+ 'etendre': 'extend',
122
+ 'insérer': 'insert',
123
+ 'retirer': 'remove',
124
+ 'extraire': 'pop',
125
+ 'vider': 'clear',
126
+ 'copier': 'copy',
127
+ 'compter': 'count',
128
+ 'indice': 'index',
129
+ 'trier liste': 'sort',
130
+ 'inverser liste': 'reverse',
131
+ 'majuscules': 'upper',
132
+ 'minuscules': 'lower',
133
+ 'titre': 'title',
134
+ 'capitaliser': 'capitalize',
135
+ 'supprimer espaces': 'strip',
136
+ 'supprimer gauche': 'lstrip',
137
+ 'supprimer droite': 'rstrip',
138
+ 'diviser': 'split',
139
+ 'joindre': 'join',
140
+ 'remplacer': 'replace',
141
+ 'trouver': 'find',
142
+ 'commence par': 'startswith',
143
+ 'finit par': 'endswith',
144
+ 'est numerique': 'isdigit',
145
+ 'est alpha': 'isalpha',
146
+ 'est alphanumerique': 'isalnum',
147
+ 'est espace': 'isspace',
148
+ 'formater': 'format',
149
+ 'clés': 'keys',
150
+ 'valeurs': 'values',
151
+ 'éléments': 'items',
152
+ 'obtenir': 'get',
153
+ 'définir défaut': 'setdefault',
154
+ 'mettre a jour': 'update',
155
+ 'union': 'union',
156
+ 'intersection': 'intersection',
157
+ 'difference': 'difference',
158
+ 'sous ensemble': 'issubset',
159
+ 'sur ensemble': 'issuperset',
160
+ 'exception': 'Exception',
161
+ 'erreur valeur': 'ValueError',
162
+ 'erreur type': 'TypeError',
163
+ 'erreur clé': 'KeyError',
164
+ 'erreur index': 'IndexError',
165
+ 'erreur attribut': 'AttributeError',
166
+ 'erreur fichier': 'FileNotFoundError',
167
+ 'erreur zero': 'ZeroDivisionError',
168
+ 'decorateur': '@',
169
+ 'propriété': 'property',
170
+ 'méthode statique': 'staticmethod',
171
+ 'méthode classe': 'classmethod',
172
+ 'super': 'super',
173
+ 'init': '__init__',
174
+ 'constructeur': '__init__',
175
+ 'representer': '__repr__',
176
+ 'chaîne dunder': '__str__',
177
+ 'iterateur': '__iter__',
178
+ 'suivant': '__next__',
179
+ 'longueur dunder': '__len__',
180
+ 'obtenir item': '__getitem__',
181
+ 'définir item': '__setitem__',
182
+ 'supprimer item': '__delitem__',
183
+ 'contient': '__contains__',
184
+ 'appeler': '__call__',
185
+ 'entrer': '__enter__',
186
+ 'sortir dunder': '__exit__'
187
+ }
188
+
189
+ const lower = word.toLowerCase()
190
+ return translations[lower] || word
191
+ }
192
+
193
+ generate(ast) {
194
+ this.output = ''
195
+ this.indent = 0
196
+
197
+ if (Array.isArray(ast)) {
198
+ for (const node of ast) {
199
+ const result = this.generateNode(node)
200
+ if (result !== undefined && result !== '' && this.output === '') {
201
+ return result
202
+ }
203
+ }
204
+ } else if (ast && ast.type) {
205
+ const result = this.generateNode(ast)
206
+ if (result !== undefined && result !== '' && this.output === '') {
207
+ return result
208
+ }
209
+ } else if (ast && ast.body) {
210
+ for (const node of ast.body) {
211
+ const result = this.generateNode(node)
212
+ if (result !== undefined && result !== '' && this.output === '') {
213
+ return result
214
+ }
215
+ }
216
+ }
217
+
218
+ return this.output.trim()
219
+ }
220
+
221
+ generateNode(node) {
222
+ if (!node) return ''
223
+
224
+ switch (node.type) {
225
+ case 'Module':
226
+ return this.generateModule(node)
227
+ case 'ImportStatement':
228
+ return this.generateImport(node)
229
+ case 'FromImportStatement':
230
+ return this.generateFromImport(node)
231
+ case 'FunctionDef':
232
+ case 'FunctionDeclaration':
233
+ return this.generateFunction(node)
234
+ case 'AsyncFunctionDef':
235
+ return this.generateAsyncFunction(node)
236
+ case 'ClassDef':
237
+ case 'ClassDeclaration':
238
+ return this.generateClass(node)
239
+ case 'IfStatement':
240
+ return this.generateIf(node)
241
+ case 'ForStatement':
242
+ return this.generateFor(node)
243
+ case 'WhileStatement':
244
+ return this.generateWhile(node)
245
+ case 'TryStatement':
246
+ return this.generateTry(node)
247
+ case 'WithStatement':
248
+ return this.generateWith(node)
249
+ case 'ReturnStatement':
250
+ return this.generateReturn(node)
251
+ case 'YieldStatement':
252
+ return this.generateYield(node)
253
+ case 'RaiseStatement':
254
+ return this.generateRaise(node)
255
+ case 'AssertStatement':
256
+ return this.generateAssert(node)
257
+ case 'PassStatement':
258
+ this.writeLine('pass')
259
+ return
260
+ case 'BreakStatement':
261
+ this.writeLine('break')
262
+ return
263
+ case 'ContinueStatement':
264
+ this.writeLine('continue')
265
+ return
266
+ case 'ExpressionStatement':
267
+ return this.generateExpressionStatement(node)
268
+ case 'AssignmentStatement':
269
+ case 'AssignmentExpression':
270
+ return this.generateAssignment(node)
271
+ case 'AugmentedAssignment':
272
+ return this.generateAugmentedAssignment(node)
273
+ case 'Decorator':
274
+ return this.generateDecorator(node)
275
+ case 'CallExpression':
276
+ return this.generateCall(node)
277
+ case 'BinaryExpression':
278
+ return this.generateBinary(node)
279
+ case 'UnaryExpression':
280
+ return this.generateUnary(node)
281
+ case 'CompareExpression':
282
+ return this.generateCompare(node)
283
+ case 'BoolOp':
284
+ return this.generateBoolOp(node)
285
+ case 'IfExpression':
286
+ case 'ConditionalExpression':
287
+ return this.generateIfExpr(node)
288
+ case 'ListExpression':
289
+ case 'ArrayExpression':
290
+ return this.generateList(node)
291
+ case 'DictExpression':
292
+ case 'ObjectExpression':
293
+ return this.generateDict(node)
294
+ case 'SetExpression':
295
+ return this.generateSet(node)
296
+ case 'TupleExpression':
297
+ return this.generateTuple(node)
298
+ case 'ListComprehension':
299
+ return this.generateListComp(node)
300
+ case 'DictComprehension':
301
+ return this.generateDictComp(node)
302
+ case 'SetComprehension':
303
+ return this.generateSetComp(node)
304
+ case 'GeneratorExpression':
305
+ return this.generateGenExpr(node)
306
+ case 'LambdaExpression':
307
+ return this.generateLambda(node)
308
+ case 'Subscript':
309
+ case 'MemberExpression':
310
+ return this.generateSubscript(node)
311
+ case 'Attribute':
312
+ return this.generateAttribute(node)
313
+ case 'Slice':
314
+ return this.generateSlice(node)
315
+ case 'FString':
316
+ case 'TemplateLiteral':
317
+ return this.generateFString(node)
318
+ case 'Identifier':
319
+ return this.translate(node.name)
320
+ case 'Literal':
321
+ return this.generateLiteral(node)
322
+ default:
323
+ return ''
324
+ }
325
+ }
326
+
327
+ generateModule(node) {
328
+ for (const stmt of node.body || []) {
329
+ this.generateNode(stmt)
330
+ }
331
+ }
332
+
333
+ generateImport(node) {
334
+ const names = (node.names || [node.name]).map(n => {
335
+ if (typeof n === 'string') return this.translate(n)
336
+ let result = this.translate(n.name)
337
+ if (n.alias) result += ' as ' + n.alias
338
+ return result
339
+ })
340
+ this.writeLine('import ' + names.join(', '))
341
+ }
342
+
343
+ generateFromImport(node) {
344
+ const module = this.translate(node.module)
345
+ const names = (node.names || []).map(n => {
346
+ if (typeof n === 'string') return this.translate(n)
347
+ let result = this.translate(n.name)
348
+ if (n.alias) result += ' as ' + n.alias
349
+ return result
350
+ })
351
+ this.writeLine(`from ${module} import ${names.join(', ')}`)
352
+ }
353
+
354
+ generateFunction(node) {
355
+ if (node.decorators) {
356
+ for (const dec of node.decorators) {
357
+ this.generateDecorator(dec)
358
+ }
359
+ }
360
+
361
+ const name = this.translate(node.name || node.id?.name || '')
362
+ const params = this.generateParams(node.params || node.args || [])
363
+ const returnType = node.returnType ? ' -> ' + this.translate(node.returnType) : ''
364
+
365
+ this.writeLine(`def ${name}(${params})${returnType}:`)
366
+ this.indent++
367
+
368
+ if (node.docstring) {
369
+ this.writeLine(`"""${node.docstring}"""`)
370
+ }
371
+
372
+ const body = node.body?.body || node.body || []
373
+ if (body.length === 0) {
374
+ this.writeLine('pass')
375
+ } else {
376
+ for (const stmt of body) {
377
+ this.generateNode(stmt)
378
+ }
379
+ }
380
+
381
+ this.indent--
382
+ this.writeLine('')
383
+ }
384
+
385
+ generateAsyncFunction(node) {
386
+ if (node.decorators) {
387
+ for (const dec of node.decorators) {
388
+ this.generateDecorator(dec)
389
+ }
390
+ }
391
+
392
+ const name = this.translate(node.name || '')
393
+ const params = this.generateParams(node.params || [])
394
+
395
+ this.writeLine(`async def ${name}(${params}):`)
396
+ this.indent++
397
+
398
+ const body = node.body?.body || node.body || []
399
+ if (body.length === 0) {
400
+ this.writeLine('pass')
401
+ } else {
402
+ for (const stmt of body) {
403
+ this.generateNode(stmt)
404
+ }
405
+ }
406
+
407
+ this.indent--
408
+ this.writeLine('')
409
+ }
410
+
411
+ generateParams(params) {
412
+ return params.map(p => {
413
+ let param = ''
414
+
415
+ if (p.kind === 'vararg' || p.vararg) {
416
+ param = '*'
417
+ } else if (p.kind === 'kwarg' || p.kwarg) {
418
+ param = '**'
419
+ }
420
+
421
+ param += this.translate(p.name || p.arg || p)
422
+
423
+ if (p.annotation || p.type) {
424
+ param += ': ' + this.translate(p.annotation || p.type)
425
+ }
426
+
427
+ if (p.default !== undefined) {
428
+ param += ' = ' + this.generateNode(p.default)
429
+ }
430
+
431
+ return param
432
+ }).join(', ')
433
+ }
434
+
435
+ generateClass(node) {
436
+ if (node.decorators) {
437
+ for (const dec of node.decorators) {
438
+ this.generateDecorator(dec)
439
+ }
440
+ }
441
+
442
+ const name = node.name || node.id?.name || ''
443
+ const bases = (node.bases || node.extends || []).map(b =>
444
+ typeof b === 'string' ? b : this.generateNode(b)
445
+ )
446
+ const basesStr = bases.length > 0 ? `(${bases.join(', ')})` : ''
447
+
448
+ this.writeLine(`class ${name}${basesStr}:`)
449
+ this.indent++
450
+
451
+ if (node.docstring) {
452
+ this.writeLine(`"""${node.docstring}"""`)
453
+ }
454
+
455
+ const body = node.body?.body || node.body || []
456
+ if (body.length === 0) {
457
+ this.writeLine('pass')
458
+ } else {
459
+ for (const member of body) {
460
+ this.generateNode(member)
461
+ }
462
+ }
463
+
464
+ this.indent--
465
+ this.writeLine('')
466
+ }
467
+
468
+ generateDecorator(node) {
469
+ let name = ''
470
+ if (typeof node === 'string') {
471
+ name = node
472
+ } else if (typeof node.name === 'string') {
473
+ name = this.translate(node.name)
474
+ } else if (node.name?.name) {
475
+ name = this.translate(node.name.name)
476
+ } else {
477
+ name = this.generateNode(node)
478
+ }
479
+ const args = node.arguments ?
480
+ '(' + node.arguments.map(a => this.generateNode(a)).join(', ') + ')' : ''
481
+ this.writeLine(`@${name}${args}`)
482
+ }
483
+
484
+ generateIf(node) {
485
+ const test = this.generateNode(node.test)
486
+ this.writeLine(`if ${test}:`)
487
+ this.indent++
488
+
489
+ const consequent = node.consequent?.body || node.consequent || node.body || []
490
+ for (const stmt of (Array.isArray(consequent) ? consequent : [consequent])) {
491
+ this.generateNode(stmt)
492
+ }
493
+
494
+ this.indent--
495
+
496
+ if (node.alternate || node.orelse) {
497
+ const alt = node.alternate || node.orelse
498
+ if (alt.type === 'IfStatement' || (Array.isArray(alt) && alt[0]?.type === 'IfStatement')) {
499
+ const elif = Array.isArray(alt) ? alt[0] : alt
500
+ this.output = this.output.trimEnd() + '\n'
501
+ const elifTest = this.generateNode(elif.test)
502
+ this.writeLine(`elif ${elifTest}:`)
503
+ this.indent++
504
+ const elifBody = elif.consequent?.body || elif.consequent || elif.body || []
505
+ for (const stmt of (Array.isArray(elifBody) ? elifBody : [elifBody])) {
506
+ this.generateNode(stmt)
507
+ }
508
+ this.indent--
509
+ if (elif.alternate || elif.orelse) {
510
+ const nextAlt = elif.alternate || elif.orelse
511
+ if (nextAlt.type === 'IfStatement') {
512
+ this.generateIf({ ...nextAlt, isElif: true })
513
+ } else {
514
+ this.writeLine('else:')
515
+ this.indent++
516
+ const nextBody = Array.isArray(nextAlt) ? nextAlt : [nextAlt]
517
+ for (const stmt of nextBody) {
518
+ this.generateNode(stmt)
519
+ }
520
+ this.indent--
521
+ }
522
+ }
523
+ } else {
524
+ this.writeLine('else:')
525
+ this.indent++
526
+ const altBody = Array.isArray(alt) ? alt : [alt]
527
+ for (const stmt of altBody) {
528
+ this.generateNode(stmt)
529
+ }
530
+ this.indent--
531
+ }
532
+ }
533
+ }
534
+
535
+ generateFor(node) {
536
+ const target = this.generateNode(node.target || node.left)
537
+ const iter = this.generateNode(node.iter || node.right)
538
+
539
+ this.writeLine(`for ${target} in ${iter}:`)
540
+ this.indent++
541
+
542
+ const body = node.body?.body || node.body || []
543
+ for (const stmt of (Array.isArray(body) ? body : [body])) {
544
+ this.generateNode(stmt)
545
+ }
546
+
547
+ this.indent--
548
+
549
+ if (node.orelse && node.orelse.length > 0) {
550
+ this.writeLine('else:')
551
+ this.indent++
552
+ for (const stmt of node.orelse) {
553
+ this.generateNode(stmt)
554
+ }
555
+ this.indent--
556
+ }
557
+ }
558
+
559
+ generateWhile(node) {
560
+ const test = this.generateNode(node.test)
561
+
562
+ this.writeLine(`while ${test}:`)
563
+ this.indent++
564
+
565
+ const body = node.body?.body || node.body || []
566
+ for (const stmt of (Array.isArray(body) ? body : [body])) {
567
+ this.generateNode(stmt)
568
+ }
569
+
570
+ this.indent--
571
+ }
572
+
573
+ generateTry(node) {
574
+ this.writeLine('try:')
575
+ this.indent++
576
+
577
+ const tryBody = node.body?.body || node.body || node.block?.body || node.block || []
578
+ for (const stmt of (Array.isArray(tryBody) ? tryBody : [tryBody])) {
579
+ this.generateNode(stmt)
580
+ }
581
+
582
+ this.indent--
583
+
584
+ for (const handler of node.handlers || (node.handler ? [node.handler] : [])) {
585
+ let exceptLine = 'except'
586
+ if (handler.type) {
587
+ exceptLine += ' ' + this.translate(handler.type)
588
+ if (handler.name || handler.param) {
589
+ exceptLine += ' as ' + (handler.name || this.generateNode(handler.param))
590
+ }
591
+ }
592
+ this.writeLine(exceptLine + ':')
593
+ this.indent++
594
+
595
+ const handlerBody = handler.body?.body || handler.body || []
596
+ for (const stmt of (Array.isArray(handlerBody) ? handlerBody : [handlerBody])) {
597
+ this.generateNode(stmt)
598
+ }
599
+
600
+ this.indent--
601
+ }
602
+
603
+ if (node.orelse && node.orelse.length > 0) {
604
+ this.writeLine('else:')
605
+ this.indent++
606
+ for (const stmt of node.orelse) {
607
+ this.generateNode(stmt)
608
+ }
609
+ this.indent--
610
+ }
611
+
612
+ if (node.finalbody || node.finalizer) {
613
+ this.writeLine('finally:')
614
+ this.indent++
615
+ const finalBody = node.finalbody || node.finalizer?.body || node.finalizer || []
616
+ for (const stmt of (Array.isArray(finalBody) ? finalBody : [finalBody])) {
617
+ this.generateNode(stmt)
618
+ }
619
+ this.indent--
620
+ }
621
+ }
622
+
623
+ generateWith(node) {
624
+ const items = (node.items || [node]).map(item => {
625
+ let result = this.generateNode(item.context_expr || item.expression)
626
+ if (item.optional_vars || item.alias) {
627
+ result += ' as ' + this.generateNode(item.optional_vars || item.alias)
628
+ }
629
+ return result
630
+ })
631
+
632
+ this.writeLine(`with ${items.join(', ')}:`)
633
+ this.indent++
634
+
635
+ const body = node.body?.body || node.body || []
636
+ for (const stmt of (Array.isArray(body) ? body : [body])) {
637
+ this.generateNode(stmt)
638
+ }
639
+
640
+ this.indent--
641
+ }
642
+
643
+ generateReturn(node) {
644
+ if (node.value || node.argument) {
645
+ const value = this.generateNode(node.value || node.argument)
646
+ this.writeLine(`return ${value}`)
647
+ } else {
648
+ this.writeLine('return')
649
+ }
650
+ }
651
+
652
+ generateYield(node) {
653
+ if (node.value) {
654
+ const value = this.generateNode(node.value)
655
+ if (node.from) {
656
+ this.writeLine(`yield from ${value}`)
657
+ } else {
658
+ this.writeLine(`yield ${value}`)
659
+ }
660
+ } else {
661
+ this.writeLine('yield')
662
+ }
663
+ }
664
+
665
+ generateRaise(node) {
666
+ if (node.exc || node.argument) {
667
+ const exc = this.generateNode(node.exc || node.argument)
668
+ if (node.cause) {
669
+ this.writeLine(`raise ${exc} from ${this.generateNode(node.cause)}`)
670
+ } else {
671
+ this.writeLine(`raise ${exc}`)
672
+ }
673
+ } else {
674
+ this.writeLine('raise')
675
+ }
676
+ }
677
+
678
+ generateAssert(node) {
679
+ const test = this.generateNode(node.test)
680
+ if (node.msg) {
681
+ this.writeLine(`assert ${test}, ${this.generateNode(node.msg)}`)
682
+ } else {
683
+ this.writeLine(`assert ${test}`)
684
+ }
685
+ }
686
+
687
+ generateExpressionStatement(node) {
688
+ const expr = this.generateNode(node.expression)
689
+ this.writeLine(expr)
690
+ }
691
+
692
+ generateAssignment(node) {
693
+ const targets = (node.targets || [node.left]).map(t => this.generateNode(t))
694
+ const value = this.generateNode(node.value || node.right)
695
+ this.writeLine(`${targets.join(' = ')} = ${value}`)
696
+ }
697
+
698
+ generateAugmentedAssignment(node) {
699
+ const target = this.generateNode(node.target)
700
+ const value = this.generateNode(node.value)
701
+ const op = node.op || node.operator
702
+ this.writeLine(`${target} ${op}= ${value}`)
703
+ }
704
+
705
+ generateCall(node) {
706
+ const func = this.generateNode(node.func || node.callee)
707
+ const args = (node.args || node.arguments || []).map(a => this.generateNode(a))
708
+ const kwargs = (node.keywords || []).map(kw =>
709
+ `${kw.arg}=${this.generateNode(kw.value)}`
710
+ )
711
+ const allArgs = [...args, ...kwargs].join(', ')
712
+ return `${func}(${allArgs})`
713
+ }
714
+
715
+ generateBinary(node) {
716
+ const left = this.generateNode(node.left)
717
+ const right = this.generateNode(node.right)
718
+ const op = this.translateOperator(node.op || node.operator)
719
+ return `${left} ${op} ${right}`
720
+ }
721
+
722
+ generateUnary(node) {
723
+ const operand = this.generateNode(node.operand || node.argument)
724
+ const op = this.translateOperator(node.op || node.operator)
725
+ if (op === 'not') {
726
+ return `not ${operand}`
727
+ }
728
+ return `${op}${operand}`
729
+ }
730
+
731
+ generateCompare(node) {
732
+ let result = this.generateNode(node.left)
733
+ const ops = node.ops || [node.operator]
734
+ const comparators = node.comparators || [node.right]
735
+
736
+ for (let i = 0; i < ops.length; i++) {
737
+ result += ' ' + this.translateOperator(ops[i]) + ' ' + this.generateNode(comparators[i])
738
+ }
739
+
740
+ return result
741
+ }
742
+
743
+ generateBoolOp(node) {
744
+ const op = node.op === 'And' || node.op === 'et' ? ' and ' : ' or '
745
+ return node.values.map(v => this.generateNode(v)).join(op)
746
+ }
747
+
748
+ generateIfExpr(node) {
749
+ const body = this.generateNode(node.body || node.consequent)
750
+ const test = this.generateNode(node.test)
751
+ const orelse = this.generateNode(node.orelse || node.alternate)
752
+ return `${body} if ${test} else ${orelse}`
753
+ }
754
+
755
+ generateList(node) {
756
+ const elements = (node.elts || node.elements || []).map(e => this.generateNode(e))
757
+ return `[${elements.join(', ')}]`
758
+ }
759
+
760
+ generateDict(node) {
761
+ const pairs = []
762
+ const keys = node.keys || []
763
+ const values = node.values || []
764
+
765
+ if (node.properties) {
766
+ for (const prop of node.properties) {
767
+ const key = this.generateNode(prop.key)
768
+ const value = this.generateNode(prop.value)
769
+ pairs.push(`${key}: ${value}`)
770
+ }
771
+ } else {
772
+ for (let i = 0; i < keys.length; i++) {
773
+ const key = this.generateNode(keys[i])
774
+ const value = this.generateNode(values[i])
775
+ pairs.push(`${key}: ${value}`)
776
+ }
777
+ }
778
+
779
+ return `{${pairs.join(', ')}}`
780
+ }
781
+
782
+ generateSet(node) {
783
+ const elements = (node.elts || node.elements || []).map(e => this.generateNode(e))
784
+ return `{${elements.join(', ')}}`
785
+ }
786
+
787
+ generateTuple(node) {
788
+ const elements = (node.elts || node.elements || []).map(e => this.generateNode(e))
789
+ if (elements.length === 1) {
790
+ return `(${elements[0]},)`
791
+ }
792
+ return `(${elements.join(', ')})`
793
+ }
794
+
795
+ generateListComp(node) {
796
+ const elt = this.generateNode(node.elt || node.element)
797
+ const generators = (node.generators || []).map(g => this.generateComprehensionGen(g))
798
+ return `[${elt} ${generators.join(' ')}]`
799
+ }
800
+
801
+ generateDictComp(node) {
802
+ const key = this.generateNode(node.key)
803
+ const value = this.generateNode(node.value)
804
+ const generators = (node.generators || []).map(g => this.generateComprehensionGen(g))
805
+ return `{${key}: ${value} ${generators.join(' ')}}`
806
+ }
807
+
808
+ generateSetComp(node) {
809
+ const elt = this.generateNode(node.elt || node.element)
810
+ const generators = (node.generators || []).map(g => this.generateComprehensionGen(g))
811
+ return `{${elt} ${generators.join(' ')}}`
812
+ }
813
+
814
+ generateGenExpr(node) {
815
+ const elt = this.generateNode(node.elt || node.element)
816
+ const generators = (node.generators || []).map(g => this.generateComprehensionGen(g))
817
+ return `(${elt} ${generators.join(' ')})`
818
+ }
819
+
820
+ generateComprehensionGen(gen) {
821
+ const target = this.generateNode(gen.target)
822
+ const iter = this.generateNode(gen.iter)
823
+ let result = `for ${target} in ${iter}`
824
+
825
+ for (const if_ of gen.ifs || []) {
826
+ result += ` if ${this.generateNode(if_)}`
827
+ }
828
+
829
+ return result
830
+ }
831
+
832
+ generateLambda(node) {
833
+ const args = this.generateParams(node.args?.args || node.params || [])
834
+ const body = this.generateNode(node.body)
835
+ return `lambda ${args}: ${body}`
836
+ }
837
+
838
+ generateSubscript(node) {
839
+ const value = this.generateNode(node.value || node.object)
840
+ const slice = this.generateNode(node.slice || node.property)
841
+
842
+ if (node.computed === false) {
843
+ return `${value}.${slice}`
844
+ }
845
+
846
+ return `${value}[${slice}]`
847
+ }
848
+
849
+ generateAttribute(node) {
850
+ const value = this.generateNode(node.value)
851
+ const attr = this.translate(node.attr)
852
+ return `${value}.${attr}`
853
+ }
854
+
855
+ generateSlice(node) {
856
+ const lower = node.lower ? this.generateNode(node.lower) : ''
857
+ const upper = node.upper ? this.generateNode(node.upper) : ''
858
+ const step = node.step ? ':' + this.generateNode(node.step) : ''
859
+ return `${lower}:${upper}${step}`
860
+ }
861
+
862
+ generateFString(node) {
863
+ let result = 'f"'
864
+ for (const part of node.values || node.parts || []) {
865
+ if (part.type === 'Literal' || typeof part === 'string') {
866
+ result += typeof part === 'string' ? part : part.value
867
+ } else {
868
+ result += '{' + this.generateNode(part.value || part) + '}'
869
+ }
870
+ }
871
+ result += '"'
872
+ return result
873
+ }
874
+
875
+ generateLiteral(node) {
876
+ if (node.value === null || node.value === undefined) return 'None'
877
+ if (node.value === true) return 'True'
878
+ if (node.value === false) return 'False'
879
+ if (typeof node.value === 'string') {
880
+ return `"${node.value.replace(/"/g, '\\"')}"`
881
+ }
882
+ return String(node.value)
883
+ }
884
+
885
+ translateOperator(op) {
886
+ const operators = {
887
+ 'et': 'and',
888
+ 'ou': 'or',
889
+ 'non': 'not',
890
+ 'est': 'is',
891
+ 'dans': 'in',
892
+ 'pas dans': 'not in',
893
+ 'est pas': 'is not',
894
+ 'egal': '==',
895
+ 'different': '!=',
896
+ 'puissance': '**',
897
+ 'div entiere': '//'
898
+ }
899
+ return operators[op] || op
900
+ }
901
+
902
+ writeLine(text) {
903
+ this.output += this.getIndent() + text + '\n'
904
+ }
905
+
906
+ getIndent() {
907
+ return ' '.repeat(this.indent)
908
+ }
909
+ }
910
+
911
+ module.exports = {
912
+ PythonGenerator
913
+ }