ether-code 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/ether.js +1 -1
- package/generators/php-generator.js +570 -459
- package/i18n/i18n-php.json +464 -4414
- package/package.json +1 -1
- package/parsers/ether-parser-php.js +2404 -0
- package/parsers/ether-parser.js +3 -0
|
@@ -5,6 +5,8 @@ class PHPGenerator {
|
|
|
5
5
|
this.i18n = null
|
|
6
6
|
this.indent = 0
|
|
7
7
|
this.output = ''
|
|
8
|
+
this.translationMap = {}
|
|
9
|
+
this.supportedLanguages = ['fr', 'en', 'es', 'ru', 'zh', 'ja']
|
|
8
10
|
|
|
9
11
|
if (i18nPath) {
|
|
10
12
|
this.loadI18n(i18nPath)
|
|
@@ -14,447 +16,260 @@ class PHPGenerator {
|
|
|
14
16
|
loadI18n(filePath) {
|
|
15
17
|
const content = fs.readFileSync(filePath, 'utf-8')
|
|
16
18
|
this.i18n = JSON.parse(content)
|
|
17
|
-
this.
|
|
19
|
+
this.buildTranslationMap()
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
this.
|
|
22
|
-
this.functionMap = {}
|
|
22
|
+
buildTranslationMap() {
|
|
23
|
+
this.translationMap = {}
|
|
23
24
|
|
|
24
25
|
if (!this.i18n) return
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
for (const [sectionName, section] of Object.entries(this.i18n)) {
|
|
37
|
-
if (typeof section === 'object' && section !== null) {
|
|
38
|
-
addToMap(map, section)
|
|
27
|
+
for (const [sectionName, section] of Object.entries(this.i18n)) {
|
|
28
|
+
if (sectionName === 'metadata' || typeof section !== 'object') continue
|
|
29
|
+
|
|
30
|
+
for (const lang of this.supportedLanguages) {
|
|
31
|
+
if (!section[lang]) continue
|
|
32
|
+
|
|
33
|
+
for (const [etherWord, phpCode] of Object.entries(section[lang])) {
|
|
34
|
+
const normalizedKey = etherWord.toLowerCase().trim()
|
|
35
|
+
const cleanPhp = this.cleanPhpValue(phpCode)
|
|
36
|
+
this.translationMap[normalizedKey] = cleanPhp
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
}
|
|
40
|
+
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
cleanPhpValue(value) {
|
|
43
|
+
if (typeof value !== 'string') return value
|
|
44
|
+
let cleaned = value.replace(/\(\)$/, '')
|
|
45
|
+
return cleaned
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
translate(word) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
'cas': 'case',
|
|
67
|
-
'defaut': 'default',
|
|
68
|
-
'sortir': 'break',
|
|
69
|
-
'continuer': 'continue',
|
|
70
|
-
'essayer': 'try',
|
|
71
|
-
'attraper': 'catch',
|
|
72
|
-
'finalement': 'finally',
|
|
73
|
-
'lancer': 'throw',
|
|
74
|
-
'nouveau': 'new',
|
|
75
|
-
'classe': 'class',
|
|
76
|
-
'interface': 'interface',
|
|
77
|
-
'trait': 'trait',
|
|
78
|
-
'etend': 'extends',
|
|
79
|
-
'implemente': 'implements',
|
|
80
|
-
'utiliser': 'use',
|
|
81
|
-
'public': 'public',
|
|
82
|
-
'prive': 'private',
|
|
83
|
-
'protege': 'protected',
|
|
84
|
-
'statique': 'static',
|
|
85
|
-
'final': 'final',
|
|
86
|
-
'abstrait': 'abstract',
|
|
87
|
-
'constructeur': '__construct',
|
|
88
|
-
'destructeur': '__destruct',
|
|
89
|
-
'obtenir': '__get',
|
|
90
|
-
'definir': '__set',
|
|
91
|
-
'appeler': '__call',
|
|
92
|
-
'vers chaine': '__toString',
|
|
93
|
-
'espace de noms': 'namespace',
|
|
94
|
-
'comme': 'as',
|
|
95
|
-
'vrai': 'true',
|
|
96
|
-
'faux': 'false',
|
|
97
|
-
'nul': 'null',
|
|
98
|
-
'ceci': '$this',
|
|
99
|
-
'parent': 'parent',
|
|
100
|
-
'soi': 'self',
|
|
101
|
-
'et': '&&',
|
|
102
|
-
'ou': '||',
|
|
103
|
-
'non': '!',
|
|
104
|
-
'egal': '===',
|
|
105
|
-
'different': '!==',
|
|
106
|
-
'concatener': '.',
|
|
107
|
-
'tableau': 'array',
|
|
108
|
-
'chaine': 'string',
|
|
109
|
-
'entier': 'int',
|
|
110
|
-
'flottant': 'float',
|
|
111
|
-
'booleen': 'bool',
|
|
112
|
-
'objet': 'object',
|
|
113
|
-
'vide': 'void',
|
|
114
|
-
'mixte': 'mixed',
|
|
115
|
-
'afficher': 'echo',
|
|
116
|
-
'imprimer': 'print',
|
|
117
|
-
'longueur': 'strlen',
|
|
118
|
-
'compter': 'count',
|
|
119
|
-
'exploser': 'explode',
|
|
120
|
-
'imploser': 'implode',
|
|
121
|
-
'remplacer': 'str_replace',
|
|
122
|
-
'position': 'strpos',
|
|
123
|
-
'sous chaine': 'substr',
|
|
124
|
-
'majuscules': 'strtoupper',
|
|
125
|
-
'minuscules': 'strtolower',
|
|
126
|
-
'supprimer espaces': 'trim',
|
|
127
|
-
'ajouter': 'array_push',
|
|
128
|
-
'retirer': 'array_pop',
|
|
129
|
-
'fusionner': 'array_merge',
|
|
130
|
-
'filtrer': 'array_filter',
|
|
131
|
-
'mapper': 'array_map',
|
|
132
|
-
'reduire': 'array_reduce',
|
|
133
|
-
'trier': 'sort',
|
|
134
|
-
'inverser': 'array_reverse',
|
|
135
|
-
'cles': 'array_keys',
|
|
136
|
-
'valeurs': 'array_values',
|
|
137
|
-
'existe': 'isset',
|
|
138
|
-
'vide test': 'empty',
|
|
139
|
-
'est tableau': 'is_array',
|
|
140
|
-
'est chaine': 'is_string',
|
|
141
|
-
'est entier': 'is_int',
|
|
142
|
-
'est flottant': 'is_float',
|
|
143
|
-
'est numerique': 'is_numeric',
|
|
144
|
-
'est nul': 'is_null',
|
|
145
|
-
'type de': 'gettype',
|
|
146
|
-
'convertir chaine': 'strval',
|
|
147
|
-
'convertir entier': 'intval',
|
|
148
|
-
'convertir flottant': 'floatval',
|
|
149
|
-
'convertir booleen': 'boolval',
|
|
150
|
-
'definir type': 'settype',
|
|
151
|
-
'date': 'date',
|
|
152
|
-
'temps': 'time',
|
|
153
|
-
'maintenant': 'now',
|
|
154
|
-
'fichier existe': 'file_exists',
|
|
155
|
-
'lire fichier': 'file_get_contents',
|
|
156
|
-
'ecrire fichier': 'file_put_contents',
|
|
157
|
-
'ouvrir': 'fopen',
|
|
158
|
-
'fermer': 'fclose',
|
|
159
|
-
'lire': 'fread',
|
|
160
|
-
'ecrire': 'fwrite',
|
|
161
|
-
'json encoder': 'json_encode',
|
|
162
|
-
'json decoder': 'json_decode',
|
|
163
|
-
'regex correspondance': 'preg_match',
|
|
164
|
-
'regex toutes': 'preg_match_all',
|
|
165
|
-
'regex remplacer': 'preg_replace',
|
|
166
|
-
'en tete': 'header',
|
|
167
|
-
'rediriger': 'header',
|
|
168
|
-
'session demarrer': 'session_start',
|
|
169
|
-
'session': '$_SESSION',
|
|
170
|
-
'post': '$_POST',
|
|
171
|
-
'get': '$_GET',
|
|
172
|
-
'requete': '$_REQUEST',
|
|
173
|
-
'serveur': '$_SERVER',
|
|
174
|
-
'fichiers': '$_FILES',
|
|
175
|
-
'cookie': '$_COOKIE',
|
|
176
|
-
'mourir': 'die',
|
|
177
|
-
'sortie': 'exit',
|
|
178
|
-
'inclure': 'include',
|
|
179
|
-
'inclure une fois': 'include_once',
|
|
180
|
-
'requiert': 'require',
|
|
181
|
-
'requiert une fois': 'require_once',
|
|
182
|
-
'mapper tableau': 'array_map',
|
|
183
|
-
'filtrer tableau': 'array_filter',
|
|
184
|
-
'reduire tableau': 'array_reduce',
|
|
185
|
-
'parcourir tableau': 'array_walk',
|
|
186
|
-
'parcourir recursif': 'array_walk_recursive',
|
|
187
|
-
'decaler tableau': 'array_shift',
|
|
188
|
-
'depiler tableau': 'array_pop',
|
|
189
|
-
'empiler tableau': 'array_push',
|
|
190
|
-
'prefixer tableau': 'array_unshift',
|
|
191
|
-
'chercher tableau': 'array_search',
|
|
192
|
-
'cle existe tableau': 'array_key_exists',
|
|
193
|
-
'dans tableau': 'in_array',
|
|
194
|
-
'somme tableau': 'array_sum',
|
|
195
|
-
'produit tableau': 'array_product',
|
|
196
|
-
'compter valeurs': 'array_count_values',
|
|
197
|
-
'aleatoire tableau': 'array_rand',
|
|
198
|
-
'element courant': 'current',
|
|
199
|
-
'element suivant': 'next',
|
|
200
|
-
'element precedent': 'prev',
|
|
201
|
-
'cle courante': 'key',
|
|
202
|
-
'premier element': 'reset',
|
|
203
|
-
'dernier element': 'end',
|
|
204
|
-
'remplir tableau': 'array_fill',
|
|
205
|
-
'remplir cles tableau': 'array_fill_keys',
|
|
206
|
-
'rembourrer tableau': 'array_pad',
|
|
207
|
-
'plage': 'range',
|
|
208
|
-
'fonction existe': 'function_exists',
|
|
209
|
-
'classe existe': 'class_exists',
|
|
210
|
-
'methode existe': 'method_exists',
|
|
211
|
-
'propriete existe': 'property_exists',
|
|
212
|
-
'interface existe': 'interface_exists',
|
|
213
|
-
'trait existe': 'trait_exists',
|
|
214
|
-
'obtenir classe': 'get_class',
|
|
215
|
-
'obtenir parent classe': 'get_parent_class',
|
|
216
|
-
'obtenir methodes classe': 'get_class_methods',
|
|
217
|
-
'obtenir variables classe': 'get_class_vars',
|
|
218
|
-
'obtenir variables objet': 'get_object_vars',
|
|
219
|
-
'est instance de': 'is_a',
|
|
220
|
-
'est sous-classe de': 'is_subclass_of',
|
|
221
|
-
'classes declarees': 'get_declared_classes',
|
|
222
|
-
'interfaces declarees': 'get_declared_interfaces',
|
|
223
|
-
'traits declares': 'get_declared_traits',
|
|
224
|
-
'entete http': 'header',
|
|
225
|
-
'entetes envoyes': 'headers_sent',
|
|
226
|
-
'liste entetes': 'headers_list',
|
|
227
|
-
'retirer entete': 'header_remove',
|
|
228
|
-
'code reponse http': 'http_response_code',
|
|
229
|
-
'analyser url': 'parse_url',
|
|
230
|
-
'construire requete http': 'http_build_query',
|
|
231
|
-
'analyser parametres': 'parse_str',
|
|
232
|
-
'encoder url': 'urlencode',
|
|
233
|
-
'decoder url': 'urldecode',
|
|
234
|
-
'encoder url brut': 'rawurlencode',
|
|
235
|
-
'decoder url brut': 'rawurldecode',
|
|
236
|
-
'encoder base64': 'base64_encode',
|
|
237
|
-
'decoder base64': 'base64_decode',
|
|
238
|
-
'hacher mot de passe': 'password_hash',
|
|
239
|
-
'verifier mot de passe': 'password_verify',
|
|
240
|
-
'rehachage necessaire': 'password_needs_rehash',
|
|
241
|
-
'info mot de passe': 'password_get_info',
|
|
242
|
-
'bcrypt par defaut': 'PASSWORD_DEFAULT',
|
|
243
|
-
'bcrypt': 'PASSWORD_BCRYPT',
|
|
244
|
-
'argon2i': 'PASSWORD_ARGON2I',
|
|
245
|
-
'argon2id': 'PASSWORD_ARGON2ID',
|
|
246
|
-
'appeler fonction utilisateur': 'call_user_func',
|
|
247
|
-
'appeler avec arguments': 'call_user_func_array',
|
|
248
|
-
'creer fonction': 'create_function',
|
|
249
|
-
'filtrer variable': 'filter_var',
|
|
250
|
-
'filtrer entree': 'filter_input',
|
|
251
|
-
'filtrer tableau entree': 'filter_input_array',
|
|
252
|
-
'filtrer tableau variable': 'filter_var_array',
|
|
253
|
-
'liste filtres': 'filter_list',
|
|
254
|
-
'id filtre': 'filter_id',
|
|
255
|
-
'valider email': 'FILTER_VALIDATE_EMAIL',
|
|
256
|
-
'valider url': 'FILTER_VALIDATE_URL',
|
|
257
|
-
'valider ip': 'FILTER_VALIDATE_IP',
|
|
258
|
-
'valider entier': 'FILTER_VALIDATE_INT',
|
|
259
|
-
'valider flottant': 'FILTER_VALIDATE_FLOAT',
|
|
260
|
-
'valider booleen': 'FILTER_VALIDATE_BOOLEAN',
|
|
261
|
-
'nettoyer chaine': 'FILTER_SANITIZE_STRING',
|
|
262
|
-
'nettoyer email': 'FILTER_SANITIZE_EMAIL',
|
|
263
|
-
'nettoyer url': 'FILTER_SANITIZE_URL',
|
|
264
|
-
'nettoyer entier': 'FILTER_SANITIZE_NUMBER_INT',
|
|
265
|
-
'nettoyer flottant': 'FILTER_SANITIZE_NUMBER_FLOAT',
|
|
266
|
-
'obtenir config': 'ini_get',
|
|
267
|
-
'definir config': 'ini_set',
|
|
268
|
-
'restaurer config': 'ini_restore',
|
|
269
|
-
'toutes configs': 'ini_get_all',
|
|
270
|
-
'obtenir environnement': 'getenv',
|
|
271
|
-
'definir environnement': 'putenv',
|
|
272
|
-
'version php': 'phpversion',
|
|
273
|
-
'info php': 'phpinfo',
|
|
274
|
-
'comparer versions': 'version_compare',
|
|
275
|
-
'extension chargee': 'extension_loaded',
|
|
276
|
-
'extensions chargees': 'get_loaded_extensions',
|
|
277
|
-
'formater chaine': 'sprintf',
|
|
278
|
-
'afficher formate': 'printf',
|
|
279
|
-
'formater vers flux': 'fprintf',
|
|
280
|
-
'formater avec tableau': 'vsprintf',
|
|
281
|
-
'afficher avec tableau': 'vprintf',
|
|
282
|
-
'analyser formate': 'sscanf',
|
|
283
|
-
'formater nombre': 'number_format',
|
|
284
|
-
'formater monnaie': 'money_format',
|
|
285
|
-
'ajouter echappements': 'addslashes',
|
|
286
|
-
'retirer echappements': 'stripslashes',
|
|
287
|
-
'ajouter echappements c': 'addcslashes',
|
|
288
|
-
'retirer echappements c': 'stripcslashes',
|
|
289
|
-
'citer meta': 'quotemeta',
|
|
290
|
-
'compacter': 'compact',
|
|
291
|
-
'extraire': 'extract',
|
|
292
|
-
'variables definies': 'get_defined_vars',
|
|
293
|
-
'enregistrer autoload': 'spl_autoload_register',
|
|
294
|
-
'desenregistrer autoload': 'spl_autoload_unregister',
|
|
295
|
-
'fonctions autoload': 'spl_autoload_functions',
|
|
296
|
-
'autoload': 'spl_autoload',
|
|
297
|
-
'extensions autoload': 'spl_autoload_extensions',
|
|
298
|
-
'hacher': 'hash',
|
|
299
|
-
'hacher fichier': 'hash_file',
|
|
300
|
-
'hacher hmac': 'hash_hmac',
|
|
301
|
-
'algorithmes hachage': 'hash_algos',
|
|
302
|
-
'md5': 'md5',
|
|
303
|
-
'md5 fichier': 'md5_file',
|
|
304
|
-
'sha1': 'sha1',
|
|
305
|
-
'sha1 fichier': 'sha1_file',
|
|
306
|
-
'crc32': 'crc32',
|
|
307
|
-
'octets aleatoires': 'random_bytes',
|
|
308
|
-
'entier aleatoire': 'random_int',
|
|
309
|
-
'traduire caracteres': 'strtr',
|
|
310
|
-
'sous-chaine compte': 'substr_count',
|
|
311
|
-
'sous-chaine remplacer': 'substr_replace',
|
|
312
|
-
'comparer sous-chaine': 'substr_compare',
|
|
313
|
-
'chercher chaine': 'strstr',
|
|
314
|
-
'chercher insensible': 'stristr',
|
|
315
|
-
'chercher caractere': 'strchr',
|
|
316
|
-
'chercher caractere inverse': 'strrchr',
|
|
317
|
-
'dormir': 'sleep',
|
|
318
|
-
'dormir micro': 'usleep',
|
|
319
|
-
'memoire utilisee': 'memory_get_usage',
|
|
320
|
-
'memoire pic': 'memory_get_peak_usage',
|
|
321
|
-
'limite memoire': "ini_get('memory_limit')",
|
|
322
|
-
'chemin inclus': 'get_include_path',
|
|
323
|
-
'definir chemin inclus': 'set_include_path'
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const lower = word.toLowerCase()
|
|
327
|
-
return translations[lower] || word
|
|
49
|
+
if (!word || typeof word !== 'string') return word
|
|
50
|
+
|
|
51
|
+
const normalized = word.toLowerCase().trim()
|
|
52
|
+
|
|
53
|
+
if (this.translationMap[normalized]) {
|
|
54
|
+
return this.translationMap[normalized]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const withoutAccents = this.removeAccents(normalized)
|
|
58
|
+
if (this.translationMap[withoutAccents]) {
|
|
59
|
+
return this.translationMap[withoutAccents]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return word
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
removeAccents(str) {
|
|
66
|
+
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
|
328
67
|
}
|
|
329
68
|
|
|
330
69
|
generate(ast) {
|
|
331
|
-
this.output = '<?php\n
|
|
70
|
+
this.output = '<?php\n'
|
|
332
71
|
this.indent = 0
|
|
72
|
+
|
|
73
|
+
if (ast.strict) {
|
|
74
|
+
this.writeLine("declare(strict_types=1);")
|
|
75
|
+
this.writeLine('')
|
|
76
|
+
}
|
|
333
77
|
|
|
334
|
-
if (Array.isArray(ast)) {
|
|
335
|
-
for (const node of ast) {
|
|
336
|
-
this.generateNode(node)
|
|
337
|
-
}
|
|
338
|
-
} else if (ast && ast.type) {
|
|
339
|
-
this.generateNode(ast)
|
|
340
|
-
} else if (ast && ast.body) {
|
|
78
|
+
if (Array.isArray(ast.body)) {
|
|
341
79
|
for (const node of ast.body) {
|
|
342
80
|
this.generateNode(node)
|
|
343
81
|
}
|
|
82
|
+
} else if (ast.body) {
|
|
83
|
+
this.generateNode(ast.body)
|
|
84
|
+
} else {
|
|
85
|
+
this.generateNode(ast)
|
|
344
86
|
}
|
|
345
87
|
|
|
346
|
-
return this.output
|
|
88
|
+
return this.output
|
|
347
89
|
}
|
|
348
90
|
|
|
349
91
|
generateNode(node) {
|
|
350
92
|
if (!node) return ''
|
|
351
93
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
case 'Literal':
|
|
410
|
-
return this.generateLiteral(node)
|
|
411
|
-
case 'NewExpression':
|
|
412
|
-
return this.generateNewExpression(node)
|
|
413
|
-
default:
|
|
414
|
-
return ''
|
|
94
|
+
if (Array.isArray(node)) {
|
|
95
|
+
return node.map(n => this.generateNode(n)).join('')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const type = node.type || node.nodeType
|
|
99
|
+
|
|
100
|
+
const generators = {
|
|
101
|
+
'Program': () => this.generateProgram(node),
|
|
102
|
+
'FunctionDeclaration': () => this.generateFunctionDeclaration(node),
|
|
103
|
+
'ClassDeclaration': () => this.generateClassDeclaration(node),
|
|
104
|
+
'InterfaceDeclaration': () => this.generateInterfaceDeclaration(node),
|
|
105
|
+
'TraitDeclaration': () => this.generateTraitDeclaration(node),
|
|
106
|
+
'EnumDeclaration': () => this.generateEnumDeclaration(node),
|
|
107
|
+
'MethodDefinition': () => this.generateMethodDefinition(node),
|
|
108
|
+
'PropertyDeclaration': () => this.generatePropertyDeclaration(node),
|
|
109
|
+
'VariableDeclaration': () => this.generateVariableDeclaration(node),
|
|
110
|
+
'ConstantDeclaration': () => this.generateConstantDeclaration(node),
|
|
111
|
+
'IfStatement': () => this.generateIfStatement(node),
|
|
112
|
+
'ForStatement': () => this.generateForStatement(node),
|
|
113
|
+
'ForEachStatement': () => this.generateForEachStatement(node),
|
|
114
|
+
'ForeachStatement': () => this.generateForEachStatement(node),
|
|
115
|
+
'WhileStatement': () => this.generateWhileStatement(node),
|
|
116
|
+
'DoWhileStatement': () => this.generateDoWhileStatement(node),
|
|
117
|
+
'SwitchStatement': () => this.generateSwitchStatement(node),
|
|
118
|
+
'MatchExpression': () => this.generateMatchExpression(node),
|
|
119
|
+
'TryStatement': () => this.generateTryStatement(node),
|
|
120
|
+
'ReturnStatement': () => this.generateReturnStatement(node),
|
|
121
|
+
'ThrowStatement': () => this.generateThrowStatement(node),
|
|
122
|
+
'BreakStatement': () => this.writeLine('break;'),
|
|
123
|
+
'ContinueStatement': () => this.writeLine('continue;'),
|
|
124
|
+
'ExpressionStatement': () => this.generateExpressionStatement(node),
|
|
125
|
+
'EchoStatement': () => this.generateEchoStatement(node),
|
|
126
|
+
'PrintStatement': () => this.generatePrintStatement(node),
|
|
127
|
+
'Namespace': () => this.generateNamespace(node),
|
|
128
|
+
'UseStatement': () => this.generateUseStatement(node),
|
|
129
|
+
'IncludeStatement': () => this.generateIncludeStatement(node),
|
|
130
|
+
'Include': () => this.generateInclude(node),
|
|
131
|
+
'CallExpression': () => this.generateCallExpression(node),
|
|
132
|
+
'MemberExpression': () => this.generateMemberExpression(node),
|
|
133
|
+
'BinaryExpression': () => this.generateBinaryExpression(node),
|
|
134
|
+
'LogicalExpression': () => this.generateBinaryExpression(node),
|
|
135
|
+
'UnaryExpression': () => this.generateUnaryExpression(node),
|
|
136
|
+
'AssignmentExpression': () => this.generateAssignmentExpression(node),
|
|
137
|
+
'UpdateExpression': () => this.generateUpdateExpression(node),
|
|
138
|
+
'ConditionalExpression': () => this.generateConditionalExpression(node),
|
|
139
|
+
'NullCoalescing': () => this.generateNullCoalescing(node),
|
|
140
|
+
'ArrayExpression': () => this.generateArrayExpression(node),
|
|
141
|
+
'ObjectExpression': () => this.generateObjectExpression(node),
|
|
142
|
+
'ArrowFunction': () => this.generateArrowFunction(node),
|
|
143
|
+
'Closure': () => this.generateClosure(node),
|
|
144
|
+
'Identifier': () => this.generateIdentifier(node),
|
|
145
|
+
'Literal': () => this.generateLiteral(node),
|
|
146
|
+
'NewExpression': () => this.generateNewExpression(node),
|
|
147
|
+
'InstanceOf': () => this.generateInstanceOf(node),
|
|
148
|
+
'BlockStatement': () => this.generateBlockStatement(node),
|
|
149
|
+
'EmptyStatement': () => '',
|
|
150
|
+
'Comment': () => ''
|
|
415
151
|
}
|
|
152
|
+
|
|
153
|
+
if (generators[type]) {
|
|
154
|
+
return generators[type]()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (node.expression) {
|
|
158
|
+
return this.generateNode(node.expression)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return ''
|
|
416
162
|
}
|
|
417
163
|
|
|
418
|
-
|
|
419
|
-
for (const
|
|
420
|
-
|
|
421
|
-
if (decl.init) {
|
|
422
|
-
const value = this.generateNode(decl.init)
|
|
423
|
-
this.writeLine(`${name} = ${value};`)
|
|
424
|
-
} else {
|
|
425
|
-
this.writeLine(`${name} = null;`)
|
|
426
|
-
}
|
|
164
|
+
generateProgram(node) {
|
|
165
|
+
for (const stmt of node.body || []) {
|
|
166
|
+
this.generateNode(stmt)
|
|
427
167
|
}
|
|
428
168
|
}
|
|
429
169
|
|
|
430
170
|
generateFunctionDeclaration(node) {
|
|
431
|
-
const name =
|
|
432
|
-
const params = (node.params || [])
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
171
|
+
const name = this.translate(node.name || node.id?.name || 'anonymous')
|
|
172
|
+
const params = this.generateParams(node.params || [])
|
|
173
|
+
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
174
|
+
|
|
175
|
+
this.writeLine(`function ${name}(${params})${returnType} {`)
|
|
176
|
+
this.indent++
|
|
177
|
+
this.generateNode(node.body)
|
|
178
|
+
this.indent--
|
|
179
|
+
this.writeLine('}')
|
|
180
|
+
this.writeLine('')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
generateParams(params) {
|
|
184
|
+
return params.map(p => {
|
|
185
|
+
let result = ''
|
|
186
|
+
|
|
187
|
+
if (p.visibility) {
|
|
188
|
+
result += this.translate(p.visibility) + ' '
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (p.type) {
|
|
192
|
+
result += this.translateType(p.type) + ' '
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (p.variadic) {
|
|
196
|
+
result += '...'
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (p.reference) {
|
|
200
|
+
result += '&'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const name = p.name || p.id?.name || p
|
|
204
|
+
result += '$' + this.translate(typeof name === 'string' ? name : name.name || 'param')
|
|
205
|
+
|
|
206
|
+
if (p.default !== undefined) {
|
|
207
|
+
result += ' = ' + this.generateNode(p.default)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return result
|
|
437
211
|
}).join(', ')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
translateType(type) {
|
|
215
|
+
if (!type) return ''
|
|
438
216
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
217
|
+
if (typeof type === 'string') {
|
|
218
|
+
const translated = this.translate(type)
|
|
219
|
+
const typeMap = {
|
|
220
|
+
'chaîne': 'string', 'chaine': 'string', 'string': 'string',
|
|
221
|
+
'entier': 'int', 'integer': 'int', 'int': 'int',
|
|
222
|
+
'flottant': 'float', 'float': 'float',
|
|
223
|
+
'booléen': 'bool', 'booleen': 'bool', 'boolean': 'bool', 'bool': 'bool',
|
|
224
|
+
'tableau': 'array', 'array': 'array',
|
|
225
|
+
'objet': 'object', 'object': 'object',
|
|
226
|
+
'nul': 'null', 'null': 'null',
|
|
227
|
+
'vide': 'void', 'void': 'void',
|
|
228
|
+
'mixte': 'mixed', 'mixed': 'mixed',
|
|
229
|
+
'appelable': 'callable', 'callable': 'callable',
|
|
230
|
+
'itérable': 'iterable', 'iterable': 'iterable',
|
|
231
|
+
'jamais': 'never', 'never': 'never'
|
|
232
|
+
}
|
|
233
|
+
return typeMap[translated.toLowerCase()] || typeMap[type.toLowerCase()] || type
|
|
234
|
+
}
|
|
442
235
|
|
|
443
|
-
|
|
236
|
+
if (type.union) {
|
|
237
|
+
return type.types.map(t => this.translateType(t)).join('|')
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (type.intersection) {
|
|
241
|
+
return type.types.map(t => this.translateType(t)).join('&')
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (type.nullable) {
|
|
245
|
+
return '?' + this.translateType(type.type)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return type.name || type
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
generateClassDeclaration(node) {
|
|
252
|
+
let declaration = ''
|
|
253
|
+
|
|
254
|
+
if (node.abstract) declaration += 'abstract '
|
|
255
|
+
if (node.final) declaration += 'final '
|
|
256
|
+
if (node.readonly) declaration += 'readonly '
|
|
257
|
+
|
|
258
|
+
declaration += 'class ' + this.translate(node.name || node.id?.name)
|
|
259
|
+
|
|
260
|
+
if (node.extends) {
|
|
261
|
+
declaration += ' extends ' + this.translate(node.extends)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (node.implements && node.implements.length > 0) {
|
|
265
|
+
declaration += ' implements ' + node.implements.map(i => this.translate(i)).join(', ')
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.writeLine(declaration + ' {')
|
|
444
269
|
this.indent++
|
|
445
270
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
for (const stmt of node.body) {
|
|
449
|
-
this.generateNode(stmt)
|
|
450
|
-
}
|
|
451
|
-
} else if (node.body.body) {
|
|
452
|
-
for (const stmt of node.body.body) {
|
|
453
|
-
this.generateNode(stmt)
|
|
454
|
-
}
|
|
455
|
-
} else {
|
|
456
|
-
this.generateNode(node.body)
|
|
457
|
-
}
|
|
271
|
+
for (const member of node.body || node.members || []) {
|
|
272
|
+
this.generateNode(member)
|
|
458
273
|
}
|
|
459
274
|
|
|
460
275
|
this.indent--
|
|
@@ -462,57 +277,201 @@ class PHPGenerator {
|
|
|
462
277
|
this.writeLine('')
|
|
463
278
|
}
|
|
464
279
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
let declaration = 'class ' + name
|
|
280
|
+
generateInterfaceDeclaration(node) {
|
|
281
|
+
let declaration = 'interface ' + this.translate(node.name || node.id?.name)
|
|
468
282
|
|
|
469
|
-
if (node.
|
|
470
|
-
declaration += ' extends ' +
|
|
283
|
+
if (node.extends && node.extends.length > 0) {
|
|
284
|
+
declaration += ' extends ' + node.extends.map(e => this.translate(e)).join(', ')
|
|
471
285
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
286
|
+
|
|
287
|
+
this.writeLine(declaration + ' {')
|
|
288
|
+
this.indent++
|
|
289
|
+
|
|
290
|
+
for (const member of node.body || node.members || []) {
|
|
291
|
+
this.generateNode(member)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.indent--
|
|
295
|
+
this.writeLine('}')
|
|
296
|
+
this.writeLine('')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
generateTraitDeclaration(node) {
|
|
300
|
+
this.writeLine('trait ' + this.translate(node.name || node.id?.name) + ' {')
|
|
301
|
+
this.indent++
|
|
302
|
+
|
|
303
|
+
for (const member of node.body || node.members || []) {
|
|
304
|
+
this.generateNode(member)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
this.indent--
|
|
308
|
+
this.writeLine('}')
|
|
309
|
+
this.writeLine('')
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
generateEnumDeclaration(node) {
|
|
313
|
+
let declaration = 'enum ' + this.translate(node.name || node.id?.name)
|
|
314
|
+
|
|
315
|
+
if (node.backingType) {
|
|
316
|
+
declaration += ': ' + this.translateType(node.backingType)
|
|
475
317
|
}
|
|
476
318
|
|
|
477
319
|
this.writeLine(declaration + ' {')
|
|
478
320
|
this.indent++
|
|
479
321
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
for (const member of body) {
|
|
484
|
-
this.generateNode(member)
|
|
485
|
-
}
|
|
322
|
+
for (const member of node.cases || node.members || []) {
|
|
323
|
+
if (member.value !== undefined) {
|
|
324
|
+
this.writeLine(`case ${member.name} = ${this.generateNode(member.value)};`)
|
|
486
325
|
} else {
|
|
487
|
-
this.
|
|
326
|
+
this.writeLine(`case ${member.name};`)
|
|
488
327
|
}
|
|
489
328
|
}
|
|
490
329
|
|
|
330
|
+
for (const method of node.methods || []) {
|
|
331
|
+
this.generateNode(method)
|
|
332
|
+
}
|
|
333
|
+
|
|
491
334
|
this.indent--
|
|
492
335
|
this.writeLine('}')
|
|
493
336
|
this.writeLine('')
|
|
494
337
|
}
|
|
495
338
|
|
|
339
|
+
generateMethodDefinition(node) {
|
|
340
|
+
let declaration = ''
|
|
341
|
+
|
|
342
|
+
const visibility = node.visibility || node.access || 'public'
|
|
343
|
+
declaration += this.translate(visibility) + ' '
|
|
344
|
+
|
|
345
|
+
if (node.static) declaration += 'static '
|
|
346
|
+
if (node.final) declaration += 'final '
|
|
347
|
+
if (node.abstract) declaration += 'abstract '
|
|
348
|
+
|
|
349
|
+
const name = this.translateMethodName(node.name || node.key?.name)
|
|
350
|
+
const params = this.generateParams(node.params || node.value?.params || [])
|
|
351
|
+
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
352
|
+
|
|
353
|
+
if (node.abstract) {
|
|
354
|
+
this.writeLine(`${declaration}function ${name}(${params})${returnType};`)
|
|
355
|
+
} else {
|
|
356
|
+
this.writeLine(`${declaration}function ${name}(${params})${returnType} {`)
|
|
357
|
+
this.indent++
|
|
358
|
+
this.generateNode(node.body || node.value?.body)
|
|
359
|
+
this.indent--
|
|
360
|
+
this.writeLine('}')
|
|
361
|
+
}
|
|
362
|
+
this.writeLine('')
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
translateMethodName(name) {
|
|
366
|
+
if (!name) return 'method'
|
|
367
|
+
|
|
368
|
+
const magicMethods = {
|
|
369
|
+
'constructeur': '__construct',
|
|
370
|
+
'constructor': '__construct',
|
|
371
|
+
'destructeur': '__destruct',
|
|
372
|
+
'destructor': '__destruct',
|
|
373
|
+
'obtenir': '__get',
|
|
374
|
+
'get': '__get',
|
|
375
|
+
'définir': '__set',
|
|
376
|
+
'definir': '__set',
|
|
377
|
+
'set': '__set',
|
|
378
|
+
'appeler': '__call',
|
|
379
|
+
'call': '__call',
|
|
380
|
+
'appeler statique': '__callStatic',
|
|
381
|
+
'call static': '__callStatic',
|
|
382
|
+
'vers chaîne': '__toString',
|
|
383
|
+
'vers chaine': '__toString',
|
|
384
|
+
'to string': '__toString',
|
|
385
|
+
'invoquer': '__invoke',
|
|
386
|
+
'invoke': '__invoke',
|
|
387
|
+
'cloner': '__clone',
|
|
388
|
+
'clone': '__clone',
|
|
389
|
+
'dormir': '__sleep',
|
|
390
|
+
'sleep': '__sleep',
|
|
391
|
+
'réveiller': '__wakeup',
|
|
392
|
+
'reveiller': '__wakeup',
|
|
393
|
+
'wakeup': '__wakeup',
|
|
394
|
+
'sérialiser': '__serialize',
|
|
395
|
+
'serialiser': '__serialize',
|
|
396
|
+
'serialize': '__serialize',
|
|
397
|
+
'désérialiser': '__unserialize',
|
|
398
|
+
'deserialiser': '__unserialize',
|
|
399
|
+
'unserialize': '__unserialize',
|
|
400
|
+
'isset': '__isset',
|
|
401
|
+
'existe propriété': '__isset',
|
|
402
|
+
'existe propriete': '__isset',
|
|
403
|
+
'unset': '__unset',
|
|
404
|
+
'détruire propriété': '__unset',
|
|
405
|
+
'detruire propriete': '__unset',
|
|
406
|
+
'déboguer info': '__debugInfo',
|
|
407
|
+
'deboguer info': '__debugInfo',
|
|
408
|
+
'debug info': '__debugInfo'
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const normalized = name.toLowerCase().trim()
|
|
412
|
+
return magicMethods[normalized] || this.translate(name)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
generatePropertyDeclaration(node) {
|
|
416
|
+
let declaration = ''
|
|
417
|
+
|
|
418
|
+
const visibility = node.visibility || node.access || 'public'
|
|
419
|
+
declaration += this.translate(visibility) + ' '
|
|
420
|
+
|
|
421
|
+
if (node.static) declaration += 'static '
|
|
422
|
+
if (node.readonly) declaration += 'readonly '
|
|
423
|
+
|
|
424
|
+
if (node.type) {
|
|
425
|
+
declaration += this.translateType(node.type) + ' '
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const name = this.translate(node.name || node.key?.name)
|
|
429
|
+
declaration += '$' + name
|
|
430
|
+
|
|
431
|
+
if (node.value !== undefined) {
|
|
432
|
+
declaration += ' = ' + this.generateNode(node.value)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
this.writeLine(declaration + ';')
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
generateVariableDeclaration(node) {
|
|
439
|
+
for (const decl of node.declarations || [node]) {
|
|
440
|
+
const name = decl.name || decl.id?.name || decl.id
|
|
441
|
+
const varName = '$' + this.translate(typeof name === 'string' ? name : name.name || 'var')
|
|
442
|
+
|
|
443
|
+
if (decl.init !== undefined) {
|
|
444
|
+
const value = this.generateNode(decl.init)
|
|
445
|
+
this.writeLine(`${varName} = ${value};`)
|
|
446
|
+
} else {
|
|
447
|
+
this.writeLine(`${varName} = null;`)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
generateConstantDeclaration(node) {
|
|
453
|
+
const name = node.name || node.id?.name
|
|
454
|
+
const value = this.generateNode(node.value || node.init)
|
|
455
|
+
|
|
456
|
+
if (node.classLevel) {
|
|
457
|
+
const visibility = node.visibility ? this.translate(node.visibility) + ' ' : ''
|
|
458
|
+
this.writeLine(`${visibility}const ${name.toUpperCase()} = ${value};`)
|
|
459
|
+
} else {
|
|
460
|
+
this.writeLine(`define('${name.toUpperCase()}', ${value});`)
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
496
464
|
generateIfStatement(node) {
|
|
497
465
|
const test = this.generateNode(node.test)
|
|
498
466
|
this.writeLine(`if (${test}) {`)
|
|
499
467
|
this.indent++
|
|
500
468
|
this.generateNode(node.consequent)
|
|
501
469
|
this.indent--
|
|
502
|
-
|
|
470
|
+
|
|
503
471
|
if (node.alternate) {
|
|
504
472
|
if (node.alternate.type === 'IfStatement') {
|
|
505
|
-
this.
|
|
506
|
-
|
|
507
|
-
this.output += `(${altTest}) {\n`
|
|
508
|
-
this.indent++
|
|
509
|
-
this.generateNode(node.alternate.consequent)
|
|
510
|
-
this.indent--
|
|
511
|
-
if (node.alternate.alternate) {
|
|
512
|
-
this.generateIfStatement({ alternate: node.alternate.alternate })
|
|
513
|
-
} else {
|
|
514
|
-
this.writeLine('}')
|
|
515
|
-
}
|
|
473
|
+
this.write('} else')
|
|
474
|
+
this.generateIfStatement({ ...node.alternate, isElseIf: true })
|
|
516
475
|
} else {
|
|
517
476
|
this.writeLine('} else {')
|
|
518
477
|
this.indent++
|
|
@@ -538,9 +497,9 @@ class PHPGenerator {
|
|
|
538
497
|
}
|
|
539
498
|
|
|
540
499
|
generateForEachStatement(node) {
|
|
541
|
-
const array = this.generateNode(node.array || node.right)
|
|
542
|
-
const value = this.generateIdentifier(node.value || node.left)
|
|
543
|
-
const key = node.key ? this.generateIdentifier(node.key) + ' => ' : ''
|
|
500
|
+
const array = this.generateNode(node.array || node.right || node.iterable)
|
|
501
|
+
const value = this.generateIdentifier(node.value || node.left || node.valueVar)
|
|
502
|
+
const key = node.key || node.keyVar ? this.generateIdentifier(node.key || node.keyVar) + ' => ' : ''
|
|
544
503
|
|
|
545
504
|
this.writeLine(`foreach (${array} as ${key}${value}) {`)
|
|
546
505
|
this.indent++
|
|
@@ -590,18 +549,37 @@ class PHPGenerator {
|
|
|
590
549
|
this.writeLine('}')
|
|
591
550
|
}
|
|
592
551
|
|
|
552
|
+
generateMatchExpression(node) {
|
|
553
|
+
const subject = this.generateNode(node.subject || node.discriminant)
|
|
554
|
+
let result = `match (${subject}) {\n`
|
|
555
|
+
|
|
556
|
+
for (const arm of node.arms || node.cases || []) {
|
|
557
|
+
this.indent++
|
|
558
|
+
if (arm.conditions) {
|
|
559
|
+
const conditions = arm.conditions.map(c => this.generateNode(c)).join(', ')
|
|
560
|
+
result += this.getIndent() + `${conditions} => ${this.generateNode(arm.body)},\n`
|
|
561
|
+
} else if (arm.default) {
|
|
562
|
+
result += this.getIndent() + `default => ${this.generateNode(arm.body)},\n`
|
|
563
|
+
}
|
|
564
|
+
this.indent--
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
result += this.getIndent() + '}'
|
|
568
|
+
return result
|
|
569
|
+
}
|
|
570
|
+
|
|
593
571
|
generateTryStatement(node) {
|
|
594
572
|
this.writeLine('try {')
|
|
595
573
|
this.indent++
|
|
596
574
|
this.generateNode(node.block)
|
|
597
575
|
this.indent--
|
|
598
576
|
|
|
599
|
-
|
|
600
|
-
const exceptionType =
|
|
601
|
-
const param =
|
|
577
|
+
for (const handler of node.handlers || (node.handler ? [node.handler] : [])) {
|
|
578
|
+
const exceptionType = handler.type || handler.param?.type || 'Exception'
|
|
579
|
+
const param = handler.param ? this.generateIdentifier(handler.param) : '$e'
|
|
602
580
|
this.writeLine(`} catch (${exceptionType} ${param}) {`)
|
|
603
581
|
this.indent++
|
|
604
|
-
this.generateNode(
|
|
582
|
+
this.generateNode(handler.body)
|
|
605
583
|
this.indent--
|
|
606
584
|
}
|
|
607
585
|
|
|
@@ -635,10 +613,15 @@ class PHPGenerator {
|
|
|
635
613
|
}
|
|
636
614
|
|
|
637
615
|
generateEchoStatement(node) {
|
|
638
|
-
const args = (node.arguments || [node.argument]).map(a => this.generateNode(a)).join(', ')
|
|
616
|
+
const args = (node.arguments || [node.argument]).filter(Boolean).map(a => this.generateNode(a)).join(', ')
|
|
639
617
|
this.writeLine(`echo ${args};`)
|
|
640
618
|
}
|
|
641
619
|
|
|
620
|
+
generatePrintStatement(node) {
|
|
621
|
+
const arg = this.generateNode(node.argument)
|
|
622
|
+
this.writeLine(`print ${arg};`)
|
|
623
|
+
}
|
|
624
|
+
|
|
642
625
|
generateNamespace(node) {
|
|
643
626
|
this.writeLine(`namespace ${node.name};`)
|
|
644
627
|
this.writeLine('')
|
|
@@ -647,11 +630,14 @@ class PHPGenerator {
|
|
|
647
630
|
generateUseStatement(node) {
|
|
648
631
|
const name = node.name || node.source
|
|
649
632
|
const alias = node.alias ? ' as ' + node.alias : ''
|
|
650
|
-
|
|
633
|
+
const type = node.type === 'function' ? 'function ' : (node.type === 'const' ? 'const ' : '')
|
|
634
|
+
this.writeLine(`use ${type}${name}${alias};`)
|
|
651
635
|
}
|
|
652
636
|
|
|
653
637
|
generateIncludeStatement(node) {
|
|
654
|
-
const type = node.once
|
|
638
|
+
const type = node.once
|
|
639
|
+
? (node.required ? 'require_once' : 'include_once')
|
|
640
|
+
: (node.required ? 'require' : 'include')
|
|
655
641
|
const path = typeof node.path === 'string' ? `'${node.path}'` : this.generateNode(node.path)
|
|
656
642
|
this.writeLine(`${type} ${path};`)
|
|
657
643
|
}
|
|
@@ -661,16 +647,30 @@ class PHPGenerator {
|
|
|
661
647
|
for (const child of node.children) {
|
|
662
648
|
this.generateNode(child)
|
|
663
649
|
}
|
|
664
|
-
} else {
|
|
665
|
-
this.writeLine(`// Include non résolu: ${node.path || 'inconnu'}`)
|
|
666
650
|
}
|
|
667
651
|
}
|
|
668
652
|
|
|
669
653
|
generateCallExpression(node) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
654
|
+
let callee
|
|
655
|
+
|
|
656
|
+
if (typeof node.callee === 'string') {
|
|
657
|
+
callee = this.translate(node.callee)
|
|
658
|
+
} else if (node.callee.type === 'MemberExpression') {
|
|
659
|
+
callee = this.generateMemberExpression(node.callee)
|
|
660
|
+
} else {
|
|
661
|
+
callee = this.generateNode(node.callee)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const args = (node.arguments || []).map(a => {
|
|
665
|
+
if (a.spread) {
|
|
666
|
+
return '...' + this.generateNode(a.argument || a)
|
|
667
|
+
}
|
|
668
|
+
if (a.name && a.value) {
|
|
669
|
+
return `${a.name}: ${this.generateNode(a.value)}`
|
|
670
|
+
}
|
|
671
|
+
return this.generateNode(a)
|
|
672
|
+
}).join(', ')
|
|
673
|
+
|
|
674
674
|
return `${callee}(${args})`
|
|
675
675
|
}
|
|
676
676
|
|
|
@@ -686,6 +686,9 @@ class PHPGenerator {
|
|
|
686
686
|
if (node.computed) {
|
|
687
687
|
return `${object}[${property}]`
|
|
688
688
|
}
|
|
689
|
+
if (node.nullSafe) {
|
|
690
|
+
return `${object}?->${property}`
|
|
691
|
+
}
|
|
689
692
|
return `${object}->${property}`
|
|
690
693
|
}
|
|
691
694
|
|
|
@@ -695,15 +698,41 @@ class PHPGenerator {
|
|
|
695
698
|
let op = node.operator
|
|
696
699
|
|
|
697
700
|
const opMap = {
|
|
698
|
-
'et': '&&',
|
|
699
|
-
'ou': '||',
|
|
700
|
-
'
|
|
701
|
+
'et': '&&', 'and': '&&',
|
|
702
|
+
'ou': '||', 'or': '||',
|
|
703
|
+
'non': '!', 'not': '!',
|
|
704
|
+
'égal': '===', 'egal': '===', 'equal': '===',
|
|
705
|
+
'différent': '!==', 'different': '!==', 'not equal': '!==',
|
|
706
|
+
'concaténer': '.', 'concatener': '.', 'concatenate': '.',
|
|
707
|
+
'vaisseau spatial': '<=>', 'spaceship': '<=>',
|
|
708
|
+
'fusion null': '??', 'null coalescing': '??'
|
|
701
709
|
}
|
|
702
|
-
|
|
710
|
+
|
|
711
|
+
op = opMap[op?.toLowerCase()] || op
|
|
703
712
|
|
|
704
713
|
return `${left} ${op} ${right}`
|
|
705
714
|
}
|
|
706
715
|
|
|
716
|
+
generateUnaryExpression(node) {
|
|
717
|
+
const argument = this.generateNode(node.argument)
|
|
718
|
+
const op = node.operator === 'non' || node.operator === 'not' ? '!' : node.operator
|
|
719
|
+
|
|
720
|
+
if (node.prefix) {
|
|
721
|
+
return `${op}${argument}`
|
|
722
|
+
}
|
|
723
|
+
return `${argument}${op}`
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
generateUpdateExpression(node) {
|
|
727
|
+
const argument = this.generateNode(node.argument)
|
|
728
|
+
const op = node.operator
|
|
729
|
+
|
|
730
|
+
if (node.prefix) {
|
|
731
|
+
return `${op}${argument}`
|
|
732
|
+
}
|
|
733
|
+
return `${argument}${op}`
|
|
734
|
+
}
|
|
735
|
+
|
|
707
736
|
generateAssignmentExpression(node) {
|
|
708
737
|
const left = this.generateNode(node.left)
|
|
709
738
|
const right = this.generateNode(node.right)
|
|
@@ -711,18 +740,35 @@ class PHPGenerator {
|
|
|
711
740
|
return `${left} ${op} ${right}`
|
|
712
741
|
}
|
|
713
742
|
|
|
743
|
+
generateConditionalExpression(node) {
|
|
744
|
+
const test = this.generateNode(node.test)
|
|
745
|
+
const consequent = this.generateNode(node.consequent)
|
|
746
|
+
const alternate = this.generateNode(node.alternate)
|
|
747
|
+
return `${test} ? ${consequent} : ${alternate}`
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
generateNullCoalescing(node) {
|
|
751
|
+
const left = this.generateNode(node.left)
|
|
752
|
+
const right = this.generateNode(node.right)
|
|
753
|
+
return `${left} ?? ${right}`
|
|
754
|
+
}
|
|
755
|
+
|
|
714
756
|
generateArrayExpression(node) {
|
|
715
757
|
const elements = (node.elements || []).map(e => {
|
|
716
|
-
if (e
|
|
758
|
+
if (!e) return 'null'
|
|
759
|
+
if (e.key !== undefined) {
|
|
717
760
|
const key = this.generateNode(e.key)
|
|
718
761
|
const value = this.generateNode(e.value || e)
|
|
719
762
|
return `${key} => ${value}`
|
|
720
763
|
}
|
|
764
|
+
if (e.spread) {
|
|
765
|
+
return '...' + this.generateNode(e.argument || e)
|
|
766
|
+
}
|
|
721
767
|
return this.generateNode(e)
|
|
722
768
|
})
|
|
723
769
|
|
|
724
770
|
if (elements.length === 0) return '[]'
|
|
725
|
-
if (elements.length <= 3) {
|
|
771
|
+
if (elements.length <= 3 && !elements.some(e => e.includes('=>'))) {
|
|
726
772
|
return `[${elements.join(', ')}]`
|
|
727
773
|
}
|
|
728
774
|
return `[\n${this.getIndent()} ${elements.join(',\n' + this.getIndent() + ' ')}\n${this.getIndent()}]`
|
|
@@ -732,26 +778,75 @@ class PHPGenerator {
|
|
|
732
778
|
return this.generateArrayExpression(node)
|
|
733
779
|
}
|
|
734
780
|
|
|
781
|
+
generateArrowFunction(node) {
|
|
782
|
+
const params = this.generateParams(node.params || [])
|
|
783
|
+
const body = this.generateNode(node.body)
|
|
784
|
+
return `fn(${params}) => ${body}`
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
generateClosure(node) {
|
|
788
|
+
const params = this.generateParams(node.params || [])
|
|
789
|
+
const useVars = node.use && node.use.length > 0
|
|
790
|
+
? ` use (${node.use.map(u => (u.byRef ? '&' : '') + '$' + this.translate(u.name || u)).join(', ')})`
|
|
791
|
+
: ''
|
|
792
|
+
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
793
|
+
|
|
794
|
+
let result = `function(${params})${useVars}${returnType} {\n`
|
|
795
|
+
this.indent++
|
|
796
|
+
|
|
797
|
+
if (Array.isArray(node.body)) {
|
|
798
|
+
for (const stmt of node.body) {
|
|
799
|
+
result += this.getIndent() + this.generateNode(stmt)
|
|
800
|
+
}
|
|
801
|
+
} else {
|
|
802
|
+
result += this.getIndent() + 'return ' + this.generateNode(node.body) + ';\n'
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
this.indent--
|
|
806
|
+
result += this.getIndent() + '}'
|
|
807
|
+
return result
|
|
808
|
+
}
|
|
809
|
+
|
|
735
810
|
generateIdentifier(node) {
|
|
736
|
-
const name = node.name || node
|
|
811
|
+
const name = node.name || node.id?.name || node
|
|
737
812
|
if (typeof name !== 'string') return '$var'
|
|
738
813
|
|
|
739
814
|
const translated = this.translate(name)
|
|
740
815
|
|
|
741
816
|
if (translated.startsWith('$')) return translated
|
|
742
|
-
|
|
817
|
+
|
|
818
|
+
const keywords = [
|
|
819
|
+
'true', 'false', 'null',
|
|
820
|
+
'self', 'parent', 'static',
|
|
821
|
+
'this', '$this'
|
|
822
|
+
]
|
|
823
|
+
if (keywords.includes(translated.toLowerCase())) {
|
|
824
|
+
if (translated.toLowerCase() === 'this') return '$this'
|
|
743
825
|
return translated
|
|
744
826
|
}
|
|
827
|
+
|
|
745
828
|
if (/^[A-Z]/.test(translated)) return translated
|
|
746
|
-
|
|
829
|
+
|
|
830
|
+
if (translated.includes('(') || translated.includes('::')) return translated
|
|
831
|
+
|
|
832
|
+
const superglobals = ['_GET', '_POST', '_SERVER', '_SESSION', '_COOKIE', '_FILES', '_REQUEST', '_ENV', 'GLOBALS']
|
|
833
|
+
if (superglobals.includes(translated) || superglobals.includes(translated.toUpperCase())) {
|
|
834
|
+
return '$' + translated.toUpperCase()
|
|
835
|
+
}
|
|
747
836
|
|
|
748
837
|
return '$' + translated
|
|
749
838
|
}
|
|
750
839
|
|
|
751
840
|
generateLiteral(node) {
|
|
752
|
-
if (node.raw) return node.raw
|
|
841
|
+
if (node.raw !== undefined) return node.raw
|
|
753
842
|
if (typeof node.value === 'string') {
|
|
754
|
-
|
|
843
|
+
const escaped = node.value
|
|
844
|
+
.replace(/\\/g, '\\\\')
|
|
845
|
+
.replace(/"/g, '\\"')
|
|
846
|
+
.replace(/\n/g, '\\n')
|
|
847
|
+
.replace(/\r/g, '\\r')
|
|
848
|
+
.replace(/\t/g, '\\t')
|
|
849
|
+
return `"${escaped}"`
|
|
755
850
|
}
|
|
756
851
|
if (node.value === null) return 'null'
|
|
757
852
|
if (node.value === true) return 'true'
|
|
@@ -761,12 +856,28 @@ class PHPGenerator {
|
|
|
761
856
|
|
|
762
857
|
generateNewExpression(node) {
|
|
763
858
|
const callee = typeof node.callee === 'string'
|
|
764
|
-
? node.callee
|
|
859
|
+
? this.translate(node.callee)
|
|
765
860
|
: this.generateNode(node.callee)
|
|
766
861
|
const args = (node.arguments || []).map(a => this.generateNode(a)).join(', ')
|
|
767
862
|
return `new ${callee}(${args})`
|
|
768
863
|
}
|
|
769
864
|
|
|
865
|
+
generateInstanceOf(node) {
|
|
866
|
+
const left = this.generateNode(node.left)
|
|
867
|
+
const right = this.generateNode(node.right)
|
|
868
|
+
return `${left} instanceof ${right}`
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
generateBlockStatement(node) {
|
|
872
|
+
for (const stmt of node.body || []) {
|
|
873
|
+
this.generateNode(stmt)
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
write(text) {
|
|
878
|
+
this.output += text
|
|
879
|
+
}
|
|
880
|
+
|
|
770
881
|
writeLine(text) {
|
|
771
882
|
this.output += this.getIndent() + text + '\n'
|
|
772
883
|
}
|
|
@@ -776,6 +887,6 @@ class PHPGenerator {
|
|
|
776
887
|
}
|
|
777
888
|
}
|
|
778
889
|
|
|
779
|
-
module.exports = {
|
|
780
|
-
PHPGenerator
|
|
890
|
+
module.exports = {
|
|
891
|
+
PHPGenerator
|
|
781
892
|
}
|