IncludeCPP 3.7.3__tar.gz → 3.7.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 (57) hide show
  1. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.7.3 → includecpp-3.7.4}/PKG-INFO +1 -1
  3. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/__init__.py +1 -1
  4. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_parser.py +62 -2
  5. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_runtime.py +113 -8
  6. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl_bridge.py +477 -48
  7. {includecpp-3.7.3 → includecpp-3.7.4}/pyproject.toml +1 -1
  8. {includecpp-3.7.3 → includecpp-3.7.4}/setup.py +1 -1
  9. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/SOURCES.txt +0 -0
  10. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  11. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/entry_points.txt +0 -0
  12. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/requires.txt +0 -0
  13. {includecpp-3.7.3 → includecpp-3.7.4}/IncludeCPP.egg-info/top_level.txt +0 -0
  14. {includecpp-3.7.3 → includecpp-3.7.4}/LICENSE +0 -0
  15. {includecpp-3.7.3 → includecpp-3.7.4}/MANIFEST.in +0 -0
  16. {includecpp-3.7.3 → includecpp-3.7.4}/README.md +0 -0
  17. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/__init__.pyi +0 -0
  18. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/__main__.py +0 -0
  19. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/cli/__init__.py +0 -0
  20. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/cli/commands.py +0 -0
  21. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/cli/config_parser.py +0 -0
  22. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/__init__.py +0 -0
  23. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/ai_integration.py +0 -0
  24. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/build_manager.py +0 -0
  25. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cpp_api.py +0 -0
  26. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cpp_api.pyi +0 -0
  27. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cppy_converter.py +0 -0
  28. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +0 -0
  29. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/__init__.py +0 -0
  30. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_builtins.py +0 -0
  31. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
  32. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_events.py +0 -0
  33. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_modules.py +0 -0
  34. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_syntax.py +0 -0
  35. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl/cssl_types.py +0 -0
  36. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/cssl_bridge.pyi +0 -0
  37. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/error_catalog.py +0 -0
  38. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/error_formatter.py +0 -0
  39. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/exceptions.py +0 -0
  40. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/path_discovery.py +0 -0
  41. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/project_ui.py +0 -0
  42. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/core/settings_ui.py +0 -0
  43. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/generator/__init__.py +0 -0
  44. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/generator/parser.cpp +0 -0
  45. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/generator/parser.h +0 -0
  46. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/generator/type_resolver.cpp +0 -0
  47. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/generator/type_resolver.h +0 -0
  48. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/py.typed +0 -0
  49. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/templates/cpp.proj.template +0 -0
  50. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/__init__.py +0 -0
  51. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/cssl/__init__.py +0 -0
  52. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/cssl/language-configuration.json +0 -0
  53. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/cssl/package.json +0 -0
  54. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
  55. {includecpp-3.7.3 → includecpp-3.7.4}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
  56. {includecpp-3.7.3 → includecpp-3.7.4}/requirements.txt +0 -0
  57. {includecpp-3.7.3 → includecpp-3.7.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.7.3
3
+ Version: 3.7.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.7.3
3
+ Version: 3.7.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.7.3"
5
+ __version__ = "3.7.4"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -108,6 +108,8 @@ class TokenType(Enum):
108
108
  COMMENT = auto()
109
109
  NEWLINE = auto()
110
110
  EOF = auto()
111
+ # Super-functions for .cssl-pl payload files (v3.8.0)
112
+ SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
111
113
 
112
114
 
113
115
  KEYWORDS = {
@@ -212,9 +214,14 @@ class CSSLLexer:
212
214
 
213
215
  char = self.source[self.pos]
214
216
 
215
- # Comments: both # and // style
217
+ # Super-functions (#$) or Comments (# and // style)
216
218
  if char == '#':
217
- self._skip_comment()
219
+ if self._peek(1) == '$':
220
+ # Super-function: #$run(), #$exec(), #$printl()
221
+ self._read_super_function()
222
+ else:
223
+ # Regular comment
224
+ self._skip_comment()
218
225
  elif char == '/' and self._peek(1) == '/':
219
226
  # C-style // comment - NEW
220
227
  self._skip_comment()
@@ -446,6 +453,31 @@ class CSSLLexer:
446
453
  else:
447
454
  self._add_token(TokenType.IDENTIFIER, value)
448
455
 
456
+ def _read_super_function(self):
457
+ """Read #$<name>(...) super-function call for .cssl-pl payloads.
458
+
459
+ Super-functions are pre-execution hooks that run when a payload is loaded.
460
+ Valid super-functions: #$run(), #$exec(), #$printl()
461
+
462
+ Syntax:
463
+ #$run(initFunction); // Call a function at load time
464
+ #$exec(setup()); // Execute expression at load time
465
+ #$printl("Payload loaded"); // Print at load time
466
+ """
467
+ start = self.pos
468
+ self._advance() # skip '#'
469
+ self._advance() # skip '$'
470
+
471
+ # Read the super-function name (run, exec, printl, etc.)
472
+ name_start = self.pos
473
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
474
+ self._advance()
475
+ func_name = self.source[name_start:self.pos]
476
+
477
+ # Store as #$<name> token value
478
+ value = f'#${func_name}'
479
+ self._add_token(TokenType.SUPER_FUNC, value)
480
+
449
481
  def _read_self_ref(self):
450
482
  """Read s@<name> or s@<name>.<member>... self-reference"""
451
483
  start = self.pos
@@ -1377,6 +1409,9 @@ class CSSLParser:
1377
1409
  elif self._looks_like_function_declaration():
1378
1410
  # Nested typed function (e.g., void Level2() { ... })
1379
1411
  return self._parse_typed_function()
1412
+ elif self._check(TokenType.SUPER_FUNC):
1413
+ # Super-function for .cssl-pl payload files
1414
+ return self._parse_super_function()
1380
1415
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1381
1416
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
1382
1417
  self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
@@ -1728,6 +1763,31 @@ class CSSLParser:
1728
1763
  self._match(TokenType.SEMICOLON)
1729
1764
  return ASTNode('return', value=value)
1730
1765
 
1766
+ def _parse_super_function(self) -> ASTNode:
1767
+ """Parse super-function for .cssl-pl payload files.
1768
+
1769
+ Syntax:
1770
+ #$run(initFunction); // Call function at load time
1771
+ #$exec(setup()); // Execute expression at load time
1772
+ #$printl("Payload loaded"); // Print at load time
1773
+
1774
+ These are pre-execution hooks that run when payload() loads the file.
1775
+ """
1776
+ token = self._advance() # Get the SUPER_FUNC token
1777
+ super_name = token.value # e.g., "#$run", "#$exec", "#$printl"
1778
+
1779
+ # Parse the arguments
1780
+ self._expect(TokenType.PAREN_START)
1781
+ args = []
1782
+ if not self._check(TokenType.PAREN_END):
1783
+ args.append(self._parse_expression())
1784
+ while self._match(TokenType.COMMA):
1785
+ args.append(self._parse_expression())
1786
+ self._expect(TokenType.PAREN_END)
1787
+ self._match(TokenType.SEMICOLON)
1788
+
1789
+ return ASTNode('super_func', value={'name': super_name, 'args': args})
1790
+
1731
1791
  def _parse_try(self) -> ASTNode:
1732
1792
  node = ASTNode('try', children=[])
1733
1793
 
@@ -401,6 +401,9 @@ class CSSLRuntime:
401
401
  elif child.type == 'instance_declaration':
402
402
  # Handle instance declaration: instance<"name"> varName;
403
403
  result = self._exec_instance_declaration(child)
404
+ elif child.type == 'super_func':
405
+ # Super-function for .cssl-pl payload files (#$run, #$exec, #$printl)
406
+ result = self._exec_super_func(child)
404
407
  elif child.type in ('assignment', 'expression', 'inject', 'receive', 'flow',
405
408
  'if', 'while', 'for', 'c_for', 'foreach', 'switch', 'try'):
406
409
  result = self._execute_node(child)
@@ -820,6 +823,82 @@ class CSSLRuntime:
820
823
  self.scope.set(var_name, instance)
821
824
  return instance
822
825
 
826
+ def _exec_super_func(self, node: ASTNode) -> Any:
827
+ """Execute super-function for .cssl-pl payload files.
828
+
829
+ Super-functions are pre-execution hooks that run when payload() loads a file.
830
+
831
+ Supported super-functions:
832
+ #$run(funcName) - Call a function defined in the payload
833
+ #$exec(expression) - Execute an expression immediately
834
+ #$printl(message) - Print a message during load
835
+
836
+ Example .cssl-pl file:
837
+ void initDatabase() {
838
+ printl("DB initialized");
839
+ }
840
+
841
+ #$run(initDatabase); // Calls initDatabase when payload loads
842
+ #$printl("Payload loaded"); // Prints during load
843
+ """
844
+ super_info = node.value
845
+ super_name = super_info.get('name', '') # e.g., "#$run", "#$exec", "#$printl"
846
+ args = super_info.get('args', [])
847
+
848
+ # Extract the function name part (after #$)
849
+ if super_name.startswith('#$'):
850
+ func_type = super_name[2:] # "run", "exec", "printl"
851
+ else:
852
+ func_type = super_name
853
+
854
+ if func_type == 'run':
855
+ # #$run(funcName) - Call a function by name
856
+ if args:
857
+ func_ref = args[0]
858
+ if isinstance(func_ref, ASTNode):
859
+ if func_ref.type == 'identifier':
860
+ func_name = func_ref.value
861
+ elif func_ref.type == 'call':
862
+ # Direct call like #$run(setup())
863
+ return self._eval_call(func_ref)
864
+ else:
865
+ func_name = self._evaluate(func_ref)
866
+ else:
867
+ func_name = str(func_ref)
868
+
869
+ # Look up and call the function
870
+ func_node = self.scope.get(func_name)
871
+ if func_node and isinstance(func_node, ASTNode) and func_node.type == 'function':
872
+ return self._call_function(func_node, [])
873
+ else:
874
+ raise CSSLRuntimeError(f"#$run: Function '{func_name}' not found", node.line)
875
+
876
+ elif func_type == 'exec':
877
+ # #$exec(expression) - Execute an expression
878
+ if args:
879
+ return self._evaluate(args[0])
880
+
881
+ elif func_type == 'printl':
882
+ # #$printl(message) - Print a message
883
+ if args:
884
+ msg = self._evaluate(args[0])
885
+ print(str(msg))
886
+ self.output_buffer.append(str(msg))
887
+ return None
888
+
889
+ elif func_type == 'print':
890
+ # #$print(message) - Print without newline
891
+ if args:
892
+ msg = self._evaluate(args[0])
893
+ print(str(msg), end='')
894
+ self.output_buffer.append(str(msg))
895
+ return None
896
+
897
+ else:
898
+ raise CSSLRuntimeError(f"Unknown super-function: {super_name}", node.line)
899
+
900
+ return None
901
+
823
902
  def _exec_global_assignment(self, node: ASTNode) -> Any:
824
903
  """Execute global variable assignment: global Name = value
825
904
 
@@ -1778,9 +1857,12 @@ class CSSLRuntime:
1778
1857
 
1779
1858
  if node.type == 'literal':
1780
1859
  value = node.value
1781
- # NEW: String interpolation - replace <variable> with scope values
1782
- if isinstance(value, str) and '<' in value and '>' in value:
1783
- value = self._interpolate_string(value)
1860
+ # String interpolation - replace {var} or <var> with scope values
1861
+ if isinstance(value, str):
1862
+ has_fstring = '{' in value and '}' in value
1863
+ has_legacy = '<' in value and '>' in value
1864
+ if has_fstring or has_legacy:
1865
+ value = self._interpolate_string(value)
1784
1866
  return value
1785
1867
 
1786
1868
  # NEW: Type literals (list, dict) - create empty instances
@@ -2725,14 +2807,24 @@ class CSSLRuntime:
2725
2807
  elif isinstance(obj, dict):
2726
2808
  obj[final_attr] = value
2727
2809
 
2728
- # NEW: String interpolation
2810
+ # String interpolation (supports both <var> and {var} syntax)
2729
2811
  def _interpolate_string(self, string: str) -> str:
2730
- """Replace <variable> placeholders with values from scope - NEW
2812
+ """Replace {variable} and <variable> placeholders with values from scope.
2813
+
2814
+ Both syntaxes are supported (variables only, not expressions):
2815
+ "Hello {name}!" -> "Hello John!" (f-string style)
2816
+ "Hello <name>!" -> "Hello John!" (legacy CSSL style)
2817
+
2818
+ Examples:
2819
+ string name = "Alice";
2820
+ int age = 30;
2821
+ printl("Hello {name}, you are {age} years old!");
2822
+ printl("Hello <name>, you are <age> years old!");
2731
2823
 
2732
- Example: "Hello <name>!" becomes "Hello John!" if name = "John"
2824
+ Note: Only simple variable names are supported, not expressions.
2825
+ Use string concatenation for complex expressions.
2733
2826
  """
2734
2827
  import re
2735
- pattern = r'<([A-Za-z_][A-Za-z0-9_]*)>'
2736
2828
 
2737
2829
  def replacer(match):
2738
2830
  var_name = match.group(1)
@@ -2744,10 +2836,23 @@ class CSSLRuntime:
2744
2836
  # Try modules
2745
2837
  if value is None:
2746
2838
  value = self._modules.get(var_name)
2839
+ # Try global scope
2840
+ if value is None:
2841
+ value = self.global_scope.get(var_name)
2747
2842
  # Return string representation or empty string if None
2748
2843
  return str(value) if value is not None else ''
2749
2844
 
2750
- return re.sub(pattern, replacer, string)
2845
+ # Support both {var} and <var> syntax - simple variable names only
2846
+ # Pattern: {identifier} or <identifier>
2847
+ patterns = [
2848
+ r'\{([A-Za-z_][A-Za-z0-9_]*)\}', # {name} f-string style
2849
+ r'<([A-Za-z_][A-Za-z0-9_]*)>', # <name> legacy CSSL style
2850
+ ]
2851
+
2852
+ result = string
2853
+ for pattern in patterns:
2854
+ result = re.sub(pattern, replacer, result)
2855
+ return result
2751
2856
 
2752
2857
  # NEW: Promote variable to global scope via global()
2753
2858
  def promote_to_global(self, s_ref_name: str):
@@ -1,14 +1,23 @@
1
1
  """
2
2
  CSSL Bridge - Python API for CSSL Language
3
3
  Provides CsslLang class for executing CSSL code from Python.
4
+
5
+ v3.8.0 API:
6
+ cssl.run(code, *args) - Execute CSSL code
7
+ cssl.script("cssl", code) - Create typed script
8
+ cssl.makemodule(script, pl) - Bundle main script + payload
9
+ cssl.load(path, name) - Load .cssl/.cssl-pl file
10
+ cssl.execute(name) - Execute loaded script
11
+ cssl.include(path, name) - Register for payload(name)
4
12
  """
5
13
 
6
14
  import os
7
15
  import pickle
8
16
  import random
9
17
  import threading
18
+ import warnings
10
19
  from pathlib import Path
11
- from typing import Any, List, Optional, Callable, Dict
20
+ from typing import Any, List, Optional, Callable, Dict, Union, Tuple
12
21
 
13
22
 
14
23
  def _get_share_directory() -> Path:
@@ -142,6 +151,79 @@ class CSSLModule:
142
151
  return f"<CSSLModule code_len={len(self._code)}>"
143
152
 
144
153
 
154
+ class CSSLScript:
155
+ """
156
+ A typed CSSL script object.
157
+
158
+ Created via cssl.script("cssl", code) or cssl.script("cssl-pl", code).
159
+ Can be executed directly or bundled into a module.
160
+
161
+ Usage:
162
+ main = cssl.script("cssl", '''
163
+ printl("Main script");
164
+ myFunc();
165
+ ''')
166
+
167
+ payload = cssl.script("cssl-pl", '''
168
+ void myFunc() {
169
+ printl("From payload!");
170
+ }
171
+ ''')
172
+
173
+ # Execute directly
174
+ main.run()
175
+
176
+ # Or bundle into module
177
+ mod = cssl.makemodule(main, payload, "mymod")
178
+ """
179
+
180
+ def __init__(self, cssl_instance: 'CsslLang', script_type: str, code: str, params: Tuple = ()):
181
+ """
182
+ Initialize a CSSL script.
183
+
184
+ Args:
185
+ cssl_instance: The parent CsslLang instance
186
+ script_type: "cssl" for main script, "cssl-pl" for payload
187
+ code: The CSSL code
188
+ params: Optional parameters accessible via parameter.get(index)
189
+ """
190
+ if script_type not in ('cssl', 'cssl-pl'):
191
+ raise ValueError(f"Invalid script type '{script_type}'. Must be 'cssl' or 'cssl-pl'")
192
+
193
+ self._cssl = cssl_instance
194
+ self._type = script_type
195
+ self._code = code
196
+ self._params = params
197
+ self._name: Optional[str] = None
198
+
199
+ @property
200
+ def type(self) -> str:
201
+ """Get script type ('cssl' or 'cssl-pl')."""
202
+ return self._type
203
+
204
+ @property
205
+ def code(self) -> str:
206
+ """Get the script code."""
207
+ return self._code
208
+
209
+ @property
210
+ def is_payload(self) -> bool:
211
+ """Check if this is a payload script."""
212
+ return self._type == 'cssl-pl'
213
+
214
+ def run(self, *args) -> Any:
215
+ """Execute this script with optional arguments."""
216
+ all_args = self._params + args
217
+ return self._cssl.run(self._code, *all_args)
218
+
219
+ def __call__(self, *args) -> Any:
220
+ """Allow calling the script directly."""
221
+ return self.run(*args)
222
+
223
+ def __repr__(self) -> str:
224
+ return f"<CSSLScript type='{self._type}' code_len={len(self._code)}>"
225
+
226
+
145
227
  class CSSLFunctionModule:
146
228
  """
147
229
  A CSSL module with accessible functions as methods.
@@ -150,9 +232,11 @@ class CSSLFunctionModule:
150
232
  become callable attributes on this module.
151
233
  """
152
234
 
153
- def __init__(self, cssl_instance: 'CsslLang', code: str):
235
+ def __init__(self, cssl_instance: 'CsslLang', code: str, payload_code: str = None, name: str = None):
154
236
  self._cssl = cssl_instance
155
237
  self._code = code
238
+ self._payload_code = payload_code
239
+ self._name = name
156
240
  self._runtime = None
157
241
  self._functions: Dict[str, Any] = {}
158
242
  self._initialized = False
@@ -167,7 +251,22 @@ class CSSLFunctionModule:
167
251
  # Create a dedicated runtime for this module
168
252
  self._runtime = CSSLRuntime()
169
253
 
170
- # Parse the code
254
+ # If we have a payload, load it first (defines functions/globals for main)
255
+ if self._payload_code:
256
+ payload_ast = parse_cssl_program(self._payload_code)
257
+ for child in payload_ast.children:
258
+ if child.type == 'function':
259
+ func_info = child.value
260
+ func_name = func_info.get('name')
261
+ self._functions[func_name] = child
262
+ self._runtime.scope.set(func_name, child)
263
+ else:
264
+ try:
265
+ self._runtime._execute_node(child)
266
+ except Exception:
267
+ pass
268
+
269
+ # Parse the main code
171
270
  ast = parse_cssl_program(self._code)
172
271
 
173
272
  # Execute to register all function definitions
@@ -184,6 +283,16 @@ class CSSLFunctionModule:
184
283
  except Exception:
185
284
  pass
186
285
 
286
+ # If module has a name, register for payload() access
287
+ if self._name:
288
+ cssl_instance = self._cssl
289
+ runtime = cssl_instance._get_runtime()
290
+ if not hasattr(runtime, '_inline_payloads'):
291
+ runtime._inline_payloads = {}
292
+ # Store combined code for payload() access
293
+ combined = (self._payload_code or '') + '\n' + self._code
294
+ runtime._inline_payloads[self._name] = combined
295
+
187
296
  self._initialized = True
188
297
 
189
298
  def __getattr__(self, name: str) -> Callable:
@@ -224,11 +333,27 @@ class CsslLang:
224
333
  """
225
334
  CSSL Language interface for Python.
226
335
 
227
- Usage:
336
+ v3.8.0 API:
228
337
  from includecpp import CSSL
229
338
  cssl = CSSL.CsslLang()
230
- result = cssl.exec("script.cssl", arg1, arg2)
231
- cssl.T_exec("async_script.cssl", arg1) # Threaded
339
+
340
+ # Execute CSSL code
341
+ result = cssl.run("script.cssl", arg1, arg2)
342
+ result = cssl.run('''printl("Hello");''')
343
+
344
+ # Create typed scripts
345
+ main = cssl.script("cssl", '''printl("Main");''')
346
+ payload = cssl.script("cssl-pl", '''void helper() {}''')
347
+
348
+ # Bundle into module
349
+ mod = cssl.makemodule(main, payload, "mymod")
350
+
351
+ # Load and execute files
352
+ cssl.load("utils.cssl-pl", "utils")
353
+ cssl.execute("utils")
354
+
355
+ # Register for payload() access
356
+ cssl.include("helpers.cssl-pl", "helpers")
232
357
  """
233
358
 
234
359
  def __init__(self, output_callback: Optional[Callable[[str, str], None]] = None):
@@ -241,6 +366,7 @@ class CsslLang:
241
366
  self._output_callback = output_callback
242
367
  self._runtime = None
243
368
  self._threads: List[threading.Thread] = []
369
+ self._loaded_scripts: Dict[str, Dict[str, Any]] = {}
244
370
 
245
371
  def _get_runtime(self):
246
372
  """Lazy load CSSL runtime."""
@@ -249,23 +375,38 @@ class CsslLang:
249
375
  self._runtime = CSSLRuntime(output_callback=self._output_callback)
250
376
  return self._runtime
251
377
 
252
- def exec(self, path_or_code: str, *args) -> Any:
378
+ def _detect_type(self, path: str) -> str:
379
+ """Detect script type from file extension."""
380
+ path_obj = Path(path)
381
+ if path_obj.suffix == '.cssl-pl':
382
+ return 'cssl-pl'
383
+ return 'cssl'
384
+
385
+ def run(self, path_or_code: str, *args) -> Any:
253
386
  """
254
387
  Execute CSSL code or file.
255
388
 
389
+ This is the primary method for running CSSL code in v3.8.0+.
390
+
256
391
  Args:
257
392
  path_or_code: Path to .cssl file or CSSL code string
258
- *args: Arguments to pass to the script
393
+ *args: Arguments to pass to the script (accessible via parameter.get())
259
394
 
260
395
  Returns:
261
396
  Execution result. If parameter.return() was called, returns
262
397
  the list of returned values (or single value if only one).
398
+
399
+ Usage:
400
+ cssl.run("script.cssl", "arg1", 42)
401
+ cssl.run('''
402
+ printl("Hello " + parameter.get(0));
403
+ ''', "World")
263
404
  """
264
405
  runtime = self._get_runtime()
265
406
 
266
407
  # Check if it's a file path
267
408
  path = Path(path_or_code)
268
- if path.exists() and path.suffix in ('.cssl', '.cssl-mod'):
409
+ if path.exists() and path.suffix in ('.cssl', '.cssl-mod', '.cssl-pl'):
269
410
  source = path.read_text(encoding='utf-8')
270
411
  else:
271
412
  source = path_or_code
@@ -296,7 +437,27 @@ class CsslLang:
296
437
  raise RuntimeError(error_msg) from e
297
438
  raise RuntimeError(f"CSSL Error:\n{error_msg}") from e
298
439
 
299
- def T_exec(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
440
+ def exec(self, path_or_code: str, *args) -> Any:
441
+ """
442
+ Execute CSSL code or file.
443
+
444
+ DEPRECATED: Use run() instead. This method is kept for backwards compatibility.
445
+
446
+ Args:
447
+ path_or_code: Path to .cssl file or CSSL code string
448
+ *args: Arguments to pass to the script
449
+
450
+ Returns:
451
+ Execution result
452
+ """
453
+ warnings.warn(
454
+ "exec() is deprecated, use run() instead",
455
+ DeprecationWarning,
456
+ stacklevel=2
457
+ )
458
+ return self.run(path_or_code, *args)
459
+
460
+ def T_run(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
300
461
  """
301
462
  Execute CSSL code asynchronously in a thread.
302
463
 
@@ -308,20 +469,33 @@ class CsslLang:
308
469
  Returns:
309
470
  Thread object
310
471
  """
311
- def _run():
472
+ def _run_async():
312
473
  try:
313
- result = self.exec(path_or_code, *args)
474
+ result = self.run(path_or_code, *args)
314
475
  if callback:
315
476
  callback(result)
316
477
  except Exception as e:
317
478
  if callback:
318
479
  callback(e)
319
480
 
320
- thread = threading.Thread(target=_run, daemon=True)
481
+ thread = threading.Thread(target=_run_async, daemon=True)
321
482
  thread.start()
322
483
  self._threads.append(thread)
323
484
  return thread
324
485
 
486
+ def T_exec(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
487
+ """
488
+ Execute CSSL code asynchronously in a thread.
489
+
490
+ DEPRECATED: Use T_run() instead.
491
+ """
492
+ warnings.warn(
493
+ "T_exec() is deprecated, use T_run() instead",
494
+ DeprecationWarning,
495
+ stacklevel=2
496
+ )
497
+ return self.T_run(path_or_code, *args, callback=callback)
498
+
325
499
  def wait_all(self, timeout: Optional[float] = None):
326
500
  """Wait for all async executions to complete."""
327
501
  for thread in self._threads:
@@ -368,32 +542,185 @@ class CsslLang:
368
542
  """
369
543
  return CSSLModule(self, code)
370
544
 
371
- def makemodule(self, code: str) -> 'CSSLFunctionModule':
545
+ def script(self, script_type: str, code: str, *params) -> 'CSSLScript':
546
+ """
547
+ Create a typed CSSL script.
548
+
549
+ Args:
550
+ script_type: "cssl" for main script, "cssl-pl" for payload
551
+ code: The CSSL code
552
+ *params: Optional parameters accessible via parameter.get(index)
553
+
554
+ Returns:
555
+ CSSLScript object that can be executed or bundled
556
+
557
+ Usage:
558
+ main = cssl.script("cssl", '''
559
+ printl("Main script running");
560
+ helper();
561
+ ''')
562
+
563
+ payload = cssl.script("cssl-pl", '''
564
+ void helper() {
565
+ printl("Helper called!");
566
+ }
567
+ ''')
568
+
569
+ # Execute directly
570
+ main.run()
571
+
572
+ # Or bundle into module
573
+ mod = cssl.makemodule(main, payload, "mymod")
574
+ """
575
+ return CSSLScript(self, script_type, code, params)
576
+
577
+ def makemodule(
578
+ self,
579
+ main_script: Union[str, 'CSSLScript'],
580
+ payload_script: Union[str, 'CSSLScript', None] = None,
581
+ name: str = None
582
+ ) -> 'CSSLFunctionModule':
372
583
  """
373
584
  Create a CSSL module with accessible functions.
374
585
 
375
586
  Functions defined in the code become methods on the returned module.
587
+ Optionally registers the module for payload() access in other scripts.
376
588
 
377
- Usage:
378
- module = CSSL.makemodule('''
589
+ Args:
590
+ main_script: Main CSSL code (string or CSSLScript)
591
+ payload_script: Optional payload code (string or CSSLScript)
592
+ name: Optional name to register for payload(name) access
593
+
594
+ Returns:
595
+ CSSLFunctionModule - module with callable function attributes
596
+
597
+ Usage (v3.8.0 - with CSSLScript objects):
598
+ main = cssl.script("cssl", '''
599
+ printl("Main");
600
+ helper();
601
+ ''')
602
+ payload = cssl.script("cssl-pl", '''
603
+ void helper() { printl("Helper!"); }
604
+ ''')
605
+ mod = cssl.makemodule(main, payload, "mymod")
606
+ mod.helper() # Direct call
607
+
608
+ # Also available in other scripts:
609
+ cssl.run('''
610
+ payload("mymod");
611
+ helper(); // Works!
612
+ ''')
613
+
614
+ Usage (legacy - code string):
615
+ module = cssl.makemodule('''
379
616
  string greet(string name) {
380
617
  return "Hello, " + name + "!";
381
618
  }
382
-
383
- int add(int a, int b) {
384
- return a + b;
385
- }
386
619
  ''')
387
620
  module.greet("World") # Returns "Hello, World!"
388
- module.add(2, 3) # Returns 5
621
+ """
622
+ # Extract code from CSSLScript objects if provided
623
+ if isinstance(main_script, CSSLScript):
624
+ main_code = main_script.code
625
+ else:
626
+ main_code = main_script
627
+
628
+ payload_code = None
629
+ if payload_script is not None:
630
+ if isinstance(payload_script, CSSLScript):
631
+ payload_code = payload_script.code
632
+ else:
633
+ payload_code = payload_script
634
+
635
+ return CSSLFunctionModule(self, main_code, payload_code, name)
636
+
637
+ def load(self, path: str, name: str) -> None:
638
+ """
639
+ Load a .cssl or .cssl-pl file and register by name.
640
+
641
+ The file becomes accessible for execute(name) or payload(name).
642
+
643
+ Args:
644
+ path: Path to the .cssl or .cssl-pl file
645
+ name: Name to register the script under
646
+
647
+ Usage:
648
+ cssl.load("utils.cssl-pl", "utils")
649
+ cssl.execute("utils") # Run it
650
+
651
+ # Or in CSSL code:
652
+ cssl.run('''
653
+ payload("utils"); // Loads the registered file
654
+ ''')
655
+ """
656
+ path_obj = Path(path)
657
+ if not path_obj.exists():
658
+ raise FileNotFoundError(f"CSSL file not found: {path}")
659
+
660
+ script_type = self._detect_type(path)
661
+ code = path_obj.read_text(encoding='utf-8')
662
+
663
+ self._loaded_scripts[name] = {
664
+ 'path': str(path_obj.absolute()),
665
+ 'type': script_type,
666
+ 'code': code
667
+ }
668
+
669
+ # Also register for payload() access
670
+ runtime = self._get_runtime()
671
+ if not hasattr(runtime, '_inline_payloads'):
672
+ runtime._inline_payloads = {}
673
+ runtime._inline_payloads[name] = code
674
+
675
+ def execute(self, name: str, *args) -> Any:
676
+ """
677
+ Execute a previously loaded script by name.
389
678
 
390
679
  Args:
391
- code: CSSL code string with function definitions
680
+ name: Name of the loaded script
681
+ *args: Arguments to pass to the script
392
682
 
393
683
  Returns:
394
- CSSLFunctionModule - module with callable function attributes
684
+ Execution result
685
+
686
+ Usage:
687
+ cssl.load("utils.cssl-pl", "utils")
688
+ result = cssl.execute("utils", arg1, arg2)
395
689
  """
396
- return CSSLFunctionModule(self, code)
690
+ if name not in self._loaded_scripts:
691
+ raise KeyError(f"No script loaded with name '{name}'. Use load() first.")
692
+
693
+ script_info = self._loaded_scripts[name]
694
+ return self.run(script_info['code'], *args)
695
+
696
+ def include(self, path: str, name: str) -> None:
697
+ """
698
+ Register a file to be accessible via payload(name) or include(name) in CSSL.
699
+
700
+ Unlike load(), this doesn't store the script for execute() - it only
701
+ makes it available for payload() calls within CSSL code.
702
+
703
+ Args:
704
+ path: Path to the .cssl or .cssl-pl file
705
+ name: Name for payload() access
706
+
707
+ Usage:
708
+ cssl.include("helpers.cssl-pl", "helpers")
709
+ cssl.run('''
710
+ payload("helpers");
711
+ // Functions from helpers are now available
712
+ ''')
713
+ """
714
+ path_obj = Path(path)
715
+ if not path_obj.exists():
716
+ raise FileNotFoundError(f"CSSL file not found: {path}")
717
+
718
+ code = path_obj.read_text(encoding='utf-8')
719
+
720
+ runtime = self._get_runtime()
721
+ if not hasattr(runtime, '_inline_payloads'):
722
+ runtime._inline_payloads = {}
723
+ runtime._inline_payloads[name] = code
397
724
 
398
725
  def code(self, name: str, code: str) -> None:
399
726
  """
@@ -748,15 +1075,18 @@ def get_cssl() -> CsslLang:
748
1075
  return _default_instance
749
1076
 
750
1077
 
751
- # Module-level convenience functions
752
- def exec(path_or_code: str, *args) -> Any:
1078
+ # Module-level convenience functions (v3.8.0 API)
1079
+
1080
+ def run(path_or_code: str, *args) -> Any:
753
1081
  """
754
1082
  Execute CSSL code or file.
755
1083
 
1084
+ This is the primary method for running CSSL code in v3.8.0+.
1085
+
756
1086
  Usage:
757
1087
  from includecpp import CSSL
758
- CSSL.exec("script.cssl", arg1, arg2)
759
- CSSL.exec("printl('Hello World');")
1088
+ CSSL.run("script.cssl", arg1, arg2)
1089
+ CSSL.run("printl('Hello World');")
760
1090
 
761
1091
  Args:
762
1092
  path_or_code: Path to .cssl file or CSSL code string
@@ -765,16 +1095,30 @@ def exec(path_or_code: str, *args) -> Any:
765
1095
  Returns:
766
1096
  Execution result
767
1097
  """
768
- return get_cssl().exec(path_or_code, *args)
1098
+ return get_cssl().run(path_or_code, *args)
769
1099
 
770
1100
 
771
- def T_exec(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
1101
+ def exec(path_or_code: str, *args) -> Any:
1102
+ """
1103
+ Execute CSSL code or file.
1104
+
1105
+ DEPRECATED: Use run() instead.
1106
+ """
1107
+ warnings.warn(
1108
+ "exec() is deprecated, use run() instead",
1109
+ DeprecationWarning,
1110
+ stacklevel=2
1111
+ )
1112
+ return get_cssl().run(path_or_code, *args)
1113
+
1114
+
1115
+ def T_run(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
772
1116
  """
773
1117
  Execute CSSL code asynchronously in a thread.
774
1118
 
775
1119
  Usage:
776
1120
  from includecpp import CSSL
777
- CSSL.T_exec("async_script.cssl", arg1, callback=on_done)
1121
+ CSSL.T_run("async_script.cssl", arg1, callback=on_done)
778
1122
 
779
1123
  Args:
780
1124
  path_or_code: Path to .cssl file or CSSL code string
@@ -784,7 +1128,75 @@ def T_exec(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] =
784
1128
  Returns:
785
1129
  Thread object
786
1130
  """
787
- return get_cssl().T_exec(path_or_code, *args, callback=callback)
1131
+ return get_cssl().T_run(path_or_code, *args, callback=callback)
1132
+
1133
+
1134
+ def T_exec(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
1135
+ """
1136
+ Execute CSSL code asynchronously in a thread.
1137
+
1138
+ DEPRECATED: Use T_run() instead.
1139
+ """
1140
+ warnings.warn(
1141
+ "T_exec() is deprecated, use T_run() instead",
1142
+ DeprecationWarning,
1143
+ stacklevel=2
1144
+ )
1145
+ return get_cssl().T_run(path_or_code, *args, callback=callback)
1146
+
1147
+
1148
+ def script(script_type: str, code: str, *params) -> CSSLScript:
1149
+ """
1150
+ Create a typed CSSL script.
1151
+
1152
+ Usage:
1153
+ from includecpp import CSSL
1154
+ main = CSSL.script("cssl", '''printl("Main");''')
1155
+ payload = CSSL.script("cssl-pl", '''void helper() {}''')
1156
+ mod = CSSL.makemodule(main, payload, "mymod")
1157
+
1158
+ Args:
1159
+ script_type: "cssl" for main script, "cssl-pl" for payload
1160
+ code: The CSSL code
1161
+ *params: Optional parameters
1162
+
1163
+ Returns:
1164
+ CSSLScript object
1165
+ """
1166
+ return get_cssl().script(script_type, code, *params)
1167
+
1168
+
1169
+ def load(path: str, name: str) -> None:
1170
+ """
1171
+ Load a .cssl or .cssl-pl file and register by name.
1172
+
1173
+ Usage:
1174
+ CSSL.load("utils.cssl-pl", "utils")
1175
+ CSSL.execute("utils")
1176
+ """
1177
+ return get_cssl().load(path, name)
1178
+
1179
+
1180
+ def execute(name: str, *args) -> Any:
1181
+ """
1182
+ Execute a previously loaded script by name.
1183
+
1184
+ Usage:
1185
+ CSSL.load("utils.cssl-pl", "utils")
1186
+ result = CSSL.execute("utils", arg1, arg2)
1187
+ """
1188
+ return get_cssl().execute(name, *args)
1189
+
1190
+
1191
+ def include(path: str, name: str) -> None:
1192
+ """
1193
+ Register a file for payload(name) access in CSSL.
1194
+
1195
+ Usage:
1196
+ CSSL.include("helpers.cssl-pl", "helpers")
1197
+ CSSL.run('payload("helpers");')
1198
+ """
1199
+ return get_cssl().include(path, name)
788
1200
 
789
1201
 
790
1202
  def set_global(name: str, value: Any) -> None:
@@ -808,7 +1220,9 @@ def clear_output() -> None:
808
1220
 
809
1221
 
810
1222
  # Aliases to avoid conflict with Python builtin exec
1223
+ _run = run
811
1224
  _exec = exec
1225
+ _T_run = T_run
812
1226
  _T_exec = T_exec
813
1227
 
814
1228
 
@@ -832,43 +1246,58 @@ def module(code: str) -> CSSLModule:
832
1246
  return get_cssl().module(code)
833
1247
 
834
1248
 
835
- def makemodule(code: str) -> CSSLFunctionModule:
1249
+ def makemodule(
1250
+ main_script: Union[str, CSSLScript],
1251
+ payload_script: Union[str, CSSLScript, None] = None,
1252
+ name: str = None
1253
+ ) -> CSSLFunctionModule:
836
1254
  """
837
1255
  Create a CSSL module with accessible functions.
838
1256
 
839
- Usage:
840
- from includecpp import CSSL
841
- math_mod = CSSL.makemodule('''
842
- int add(int a, int b) {
843
- return a + b;
844
- }
1257
+ Usage (v3.8.0 - with CSSLScript):
1258
+ main = CSSL.script("cssl", '''printl("Main");''')
1259
+ payload = CSSL.script("cssl-pl", '''void helper() {}''')
1260
+ mod = CSSL.makemodule(main, payload, "mymod")
845
1261
 
846
- int multiply(int a, int b) {
847
- return a * b;
848
- }
1262
+ Usage (legacy - code string):
1263
+ math_mod = CSSL.makemodule('''
1264
+ int add(int a, int b) { return a + b; }
849
1265
  ''')
850
- math_mod.add(2, 3) # Returns 5
851
- math_mod.multiply(4, 5) # Returns 20
1266
+ math_mod.add(2, 3) # Returns 5
852
1267
 
853
1268
  Args:
854
- code: CSSL code string with function definitions
1269
+ main_script: Main CSSL code (string or CSSLScript)
1270
+ payload_script: Optional payload code (string or CSSLScript)
1271
+ name: Optional name to register for payload(name) access
855
1272
 
856
1273
  Returns:
857
1274
  CSSLFunctionModule - module with callable function attributes
858
1275
  """
859
- return get_cssl().makemodule(code)
1276
+ return get_cssl().makemodule(main_script, payload_script, name)
860
1277
 
861
1278
 
862
1279
  # Export all
863
1280
  __all__ = [
864
1281
  'CsslLang',
865
1282
  'CSSLModule',
1283
+ 'CSSLScript',
866
1284
  'CSSLFunctionModule',
867
1285
  'get_cssl',
1286
+ # v3.8.0 primary API
1287
+ 'run',
1288
+ '_run',
1289
+ 'T_run',
1290
+ '_T_run',
1291
+ 'script',
1292
+ 'load',
1293
+ 'execute',
1294
+ 'include',
1295
+ # Legacy (deprecated)
868
1296
  'exec',
869
- '_exec', # Alias for exec (avoids Python builtin conflict)
1297
+ '_exec',
870
1298
  'T_exec',
871
- '_T_exec', # Alias for T_exec
1299
+ '_T_exec',
1300
+ # Other
872
1301
  'set_global',
873
1302
  'get_global',
874
1303
  'get_output',
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "IncludeCPP"
7
- version = "3.7.3"
7
+ version = "3.7.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"
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text(encoding="utf-8")
6
6
 
7
7
  setup(
8
8
  name="IncludeCPP",
9
- version="3.7.3",
9
+ version="3.7.4",
10
10
  author="Lilias Hatterscheidt",
11
11
  author_email="lilias@includecpp.dev",
12
12
  description="Professional C++ Python bindings with type-generic templates and native threading",
File without changes
File without changes
File without changes
File without changes
File without changes