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.
Files changed (30) hide show
  1. includecpp/CHANGELOG.md +22 -0
  2. includecpp/__init__.py +1 -1
  3. includecpp/__init__.pyi +1 -4
  4. includecpp/cli/commands.py +1218 -25
  5. includecpp/core/cpp_api_extensions.pyi +204 -200
  6. includecpp/core/cssl/__init__.py +317 -0
  7. includecpp/core/cssl/cpp/build/api.pyd +0 -0
  8. includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
  9. includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
  10. includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
  11. includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
  12. includecpp/core/cssl/cpp/cssl_core.cp +108 -0
  13. includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
  14. includecpp/core/cssl/cssl_builtins.py +142 -27
  15. includecpp/core/cssl/cssl_compiler.py +448 -0
  16. includecpp/core/cssl/cssl_optimizer.py +833 -0
  17. includecpp/core/cssl/cssl_parser.py +433 -38
  18. includecpp/core/cssl/cssl_runtime.py +294 -15
  19. includecpp/core/cssl/cssl_syntax.py +17 -0
  20. includecpp/core/cssl/cssl_types.py +143 -11
  21. includecpp/core/cssl_bridge.py +39 -2
  22. includecpp/generator/parser.cpp +38 -14
  23. includecpp/vscode/cssl/package.json +15 -0
  24. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -0
  25. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/METADATA +1 -1
  26. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/RECORD +30 -21
  27. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/WHEEL +0 -0
  28. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/entry_points.txt +0 -0
  29. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/licenses/LICENSE +0 -0
  30. {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
- enum_obj = {}
850
+ new_values = {}
836
851
  for member in members:
837
852
  member_name = member['name']
838
853
  member_value = member['value']
839
- enum_obj[member_name] = member_value
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
- # Register the enum in scope (accessible as EnumName::VALUE)
842
- self.scope.set(enum_name, enum_obj)
843
- self.global_scope.set(enum_name, enum_obj)
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
- open_kwargs = self.scope.get('_OpenKwargs') or {}
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
- return param in kwargs
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
- return param not in kwargs
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
- # Convenience function
5807
- def run_cssl(source: str, service_engine=None) -> Any:
5808
- """Run CSSL source code"""
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