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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs')
2
- const { EtherLexer, Token, TokenType } = require('../lexer/ether-lexer')
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 égal': '===',
20
+ 'strictement égal': '===',
21
21
  'strictement different': '!==',
22
- 'strictement différent': '!==',
22
+ 'strictement différent': '!==',
23
23
  'superieur ou egal': '>=',
24
- 'supérieur ou égal': '>=',
24
+ 'supérieur ou égal': '>=',
25
25
  'inferieur ou egal': '<=',
26
- 'inférieur ou égal': '<=',
26
+ 'inférieur ou égal': '<=',
27
27
  'coalescence nulle': '??',
28
28
  'chainage optionnel': '?.',
29
- 'chaînage optionnel': '?.'
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 génératrice': 'function*',
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}, reçu ${token ? token.type : 'EOF'}`)
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.parseExpression(lang)
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
- const nextVal = this.current() ? this.normalizeAccents(String(this.current().value).toLowerCase()) : ''
1673
- if (['cas', 'case', 'defaut', 'default'].includes(nextVal) ||
1674
- this.current().type === TokenType.RBRACE ||
1675
- this.current().type === TokenType.DEDENT) {
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
- if (this.current().type === TokenType.RBRACE || this.current().type === TokenType.DEDENT) {
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 = []