IncludeCPP 3.8.3__tar.gz → 3.8.4__tar.gz

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.
Files changed (60) hide show
  1. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.8.3 → includecpp-3.8.4}/PKG-INFO +1 -1
  3. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/__init__.py +1 -1
  4. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +196 -1
  5. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_builtins.py +133 -0
  6. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_parser.py +99 -7
  7. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_runtime.py +205 -2
  8. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_types.py +58 -9
  9. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +33 -0
  10. {includecpp-3.8.3 → includecpp-3.8.4}/pyproject.toml +1 -1
  11. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/SOURCES.txt +0 -0
  12. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  13. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/entry_points.txt +0 -0
  14. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/requires.txt +0 -0
  15. {includecpp-3.8.3 → includecpp-3.8.4}/IncludeCPP.egg-info/top_level.txt +0 -0
  16. {includecpp-3.8.3 → includecpp-3.8.4}/LICENSE +0 -0
  17. {includecpp-3.8.3 → includecpp-3.8.4}/MANIFEST.in +0 -0
  18. {includecpp-3.8.3 → includecpp-3.8.4}/README.md +0 -0
  19. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/__init__.pyi +0 -0
  20. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/__main__.py +0 -0
  21. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/cli/__init__.py +0 -0
  22. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/cli/commands.py +0 -0
  23. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/cli/config_parser.py +0 -0
  24. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/__init__.py +0 -0
  25. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/ai_integration.py +0 -0
  26. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/build_manager.py +0 -0
  27. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cpp_api.py +0 -0
  28. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cpp_api.pyi +0 -0
  29. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cppy_converter.py +0 -0
  30. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/__init__.py +0 -0
  31. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
  32. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_events.py +0 -0
  33. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_modules.py +0 -0
  34. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl/cssl_syntax.py +0 -0
  35. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl_bridge.py +0 -0
  36. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/cssl_bridge.pyi +0 -0
  37. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/error_catalog.py +0 -0
  38. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/error_formatter.py +0 -0
  39. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/exceptions.py +0 -0
  40. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/path_discovery.py +0 -0
  41. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/project_ui.py +0 -0
  42. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/core/settings_ui.py +0 -0
  43. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/generator/__init__.py +0 -0
  44. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/generator/parser.cpp +0 -0
  45. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/generator/parser.h +0 -0
  46. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/generator/type_resolver.cpp +0 -0
  47. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/generator/type_resolver.h +0 -0
  48. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/py.typed +0 -0
  49. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/templates/cpp.proj.template +0 -0
  50. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/__init__.py +0 -0
  51. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/__init__.py +0 -0
  52. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/extension.js +0 -0
  53. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/images/cssl.png +0 -0
  54. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
  55. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/language-configuration.json +0 -0
  56. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/package.json +0 -0
  57. {includecpp-3.8.3 → includecpp-3.8.4}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
  58. {includecpp-3.8.3 → includecpp-3.8.4}/requirements.txt +0 -0
  59. {includecpp-3.8.3 → includecpp-3.8.4}/setup.cfg +0 -0
  60. {includecpp-3.8.3 → includecpp-3.8.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.8.3
3
+ Version: 3.8.4
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.8.3
3
+ Version: 3.8.4
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "3.8.3"
5
+ __version__ = "3.8.4"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -1,6 +1,6 @@
1
1
  # CSSL - C-Style Scripting Language
2
2
 
3
- > Version 3.7.6 | A modern scripting language with C++-style syntax and unique features like CodeInfusion and BruteInjection.
3
+ > Version 3.8.4 | A modern scripting language with C++-style syntax and unique features like CodeInfusion, BruteInjection, and Python Interop.
4
4
 
5
5
  ---
6
6
 
@@ -1696,6 +1696,201 @@ string result = b.add("Hello ").add("World!").build();
1696
1696
  printl(result); // prints: "Hello World!"
1697
1697
  ```
1698
1698
 
1699
+ ### Class Inheritance (extends)
1700
+
1701
+ CSSL supports class inheritance using the `: extends` syntax:
1702
+
1703
+ ```cssl
1704
+ // Base class
1705
+ class Animal {
1706
+ string name;
1707
+
1708
+ void Animal(string n) {
1709
+ this->name = n;
1710
+ }
1711
+
1712
+ void speak() {
1713
+ printl("Some sound");
1714
+ }
1715
+ }
1716
+
1717
+ // Derived class - inherits all members and methods from Animal
1718
+ class Dog : extends Animal {
1719
+ void Dog(string n) {
1720
+ this->name = n;
1721
+ }
1722
+
1723
+ // Override parent method
1724
+ void speak() {
1725
+ printl("Woof! I'm " + this->name);
1726
+ }
1727
+
1728
+ // New method only in Dog
1729
+ void fetch() {
1730
+ printl(this->name + " fetches the ball!");
1731
+ }
1732
+ }
1733
+
1734
+ Dog d = new Dog("Buddy");
1735
+ d.speak(); // "Woof! I'm Buddy"
1736
+ d.fetch(); // "Buddy fetches the ball!"
1737
+ ```
1738
+
1739
+ ### Extending Python Objects
1740
+
1741
+ You can extend Python classes/objects directly:
1742
+
1743
+ ```cssl
1744
+ // Extend a Python object using $
1745
+ class ExtendedGame : extends $GameEngine {
1746
+ void newFeature() {
1747
+ printl("New CSSL feature!");
1748
+ }
1749
+
1750
+ // Override a Python method
1751
+ void showUsername() {
1752
+ printl("Custom username display: " + this->username);
1753
+ }
1754
+ }
1755
+ ```
1756
+
1757
+ In Python:
1758
+ ```python
1759
+ class GameEngine:
1760
+ def __init__(self):
1761
+ self.username = "Player1"
1762
+ def showUsername(self):
1763
+ print(f"Username: {self.username}")
1764
+
1765
+ cssl = CSSL.CsslLang()
1766
+ cssl.share('GameEngine', GameEngine())
1767
+ cssl.run('''
1768
+ class MyGame : extends $GameEngine {
1769
+ void customMethod() {
1770
+ printl("Extended from Python!");
1771
+ }
1772
+ }
1773
+ ''')
1774
+ ```
1775
+
1776
+ ### Class Overwrites
1777
+
1778
+ Use `: overwrites` to replace methods in an existing class/object:
1779
+
1780
+ ```cssl
1781
+ // Overwrite methods in a Python object
1782
+ class MyOverrides : extends $GameEngine : overwrites $GameEngine {
1783
+ // This method will REPLACE the original showUsername() in $GameEngine
1784
+ void showUsername() {
1785
+ printl("OVERWRITTEN: " + this->username);
1786
+ }
1787
+ }
1788
+ ```
1789
+
1790
+ When you use `: overwrites TargetClass`, all methods defined in your class will replace the corresponding methods in the target. This works with:
1791
+ - Other CSSL classes
1792
+ - Python objects via `$ObjectName`
1793
+ - Shared objects
1794
+
1795
+ ### python::csslize() - Import Python Objects
1796
+
1797
+ Convert Python objects to CSSL-compatible wrappers:
1798
+
1799
+ ```cssl
1800
+ // Import a Python object
1801
+ py_obj <== python::csslize($MyPythonInstance);
1802
+
1803
+ // Now use it like a CSSL object
1804
+ py_obj.someMethod();
1805
+ printl(py_obj.someProperty);
1806
+
1807
+ // Or use it as a base class
1808
+ class Extended : extends py_obj {
1809
+ void newMethod() { ... }
1810
+ }
1811
+ ```
1812
+
1813
+ In Python:
1814
+ ```python
1815
+ class MyPythonClass:
1816
+ def __init__(self, name):
1817
+ self.name = name
1818
+ def greet(self):
1819
+ return f"Hello, {self.name}!"
1820
+
1821
+ cssl = CSSL.CsslLang()
1822
+ cssl.share('MyPython', MyPythonClass("World"))
1823
+ result = cssl.run('''
1824
+ py_obj <== python::csslize($MyPython);
1825
+ printl(py_obj.greet()); // "Hello, World!"
1826
+ ''')
1827
+ ```
1828
+
1829
+ ### Function Extends & Overwrites
1830
+
1831
+ Functions can also extend or overwrite other functions:
1832
+
1833
+ ```cssl
1834
+ // Base function
1835
+ define baseFunction() {
1836
+ string greeting = "Hello";
1837
+ int count = 42;
1838
+ printl(greeting);
1839
+ }
1840
+
1841
+ // Extend: inherit local variables from baseFunction
1842
+ define extendedFunc : extends baseFunction() {
1843
+ // 'greeting' and 'count' are available here!
1844
+ printl(greeting + " World! Count: " + count);
1845
+ }
1846
+
1847
+ // Overwrite: replace the original function
1848
+ define myReplacement : overwrites baseFunction() {
1849
+ printl("This replaces baseFunction entirely!");
1850
+ }
1851
+
1852
+ // After defining myReplacement, calling baseFunction()
1853
+ // will now execute myReplacement instead
1854
+ baseFunction(); // prints: "This replaces baseFunction entirely!"
1855
+ ```
1856
+
1857
+ Overwriting Python functions:
1858
+ ```cssl
1859
+ // Replace a shared Python function
1860
+ define myVersion : overwrites $pythonFunc() {
1861
+ printl("CSSL implementation replaces Python!");
1862
+ }
1863
+ ```
1864
+
1865
+ ### Non-Null Declarations
1866
+
1867
+ Use `*` prefix to declare non-nullable items:
1868
+
1869
+ ```cssl
1870
+ // Non-null variable - can never be None
1871
+ vector<dynamic> *myList; // Always initialized, never null
1872
+
1873
+ // Non-null function - must never return None
1874
+ define *alwaysReturns() {
1875
+ return "Always a value"; // Error if returns null
1876
+ }
1877
+
1878
+ // Non-null class - all methods return non-null
1879
+ class *MyClass {
1880
+ string getValue() {
1881
+ return "Value"; // All methods must return non-null
1882
+ }
1883
+ }
1884
+
1885
+ // Non-null open parameter - filters out None values
1886
+ define process(open *Params) {
1887
+ // Params will never contain None values
1888
+ foreach item in Params {
1889
+ printl(item); // Guaranteed non-null
1890
+ }
1891
+ }
1892
+ ```
1893
+
1699
1894
  ---
1700
1895
 
1701
1896
  ## Map Container
@@ -209,6 +209,8 @@ class CSSLBuiltins:
209
209
  self._functions['python::pythonize'] = self.builtin_python_pythonize
210
210
  self._functions['python::wrap'] = self.builtin_python_pythonize # Alias
211
211
  self._functions['python::export'] = self.builtin_python_pythonize # Alias
212
+ self._functions['python::csslize'] = self.builtin_python_csslize
213
+ self._functions['python::import'] = self.builtin_python_csslize # Alias
212
214
 
213
215
  # Regex functions
214
216
  self._functions['match'] = self.builtin_match
@@ -2524,6 +2526,137 @@ class CSSLBuiltins:
2524
2526
 
2525
2527
  return PythonizedCSSLInstance(cssl_instance, self.runtime)
2526
2528
 
2529
+ def builtin_python_csslize(self, python_obj: Any) -> Any:
2530
+ """Convert a Python object (class instance or function) to a CSSL-compatible wrapper.
2531
+
2532
+ Syntax:
2533
+ cssl_obj <== python::csslize($python_instance);
2534
+ cssl_func <== python::csslize($python_function);
2535
+
2536
+ Example:
2537
+ # In Python:
2538
+ class MyPythonClass:
2539
+ def __init__(self, name):
2540
+ self.name = name
2541
+ def greet(self):
2542
+ return f"Hello, {self.name}!"
2543
+
2544
+ cssl = CSSL.CsslLang()
2545
+ cssl.set_variable('MyPython', MyPythonClass("World"))
2546
+ result = cssl.run('''
2547
+ py_obj <== python::csslize($MyPython);
2548
+ printl(py_obj.greet()); // "Hello, World!"
2549
+ ''')
2550
+
2551
+ For class inheritance:
2552
+ py_class <== python::csslize($MyPythonClass);
2553
+ class MyExtended : extends py_class {
2554
+ void newMethod() { ... }
2555
+ }
2556
+
2557
+ Args:
2558
+ python_obj: A Python object (class instance, function, or class)
2559
+
2560
+ Returns:
2561
+ CSSLizedPythonObject - A CSSL-compatible wrapper
2562
+ """
2563
+ if python_obj is None:
2564
+ return None
2565
+
2566
+ # Already csslized
2567
+ if isinstance(python_obj, CSSLizedPythonObject):
2568
+ return python_obj
2569
+
2570
+ # Wrap the Python object
2571
+ return CSSLizedPythonObject(python_obj, self.runtime)
2572
+
2573
+
2574
+ class CSSLizedPythonObject:
2575
+ """CSSL wrapper for Python objects (classes, instances, functions).
2576
+
2577
+ Allows Python objects to be used within CSSL code, including as base classes.
2578
+ """
2579
+
2580
+ def __init__(self, python_obj: Any, runtime: Any = None):
2581
+ self._python_obj = python_obj
2582
+ self._runtime = runtime
2583
+ self._is_class = isinstance(python_obj, type)
2584
+ self._is_callable = callable(python_obj) and not self._is_class
2585
+
2586
+ def __repr__(self):
2587
+ if self._is_class:
2588
+ return f"<CSSLizedPythonClass: {self._python_obj.__name__}>"
2589
+ elif self._is_callable:
2590
+ return f"<CSSLizedPythonFunction: {getattr(self._python_obj, '__name__', 'anonymous')}>"
2591
+ else:
2592
+ return f"<CSSLizedPythonInstance: {type(self._python_obj).__name__}>"
2593
+
2594
+ def __call__(self, *args, **kwargs):
2595
+ """Call the wrapped object (for functions or class instantiation)."""
2596
+ return self._python_obj(*args, **kwargs)
2597
+
2598
+ def __getattr__(self, name: str) -> Any:
2599
+ """Get attribute from wrapped Python object."""
2600
+ if name.startswith('_'):
2601
+ raise AttributeError(f"Cannot access private attribute '{name}'")
2602
+
2603
+ obj = object.__getattribute__(self, '_python_obj')
2604
+
2605
+ if hasattr(obj, name):
2606
+ attr = getattr(obj, name)
2607
+ # If it's a method, wrap it for CSSL calling
2608
+ if callable(attr):
2609
+ return CSSLizedPythonMethod(attr, self._runtime)
2610
+ return attr
2611
+
2612
+ raise AttributeError(f"Python object has no attribute '{name}'")
2613
+
2614
+ def __setattr__(self, name: str, value: Any):
2615
+ """Set attribute on wrapped Python object."""
2616
+ if name.startswith('_'):
2617
+ object.__setattr__(self, name, value)
2618
+ else:
2619
+ setattr(self._python_obj, name, value)
2620
+
2621
+ def has_member(self, name: str) -> bool:
2622
+ """Check if the Python object has a member."""
2623
+ return hasattr(self._python_obj, name)
2624
+
2625
+ def get_member(self, name: str) -> Any:
2626
+ """Get a member from the Python object."""
2627
+ return getattr(self._python_obj, name, None)
2628
+
2629
+ def set_member(self, name: str, value: Any):
2630
+ """Set a member on the Python object."""
2631
+ setattr(self._python_obj, name, value)
2632
+
2633
+ def get_method(self, name: str):
2634
+ """Get a method from the Python object."""
2635
+ if hasattr(self._python_obj, name):
2636
+ method = getattr(self._python_obj, name)
2637
+ if callable(method):
2638
+ return CSSLizedPythonMethod(method, self._runtime)
2639
+ return None
2640
+
2641
+ def get_python_obj(self):
2642
+ """Get the underlying Python object (for inheritance)."""
2643
+ return self._python_obj
2644
+
2645
+
2646
+ class CSSLizedPythonMethod:
2647
+ """Wrapper for Python methods to be called from CSSL."""
2648
+
2649
+ def __init__(self, method: Any, runtime: Any = None):
2650
+ self._method = method
2651
+ self._runtime = runtime
2652
+
2653
+ def __call__(self, *args, **kwargs):
2654
+ """Call the Python method."""
2655
+ return self._method(*args, **kwargs)
2656
+
2657
+ def __repr__(self):
2658
+ return f"<CSSLizedPythonMethod: {getattr(self._method, '__name__', 'anonymous')}>"
2659
+
2527
2660
 
2528
2661
  class PythonizedCSSLInstance:
2529
2662
  """Python wrapper for CSSL class instances.
@@ -114,7 +114,7 @@ class TokenType(Enum):
114
114
 
115
115
  KEYWORDS = {
116
116
  # Service structure
117
- 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'new', 'this',
117
+ 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'extends', 'overwrites', 'new', 'this',
118
118
  # Control flow
119
119
  'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
120
120
  'switch', 'case', 'default', 'break', 'continue', 'return',
@@ -1045,7 +1045,7 @@ class CSSLParser:
1045
1045
 
1046
1046
  # Check for * prefix (non-nullable indicator)
1047
1047
  non_null = False
1048
- if self._match(TokenType.ASTERISK):
1048
+ if self._match(TokenType.MULTIPLY):
1049
1049
  non_null = True
1050
1050
 
1051
1051
  # Get variable name
@@ -1378,12 +1378,56 @@ class CSSLParser:
1378
1378
  """
1379
1379
  # Check for * prefix (non-null class - all methods return non-null)
1380
1380
  non_null = False
1381
- if self._match(TokenType.ASTERISK):
1381
+ if self._match(TokenType.MULTIPLY):
1382
1382
  non_null = True
1383
1383
 
1384
1384
  class_name = self._advance().value
1385
1385
 
1386
- node = ASTNode('class', value={'name': class_name, 'non_null': non_null}, children=[])
1386
+ # Check for inheritance and overwrites:
1387
+ # class Child : extends Parent { ... }
1388
+ # class Child : extends $PythonObject { ... }
1389
+ # class Child : extends Parent : overwrites Parent { ... }
1390
+ extends_class = None
1391
+ extends_is_python = False
1392
+ overwrites_class = None
1393
+ overwrites_is_python = False
1394
+
1395
+ if self._match(TokenType.COLON):
1396
+ # Parse extends and/or overwrites (can be chained)
1397
+ while True:
1398
+ if self._match_keyword('extends'):
1399
+ if self._check(TokenType.IDENTIFIER):
1400
+ extends_class = self._advance().value
1401
+ elif self._check(TokenType.SHARED_REF):
1402
+ extends_class = self._advance().value
1403
+ extends_is_python = True
1404
+ else:
1405
+ raise CSSLSyntaxError("Expected parent class name after 'extends'")
1406
+ elif self._match_keyword('overwrites'):
1407
+ if self._check(TokenType.IDENTIFIER):
1408
+ overwrites_class = self._advance().value
1409
+ elif self._check(TokenType.SHARED_REF):
1410
+ overwrites_class = self._advance().value
1411
+ overwrites_is_python = True
1412
+ else:
1413
+ raise CSSLSyntaxError("Expected class name after 'overwrites'")
1414
+ # Skip optional () after class name
1415
+ if self._match(TokenType.PAREN_START):
1416
+ self._expect(TokenType.PAREN_END)
1417
+ else:
1418
+ raise CSSLSyntaxError("Expected 'extends' or 'overwrites' after ':' in class declaration")
1419
+ # Check for another : for chaining
1420
+ if not self._match(TokenType.COLON):
1421
+ break
1422
+
1423
+ node = ASTNode('class', value={
1424
+ 'name': class_name,
1425
+ 'non_null': non_null,
1426
+ 'extends': extends_class,
1427
+ 'extends_is_python': extends_is_python,
1428
+ 'overwrites': overwrites_class,
1429
+ 'overwrites_is_python': overwrites_is_python
1430
+ }, children=[])
1387
1431
  self._expect(TokenType.BLOCK_START)
1388
1432
 
1389
1433
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
@@ -1424,13 +1468,53 @@ class CSSLParser:
1424
1468
  Syntax:
1425
1469
  define MyFunc(args) { }
1426
1470
  define *MyFunc(args) { } // Non-null: must never return None
1471
+ define MyFunc : extends OtherFunc() { } // Inherit local vars
1472
+ define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
1427
1473
  """
1428
1474
  # Check for * prefix (non-null function - must return non-null)
1429
1475
  non_null = False
1430
- if self._match(TokenType.ASTERISK):
1476
+ if self._match(TokenType.MULTIPLY):
1431
1477
  non_null = True
1432
1478
 
1433
1479
  name = self._advance().value
1480
+
1481
+ # Check for extends/overwrites: define func : extends/overwrites target() { }
1482
+ extends_func = None
1483
+ overwrites_func = None
1484
+ extends_is_python = False
1485
+ overwrites_is_python = False
1486
+
1487
+ if self._match(TokenType.COLON):
1488
+ # Parse extends and/or overwrites
1489
+ while True:
1490
+ if self._match_keyword('extends'):
1491
+ if self._check(TokenType.IDENTIFIER):
1492
+ extends_func = self._advance().value
1493
+ elif self._check(TokenType.SHARED_REF):
1494
+ extends_func = self._advance().value
1495
+ extends_is_python = True
1496
+ else:
1497
+ raise CSSLSyntaxError("Expected function name after 'extends'")
1498
+ # Skip optional () after function name
1499
+ if self._match(TokenType.PAREN_START):
1500
+ self._expect(TokenType.PAREN_END)
1501
+ elif self._match_keyword('overwrites'):
1502
+ if self._check(TokenType.IDENTIFIER):
1503
+ overwrites_func = self._advance().value
1504
+ elif self._check(TokenType.SHARED_REF):
1505
+ overwrites_func = self._advance().value
1506
+ overwrites_is_python = True
1507
+ else:
1508
+ raise CSSLSyntaxError("Expected function name after 'overwrites'")
1509
+ # Skip optional () after function name
1510
+ if self._match(TokenType.PAREN_START):
1511
+ self._expect(TokenType.PAREN_END)
1512
+ else:
1513
+ break
1514
+ # Check for another : for chaining extends/overwrites
1515
+ if not self._match(TokenType.COLON):
1516
+ break
1517
+
1434
1518
  params = []
1435
1519
 
1436
1520
  if self._match(TokenType.PAREN_START):
@@ -1446,7 +1530,7 @@ class CSSLParser:
1446
1530
  if self._match(TokenType.AMPERSAND):
1447
1531
  param_info['ref'] = True
1448
1532
  # Handle * prefix for non-null parameters
1449
- if self._match(TokenType.ASTERISK):
1533
+ if self._match(TokenType.MULTIPLY):
1450
1534
  param_info['non_null'] = True
1451
1535
  # Get parameter name
1452
1536
  if self._check(TokenType.IDENTIFIER):
@@ -1468,7 +1552,15 @@ class CSSLParser:
1468
1552
  break
1469
1553
  self._expect(TokenType.PAREN_END)
1470
1554
 
1471
- node = ASTNode('function', value={'name': name, 'params': params, 'non_null': non_null}, children=[])
1555
+ node = ASTNode('function', value={
1556
+ 'name': name,
1557
+ 'params': params,
1558
+ 'non_null': non_null,
1559
+ 'extends': extends_func,
1560
+ 'extends_is_python': extends_is_python,
1561
+ 'overwrites': overwrites_func,
1562
+ 'overwrites_is_python': overwrites_is_python
1563
+ }, children=[])
1472
1564
  self._expect(TokenType.BLOCK_START)
1473
1565
 
1474
1566
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
@@ -715,9 +715,43 @@ class CSSLRuntime:
715
715
 
716
716
  Parses class members and methods, creating a CSSLClass object
717
717
  that can be instantiated with 'new'.
718
+ Supports inheritance via 'extends' keyword and method overwriting via 'overwrites'.
718
719
  """
719
720
  class_info = node.value
720
721
  class_name = class_info.get('name')
722
+ extends_class_name = class_info.get('extends')
723
+ extends_is_python = class_info.get('extends_is_python', False)
724
+ overwrites_class_name = class_info.get('overwrites')
725
+ overwrites_is_python = class_info.get('overwrites_is_python', False)
726
+
727
+ # Resolve parent class if extends is specified
728
+ parent_class = None
729
+ if extends_class_name:
730
+ if extends_is_python:
731
+ # extends $PythonObject - look up in shared objects
732
+ from ..cssl_bridge import _live_objects, SharedObjectProxy
733
+ if extends_class_name in _live_objects:
734
+ parent_class = _live_objects[extends_class_name]
735
+ # Unwrap SharedObjectProxy if needed
736
+ if isinstance(parent_class, SharedObjectProxy):
737
+ parent_class = parent_class._obj
738
+ else:
739
+ # Also check scope with $ prefix
740
+ parent_class = self.global_scope.get(f'${extends_class_name}')
741
+ else:
742
+ # Try to resolve from scope (could be CSSL class or variable holding Python object)
743
+ parent_class = self.scope.get(extends_class_name)
744
+ if parent_class is None:
745
+ parent_class = self.global_scope.get(extends_class_name)
746
+
747
+ if parent_class is None:
748
+ raise ValueError(f"Cannot extend unknown class '{extends_class_name}'")
749
+
750
+ # Auto-wrap Python objects for inheritance
751
+ from .cssl_builtins import CSSLizedPythonObject
752
+ if not isinstance(parent_class, (CSSLClass, CSSLizedPythonObject)):
753
+ # Wrap raw Python object
754
+ parent_class = CSSLizedPythonObject(parent_class, self)
721
755
 
722
756
  members = {} # Member variable defaults/types
723
757
  methods = {} # Method AST nodes
@@ -752,22 +786,152 @@ class CSSLRuntime:
752
786
  name=class_name,
753
787
  members=members,
754
788
  methods=methods,
755
- constructor=constructor
789
+ constructor=constructor,
790
+ parent=parent_class
756
791
  )
757
792
 
758
793
  # Register class in scope
759
794
  self.scope.set(class_name, class_def)
760
795
  self.global_scope.set(class_name, class_def)
761
796
 
797
+ # Handle class overwrites - replace methods in target class
798
+ if overwrites_class_name:
799
+ self._apply_class_overwrites(
800
+ class_def, overwrites_class_name, overwrites_is_python
801
+ )
802
+
762
803
  return class_def
763
804
 
805
+ def _apply_class_overwrites(self, new_class: CSSLClass, target_name: str, is_python: bool):
806
+ """Apply method overwrites from new_class to target class/object.
807
+
808
+ When a class has 'overwrites' specified, all methods defined in new_class
809
+ will replace the corresponding methods in the target.
810
+ """
811
+ from .cssl_builtins import CSSLizedPythonObject
812
+
813
+ # Resolve target
814
+ target = None
815
+ if is_python:
816
+ from ..cssl_bridge import _live_objects
817
+ if target_name in _live_objects:
818
+ target = _live_objects[target_name]
819
+ else:
820
+ target = self.scope.get(target_name)
821
+ if target is None:
822
+ target = self.global_scope.get(target_name)
823
+
824
+ if target is None:
825
+ return # Target not found, silently skip
826
+
827
+ # Get methods to overwrite
828
+ methods_to_overwrite = new_class.methods
829
+
830
+ if is_python and hasattr(target, '__class__'):
831
+ # Python object - overwrite methods on the object/class
832
+ for method_name, method_node in methods_to_overwrite.items():
833
+ # Create a Python-callable wrapper for the CSSL method
834
+ wrapper = self._create_method_wrapper(method_node, target)
835
+ # Set on the object
836
+ try:
837
+ setattr(target, method_name, wrapper)
838
+ except AttributeError:
839
+ # Try setting on class instead
840
+ try:
841
+ setattr(target.__class__, method_name, wrapper)
842
+ except:
843
+ pass
844
+ elif isinstance(target, CSSLClass):
845
+ # CSSL class - directly replace methods
846
+ for method_name, method_node in methods_to_overwrite.items():
847
+ target.methods[method_name] = method_node
848
+ elif isinstance(target, CSSLizedPythonObject):
849
+ # CSSLized Python object - get underlying object and overwrite
850
+ py_obj = target.get_python_obj()
851
+ for method_name, method_node in methods_to_overwrite.items():
852
+ wrapper = self._create_method_wrapper(method_node, py_obj)
853
+ try:
854
+ setattr(py_obj, method_name, wrapper)
855
+ except AttributeError:
856
+ try:
857
+ setattr(py_obj.__class__, method_name, wrapper)
858
+ except:
859
+ pass
860
+
861
+ def _create_method_wrapper(self, method_node: ASTNode, instance: Any):
862
+ """Create a Python-callable wrapper for a CSSL method that works with an instance."""
863
+ def wrapper(*args, **kwargs):
864
+ # Set up instance context for this->
865
+ old_instance = self._current_instance
866
+ # Create a fake CSSLInstance-like wrapper if needed
867
+ self._current_instance = instance
868
+ try:
869
+ return self._call_function(method_node, list(args), kwargs)
870
+ finally:
871
+ self._current_instance = old_instance
872
+ return wrapper
873
+
764
874
  def _exec_function(self, node: ASTNode) -> Any:
765
- """Execute function definition - just registers it"""
875
+ """Execute function definition - registers it and handles extends/overwrites.
876
+
877
+ Syntax:
878
+ define func() { ... }
879
+ define func : extends otherFunc() { ... } - Inherit local vars
880
+ define func : overwrites otherFunc() { ... } - Replace otherFunc
881
+ """
766
882
  func_info = node.value
767
883
  func_name = func_info.get('name')
884
+ extends_func = func_info.get('extends')
885
+ extends_is_python = func_info.get('extends_is_python', False)
886
+ overwrites_func = func_info.get('overwrites')
887
+ overwrites_is_python = func_info.get('overwrites_is_python', False)
888
+
889
+ # Store function extends info for runtime use
890
+ if extends_func:
891
+ node.value['_extends_resolved'] = self._resolve_function_target(
892
+ extends_func, extends_is_python
893
+ )
894
+
895
+ # Handle overwrites - replace the target function
896
+ if overwrites_func:
897
+ target = self._resolve_function_target(overwrites_func, overwrites_is_python)
898
+ if target is not None:
899
+ # Store original for reference
900
+ node.value['_overwrites_original'] = target
901
+ # Replace the target function with this one
902
+ if overwrites_is_python:
903
+ from ..cssl_bridge import _live_objects
904
+ if overwrites_func in _live_objects:
905
+ # Create a wrapper that calls the CSSL function
906
+ _live_objects[overwrites_func] = self._create_python_wrapper(node)
907
+ else:
908
+ # Replace in CSSL scope
909
+ self.scope.set(overwrites_func, node)
910
+ self.global_scope.set(overwrites_func, node)
911
+
912
+ # Register the function
768
913
  self.scope.set(func_name, node)
769
914
  return None
770
915
 
916
+ def _resolve_function_target(self, name: str, is_python: bool) -> Any:
917
+ """Resolve a function target for extends/overwrites."""
918
+ if is_python:
919
+ from ..cssl_bridge import _live_objects
920
+ if name in _live_objects:
921
+ return _live_objects[name]
922
+ return self.global_scope.get(f'${name}')
923
+ else:
924
+ target = self.scope.get(name)
925
+ if target is None:
926
+ target = self.global_scope.get(name)
927
+ return target
928
+
929
+ def _create_python_wrapper(self, func_node: ASTNode):
930
+ """Create a Python-callable wrapper for a CSSL function."""
931
+ def wrapper(*args, **kwargs):
932
+ return self._call_function(func_node, list(args), kwargs)
933
+ return wrapper
934
+
771
935
  def _exec_typed_declaration(self, node: ASTNode) -> Any:
772
936
  """Execute typed variable declaration: type<T> varName = value;
773
937
 
@@ -1031,6 +1195,9 @@ class CSSLRuntime:
1031
1195
  func_node: The function AST node
1032
1196
  args: List of positional arguments
1033
1197
  kwargs: Dict of named arguments (param_name -> value)
1198
+
1199
+ Supports:
1200
+ define func : extends otherFunc() { ... } - Inherit local vars from otherFunc
1034
1201
  """
1035
1202
  func_info = func_node.value
1036
1203
  params = func_info.get('params', [])
@@ -1043,6 +1210,34 @@ class CSSLRuntime:
1043
1210
  # Create new scope
1044
1211
  new_scope = Scope(parent=self.scope)
1045
1212
 
1213
+ # Handle function extends - inherit local vars from extended function
1214
+ extends_resolved = func_info.get('_extends_resolved')
1215
+ if extends_resolved:
1216
+ if callable(extends_resolved):
1217
+ # Python function - call it first to populate any state
1218
+ try:
1219
+ extends_resolved(*args, **kwargs)
1220
+ except:
1221
+ pass
1222
+ elif hasattr(extends_resolved, 'value'):
1223
+ # CSSL function - execute it in a temporary scope to get local vars
1224
+ old_scope = self.scope
1225
+ temp_scope = Scope(parent=self.scope)
1226
+ self.scope = temp_scope
1227
+ try:
1228
+ # Execute extended function body to populate local vars
1229
+ for child in extends_resolved.children:
1230
+ if not self._running:
1231
+ break
1232
+ self._execute(child)
1233
+ # Copy all local vars to new scope
1234
+ for name, value in temp_scope._vars.items():
1235
+ new_scope.set(name, value)
1236
+ except:
1237
+ pass
1238
+ finally:
1239
+ self.scope = old_scope
1240
+
1046
1241
  # Bind parameters - handle both positional and named arguments
1047
1242
  for i, param in enumerate(params):
1048
1243
  # Extract param name and type from dict format: {'name': 'a', 'type': 'int'}
@@ -2957,6 +3152,10 @@ class CSSLRuntime:
2957
3152
  if instance.has_method(member):
2958
3153
  # Return a callable that will invoke the method with instance context
2959
3154
  method_node = instance.get_method(member)
3155
+ # Check if this is an inherited Python method
3156
+ if isinstance(method_node, tuple) and method_node[0] == 'python_method':
3157
+ python_method = method_node[1]
3158
+ return lambda *args, **kwargs: python_method(*args, **kwargs)
2960
3159
  return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
2961
3160
 
2962
3161
  raise CSSLRuntimeError(
@@ -3038,6 +3237,10 @@ class CSSLRuntime:
3038
3237
  # Check for method
3039
3238
  if obj.has_method(member):
3040
3239
  method_node = obj.get_method(member)
3240
+ # Check if this is an inherited Python method
3241
+ if isinstance(method_node, tuple) and method_node[0] == 'python_method':
3242
+ python_method = method_node[1]
3243
+ return lambda *args, **kwargs: python_method(*args, **kwargs)
3041
3244
  return lambda *args, **kwargs: self._call_method(obj, method_node, list(args), kwargs)
3042
3245
  raise CSSLRuntimeError(f"'{obj._class.name}' has no member or method '{member}'")
3043
3246
 
@@ -1448,17 +1448,62 @@ class CSSLClass:
1448
1448
 
1449
1449
  Stores class name, member variables, methods, and constructor.
1450
1450
  Used by the runtime to instantiate CSSLInstance objects.
1451
+ Supports inheritance via the 'parent' attribute.
1451
1452
  """
1452
1453
 
1453
1454
  def __init__(self, name: str, members: Dict[str, Any] = None,
1454
- methods: Dict[str, Any] = None, constructor: Any = None):
1455
+ methods: Dict[str, Any] = None, constructor: Any = None,
1456
+ parent: Any = None):
1455
1457
  self.name = name
1456
1458
  self.members = members or {} # Default member values/types
1457
1459
  self.methods = methods or {} # Method AST nodes
1458
1460
  self.constructor = constructor # Constructor AST node
1461
+ self.parent = parent # Parent class (CSSLClass or CSSLizedPythonObject)
1462
+
1463
+ def get_all_members(self) -> Dict[str, Any]:
1464
+ """Get all members including inherited ones."""
1465
+ all_members = {}
1466
+ # First add parent members (can be overridden)
1467
+ if self.parent:
1468
+ if hasattr(self.parent, 'get_all_members'):
1469
+ all_members.update(self.parent.get_all_members())
1470
+ elif hasattr(self.parent, 'members'):
1471
+ all_members.update(self.parent.members)
1472
+ elif hasattr(self.parent, '_python_obj'):
1473
+ # CSSLizedPythonObject - get attributes from Python object
1474
+ py_obj = self.parent._python_obj
1475
+ if hasattr(py_obj, '__dict__'):
1476
+ for key, val in py_obj.__dict__.items():
1477
+ if not key.startswith('_'):
1478
+ all_members[key] = {'type': 'dynamic', 'default': val}
1479
+ # Then add own members (override parent)
1480
+ all_members.update(self.members)
1481
+ return all_members
1482
+
1483
+ def get_all_methods(self) -> Dict[str, Any]:
1484
+ """Get all methods including inherited ones."""
1485
+ all_methods = {}
1486
+ # First add parent methods (can be overridden)
1487
+ if self.parent:
1488
+ if hasattr(self.parent, 'get_all_methods'):
1489
+ all_methods.update(self.parent.get_all_methods())
1490
+ elif hasattr(self.parent, 'methods'):
1491
+ all_methods.update(self.parent.methods)
1492
+ elif hasattr(self.parent, '_python_obj'):
1493
+ # CSSLizedPythonObject - get methods from Python object
1494
+ py_obj = self.parent._python_obj
1495
+ for name in dir(py_obj):
1496
+ if not name.startswith('_'):
1497
+ attr = getattr(py_obj, name, None)
1498
+ if callable(attr):
1499
+ all_methods[name] = ('python_method', attr)
1500
+ # Then add own methods (override parent)
1501
+ all_methods.update(self.methods)
1502
+ return all_methods
1459
1503
 
1460
1504
  def __repr__(self):
1461
- return f"<CSSLClass '{self.name}' with {len(self.methods)} methods>"
1505
+ parent_info = f" extends {self.parent.name}" if self.parent and hasattr(self.parent, 'name') else ""
1506
+ return f"<CSSLClass '{self.name}'{parent_info} with {len(self.methods)} methods>"
1462
1507
 
1463
1508
 
1464
1509
  class CSSLInstance:
@@ -1471,8 +1516,9 @@ class CSSLInstance:
1471
1516
  def __init__(self, class_def: CSSLClass):
1472
1517
  self._class = class_def
1473
1518
  self._members: Dict[str, Any] = {}
1474
- # Initialize members with defaults from class definition
1475
- for name, default in class_def.members.items():
1519
+ # Initialize members with defaults from class definition (including inherited)
1520
+ all_members = class_def.get_all_members() if hasattr(class_def, 'get_all_members') else class_def.members
1521
+ for name, default in all_members.items():
1476
1522
  if isinstance(default, dict):
1477
1523
  # Type declaration with optional default
1478
1524
  member_type = default.get('type')
@@ -1541,14 +1587,17 @@ class CSSLInstance:
1541
1587
  return name in self._members
1542
1588
 
1543
1589
  def get_method(self, name: str) -> Any:
1544
- """Get method AST node by name"""
1545
- if name in self._class.methods:
1546
- return self._class.methods[name]
1590
+ """Get method AST node by name (including inherited methods)"""
1591
+ # Use get_all_methods to include inherited methods
1592
+ all_methods = self._class.get_all_methods() if hasattr(self._class, 'get_all_methods') else self._class.methods
1593
+ if name in all_methods:
1594
+ return all_methods[name]
1547
1595
  raise AttributeError(f"'{self._class.name}' has no method '{name}'")
1548
1596
 
1549
1597
  def has_method(self, name: str) -> bool:
1550
- """Check if method exists"""
1551
- return name in self._class.methods
1598
+ """Check if method exists (including inherited methods)"""
1599
+ all_methods = self._class.get_all_methods() if hasattr(self._class, 'get_all_methods') else self._class.methods
1600
+ return name in all_methods
1552
1601
 
1553
1602
  def __getattr__(self, name: str) -> Any:
1554
1603
  """Allow direct attribute access for members"""
@@ -164,6 +164,35 @@
164
164
  },
165
165
  "class-definition": {
166
166
  "patterns": [
167
+ {
168
+ "comment": "Class with inheritance: class Child : extends Parent { }",
169
+ "name": "meta.class.extends.cssl",
170
+ "begin": "\\b(class)\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*:\\s*(extends)\\s+(\\$?[a-zA-Z_][a-zA-Z0-9_]*)\\s*\\{",
171
+ "beginCaptures": {
172
+ "1": { "name": "storage.type.class.cssl" },
173
+ "2": { "name": "entity.name.class.cssl" },
174
+ "3": { "name": "storage.modifier.extends.cssl" },
175
+ "4": { "name": "entity.other.inherited-class.cssl" }
176
+ },
177
+ "end": "\\}",
178
+ "patterns": [
179
+ { "include": "#comments" },
180
+ { "include": "#constructor-definition" },
181
+ { "include": "#class-method-definition" },
182
+ { "include": "#class-member-declaration" },
183
+ { "include": "#types" },
184
+ { "include": "#this-access" },
185
+ { "include": "#captured-references" },
186
+ { "include": "#global-references" },
187
+ { "include": "#shared-references" },
188
+ { "include": "#strings" },
189
+ { "include": "#numbers" },
190
+ { "include": "#keywords" },
191
+ { "include": "#function-calls" },
192
+ { "include": "#builtins" },
193
+ { "include": "#operators" }
194
+ ]
195
+ },
167
196
  {
168
197
  "name": "meta.class.cssl",
169
198
  "begin": "\\b(class)\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\{",
@@ -263,6 +292,10 @@
263
292
  "name": "storage.type.class.cssl",
264
293
  "match": "\\b(class|struct|structure|enum|interface)\\b"
265
294
  },
295
+ {
296
+ "name": "storage.modifier.extends.cssl",
297
+ "match": "\\b(extends|overwrites)\\b"
298
+ },
266
299
  {
267
300
  "name": "keyword.operator.new.cssl",
268
301
  "match": "\\bnew\\b"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "IncludeCPP"
7
- version = "3.8.3"
7
+ version = "3.8.4"
8
8
  description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes