ether-code 0.4.8 → 0.4.9

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 CHANGED
@@ -6,7 +6,7 @@ const http = require('http')
6
6
  const { EtherCompiler } = require('./compiler')
7
7
  const { Watcher } = require('./watcher')
8
8
 
9
- const VERSION = '0.4.8'
9
+ const VERSION = '0.4.9'
10
10
 
11
11
  const COLORS = {
12
12
  reset: '\x1b[0m',
package/ether-parser.js CHANGED
@@ -118,9 +118,9 @@ class EtherParser {
118
118
  'absolu': 'abs',
119
119
  'maximum': 'max',
120
120
  'minimum': 'min',
121
- 'date': 'Date',
121
+
122
122
  'maintenant': 'now',
123
- 'carte': 'Map',
123
+
124
124
  'ensemble': 'Set',
125
125
  'symbole': 'Symbol',
126
126
  'objet': 'Object',
@@ -297,9 +297,36 @@ class EtherParser {
297
297
  const token = this.current()
298
298
  if (!token || token.value === null || token.value === undefined) return null
299
299
  const tokenVal = String(token.value).toLowerCase()
300
- if (tokenVal === value.toLowerCase()) {
300
+ const valueLower = value.toLowerCase()
301
+
302
+ if (tokenVal === valueLower) {
301
303
  return this.advance()
302
304
  }
305
+
306
+ if (valueLower.includes(' ')) {
307
+ const parts = valueLower.split(' ')
308
+ if (tokenVal === parts[0]) {
309
+ const savedPos = this.pos
310
+ const tokens = [this.advance()]
311
+ let matched = true
312
+
313
+ for (let i = 1; i < parts.length && matched; i++) {
314
+ const nextToken = this.current()
315
+ if (nextToken && String(nextToken.value).toLowerCase() === parts[i]) {
316
+ tokens.push(this.advance())
317
+ } else {
318
+ matched = false
319
+ }
320
+ }
321
+
322
+ if (matched) {
323
+ return tokens[tokens.length - 1]
324
+ } else {
325
+ this.pos = savedPos
326
+ }
327
+ }
328
+ }
329
+
303
330
  return null
304
331
  }
305
332
 
@@ -314,6 +341,27 @@ class EtherParser {
314
341
  detectTargetLanguage(source) {
315
342
  const lower = source.toLowerCase()
316
343
 
344
+ const targetMatch = source.match(/\/\/\s*cible\s*:\s*(\w+)/i)
345
+ if (targetMatch) {
346
+ const target = targetMatch[1].toLowerCase()
347
+ const langMap = {
348
+ 'js': 'js', 'javascript': 'js',
349
+ 'css': 'css', 'style': 'css',
350
+ 'html': 'html', 'page': 'html',
351
+ 'ts': 'ts', 'typescript': 'ts',
352
+ 'react': 'react', 'jsx': 'react',
353
+ 'php': 'php',
354
+ 'python': 'python', 'py': 'python',
355
+ 'ruby': 'ruby', 'rb': 'ruby',
356
+ 'sql': 'sql',
357
+ 'node': 'node', 'nodejs': 'node',
358
+ 'graphql': 'graphql', 'gql': 'graphql'
359
+ }
360
+ if (langMap[target]) {
361
+ return langMap[target]
362
+ }
363
+ }
364
+
317
365
  if (/^\s*(document|page|<!doctype|<html|tete|corps|entete|navigation|section|article)/m.test(lower)) {
318
366
  return 'html'
319
367
  }
@@ -1250,7 +1298,7 @@ class EtherParser {
1250
1298
  'cesure': 'wbr',
1251
1299
  'noscript': 'noscript',
1252
1300
  'sans script': 'noscript',
1253
- 'carte': 'map',
1301
+
1254
1302
  'zone': 'area'
1255
1303
  }
1256
1304
 
@@ -1506,6 +1554,47 @@ class EtherParser {
1506
1554
  }
1507
1555
  }
1508
1556
 
1557
+ parseFunctionExpression(lang) {
1558
+ this.advance()
1559
+
1560
+ let name = null
1561
+ const nameToken = this.current()
1562
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER && !this.check(TokenType.LPAREN)) {
1563
+ const nextToken = this.peek(1)
1564
+ if (nextToken && nextToken.type === TokenType.LPAREN) {
1565
+ name = nameToken.value
1566
+ this.advance()
1567
+ }
1568
+ }
1569
+
1570
+ const params = []
1571
+ if (this.match(TokenType.LPAREN)) {
1572
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
1573
+ const param = this.parseParameter(lang)
1574
+ if (param) {
1575
+ params.push(param)
1576
+ }
1577
+ this.match(TokenType.COMMA)
1578
+ }
1579
+ }
1580
+
1581
+ let returnType = null
1582
+ if (this.match(TokenType.COLON) || this.match(TokenType.ARROW)) {
1583
+ returnType = this.parseType(lang)
1584
+ }
1585
+
1586
+ this.skipNewlines()
1587
+ const body = this.parseBlock(lang)
1588
+
1589
+ return {
1590
+ type: 'FunctionExpression',
1591
+ name: name,
1592
+ params: params,
1593
+ returnType: returnType,
1594
+ body: body
1595
+ }
1596
+ }
1597
+
1509
1598
  parseParameter(lang) {
1510
1599
  const nameToken = this.current()
1511
1600
  if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
@@ -1590,7 +1679,7 @@ class EtherParser {
1590
1679
  'jamais': 'never',
1591
1680
  'inconnu': 'unknown',
1592
1681
  'symbole': 'symbol',
1593
- 'date': 'Date',
1682
+
1594
1683
  'promesse': 'Promise',
1595
1684
  'fonction': 'Function'
1596
1685
  }
@@ -1640,8 +1729,10 @@ class EtherParser {
1640
1729
  }
1641
1730
  }
1642
1731
 
1643
- parseConditional(lang) {
1644
- const keyword = this.advance()
1732
+ parseConditional(lang, isElseIf = false) {
1733
+ if (!isElseIf) {
1734
+ this.advance()
1735
+ }
1645
1736
  const condition = this.parseExpression(lang)
1646
1737
 
1647
1738
  this.skipNewlines()
@@ -1652,7 +1743,7 @@ class EtherParser {
1652
1743
 
1653
1744
  if (this.matchValue('sinon')) {
1654
1745
  if (this.matchValue('si')) {
1655
- alternate = this.parseConditional(lang)
1746
+ alternate = this.parseConditional(lang, true)
1656
1747
  } else {
1657
1748
  this.skipNewlines()
1658
1749
  alternate = this.parseBlock(lang)
@@ -1844,17 +1935,42 @@ class EtherParser {
1844
1935
  parseBlock(lang) {
1845
1936
  const body = []
1846
1937
 
1847
- if (this.match(TokenType.INDENT)) {
1938
+ const hasBrace = this.match(TokenType.LBRACE)
1939
+ this.skipNewlines()
1940
+
1941
+ if (hasBrace) {
1942
+ this.match(TokenType.INDENT)
1943
+ }
1944
+
1945
+ if (hasBrace || this.match(TokenType.INDENT)) {
1848
1946
  while (!this.isAtEnd()) {
1947
+ this.skipNewlines()
1948
+
1849
1949
  const current = this.current()
1850
1950
 
1851
1951
  if (current && current.type === TokenType.DEDENT) {
1952
+ this.advance()
1953
+ if (hasBrace) {
1954
+ this.skipNewlines()
1955
+ this.match(TokenType.RBRACE)
1956
+ }
1957
+ break
1958
+ }
1959
+
1960
+ if (hasBrace && current && current.type === TokenType.RBRACE) {
1852
1961
  this.advance()
1853
1962
  break
1854
1963
  }
1855
1964
 
1965
+ if (current && (current.type === TokenType.INDENT || current.type === TokenType.NEWLINE)) {
1966
+ this.advance()
1967
+ continue
1968
+ }
1969
+
1856
1970
  const statement = this.parseStatement(lang)
1857
- if (statement) {
1971
+ if (statement && statement.expression?.value !== null) {
1972
+ body.push(statement)
1973
+ } else if (statement && statement.type !== 'ExpressionStatement') {
1858
1974
  body.push(statement)
1859
1975
  }
1860
1976
 
@@ -1924,17 +2040,16 @@ class EtherParser {
1924
2040
  let left = this.parseComparison(lang)
1925
2041
 
1926
2042
  while (true) {
1927
- const compoundOp = this.tryMatchCompoundOperator()
1928
- if (compoundOp === '===' || compoundOp === '!==') {
2043
+ if (this.matchValue('strictement egal') || this.matchValue('strictement égal')) {
1929
2044
  const right = this.parseComparison(lang)
1930
- left = { type: 'BinaryExpression', operator: compoundOp, left, right }
1931
- continue
1932
- }
1933
-
1934
- if (this.match(TokenType.DOUBLE_EQUALS) || this.matchValue('egal') || this.matchValue('egale')) {
2045
+ left = { type: 'BinaryExpression', operator: '===', left, right }
2046
+ } else if (this.matchValue('strictement different') || this.matchValue('strictement différent')) {
2047
+ const right = this.parseComparison(lang)
2048
+ left = { type: 'BinaryExpression', operator: '!==', left, right }
2049
+ } else if (this.match(TokenType.DOUBLE_EQUALS) || this.matchValue('egal') || this.matchValue('egale') || this.matchValue('égal')) {
1935
2050
  const right = this.parseComparison(lang)
1936
2051
  left = { type: 'BinaryExpression', operator: '===', left, right }
1937
- } else if (this.match(TokenType.NOT_EQUALS) || this.matchValue('different')) {
2052
+ } else if (this.match(TokenType.NOT_EQUALS) || this.matchValue('different') || this.matchValue('différent')) {
1938
2053
  const right = this.parseComparison(lang)
1939
2054
  left = { type: 'BinaryExpression', operator: '!==', left, right }
1940
2055
  } else {
@@ -1949,25 +2064,18 @@ class EtherParser {
1949
2064
  let left = this.parseAdditive(lang)
1950
2065
 
1951
2066
  while (true) {
1952
- const compoundOp = this.tryMatchCompoundOperator()
1953
- if (compoundOp === '>=' || compoundOp === '<=') {
2067
+ if (this.matchValue('superieur ou egal') || this.matchValue('supérieur ou égal') || this.match(TokenType.GTE)) {
1954
2068
  const right = this.parseAdditive(lang)
1955
- left = { type: 'BinaryExpression', operator: compoundOp, left, right }
1956
- continue
1957
- }
1958
-
1959
- if (this.match(TokenType.LT) || this.matchValue('inferieur')) {
2069
+ left = { type: 'BinaryExpression', operator: '>=', left, right }
2070
+ } else if (this.matchValue('inferieur ou egal') || this.matchValue('inférieur ou égal') || this.match(TokenType.LTE)) {
2071
+ const right = this.parseAdditive(lang)
2072
+ left = { type: 'BinaryExpression', operator: '<=', left, right }
2073
+ } else if (this.match(TokenType.LT) || this.matchValue('inferieur') || this.matchValue('inférieur')) {
1960
2074
  const right = this.parseAdditive(lang)
1961
2075
  left = { type: 'BinaryExpression', operator: '<', left, right }
1962
- } else if (this.match(TokenType.GT) || this.matchValue('superieur')) {
2076
+ } else if (this.match(TokenType.GT) || this.matchValue('superieur') || this.matchValue('supérieur')) {
1963
2077
  const right = this.parseAdditive(lang)
1964
2078
  left = { type: 'BinaryExpression', operator: '>', left, right }
1965
- } else if (this.match(TokenType.LTE)) {
1966
- const right = this.parseAdditive(lang)
1967
- left = { type: 'BinaryExpression', operator: '<=', left, right }
1968
- } else if (this.match(TokenType.GTE)) {
1969
- const right = this.parseAdditive(lang)
1970
- left = { type: 'BinaryExpression', operator: '>=', left, right }
1971
2079
  } else {
1972
2080
  break
1973
2081
  }
@@ -2086,6 +2194,10 @@ class EtherParser {
2086
2194
  if (token.type === TokenType.IDENTIFIER) {
2087
2195
  const value = token.value.toLowerCase()
2088
2196
 
2197
+ if (value === 'fonction' || value === 'function') {
2198
+ return this.parseFunctionExpression(lang)
2199
+ }
2200
+
2089
2201
  if (value === 'vrai' || value === 'true') {
2090
2202
  this.advance()
2091
2203
  return { type: 'Literal', value: true }
@@ -5,6 +5,9 @@ class JSGenerator {
5
5
  this.i18n = null
6
6
  this.indent = 0
7
7
  this.output = ''
8
+ this.keywordMap = {}
9
+ this.methodMap = {}
10
+ this.builtinMap = {}
8
11
 
9
12
  if (i18nPath) {
10
13
  this.loadI18n(i18nPath)
@@ -18,10 +21,6 @@ class JSGenerator {
18
21
  }
19
22
 
20
23
  buildMaps() {
21
- this.keywordMap = {}
22
- this.methodMap = {}
23
- this.builtinMap = {}
24
-
25
24
  if (!this.i18n) return
26
25
 
27
26
  const addToMap = (map, section) => {
@@ -326,6 +325,8 @@ class JSGenerator {
326
325
  break
327
326
  case 'ArrowFunctionExpression':
328
327
  return this.generateArrowFunction(node)
328
+ case 'FunctionExpression':
329
+ return this.generateFunctionExpression(node)
329
330
  case 'CallExpression':
330
331
  return this.generateCallExpression(node)
331
332
  case 'MemberExpression':
@@ -407,6 +408,28 @@ class JSGenerator {
407
408
  this.writeLine('')
408
409
  }
409
410
 
411
+ generateFunctionExpression(node) {
412
+ const async = node.async ? 'async ' : ''
413
+ const generator = node.generator ? '*' : ''
414
+ const name = node.name ? this.translate(node.name) : ''
415
+ const params = (node.params || []).map(p => this.generateParameter(p)).join(', ')
416
+
417
+ const bodyStatements = node.body?.body || []
418
+ const bodyCode = bodyStatements.map(stmt => {
419
+ const savedOutput = this.output
420
+ const savedIndent = this.indent
421
+ this.output = ''
422
+ this.indent = 1
423
+ this.generateNode(stmt)
424
+ const stmtCode = this.output.trim()
425
+ this.output = savedOutput
426
+ this.indent = savedIndent
427
+ return stmtCode
428
+ }).join('\n ')
429
+
430
+ return `${async}function${generator}${name ? ' ' + name : ''}(${params}) {\n ${bodyCode}\n }`
431
+ }
432
+
410
433
  generateParameter(node) {
411
434
  if (!node) return ''
412
435
  if (typeof node === 'string') return node
@@ -466,17 +489,22 @@ class JSGenerator {
466
489
  this.writeLine('')
467
490
  }
468
491
 
469
- generateIfStatement(node) {
470
- const test = this.generateNode(node.test)
471
- this.writeLine(`if (${test}) {`)
492
+ generateIfStatement(node, isElseIf = false) {
493
+ const test = this.generateNode(node.test || node.condition)
494
+
495
+ if (isElseIf) {
496
+ this.writeLine(`} else if (${test}) {`)
497
+ } else {
498
+ this.writeLine(`if (${test}) {`)
499
+ }
500
+
472
501
  this.indent++
473
502
  this.generateNode(node.consequent)
474
503
  this.indent--
475
504
 
476
505
  if (node.alternate) {
477
506
  if (node.alternate.type === 'IfStatement') {
478
- this.output = this.output.trimEnd() + ' else '
479
- this.generateIfStatement(node.alternate)
507
+ this.generateIfStatement(node.alternate, true)
480
508
  } else {
481
509
  this.writeLine('} else {')
482
510
  this.indent++
package/i18n/i18n-js.json CHANGED
@@ -158,14 +158,6 @@
158
158
  "zh": "正则表达式",
159
159
  "ja": "正規表現"
160
160
  },
161
- "carte": {
162
- "fr": "carte",
163
- "en": "map",
164
- "es": "mapa",
165
- "ru": "карта",
166
- "zh": "映射",
167
- "ja": "マップ"
168
- },
169
161
  "ensemble": {
170
162
  "fr": "ensemble",
171
163
  "en": "set",
@@ -2787,4 +2779,4 @@
2787
2779
  "ja": "レングス"
2788
2780
  }
2789
2781
  }
2790
- }
2782
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {