ether-code 0.9.5 → 0.9.7

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.5'
9
+ const VERSION = '0.9.7'
10
10
 
11
11
  const COLORS = {
12
12
  reset: '\x1b[0m',
@@ -325,15 +325,30 @@ class PHPGenerator {
325
325
 
326
326
  extractTypeName(typeNode) {
327
327
  if (!typeNode) return ''
328
- if (typeof typeNode === 'string') return this.translateKeyword(typeNode)
328
+ if (typeof typeNode === 'string') {
329
+ const translated = this.translateKeyword(typeNode)
330
+ return this.prefixGlobalClass(translated)
331
+ }
329
332
  if (typeNode.type === 'TypeHint') {
330
- const types = (typeNode.types || []).map(t => this.translateKeyword(t))
333
+ const types = (typeNode.types || []).map(t => {
334
+ const translated = this.translateKeyword(t)
335
+ return this.prefixGlobalClass(translated)
336
+ })
331
337
  const result = types.join('|')
332
338
  return typeNode.nullable ? '?' + result : result
333
339
  }
334
- if (typeNode.name) return this.translateKeyword(typeNode.name)
335
- if (typeNode.type === 'Identifier') return this.translateKeyword(typeNode.name || typeNode.value || '')
336
- if (typeNode.value) return this.translateKeyword(typeNode.value)
340
+ if (typeNode.name) {
341
+ const translated = this.translateKeyword(typeNode.name)
342
+ return this.prefixGlobalClass(translated)
343
+ }
344
+ if (typeNode.type === 'Identifier') {
345
+ const translated = this.translateKeyword(typeNode.name || typeNode.value || '')
346
+ return this.prefixGlobalClass(translated)
347
+ }
348
+ if (typeNode.value) {
349
+ const translated = this.translateKeyword(typeNode.value)
350
+ return this.prefixGlobalClass(translated)
351
+ }
337
352
  return ''
338
353
  }
339
354
 
@@ -341,8 +356,10 @@ class PHPGenerator {
341
356
  this.output = ''
342
357
  this.indent = 0
343
358
  this.closureVariables = new Set()
359
+ this.importedClasses = new Set()
344
360
 
345
361
  this.collectClosureVariables(ast)
362
+ this.collectImportedClasses(ast)
346
363
 
347
364
  if (ast.phpTag !== false) {
348
365
  this.output = '<?php\n'
@@ -367,6 +384,27 @@ class PHPGenerator {
367
384
  return this.output.trim()
368
385
  }
369
386
 
387
+ collectImportedClasses(ast) {
388
+ const nodes = Array.isArray(ast) ? ast : (ast?.body || [ast])
389
+
390
+ for (const node of nodes) {
391
+ if (!node) continue
392
+
393
+ if (node.type === 'UseStatement') {
394
+ if (node.imports && node.imports.length > 0) {
395
+ for (const imp of node.imports) {
396
+ const path = imp.path || imp.name || ''
397
+ const className = path.split('\\').pop()
398
+ if (className) this.importedClasses.add(className)
399
+ }
400
+ } else if (node.name) {
401
+ const className = node.name.split('\\').pop()
402
+ if (className) this.importedClasses.add(className)
403
+ }
404
+ }
405
+ }
406
+ }
407
+
370
408
  collectClosureVariables(ast) {
371
409
  const nodes = Array.isArray(ast) ? ast : (ast?.body || [ast])
372
410
 
@@ -664,7 +702,7 @@ class PHPGenerator {
664
702
  generateClassMember(node) {
665
703
  if (!node) return
666
704
 
667
- if (node.type === 'UseTraitStatement') {
705
+ if (node.type === 'UseTraitStatement' || node.type === 'TraitUse') {
668
706
  this.writeLine(`use ${node.traits.join(', ')};`)
669
707
  return
670
708
  }
@@ -923,9 +961,9 @@ class PHPGenerator {
923
961
  const catches = node.catches || (node.handler ? [node.handler] : [])
924
962
  for (const catchClause of catches) {
925
963
  const types = catchClause.types || []
926
- const exceptionType = types.length > 0
927
- ? types.join('|')
928
- : (catchClause.exceptionType || catchClause.type || 'Exception')
964
+ let exceptionType = types.length > 0
965
+ ? types.map(t => this.prefixGlobalClass(t)).join('|')
966
+ : this.prefixGlobalClass(catchClause.exceptionType || catchClause.type || 'Exception')
929
967
  const param = catchClause.param
930
968
  ? this.generateVariable(catchClause.param)
931
969
  : '$e'
@@ -947,6 +985,37 @@ class PHPGenerator {
947
985
  return ''
948
986
  }
949
987
 
988
+ prefixGlobalClass(name) {
989
+ if (!name) return name
990
+
991
+ if (this.importedClasses && this.importedClasses.has(name)) {
992
+ return name
993
+ }
994
+
995
+ const phpGlobalClasses = [
996
+ 'Exception', 'Error', 'TypeError', 'ValueError', 'ArgumentCountError',
997
+ 'ArithmeticError', 'DivisionByZeroError', 'ParseError', 'AssertionError',
998
+ 'CompileError', 'UnhandledMatchError', 'FiberError',
999
+ 'ErrorException', 'BadFunctionCallException', 'BadMethodCallException',
1000
+ 'DomainException', 'InvalidArgumentException', 'LengthException',
1001
+ 'LogicException', 'OutOfBoundsException', 'OutOfRangeException',
1002
+ 'OverflowException', 'RangeException', 'RuntimeException',
1003
+ 'UnderflowException', 'UnexpectedValueException',
1004
+ 'PDOException', 'JsonException', 'IntlException',
1005
+ 'Generator', 'Iterator', 'IteratorAggregate', 'Traversable',
1006
+ 'ArrayAccess', 'Countable', 'Serializable', 'Stringable',
1007
+ 'DateTime', 'DateTimeImmutable', 'DateTimeInterface', 'DateInterval', 'DatePeriod',
1008
+ 'PDO', 'PDOStatement', 'Closure', 'stdClass', 'WeakReference', 'WeakMap',
1009
+ 'SplFileInfo', 'SplFileObject', 'SplTempFileObject',
1010
+ 'ArrayObject', 'ArrayIterator', 'RecursiveArrayIterator',
1011
+ 'Fiber', 'ReflectionClass', 'ReflectionMethod', 'ReflectionProperty'
1012
+ ]
1013
+ if (phpGlobalClasses.includes(name) && !name.startsWith('\\')) {
1014
+ return '\\' + name
1015
+ }
1016
+ return name
1017
+ }
1018
+
950
1019
  generateReturnStatement(node) {
951
1020
  if (node.argument) {
952
1021
  const arg = this.generateNode(node.argument)
@@ -1241,9 +1310,9 @@ class PHPGenerator {
1241
1310
  generateNewExpression(node) {
1242
1311
  let callee
1243
1312
  if (typeof node.callee === 'string') {
1244
- callee = node.callee
1313
+ callee = this.prefixGlobalClass(node.callee)
1245
1314
  } else if (node.callee.type === 'Identifier') {
1246
- callee = node.callee.name
1315
+ callee = this.prefixGlobalClass(node.callee.name)
1247
1316
  } else {
1248
1317
  callee = this.generateNode(node.callee)
1249
1318
  }
@@ -419,7 +419,7 @@ class EtherLexer {
419
419
  break
420
420
  }
421
421
  if (this.peek() === '\n') {
422
- this.tokens.push(new Token(TokenType.ERROR, 'Chaîne non terminée', startLine, startCol, this.currentIndent))
422
+ this.tokens.push(new Token(TokenType.ERROR, 'Chaîne non terminée', startLine, startCol, this.currentIndent))
423
423
  return
424
424
  }
425
425
  }
@@ -458,7 +458,7 @@ class EtherLexer {
458
458
  value += String.fromCodePoint(parseInt(unicode, 16))
459
459
  break
460
460
  default:
461
- value += escaped
461
+ value += '\\' + escaped
462
462
  }
463
463
  } else {
464
464
  value += this.advance()
@@ -1001,7 +1001,7 @@ class EtherLexer {
1001
1001
  break
1002
1002
 
1003
1003
  default:
1004
- this.tokens.push(new Token(TokenType.ERROR, `Caractère inattendu: ${char}`, startLine, startCol, this.currentIndent))
1004
+ this.tokens.push(new Token(TokenType.ERROR, `Caractère inattendu: ${char}`, startLine, startCol, this.currentIndent))
1005
1005
  }
1006
1006
  }
1007
1007
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {