IncludeCPP 3.8.0__py3-none-any.whl → 3.8.9__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/core/cssl/CSSL_DOCUMENTATION.md +411 -1
- includecpp/core/cssl/cssl_builtins.py +133 -0
- includecpp/core/cssl/cssl_parser.py +480 -8
- includecpp/core/cssl/cssl_runtime.py +616 -16
- includecpp/core/cssl/cssl_types.py +58 -9
- includecpp/vscode/cssl/package.json +1 -1
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +250 -3
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/METADATA +1 -1
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/RECORD +14 -14
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/WHEEL +0 -0
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/entry_points.txt +0 -0
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.8.0.dist-info → includecpp-3.8.9.dist-info}/top_level.txt +0 -0
|
@@ -110,11 +110,14 @@ class TokenType(Enum):
|
|
|
110
110
|
EOF = auto()
|
|
111
111
|
# Super-functions for .cssl-pl payload files (v3.8.0)
|
|
112
112
|
SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
|
|
113
|
+
# Append operator for constructor/function extension
|
|
114
|
+
PLUS_PLUS = auto() # ++ for constructor/function append (keeps old + adds new)
|
|
115
|
+
MINUS_MINUS = auto() # -- for potential future use
|
|
113
116
|
|
|
114
117
|
|
|
115
118
|
KEYWORDS = {
|
|
116
119
|
# Service structure
|
|
117
|
-
'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'new', 'this',
|
|
120
|
+
'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'constr', 'extends', 'overwrites', 'new', 'this', 'super',
|
|
118
121
|
# Control flow
|
|
119
122
|
'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
|
|
120
123
|
'switch', 'case', 'default', 'break', 'continue', 'return',
|
|
@@ -307,8 +310,13 @@ class CSSLLexer:
|
|
|
307
310
|
self._add_token(TokenType.DOT, '.')
|
|
308
311
|
self._advance()
|
|
309
312
|
elif char == '+':
|
|
313
|
+
# Check for ++ (append operator for constructor/function extension)
|
|
314
|
+
if self._peek(1) == '+':
|
|
315
|
+
self._add_token(TokenType.PLUS_PLUS, '++')
|
|
316
|
+
self._advance()
|
|
317
|
+
self._advance()
|
|
310
318
|
# Check for BruteForce Injection: +<== or +<<==
|
|
311
|
-
|
|
319
|
+
elif self._peek(1) == '<' and self._peek(2) == '<' and self._peek(3) == '=' and self._peek(4) == '=':
|
|
312
320
|
self._add_token(TokenType.INFUSE_PLUS_LEFT, '+<<==')
|
|
313
321
|
for _ in range(5): self._advance()
|
|
314
322
|
elif self._peek(1) == '<' and self._peek(2) == '=' and self._peek(3) == '=':
|
|
@@ -1025,7 +1033,11 @@ class CSSLParser:
|
|
|
1025
1033
|
return result
|
|
1026
1034
|
|
|
1027
1035
|
def _parse_typed_variable(self) -> Optional[ASTNode]:
|
|
1028
|
-
"""Parse a typed variable declaration: type varName; or type<T> varName = value;
|
|
1036
|
+
"""Parse a typed variable declaration: type varName; or type<T> *varName = value;
|
|
1037
|
+
|
|
1038
|
+
The * prefix indicates a non-nullable variable (can never be None/null).
|
|
1039
|
+
Example: vector<dynamic> *MyVector - can never contain None values.
|
|
1040
|
+
"""
|
|
1029
1041
|
# Get type name
|
|
1030
1042
|
type_name = self._advance().value # Consume type keyword
|
|
1031
1043
|
|
|
@@ -1039,6 +1051,11 @@ class CSSLParser:
|
|
|
1039
1051
|
element_type = self._advance().value
|
|
1040
1052
|
self._expect(TokenType.COMPARE_GT)
|
|
1041
1053
|
|
|
1054
|
+
# Check for * prefix (non-nullable indicator)
|
|
1055
|
+
non_null = False
|
|
1056
|
+
if self._match(TokenType.MULTIPLY):
|
|
1057
|
+
non_null = True
|
|
1058
|
+
|
|
1042
1059
|
# Get variable name
|
|
1043
1060
|
if not self._check(TokenType.IDENTIFIER):
|
|
1044
1061
|
return None
|
|
@@ -1056,14 +1073,16 @@ class CSSLParser:
|
|
|
1056
1073
|
return ASTNode('instance_declaration', value={
|
|
1057
1074
|
'instance_name': element_type,
|
|
1058
1075
|
'name': var_name,
|
|
1059
|
-
'value': value
|
|
1076
|
+
'value': value,
|
|
1077
|
+
'non_null': non_null
|
|
1060
1078
|
})
|
|
1061
1079
|
|
|
1062
1080
|
return ASTNode('typed_declaration', value={
|
|
1063
1081
|
'type': type_name,
|
|
1064
1082
|
'element_type': element_type,
|
|
1065
1083
|
'name': var_name,
|
|
1066
|
-
'value': value
|
|
1084
|
+
'value': value,
|
|
1085
|
+
'non_null': non_null
|
|
1067
1086
|
})
|
|
1068
1087
|
|
|
1069
1088
|
def parse_program(self) -> ASTNode:
|
|
@@ -1361,10 +1380,79 @@ class CSSLParser:
|
|
|
1361
1380
|
printl("Hello " + this->name);
|
|
1362
1381
|
}
|
|
1363
1382
|
}
|
|
1383
|
+
|
|
1384
|
+
Non-null class (all methods return non-null):
|
|
1385
|
+
class *MyClass { ... }
|
|
1364
1386
|
"""
|
|
1387
|
+
# Check for * prefix (non-null class - all methods return non-null)
|
|
1388
|
+
non_null = False
|
|
1389
|
+
if self._match(TokenType.MULTIPLY):
|
|
1390
|
+
non_null = True
|
|
1391
|
+
|
|
1365
1392
|
class_name = self._advance().value
|
|
1366
1393
|
|
|
1367
|
-
|
|
1394
|
+
# Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
|
|
1395
|
+
class_params = []
|
|
1396
|
+
if self._match(TokenType.PAREN_START):
|
|
1397
|
+
class_params = self._parse_parameter_list()
|
|
1398
|
+
self._expect(TokenType.PAREN_END)
|
|
1399
|
+
|
|
1400
|
+
# Check for inheritance and overwrites:
|
|
1401
|
+
# class Child : extends Parent { ... }
|
|
1402
|
+
# class Child : extends $PythonObject { ... }
|
|
1403
|
+
# class Child : extends Parent : overwrites Parent { ... }
|
|
1404
|
+
# class Child : extends Parent (param1, param2) { ... } <- constructor args for parent
|
|
1405
|
+
extends_class = None
|
|
1406
|
+
extends_is_python = False
|
|
1407
|
+
extends_args = []
|
|
1408
|
+
overwrites_class = None
|
|
1409
|
+
overwrites_is_python = False
|
|
1410
|
+
|
|
1411
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1412
|
+
# Parse extends and/or overwrites (can be chained with : or ::)
|
|
1413
|
+
while True:
|
|
1414
|
+
if self._match_keyword('extends'):
|
|
1415
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1416
|
+
extends_class = self._advance().value
|
|
1417
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1418
|
+
extends_class = self._advance().value
|
|
1419
|
+
extends_is_python = True
|
|
1420
|
+
else:
|
|
1421
|
+
raise CSSLSyntaxError("Expected parent class name after 'extends'")
|
|
1422
|
+
# Check for constructor arguments: extends Parent (arg1, arg2)
|
|
1423
|
+
if self._match(TokenType.PAREN_START):
|
|
1424
|
+
while not self._check(TokenType.PAREN_END):
|
|
1425
|
+
arg = self._parse_expression()
|
|
1426
|
+
extends_args.append(arg)
|
|
1427
|
+
self._match(TokenType.COMMA)
|
|
1428
|
+
self._expect(TokenType.PAREN_END)
|
|
1429
|
+
elif self._match_keyword('overwrites'):
|
|
1430
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1431
|
+
overwrites_class = self._advance().value
|
|
1432
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1433
|
+
overwrites_class = self._advance().value
|
|
1434
|
+
overwrites_is_python = True
|
|
1435
|
+
else:
|
|
1436
|
+
raise CSSLSyntaxError("Expected class name after 'overwrites'")
|
|
1437
|
+
# Skip optional () after class name
|
|
1438
|
+
if self._match(TokenType.PAREN_START):
|
|
1439
|
+
self._expect(TokenType.PAREN_END)
|
|
1440
|
+
else:
|
|
1441
|
+
raise CSSLSyntaxError("Expected 'extends' or 'overwrites' after ':' or '::' in class declaration")
|
|
1442
|
+
# Check for another : or :: for chaining
|
|
1443
|
+
if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
|
|
1444
|
+
break
|
|
1445
|
+
|
|
1446
|
+
node = ASTNode('class', value={
|
|
1447
|
+
'name': class_name,
|
|
1448
|
+
'non_null': non_null,
|
|
1449
|
+
'class_params': class_params,
|
|
1450
|
+
'extends': extends_class,
|
|
1451
|
+
'extends_is_python': extends_is_python,
|
|
1452
|
+
'extends_args': extends_args,
|
|
1453
|
+
'overwrites': overwrites_class,
|
|
1454
|
+
'overwrites_is_python': overwrites_is_python
|
|
1455
|
+
}, children=[])
|
|
1368
1456
|
self._expect(TokenType.BLOCK_START)
|
|
1369
1457
|
|
|
1370
1458
|
while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
|
|
@@ -1393,14 +1481,297 @@ class CSSLParser:
|
|
|
1393
1481
|
method = self._parse_define()
|
|
1394
1482
|
node.children.append(method)
|
|
1395
1483
|
|
|
1484
|
+
# Check for constr keyword (constructor declaration)
|
|
1485
|
+
# Syntax: constr ConstructorName() { ... }
|
|
1486
|
+
# or: constr ConstructorName() : extends Parent::ConstructorName { ... }
|
|
1487
|
+
elif self._match_keyword('constr'):
|
|
1488
|
+
constructor = self._parse_constructor(class_name)
|
|
1489
|
+
node.children.append(constructor)
|
|
1490
|
+
|
|
1396
1491
|
else:
|
|
1397
1492
|
self._advance()
|
|
1398
1493
|
|
|
1399
1494
|
self._expect(TokenType.BLOCK_END)
|
|
1400
1495
|
return node
|
|
1401
1496
|
|
|
1497
|
+
def _parse_constructor(self, class_name: str) -> ASTNode:
|
|
1498
|
+
"""Parse constructor declaration inside a class.
|
|
1499
|
+
|
|
1500
|
+
Syntax:
|
|
1501
|
+
constr ConstructorName() { ... }
|
|
1502
|
+
constr ConstructorName() ++ { ... } // Append: keeps parent constructor + adds new code
|
|
1503
|
+
constr ConstructorName() &ParentClass::constructors ++ { ... } // Append specific parent constructor
|
|
1504
|
+
constr ConstructorName() : extends ParentClass::ConstructorName { ... }
|
|
1505
|
+
constr ConstructorName() : extends ParentClass::ConstructorName : overwrites ParentClass::ConstructorName { ... }
|
|
1506
|
+
|
|
1507
|
+
The ++ operator means: execute parent's version first, then execute this code (append mode).
|
|
1508
|
+
The &ClassName::member syntax references a specific member from the overwritten class.
|
|
1509
|
+
"""
|
|
1510
|
+
# Get constructor name
|
|
1511
|
+
if not self._check(TokenType.IDENTIFIER):
|
|
1512
|
+
raise CSSLSyntaxError("Expected constructor name after 'constr'")
|
|
1513
|
+
constr_name = self._advance().value
|
|
1514
|
+
|
|
1515
|
+
# Parse method-level extends/overwrites with :: syntax
|
|
1516
|
+
extends_target = None
|
|
1517
|
+
extends_class_ref = None
|
|
1518
|
+
extends_method_ref = None
|
|
1519
|
+
overwrites_target = None
|
|
1520
|
+
overwrites_class_ref = None
|
|
1521
|
+
overwrites_method_ref = None
|
|
1522
|
+
|
|
1523
|
+
# New: Append mode and reference tracking
|
|
1524
|
+
append_mode = False # ++ operator: keep parent code + add new
|
|
1525
|
+
append_ref_class = None # &ClassName part
|
|
1526
|
+
append_ref_member = None # ::member part (constructors, functionName, etc.)
|
|
1527
|
+
|
|
1528
|
+
# Parse parameters
|
|
1529
|
+
params = []
|
|
1530
|
+
if self._match(TokenType.PAREN_START):
|
|
1531
|
+
params = self._parse_parameter_list()
|
|
1532
|
+
self._expect(TokenType.PAREN_END)
|
|
1533
|
+
|
|
1534
|
+
# Check for &ClassName::member reference (for targeting specific parent member)
|
|
1535
|
+
# Syntax: constr Name() &ParentClass::constructors ++ { ... }
|
|
1536
|
+
if self._match(TokenType.AMPERSAND):
|
|
1537
|
+
# Parse the class reference
|
|
1538
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1539
|
+
append_ref_class = self._advance().value
|
|
1540
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1541
|
+
append_ref_class = f'${self._advance().value}'
|
|
1542
|
+
else:
|
|
1543
|
+
raise CSSLSyntaxError("Expected class name after '&' in constructor reference")
|
|
1544
|
+
|
|
1545
|
+
# Check for ::member
|
|
1546
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1547
|
+
if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
|
|
1548
|
+
append_ref_member = self._advance().value
|
|
1549
|
+
else:
|
|
1550
|
+
raise CSSLSyntaxError("Expected member name after '::' in constructor reference")
|
|
1551
|
+
|
|
1552
|
+
# Check for ++ append operator
|
|
1553
|
+
if self._match(TokenType.PLUS_PLUS):
|
|
1554
|
+
append_mode = True
|
|
1555
|
+
|
|
1556
|
+
# Check for method-level extends/overwrites with :: or :
|
|
1557
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1558
|
+
while True:
|
|
1559
|
+
if self._match_keyword('extends'):
|
|
1560
|
+
# Parse Parent::method or just method
|
|
1561
|
+
extends_target = self._parse_qualified_method_ref()
|
|
1562
|
+
if '::' in extends_target:
|
|
1563
|
+
parts = extends_target.split('::')
|
|
1564
|
+
extends_class_ref = parts[0]
|
|
1565
|
+
extends_method_ref = parts[1]
|
|
1566
|
+
else:
|
|
1567
|
+
extends_method_ref = extends_target
|
|
1568
|
+
elif self._match_keyword('overwrites'):
|
|
1569
|
+
# Parse Parent::method or just method
|
|
1570
|
+
overwrites_target = self._parse_qualified_method_ref()
|
|
1571
|
+
if '::' in overwrites_target:
|
|
1572
|
+
parts = overwrites_target.split('::')
|
|
1573
|
+
overwrites_class_ref = parts[0]
|
|
1574
|
+
overwrites_method_ref = parts[1]
|
|
1575
|
+
else:
|
|
1576
|
+
overwrites_method_ref = overwrites_target
|
|
1577
|
+
else:
|
|
1578
|
+
break
|
|
1579
|
+
# Check for another :: or : for chaining
|
|
1580
|
+
if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
|
|
1581
|
+
break
|
|
1582
|
+
|
|
1583
|
+
# Parse constructor body
|
|
1584
|
+
self._expect(TokenType.BLOCK_START)
|
|
1585
|
+
body = []
|
|
1586
|
+
while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
|
|
1587
|
+
stmt = self._parse_statement()
|
|
1588
|
+
if stmt:
|
|
1589
|
+
body.append(stmt)
|
|
1590
|
+
self._expect(TokenType.BLOCK_END)
|
|
1591
|
+
|
|
1592
|
+
return ASTNode('constructor', value={
|
|
1593
|
+
'name': constr_name,
|
|
1594
|
+
'class_name': class_name,
|
|
1595
|
+
'params': params,
|
|
1596
|
+
'is_constructor': True,
|
|
1597
|
+
'extends_target': extends_target,
|
|
1598
|
+
'extends_class': extends_class_ref,
|
|
1599
|
+
'extends_method': extends_method_ref,
|
|
1600
|
+
'overwrites_target': overwrites_target,
|
|
1601
|
+
'overwrites_class': overwrites_class_ref,
|
|
1602
|
+
'overwrites_method': overwrites_method_ref,
|
|
1603
|
+
# New append mode fields
|
|
1604
|
+
'append_mode': append_mode,
|
|
1605
|
+
'append_ref_class': append_ref_class,
|
|
1606
|
+
'append_ref_member': append_ref_member
|
|
1607
|
+
}, children=body)
|
|
1608
|
+
|
|
1609
|
+
def _parse_qualified_method_ref(self) -> str:
|
|
1610
|
+
"""Parse a qualified method reference like 'ParentClass::methodName' or just 'methodName'.
|
|
1611
|
+
|
|
1612
|
+
Returns the qualified name as a string (e.g., 'Parent::init' or just 'init').
|
|
1613
|
+
"""
|
|
1614
|
+
# Check for $PythonObject
|
|
1615
|
+
if self._check(TokenType.SHARED_REF):
|
|
1616
|
+
class_ref = self._advance().value # Gets the name without $
|
|
1617
|
+
class_ref = f'${class_ref}'
|
|
1618
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1619
|
+
class_ref = self._advance().value
|
|
1620
|
+
else:
|
|
1621
|
+
raise CSSLSyntaxError("Expected class or method name in extends/overwrites")
|
|
1622
|
+
|
|
1623
|
+
# Check for :: to get method part
|
|
1624
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1625
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1626
|
+
method_ref = self._advance().value
|
|
1627
|
+
return f'{class_ref}::{method_ref}'
|
|
1628
|
+
else:
|
|
1629
|
+
raise CSSLSyntaxError("Expected method name after '::'")
|
|
1630
|
+
|
|
1631
|
+
# Just method name, no class qualifier
|
|
1632
|
+
return class_ref
|
|
1633
|
+
|
|
1634
|
+
def _parse_parameter_list(self) -> list:
|
|
1635
|
+
"""Parse a list of parameters (without the surrounding parentheses).
|
|
1636
|
+
|
|
1637
|
+
Returns a list of parameter definitions, each can be:
|
|
1638
|
+
- Simple string name: "paramName"
|
|
1639
|
+
- Dict with type info: {'name': 'paramName', 'type': 'string', 'ref': True, ...}
|
|
1640
|
+
"""
|
|
1641
|
+
params = []
|
|
1642
|
+
while not self._check(TokenType.PAREN_END) and not self._is_at_end():
|
|
1643
|
+
param_info = {}
|
|
1644
|
+
|
|
1645
|
+
# Handle 'open' keyword for open parameters
|
|
1646
|
+
if self._match_keyword('open'):
|
|
1647
|
+
param_info['open'] = True
|
|
1648
|
+
|
|
1649
|
+
# Handle type annotations (e.g., string, int, dynamic, etc.)
|
|
1650
|
+
if self._check(TokenType.KEYWORD):
|
|
1651
|
+
param_info['type'] = self._advance().value
|
|
1652
|
+
|
|
1653
|
+
# Handle reference operator &
|
|
1654
|
+
if self._match(TokenType.AMPERSAND):
|
|
1655
|
+
param_info['ref'] = True
|
|
1656
|
+
|
|
1657
|
+
# Handle * prefix for non-null parameters
|
|
1658
|
+
if self._match(TokenType.MULTIPLY):
|
|
1659
|
+
param_info['non_null'] = True
|
|
1660
|
+
|
|
1661
|
+
# Get parameter name
|
|
1662
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1663
|
+
param_name = self._advance().value
|
|
1664
|
+
if param_info:
|
|
1665
|
+
params.append({'name': param_name, **param_info})
|
|
1666
|
+
else:
|
|
1667
|
+
params.append(param_name)
|
|
1668
|
+
self._match(TokenType.COMMA)
|
|
1669
|
+
elif self._check(TokenType.KEYWORD):
|
|
1670
|
+
# Parameter name could be a keyword like 'Params'
|
|
1671
|
+
param_name = self._advance().value
|
|
1672
|
+
if param_info:
|
|
1673
|
+
params.append({'name': param_name, **param_info})
|
|
1674
|
+
else:
|
|
1675
|
+
params.append(param_name)
|
|
1676
|
+
self._match(TokenType.COMMA)
|
|
1677
|
+
else:
|
|
1678
|
+
break
|
|
1679
|
+
|
|
1680
|
+
return params
|
|
1681
|
+
|
|
1402
1682
|
def _parse_define(self) -> ASTNode:
|
|
1683
|
+
"""Parse define function declaration.
|
|
1684
|
+
|
|
1685
|
+
Syntax:
|
|
1686
|
+
define MyFunc(args) { }
|
|
1687
|
+
define *MyFunc(args) { } // Non-null: must never return None
|
|
1688
|
+
define MyFunc : extends OtherFunc() { } // Inherit local vars
|
|
1689
|
+
define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
|
|
1690
|
+
define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
|
|
1691
|
+
"""
|
|
1692
|
+
# Check for * prefix (non-null function - must return non-null)
|
|
1693
|
+
non_null = False
|
|
1694
|
+
if self._match(TokenType.MULTIPLY):
|
|
1695
|
+
non_null = True
|
|
1696
|
+
|
|
1403
1697
|
name = self._advance().value
|
|
1698
|
+
|
|
1699
|
+
# Check for extends/overwrites: define func : extends/overwrites target() { }
|
|
1700
|
+
# Also supports method-level :: syntax: define func :: extends Parent::method
|
|
1701
|
+
extends_func = None
|
|
1702
|
+
overwrites_func = None
|
|
1703
|
+
extends_is_python = False
|
|
1704
|
+
overwrites_is_python = False
|
|
1705
|
+
extends_class_ref = None
|
|
1706
|
+
extends_method_ref = None
|
|
1707
|
+
overwrites_class_ref = None
|
|
1708
|
+
overwrites_method_ref = None
|
|
1709
|
+
|
|
1710
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1711
|
+
# Parse extends and/or overwrites (supports :: method-level syntax)
|
|
1712
|
+
while True:
|
|
1713
|
+
if self._match_keyword('extends'):
|
|
1714
|
+
# Check for qualified reference: Parent::method
|
|
1715
|
+
if self._check(TokenType.SHARED_REF):
|
|
1716
|
+
extends_is_python = True
|
|
1717
|
+
extends_func = self._advance().value
|
|
1718
|
+
# Check for ::method
|
|
1719
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1720
|
+
extends_class_ref = f'${extends_func}'
|
|
1721
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1722
|
+
extends_method_ref = self._advance().value
|
|
1723
|
+
else:
|
|
1724
|
+
raise CSSLSyntaxError("Expected method name after '::'")
|
|
1725
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1726
|
+
first_part = self._advance().value
|
|
1727
|
+
# Check for ::method (qualified reference)
|
|
1728
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1729
|
+
extends_class_ref = first_part
|
|
1730
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1731
|
+
extends_method_ref = self._advance().value
|
|
1732
|
+
else:
|
|
1733
|
+
raise CSSLSyntaxError("Expected method name after '::'")
|
|
1734
|
+
else:
|
|
1735
|
+
extends_func = first_part
|
|
1736
|
+
else:
|
|
1737
|
+
raise CSSLSyntaxError("Expected function name after 'extends'")
|
|
1738
|
+
# Skip optional () after function/method name
|
|
1739
|
+
if self._match(TokenType.PAREN_START):
|
|
1740
|
+
self._expect(TokenType.PAREN_END)
|
|
1741
|
+
elif self._match_keyword('overwrites'):
|
|
1742
|
+
# Check for qualified reference: Parent::method
|
|
1743
|
+
if self._check(TokenType.SHARED_REF):
|
|
1744
|
+
overwrites_is_python = True
|
|
1745
|
+
overwrites_func = self._advance().value
|
|
1746
|
+
# Check for ::method
|
|
1747
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1748
|
+
overwrites_class_ref = f'${overwrites_func}'
|
|
1749
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1750
|
+
overwrites_method_ref = self._advance().value
|
|
1751
|
+
else:
|
|
1752
|
+
raise CSSLSyntaxError("Expected method name after '::'")
|
|
1753
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1754
|
+
first_part = self._advance().value
|
|
1755
|
+
# Check for ::method (qualified reference)
|
|
1756
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1757
|
+
overwrites_class_ref = first_part
|
|
1758
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1759
|
+
overwrites_method_ref = self._advance().value
|
|
1760
|
+
else:
|
|
1761
|
+
raise CSSLSyntaxError("Expected method name after '::'")
|
|
1762
|
+
else:
|
|
1763
|
+
overwrites_func = first_part
|
|
1764
|
+
else:
|
|
1765
|
+
raise CSSLSyntaxError("Expected function name after 'overwrites'")
|
|
1766
|
+
# Skip optional () after function/method name
|
|
1767
|
+
if self._match(TokenType.PAREN_START):
|
|
1768
|
+
self._expect(TokenType.PAREN_END)
|
|
1769
|
+
else:
|
|
1770
|
+
break
|
|
1771
|
+
# Check for another :: or : for chaining extends/overwrites
|
|
1772
|
+
if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
|
|
1773
|
+
break
|
|
1774
|
+
|
|
1404
1775
|
params = []
|
|
1405
1776
|
|
|
1406
1777
|
if self._match(TokenType.PAREN_START):
|
|
@@ -1415,6 +1786,9 @@ class CSSLParser:
|
|
|
1415
1786
|
# Handle reference operator &
|
|
1416
1787
|
if self._match(TokenType.AMPERSAND):
|
|
1417
1788
|
param_info['ref'] = True
|
|
1789
|
+
# Handle * prefix for non-null parameters
|
|
1790
|
+
if self._match(TokenType.MULTIPLY):
|
|
1791
|
+
param_info['non_null'] = True
|
|
1418
1792
|
# Get parameter name
|
|
1419
1793
|
if self._check(TokenType.IDENTIFIER):
|
|
1420
1794
|
param_name = self._advance().value
|
|
@@ -1435,7 +1809,50 @@ class CSSLParser:
|
|
|
1435
1809
|
break
|
|
1436
1810
|
self._expect(TokenType.PAREN_END)
|
|
1437
1811
|
|
|
1438
|
-
|
|
1812
|
+
# New: Append mode and reference tracking for functions
|
|
1813
|
+
# Syntax: define XYZ(int zahl) &overwrittenclass::functionyouwanttokeep ++ { ... }
|
|
1814
|
+
append_mode = False
|
|
1815
|
+
append_ref_class = None
|
|
1816
|
+
append_ref_member = None
|
|
1817
|
+
|
|
1818
|
+
# Check for &ClassName::member reference
|
|
1819
|
+
if self._match(TokenType.AMPERSAND):
|
|
1820
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1821
|
+
append_ref_class = self._advance().value
|
|
1822
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1823
|
+
append_ref_class = f'${self._advance().value}'
|
|
1824
|
+
else:
|
|
1825
|
+
raise CSSLSyntaxError("Expected class name after '&' in function reference")
|
|
1826
|
+
|
|
1827
|
+
# Check for ::member
|
|
1828
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1829
|
+
if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
|
|
1830
|
+
append_ref_member = self._advance().value
|
|
1831
|
+
else:
|
|
1832
|
+
raise CSSLSyntaxError("Expected member name after '::' in function reference")
|
|
1833
|
+
|
|
1834
|
+
# Check for ++ append operator
|
|
1835
|
+
if self._match(TokenType.PLUS_PLUS):
|
|
1836
|
+
append_mode = True
|
|
1837
|
+
|
|
1838
|
+
node = ASTNode('function', value={
|
|
1839
|
+
'name': name,
|
|
1840
|
+
'params': params,
|
|
1841
|
+
'non_null': non_null,
|
|
1842
|
+
'extends': extends_func,
|
|
1843
|
+
'extends_is_python': extends_is_python,
|
|
1844
|
+
'overwrites': overwrites_func,
|
|
1845
|
+
'overwrites_is_python': overwrites_is_python,
|
|
1846
|
+
# Method-level inheritance (Parent::method syntax)
|
|
1847
|
+
'extends_class': extends_class_ref,
|
|
1848
|
+
'extends_method': extends_method_ref,
|
|
1849
|
+
'overwrites_class': overwrites_class_ref,
|
|
1850
|
+
'overwrites_method': overwrites_method_ref,
|
|
1851
|
+
# New append mode fields
|
|
1852
|
+
'append_mode': append_mode,
|
|
1853
|
+
'append_ref_class': append_ref_class,
|
|
1854
|
+
'append_ref_member': append_ref_member
|
|
1855
|
+
}, children=[])
|
|
1439
1856
|
self._expect(TokenType.BLOCK_START)
|
|
1440
1857
|
|
|
1441
1858
|
while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
|
|
@@ -1481,6 +1898,11 @@ class CSSLParser:
|
|
|
1481
1898
|
elif self._check(TokenType.SUPER_FUNC):
|
|
1482
1899
|
# Super-function for .cssl-pl payload files
|
|
1483
1900
|
return self._parse_super_function()
|
|
1901
|
+
elif (self._check(TokenType.KEYWORD) and self._current().value == 'super' and
|
|
1902
|
+
(self._peek(1).type == TokenType.PAREN_START or
|
|
1903
|
+
self._peek(1).type == TokenType.DOUBLE_COLON)):
|
|
1904
|
+
# super() or super::method() call - calls parent constructor/method
|
|
1905
|
+
return self._parse_super_call()
|
|
1484
1906
|
elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1485
1907
|
self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
|
|
1486
1908
|
self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
|
|
@@ -1491,6 +1913,43 @@ class CSSLParser:
|
|
|
1491
1913
|
self._advance()
|
|
1492
1914
|
return None
|
|
1493
1915
|
|
|
1916
|
+
def _parse_super_call(self) -> ASTNode:
|
|
1917
|
+
"""Parse super() call to invoke parent constructor or method.
|
|
1918
|
+
|
|
1919
|
+
Syntax:
|
|
1920
|
+
super() - Call parent constructor with no args
|
|
1921
|
+
super(arg1, arg2) - Call parent constructor with args
|
|
1922
|
+
super::method() - Call specific parent method
|
|
1923
|
+
super::method(args) - Call specific parent method with args
|
|
1924
|
+
|
|
1925
|
+
Used inside constructors (constr) and methods to call parent implementations.
|
|
1926
|
+
"""
|
|
1927
|
+
# Consume 'super' keyword
|
|
1928
|
+
self._advance()
|
|
1929
|
+
|
|
1930
|
+
# Check for ::method syntax
|
|
1931
|
+
target_method = None
|
|
1932
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1933
|
+
if not self._check(TokenType.IDENTIFIER):
|
|
1934
|
+
raise CSSLSyntaxError("Expected method name after 'super::'")
|
|
1935
|
+
target_method = self._advance().value
|
|
1936
|
+
|
|
1937
|
+
# Parse arguments
|
|
1938
|
+
args = []
|
|
1939
|
+
self._expect(TokenType.PAREN_START)
|
|
1940
|
+
while not self._check(TokenType.PAREN_END):
|
|
1941
|
+
arg = self._parse_expression()
|
|
1942
|
+
args.append(arg)
|
|
1943
|
+
if not self._match(TokenType.COMMA):
|
|
1944
|
+
break
|
|
1945
|
+
self._expect(TokenType.PAREN_END)
|
|
1946
|
+
self._match(TokenType.SEMICOLON)
|
|
1947
|
+
|
|
1948
|
+
return ASTNode('super_call', value={
|
|
1949
|
+
'method': target_method, # None for constructor, method name for specific method
|
|
1950
|
+
'args': args
|
|
1951
|
+
})
|
|
1952
|
+
|
|
1494
1953
|
def _parse_if(self) -> ASTNode:
|
|
1495
1954
|
"""Parse if statement with support for else if AND elif syntax."""
|
|
1496
1955
|
self._expect(TokenType.PAREN_START)
|
|
@@ -2610,12 +3069,24 @@ class CSSLParser:
|
|
|
2610
3069
|
'init_values': init_values
|
|
2611
3070
|
})
|
|
2612
3071
|
|
|
2613
|
-
# Check for type-parameterized function call: OpenFind<string>(0)
|
|
3072
|
+
# Check for type-parameterized function call: OpenFind<string>(0) or OpenFind<dynamic, "name">
|
|
2614
3073
|
if name in TYPE_PARAM_FUNCTIONS and self._check(TokenType.COMPARE_LT):
|
|
2615
3074
|
self._advance() # consume <
|
|
2616
3075
|
type_param = 'dynamic'
|
|
3076
|
+
param_name = None # Optional: named parameter search
|
|
3077
|
+
|
|
2617
3078
|
if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
|
|
2618
3079
|
type_param = self._advance().value
|
|
3080
|
+
|
|
3081
|
+
# Check for second parameter: OpenFind<type, "name">
|
|
3082
|
+
if self._check(TokenType.COMMA):
|
|
3083
|
+
self._advance() # consume comma
|
|
3084
|
+
# Expect a string literal for the parameter name
|
|
3085
|
+
if self._check(TokenType.STRING):
|
|
3086
|
+
param_name = self._advance().value
|
|
3087
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
3088
|
+
param_name = self._advance().value
|
|
3089
|
+
|
|
2619
3090
|
self._expect(TokenType.COMPARE_GT) # consume >
|
|
2620
3091
|
|
|
2621
3092
|
# Must be followed by ()
|
|
@@ -2632,6 +3103,7 @@ class CSSLParser:
|
|
|
2632
3103
|
return ASTNode('typed_call', value={
|
|
2633
3104
|
'name': name,
|
|
2634
3105
|
'type_param': type_param,
|
|
3106
|
+
'param_name': param_name, # Named parameter for OpenFind
|
|
2635
3107
|
'args': args
|
|
2636
3108
|
})
|
|
2637
3109
|
|