ether-code 0.9.0 → 0.9.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 +253 -250
- package/i18n/i18n-php.json +8 -0
- package/lexer/ether-lexer.js +399 -392
- package/package.json +1 -1
- package/parsers/ether-parser-php.js +294 -317
|
@@ -6,6 +6,7 @@ class PHPGenerator {
|
|
|
6
6
|
this.indent = 0
|
|
7
7
|
this.output = ''
|
|
8
8
|
this.translationMap = {}
|
|
9
|
+
this.functionMap = {}
|
|
9
10
|
this.supportedLanguages = ['fr', 'en', 'es', 'ru', 'zh', 'ja']
|
|
10
11
|
|
|
11
12
|
if (i18nPath) {
|
|
@@ -21,6 +22,7 @@ class PHPGenerator {
|
|
|
21
22
|
|
|
22
23
|
buildTranslationMap() {
|
|
23
24
|
this.translationMap = {}
|
|
25
|
+
this.functionMap = {}
|
|
24
26
|
|
|
25
27
|
if (!this.i18n) return
|
|
26
28
|
|
|
@@ -34,6 +36,15 @@ class PHPGenerator {
|
|
|
34
36
|
const fixed = this.normalizeUTF8(etherWord)
|
|
35
37
|
const normalizedKey = fixed.toLowerCase().trim()
|
|
36
38
|
const cleanPhp = this.cleanPhpValue(phpCode)
|
|
39
|
+
|
|
40
|
+
if (phpCode.endsWith('()')) {
|
|
41
|
+
this.functionMap[normalizedKey] = cleanPhp
|
|
42
|
+
const withoutAccents = this.removeAccents(normalizedKey)
|
|
43
|
+
if (withoutAccents !== normalizedKey) {
|
|
44
|
+
this.functionMap[withoutAccents] = cleanPhp
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
this.translationMap[normalizedKey] = cleanPhp
|
|
38
49
|
|
|
39
50
|
const withoutAccents = this.removeAccents(normalizedKey)
|
|
@@ -47,7 +58,6 @@ class PHPGenerator {
|
|
|
47
58
|
|
|
48
59
|
normalizeUTF8(str) {
|
|
49
60
|
if (typeof str !== 'string') return String(str)
|
|
50
|
-
|
|
51
61
|
try {
|
|
52
62
|
const bytes = new Uint8Array(str.length)
|
|
53
63
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -67,8 +77,7 @@ class PHPGenerator {
|
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
translate(word) {
|
|
70
|
-
if (!word) return word
|
|
71
|
-
if (typeof word !== 'string') return String(word)
|
|
80
|
+
if (!word || typeof word !== 'string') return word
|
|
72
81
|
|
|
73
82
|
const normalized = word.toLowerCase().trim()
|
|
74
83
|
|
|
@@ -81,41 +90,35 @@ class PHPGenerator {
|
|
|
81
90
|
return this.translationMap[withoutAccents]
|
|
82
91
|
}
|
|
83
92
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const result = this.translationMap[firstWordNoAccent]
|
|
108
|
-
if (!result.startsWith('__') && !result.startsWith('$')) {
|
|
109
|
-
return result
|
|
110
|
-
}
|
|
111
|
-
}
|
|
93
|
+
return word
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
translateFunction(word) {
|
|
97
|
+
if (!word || typeof word !== 'string') return word
|
|
98
|
+
|
|
99
|
+
const normalized = word.toLowerCase().trim()
|
|
100
|
+
const withoutAccents = this.removeAccents(normalized)
|
|
101
|
+
|
|
102
|
+
if (this.functionMap[normalized]) {
|
|
103
|
+
return this.functionMap[normalized]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (this.functionMap[withoutAccents]) {
|
|
107
|
+
return this.functionMap[withoutAccents]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (this.translationMap[normalized]) {
|
|
111
|
+
return this.translationMap[normalized]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (this.translationMap[withoutAccents]) {
|
|
115
|
+
return this.translationMap[withoutAccents]
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
return word
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
removeAccents(str) {
|
|
118
|
-
if (typeof str !== 'string') return String(str)
|
|
119
122
|
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
|
120
123
|
}
|
|
121
124
|
|
|
@@ -152,18 +155,16 @@ class PHPGenerator {
|
|
|
152
155
|
|
|
153
156
|
const generators = {
|
|
154
157
|
'Program': () => this.generateProgram(node),
|
|
155
|
-
'DeclareStatement': () => this.generateDeclareStatement(node),
|
|
156
|
-
'NamespaceDeclaration': () => this.generateNamespaceDeclaration(node),
|
|
157
158
|
'FunctionDeclaration': () => this.generateFunctionDeclaration(node),
|
|
158
159
|
'ClassDeclaration': () => this.generateClassDeclaration(node),
|
|
159
160
|
'InterfaceDeclaration': () => this.generateInterfaceDeclaration(node),
|
|
160
161
|
'TraitDeclaration': () => this.generateTraitDeclaration(node),
|
|
161
162
|
'EnumDeclaration': () => this.generateEnumDeclaration(node),
|
|
162
163
|
'MethodDefinition': () => this.generateMethodDefinition(node),
|
|
164
|
+
'MethodDeclaration': () => this.generateMethodDefinition(node),
|
|
163
165
|
'PropertyDeclaration': () => this.generatePropertyDeclaration(node),
|
|
164
166
|
'VariableDeclaration': () => this.generateVariableDeclaration(node),
|
|
165
167
|
'ConstantDeclaration': () => this.generateConstantDeclaration(node),
|
|
166
|
-
'DefineDeclaration': () => this.generateDefineDeclaration(node),
|
|
167
168
|
'IfStatement': () => this.generateIfStatement(node),
|
|
168
169
|
'ForStatement': () => this.generateForStatement(node),
|
|
169
170
|
'ForEachStatement': () => this.generateForEachStatement(node),
|
|
@@ -174,6 +175,7 @@ class PHPGenerator {
|
|
|
174
175
|
'MatchExpression': () => this.generateMatchExpression(node),
|
|
175
176
|
'TryStatement': () => this.generateTryStatement(node),
|
|
176
177
|
'ReturnStatement': () => this.generateReturnStatement(node),
|
|
178
|
+
'YieldExpression': () => this.generateYieldExpression(node),
|
|
177
179
|
'ThrowStatement': () => this.generateThrowStatement(node),
|
|
178
180
|
'BreakStatement': () => this.writeLine('break;'),
|
|
179
181
|
'ContinueStatement': () => this.writeLine('continue;'),
|
|
@@ -182,10 +184,13 @@ class PHPGenerator {
|
|
|
182
184
|
'PrintStatement': () => this.generatePrintStatement(node),
|
|
183
185
|
'Namespace': () => this.generateNamespace(node),
|
|
184
186
|
'UseStatement': () => this.generateUseStatement(node),
|
|
187
|
+
'DeclareStatement': () => this.generateDeclareStatement(node),
|
|
185
188
|
'IncludeStatement': () => this.generateIncludeStatement(node),
|
|
186
189
|
'Include': () => this.generateInclude(node),
|
|
187
190
|
'CallExpression': () => this.generateCallExpression(node),
|
|
188
191
|
'MemberExpression': () => this.generateMemberExpression(node),
|
|
192
|
+
'StaticMemberExpression': () => this.generateStaticMemberExpression(node),
|
|
193
|
+
'IndexExpression': () => this.generateIndexExpression(node),
|
|
189
194
|
'BinaryExpression': () => this.generateBinaryExpression(node),
|
|
190
195
|
'LogicalExpression': () => this.generateBinaryExpression(node),
|
|
191
196
|
'UnaryExpression': () => this.generateUnaryExpression(node),
|
|
@@ -197,19 +202,19 @@ class PHPGenerator {
|
|
|
197
202
|
'ObjectExpression': () => this.generateObjectExpression(node),
|
|
198
203
|
'ArrowFunction': () => this.generateArrowFunction(node),
|
|
199
204
|
'ArrowFunctionExpression': () => this.generateArrowFunction(node),
|
|
205
|
+
'FunctionExpression': () => this.generateFunctionExpression(node),
|
|
200
206
|
'Closure': () => this.generateClosure(node),
|
|
201
|
-
'FunctionExpression': () => this.generateClosure(node),
|
|
202
207
|
'Identifier': () => this.generateIdentifier(node),
|
|
203
|
-
'
|
|
208
|
+
'ThisExpression': () => '$this',
|
|
204
209
|
'Literal': () => this.generateLiteral(node),
|
|
205
|
-
'StringLiteral': () => this.
|
|
210
|
+
'StringLiteral': () => this.generateLiteral(node),
|
|
211
|
+
'NumericLiteral': () => this.generateLiteral(node),
|
|
212
|
+
'BooleanLiteral': () => this.generateLiteral(node),
|
|
213
|
+
'NullLiteral': () => 'null',
|
|
206
214
|
'NewExpression': () => this.generateNewExpression(node),
|
|
207
215
|
'InstanceOf': () => this.generateInstanceOf(node),
|
|
208
216
|
'BlockStatement': () => this.generateBlockStatement(node),
|
|
209
|
-
'
|
|
210
|
-
'StaticMemberExpression': () => this.generateStaticMemberExpression(node),
|
|
211
|
-
'IndexExpression': () => this.generateIndexExpression(node),
|
|
212
|
-
'YieldExpression': () => this.generateYieldExpression(node),
|
|
217
|
+
'NamespaceDeclaration': () => this.generateNamespace(node),
|
|
213
218
|
'EmptyStatement': () => '',
|
|
214
219
|
'Comment': () => ''
|
|
215
220
|
}
|
|
@@ -231,40 +236,12 @@ class PHPGenerator {
|
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
|
|
234
|
-
generateDeclareStatement(node) {
|
|
235
|
-
const directives = (node.directives || []).map(d => {
|
|
236
|
-
const name = this.safeString(d.name)
|
|
237
|
-
const value = this.generateNode(d.value)
|
|
238
|
-
return `${name}=${value}`
|
|
239
|
-
}).join(', ')
|
|
240
|
-
|
|
241
|
-
this.writeLine(`declare(${directives});`)
|
|
242
|
-
this.writeLine('')
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
generateNamespaceDeclaration(node) {
|
|
246
|
-
const name = this.safeString(node.name)
|
|
247
|
-
this.writeLine(`namespace ${name};`)
|
|
248
|
-
this.writeLine('')
|
|
249
|
-
|
|
250
|
-
if (node.body) {
|
|
251
|
-
this.generateNode(node.body)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
generateDefineDeclaration(node) {
|
|
256
|
-
const name = this.safeString(node.name)
|
|
257
|
-
const value = this.generateNode(node.value)
|
|
258
|
-
this.writeLine(`define('${name}', ${value});`)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
239
|
generateFunctionDeclaration(node) {
|
|
262
|
-
const name =
|
|
263
|
-
const translatedName = this.translate(name)
|
|
240
|
+
const name = node.name || node.id?.name || 'anonymous'
|
|
264
241
|
const params = this.generateParams(node.params || [])
|
|
265
242
|
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
266
243
|
|
|
267
|
-
this.writeLine(`function ${
|
|
244
|
+
this.writeLine(`function ${name}(${params})${returnType} {`)
|
|
268
245
|
this.indent++
|
|
269
246
|
this.generateNode(node.body)
|
|
270
247
|
this.indent--
|
|
@@ -280,25 +257,20 @@ class PHPGenerator {
|
|
|
280
257
|
result += this.translate(p.visibility) + ' '
|
|
281
258
|
}
|
|
282
259
|
|
|
283
|
-
if (p.
|
|
284
|
-
result += '
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const typeHint = p.typeHint || (p.type !== 'Parameter' ? p.type : null)
|
|
288
|
-
if (typeHint && typeHint !== 'Parameter') {
|
|
289
|
-
result += this.translateType(typeHint) + ' '
|
|
260
|
+
if (p.typeHint) {
|
|
261
|
+
result += this.translateType(p.typeHint) + ' '
|
|
290
262
|
}
|
|
291
263
|
|
|
292
264
|
if (p.variadic) {
|
|
293
265
|
result += '...'
|
|
294
266
|
}
|
|
295
267
|
|
|
296
|
-
if (p.
|
|
268
|
+
if (p.reference || p.byReference) {
|
|
297
269
|
result += '&'
|
|
298
270
|
}
|
|
299
271
|
|
|
300
|
-
const name =
|
|
301
|
-
result += '$' + name
|
|
272
|
+
const name = p.name || p.id?.name || p
|
|
273
|
+
result += '$' + (typeof name === 'string' ? name : name.name || 'param')
|
|
302
274
|
|
|
303
275
|
if (p.default !== undefined && p.default !== null) {
|
|
304
276
|
result += ' = ' + this.generateNode(p.default)
|
|
@@ -308,18 +280,11 @@ class PHPGenerator {
|
|
|
308
280
|
}).join(', ')
|
|
309
281
|
}
|
|
310
282
|
|
|
311
|
-
safeString(value) {
|
|
312
|
-
if (typeof value === 'string') return value
|
|
313
|
-
if (value && typeof value === 'object') {
|
|
314
|
-
return value.name || value.value || 'unknown'
|
|
315
|
-
}
|
|
316
|
-
return String(value || 'unknown')
|
|
317
|
-
}
|
|
318
|
-
|
|
319
283
|
translateType(type) {
|
|
320
284
|
if (!type) return ''
|
|
321
285
|
|
|
322
286
|
if (typeof type === 'string') {
|
|
287
|
+
const translated = this.translate(type)
|
|
323
288
|
const typeMap = {
|
|
324
289
|
'chaîne': 'string', 'chaine': 'string', 'string': 'string',
|
|
325
290
|
'entier': 'int', 'integer': 'int', 'int': 'int',
|
|
@@ -334,50 +299,53 @@ class PHPGenerator {
|
|
|
334
299
|
'itérable': 'iterable', 'iterable': 'iterable',
|
|
335
300
|
'jamais': 'never', 'never': 'never'
|
|
336
301
|
}
|
|
337
|
-
|
|
338
|
-
return typeMap[lower] || type
|
|
302
|
+
return typeMap[translated.toLowerCase()] || typeMap[type.toLowerCase()] || type
|
|
339
303
|
}
|
|
340
304
|
|
|
341
|
-
if (type.type === 'TypeHint' && type.types) {
|
|
342
|
-
const
|
|
343
|
-
|
|
305
|
+
if (type.type === 'TypeHint' && type.types && type.types.length > 0) {
|
|
306
|
+
const prefix = type.nullable ? '?' : ''
|
|
307
|
+
if (type.union || type.types.length > 1) {
|
|
308
|
+
return prefix + type.types.map(t => this.translateType(t)).join('|')
|
|
309
|
+
}
|
|
310
|
+
return prefix + this.translateType(type.types[0])
|
|
344
311
|
}
|
|
345
312
|
|
|
346
|
-
if (type.union
|
|
313
|
+
if (type.union) {
|
|
347
314
|
return type.types.map(t => this.translateType(t)).join('|')
|
|
348
315
|
}
|
|
349
316
|
|
|
350
|
-
if (type.intersection
|
|
317
|
+
if (type.intersection) {
|
|
351
318
|
return type.types.map(t => this.translateType(t)).join('&')
|
|
352
319
|
}
|
|
353
320
|
|
|
354
|
-
if (type.nullable
|
|
321
|
+
if (type.nullable) {
|
|
355
322
|
return '?' + this.translateType(type.type)
|
|
356
323
|
}
|
|
357
324
|
|
|
358
|
-
|
|
359
|
-
return this.translateType(type.name)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return String(type)
|
|
325
|
+
return type.name || type
|
|
363
326
|
}
|
|
364
327
|
|
|
365
328
|
generateClassDeclaration(node) {
|
|
366
329
|
let declaration = ''
|
|
367
330
|
|
|
368
|
-
|
|
369
|
-
if (node.
|
|
370
|
-
if (node.
|
|
331
|
+
const modifiers = node.modifiers || []
|
|
332
|
+
if (modifiers.includes('abstract') || node.abstract) declaration += 'abstract '
|
|
333
|
+
if (modifiers.includes('final') || node.final) declaration += 'final '
|
|
334
|
+
if (modifiers.includes('readonly') || node.readonly) declaration += 'readonly '
|
|
371
335
|
|
|
372
|
-
|
|
373
|
-
declaration += 'class ' + this.translate(className)
|
|
336
|
+
declaration += 'class ' + (node.name || node.id?.name)
|
|
374
337
|
|
|
375
|
-
if (node.
|
|
376
|
-
|
|
338
|
+
if (node.superClass) {
|
|
339
|
+
const superName = typeof node.superClass === 'string' ? node.superClass : node.superClass.name
|
|
340
|
+
declaration += ' extends ' + superName
|
|
341
|
+
} else if (node.extends) {
|
|
342
|
+
declaration += ' extends ' + (typeof node.extends === 'string' ? node.extends : node.extends.name)
|
|
377
343
|
}
|
|
378
344
|
|
|
379
|
-
if (node.
|
|
380
|
-
declaration += ' implements ' + node.
|
|
345
|
+
if (node.interfaces && node.interfaces.length > 0) {
|
|
346
|
+
declaration += ' implements ' + node.interfaces.map(i => typeof i === 'string' ? i : i.name).join(', ')
|
|
347
|
+
} else if (node.implements && node.implements.length > 0) {
|
|
348
|
+
declaration += ' implements ' + node.implements.map(i => typeof i === 'string' ? i : i.name).join(', ')
|
|
381
349
|
}
|
|
382
350
|
|
|
383
351
|
this.writeLine(declaration + ' {')
|
|
@@ -393,11 +361,10 @@ class PHPGenerator {
|
|
|
393
361
|
}
|
|
394
362
|
|
|
395
363
|
generateInterfaceDeclaration(node) {
|
|
396
|
-
|
|
397
|
-
let declaration = 'interface ' + this.translate(name)
|
|
364
|
+
let declaration = 'interface ' + this.translate(node.name || node.id?.name)
|
|
398
365
|
|
|
399
366
|
if (node.extends && node.extends.length > 0) {
|
|
400
|
-
declaration += ' extends ' + node.extends.map(e => this.translate(
|
|
367
|
+
declaration += ' extends ' + node.extends.map(e => this.translate(e)).join(', ')
|
|
401
368
|
}
|
|
402
369
|
|
|
403
370
|
this.writeLine(declaration + ' {')
|
|
@@ -413,8 +380,7 @@ class PHPGenerator {
|
|
|
413
380
|
}
|
|
414
381
|
|
|
415
382
|
generateTraitDeclaration(node) {
|
|
416
|
-
|
|
417
|
-
this.writeLine('trait ' + this.translate(name) + ' {')
|
|
383
|
+
this.writeLine('trait ' + this.translate(node.name || node.id?.name) + ' {')
|
|
418
384
|
this.indent++
|
|
419
385
|
|
|
420
386
|
for (const member of node.body || node.members || []) {
|
|
@@ -427,8 +393,7 @@ class PHPGenerator {
|
|
|
427
393
|
}
|
|
428
394
|
|
|
429
395
|
generateEnumDeclaration(node) {
|
|
430
|
-
|
|
431
|
-
let declaration = 'enum ' + this.translate(name)
|
|
396
|
+
let declaration = 'enum ' + this.translate(node.name || node.id?.name)
|
|
432
397
|
|
|
433
398
|
if (node.backingType) {
|
|
434
399
|
declaration += ': ' + this.translateType(node.backingType)
|
|
@@ -464,16 +429,19 @@ class PHPGenerator {
|
|
|
464
429
|
if (node.final) declaration += 'final '
|
|
465
430
|
if (node.abstract) declaration += 'abstract '
|
|
466
431
|
|
|
467
|
-
const name = this.translateMethodName(
|
|
432
|
+
const name = this.translateMethodName(node.name || node.key?.name)
|
|
468
433
|
const params = this.generateParams(node.params || node.value?.params || [])
|
|
469
434
|
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
470
435
|
|
|
471
|
-
|
|
436
|
+
const body = node.body || node.value?.body
|
|
437
|
+
const hasEmptyBody = !body || (body.type === 'BlockStatement' && (!body.body || body.body.length === 0))
|
|
438
|
+
|
|
439
|
+
if (node.abstract || hasEmptyBody) {
|
|
472
440
|
this.writeLine(`${declaration}function ${name}(${params})${returnType};`)
|
|
473
441
|
} else {
|
|
474
442
|
this.writeLine(`${declaration}function ${name}(${params})${returnType} {`)
|
|
475
443
|
this.indent++
|
|
476
|
-
this.generateNode(
|
|
444
|
+
this.generateNode(body)
|
|
477
445
|
this.indent--
|
|
478
446
|
this.writeLine('}')
|
|
479
447
|
}
|
|
@@ -527,7 +495,7 @@ class PHPGenerator {
|
|
|
527
495
|
}
|
|
528
496
|
|
|
529
497
|
const normalized = name.toLowerCase().trim()
|
|
530
|
-
return magicMethods[normalized] ||
|
|
498
|
+
return magicMethods[normalized] || name
|
|
531
499
|
}
|
|
532
500
|
|
|
533
501
|
generatePropertyDeclaration(node) {
|
|
@@ -539,14 +507,16 @@ class PHPGenerator {
|
|
|
539
507
|
if (node.static) declaration += 'static '
|
|
540
508
|
if (node.readonly) declaration += 'readonly '
|
|
541
509
|
|
|
542
|
-
if (node.
|
|
543
|
-
declaration += this.translateType(node.
|
|
510
|
+
if (node.typeHint) {
|
|
511
|
+
declaration += this.translateType(node.typeHint) + ' '
|
|
544
512
|
}
|
|
545
513
|
|
|
546
|
-
const name =
|
|
547
|
-
declaration += '$' +
|
|
514
|
+
const name = node.name || node.key?.name
|
|
515
|
+
declaration += '$' + name
|
|
548
516
|
|
|
549
|
-
if (node.
|
|
517
|
+
if (node.default !== undefined && node.default !== null) {
|
|
518
|
+
declaration += ' = ' + this.generateNode(node.default)
|
|
519
|
+
} else if (node.value !== undefined && node.value !== null) {
|
|
550
520
|
declaration += ' = ' + this.generateNode(node.value)
|
|
551
521
|
}
|
|
552
522
|
|
|
@@ -555,8 +525,8 @@ class PHPGenerator {
|
|
|
555
525
|
|
|
556
526
|
generateVariableDeclaration(node) {
|
|
557
527
|
for (const decl of node.declarations || [node]) {
|
|
558
|
-
const name =
|
|
559
|
-
const varName = '$' + name
|
|
528
|
+
const name = decl.name || decl.id?.name || decl.id
|
|
529
|
+
const varName = '$' + (typeof name === 'string' ? name : name.name || 'var')
|
|
560
530
|
|
|
561
531
|
if (decl.init !== undefined) {
|
|
562
532
|
const value = this.generateNode(decl.init)
|
|
@@ -568,7 +538,7 @@ class PHPGenerator {
|
|
|
568
538
|
}
|
|
569
539
|
|
|
570
540
|
generateConstantDeclaration(node) {
|
|
571
|
-
const name =
|
|
541
|
+
const name = node.name || node.id?.name
|
|
572
542
|
const value = this.generateNode(node.value || node.init)
|
|
573
543
|
|
|
574
544
|
if (node.classLevel) {
|
|
@@ -587,8 +557,8 @@ class PHPGenerator {
|
|
|
587
557
|
this.indent--
|
|
588
558
|
|
|
589
559
|
if (node.alternate) {
|
|
590
|
-
if (node.alternate.type === 'IfStatement') {
|
|
591
|
-
this.write('} else
|
|
560
|
+
if (node.alternate.type === 'IfStatement' || node.alternate.type === 'ElseIfStatement') {
|
|
561
|
+
this.write('} else')
|
|
592
562
|
this.generateIfStatement({ ...node.alternate, isElseIf: true })
|
|
593
563
|
} else {
|
|
594
564
|
this.writeLine('} else {')
|
|
@@ -616,8 +586,17 @@ class PHPGenerator {
|
|
|
616
586
|
|
|
617
587
|
generateForEachStatement(node) {
|
|
618
588
|
const array = this.generateNode(node.array || node.right || node.iterable)
|
|
619
|
-
|
|
620
|
-
const
|
|
589
|
+
|
|
590
|
+
const valueNode = node.value || node.left || node.valueVar
|
|
591
|
+
const value = typeof valueNode === 'string'
|
|
592
|
+
? '$' + valueNode
|
|
593
|
+
: this.generateIdentifier(valueNode)
|
|
594
|
+
|
|
595
|
+
let key = ''
|
|
596
|
+
const keyNode = node.key || node.keyVar
|
|
597
|
+
if (keyNode) {
|
|
598
|
+
key = (typeof keyNode === 'string' ? '$' + keyNode : this.generateIdentifier(keyNode)) + ' => '
|
|
599
|
+
}
|
|
621
600
|
|
|
622
601
|
this.writeLine(`foreach (${array} as ${key}${value}) {`)
|
|
623
602
|
this.indent++
|
|
@@ -692,19 +671,25 @@ class PHPGenerator {
|
|
|
692
671
|
this.generateNode(node.block)
|
|
693
672
|
this.indent--
|
|
694
673
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const
|
|
698
|
-
|
|
674
|
+
const handlers = node.catches || node.handlers || (node.handler ? [node.handler] : [])
|
|
675
|
+
for (const handler of handlers) {
|
|
676
|
+
const types = handler.types && handler.types.length > 0
|
|
677
|
+
? handler.types.join(' | ')
|
|
678
|
+
: (handler.type || 'Exception')
|
|
679
|
+
const param = handler.param
|
|
680
|
+
? (typeof handler.param === 'string' ? '$' + handler.param : this.generateIdentifier(handler.param))
|
|
681
|
+
: '$e'
|
|
682
|
+
this.writeLine(`} catch (${types} ${param}) {`)
|
|
699
683
|
this.indent++
|
|
700
684
|
this.generateNode(handler.body)
|
|
701
685
|
this.indent--
|
|
702
686
|
}
|
|
703
687
|
|
|
704
|
-
|
|
688
|
+
const finallyBlock = node.finally || node.finalizer
|
|
689
|
+
if (finallyBlock) {
|
|
705
690
|
this.writeLine('} finally {')
|
|
706
691
|
this.indent++
|
|
707
|
-
this.generateNode(
|
|
692
|
+
this.generateNode(finallyBlock)
|
|
708
693
|
this.indent--
|
|
709
694
|
}
|
|
710
695
|
|
|
@@ -720,6 +705,14 @@ class PHPGenerator {
|
|
|
720
705
|
}
|
|
721
706
|
}
|
|
722
707
|
|
|
708
|
+
generateYieldExpression(node) {
|
|
709
|
+
const arg = node.argument ? this.generateNode(node.argument) : ''
|
|
710
|
+
if (node.delegate) {
|
|
711
|
+
return `yield from ${arg}`
|
|
712
|
+
}
|
|
713
|
+
return `yield ${arg}`
|
|
714
|
+
}
|
|
715
|
+
|
|
723
716
|
generateThrowStatement(node) {
|
|
724
717
|
const arg = this.generateNode(node.argument)
|
|
725
718
|
this.writeLine(`throw ${arg};`)
|
|
@@ -742,8 +735,7 @@ class PHPGenerator {
|
|
|
742
735
|
}
|
|
743
736
|
|
|
744
737
|
generateNamespace(node) {
|
|
745
|
-
|
|
746
|
-
this.writeLine(`namespace ${name};`)
|
|
738
|
+
this.writeLine(`namespace ${node.name};`)
|
|
747
739
|
this.writeLine('')
|
|
748
740
|
}
|
|
749
741
|
|
|
@@ -752,17 +744,25 @@ class PHPGenerator {
|
|
|
752
744
|
|
|
753
745
|
if (node.imports && node.imports.length > 0) {
|
|
754
746
|
for (const imp of node.imports) {
|
|
755
|
-
const path =
|
|
747
|
+
const path = imp.path || imp.name || imp
|
|
756
748
|
const alias = imp.alias ? ' as ' + imp.alias : ''
|
|
757
749
|
this.writeLine(`use ${typePrefix}${path}${alias};`)
|
|
758
750
|
}
|
|
759
751
|
} else {
|
|
760
|
-
const name =
|
|
752
|
+
const name = node.name || node.source || 'undefined'
|
|
761
753
|
const alias = node.alias ? ' as ' + node.alias : ''
|
|
762
754
|
this.writeLine(`use ${typePrefix}${name}${alias};`)
|
|
763
755
|
}
|
|
764
756
|
}
|
|
765
757
|
|
|
758
|
+
generateDeclareStatement(node) {
|
|
759
|
+
const directives = (node.directives || []).map(d => {
|
|
760
|
+
const value = typeof d.value === 'object' ? this.generateNode(d.value) : d.value
|
|
761
|
+
return `${d.name}=${value}`
|
|
762
|
+
}).join(', ')
|
|
763
|
+
this.writeLine(`declare(${directives});`)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
766
|
generateIncludeStatement(node) {
|
|
767
767
|
const type = node.once
|
|
768
768
|
? (node.required ? 'require_once' : 'include_once')
|
|
@@ -783,23 +783,30 @@ class PHPGenerator {
|
|
|
783
783
|
let callee
|
|
784
784
|
|
|
785
785
|
if (typeof node.callee === 'string') {
|
|
786
|
-
callee = this.
|
|
787
|
-
} else if (node.callee
|
|
786
|
+
callee = this.translateFunction(node.callee)
|
|
787
|
+
} else if (node.callee.type === 'MemberExpression') {
|
|
788
788
|
callee = this.generateMemberExpression(node.callee)
|
|
789
|
-
} else if (node.callee
|
|
789
|
+
} else if (node.callee.type === 'StaticMemberExpression') {
|
|
790
790
|
callee = this.generateStaticMemberExpression(node.callee)
|
|
791
|
-
} else if (node.callee
|
|
792
|
-
const name =
|
|
793
|
-
|
|
791
|
+
} else if (node.callee.type === 'Identifier') {
|
|
792
|
+
const name = node.callee.name
|
|
793
|
+
const translated = this.translateFunction(name)
|
|
794
|
+
if (translated !== name) {
|
|
795
|
+
callee = translated
|
|
796
|
+
} else if (name.includes(' ')) {
|
|
797
|
+
callee = name.replace(/ /g, '_')
|
|
798
|
+
} else {
|
|
799
|
+
callee = name
|
|
800
|
+
}
|
|
794
801
|
} else {
|
|
795
802
|
callee = this.generateNode(node.callee)
|
|
796
803
|
}
|
|
797
804
|
|
|
798
805
|
const args = (node.arguments || []).map(a => {
|
|
799
|
-
if (a
|
|
806
|
+
if (a.spread) {
|
|
800
807
|
return '...' + this.generateNode(a.argument || a)
|
|
801
808
|
}
|
|
802
|
-
if (a && a.
|
|
809
|
+
if (a.name && a.value) {
|
|
803
810
|
return `${a.name}: ${this.generateNode(a.value)}`
|
|
804
811
|
}
|
|
805
812
|
return this.generateNode(a)
|
|
@@ -813,11 +820,18 @@ class PHPGenerator {
|
|
|
813
820
|
let property
|
|
814
821
|
|
|
815
822
|
if (typeof node.property === 'string') {
|
|
816
|
-
property =
|
|
817
|
-
} else if (node.property
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
823
|
+
property = node.property
|
|
824
|
+
} else if (node.property.type === 'Identifier') {
|
|
825
|
+
let propName = node.property.name
|
|
826
|
+
let translated = this.translateFunction(propName)
|
|
827
|
+
if (translated.includes('->')) {
|
|
828
|
+
translated = translated.split('->').pop()
|
|
829
|
+
} else if (translated.includes('::')) {
|
|
830
|
+
translated = translated.split('::').pop()
|
|
831
|
+
} else if (translated !== propName && !translated.includes('(')) {
|
|
832
|
+
translated = propName
|
|
833
|
+
}
|
|
834
|
+
property = translated
|
|
821
835
|
} else {
|
|
822
836
|
property = this.generateNode(node.property)
|
|
823
837
|
}
|
|
@@ -828,55 +842,35 @@ class PHPGenerator {
|
|
|
828
842
|
if (node.computed) {
|
|
829
843
|
return `${object}[${property}]`
|
|
830
844
|
}
|
|
831
|
-
if (node.
|
|
845
|
+
if (node.nullSafe) {
|
|
832
846
|
return `${object}?->${property}`
|
|
833
847
|
}
|
|
834
848
|
return `${object}->${property}`
|
|
835
849
|
}
|
|
836
850
|
|
|
837
|
-
translateMethodName(name) {
|
|
838
|
-
if (!name) return name
|
|
839
|
-
const translated = this.translate(name)
|
|
840
|
-
if (translated.includes('->')) {
|
|
841
|
-
const parts = translated.split('->')
|
|
842
|
-
return parts[parts.length - 1].replace(/\(\)$/, '')
|
|
843
|
-
}
|
|
844
|
-
if (translated.includes('::')) {
|
|
845
|
-
const parts = translated.split('::')
|
|
846
|
-
return parts[parts.length - 1].replace(/\(\)$/, '')
|
|
847
|
-
}
|
|
848
|
-
return translated.replace(/\(\)$/, '')
|
|
849
|
-
}
|
|
850
|
-
|
|
851
851
|
generateStaticMemberExpression(node) {
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
852
|
+
const classNode = node.class || node.object
|
|
853
|
+
const className = classNode.type === 'Identifier' ? classNode.name : this.generateNode(classNode)
|
|
854
|
+
|
|
855
|
+
const memberNode = node.member || node.property
|
|
856
|
+
let memberName
|
|
857
|
+
if (typeof memberNode === 'string') {
|
|
858
|
+
memberName = memberNode
|
|
859
|
+
} else if (memberNode.type === 'Identifier') {
|
|
860
|
+
memberName = this.translateMethodName(memberNode.name)
|
|
859
861
|
} else {
|
|
860
|
-
|
|
862
|
+
memberName = this.generateNode(memberNode)
|
|
861
863
|
}
|
|
862
864
|
|
|
863
|
-
return `${
|
|
865
|
+
return `${className}::${memberName}`
|
|
864
866
|
}
|
|
865
867
|
|
|
866
868
|
generateIndexExpression(node) {
|
|
867
869
|
const object = this.generateNode(node.object)
|
|
868
|
-
const index =
|
|
870
|
+
const index = this.generateNode(node.index)
|
|
869
871
|
return `${object}[${index}]`
|
|
870
872
|
}
|
|
871
873
|
|
|
872
|
-
generateYieldExpression(node) {
|
|
873
|
-
const argument = node.argument ? this.generateNode(node.argument) : ''
|
|
874
|
-
if (node.delegate) {
|
|
875
|
-
return `yield from ${argument}`
|
|
876
|
-
}
|
|
877
|
-
return argument ? `yield ${argument}` : 'yield'
|
|
878
|
-
}
|
|
879
|
-
|
|
880
874
|
generateBinaryExpression(node) {
|
|
881
875
|
const left = this.generateNode(node.left)
|
|
882
876
|
const right = this.generateNode(node.right)
|
|
@@ -893,16 +887,15 @@ class PHPGenerator {
|
|
|
893
887
|
'fusion null': '??', 'null coalescing': '??'
|
|
894
888
|
}
|
|
895
889
|
|
|
896
|
-
|
|
897
|
-
op = opMap[opLower] || op
|
|
890
|
+
op = opMap[op?.toLowerCase()] || op
|
|
898
891
|
|
|
899
|
-
|
|
892
|
+
const result = `${left} ${op} ${right}`
|
|
893
|
+
return node.parenthesized ? `(${result})` : result
|
|
900
894
|
}
|
|
901
895
|
|
|
902
896
|
generateUnaryExpression(node) {
|
|
903
897
|
const argument = this.generateNode(node.argument || node.operand)
|
|
904
|
-
|
|
905
|
-
if (op === 'non' || op === 'not') op = '!'
|
|
898
|
+
const op = node.operator === 'non' || node.operator === 'not' ? '!' : node.operator
|
|
906
899
|
|
|
907
900
|
if (node.prefix !== false) {
|
|
908
901
|
return `${op}${argument}`
|
|
@@ -914,7 +907,7 @@ class PHPGenerator {
|
|
|
914
907
|
const argument = this.generateNode(node.argument || node.operand)
|
|
915
908
|
const op = node.operator
|
|
916
909
|
|
|
917
|
-
if (node.prefix
|
|
910
|
+
if (node.prefix) {
|
|
918
911
|
return `${op}${argument}`
|
|
919
912
|
}
|
|
920
913
|
return `${argument}${op}`
|
|
@@ -943,9 +936,6 @@ class PHPGenerator {
|
|
|
943
936
|
generateArrayExpression(node) {
|
|
944
937
|
const elements = (node.elements || []).map(e => {
|
|
945
938
|
if (!e) return 'null'
|
|
946
|
-
if (e.type === 'SpreadElement') {
|
|
947
|
-
return '...' + this.generateNode(e.argument || e)
|
|
948
|
-
}
|
|
949
939
|
if (e.type === 'ArrayElement') {
|
|
950
940
|
if (e.key !== null && e.key !== undefined) {
|
|
951
941
|
const key = this.generateNode(e.key)
|
|
@@ -959,6 +949,9 @@ class PHPGenerator {
|
|
|
959
949
|
const value = this.generateNode(e.value || e)
|
|
960
950
|
return `${key} => ${value}`
|
|
961
951
|
}
|
|
952
|
+
if (e.spread) {
|
|
953
|
+
return '...' + this.generateNode(e.argument || e)
|
|
954
|
+
}
|
|
962
955
|
return this.generateNode(e)
|
|
963
956
|
})
|
|
964
957
|
|
|
@@ -979,68 +972,94 @@ class PHPGenerator {
|
|
|
979
972
|
return `fn(${params}) => ${body}`
|
|
980
973
|
}
|
|
981
974
|
|
|
982
|
-
|
|
975
|
+
generateFunctionExpression(node) {
|
|
983
976
|
const params = this.generateParams(node.params || [])
|
|
984
|
-
const
|
|
985
|
-
|
|
977
|
+
const uses = node.uses || node.use || []
|
|
978
|
+
const useVars = uses.length > 0
|
|
979
|
+
? ` use (${uses.map(u => (u.byReference || u.byRef ? '&' : '') + '$' + (u.name || u)).join(', ')})`
|
|
986
980
|
: ''
|
|
987
981
|
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
988
982
|
|
|
989
983
|
let result = `function(${params})${useVars}${returnType} {\n`
|
|
984
|
+
|
|
985
|
+
const savedOutput = this.output
|
|
986
|
+
const savedIndent = this.indent
|
|
987
|
+
this.output = ''
|
|
990
988
|
this.indent++
|
|
991
989
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
990
|
+
const body = node.body
|
|
991
|
+
if (body && body.type === 'BlockStatement' && body.body) {
|
|
992
|
+
for (const stmt of body.body) {
|
|
993
|
+
this.generateNode(stmt)
|
|
995
994
|
}
|
|
996
|
-
} else if (
|
|
997
|
-
|
|
995
|
+
} else if (body) {
|
|
996
|
+
this.writeLine('return ' + this.generateNode(body) + ';')
|
|
998
997
|
}
|
|
999
998
|
|
|
1000
|
-
this.
|
|
999
|
+
const bodyOutput = this.output
|
|
1000
|
+
this.output = savedOutput
|
|
1001
|
+
this.indent = savedIndent
|
|
1002
|
+
|
|
1003
|
+
result += bodyOutput
|
|
1001
1004
|
result += this.getIndent() + '}'
|
|
1002
1005
|
return result
|
|
1003
1006
|
}
|
|
1004
1007
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1008
|
+
generateClosure(node) {
|
|
1009
|
+
const params = this.generateParams(node.params || [])
|
|
1010
|
+
const useVars = node.use && node.use.length > 0
|
|
1011
|
+
? ` use (${node.use.map(u => (u.byRef ? '&' : '') + '$' + this.translate(u.name || u)).join(', ')})`
|
|
1012
|
+
: ''
|
|
1013
|
+
const returnType = node.returnType ? ': ' + this.translateType(node.returnType) : ''
|
|
1014
|
+
|
|
1015
|
+
let result = `function(${params})${useVars}${returnType} {\n`
|
|
1016
|
+
this.indent++
|
|
1007
1017
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1018
|
+
if (Array.isArray(node.body)) {
|
|
1019
|
+
for (const stmt of node.body) {
|
|
1020
|
+
result += this.getIndent() + this.generateNode(stmt)
|
|
1021
|
+
}
|
|
1022
|
+
} else {
|
|
1023
|
+
result += this.getIndent() + 'return ' + this.generateNode(node.body) + ';\n'
|
|
1024
|
+
}
|
|
1010
1025
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1026
|
+
this.indent--
|
|
1027
|
+
result += this.getIndent() + '}'
|
|
1028
|
+
return result
|
|
1013
1029
|
}
|
|
1014
1030
|
|
|
1015
1031
|
generateIdentifier(node) {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
const name = this.safeString(node.name || node.id?.name || node)
|
|
1019
|
-
const nameStr = String(name)
|
|
1020
|
-
|
|
1021
|
-
if (nameStr.startsWith('$')) return nameStr
|
|
1032
|
+
const name = node.name || node.id?.name || node
|
|
1033
|
+
if (typeof name !== 'string') return '$var'
|
|
1022
1034
|
|
|
1023
1035
|
const keywords = [
|
|
1024
1036
|
'true', 'false', 'null',
|
|
1025
1037
|
'self', 'parent', 'static',
|
|
1026
|
-
'this', '$this'
|
|
1038
|
+
'this', '$this', 'vrai', 'faux', 'nul', 'ceci'
|
|
1027
1039
|
]
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1040
|
+
const lowerName = name.toLowerCase()
|
|
1041
|
+
|
|
1042
|
+
if (lowerName === 'vrai') return 'true'
|
|
1043
|
+
if (lowerName === 'faux') return 'false'
|
|
1044
|
+
if (lowerName === 'nul') return 'null'
|
|
1045
|
+
if (lowerName === 'ceci' || lowerName === 'this') return '$this'
|
|
1046
|
+
|
|
1047
|
+
if (keywords.includes(lowerName)) {
|
|
1048
|
+
return name
|
|
1031
1049
|
}
|
|
1032
1050
|
|
|
1033
|
-
if (
|
|
1051
|
+
if (name.startsWith('$')) return name
|
|
1034
1052
|
|
|
1035
|
-
if (
|
|
1053
|
+
if (/^[A-Z]/.test(name)) return name
|
|
1054
|
+
|
|
1055
|
+
if (name.includes('(') || name.includes('::') || name.includes('->')) return name
|
|
1036
1056
|
|
|
1037
1057
|
const superglobals = ['_GET', '_POST', '_SERVER', '_SESSION', '_COOKIE', '_FILES', '_REQUEST', '_ENV', 'GLOBALS']
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
return '$' + upper
|
|
1058
|
+
if (superglobals.includes(name) || superglobals.includes(name.toUpperCase())) {
|
|
1059
|
+
return '$' + name.toUpperCase()
|
|
1041
1060
|
}
|
|
1042
1061
|
|
|
1043
|
-
return '$' +
|
|
1062
|
+
return '$' + name
|
|
1044
1063
|
}
|
|
1045
1064
|
|
|
1046
1065
|
generateLiteral(node) {
|
|
@@ -1060,26 +1079,10 @@ class PHPGenerator {
|
|
|
1060
1079
|
return String(node.value)
|
|
1061
1080
|
}
|
|
1062
1081
|
|
|
1063
|
-
generateStringLiteral(node) {
|
|
1064
|
-
const value = node.value || ''
|
|
1065
|
-
const escaped = value
|
|
1066
|
-
.replace(/\\/g, '\\\\')
|
|
1067
|
-
.replace(/"/g, '\\"')
|
|
1068
|
-
.replace(/\n/g, '\\n')
|
|
1069
|
-
.replace(/\r/g, '\\r')
|
|
1070
|
-
.replace(/\t/g, '\\t')
|
|
1071
|
-
return node.doubleQuoted !== false ? `"${escaped}"` : `'${escaped}'`
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
1082
|
generateNewExpression(node) {
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
} else if (node.callee && node.callee.name) {
|
|
1079
|
-
callee = this.translate(node.callee.name)
|
|
1080
|
-
} else {
|
|
1081
|
-
callee = this.generateNode(node.callee)
|
|
1082
|
-
}
|
|
1083
|
+
const callee = typeof node.callee === 'string'
|
|
1084
|
+
? this.translate(node.callee)
|
|
1085
|
+
: this.generateNode(node.callee)
|
|
1083
1086
|
const args = (node.arguments || []).map(a => this.generateNode(a)).join(', ')
|
|
1084
1087
|
return `new ${callee}(${args})`
|
|
1085
1088
|
}
|