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.
@@ -15,7 +15,7 @@ from .cssl_modules import get_module_registry, get_standard_module
15
15
  from .cssl_types import (
16
16
  Parameter, DataStruct, Shuffled, Iterator, Combo,
17
17
  Stack, Vector, Array, DataSpace, OpenQuote, List, Dictionary, Map,
18
- CSSLClass, CSSLInstance
18
+ CSSLClass, CSSLInstance, ByteArrayed
19
19
  )
20
20
 
21
21
 
@@ -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:
@@ -512,6 +532,10 @@ class CSSLRuntime:
512
532
  self._exec_struct(child)
513
533
  elif child.type == 'class':
514
534
  self._exec_class(child)
535
+ elif child.type == 'enum':
536
+ self._exec_enum(child)
537
+ elif child.type == 'bytearrayed':
538
+ self._exec_bytearrayed(child)
515
539
  elif child.type == 'function':
516
540
  self._exec_function(child)
517
541
  elif child.type == 'global_assignment':
@@ -793,6 +817,74 @@ class CSSLRuntime:
793
817
 
794
818
  return struct_data
795
819
 
820
+ def _exec_enum(self, node: ASTNode) -> Dict[str, Any]:
821
+ """Execute enum declaration - registers enum values in scope.
822
+
823
+ Creates a dictionary-like enum object accessible via EnumName::VALUE syntax.
824
+
825
+ Example:
826
+ enum Colors { RED, GREEN, BLUE }
827
+ Colors::RED // returns 0
828
+ Colors::GREEN // returns 1
829
+ """
830
+ enum_info = node.value
831
+ enum_name = enum_info.get('name')
832
+ members = enum_info.get('members', [])
833
+
834
+ # Create enum object as a dict-like object with members
835
+ enum_obj = {}
836
+ for member in members:
837
+ member_name = member['name']
838
+ member_value = member['value']
839
+ enum_obj[member_name] = member_value
840
+
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)
844
+
845
+ return enum_obj
846
+
847
+ def _exec_bytearrayed(self, node: ASTNode) -> 'ByteArrayed':
848
+ """Execute bytearrayed declaration - function-to-byte mapping with pattern matching.
849
+
850
+ Creates a ByteArrayed object that:
851
+ - Maps function references to byte positions (0x0, 0x1, etc.)
852
+ - Executes functions "invisibly" when called to get return values
853
+ - Matches case patterns based on return values
854
+ - Supports indexing: MyBytes["0x0"] or MyBytes[0]
855
+
856
+ Example:
857
+ bytearrayed MyBytes {
858
+ &func1; // 0x0
859
+ &func2; // 0x1
860
+ case {0, 1} { // func1=0, func2=1
861
+ printl("Match!");
862
+ }
863
+ }
864
+ MyBytes(); // Execute pattern matching
865
+ x = MyBytes["0x0"]; // Get value at position 0
866
+ """
867
+ info = node.value
868
+ name = info.get('name')
869
+ func_refs = info.get('func_refs', [])
870
+ cases = info.get('cases', [])
871
+ default_block = info.get('default')
872
+
873
+ # Create ByteArrayed object
874
+ bytearrayed_obj = ByteArrayed(
875
+ name=name,
876
+ func_refs=func_refs,
877
+ cases=cases,
878
+ default_block=default_block,
879
+ runtime=self
880
+ )
881
+
882
+ # Register in scope
883
+ self.scope.set(name, bytearrayed_obj)
884
+ self.global_scope.set(name, bytearrayed_obj)
885
+
886
+ return bytearrayed_obj
887
+
796
888
  def _exec_class(self, node: ASTNode) -> CSSLClass:
797
889
  """Execute class definition - registers class in scope.
798
890
 
@@ -863,6 +955,18 @@ class CSSLRuntime:
863
955
  class_params = class_info.get('class_params', [])
864
956
  extends_args = class_info.get('extends_args', [])
865
957
 
958
+ # v4.2.0: Handle 'supports' language transformation for raw_body
959
+ supports_language = class_info.get('supports_language')
960
+ raw_body = class_info.get('raw_body')
961
+
962
+ if raw_body and supports_language:
963
+ # Transform raw body from target language to CSSL and parse
964
+ transformed_children = self._transform_and_parse_class_body(
965
+ raw_body, supports_language, class_name
966
+ )
967
+ # Add transformed children to node's children
968
+ node.children = transformed_children
969
+
866
970
  for child in node.children:
867
971
  if child.type == 'constructor':
868
972
  # New-style constructor from 'constr' keyword
@@ -910,6 +1014,22 @@ class CSSLRuntime:
910
1014
  self.global_scope.set(class_name, class_def)
911
1015
  self._promoted_globals[class_name] = class_def
912
1016
 
1017
+ # v4.2.5: Handle &target replacement for classes
1018
+ # embedded class MyClass &$Target { } - immediate replacement
1019
+ # class MyClass &$Target { } - deferred until instantiation
1020
+ append_ref_class = class_info.get('append_ref_class')
1021
+ is_embedded = class_info.get('is_embedded', False)
1022
+ if append_ref_class and is_embedded:
1023
+ append_ref_member = class_info.get('append_ref_member')
1024
+ self._overwrite_class_target(append_ref_class, append_ref_member, class_def)
1025
+ class_def._target_applied = True
1026
+ elif append_ref_class:
1027
+ # Store reference info for deferred replacement
1028
+ class_def._pending_target = {
1029
+ 'append_ref_class': append_ref_class,
1030
+ 'append_ref_member': class_info.get('append_ref_member')
1031
+ }
1032
+
913
1033
  # Handle class overwrites - replace methods in target class
914
1034
  if overwrites_class_name:
915
1035
  self._apply_class_overwrites(
@@ -987,6 +1107,119 @@ class CSSLRuntime:
987
1107
  self._current_instance = old_instance
988
1108
  return wrapper
989
1109
 
1110
+ def _transform_and_parse_class_body(self, raw_body: str, language: str, class_name: str) -> list:
1111
+ """Transform source code from another language to CSSL and parse as class body.
1112
+
1113
+ v4.2.0: Used for 'supports <lang>' in class definitions.
1114
+
1115
+ Args:
1116
+ raw_body: Raw source code in the target language
1117
+ language: Language identifier (py, python, cpp, c++, js, javascript, etc.)
1118
+ class_name: Name of the class (for constructor recognition)
1119
+
1120
+ Returns:
1121
+ List of parsed AST nodes representing methods, constructors, and members
1122
+ """
1123
+ import textwrap
1124
+ from .cssl_languages import get_language
1125
+ from .cssl_parser import parse_cssl_program, ASTNode
1126
+
1127
+ # Normalize language ID
1128
+ lang_id = language.lstrip('@').lower()
1129
+
1130
+ # Get language support and transformer
1131
+ lang_support = get_language(lang_id)
1132
+ if lang_support is None:
1133
+ raise CSSLRuntimeError(f"Unknown language '{lang_id}' in 'supports' clause")
1134
+
1135
+ # Dedent the raw body to normalize indentation
1136
+ # This fixes the issue where code inside CSSL {} has relative indentation
1137
+ dedented_body = textwrap.dedent(raw_body)
1138
+
1139
+ # Transform the raw body to CSSL syntax
1140
+ transformer = lang_support.get_transformer()
1141
+ transformed_source = transformer.transform_source(dedented_body)
1142
+
1143
+ # Wrap in a dummy class for parsing
1144
+ wrapper_source = f"class _TempClass {{\n{transformed_source}\n}}"
1145
+
1146
+ try:
1147
+ ast = parse_cssl_program(wrapper_source)
1148
+ except Exception as e:
1149
+ raise CSSLRuntimeError(
1150
+ f"Failed to parse transformed '{lang_id}' code: {e}\n"
1151
+ f"Dedented:\n{dedented_body}\n"
1152
+ f"Transformed:\n{transformed_source}"
1153
+ )
1154
+
1155
+ # Extract children from the parsed temp class
1156
+ children = []
1157
+ for top_level in ast.children:
1158
+ if top_level.type == 'class':
1159
+ for child in top_level.children:
1160
+ # Mark constructor if method name matches class_name or is __init__
1161
+ if child.type == 'function':
1162
+ func_info = child.value
1163
+ method_name = func_info.get('name')
1164
+ if method_name == class_name or method_name == '__init__':
1165
+ child.value['is_constructor'] = True
1166
+ children.append(child)
1167
+ break
1168
+
1169
+ return children
1170
+
1171
+ def _transform_and_parse_function_body(self, raw_body: str, language: str) -> list:
1172
+ """Transform source code from another language to CSSL and parse as function body.
1173
+
1174
+ v4.2.0: Used for 'supports <lang>' in function definitions.
1175
+
1176
+ Args:
1177
+ raw_body: Raw source code in the target language
1178
+ language: Language identifier (py, python, cpp, c++, js, javascript, etc.)
1179
+
1180
+ Returns:
1181
+ List of parsed AST nodes representing statements in the function body
1182
+ """
1183
+ import textwrap
1184
+ from .cssl_languages import get_language
1185
+ from .cssl_parser import parse_cssl_program
1186
+
1187
+ # Normalize language ID
1188
+ lang_id = language.lstrip('@').lower()
1189
+
1190
+ # Get language support and transformer
1191
+ lang_support = get_language(lang_id)
1192
+ if lang_support is None:
1193
+ raise CSSLRuntimeError(f"Unknown language '{lang_id}' in 'supports' clause")
1194
+
1195
+ # Dedent the raw body to normalize indentation
1196
+ dedented_body = textwrap.dedent(raw_body)
1197
+
1198
+ # Transform the raw body to CSSL syntax
1199
+ transformer = lang_support.get_transformer()
1200
+ transformed_source = transformer.transform_source(dedented_body)
1201
+
1202
+ # Wrap in a dummy function for parsing
1203
+ wrapper_source = f"define _TempFunc() {{\n{transformed_source}\n}}"
1204
+
1205
+ try:
1206
+ ast = parse_cssl_program(wrapper_source)
1207
+ except Exception as e:
1208
+ raise CSSLRuntimeError(
1209
+ f"Failed to parse transformed '{lang_id}' code: {e}\n"
1210
+ f"Dedented:\n{dedented_body}\n"
1211
+ f"Transformed:\n{transformed_source}"
1212
+ )
1213
+
1214
+ # Extract children from the parsed temp function
1215
+ children = []
1216
+ for top_level in ast.children:
1217
+ if top_level.type == 'function':
1218
+ children = top_level.children
1219
+ break
1220
+
1221
+ return children
1222
+
990
1223
  def _exec_function(self, node: ASTNode) -> Any:
991
1224
  """Execute function definition - registers it and handles extends/overwrites.
992
1225
 
@@ -1019,13 +1252,18 @@ class CSSLRuntime:
1019
1252
  # Handle &Class::method syntax
1020
1253
  # Without ++ = full replacement
1021
1254
  # With ++ = append (run original first, then new code)
1022
- if append_ref_class:
1255
+ # v4.2.5: Only do immediate replacement if is_embedded=True
1256
+ # For regular 'define', replacement is deferred until function is called
1257
+ is_embedded = func_info.get('is_embedded', False)
1258
+ if append_ref_class and is_embedded:
1023
1259
  if append_mode:
1024
1260
  # Append mode: wrap original to run original + new
1025
1261
  self._append_to_target(append_ref_class, append_ref_member, node)
1026
1262
  else:
1027
1263
  # Full replacement
1028
1264
  self._overwrite_target(append_ref_class, append_ref_member, node)
1265
+ # Mark as already applied so we don't apply again on call
1266
+ node.value['_target_applied'] = True
1029
1267
 
1030
1268
  # Handle overwrites keyword - replace the target function
1031
1269
  if overwrites_func:
@@ -1070,6 +1308,34 @@ class CSSLRuntime:
1070
1308
  return self._call_function(func_node, list(args), kwargs)
1071
1309
  return wrapper
1072
1310
 
1311
+ def _create_python_method_wrapper(self, func_node: ASTNode, python_obj):
1312
+ """Create a Python-callable wrapper that passes python_obj as 'this'.
1313
+
1314
+ v4.3.0: Used when replacing Python object methods with CSSL functions.
1315
+ The wrapper ensures 'this->' in CSSL refers to the Python object.
1316
+ """
1317
+ runtime = self
1318
+ _captured_obj = python_obj
1319
+
1320
+ def wrapper(*args, **kwargs):
1321
+ # Save current instance context
1322
+ old_instance = runtime._current_instance
1323
+ old_this = runtime.scope.get('this')
1324
+ try:
1325
+ # Set Python object as current instance for this-> access
1326
+ runtime._current_instance = _captured_obj
1327
+ runtime.scope.set('this', _captured_obj)
1328
+ return runtime._call_function(func_node, list(args), kwargs)
1329
+ finally:
1330
+ # Restore previous context
1331
+ runtime._current_instance = old_instance
1332
+ if old_this is not None:
1333
+ runtime.scope.set('this', old_this)
1334
+ elif 'this' in runtime.scope.variables:
1335
+ del runtime.scope.variables['this']
1336
+
1337
+ return wrapper
1338
+
1073
1339
  def _overwrite_target(self, ref_class: str, ref_member: str, replacement_node: ASTNode):
1074
1340
  """Overwrite a class method or function with the replacement.
1075
1341
 
@@ -1077,9 +1343,25 @@ class CSSLRuntime:
1077
1343
  - &ClassName::method - Overwrite method in CSSL class
1078
1344
  - &$PyObject.method - Overwrite method in Python shared object
1079
1345
  - &functionName - Overwrite standalone function
1346
+
1347
+ v4.2.6: In namespace mode (_payload_namespace_mode), track replacements
1348
+ instead of applying globally. The namespace handler will scope them.
1080
1349
  """
1081
1350
  from ..cssl_bridge import _live_objects, SharedObjectProxy
1082
1351
 
1352
+ # v4.2.6: Check for namespace mode
1353
+ namespace_mode = getattr(self, '_payload_namespace_mode', None)
1354
+ if namespace_mode and ref_member is None and not ref_class.startswith('$'):
1355
+ # Standalone function replacement in namespace mode
1356
+ # Track it for the namespace handler
1357
+ if not hasattr(self, '_namespace_replacements'):
1358
+ self._namespace_replacements = {}
1359
+ self._namespace_replacements[ref_class] = replacement_node
1360
+ # Still register the function normally (namespace handler will move it)
1361
+ self.scope.set(ref_class, replacement_node)
1362
+ self.global_scope.set(ref_class, replacement_node)
1363
+ return
1364
+
1083
1365
  # Handle Python shared objects
1084
1366
  if ref_class.startswith('$'):
1085
1367
  var_name = ref_class[1:]
@@ -1096,7 +1378,8 @@ class CSSLRuntime:
1096
1378
 
1097
1379
  # Overwrite Python object method
1098
1380
  if ref_member and hasattr(ref_obj, ref_member):
1099
- wrapper = self._create_python_wrapper(replacement_node)
1381
+ # v4.3.0: Create wrapper that passes Python object as 'this' context
1382
+ wrapper = self._create_python_method_wrapper(replacement_node, ref_obj)
1100
1383
  try:
1101
1384
  setattr(ref_obj, ref_member, wrapper)
1102
1385
  except (AttributeError, TypeError):
@@ -1105,12 +1388,49 @@ class CSSLRuntime:
1105
1388
 
1106
1389
  # Handle CSSL class method overwrite
1107
1390
  target_class = self.scope.get(ref_class) or self.global_scope.get(ref_class)
1108
- if target_class is None:
1109
- # Maybe it's a standalone function reference (no ::member)
1110
- if ref_member is None:
1111
- # &functionName - overwrite the function
1391
+
1392
+ # v4.2.3: Handle standalone function reference (&functionName) including builtins
1393
+ if ref_member is None:
1394
+ # Check if this is a builtin function
1395
+ is_builtin = hasattr(self, 'builtins') and self.builtins.has_function(ref_class)
1396
+
1397
+ # Check if target_class is NOT a CSSLClass (it's either a function/builtin or None)
1398
+ is_cssl_class = isinstance(target_class, CSSLClass)
1399
+ # v4.2.5: Also check if target is a CSSL function (ASTNode with type 'function')
1400
+ is_cssl_function = (hasattr(target_class, 'type') and target_class.type == 'function')
1401
+
1402
+ if is_builtin or (target_class is None) or (not is_cssl_class and callable(target_class)) or is_cssl_function:
1403
+ # v4.2.3: CRITICAL - Store original BEFORE overwriting for %name captures
1404
+ # This ensures %exit() refers to the ORIGINAL exit, not the replacement
1405
+ if ref_class not in self._original_functions:
1406
+ if is_builtin:
1407
+ # Store the original builtin from _functions dict
1408
+ # (handles aliases like printl -> builtin_println)
1409
+ original_builtin = self.builtins._functions.get(ref_class)
1410
+ if original_builtin is not None:
1411
+ self._original_functions[ref_class] = original_builtin
1412
+ elif is_cssl_function:
1413
+ # v4.2.5: Store original CSSL function (ASTNode)
1414
+ self._original_functions[ref_class] = target_class
1415
+ elif target_class is not None and callable(target_class):
1416
+ # Store the original function/callable
1417
+ self._original_functions[ref_class] = target_class
1418
+
1419
+ # &functionName - overwrite the function/builtin
1112
1420
  self.scope.set(ref_class, replacement_node)
1113
1421
  self.global_scope.set(ref_class, replacement_node)
1422
+
1423
+ # Also overwrite in builtins dict if it's a builtin
1424
+ if is_builtin:
1425
+ # Create wrapper that calls CSSL function instead of builtin
1426
+ def make_wrapper(node, runtime):
1427
+ def wrapper(*args, **kwargs):
1428
+ return runtime._call_function(node, list(args), kwargs)
1429
+ return wrapper
1430
+ self.builtins._functions[ref_class] = make_wrapper(replacement_node, self)
1431
+ return
1432
+
1433
+ if target_class is None:
1114
1434
  return
1115
1435
 
1116
1436
  if isinstance(target_class, CSSLClass) and ref_member:
@@ -1152,16 +1472,22 @@ class CSSLRuntime:
1152
1472
  if ref_member and hasattr(ref_obj, ref_member):
1153
1473
  original_method = getattr(ref_obj, ref_member)
1154
1474
  runtime = self
1475
+ # Store the original method before wrapping
1476
+ _saved_original = original_method
1155
1477
  def appended_wrapper(*args, **kwargs):
1156
- # Run original first
1478
+ # Run original first (use saved reference to avoid recursion)
1157
1479
  result = None
1158
- if callable(original_method):
1480
+ if callable(_saved_original):
1159
1481
  try:
1160
- result = original_method(*args, **kwargs)
1482
+ result = _saved_original(*args, **kwargs)
1161
1483
  except:
1162
1484
  pass
1163
- # Then run appended code
1164
- return runtime._call_function(append_node, list(args), kwargs)
1485
+ # Then run appended code - disable append_mode to prevent recursion
1486
+ append_node.value['append_mode'] = False
1487
+ try:
1488
+ return runtime._call_function(append_node, list(args), kwargs)
1489
+ finally:
1490
+ append_node.value['append_mode'] = True
1165
1491
  try:
1166
1492
  setattr(ref_obj, ref_member, appended_wrapper)
1167
1493
  except (AttributeError, TypeError):
@@ -1206,6 +1532,58 @@ class CSSLRuntime:
1206
1532
  target_class.members[i] = append_node
1207
1533
  break
1208
1534
 
1535
+ def _overwrite_class_target(self, ref_class: str, ref_member: str, replacement_class: 'CSSLClass'):
1536
+ """Overwrite a target class with the replacement class.
1537
+
1538
+ v4.2.5: Used by 'embedded class' with &target syntax.
1539
+ Handles:
1540
+ - &ClassName - Overwrite CSSL class
1541
+ - &$PyObject - Overwrite Python shared object
1542
+
1543
+ v4.2.6: In namespace mode, track replacements instead of applying globally.
1544
+ """
1545
+ from ..cssl_bridge import _live_objects, SharedObjectProxy
1546
+
1547
+ # v4.2.6: Check for namespace mode
1548
+ namespace_mode = getattr(self, '_payload_namespace_mode', None)
1549
+ if namespace_mode and not ref_class.startswith('$') and not ref_class.startswith('@'):
1550
+ # Class replacement in namespace mode
1551
+ # Track it for the namespace handler
1552
+ if not hasattr(self, '_namespace_replacements'):
1553
+ self._namespace_replacements = {}
1554
+ self._namespace_replacements[ref_class] = replacement_class
1555
+ # Still register the class normally (namespace handler will move it)
1556
+ self.scope.set(ref_class, replacement_class)
1557
+ self.global_scope.set(ref_class, replacement_class)
1558
+ return
1559
+
1560
+ # Handle Python shared objects
1561
+ if ref_class.startswith('$'):
1562
+ var_name = ref_class[1:]
1563
+ # Replace the shared object with the new class
1564
+ _live_objects[var_name] = replacement_class
1565
+ self.scope.set(var_name, replacement_class)
1566
+ self.global_scope.set(var_name, replacement_class)
1567
+ return
1568
+
1569
+ # Handle @ prefix (global reference)
1570
+ if ref_class.startswith('@'):
1571
+ var_name = ref_class[1:]
1572
+ self.global_scope.set(var_name, replacement_class)
1573
+ self._promoted_globals[var_name] = replacement_class
1574
+ return
1575
+
1576
+ # Handle regular class reference
1577
+ target_class = self.scope.get(ref_class)
1578
+ if target_class is None:
1579
+ target_class = self.global_scope.get(ref_class)
1580
+
1581
+ # Replace the class definition
1582
+ self.scope.set(ref_class, replacement_class)
1583
+ self.global_scope.set(ref_class, replacement_class)
1584
+ if ref_class in self._promoted_globals:
1585
+ self._promoted_globals[ref_class] = replacement_class
1586
+
1209
1587
  def _exec_typed_declaration(self, node: ASTNode) -> Any:
1210
1588
  """Execute typed variable declaration: type<T> varName = value;
1211
1589
 
@@ -1310,29 +1688,38 @@ class CSSLRuntime:
1310
1688
  def _exec_instance_declaration(self, node: ASTNode) -> Any:
1311
1689
  """Execute instance declaration: instance<"name"> varName;
1312
1690
 
1313
- Gets or creates a shared instance by name.
1691
+ Gets or creates a universal shared instance by name.
1692
+ Universal instances are accessible from CSSL, Python, and C++.
1693
+
1694
+ Usage:
1695
+ instance<"myContainer"> container; // Creates or gets instance
1696
+ container.member = "value"; // Set member
1697
+ container +<<== { void func() {} } // Inject methods
1314
1698
  """
1315
- from ..cssl_bridge import _live_objects, SharedObjectProxy
1699
+ from .cssl_types import UniversalInstance
1700
+
1316
1701
  decl = node.value
1317
1702
  instance_name = decl.get('instance_name')
1318
1703
  var_name = decl.get('name')
1319
1704
  value_node = decl.get('value')
1320
1705
 
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}')
1706
+ # Get existing or create new universal instance
1707
+ instance = UniversalInstance.get_or_create(instance_name)
1327
1708
 
1328
- # If value is provided, use that and register as shared
1709
+ # If value is provided, set it as initial content
1329
1710
  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)
1711
+ initial_value = self._evaluate(value_node)
1712
+ # If it's a dict, set all keys as members
1713
+ if isinstance(initial_value, dict):
1714
+ for key, val in initial_value.items():
1715
+ instance.set_member(key, val)
1716
+ else:
1717
+ instance.set_member('value', initial_value)
1333
1718
 
1334
- # Store in scope
1719
+ # Store in scope and global scope for access
1335
1720
  self.scope.set(var_name, instance)
1721
+ self.global_scope.set(f'${instance_name}', instance)
1722
+
1336
1723
  return instance
1337
1724
 
1338
1725
  def _exec_super_func(self, node: ASTNode) -> Any:
@@ -1478,6 +1865,18 @@ class CSSLRuntime:
1478
1865
  modifiers = func_info.get('modifiers', [])
1479
1866
  kwargs = kwargs or {}
1480
1867
 
1868
+ # v4.2.5: Deferred &target replacement for non-embedded functions
1869
+ # If function has &target and hasn't been applied yet, apply now on first call
1870
+ append_ref_class = func_info.get('append_ref_class')
1871
+ if append_ref_class and not func_info.get('_target_applied', False):
1872
+ append_mode = func_info.get('append_mode', False)
1873
+ append_ref_member = func_info.get('append_ref_member')
1874
+ if append_mode:
1875
+ self._append_to_target(append_ref_class, append_ref_member, func_node)
1876
+ else:
1877
+ self._overwrite_target(append_ref_class, append_ref_member, func_node)
1878
+ func_node.value['_target_applied'] = True
1879
+
1481
1880
  # Check for undefined modifier - suppress errors if present
1482
1881
  is_undefined = 'undefined' in modifiers
1483
1882
 
@@ -1517,13 +1916,15 @@ class CSSLRuntime:
1517
1916
 
1518
1917
  # Bind parameters - handle both positional and named arguments
1519
1918
  for i, param in enumerate(params):
1520
- # Extract param name and type from dict format: {'name': 'a', 'type': 'int'}
1919
+ # Extract param name, type, and default from dict format: {'name': 'a', 'type': 'int', 'default': ...}
1521
1920
  if isinstance(param, dict):
1522
1921
  param_name = param['name']
1523
1922
  param_type = param.get('type', '')
1923
+ param_default = param.get('default') # v4.2.0: Default value AST node
1524
1924
  else:
1525
1925
  param_name = param
1526
1926
  param_type = ''
1927
+ param_default = None
1527
1928
 
1528
1929
  # Check if this is an 'open' parameter - receives all args as a list
1529
1930
  # The parser sets param['open'] = True for 'open' keyword
@@ -1546,6 +1947,10 @@ class CSSLRuntime:
1546
1947
  elif i < len(args):
1547
1948
  # Positional argument
1548
1949
  new_scope.set(param_name, args[i])
1950
+ elif param_default is not None:
1951
+ # v4.2.0: Use default value if no argument provided
1952
+ default_value = self._evaluate(param_default)
1953
+ new_scope.set(param_name, default_value)
1549
1954
  else:
1550
1955
  new_scope.set(param_name, None)
1551
1956
 
@@ -1565,11 +1970,24 @@ class CSSLRuntime:
1565
1970
  args, kwargs, {}, is_constructor=False
1566
1971
  )
1567
1972
 
1568
- for child in func_node.children:
1569
- # Check if exit() was called
1570
- if not self._running:
1571
- break
1572
- self._execute_node(child)
1973
+ # v4.2.0: Handle raw_body with supports_language (multi-language support)
1974
+ raw_body = func_info.get('raw_body')
1975
+ supports_language = func_info.get('supports_language')
1976
+
1977
+ if raw_body and supports_language:
1978
+ # Transform and parse the raw body from the target language
1979
+ body_children = self._transform_and_parse_function_body(raw_body, supports_language)
1980
+ for child in body_children:
1981
+ if not self._running:
1982
+ break
1983
+ self._execute_node(child)
1984
+ else:
1985
+ # Normal CSSL function body
1986
+ for child in func_node.children:
1987
+ # Check if exit() was called
1988
+ if not self._running:
1989
+ break
1990
+ self._execute_node(child)
1573
1991
  except CSSLReturn as ret:
1574
1992
  return_value = ret.value
1575
1993
 
@@ -1833,6 +2251,101 @@ class CSSLRuntime:
1833
2251
 
1834
2252
  return None
1835
2253
 
2254
+ def _exec_param_switch(self, node: ASTNode) -> Any:
2255
+ """Execute param switch statement for open parameters.
2256
+
2257
+ v4.2.5: Switch on which parameters were provided.
2258
+
2259
+ Syntax:
2260
+ switch(Params) {
2261
+ case name: // if 'name' param exists
2262
+ case name & age: // if both exist
2263
+ case name & not age: // if 'name' exists but 'age' doesn't
2264
+ except name: // if 'name' does NOT exist
2265
+ default: // fallback
2266
+ always: // always runs after match
2267
+ finally: // cleanup, always runs
2268
+ }
2269
+ """
2270
+ params_name = node.value.get('params')
2271
+ open_kwargs = self.scope.get('_OpenKwargs') or {}
2272
+
2273
+ matched = False
2274
+ always_node = None
2275
+ finally_node = None
2276
+ default_node = None
2277
+
2278
+ # First pass: find always, finally, default nodes
2279
+ for child in node.children:
2280
+ if child.type == 'param_always':
2281
+ always_node = child
2282
+ elif child.type == 'param_finally':
2283
+ finally_node = child
2284
+ elif child.type == 'param_default':
2285
+ default_node = child
2286
+
2287
+ try:
2288
+ # Execute matching cases
2289
+ for child in node.children:
2290
+ if child.type == 'param_case':
2291
+ condition = child.value.get('condition')
2292
+ if self._eval_param_condition(condition, open_kwargs):
2293
+ matched = True
2294
+ try:
2295
+ for stmt in child.children:
2296
+ self._execute_node(stmt)
2297
+ except CSSLBreak:
2298
+ break
2299
+
2300
+ # Execute default if no match
2301
+ if not matched and default_node:
2302
+ try:
2303
+ for stmt in default_node.children:
2304
+ self._execute_node(stmt)
2305
+ except CSSLBreak:
2306
+ pass
2307
+
2308
+ # Execute always block (runs after a match, before finally)
2309
+ if matched and always_node:
2310
+ try:
2311
+ for stmt in always_node.children:
2312
+ self._execute_node(stmt)
2313
+ except CSSLBreak:
2314
+ pass
2315
+
2316
+ finally:
2317
+ # Execute finally block (always runs, even on break/exception)
2318
+ if finally_node:
2319
+ for stmt in finally_node.children:
2320
+ self._execute_node(stmt)
2321
+
2322
+ return None
2323
+
2324
+ def _eval_param_condition(self, condition: dict, kwargs: dict) -> bool:
2325
+ """Evaluate a param switch condition.
2326
+
2327
+ Condition types:
2328
+ {'type': 'exists', 'param': 'name'} -> 'name' in kwargs
2329
+ {'type': 'not', 'param': 'name'} -> 'name' not in kwargs
2330
+ {'type': 'and', 'left': {...}, 'right': {...}} -> left AND right
2331
+ """
2332
+ cond_type = condition.get('type')
2333
+
2334
+ if cond_type == 'exists':
2335
+ param = condition.get('param')
2336
+ return param in kwargs
2337
+
2338
+ elif cond_type == 'not':
2339
+ param = condition.get('param')
2340
+ return param not in kwargs
2341
+
2342
+ elif cond_type == 'and':
2343
+ left = self._eval_param_condition(condition.get('left'), kwargs)
2344
+ right = self._eval_param_condition(condition.get('right'), kwargs)
2345
+ return left and right
2346
+
2347
+ return False
2348
+
1836
2349
  def _exec_return(self, node: ASTNode) -> Any:
1837
2350
  """Execute return statement.
1838
2351
 
@@ -1935,7 +2448,7 @@ class CSSLRuntime:
1935
2448
  return None
1936
2449
 
1937
2450
  def _exec_try(self, node: ASTNode) -> Any:
1938
- """Execute try/catch block"""
2451
+ """Execute try/catch/finally block"""
1939
2452
  try:
1940
2453
  for child in node.children:
1941
2454
  if child.type == 'try-block':
@@ -1949,9 +2462,89 @@ class CSSLRuntime:
1949
2462
  self.scope.set(error_var, str(e))
1950
2463
  for stmt in child.children:
1951
2464
  self._execute_node(stmt)
2465
+ except Exception as e:
2466
+ # v4.2.6: Also catch Python exceptions
2467
+ for child in node.children:
2468
+ if child.type == 'catch-block':
2469
+ error_var = child.value.get('error_var') if child.value else None
2470
+ if error_var:
2471
+ self.scope.set(error_var, str(e))
2472
+ for stmt in child.children:
2473
+ self._execute_node(stmt)
2474
+ finally:
2475
+ # v4.2.6: Execute finally block if present
2476
+ for child in node.children:
2477
+ if child.type == 'finally-block':
2478
+ for stmt in child.children:
2479
+ self._execute_node(stmt)
1952
2480
 
1953
2481
  return None
1954
2482
 
2483
+ def _exec_supports_block(self, node: ASTNode) -> Any:
2484
+ """Execute standalone supports block for multi-language syntax.
2485
+
2486
+ v4.2.0: Allows 'supports' to be used anywhere, not just in class/function.
2487
+
2488
+ Syntax:
2489
+ supports py {
2490
+ for i in range(10):
2491
+ print(i)
2492
+ }
2493
+
2494
+ supports cpp {
2495
+ int x = 42;
2496
+ std::cout << x << std::endl;
2497
+ }
2498
+ """
2499
+ block_info = node.value
2500
+ language = block_info.get('language')
2501
+ raw_source = block_info.get('raw_source')
2502
+
2503
+ # If we have raw_source, transform and execute
2504
+ if raw_source and language:
2505
+ import textwrap
2506
+ from .cssl_languages import get_language
2507
+ from .cssl_parser import parse_cssl_program
2508
+
2509
+ # Normalize language ID
2510
+ lang_id = language.lstrip('@').lower()
2511
+
2512
+ # Get language support and transformer
2513
+ lang_support = get_language(lang_id)
2514
+ if lang_support is None:
2515
+ raise CSSLRuntimeError(f"Unknown language '{lang_id}' in 'supports' block")
2516
+
2517
+ # Dedent the raw source to normalize indentation
2518
+ dedented_source = textwrap.dedent(raw_source)
2519
+
2520
+ # Transform the raw source to CSSL
2521
+ transformer = lang_support.get_transformer()
2522
+ transformed_source = transformer.transform_source(dedented_source)
2523
+
2524
+ # Parse the transformed CSSL
2525
+ try:
2526
+ ast = parse_cssl_program(transformed_source)
2527
+ except Exception as e:
2528
+ raise CSSLRuntimeError(
2529
+ f"Failed to parse transformed '{lang_id}' code in supports block: {e}\n"
2530
+ f"Dedented:\n{dedented_source}\n"
2531
+ f"Transformed:\n{transformed_source}"
2532
+ )
2533
+
2534
+ # Execute the transformed AST
2535
+ result = None
2536
+ for child in ast.children:
2537
+ result = self._execute_node(child)
2538
+
2539
+ return result
2540
+
2541
+ # Fallback: execute already-parsed children (CSSL syntax)
2542
+ result = None
2543
+ for child in node.children:
2544
+ result = self._execute_node(child)
2545
+
2546
+ return result
2547
+
1955
2548
  def _exec_createcmd_inject(self, node: ASTNode) -> Any:
1956
2549
  """Execute createcmd injection: createcmd('cmd') <== { action }"""
1957
2550
  command_call = node.value.get('command_call')
@@ -2520,24 +3113,60 @@ class CSSLRuntime:
2520
3113
  if filter_info:
2521
3114
  source = self._apply_injection_filter(source, filter_info)
2522
3115
 
2523
- # Get current target value for add/move modes
3116
+ # Get current target value for add/move/replace modes (needed for UniversalInstance handling)
2524
3117
  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
3118
+ try:
3119
+ current_value = self._evaluate(target)
3120
+ except Exception:
3121
+ # Target might not exist yet, that's okay for add mode
3122
+ current_value = None
2531
3123
 
2532
3124
  # Determine final value based on mode
2533
3125
  if mode == 'replace':
2534
- final_value = source
3126
+ from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
3127
+ # Special handling for UniversalInstance targets - inject instead of replace
3128
+ if isinstance(current_value, UniversalInstance):
3129
+ if isinstance(source, CSSLClass):
3130
+ current_value.set_member(source.name, source)
3131
+ final_value = current_value
3132
+ elif isinstance(source, ASTNode) and source.type == 'function':
3133
+ func_info = source.value
3134
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
3135
+ if func_name:
3136
+ current_value.set_method(func_name, source, self)
3137
+ final_value = current_value
3138
+ elif isinstance(source, CSSLInstance):
3139
+ current_value.set_member(source._class.name, source)
3140
+ final_value = current_value
3141
+ else:
3142
+ # For other types, store as member with source type name
3143
+ final_value = source
3144
+ else:
3145
+ final_value = source
2535
3146
  elif mode == 'add':
2536
3147
  # Copy & add - preserve target and add source
2537
- from .cssl_types import CSSLInstance
3148
+ from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
2538
3149
 
3150
+ # Special handling for UniversalInstance + CSSLClass
3151
+ if isinstance(current_value, UniversalInstance) and isinstance(source, CSSLClass):
3152
+ # Inject class definition into universal instance
3153
+ current_value.set_member(source.name, source)
3154
+ final_value = current_value
3155
+ # Special handling for UniversalInstance + Function (AST node)
3156
+ elif isinstance(current_value, UniversalInstance) and isinstance(source, ASTNode) and source.type == 'function':
3157
+ # Inject function as a method into universal instance
3158
+ func_info = source.value
3159
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
3160
+ if func_name:
3161
+ current_value.set_method(func_name, source, self)
3162
+ final_value = current_value
3163
+ # Special handling for UniversalInstance + CSSLInstance
3164
+ elif isinstance(current_value, UniversalInstance) and isinstance(source, CSSLInstance):
3165
+ class_name = source._class.name
3166
+ current_value.set_member(class_name, source)
3167
+ final_value = current_value
2539
3168
  # Special handling for CSSLInstance - merge classes
2540
- if isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
3169
+ elif isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
2541
3170
  # Add the new class instance as a member with class name as key
2542
3171
  class_name = source._class.name
2543
3172
  current_value._members[class_name] = source
@@ -2551,6 +3180,15 @@ class CSSLRuntime:
2551
3180
  final_value = {**current_value, **source}
2552
3181
  elif isinstance(current_value, str) and isinstance(source, str):
2553
3182
  final_value = current_value + source
3183
+ # Handle CSSL container types (DataStruct, Vector, Stack, etc.)
3184
+ elif hasattr(current_value, 'append') or hasattr(current_value, 'push') or hasattr(current_value, 'add'):
3185
+ if hasattr(current_value, 'append'):
3186
+ current_value.append(source)
3187
+ elif hasattr(current_value, 'push'):
3188
+ current_value.push(source)
3189
+ elif hasattr(current_value, 'add'):
3190
+ current_value.add(source)
3191
+ final_value = current_value
2554
3192
  elif current_value is None:
2555
3193
  final_value = [source] if not isinstance(source, list) else source
2556
3194
  else:
@@ -2736,8 +3374,13 @@ class CSSLRuntime:
2736
3374
  - add: func +<<== { code } - ADDS code to function (both execute)
2737
3375
  - remove: func -<<== { code } - REMOVES matching code from function
2738
3376
 
3377
+ Also supports instance injection:
3378
+ - instance +<<== { void method() { ... } } - ADDS methods to UniversalInstance
3379
+
2739
3380
  Also supports expression form: func <<== %exit() (wraps in action_block)
2740
3381
  """
3382
+ from .cssl_types import UniversalInstance
3383
+
2741
3384
  target = node.value.get('target')
2742
3385
  code_block = node.value.get('code')
2743
3386
  source_expr = node.value.get('source') # For expression form: func <<== expr
@@ -2749,6 +3392,17 @@ class CSSLRuntime:
2749
3392
  expr_node = ASTNode('expression', value=source_expr)
2750
3393
  code_block = ASTNode('action_block', children=[expr_node])
2751
3394
 
3395
+ # Check if target is a UniversalInstance
3396
+ target_value = None
3397
+ if isinstance(target, ASTNode) and target.type == 'identifier':
3398
+ target_value = self.scope.get(target.value)
3399
+ if target_value is None:
3400
+ target_value = self.global_scope.get(target.value)
3401
+
3402
+ # Handle UniversalInstance injection
3403
+ if isinstance(target_value, UniversalInstance):
3404
+ return self._inject_into_instance(target_value, code_block, mode)
3405
+
2752
3406
  # Get function name from target
2753
3407
  func_name = None
2754
3408
  if isinstance(target, ASTNode):
@@ -2796,6 +3450,60 @@ class CSSLRuntime:
2796
3450
 
2797
3451
  return None
2798
3452
 
3453
+ def _inject_into_instance(self, instance: Any, code_block: Any, mode: str) -> Any:
3454
+ """Inject code/methods into a UniversalInstance.
3455
+
3456
+ Usage:
3457
+ instance<"myContainer"> container;
3458
+ container +<<== {
3459
+ void sayHello() { printl("Hello!"); }
3460
+ int value = 42;
3461
+ }
3462
+ """
3463
+ from .cssl_types import UniversalInstance
3464
+
3465
+ if not isinstance(instance, UniversalInstance):
3466
+ return None
3467
+
3468
+ if code_block is None:
3469
+ return None
3470
+
3471
+ # Store the raw injection
3472
+ instance.add_injection(code_block)
3473
+
3474
+ # Parse the code block for function definitions and variable declarations
3475
+ if isinstance(code_block, ASTNode):
3476
+ children = code_block.children if hasattr(code_block, 'children') else []
3477
+
3478
+ for child in children:
3479
+ if isinstance(child, ASTNode):
3480
+ if child.type == 'function':
3481
+ # Extract function name and store the AST node
3482
+ func_info = child.value
3483
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
3484
+ if func_name:
3485
+ instance.set_method(func_name, child, self)
3486
+ elif child.type == 'var_declaration':
3487
+ # Extract variable and value
3488
+ var_info = child.value
3489
+ if isinstance(var_info, dict):
3490
+ var_name = var_info.get('name')
3491
+ value_node = var_info.get('value')
3492
+ if var_name:
3493
+ value = self._evaluate(value_node) if value_node else None
3494
+ instance.set_member(var_name, value)
3495
+ elif child.type == 'typed_var_declaration':
3496
+ # Typed variable declaration
3497
+ var_info = child.value
3498
+ if isinstance(var_info, dict):
3499
+ var_name = var_info.get('name')
3500
+ value_node = var_info.get('value')
3501
+ if var_name:
3502
+ value = self._evaluate(value_node) if value_node else None
3503
+ instance.set_member(var_name, value)
3504
+
3505
+ return instance
3506
+
2799
3507
  def _exec_infuse_right(self, node: ASTNode) -> Any:
2800
3508
  """Execute right-side code infusion (==>>)"""
2801
3509
  source = node.value.get('source')
@@ -2882,7 +3590,13 @@ class CSSLRuntime:
2882
3590
  if self._current_instance is None:
2883
3591
  raise CSSLRuntimeError("'this' used outside of class method context")
2884
3592
  member = target.value.get('member')
2885
- self._current_instance.set_member(member, value)
3593
+ instance = self._current_instance
3594
+ # Check if instance is a CSSL instance or a plain Python object
3595
+ if hasattr(instance, 'set_member'):
3596
+ instance.set_member(member, value)
3597
+ else:
3598
+ # Plain Python object - use setattr
3599
+ setattr(instance, member, value)
2886
3600
  elif isinstance(target, str):
2887
3601
  self.scope.set(target, value)
2888
3602
 
@@ -2997,6 +3711,31 @@ class CSSLRuntime:
2997
3711
 
2998
3712
  if node.type == 'identifier':
2999
3713
  name = node.value
3714
+
3715
+ # Handle enum/namespace access: Colors::RED, MyNamespace::func
3716
+ if '::' in name:
3717
+ parts = name.split('::', 1)
3718
+ container_name = parts[0]
3719
+ member_name = parts[1]
3720
+
3721
+ # Look up the container (enum, class, or namespace)
3722
+ container = self.scope.get(container_name)
3723
+ if container is None:
3724
+ container = self.global_scope.get(container_name)
3725
+ if container is None:
3726
+ container = self._promoted_globals.get(container_name)
3727
+
3728
+ if container is not None:
3729
+ # If it's a dict-like object (enum or namespace), get the member
3730
+ if isinstance(container, dict):
3731
+ return container.get(member_name)
3732
+ # If it's an object with the member as an attribute
3733
+ elif hasattr(container, member_name):
3734
+ return getattr(container, member_name)
3735
+
3736
+ # Fall through to normal lookup if container not found
3737
+ return None
3738
+
3000
3739
  value = self.scope.get(name)
3001
3740
  # Check if it's a class member in current instance context
3002
3741
  # This allows accessing members without 'this->' inside methods
@@ -3070,14 +3809,22 @@ class CSSLRuntime:
3070
3809
 
3071
3810
  if node.type == 'captured_ref':
3072
3811
  # %<name> captured reference - use value captured at infusion registration time
3812
+ # Priority: The % prefix means "get the ORIGINAL value before any replacement"
3073
3813
  name = node.value
3074
- # First check captured values from current injection context
3814
+
3815
+ # 1. First check captured values from current injection context
3075
3816
  if name in self._current_captured_values:
3076
3817
  captured_value = self._current_captured_values[name]
3077
- # Only use captured value if it's not None
3078
3818
  if captured_value is not None:
3079
3819
  return captured_value
3080
- # Fall back to normal resolution if not captured or capture was None
3820
+
3821
+ # 2. v4.2.3: Check _original_functions FIRST - this is the pre-replacement value
3822
+ # This ensures %exit() refers to the ORIGINAL exit when using &exit
3823
+ value = self._original_functions.get(name)
3824
+ if value is not None:
3825
+ return value
3826
+
3827
+ # 3. Fall back to scope/builtins if no original was captured
3081
3828
  value = self.scope.get(name)
3082
3829
  if value is None:
3083
3830
  value = self.global_scope.get(name)
@@ -3088,9 +3835,6 @@ class CSSLRuntime:
3088
3835
  value = lambda code=0, rt=runtime: rt.exit(code)
3089
3836
  else:
3090
3837
  value = getattr(self.builtins, f'builtin_{name}', None)
3091
- if value is None:
3092
- # Check original functions (for replaced functions)
3093
- value = self._original_functions.get(name)
3094
3838
  if value is not None:
3095
3839
  return value
3096
3840
  # Build helpful error for captured reference
@@ -3115,6 +3859,83 @@ class CSSLRuntime:
3115
3859
  # Return None if instance doesn't exist (can be created via ==>)
3116
3860
  return None
3117
3861
 
3862
+ # v4.1.0/v4.1.1: Cross-language instance reference: cpp$ClassName, py$Object
3863
+ # Enhanced bidirectional access with real runtime bridges
3864
+ if node.type == 'lang_instance_ref':
3865
+ ref = node.value # {'lang': 'cpp', 'instance': 'ClassName'}
3866
+ lang_id = ref['lang']
3867
+ instance_name = ref['instance']
3868
+
3869
+ # First, try to get the language support object from scope
3870
+ lang_support = self.scope.get(lang_id)
3871
+ if lang_support is None:
3872
+ lang_support = self.global_scope.get(lang_id)
3873
+
3874
+ # If not found in scope, try to get from modules
3875
+ if lang_support is None:
3876
+ lang_support = self._modules.get(lang_id)
3877
+
3878
+ # If still not found, try getting default language support
3879
+ if lang_support is None:
3880
+ from .cssl_languages import get_language
3881
+ lang_support = get_language(lang_id)
3882
+
3883
+ if lang_support is not None:
3884
+ # v4.1.1: Check if it's a LanguageSupport object with get_instance method
3885
+ if hasattr(lang_support, 'get_instance'):
3886
+ instance = lang_support.get_instance(instance_name)
3887
+ if instance is not None:
3888
+ return instance
3889
+
3890
+ # v4.1.1: For C++, also try to get class from loaded modules directly
3891
+ if hasattr(lang_support, '_get_bridge'):
3892
+ bridge = lang_support._get_bridge()
3893
+ if bridge is not None:
3894
+ # Try to get from bridge's instances
3895
+ bridge_instance = bridge.get_instance(instance_name)
3896
+ if bridge_instance is not None:
3897
+ return bridge_instance
3898
+
3899
+ # For C++: Try to access class from IncludeCPP modules
3900
+ if hasattr(bridge, '_modules'):
3901
+ for mod in bridge._modules.values():
3902
+ if hasattr(mod, instance_name):
3903
+ cls_or_instance = getattr(mod, instance_name)
3904
+ # Cache it for future access
3905
+ lang_support._instances[instance_name] = cls_or_instance
3906
+ return cls_or_instance
3907
+
3908
+ # Check _instances dict directly as fallback
3909
+ if hasattr(lang_support, '_instances'):
3910
+ if instance_name in lang_support._instances:
3911
+ return lang_support._instances[instance_name]
3912
+
3913
+ # Build helpful error message based on language
3914
+ if lang_id in ('cpp', 'c++'):
3915
+ hint = (f"For C++ access:\n"
3916
+ f" 1. Build your module with 'includecpp build'\n"
3917
+ f" 2. Use cpp.share(\"{instance_name}\", instance) to register\n"
3918
+ f" 3. Or access a class directly: obj = new cpp${instance_name}()")
3919
+ elif lang_id in ('java',):
3920
+ hint = (f"For Java access:\n"
3921
+ f" 1. Install JPype: pip install jpype1\n"
3922
+ f" 2. Add classpath: java.add_classpath(\"path/to/jar\")\n"
3923
+ f" 3. Load class: MyClass = java.load_class(\"com.example.{instance_name}\")\n"
3924
+ f" 4. Share instance: java.share(\"{instance_name}\", instance)")
3925
+ elif lang_id in ('js', 'javascript'):
3926
+ hint = (f"For JavaScript access:\n"
3927
+ f" 1. Make sure Node.js is installed\n"
3928
+ f" 2. Define in JS: js.eval(\"function {instance_name}() {{...}}\")\n"
3929
+ f" 3. Share result: js.share(\"{instance_name}\", result)")
3930
+ else:
3931
+ hint = f"Use '{lang_id}.share(\"{instance_name}\", instance)' to register the instance first."
3932
+
3933
+ raise self._format_error(
3934
+ node.line if hasattr(node, 'line') else 0,
3935
+ f"Cross-language instance '{lang_id}${instance_name}' not found",
3936
+ hint
3937
+ )
3938
+
3118
3939
  if node.type == 'new':
3119
3940
  # Create new instance of a class: new ClassName(args)
3120
3941
  return self._eval_new(node)
@@ -3188,6 +4009,14 @@ class CSSLRuntime:
3188
4009
  if node.type == 'unary':
3189
4010
  return self._eval_unary(node)
3190
4011
 
4012
+ # Increment: ++i or i++
4013
+ if node.type == 'increment':
4014
+ return self._eval_increment(node)
4015
+
4016
+ # Decrement: --i or i--
4017
+ if node.type == 'decrement':
4018
+ return self._eval_decrement(node)
4019
+
3191
4020
  if node.type == 'non_null_assert':
3192
4021
  # *$var, *@module, *identifier - assert value is not null/None
3193
4022
  operand = node.value.get('operand')
@@ -3341,15 +4170,21 @@ class CSSLRuntime:
3341
4170
 
3342
4171
  if op == '/':
3343
4172
  r = self._to_number(right)
3344
- return self._to_number(left) / r if r != 0 else 0
4173
+ if r == 0:
4174
+ raise CSSLRuntimeError("Division by zero")
4175
+ return self._to_number(left) / r
3345
4176
 
3346
4177
  if op == '//':
3347
4178
  r = self._to_number(right)
3348
- return self._to_number(left) // r if r != 0 else 0
4179
+ if r == 0:
4180
+ raise CSSLRuntimeError("Integer division by zero")
4181
+ return self._to_number(left) // r
3349
4182
 
3350
4183
  if op == '%':
3351
4184
  r = self._to_number(right)
3352
- return self._to_number(left) % r if r != 0 else 0
4185
+ if r == 0:
4186
+ raise CSSLRuntimeError("Modulo by zero")
4187
+ return self._to_number(left) % r
3353
4188
 
3354
4189
  if op == '**':
3355
4190
  return self._to_number(left) ** self._to_number(right)
@@ -3473,6 +4308,74 @@ class CSSLRuntime:
3473
4308
 
3474
4309
  return None
3475
4310
 
4311
+ def _eval_increment(self, node: ASTNode) -> Any:
4312
+ """Evaluate increment operation (++i or i++)"""
4313
+ op_type = node.value.get('op') # 'prefix' or 'postfix'
4314
+ operand = node.value.get('operand')
4315
+
4316
+ # Get variable name
4317
+ var_name = None
4318
+ if isinstance(operand, ASTNode):
4319
+ if operand.type == 'identifier':
4320
+ var_name = operand.value
4321
+ elif operand.type == 'shared_ref':
4322
+ # Handle $var++
4323
+ var_name = operand.value
4324
+ current = self.shared_vars.get(var_name, 0)
4325
+ if op_type == 'prefix':
4326
+ self.shared_vars[var_name] = current + 1
4327
+ return current + 1
4328
+ else: # postfix
4329
+ self.shared_vars[var_name] = current + 1
4330
+ return current
4331
+
4332
+ if var_name:
4333
+ current = self.scope.get(var_name, 0)
4334
+ if op_type == 'prefix':
4335
+ # ++i: increment then return
4336
+ self.scope.set(var_name, current + 1)
4337
+ return current + 1
4338
+ else:
4339
+ # i++: return then increment
4340
+ self.scope.set(var_name, current + 1)
4341
+ return current
4342
+
4343
+ return None
4344
+
4345
+ def _eval_decrement(self, node: ASTNode) -> Any:
4346
+ """Evaluate decrement operation (--i or i--)"""
4347
+ op_type = node.value.get('op') # 'prefix' or 'postfix'
4348
+ operand = node.value.get('operand')
4349
+
4350
+ # Get variable name
4351
+ var_name = None
4352
+ if isinstance(operand, ASTNode):
4353
+ if operand.type == 'identifier':
4354
+ var_name = operand.value
4355
+ elif operand.type == 'shared_ref':
4356
+ # Handle $var--
4357
+ var_name = operand.value
4358
+ current = self.shared_vars.get(var_name, 0)
4359
+ if op_type == 'prefix':
4360
+ self.shared_vars[var_name] = current - 1
4361
+ return current - 1
4362
+ else: # postfix
4363
+ self.shared_vars[var_name] = current - 1
4364
+ return current
4365
+
4366
+ if var_name:
4367
+ current = self.scope.get(var_name, 0)
4368
+ if op_type == 'prefix':
4369
+ # --i: decrement then return
4370
+ self.scope.set(var_name, current - 1)
4371
+ return current - 1
4372
+ else:
4373
+ # i--: return then decrement
4374
+ self.scope.set(var_name, current - 1)
4375
+ return current
4376
+
4377
+ return None
4378
+
3476
4379
  def _eval_call(self, node: ASTNode) -> Any:
3477
4380
  """Evaluate function call with optional named arguments"""
3478
4381
  callee_node = node.value.get('callee')
@@ -3516,7 +4419,33 @@ class CSSLRuntime:
3516
4419
  if isinstance(callee, ASTNode) and callee.type == 'function':
3517
4420
  return self._call_function(callee, args, kwargs)
3518
4421
 
3519
- callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
4422
+ # Extract callee name for error messages
4423
+ if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value'):
4424
+ val = callee_node.value
4425
+ if isinstance(val, str):
4426
+ callee_name = val
4427
+ elif isinstance(val, dict):
4428
+ # For member access nodes like obj.method, get the member name
4429
+ if 'member' in val:
4430
+ obj_node = val.get('object')
4431
+ member = val.get('member')
4432
+ obj_name = obj_node.value if isinstance(obj_node, ASTNode) else str(obj_node)
4433
+ callee_name = f"{obj_name}.{member}"
4434
+ # For call nodes, try to get the callee name
4435
+ elif 'callee' in val:
4436
+ callee_val = val.get('callee')
4437
+ if isinstance(callee_val, ASTNode):
4438
+ callee_name = callee_val.value if isinstance(callee_val.value, str) else str(callee_val.value)
4439
+ else:
4440
+ callee_name = str(callee_val)
4441
+ elif 'name' in val:
4442
+ callee_name = str(val.get('name'))
4443
+ else:
4444
+ callee_name = str(val)
4445
+ else:
4446
+ callee_name = str(val)
4447
+ else:
4448
+ callee_name = str(callee_node)
3520
4449
 
3521
4450
  # Build detailed error with suggestions
3522
4451
  available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
@@ -3609,30 +4538,44 @@ class CSSLRuntime:
3609
4538
  )
3610
4539
 
3611
4540
  def _eval_new(self, node: ASTNode) -> CSSLInstance:
3612
- """Evaluate 'new ClassName(args)' or 'new @ClassName(args)' expression.
4541
+ """Evaluate 'new ClassName(args)' or 'new @ClassName(args)' or 'new Namespace::ClassName(args)' expression.
3613
4542
 
3614
4543
  Creates a new instance of a CSSL class and calls its constructor.
3615
4544
  Supports multiple constructors (constr keyword), class parameters,
3616
4545
  and automatic parent constructor calling.
3617
4546
 
3618
4547
  With '@' prefix (new @ClassName), looks only in global scope.
4548
+ With Namespace:: prefix, looks in the namespace dict first.
3619
4549
  """
3620
4550
  class_name = node.value.get('class')
4551
+ namespace = node.value.get('namespace') # v4.2.6: Namespace::ClassName support
3621
4552
  is_global_ref = node.value.get('is_global_ref', False)
3622
4553
  args = [self._evaluate(arg) for arg in node.value.get('args', [])]
3623
4554
  kwargs = {k: self._evaluate(v) for k, v in node.value.get('kwargs', {}).items()}
3624
4555
 
3625
- # Get class definition from scope
3626
- if is_global_ref:
3627
- # With @ prefix, only look in global scope
3628
- class_def = self._promoted_globals.get(class_name)
3629
- if class_def is None:
3630
- class_def = self.global_scope.get(class_name)
3631
- else:
3632
- # Normal lookup: local scope first, then global
3633
- class_def = self.scope.get(class_name)
3634
- if class_def is None:
3635
- class_def = self.global_scope.get(class_name)
4556
+ class_def = None
4557
+
4558
+ # v4.2.6: Handle Namespace::ClassName lookup
4559
+ if namespace:
4560
+ # Look up namespace dict first
4561
+ ns_dict = self.scope.get(namespace)
4562
+ if ns_dict is None:
4563
+ ns_dict = self.global_scope.get(namespace)
4564
+ if isinstance(ns_dict, dict) and class_name in ns_dict:
4565
+ class_def = ns_dict[class_name]
4566
+
4567
+ # Get class definition from scope (if not found in namespace)
4568
+ if class_def is None:
4569
+ if is_global_ref:
4570
+ # With @ prefix, only look in global scope
4571
+ class_def = self._promoted_globals.get(class_name)
4572
+ if class_def is None:
4573
+ class_def = self.global_scope.get(class_name)
4574
+ else:
4575
+ # Normal lookup: local scope first, then global
4576
+ class_def = self.scope.get(class_name)
4577
+ if class_def is None:
4578
+ class_def = self.global_scope.get(class_name)
3636
4579
 
3637
4580
  if class_def is None:
3638
4581
  # Build detailed error with suggestions
@@ -3658,6 +4601,22 @@ class CSSLRuntime:
3658
4601
  hint
3659
4602
  )
3660
4603
 
4604
+ # If we got a variable that holds a class reference, use that class
4605
+ if not isinstance(class_def, CSSLClass):
4606
+ # Check if it's a variable holding a class (dynamic class instantiation)
4607
+ if hasattr(class_def, '__class__') and isinstance(class_def, CSSLClass):
4608
+ pass # Already a CSSLClass, continue
4609
+ elif isinstance(class_def, dict) and 'class_def' in class_def:
4610
+ # Injected class reference from +<== operator
4611
+ class_def = class_def['class_def']
4612
+ else:
4613
+ # Not a class - show error
4614
+ raise CSSLRuntimeError(
4615
+ f"'{class_name}' is not a class",
4616
+ node.line,
4617
+ hint=f"'{class_name}' is of type {type(class_def).__name__}"
4618
+ )
4619
+
3661
4620
  if not isinstance(class_def, CSSLClass):
3662
4621
  raise CSSLRuntimeError(
3663
4622
  f"'{class_name}' is not a class",
@@ -3665,6 +4624,18 @@ class CSSLRuntime:
3665
4624
  hint=f"'{class_name}' is of type {type(class_def).__name__}"
3666
4625
  )
3667
4626
 
4627
+ # v4.2.5: Deferred &target replacement for non-embedded classes
4628
+ # Apply on first instantiation if pending
4629
+ if hasattr(class_def, '_pending_target') and class_def._pending_target:
4630
+ pending = class_def._pending_target
4631
+ self._overwrite_class_target(
4632
+ pending['append_ref_class'],
4633
+ pending.get('append_ref_member'),
4634
+ class_def
4635
+ )
4636
+ class_def._target_applied = True
4637
+ class_def._pending_target = None # Clear pending
4638
+
3668
4639
  # Create new instance
3669
4640
  instance = CSSLInstance(class_def)
3670
4641
 
@@ -3955,24 +4926,40 @@ class CSSLRuntime:
3955
4926
  # Direct this->member access
3956
4927
  instance = self._current_instance
3957
4928
 
3958
- # Check if it's a member variable
3959
- if instance.has_member(member):
3960
- return instance.get_member(member)
4929
+ # Check if instance is a CSSL instance or a plain Python object
4930
+ is_cssl_instance = hasattr(instance, 'has_member') and hasattr(instance, 'has_method')
4931
+
4932
+ if is_cssl_instance:
4933
+ # CSSL instance - use CSSL methods
4934
+ if instance.has_member(member):
4935
+ return instance.get_member(member)
3961
4936
 
3962
- # Check if it's a method
3963
- if instance.has_method(member):
3964
- # Return a callable that will invoke the method with instance context
3965
- method_node = instance.get_method(member)
3966
- # Check if this is an inherited Python method
3967
- if isinstance(method_node, tuple) and method_node[0] == 'python_method':
3968
- python_method = method_node[1]
3969
- return lambda *args, **kwargs: python_method(*args, **kwargs)
3970
- return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
4937
+ # Check if it's a method
4938
+ if instance.has_method(member):
4939
+ # Return a callable that will invoke the method with instance context
4940
+ method_node = instance.get_method(member)
4941
+ # Check if this is an inherited Python method
4942
+ if isinstance(method_node, tuple) and method_node[0] == 'python_method':
4943
+ python_method = method_node[1]
4944
+ return lambda *args, **kwargs: python_method(*args, **kwargs)
4945
+ return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
4946
+ else:
4947
+ # Plain Python object - use standard attribute access
4948
+ if hasattr(instance, member):
4949
+ return getattr(instance, member)
4950
+ # Also check __dict__ for dynamic attributes
4951
+ if hasattr(instance, '__dict__') and member in instance.__dict__:
4952
+ return instance.__dict__[member]
3971
4953
 
3972
4954
  # Build helpful error with available members
3973
- class_name = instance._class.name
3974
- available_members = list(instance._members.keys()) if hasattr(instance, '_members') else []
3975
- available_methods = list(instance._methods.keys()) if hasattr(instance, '_methods') else []
4955
+ if is_cssl_instance:
4956
+ class_name = instance._class.name
4957
+ available_members = list(instance._members.keys()) if hasattr(instance, '_members') else []
4958
+ available_methods = list(instance._methods.keys()) if hasattr(instance, '_methods') else []
4959
+ else:
4960
+ class_name = type(instance).__name__
4961
+ available_members = [k for k in dir(instance) if not k.startswith('_')]
4962
+ available_methods = []
3976
4963
  all_available = available_members + available_methods
3977
4964
  similar = _find_similar_names(member, all_available)
3978
4965
 
@@ -4112,6 +5099,48 @@ class CSSLRuntime:
4112
5099
  hint
4113
5100
  )
4114
5101
 
5102
+ # === UNIVERSAL INSTANCE METHODS ===
5103
+ from .cssl_types import UniversalInstance
5104
+ if isinstance(obj, UniversalInstance):
5105
+ # Check for member variable
5106
+ if obj.has_member(member):
5107
+ return obj.get_member(member)
5108
+ # Check for method
5109
+ if obj.has_method(member):
5110
+ method_node = obj.get_method(member)
5111
+ # Create a callable that executes the method in context
5112
+ def instance_method_caller(*args, **kwargs):
5113
+ # Set 'this' to refer to the instance
5114
+ old_this = self.scope.get('this')
5115
+ self.scope.set('this', obj)
5116
+ try:
5117
+ return self._call_function(method_node, list(args))
5118
+ finally:
5119
+ if old_this is not None:
5120
+ self.scope.set('this', old_this)
5121
+ else:
5122
+ self.scope.remove('this') if hasattr(self.scope, 'remove') else None
5123
+ return instance_method_caller
5124
+ # Build helpful error with available members
5125
+ instance_name = obj.name
5126
+ available_members = list(obj.get_all_members().keys())
5127
+ available_methods = list(obj.get_all_methods().keys())
5128
+ all_available = available_members + available_methods
5129
+ similar = _find_similar_names(member, all_available)
5130
+
5131
+ if similar:
5132
+ hint = f"Did you mean: {', '.join(similar)}?"
5133
+ elif all_available:
5134
+ hint = f"Available: {', '.join(all_available[:5])}"
5135
+ else:
5136
+ hint = f"Instance '{instance_name}' has no accessible members."
5137
+
5138
+ raise self._format_error(
5139
+ node.line,
5140
+ f"Instance '{instance_name}' has no member or method '{member}'",
5141
+ hint
5142
+ )
5143
+
4115
5144
  # === STRING METHODS ===
4116
5145
  if isinstance(obj, str):
4117
5146
  string_methods = self._get_string_method(obj, member)
@@ -4330,12 +5359,19 @@ class CSSLRuntime:
4330
5359
  index = self._evaluate(node.value.get('index'))
4331
5360
 
4332
5361
  if obj is None:
4333
- return None
5362
+ raise CSSLRuntimeError(f"Cannot index into None/null value")
4334
5363
 
4335
5364
  try:
4336
5365
  return obj[index]
4337
- except (IndexError, KeyError, TypeError):
4338
- return None
5366
+ except IndexError:
5367
+ # v4.2.6: Throw error instead of returning None
5368
+ length = len(obj) if hasattr(obj, '__len__') else 'unknown'
5369
+ raise CSSLRuntimeError(f"Index {index} out of bounds (length: {length})")
5370
+ except KeyError:
5371
+ # v4.2.6: Throw error for missing dict keys
5372
+ raise CSSLRuntimeError(f"Key '{index}' not found in dictionary")
5373
+ except TypeError as e:
5374
+ raise CSSLRuntimeError(f"Cannot index: {e}")
4339
5375
 
4340
5376
  def _set_member(self, node: ASTNode, value: Any):
4341
5377
  """Set member value"""
@@ -4350,6 +5386,12 @@ class CSSLRuntime:
4350
5386
  obj.set_member(member, value)
4351
5387
  return
4352
5388
 
5389
+ # Check for UniversalInstance - use set_member method
5390
+ from .cssl_types import UniversalInstance
5391
+ if isinstance(obj, UniversalInstance):
5392
+ obj.set_member(member, value)
5393
+ return
5394
+
4353
5395
  # Check for SharedObjectProxy - directly access underlying object
4354
5396
  # This is more robust than relying on the proxy's __setattr__
4355
5397
  if hasattr(obj, '_direct_object') and hasattr(obj, '_name'):
@@ -4623,10 +5665,17 @@ class CSSLRuntime:
4623
5665
 
4624
5666
  def _emit_output(self, text: str, level: str = 'normal'):
4625
5667
  """Emit output through callback or print"""
5668
+ import sys
4626
5669
  if self._output_callback:
4627
5670
  self._output_callback(text, level)
4628
5671
  else:
4629
- print(text, end='')
5672
+ # Handle encoding issues on Windows console
5673
+ try:
5674
+ print(text, end='')
5675
+ except UnicodeEncodeError:
5676
+ # Fallback: encode with errors='replace' for unsupported chars
5677
+ encoded = text.encode(sys.stdout.encoding or 'utf-8', errors='replace')
5678
+ print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'), end='')
4630
5679
 
4631
5680
  def output(self, text: str):
4632
5681
  """Output text"""