IncludeCPP 4.0.1__py3-none-any.whl → 4.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
includecpp/__init__.py CHANGED
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "4.0.1"
5
+ __version__ = "4.0.2"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -278,6 +278,26 @@ class CSSLRuntime:
278
278
  self._setup_modules()
279
279
  self._setup_builtins()
280
280
 
281
+ def output(self, text: str, level: str = 'normal') -> None:
282
+ """Output text, using callback if available, otherwise print."""
283
+ if self._output_callback:
284
+ self._output_callback(text, level)
285
+ else:
286
+ print(text, end='')
287
+ self.output_buffer.append(text)
288
+
289
+ def debug(self, text: str) -> None:
290
+ """Debug output."""
291
+ self.output(f"[DEBUG] {text}\n", 'debug')
292
+
293
+ def error(self, text: str) -> None:
294
+ """Error output."""
295
+ self.output(f"[ERROR] {text}\n", 'error')
296
+
297
+ def warn(self, text: str) -> None:
298
+ """Warning output."""
299
+ self.output(f"[WARN] {text}\n", 'warning')
300
+
281
301
  def _setup_modules(self):
282
302
  """Setup module references for @KernelClient, @VSRAM, etc."""
283
303
  if self.service_engine:
@@ -1310,29 +1330,38 @@ class CSSLRuntime:
1310
1330
  def _exec_instance_declaration(self, node: ASTNode) -> Any:
1311
1331
  """Execute instance declaration: instance<"name"> varName;
1312
1332
 
1313
- Gets or creates a shared instance by name.
1333
+ Gets or creates a universal shared instance by name.
1334
+ Universal instances are accessible from CSSL, Python, and C++.
1335
+
1336
+ Usage:
1337
+ instance<"myContainer"> container; // Creates or gets instance
1338
+ container.member = "value"; // Set member
1339
+ container +<<== { void func() {} } // Inject methods
1314
1340
  """
1315
- from ..cssl_bridge import _live_objects, SharedObjectProxy
1341
+ from .cssl_types import UniversalInstance
1342
+
1316
1343
  decl = node.value
1317
1344
  instance_name = decl.get('instance_name')
1318
1345
  var_name = decl.get('name')
1319
1346
  value_node = decl.get('value')
1320
1347
 
1321
- # Get existing shared instance
1322
- instance = None
1323
- if instance_name in _live_objects:
1324
- instance = SharedObjectProxy(instance_name, _live_objects[instance_name])
1325
- elif self.global_scope.has(f'${instance_name}'):
1326
- instance = self.global_scope.get(f'${instance_name}')
1348
+ # Get existing or create new universal instance
1349
+ instance = UniversalInstance.get_or_create(instance_name)
1327
1350
 
1328
- # If value is provided, use that and register as shared
1351
+ # If value is provided, set it as initial content
1329
1352
  if value_node:
1330
- instance = self._evaluate(value_node)
1331
- # Register in global scope for future access
1332
- self.global_scope.set(f'${instance_name}', instance)
1353
+ initial_value = self._evaluate(value_node)
1354
+ # If it's a dict, set all keys as members
1355
+ if isinstance(initial_value, dict):
1356
+ for key, val in initial_value.items():
1357
+ instance.set_member(key, val)
1358
+ else:
1359
+ instance.set_member('value', initial_value)
1333
1360
 
1334
- # Store in scope
1361
+ # Store in scope and global scope for access
1335
1362
  self.scope.set(var_name, instance)
1363
+ self.global_scope.set(f'${instance_name}', instance)
1364
+
1336
1365
  return instance
1337
1366
 
1338
1367
  def _exec_super_func(self, node: ASTNode) -> Any:
@@ -2736,8 +2765,13 @@ class CSSLRuntime:
2736
2765
  - add: func +<<== { code } - ADDS code to function (both execute)
2737
2766
  - remove: func -<<== { code } - REMOVES matching code from function
2738
2767
 
2768
+ Also supports instance injection:
2769
+ - instance +<<== { void method() { ... } } - ADDS methods to UniversalInstance
2770
+
2739
2771
  Also supports expression form: func <<== %exit() (wraps in action_block)
2740
2772
  """
2773
+ from .cssl_types import UniversalInstance
2774
+
2741
2775
  target = node.value.get('target')
2742
2776
  code_block = node.value.get('code')
2743
2777
  source_expr = node.value.get('source') # For expression form: func <<== expr
@@ -2749,6 +2783,17 @@ class CSSLRuntime:
2749
2783
  expr_node = ASTNode('expression', value=source_expr)
2750
2784
  code_block = ASTNode('action_block', children=[expr_node])
2751
2785
 
2786
+ # Check if target is a UniversalInstance
2787
+ target_value = None
2788
+ if isinstance(target, ASTNode) and target.type == 'identifier':
2789
+ target_value = self.scope.get(target.value)
2790
+ if target_value is None:
2791
+ target_value = self.global_scope.get(target.value)
2792
+
2793
+ # Handle UniversalInstance injection
2794
+ if isinstance(target_value, UniversalInstance):
2795
+ return self._inject_into_instance(target_value, code_block, mode)
2796
+
2752
2797
  # Get function name from target
2753
2798
  func_name = None
2754
2799
  if isinstance(target, ASTNode):
@@ -2796,6 +2841,60 @@ class CSSLRuntime:
2796
2841
 
2797
2842
  return None
2798
2843
 
2844
+ def _inject_into_instance(self, instance: Any, code_block: Any, mode: str) -> Any:
2845
+ """Inject code/methods into a UniversalInstance.
2846
+
2847
+ Usage:
2848
+ instance<"myContainer"> container;
2849
+ container +<<== {
2850
+ void sayHello() { printl("Hello!"); }
2851
+ int value = 42;
2852
+ }
2853
+ """
2854
+ from .cssl_types import UniversalInstance
2855
+
2856
+ if not isinstance(instance, UniversalInstance):
2857
+ return None
2858
+
2859
+ if code_block is None:
2860
+ return None
2861
+
2862
+ # Store the raw injection
2863
+ instance.add_injection(code_block)
2864
+
2865
+ # Parse the code block for function definitions and variable declarations
2866
+ if isinstance(code_block, ASTNode):
2867
+ children = code_block.children if hasattr(code_block, 'children') else []
2868
+
2869
+ for child in children:
2870
+ if isinstance(child, ASTNode):
2871
+ if child.type == 'function':
2872
+ # Extract function name and store the AST node
2873
+ func_info = child.value
2874
+ func_name = func_info.get('name') if isinstance(func_info, dict) else None
2875
+ if func_name:
2876
+ instance.set_method(func_name, child)
2877
+ elif child.type == 'var_declaration':
2878
+ # Extract variable and value
2879
+ var_info = child.value
2880
+ if isinstance(var_info, dict):
2881
+ var_name = var_info.get('name')
2882
+ value_node = var_info.get('value')
2883
+ if var_name:
2884
+ value = self._evaluate(value_node) if value_node else None
2885
+ instance.set_member(var_name, value)
2886
+ elif child.type == 'typed_var_declaration':
2887
+ # Typed variable declaration
2888
+ var_info = child.value
2889
+ if isinstance(var_info, dict):
2890
+ var_name = var_info.get('name')
2891
+ value_node = var_info.get('value')
2892
+ if var_name:
2893
+ value = self._evaluate(value_node) if value_node else None
2894
+ instance.set_member(var_name, value)
2895
+
2896
+ return instance
2897
+
2799
2898
  def _exec_infuse_right(self, node: ASTNode) -> Any:
2800
2899
  """Execute right-side code infusion (==>>)"""
2801
2900
  source = node.value.get('source')
@@ -3516,7 +3615,33 @@ class CSSLRuntime:
3516
3615
  if isinstance(callee, ASTNode) and callee.type == 'function':
3517
3616
  return self._call_function(callee, args, kwargs)
3518
3617
 
3519
- callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
3618
+ # Extract callee name for error messages
3619
+ if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value'):
3620
+ val = callee_node.value
3621
+ if isinstance(val, str):
3622
+ callee_name = val
3623
+ elif isinstance(val, dict):
3624
+ # For member access nodes like obj.method, get the member name
3625
+ if 'member' in val:
3626
+ obj_node = val.get('object')
3627
+ member = val.get('member')
3628
+ obj_name = obj_node.value if isinstance(obj_node, ASTNode) else str(obj_node)
3629
+ callee_name = f"{obj_name}.{member}"
3630
+ # For call nodes, try to get the callee name
3631
+ elif 'callee' in val:
3632
+ callee_val = val.get('callee')
3633
+ if isinstance(callee_val, ASTNode):
3634
+ callee_name = callee_val.value if isinstance(callee_val.value, str) else str(callee_val.value)
3635
+ else:
3636
+ callee_name = str(callee_val)
3637
+ elif 'name' in val:
3638
+ callee_name = str(val.get('name'))
3639
+ else:
3640
+ callee_name = str(val)
3641
+ else:
3642
+ callee_name = str(val)
3643
+ else:
3644
+ callee_name = str(callee_node)
3520
3645
 
3521
3646
  # Build detailed error with suggestions
3522
3647
  available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
@@ -4112,6 +4237,48 @@ class CSSLRuntime:
4112
4237
  hint
4113
4238
  )
4114
4239
 
4240
+ # === UNIVERSAL INSTANCE METHODS ===
4241
+ from .cssl_types import UniversalInstance
4242
+ if isinstance(obj, UniversalInstance):
4243
+ # Check for member variable
4244
+ if obj.has_member(member):
4245
+ return obj.get_member(member)
4246
+ # Check for method
4247
+ if obj.has_method(member):
4248
+ method_node = obj.get_method(member)
4249
+ # Create a callable that executes the method in context
4250
+ def instance_method_caller(*args, **kwargs):
4251
+ # Set 'this' to refer to the instance
4252
+ old_this = self.scope.get('this')
4253
+ self.scope.set('this', obj)
4254
+ try:
4255
+ return self._call_function(method_node, list(args))
4256
+ finally:
4257
+ if old_this is not None:
4258
+ self.scope.set('this', old_this)
4259
+ else:
4260
+ self.scope.remove('this') if hasattr(self.scope, 'remove') else None
4261
+ return instance_method_caller
4262
+ # Build helpful error with available members
4263
+ instance_name = obj.name
4264
+ available_members = list(obj.get_all_members().keys())
4265
+ available_methods = list(obj.get_all_methods().keys())
4266
+ all_available = available_members + available_methods
4267
+ similar = _find_similar_names(member, all_available)
4268
+
4269
+ if similar:
4270
+ hint = f"Did you mean: {', '.join(similar)}?"
4271
+ elif all_available:
4272
+ hint = f"Available: {', '.join(all_available[:5])}"
4273
+ else:
4274
+ hint = f"Instance '{instance_name}' has no accessible members."
4275
+
4276
+ raise self._format_error(
4277
+ node.line,
4278
+ f"Instance '{instance_name}' has no member or method '{member}'",
4279
+ hint
4280
+ )
4281
+
4115
4282
  # === STRING METHODS ===
4116
4283
  if isinstance(obj, str):
4117
4284
  string_methods = self._get_string_method(obj, member)
@@ -4350,6 +4517,12 @@ class CSSLRuntime:
4350
4517
  obj.set_member(member, value)
4351
4518
  return
4352
4519
 
4520
+ # Check for UniversalInstance - use set_member method
4521
+ from .cssl_types import UniversalInstance
4522
+ if isinstance(obj, UniversalInstance):
4523
+ obj.set_member(member, value)
4524
+ return
4525
+
4353
4526
  # Check for SharedObjectProxy - directly access underlying object
4354
4527
  # This is more robust than relying on the proxy's __setattr__
4355
4528
  if hasattr(obj, '_direct_object') and hasattr(obj, '_name'):
@@ -1624,10 +1624,152 @@ class CSSLInstance:
1624
1624
  return f"<{self._class.name} instance at 0x{id(self):x}>"
1625
1625
 
1626
1626
 
1627
+ class UniversalInstance:
1628
+ """Universal shared container accessible from CSSL, Python, and C++.
1629
+
1630
+ Created via instance<"name"> syntax in CSSL or getInstance("name") in Python.
1631
+ Supports dynamic member/method injection via +<<== operator.
1632
+
1633
+ Example CSSL:
1634
+ instance<"myContainer"> container;
1635
+ container +<<== { void sayHello() { printl("Hello!"); } }
1636
+ container.sayHello();
1637
+
1638
+ Example Python:
1639
+ container = cssl.getInstance("myContainer")
1640
+ container.sayHello()
1641
+ """
1642
+
1643
+ # Global registry for all universal instances
1644
+ _registry: Dict[str, 'UniversalInstance'] = {}
1645
+
1646
+ def __init__(self, name: str):
1647
+ self._name = name
1648
+ self._members: Dict[str, Any] = {}
1649
+ self._methods: Dict[str, Any] = {} # Method name -> AST node or callable
1650
+ self._injections: List[Any] = [] # Code blocks injected via +<<==
1651
+ # Register globally
1652
+ UniversalInstance._registry[name] = self
1653
+
1654
+ @classmethod
1655
+ def get_or_create(cls, name: str) -> 'UniversalInstance':
1656
+ """Get existing instance or create new one."""
1657
+ if name in cls._registry:
1658
+ return cls._registry[name]
1659
+ return cls(name)
1660
+
1661
+ @classmethod
1662
+ def get(cls, name: str) -> Optional['UniversalInstance']:
1663
+ """Get existing instance by name, returns None if not found."""
1664
+ return cls._registry.get(name)
1665
+
1666
+ @classmethod
1667
+ def exists(cls, name: str) -> bool:
1668
+ """Check if instance exists."""
1669
+ return name in cls._registry
1670
+
1671
+ @classmethod
1672
+ def delete(cls, name: str) -> bool:
1673
+ """Delete instance from registry."""
1674
+ if name in cls._registry:
1675
+ del cls._registry[name]
1676
+ return True
1677
+ return False
1678
+
1679
+ @classmethod
1680
+ def clear_all(cls) -> int:
1681
+ """Clear all instances. Returns count of cleared instances."""
1682
+ count = len(cls._registry)
1683
+ cls._registry.clear()
1684
+ return count
1685
+
1686
+ @classmethod
1687
+ def list_all(cls) -> List[str]:
1688
+ """List all instance names."""
1689
+ return list(cls._registry.keys())
1690
+
1691
+ @property
1692
+ def name(self) -> str:
1693
+ """Get instance name."""
1694
+ return self._name
1695
+
1696
+ def set_member(self, name: str, value: Any) -> None:
1697
+ """Set a member value."""
1698
+ self._members[name] = value
1699
+
1700
+ def get_member(self, name: str) -> Any:
1701
+ """Get a member value."""
1702
+ if name in self._members:
1703
+ return self._members[name]
1704
+ raise AttributeError(f"Instance '{self._name}' has no member '{name}'")
1705
+
1706
+ def has_member(self, name: str) -> bool:
1707
+ """Check if member exists."""
1708
+ return name in self._members
1709
+
1710
+ def set_method(self, name: str, method: Any) -> None:
1711
+ """Set a method (AST node or callable)."""
1712
+ self._methods[name] = method
1713
+
1714
+ def get_method(self, name: str) -> Any:
1715
+ """Get a method by name."""
1716
+ if name in self._methods:
1717
+ return self._methods[name]
1718
+ raise AttributeError(f"Instance '{self._name}' has no method '{name}'")
1719
+
1720
+ def has_method(self, name: str) -> bool:
1721
+ """Check if method exists."""
1722
+ return name in self._methods
1723
+
1724
+ def add_injection(self, code_block: Any) -> None:
1725
+ """Add a code injection (from +<<== operator)."""
1726
+ self._injections.append(code_block)
1727
+
1728
+ def get_injections(self) -> List[Any]:
1729
+ """Get all injected code blocks."""
1730
+ return self._injections
1731
+
1732
+ def get_all_members(self) -> Dict[str, Any]:
1733
+ """Get all members."""
1734
+ return dict(self._members)
1735
+
1736
+ def get_all_methods(self) -> Dict[str, Any]:
1737
+ """Get all methods."""
1738
+ return dict(self._methods)
1739
+
1740
+ def __getattr__(self, name: str) -> Any:
1741
+ """Allow direct attribute access for members and methods."""
1742
+ if name.startswith('_'):
1743
+ raise AttributeError(name)
1744
+ if name in object.__getattribute__(self, '_members'):
1745
+ return object.__getattribute__(self, '_members')[name]
1746
+ if name in object.__getattribute__(self, '_methods'):
1747
+ return object.__getattribute__(self, '_methods')[name]
1748
+ raise AttributeError(f"Instance '{object.__getattribute__(self, '_name')}' has no attribute '{name}'")
1749
+
1750
+ def __setattr__(self, name: str, value: Any) -> None:
1751
+ """Allow direct attribute setting for members."""
1752
+ if name.startswith('_'):
1753
+ object.__setattr__(self, name, value)
1754
+ else:
1755
+ if hasattr(self, '_members'):
1756
+ self._members[name] = value
1757
+ else:
1758
+ object.__setattr__(self, name, value)
1759
+
1760
+ def __repr__(self):
1761
+ members = len(self._members)
1762
+ methods = len(self._methods)
1763
+ return f"<UniversalInstance '{self._name}' ({members} members, {methods} methods)>"
1764
+
1765
+ def __str__(self):
1766
+ return f"<UniversalInstance '{self._name}'>"
1767
+
1768
+
1627
1769
  __all__ = [
1628
1770
  'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
1629
1771
  'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array', 'List', 'Dictionary', 'Map',
1630
- 'CSSLClass', 'CSSLInstance',
1772
+ 'CSSLClass', 'CSSLInstance', 'UniversalInstance',
1631
1773
  'create_datastruct', 'create_shuffled', 'create_iterator',
1632
1774
  'create_combo', 'create_dataspace', 'create_openquote', 'create_parameter',
1633
1775
  'create_stack', 'create_vector', 'create_array', 'create_list', 'create_dictionary', 'create_map'