IncludeCPP 3.6.0__py3-none-any.whl → 3.7.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.
@@ -101,17 +101,20 @@ class TokenType(Enum):
101
101
  SELF_REF = auto() # s@<name> self-reference to global struct
102
102
  SHARED_REF = auto() # $<name> shared object reference
103
103
  CAPTURED_REF = auto() # %<name> captured reference (for infusion)
104
+ THIS_REF = auto() # this-><name> class member reference
104
105
  PACKAGE = auto()
105
106
  PACKAGE_INCLUDES = auto()
106
107
  AS = auto()
107
108
  COMMENT = auto()
108
109
  NEWLINE = auto()
109
110
  EOF = auto()
111
+ # Super-functions for .cssl-pl payload files (v3.8.0)
112
+ SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
110
113
 
111
114
 
112
115
  KEYWORDS = {
113
116
  # Service structure
114
- 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main',
117
+ 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'new', 'this',
115
118
  # Control flow
116
119
  'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
117
120
  'switch', 'case', 'default', 'break', 'continue', 'return',
@@ -126,7 +129,7 @@ KEYWORDS = {
126
129
  'package', 'package-includes', 'exec', 'as', 'global',
127
130
  # CSSL Type Keywords
128
131
  'int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
129
- 'list', 'dictionary', 'dict', # Python-like types
132
+ 'list', 'dictionary', 'dict', 'instance', 'map', # Python-like types
130
133
  'dynamic', # No type declaration (slow but flexible)
131
134
  'undefined', # Function errors ignored
132
135
  'open', # Accept any parameter type
@@ -154,7 +157,7 @@ TYPE_LITERALS = {'list', 'dict'}
154
157
  # Generic type keywords that use <T> syntax
155
158
  TYPE_GENERICS = {
156
159
  'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo',
157
- 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary'
160
+ 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary', 'map'
158
161
  }
159
162
 
160
163
  # Functions that accept type parameters: FuncName<type>(args)
@@ -211,9 +214,14 @@ class CSSLLexer:
211
214
 
212
215
  char = self.source[self.pos]
213
216
 
214
- # Comments: both # and // style
217
+ # Super-functions (#$) or Comments (# and // style)
215
218
  if char == '#':
216
- self._skip_comment()
219
+ if self._peek(1) == '$':
220
+ # Super-function: #$run(), #$exec(), #$printl()
221
+ self._read_super_function()
222
+ else:
223
+ # Regular comment
224
+ self._skip_comment()
217
225
  elif char == '/' and self._peek(1) == '/':
218
226
  # C-style // comment - NEW
219
227
  self._skip_comment()
@@ -445,6 +453,31 @@ class CSSLLexer:
445
453
  else:
446
454
  self._add_token(TokenType.IDENTIFIER, value)
447
455
 
456
+ def _read_super_function(self):
457
+ """Read #$<name>(...) super-function call for .cssl-pl payloads.
458
+
459
+ Super-functions are pre-execution hooks that run when a payload is loaded.
460
+ Valid super-functions: #$run(), #$exec(), #$printl()
461
+
462
+ Syntax:
463
+ #$run(initFunction); // Call a function at load time
464
+ #$exec(setup()); // Execute expression at load time
465
+ #$printl("Payload loaded"); // Print at load time
466
+ """
467
+ start = self.pos
468
+ self._advance() # skip '#'
469
+ self._advance() # skip '$'
470
+
471
+ # Read the super-function name (run, exec, printl, etc.)
472
+ name_start = self.pos
473
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
474
+ self._advance()
475
+ func_name = self.source[name_start:self.pos]
476
+
477
+ # Store as #$<name> token value
478
+ value = f'#${func_name}'
479
+ self._add_token(TokenType.SUPER_FUNC, value)
480
+
448
481
  def _read_self_ref(self):
449
482
  """Read s@<name> or s@<name>.<member>... self-reference"""
450
483
  start = self.pos
@@ -679,7 +712,7 @@ class CSSLParser:
679
712
  def _is_type_keyword(self, value: str) -> bool:
680
713
  """Check if a keyword is a type declaration"""
681
714
  return value in ('int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
682
- 'list', 'dictionary', 'dict',
715
+ 'list', 'dictionary', 'dict', 'instance', 'map',
683
716
  'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure')
684
717
 
685
718
  def _looks_like_function_declaration(self) -> bool:
@@ -898,7 +931,7 @@ class CSSLParser:
898
931
  type_keywords = {'int', 'string', 'float', 'bool', 'dynamic', 'void',
899
932
  'stack', 'vector', 'datastruct', 'dataspace', 'shuffled',
900
933
  'iterator', 'combo', 'array', 'openquote', 'json',
901
- 'list', 'dictionary', 'dict'}
934
+ 'list', 'dictionary', 'dict', 'instance', 'map'}
902
935
  if type_name not in type_keywords:
903
936
  return False
904
937
 
@@ -927,11 +960,13 @@ class CSSLParser:
927
960
  # Get type name
928
961
  type_name = self._advance().value # Consume type keyword
929
962
 
930
- # Check for generic type <T>
963
+ # Check for generic type <T> or instance<"name">
931
964
  element_type = None
932
965
  if self._match(TokenType.COMPARE_LT):
933
- # Get element type
934
- if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
966
+ # For instance<"name">, element_type can be a string literal
967
+ if type_name == 'instance' and self._check(TokenType.STRING):
968
+ element_type = self._advance().value
969
+ elif self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
935
970
  element_type = self._advance().value
936
971
  self._expect(TokenType.COMPARE_GT)
937
972
 
@@ -947,6 +982,14 @@ class CSSLParser:
947
982
 
948
983
  self._match(TokenType.SEMICOLON)
949
984
 
985
+ # For instance<"name">, create a special node type
986
+ if type_name == 'instance':
987
+ return ASTNode('instance_declaration', value={
988
+ 'instance_name': element_type,
989
+ 'name': var_name,
990
+ 'value': value
991
+ })
992
+
950
993
  return ASTNode('typed_declaration', value={
951
994
  'type': type_name,
952
995
  'element_type': element_type,
@@ -961,6 +1004,8 @@ class CSSLParser:
961
1004
  while not self._is_at_end():
962
1005
  if self._match_keyword('struct'):
963
1006
  root.children.append(self._parse_struct())
1007
+ elif self._match_keyword('class'):
1008
+ root.children.append(self._parse_class())
964
1009
  elif self._match_keyword('define'):
965
1010
  root.children.append(self._parse_define())
966
1011
  # Check for C-style typed function declarations
@@ -1233,6 +1278,58 @@ class CSSLParser:
1233
1278
  self._expect(TokenType.BLOCK_END)
1234
1279
  return node
1235
1280
 
1281
+ def _parse_class(self) -> ASTNode:
1282
+ """Parse class declaration with members and methods.
1283
+
1284
+ Syntax:
1285
+ class ClassName {
1286
+ string name;
1287
+ int age;
1288
+
1289
+ void ClassName(string n) { this->name = n; }
1290
+
1291
+ void sayHello() {
1292
+ printl("Hello " + this->name);
1293
+ }
1294
+ }
1295
+ """
1296
+ class_name = self._advance().value
1297
+
1298
+ node = ASTNode('class', value={'name': class_name}, children=[])
1299
+ self._expect(TokenType.BLOCK_START)
1300
+
1301
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1302
+ # Check for typed function (method) declaration
1303
+ if self._looks_like_function_declaration():
1304
+ method = self._parse_typed_function()
1305
+ method_info = method.value
1306
+ method_name = method_info.get('name')
1307
+
1308
+ # Mark constructor (same name as class or __init__)
1309
+ if method_name == class_name or method_name == '__init__':
1310
+ method.value['is_constructor'] = True
1311
+
1312
+ node.children.append(method)
1313
+
1314
+ # Check for typed member variable declaration
1315
+ elif self._looks_like_typed_variable():
1316
+ member = self._parse_typed_variable()
1317
+ if member:
1318
+ # Mark as class member
1319
+ member.value['is_member'] = True
1320
+ node.children.append(member)
1321
+
1322
+ # Check for define-style method
1323
+ elif self._match_keyword('define'):
1324
+ method = self._parse_define()
1325
+ node.children.append(method)
1326
+
1327
+ else:
1328
+ self._advance()
1329
+
1330
+ self._expect(TokenType.BLOCK_END)
1331
+ return node
1332
+
1236
1333
  def _parse_define(self) -> ASTNode:
1237
1334
  name = self._advance().value
1238
1335
  params = []
@@ -1312,9 +1409,13 @@ class CSSLParser:
1312
1409
  elif self._looks_like_function_declaration():
1313
1410
  # Nested typed function (e.g., void Level2() { ... })
1314
1411
  return self._parse_typed_function()
1412
+ elif self._check(TokenType.SUPER_FUNC):
1413
+ # Super-function for .cssl-pl payload files
1414
+ return self._parse_super_function()
1315
1415
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1316
1416
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
1317
- self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF)):
1417
+ self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
1418
+ (self._check(TokenType.KEYWORD) and self._current().value in ('this', 'new'))):
1318
1419
  return self._parse_expression_statement()
1319
1420
  else:
1320
1421
  self._advance()
@@ -1528,23 +1629,42 @@ class CSSLParser:
1528
1629
  return ASTNode('c_for_update', value={'var': var_name, 'op': 'none'})
1529
1630
 
1530
1631
  def _parse_python_style_for(self) -> ASTNode:
1531
- """Parse Python-style for loop: for (i in range(...)) { }
1632
+ """Parse Python-style for loop: for (i in range(...)) { } or for (item in collection) { }
1532
1633
 
1533
1634
  Supports:
1534
1635
  for (i in range(n)) { } - 0 to n-1
1535
1636
  for (i in range(start, end)) { } - start to end-1
1536
1637
  for (i in range(start, end, step)) { }
1638
+ for (item in collection) { } - iterate over list/vector
1639
+ for (item in @global_collection) { } - iterate over global
1537
1640
  """
1538
1641
  var_name = self._advance().value
1539
1642
  self._expect(TokenType.KEYWORD) # 'in'
1540
1643
 
1541
- # 'range' can be keyword or identifier
1644
+ # Check if this is range() or collection iteration
1645
+ is_range = False
1542
1646
  if self._check(TokenType.KEYWORD) and self._peek().value == 'range':
1543
1647
  self._advance() # consume 'range' keyword
1648
+ is_range = True
1544
1649
  elif self._check(TokenType.IDENTIFIER) and self._peek().value == 'range':
1545
1650
  self._advance() # consume 'range' identifier
1546
- else:
1547
- self.error(f"Expected 'range', got {self._peek().value}")
1651
+ is_range = True
1652
+
1653
+ # If not range, parse as collection iteration
1654
+ if not is_range:
1655
+ iterable = self._parse_expression()
1656
+ self._expect(TokenType.PAREN_END)
1657
+
1658
+ node = ASTNode('foreach', value={'var': var_name, 'iterable': iterable}, children=[])
1659
+ self._expect(TokenType.BLOCK_START)
1660
+
1661
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1662
+ stmt = self._parse_statement()
1663
+ if stmt:
1664
+ node.children.append(stmt)
1665
+
1666
+ self._expect(TokenType.BLOCK_END)
1667
+ return node
1548
1668
 
1549
1669
  self._expect(TokenType.PAREN_START)
1550
1670
  first_arg = self._parse_expression()
@@ -1656,11 +1776,56 @@ class CSSLParser:
1656
1776
  return node
1657
1777
 
1658
1778
  def _parse_return(self) -> ASTNode:
1659
- value = None
1779
+ """Parse return statement, supporting multiple values for shuffled functions.
1780
+
1781
+ Syntax:
1782
+ return; // Return None
1783
+ return value; // Return single value
1784
+ return a, b, c; // Return multiple values (for shuffled)
1785
+ """
1786
+ values = []
1660
1787
  if not self._check(TokenType.SEMICOLON) and not self._check(TokenType.BLOCK_END):
1661
- value = self._parse_expression()
1788
+ values.append(self._parse_expression())
1789
+
1790
+ # Check for comma-separated return values (shuffled return)
1791
+ while self._check(TokenType.COMMA):
1792
+ self._advance() # consume comma
1793
+ values.append(self._parse_expression())
1794
+
1662
1795
  self._match(TokenType.SEMICOLON)
1663
- return ASTNode('return', value=value)
1796
+
1797
+ if len(values) == 0:
1798
+ return ASTNode('return', value=None)
1799
+ elif len(values) == 1:
1800
+ return ASTNode('return', value=values[0])
1801
+ else:
1802
+ # Multiple return values - create tuple return
1803
+ return ASTNode('return', value={'multiple': True, 'values': values})
1804
+
1805
+ def _parse_super_function(self) -> ASTNode:
1806
+ """Parse super-function for .cssl-pl payload files.
1807
+
1808
+ Syntax:
1809
+ #$run(initFunction); // Call function at load time
1810
+ #$exec(setup()); // Execute expression at load time
1811
+ #$printl("Payload loaded"); // Print at load time
1812
+
1813
+ These are pre-execution hooks that run when payload() loads the file.
1814
+ """
1815
+ token = self._advance() # Get the SUPER_FUNC token
1816
+ super_name = token.value # e.g., "#$run", "#$exec", "#$printl"
1817
+
1818
+ # Parse the arguments
1819
+ self._expect(TokenType.PAREN_START)
1820
+ args = []
1821
+ if not self._check(TokenType.PAREN_END):
1822
+ args.append(self._parse_expression())
1823
+ while self._match(TokenType.COMMA):
1824
+ args.append(self._parse_expression())
1825
+ self._expect(TokenType.PAREN_END)
1826
+ self._match(TokenType.SEMICOLON)
1827
+
1828
+ return ASTNode('super_func', value={'name': super_name, 'args': args})
1664
1829
 
1665
1830
  def _parse_try(self) -> ASTNode:
1666
1831
  node = ASTNode('try', children=[])
@@ -1747,6 +1912,25 @@ class CSSLParser:
1747
1912
  def _parse_expression_statement(self) -> Optional[ASTNode]:
1748
1913
  expr = self._parse_expression()
1749
1914
 
1915
+ # === TUPLE UNPACKING: a, b, c = shuffled_func() ===
1916
+ # Check if we have comma-separated identifiers before =
1917
+ if expr.type == 'identifier' and self._check(TokenType.COMMA):
1918
+ targets = [expr]
1919
+ while self._match(TokenType.COMMA):
1920
+ next_expr = self._parse_expression()
1921
+ if next_expr.type == 'identifier':
1922
+ targets.append(next_expr)
1923
+ else:
1924
+ # Not a simple identifier list, this is something else
1925
+ # Restore and fall through to normal parsing
1926
+ break
1927
+
1928
+ # Check if followed by =
1929
+ if self._match(TokenType.EQUALS):
1930
+ value = self._parse_expression()
1931
+ self._match(TokenType.SEMICOLON)
1932
+ return ASTNode('tuple_assignment', value={'targets': targets, 'value': value})
1933
+
1750
1934
  # === BASIC INJECTION: <== (replace target with source) ===
1751
1935
  if self._match(TokenType.INJECT_LEFT):
1752
1936
  # Check if this is a createcmd injection with a code block
@@ -1782,14 +1966,14 @@ class CSSLParser:
1782
1966
  if self._check(TokenType.BRACKET_START):
1783
1967
  # Peek ahead to see if this is an index [n] or a filter [type::helper=...]
1784
1968
  # Only consume if it's a simple number index
1785
- saved_pos = self._current
1969
+ saved_pos = self.pos
1786
1970
  self._advance() # consume [
1787
1971
  if self._check(TokenType.NUMBER):
1788
1972
  remove_index = int(self._advance().value)
1789
1973
  self._expect(TokenType.BRACKET_END)
1790
1974
  else:
1791
1975
  # Not a number - restore position for filter parsing
1792
- self._current = saved_pos
1976
+ self.pos = saved_pos
1793
1977
 
1794
1978
  filter_info = self._parse_injection_filter()
1795
1979
  source = self._parse_expression()
@@ -1824,14 +2008,14 @@ class CSSLParser:
1824
2008
  remove_index = None
1825
2009
  if self._check(TokenType.BRACKET_START):
1826
2010
  # Peek ahead to see if this is an index [n] or something else
1827
- saved_pos = self._current
2011
+ saved_pos = self.pos
1828
2012
  self._advance() # consume [
1829
2013
  if self._check(TokenType.NUMBER):
1830
2014
  remove_index = int(self._advance().value)
1831
2015
  self._expect(TokenType.BRACKET_END)
1832
2016
  else:
1833
2017
  # Not a number - restore position
1834
- self._current = saved_pos
2018
+ self.pos = saved_pos
1835
2019
 
1836
2020
  if self._check(TokenType.BLOCK_START):
1837
2021
  code_block = self._parse_action_block()
@@ -1987,19 +2171,75 @@ class CSSLParser:
1987
2171
  return self._parse_primary()
1988
2172
 
1989
2173
  def _parse_primary(self) -> ASTNode:
2174
+ # Handle 'this->' member access
2175
+ if self._check(TokenType.KEYWORD) and self._current().value == 'this':
2176
+ self._advance() # consume 'this'
2177
+ if self._match(TokenType.FLOW_RIGHT): # ->
2178
+ member = self._advance().value
2179
+ node = ASTNode('this_access', value={'member': member})
2180
+ # Continue to check for calls, member access, indexing
2181
+ while True:
2182
+ if self._match(TokenType.PAREN_START):
2183
+ # Method call: this->method()
2184
+ args, kwargs = self._parse_call_arguments()
2185
+ self._expect(TokenType.PAREN_END)
2186
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2187
+ elif self._match(TokenType.DOT):
2188
+ # Chained access: this->obj.method
2189
+ member = self._advance().value
2190
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2191
+ elif self._match(TokenType.BRACKET_START):
2192
+ # Index access: this->arr[0]
2193
+ index = self._parse_expression()
2194
+ self._expect(TokenType.BRACKET_END)
2195
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2196
+ elif self._match(TokenType.FLOW_RIGHT):
2197
+ # Chained this->a->b style access
2198
+ member = self._advance().value
2199
+ node = ASTNode('this_access', value={'member': member, 'object': node})
2200
+ else:
2201
+ break
2202
+ return node
2203
+ else:
2204
+ # Just 'this' keyword alone - return as identifier for now
2205
+ return ASTNode('identifier', value='this')
2206
+
2207
+ # Handle 'new ClassName(args)' instantiation
2208
+ if self._check(TokenType.KEYWORD) and self._current().value == 'new':
2209
+ self._advance() # consume 'new'
2210
+ class_name = self._advance().value # get class name
2211
+ args = []
2212
+ kwargs = {}
2213
+ if self._match(TokenType.PAREN_START):
2214
+ args, kwargs = self._parse_call_arguments()
2215
+ self._expect(TokenType.PAREN_END)
2216
+ node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs})
2217
+ # Continue to check for member access, calls on the new object
2218
+ while True:
2219
+ if self._match(TokenType.DOT):
2220
+ member = self._advance().value
2221
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2222
+ if self._match(TokenType.PAREN_START):
2223
+ args, kwargs = self._parse_call_arguments()
2224
+ self._expect(TokenType.PAREN_END)
2225
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2226
+ elif self._match(TokenType.BRACKET_START):
2227
+ index = self._parse_expression()
2228
+ self._expect(TokenType.BRACKET_END)
2229
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2230
+ else:
2231
+ break
2232
+ return node
2233
+
1990
2234
  if self._match(TokenType.AT):
1991
2235
  node = self._parse_module_reference()
1992
2236
  # Continue to check for calls, indexing, member access on module refs
1993
2237
  while True:
1994
2238
  if self._match(TokenType.PAREN_START):
1995
- # Function call on module ref: @Module.method()
1996
- args = []
1997
- while not self._check(TokenType.PAREN_END) and not self._is_at_end():
1998
- args.append(self._parse_expression())
1999
- if not self._check(TokenType.PAREN_END):
2000
- self._expect(TokenType.COMMA)
2239
+ # Function call on module ref: @Module.method() - with kwargs support
2240
+ args, kwargs = self._parse_call_arguments()
2001
2241
  self._expect(TokenType.PAREN_END)
2002
- node = ASTNode('call', value={'callee': node, 'args': args})
2242
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2003
2243
  elif self._match(TokenType.DOT):
2004
2244
  # Member access: @Module.property
2005
2245
  member = self._advance().value
@@ -2017,31 +2257,23 @@ class CSSLParser:
2017
2257
  # s@<name> self-reference to global struct
2018
2258
  token = self._advance()
2019
2259
  node = ASTNode('self_ref', value=token.value, line=token.line, column=token.column)
2020
- # Check for function call: s@Backend.Loop.Start()
2260
+ # Check for function call: s@Backend.Loop.Start() - with kwargs support
2021
2261
  if self._match(TokenType.PAREN_START):
2022
- args = []
2023
- while not self._check(TokenType.PAREN_END):
2024
- args.append(self._parse_expression())
2025
- if not self._check(TokenType.PAREN_END):
2026
- self._expect(TokenType.COMMA)
2262
+ args, kwargs = self._parse_call_arguments()
2027
2263
  self._expect(TokenType.PAREN_END)
2028
- node = ASTNode('call', value={'callee': node, 'args': args})
2264
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2029
2265
  return node
2030
2266
 
2031
2267
  if self._check(TokenType.GLOBAL_REF):
2032
2268
  # r@<name> global variable reference/declaration
2033
2269
  token = self._advance()
2034
2270
  node = ASTNode('global_ref', value=token.value, line=token.line, column=token.column)
2035
- # Check for member access, calls, indexing
2271
+ # Check for member access, calls, indexing - with kwargs support
2036
2272
  while True:
2037
2273
  if self._match(TokenType.PAREN_START):
2038
- args = []
2039
- while not self._check(TokenType.PAREN_END):
2040
- args.append(self._parse_expression())
2041
- if not self._check(TokenType.PAREN_END):
2042
- self._expect(TokenType.COMMA)
2274
+ args, kwargs = self._parse_call_arguments()
2043
2275
  self._expect(TokenType.PAREN_END)
2044
- node = ASTNode('call', value={'callee': node, 'args': args})
2276
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2045
2277
  elif self._match(TokenType.DOT):
2046
2278
  member = self._advance().value
2047
2279
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2057,16 +2289,12 @@ class CSSLParser:
2057
2289
  # $<name> shared object reference
2058
2290
  token = self._advance()
2059
2291
  node = ASTNode('shared_ref', value=token.value, line=token.line, column=token.column)
2060
- # Check for member access, calls, indexing
2292
+ # Check for member access, calls, indexing - with kwargs support
2061
2293
  while True:
2062
2294
  if self._match(TokenType.PAREN_START):
2063
- args = []
2064
- while not self._check(TokenType.PAREN_END):
2065
- args.append(self._parse_expression())
2066
- if not self._check(TokenType.PAREN_END):
2067
- self._expect(TokenType.COMMA)
2295
+ args, kwargs = self._parse_call_arguments()
2068
2296
  self._expect(TokenType.PAREN_END)
2069
- node = ASTNode('call', value={'callee': node, 'args': args})
2297
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2070
2298
  elif self._match(TokenType.DOT):
2071
2299
  member = self._advance().value
2072
2300
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2082,16 +2310,12 @@ class CSSLParser:
2082
2310
  # %<name> captured reference (captures value at infusion registration time)
2083
2311
  token = self._advance()
2084
2312
  node = ASTNode('captured_ref', value=token.value, line=token.line, column=token.column)
2085
- # Check for member access, calls, indexing
2313
+ # Check for member access, calls, indexing - with kwargs support
2086
2314
  while True:
2087
2315
  if self._match(TokenType.PAREN_START):
2088
- args = []
2089
- while not self._check(TokenType.PAREN_END):
2090
- args.append(self._parse_expression())
2091
- if not self._check(TokenType.PAREN_END):
2092
- self._expect(TokenType.COMMA)
2316
+ args, kwargs = self._parse_call_arguments()
2093
2317
  self._expect(TokenType.PAREN_END)
2094
- node = ASTNode('call', value={'callee': node, 'args': args})
2318
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2095
2319
  elif self._match(TokenType.DOT):
2096
2320
  member = self._advance().value
2097
2321
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2160,14 +2384,10 @@ class CSSLParser:
2160
2384
  member = self._advance().value
2161
2385
  node = ASTNode('member_access', value={'object': node, 'member': member})
2162
2386
  elif self._match(TokenType.PAREN_START):
2163
- # Function call
2164
- args = []
2165
- while not self._check(TokenType.PAREN_END):
2166
- args.append(self._parse_expression())
2167
- if not self._check(TokenType.PAREN_END):
2168
- self._expect(TokenType.COMMA)
2387
+ # Function call - use _parse_call_arguments for kwargs support
2388
+ args, kwargs = self._parse_call_arguments()
2169
2389
  self._expect(TokenType.PAREN_END)
2170
- node = ASTNode('call', value={'callee': node, 'args': args})
2390
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2171
2391
  elif self._match(TokenType.BRACKET_START):
2172
2392
  # Index access
2173
2393
  index = self._parse_expression()
@@ -2191,7 +2411,7 @@ class CSSLParser:
2191
2411
  while not self._check(TokenType.PAREN_END) and not self._is_at_end():
2192
2412
  # Check for named argument: identifier = expression
2193
2413
  if self._check(TokenType.IDENTIFIER):
2194
- saved_pos = self._current
2414
+ saved_pos = self.pos # Save token position
2195
2415
  name_token = self._advance()
2196
2416
 
2197
2417
  if self._check(TokenType.EQUALS):
@@ -2201,7 +2421,7 @@ class CSSLParser:
2201
2421
  kwargs[name_token.value] = value
2202
2422
  else:
2203
2423
  # Not named, restore and parse as expression
2204
- self._current = saved_pos
2424
+ self.pos = saved_pos # Restore token position
2205
2425
  args.append(self._parse_expression())
2206
2426
  else:
2207
2427
  args.append(self._parse_expression())
@@ -2220,17 +2440,75 @@ class CSSLParser:
2220
2440
  namespace_member = self._advance().value
2221
2441
  name = f"{name}::{namespace_member}"
2222
2442
 
2223
- # Check for type generic instantiation: stack<string>, vector<int>, etc.
2443
+ # Check for instance<"name"> syntax - gets/creates shared instance
2444
+ if name == 'instance' and self._check(TokenType.COMPARE_LT):
2445
+ self._advance() # consume <
2446
+ # Expect string literal for instance name
2447
+ if self._check(TokenType.STRING):
2448
+ instance_name = self._advance().value
2449
+ elif self._check(TokenType.IDENTIFIER):
2450
+ instance_name = self._advance().value
2451
+ else:
2452
+ raise CSSLParserError("Expected instance name (string or identifier)", self._current_line())
2453
+ self._expect(TokenType.COMPARE_GT) # consume >
2454
+ return ASTNode('instance_ref', value=instance_name)
2455
+
2456
+ # Check for type generic instantiation: stack<string>, vector<int>, map<string, int>, etc.
2224
2457
  # This creates a new instance of the type with the specified element type
2225
2458
  if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
2226
2459
  self._advance() # consume <
2227
2460
  element_type = 'dynamic'
2461
+ value_type = None # For map<K, V>
2462
+
2228
2463
  if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2229
2464
  element_type = self._advance().value
2465
+
2466
+ # Check for second type parameter (map<K, V>)
2467
+ if name == 'map' and self._check(TokenType.COMMA):
2468
+ self._advance() # consume ,
2469
+ if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2470
+ value_type = self._advance().value
2471
+ else:
2472
+ value_type = 'dynamic'
2473
+
2230
2474
  self._expect(TokenType.COMPARE_GT) # consume >
2475
+
2476
+ # Check for inline initialization: map<K,V>{"key": "value", ...}
2477
+ init_values = None
2478
+ if self._check(TokenType.BLOCK_START):
2479
+ self._advance() # consume {
2480
+ init_values = {}
2481
+
2482
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2483
+ # Parse key
2484
+ if self._check(TokenType.STRING):
2485
+ key = self._advance().value
2486
+ elif self._check(TokenType.IDENTIFIER):
2487
+ key = self._advance().value
2488
+ else:
2489
+ key = str(self._parse_expression().value) if hasattr(self._parse_expression(), 'value') else 'key'
2490
+
2491
+ # Expect : or =
2492
+ if self._check(TokenType.COLON):
2493
+ self._advance()
2494
+ elif self._check(TokenType.EQUALS):
2495
+ self._advance()
2496
+
2497
+ # Parse value
2498
+ value = self._parse_expression()
2499
+ init_values[key] = value
2500
+
2501
+ # Optional comma
2502
+ if self._check(TokenType.COMMA):
2503
+ self._advance()
2504
+
2505
+ self._expect(TokenType.BLOCK_END) # consume }
2506
+
2231
2507
  return ASTNode('type_instantiation', value={
2232
2508
  'type': name,
2233
- 'element_type': element_type
2509
+ 'element_type': element_type,
2510
+ 'value_type': value_type,
2511
+ 'init_values': init_values
2234
2512
  })
2235
2513
 
2236
2514
  # Check for type-parameterized function call: OpenFind<string>(0)
@@ -2288,7 +2566,7 @@ class CSSLParser:
2288
2566
  return False
2289
2567
 
2290
2568
  # Save position for lookahead
2291
- saved_pos = self._current
2569
+ saved_pos = self.pos
2292
2570
 
2293
2571
  # Check if it looks like key = value pattern
2294
2572
  is_object = False
@@ -2299,7 +2577,7 @@ class CSSLParser:
2299
2577
  is_object = True
2300
2578
 
2301
2579
  # Restore position
2302
- self._current = saved_pos
2580
+ self.pos = saved_pos
2303
2581
  return is_object
2304
2582
 
2305
2583
  def _parse_action_block_expression(self) -> ASTNode: