IncludeCPP 4.0.2__py3-none-any.whl → 4.1.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.
@@ -278,6 +278,26 @@ class CSSLRuntime:
278
278
  self._setup_modules()
279
279
  self._setup_builtins()
280
280
 
281
+ def output(self, text: str, level: str = 'normal') -> None:
282
+ """Output text, using callback if available, otherwise print."""
283
+ if self._output_callback:
284
+ self._output_callback(text, level)
285
+ else:
286
+ print(text, end='')
287
+ self.output_buffer.append(text)
288
+
289
+ def debug(self, text: str) -> None:
290
+ """Debug output."""
291
+ self.output(f"[DEBUG] {text}\n", 'debug')
292
+
293
+ def error(self, text: str) -> None:
294
+ """Error output."""
295
+ self.output(f"[ERROR] {text}\n", 'error')
296
+
297
+ def warn(self, text: str) -> None:
298
+ """Warning output."""
299
+ self.output(f"[WARN] {text}\n", 'warning')
300
+
281
301
  def _setup_modules(self):
282
302
  """Setup module references for @KernelClient, @VSRAM, etc."""
283
303
  if self.service_engine:
@@ -1310,29 +1330,38 @@ class CSSLRuntime:
1310
1330
  def _exec_instance_declaration(self, node: ASTNode) -> Any:
1311
1331
  """Execute instance declaration: instance<"name"> varName;
1312
1332
 
1313
- Gets or creates a shared instance by name.
1333
+ Gets or creates a universal shared instance by name.
1334
+ Universal instances are accessible from CSSL, Python, and C++.
1335
+
1336
+ Usage:
1337
+ instance<"myContainer"> container; // Creates or gets instance
1338
+ container.member = "value"; // Set member
1339
+ container +<<== { void func() {} } // Inject methods
1314
1340
  """
1315
- from ..cssl_bridge import _live_objects, SharedObjectProxy
1341
+ from .cssl_types import UniversalInstance
1342
+
1316
1343
  decl = node.value
1317
1344
  instance_name = decl.get('instance_name')
1318
1345
  var_name = decl.get('name')
1319
1346
  value_node = decl.get('value')
1320
1347
 
1321
- # Get existing shared instance
1322
- instance = None
1323
- if instance_name in _live_objects:
1324
- instance = SharedObjectProxy(instance_name, _live_objects[instance_name])
1325
- elif self.global_scope.has(f'${instance_name}'):
1326
- instance = self.global_scope.get(f'${instance_name}')
1348
+ # Get existing or create new universal instance
1349
+ instance = UniversalInstance.get_or_create(instance_name)
1327
1350
 
1328
- # If value is provided, use that and register as shared
1351
+ # If value is provided, set it as initial content
1329
1352
  if value_node:
1330
- instance = self._evaluate(value_node)
1331
- # Register in global scope for future access
1332
- self.global_scope.set(f'${instance_name}', instance)
1353
+ initial_value = self._evaluate(value_node)
1354
+ # If it's a dict, set all keys as members
1355
+ if isinstance(initial_value, dict):
1356
+ for key, val in initial_value.items():
1357
+ instance.set_member(key, val)
1358
+ else:
1359
+ instance.set_member('value', initial_value)
1333
1360
 
1334
- # Store in scope
1361
+ # Store in scope and global scope for access
1335
1362
  self.scope.set(var_name, instance)
1363
+ self.global_scope.set(f'${instance_name}', instance)
1364
+
1336
1365
  return instance
1337
1366
 
1338
1367
  def _exec_super_func(self, node: ASTNode) -> Any:
@@ -2520,24 +2549,60 @@ class CSSLRuntime:
2520
2549
  if filter_info:
2521
2550
  source = self._apply_injection_filter(source, filter_info)
2522
2551
 
2523
- # Get current target value for add/move modes
2552
+ # Get current target value for add/move/replace modes (needed for UniversalInstance handling)
2524
2553
  current_value = None
2525
- if mode in ('add', 'move'):
2526
- try:
2527
- current_value = self._evaluate(target)
2528
- except Exception:
2529
- # Target might not exist yet, that's okay for add mode
2530
- current_value = None
2554
+ try:
2555
+ current_value = self._evaluate(target)
2556
+ except Exception:
2557
+ # Target might not exist yet, that's okay for add mode
2558
+ current_value = None
2531
2559
 
2532
2560
  # Determine final value based on mode
2533
2561
  if mode == 'replace':
2534
- final_value = source
2562
+ from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
2563
+ # Special handling for UniversalInstance targets - inject instead of replace
2564
+ if isinstance(current_value, UniversalInstance):
2565
+ if isinstance(source, CSSLClass):
2566
+ current_value.set_member(source.name, source)
2567
+ final_value = current_value
2568
+ elif isinstance(source, ASTNode) and source.type == 'function':
2569
+ func_info = source.value
2570
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
2571
+ if func_name:
2572
+ current_value.set_method(func_name, source, self)
2573
+ final_value = current_value
2574
+ elif isinstance(source, CSSLInstance):
2575
+ current_value.set_member(source._class.name, source)
2576
+ final_value = current_value
2577
+ else:
2578
+ # For other types, store as member with source type name
2579
+ final_value = source
2580
+ else:
2581
+ final_value = source
2535
2582
  elif mode == 'add':
2536
2583
  # Copy & add - preserve target and add source
2537
- from .cssl_types import CSSLInstance
2584
+ from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
2538
2585
 
2586
+ # Special handling for UniversalInstance + CSSLClass
2587
+ if isinstance(current_value, UniversalInstance) and isinstance(source, CSSLClass):
2588
+ # Inject class definition into universal instance
2589
+ current_value.set_member(source.name, source)
2590
+ final_value = current_value
2591
+ # Special handling for UniversalInstance + Function (AST node)
2592
+ elif isinstance(current_value, UniversalInstance) and isinstance(source, ASTNode) and source.type == 'function':
2593
+ # Inject function as a method into universal instance
2594
+ func_info = source.value
2595
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
2596
+ if func_name:
2597
+ current_value.set_method(func_name, source, self)
2598
+ final_value = current_value
2599
+ # Special handling for UniversalInstance + CSSLInstance
2600
+ elif isinstance(current_value, UniversalInstance) and isinstance(source, CSSLInstance):
2601
+ class_name = source._class.name
2602
+ current_value.set_member(class_name, source)
2603
+ final_value = current_value
2539
2604
  # Special handling for CSSLInstance - merge classes
2540
- if isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
2605
+ elif isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
2541
2606
  # Add the new class instance as a member with class name as key
2542
2607
  class_name = source._class.name
2543
2608
  current_value._members[class_name] = source
@@ -2736,8 +2801,13 @@ class CSSLRuntime:
2736
2801
  - add: func +<<== { code } - ADDS code to function (both execute)
2737
2802
  - remove: func -<<== { code } - REMOVES matching code from function
2738
2803
 
2804
+ Also supports instance injection:
2805
+ - instance +<<== { void method() { ... } } - ADDS methods to UniversalInstance
2806
+
2739
2807
  Also supports expression form: func <<== %exit() (wraps in action_block)
2740
2808
  """
2809
+ from .cssl_types import UniversalInstance
2810
+
2741
2811
  target = node.value.get('target')
2742
2812
  code_block = node.value.get('code')
2743
2813
  source_expr = node.value.get('source') # For expression form: func <<== expr
@@ -2749,6 +2819,17 @@ class CSSLRuntime:
2749
2819
  expr_node = ASTNode('expression', value=source_expr)
2750
2820
  code_block = ASTNode('action_block', children=[expr_node])
2751
2821
 
2822
+ # Check if target is a UniversalInstance
2823
+ target_value = None
2824
+ if isinstance(target, ASTNode) and target.type == 'identifier':
2825
+ target_value = self.scope.get(target.value)
2826
+ if target_value is None:
2827
+ target_value = self.global_scope.get(target.value)
2828
+
2829
+ # Handle UniversalInstance injection
2830
+ if isinstance(target_value, UniversalInstance):
2831
+ return self._inject_into_instance(target_value, code_block, mode)
2832
+
2752
2833
  # Get function name from target
2753
2834
  func_name = None
2754
2835
  if isinstance(target, ASTNode):
@@ -2796,6 +2877,60 @@ class CSSLRuntime:
2796
2877
 
2797
2878
  return None
2798
2879
 
2880
+ def _inject_into_instance(self, instance: Any, code_block: Any, mode: str) -> Any:
2881
+ """Inject code/methods into a UniversalInstance.
2882
+
2883
+ Usage:
2884
+ instance<"myContainer"> container;
2885
+ container +<<== {
2886
+ void sayHello() { printl("Hello!"); }
2887
+ int value = 42;
2888
+ }
2889
+ """
2890
+ from .cssl_types import UniversalInstance
2891
+
2892
+ if not isinstance(instance, UniversalInstance):
2893
+ return None
2894
+
2895
+ if code_block is None:
2896
+ return None
2897
+
2898
+ # Store the raw injection
2899
+ instance.add_injection(code_block)
2900
+
2901
+ # Parse the code block for function definitions and variable declarations
2902
+ if isinstance(code_block, ASTNode):
2903
+ children = code_block.children if hasattr(code_block, 'children') else []
2904
+
2905
+ for child in children:
2906
+ if isinstance(child, ASTNode):
2907
+ if child.type == 'function':
2908
+ # Extract function name and store the AST node
2909
+ func_info = child.value
2910
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
2911
+ if func_name:
2912
+ instance.set_method(func_name, child, self)
2913
+ elif child.type == 'var_declaration':
2914
+ # Extract variable and value
2915
+ var_info = child.value
2916
+ if isinstance(var_info, dict):
2917
+ var_name = var_info.get('name')
2918
+ value_node = var_info.get('value')
2919
+ if var_name:
2920
+ value = self._evaluate(value_node) if value_node else None
2921
+ instance.set_member(var_name, value)
2922
+ elif child.type == 'typed_var_declaration':
2923
+ # Typed variable declaration
2924
+ var_info = child.value
2925
+ if isinstance(var_info, dict):
2926
+ var_name = var_info.get('name')
2927
+ value_node = var_info.get('value')
2928
+ if var_name:
2929
+ value = self._evaluate(value_node) if value_node else None
2930
+ instance.set_member(var_name, value)
2931
+
2932
+ return instance
2933
+
2799
2934
  def _exec_infuse_right(self, node: ASTNode) -> Any:
2800
2935
  """Execute right-side code infusion (==>>)"""
2801
2936
  source = node.value.get('source')
@@ -3115,6 +3250,45 @@ class CSSLRuntime:
3115
3250
  # Return None if instance doesn't exist (can be created via ==>)
3116
3251
  return None
3117
3252
 
3253
+ # v4.1.0: Cross-language instance reference: cpp$ClassName, py$Object
3254
+ if node.type == 'lang_instance_ref':
3255
+ ref = node.value # {'lang': 'cpp', 'instance': 'ClassName'}
3256
+ lang_id = ref['lang']
3257
+ instance_name = ref['instance']
3258
+
3259
+ # First, try to get the language support object from scope
3260
+ lang_support = self.scope.get(lang_id)
3261
+ if lang_support is None:
3262
+ lang_support = self.global_scope.get(lang_id)
3263
+
3264
+ # If not found in scope, try to get from modules
3265
+ if lang_support is None:
3266
+ lang_support = self._modules.get(lang_id)
3267
+
3268
+ # If still not found, try getting default language support
3269
+ if lang_support is None:
3270
+ from .cssl_languages import get_language
3271
+ lang_support = get_language(lang_id)
3272
+
3273
+ if lang_support is not None:
3274
+ # Check if it's a LanguageSupport object with get_instance method
3275
+ if hasattr(lang_support, 'get_instance'):
3276
+ instance = lang_support.get_instance(instance_name)
3277
+ if instance is not None:
3278
+ return instance
3279
+ # Check _instances dict directly
3280
+ if hasattr(lang_support, '_instances'):
3281
+ if instance_name in lang_support._instances:
3282
+ return lang_support._instances[instance_name]
3283
+
3284
+ # Build helpful error message
3285
+ hint = f"Use '{lang_id}.share(\"{instance_name}\", instance)' to register the instance first."
3286
+ raise self._format_error(
3287
+ node.line if hasattr(node, 'line') else 0,
3288
+ f"Cross-language instance '{lang_id}${instance_name}' not found",
3289
+ hint
3290
+ )
3291
+
3118
3292
  if node.type == 'new':
3119
3293
  # Create new instance of a class: new ClassName(args)
3120
3294
  return self._eval_new(node)
@@ -3188,6 +3362,14 @@ class CSSLRuntime:
3188
3362
  if node.type == 'unary':
3189
3363
  return self._eval_unary(node)
3190
3364
 
3365
+ # Increment: ++i or i++
3366
+ if node.type == 'increment':
3367
+ return self._eval_increment(node)
3368
+
3369
+ # Decrement: --i or i--
3370
+ if node.type == 'decrement':
3371
+ return self._eval_decrement(node)
3372
+
3191
3373
  if node.type == 'non_null_assert':
3192
3374
  # *$var, *@module, *identifier - assert value is not null/None
3193
3375
  operand = node.value.get('operand')
@@ -3473,6 +3655,74 @@ class CSSLRuntime:
3473
3655
 
3474
3656
  return None
3475
3657
 
3658
+ def _eval_increment(self, node: ASTNode) -> Any:
3659
+ """Evaluate increment operation (++i or i++)"""
3660
+ op_type = node.value.get('op') # 'prefix' or 'postfix'
3661
+ operand = node.value.get('operand')
3662
+
3663
+ # Get variable name
3664
+ var_name = None
3665
+ if isinstance(operand, ASTNode):
3666
+ if operand.type == 'identifier':
3667
+ var_name = operand.value
3668
+ elif operand.type == 'shared_ref':
3669
+ # Handle $var++
3670
+ var_name = operand.value
3671
+ current = self.shared_vars.get(var_name, 0)
3672
+ if op_type == 'prefix':
3673
+ self.shared_vars[var_name] = current + 1
3674
+ return current + 1
3675
+ else: # postfix
3676
+ self.shared_vars[var_name] = current + 1
3677
+ return current
3678
+
3679
+ if var_name:
3680
+ current = self.scope.get(var_name, 0)
3681
+ if op_type == 'prefix':
3682
+ # ++i: increment then return
3683
+ self.scope.set(var_name, current + 1)
3684
+ return current + 1
3685
+ else:
3686
+ # i++: return then increment
3687
+ self.scope.set(var_name, current + 1)
3688
+ return current
3689
+
3690
+ return None
3691
+
3692
+ def _eval_decrement(self, node: ASTNode) -> Any:
3693
+ """Evaluate decrement operation (--i or i--)"""
3694
+ op_type = node.value.get('op') # 'prefix' or 'postfix'
3695
+ operand = node.value.get('operand')
3696
+
3697
+ # Get variable name
3698
+ var_name = None
3699
+ if isinstance(operand, ASTNode):
3700
+ if operand.type == 'identifier':
3701
+ var_name = operand.value
3702
+ elif operand.type == 'shared_ref':
3703
+ # Handle $var--
3704
+ var_name = operand.value
3705
+ current = self.shared_vars.get(var_name, 0)
3706
+ if op_type == 'prefix':
3707
+ self.shared_vars[var_name] = current - 1
3708
+ return current - 1
3709
+ else: # postfix
3710
+ self.shared_vars[var_name] = current - 1
3711
+ return current
3712
+
3713
+ if var_name:
3714
+ current = self.scope.get(var_name, 0)
3715
+ if op_type == 'prefix':
3716
+ # --i: decrement then return
3717
+ self.scope.set(var_name, current - 1)
3718
+ return current - 1
3719
+ else:
3720
+ # i--: return then decrement
3721
+ self.scope.set(var_name, current - 1)
3722
+ return current
3723
+
3724
+ return None
3725
+
3476
3726
  def _eval_call(self, node: ASTNode) -> Any:
3477
3727
  """Evaluate function call with optional named arguments"""
3478
3728
  callee_node = node.value.get('callee')
@@ -3516,7 +3766,33 @@ class CSSLRuntime:
3516
3766
  if isinstance(callee, ASTNode) and callee.type == 'function':
3517
3767
  return self._call_function(callee, args, kwargs)
3518
3768
 
3519
- callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
3769
+ # Extract callee name for error messages
3770
+ if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value'):
3771
+ val = callee_node.value
3772
+ if isinstance(val, str):
3773
+ callee_name = val
3774
+ elif isinstance(val, dict):
3775
+ # For member access nodes like obj.method, get the member name
3776
+ if 'member' in val:
3777
+ obj_node = val.get('object')
3778
+ member = val.get('member')
3779
+ obj_name = obj_node.value if isinstance(obj_node, ASTNode) else str(obj_node)
3780
+ callee_name = f"{obj_name}.{member}"
3781
+ # For call nodes, try to get the callee name
3782
+ elif 'callee' in val:
3783
+ callee_val = val.get('callee')
3784
+ if isinstance(callee_val, ASTNode):
3785
+ callee_name = callee_val.value if isinstance(callee_val.value, str) else str(callee_val.value)
3786
+ else:
3787
+ callee_name = str(callee_val)
3788
+ elif 'name' in val:
3789
+ callee_name = str(val.get('name'))
3790
+ else:
3791
+ callee_name = str(val)
3792
+ else:
3793
+ callee_name = str(val)
3794
+ else:
3795
+ callee_name = str(callee_node)
3520
3796
 
3521
3797
  # Build detailed error with suggestions
3522
3798
  available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
@@ -3658,6 +3934,22 @@ class CSSLRuntime:
3658
3934
  hint
3659
3935
  )
3660
3936
 
3937
+ # If we got a variable that holds a class reference, use that class
3938
+ if not isinstance(class_def, CSSLClass):
3939
+ # Check if it's a variable holding a class (dynamic class instantiation)
3940
+ if hasattr(class_def, '__class__') and isinstance(class_def, CSSLClass):
3941
+ pass # Already a CSSLClass, continue
3942
+ elif isinstance(class_def, dict) and 'class_def' in class_def:
3943
+ # Injected class reference from +<== operator
3944
+ class_def = class_def['class_def']
3945
+ else:
3946
+ # Not a class - show error
3947
+ raise CSSLRuntimeError(
3948
+ f"'{class_name}' is not a class",
3949
+ node.line,
3950
+ hint=f"'{class_name}' is of type {type(class_def).__name__}"
3951
+ )
3952
+
3661
3953
  if not isinstance(class_def, CSSLClass):
3662
3954
  raise CSSLRuntimeError(
3663
3955
  f"'{class_name}' is not a class",
@@ -4112,6 +4404,48 @@ class CSSLRuntime:
4112
4404
  hint
4113
4405
  )
4114
4406
 
4407
+ # === UNIVERSAL INSTANCE METHODS ===
4408
+ from .cssl_types import UniversalInstance
4409
+ if isinstance(obj, UniversalInstance):
4410
+ # Check for member variable
4411
+ if obj.has_member(member):
4412
+ return obj.get_member(member)
4413
+ # Check for method
4414
+ if obj.has_method(member):
4415
+ method_node = obj.get_method(member)
4416
+ # Create a callable that executes the method in context
4417
+ def instance_method_caller(*args, **kwargs):
4418
+ # Set 'this' to refer to the instance
4419
+ old_this = self.scope.get('this')
4420
+ self.scope.set('this', obj)
4421
+ try:
4422
+ return self._call_function(method_node, list(args))
4423
+ finally:
4424
+ if old_this is not None:
4425
+ self.scope.set('this', old_this)
4426
+ else:
4427
+ self.scope.remove('this') if hasattr(self.scope, 'remove') else None
4428
+ return instance_method_caller
4429
+ # Build helpful error with available members
4430
+ instance_name = obj.name
4431
+ available_members = list(obj.get_all_members().keys())
4432
+ available_methods = list(obj.get_all_methods().keys())
4433
+ all_available = available_members + available_methods
4434
+ similar = _find_similar_names(member, all_available)
4435
+
4436
+ if similar:
4437
+ hint = f"Did you mean: {', '.join(similar)}?"
4438
+ elif all_available:
4439
+ hint = f"Available: {', '.join(all_available[:5])}"
4440
+ else:
4441
+ hint = f"Instance '{instance_name}' has no accessible members."
4442
+
4443
+ raise self._format_error(
4444
+ node.line,
4445
+ f"Instance '{instance_name}' has no member or method '{member}'",
4446
+ hint
4447
+ )
4448
+
4115
4449
  # === STRING METHODS ===
4116
4450
  if isinstance(obj, str):
4117
4451
  string_methods = self._get_string_method(obj, member)
@@ -4350,6 +4684,12 @@ class CSSLRuntime:
4350
4684
  obj.set_member(member, value)
4351
4685
  return
4352
4686
 
4687
+ # Check for UniversalInstance - use set_member method
4688
+ from .cssl_types import UniversalInstance
4689
+ if isinstance(obj, UniversalInstance):
4690
+ obj.set_member(member, value)
4691
+ return
4692
+
4353
4693
  # Check for SharedObjectProxy - directly access underlying object
4354
4694
  # This is more robust than relying on the proxy's __setattr__
4355
4695
  if hasattr(obj, '_direct_object') and hasattr(obj, '_name'):
@@ -31,6 +31,11 @@ class TokenCategory(Enum):
31
31
  NULL = auto() # null, None
32
32
  PACKAGE_KW = auto() # package, package-includes - NEW
33
33
  TYPE_LITERAL = auto() # list, dict - NEW
34
+ # v4.1.0: Multi-language support
35
+ SUPPORTS_KW = auto() # supports keyword (magenta)
36
+ LIBINCLUDE_KW = auto() # libinclude (yellow/gold)
37
+ LANG_PREFIX = auto() # Language prefix before $ (cyan): cpp$, py$, java$
38
+ LANG_INSTANCE = auto() # Instance name after $ (orange): cpp$ClassName
34
39
 
35
40
 
36
41
  @dataclass
@@ -52,9 +57,17 @@ KEYWORDS = {
52
57
  'start', 'stop', 'wait_for', 'on_event', 'emit_event',
53
58
  'await',
54
59
  # NEW: Extended keywords
55
- 'package', 'package-includes', 'exec', 'as', 'global'
60
+ 'package', 'package-includes', 'exec', 'as', 'global',
61
+ # v4.1.0: Multi-language support (handled separately for special colors)
62
+ # 'supports', 'libinclude' - see MULTI_LANG_KEYWORDS
56
63
  }
57
64
 
65
+ # v4.1.0: Multi-language keywords with special highlighting
66
+ MULTI_LANG_KEYWORDS = {'supports', 'libinclude'}
67
+
68
+ # v4.1.0: Language identifiers for cross-language instance access
69
+ LANGUAGE_IDS = {'cpp', 'py', 'python', 'java', 'csharp', 'js', 'javascript'}
70
+
58
71
  # NEW: Package-related keywords for special highlighting
59
72
  PACKAGE_KEYWORDS = {'package', 'package-includes'}
60
73
 
@@ -145,6 +158,33 @@ class CSSLSyntaxRules:
145
158
  category=TokenCategory.TYPE_LITERAL
146
159
  ))
147
160
 
161
+ # v4.1.0: Multi-language support keywords
162
+ # 'supports' keyword (magenta) - must be before regular keywords
163
+ rules.append(HighlightRule(
164
+ pattern=r'\bsupports\b',
165
+ category=TokenCategory.SUPPORTS_KW
166
+ ))
167
+
168
+ # 'libinclude' keyword (yellow/gold)
169
+ rules.append(HighlightRule(
170
+ pattern=r'\blibinclude\b',
171
+ category=TokenCategory.LIBINCLUDE_KW
172
+ ))
173
+
174
+ # v4.1.0: Language$Instance patterns (cpp$ClassName, py$Object)
175
+ # Match language prefix before $ (cyan)
176
+ rules.append(HighlightRule(
177
+ pattern=r'\b(cpp|py|python|java|csharp|js|javascript)\$',
178
+ category=TokenCategory.LANG_PREFIX,
179
+ group=1
180
+ ))
181
+ # Match instance name after $ (orange)
182
+ rules.append(HighlightRule(
183
+ pattern=r'\b(?:cpp|py|python|java|csharp|js|javascript)\$([A-Za-z_][A-Za-z0-9_]*)',
184
+ category=TokenCategory.LANG_INSTANCE,
185
+ group=1
186
+ ))
187
+
148
188
  # Self-references (s@Name, s@Backend.Loop)
149
189
  rules.append(HighlightRule(
150
190
  pattern=r's@[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*',
@@ -233,6 +273,11 @@ class ColorScheme:
233
273
  TokenCategory.NULL: '#ff6464', # Red
234
274
  TokenCategory.PACKAGE_KW: '#bd93f9', # Purple for package - NEW
235
275
  TokenCategory.TYPE_LITERAL: '#8be9fd', # Cyan for type literals - NEW
276
+ # v4.1.0: Multi-language support colors
277
+ TokenCategory.SUPPORTS_KW: '#ff79c6', # Magenta/Pink for 'supports'
278
+ TokenCategory.LIBINCLUDE_KW: '#f1fa8c',# Yellow/Gold for 'libinclude'
279
+ TokenCategory.LANG_PREFIX: '#8be9fd', # Cyan for language prefix (cpp$)
280
+ TokenCategory.LANG_INSTANCE: '#ffb86c',# Orange for instance name ($ClassName)
236
281
  }
237
282
 
238
283
  # Light theme variant
@@ -252,6 +297,11 @@ class ColorScheme:
252
297
  TokenCategory.NULL: '#ff0000', # Red
253
298
  TokenCategory.PACKAGE_KW: '#8b008b', # DarkMagenta for package - NEW
254
299
  TokenCategory.TYPE_LITERAL: '#008b8b', # Dark cyan for type literals - NEW
300
+ # v4.1.0: Multi-language support colors
301
+ TokenCategory.SUPPORTS_KW: '#d63384', # Dark Magenta for 'supports'
302
+ TokenCategory.LIBINCLUDE_KW: '#b8860b',# DarkGoldenrod for 'libinclude'
303
+ TokenCategory.LANG_PREFIX: '#0d6efd', # Blue for language prefix (cpp$)
304
+ TokenCategory.LANG_INSTANCE: '#fd7e14',# Orange for instance name ($ClassName)
255
305
  }
256
306
 
257
307
 
@@ -334,6 +384,11 @@ def highlight_cssl_ansi(source: str) -> str:
334
384
  TokenCategory.NULL: '\033[91m', # Red
335
385
  TokenCategory.PACKAGE_KW: '\033[95m', # Magenta for package - NEW
336
386
  TokenCategory.TYPE_LITERAL: '\033[96m', # Cyan for type literals - NEW
387
+ # v4.1.0: Multi-language support colors
388
+ TokenCategory.SUPPORTS_KW: '\033[95m', # Magenta for 'supports'
389
+ TokenCategory.LIBINCLUDE_KW: '\033[93m',# Yellow for 'libinclude'
390
+ TokenCategory.LANG_PREFIX: '\033[96m', # Cyan for language prefix (cpp$)
391
+ TokenCategory.LANG_INSTANCE: '\033[33m',# Orange/Yellow for instance name
337
392
  }
338
393
  RESET = '\033[0m'
339
394
 
@@ -439,6 +494,10 @@ def export_textmate_grammar() -> dict:
439
494
  "name": "comment.line.cssl",
440
495
  "match": "#.*$"
441
496
  },
497
+ {
498
+ "name": "comment.line.double-slash.cssl",
499
+ "match": "//.*$"
500
+ },
442
501
  {
443
502
  "name": "string.quoted.double.cssl",
444
503
  "match": '"(?:[^"\\\\]|\\\\.)*"'
@@ -447,6 +506,23 @@ def export_textmate_grammar() -> dict:
447
506
  "name": "string.quoted.single.cssl",
448
507
  "match": "'(?:[^'\\\\]|\\\\.)*'"
449
508
  },
509
+ # v4.1.0: Multi-language support
510
+ {
511
+ "name": "keyword.control.supports.cssl",
512
+ "match": "\\bsupports\\b"
513
+ },
514
+ {
515
+ "name": "support.function.libinclude.cssl",
516
+ "match": "\\blibinclude\\b"
517
+ },
518
+ {
519
+ "name": "variable.language.lang-instance.cssl",
520
+ "match": "\\b(cpp|py|python|java|csharp|js|javascript)\\$([A-Za-z_][A-Za-z0-9_]*)",
521
+ "captures": {
522
+ "1": {"name": "entity.name.type.language.cssl"},
523
+ "2": {"name": "variable.other.instance.cssl"}
524
+ }
525
+ },
450
526
  {
451
527
  "name": "variable.other.self-reference.cssl",
452
528
  "match": "s@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
@@ -455,9 +531,13 @@ def export_textmate_grammar() -> dict:
455
531
  "name": "variable.other.module-reference.cssl",
456
532
  "match": "@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
457
533
  },
534
+ {
535
+ "name": "keyword.other.package.cssl",
536
+ "match": "\\b(package|package-includes)\\b"
537
+ },
458
538
  {
459
539
  "name": "keyword.control.cssl",
460
- "match": "\\b(service-init|service-run|service-include|struct|define|if|else|elif|while|for|foreach|in|switch|case|default|break|continue|return|try|catch|await)\\b"
540
+ "match": "\\b(service-init|service-run|service-include|struct|define|class|constr|if|else|elif|while|for|foreach|in|switch|case|default|break|continue|return|try|catch|finally|throw|await|extends|overwrites|global|as|exec)\\b"
461
541
  },
462
542
  {
463
543
  "name": "keyword.operator.cssl",
@@ -465,7 +545,7 @@ def export_textmate_grammar() -> dict:
465
545
  },
466
546
  {
467
547
  "name": "constant.language.cssl",
468
- "match": "\\b(True|False|true|false|null|None)\\b"
548
+ "match": "\\b(True|False|true|false|null|None|none)\\b"
469
549
  },
470
550
  {
471
551
  "name": "constant.numeric.cssl",
@@ -473,7 +553,11 @@ def export_textmate_grammar() -> dict:
473
553
  },
474
554
  {
475
555
  "name": "keyword.operator.assignment.cssl",
476
- "match": "<==|==>|->|<-"
556
+ "match": "<==|==>|->|<-|::"
557
+ },
558
+ {
559
+ "name": "support.type.cssl",
560
+ "match": "\\b(list|dict)\\b(?!\\s*\\()"
477
561
  }
478
562
  ]
479
563
  }