IncludeCPP 4.0.2__py3-none-any.whl → 4.3.0__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 +142 -0
- includecpp/DOCUMENTATION.md +446 -0
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +4 -1
- includecpp/cli/commands.py +700 -86
- includecpp/core/ai_integration.py +46 -13
- includecpp/core/cpp_api_extensions.pyi +350 -0
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +1535 -1316
- includecpp/core/cssl/cssl_builtins.py +230 -23
- includecpp/core/cssl/cssl_languages.py +1757 -0
- includecpp/core/cssl/cssl_parser.py +967 -126
- includecpp/core/cssl/cssl_runtime.py +1133 -84
- includecpp/core/cssl/cssl_syntax.py +88 -4
- includecpp/core/cssl/cssl_types.py +361 -1
- includecpp/core/cssl_bridge.py +194 -8
- includecpp/core/cssl_bridge.pyi +148 -10
- includecpp/generator/parser.cpp +121 -4
- includecpp/generator/parser.h +6 -0
- includecpp/vscode/cssl/package.json +43 -1
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +178 -19
- includecpp-4.3.0.dist-info/METADATA +277 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/RECORD +26 -22
- includecpp-4.0.2.dist-info/METADATA +0 -908
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/WHEEL +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/entry_points.txt +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/top_level.txt +0 -0
|
@@ -36,6 +36,7 @@ class CSSLBuiltins:
|
|
|
36
36
|
# Output functions
|
|
37
37
|
self._functions['print'] = self.builtin_print
|
|
38
38
|
self._functions['println'] = self.builtin_println
|
|
39
|
+
self._functions['input'] = self.builtin_input
|
|
39
40
|
self._functions['debug'] = self.builtin_debug
|
|
40
41
|
self._functions['error'] = self.builtin_error
|
|
41
42
|
self._functions['warn'] = self.builtin_warn
|
|
@@ -291,6 +292,7 @@ class CSSLBuiltins:
|
|
|
291
292
|
self._functions['include'] = self.builtin_include
|
|
292
293
|
self._functions['payload'] = self.builtin_payload
|
|
293
294
|
self._functions['get'] = self.builtin_get
|
|
295
|
+
self._functions['libinclude'] = self.builtin_libinclude # v4.1.0: Multi-language support
|
|
294
296
|
|
|
295
297
|
# NEW: Extended OS Functions
|
|
296
298
|
self._functions['Listdir'] = self.builtin_listdir # Alias with capital L
|
|
@@ -348,22 +350,56 @@ class CSSLBuiltins:
|
|
|
348
350
|
|
|
349
351
|
def builtin_print(self, *args, **kwargs) -> None:
|
|
350
352
|
"""Print without newline"""
|
|
353
|
+
import sys
|
|
351
354
|
sep = kwargs.get('sep', ' ')
|
|
352
355
|
end = kwargs.get('end', '')
|
|
353
356
|
output = sep.join(str(a) for a in args) + end
|
|
354
357
|
if self.runtime and hasattr(self.runtime, 'output'):
|
|
355
358
|
self.runtime.output(output)
|
|
356
359
|
else:
|
|
357
|
-
|
|
360
|
+
# Handle encoding issues on Windows console
|
|
361
|
+
try:
|
|
362
|
+
print(output, end='')
|
|
363
|
+
except UnicodeEncodeError:
|
|
364
|
+
encoded = output.encode(sys.stdout.encoding or 'utf-8', errors='replace')
|
|
365
|
+
print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'), end='')
|
|
358
366
|
|
|
359
367
|
def builtin_println(self, *args, **kwargs) -> None:
|
|
360
368
|
"""Print with newline"""
|
|
369
|
+
import sys
|
|
361
370
|
sep = kwargs.get('sep', ' ')
|
|
362
371
|
output = sep.join(str(a) for a in args)
|
|
363
372
|
if self.runtime and hasattr(self.runtime, 'output'):
|
|
364
373
|
self.runtime.output(output + '\n')
|
|
365
374
|
else:
|
|
366
|
-
|
|
375
|
+
# Handle encoding issues on Windows console
|
|
376
|
+
try:
|
|
377
|
+
print(output)
|
|
378
|
+
except UnicodeEncodeError:
|
|
379
|
+
# Fallback: encode with errors='replace' for unsupported chars
|
|
380
|
+
encoded = output.encode(sys.stdout.encoding or 'utf-8', errors='replace')
|
|
381
|
+
print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'))
|
|
382
|
+
|
|
383
|
+
def builtin_input(self, prompt: str = "") -> str:
|
|
384
|
+
"""Read user input from console.
|
|
385
|
+
|
|
386
|
+
Usage:
|
|
387
|
+
name = input("Enter your name: ");
|
|
388
|
+
age = int(input("Enter your age: "));
|
|
389
|
+
|
|
390
|
+
// Without prompt
|
|
391
|
+
value = input();
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
prompt: Optional prompt text to display
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
The user's input as a string
|
|
398
|
+
"""
|
|
399
|
+
if self.runtime and hasattr(self.runtime, 'input'):
|
|
400
|
+
return self.runtime.input(prompt)
|
|
401
|
+
else:
|
|
402
|
+
return input(prompt)
|
|
367
403
|
|
|
368
404
|
def builtin_debug(self, *args) -> None:
|
|
369
405
|
"""Debug output"""
|
|
@@ -1418,8 +1454,20 @@ class CSSLBuiltins:
|
|
|
1418
1454
|
time.sleep(ms / 1000.0)
|
|
1419
1455
|
|
|
1420
1456
|
def builtin_pyimport(self, module_name: str) -> Any:
|
|
1421
|
-
"""
|
|
1422
|
-
|
|
1457
|
+
"""
|
|
1458
|
+
Import a Python module for use in CSSL.
|
|
1459
|
+
|
|
1460
|
+
v4.1.1: Fixed to use importlib.import_module for proper nested module support.
|
|
1461
|
+
|
|
1462
|
+
Usage:
|
|
1463
|
+
module = pyimport("plugins.app")
|
|
1464
|
+
result = module.my_function()
|
|
1465
|
+
|
|
1466
|
+
os = pyimport("os")
|
|
1467
|
+
path = os.path.join("a", "b")
|
|
1468
|
+
"""
|
|
1469
|
+
import importlib
|
|
1470
|
+
return importlib.import_module(module_name)
|
|
1423
1471
|
|
|
1424
1472
|
# ============= Extended String Functions =============
|
|
1425
1473
|
|
|
@@ -1937,6 +1985,45 @@ class CSSLBuiltins:
|
|
|
1937
1985
|
except Exception as e:
|
|
1938
1986
|
raise CSSLBuiltinError(f"Failed to include '{filepath}': {e}")
|
|
1939
1987
|
|
|
1988
|
+
def builtin_libinclude(self, lang_id: str) -> Any:
|
|
1989
|
+
"""
|
|
1990
|
+
Load a language support module for multi-language syntax support.
|
|
1991
|
+
|
|
1992
|
+
v4.1.0: Multi-language support for CSSL.
|
|
1993
|
+
|
|
1994
|
+
Usage:
|
|
1995
|
+
@py = libinclude("python")
|
|
1996
|
+
cpp = libinclude("c++")
|
|
1997
|
+
java = libinclude("java")
|
|
1998
|
+
js = libinclude("javascript")
|
|
1999
|
+
csharp = libinclude("c#")
|
|
2000
|
+
|
|
2001
|
+
Returns: LanguageSupport object that can be used with 'supports' keyword.
|
|
2002
|
+
|
|
2003
|
+
Example:
|
|
2004
|
+
@py = libinclude("python");
|
|
2005
|
+
|
|
2006
|
+
define my_func() : supports @py {
|
|
2007
|
+
# Python syntax here!
|
|
2008
|
+
for i in range(10):
|
|
2009
|
+
print(i)
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
class MyClass : extends cpp$BaseClass {
|
|
2013
|
+
// Inherit from C++ class
|
|
2014
|
+
}
|
|
2015
|
+
"""
|
|
2016
|
+
from .cssl_languages import get_language
|
|
2017
|
+
|
|
2018
|
+
lang_support = get_language(lang_id)
|
|
2019
|
+
if lang_support is None:
|
|
2020
|
+
supported = ["python", "py", "java", "c#", "csharp", "c++", "cpp", "javascript", "js"]
|
|
2021
|
+
raise CSSLBuiltinError(
|
|
2022
|
+
f"Unknown language '{lang_id}'. Supported languages: {', '.join(supported)}"
|
|
2023
|
+
)
|
|
2024
|
+
|
|
2025
|
+
return lang_support
|
|
2026
|
+
|
|
1940
2027
|
def _load_cssl_module(self, filepath: str, source: str) -> Any:
|
|
1941
2028
|
"""
|
|
1942
2029
|
Load a .cssl-mod module file and return a callable module object.
|
|
@@ -2037,9 +2124,9 @@ class CSSLBuiltins:
|
|
|
2037
2124
|
|
|
2038
2125
|
return CppModuleStub(name, source)
|
|
2039
2126
|
|
|
2040
|
-
def builtin_payload(self, filepath: str) -> None:
|
|
2127
|
+
def builtin_payload(self, filepath: str, libname: str = None) -> None:
|
|
2041
2128
|
"""
|
|
2042
|
-
Load a CSSL payload file (.cssl-pl) and execute it
|
|
2129
|
+
Load a CSSL payload file (.cssl-pl) and execute it.
|
|
2043
2130
|
|
|
2044
2131
|
Payloads are like header files but for CSSL:
|
|
2045
2132
|
- Define global variables (accessible via @name)
|
|
@@ -2048,8 +2135,19 @@ class CSSLBuiltins:
|
|
|
2048
2135
|
- Set configuration values
|
|
2049
2136
|
|
|
2050
2137
|
Usage in .cssl file:
|
|
2138
|
+
// Standard: everything is applied globally
|
|
2051
2139
|
payload("myconfig.cssl-pl");
|
|
2052
|
-
|
|
2140
|
+
|
|
2141
|
+
// Namespaced: everything goes into a namespace
|
|
2142
|
+
payload("myconfig.cssl-pl", "mylib");
|
|
2143
|
+
mylib::myFunction(); // Access via namespace
|
|
2144
|
+
|
|
2145
|
+
Namespace behavior:
|
|
2146
|
+
- Without libname: All changes are global (embedded replaces globally)
|
|
2147
|
+
- With libname: All definitions go into namespace
|
|
2148
|
+
- embedded new_exit &exit {} -> mylib::exit is new_exit
|
|
2149
|
+
- Global exit remains unchanged
|
|
2150
|
+
- Access via libname::function(), libname::MyClass
|
|
2053
2151
|
|
|
2054
2152
|
Usage in Python:
|
|
2055
2153
|
cssl = CSSL.CsslLang()
|
|
@@ -2081,6 +2179,10 @@ class CSSLBuiltins:
|
|
|
2081
2179
|
if hasattr(self.runtime, '_inline_payloads') and filepath in self.runtime._inline_payloads:
|
|
2082
2180
|
source = self.runtime._inline_payloads[filepath]
|
|
2083
2181
|
else:
|
|
2182
|
+
# v4.2.6: Auto-append .cssl-pl extension if not specified
|
|
2183
|
+
# payload("engine") -> looks for engine.cssl-pl
|
|
2184
|
+
original_filepath = filepath
|
|
2185
|
+
|
|
2084
2186
|
# Handle absolute paths
|
|
2085
2187
|
is_absolute = os.path.isabs(filepath) or (len(filepath) > 2 and filepath[1] == ':')
|
|
2086
2188
|
|
|
@@ -2090,42 +2192,124 @@ class CSSLBuiltins:
|
|
|
2090
2192
|
if os.path.exists(cwd_path):
|
|
2091
2193
|
filepath = cwd_path
|
|
2092
2194
|
else:
|
|
2093
|
-
#
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2195
|
+
# Try with .cssl-pl extension
|
|
2196
|
+
cwd_path_pl = os.path.join(os.getcwd(), filepath + '.cssl-pl')
|
|
2197
|
+
if os.path.exists(cwd_path_pl):
|
|
2198
|
+
filepath = cwd_path_pl
|
|
2199
|
+
else:
|
|
2200
|
+
# Fall back to cso_root for service context
|
|
2201
|
+
filepath = self.builtin_cso_root(filepath)
|
|
2202
|
+
|
|
2203
|
+
# Check file exists, try with .cssl-pl extension if not
|
|
2097
2204
|
if not os.path.exists(filepath):
|
|
2098
|
-
|
|
2205
|
+
# Try adding .cssl-pl extension
|
|
2206
|
+
filepath_with_ext = filepath + '.cssl-pl'
|
|
2207
|
+
if os.path.exists(filepath_with_ext):
|
|
2208
|
+
filepath = filepath_with_ext
|
|
2209
|
+
else:
|
|
2210
|
+
raise CSSLBuiltinError(f"Payload file not found: {original_filepath} (tried {filepath} and {filepath_with_ext})")
|
|
2099
2211
|
|
|
2100
2212
|
# Check payload cache to prevent double loading
|
|
2101
2213
|
if not hasattr(self.runtime, '_payload_cache'):
|
|
2102
2214
|
self.runtime._payload_cache = set()
|
|
2103
2215
|
|
|
2104
|
-
|
|
2216
|
+
# For namespaced payloads, use different cache key
|
|
2217
|
+
cache_key = f"{filepath}::{libname}" if libname else filepath
|
|
2218
|
+
if cache_key in self.runtime._payload_cache:
|
|
2105
2219
|
return # Already loaded
|
|
2106
2220
|
|
|
2107
2221
|
# Read the payload file
|
|
2108
2222
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
2109
2223
|
source = f.read()
|
|
2110
2224
|
|
|
2111
|
-
self.runtime._payload_cache.add(
|
|
2225
|
+
self.runtime._payload_cache.add(cache_key)
|
|
2112
2226
|
|
|
2113
|
-
# Parse and execute the payload
|
|
2114
|
-
# This makes all globals, functions, and injections available
|
|
2227
|
+
# Parse and execute the payload
|
|
2115
2228
|
try:
|
|
2116
2229
|
from .cssl_parser import parse_cssl_program
|
|
2117
2230
|
|
|
2118
2231
|
ast = parse_cssl_program(source)
|
|
2119
2232
|
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2233
|
+
if libname:
|
|
2234
|
+
# Namespaced execution: execute in isolated scope
|
|
2235
|
+
self._execute_payload_namespaced(ast, libname, source)
|
|
2236
|
+
else:
|
|
2237
|
+
# Standard execution: apply globally
|
|
2238
|
+
# Execute the payload - this will:
|
|
2239
|
+
# - Register global variables (accessible via @name)
|
|
2240
|
+
# - Define functions in current scope
|
|
2241
|
+
# - Set up any code injections
|
|
2242
|
+
self.runtime._execute_node(ast)
|
|
2125
2243
|
|
|
2126
2244
|
except Exception as e:
|
|
2127
2245
|
raise CSSLBuiltinError(f"Failed to load payload '{filepath}': {e}")
|
|
2128
2246
|
|
|
2247
|
+
def _execute_payload_namespaced(self, ast, libname: str, source: str) -> None:
|
|
2248
|
+
"""
|
|
2249
|
+
Execute payload in a namespace.
|
|
2250
|
+
|
|
2251
|
+
All definitions go into the namespace dict.
|
|
2252
|
+
embedded replacements are scoped to the namespace only.
|
|
2253
|
+
"""
|
|
2254
|
+
# Create namespace dict
|
|
2255
|
+
namespace = {}
|
|
2256
|
+
|
|
2257
|
+
# Save current scope state
|
|
2258
|
+
old_scope = self.runtime.scope.copy()
|
|
2259
|
+
old_global = self.runtime.global_scope.copy()
|
|
2260
|
+
|
|
2261
|
+
# Track what gets added during payload execution
|
|
2262
|
+
scope_before = set(self.runtime.scope.keys())
|
|
2263
|
+
global_before = set(self.runtime.global_scope.keys())
|
|
2264
|
+
|
|
2265
|
+
# Set a flag to tell runtime we're in namespace mode
|
|
2266
|
+
self.runtime._payload_namespace_mode = libname
|
|
2267
|
+
|
|
2268
|
+
try:
|
|
2269
|
+
# Execute the payload
|
|
2270
|
+
self.runtime._execute_node(ast)
|
|
2271
|
+
|
|
2272
|
+
# Collect new definitions from scope
|
|
2273
|
+
for key in self.runtime.scope:
|
|
2274
|
+
if key not in scope_before:
|
|
2275
|
+
namespace[key] = self.runtime.scope[key]
|
|
2276
|
+
|
|
2277
|
+
# Collect new definitions from global_scope (but not the namespace itself)
|
|
2278
|
+
for key in self.runtime.global_scope:
|
|
2279
|
+
if key not in global_before and key != libname:
|
|
2280
|
+
namespace[key] = self.runtime.global_scope[key]
|
|
2281
|
+
|
|
2282
|
+
# Handle embedded replacements: move replaced targets into namespace
|
|
2283
|
+
if hasattr(self.runtime, '_namespace_replacements'):
|
|
2284
|
+
for target_name, new_impl in self.runtime._namespace_replacements.items():
|
|
2285
|
+
# Get the original from before execution
|
|
2286
|
+
original = old_scope.get(target_name) or old_global.get(target_name)
|
|
2287
|
+
if original is not None:
|
|
2288
|
+
# Restore original globally
|
|
2289
|
+
if target_name in old_scope:
|
|
2290
|
+
self.runtime.scope[target_name] = original
|
|
2291
|
+
if target_name in old_global:
|
|
2292
|
+
self.runtime.global_scope[target_name] = original
|
|
2293
|
+
# Put the replacement in namespace
|
|
2294
|
+
namespace[target_name] = new_impl
|
|
2295
|
+
del self.runtime._namespace_replacements
|
|
2296
|
+
|
|
2297
|
+
# Remove new definitions from global scope (they're in namespace now)
|
|
2298
|
+
for key in list(self.runtime.scope.keys()):
|
|
2299
|
+
if key not in scope_before:
|
|
2300
|
+
del self.runtime.scope[key]
|
|
2301
|
+
|
|
2302
|
+
for key in list(self.runtime.global_scope.keys()):
|
|
2303
|
+
if key not in global_before and key != libname:
|
|
2304
|
+
del self.runtime.global_scope[key]
|
|
2305
|
+
|
|
2306
|
+
finally:
|
|
2307
|
+
# Clear namespace mode flag
|
|
2308
|
+
self.runtime._payload_namespace_mode = None
|
|
2309
|
+
|
|
2310
|
+
# Register namespace in global scope
|
|
2311
|
+
self.runtime.global_scope[libname] = namespace
|
|
2312
|
+
|
|
2129
2313
|
def builtin_get(self, source: Any, key: str = None) -> Any:
|
|
2130
2314
|
"""
|
|
2131
2315
|
Get value from module, ServiceDefinition, or dict
|
|
@@ -2688,8 +2872,8 @@ class PythonizedCSSLInstance:
|
|
|
2688
2872
|
return value
|
|
2689
2873
|
|
|
2690
2874
|
# Check for method
|
|
2691
|
-
|
|
2692
|
-
|
|
2875
|
+
if instance.has_method(name):
|
|
2876
|
+
method = instance.get_method(name)
|
|
2693
2877
|
# Return a callable wrapper for the method
|
|
2694
2878
|
return PythonizedMethod(instance, name, method, runtime)
|
|
2695
2879
|
|
|
@@ -2744,6 +2928,29 @@ class PythonizedMethod:
|
|
|
2744
2928
|
if self._runtime is None:
|
|
2745
2929
|
raise RuntimeError(f"Cannot call method '{self._method_name}' - no runtime available")
|
|
2746
2930
|
|
|
2931
|
+
# Validate argument count
|
|
2932
|
+
# Method AST structure: node.value is a dict with 'params' key
|
|
2933
|
+
method_info = getattr(self._method_ast, 'value', {}) or {}
|
|
2934
|
+
method_params = method_info.get('params', []) if isinstance(method_info, dict) else []
|
|
2935
|
+
param_names = [p.get('name', str(p)) if isinstance(p, dict) else (p.name if hasattr(p, 'name') else str(p)) for p in method_params]
|
|
2936
|
+
expected_count = len(param_names)
|
|
2937
|
+
actual_count = len(args)
|
|
2938
|
+
|
|
2939
|
+
if actual_count < expected_count:
|
|
2940
|
+
missing = param_names[actual_count:]
|
|
2941
|
+
class_name = self._instance._class.name
|
|
2942
|
+
raise TypeError(
|
|
2943
|
+
f"{class_name}.{self._method_name}() missing {len(missing)} required argument(s): {', '.join(repr(p) for p in missing)}\n"
|
|
2944
|
+
f" Expected: {self._method_name}({', '.join(param_names)})\n"
|
|
2945
|
+
f" Got: {self._method_name}({', '.join(repr(a) for a in args)})"
|
|
2946
|
+
)
|
|
2947
|
+
elif actual_count > expected_count:
|
|
2948
|
+
class_name = self._instance._class.name
|
|
2949
|
+
raise TypeError(
|
|
2950
|
+
f"{class_name}.{self._method_name}() takes {expected_count} argument(s) but {actual_count} were given\n"
|
|
2951
|
+
f" Expected: {self._method_name}({', '.join(param_names)})"
|
|
2952
|
+
)
|
|
2953
|
+
|
|
2747
2954
|
# Execute the method through the runtime
|
|
2748
2955
|
# Pass the method AST node, not the method name
|
|
2749
2956
|
result = self._runtime._call_method(self._instance, self._method_ast, list(args), kwargs)
|