IncludeCPP 4.2.2__py3-none-any.whl → 4.5.2__py3-none-any.whl

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 (33) hide show
  1. includecpp/CHANGELOG.md +104 -115
  2. includecpp/DOCUMENTATION.md +208 -355
  3. includecpp/__init__.py +1 -1
  4. includecpp/__init__.pyi +1 -4
  5. includecpp/cli/commands.py +1220 -27
  6. includecpp/core/cpp_api_extensions.pyi +204 -200
  7. includecpp/core/cssl/CSSL_DOCUMENTATION.md +1505 -1467
  8. includecpp/core/cssl/__init__.py +317 -0
  9. includecpp/core/cssl/cpp/build/api.pyd +0 -0
  10. includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
  11. includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
  12. includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
  13. includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
  14. includecpp/core/cssl/cpp/cssl_core.cp +108 -0
  15. includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
  16. includecpp/core/cssl/cssl_builtins.py +245 -20
  17. includecpp/core/cssl/cssl_compiler.py +448 -0
  18. includecpp/core/cssl/cssl_optimizer.py +833 -0
  19. includecpp/core/cssl/cssl_parser.py +945 -40
  20. includecpp/core/cssl/cssl_runtime.py +751 -38
  21. includecpp/core/cssl/cssl_syntax.py +17 -0
  22. includecpp/core/cssl/cssl_types.py +321 -0
  23. includecpp/core/cssl_bridge.py +36 -2
  24. includecpp/generator/parser.cpp +38 -14
  25. includecpp/vscode/cssl/package.json +15 -0
  26. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +134 -2
  27. includecpp-4.5.2.dist-info/METADATA +277 -0
  28. {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/RECORD +32 -23
  29. includecpp-4.2.2.dist-info/METADATA +0 -1008
  30. {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/WHEEL +0 -0
  31. {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/entry_points.txt +0 -0
  32. {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/licenses/LICENSE +0 -0
  33. {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,7 @@ class CSSLBuiltins:
41
41
  self._functions['error'] = self.builtin_error
42
42
  self._functions['warn'] = self.builtin_warn
43
43
  self._functions['log'] = self.builtin_log
44
+ self._functions['encode'] = self.builtin_encode # v4.3.2: Safe unicode encoding
44
45
 
45
46
  # Type conversion
46
47
  self._functions['int'] = self.builtin_int
@@ -350,22 +351,73 @@ class CSSLBuiltins:
350
351
 
351
352
  def builtin_print(self, *args, **kwargs) -> None:
352
353
  """Print without newline"""
354
+ import sys
353
355
  sep = kwargs.get('sep', ' ')
354
356
  end = kwargs.get('end', '')
355
357
  output = sep.join(str(a) for a in args) + end
356
358
  if self.runtime and hasattr(self.runtime, 'output'):
357
359
  self.runtime.output(output)
358
360
  else:
359
- print(output, end='')
361
+ # Handle encoding issues on Windows console
362
+ try:
363
+ print(output, end='')
364
+ except UnicodeEncodeError:
365
+ encoded = output.encode(sys.stdout.encoding or 'utf-8', errors='replace')
366
+ print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'), end='')
360
367
 
361
368
  def builtin_println(self, *args, **kwargs) -> None:
362
369
  """Print with newline"""
370
+ import sys
363
371
  sep = kwargs.get('sep', ' ')
364
372
  output = sep.join(str(a) for a in args)
365
373
  if self.runtime and hasattr(self.runtime, 'output'):
366
374
  self.runtime.output(output + '\n')
367
375
  else:
368
- print(output)
376
+ # Handle encoding issues on Windows console
377
+ try:
378
+ print(output)
379
+ except UnicodeEncodeError:
380
+ # Fallback: encode with errors='replace' for unsupported chars
381
+ encoded = output.encode(sys.stdout.encoding or 'utf-8', errors='replace')
382
+ print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'))
383
+
384
+ def builtin_encode(self, content: str, fallback: str = "?") -> str:
385
+ """Encode unicode/emoji characters for safe console output.
386
+
387
+ v4.3.2: Safely encode emojis and special unicode characters that may not
388
+ be supported by the current console encoding (e.g., Windows cp1252).
389
+
390
+ Usage:
391
+ printl("Status: " + encode("✅"));
392
+ printl("Result: " + encode("😂", "[emoji]"));
393
+
394
+ // With custom fallback
395
+ msg = encode("🎉 Success!", "[party]");
396
+
397
+ Args:
398
+ content: String containing unicode/emoji characters
399
+ fallback: Replacement string for unencodable characters (default: "?")
400
+
401
+ Returns:
402
+ String safe for console output
403
+ """
404
+ import sys
405
+ encoding = sys.stdout.encoding or 'utf-8'
406
+
407
+ try:
408
+ # Test if content can be encoded with current console encoding
409
+ content.encode(encoding)
410
+ return content
411
+ except UnicodeEncodeError:
412
+ # Replace unencodable characters with fallback
413
+ result = []
414
+ for char in content:
415
+ try:
416
+ char.encode(encoding)
417
+ result.append(char)
418
+ except UnicodeEncodeError:
419
+ result.append(fallback)
420
+ return ''.join(result)
369
421
 
370
422
  def builtin_input(self, prompt: str = "") -> str:
371
423
  """Read user input from console.
@@ -632,19 +684,85 @@ class CSSLBuiltins:
632
684
  # ============= List Functions =============
633
685
 
634
686
  def builtin_push(self, lst: list, *items) -> list:
687
+ """Push items onto a list/stack/vector.
688
+
689
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
690
+ For regular lists, creates a copy (immutable behavior).
691
+ """
692
+ if lst is None:
693
+ lst = []
694
+ lst.extend(items)
695
+ return lst
696
+
697
+ # v4.5.1: For CSSL typed containers, modify in place
698
+ from .cssl_types import Stack, Vector, Array, DataStruct
699
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
700
+ for item in items:
701
+ lst.append(item)
702
+ return lst
703
+
704
+ # For regular lists, create a copy (immutable behavior)
635
705
  lst = list(lst)
636
706
  lst.extend(items)
637
707
  return lst
638
708
 
639
709
  def builtin_pop(self, lst: list, index: int = -1) -> Any:
710
+ """Pop item from list/stack/vector.
711
+
712
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
713
+ """
714
+ if lst is None:
715
+ return None
716
+
717
+ # v4.5.1: For CSSL typed containers, modify in place
718
+ from .cssl_types import Stack, Vector, Array, DataStruct
719
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
720
+ if len(lst) == 0:
721
+ return None
722
+ return lst.pop(index)
723
+
724
+ # For regular lists, create a copy
640
725
  lst = list(lst)
641
- return lst.pop(index)
726
+ return lst.pop(index) if lst else None
642
727
 
643
728
  def builtin_shift(self, lst: list) -> Any:
729
+ """Remove and return first element.
730
+
731
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
732
+ """
733
+ if lst is None:
734
+ return None
735
+
736
+ # v4.5.1: For CSSL typed containers, modify in place
737
+ from .cssl_types import Stack, Vector, Array, DataStruct
738
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
739
+ if len(lst) == 0:
740
+ return None
741
+ return lst.pop(0)
742
+
743
+ # For regular lists, create a copy
644
744
  lst = list(lst)
645
745
  return lst.pop(0) if lst else None
646
746
 
647
747
  def builtin_unshift(self, lst: list, *items) -> list:
748
+ """Add items to the front of a list/stack/vector.
749
+
750
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
751
+ """
752
+ if lst is None:
753
+ lst = []
754
+ for item in reversed(items):
755
+ lst.insert(0, item)
756
+ return lst
757
+
758
+ # v4.5.1: For CSSL typed containers, modify in place
759
+ from .cssl_types import Stack, Vector, Array, DataStruct
760
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
761
+ for item in reversed(items):
762
+ lst.insert(0, item)
763
+ return lst
764
+
765
+ # For regular lists, create a copy
648
766
  lst = list(lst)
649
767
  for item in reversed(items):
650
768
  lst.insert(0, item)
@@ -2111,9 +2229,9 @@ class CSSLBuiltins:
2111
2229
 
2112
2230
  return CppModuleStub(name, source)
2113
2231
 
2114
- def builtin_payload(self, filepath: str) -> None:
2232
+ def builtin_payload(self, filepath: str, libname: str = None) -> None:
2115
2233
  """
2116
- Load a CSSL payload file (.cssl-pl) and execute it in the current scope.
2234
+ Load a CSSL payload file (.cssl-pl) and execute it.
2117
2235
 
2118
2236
  Payloads are like header files but for CSSL:
2119
2237
  - Define global variables (accessible via @name)
@@ -2122,8 +2240,19 @@ class CSSLBuiltins:
2122
2240
  - Set configuration values
2123
2241
 
2124
2242
  Usage in .cssl file:
2243
+ // Standard: everything is applied globally
2125
2244
  payload("myconfig.cssl-pl");
2126
- // Now all globals, functions, and injections are active
2245
+
2246
+ // Namespaced: everything goes into a namespace
2247
+ payload("myconfig.cssl-pl", "mylib");
2248
+ mylib::myFunction(); // Access via namespace
2249
+
2250
+ Namespace behavior:
2251
+ - Without libname: All changes are global (embedded replaces globally)
2252
+ - With libname: All definitions go into namespace
2253
+ - embedded new_exit &exit {} -> mylib::exit is new_exit
2254
+ - Global exit remains unchanged
2255
+ - Access via libname::function(), libname::MyClass
2127
2256
 
2128
2257
  Usage in Python:
2129
2258
  cssl = CSSL.CsslLang()
@@ -2155,6 +2284,10 @@ class CSSLBuiltins:
2155
2284
  if hasattr(self.runtime, '_inline_payloads') and filepath in self.runtime._inline_payloads:
2156
2285
  source = self.runtime._inline_payloads[filepath]
2157
2286
  else:
2287
+ # v4.2.6: Auto-append .cssl-pl extension if not specified
2288
+ # payload("engine") -> looks for engine.cssl-pl
2289
+ original_filepath = filepath
2290
+
2158
2291
  # Handle absolute paths
2159
2292
  is_absolute = os.path.isabs(filepath) or (len(filepath) > 2 and filepath[1] == ':')
2160
2293
 
@@ -2164,42 +2297,134 @@ class CSSLBuiltins:
2164
2297
  if os.path.exists(cwd_path):
2165
2298
  filepath = cwd_path
2166
2299
  else:
2167
- # Fall back to cso_root for service context
2168
- filepath = self.builtin_cso_root(filepath)
2169
-
2170
- # Check file exists
2300
+ # Try with .cssl-pl extension
2301
+ cwd_path_pl = os.path.join(os.getcwd(), filepath + '.cssl-pl')
2302
+ if os.path.exists(cwd_path_pl):
2303
+ filepath = cwd_path_pl
2304
+ else:
2305
+ # Fall back to cso_root for service context
2306
+ filepath = self.builtin_cso_root(filepath)
2307
+
2308
+ # Check file exists, try with .cssl-pl extension if not
2171
2309
  if not os.path.exists(filepath):
2172
- raise CSSLBuiltinError(f"Payload file not found: {filepath}")
2310
+ # Try adding .cssl-pl extension
2311
+ filepath_with_ext = filepath + '.cssl-pl'
2312
+ if os.path.exists(filepath_with_ext):
2313
+ filepath = filepath_with_ext
2314
+ else:
2315
+ raise CSSLBuiltinError(f"Payload file not found: {original_filepath} (tried {filepath} and {filepath_with_ext})")
2173
2316
 
2174
2317
  # Check payload cache to prevent double loading
2175
2318
  if not hasattr(self.runtime, '_payload_cache'):
2176
2319
  self.runtime._payload_cache = set()
2177
2320
 
2178
- if filepath in self.runtime._payload_cache:
2321
+ # For namespaced payloads, use different cache key
2322
+ cache_key = f"{filepath}::{libname}" if libname else filepath
2323
+ if cache_key in self.runtime._payload_cache:
2179
2324
  return # Already loaded
2180
2325
 
2181
2326
  # Read the payload file
2182
2327
  with open(filepath, 'r', encoding='utf-8') as f:
2183
2328
  source = f.read()
2184
2329
 
2185
- self.runtime._payload_cache.add(filepath)
2330
+ self.runtime._payload_cache.add(cache_key)
2186
2331
 
2187
- # Parse and execute the payload in current scope
2188
- # This makes all globals, functions, and injections available
2332
+ # Parse and execute the payload
2189
2333
  try:
2190
2334
  from .cssl_parser import parse_cssl_program
2191
2335
 
2192
2336
  ast = parse_cssl_program(source)
2193
2337
 
2194
- # Execute the payload - this will:
2195
- # - Register global variables (accessible via @name)
2196
- # - Define functions in current scope
2197
- # - Set up any code injections
2198
- self.runtime._execute_node(ast)
2338
+ if libname:
2339
+ # Namespaced execution: execute in isolated scope
2340
+ self._execute_payload_namespaced(ast, libname, source)
2341
+ else:
2342
+ # Standard execution: apply globally
2343
+ # Execute the payload - this will:
2344
+ # - Register global variables (accessible via @name)
2345
+ # - Define functions in current scope
2346
+ # - Set up any code injections
2347
+ self.runtime._execute_node(ast)
2199
2348
 
2200
2349
  except Exception as e:
2201
2350
  raise CSSLBuiltinError(f"Failed to load payload '{filepath}': {e}")
2202
2351
 
2352
+ def _execute_payload_namespaced(self, ast, libname: str, source: str) -> None:
2353
+ """
2354
+ Execute payload in a namespace.
2355
+
2356
+ All definitions go into the namespace dict.
2357
+ embedded replacements are scoped to the namespace only.
2358
+ Variables declared with 'global' keyword remain truly global (accessible via @).
2359
+ """
2360
+ # Create namespace dict
2361
+ namespace = {}
2362
+
2363
+ # Save current scope state (copy the variables dicts)
2364
+ old_scope_vars = dict(self.runtime.scope.variables)
2365
+ old_global_vars = dict(self.runtime.global_scope.variables)
2366
+ old_promoted_globals = dict(self.runtime._promoted_globals)
2367
+
2368
+ # Track what gets added during payload execution
2369
+ scope_before = set(self.runtime.scope.variables.keys())
2370
+ global_before = set(self.runtime.global_scope.variables.keys())
2371
+ promoted_before = set(self.runtime._promoted_globals.keys())
2372
+
2373
+ # Set a flag to tell runtime we're in namespace mode
2374
+ self.runtime._payload_namespace_mode = libname
2375
+
2376
+ try:
2377
+ # Execute the payload
2378
+ self.runtime._execute_node(ast)
2379
+
2380
+ # Find which variables were explicitly promoted to global (via 'global' keyword)
2381
+ new_promoted = set(self.runtime._promoted_globals.keys()) - promoted_before
2382
+
2383
+ # Collect new definitions from scope (but not promoted globals)
2384
+ for key in self.runtime.scope.variables:
2385
+ if key not in scope_before and key not in new_promoted:
2386
+ namespace[key] = self.runtime.scope.get(key)
2387
+
2388
+ # Collect new definitions from global_scope (but not namespace itself, not promoted globals)
2389
+ for key in self.runtime.global_scope.variables:
2390
+ if key not in global_before and key != libname and key not in new_promoted:
2391
+ namespace[key] = self.runtime.global_scope.get(key)
2392
+
2393
+ # Handle embedded replacements: move replaced targets into namespace
2394
+ if hasattr(self.runtime, '_namespace_replacements'):
2395
+ for target_name, new_impl in self.runtime._namespace_replacements.items():
2396
+ # Get the original from before execution
2397
+ original = old_scope_vars.get(target_name) or old_global_vars.get(target_name)
2398
+ if original is not None:
2399
+ # Restore original globally
2400
+ if target_name in old_scope_vars:
2401
+ self.runtime.scope.set(target_name, original)
2402
+ if target_name in old_global_vars:
2403
+ self.runtime.global_scope.set(target_name, original)
2404
+ # Put the replacement in namespace
2405
+ namespace[target_name] = new_impl
2406
+ del self.runtime._namespace_replacements
2407
+
2408
+ # Remove new definitions from scope (they're in namespace now)
2409
+ # BUT keep promoted globals - they stay global!
2410
+ for key in list(self.runtime.scope.variables.keys()):
2411
+ if key not in scope_before and key not in new_promoted:
2412
+ del self.runtime.scope.variables[key]
2413
+
2414
+ for key in list(self.runtime.global_scope.variables.keys()):
2415
+ if key not in global_before and key != libname and key not in new_promoted:
2416
+ del self.runtime.global_scope.variables[key]
2417
+
2418
+ # Promoted globals stay in _promoted_globals and global_scope (not moved to namespace)
2419
+ # They are accessible via @name from anywhere
2420
+
2421
+ finally:
2422
+ # Clear namespace mode flag
2423
+ self.runtime._payload_namespace_mode = None
2424
+
2425
+ # Register namespace in global scope
2426
+ self.runtime.global_scope.set(libname, namespace)
2427
+
2203
2428
  def builtin_get(self, source: Any, key: str = None) -> Any:
2204
2429
  """
2205
2430
  Get value from module, ServiceDefinition, or dict