IncludeCPP 3.7.9__py3-none-any.whl → 3.7.25__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.
@@ -19,6 +19,45 @@ from .cssl_types import (
19
19
  )
20
20
 
21
21
 
22
+ # Global custom filter registry
23
+ # Structure: { "type::helper": callback_function }
24
+ # Callback signature: (source, filter_value, runtime) -> Any
25
+ _custom_filters: Dict[str, Callable[[Any, Any, Any], Any]] = {}
26
+
27
+
28
+ def register_filter(filter_type: str, helper: str, callback: Callable[[Any, Any, Any], Any]) -> None:
29
+ """Register a custom filter.
30
+
31
+ Args:
32
+ filter_type: The filter type (e.g., "mytype")
33
+ helper: The helper name (e.g., "where", "index", or "*" for catch-all)
34
+ callback: Function(source, filter_value, runtime) -> filtered_result
35
+
36
+ Usage in CSSL:
37
+ result <==[mytype::where="value"] source;
38
+
39
+ Usage from Python:
40
+ from includecpp.core.cssl.cssl_runtime import register_filter
41
+ register_filter("mytype", "where", lambda src, val, rt: ...)
42
+ """
43
+ key = f"{filter_type}::{helper}"
44
+ _custom_filters[key] = callback
45
+
46
+
47
+ def unregister_filter(filter_type: str, helper: str) -> bool:
48
+ """Unregister a custom filter."""
49
+ key = f"{filter_type}::{helper}"
50
+ if key in _custom_filters:
51
+ del _custom_filters[key]
52
+ return True
53
+ return False
54
+
55
+
56
+ def get_custom_filters() -> Dict[str, Callable]:
57
+ """Get all registered custom filters."""
58
+ return _custom_filters.copy()
59
+
60
+
22
61
  class CSSLRuntimeError(Exception):
23
62
  """Runtime error during CSSL execution with detailed context"""
24
63
  def __init__(self, message: str, line: int = 0, context: str = None, hint: str = None):
@@ -791,8 +830,18 @@ class CSSLRuntime:
791
830
  if hasattr(instance, 'append'):
792
831
  instance.append(init_value)
793
832
 
833
+ # Check for global modifier
834
+ modifiers = decl.get('modifiers', [])
835
+ is_global = 'global' in modifiers
836
+
794
837
  # Store in scope
795
838
  self.scope.set(var_name, instance)
839
+
840
+ # If global, also store in promoted_globals and global_scope
841
+ if is_global:
842
+ self._promoted_globals[var_name] = instance
843
+ self.global_scope.set(var_name, instance)
844
+
796
845
  return instance
797
846
 
798
847
  def _exec_instance_declaration(self, node: ASTNode) -> Any:
@@ -939,6 +988,14 @@ class CSSLRuntime:
939
988
  result = self._evaluate(inner.value)
940
989
  return result
941
990
 
991
+ # Handle typed declaration: global datastruct<int> data;
992
+ elif inner.type == 'typed_declaration':
993
+ # Add global modifier to the declaration
994
+ if isinstance(inner.value, dict):
995
+ inner.value['modifiers'] = inner.value.get('modifiers', []) + ['global']
996
+ result = self._exec_typed_declaration(inner)
997
+ return result
998
+
942
999
  # Fallback: execute normally
943
1000
  return self._execute_node(inner)
944
1001
 
@@ -1274,8 +1331,11 @@ class CSSLRuntime:
1274
1331
 
1275
1332
  return command_name
1276
1333
 
1277
- def _apply_injection_filter(self, source: Any, filter_info: dict) -> Any:
1278
- """Apply injection filter to extract specific data from source.
1334
+ def _apply_injection_filter(self, source: Any, filter_info) -> Any:
1335
+ """Apply injection filter(s) to extract specific data from source.
1336
+
1337
+ Supports both single filter dict and list of filter dicts for chained filters.
1338
+ Example: [dynamic::content=10][dynamic::content=100] applies both filters.
1279
1339
 
1280
1340
  All BruteInjector Helpers:
1281
1341
  - string::where=VALUE - Filter strings containing VALUE
@@ -1292,10 +1352,31 @@ class CSSLRuntime:
1292
1352
  - combo::blocked - Get blocked items from combo
1293
1353
  - dynamic::VarName=VALUE - Filter by dynamic variable value
1294
1354
  - sql::data - Return only SQL-compatible data
1355
+ - instance::class - Get classes from object
1356
+ - instance::method - Get methods from object
1357
+ - instance::var - Get variables from object
1358
+ - instance::all - Get all categorized (methods, classes, vars)
1359
+ - instance::"ClassName" - Get specific class by name
1360
+ - name::"Name" - Filter by name (class, dict key, attribute)
1295
1361
  """
1296
1362
  if not filter_info:
1297
1363
  return source
1298
1364
 
1365
+ # Handle list of filters (chained filters)
1366
+ if isinstance(filter_info, list):
1367
+ result = source
1368
+ for single_filter in filter_info:
1369
+ result = self._apply_single_filter(result, single_filter)
1370
+ return result
1371
+
1372
+ # Single filter (dict)
1373
+ return self._apply_single_filter(source, filter_info)
1374
+
1375
+ def _apply_single_filter(self, source: Any, filter_info: dict) -> Any:
1376
+ """Apply a single injection filter to extract specific data from source."""
1377
+ if not filter_info:
1378
+ return source
1379
+
1299
1380
  result = source
1300
1381
 
1301
1382
  for filter_key, filter_value in filter_info.items():
@@ -1303,6 +1384,18 @@ class CSSLRuntime:
1303
1384
  filter_type, helper = filter_key.split('::', 1)
1304
1385
  filter_val = self._evaluate(filter_value) if isinstance(filter_value, ASTNode) else filter_value
1305
1386
 
1387
+ # === CHECK CUSTOM FILTERS FIRST ===
1388
+ custom_key = f"{filter_type}::{helper}"
1389
+ if custom_key in _custom_filters:
1390
+ result = _custom_filters[custom_key](result, filter_val, self)
1391
+ continue
1392
+
1393
+ # Check for catch-all custom filter (type::*)
1394
+ catchall_key = f"{filter_type}::*"
1395
+ if catchall_key in _custom_filters:
1396
+ result = _custom_filters[catchall_key](result, filter_val, self)
1397
+ continue
1398
+
1306
1399
  # === STRING HELPERS ===
1307
1400
  if filter_type == 'string':
1308
1401
  if helper == 'where':
@@ -1479,13 +1572,112 @@ class CSSLRuntime:
1479
1572
 
1480
1573
  # === DYNAMIC HELPERS ===
1481
1574
  elif filter_type == 'dynamic':
1482
- # dynamic::VarName=VALUE - Match if variable equals value
1483
- var_name = helper
1484
- var_value = self.scope.get(var_name)
1485
- if var_value == filter_val:
1486
- pass # Keep result
1575
+ if helper == 'content':
1576
+ # dynamic::content=VALUE - General content filter for any type
1577
+ # Filters elements where content equals VALUE
1578
+ if isinstance(result, (list, tuple)):
1579
+ # Filter list/tuple elements by content value
1580
+ result = [item for item in result if item == filter_val]
1581
+ elif isinstance(result, dict):
1582
+ # Filter dict by values matching filter_val
1583
+ result = {k: v for k, v in result.items() if v == filter_val}
1584
+ elif result == filter_val:
1585
+ pass # Keep result if it matches
1586
+ else:
1587
+ result = None
1588
+ elif helper == 'not':
1589
+ # dynamic::not=VALUE - Exclude elements equal to VALUE
1590
+ if isinstance(result, (list, tuple)):
1591
+ result = [item for item in result if item != filter_val]
1592
+ elif isinstance(result, dict):
1593
+ result = {k: v for k, v in result.items() if v != filter_val}
1594
+ elif result != filter_val:
1595
+ pass # Keep result if it doesn't match
1596
+ else:
1597
+ result = None
1598
+ elif helper == 'gt':
1599
+ # dynamic::gt=VALUE - Greater than
1600
+ if isinstance(result, (list, tuple)):
1601
+ result = [item for item in result if item > filter_val]
1602
+ elif result > filter_val:
1603
+ pass
1604
+ else:
1605
+ result = None
1606
+ elif helper == 'lt':
1607
+ # dynamic::lt=VALUE - Less than
1608
+ if isinstance(result, (list, tuple)):
1609
+ result = [item for item in result if item < filter_val]
1610
+ elif result < filter_val:
1611
+ pass
1612
+ else:
1613
+ result = None
1614
+ elif helper == 'gte':
1615
+ # dynamic::gte=VALUE - Greater than or equal
1616
+ if isinstance(result, (list, tuple)):
1617
+ result = [item for item in result if item >= filter_val]
1618
+ elif result >= filter_val:
1619
+ pass
1620
+ else:
1621
+ result = None
1622
+ elif helper == 'lte':
1623
+ # dynamic::lte=VALUE - Less than or equal
1624
+ if isinstance(result, (list, tuple)):
1625
+ result = [item for item in result if item <= filter_val]
1626
+ elif result <= filter_val:
1627
+ pass
1628
+ else:
1629
+ result = None
1630
+ elif helper == 'mod':
1631
+ # dynamic::mod=VALUE - Modulo filter (item % VALUE == 0)
1632
+ if isinstance(result, (list, tuple)):
1633
+ result = [item for item in result if isinstance(item, (int, float)) and item % filter_val == 0]
1634
+ elif isinstance(result, (int, float)) and result % filter_val == 0:
1635
+ pass
1636
+ else:
1637
+ result = None
1638
+ elif helper == 'range':
1639
+ # dynamic::range="min:max" - Filter values in range
1640
+ if isinstance(filter_val, str) and ':' in filter_val:
1641
+ parts = filter_val.split(':')
1642
+ min_val = int(parts[0]) if parts[0] else None
1643
+ max_val = int(parts[1]) if parts[1] else None
1644
+ if isinstance(result, (list, tuple)):
1645
+ def in_range(x):
1646
+ if min_val is not None and x < min_val:
1647
+ return False
1648
+ if max_val is not None and x > max_val:
1649
+ return False
1650
+ return True
1651
+ result = [item for item in result if in_range(item)]
1652
+ elif isinstance(result, (int, float)):
1653
+ if min_val is not None and result < min_val:
1654
+ result = None
1655
+ elif max_val is not None and result > max_val:
1656
+ result = None
1657
+ elif helper == 'even':
1658
+ # dynamic::even - Filter even numbers
1659
+ if isinstance(result, (list, tuple)):
1660
+ result = [item for item in result if isinstance(item, int) and item % 2 == 0]
1661
+ elif isinstance(result, int) and result % 2 == 0:
1662
+ pass
1663
+ else:
1664
+ result = None
1665
+ elif helper == 'odd':
1666
+ # dynamic::odd - Filter odd numbers
1667
+ if isinstance(result, (list, tuple)):
1668
+ result = [item for item in result if isinstance(item, int) and item % 2 != 0]
1669
+ elif isinstance(result, int) and result % 2 != 0:
1670
+ pass
1671
+ else:
1672
+ result = None
1487
1673
  else:
1488
- result = None
1674
+ # dynamic::VarName=VALUE - Match if variable equals value
1675
+ var_name = helper
1676
+ var_value = self.scope.get(var_name)
1677
+ if var_value == filter_val:
1678
+ pass # Keep result
1679
+ else:
1680
+ result = None
1489
1681
 
1490
1682
  # === SQL HELPERS ===
1491
1683
  elif filter_type == 'sql':
@@ -1496,6 +1688,128 @@ class CSSLRuntime:
1496
1688
  else:
1497
1689
  result = str(result) # Convert to string
1498
1690
 
1691
+ # === INSTANCE HELPERS ===
1692
+ # Works on CSSLInstance, Python objects, dicts, modules
1693
+ elif filter_type == 'instance':
1694
+ from .cssl_types import CSSLInstance
1695
+ import inspect
1696
+
1697
+ if isinstance(result, CSSLInstance):
1698
+ # Filter CSSL instances
1699
+ if helper in ('class', 'classes'):
1700
+ classes = {}
1701
+ for name, member in result._members.items():
1702
+ if isinstance(member, CSSLInstance):
1703
+ classes[name] = member
1704
+ result = classes if classes else None
1705
+ elif helper in ('method', 'methods'):
1706
+ result = dict(result._class.methods)
1707
+ elif helper in ('var', 'vars', 'variable', 'variables'):
1708
+ vars_dict = {}
1709
+ for name, member in result._members.items():
1710
+ if not isinstance(member, CSSLInstance):
1711
+ vars_dict[name] = member
1712
+ result = vars_dict
1713
+ elif helper in ('all',):
1714
+ result = {
1715
+ 'methods': list(result._class.methods.keys()),
1716
+ 'classes': [result._class.name] + [m._class.name for m in result._members.values() if isinstance(m, CSSLInstance)],
1717
+ 'vars': [n for n, m in result._members.items() if not isinstance(m, CSSLInstance)]
1718
+ }
1719
+ else:
1720
+ # Filter by class name
1721
+ class_name = filter_val if filter_val else helper
1722
+ found = None
1723
+ if result._class.name == class_name:
1724
+ found = result
1725
+ else:
1726
+ for name, member in result._members.items():
1727
+ if isinstance(member, CSSLInstance) and member._class.name == class_name:
1728
+ found = member
1729
+ break
1730
+ result = found
1731
+ elif isinstance(result, dict):
1732
+ # Filter dicts
1733
+ if helper in ('class', 'classes'):
1734
+ result = {k: v for k, v in result.items() if inspect.isclass(v)}
1735
+ elif helper in ('method', 'methods', 'func', 'function', 'functions'):
1736
+ result = {k: v for k, v in result.items() if callable(v)}
1737
+ elif helper in ('var', 'vars', 'variable', 'variables'):
1738
+ result = {k: v for k, v in result.items() if not callable(v) and not inspect.isclass(v)}
1739
+ else:
1740
+ # Get by key
1741
+ key_name = filter_val if filter_val else helper
1742
+ result = result.get(key_name)
1743
+ elif hasattr(result, '__dict__') or hasattr(result, '__class__'):
1744
+ # Filter Python objects/modules
1745
+ if helper in ('class', 'classes'):
1746
+ classes = {}
1747
+ for name in dir(result):
1748
+ if not name.startswith('_'):
1749
+ attr = getattr(result, name, None)
1750
+ if inspect.isclass(attr):
1751
+ classes[name] = attr
1752
+ result = classes if classes else None
1753
+ elif helper in ('method', 'methods', 'func', 'function', 'functions'):
1754
+ methods = {}
1755
+ for name in dir(result):
1756
+ if not name.startswith('_'):
1757
+ attr = getattr(result, name, None)
1758
+ if callable(attr):
1759
+ methods[name] = attr
1760
+ result = methods if methods else None
1761
+ elif helper in ('var', 'vars', 'variable', 'variables'):
1762
+ vars_dict = {}
1763
+ for name in dir(result):
1764
+ if not name.startswith('_'):
1765
+ attr = getattr(result, name, None)
1766
+ if not callable(attr) and not inspect.isclass(attr):
1767
+ vars_dict[name] = attr
1768
+ result = vars_dict if vars_dict else None
1769
+ elif helper in ('all',):
1770
+ all_info = {'methods': [], 'classes': [], 'vars': []}
1771
+ for name in dir(result):
1772
+ if not name.startswith('_'):
1773
+ attr = getattr(result, name, None)
1774
+ if inspect.isclass(attr):
1775
+ all_info['classes'].append(name)
1776
+ elif callable(attr):
1777
+ all_info['methods'].append(name)
1778
+ else:
1779
+ all_info['vars'].append(name)
1780
+ result = all_info
1781
+ else:
1782
+ # Get attribute by name
1783
+ attr_name = filter_val if filter_val else helper
1784
+ result = getattr(result, attr_name, None)
1785
+
1786
+ # === NAME HELPERS ===
1787
+ # General name filter for any object type
1788
+ elif filter_type == 'name':
1789
+ from .cssl_types import CSSLInstance
1790
+ target_name = filter_val if filter_val else helper
1791
+
1792
+ if isinstance(result, CSSLInstance):
1793
+ if result._class.name == target_name:
1794
+ pass # Keep result
1795
+ else:
1796
+ found = None
1797
+ for name, member in result._members.items():
1798
+ if isinstance(member, CSSLInstance) and member._class.name == target_name:
1799
+ found = member
1800
+ break
1801
+ result = found
1802
+ elif isinstance(result, dict):
1803
+ result = result.get(target_name)
1804
+ elif isinstance(result, list):
1805
+ result = [item for item in result if str(item) == target_name or (hasattr(item, 'name') and item.name == target_name)]
1806
+ elif hasattr(result, target_name):
1807
+ result = getattr(result, target_name)
1808
+ elif hasattr(result, '__class__') and result.__class__.__name__ == target_name:
1809
+ pass # Keep result if class name matches
1810
+ else:
1811
+ result = None
1812
+
1499
1813
  return result
1500
1814
 
1501
1815
  def _exec_inject(self, node: ASTNode) -> Any:
@@ -1553,7 +1867,15 @@ class CSSLRuntime:
1553
1867
  final_value = source
1554
1868
  elif mode == 'add':
1555
1869
  # Copy & add - preserve target and add source
1556
- if isinstance(current_value, list):
1870
+ from .cssl_types import CSSLInstance
1871
+
1872
+ # Special handling for CSSLInstance - merge classes
1873
+ if isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
1874
+ # Add the new class instance as a member with class name as key
1875
+ class_name = source._class.name
1876
+ current_value._members[class_name] = source
1877
+ final_value = current_value
1878
+ elif isinstance(current_value, list):
1557
1879
  if isinstance(source, list):
1558
1880
  final_value = current_value + source
1559
1881
  else:
@@ -1569,9 +1891,14 @@ class CSSLRuntime:
1569
1891
  elif mode == 'move':
1570
1892
  # Move & remove from source
1571
1893
  final_value = source
1572
- # Clear the source
1573
- if isinstance(source_node, ASTNode) and source_node.type == 'identifier':
1574
- self.scope.set(source_node.value, None)
1894
+ # Clear the source - handle all node types
1895
+ if isinstance(source_node, ASTNode):
1896
+ if source_node.type == 'identifier':
1897
+ self.scope.set(source_node.value, None)
1898
+ elif source_node.type == 'module_ref':
1899
+ self._set_module_value(source_node.value, None)
1900
+ elif source_node.type == 'member_access':
1901
+ self._set_member(source_node, None)
1575
1902
  else:
1576
1903
  final_value = source
1577
1904
 
@@ -1643,9 +1970,36 @@ class CSSLRuntime:
1643
1970
  final_value = [current_value, source]
1644
1971
  elif mode == 'move':
1645
1972
  final_value = source
1646
- # Clear the source
1647
- if isinstance(source_node, ASTNode) and source_node.type == 'identifier':
1648
- self.scope.set(source_node.value, None)
1973
+ # Remove filtered elements from source (not clear entirely)
1974
+ if isinstance(source_node, ASTNode):
1975
+ if filter_info:
1976
+ # Get original source value
1977
+ original_source = self._evaluate(source_node)
1978
+ if isinstance(original_source, list) and isinstance(final_value, list):
1979
+ # Remove filtered items from original list
1980
+ remaining = [item for item in original_source if item not in final_value]
1981
+ if source_node.type == 'identifier':
1982
+ self.scope.set(source_node.value, remaining)
1983
+ elif source_node.type == 'module_ref':
1984
+ self._set_module_value(source_node.value, remaining)
1985
+ elif source_node.type == 'member_access':
1986
+ self._set_member(source_node, remaining)
1987
+ else:
1988
+ # Single value filter - set source to None
1989
+ if source_node.type == 'identifier':
1990
+ self.scope.set(source_node.value, None)
1991
+ elif source_node.type == 'module_ref':
1992
+ self._set_module_value(source_node.value, None)
1993
+ elif source_node.type == 'member_access':
1994
+ self._set_member(source_node, None)
1995
+ else:
1996
+ # No filter - clear entire source
1997
+ if source_node.type == 'identifier':
1998
+ self.scope.set(source_node.value, None)
1999
+ elif source_node.type == 'module_ref':
2000
+ self._set_module_value(source_node.value, None)
2001
+ elif source_node.type == 'member_access':
2002
+ self._set_member(source_node, None)
1649
2003
  else:
1650
2004
  final_value = source
1651
2005
 
@@ -1668,6 +2022,42 @@ class CSSLRuntime:
1668
2022
  self.global_scope.set(f'${name}', SharedObjectProxy(name, final_value))
1669
2023
  elif target.type == 'member_access':
1670
2024
  self._set_member(target, final_value)
2025
+ elif target.type == 'typed_declaration':
2026
+ # Handle typed target: source ==> datastruct<dynamic> Output
2027
+ var_name = target.value.get('name')
2028
+ type_name = target.value.get('type_name')
2029
+ element_type = target.value.get('element_type', 'dynamic')
2030
+
2031
+ # Create appropriate container with final_value
2032
+ from .cssl_types import (create_datastruct, create_vector, create_array,
2033
+ create_stack, create_list, create_dictionary, create_map)
2034
+
2035
+ container = None
2036
+ if type_name == 'datastruct':
2037
+ container = create_datastruct(element_type)
2038
+ elif type_name == 'vector':
2039
+ container = create_vector(element_type)
2040
+ elif type_name == 'array':
2041
+ container = create_array(element_type)
2042
+ elif type_name == 'stack':
2043
+ container = create_stack(element_type)
2044
+ elif type_name == 'list':
2045
+ container = create_list(element_type)
2046
+ elif type_name == 'dictionary':
2047
+ container = create_dictionary()
2048
+ elif type_name == 'map':
2049
+ container = create_map()
2050
+
2051
+ if container is not None:
2052
+ # Add final_value to container
2053
+ if isinstance(final_value, (list, tuple)):
2054
+ container.extend(final_value)
2055
+ elif final_value is not None:
2056
+ container.append(final_value)
2057
+ self.scope.set(var_name, container)
2058
+ else:
2059
+ # Unknown type, just set the value directly
2060
+ self.scope.set(var_name, final_value)
1671
2061
 
1672
2062
  return final_value
1673
2063
 
@@ -1860,6 +2250,10 @@ class CSSLRuntime:
1860
2250
  """Execute expression statement"""
1861
2251
  return self._evaluate(node.value)
1862
2252
 
2253
+ def _exec_type_instantiation(self, node: ASTNode) -> Any:
2254
+ """Execute type instantiation as statement (e.g., vector<int>)"""
2255
+ return self._evaluate(node)
2256
+
1863
2257
  def _exec_await(self, node: ASTNode) -> Any:
1864
2258
  """Execute await statement - waits for expression to complete"""
1865
2259
  # Evaluate the awaited expression
@@ -1941,12 +2335,13 @@ class CSSLRuntime:
1941
2335
  return value
1942
2336
 
1943
2337
  if node.type == 'module_ref':
1944
- # Check modules first, then promoted globals, then scope
1945
- value = self.get_module(node.value)
1946
- if value is None:
1947
- value = self._promoted_globals.get(node.value)
2338
+ # User-defined globals have priority over SDK modules
2339
+ # Check promoted globals first, then global scope, then SDK modules
2340
+ value = self._promoted_globals.get(node.value)
1948
2341
  if value is None:
1949
2342
  value = self.global_scope.get(node.value)
2343
+ if value is None:
2344
+ value = self.get_module(node.value) # SDK modules as fallback
1950
2345
  return value
1951
2346
 
1952
2347
  if node.type == 'self_ref':
@@ -2030,12 +2425,28 @@ class CSSLRuntime:
2030
2425
  value_type = node.value.get('value_type') # For map<K, V>
2031
2426
  init_values = node.value.get('init_values') # For inline init: map<K,V>{...}
2032
2427
 
2428
+ # Helper to populate container with init values
2429
+ def _populate_container(container, init_vals):
2430
+ if init_vals and isinstance(init_vals, list):
2431
+ for val_node in init_vals:
2432
+ val = self._evaluate(val_node) if isinstance(val_node, ASTNode) else val_node
2433
+ if hasattr(container, 'push'):
2434
+ container.push(val)
2435
+ elif hasattr(container, 'add'):
2436
+ container.add(val)
2437
+ elif hasattr(container, 'append'):
2438
+ container.append(val)
2439
+ return container
2440
+
2033
2441
  if type_name == 'stack':
2034
- return Stack(element_type)
2442
+ s = Stack(element_type)
2443
+ return _populate_container(s, init_values)
2035
2444
  elif type_name == 'vector':
2036
- return Vector(element_type)
2445
+ v = Vector(element_type)
2446
+ return _populate_container(v, init_values)
2037
2447
  elif type_name == 'datastruct':
2038
- return DataStruct(element_type)
2448
+ d = DataStruct(element_type)
2449
+ return _populate_container(d, init_values)
2039
2450
  elif type_name == 'shuffled':
2040
2451
  return Shuffled(element_type)
2041
2452
  elif type_name == 'iterator':
@@ -2047,9 +2458,11 @@ class CSSLRuntime:
2047
2458
  elif type_name == 'openquote':
2048
2459
  return OpenQuote()
2049
2460
  elif type_name == 'array':
2050
- return Array(element_type)
2461
+ a = Array(element_type)
2462
+ return _populate_container(a, init_values)
2051
2463
  elif type_name == 'list':
2052
- return List(element_type)
2464
+ l = List(element_type)
2465
+ return _populate_container(l, init_values)
2053
2466
  elif type_name in ('dictionary', 'dict'):
2054
2467
  return Dictionary(element_type)
2055
2468
  elif type_name == 'map':
@@ -2836,12 +3249,20 @@ class CSSLRuntime:
2836
3249
  pass
2837
3250
 
2838
3251
  def _set_module_value(self, path: str, value: Any):
2839
- """Set a value on a module path"""
3252
+ """Set a value on a module path or promoted global"""
2840
3253
  parts = path.split('.')
2841
3254
  if len(parts) < 2:
3255
+ # Single name (no dots) - set in promoted_globals and global_scope
3256
+ self._promoted_globals[path] = value
3257
+ self.global_scope.set(path, value)
2842
3258
  return
2843
3259
 
2844
3260
  obj = self._modules.get(parts[0])
3261
+ # Also check promoted_globals for the base object
3262
+ if obj is None:
3263
+ obj = self._promoted_globals.get(parts[0])
3264
+ if obj is None:
3265
+ obj = self.global_scope.get(parts[0])
2845
3266
  if obj is None:
2846
3267
  return
2847
3268
 
@@ -1,7 +1,7 @@
1
1
  """
2
2
  CSSL Syntax Highlighting
3
3
 
4
- Provides syntax highlighting for CSSL (CSO Service Script Language) code.
4
+ Provides syntax highlighting for CSSL code.
5
5
  Can be used with:
6
6
  - PyQt5/6 QSyntaxHighlighter
7
7
  - VSCode/TextMate grammar export
@@ -216,8 +216,8 @@ class CSSLSyntaxRules:
216
216
  class ColorScheme:
217
217
  """Color scheme for syntax highlighting"""
218
218
 
219
- # CSO Theme (Orange accent, dark background)
220
- CSO_THEME = {
219
+ # CSSL Theme (Orange accent, dark background)
220
+ CSSL_THEME = {
221
221
  TokenCategory.KEYWORD: '#508cff', # Blue
222
222
  TokenCategory.BUILTIN: '#ff8c00', # Orange
223
223
  TokenCategory.OPERATOR: '#c8c8d2', # Light gray
@@ -261,13 +261,13 @@ def highlight_cssl(source: str, scheme: Dict[TokenCategory, str] = None) -> List
261
261
 
262
262
  Args:
263
263
  source: CSSL source code
264
- scheme: Color scheme dict (defaults to CSO_THEME)
264
+ scheme: Color scheme dict (defaults to CSSL_THEME)
265
265
 
266
266
  Returns:
267
267
  List of (start, end, color, category) tuples
268
268
  """
269
269
  if scheme is None:
270
- scheme = ColorScheme.CSO_THEME
270
+ scheme = ColorScheme.CSSL_THEME
271
271
 
272
272
  highlights = []
273
273
  rules = CSSLSyntaxRules.get_rules()
@@ -337,7 +337,7 @@ def highlight_cssl_ansi(source: str) -> str:
337
337
  }
338
338
  RESET = '\033[0m'
339
339
 
340
- highlights = highlight_cssl(source, ColorScheme.CSO_THEME)
340
+ highlights = highlight_cssl(source, ColorScheme.CSSL_THEME)
341
341
 
342
342
  # Build highlighted string
343
343
  result = []
@@ -388,7 +388,7 @@ def get_pyqt_highlighter():
388
388
 
389
389
  def _setup_rules(self):
390
390
  """Setup highlighting rules"""
391
- scheme = ColorScheme.CSO_THEME
391
+ scheme = ColorScheme.CSSL_THEME
392
392
 
393
393
  for rule in CSSLSyntaxRules.get_rules():
394
394
  fmt = QTextCharFormat()