IncludeCPP 3.8.9__py3-none-any.whl → 4.0.2__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.
@@ -68,11 +68,11 @@ class CSSLRuntimeError(Exception):
68
68
  # Build detailed error message
69
69
  error_parts = []
70
70
 
71
- # Main error message
71
+ # Main error message (no "Error:" prefix - CLI handles that)
72
72
  if line:
73
- error_parts.append(f"Error at line {line}: {message}")
73
+ error_parts.append(f"Line {line}: {message}")
74
74
  else:
75
- error_parts.append(f"Error: {message}")
75
+ error_parts.append(message)
76
76
 
77
77
  # Add context if available
78
78
  if context:
@@ -99,6 +99,89 @@ ERROR_HINTS = {
99
99
  }
100
100
 
101
101
 
102
+ def _find_similar_names(name: str, candidates: list, max_distance: int = 2) -> list:
103
+ """Find similar names for 'did you mean' suggestions using Levenshtein distance."""
104
+ if not candidates:
105
+ return []
106
+
107
+ def levenshtein(s1: str, s2: str) -> int:
108
+ if len(s1) < len(s2):
109
+ s1, s2 = s2, s1
110
+ if len(s2) == 0:
111
+ return len(s1)
112
+ prev_row = range(len(s2) + 1)
113
+ for i, c1 in enumerate(s1):
114
+ curr_row = [i + 1]
115
+ for j, c2 in enumerate(s2):
116
+ insertions = prev_row[j + 1] + 1
117
+ deletions = curr_row[j] + 1
118
+ substitutions = prev_row[j] + (c1.lower() != c2.lower())
119
+ curr_row.append(min(insertions, deletions, substitutions))
120
+ prev_row = curr_row
121
+ return prev_row[-1]
122
+
123
+ similar = []
124
+ name_lower = name.lower()
125
+ for candidate in candidates:
126
+ if candidate.startswith('_'):
127
+ continue
128
+ dist = levenshtein(name, candidate)
129
+ # Also check case-insensitive exact match
130
+ if name_lower == candidate.lower() and name != candidate:
131
+ similar.insert(0, candidate) # Exact case mismatch goes first
132
+ elif dist <= max_distance:
133
+ similar.append(candidate)
134
+
135
+ return similar[:3] # Return top 3 suggestions
136
+
137
+
138
+ def _get_available_classes(scope: 'Scope', global_scope: 'Scope', promoted_globals: dict) -> list:
139
+ """Get list of all available class names."""
140
+ classes = []
141
+ # Check current scope chain
142
+ current = scope
143
+ while current:
144
+ for name, val in current.variables.items():
145
+ if isinstance(val, CSSLClass) and name not in classes:
146
+ classes.append(name)
147
+ current = current.parent
148
+ # Check global scope
149
+ for name, val in global_scope.variables.items():
150
+ if isinstance(val, CSSLClass) and name not in classes:
151
+ classes.append(name)
152
+ # Check promoted globals
153
+ for name, val in promoted_globals.items():
154
+ if isinstance(val, CSSLClass) and name not in classes:
155
+ classes.append(name)
156
+ return classes
157
+
158
+
159
+ def _get_available_functions(scope: 'Scope', global_scope: 'Scope', builtins) -> list:
160
+ """Get list of all available function names."""
161
+ functions = []
162
+ # Check current scope chain
163
+ current = scope
164
+ while current:
165
+ for name, val in current.variables.items():
166
+ if callable(val) or (isinstance(val, ASTNode) and val.type == 'function'):
167
+ if name not in functions:
168
+ functions.append(name)
169
+ current = current.parent
170
+ # Check global scope
171
+ for name, val in global_scope.variables.items():
172
+ if callable(val) or (isinstance(val, ASTNode) and val.type == 'function'):
173
+ if name not in functions:
174
+ functions.append(name)
175
+ # Check builtins
176
+ if builtins:
177
+ for name in dir(builtins):
178
+ if name.startswith('builtin_'):
179
+ func_name = name[8:] # Remove 'builtin_' prefix
180
+ if func_name not in functions:
181
+ functions.append(func_name)
182
+ return functions
183
+
184
+
102
185
  class CSSLBreak(Exception):
103
186
  """Break statement"""
104
187
  pass
@@ -280,11 +363,11 @@ class CSSLRuntime:
280
363
  """Format a detailed error with source context"""
281
364
  error_parts = []
282
365
 
283
- # Main error header
366
+ # Main error header (no "Error:" prefix - CLI handles that)
284
367
  if line and line > 0:
285
- error_parts.append(f"Error at line {line} in {self._current_file}:")
368
+ error_parts.append(f"Line {line} in {self._current_file}:")
286
369
  else:
287
- error_parts.append(f"Error in {self._current_file}:")
370
+ error_parts.append(f"In {self._current_file}:")
288
371
 
289
372
  # Extract message without existing line info
290
373
  clean_msg = message
@@ -716,9 +799,12 @@ class CSSLRuntime:
716
799
  Parses class members and methods, creating a CSSLClass object
717
800
  that can be instantiated with 'new'.
718
801
  Supports inheritance via 'extends' keyword and method overwriting via 'overwrites'.
802
+
803
+ Classes are local by default. Use 'global class' or 'class @Name' for global classes.
719
804
  """
720
805
  class_info = node.value
721
806
  class_name = class_info.get('name')
807
+ is_global = class_info.get('is_global', False)
722
808
  extends_class_name = class_info.get('extends')
723
809
  extends_is_python = class_info.get('extends_is_python', False)
724
810
  overwrites_class_name = class_info.get('overwrites')
@@ -745,7 +831,22 @@ class CSSLRuntime:
745
831
  parent_class = self.global_scope.get(extends_class_name)
746
832
 
747
833
  if parent_class is None:
748
- raise ValueError(f"Cannot extend unknown class '{extends_class_name}'")
834
+ # Build detailed error for extends
835
+ available_classes = _get_available_classes(self.scope, self.global_scope, self._promoted_globals)
836
+ similar = _find_similar_names(extends_class_name, available_classes)
837
+
838
+ if similar:
839
+ hint = f"Did you mean: {', '.join(similar)}?"
840
+ elif extends_is_python:
841
+ hint = f"Python object '${extends_class_name}' not found. Use share() to share Python objects first."
842
+ else:
843
+ hint = f"Define class '{extends_class_name}' before this class, or use 'extends $PyObject' for Python objects"
844
+
845
+ raise self._format_error(
846
+ node.line,
847
+ f"Cannot extend unknown class '{extends_class_name}'",
848
+ hint
849
+ )
749
850
 
750
851
  # Auto-wrap Python objects for inheritance
751
852
  from .cssl_builtins import CSSLizedPythonObject
@@ -803,9 +904,11 @@ class CSSLRuntime:
803
904
  class_def.class_params = class_params # Class-level constructor parameters
804
905
  class_def.extends_args = extends_args # Arguments to pass to parent constructor
805
906
 
806
- # Register class in scope
907
+ # Register class in scope (local by default, global if marked)
807
908
  self.scope.set(class_name, class_def)
808
- self.global_scope.set(class_name, class_def)
909
+ if is_global:
910
+ self.global_scope.set(class_name, class_def)
911
+ self._promoted_globals[class_name] = class_def
809
912
 
810
913
  # Handle class overwrites - replace methods in target class
811
914
  if overwrites_class_name:
@@ -888,24 +991,43 @@ class CSSLRuntime:
888
991
  """Execute function definition - registers it and handles extends/overwrites.
889
992
 
890
993
  Syntax:
891
- define func() { ... }
892
- define func : extends otherFunc() { ... } - Inherit local vars
893
- define func : overwrites otherFunc() { ... } - Replace otherFunc
994
+ define func() { ... } - Local function
995
+ global define func() { ... } - Global function
996
+ define @func() { ... } - Global function (alternative)
997
+ define func : extends otherFunc() { ... } - Inherit local vars
998
+ define func : overwrites otherFunc() { ... } - Replace otherFunc
894
999
  """
895
1000
  func_info = node.value
896
1001
  func_name = func_info.get('name')
1002
+ is_global = func_info.get('is_global', False)
897
1003
  extends_func = func_info.get('extends')
898
1004
  extends_is_python = func_info.get('extends_is_python', False)
899
1005
  overwrites_func = func_info.get('overwrites')
900
1006
  overwrites_is_python = func_info.get('overwrites_is_python', False)
901
1007
 
1008
+ # Get append/overwrite reference info (&Class::method syntax)
1009
+ append_mode = func_info.get('append_mode', False)
1010
+ append_ref_class = func_info.get('append_ref_class')
1011
+ append_ref_member = func_info.get('append_ref_member')
1012
+
902
1013
  # Store function extends info for runtime use
903
1014
  if extends_func:
904
1015
  node.value['_extends_resolved'] = self._resolve_function_target(
905
1016
  extends_func, extends_is_python
906
1017
  )
907
1018
 
908
- # Handle overwrites - replace the target function
1019
+ # Handle &Class::method syntax
1020
+ # Without ++ = full replacement
1021
+ # With ++ = append (run original first, then new code)
1022
+ if append_ref_class:
1023
+ if append_mode:
1024
+ # Append mode: wrap original to run original + new
1025
+ self._append_to_target(append_ref_class, append_ref_member, node)
1026
+ else:
1027
+ # Full replacement
1028
+ self._overwrite_target(append_ref_class, append_ref_member, node)
1029
+
1030
+ # Handle overwrites keyword - replace the target function
909
1031
  if overwrites_func:
910
1032
  target = self._resolve_function_target(overwrites_func, overwrites_is_python)
911
1033
  if target is not None:
@@ -922,8 +1044,11 @@ class CSSLRuntime:
922
1044
  self.scope.set(overwrites_func, node)
923
1045
  self.global_scope.set(overwrites_func, node)
924
1046
 
925
- # Register the function
1047
+ # Register the function (local by default, global if marked)
926
1048
  self.scope.set(func_name, node)
1049
+ if is_global:
1050
+ self.global_scope.set(func_name, node)
1051
+ self._promoted_globals[func_name] = node
927
1052
  return None
928
1053
 
929
1054
  def _resolve_function_target(self, name: str, is_python: bool) -> Any:
@@ -945,6 +1070,142 @@ class CSSLRuntime:
945
1070
  return self._call_function(func_node, list(args), kwargs)
946
1071
  return wrapper
947
1072
 
1073
+ def _overwrite_target(self, ref_class: str, ref_member: str, replacement_node: ASTNode):
1074
+ """Overwrite a class method or function with the replacement.
1075
+
1076
+ Handles:
1077
+ - &ClassName::method - Overwrite method in CSSL class
1078
+ - &$PyObject.method - Overwrite method in Python shared object
1079
+ - &functionName - Overwrite standalone function
1080
+ """
1081
+ from ..cssl_bridge import _live_objects, SharedObjectProxy
1082
+
1083
+ # Handle Python shared objects
1084
+ if ref_class.startswith('$'):
1085
+ var_name = ref_class[1:]
1086
+ ref_obj = _live_objects.get(var_name)
1087
+ if ref_obj is None:
1088
+ ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
1089
+
1090
+ if ref_obj is None:
1091
+ return
1092
+
1093
+ # Unwrap SharedObjectProxy
1094
+ if isinstance(ref_obj, SharedObjectProxy):
1095
+ ref_obj = ref_obj._obj
1096
+
1097
+ # Overwrite Python object method
1098
+ if ref_member and hasattr(ref_obj, ref_member):
1099
+ wrapper = self._create_python_wrapper(replacement_node)
1100
+ try:
1101
+ setattr(ref_obj, ref_member, wrapper)
1102
+ except (AttributeError, TypeError):
1103
+ pass # Can't overwrite (immutable or builtin)
1104
+ return
1105
+
1106
+ # Handle CSSL class method overwrite
1107
+ 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
1112
+ self.scope.set(ref_class, replacement_node)
1113
+ self.global_scope.set(ref_class, replacement_node)
1114
+ return
1115
+
1116
+ if isinstance(target_class, CSSLClass) and ref_member:
1117
+ # Overwrite method in the class
1118
+ if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
1119
+ target_class.methods[ref_member] = replacement_node
1120
+ # Also check members list
1121
+ if hasattr(target_class, 'members'):
1122
+ for i, member in enumerate(target_class.members):
1123
+ if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
1124
+ target_class.members[i] = replacement_node
1125
+ break
1126
+
1127
+ def _append_to_target(self, ref_class: str, ref_member: str, append_node: ASTNode):
1128
+ """Append new code to an existing class method or function.
1129
+
1130
+ Creates a wrapper that runs original first, then the appended code.
1131
+ Handles:
1132
+ - &ClassName::method ++ - Append to method in CSSL class
1133
+ - &$PyObject.method ++ - Append to method in Python shared object
1134
+ - &functionName ++ - Append to standalone function
1135
+ """
1136
+ from ..cssl_bridge import _live_objects, SharedObjectProxy
1137
+
1138
+ # Handle Python shared objects
1139
+ if ref_class.startswith('$'):
1140
+ var_name = ref_class[1:]
1141
+ ref_obj = _live_objects.get(var_name)
1142
+ if ref_obj is None:
1143
+ ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
1144
+
1145
+ if ref_obj is None:
1146
+ return
1147
+
1148
+ if isinstance(ref_obj, SharedObjectProxy):
1149
+ ref_obj = ref_obj._obj
1150
+
1151
+ # Create wrapper that calls original + new
1152
+ if ref_member and hasattr(ref_obj, ref_member):
1153
+ original_method = getattr(ref_obj, ref_member)
1154
+ runtime = self
1155
+ def appended_wrapper(*args, **kwargs):
1156
+ # Run original first
1157
+ result = None
1158
+ if callable(original_method):
1159
+ try:
1160
+ result = original_method(*args, **kwargs)
1161
+ except:
1162
+ pass
1163
+ # Then run appended code
1164
+ return runtime._call_function(append_node, list(args), kwargs)
1165
+ try:
1166
+ setattr(ref_obj, ref_member, appended_wrapper)
1167
+ except (AttributeError, TypeError):
1168
+ pass
1169
+ return
1170
+
1171
+ # Handle CSSL class method append
1172
+ target_class = self.scope.get(ref_class) or self.global_scope.get(ref_class)
1173
+ if target_class is None:
1174
+ # Standalone function append
1175
+ if ref_member is None:
1176
+ original_func = self.scope.get(ref_class) or self.global_scope.get(ref_class)
1177
+ if original_func:
1178
+ # Store original in append_node so it can run first
1179
+ append_node.value['_original_func'] = original_func
1180
+ self.scope.set(ref_class, append_node)
1181
+ self.global_scope.set(ref_class, append_node)
1182
+ return
1183
+
1184
+ if isinstance(target_class, CSSLClass) and ref_member:
1185
+ # Find original method
1186
+ original_method = None
1187
+ if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
1188
+ original_method = target_class.methods.get(ref_member)
1189
+
1190
+ if original_method is None and hasattr(target_class, 'members'):
1191
+ for member in target_class.members:
1192
+ if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
1193
+ original_method = member
1194
+ break
1195
+
1196
+ # Store original in append_node for runtime execution
1197
+ if original_method:
1198
+ append_node.value['_original_method'] = original_method
1199
+
1200
+ # Replace with append_node (which will call original first via _call_function)
1201
+ if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
1202
+ target_class.methods[ref_member] = append_node
1203
+ if hasattr(target_class, 'members'):
1204
+ for i, member in enumerate(target_class.members):
1205
+ if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
1206
+ target_class.members[i] = append_node
1207
+ break
1208
+
948
1209
  def _exec_typed_declaration(self, node: ASTNode) -> Any:
949
1210
  """Execute typed variable declaration: type<T> varName = value;
950
1211
 
@@ -1243,12 +1504,15 @@ class CSSLRuntime:
1243
1504
  if not self._running:
1244
1505
  break
1245
1506
  self._execute_node(child)
1246
- # Copy all local vars to new scope
1247
- for name, value in temp_scope._vars.items():
1248
- new_scope.set(name, value)
1507
+ except CSSLReturn:
1508
+ # Parent returned - that's fine, we just want the local vars
1509
+ pass
1249
1510
  except:
1250
1511
  pass
1251
1512
  finally:
1513
+ # ALWAYS copy local vars (even if parent returned)
1514
+ for name, value in temp_scope.variables.items():
1515
+ new_scope.set(name, value)
1252
1516
  self.scope = old_scope
1253
1517
 
1254
1518
  # Bind parameters - handle both positional and named arguments
@@ -1307,7 +1571,80 @@ class CSSLRuntime:
1307
1571
  break
1308
1572
  self._execute_node(child)
1309
1573
  except CSSLReturn as ret:
1310
- return ret.value
1574
+ return_value = ret.value
1575
+
1576
+ # Check exclude_type: *[type] - must NOT return excluded type
1577
+ exclude_type = func_info.get('exclude_type')
1578
+ if exclude_type and isinstance(exclude_type, str):
1579
+ type_map = {
1580
+ 'string': str, 'int': int, 'float': float, 'bool': bool,
1581
+ 'null': type(None), 'none': type(None),
1582
+ 'list': list, 'array': list, 'dict': dict, 'json': dict,
1583
+ }
1584
+ excluded_py_type = type_map.get(exclude_type.lower())
1585
+ # For shuffled returns (tuples), check each element
1586
+ if isinstance(return_value, tuple):
1587
+ for val in return_value:
1588
+ if excluded_py_type and isinstance(val, excluded_py_type):
1589
+ raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}' values")
1590
+ elif excluded_py_type and isinstance(return_value, excluded_py_type):
1591
+ raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}'")
1592
+
1593
+ # Enforce return type for typed functions (like C++)
1594
+ # Typed functions MUST return the declared type
1595
+ # Exception: 'meta' modifier allows any return type
1596
+ enforce_return_type = func_info.get('enforce_return_type', False)
1597
+ return_type = func_info.get('return_type')
1598
+
1599
+ if enforce_return_type and return_type and return_type != 'void':
1600
+ # Type mapping from CSSL types to Python types
1601
+ type_validate_map = {
1602
+ 'string': str, 'int': int, 'float': (int, float), 'bool': bool,
1603
+ 'list': list, 'array': list, 'dict': dict, 'json': dict,
1604
+ 'dynamic': object, # Any type
1605
+ 'void': type(None),
1606
+ }
1607
+
1608
+ # Generic container types - accept lists/tuples
1609
+ container_types = {
1610
+ 'vector', 'stack', 'datastruct', 'dataspace',
1611
+ 'shuffled', 'iterator', 'combo', 'openquote', 'map'
1612
+ }
1613
+
1614
+ if return_type in container_types:
1615
+ # Container types accept list, tuple, dict depending on type
1616
+ if return_type == 'map':
1617
+ expected = dict
1618
+ elif return_type == 'shuffled':
1619
+ expected = (list, tuple)
1620
+ else:
1621
+ expected = (list, tuple, object)
1622
+
1623
+ if not isinstance(return_value, expected):
1624
+ func_name = func_info.get('name', 'unknown')
1625
+ actual_type = type(return_value).__name__
1626
+ raise CSSLRuntimeError(
1627
+ f"Type error in '{func_name}': declared return type '{return_type}' "
1628
+ f"but returned '{actual_type}'. Typed functions must return declared type."
1629
+ )
1630
+ elif return_type in type_validate_map:
1631
+ expected = type_validate_map[return_type]
1632
+ if expected != object and return_value is not None:
1633
+ if not isinstance(return_value, expected):
1634
+ func_name = func_info.get('name', 'unknown')
1635
+ actual_type = type(return_value).__name__
1636
+ raise CSSLRuntimeError(
1637
+ f"Type error in '{func_name}': declared return type '{return_type}' "
1638
+ f"but returned '{actual_type}'. Typed functions must return declared type."
1639
+ )
1640
+
1641
+ # Check non_null: function must return a value (not None)
1642
+ non_null = func_info.get('non_null', False)
1643
+ if non_null and return_value is None:
1644
+ func_name = func_info.get('name', 'unknown')
1645
+ raise CSSLRuntimeError(f"Non-null function '{func_name}' returned null/None")
1646
+
1647
+ return return_value
1311
1648
  except Exception as e:
1312
1649
  # If undefined modifier, suppress all errors
1313
1650
  if is_undefined:
@@ -2715,7 +3052,21 @@ class CSSLRuntime:
2715
3052
  scoped_val = self.global_scope.get(f'${name}')
2716
3053
  if scoped_val is not None:
2717
3054
  return scoped_val
2718
- raise CSSLRuntimeError(f"Shared object '${name}' not found. Use share() to share objects.")
3055
+ # List available shared objects for helpful error
3056
+ available_shared = list(_live_objects.keys())
3057
+ similar = _find_similar_names(name, available_shared)
3058
+ if similar:
3059
+ hint = f"Did you mean: ${', $'.join(similar)}?"
3060
+ elif available_shared:
3061
+ hint = f"Available shared objects: ${', $'.join(available_shared[:5])}"
3062
+ else:
3063
+ hint = "Use share(name, object) from Python to share objects first."
3064
+
3065
+ raise self._format_error(
3066
+ node.line if hasattr(node, 'line') else 0,
3067
+ f"Shared object '${name}' not found",
3068
+ hint
3069
+ )
2719
3070
 
2720
3071
  if node.type == 'captured_ref':
2721
3072
  # %<name> captured reference - use value captured at infusion registration time
@@ -2742,7 +3093,13 @@ class CSSLRuntime:
2742
3093
  value = self._original_functions.get(name)
2743
3094
  if value is not None:
2744
3095
  return value
2745
- raise CSSLRuntimeError(f"Captured reference '%{name}' not found.")
3096
+ # Build helpful error for captured reference
3097
+ hint = f"Variable '{name}' must exist when the infusion is registered. Check that '%{name}' is defined before the <<== operator."
3098
+ raise self._format_error(
3099
+ node.line if hasattr(node, 'line') else 0,
3100
+ f"Captured reference '%{name}' not found",
3101
+ hint
3102
+ )
2746
3103
 
2747
3104
  if node.type == 'instance_ref':
2748
3105
  # instance<"name"> - get shared instance by name
@@ -2831,6 +3188,58 @@ class CSSLRuntime:
2831
3188
  if node.type == 'unary':
2832
3189
  return self._eval_unary(node)
2833
3190
 
3191
+ if node.type == 'non_null_assert':
3192
+ # *$var, *@module, *identifier - assert value is not null/None
3193
+ operand = node.value.get('operand')
3194
+ value = self._evaluate(operand)
3195
+ if value is None:
3196
+ # Get name of the operand for better error message
3197
+ operand_name = "unknown"
3198
+ if isinstance(operand, ASTNode):
3199
+ if operand.type == 'identifier':
3200
+ operand_name = operand.value
3201
+ elif operand.type == 'shared_ref':
3202
+ operand_name = f"${operand.value}"
3203
+ elif operand.type == 'module_ref':
3204
+ operand_name = f"@{operand.value}"
3205
+ elif operand.type == 'global_ref':
3206
+ operand_name = f"r@{operand.value}"
3207
+ raise self._format_error(
3208
+ node.line if hasattr(node, 'line') else 0,
3209
+ f"Non-null assertion failed: '{operand_name}' is null/None",
3210
+ f"The value accessed via '*{operand_name}' must not be null. Check that it is defined and initialized."
3211
+ )
3212
+ return value
3213
+
3214
+ if node.type == 'type_exclude_assert':
3215
+ # *[type]expr - assert value is NOT of excluded type
3216
+ exclude_type = node.value.get('exclude_type')
3217
+ operand = node.value.get('operand')
3218
+ value = self._evaluate(operand)
3219
+
3220
+ # Map CSSL types to Python types
3221
+ type_map = {
3222
+ 'string': str,
3223
+ 'int': int,
3224
+ 'float': float,
3225
+ 'bool': bool,
3226
+ 'null': type(None),
3227
+ 'none': type(None),
3228
+ 'list': list,
3229
+ 'array': list,
3230
+ 'dict': dict,
3231
+ 'json': dict,
3232
+ }
3233
+
3234
+ excluded_py_type = type_map.get(exclude_type.lower() if isinstance(exclude_type, str) else exclude_type)
3235
+ if excluded_py_type and isinstance(value, excluded_py_type):
3236
+ raise self._format_error(
3237
+ node.line if hasattr(node, 'line') else 0,
3238
+ f"Type exclusion assertion failed: value is of excluded type '{exclude_type}'",
3239
+ f"The expression was marked *[{exclude_type}] meaning it must NOT return {exclude_type}, but it did."
3240
+ )
3241
+ return value
3242
+
2834
3243
  if node.type == 'call':
2835
3244
  return self._eval_call(node)
2836
3245
 
@@ -3108,12 +3517,33 @@ class CSSLRuntime:
3108
3517
  return self._call_function(callee, args, kwargs)
3109
3518
 
3110
3519
  callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
3111
- raise CSSLRuntimeError(
3112
- f"Cannot call '{callee_name}' - it is not a function",
3113
- node.line,
3114
- context=f"Type: {type(callee).__name__}",
3115
- hint=ERROR_HINTS['undefined_function']
3116
- )
3520
+
3521
+ # Build detailed error with suggestions
3522
+ available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
3523
+ similar = _find_similar_names(callee_name, available_funcs)
3524
+
3525
+ if callee is None:
3526
+ # Function not found at all
3527
+ if similar:
3528
+ hint = f"Did you mean: {', '.join(similar)}?"
3529
+ else:
3530
+ hint = f"Function '{callee_name}' is not defined. Define it with: define {callee_name}() {{ }}"
3531
+ raise self._format_error(
3532
+ node.line,
3533
+ f"Function '{callee_name}' not found",
3534
+ hint
3535
+ )
3536
+ else:
3537
+ # Found something but it's not callable
3538
+ if similar:
3539
+ hint = f"'{callee_name}' is a {type(callee).__name__}, not a function. Did you mean: {', '.join(similar)}?"
3540
+ else:
3541
+ hint = f"'{callee_name}' is a {type(callee).__name__}. Functions must be defined with 'define' keyword."
3542
+ raise self._format_error(
3543
+ node.line,
3544
+ f"Cannot call '{callee_name}' - it is not a function",
3545
+ hint
3546
+ )
3117
3547
 
3118
3548
  def _eval_typed_call(self, node: ASTNode) -> Any:
3119
3549
  """Evaluate typed function call like OpenFind<string>(0) or OpenFind<dynamic, "name">"""
@@ -3179,26 +3609,53 @@ class CSSLRuntime:
3179
3609
  )
3180
3610
 
3181
3611
  def _eval_new(self, node: ASTNode) -> CSSLInstance:
3182
- """Evaluate 'new ClassName(args)' expression.
3612
+ """Evaluate 'new ClassName(args)' or 'new @ClassName(args)' expression.
3183
3613
 
3184
3614
  Creates a new instance of a CSSL class and calls its constructor.
3185
3615
  Supports multiple constructors (constr keyword), class parameters,
3186
3616
  and automatic parent constructor calling.
3617
+
3618
+ With '@' prefix (new @ClassName), looks only in global scope.
3187
3619
  """
3188
3620
  class_name = node.value.get('class')
3621
+ is_global_ref = node.value.get('is_global_ref', False)
3189
3622
  args = [self._evaluate(arg) for arg in node.value.get('args', [])]
3190
3623
  kwargs = {k: self._evaluate(v) for k, v in node.value.get('kwargs', {}).items()}
3191
3624
 
3192
3625
  # Get class definition from scope
3193
- class_def = self.scope.get(class_name)
3194
- if class_def is None:
3195
- class_def = self.global_scope.get(class_name)
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)
3196
3636
 
3197
3637
  if class_def is None:
3198
- raise CSSLRuntimeError(
3199
- f"Class '{class_name}' not found",
3638
+ # Build detailed error with suggestions
3639
+ source_line = self._get_source_line(node.line)
3640
+ available_classes = _get_available_classes(self.scope, self.global_scope, self._promoted_globals)
3641
+ similar = _find_similar_names(class_name, available_classes)
3642
+
3643
+ # Check if class exists in global scope (user forgot @)
3644
+ global_class = self._promoted_globals.get(class_name) or self.global_scope.get(class_name)
3645
+ if global_class and isinstance(global_class, CSSLClass) and not is_global_ref:
3646
+ hint = f"Class '{class_name}' exists in global scope. Use: new @{class_name}()"
3647
+ elif similar:
3648
+ hint = f"Did you mean: {', '.join(similar)}?"
3649
+ elif available_classes:
3650
+ hint = f"Available classes: {', '.join(available_classes[:5])}"
3651
+ else:
3652
+ hint = "Define the class before instantiation, or use 'global class' / 'class @Name' for global classes"
3653
+
3654
+ context = f"in expression: {source_line.strip()}" if source_line else None
3655
+ raise self._format_error(
3200
3656
  node.line,
3201
- hint="Make sure the class is defined before instantiation"
3657
+ f"Class '{class_name}' not found",
3658
+ hint
3202
3659
  )
3203
3660
 
3204
3661
  if not isinstance(class_def, CSSLClass):
@@ -3326,12 +3783,34 @@ class CSSLRuntime:
3326
3783
 
3327
3784
  # Resolve the class/instance reference
3328
3785
  if ref_class.startswith('$'):
3329
- # Dynamic instance reference: &$instanceVar::member
3786
+ # Dynamic instance reference: &$instanceVar::member or &$PyObject.method
3330
3787
  var_name = ref_class[1:]
3331
- ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
3788
+
3789
+ # First check in _live_objects for Python shared objects
3790
+ from ..cssl_bridge import _live_objects, SharedObjectProxy
3791
+ ref_obj = _live_objects.get(var_name)
3792
+ if ref_obj is None:
3793
+ ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
3794
+
3332
3795
  if ref_obj is None:
3333
3796
  return # Instance not found, skip silently
3334
3797
 
3798
+ # Handle Python shared objects
3799
+ if isinstance(ref_obj, SharedObjectProxy):
3800
+ ref_obj = ref_obj._obj
3801
+
3802
+ # If it's a Python object (not CSSL), call the method directly
3803
+ if not isinstance(ref_obj, (CSSLInstance, CSSLClass)):
3804
+ if ref_member and hasattr(ref_obj, ref_member):
3805
+ method = getattr(ref_obj, ref_member)
3806
+ if callable(method):
3807
+ try:
3808
+ method(*args, **kwargs)
3809
+ except TypeError:
3810
+ # Try without args
3811
+ method()
3812
+ return
3813
+
3335
3814
  if isinstance(ref_obj, CSSLInstance):
3336
3815
  # Get the class definition from the instance
3337
3816
  target_class = ref_obj.class_def
@@ -3490,9 +3969,24 @@ class CSSLRuntime:
3490
3969
  return lambda *args, **kwargs: python_method(*args, **kwargs)
3491
3970
  return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
3492
3971
 
3493
- raise CSSLRuntimeError(
3494
- f"'{instance._class.name}' has no member or method '{member}'",
3495
- node.line if hasattr(node, 'line') else 0
3972
+ # 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 []
3976
+ all_available = available_members + available_methods
3977
+ similar = _find_similar_names(member, all_available)
3978
+
3979
+ if similar:
3980
+ hint = f"Did you mean: {', '.join(similar)}?"
3981
+ elif all_available:
3982
+ hint = f"Available: {', '.join(all_available[:5])}"
3983
+ else:
3984
+ hint = f"Class '{class_name}' has no accessible members. Check class definition."
3985
+
3986
+ raise self._format_error(
3987
+ node.line if hasattr(node, 'line') else 0,
3988
+ f"'{class_name}' has no member or method '{member}'",
3989
+ hint
3496
3990
  )
3497
3991
 
3498
3992
  def _call_method(self, instance: CSSLInstance, method_node: ASTNode, args: list, kwargs: dict = None) -> Any:
@@ -3536,9 +4030,19 @@ class CSSLRuntime:
3536
4030
  self.scope = new_scope
3537
4031
  self._current_instance = instance
3538
4032
 
4033
+ original_return = None
3539
4034
  try:
4035
+ # Handle append mode via _append_to_target (stored original)
4036
+ original_method = func_info.get('_original_method')
4037
+ if original_method:
4038
+ # Execute original method first - capture return for fallback
4039
+ try:
4040
+ original_return = self._call_method(instance, original_method, args, kwargs)
4041
+ except CSSLReturn as ret:
4042
+ original_return = ret.value
4043
+
3540
4044
  # Handle append mode (++) - execute referenced parent method first
3541
- if append_mode and append_ref_class:
4045
+ elif append_mode and append_ref_class:
3542
4046
  self._execute_append_reference(
3543
4047
  instance, append_ref_class, append_ref_member,
3544
4048
  args, kwargs, {}, is_constructor=False
@@ -3559,7 +4063,8 @@ class CSSLRuntime:
3559
4063
  self.scope = old_scope
3560
4064
  self._current_instance = old_instance
3561
4065
 
3562
- return None
4066
+ # If no return in appended code, use original's return
4067
+ return original_return
3563
4068
 
3564
4069
  def _eval_member_access(self, node: ASTNode) -> Any:
3565
4070
  """Evaluate member access"""
@@ -3587,7 +4092,25 @@ class CSSLRuntime:
3587
4092
  python_method = method_node[1]
3588
4093
  return lambda *args, **kwargs: python_method(*args, **kwargs)
3589
4094
  return lambda *args, **kwargs: self._call_method(obj, method_node, list(args), kwargs)
3590
- raise CSSLRuntimeError(f"'{obj._class.name}' has no member or method '{member}'")
4095
+ # Build helpful error with available members
4096
+ class_name = obj._class.name
4097
+ available_members = list(obj._members.keys()) if hasattr(obj, '_members') else []
4098
+ available_methods = list(obj._methods.keys()) if hasattr(obj, '_methods') else []
4099
+ all_available = available_members + available_methods
4100
+ similar = _find_similar_names(member, all_available)
4101
+
4102
+ if similar:
4103
+ hint = f"Did you mean: {', '.join(similar)}?"
4104
+ elif all_available:
4105
+ hint = f"Available: {', '.join(all_available[:5])}"
4106
+ else:
4107
+ hint = f"Class '{class_name}' has no accessible members."
4108
+
4109
+ raise self._format_error(
4110
+ node.line,
4111
+ f"'{class_name}' has no member or method '{member}'",
4112
+ hint
4113
+ )
3591
4114
 
3592
4115
  # === STRING METHODS ===
3593
4116
  if isinstance(obj, str):