IncludeCPP 4.0.2__py3-none-any.whl → 4.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/CHANGELOG.md +142 -0
- includecpp/DOCUMENTATION.md +446 -0
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +4 -1
- includecpp/cli/commands.py +700 -86
- includecpp/core/ai_integration.py +46 -13
- includecpp/core/cpp_api_extensions.pyi +350 -0
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +1535 -1316
- includecpp/core/cssl/cssl_builtins.py +230 -23
- includecpp/core/cssl/cssl_languages.py +1757 -0
- includecpp/core/cssl/cssl_parser.py +967 -126
- includecpp/core/cssl/cssl_runtime.py +1133 -84
- includecpp/core/cssl/cssl_syntax.py +88 -4
- includecpp/core/cssl/cssl_types.py +361 -1
- includecpp/core/cssl_bridge.py +194 -8
- includecpp/core/cssl_bridge.pyi +148 -10
- includecpp/generator/parser.cpp +121 -4
- includecpp/generator/parser.h +6 -0
- includecpp/vscode/cssl/package.json +43 -1
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +178 -19
- includecpp-4.3.0.dist-info/METADATA +277 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/RECORD +26 -22
- includecpp-4.0.2.dist-info/METADATA +0 -908
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/WHEEL +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/entry_points.txt +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.0.2.dist-info → includecpp-4.3.0.dist-info}/top_level.txt +0 -0
|
@@ -31,6 +31,11 @@ class TokenCategory(Enum):
|
|
|
31
31
|
NULL = auto() # null, None
|
|
32
32
|
PACKAGE_KW = auto() # package, package-includes - NEW
|
|
33
33
|
TYPE_LITERAL = auto() # list, dict - NEW
|
|
34
|
+
# v4.1.0: Multi-language support
|
|
35
|
+
SUPPORTS_KW = auto() # supports keyword (magenta)
|
|
36
|
+
LIBINCLUDE_KW = auto() # libinclude (yellow/gold)
|
|
37
|
+
LANG_PREFIX = auto() # Language prefix before $ (cyan): cpp$, py$, java$
|
|
38
|
+
LANG_INSTANCE = auto() # Instance name after $ (orange): cpp$ClassName
|
|
34
39
|
|
|
35
40
|
|
|
36
41
|
@dataclass
|
|
@@ -52,9 +57,17 @@ KEYWORDS = {
|
|
|
52
57
|
'start', 'stop', 'wait_for', 'on_event', 'emit_event',
|
|
53
58
|
'await',
|
|
54
59
|
# NEW: Extended keywords
|
|
55
|
-
'package', 'package-includes', 'exec', 'as', 'global'
|
|
60
|
+
'package', 'package-includes', 'exec', 'as', 'global',
|
|
61
|
+
# v4.1.0: Multi-language support (handled separately for special colors)
|
|
62
|
+
# 'supports', 'libinclude' - see MULTI_LANG_KEYWORDS
|
|
56
63
|
}
|
|
57
64
|
|
|
65
|
+
# v4.1.0: Multi-language keywords with special highlighting
|
|
66
|
+
MULTI_LANG_KEYWORDS = {'supports', 'libinclude'}
|
|
67
|
+
|
|
68
|
+
# v4.1.0: Language identifiers for cross-language instance access
|
|
69
|
+
LANGUAGE_IDS = {'cpp', 'py', 'python', 'java', 'csharp', 'js', 'javascript'}
|
|
70
|
+
|
|
58
71
|
# NEW: Package-related keywords for special highlighting
|
|
59
72
|
PACKAGE_KEYWORDS = {'package', 'package-includes'}
|
|
60
73
|
|
|
@@ -145,6 +158,33 @@ class CSSLSyntaxRules:
|
|
|
145
158
|
category=TokenCategory.TYPE_LITERAL
|
|
146
159
|
))
|
|
147
160
|
|
|
161
|
+
# v4.1.0: Multi-language support keywords
|
|
162
|
+
# 'supports' keyword (magenta) - must be before regular keywords
|
|
163
|
+
rules.append(HighlightRule(
|
|
164
|
+
pattern=r'\bsupports\b',
|
|
165
|
+
category=TokenCategory.SUPPORTS_KW
|
|
166
|
+
))
|
|
167
|
+
|
|
168
|
+
# 'libinclude' keyword (yellow/gold)
|
|
169
|
+
rules.append(HighlightRule(
|
|
170
|
+
pattern=r'\blibinclude\b',
|
|
171
|
+
category=TokenCategory.LIBINCLUDE_KW
|
|
172
|
+
))
|
|
173
|
+
|
|
174
|
+
# v4.1.0: Language$Instance patterns (cpp$ClassName, py$Object)
|
|
175
|
+
# Match language prefix before $ (cyan)
|
|
176
|
+
rules.append(HighlightRule(
|
|
177
|
+
pattern=r'\b(cpp|py|python|java|csharp|js|javascript)\$',
|
|
178
|
+
category=TokenCategory.LANG_PREFIX,
|
|
179
|
+
group=1
|
|
180
|
+
))
|
|
181
|
+
# Match instance name after $ (orange)
|
|
182
|
+
rules.append(HighlightRule(
|
|
183
|
+
pattern=r'\b(?:cpp|py|python|java|csharp|js|javascript)\$([A-Za-z_][A-Za-z0-9_]*)',
|
|
184
|
+
category=TokenCategory.LANG_INSTANCE,
|
|
185
|
+
group=1
|
|
186
|
+
))
|
|
187
|
+
|
|
148
188
|
# Self-references (s@Name, s@Backend.Loop)
|
|
149
189
|
rules.append(HighlightRule(
|
|
150
190
|
pattern=r's@[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*',
|
|
@@ -233,6 +273,11 @@ class ColorScheme:
|
|
|
233
273
|
TokenCategory.NULL: '#ff6464', # Red
|
|
234
274
|
TokenCategory.PACKAGE_KW: '#bd93f9', # Purple for package - NEW
|
|
235
275
|
TokenCategory.TYPE_LITERAL: '#8be9fd', # Cyan for type literals - NEW
|
|
276
|
+
# v4.1.0: Multi-language support colors
|
|
277
|
+
TokenCategory.SUPPORTS_KW: '#ff79c6', # Magenta/Pink for 'supports'
|
|
278
|
+
TokenCategory.LIBINCLUDE_KW: '#f1fa8c',# Yellow/Gold for 'libinclude'
|
|
279
|
+
TokenCategory.LANG_PREFIX: '#8be9fd', # Cyan for language prefix (cpp$)
|
|
280
|
+
TokenCategory.LANG_INSTANCE: '#ffb86c',# Orange for instance name ($ClassName)
|
|
236
281
|
}
|
|
237
282
|
|
|
238
283
|
# Light theme variant
|
|
@@ -252,6 +297,11 @@ class ColorScheme:
|
|
|
252
297
|
TokenCategory.NULL: '#ff0000', # Red
|
|
253
298
|
TokenCategory.PACKAGE_KW: '#8b008b', # DarkMagenta for package - NEW
|
|
254
299
|
TokenCategory.TYPE_LITERAL: '#008b8b', # Dark cyan for type literals - NEW
|
|
300
|
+
# v4.1.0: Multi-language support colors
|
|
301
|
+
TokenCategory.SUPPORTS_KW: '#d63384', # Dark Magenta for 'supports'
|
|
302
|
+
TokenCategory.LIBINCLUDE_KW: '#b8860b',# DarkGoldenrod for 'libinclude'
|
|
303
|
+
TokenCategory.LANG_PREFIX: '#0d6efd', # Blue for language prefix (cpp$)
|
|
304
|
+
TokenCategory.LANG_INSTANCE: '#fd7e14',# Orange for instance name ($ClassName)
|
|
255
305
|
}
|
|
256
306
|
|
|
257
307
|
|
|
@@ -334,6 +384,11 @@ def highlight_cssl_ansi(source: str) -> str:
|
|
|
334
384
|
TokenCategory.NULL: '\033[91m', # Red
|
|
335
385
|
TokenCategory.PACKAGE_KW: '\033[95m', # Magenta for package - NEW
|
|
336
386
|
TokenCategory.TYPE_LITERAL: '\033[96m', # Cyan for type literals - NEW
|
|
387
|
+
# v4.1.0: Multi-language support colors
|
|
388
|
+
TokenCategory.SUPPORTS_KW: '\033[95m', # Magenta for 'supports'
|
|
389
|
+
TokenCategory.LIBINCLUDE_KW: '\033[93m',# Yellow for 'libinclude'
|
|
390
|
+
TokenCategory.LANG_PREFIX: '\033[96m', # Cyan for language prefix (cpp$)
|
|
391
|
+
TokenCategory.LANG_INSTANCE: '\033[33m',# Orange/Yellow for instance name
|
|
337
392
|
}
|
|
338
393
|
RESET = '\033[0m'
|
|
339
394
|
|
|
@@ -439,6 +494,10 @@ def export_textmate_grammar() -> dict:
|
|
|
439
494
|
"name": "comment.line.cssl",
|
|
440
495
|
"match": "#.*$"
|
|
441
496
|
},
|
|
497
|
+
{
|
|
498
|
+
"name": "comment.line.double-slash.cssl",
|
|
499
|
+
"match": "//.*$"
|
|
500
|
+
},
|
|
442
501
|
{
|
|
443
502
|
"name": "string.quoted.double.cssl",
|
|
444
503
|
"match": '"(?:[^"\\\\]|\\\\.)*"'
|
|
@@ -447,6 +506,23 @@ def export_textmate_grammar() -> dict:
|
|
|
447
506
|
"name": "string.quoted.single.cssl",
|
|
448
507
|
"match": "'(?:[^'\\\\]|\\\\.)*'"
|
|
449
508
|
},
|
|
509
|
+
# v4.1.0: Multi-language support
|
|
510
|
+
{
|
|
511
|
+
"name": "keyword.control.supports.cssl",
|
|
512
|
+
"match": "\\bsupports\\b"
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
"name": "support.function.libinclude.cssl",
|
|
516
|
+
"match": "\\blibinclude\\b"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"name": "variable.language.lang-instance.cssl",
|
|
520
|
+
"match": "\\b(cpp|py|python|java|csharp|js|javascript)\\$([A-Za-z_][A-Za-z0-9_]*)",
|
|
521
|
+
"captures": {
|
|
522
|
+
"1": {"name": "entity.name.type.language.cssl"},
|
|
523
|
+
"2": {"name": "variable.other.instance.cssl"}
|
|
524
|
+
}
|
|
525
|
+
},
|
|
450
526
|
{
|
|
451
527
|
"name": "variable.other.self-reference.cssl",
|
|
452
528
|
"match": "s@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
|
|
@@ -455,9 +531,13 @@ def export_textmate_grammar() -> dict:
|
|
|
455
531
|
"name": "variable.other.module-reference.cssl",
|
|
456
532
|
"match": "@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
|
|
457
533
|
},
|
|
534
|
+
{
|
|
535
|
+
"name": "keyword.other.package.cssl",
|
|
536
|
+
"match": "\\b(package|package-includes)\\b"
|
|
537
|
+
},
|
|
458
538
|
{
|
|
459
539
|
"name": "keyword.control.cssl",
|
|
460
|
-
"match": "\\b(service-init|service-run|service-include|struct|define|if|else|elif|while|for|foreach|in|switch|case|default|break|continue|return|try|catch|await)\\b"
|
|
540
|
+
"match": "\\b(service-init|service-run|service-include|struct|define|class|constr|if|else|elif|while|for|foreach|in|switch|case|default|break|continue|return|try|catch|finally|throw|await|extends|overwrites|global|as|exec)\\b"
|
|
461
541
|
},
|
|
462
542
|
{
|
|
463
543
|
"name": "keyword.operator.cssl",
|
|
@@ -465,7 +545,7 @@ def export_textmate_grammar() -> dict:
|
|
|
465
545
|
},
|
|
466
546
|
{
|
|
467
547
|
"name": "constant.language.cssl",
|
|
468
|
-
"match": "\\b(True|False|true|false|null|None)\\b"
|
|
548
|
+
"match": "\\b(True|False|true|false|null|None|none)\\b"
|
|
469
549
|
},
|
|
470
550
|
{
|
|
471
551
|
"name": "constant.numeric.cssl",
|
|
@@ -473,7 +553,11 @@ def export_textmate_grammar() -> dict:
|
|
|
473
553
|
},
|
|
474
554
|
{
|
|
475
555
|
"name": "keyword.operator.assignment.cssl",
|
|
476
|
-
"match": "
|
|
556
|
+
"match": "<==|==>|->|<-|::"
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"name": "support.type.cssl",
|
|
560
|
+
"match": "\\b(list|dict)\\b(?!\\s*\\()"
|
|
477
561
|
}
|
|
478
562
|
]
|
|
479
563
|
}
|
|
@@ -1443,6 +1443,195 @@ def create_map(key_type: str = 'dynamic', value_type: str = 'dynamic') -> Map:
|
|
|
1443
1443
|
return Map(key_type, value_type)
|
|
1444
1444
|
|
|
1445
1445
|
|
|
1446
|
+
class ByteArrayed:
|
|
1447
|
+
"""Function-to-byte mapping with pattern matching (v4.2.5).
|
|
1448
|
+
|
|
1449
|
+
Maps function references to byte positions and executes pattern matching
|
|
1450
|
+
based on function return values.
|
|
1451
|
+
|
|
1452
|
+
Usage:
|
|
1453
|
+
bytearrayed MyBytes {
|
|
1454
|
+
&func1; // Position 0x0
|
|
1455
|
+
&func2; // Position 0x1
|
|
1456
|
+
case {0, 1} { // Match when func1=0, func2=1
|
|
1457
|
+
printl("Match!");
|
|
1458
|
+
}
|
|
1459
|
+
default {
|
|
1460
|
+
printl("No match");
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
MyBytes(); // Execute pattern matching
|
|
1465
|
+
x = MyBytes["0x0"]; // Get value at position 0
|
|
1466
|
+
x = MyBytes[0]; // Get value at position 0
|
|
1467
|
+
"""
|
|
1468
|
+
|
|
1469
|
+
def __init__(self, name: str, func_refs: List[Dict], cases: List[Dict],
|
|
1470
|
+
default_block: Any = None, runtime: Any = None):
|
|
1471
|
+
self.name = name
|
|
1472
|
+
self.func_refs = func_refs # [{position, hex_pos, func_ref}, ...]
|
|
1473
|
+
self.cases = cases # [{pattern, body}, ...]
|
|
1474
|
+
self.default_block = default_block
|
|
1475
|
+
self._runtime = runtime
|
|
1476
|
+
self._cached_values: Dict[int, Any] = {} # Cached return values
|
|
1477
|
+
|
|
1478
|
+
def __call__(self, *args, **kwargs) -> Any:
|
|
1479
|
+
"""Execute pattern matching - probe functions and match cases.
|
|
1480
|
+
|
|
1481
|
+
Functions are executed "invisibly" (side-effect free where possible)
|
|
1482
|
+
to get their current return values, then patterns are matched.
|
|
1483
|
+
"""
|
|
1484
|
+
# Get current return values from all referenced functions
|
|
1485
|
+
values = self._probe_functions()
|
|
1486
|
+
|
|
1487
|
+
# Try to match each case pattern
|
|
1488
|
+
for case in self.cases:
|
|
1489
|
+
pattern = case['pattern']
|
|
1490
|
+
body = case['body']
|
|
1491
|
+
if self._match_pattern(pattern, values):
|
|
1492
|
+
return self._execute_body(body)
|
|
1493
|
+
|
|
1494
|
+
# No case matched - execute default if present
|
|
1495
|
+
if self.default_block:
|
|
1496
|
+
return self._execute_body(self.default_block)
|
|
1497
|
+
|
|
1498
|
+
return None
|
|
1499
|
+
|
|
1500
|
+
def _probe_functions(self) -> List[Any]:
|
|
1501
|
+
"""Execute referenced functions invisibly to get their return values."""
|
|
1502
|
+
values = []
|
|
1503
|
+
for ref in self.func_refs:
|
|
1504
|
+
func_name = ref['func_ref']
|
|
1505
|
+
position = ref['position']
|
|
1506
|
+
|
|
1507
|
+
# Look up the function in runtime scope
|
|
1508
|
+
func = None
|
|
1509
|
+
if self._runtime:
|
|
1510
|
+
func = self._runtime.scope.get(func_name)
|
|
1511
|
+
if func is None:
|
|
1512
|
+
func = self._runtime.global_scope.get(func_name)
|
|
1513
|
+
if func is None:
|
|
1514
|
+
func = self._runtime.builtins.get_function(func_name)
|
|
1515
|
+
|
|
1516
|
+
# Execute the function to get its return value
|
|
1517
|
+
if func is not None:
|
|
1518
|
+
try:
|
|
1519
|
+
if callable(func):
|
|
1520
|
+
result = func()
|
|
1521
|
+
elif hasattr(func, 'type') and func.type == 'function':
|
|
1522
|
+
# CSSL function node
|
|
1523
|
+
result = self._runtime._call_function(func, [])
|
|
1524
|
+
else:
|
|
1525
|
+
result = func
|
|
1526
|
+
except Exception:
|
|
1527
|
+
result = None
|
|
1528
|
+
else:
|
|
1529
|
+
result = None
|
|
1530
|
+
|
|
1531
|
+
values.append(result)
|
|
1532
|
+
self._cached_values[position] = result
|
|
1533
|
+
|
|
1534
|
+
return values
|
|
1535
|
+
|
|
1536
|
+
def _match_pattern(self, pattern: List[Dict], values: List[Any]) -> bool:
|
|
1537
|
+
"""Check if pattern matches the current values."""
|
|
1538
|
+
for i, p in enumerate(pattern):
|
|
1539
|
+
if i >= len(values):
|
|
1540
|
+
return False
|
|
1541
|
+
|
|
1542
|
+
p_type = p.get('type')
|
|
1543
|
+
value = values[i]
|
|
1544
|
+
|
|
1545
|
+
if p_type == 'wildcard':
|
|
1546
|
+
# _ matches anything
|
|
1547
|
+
continue
|
|
1548
|
+
elif p_type == 'value':
|
|
1549
|
+
# Exact value match
|
|
1550
|
+
if value != p.get('value'):
|
|
1551
|
+
return False
|
|
1552
|
+
elif p_type == 'indexed':
|
|
1553
|
+
# Match at specific index
|
|
1554
|
+
idx = p.get('index')
|
|
1555
|
+
if isinstance(idx, str) and idx.startswith('0x'):
|
|
1556
|
+
idx = int(idx, 16)
|
|
1557
|
+
if idx < len(values):
|
|
1558
|
+
if values[idx] != self._runtime._evaluate(p.get('value')) if hasattr(p.get('value'), 'type') else p.get('value'):
|
|
1559
|
+
return False
|
|
1560
|
+
elif p_type == 'type_match':
|
|
1561
|
+
# Match by type
|
|
1562
|
+
type_name = p.get('type_name')
|
|
1563
|
+
if not self._check_type(value, type_name):
|
|
1564
|
+
return False
|
|
1565
|
+
elif p_type == 'variable':
|
|
1566
|
+
# Match against variable value
|
|
1567
|
+
var_name = p.get('name')
|
|
1568
|
+
var_value = self._runtime.scope.get(var_name)
|
|
1569
|
+
if var_value is None:
|
|
1570
|
+
var_value = self._runtime.global_scope.get(var_name)
|
|
1571
|
+
if value != var_value:
|
|
1572
|
+
return False
|
|
1573
|
+
|
|
1574
|
+
return True
|
|
1575
|
+
|
|
1576
|
+
def _check_type(self, value: Any, type_name: str) -> bool:
|
|
1577
|
+
"""Check if value matches the specified type."""
|
|
1578
|
+
type_checks = {
|
|
1579
|
+
'int': lambda v: isinstance(v, int) and not isinstance(v, bool),
|
|
1580
|
+
'float': lambda v: isinstance(v, float),
|
|
1581
|
+
'string': lambda v: isinstance(v, str),
|
|
1582
|
+
'bool': lambda v: isinstance(v, bool),
|
|
1583
|
+
'list': lambda v: isinstance(v, list),
|
|
1584
|
+
'dict': lambda v: isinstance(v, dict),
|
|
1585
|
+
'dynamic': lambda v: True,
|
|
1586
|
+
}
|
|
1587
|
+
if type_name in type_checks:
|
|
1588
|
+
return type_checks[type_name](value)
|
|
1589
|
+
# Check for generic types like vector<string>
|
|
1590
|
+
if '<' in type_name:
|
|
1591
|
+
base = type_name.split('<')[0]
|
|
1592
|
+
return isinstance(value, (list, tuple, set))
|
|
1593
|
+
return True
|
|
1594
|
+
|
|
1595
|
+
def _execute_body(self, body: List) -> Any:
|
|
1596
|
+
"""Execute a case body block."""
|
|
1597
|
+
if not self._runtime:
|
|
1598
|
+
return None
|
|
1599
|
+
result = None
|
|
1600
|
+
for node in body:
|
|
1601
|
+
result = self._runtime._execute_node(node)
|
|
1602
|
+
return result
|
|
1603
|
+
|
|
1604
|
+
def __getitem__(self, key: Union[int, str]) -> Any:
|
|
1605
|
+
"""Access byte value by index or hex position.
|
|
1606
|
+
|
|
1607
|
+
MyBytes[0] - Get value at position 0
|
|
1608
|
+
MyBytes["0x0"] - Get value at position 0
|
|
1609
|
+
"""
|
|
1610
|
+
if isinstance(key, str):
|
|
1611
|
+
if key.startswith('0x') or key.startswith('0X'):
|
|
1612
|
+
key = int(key, 16)
|
|
1613
|
+
elif key.isdigit():
|
|
1614
|
+
key = int(key)
|
|
1615
|
+
else:
|
|
1616
|
+
raise KeyError(f"Invalid bytearrayed key: {key}")
|
|
1617
|
+
|
|
1618
|
+
if key in self._cached_values:
|
|
1619
|
+
return self._cached_values[key]
|
|
1620
|
+
|
|
1621
|
+
# Probe functions to get values if not cached
|
|
1622
|
+
if not self._cached_values:
|
|
1623
|
+
self._probe_functions()
|
|
1624
|
+
|
|
1625
|
+
return self._cached_values.get(key)
|
|
1626
|
+
|
|
1627
|
+
def __len__(self) -> int:
|
|
1628
|
+
"""Return number of byte positions."""
|
|
1629
|
+
return len(self.func_refs)
|
|
1630
|
+
|
|
1631
|
+
def __repr__(self) -> str:
|
|
1632
|
+
return f"ByteArrayed({self.name}, positions={len(self.func_refs)})"
|
|
1633
|
+
|
|
1634
|
+
|
|
1446
1635
|
class CSSLClass:
|
|
1447
1636
|
"""Represents a CSSL class definition.
|
|
1448
1637
|
|
|
@@ -1624,10 +1813,181 @@ class CSSLInstance:
|
|
|
1624
1813
|
return f"<{self._class.name} instance at 0x{id(self):x}>"
|
|
1625
1814
|
|
|
1626
1815
|
|
|
1816
|
+
class UniversalInstance:
|
|
1817
|
+
"""Universal shared container accessible from CSSL, Python, and C++.
|
|
1818
|
+
|
|
1819
|
+
Created via instance<"name"> syntax in CSSL or getInstance("name") in Python.
|
|
1820
|
+
Supports dynamic member/method injection via +<<== operator.
|
|
1821
|
+
|
|
1822
|
+
Example CSSL:
|
|
1823
|
+
instance<"myContainer"> container;
|
|
1824
|
+
container +<<== { void sayHello() { printl("Hello!"); } }
|
|
1825
|
+
container.sayHello();
|
|
1826
|
+
|
|
1827
|
+
Example Python:
|
|
1828
|
+
container = cssl.getInstance("myContainer")
|
|
1829
|
+
container.sayHello()
|
|
1830
|
+
"""
|
|
1831
|
+
|
|
1832
|
+
# Global registry for all universal instances
|
|
1833
|
+
_registry: Dict[str, 'UniversalInstance'] = {}
|
|
1834
|
+
|
|
1835
|
+
def __init__(self, name: str):
|
|
1836
|
+
self._name = name
|
|
1837
|
+
self._members: Dict[str, Any] = {}
|
|
1838
|
+
self._methods: Dict[str, Any] = {} # Method name -> AST node or callable
|
|
1839
|
+
self._injections: List[Any] = [] # Code blocks injected via +<<==
|
|
1840
|
+
self._runtime = None # Weak reference to CSSL runtime for method calls
|
|
1841
|
+
# Register globally
|
|
1842
|
+
UniversalInstance._registry[name] = self
|
|
1843
|
+
|
|
1844
|
+
@classmethod
|
|
1845
|
+
def get_or_create(cls, name: str) -> 'UniversalInstance':
|
|
1846
|
+
"""Get existing instance or create new one."""
|
|
1847
|
+
if name in cls._registry:
|
|
1848
|
+
return cls._registry[name]
|
|
1849
|
+
return cls(name)
|
|
1850
|
+
|
|
1851
|
+
@classmethod
|
|
1852
|
+
def get(cls, name: str) -> Optional['UniversalInstance']:
|
|
1853
|
+
"""Get existing instance by name, returns None if not found."""
|
|
1854
|
+
return cls._registry.get(name)
|
|
1855
|
+
|
|
1856
|
+
@classmethod
|
|
1857
|
+
def exists(cls, name: str) -> bool:
|
|
1858
|
+
"""Check if instance exists."""
|
|
1859
|
+
return name in cls._registry
|
|
1860
|
+
|
|
1861
|
+
@classmethod
|
|
1862
|
+
def delete(cls, name: str) -> bool:
|
|
1863
|
+
"""Delete instance from registry."""
|
|
1864
|
+
if name in cls._registry:
|
|
1865
|
+
del cls._registry[name]
|
|
1866
|
+
return True
|
|
1867
|
+
return False
|
|
1868
|
+
|
|
1869
|
+
@classmethod
|
|
1870
|
+
def clear_all(cls) -> int:
|
|
1871
|
+
"""Clear all instances. Returns count of cleared instances."""
|
|
1872
|
+
count = len(cls._registry)
|
|
1873
|
+
cls._registry.clear()
|
|
1874
|
+
return count
|
|
1875
|
+
|
|
1876
|
+
@classmethod
|
|
1877
|
+
def list_all(cls) -> List[str]:
|
|
1878
|
+
"""List all instance names."""
|
|
1879
|
+
return list(cls._registry.keys())
|
|
1880
|
+
|
|
1881
|
+
@property
|
|
1882
|
+
def name(self) -> str:
|
|
1883
|
+
"""Get instance name."""
|
|
1884
|
+
return self._name
|
|
1885
|
+
|
|
1886
|
+
def set_member(self, name: str, value: Any) -> None:
|
|
1887
|
+
"""Set a member value."""
|
|
1888
|
+
self._members[name] = value
|
|
1889
|
+
|
|
1890
|
+
def get_member(self, name: str) -> Any:
|
|
1891
|
+
"""Get a member value."""
|
|
1892
|
+
if name in self._members:
|
|
1893
|
+
return self._members[name]
|
|
1894
|
+
raise AttributeError(f"Instance '{self._name}' has no member '{name}'")
|
|
1895
|
+
|
|
1896
|
+
def has_member(self, name: str) -> bool:
|
|
1897
|
+
"""Check if member exists."""
|
|
1898
|
+
return name in self._members
|
|
1899
|
+
|
|
1900
|
+
def set_runtime(self, runtime: Any) -> None:
|
|
1901
|
+
"""Set the runtime reference for method calls from Python."""
|
|
1902
|
+
import weakref
|
|
1903
|
+
self._runtime = weakref.ref(runtime)
|
|
1904
|
+
|
|
1905
|
+
def set_method(self, name: str, method: Any, runtime: Any = None) -> None:
|
|
1906
|
+
"""Set a method (AST node or callable)."""
|
|
1907
|
+
self._methods[name] = method
|
|
1908
|
+
if runtime is not None and self._runtime is None:
|
|
1909
|
+
self.set_runtime(runtime)
|
|
1910
|
+
|
|
1911
|
+
def get_method(self, name: str) -> Any:
|
|
1912
|
+
"""Get a method by name."""
|
|
1913
|
+
if name in self._methods:
|
|
1914
|
+
return self._methods[name]
|
|
1915
|
+
raise AttributeError(f"Instance '{self._name}' has no method '{name}'")
|
|
1916
|
+
|
|
1917
|
+
def has_method(self, name: str) -> bool:
|
|
1918
|
+
"""Check if method exists."""
|
|
1919
|
+
return name in self._methods
|
|
1920
|
+
|
|
1921
|
+
def add_injection(self, code_block: Any) -> None:
|
|
1922
|
+
"""Add a code injection (from +<<== operator)."""
|
|
1923
|
+
self._injections.append(code_block)
|
|
1924
|
+
|
|
1925
|
+
def get_injections(self) -> List[Any]:
|
|
1926
|
+
"""Get all injected code blocks."""
|
|
1927
|
+
return self._injections
|
|
1928
|
+
|
|
1929
|
+
def get_all_members(self) -> Dict[str, Any]:
|
|
1930
|
+
"""Get all members."""
|
|
1931
|
+
return dict(self._members)
|
|
1932
|
+
|
|
1933
|
+
def get_all_methods(self) -> Dict[str, Any]:
|
|
1934
|
+
"""Get all methods."""
|
|
1935
|
+
return dict(self._methods)
|
|
1936
|
+
|
|
1937
|
+
def __getattr__(self, name: str) -> Any:
|
|
1938
|
+
"""Allow direct attribute access for members and methods."""
|
|
1939
|
+
if name.startswith('_'):
|
|
1940
|
+
raise AttributeError(name)
|
|
1941
|
+
if name in object.__getattribute__(self, '_members'):
|
|
1942
|
+
return object.__getattribute__(self, '_members')[name]
|
|
1943
|
+
if name in object.__getattribute__(self, '_methods'):
|
|
1944
|
+
method = object.__getattribute__(self, '_methods')[name]
|
|
1945
|
+
runtime_ref = object.__getattribute__(self, '_runtime')
|
|
1946
|
+
|
|
1947
|
+
# If method is an AST node and we have a runtime, create a callable wrapper
|
|
1948
|
+
if hasattr(method, 'type') and method.type == 'function' and runtime_ref is not None:
|
|
1949
|
+
runtime = runtime_ref() # Dereference weakref
|
|
1950
|
+
if runtime is not None:
|
|
1951
|
+
instance = self
|
|
1952
|
+
def method_caller(*args, **kwargs):
|
|
1953
|
+
# Set 'this' context and call the method
|
|
1954
|
+
old_this = runtime.scope.get('this')
|
|
1955
|
+
runtime.scope.set('this', instance)
|
|
1956
|
+
try:
|
|
1957
|
+
return runtime._call_function(method, list(args))
|
|
1958
|
+
finally:
|
|
1959
|
+
if old_this is not None:
|
|
1960
|
+
runtime.scope.set('this', old_this)
|
|
1961
|
+
elif hasattr(runtime.scope, 'remove'):
|
|
1962
|
+
runtime.scope.remove('this')
|
|
1963
|
+
return method_caller
|
|
1964
|
+
# Return method directly if already callable or no runtime
|
|
1965
|
+
return method
|
|
1966
|
+
raise AttributeError(f"Instance '{object.__getattribute__(self, '_name')}' has no attribute '{name}'")
|
|
1967
|
+
|
|
1968
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
1969
|
+
"""Allow direct attribute setting for members."""
|
|
1970
|
+
if name.startswith('_'):
|
|
1971
|
+
object.__setattr__(self, name, value)
|
|
1972
|
+
else:
|
|
1973
|
+
if hasattr(self, '_members'):
|
|
1974
|
+
self._members[name] = value
|
|
1975
|
+
else:
|
|
1976
|
+
object.__setattr__(self, name, value)
|
|
1977
|
+
|
|
1978
|
+
def __repr__(self):
|
|
1979
|
+
members = len(self._members)
|
|
1980
|
+
methods = len(self._methods)
|
|
1981
|
+
return f"<UniversalInstance '{self._name}' ({members} members, {methods} methods)>"
|
|
1982
|
+
|
|
1983
|
+
def __str__(self):
|
|
1984
|
+
return f"<UniversalInstance '{self._name}'>"
|
|
1985
|
+
|
|
1986
|
+
|
|
1627
1987
|
__all__ = [
|
|
1628
1988
|
'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
|
|
1629
1989
|
'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array', 'List', 'Dictionary', 'Map',
|
|
1630
|
-
'CSSLClass', 'CSSLInstance',
|
|
1990
|
+
'CSSLClass', 'CSSLInstance', 'UniversalInstance',
|
|
1631
1991
|
'create_datastruct', 'create_shuffled', 'create_iterator',
|
|
1632
1992
|
'create_combo', 'create_dataspace', 'create_openquote', 'create_parameter',
|
|
1633
1993
|
'create_stack', 'create_vector', 'create_array', 'create_list', 'create_dictionary', 'create_map'
|