IncludeCPP 4.2.2__py3-none-any.whl → 4.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/CHANGELOG.md +104 -115
- includecpp/DOCUMENTATION.md +208 -355
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +1 -4
- includecpp/cli/commands.py +1220 -27
- includecpp/core/cpp_api_extensions.pyi +204 -200
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +1505 -1467
- includecpp/core/cssl/__init__.py +317 -0
- includecpp/core/cssl/cpp/build/api.pyd +0 -0
- includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
- includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
- includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
- includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
- includecpp/core/cssl/cpp/cssl_core.cp +108 -0
- includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
- includecpp/core/cssl/cssl_builtins.py +245 -20
- includecpp/core/cssl/cssl_compiler.py +448 -0
- includecpp/core/cssl/cssl_optimizer.py +833 -0
- includecpp/core/cssl/cssl_parser.py +945 -40
- includecpp/core/cssl/cssl_runtime.py +751 -38
- includecpp/core/cssl/cssl_syntax.py +17 -0
- includecpp/core/cssl/cssl_types.py +321 -0
- includecpp/core/cssl_bridge.py +36 -2
- includecpp/generator/parser.cpp +38 -14
- includecpp/vscode/cssl/package.json +15 -0
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +134 -2
- includecpp-4.5.2.dist-info/METADATA +277 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/RECORD +32 -23
- includecpp-4.2.2.dist-info/METADATA +0 -1008
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/WHEEL +0 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/entry_points.txt +0 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.2.2.dist-info → includecpp-4.5.2.dist-info}/top_level.txt +0 -0
|
@@ -36,6 +36,8 @@ class TokenCategory(Enum):
|
|
|
36
36
|
LIBINCLUDE_KW = auto() # libinclude (yellow/gold)
|
|
37
37
|
LANG_PREFIX = auto() # Language prefix before $ (cyan): cpp$, py$, java$
|
|
38
38
|
LANG_INSTANCE = auto() # Instance name after $ (orange): cpp$ClassName
|
|
39
|
+
# v4.6.0: C++ execution control
|
|
40
|
+
NATIVE_KW = auto() # native keyword (cyan/bright) - forces C++ execution
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
@dataclass
|
|
@@ -65,6 +67,9 @@ KEYWORDS = {
|
|
|
65
67
|
# v4.1.0: Multi-language keywords with special highlighting
|
|
66
68
|
MULTI_LANG_KEYWORDS = {'supports', 'libinclude'}
|
|
67
69
|
|
|
70
|
+
# v4.6.0: C++ execution control keyword
|
|
71
|
+
NATIVE_KEYWORD = {'native'} # Forces C++ execution (no Python fallback)
|
|
72
|
+
|
|
68
73
|
# v4.1.0: Language identifiers for cross-language instance access
|
|
69
74
|
LANGUAGE_IDS = {'cpp', 'py', 'python', 'java', 'csharp', 'js', 'javascript'}
|
|
70
75
|
|
|
@@ -171,6 +176,12 @@ class CSSLSyntaxRules:
|
|
|
171
176
|
category=TokenCategory.LIBINCLUDE_KW
|
|
172
177
|
))
|
|
173
178
|
|
|
179
|
+
# v4.6.0: 'native' keyword (cyan/bright) - forces C++ execution
|
|
180
|
+
rules.append(HighlightRule(
|
|
181
|
+
pattern=r'\bnative\b',
|
|
182
|
+
category=TokenCategory.NATIVE_KW
|
|
183
|
+
))
|
|
184
|
+
|
|
174
185
|
# v4.1.0: Language$Instance patterns (cpp$ClassName, py$Object)
|
|
175
186
|
# Match language prefix before $ (cyan)
|
|
176
187
|
rules.append(HighlightRule(
|
|
@@ -278,6 +289,8 @@ class ColorScheme:
|
|
|
278
289
|
TokenCategory.LIBINCLUDE_KW: '#f1fa8c',# Yellow/Gold for 'libinclude'
|
|
279
290
|
TokenCategory.LANG_PREFIX: '#8be9fd', # Cyan for language prefix (cpp$)
|
|
280
291
|
TokenCategory.LANG_INSTANCE: '#ffb86c',# Orange for instance name ($ClassName)
|
|
292
|
+
# v4.6.0: C++ execution control
|
|
293
|
+
TokenCategory.NATIVE_KW: '#50fa7b', # Green/Cyan for 'native' (C++ forced)
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
# Light theme variant
|
|
@@ -302,6 +315,8 @@ class ColorScheme:
|
|
|
302
315
|
TokenCategory.LIBINCLUDE_KW: '#b8860b',# DarkGoldenrod for 'libinclude'
|
|
303
316
|
TokenCategory.LANG_PREFIX: '#0d6efd', # Blue for language prefix (cpp$)
|
|
304
317
|
TokenCategory.LANG_INSTANCE: '#fd7e14',# Orange for instance name ($ClassName)
|
|
318
|
+
# v4.6.0: C++ execution control
|
|
319
|
+
TokenCategory.NATIVE_KW: '#198754', # Green for 'native' (C++ forced)
|
|
305
320
|
}
|
|
306
321
|
|
|
307
322
|
|
|
@@ -389,6 +404,8 @@ def highlight_cssl_ansi(source: str) -> str:
|
|
|
389
404
|
TokenCategory.LIBINCLUDE_KW: '\033[93m',# Yellow for 'libinclude'
|
|
390
405
|
TokenCategory.LANG_PREFIX: '\033[96m', # Cyan for language prefix (cpp$)
|
|
391
406
|
TokenCategory.LANG_INSTANCE: '\033[33m',# Orange/Yellow for instance name
|
|
407
|
+
# v4.6.0: C++ execution control
|
|
408
|
+
TokenCategory.NATIVE_KW: '\033[92m', # Bright Green for 'native'
|
|
392
409
|
}
|
|
393
410
|
RESET = '\033[0m'
|
|
394
411
|
|
|
@@ -1443,6 +1443,327 @@ 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, simulate: bool = True) -> List[Any]:
|
|
1501
|
+
"""Probe referenced functions to get their return values.
|
|
1502
|
+
|
|
1503
|
+
v4.3.2: When simulate=True, analyzes function return statements without
|
|
1504
|
+
full execution. This is more precise for pattern matching.
|
|
1505
|
+
|
|
1506
|
+
Args:
|
|
1507
|
+
simulate: If True, analyze return values without executing.
|
|
1508
|
+
If False, execute functions to get actual return values.
|
|
1509
|
+
"""
|
|
1510
|
+
values = []
|
|
1511
|
+
for ref in self.func_refs:
|
|
1512
|
+
func_name = ref['func_ref']
|
|
1513
|
+
position = ref['position']
|
|
1514
|
+
func_args = ref.get('args', []) # v4.3.2: Support function arguments
|
|
1515
|
+
|
|
1516
|
+
# Look up the function in runtime scope
|
|
1517
|
+
func = None
|
|
1518
|
+
if self._runtime:
|
|
1519
|
+
func = self._runtime.scope.get(func_name)
|
|
1520
|
+
if func is None:
|
|
1521
|
+
func = self._runtime.global_scope.get(func_name)
|
|
1522
|
+
if func is None:
|
|
1523
|
+
func = self._runtime.builtins.get_function(func_name)
|
|
1524
|
+
|
|
1525
|
+
result = None
|
|
1526
|
+
|
|
1527
|
+
if func is not None:
|
|
1528
|
+
try:
|
|
1529
|
+
# v4.3.2: Evaluate arguments if present
|
|
1530
|
+
evaluated_args = []
|
|
1531
|
+
for arg in func_args:
|
|
1532
|
+
if hasattr(arg, 'type'):
|
|
1533
|
+
evaluated_args.append(self._runtime._evaluate(arg))
|
|
1534
|
+
else:
|
|
1535
|
+
evaluated_args.append(arg)
|
|
1536
|
+
|
|
1537
|
+
if simulate and hasattr(func, 'type') and func.type == 'function':
|
|
1538
|
+
# v4.3.2: Simulate - analyze return statements without full execution
|
|
1539
|
+
result = self._simulate_function_return(func, evaluated_args)
|
|
1540
|
+
elif callable(func):
|
|
1541
|
+
result = func(*evaluated_args) if evaluated_args else func()
|
|
1542
|
+
elif hasattr(func, 'type') and func.type == 'function':
|
|
1543
|
+
# CSSL function node - execute with args
|
|
1544
|
+
result = self._runtime._call_function(func, evaluated_args)
|
|
1545
|
+
else:
|
|
1546
|
+
result = func
|
|
1547
|
+
except Exception:
|
|
1548
|
+
result = None
|
|
1549
|
+
|
|
1550
|
+
values.append(result)
|
|
1551
|
+
self._cached_values[position] = result
|
|
1552
|
+
|
|
1553
|
+
return values
|
|
1554
|
+
|
|
1555
|
+
def _simulate_function_return(self, func_node, args: List[Any] = None) -> Any:
|
|
1556
|
+
"""Simulate a function and extract its return value without full execution.
|
|
1557
|
+
|
|
1558
|
+
v4.3.2: Analyzes the function's return statements and evaluates them
|
|
1559
|
+
in isolation to get precise return values for pattern matching.
|
|
1560
|
+
"""
|
|
1561
|
+
if not self._runtime or not func_node:
|
|
1562
|
+
return None
|
|
1563
|
+
|
|
1564
|
+
# Create a temporary scope with function parameters bound to args
|
|
1565
|
+
func_info = func_node.value
|
|
1566
|
+
params = func_info.get('params', [])
|
|
1567
|
+
args = args or []
|
|
1568
|
+
|
|
1569
|
+
# Bind parameters to arguments in a temporary scope
|
|
1570
|
+
old_scope = self._runtime.scope
|
|
1571
|
+
# v4.3.2: Create child scope manually (Scope is a dataclass)
|
|
1572
|
+
from includecpp.core.cssl.cssl_runtime import Scope
|
|
1573
|
+
self._runtime.scope = Scope(variables={}, parent=old_scope)
|
|
1574
|
+
|
|
1575
|
+
try:
|
|
1576
|
+
# Bind parameters
|
|
1577
|
+
for i, param in enumerate(params):
|
|
1578
|
+
if isinstance(param, dict):
|
|
1579
|
+
param_name = param.get('name')
|
|
1580
|
+
default_value = param.get('default')
|
|
1581
|
+
if i < len(args):
|
|
1582
|
+
self._runtime.scope.set(param_name, args[i])
|
|
1583
|
+
elif default_value is not None:
|
|
1584
|
+
val = self._runtime._evaluate(default_value) if hasattr(default_value, 'type') else default_value
|
|
1585
|
+
self._runtime.scope.set(param_name, val)
|
|
1586
|
+
else:
|
|
1587
|
+
if i < len(args):
|
|
1588
|
+
self._runtime.scope.set(param, args[i])
|
|
1589
|
+
|
|
1590
|
+
# Find and evaluate the first return statement
|
|
1591
|
+
for child in func_node.children:
|
|
1592
|
+
ret_val = self._extract_return_value(child)
|
|
1593
|
+
if ret_val is not None:
|
|
1594
|
+
return ret_val
|
|
1595
|
+
|
|
1596
|
+
return None
|
|
1597
|
+
finally:
|
|
1598
|
+
# Restore original scope
|
|
1599
|
+
self._runtime.scope = old_scope
|
|
1600
|
+
|
|
1601
|
+
def _extract_return_value(self, node) -> Any:
|
|
1602
|
+
"""Extract return value from a node, handling conditionals and blocks.
|
|
1603
|
+
|
|
1604
|
+
v4.3.2: Properly evaluates if/else conditions to find the correct return path.
|
|
1605
|
+
"""
|
|
1606
|
+
if not hasattr(node, 'type'):
|
|
1607
|
+
return None
|
|
1608
|
+
|
|
1609
|
+
if node.type == 'return':
|
|
1610
|
+
# Found a return - evaluate it
|
|
1611
|
+
if node.value is None:
|
|
1612
|
+
return None
|
|
1613
|
+
if isinstance(node.value, dict) and node.value.get('multiple'):
|
|
1614
|
+
# Multiple return values (shuffled)
|
|
1615
|
+
return tuple(
|
|
1616
|
+
self._runtime._evaluate(v) for v in node.value.get('values', [])
|
|
1617
|
+
)
|
|
1618
|
+
return self._runtime._evaluate(node.value)
|
|
1619
|
+
|
|
1620
|
+
# v4.3.2: Handle if statements by evaluating condition
|
|
1621
|
+
if node.type == 'if':
|
|
1622
|
+
condition = node.value.get('condition')
|
|
1623
|
+
if condition:
|
|
1624
|
+
# Evaluate the condition
|
|
1625
|
+
cond_result = self._runtime._evaluate(condition)
|
|
1626
|
+
if cond_result:
|
|
1627
|
+
# Condition is true - check children (then block)
|
|
1628
|
+
if node.children:
|
|
1629
|
+
for child in node.children:
|
|
1630
|
+
ret_val = self._extract_return_value(child)
|
|
1631
|
+
if ret_val is not None:
|
|
1632
|
+
return ret_val
|
|
1633
|
+
else:
|
|
1634
|
+
# Condition is false - check else_block if present
|
|
1635
|
+
else_block = node.value.get('else_block')
|
|
1636
|
+
if else_block:
|
|
1637
|
+
for child in else_block:
|
|
1638
|
+
ret_val = self._extract_return_value(child)
|
|
1639
|
+
if ret_val is not None:
|
|
1640
|
+
return ret_val
|
|
1641
|
+
return None
|
|
1642
|
+
|
|
1643
|
+
# Check children for returns
|
|
1644
|
+
if hasattr(node, 'children') and node.children:
|
|
1645
|
+
for child in node.children:
|
|
1646
|
+
ret_val = self._extract_return_value(child)
|
|
1647
|
+
if ret_val is not None:
|
|
1648
|
+
return ret_val
|
|
1649
|
+
|
|
1650
|
+
return None
|
|
1651
|
+
|
|
1652
|
+
def _match_pattern(self, pattern: List[Dict], values: List[Any]) -> bool:
|
|
1653
|
+
"""Check if pattern matches the current values."""
|
|
1654
|
+
for i, p in enumerate(pattern):
|
|
1655
|
+
if i >= len(values):
|
|
1656
|
+
return False
|
|
1657
|
+
|
|
1658
|
+
p_type = p.get('type')
|
|
1659
|
+
value = values[i]
|
|
1660
|
+
|
|
1661
|
+
if p_type == 'wildcard':
|
|
1662
|
+
# _ matches anything
|
|
1663
|
+
continue
|
|
1664
|
+
elif p_type == 'value':
|
|
1665
|
+
# Exact value match
|
|
1666
|
+
if value != p.get('value'):
|
|
1667
|
+
return False
|
|
1668
|
+
elif p_type == 'indexed':
|
|
1669
|
+
# Match at specific index
|
|
1670
|
+
idx = p.get('index')
|
|
1671
|
+
if isinstance(idx, str) and idx.startswith('0x'):
|
|
1672
|
+
idx = int(idx, 16)
|
|
1673
|
+
if idx < len(values):
|
|
1674
|
+
if values[idx] != self._runtime._evaluate(p.get('value')) if hasattr(p.get('value'), 'type') else p.get('value'):
|
|
1675
|
+
return False
|
|
1676
|
+
elif p_type == 'type_match':
|
|
1677
|
+
# Match by type
|
|
1678
|
+
type_name = p.get('type_name')
|
|
1679
|
+
if not self._check_type(value, type_name):
|
|
1680
|
+
return False
|
|
1681
|
+
elif p_type == 'variable':
|
|
1682
|
+
# Match against variable value
|
|
1683
|
+
var_name = p.get('name')
|
|
1684
|
+
var_value = self._runtime.scope.get(var_name)
|
|
1685
|
+
if var_value is None:
|
|
1686
|
+
var_value = self._runtime.global_scope.get(var_name)
|
|
1687
|
+
if value != var_value:
|
|
1688
|
+
return False
|
|
1689
|
+
elif p_type == 'list':
|
|
1690
|
+
# v4.3.2: Match against list value: ["read", "write"]
|
|
1691
|
+
pattern_list = p.get('values', [])
|
|
1692
|
+
if not isinstance(value, (list, tuple)):
|
|
1693
|
+
return False
|
|
1694
|
+
if len(value) != len(pattern_list):
|
|
1695
|
+
return False
|
|
1696
|
+
for j, pval in enumerate(pattern_list):
|
|
1697
|
+
if value[j] != pval:
|
|
1698
|
+
return False
|
|
1699
|
+
|
|
1700
|
+
return True
|
|
1701
|
+
|
|
1702
|
+
def _check_type(self, value: Any, type_name: str) -> bool:
|
|
1703
|
+
"""Check if value matches the specified type."""
|
|
1704
|
+
type_checks = {
|
|
1705
|
+
'int': lambda v: isinstance(v, int) and not isinstance(v, bool),
|
|
1706
|
+
'float': lambda v: isinstance(v, float),
|
|
1707
|
+
'string': lambda v: isinstance(v, str),
|
|
1708
|
+
'bool': lambda v: isinstance(v, bool),
|
|
1709
|
+
'list': lambda v: isinstance(v, list),
|
|
1710
|
+
'dict': lambda v: isinstance(v, dict),
|
|
1711
|
+
'dynamic': lambda v: True,
|
|
1712
|
+
}
|
|
1713
|
+
if type_name in type_checks:
|
|
1714
|
+
return type_checks[type_name](value)
|
|
1715
|
+
# Check for generic types like vector<string>
|
|
1716
|
+
if '<' in type_name:
|
|
1717
|
+
base = type_name.split('<')[0]
|
|
1718
|
+
return isinstance(value, (list, tuple, set))
|
|
1719
|
+
return True
|
|
1720
|
+
|
|
1721
|
+
def _execute_body(self, body: List) -> Any:
|
|
1722
|
+
"""Execute a case body block."""
|
|
1723
|
+
if not self._runtime:
|
|
1724
|
+
return None
|
|
1725
|
+
result = None
|
|
1726
|
+
try:
|
|
1727
|
+
for node in body:
|
|
1728
|
+
result = self._runtime._execute_node(node)
|
|
1729
|
+
except Exception as e:
|
|
1730
|
+
# v4.3.2: Catch CSSLReturn exception by name to handle return statements
|
|
1731
|
+
if type(e).__name__ == 'CSSLReturn':
|
|
1732
|
+
return e.value
|
|
1733
|
+
raise
|
|
1734
|
+
return result
|
|
1735
|
+
|
|
1736
|
+
def __getitem__(self, key: Union[int, str]) -> Any:
|
|
1737
|
+
"""Access byte value by index or hex position.
|
|
1738
|
+
|
|
1739
|
+
MyBytes[0] - Get value at position 0
|
|
1740
|
+
MyBytes["0x0"] - Get value at position 0
|
|
1741
|
+
"""
|
|
1742
|
+
if isinstance(key, str):
|
|
1743
|
+
if key.startswith('0x') or key.startswith('0X'):
|
|
1744
|
+
key = int(key, 16)
|
|
1745
|
+
elif key.isdigit():
|
|
1746
|
+
key = int(key)
|
|
1747
|
+
else:
|
|
1748
|
+
raise KeyError(f"Invalid bytearrayed key: {key}")
|
|
1749
|
+
|
|
1750
|
+
if key in self._cached_values:
|
|
1751
|
+
return self._cached_values[key]
|
|
1752
|
+
|
|
1753
|
+
# Probe functions to get values if not cached
|
|
1754
|
+
if not self._cached_values:
|
|
1755
|
+
self._probe_functions()
|
|
1756
|
+
|
|
1757
|
+
return self._cached_values.get(key)
|
|
1758
|
+
|
|
1759
|
+
def __len__(self) -> int:
|
|
1760
|
+
"""Return number of byte positions."""
|
|
1761
|
+
return len(self.func_refs)
|
|
1762
|
+
|
|
1763
|
+
def __repr__(self) -> str:
|
|
1764
|
+
return f"ByteArrayed({self.name}, positions={len(self.func_refs)})"
|
|
1765
|
+
|
|
1766
|
+
|
|
1446
1767
|
class CSSLClass:
|
|
1447
1768
|
"""Represents a CSSL class definition.
|
|
1448
1769
|
|
includecpp/core/cssl_bridge.py
CHANGED
|
@@ -410,6 +410,7 @@ class CsslLang:
|
|
|
410
410
|
Execute CSSL code or file.
|
|
411
411
|
|
|
412
412
|
This is the primary method for running CSSL code in v3.8.0+.
|
|
413
|
+
Uses C++ acceleration when available (375x+ faster).
|
|
413
414
|
|
|
414
415
|
Args:
|
|
415
416
|
path_or_code: Path to .cssl file or CSSL code string
|
|
@@ -425,22 +426,44 @@ class CsslLang:
|
|
|
425
426
|
printl("Hello " + parameter.get(0));
|
|
426
427
|
''', "World")
|
|
427
428
|
"""
|
|
428
|
-
runtime = self._get_runtime()
|
|
429
|
-
|
|
430
429
|
# Check if it's a file path (not code)
|
|
431
430
|
# Code detection: contains newlines, semicolons, or braces = definitely code
|
|
432
431
|
is_likely_code = '\n' in path_or_code or ';' in path_or_code or '{' in path_or_code
|
|
433
432
|
source = path_or_code
|
|
433
|
+
is_file = False
|
|
434
|
+
file_path = None
|
|
434
435
|
|
|
435
436
|
if not is_likely_code:
|
|
436
437
|
try:
|
|
437
438
|
path = Path(path_or_code)
|
|
438
439
|
if path.exists() and path.suffix in ('.cssl', '.cssl-mod', '.cssl-pl'):
|
|
440
|
+
is_file = True
|
|
441
|
+
file_path = str(path.absolute())
|
|
439
442
|
source = path.read_text(encoding='utf-8')
|
|
440
443
|
except OSError:
|
|
441
444
|
# Path too long or invalid - treat as code
|
|
442
445
|
pass
|
|
443
446
|
|
|
447
|
+
# Try C++ accelerated execution first (375x faster)
|
|
448
|
+
# Only use C++ for simple scripts without parameter passing
|
|
449
|
+
if not args:
|
|
450
|
+
try:
|
|
451
|
+
from .cssl import run_cssl, run_cssl_file
|
|
452
|
+
if is_file and file_path:
|
|
453
|
+
return run_cssl_file(file_path)
|
|
454
|
+
else:
|
|
455
|
+
return run_cssl(source)
|
|
456
|
+
except Exception as cpp_error:
|
|
457
|
+
# Fall back to Python for unsupported features
|
|
458
|
+
error_msg = str(cpp_error).lower()
|
|
459
|
+
if 'unsupported' not in error_msg and 'not implemented' not in error_msg:
|
|
460
|
+
# Real error - re-raise it
|
|
461
|
+
raise RuntimeError(str(cpp_error)) from cpp_error
|
|
462
|
+
# Otherwise fall through to Python
|
|
463
|
+
|
|
464
|
+
# Python execution (for scripts with args or when C++ fails)
|
|
465
|
+
runtime = self._get_runtime()
|
|
466
|
+
|
|
444
467
|
# Set arguments in runtime scope
|
|
445
468
|
from .cssl import Parameter
|
|
446
469
|
param = Parameter(list(args))
|
|
@@ -459,6 +482,17 @@ class CsslLang:
|
|
|
459
482
|
return returns[0] if len(returns) == 1 else returns
|
|
460
483
|
|
|
461
484
|
return result
|
|
485
|
+
except UnicodeEncodeError as e:
|
|
486
|
+
# v4.3.2: Catch unicode/emoji encoding errors and provide helpful message
|
|
487
|
+
char = e.object[e.start:e.end] if hasattr(e, 'object') else '?'
|
|
488
|
+
error_msg = (
|
|
489
|
+
f"Unicode encoding error: Character '{char}' cannot be displayed.\n"
|
|
490
|
+
f" The console encoding ({e.encoding}) doesn't support this character.\n\n"
|
|
491
|
+
f" Hint: Use encode() to safely handle emojis/unicode:\n"
|
|
492
|
+
f" printl(\"Status: \" + encode(\"{char}\"));\n"
|
|
493
|
+
f" printl(encode(\"Your text with emojis\", \"[emoji]\"));"
|
|
494
|
+
)
|
|
495
|
+
raise RuntimeError(error_msg) from e
|
|
462
496
|
except Exception as e:
|
|
463
497
|
# Format error message nicely - don't add prefixes, let CLI handle that
|
|
464
498
|
error_msg = str(e)
|
includecpp/generator/parser.cpp
CHANGED
|
@@ -992,19 +992,32 @@ std::string generate_struct_bindings(const StructBinding& sb, const ModuleDescri
|
|
|
992
992
|
code << " })\n";
|
|
993
993
|
|
|
994
994
|
// Auto-generate from_dict() static method
|
|
995
|
-
|
|
996
|
-
|
|
995
|
+
// v4.3.2: Check if all fields have known types (not "auto")
|
|
996
|
+
bool template_all_types_known = true;
|
|
997
997
|
for (const auto& [field_type, field_name] : sb.fields) {
|
|
998
998
|
std::string actual_type = field_type;
|
|
999
|
-
if (actual_type == "T")
|
|
1000
|
-
|
|
999
|
+
if (actual_type == "T") actual_type = ttype;
|
|
1000
|
+
if (actual_type == "auto" || actual_type.empty()) {
|
|
1001
|
+
template_all_types_known = false;
|
|
1002
|
+
break;
|
|
1001
1003
|
}
|
|
1004
|
+
}
|
|
1002
1005
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1006
|
+
if (template_all_types_known && !sb.fields.empty()) {
|
|
1007
|
+
code << " .def_static(\"from_dict\", [](py::dict d) {\n";
|
|
1008
|
+
code << " " << cpp_type << " obj;\n";
|
|
1009
|
+
for (const auto& [field_type, field_name] : sb.fields) {
|
|
1010
|
+
std::string actual_type = field_type;
|
|
1011
|
+
if (actual_type == "T") {
|
|
1012
|
+
actual_type = ttype;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
code << " obj." << field_name << " = d[\"" << field_name
|
|
1016
|
+
<< "\"].cast<" << actual_type << ">();\n";
|
|
1017
|
+
}
|
|
1018
|
+
code << " return obj;\n";
|
|
1019
|
+
code << " })\n";
|
|
1005
1020
|
}
|
|
1006
|
-
code << " return obj;\n";
|
|
1007
|
-
code << " })\n";
|
|
1008
1021
|
|
|
1009
1022
|
// v2.8: Add __repr__ for better debugging output
|
|
1010
1023
|
code << " .def(\"__repr__\", [](" << cpp_type << "& self) {\n";
|
|
@@ -1052,14 +1065,25 @@ std::string generate_struct_bindings(const StructBinding& sb, const ModuleDescri
|
|
|
1052
1065
|
code << " })\n";
|
|
1053
1066
|
|
|
1054
1067
|
// Auto-generate from_dict() static method
|
|
1055
|
-
|
|
1056
|
-
|
|
1068
|
+
// v4.3.2: Check if all fields have known types (not "auto")
|
|
1069
|
+
bool all_types_known = true;
|
|
1057
1070
|
for (const auto& [field_type, field_name] : sb.fields) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1071
|
+
if (field_type == "auto" || field_type.empty()) {
|
|
1072
|
+
all_types_known = false;
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if (all_types_known && !sb.fields.empty()) {
|
|
1078
|
+
code << " .def_static(\"from_dict\", [](py::dict d) {\n";
|
|
1079
|
+
code << " " << sb.struct_name << " obj;\n";
|
|
1080
|
+
for (const auto& [field_type, field_name] : sb.fields) {
|
|
1081
|
+
code << " obj." << field_name << " = d[\"" << field_name
|
|
1082
|
+
<< "\"].cast<" << field_type << ">();\n";
|
|
1083
|
+
}
|
|
1084
|
+
code << " return obj;\n";
|
|
1085
|
+
code << " })\n";
|
|
1060
1086
|
}
|
|
1061
|
-
code << " return obj;\n";
|
|
1062
|
-
code << " })\n";
|
|
1063
1087
|
|
|
1064
1088
|
// v2.8: Add __repr__ for better debugging output
|
|
1065
1089
|
code << " .def(\"__repr__\", [](" << sb.struct_name << "& self) {\n";
|
|
@@ -56,6 +56,16 @@
|
|
|
56
56
|
"light": "./images/cssl_pl.png",
|
|
57
57
|
"dark": "./images/cssl_pl.png"
|
|
58
58
|
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "cp",
|
|
62
|
+
"aliases": ["IncludeCPP Plugin", "cp"],
|
|
63
|
+
"extensions": [".cp"],
|
|
64
|
+
"configuration": "./language-configuration.json",
|
|
65
|
+
"icon": {
|
|
66
|
+
"light": "./images/cssl.png",
|
|
67
|
+
"dark": "./images/cssl.png"
|
|
68
|
+
}
|
|
59
69
|
}
|
|
60
70
|
],
|
|
61
71
|
"grammars": [
|
|
@@ -73,6 +83,11 @@
|
|
|
73
83
|
"language": "cssl-pl",
|
|
74
84
|
"scopeName": "source.cssl",
|
|
75
85
|
"path": "./syntaxes/cssl.tmLanguage.json"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"language": "cp",
|
|
89
|
+
"scopeName": "source.cssl",
|
|
90
|
+
"path": "./syntaxes/cssl.tmLanguage.json"
|
|
76
91
|
}
|
|
77
92
|
],
|
|
78
93
|
"snippets": [
|