ether-code 0.8.7 → 0.8.8
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 +63 -3
- package/lexer/ether-lexer.js +387 -363
- package/package.json +1 -1
- package/parsers/ether-parser-base.js +9 -9
- package/parsers/ether-parser-php.js +179 -11
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
|
-
const { EtherLexer, Token, TokenType } = require('
|
|
2
|
+
const { EtherLexer, Token, TokenType } = require('./ether-lexer')
|
|
3
3
|
|
|
4
4
|
class EtherParserBase {
|
|
5
5
|
constructor(options = {}) {
|
|
@@ -17,16 +17,16 @@ class EtherParserBase {
|
|
|
17
17
|
initCompoundTerms() {
|
|
18
18
|
this.compoundOperators = {
|
|
19
19
|
'strictement egal': '===',
|
|
20
|
-
'strictement
|
|
20
|
+
'strictement égal': '===',
|
|
21
21
|
'strictement different': '!==',
|
|
22
|
-
'strictement
|
|
22
|
+
'strictement différent': '!==',
|
|
23
23
|
'superieur ou egal': '>=',
|
|
24
|
-
'
|
|
24
|
+
'supérieur ou égal': '>=',
|
|
25
25
|
'inferieur ou egal': '<=',
|
|
26
|
-
'
|
|
26
|
+
'inférieur ou égal': '<=',
|
|
27
27
|
'coalescence nulle': '??',
|
|
28
28
|
'chainage optionnel': '?.',
|
|
29
|
-
'
|
|
29
|
+
'chaînage optionnel': '?.'
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
this.compoundKeywords = {
|
|
@@ -36,7 +36,7 @@ class EtherParserBase {
|
|
|
36
36
|
'fonction asynchrone': 'async function',
|
|
37
37
|
'fonction async': 'async function',
|
|
38
38
|
'fonction generatrice': 'function*',
|
|
39
|
-
'fonction
|
|
39
|
+
'fonction génératrice': 'function*',
|
|
40
40
|
'variable globale': 'var'
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -105,7 +105,7 @@ class EtherParserBase {
|
|
|
105
105
|
expect(type) {
|
|
106
106
|
const token = this.current()
|
|
107
107
|
if (!token || token.type !== type) {
|
|
108
|
-
throw new Error(`Attendu ${type},
|
|
108
|
+
throw new Error(`Attendu ${type}, reçu ${token ? token.type : 'EOF'}`)
|
|
109
109
|
}
|
|
110
110
|
return this.advance()
|
|
111
111
|
}
|
|
@@ -358,4 +358,4 @@ class EtherParserBase {
|
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
360
|
|
|
361
|
-
module.exports = { EtherParserBase, TokenType }
|
|
361
|
+
module.exports = { EtherParserBase, TokenType }
|
|
@@ -278,6 +278,16 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
278
278
|
|
|
279
279
|
const value = token.value != null ? this.normalizeAccents(String(token.value).toLowerCase()) : ''
|
|
280
280
|
|
|
281
|
+
if (token.type === TokenType.IDENTIFIER) {
|
|
282
|
+
const multiWordCall = this.tryParseMultiWordCallFromStart(lang)
|
|
283
|
+
if (multiWordCall) {
|
|
284
|
+
return {
|
|
285
|
+
type: 'ExpressionStatement',
|
|
286
|
+
expression: multiWordCall
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
281
291
|
if (this.isDeclare(value)) {
|
|
282
292
|
return this.parseDeclare(lang)
|
|
283
293
|
}
|
|
@@ -375,7 +385,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
375
385
|
}
|
|
376
386
|
|
|
377
387
|
isNamespace(value) {
|
|
378
|
-
if (value === 'namespace') return true
|
|
388
|
+
if (value === 'namespace' || value === 'espace de noms') return true
|
|
379
389
|
if (value === 'espace') {
|
|
380
390
|
const next1 = this.peek(1)
|
|
381
391
|
const next2 = this.peek(2)
|
|
@@ -526,7 +536,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
526
536
|
const first = this.advance()
|
|
527
537
|
const firstVal = this.normalizeAccents(String(first.value).toLowerCase())
|
|
528
538
|
|
|
529
|
-
if (firstVal === 'espace') {
|
|
539
|
+
if (firstVal === 'espace' && firstVal !== 'espace de noms') {
|
|
530
540
|
this.advance()
|
|
531
541
|
this.advance()
|
|
532
542
|
}
|
|
@@ -639,6 +649,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
639
649
|
} while (this.match(TokenType.COMMA))
|
|
640
650
|
}
|
|
641
651
|
|
|
652
|
+
this.match(TokenType.COLON)
|
|
642
653
|
this.skipNewlines()
|
|
643
654
|
const body = this.parseClassBody(lang)
|
|
644
655
|
|
|
@@ -768,6 +779,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
768
779
|
}
|
|
769
780
|
}
|
|
770
781
|
|
|
782
|
+
this.match(TokenType.COLON)
|
|
771
783
|
this.skipNewlines()
|
|
772
784
|
|
|
773
785
|
let body = null
|
|
@@ -791,6 +803,11 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
791
803
|
}
|
|
792
804
|
|
|
793
805
|
parsePropertyDeclaration(lang, visibility, isStatic, isReadonly) {
|
|
806
|
+
const val = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
|
|
807
|
+
if (val === 'variable' || val === 'var') {
|
|
808
|
+
this.advance()
|
|
809
|
+
}
|
|
810
|
+
|
|
794
811
|
let typeHint = null
|
|
795
812
|
|
|
796
813
|
const current = this.current()
|
|
@@ -932,6 +949,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
932
949
|
} while (this.match(TokenType.COMMA))
|
|
933
950
|
}
|
|
934
951
|
|
|
952
|
+
this.match(TokenType.COLON)
|
|
935
953
|
this.skipNewlines()
|
|
936
954
|
const body = this.parseClassBody(lang)
|
|
937
955
|
|
|
@@ -950,6 +968,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
950
968
|
const name = nameToken ? nameToken.value : 'AnonymousTrait'
|
|
951
969
|
if (nameToken) this.advance()
|
|
952
970
|
|
|
971
|
+
this.match(TokenType.COLON)
|
|
953
972
|
this.skipNewlines()
|
|
954
973
|
const body = this.parseClassBody(lang)
|
|
955
974
|
|
|
@@ -981,6 +1000,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
981
1000
|
} while (this.match(TokenType.COMMA))
|
|
982
1001
|
}
|
|
983
1002
|
|
|
1003
|
+
this.match(TokenType.COLON)
|
|
984
1004
|
this.skipNewlines()
|
|
985
1005
|
const cases = this.parseEnumBody(lang)
|
|
986
1006
|
|
|
@@ -1336,7 +1356,10 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1336
1356
|
this.skipNewlines()
|
|
1337
1357
|
|
|
1338
1358
|
const elseVal = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
|
|
1339
|
-
if (elseVal === 'sinon') {
|
|
1359
|
+
if (elseVal === 'sinon si' || elseVal === 'elseif') {
|
|
1360
|
+
alternate = this.parseConditional(lang)
|
|
1361
|
+
alternate.type = 'IfStatement'
|
|
1362
|
+
} else if (elseVal === 'sinon') {
|
|
1340
1363
|
this.advance()
|
|
1341
1364
|
|
|
1342
1365
|
const nextVal = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
|
|
@@ -1410,7 +1433,6 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1410
1433
|
|
|
1411
1434
|
if (value === 'foreach' || value === 'pour chaque') {
|
|
1412
1435
|
this.advance()
|
|
1413
|
-
if (value === 'pour chaque') this.advance()
|
|
1414
1436
|
return this.parseForeach(lang)
|
|
1415
1437
|
}
|
|
1416
1438
|
|
|
@@ -1629,9 +1651,10 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1629
1651
|
discriminant = this.parseExpression(lang)
|
|
1630
1652
|
this.match(TokenType.RPAREN)
|
|
1631
1653
|
} else {
|
|
1632
|
-
discriminant = this.
|
|
1654
|
+
discriminant = this.parseConditionUntilColon(lang)
|
|
1633
1655
|
}
|
|
1634
1656
|
|
|
1657
|
+
this.match(TokenType.COLON)
|
|
1635
1658
|
this.skipNewlines()
|
|
1636
1659
|
const cases = this.parseSwitchBody(lang)
|
|
1637
1660
|
|
|
@@ -1645,7 +1668,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1645
1668
|
parseSwitchBody(lang) {
|
|
1646
1669
|
const cases = []
|
|
1647
1670
|
|
|
1648
|
-
this.match(TokenType.LBRACE)
|
|
1671
|
+
const hasBrace = this.match(TokenType.LBRACE)
|
|
1649
1672
|
this.skipNewlines()
|
|
1650
1673
|
this.match(TokenType.INDENT)
|
|
1651
1674
|
|
|
@@ -1666,13 +1689,20 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1666
1689
|
const test = this.parseExpression(lang)
|
|
1667
1690
|
this.match(TokenType.COLON)
|
|
1668
1691
|
this.skipNewlines()
|
|
1692
|
+
this.match(TokenType.INDENT)
|
|
1669
1693
|
|
|
1670
1694
|
const consequent = []
|
|
1671
1695
|
while (!this.isAtEnd()) {
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1696
|
+
this.skipNewlines()
|
|
1697
|
+
const cur = this.current()
|
|
1698
|
+
if (!cur) break
|
|
1699
|
+
|
|
1700
|
+
const nextVal = this.normalizeAccents(String(cur.value).toLowerCase())
|
|
1701
|
+
if (['cas', 'case', 'defaut', 'default'].includes(nextVal)) {
|
|
1702
|
+
break
|
|
1703
|
+
}
|
|
1704
|
+
if (cur.type === TokenType.RBRACE || cur.type === TokenType.DEDENT) {
|
|
1705
|
+
this.advance()
|
|
1676
1706
|
break
|
|
1677
1707
|
}
|
|
1678
1708
|
const stmt = this.parseStatement(lang)
|
|
@@ -1689,10 +1719,15 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1689
1719
|
this.advance()
|
|
1690
1720
|
this.match(TokenType.COLON)
|
|
1691
1721
|
this.skipNewlines()
|
|
1722
|
+
this.match(TokenType.INDENT)
|
|
1692
1723
|
|
|
1693
1724
|
const consequent = []
|
|
1694
1725
|
while (!this.isAtEnd()) {
|
|
1695
|
-
|
|
1726
|
+
this.skipNewlines()
|
|
1727
|
+
const cur = this.current()
|
|
1728
|
+
if (!cur) break
|
|
1729
|
+
if (cur.type === TokenType.RBRACE || cur.type === TokenType.DEDENT) {
|
|
1730
|
+
this.advance()
|
|
1696
1731
|
break
|
|
1697
1732
|
}
|
|
1698
1733
|
const stmt = this.parseStatement(lang)
|
|
@@ -1778,6 +1813,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1778
1813
|
parseTryStatement(lang) {
|
|
1779
1814
|
this.advance()
|
|
1780
1815
|
|
|
1816
|
+
this.match(TokenType.COLON)
|
|
1781
1817
|
this.skipNewlines()
|
|
1782
1818
|
const tryBlock = this.parseBlock(lang)
|
|
1783
1819
|
|
|
@@ -1816,8 +1852,26 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1816
1852
|
}
|
|
1817
1853
|
}
|
|
1818
1854
|
this.match(TokenType.RPAREN)
|
|
1855
|
+
} else {
|
|
1856
|
+
const typeToken = this.current()
|
|
1857
|
+
if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
|
|
1858
|
+
types.push(this.safeStr(typeToken.value))
|
|
1859
|
+
this.advance()
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
const asVal = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
|
|
1863
|
+
if (asVal === 'comme' || asVal === 'as') {
|
|
1864
|
+
this.advance()
|
|
1865
|
+
const paramToken = this.current()
|
|
1866
|
+
if (paramToken && paramToken.type === TokenType.IDENTIFIER) {
|
|
1867
|
+
param = this.safeStr(paramToken.value)
|
|
1868
|
+
if (param.startsWith('$')) param = param.substring(1)
|
|
1869
|
+
this.advance()
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1819
1872
|
}
|
|
1820
1873
|
|
|
1874
|
+
this.match(TokenType.COLON)
|
|
1821
1875
|
this.skipNewlines()
|
|
1822
1876
|
const catchBlock = this.parseBlock(lang)
|
|
1823
1877
|
|
|
@@ -1835,6 +1889,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1835
1889
|
const finallyVal = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
|
|
1836
1890
|
if (finallyVal === 'finalement' || finallyVal === 'finally') {
|
|
1837
1891
|
this.advance()
|
|
1892
|
+
this.match(TokenType.COLON)
|
|
1838
1893
|
this.skipNewlines()
|
|
1839
1894
|
finallyBlock = this.parseBlock(lang)
|
|
1840
1895
|
}
|
|
@@ -2278,6 +2333,112 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
2278
2333
|
}
|
|
2279
2334
|
}
|
|
2280
2335
|
|
|
2336
|
+
tryParseMultiWordCall(firstName, lang) {
|
|
2337
|
+
const words = [firstName]
|
|
2338
|
+
let lookAhead = 0
|
|
2339
|
+
|
|
2340
|
+
while (true) {
|
|
2341
|
+
const nextToken = this.peek(lookAhead)
|
|
2342
|
+
if (!nextToken) break
|
|
2343
|
+
|
|
2344
|
+
if (nextToken.type === TokenType.LPAREN) {
|
|
2345
|
+
if (words.length > 1) {
|
|
2346
|
+
for (let i = 0; i < lookAhead; i++) {
|
|
2347
|
+
this.advance()
|
|
2348
|
+
}
|
|
2349
|
+
this.advance()
|
|
2350
|
+
|
|
2351
|
+
const args = []
|
|
2352
|
+
while (!this.isAtEnd() && !this.check(TokenType.RPAREN)) {
|
|
2353
|
+
this.skipNewlines()
|
|
2354
|
+
if (this.check(TokenType.RPAREN)) break
|
|
2355
|
+
|
|
2356
|
+
if (this.match(TokenType.SPREAD) || this.matchValue('...')) {
|
|
2357
|
+
const arg = this.parseExpression(lang)
|
|
2358
|
+
args.push({ type: 'SpreadElement', argument: arg })
|
|
2359
|
+
} else {
|
|
2360
|
+
const arg = this.parseExpression(lang)
|
|
2361
|
+
args.push(arg)
|
|
2362
|
+
}
|
|
2363
|
+
this.match(TokenType.COMMA)
|
|
2364
|
+
this.skipNewlines()
|
|
2365
|
+
}
|
|
2366
|
+
this.match(TokenType.RPAREN)
|
|
2367
|
+
|
|
2368
|
+
const funcName = words.join(' ')
|
|
2369
|
+
return {
|
|
2370
|
+
type: 'CallExpression',
|
|
2371
|
+
callee: { type: 'Identifier', name: funcName },
|
|
2372
|
+
arguments: args
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
break
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
if (nextToken.type === TokenType.IDENTIFIER) {
|
|
2379
|
+
words.push(this.safeStr(nextToken.value))
|
|
2380
|
+
lookAhead++
|
|
2381
|
+
} else {
|
|
2382
|
+
break
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
return null
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
tryParseMultiWordCallFromStart(lang) {
|
|
2390
|
+
const words = []
|
|
2391
|
+
let lookAhead = 0
|
|
2392
|
+
|
|
2393
|
+
while (true) {
|
|
2394
|
+
const token = this.peek(lookAhead)
|
|
2395
|
+
if (!token) break
|
|
2396
|
+
|
|
2397
|
+
if (token.type === TokenType.LPAREN) {
|
|
2398
|
+
if (words.length >= 2) {
|
|
2399
|
+
for (let i = 0; i < lookAhead; i++) {
|
|
2400
|
+
this.advance()
|
|
2401
|
+
}
|
|
2402
|
+
this.advance()
|
|
2403
|
+
|
|
2404
|
+
const args = []
|
|
2405
|
+
while (!this.isAtEnd() && !this.check(TokenType.RPAREN)) {
|
|
2406
|
+
this.skipNewlines()
|
|
2407
|
+
if (this.check(TokenType.RPAREN)) break
|
|
2408
|
+
|
|
2409
|
+
if (this.match(TokenType.SPREAD) || this.matchValue('...')) {
|
|
2410
|
+
const arg = this.parseExpression(lang)
|
|
2411
|
+
args.push({ type: 'SpreadElement', argument: arg })
|
|
2412
|
+
} else {
|
|
2413
|
+
const arg = this.parseExpression(lang)
|
|
2414
|
+
args.push(arg)
|
|
2415
|
+
}
|
|
2416
|
+
this.match(TokenType.COMMA)
|
|
2417
|
+
this.skipNewlines()
|
|
2418
|
+
}
|
|
2419
|
+
this.match(TokenType.RPAREN)
|
|
2420
|
+
|
|
2421
|
+
const funcName = words.join(' ')
|
|
2422
|
+
return {
|
|
2423
|
+
type: 'CallExpression',
|
|
2424
|
+
callee: { type: 'Identifier', name: funcName },
|
|
2425
|
+
arguments: args
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
break
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
if (token.type === TokenType.IDENTIFIER) {
|
|
2432
|
+
words.push(this.safeStr(token.value))
|
|
2433
|
+
lookAhead++
|
|
2434
|
+
} else {
|
|
2435
|
+
break
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
return null
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2281
2442
|
parsePostfix(lang) {
|
|
2282
2443
|
let expr = this.parseCall(lang)
|
|
2283
2444
|
|
|
@@ -2298,6 +2459,13 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
2298
2459
|
parseCall(lang) {
|
|
2299
2460
|
let expr = this.parsePrimary(lang)
|
|
2300
2461
|
|
|
2462
|
+
if (expr && expr.type === 'Identifier') {
|
|
2463
|
+
const multiWordResult = this.tryParseMultiWordCall(expr.name, lang)
|
|
2464
|
+
if (multiWordResult) {
|
|
2465
|
+
return multiWordResult
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2301
2469
|
while (true) {
|
|
2302
2470
|
if (this.match(TokenType.LPAREN)) {
|
|
2303
2471
|
const args = []
|