ether-code 0.9.4 → 0.9.5

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.9.4'
9
+ const VERSION = '0.9.5'
10
10
 
11
11
  const COLORS = {
12
12
  reset: '\x1b[0m',
@@ -134,7 +134,6 @@ class PHPGenerator {
134
134
  'formater nombre': 'number_format',
135
135
  'date': 'date',
136
136
  'temps': 'time',
137
- 'maintenant': 'time',
138
137
  'creer date': 'mktime',
139
138
  'date vers temps': 'strtotime',
140
139
  'formater date': 'date_format',
@@ -305,6 +304,25 @@ class PHPGenerator {
305
304
  return this.keywordMap[normalized] || word
306
305
  }
307
306
 
307
+ translateMethodName(word) {
308
+ if (!word) return word
309
+ const normalized = this.normalizeAccents(word)
310
+ const magicMethods = {
311
+ 'constructeur': '__construct',
312
+ 'destructeur': '__destruct',
313
+ 'obtenir': '__get',
314
+ 'definir': '__set',
315
+ 'appeler': '__call',
316
+ 'vers chaine': '__toString',
317
+ 'invoquer': '__invoke',
318
+ 'cloner': '__clone',
319
+ 'serialiser': '__serialize',
320
+ 'deserialiser': '__unserialize',
321
+ 'deboguer': '__debugInfo'
322
+ }
323
+ return magicMethods[normalized] || word
324
+ }
325
+
308
326
  extractTypeName(typeNode) {
309
327
  if (!typeNode) return ''
310
328
  if (typeof typeNode === 'string') return this.translateKeyword(typeNode)
@@ -322,6 +340,9 @@ class PHPGenerator {
322
340
  generate(ast) {
323
341
  this.output = ''
324
342
  this.indent = 0
343
+ this.closureVariables = new Set()
344
+
345
+ this.collectClosureVariables(ast)
325
346
 
326
347
  if (ast.phpTag !== false) {
327
348
  this.output = '<?php\n'
@@ -346,6 +367,32 @@ class PHPGenerator {
346
367
  return this.output.trim()
347
368
  }
348
369
 
370
+ collectClosureVariables(ast) {
371
+ const nodes = Array.isArray(ast) ? ast : (ast?.body || [ast])
372
+
373
+ for (const node of nodes) {
374
+ if (!node) continue
375
+
376
+ if (node.type === 'VariableDeclaration') {
377
+ const init = node.init || node.value
378
+ if (init && (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression' || init.type === 'ClosureExpression')) {
379
+ const name = node.name || node.id?.name
380
+ if (name) this.closureVariables.add(name)
381
+ }
382
+ }
383
+
384
+ if (node.body) {
385
+ this.collectClosureVariables(node.body)
386
+ }
387
+ if (node.consequent) {
388
+ this.collectClosureVariables(Array.isArray(node.consequent) ? node.consequent : [node.consequent])
389
+ }
390
+ if (node.alternate) {
391
+ this.collectClosureVariables(Array.isArray(node.alternate) ? node.alternate : [node.alternate])
392
+ }
393
+ }
394
+ }
395
+
349
396
  generateNode(node) {
350
397
  if (!node) return ''
351
398
 
@@ -381,6 +428,8 @@ class PHPGenerator {
381
428
  return this.generateForStatement(node)
382
429
  case 'ForEachStatement':
383
430
  return this.generateForEachStatement(node)
431
+ case 'ForeachStatement':
432
+ return this.generateForEachStatement(node)
384
433
  case 'WhileStatement':
385
434
  return this.generateWhileStatement(node)
386
435
  case 'DoWhileStatement':
@@ -634,7 +683,7 @@ class PHPGenerator {
634
683
  this.writeLine(`${visibility} ${isStatic}${isReadonly}${typeHint}${name}${value};`)
635
684
  } else if (node.type === 'Method' || node.kind === 'method' || node.type === 'MethodDeclaration') {
636
685
  const name = node.name || node.key?.name || ''
637
- const translatedName = this.translateKeyword(name)
686
+ const translatedName = this.translateMethodName(name)
638
687
  const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
639
688
  let returnType = ''
640
689
 
@@ -688,7 +737,7 @@ class PHPGenerator {
688
737
 
689
738
  const visibility = 'public'
690
739
  const name = node.name || node.key?.name || ''
691
- const translatedName = this.translateKeyword(name)
740
+ const translatedName = this.translateMethodName(name)
692
741
  const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
693
742
  let returnType = ''
694
743
 
@@ -871,21 +920,26 @@ class PHPGenerator {
871
920
  this.generateBody(node.block)
872
921
  this.indent--
873
922
 
874
- if (node.handler) {
875
- const exceptionType = node.handler.exceptionType || node.handler.type || 'Exception'
876
- const param = node.handler.param
877
- ? this.generateVariable(node.handler.param)
923
+ const catches = node.catches || (node.handler ? [node.handler] : [])
924
+ for (const catchClause of catches) {
925
+ const types = catchClause.types || []
926
+ const exceptionType = types.length > 0
927
+ ? types.join('|')
928
+ : (catchClause.exceptionType || catchClause.type || 'Exception')
929
+ const param = catchClause.param
930
+ ? this.generateVariable(catchClause.param)
878
931
  : '$e'
879
932
  this.writeLine(`} catch (${exceptionType} ${param}) {`)
880
933
  this.indent++
881
- this.generateBody(node.handler.body)
934
+ this.generateBody(catchClause.body)
882
935
  this.indent--
883
936
  }
884
937
 
885
- if (node.finalizer) {
938
+ const finallyBlock = node.finally || node.finalizer
939
+ if (finallyBlock) {
886
940
  this.writeLine('} finally {')
887
941
  this.indent++
888
- this.generateBody(node.finalizer)
942
+ this.generateBody(finallyBlock)
889
943
  this.indent--
890
944
  }
891
945
 
@@ -932,19 +986,82 @@ class PHPGenerator {
932
986
 
933
987
  generateCallExpression(node) {
934
988
  let callee
989
+ let originalName = ''
935
990
 
936
991
  if (typeof node.callee === 'string') {
937
- callee = this.translateFunction(node.callee)
992
+ originalName = node.callee
993
+ if (this.closureVariables && this.closureVariables.has(node.callee)) {
994
+ callee = '$' + node.callee
995
+ } else {
996
+ callee = this.translateFunction(node.callee)
997
+ }
938
998
  } else if (node.callee.type === 'Identifier') {
939
- callee = this.translateFunction(node.callee.name)
999
+ originalName = node.callee.name
1000
+ if (this.closureVariables && this.closureVariables.has(node.callee.name)) {
1001
+ callee = '$' + node.callee.name
1002
+ } else {
1003
+ callee = this.translateFunction(node.callee.name)
1004
+ }
1005
+ } else if (node.callee.type === 'Variable') {
1006
+ callee = this.generateVariable(node.callee)
940
1007
  } else if (node.callee.type === 'MemberExpression' || node.callee.type === 'StaticMemberExpression') {
941
1008
  callee = this.generateNode(node.callee)
942
1009
  } else {
943
1010
  callee = this.generateNode(node.callee)
944
1011
  }
945
1012
 
946
- const args = (node.arguments || []).map(a => this.generateNode(a)).join(', ')
947
- return `${callee}(${args})`
1013
+ let args = (node.arguments || []).map(a => this.generateNode(a))
1014
+
1015
+ args = this.reorderArguments(callee, args, originalName)
1016
+ args = this.addDefaultArguments(callee, args)
1017
+
1018
+ return `${callee}(${args.join(', ')})`
1019
+ }
1020
+
1021
+ reorderArguments(func, args, originalName) {
1022
+ const normalized = this.normalizeAccents(originalName)
1023
+
1024
+ if ((func === 'str_replace' || normalized === 'remplacer') && args.length === 3) {
1025
+ return [args[1], args[2], args[0]]
1026
+ }
1027
+
1028
+ if ((func === 'array_map' || normalized === 'mapper' || normalized === 'mapper tableau' || normalized === 'transformer') && args.length === 2) {
1029
+ return [args[1], args[0]]
1030
+ }
1031
+
1032
+ return args
1033
+ }
1034
+
1035
+ addDefaultArguments(func, args) {
1036
+ if (func === 'password_hash' && args.length === 1) {
1037
+ return [...args, 'PASSWORD_DEFAULT']
1038
+ }
1039
+
1040
+ return args
1041
+ }
1042
+
1043
+ isNativeFunction(name) {
1044
+ const natives = [
1045
+ 'echo', 'print', 'var_dump', 'print_r', 'die', 'exit',
1046
+ 'strlen', 'substr', 'strpos', 'str_replace', 'strtoupper', 'strtolower',
1047
+ 'trim', 'ltrim', 'rtrim', 'explode', 'implode', 'sprintf', 'printf',
1048
+ 'count', 'array_push', 'array_pop', 'array_shift', 'array_unshift',
1049
+ 'array_merge', 'array_filter', 'array_map', 'array_reduce', 'array_keys',
1050
+ 'array_values', 'array_sum', 'array_unique', 'array_reverse', 'sort',
1051
+ 'in_array', 'array_key_exists', 'array_search',
1052
+ 'is_array', 'is_string', 'is_int', 'is_float', 'is_bool', 'is_null',
1053
+ 'is_numeric', 'is_object', 'is_callable', 'isset', 'empty', 'gettype',
1054
+ 'intval', 'floatval', 'strval', 'boolval', 'settype',
1055
+ 'abs', 'ceil', 'floor', 'round', 'sqrt', 'pow', 'rand', 'max', 'min', 'pi',
1056
+ 'date', 'time', 'strtotime', 'mktime',
1057
+ 'file_exists', 'file_get_contents', 'file_put_contents', 'fopen', 'fclose', 'fread', 'fwrite',
1058
+ 'json_encode', 'json_decode', 'preg_match', 'preg_match_all', 'preg_replace',
1059
+ 'header', 'session_start', 'session_destroy', 'password_hash', 'password_verify',
1060
+ 'include', 'include_once', 'require', 'require_once',
1061
+ 'class_exists', 'function_exists', 'method_exists', 'defined', 'define', 'constant',
1062
+ 'new', 'throw'
1063
+ ]
1064
+ return natives.includes(name)
948
1065
  }
949
1066
 
950
1067
  generateMemberExpression(node) {
@@ -952,9 +1069,9 @@ class PHPGenerator {
952
1069
  let property
953
1070
 
954
1071
  if (typeof node.property === 'string') {
955
- property = node.property
1072
+ property = this.translateMemberProperty(node.property)
956
1073
  } else if (node.property.type === 'Identifier') {
957
- property = this.translateFunction(node.property.name)
1074
+ property = this.translateMemberProperty(node.property.name)
958
1075
  } else {
959
1076
  property = this.generateNode(node.property)
960
1077
  }
@@ -967,6 +1084,26 @@ class PHPGenerator {
967
1084
  return `${object}${operator}${property}`
968
1085
  }
969
1086
 
1087
+ translateMemberProperty(name) {
1088
+ const translations = {
1089
+ 'valeur': 'value',
1090
+ 'nom': 'name',
1091
+ 'message': 'message',
1092
+ 'code': 'code',
1093
+ 'fichier': 'file',
1094
+ 'ligne': 'line',
1095
+ 'precedent': 'previous',
1096
+ 'trace': 'trace',
1097
+ 'formater': 'format',
1098
+ 'ajouter': 'add',
1099
+ 'modifier': 'modify',
1100
+ 'obtenir': 'get',
1101
+ 'definir': 'set'
1102
+ }
1103
+ const normalized = this.normalizeAccents(name)
1104
+ return translations[normalized] || name
1105
+ }
1106
+
970
1107
  generateStaticMemberExpression(node) {
971
1108
  const cls = node.class?.name || this.generateNode(node.class)
972
1109
  let member = node.member?.name || this.generateNode(node.member)
@@ -1060,12 +1197,6 @@ class PHPGenerator {
1060
1197
  const name = node.name || node
1061
1198
  if (typeof name !== 'string') return '$var'
1062
1199
 
1063
- const normalized = this.normalizeAccents(name)
1064
-
1065
- if (this.functionMap[normalized]) {
1066
- return this.functionMap[normalized]
1067
- }
1068
-
1069
1200
  const translated = this.translateKeyword(name)
1070
1201
 
1071
1202
  if (translated.startsWith('$')) return translated
@@ -1073,11 +1204,11 @@ class PHPGenerator {
1073
1204
  return translated
1074
1205
  }
1075
1206
  if (/^[A-Z]/.test(translated)) return translated
1076
- if (translated === name && !name.startsWith('$')) {
1207
+ if (!name.startsWith('$')) {
1077
1208
  return '$' + name
1078
1209
  }
1079
1210
 
1080
- return translated.startsWith('$') ? translated : '$' + translated
1211
+ return name
1081
1212
  }
1082
1213
 
1083
1214
  generateVariable(node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {
@@ -159,7 +159,6 @@ class EtherParserPHP extends EtherParserBase {
159
159
  'json decoder': 'json_decode',
160
160
  'date': 'date',
161
161
  'temps': 'time',
162
- 'maintenant': 'time',
163
162
  'demarrer session': 'session_start',
164
163
  'detruire session': 'session_destroy',
165
164
  'definir cookie': 'setcookie',