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.
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +2 -2
- includecpp/cli/commands.py +107 -65
- includecpp/core/cssl/__init__.py +7 -2
- includecpp/core/cssl/cssl_builtins.py +201 -9
- includecpp/core/cssl/cssl_builtins.pyi +3682 -401
- includecpp/core/cssl/cssl_parser.py +117 -29
- includecpp/core/cssl/cssl_runtime.py +446 -25
- includecpp/core/cssl/cssl_syntax.py +7 -7
- includecpp/core/cssl/cssl_types.py +75 -2
- includecpp/core/cssl_bridge.py +64 -6
- includecpp/vscode/cssl/extension.js +133 -0
- includecpp/vscode/cssl/images/cssl.png +0 -0
- includecpp/vscode/cssl/images/cssl_pl.png +0 -0
- includecpp/vscode/cssl/package.json +117 -11
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +38 -15
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/METADATA +2 -2
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/RECORD +22 -19
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/WHEEL +0 -0
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/entry_points.txt +0 -0
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.7.9.dist-info → includecpp-3.7.25.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
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
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
1574
|
-
|
|
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
|
-
#
|
|
1647
|
-
if isinstance(source_node, ASTNode)
|
|
1648
|
-
|
|
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
|
-
#
|
|
1945
|
-
|
|
1946
|
-
|
|
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
|
-
|
|
2442
|
+
s = Stack(element_type)
|
|
2443
|
+
return _populate_container(s, init_values)
|
|
2035
2444
|
elif type_name == 'vector':
|
|
2036
|
-
|
|
2445
|
+
v = Vector(element_type)
|
|
2446
|
+
return _populate_container(v, init_values)
|
|
2037
2447
|
elif type_name == 'datastruct':
|
|
2038
|
-
|
|
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
|
-
|
|
2461
|
+
a = Array(element_type)
|
|
2462
|
+
return _populate_container(a, init_values)
|
|
2051
2463
|
elif type_name == 'list':
|
|
2052
|
-
|
|
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
|
|
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
|
-
#
|
|
220
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
391
|
+
scheme = ColorScheme.CSSL_THEME
|
|
392
392
|
|
|
393
393
|
for rule in CSSLSyntaxRules.get_rules():
|
|
394
394
|
fmt = QTextCharFormat()
|