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.
- includecpp/CHANGELOG.md +104 -115
- includecpp/DOCUMENTATION.md +208 -355
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +1 -4
- includecpp/cli/commands.py +1220 -27
- includecpp/core/cpp_api_extensions.pyi +204 -200
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +1505 -1467
- includecpp/core/cssl/__init__.py +317 -0
- includecpp/core/cssl/cpp/build/api.pyd +0 -0
- includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
- includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
- includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
- includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
- includecpp/core/cssl/cpp/cssl_core.cp +108 -0
- includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
- includecpp/core/cssl/cssl_builtins.py +245 -20
- includecpp/core/cssl/cssl_compiler.py +448 -0
- includecpp/core/cssl/cssl_optimizer.py +833 -0
- includecpp/core/cssl/cssl_parser.py +945 -40
- includecpp/core/cssl/cssl_runtime.py +751 -38
- includecpp/core/cssl/cssl_syntax.py +17 -0
- includecpp/core/cssl/cssl_types.py +321 -0
- includecpp/core/cssl_bridge.py +36 -2
- includecpp/generator/parser.cpp +38 -14
- includecpp/vscode/cssl/package.json +15 -0
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +134 -2
- includecpp-4.5.2.dist-info/METADATA +277 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/RECORD +32 -23
- includecpp-4.2.2.dist-info/METADATA +0 -1008
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/WHEEL +0 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/entry_points.txt +0 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
2330
|
+
self.runtime._payload_cache.add(cache_key)
|
|
2186
2331
|
|
|
2187
|
-
# Parse and execute the payload
|
|
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
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
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
|