IncludeCPP 3.7.25__py3-none-any.whl → 3.8.8__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.
@@ -114,7 +114,7 @@ class TokenType(Enum):
114
114
 
115
115
  KEYWORDS = {
116
116
  # Service structure
117
- 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'new', 'this',
117
+ 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'constr', 'extends', 'overwrites', 'new', 'this', 'super',
118
118
  # Control flow
119
119
  'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
120
120
  'switch', 'case', 'default', 'break', 'continue', 'return',
@@ -716,7 +716,7 @@ class CSSLParser:
716
716
  def _is_type_keyword(self, value: str) -> bool:
717
717
  """Check if a keyword is a type declaration"""
718
718
  return value in ('int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
719
- 'list', 'dictionary', 'dict', 'instance', 'map',
719
+ 'list', 'dictionary', 'dict', 'instance', 'map', 'openquote', 'parameter',
720
720
  'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure')
721
721
 
722
722
  def _looks_like_function_declaration(self) -> bool:
@@ -727,14 +727,17 @@ class CSSLParser:
727
727
  - undefined int funcName(...)
728
728
  - vector<string> funcName(...)
729
729
  - undefined void funcName(...)
730
+ - private super virtual meta FuncName(...) <- modifiers without return type
730
731
  """
731
732
  saved_pos = self.pos
733
+ has_modifiers = False
732
734
 
733
735
  # Skip modifiers (undefined, open, meta, super, closed, private, virtual)
734
736
  while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
735
737
  self._advance()
738
+ has_modifiers = True
736
739
 
737
- # Check for type keyword
740
+ # Check for type keyword (optional if modifiers present)
738
741
  if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
739
742
  self._advance()
740
743
 
@@ -756,6 +759,14 @@ class CSSLParser:
756
759
  self.pos = saved_pos
757
760
  return is_func
758
761
 
762
+ # If we have modifiers and the next token is an identifier followed by (
763
+ # This handles: private super virtual meta FuncName()
764
+ elif has_modifiers and self._check(TokenType.IDENTIFIER):
765
+ self._advance()
766
+ is_func = self._check(TokenType.PAREN_START)
767
+ self.pos = saved_pos
768
+ return is_func
769
+
759
770
  self.pos = saved_pos
760
771
  return False
761
772
 
@@ -1014,7 +1025,11 @@ class CSSLParser:
1014
1025
  return result
1015
1026
 
1016
1027
  def _parse_typed_variable(self) -> Optional[ASTNode]:
1017
- """Parse a typed variable declaration: type varName; or type<T> varName = value;"""
1028
+ """Parse a typed variable declaration: type varName; or type<T> *varName = value;
1029
+
1030
+ The * prefix indicates a non-nullable variable (can never be None/null).
1031
+ Example: vector<dynamic> *MyVector - can never contain None values.
1032
+ """
1018
1033
  # Get type name
1019
1034
  type_name = self._advance().value # Consume type keyword
1020
1035
 
@@ -1028,6 +1043,11 @@ class CSSLParser:
1028
1043
  element_type = self._advance().value
1029
1044
  self._expect(TokenType.COMPARE_GT)
1030
1045
 
1046
+ # Check for * prefix (non-nullable indicator)
1047
+ non_null = False
1048
+ if self._match(TokenType.MULTIPLY):
1049
+ non_null = True
1050
+
1031
1051
  # Get variable name
1032
1052
  if not self._check(TokenType.IDENTIFIER):
1033
1053
  return None
@@ -1045,14 +1065,16 @@ class CSSLParser:
1045
1065
  return ASTNode('instance_declaration', value={
1046
1066
  'instance_name': element_type,
1047
1067
  'name': var_name,
1048
- 'value': value
1068
+ 'value': value,
1069
+ 'non_null': non_null
1049
1070
  })
1050
1071
 
1051
1072
  return ASTNode('typed_declaration', value={
1052
1073
  'type': type_name,
1053
1074
  'element_type': element_type,
1054
1075
  'name': var_name,
1055
- 'value': value
1076
+ 'value': value,
1077
+ 'non_null': non_null
1056
1078
  })
1057
1079
 
1058
1080
  def parse_program(self) -> ASTNode:
@@ -1350,10 +1372,79 @@ class CSSLParser:
1350
1372
  printl("Hello " + this->name);
1351
1373
  }
1352
1374
  }
1375
+
1376
+ Non-null class (all methods return non-null):
1377
+ class *MyClass { ... }
1353
1378
  """
1379
+ # Check for * prefix (non-null class - all methods return non-null)
1380
+ non_null = False
1381
+ if self._match(TokenType.MULTIPLY):
1382
+ non_null = True
1383
+
1354
1384
  class_name = self._advance().value
1355
1385
 
1356
- node = ASTNode('class', value={'name': class_name}, children=[])
1386
+ # Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
1387
+ class_params = []
1388
+ if self._match(TokenType.PAREN_START):
1389
+ class_params = self._parse_parameter_list()
1390
+ self._expect(TokenType.PAREN_END)
1391
+
1392
+ # Check for inheritance and overwrites:
1393
+ # class Child : extends Parent { ... }
1394
+ # class Child : extends $PythonObject { ... }
1395
+ # class Child : extends Parent : overwrites Parent { ... }
1396
+ # class Child : extends Parent (param1, param2) { ... } <- constructor args for parent
1397
+ extends_class = None
1398
+ extends_is_python = False
1399
+ extends_args = []
1400
+ overwrites_class = None
1401
+ overwrites_is_python = False
1402
+
1403
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1404
+ # Parse extends and/or overwrites (can be chained with : or ::)
1405
+ while True:
1406
+ if self._match_keyword('extends'):
1407
+ if self._check(TokenType.IDENTIFIER):
1408
+ extends_class = self._advance().value
1409
+ elif self._check(TokenType.SHARED_REF):
1410
+ extends_class = self._advance().value
1411
+ extends_is_python = True
1412
+ else:
1413
+ raise CSSLSyntaxError("Expected parent class name after 'extends'")
1414
+ # Check for constructor arguments: extends Parent (arg1, arg2)
1415
+ if self._match(TokenType.PAREN_START):
1416
+ while not self._check(TokenType.PAREN_END):
1417
+ arg = self._parse_expression()
1418
+ extends_args.append(arg)
1419
+ self._match(TokenType.COMMA)
1420
+ self._expect(TokenType.PAREN_END)
1421
+ elif self._match_keyword('overwrites'):
1422
+ if self._check(TokenType.IDENTIFIER):
1423
+ overwrites_class = self._advance().value
1424
+ elif self._check(TokenType.SHARED_REF):
1425
+ overwrites_class = self._advance().value
1426
+ overwrites_is_python = True
1427
+ else:
1428
+ raise CSSLSyntaxError("Expected class name after 'overwrites'")
1429
+ # Skip optional () after class name
1430
+ if self._match(TokenType.PAREN_START):
1431
+ self._expect(TokenType.PAREN_END)
1432
+ else:
1433
+ raise CSSLSyntaxError("Expected 'extends' or 'overwrites' after ':' or '::' in class declaration")
1434
+ # Check for another : or :: for chaining
1435
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1436
+ break
1437
+
1438
+ node = ASTNode('class', value={
1439
+ 'name': class_name,
1440
+ 'non_null': non_null,
1441
+ 'class_params': class_params,
1442
+ 'extends': extends_class,
1443
+ 'extends_is_python': extends_is_python,
1444
+ 'extends_args': extends_args,
1445
+ 'overwrites': overwrites_class,
1446
+ 'overwrites_is_python': overwrites_is_python
1447
+ }, children=[])
1357
1448
  self._expect(TokenType.BLOCK_START)
1358
1449
 
1359
1450
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
@@ -1382,14 +1473,265 @@ class CSSLParser:
1382
1473
  method = self._parse_define()
1383
1474
  node.children.append(method)
1384
1475
 
1476
+ # Check for constr keyword (constructor declaration)
1477
+ # Syntax: constr ConstructorName() { ... }
1478
+ # or: constr ConstructorName() : extends Parent::ConstructorName { ... }
1479
+ elif self._match_keyword('constr'):
1480
+ constructor = self._parse_constructor(class_name)
1481
+ node.children.append(constructor)
1482
+
1385
1483
  else:
1386
1484
  self._advance()
1387
1485
 
1388
1486
  self._expect(TokenType.BLOCK_END)
1389
1487
  return node
1390
1488
 
1489
+ def _parse_constructor(self, class_name: str) -> ASTNode:
1490
+ """Parse constructor declaration inside a class.
1491
+
1492
+ Syntax:
1493
+ constr ConstructorName() { ... }
1494
+ constr ConstructorName() : extends ParentClass::ConstructorName { ... }
1495
+ constr ConstructorName() : extends ParentClass::ConstructorName : overwrites ParentClass::ConstructorName { ... }
1496
+
1497
+ Multiple constructors are allowed and executed in order.
1498
+ Constructors can access parent constructor via super().
1499
+ """
1500
+ # Get constructor name
1501
+ if not self._check(TokenType.IDENTIFIER):
1502
+ raise CSSLSyntaxError("Expected constructor name after 'constr'")
1503
+ constr_name = self._advance().value
1504
+
1505
+ # Parse method-level extends/overwrites with :: syntax
1506
+ # constr Name() :: extends Parent::Name :: overwrites Parent::Name { ... }
1507
+ extends_target = None
1508
+ extends_class_ref = None
1509
+ extends_method_ref = None
1510
+ overwrites_target = None
1511
+ overwrites_class_ref = None
1512
+ overwrites_method_ref = None
1513
+
1514
+ # Parse parameters
1515
+ params = []
1516
+ if self._match(TokenType.PAREN_START):
1517
+ params = self._parse_parameter_list()
1518
+ self._expect(TokenType.PAREN_END)
1519
+
1520
+ # Check for method-level extends/overwrites with :: or :
1521
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1522
+ while True:
1523
+ if self._match_keyword('extends'):
1524
+ # Parse Parent::method or just method
1525
+ extends_target = self._parse_qualified_method_ref()
1526
+ if '::' in extends_target:
1527
+ parts = extends_target.split('::')
1528
+ extends_class_ref = parts[0]
1529
+ extends_method_ref = parts[1]
1530
+ else:
1531
+ extends_method_ref = extends_target
1532
+ elif self._match_keyword('overwrites'):
1533
+ # Parse Parent::method or just method
1534
+ overwrites_target = self._parse_qualified_method_ref()
1535
+ if '::' in overwrites_target:
1536
+ parts = overwrites_target.split('::')
1537
+ overwrites_class_ref = parts[0]
1538
+ overwrites_method_ref = parts[1]
1539
+ else:
1540
+ overwrites_method_ref = overwrites_target
1541
+ else:
1542
+ break
1543
+ # Check for another :: or : for chaining
1544
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1545
+ break
1546
+
1547
+ # Parse constructor body
1548
+ self._expect(TokenType.BLOCK_START)
1549
+ body = []
1550
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1551
+ stmt = self._parse_statement()
1552
+ if stmt:
1553
+ body.append(stmt)
1554
+ self._expect(TokenType.BLOCK_END)
1555
+
1556
+ return ASTNode('constructor', value={
1557
+ 'name': constr_name,
1558
+ 'class_name': class_name,
1559
+ 'params': params,
1560
+ 'is_constructor': True,
1561
+ 'extends_target': extends_target,
1562
+ 'extends_class': extends_class_ref,
1563
+ 'extends_method': extends_method_ref,
1564
+ 'overwrites_target': overwrites_target,
1565
+ 'overwrites_class': overwrites_class_ref,
1566
+ 'overwrites_method': overwrites_method_ref
1567
+ }, children=body)
1568
+
1569
+ def _parse_qualified_method_ref(self) -> str:
1570
+ """Parse a qualified method reference like 'ParentClass::methodName' or just 'methodName'.
1571
+
1572
+ Returns the qualified name as a string (e.g., 'Parent::init' or just 'init').
1573
+ """
1574
+ # Check for $PythonObject
1575
+ if self._check(TokenType.SHARED_REF):
1576
+ class_ref = self._advance().value # Gets the name without $
1577
+ class_ref = f'${class_ref}'
1578
+ elif self._check(TokenType.IDENTIFIER):
1579
+ class_ref = self._advance().value
1580
+ else:
1581
+ raise CSSLSyntaxError("Expected class or method name in extends/overwrites")
1582
+
1583
+ # Check for :: to get method part
1584
+ if self._match(TokenType.DOUBLE_COLON):
1585
+ if self._check(TokenType.IDENTIFIER):
1586
+ method_ref = self._advance().value
1587
+ return f'{class_ref}::{method_ref}'
1588
+ else:
1589
+ raise CSSLSyntaxError("Expected method name after '::'")
1590
+
1591
+ # Just method name, no class qualifier
1592
+ return class_ref
1593
+
1594
+ def _parse_parameter_list(self) -> list:
1595
+ """Parse a list of parameters (without the surrounding parentheses).
1596
+
1597
+ Returns a list of parameter definitions, each can be:
1598
+ - Simple string name: "paramName"
1599
+ - Dict with type info: {'name': 'paramName', 'type': 'string', 'ref': True, ...}
1600
+ """
1601
+ params = []
1602
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
1603
+ param_info = {}
1604
+
1605
+ # Handle 'open' keyword for open parameters
1606
+ if self._match_keyword('open'):
1607
+ param_info['open'] = True
1608
+
1609
+ # Handle type annotations (e.g., string, int, dynamic, etc.)
1610
+ if self._check(TokenType.KEYWORD):
1611
+ param_info['type'] = self._advance().value
1612
+
1613
+ # Handle reference operator &
1614
+ if self._match(TokenType.AMPERSAND):
1615
+ param_info['ref'] = True
1616
+
1617
+ # Handle * prefix for non-null parameters
1618
+ if self._match(TokenType.MULTIPLY):
1619
+ param_info['non_null'] = True
1620
+
1621
+ # Get parameter name
1622
+ if self._check(TokenType.IDENTIFIER):
1623
+ param_name = self._advance().value
1624
+ if param_info:
1625
+ params.append({'name': param_name, **param_info})
1626
+ else:
1627
+ params.append(param_name)
1628
+ self._match(TokenType.COMMA)
1629
+ elif self._check(TokenType.KEYWORD):
1630
+ # Parameter name could be a keyword like 'Params'
1631
+ param_name = self._advance().value
1632
+ if param_info:
1633
+ params.append({'name': param_name, **param_info})
1634
+ else:
1635
+ params.append(param_name)
1636
+ self._match(TokenType.COMMA)
1637
+ else:
1638
+ break
1639
+
1640
+ return params
1641
+
1391
1642
  def _parse_define(self) -> ASTNode:
1643
+ """Parse define function declaration.
1644
+
1645
+ Syntax:
1646
+ define MyFunc(args) { }
1647
+ define *MyFunc(args) { } // Non-null: must never return None
1648
+ define MyFunc : extends OtherFunc() { } // Inherit local vars
1649
+ define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
1650
+ define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
1651
+ """
1652
+ # Check for * prefix (non-null function - must return non-null)
1653
+ non_null = False
1654
+ if self._match(TokenType.MULTIPLY):
1655
+ non_null = True
1656
+
1392
1657
  name = self._advance().value
1658
+
1659
+ # Check for extends/overwrites: define func : extends/overwrites target() { }
1660
+ # Also supports method-level :: syntax: define func :: extends Parent::method
1661
+ extends_func = None
1662
+ overwrites_func = None
1663
+ extends_is_python = False
1664
+ overwrites_is_python = False
1665
+ extends_class_ref = None
1666
+ extends_method_ref = None
1667
+ overwrites_class_ref = None
1668
+ overwrites_method_ref = None
1669
+
1670
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1671
+ # Parse extends and/or overwrites (supports :: method-level syntax)
1672
+ while True:
1673
+ if self._match_keyword('extends'):
1674
+ # Check for qualified reference: Parent::method
1675
+ if self._check(TokenType.SHARED_REF):
1676
+ extends_is_python = True
1677
+ extends_func = self._advance().value
1678
+ # Check for ::method
1679
+ if self._match(TokenType.DOUBLE_COLON):
1680
+ extends_class_ref = f'${extends_func}'
1681
+ if self._check(TokenType.IDENTIFIER):
1682
+ extends_method_ref = self._advance().value
1683
+ else:
1684
+ raise CSSLSyntaxError("Expected method name after '::'")
1685
+ elif self._check(TokenType.IDENTIFIER):
1686
+ first_part = self._advance().value
1687
+ # Check for ::method (qualified reference)
1688
+ if self._match(TokenType.DOUBLE_COLON):
1689
+ extends_class_ref = first_part
1690
+ if self._check(TokenType.IDENTIFIER):
1691
+ extends_method_ref = self._advance().value
1692
+ else:
1693
+ raise CSSLSyntaxError("Expected method name after '::'")
1694
+ else:
1695
+ extends_func = first_part
1696
+ else:
1697
+ raise CSSLSyntaxError("Expected function name after 'extends'")
1698
+ # Skip optional () after function/method name
1699
+ if self._match(TokenType.PAREN_START):
1700
+ self._expect(TokenType.PAREN_END)
1701
+ elif self._match_keyword('overwrites'):
1702
+ # Check for qualified reference: Parent::method
1703
+ if self._check(TokenType.SHARED_REF):
1704
+ overwrites_is_python = True
1705
+ overwrites_func = self._advance().value
1706
+ # Check for ::method
1707
+ if self._match(TokenType.DOUBLE_COLON):
1708
+ overwrites_class_ref = f'${overwrites_func}'
1709
+ if self._check(TokenType.IDENTIFIER):
1710
+ overwrites_method_ref = self._advance().value
1711
+ else:
1712
+ raise CSSLSyntaxError("Expected method name after '::'")
1713
+ elif self._check(TokenType.IDENTIFIER):
1714
+ first_part = self._advance().value
1715
+ # Check for ::method (qualified reference)
1716
+ if self._match(TokenType.DOUBLE_COLON):
1717
+ overwrites_class_ref = first_part
1718
+ if self._check(TokenType.IDENTIFIER):
1719
+ overwrites_method_ref = self._advance().value
1720
+ else:
1721
+ raise CSSLSyntaxError("Expected method name after '::'")
1722
+ else:
1723
+ overwrites_func = first_part
1724
+ else:
1725
+ raise CSSLSyntaxError("Expected function name after 'overwrites'")
1726
+ # Skip optional () after function/method name
1727
+ if self._match(TokenType.PAREN_START):
1728
+ self._expect(TokenType.PAREN_END)
1729
+ else:
1730
+ break
1731
+ # Check for another :: or : for chaining extends/overwrites
1732
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1733
+ break
1734
+
1393
1735
  params = []
1394
1736
 
1395
1737
  if self._match(TokenType.PAREN_START):
@@ -1404,6 +1746,9 @@ class CSSLParser:
1404
1746
  # Handle reference operator &
1405
1747
  if self._match(TokenType.AMPERSAND):
1406
1748
  param_info['ref'] = True
1749
+ # Handle * prefix for non-null parameters
1750
+ if self._match(TokenType.MULTIPLY):
1751
+ param_info['non_null'] = True
1407
1752
  # Get parameter name
1408
1753
  if self._check(TokenType.IDENTIFIER):
1409
1754
  param_name = self._advance().value
@@ -1424,7 +1769,20 @@ class CSSLParser:
1424
1769
  break
1425
1770
  self._expect(TokenType.PAREN_END)
1426
1771
 
1427
- node = ASTNode('function', value={'name': name, 'params': params}, children=[])
1772
+ node = ASTNode('function', value={
1773
+ 'name': name,
1774
+ 'params': params,
1775
+ 'non_null': non_null,
1776
+ 'extends': extends_func,
1777
+ 'extends_is_python': extends_is_python,
1778
+ 'overwrites': overwrites_func,
1779
+ 'overwrites_is_python': overwrites_is_python,
1780
+ # Method-level inheritance (Parent::method syntax)
1781
+ 'extends_class': extends_class_ref,
1782
+ 'extends_method': extends_method_ref,
1783
+ 'overwrites_class': overwrites_class_ref,
1784
+ 'overwrites_method': overwrites_method_ref
1785
+ }, children=[])
1428
1786
  self._expect(TokenType.BLOCK_START)
1429
1787
 
1430
1788
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
@@ -1470,6 +1828,11 @@ class CSSLParser:
1470
1828
  elif self._check(TokenType.SUPER_FUNC):
1471
1829
  # Super-function for .cssl-pl payload files
1472
1830
  return self._parse_super_function()
1831
+ elif (self._check(TokenType.KEYWORD) and self._current().value == 'super' and
1832
+ (self._peek(1).type == TokenType.PAREN_START or
1833
+ self._peek(1).type == TokenType.DOUBLE_COLON)):
1834
+ # super() or super::method() call - calls parent constructor/method
1835
+ return self._parse_super_call()
1473
1836
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1474
1837
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
1475
1838
  self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
@@ -1480,6 +1843,43 @@ class CSSLParser:
1480
1843
  self._advance()
1481
1844
  return None
1482
1845
 
1846
+ def _parse_super_call(self) -> ASTNode:
1847
+ """Parse super() call to invoke parent constructor or method.
1848
+
1849
+ Syntax:
1850
+ super() - Call parent constructor with no args
1851
+ super(arg1, arg2) - Call parent constructor with args
1852
+ super::method() - Call specific parent method
1853
+ super::method(args) - Call specific parent method with args
1854
+
1855
+ Used inside constructors (constr) and methods to call parent implementations.
1856
+ """
1857
+ # Consume 'super' keyword
1858
+ self._advance()
1859
+
1860
+ # Check for ::method syntax
1861
+ target_method = None
1862
+ if self._match(TokenType.DOUBLE_COLON):
1863
+ if not self._check(TokenType.IDENTIFIER):
1864
+ raise CSSLSyntaxError("Expected method name after 'super::'")
1865
+ target_method = self._advance().value
1866
+
1867
+ # Parse arguments
1868
+ args = []
1869
+ self._expect(TokenType.PAREN_START)
1870
+ while not self._check(TokenType.PAREN_END):
1871
+ arg = self._parse_expression()
1872
+ args.append(arg)
1873
+ if not self._match(TokenType.COMMA):
1874
+ break
1875
+ self._expect(TokenType.PAREN_END)
1876
+ self._match(TokenType.SEMICOLON)
1877
+
1878
+ return ASTNode('super_call', value={
1879
+ 'method': target_method, # None for constructor, method name for specific method
1880
+ 'args': args
1881
+ })
1882
+
1483
1883
  def _parse_if(self) -> ASTNode:
1484
1884
  """Parse if statement with support for else if AND elif syntax."""
1485
1885
  self._expect(TokenType.PAREN_START)
@@ -2599,12 +2999,24 @@ class CSSLParser:
2599
2999
  'init_values': init_values
2600
3000
  })
2601
3001
 
2602
- # Check for type-parameterized function call: OpenFind<string>(0)
3002
+ # Check for type-parameterized function call: OpenFind<string>(0) or OpenFind<dynamic, "name">
2603
3003
  if name in TYPE_PARAM_FUNCTIONS and self._check(TokenType.COMPARE_LT):
2604
3004
  self._advance() # consume <
2605
3005
  type_param = 'dynamic'
3006
+ param_name = None # Optional: named parameter search
3007
+
2606
3008
  if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2607
3009
  type_param = self._advance().value
3010
+
3011
+ # Check for second parameter: OpenFind<type, "name">
3012
+ if self._check(TokenType.COMMA):
3013
+ self._advance() # consume comma
3014
+ # Expect a string literal for the parameter name
3015
+ if self._check(TokenType.STRING):
3016
+ param_name = self._advance().value
3017
+ elif self._check(TokenType.IDENTIFIER):
3018
+ param_name = self._advance().value
3019
+
2608
3020
  self._expect(TokenType.COMPARE_GT) # consume >
2609
3021
 
2610
3022
  # Must be followed by ()
@@ -2621,6 +3033,7 @@ class CSSLParser:
2621
3033
  return ASTNode('typed_call', value={
2622
3034
  'name': name,
2623
3035
  'type_param': type_param,
3036
+ 'param_name': param_name, # Named parameter for OpenFind
2624
3037
  'args': args
2625
3038
  })
2626
3039