IncludeCPP 4.3.0__py3-none-any.whl → 4.6.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 +22 -0
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +1 -4
- includecpp/cli/commands.py +1218 -25
- includecpp/core/cpp_api_extensions.pyi +204 -200
- 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 +142 -27
- includecpp/core/cssl/cssl_compiler.py +448 -0
- includecpp/core/cssl/cssl_optimizer.py +833 -0
- includecpp/core/cssl/cssl_parser.py +433 -38
- includecpp/core/cssl/cssl_runtime.py +294 -15
- includecpp/core/cssl/cssl_syntax.py +17 -0
- includecpp/core/cssl/cssl_types.py +143 -11
- includecpp/core/cssl_bridge.py +39 -2
- includecpp/generator/parser.cpp +38 -14
- includecpp/vscode/cssl/package.json +15 -0
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/METADATA +1 -1
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/RECORD +30 -21
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/WHEEL +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/entry_points.txt +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/top_level.txt +0 -0
|
@@ -199,6 +199,13 @@ class CSSLReturn(Exception):
|
|
|
199
199
|
super().__init__()
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
class CSSLThrow(Exception):
|
|
203
|
+
"""Throw statement - v4.5.1: User-thrown exceptions that propagate to catch blocks"""
|
|
204
|
+
def __init__(self, message: Any = None):
|
|
205
|
+
self.message = message
|
|
206
|
+
super().__init__(str(message) if message else "")
|
|
207
|
+
|
|
208
|
+
|
|
202
209
|
@dataclass
|
|
203
210
|
class Scope:
|
|
204
211
|
"""Variable scope"""
|
|
@@ -826,21 +833,70 @@ class CSSLRuntime:
|
|
|
826
833
|
enum Colors { RED, GREEN, BLUE }
|
|
827
834
|
Colors::RED // returns 0
|
|
828
835
|
Colors::GREEN // returns 1
|
|
836
|
+
|
|
837
|
+
v4.3.2: Support for embedded enum modification:
|
|
838
|
+
embedded __NewEnum &OldEnum { ... } // Replace OldEnum
|
|
839
|
+
embedded __NewEnum &OldEnum ++ { ... } // Add to OldEnum
|
|
840
|
+
embedded __NewEnum &OldEnum -- { ... } // Remove from OldEnum
|
|
829
841
|
"""
|
|
830
842
|
enum_info = node.value
|
|
831
843
|
enum_name = enum_info.get('name')
|
|
832
844
|
members = enum_info.get('members', [])
|
|
845
|
+
is_embedded = enum_info.get('is_embedded', False)
|
|
846
|
+
replace_target = enum_info.get('replace_target')
|
|
847
|
+
mode = enum_info.get('mode', 'replace')
|
|
833
848
|
|
|
834
849
|
# Create enum object as a dict-like object with members
|
|
835
|
-
|
|
850
|
+
new_values = {}
|
|
836
851
|
for member in members:
|
|
837
852
|
member_name = member['name']
|
|
838
853
|
member_value = member['value']
|
|
839
|
-
|
|
854
|
+
# Evaluate if value is an ASTNode
|
|
855
|
+
if isinstance(member_value, ASTNode):
|
|
856
|
+
member_value = self._evaluate(member_value)
|
|
857
|
+
new_values[member_name] = member_value
|
|
858
|
+
|
|
859
|
+
# v4.3.2: Handle embedded modification
|
|
860
|
+
if is_embedded and replace_target:
|
|
861
|
+
target_name = replace_target.lstrip('@') if replace_target.startswith('@') else replace_target
|
|
862
|
+
|
|
863
|
+
if mode == 'add':
|
|
864
|
+
# Get existing enum and add new values
|
|
865
|
+
existing = self.scope.get(target_name) or self.global_scope.get(target_name) or {}
|
|
866
|
+
if isinstance(existing, dict):
|
|
867
|
+
# For add mode, auto-increment from highest existing int value
|
|
868
|
+
max_val = -1
|
|
869
|
+
for v in existing.values():
|
|
870
|
+
if isinstance(v, int) and v > max_val:
|
|
871
|
+
max_val = v
|
|
872
|
+
# Update new values that don't have explicit values
|
|
873
|
+
for name, val in new_values.items():
|
|
874
|
+
if isinstance(val, int) and val <= max_val:
|
|
875
|
+
max_val += 1
|
|
876
|
+
new_values[name] = max_val
|
|
877
|
+
enum_obj = {**existing, **new_values}
|
|
878
|
+
else:
|
|
879
|
+
enum_obj = new_values
|
|
880
|
+
elif mode == 'remove':
|
|
881
|
+
# Get existing enum and remove specified keys
|
|
882
|
+
existing = self.scope.get(target_name) or self.global_scope.get(target_name) or {}
|
|
883
|
+
if isinstance(existing, dict):
|
|
884
|
+
enum_obj = {k: v for k, v in existing.items() if k not in new_values}
|
|
885
|
+
else:
|
|
886
|
+
enum_obj = {}
|
|
887
|
+
else:
|
|
888
|
+
# Replace mode - just use new values
|
|
889
|
+
enum_obj = new_values
|
|
840
890
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
891
|
+
self.scope.set(target_name, enum_obj)
|
|
892
|
+
self.global_scope.set(target_name, enum_obj)
|
|
893
|
+
if replace_target.startswith('@'):
|
|
894
|
+
self._promoted_globals[target_name] = enum_obj
|
|
895
|
+
else:
|
|
896
|
+
# Regular enum - just register it
|
|
897
|
+
enum_obj = new_values
|
|
898
|
+
self.scope.set(enum_name, enum_obj)
|
|
899
|
+
self.global_scope.set(enum_name, enum_obj)
|
|
844
900
|
|
|
845
901
|
return enum_obj
|
|
846
902
|
|
|
@@ -1346,9 +1402,34 @@ class CSSLRuntime:
|
|
|
1346
1402
|
|
|
1347
1403
|
v4.2.6: In namespace mode (_payload_namespace_mode), track replacements
|
|
1348
1404
|
instead of applying globally. The namespace handler will scope them.
|
|
1405
|
+
|
|
1406
|
+
v4.5.1: Respects 'private' modifier - private functions/methods cannot be overwritten.
|
|
1349
1407
|
"""
|
|
1350
1408
|
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
1351
1409
|
|
|
1410
|
+
# v4.5.1: Check if target has 'private' modifier - prevent overwrite
|
|
1411
|
+
if not ref_class.startswith('$'):
|
|
1412
|
+
target_func = self.scope.get(ref_class) or self.global_scope.get(ref_class)
|
|
1413
|
+
if target_func is not None:
|
|
1414
|
+
# Check for function with private modifier
|
|
1415
|
+
if hasattr(target_func, 'value') and isinstance(target_func.value, dict):
|
|
1416
|
+
modifiers = target_func.value.get('modifiers', [])
|
|
1417
|
+
if 'private' in modifiers:
|
|
1418
|
+
raise CSSLRuntimeError(
|
|
1419
|
+
f"Cannot overwrite private function '{ref_class}' - "
|
|
1420
|
+
f"private functions are protected from embedded replacements"
|
|
1421
|
+
)
|
|
1422
|
+
# Check for class with private method
|
|
1423
|
+
if ref_member and isinstance(target_func, CSSLClass):
|
|
1424
|
+
method = target_func.methods.get(ref_member) if hasattr(target_func, 'methods') else None
|
|
1425
|
+
if method and hasattr(method, 'value') and isinstance(method.value, dict):
|
|
1426
|
+
modifiers = method.value.get('modifiers', [])
|
|
1427
|
+
if 'private' in modifiers:
|
|
1428
|
+
raise CSSLRuntimeError(
|
|
1429
|
+
f"Cannot overwrite private method '{ref_class}::{ref_member}' - "
|
|
1430
|
+
f"private methods are protected from embedded replacements"
|
|
1431
|
+
)
|
|
1432
|
+
|
|
1352
1433
|
# v4.2.6: Check for namespace mode
|
|
1353
1434
|
namespace_mode = getattr(self, '_payload_namespace_mode', None)
|
|
1354
1435
|
if namespace_mode and ref_member is None and not ref_class.startswith('$'):
|
|
@@ -1452,9 +1533,34 @@ class CSSLRuntime:
|
|
|
1452
1533
|
- &ClassName::method ++ - Append to method in CSSL class
|
|
1453
1534
|
- &$PyObject.method ++ - Append to method in Python shared object
|
|
1454
1535
|
- &functionName ++ - Append to standalone function
|
|
1536
|
+
|
|
1537
|
+
v4.5.1: Respects 'private' modifier - private functions/methods cannot be appended to.
|
|
1455
1538
|
"""
|
|
1456
1539
|
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
1457
1540
|
|
|
1541
|
+
# v4.5.1: Check if target has 'private' modifier - prevent append
|
|
1542
|
+
if not ref_class.startswith('$'):
|
|
1543
|
+
target_func = self.scope.get(ref_class) or self.global_scope.get(ref_class)
|
|
1544
|
+
if target_func is not None:
|
|
1545
|
+
# Check for function with private modifier
|
|
1546
|
+
if hasattr(target_func, 'value') and isinstance(target_func.value, dict):
|
|
1547
|
+
modifiers = target_func.value.get('modifiers', [])
|
|
1548
|
+
if 'private' in modifiers:
|
|
1549
|
+
raise CSSLRuntimeError(
|
|
1550
|
+
f"Cannot append to private function '{ref_class}' - "
|
|
1551
|
+
f"private functions are protected from embedded modifications"
|
|
1552
|
+
)
|
|
1553
|
+
# Check for class with private method
|
|
1554
|
+
if ref_member and isinstance(target_func, CSSLClass):
|
|
1555
|
+
method = target_func.methods.get(ref_member) if hasattr(target_func, 'methods') else None
|
|
1556
|
+
if method and hasattr(method, 'value') and isinstance(method.value, dict):
|
|
1557
|
+
modifiers = method.value.get('modifiers', [])
|
|
1558
|
+
if 'private' in modifiers:
|
|
1559
|
+
raise CSSLRuntimeError(
|
|
1560
|
+
f"Cannot append to private method '{ref_class}::{ref_member}' - "
|
|
1561
|
+
f"private methods are protected from embedded modifications"
|
|
1562
|
+
)
|
|
1563
|
+
|
|
1458
1564
|
# Handle Python shared objects
|
|
1459
1565
|
if ref_class.startswith('$'):
|
|
1460
1566
|
var_name = ref_class[1:]
|
|
@@ -2268,7 +2374,18 @@ class CSSLRuntime:
|
|
|
2268
2374
|
}
|
|
2269
2375
|
"""
|
|
2270
2376
|
params_name = node.value.get('params')
|
|
2271
|
-
|
|
2377
|
+
# v4.3.2: Use the actual variable from switch(Variable), not just _OpenKwargs
|
|
2378
|
+
# This allows switch(Input) where Input is the open parameter
|
|
2379
|
+
if params_name == 'Params':
|
|
2380
|
+
open_kwargs = self.scope.get('_OpenKwargs') or {}
|
|
2381
|
+
else:
|
|
2382
|
+
# Try to get kwargs from the named variable
|
|
2383
|
+
open_kwargs = self.scope.get(params_name)
|
|
2384
|
+
if open_kwargs is None:
|
|
2385
|
+
open_kwargs = self.scope.get('_OpenKwargs') or {}
|
|
2386
|
+
elif not isinstance(open_kwargs, dict):
|
|
2387
|
+
# If it's not a dict, try _OpenKwargs as fallback
|
|
2388
|
+
open_kwargs = self.scope.get('_OpenKwargs') or {}
|
|
2272
2389
|
|
|
2273
2390
|
matched = False
|
|
2274
2391
|
always_node = None
|
|
@@ -2325,25 +2442,54 @@ class CSSLRuntime:
|
|
|
2325
2442
|
"""Evaluate a param switch condition.
|
|
2326
2443
|
|
|
2327
2444
|
Condition types:
|
|
2328
|
-
{'type': 'exists', 'param': 'name'} -> 'name' in kwargs
|
|
2329
|
-
{'type': 'not', 'param': 'name'} -> 'name' not in kwargs
|
|
2445
|
+
{'type': 'exists', 'param': 'name'} -> 'name' in kwargs OR variable 'name' is truthy
|
|
2446
|
+
{'type': 'not', 'param': 'name'} -> 'name' not in kwargs AND variable 'name' is falsy
|
|
2330
2447
|
{'type': 'and', 'left': {...}, 'right': {...}} -> left AND right
|
|
2448
|
+
{'type': 'or', 'left': {...}, 'right': {...}} -> left OR right
|
|
2449
|
+
|
|
2450
|
+
v4.3.2: Added 'or' type for || operator support.
|
|
2451
|
+
v4.3.2: Enhanced to check both kwargs AND scope variables (from OpenFind).
|
|
2452
|
+
This allows positional args found via OpenFind<type>(index) to work
|
|
2453
|
+
with param_switch conditions like 'case text & !error:'.
|
|
2331
2454
|
"""
|
|
2332
2455
|
cond_type = condition.get('type')
|
|
2333
2456
|
|
|
2334
2457
|
if cond_type == 'exists':
|
|
2335
2458
|
param = condition.get('param')
|
|
2336
|
-
|
|
2459
|
+
# Check kwargs first
|
|
2460
|
+
if param in kwargs:
|
|
2461
|
+
return True
|
|
2462
|
+
# Also check if a variable with this name exists in scope and is truthy
|
|
2463
|
+
# This allows OpenFind results to work with param_switch
|
|
2464
|
+
var_value = self.scope.get(param)
|
|
2465
|
+
if var_value is not None and var_value != '' and var_value != 0 and var_value != False:
|
|
2466
|
+
# Make sure it's not a builtin function
|
|
2467
|
+
if not callable(var_value):
|
|
2468
|
+
return True
|
|
2469
|
+
return False
|
|
2337
2470
|
|
|
2338
2471
|
elif cond_type == 'not':
|
|
2339
2472
|
param = condition.get('param')
|
|
2340
|
-
|
|
2473
|
+
# Check kwargs first
|
|
2474
|
+
if param in kwargs:
|
|
2475
|
+
return False
|
|
2476
|
+
# Also check if variable is truthy (then it's "provided")
|
|
2477
|
+
var_value = self.scope.get(param)
|
|
2478
|
+
if var_value is not None and var_value != '' and var_value != 0 and var_value != False:
|
|
2479
|
+
if not callable(var_value):
|
|
2480
|
+
return False # Variable has value, so it IS provided
|
|
2481
|
+
return True # Not in kwargs and variable is null/empty
|
|
2341
2482
|
|
|
2342
2483
|
elif cond_type == 'and':
|
|
2343
2484
|
left = self._eval_param_condition(condition.get('left'), kwargs)
|
|
2344
2485
|
right = self._eval_param_condition(condition.get('right'), kwargs)
|
|
2345
2486
|
return left and right
|
|
2346
2487
|
|
|
2488
|
+
elif cond_type == 'or':
|
|
2489
|
+
left = self._eval_param_condition(condition.get('left'), kwargs)
|
|
2490
|
+
right = self._eval_param_condition(condition.get('right'), kwargs)
|
|
2491
|
+
return left or right
|
|
2492
|
+
|
|
2347
2493
|
return False
|
|
2348
2494
|
|
|
2349
2495
|
def _exec_return(self, node: ASTNode) -> Any:
|
|
@@ -2371,6 +2517,23 @@ class CSSLRuntime:
|
|
|
2371
2517
|
"""Execute continue statement"""
|
|
2372
2518
|
raise CSSLContinue()
|
|
2373
2519
|
|
|
2520
|
+
def _exec_throw(self, node: ASTNode) -> Any:
|
|
2521
|
+
"""Execute throw statement - v4.5.1
|
|
2522
|
+
|
|
2523
|
+
Throws a CSSLThrow exception that propagates to the nearest catch block.
|
|
2524
|
+
|
|
2525
|
+
Syntax:
|
|
2526
|
+
throw "Error message";
|
|
2527
|
+
throw errorVar;
|
|
2528
|
+
throw; // re-throw current exception
|
|
2529
|
+
"""
|
|
2530
|
+
if node.value is None:
|
|
2531
|
+
# throw; - re-throw current exception (should be in a catch block)
|
|
2532
|
+
raise CSSLThrow("Re-thrown exception")
|
|
2533
|
+
|
|
2534
|
+
message = self._evaluate(node.value)
|
|
2535
|
+
raise CSSLThrow(message)
|
|
2536
|
+
|
|
2374
2537
|
def _exec_constructor(self, node: ASTNode) -> Any:
|
|
2375
2538
|
"""Execute constructor node - only called when encountered directly.
|
|
2376
2539
|
|
|
@@ -2454,6 +2617,20 @@ class CSSLRuntime:
|
|
|
2454
2617
|
if child.type == 'try-block':
|
|
2455
2618
|
for stmt in child.children:
|
|
2456
2619
|
self._execute_node(stmt)
|
|
2620
|
+
except CSSLThrow as e:
|
|
2621
|
+
# v4.5.1: Handle user-thrown exceptions from throw statement
|
|
2622
|
+
for child in node.children:
|
|
2623
|
+
if child.type == 'catch-block':
|
|
2624
|
+
error_var = child.value.get('error_var') if child.value else None
|
|
2625
|
+
if error_var:
|
|
2626
|
+
# Store the thrown message in the error variable
|
|
2627
|
+
self.scope.set(error_var, e.message if e.message else str(e))
|
|
2628
|
+
for stmt in child.children:
|
|
2629
|
+
self._execute_node(stmt)
|
|
2630
|
+
break # Only execute first matching catch block
|
|
2631
|
+
else:
|
|
2632
|
+
# No catch block found - re-raise for outer try-catch
|
|
2633
|
+
raise
|
|
2457
2634
|
except CSSLRuntimeError as e:
|
|
2458
2635
|
for child in node.children:
|
|
2459
2636
|
if child.type == 'catch-block':
|
|
@@ -2462,6 +2639,9 @@ class CSSLRuntime:
|
|
|
2462
2639
|
self.scope.set(error_var, str(e))
|
|
2463
2640
|
for stmt in child.children:
|
|
2464
2641
|
self._execute_node(stmt)
|
|
2642
|
+
break
|
|
2643
|
+
else:
|
|
2644
|
+
raise # Re-raise if no catch block
|
|
2465
2645
|
except Exception as e:
|
|
2466
2646
|
# v4.2.6: Also catch Python exceptions
|
|
2467
2647
|
for child in node.children:
|
|
@@ -2471,6 +2651,9 @@ class CSSLRuntime:
|
|
|
2471
2651
|
self.scope.set(error_var, str(e))
|
|
2472
2652
|
for stmt in child.children:
|
|
2473
2653
|
self._execute_node(stmt)
|
|
2654
|
+
break
|
|
2655
|
+
else:
|
|
2656
|
+
raise # Re-raise if no catch block
|
|
2474
2657
|
finally:
|
|
2475
2658
|
# v4.2.6: Execute finally block if present
|
|
2476
2659
|
for child in node.children:
|
|
@@ -3733,6 +3916,10 @@ class CSSLRuntime:
|
|
|
3733
3916
|
elif hasattr(container, member_name):
|
|
3734
3917
|
return getattr(container, member_name)
|
|
3735
3918
|
|
|
3919
|
+
# v4.3.2: Check if full name exists as builtin function (json::write, string::cut, etc.)
|
|
3920
|
+
if self.builtins.has_function(name):
|
|
3921
|
+
return self.builtins.get_function(name)
|
|
3922
|
+
|
|
3736
3923
|
# Fall through to normal lookup if container not found
|
|
3737
3924
|
return None
|
|
3738
3925
|
|
|
@@ -5066,6 +5253,33 @@ class CSSLRuntime:
|
|
|
5066
5253
|
if isinstance(obj, Parameter) and member == 'return':
|
|
5067
5254
|
member = 'return_'
|
|
5068
5255
|
|
|
5256
|
+
# === ServiceDefinition (from include()) ===
|
|
5257
|
+
if isinstance(obj, ServiceDefinition):
|
|
5258
|
+
# Check functions dict first
|
|
5259
|
+
if member in obj.functions:
|
|
5260
|
+
func_node = obj.functions[member]
|
|
5261
|
+
return lambda *args, **kwargs: self._call_function(func_node, list(args), kwargs)
|
|
5262
|
+
# Check structs dict
|
|
5263
|
+
if member in obj.structs:
|
|
5264
|
+
return obj.structs[member]
|
|
5265
|
+
# Check regular attributes
|
|
5266
|
+
if hasattr(obj, member):
|
|
5267
|
+
return getattr(obj, member)
|
|
5268
|
+
# Build helpful error
|
|
5269
|
+
available = list(obj.functions.keys()) + list(obj.structs.keys())
|
|
5270
|
+
similar = _find_similar_names(member, available)
|
|
5271
|
+
if similar:
|
|
5272
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
5273
|
+
elif available:
|
|
5274
|
+
hint = f"Available: {', '.join(available[:10])}"
|
|
5275
|
+
else:
|
|
5276
|
+
hint = "No functions or structs defined in this module."
|
|
5277
|
+
raise self._format_error(
|
|
5278
|
+
node.line if hasattr(node, 'line') else 0,
|
|
5279
|
+
f"Module has no function or struct '{member}'",
|
|
5280
|
+
hint
|
|
5281
|
+
)
|
|
5282
|
+
|
|
5069
5283
|
# === CSSL CLASS INSTANCE METHODS ===
|
|
5070
5284
|
if isinstance(obj, CSSLInstance):
|
|
5071
5285
|
# Check for member variable
|
|
@@ -5803,14 +6017,79 @@ class CSSLServiceRunner:
|
|
|
5803
6017
|
return list(self.running_services.keys())
|
|
5804
6018
|
|
|
5805
6019
|
|
|
5806
|
-
#
|
|
5807
|
-
|
|
5808
|
-
|
|
6020
|
+
# C++ interpreter cache
|
|
6021
|
+
_cpp_interpreter = None
|
|
6022
|
+
|
|
6023
|
+
|
|
6024
|
+
def _get_cpp_interpreter():
|
|
6025
|
+
"""Get or create C++ interpreter instance."""
|
|
6026
|
+
global _cpp_interpreter
|
|
6027
|
+
if _cpp_interpreter is not None:
|
|
6028
|
+
return _cpp_interpreter
|
|
6029
|
+
|
|
6030
|
+
try:
|
|
6031
|
+
from . import _CPP_AVAILABLE, _cpp_module
|
|
6032
|
+
if _CPP_AVAILABLE and _cpp_module and hasattr(_cpp_module, 'Interpreter'):
|
|
6033
|
+
_cpp_interpreter = _cpp_module.Interpreter()
|
|
6034
|
+
return _cpp_interpreter
|
|
6035
|
+
except Exception:
|
|
6036
|
+
pass
|
|
6037
|
+
return None
|
|
6038
|
+
|
|
6039
|
+
|
|
6040
|
+
def run_cssl(source: str, service_engine=None, force_python: bool = False) -> Any:
|
|
6041
|
+
"""Run CSSL source code.
|
|
6042
|
+
|
|
6043
|
+
Uses C++ interpreter for maximum performance when available.
|
|
6044
|
+
Falls back to Python interpreter for unsupported features.
|
|
6045
|
+
|
|
6046
|
+
Args:
|
|
6047
|
+
source: CSSL source code
|
|
6048
|
+
service_engine: Optional service engine for external integrations
|
|
6049
|
+
force_python: Force Python interpreter (for debugging)
|
|
6050
|
+
|
|
6051
|
+
Returns:
|
|
6052
|
+
Execution result
|
|
6053
|
+
"""
|
|
6054
|
+
# Try C++ interpreter first (10-20x faster)
|
|
6055
|
+
if not force_python:
|
|
6056
|
+
cpp_interp = _get_cpp_interpreter()
|
|
6057
|
+
if cpp_interp:
|
|
6058
|
+
try:
|
|
6059
|
+
return cpp_interp.run_string(source)
|
|
6060
|
+
except Exception as e:
|
|
6061
|
+
# C++ doesn't support this feature, fall back to Python
|
|
6062
|
+
error_msg = str(e).lower()
|
|
6063
|
+
# Only fall back for unsupported features, not syntax errors
|
|
6064
|
+
if 'unsupported' in error_msg or 'not implemented' in error_msg:
|
|
6065
|
+
pass # Fall through to Python
|
|
6066
|
+
else:
|
|
6067
|
+
# Re-raise actual errors
|
|
6068
|
+
raise CSSLRuntimeError(str(e))
|
|
6069
|
+
|
|
6070
|
+
# Python fallback (full feature support)
|
|
5809
6071
|
runtime = CSSLRuntime(service_engine)
|
|
5810
6072
|
return runtime.execute(source)
|
|
5811
6073
|
|
|
5812
6074
|
|
|
5813
|
-
def run_cssl_file(filepath: str, service_engine=None) -> Any:
|
|
5814
|
-
"""Run a CSSL file
|
|
6075
|
+
def run_cssl_file(filepath: str, service_engine=None, force_python: bool = False) -> Any:
|
|
6076
|
+
"""Run a CSSL file.
|
|
6077
|
+
|
|
6078
|
+
Uses C++ interpreter for maximum performance when available.
|
|
6079
|
+
"""
|
|
6080
|
+
# Try C++ interpreter first
|
|
6081
|
+
if not force_python:
|
|
6082
|
+
cpp_interp = _get_cpp_interpreter()
|
|
6083
|
+
if cpp_interp:
|
|
6084
|
+
try:
|
|
6085
|
+
return cpp_interp.run(filepath)
|
|
6086
|
+
except Exception as e:
|
|
6087
|
+
error_msg = str(e).lower()
|
|
6088
|
+
if 'unsupported' in error_msg or 'not implemented' in error_msg:
|
|
6089
|
+
pass # Fall through to Python
|
|
6090
|
+
else:
|
|
6091
|
+
raise CSSLRuntimeError(str(e))
|
|
6092
|
+
|
|
6093
|
+
# Python fallback
|
|
5815
6094
|
runtime = CSSLRuntime(service_engine)
|
|
5816
6095
|
return runtime.execute_file(filepath)
|
|
@@ -36,6 +36,8 @@ class TokenCategory(Enum):
|
|
|
36
36
|
LIBINCLUDE_KW = auto() # libinclude (yellow/gold)
|
|
37
37
|
LANG_PREFIX = auto() # Language prefix before $ (cyan): cpp$, py$, java$
|
|
38
38
|
LANG_INSTANCE = auto() # Instance name after $ (orange): cpp$ClassName
|
|
39
|
+
# v4.6.0: C++ execution control
|
|
40
|
+
NATIVE_KW = auto() # native keyword (cyan/bright) - forces C++ execution
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
@dataclass
|
|
@@ -65,6 +67,9 @@ KEYWORDS = {
|
|
|
65
67
|
# v4.1.0: Multi-language keywords with special highlighting
|
|
66
68
|
MULTI_LANG_KEYWORDS = {'supports', 'libinclude'}
|
|
67
69
|
|
|
70
|
+
# v4.6.0: C++ execution control keyword
|
|
71
|
+
NATIVE_KEYWORD = {'native'} # Forces C++ execution (no Python fallback)
|
|
72
|
+
|
|
68
73
|
# v4.1.0: Language identifiers for cross-language instance access
|
|
69
74
|
LANGUAGE_IDS = {'cpp', 'py', 'python', 'java', 'csharp', 'js', 'javascript'}
|
|
70
75
|
|
|
@@ -171,6 +176,12 @@ class CSSLSyntaxRules:
|
|
|
171
176
|
category=TokenCategory.LIBINCLUDE_KW
|
|
172
177
|
))
|
|
173
178
|
|
|
179
|
+
# v4.6.0: 'native' keyword (cyan/bright) - forces C++ execution
|
|
180
|
+
rules.append(HighlightRule(
|
|
181
|
+
pattern=r'\bnative\b',
|
|
182
|
+
category=TokenCategory.NATIVE_KW
|
|
183
|
+
))
|
|
184
|
+
|
|
174
185
|
# v4.1.0: Language$Instance patterns (cpp$ClassName, py$Object)
|
|
175
186
|
# Match language prefix before $ (cyan)
|
|
176
187
|
rules.append(HighlightRule(
|
|
@@ -278,6 +289,8 @@ class ColorScheme:
|
|
|
278
289
|
TokenCategory.LIBINCLUDE_KW: '#f1fa8c',# Yellow/Gold for 'libinclude'
|
|
279
290
|
TokenCategory.LANG_PREFIX: '#8be9fd', # Cyan for language prefix (cpp$)
|
|
280
291
|
TokenCategory.LANG_INSTANCE: '#ffb86c',# Orange for instance name ($ClassName)
|
|
292
|
+
# v4.6.0: C++ execution control
|
|
293
|
+
TokenCategory.NATIVE_KW: '#50fa7b', # Green/Cyan for 'native' (C++ forced)
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
# Light theme variant
|
|
@@ -302,6 +315,8 @@ class ColorScheme:
|
|
|
302
315
|
TokenCategory.LIBINCLUDE_KW: '#b8860b',# DarkGoldenrod for 'libinclude'
|
|
303
316
|
TokenCategory.LANG_PREFIX: '#0d6efd', # Blue for language prefix (cpp$)
|
|
304
317
|
TokenCategory.LANG_INSTANCE: '#fd7e14',# Orange for instance name ($ClassName)
|
|
318
|
+
# v4.6.0: C++ execution control
|
|
319
|
+
TokenCategory.NATIVE_KW: '#198754', # Green for 'native' (C++ forced)
|
|
305
320
|
}
|
|
306
321
|
|
|
307
322
|
|
|
@@ -389,6 +404,8 @@ def highlight_cssl_ansi(source: str) -> str:
|
|
|
389
404
|
TokenCategory.LIBINCLUDE_KW: '\033[93m',# Yellow for 'libinclude'
|
|
390
405
|
TokenCategory.LANG_PREFIX: '\033[96m', # Cyan for language prefix (cpp$)
|
|
391
406
|
TokenCategory.LANG_INSTANCE: '\033[33m',# Orange/Yellow for instance name
|
|
407
|
+
# v4.6.0: C++ execution control
|
|
408
|
+
TokenCategory.NATIVE_KW: '\033[92m', # Bright Green for 'native'
|
|
392
409
|
}
|
|
393
410
|
RESET = '\033[0m'
|
|
394
411
|
|