ether-code 0.8.2 → 0.8.4

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.8.2'
9
+ const VERSION = '0.8.4'
10
10
 
11
11
  const COLORS = {
12
12
  reset: '\x1b[0m',
@@ -101,6 +101,8 @@ class PHPGenerator {
101
101
 
102
102
  const generators = {
103
103
  'Program': () => this.generateProgram(node),
104
+ 'DeclareStatement': () => this.generateDeclareStatement(node),
105
+ 'NamespaceDeclaration': () => this.generateNamespaceDeclaration(node),
104
106
  'FunctionDeclaration': () => this.generateFunctionDeclaration(node),
105
107
  'ClassDeclaration': () => this.generateClassDeclaration(node),
106
108
  'InterfaceDeclaration': () => this.generateInterfaceDeclaration(node),
@@ -110,6 +112,7 @@ class PHPGenerator {
110
112
  'PropertyDeclaration': () => this.generatePropertyDeclaration(node),
111
113
  'VariableDeclaration': () => this.generateVariableDeclaration(node),
112
114
  'ConstantDeclaration': () => this.generateConstantDeclaration(node),
115
+ 'DefineDeclaration': () => this.generateDefineDeclaration(node),
113
116
  'IfStatement': () => this.generateIfStatement(node),
114
117
  'ForStatement': () => this.generateForStatement(node),
115
118
  'ForEachStatement': () => this.generateForEachStatement(node),
@@ -176,6 +179,33 @@ class PHPGenerator {
176
179
  }
177
180
  }
178
181
 
182
+ generateDeclareStatement(node) {
183
+ const directives = (node.directives || []).map(d => {
184
+ const name = this.safeString(d.name)
185
+ const value = this.generateNode(d.value)
186
+ return `${name}=${value}`
187
+ }).join(', ')
188
+
189
+ this.writeLine(`declare(${directives});`)
190
+ this.writeLine('')
191
+ }
192
+
193
+ generateNamespaceDeclaration(node) {
194
+ const name = this.safeString(node.name)
195
+ this.writeLine(`namespace ${name};`)
196
+ this.writeLine('')
197
+
198
+ if (node.body) {
199
+ this.generateNode(node.body)
200
+ }
201
+ }
202
+
203
+ generateDefineDeclaration(node) {
204
+ const name = this.safeString(node.name)
205
+ const value = this.generateNode(node.value)
206
+ this.writeLine(`define('${name}', ${value});`)
207
+ }
208
+
179
209
  generateFunctionDeclaration(node) {
180
210
  const name = this.safeString(node.name || node.id?.name || 'anonymous')
181
211
  const translatedName = this.translate(name)
@@ -465,7 +495,7 @@ class PHPGenerator {
465
495
  generateVariableDeclaration(node) {
466
496
  for (const decl of node.declarations || [node]) {
467
497
  const name = this.safeString(decl.name || decl.id?.name || decl.id)
468
- const varName = '$' + this.translate(name)
498
+ const varName = '$' + name
469
499
 
470
500
  if (decl.init !== undefined) {
471
501
  const value = this.generateNode(decl.init)
@@ -640,7 +670,8 @@ class PHPGenerator {
640
670
  }
641
671
 
642
672
  generateEchoStatement(node) {
643
- const args = (node.arguments || [node.argument]).filter(Boolean).map(a => this.generateNode(a)).join(', ')
673
+ const exprs = node.expressions || node.arguments || [node.argument]
674
+ const args = exprs.filter(Boolean).map(a => this.generateNode(a)).join(', ')
644
675
  this.writeLine(`echo ${args};`)
645
676
  }
646
677
 
@@ -656,10 +687,19 @@ class PHPGenerator {
656
687
  }
657
688
 
658
689
  generateUseStatement(node) {
659
- const name = this.safeString(node.name || node.source)
660
- const alias = node.alias ? ' as ' + node.alias : ''
661
- const type = node.type === 'function' ? 'function ' : (node.type === 'const' ? 'const ' : '')
662
- this.writeLine(`use ${type}${name}${alias};`)
690
+ const typePrefix = node.useType === 'function' ? 'function ' : (node.useType === 'const' ? 'const ' : '')
691
+
692
+ if (node.imports && node.imports.length > 0) {
693
+ for (const imp of node.imports) {
694
+ const path = this.safeString(imp.path)
695
+ const alias = imp.alias ? ' as ' + imp.alias : ''
696
+ this.writeLine(`use ${typePrefix}${path}${alias};`)
697
+ }
698
+ } else {
699
+ const name = this.safeString(node.name || node.source)
700
+ const alias = node.alias ? ' as ' + node.alias : ''
701
+ this.writeLine(`use ${typePrefix}${name}${alias};`)
702
+ }
663
703
  }
664
704
 
665
705
  generateIncludeStatement(node) {
@@ -878,43 +918,41 @@ class PHPGenerator {
878
918
  if (!node) return '$var'
879
919
 
880
920
  const name = this.safeString(node.name || node.id?.name || node)
881
- const translated = this.translate(name)
882
- const translatedStr = String(translated)
921
+ const nameStr = String(name)
883
922
 
884
- if (translatedStr.startsWith('$')) return translatedStr
885
- return '$' + translatedStr
923
+ if (nameStr.startsWith('$')) return nameStr
924
+ return '$' + nameStr
886
925
  }
887
926
 
888
927
  generateIdentifier(node) {
889
928
  if (!node) return '$var'
890
929
 
891
930
  const name = this.safeString(node.name || node.id?.name || node)
892
- const translated = this.translate(name)
893
- const translatedStr = String(translated)
931
+ const nameStr = String(name)
894
932
 
895
- if (translatedStr.startsWith('$')) return translatedStr
933
+ if (nameStr.startsWith('$')) return nameStr
896
934
 
897
935
  const keywords = [
898
936
  'true', 'false', 'null',
899
937
  'self', 'parent', 'static',
900
938
  'this', '$this'
901
939
  ]
902
- if (keywords.includes(translatedStr.toLowerCase())) {
903
- if (translatedStr.toLowerCase() === 'this') return '$this'
904
- return translatedStr
940
+ if (keywords.includes(nameStr.toLowerCase())) {
941
+ if (nameStr.toLowerCase() === 'this') return '$this'
942
+ return nameStr
905
943
  }
906
944
 
907
- if (/^[A-Z]/.test(translatedStr)) return translatedStr
945
+ if (/^[A-Z]/.test(nameStr)) return nameStr
908
946
 
909
- if (translatedStr.includes('(') || translatedStr.includes('::')) return translatedStr
947
+ if (nameStr.includes('(') || nameStr.includes('::')) return nameStr
910
948
 
911
949
  const superglobals = ['_GET', '_POST', '_SERVER', '_SESSION', '_COOKIE', '_FILES', '_REQUEST', '_ENV', 'GLOBALS']
912
- const upper = translatedStr.toUpperCase()
913
- if (superglobals.includes(translatedStr) || superglobals.includes(upper)) {
950
+ const upper = nameStr.toUpperCase()
951
+ if (superglobals.includes(nameStr) || superglobals.includes(upper)) {
914
952
  return '$' + upper
915
953
  }
916
954
 
917
- return '$' + translatedStr
955
+ return '$' + nameStr
918
956
  }
919
957
 
920
958
  generateLiteral(node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {
@@ -226,6 +226,12 @@ class EtherParserPHP extends EtherParserBase {
226
226
  this.phpModifiers = ['statique', 'static', 'final', 'finale', 'abstrait', 'abstraite', 'abstract', 'readonly', 'lecture seule']
227
227
  }
228
228
 
229
+ safeStr(val) {
230
+ if (typeof val === 'string') return val
231
+ if (val && typeof val === 'object') return String(val.name || val.value || '')
232
+ return String(val || '')
233
+ }
234
+
229
235
  translatePHP(word) {
230
236
  if (!word) return word
231
237
  const lower = this.normalizeAccents(String(word))
@@ -272,6 +278,10 @@ class EtherParserPHP extends EtherParserBase {
272
278
 
273
279
  const value = token.value != null ? this.normalizeAccents(String(token.value).toLowerCase()) : ''
274
280
 
281
+ if (this.isDeclare(value)) {
282
+ return this.parseDeclare(lang)
283
+ }
284
+
275
285
  if (this.isNamespace(value)) {
276
286
  return this.parseNamespace(lang)
277
287
  }
@@ -365,7 +375,17 @@ class EtherParserPHP extends EtherParserBase {
365
375
  }
366
376
 
367
377
  isNamespace(value) {
368
- return ['namespace', 'espace de noms'].includes(value)
378
+ if (value === 'namespace') return true
379
+ if (value === 'espace') {
380
+ const next1 = this.peek(1)
381
+ const next2 = this.peek(2)
382
+ if (next1 && next2) {
383
+ const val1 = this.normalizeAccents(String(next1.value).toLowerCase())
384
+ const val2 = this.normalizeAccents(String(next2.value).toLowerCase())
385
+ if (val1 === 'de' && val2 === 'noms') return true
386
+ }
387
+ }
388
+ return false
369
389
  }
370
390
 
371
391
  isUse(value) {
@@ -463,8 +483,54 @@ class EtherParserPHP extends EtherParserBase {
463
483
  return value === 'match'
464
484
  }
465
485
 
466
- parseNamespace(lang) {
486
+ isDeclare(value) {
487
+ return ['declare', 'declarer', 'déclarer'].includes(value)
488
+ }
489
+
490
+ parseDeclare(lang) {
467
491
  this.advance()
492
+
493
+ const directives = []
494
+
495
+ if (this.match(TokenType.LPAREN)) {
496
+ do {
497
+ const nameToken = this.current()
498
+ const name = nameToken ? this.safeStr(nameToken.value) : ''
499
+ this.advance()
500
+
501
+ this.match(TokenType.EQUALS)
502
+
503
+ const value = this.parseExpression(lang)
504
+ directives.push({ name, value })
505
+ } while (this.match(TokenType.COMMA))
506
+
507
+ this.match(TokenType.RPAREN)
508
+ } else {
509
+ const nameToken = this.current()
510
+ const name = nameToken ? this.safeStr(nameToken.value) : ''
511
+ this.advance()
512
+
513
+ this.match(TokenType.EQUALS)
514
+
515
+ const value = this.parseExpression(lang)
516
+ directives.push({ name, value })
517
+ }
518
+
519
+ return {
520
+ type: 'DeclareStatement',
521
+ directives: directives
522
+ }
523
+ }
524
+
525
+ parseNamespace(lang) {
526
+ const first = this.advance()
527
+ const firstVal = this.normalizeAccents(String(first.value).toLowerCase())
528
+
529
+ if (firstVal === 'espace') {
530
+ this.advance()
531
+ this.advance()
532
+ }
533
+
468
534
  const name = this.parseNamespacePath(lang)
469
535
  this.skipNewlines()
470
536
 
@@ -736,7 +802,7 @@ class EtherParserPHP extends EtherParserBase {
736
802
  }
737
803
 
738
804
  const nameToken = this.current()
739
- let name = nameToken ? nameToken.value : 'property'
805
+ let name = this.safeStr(nameToken ? nameToken.value : 'property')
740
806
 
741
807
  if (name.startsWith('$')) {
742
808
  name = name.substring(1)
@@ -1047,7 +1113,7 @@ class EtherParserPHP extends EtherParserBase {
1047
1113
  }
1048
1114
 
1049
1115
  const varToken = this.current()
1050
- let varName = varToken ? varToken.value : ''
1116
+ let varName = this.safeStr(varToken ? varToken.value : '')
1051
1117
  if (varName.startsWith('$')) {
1052
1118
  varName = varName.substring(1)
1053
1119
  }
@@ -1126,7 +1192,7 @@ class EtherParserPHP extends EtherParserBase {
1126
1192
  const nameToken = this.current()
1127
1193
  if (!nameToken) return null
1128
1194
 
1129
- let name = nameToken.value
1195
+ let name = this.safeStr(nameToken.value)
1130
1196
  if (name.startsWith('$')) {
1131
1197
  name = name.substring(1)
1132
1198
  }
@@ -1218,7 +1284,7 @@ class EtherParserPHP extends EtherParserBase {
1218
1284
  }
1219
1285
 
1220
1286
  const nameToken = this.current()
1221
- let name = nameToken ? nameToken.value : 'variable'
1287
+ let name = this.safeStr(nameToken ? nameToken.value : 'variable')
1222
1288
  if (name.startsWith('$')) {
1223
1289
  name = name.substring(1)
1224
1290
  }
@@ -1372,7 +1438,7 @@ class EtherParserPHP extends EtherParserBase {
1372
1438
  }
1373
1439
 
1374
1440
  const firstVar = this.current()
1375
- let firstName = firstVar ? firstVar.value : 'item'
1441
+ let firstName = this.safeStr(firstVar ? firstVar.value : 'item')
1376
1442
  if (firstName.startsWith('$')) firstName = firstName.substring(1)
1377
1443
  this.advance()
1378
1444
 
@@ -1384,7 +1450,7 @@ class EtherParserPHP extends EtherParserBase {
1384
1450
  }
1385
1451
 
1386
1452
  const valueVar = this.current()
1387
- value = valueVar ? valueVar.value : 'value'
1453
+ let value = this.safeStr(valueVar ? valueVar.value : 'value')
1388
1454
  if (value.startsWith('$')) value = value.substring(1)
1389
1455
  this.advance()
1390
1456
  } else {
@@ -1632,7 +1698,7 @@ class EtherParserPHP extends EtherParserBase {
1632
1698
  do {
1633
1699
  const typeToken = this.current()
1634
1700
  if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
1635
- const typeName = typeToken.value
1701
+ const typeName = this.safeStr(typeToken.value)
1636
1702
  if (typeName.startsWith('$')) {
1637
1703
  param = typeName.substring(1)
1638
1704
  } else {
@@ -1645,7 +1711,7 @@ class EtherParserPHP extends EtherParserBase {
1645
1711
  if (!param) {
1646
1712
  const paramToken = this.current()
1647
1713
  if (paramToken && paramToken.type === TokenType.IDENTIFIER) {
1648
- param = paramToken.value
1714
+ param = this.safeStr(paramToken.value)
1649
1715
  if (param.startsWith('$')) param = param.substring(1)
1650
1716
  this.advance()
1651
1717
  }
@@ -1759,7 +1825,7 @@ class EtherParserPHP extends EtherParserBase {
1759
1825
  const variables = []
1760
1826
  do {
1761
1827
  const varToken = this.current()
1762
- let varName = varToken ? varToken.value : ''
1828
+ let varName = this.safeStr(varToken ? varToken.value : '')
1763
1829
  if (varName.startsWith('$')) varName = varName.substring(1)
1764
1830
  this.advance()
1765
1831
  variables.push(varName)
@@ -2209,11 +2275,11 @@ class EtherParserPHP extends EtherParserBase {
2209
2275
 
2210
2276
  if (token.type === TokenType.STRING) {
2211
2277
  this.advance()
2212
- let value = token.value
2278
+ let value = this.safeStr(token.value)
2213
2279
  if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
2214
2280
  value = value.slice(1, -1)
2215
2281
  }
2216
- const isDouble = token.value.startsWith('"')
2282
+ const isDouble = value.startsWith('"') || this.safeStr(token.value).startsWith('"')
2217
2283
  return { type: 'StringLiteral', value, doubleQuoted: isDouble }
2218
2284
  }
2219
2285
 
@@ -2223,7 +2289,7 @@ class EtherParserPHP extends EtherParserBase {
2223
2289
  }
2224
2290
 
2225
2291
  if (token.type === TokenType.IDENTIFIER) {
2226
- const value = token.value
2292
+ const value = this.safeStr(token.value)
2227
2293
  const valueLower = this.normalizeAccents(value.toLowerCase())
2228
2294
 
2229
2295
  if (valueLower === 'vrai' || valueLower === 'true') {
@@ -2285,7 +2351,7 @@ class EtherParserPHP extends EtherParserBase {
2285
2351
 
2286
2352
  if (token.type === TokenType.VARIABLE) {
2287
2353
  this.advance()
2288
- let name = token.value
2354
+ let name = this.safeStr(token.value)
2289
2355
  if (name.startsWith('$')) name = name.substring(1)
2290
2356
  return { type: 'Variable', name }
2291
2357
  }
@@ -30,13 +30,23 @@ class EtherParser {
30
30
  if (!this.parsers[lang]) {
31
31
  switch (lang) {
32
32
  case 'js':
33
+ this.parsers[lang] = new EtherParserJS(this.options)
34
+ break
33
35
  case 'ts':
36
+ this.parsers[lang] = new EtherParserJS(this.options)
37
+ break
34
38
  case 'react':
39
+ this.parsers[lang] = new EtherParserJS(this.options)
40
+ break
35
41
  case 'node':
42
+ this.parsers[lang] = new EtherParserJS(this.options)
43
+ break
36
44
  case 'php':
37
45
  this.parsers[lang] = new EtherParserPHP(this.options)
38
46
  break
39
47
  case 'python':
48
+ this.parsers[lang] = new EtherParserJS(this.options)
49
+ break
40
50
  case 'ruby':
41
51
  this.parsers[lang] = new EtherParserJS(this.options)
42
52
  break
@@ -53,15 +63,13 @@ class EtherParser {
53
63
  this.parsers[lang] = new EtherParserGraphQL(this.options)
54
64
  break
55
65
  default:
56
- this.parsers[lang] = new EtherParserJS(this.options)
66
+ this.parsers[lang] = new EtherParserHTML(this.options)
57
67
  }
58
68
  }
59
69
  return this.parsers[lang]
60
70
  }
61
71
 
62
72
  detectTargetLanguage(source) {
63
- const lower = source.toLowerCase()
64
-
65
73
  const targetMatch = source.match(/\/\/\s*cible\s*:\s*(\w+)/i)
66
74
  if (targetMatch) {
67
75
  const target = targetMatch[1].toLowerCase()
@@ -83,6 +91,8 @@ class EtherParser {
83
91
  }
84
92
  }
85
93
 
94
+ const lower = source.toLowerCase()
95
+
86
96
  if (/^\s*(document|page|<!doctype|<html|tete|corps|entete|navigation|section|article)/m.test(lower)) {
87
97
  return 'html'
88
98
  }
@@ -133,7 +143,7 @@ class EtherParser {
133
143
  return 'js'
134
144
  }
135
145
 
136
- return 'js'
146
+ return 'html'
137
147
  }
138
148
 
139
149
  parse(source, targetLang = null) {
@@ -145,4 +155,4 @@ class EtherParser {
145
155
  }
146
156
  }
147
157
 
148
- module.exports = { EtherParser, TokenType }
158
+ module.exports = { EtherParser, TokenType }