IncludeCPP 4.5.2__py3-none-any.whl → 4.9.3__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.
Files changed (35) hide show
  1. includecpp/CHANGELOG.md +241 -0
  2. includecpp/__init__.py +89 -3
  3. includecpp/__init__.pyi +2 -1
  4. includecpp/cli/commands.py +1747 -266
  5. includecpp/cli/config_parser.py +1 -1
  6. includecpp/core/build_manager.py +64 -13
  7. includecpp/core/cpp_api_extensions.pyi +43 -270
  8. includecpp/core/cssl/CSSL_DOCUMENTATION.md +1799 -1445
  9. includecpp/core/cssl/cpp/build/api.pyd +0 -0
  10. includecpp/core/cssl/cpp/build/api.pyi +274 -0
  11. includecpp/core/cssl/cpp/build/cssl_core.pyi +0 -99
  12. includecpp/core/cssl/cpp/cssl_core.cp +2 -23
  13. includecpp/core/cssl/cssl_builtins.py +2116 -171
  14. includecpp/core/cssl/cssl_builtins.pyi +1324 -104
  15. includecpp/core/cssl/cssl_compiler.py +4 -1
  16. includecpp/core/cssl/cssl_modules.py +605 -6
  17. includecpp/core/cssl/cssl_optimizer.py +12 -1
  18. includecpp/core/cssl/cssl_parser.py +1048 -52
  19. includecpp/core/cssl/cssl_runtime.py +2041 -131
  20. includecpp/core/cssl/cssl_syntax.py +405 -277
  21. includecpp/core/cssl/cssl_types.py +5891 -1655
  22. includecpp/core/cssl_bridge.py +429 -3
  23. includecpp/core/error_catalog.py +54 -10
  24. includecpp/core/homeserver.py +1037 -0
  25. includecpp/generator/parser.cpp +203 -39
  26. includecpp/generator/parser.h +15 -1
  27. includecpp/templates/cpp.proj.template +1 -1
  28. includecpp/vscode/cssl/snippets/cssl.snippets.json +163 -0
  29. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +87 -12
  30. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/METADATA +81 -10
  31. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/RECORD +35 -33
  32. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/WHEEL +1 -1
  33. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/entry_points.txt +0 -0
  34. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/licenses/LICENSE +0 -0
  35. {includecpp-4.5.2.dist-info → includecpp-4.9.3.dist-info}/top_level.txt +0 -0
@@ -84,6 +84,9 @@ class TokenType(Enum):
84
84
  AND = auto()
85
85
  OR = auto()
86
86
  NOT = auto()
87
+ TILDE = auto() # ~ for destructors (v4.8.8)
88
+ CARET = auto() # ^ for byte notation (v4.9.0)
89
+ QUESTION = auto() # ? for pointer references (v4.9.0)
87
90
  AMPERSAND = auto() # & for references
88
91
  BLOCK_START = auto()
89
92
  BLOCK_END = auto()
@@ -101,7 +104,9 @@ class TokenType(Enum):
101
104
  SELF_REF = auto() # s@<name> self-reference to global struct
102
105
  SHARED_REF = auto() # $<name> shared object reference
103
106
  CAPTURED_REF = auto() # %<name> captured reference (for infusion)
107
+ POINTER_REF = auto() # ?<name> pointer reference (v4.9.0)
104
108
  THIS_REF = auto() # this-><name> class member reference
109
+ LOCAL_REF = auto() # local::<name> hooked function local variable access (v4.9.2)
105
110
  PACKAGE = auto()
106
111
  PACKAGE_INCLUDES = auto()
107
112
  AS = auto()
@@ -115,15 +120,20 @@ class TokenType(Enum):
115
120
  MINUS_MINUS = auto() # -- for potential future use
116
121
  # Multi-language support (v4.1.0)
117
122
  LANG_INSTANCE_REF = auto() # cpp$InstanceName, py$Object - cross-language instance access
123
+ # v4.8.4: Pipe operator and stream operators
124
+ PIPE = auto() # | for data piping
125
+ STREAM_OUT = auto() # << for stream output (cout << x)
126
+ STREAM_IN = auto() # >> for stream input (cin >> x)
127
+ IN = auto() # 'in' keyword for containment check
118
128
 
119
129
 
120
130
  KEYWORDS = {
121
131
  # Service structure
122
- 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'constr', 'extends', 'overwrites', 'new', 'this', 'super', 'enum',
132
+ 'service-init', 'service-run', 'service-include', 'struct', 'define', 'class', 'namespace', 'constr', 'extends', 'overwrites', 'new', 'this', 'super', 'enum',
123
133
  # Control flow
124
134
  'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
125
135
  'switch', 'case', 'default', 'break', 'continue', 'return',
126
- 'try', 'catch', 'finally', 'throw',
136
+ 'try', 'catch', 'finally', 'throw', 'raise',
127
137
  'except', 'always', # v4.2.5: param switch keywords
128
138
  # Literals
129
139
  'True', 'False', 'null', 'None', 'true', 'false',
@@ -131,11 +141,14 @@ KEYWORDS = {
131
141
  'and', 'or', 'not',
132
142
  # Async/Events
133
143
  'start', 'stop', 'wait_for', 'on_event', 'emit_event', 'await',
144
+ 'async', 'yield', 'generator', 'future', # v4.9.3: Full async/generator support
134
145
  # Package system
135
146
  'package', 'package-includes', 'exec', 'as', 'global',
136
147
  # CSSL Type Keywords
137
148
  'int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
138
- 'list', 'dictionary', 'dict', 'instance', 'map', # Python-like types
149
+ 'list', 'dictionary', 'dict', 'instance', 'map', 'queue', # Python-like types + queue (v4.7)
150
+ 'bit', 'byte', 'address', 'ptr', 'pointer', # v4.9.0: Binary types, address, ptr/pointer
151
+ 'local', # v4.9.2: Hook local variable access (local::varname)
139
152
  'dynamic', # No type declaration (slow but flexible)
140
153
  'undefined', # Function errors ignored
141
154
  'open', # Accept any parameter type
@@ -159,17 +172,25 @@ KEYWORDS = {
159
172
  'static', # Static method/function
160
173
  'embedded', # Immediate &target replacement at registration (v4.2.5)
161
174
  'native', # Force C++ execution (no Python fallback)
175
+ 'unative', # Force Python execution (no C++ - opposite of native)
176
+ 'secure', # v4.8.8: Constructor runs only on exception
177
+ 'callable', # v4.8.8: Constructor must be manually called
162
178
  # CSSL Include Keywords
163
- 'include', 'get',
179
+ 'include', # v4.8.6: Removed 'get' from keywords - it's a builtin function, not keyword
164
180
  # Multi-language support (v4.1.0)
165
181
  'supports', 'libinclude',
182
+ # Memory binding (v4.9.0)
183
+ 'uses', 'memory',
166
184
  }
167
185
 
168
186
  # Function modifiers that can appear in any order before function name
169
187
  FUNCTION_MODIFIERS = {
170
188
  'undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual',
171
189
  'sqlbased', 'const', 'public', 'static', 'global', 'shuffled', 'embedded',
172
- 'native' # Force C++ execution
190
+ 'native', # Force C++ execution
191
+ 'unative', # Force Python execution (opposite of native)
192
+ 'bytearrayed', # v4.7: Function-to-byte mapping with pattern matching
193
+ 'async', # v4.9.3: Async function modifier
173
194
  }
174
195
 
175
196
  # Type literals that create empty instances
@@ -178,7 +199,9 @@ TYPE_LITERALS = {'list', 'dict'}
178
199
  # Generic type keywords that use <T> syntax
179
200
  TYPE_GENERICS = {
180
201
  'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo',
181
- 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary', 'map'
202
+ 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary', 'map',
203
+ 'queue', # v4.7: Thread-safe queue with multi-iterator support
204
+ 'generator', 'future', # v4.9.3: Async types
182
205
  }
183
206
 
184
207
  # Functions that accept type parameters: FuncName<type>(args)
@@ -271,6 +294,14 @@ class CSSLLexer:
271
294
  # s@<name> self-reference to global struct
272
295
  self._read_self_ref()
273
296
  elif char.isalpha() or char == '_':
297
+ # v4.8.6: Detect f-string syntax and throw clear error
298
+ if char == 'f' and self._peek(1) in ('"', "'"):
299
+ raise CSSLSyntaxError(
300
+ f"f-string syntax is not supported in CSSL. Use string concatenation instead:\n"
301
+ f" Instead of: f\"Hello {{name}}\"\n"
302
+ f" Use: \"Hello \" + name",
303
+ line=self.line
304
+ )
274
305
  self._read_identifier()
275
306
  elif char == '@':
276
307
  self._add_token(TokenType.AT, '@')
@@ -379,6 +410,26 @@ class CSSLLexer:
379
410
  self._advance()
380
411
  self._advance()
381
412
  else:
413
+ # v4.8.4: Single | is pipe operator
414
+ self._add_token(TokenType.PIPE, '|')
415
+ self._advance()
416
+ elif char == '~':
417
+ # v4.8.8: Tilde for destructors (constr ~Name())
418
+ self._add_token(TokenType.TILDE, '~')
419
+ self._advance()
420
+ elif char == '^':
421
+ # v4.9.0: Caret for byte notation (1^250, 0^102)
422
+ self._add_token(TokenType.CARET, '^')
423
+ self._advance()
424
+ elif char == '?':
425
+ # v4.9.0: Check if this is ?<name> pointer reference
426
+ next_char = self._peek(1)
427
+ if next_char and (next_char.isalpha() or next_char == '_'):
428
+ # ?<name> pointer reference
429
+ self._read_pointer_ref()
430
+ else:
431
+ # Just ? (ternary operator or other use)
432
+ self._add_token(TokenType.QUESTION, '?')
382
433
  self._advance()
383
434
  else:
384
435
  self._advance()
@@ -540,6 +591,20 @@ class CSSLLexer:
540
591
  # NEW: 'as' keyword for foreach ... as ... syntax
541
592
  self._add_token(TokenType.AS, value)
542
593
  elif value in KEYWORDS:
594
+ # v4.9.2: Check for local:: syntax for hook local variable access
595
+ if value == 'local' and self.pos + 1 < len(self.source) and self.source[self.pos:self.pos+2] == '::':
596
+ self._advance() # skip first :
597
+ self._advance() # skip second :
598
+ # Read the local variable/function name
599
+ local_start = self.pos
600
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
601
+ self._advance()
602
+ local_name = self.source[local_start:self.pos]
603
+ if local_name:
604
+ self._add_token(TokenType.LOCAL_REF, local_name)
605
+ return
606
+ # If no name, revert to keyword
607
+ self.pos = start + len(value)
543
608
  self._add_token(TokenType.KEYWORD, value)
544
609
  else:
545
610
  self._add_token(TokenType.IDENTIFIER, value)
@@ -636,11 +701,30 @@ class CSSLLexer:
636
701
  self.error("Expected identifier after '%'")
637
702
  self._add_token(TokenType.CAPTURED_REF, value)
638
703
 
704
+ def _read_pointer_ref(self):
705
+ """Read ?<name> pointer reference (v4.9.0)"""
706
+ self._advance() # skip '?'
707
+
708
+ # Read the identifier (pointer reference name)
709
+ name_start = self.pos
710
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
711
+ self._advance()
712
+
713
+ value = self.source[name_start:self.pos]
714
+ if not value:
715
+ self.error("Expected identifier after '?'")
716
+ self._add_token(TokenType.POINTER_REF, value)
717
+
639
718
  def _read_less_than(self):
640
719
  # Check for <<== (code infusion left)
641
720
  if self._peek(1) == '<' and self._peek(2) == '=' and self._peek(3) == '=':
642
721
  self._add_token(TokenType.INFUSE_LEFT, '<<==')
643
722
  for _ in range(4): self._advance()
723
+ # v4.8.4: Check for << (stream output operator) - but NOT <<==
724
+ elif self._peek(1) == '<' and self._peek(2) != '=':
725
+ self._add_token(TokenType.STREAM_OUT, '<<')
726
+ self._advance()
727
+ self._advance()
644
728
  # Check for <== (basic injection left)
645
729
  elif self._peek(1) == '=' and self._peek(2) == '=':
646
730
  self._add_token(TokenType.INJECT_LEFT, '<==')
@@ -662,6 +746,11 @@ class CSSLLexer:
662
746
  self._add_token(TokenType.COMPARE_GE, '>=')
663
747
  self._advance()
664
748
  self._advance()
749
+ # v4.8.4: Check for >> (stream input operator)
750
+ elif self._peek(1) == '>':
751
+ self._add_token(TokenType.STREAM_IN, '>>')
752
+ self._advance()
753
+ self._advance()
665
754
  else:
666
755
  self._add_token(TokenType.COMPARE_GT, '>')
667
756
  self._advance()
@@ -805,7 +894,9 @@ class CSSLParser:
805
894
  """Check if a keyword is a type declaration"""
806
895
  return value in ('int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
807
896
  'list', 'dictionary', 'dict', 'instance', 'map', 'openquote', 'parameter',
808
- 'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure')
897
+ 'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure',
898
+ 'queue', # v4.7: Thread-safe queue
899
+ 'bit', 'byte', 'address', 'ptr', 'pointer') # v4.9.0: Binary types, address, ptr/pointer
809
900
 
810
901
  def _parse_generic_type_content(self) -> str:
811
902
  """Parse generic type content including nested generics.
@@ -833,6 +924,9 @@ class CSSLParser:
833
924
  self._advance()
834
925
  elif self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
835
926
  parts.append(self._advance().value)
927
+ elif self._check(TokenType.NUMBER):
928
+ # v4.7: For queue<type, size> where size is a number
929
+ parts.append(str(int(self._advance().value)))
836
930
  elif self._check(TokenType.STRING):
837
931
  # For instance<"name">
838
932
  parts.append(f'"{self._advance().value}"')
@@ -880,7 +974,9 @@ class CSSLParser:
880
974
  return False # Let _parse_define handle this
881
975
 
882
976
  # Check for type keyword (int, string, void, vector, datastruct, etc.)
883
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
977
+ # v4.8: Also handle TYPE_LITERAL (dict, list) and custom class types (IDENTIFIER)
978
+ if (self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or \
979
+ self._check(TokenType.TYPE_LITERAL):
884
980
  self._advance()
885
981
  has_type = True
886
982
 
@@ -895,6 +991,31 @@ class CSSLParser:
895
991
  depth -= 1
896
992
  self._advance()
897
993
 
994
+ # v4.8: Check for custom class type (IDENTIFIER followed by another IDENTIFIER)
995
+ # Pattern: CustomClass funcName() { } where CustomClass is a user-defined class
996
+ elif self._check(TokenType.IDENTIFIER):
997
+ # Save position and check if this is "Type Name(" pattern
998
+ inner_saved = self.pos
999
+ self._advance() # Skip potential type
1000
+
1001
+ # Skip generic type parameters if present
1002
+ if self._check(TokenType.COMPARE_LT):
1003
+ depth = 1
1004
+ self._advance()
1005
+ while depth > 0 and not self._is_at_end():
1006
+ if self._check(TokenType.COMPARE_LT):
1007
+ depth += 1
1008
+ elif self._check(TokenType.COMPARE_GT):
1009
+ depth -= 1
1010
+ self._advance()
1011
+
1012
+ # Check if followed by another identifier (function name)
1013
+ if self._check(TokenType.IDENTIFIER):
1014
+ has_type = True
1015
+ else:
1016
+ # Not a "Type Name" pattern, restore position
1017
+ self.pos = inner_saved
1018
+
898
1019
  # Check for * prefix (non-null) or *[type] (type exclusion)
899
1020
  if self._check(TokenType.MULTIPLY):
900
1021
  self._advance()
@@ -945,13 +1066,17 @@ class CSSLParser:
945
1066
  - int x;
946
1067
  - stack<string> myStack;
947
1068
  - vector<int> nums = [1,2,3];
1069
+ - list<int> myList; (v4.8.7: list/dict are TYPE_LITERAL tokens)
948
1070
 
949
1071
  Distinguishes from function declarations by checking for '(' after identifier.
950
1072
  """
951
1073
  saved_pos = self.pos
952
1074
 
953
1075
  # Check for type keyword
954
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
1076
+ # v4.8.7: Also check TYPE_LITERAL (list, dict) which are tokenized differently
1077
+ is_type_token = ((self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or
1078
+ (self._check(TokenType.TYPE_LITERAL) and self._current().value in ('list', 'dict')))
1079
+ if is_type_token:
955
1080
  self._advance()
956
1081
 
957
1082
  # Skip generic type parameters <T>
@@ -976,7 +1101,7 @@ class CSSLParser:
976
1101
  self.pos = saved_pos
977
1102
  return False
978
1103
 
979
- def _parse_typed_function(self, is_global: bool = False, is_embedded: bool = False) -> ASTNode:
1104
+ def _parse_typed_function(self, is_global: bool = False, is_embedded: bool = False, modifiers: list = None) -> ASTNode:
980
1105
  """Parse C-style typed function declaration with flexible modifier ordering.
981
1106
 
982
1107
  Supports any order of modifiers, types, non-null (*), and global (@):
@@ -1000,7 +1125,7 @@ class CSSLParser:
1000
1125
  Functions with 'meta' modifier can return any type regardless of declaration.
1001
1126
  Functions with 'define' are dynamic (any return type allowed).
1002
1127
  """
1003
- modifiers = []
1128
+ modifiers = modifiers if modifiers is not None else []
1004
1129
  return_type = None
1005
1130
  generic_type = None
1006
1131
  non_null = False
@@ -1030,7 +1155,9 @@ class CSSLParser:
1030
1155
  continue
1031
1156
 
1032
1157
  # Check for type keyword (int, string, void, vector, datastruct, etc.)
1033
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value) and return_type is None:
1158
+ # v4.8: Also handle TYPE_LITERAL (dict, list) as return types
1159
+ if ((self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or
1160
+ self._check(TokenType.TYPE_LITERAL)) and return_type is None:
1034
1161
  return_type = self._advance().value
1035
1162
 
1036
1163
  # Check for generic type <T> or <T, U>
@@ -1054,6 +1181,32 @@ class CSSLParser:
1054
1181
  generic_type = ''.join(generic_parts)
1055
1182
  continue
1056
1183
 
1184
+ # v4.8: Check for custom class type as return type (IDENTIFIER followed by another IDENTIFIER)
1185
+ # Pattern: CustomClass funcName() { } where CustomClass is a user-defined class
1186
+ if self._check(TokenType.IDENTIFIER) and return_type is None:
1187
+ # Look ahead to see if this is "Type Name(" pattern
1188
+ saved_inner = self.pos
1189
+ potential_type = self._advance().value
1190
+
1191
+ # Skip generic type parameters if present
1192
+ if self._check(TokenType.COMPARE_LT):
1193
+ self._advance()
1194
+ depth = 1
1195
+ while depth > 0 and not self._is_at_end():
1196
+ if self._check(TokenType.COMPARE_LT):
1197
+ depth += 1
1198
+ elif self._check(TokenType.COMPARE_GT):
1199
+ depth -= 1
1200
+ self._advance()
1201
+
1202
+ # Check if followed by another identifier (function name)
1203
+ if self._check(TokenType.IDENTIFIER):
1204
+ return_type = potential_type
1205
+ continue
1206
+ else:
1207
+ # Not a "Type Name" pattern, restore position
1208
+ self.pos = saved_inner
1209
+
1057
1210
  # Check for * prefix (non-null) or *[type] (type exclusion)
1058
1211
  if self._check(TokenType.MULTIPLY):
1059
1212
  self._advance()
@@ -1100,7 +1253,9 @@ class CSSLParser:
1100
1253
  param_info['const'] = True
1101
1254
 
1102
1255
  # Handle type annotations (builtin types like int, string, etc.)
1103
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
1256
+ # v4.8: Also handle TYPE_LITERAL (dict, list) which are tokenized differently
1257
+ if (self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or \
1258
+ self._check(TokenType.TYPE_LITERAL):
1104
1259
  param_info['type'] = self._advance().value
1105
1260
 
1106
1261
  # Check for generic type parameter <T>
@@ -1325,7 +1480,8 @@ class CSSLParser:
1325
1480
  saved_pos = self.pos
1326
1481
 
1327
1482
  # Must start with a type keyword (int, string, stack, vector, etc.)
1328
- if not self._check(TokenType.KEYWORD):
1483
+ # v4.8.7: Also check TYPE_LITERAL (list, dict) which are tokenized differently
1484
+ if not self._check(TokenType.KEYWORD) and not self._check(TokenType.TYPE_LITERAL):
1329
1485
  return False
1330
1486
 
1331
1487
  type_name = self._current().value
@@ -1334,7 +1490,9 @@ class CSSLParser:
1334
1490
  type_keywords = {'int', 'string', 'float', 'bool', 'dynamic', 'void',
1335
1491
  'stack', 'vector', 'datastruct', 'dataspace', 'shuffled',
1336
1492
  'iterator', 'combo', 'array', 'openquote', 'json',
1337
- 'list', 'dictionary', 'dict', 'instance', 'map'}
1493
+ 'list', 'dictionary', 'dict', 'instance', 'map',
1494
+ 'queue', # v4.7: Added queue
1495
+ 'bit', 'byte', 'address', 'ptr', 'pointer'} # v4.9.0: Binary types, address, ptr/pointer
1338
1496
  if type_name not in type_keywords:
1339
1497
  return False
1340
1498
 
@@ -1351,6 +1509,10 @@ class CSSLParser:
1351
1509
  depth -= 1
1352
1510
  self._advance()
1353
1511
 
1512
+ # v4.8.6: Check for @ prefix (global variable marker)
1513
+ if self._check(TokenType.AT):
1514
+ self._advance()
1515
+
1354
1516
  # Next should be an identifier (variable name), not '(' (function) or ';'
1355
1517
  result = self._check(TokenType.IDENTIFIER)
1356
1518
 
@@ -1379,10 +1541,32 @@ class CSSLParser:
1379
1541
  if self._match(TokenType.MULTIPLY):
1380
1542
  non_null = True
1381
1543
 
1382
- # Get variable name
1383
- if not self._check(TokenType.IDENTIFIER):
1544
+ # v4.8.6: Check for @ prefix (global variable marker)
1545
+ is_global_ref = False
1546
+ if self._match(TokenType.AT):
1547
+ is_global_ref = True
1548
+
1549
+ # Get variable name - can be identifier or this->member
1550
+ # v4.9.2: Support this->member syntax for class member declarations
1551
+ is_this_member = False
1552
+ if self._check(TokenType.KEYWORD) and self._current().value == 'this':
1553
+ self._advance() # consume 'this'
1554
+ if self._match(TokenType.FLOW_RIGHT):
1555
+ if self._check(TokenType.IDENTIFIER):
1556
+ var_name = self._advance().value
1557
+ is_this_member = True
1558
+ else:
1559
+ return None
1560
+ else:
1561
+ return None
1562
+ elif not self._check(TokenType.IDENTIFIER):
1384
1563
  return None
1385
- var_name = self._advance().value
1564
+ else:
1565
+ var_name = self._advance().value
1566
+
1567
+ # v4.8.6: Store @ prefix in var_name for global reference
1568
+ if is_global_ref:
1569
+ var_name = '@' + var_name
1386
1570
 
1387
1571
  # Check for assignment or just declaration
1388
1572
  value = None
@@ -1391,21 +1575,38 @@ class CSSLParser:
1391
1575
 
1392
1576
  self._match(TokenType.SEMICOLON)
1393
1577
 
1394
- # For instance<"name">, create a special node type
1395
- if type_name == 'instance':
1578
+ # For instance<"name">, create a special UniversalInstance node
1579
+ # But for plain "instance varName", treat as regular type annotation (like dynamic)
1580
+ if type_name == 'instance' and element_type:
1581
+ # instance<"containerName"> - creates/gets UniversalInstance
1396
1582
  return ASTNode('instance_declaration', value={
1397
1583
  'instance_name': element_type,
1398
1584
  'name': var_name,
1399
1585
  'value': value,
1400
1586
  'non_null': non_null
1401
1587
  })
1588
+ # v4.8.8: Plain "instance varName = new Class()" is a type annotation
1589
+ # allowing any CSSLInstance to be stored (like dynamic but for objects)
1590
+
1591
+ # v4.7: For queue<type, size>, extract size from element_type string
1592
+ queue_size = 'dynamic'
1593
+ if type_name == 'queue' and element_type and ', ' in element_type:
1594
+ parts = element_type.split(', ', 1)
1595
+ element_type = parts[0].strip()
1596
+ size_str = parts[1].strip()
1597
+ if size_str.isdigit():
1598
+ queue_size = int(size_str)
1599
+ else:
1600
+ queue_size = size_str # 'dynamic' or other
1402
1601
 
1403
1602
  return ASTNode('typed_declaration', value={
1404
1603
  'type': type_name,
1405
1604
  'element_type': element_type,
1406
1605
  'name': var_name,
1407
1606
  'value': value,
1408
- 'non_null': non_null
1607
+ 'non_null': non_null,
1608
+ 'size': queue_size, # v4.7: For queue<T, size>
1609
+ 'is_this_member': is_this_member # v4.9.2: this->member declaration
1409
1610
  })
1410
1611
 
1411
1612
  def parse_program(self) -> ASTNode:
@@ -1417,10 +1618,22 @@ class CSSLParser:
1417
1618
  root.children.append(self._parse_struct())
1418
1619
  elif self._match_keyword('class'):
1419
1620
  root.children.append(self._parse_class())
1621
+ elif self._match_keyword('namespace'):
1622
+ root.children.append(self._parse_namespace())
1420
1623
  elif self._match_keyword('enum'):
1421
1624
  root.children.append(self._parse_enum())
1422
- elif self._match_keyword('bytearrayed'):
1423
- root.children.append(self._parse_bytearrayed())
1625
+ # v4.7: bytearrayed can be a modifier (bytearrayed define) or standalone block
1626
+ elif self._check(TokenType.KEYWORD) and self._current().value == 'bytearrayed':
1627
+ # Peek ahead: if next token is 'define', treat as modifier and handle in-place
1628
+ next_tok = self._peek(1)
1629
+ if next_tok.type == TokenType.KEYWORD and next_tok.value == 'define':
1630
+ # Handle bytearrayed define directly
1631
+ self._advance() # consume 'bytearrayed'
1632
+ self._advance() # consume 'define'
1633
+ root.children.append(self._parse_define(modifiers=['bytearrayed']))
1634
+ else:
1635
+ self._advance() # consume 'bytearrayed'
1636
+ root.children.append(self._parse_bytearrayed())
1424
1637
  elif self._match_keyword('define'):
1425
1638
  root.children.append(self._parse_define())
1426
1639
  # v4.5.1: Handle function modifiers (private, const, static, etc.) before define
@@ -1444,10 +1657,28 @@ class CSSLParser:
1444
1657
  is_global=is_global, is_embedded=is_embedded,
1445
1658
  has_open_params=has_open_params, modifiers=modifiers
1446
1659
  ))
1660
+ elif self._match_keyword('class'):
1661
+ # v4.8.6: Support 'global class @ClassName' syntax
1662
+ root.children.append(self._parse_class(is_global=is_global, is_embedded=is_embedded))
1447
1663
  elif self._looks_like_function_declaration():
1448
1664
  root.children.append(self._parse_typed_function(modifiers=modifiers))
1665
+ elif self._looks_like_typed_variable():
1666
+ # v4.8.6: Support 'global int @varname = value' syntax
1667
+ decl = self._parse_typed_variable()
1668
+ if decl and is_global:
1669
+ # Wrap in global_assignment to mark as global variable
1670
+ global_stmt = ASTNode('global_assignment', value=decl)
1671
+ root.children.append(global_stmt)
1672
+ elif decl:
1673
+ root.children.append(decl)
1674
+ elif is_global:
1675
+ # v4.8.6: Handle 'global @varname = value' or 'global varname = value'
1676
+ stmt = self._parse_expression_statement()
1677
+ if stmt:
1678
+ global_stmt = ASTNode('global_assignment', value=stmt)
1679
+ root.children.append(global_stmt)
1449
1680
  else:
1450
- self.error(f"Expected 'define' or function declaration after modifiers: {modifiers}")
1681
+ self.error(f"Expected 'define', 'class', function, or variable declaration after modifiers: {modifiers}")
1451
1682
  # Check for C-style typed function declarations
1452
1683
  elif self._looks_like_function_declaration():
1453
1684
  root.children.append(self._parse_typed_function())
@@ -1544,9 +1775,12 @@ class CSSLParser:
1544
1775
  root.children.append(self._parse_switch())
1545
1776
  # Handle statements - keywords like 'instance', 'list', 'map' can be variable names
1546
1777
  # v4.2.1: Added LANG_INSTANCE_REF for lang$instance statements (js$GameData.score = 1337)
1778
+ # v4.8.8: Added CAPTURED_REF for %snapshot(args) function calls
1779
+ # v4.9.0: Added POINTER_REF for ?name = value pointer assignments
1547
1780
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1548
1781
  self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
1549
- self._check(TokenType.KEYWORD) or self._check(TokenType.LANG_INSTANCE_REF)):
1782
+ self._check(TokenType.KEYWORD) or self._check(TokenType.LANG_INSTANCE_REF) or
1783
+ self._check(TokenType.CAPTURED_REF) or self._check(TokenType.POINTER_REF)):
1550
1784
  stmt = self._parse_expression_statement()
1551
1785
  if stmt:
1552
1786
  root.children.append(stmt)
@@ -2136,6 +2370,225 @@ class CSSLParser:
2136
2370
  'default': default_block
2137
2371
  })
2138
2372
 
2373
+ def _parse_bytearrayed_body(self) -> List[ASTNode]:
2374
+ """Parse body of a bytearrayed define function (v4.7).
2375
+
2376
+ Syntax:
2377
+ bytearrayed define Localize() {
2378
+ case "en": &GetLang() {
2379
+ return "Hello";
2380
+ }
2381
+ case "de": &GetLang() {
2382
+ return "Hallo";
2383
+ }
2384
+ default: {
2385
+ return "Unknown";
2386
+ }
2387
+ }
2388
+
2389
+ Returns list of AST nodes: case nodes with func_refs, and default node.
2390
+ """
2391
+ children = []
2392
+
2393
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2394
+ # Handle case blocks: case "value": &FuncRef() { body }
2395
+ if self._match_keyword('case'):
2396
+ case_values = []
2397
+ func_refs = []
2398
+
2399
+ # Parse case values (comma-separated): case "en", "de": ...
2400
+ # v4.8.8: Also support tuple patterns: case {0, 0}: for matching multiple byte values
2401
+ while True:
2402
+ if self._check(TokenType.STRING):
2403
+ case_values.append(self._advance().value)
2404
+ elif self._check(TokenType.NUMBER):
2405
+ case_values.append(self._advance().value)
2406
+ elif self._check(TokenType.BOOLEAN):
2407
+ case_values.append(self._advance().value)
2408
+ elif self._check(TokenType.IDENTIFIER):
2409
+ case_values.append(self._advance().value)
2410
+ elif self._check(TokenType.BLOCK_START):
2411
+ # v4.8.8: Tuple pattern {val1, val2, ...} for matching multiple byte values
2412
+ self._advance() # consume {
2413
+ tuple_values = []
2414
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2415
+ if self._check(TokenType.NUMBER):
2416
+ tuple_values.append(self._advance().value)
2417
+ elif self._check(TokenType.STRING):
2418
+ tuple_values.append(self._advance().value)
2419
+ elif self._check(TokenType.BOOLEAN):
2420
+ tuple_values.append(self._advance().value)
2421
+ elif self._check(TokenType.IDENTIFIER):
2422
+ tuple_values.append(self._advance().value)
2423
+ elif self._check(TokenType.COMMA):
2424
+ self._advance() # skip comma
2425
+ else:
2426
+ break
2427
+ self._expect(TokenType.BLOCK_END) # consume }
2428
+ case_values.append(tuple(tuple_values)) # Store as tuple
2429
+ else:
2430
+ break
2431
+ if not self._match(TokenType.COMMA):
2432
+ break
2433
+
2434
+ # Expect colon after case values
2435
+ self._expect(TokenType.COLON)
2436
+
2437
+ # Parse function references: &FuncRef(), &FuncRef2(), ...
2438
+ while self._check(TokenType.AMPERSAND):
2439
+ self._advance() # consume &
2440
+ if self._check(TokenType.IDENTIFIER):
2441
+ func_name = self._advance().value
2442
+ func_args = []
2443
+ if self._match(TokenType.PAREN_START):
2444
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
2445
+ if self._check(TokenType.COMMA):
2446
+ self._advance()
2447
+ continue
2448
+ arg = self._parse_expression()
2449
+ func_args.append(arg)
2450
+ self._expect(TokenType.PAREN_END)
2451
+ func_refs.append({'name': func_name, 'args': func_args})
2452
+ if not self._match(TokenType.COMMA):
2453
+ break
2454
+
2455
+ # Parse case body - either block { } or inline statements until next case/default
2456
+ body_children = []
2457
+ if self._check(TokenType.BLOCK_START):
2458
+ # Block syntax: case val: { ... }
2459
+ self._advance() # consume {
2460
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2461
+ stmt = self._parse_statement()
2462
+ if stmt:
2463
+ body_children.append(stmt)
2464
+ self._expect(TokenType.BLOCK_END)
2465
+ else:
2466
+ # v4.8.8: Inline syntax: case val: stmt1; stmt2; return x; (until next case/default/})
2467
+ while not self._is_at_end():
2468
+ # Stop at next case, default, or block end
2469
+ if self._check(TokenType.KEYWORD) and self._current().value in ('case', 'default'):
2470
+ break
2471
+ if self._check(TokenType.BLOCK_END):
2472
+ break
2473
+ stmt = self._parse_statement()
2474
+ if stmt:
2475
+ body_children.append(stmt)
2476
+
2477
+ children.append(ASTNode('case', value={
2478
+ 'patterns': case_values,
2479
+ 'func_refs': func_refs,
2480
+ 'body': body_children
2481
+ }))
2482
+
2483
+ # Handle default block: default: { body } or default: stmt (inline)
2484
+ elif self._match_keyword('default'):
2485
+ self._match(TokenType.COLON) # Optional colon
2486
+ body_children = []
2487
+ if self._check(TokenType.BLOCK_START):
2488
+ # Block syntax
2489
+ self._advance() # consume {
2490
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2491
+ stmt = self._parse_statement()
2492
+ if stmt:
2493
+ body_children.append(stmt)
2494
+ self._expect(TokenType.BLOCK_END)
2495
+ else:
2496
+ # v4.8.8: Inline syntax: default: stmt1; return x; (until block end)
2497
+ while not self._is_at_end():
2498
+ if self._check(TokenType.BLOCK_END):
2499
+ break
2500
+ # Also stop at next case (shouldn't happen after default, but be safe)
2501
+ if self._check(TokenType.KEYWORD) and self._current().value == 'case':
2502
+ break
2503
+ stmt = self._parse_statement()
2504
+ if stmt:
2505
+ body_children.append(stmt)
2506
+
2507
+ children.append(ASTNode('default', value={
2508
+ 'body': body_children
2509
+ }))
2510
+
2511
+ # v4.8.8: Handle func_ref statements (&func; or &func(args);)
2512
+ elif self._check(TokenType.AMPERSAND):
2513
+ self._advance() # consume &
2514
+ if self._check(TokenType.IDENTIFIER):
2515
+ func_name = self._advance().value
2516
+ func_args = []
2517
+ # Check for arguments
2518
+ if self._match(TokenType.PAREN_START):
2519
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
2520
+ if self._check(TokenType.COMMA):
2521
+ self._advance()
2522
+ continue
2523
+ arg = self._parse_expression()
2524
+ func_args.append(arg)
2525
+ self._expect(TokenType.PAREN_END)
2526
+ self._match(TokenType.SEMICOLON) # Optional semicolon
2527
+ children.append(ASTNode('func_ref', value={
2528
+ 'name': func_name,
2529
+ 'args': func_args
2530
+ }))
2531
+ else:
2532
+ self.error("Expected identifier after '&' in bytearrayed body")
2533
+
2534
+ # Handle other statements (e.g., expressions, function calls)
2535
+ else:
2536
+ stmt = self._parse_statement()
2537
+ if stmt:
2538
+ children.append(stmt)
2539
+
2540
+ return children
2541
+
2542
+ def _parse_namespace(self) -> ASTNode:
2543
+ """Parse namespace definition.
2544
+
2545
+ Syntax:
2546
+ namespace mylib {
2547
+ void myFunc() { ... }
2548
+ class MyClass { ... }
2549
+ namespace nested { ... }
2550
+ }
2551
+
2552
+ Access: mylib::myFunc(), mylib::MyClass, mylib::nested::innerFunc()
2553
+ """
2554
+ # Get namespace name
2555
+ if not self._check(TokenType.IDENTIFIER):
2556
+ self.error("Expected namespace name after 'namespace'")
2557
+ name = self._advance().value
2558
+
2559
+ # Expect opening brace
2560
+ if not self._match(TokenType.BLOCK_START):
2561
+ self.error(f"Expected '{{' after 'namespace {name}'")
2562
+
2563
+ # Parse namespace contents
2564
+ members = []
2565
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2566
+ if self._match_keyword('namespace'):
2567
+ # Nested namespace
2568
+ members.append(self._parse_namespace())
2569
+ elif self._match_keyword('class'):
2570
+ members.append(self._parse_class())
2571
+ elif self._match_keyword('struct'):
2572
+ members.append(self._parse_struct())
2573
+ elif self._match_keyword('enum'):
2574
+ members.append(self._parse_enum())
2575
+ elif self._match_keyword('define'):
2576
+ members.append(self._parse_define())
2577
+ elif self._looks_like_function_declaration():
2578
+ members.append(self._parse_typed_function())
2579
+ elif self._check(TokenType.COMMENT):
2580
+ self._advance() # Skip comments
2581
+ else:
2582
+ stmt = self._parse_expression_statement()
2583
+ if stmt:
2584
+ members.append(stmt)
2585
+
2586
+ # Expect closing brace
2587
+ if not self._match(TokenType.BLOCK_END):
2588
+ self.error(f"Expected '}}' to close namespace '{name}'")
2589
+
2590
+ return ASTNode('namespace', value={'name': name}, children=members)
2591
+
2139
2592
  def _parse_class(self, is_global: bool = False, is_embedded: bool = False) -> ASTNode:
2140
2593
  """Parse class declaration with members and methods.
2141
2594
 
@@ -2201,8 +2654,30 @@ class CSSLParser:
2201
2654
  overwrites_class = None
2202
2655
  overwrites_is_python = False
2203
2656
  supports_language = None # v4.1.0: Multi-language syntax support
2204
-
2205
- if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
2657
+ uses_memory = None # v4.9.0: Memory binding for deferred execution
2658
+
2659
+ # v4.8.8: Support C++ style "class Child extends Parent" without colon
2660
+ if self._match_keyword('extends'):
2661
+ # Direct extends without colon: class Dog extends Animal
2662
+ if self._check(TokenType.LANG_INSTANCE_REF):
2663
+ ref = self._advance().value
2664
+ extends_lang_ref = ref
2665
+ extends_class = ref['instance']
2666
+ elif self._check(TokenType.IDENTIFIER):
2667
+ extends_class = self._advance().value
2668
+ elif self._check(TokenType.SHARED_REF):
2669
+ extends_class = self._advance().value
2670
+ extends_is_python = True
2671
+ else:
2672
+ raise CSSLSyntaxError("Expected parent class name after 'extends'")
2673
+ # Check for constructor arguments: extends Parent(arg1, arg2)
2674
+ if self._match(TokenType.PAREN_START):
2675
+ while not self._check(TokenType.PAREN_END):
2676
+ arg = self._parse_expression()
2677
+ extends_args.append(arg)
2678
+ self._match(TokenType.COMMA)
2679
+ self._expect(TokenType.PAREN_END)
2680
+ elif self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
2206
2681
  # Parse extends and/or overwrites (can be chained with : or ::)
2207
2682
  while True:
2208
2683
  if self._match_keyword('extends'):
@@ -2248,8 +2723,18 @@ class CSSLParser:
2248
2723
  supports_language = self._advance().value
2249
2724
  else:
2250
2725
  raise CSSLSyntaxError("Expected language identifier after 'supports'")
2726
+ # v4.9.0: Parse 'uses' keyword for memory binding (deferred execution)
2727
+ # Syntax: class MyClass : uses memory(address) { }
2728
+ elif self._match_keyword('uses'):
2729
+ if (self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD)) and self._current().value == 'memory':
2730
+ self._advance() # consume 'memory'
2731
+ self._expect(TokenType.PAREN_START)
2732
+ uses_memory = self._parse_expression() # Parse the address expression
2733
+ self._expect(TokenType.PAREN_END)
2734
+ else:
2735
+ raise CSSLSyntaxError("Expected 'memory(address)' after 'uses'")
2251
2736
  else:
2252
- raise CSSLSyntaxError("Expected 'extends', 'overwrites', or 'supports' after ':' or '::' in class declaration")
2737
+ raise CSSLSyntaxError("Expected 'extends', 'overwrites', 'supports', or 'uses' after ':' or '::' in class declaration")
2253
2738
  # Check for another : or :: for chaining
2254
2739
  if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
2255
2740
  break
@@ -2274,7 +2759,8 @@ class CSSLParser:
2274
2759
  'supports_language': supports_language, # v4.1.0
2275
2760
  'raw_body': raw_body, # v4.2.0: Raw body for language transformation
2276
2761
  'append_ref_class': append_ref_class, # v4.2.5: &target class reference
2277
- 'append_ref_member': append_ref_member # v4.2.5: &target member reference
2762
+ 'append_ref_member': append_ref_member, # v4.2.5: &target member reference
2763
+ 'uses_memory': uses_memory # v4.9.0: Memory binding for deferred execution
2278
2764
  }, children=[])
2279
2765
 
2280
2766
  # v4.2.0: If we have raw_body for language transformation, skip regular parsing
@@ -2320,12 +2806,46 @@ class CSSLParser:
2320
2806
  method = self._parse_define()
2321
2807
  node.children.append(method)
2322
2808
 
2809
+ # v4.7: Check for function modifiers before define (e.g., bytearrayed define, private define)
2810
+ elif self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
2811
+ modifiers = []
2812
+ is_embedded = False
2813
+ is_global = False
2814
+ while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
2815
+ mod = self._advance().value
2816
+ modifiers.append(mod)
2817
+ if mod == 'embedded':
2818
+ is_embedded = True
2819
+ elif mod == 'global':
2820
+ is_global = True
2821
+ # After modifiers, expect 'define' or typed function
2822
+ if self._match_keyword('define'):
2823
+ method = self._parse_define(
2824
+ is_global=is_global, is_embedded=is_embedded,
2825
+ modifiers=modifiers
2826
+ )
2827
+ node.children.append(method)
2828
+ elif self._looks_like_function_declaration():
2829
+ method = self._parse_typed_function(modifiers=modifiers)
2830
+ node.children.append(method)
2831
+ else:
2832
+ self.error(f"Expected 'define' or function after modifiers in class: {modifiers}")
2833
+
2323
2834
  # Check for constr keyword (constructor declaration)
2324
2835
  # Syntax: constr ConstructorName() { ... }
2325
2836
  # or: constr ConstructorName() : extends Parent::ConstructorName { ... }
2837
+ # v4.8.8: Also supports: secure constr Name(), callable constr Name()
2326
2838
  elif self._match_keyword('constr'):
2327
- constructor = self._parse_constructor(class_name)
2839
+ constructor = self._parse_constructor(class_name, modifiers=[])
2328
2840
  node.children.append(constructor)
2841
+ # v4.8.8: Check for secure/callable modifiers before constr
2842
+ elif self._match_keyword('secure') or self._match_keyword('callable'):
2843
+ constr_modifier = self.tokens[self.pos - 1].value # 'secure' or 'callable'
2844
+ if self._match_keyword('constr'):
2845
+ constructor = self._parse_constructor(class_name, modifiers=[constr_modifier])
2846
+ node.children.append(constructor)
2847
+ else:
2848
+ self.error(f"Expected 'constr' after '{constr_modifier}'")
2329
2849
 
2330
2850
  else:
2331
2851
  self._advance()
@@ -2333,24 +2853,40 @@ class CSSLParser:
2333
2853
  self._expect(TokenType.BLOCK_END)
2334
2854
  return node
2335
2855
 
2336
- def _parse_constructor(self, class_name: str) -> ASTNode:
2337
- """Parse constructor declaration inside a class.
2856
+ def _parse_constructor(self, class_name: str, modifiers: list = None) -> ASTNode:
2857
+ """Parse constructor or destructor declaration inside a class.
2338
2858
 
2339
2859
  Syntax:
2340
2860
  constr ConstructorName() { ... }
2861
+ constr ~ClassName() { ... } // v4.8.8: Destructor (cleanup code)
2341
2862
  constr ConstructorName() ++ { ... } // Append: keeps parent constructor + adds new code
2342
2863
  constr ConstructorName() &ParentClass::constructors ++ { ... } // Append specific parent constructor
2343
2864
  constr ConstructorName() : extends ParentClass::ConstructorName { ... }
2344
2865
  constr ConstructorName() : extends ParentClass::ConstructorName : overwrites ParentClass::ConstructorName { ... }
2345
2866
 
2867
+ v4.8.8 Modifiers:
2868
+ secure constr Name() { ... } - Only runs on exception in class
2869
+ callable constr Name() { ... } - Must be manually called, not auto-run
2870
+
2346
2871
  The ++ operator means: execute parent's version first, then execute this code (append mode).
2347
2872
  The &ClassName::member syntax references a specific member from the overwritten class.
2873
+ Destructor (~Name) is called when instance is deleted or goes out of scope.
2348
2874
  """
2349
- # Get constructor name
2875
+ modifiers = modifiers or []
2876
+ # v4.8.8: Check for destructor prefix ~
2877
+ is_destructor = False
2878
+ if self._match(TokenType.TILDE): # ~ operator for destructors
2879
+ is_destructor = True
2880
+
2881
+ # Get constructor/destructor name
2350
2882
  if not self._check(TokenType.IDENTIFIER):
2351
- raise CSSLSyntaxError("Expected constructor name after 'constr'")
2883
+ raise CSSLSyntaxError("Expected constructor name after 'constr'" + (" ~" if is_destructor else ""))
2352
2884
  constr_name = self._advance().value
2353
2885
 
2886
+ # v4.8.8: Destructor name should match class name
2887
+ if is_destructor:
2888
+ constr_name = f"~{constr_name}" # Store with ~ prefix
2889
+
2354
2890
  # Parse method-level extends/overwrites with :: syntax
2355
2891
  extends_target = None
2356
2892
  extends_class_ref = None
@@ -2432,7 +2968,10 @@ class CSSLParser:
2432
2968
  'name': constr_name,
2433
2969
  'class_name': class_name,
2434
2970
  'params': params,
2435
- 'is_constructor': True,
2971
+ 'is_constructor': not is_destructor, # v4.8.8: False for destructors
2972
+ 'is_destructor': is_destructor, # v4.8.8: True for ~Name()
2973
+ 'is_secure': 'secure' in modifiers, # v4.8.8: Only run on exception
2974
+ 'is_callable': 'callable' in modifiers, # v4.8.8: Manual call only
2436
2975
  'extends_target': extends_target,
2437
2976
  'extends_class': extends_class_ref,
2438
2977
  'extends_method': extends_method_ref,
@@ -2565,7 +3104,9 @@ class CSSLParser:
2565
3104
  if self._match_keyword('open'):
2566
3105
  param_info['open'] = True
2567
3106
  # Handle type annotations (e.g., string, int, dynamic, etc.)
2568
- if self._check(TokenType.KEYWORD):
3107
+ # v4.9.2: Also handle TYPE_LITERAL (dict, list) which are tokenized differently
3108
+ if (self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or \
3109
+ self._check(TokenType.TYPE_LITERAL):
2569
3110
  param_info['type'] = self._advance().value
2570
3111
  # Handle reference operator &
2571
3112
  if self._match(TokenType.AMPERSAND):
@@ -2613,6 +3154,7 @@ class CSSLParser:
2613
3154
  overwrites_class_ref = None
2614
3155
  overwrites_method_ref = None
2615
3156
  supports_language = None # v4.1.0: Multi-language syntax support
3157
+ uses_memory = None # v4.9.0: Memory binding for deferred execution
2616
3158
 
2617
3159
  if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
2618
3160
  # Parse extends and/or overwrites (supports :: method-level syntax)
@@ -2685,6 +3227,16 @@ class CSSLParser:
2685
3227
  supports_language = self._advance().value
2686
3228
  else:
2687
3229
  raise CSSLSyntaxError("Expected language identifier after 'supports'")
3230
+ # v4.9.0: Parse 'uses' keyword for memory binding (deferred execution)
3231
+ # Syntax: define func() : uses memory(address) { }
3232
+ elif self._match_keyword('uses'):
3233
+ if (self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD)) and self._current().value == 'memory':
3234
+ self._advance() # consume 'memory'
3235
+ self._expect(TokenType.PAREN_START)
3236
+ uses_memory = self._parse_expression() # Parse the address expression
3237
+ self._expect(TokenType.PAREN_END)
3238
+ else:
3239
+ raise CSSLSyntaxError("Expected 'memory(address)' after 'uses'")
2688
3240
  else:
2689
3241
  break
2690
3242
  # Check for another :: or : for chaining extends/overwrites
@@ -2696,22 +3248,54 @@ class CSSLParser:
2696
3248
  append_mode = False
2697
3249
  append_ref_class = None
2698
3250
  append_ref_member = None
3251
+ append_position = None # v4.9.2: Optional position for hook placement (e.g., &name[-1])
2699
3252
 
2700
- # Check for &ClassName::member reference
3253
+ # Check for &ClassName::member or &builtinName reference
3254
+ # v4.9.2: Support &builtinName ++ for hooking into builtin functions
2701
3255
  if self._match(TokenType.AMPERSAND):
2702
3256
  if self._check(TokenType.IDENTIFIER):
2703
- append_ref_class = self._advance().value
3257
+ ref_name = self._advance().value
3258
+ elif self._check(TokenType.KEYWORD):
3259
+ # v4.9.2: Allow keywords as function names (e.g., &reflect, &address)
3260
+ ref_name = self._advance().value
2704
3261
  elif self._check(TokenType.SHARED_REF):
2705
- append_ref_class = f'${self._advance().value}'
3262
+ ref_name = f'${self._advance().value}'
3263
+ elif self._check(TokenType.AT):
3264
+ # &@globalFunc reference
3265
+ self._advance() # consume @
3266
+ if self._check(TokenType.IDENTIFIER):
3267
+ ref_name = '@' + self._advance().value
3268
+ else:
3269
+ raise CSSLSyntaxError("Expected identifier after '&@'")
3270
+ elif self._check(TokenType.TYPE_LITERAL):
3271
+ # v4.9.2: Allow type literals as function names (dict, list)
3272
+ ref_name = self._advance().value
2706
3273
  else:
2707
- raise CSSLSyntaxError("Expected class name after '&' in function reference")
3274
+ # Debug: show what token we got
3275
+ cur = self._current()
3276
+ raise CSSLSyntaxError(f"Expected function/class name after '&' in function reference, got {cur.type.name}='{cur.value}'")
2708
3277
 
2709
- # Check for ::member
3278
+ # Check for ::member (class method reference)
2710
3279
  if self._match(TokenType.DOUBLE_COLON):
3280
+ # It's a class::member reference
3281
+ append_ref_class = ref_name
2711
3282
  if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
2712
3283
  append_ref_member = self._advance().value
2713
3284
  else:
2714
3285
  raise CSSLSyntaxError("Expected member name after '::' in function reference")
3286
+ else:
3287
+ # v4.9.2: No ::, it's a builtin function reference like &reflect
3288
+ # Store as special builtin reference (class=None, member=builtinName)
3289
+ append_ref_class = '__builtins__'
3290
+ append_ref_member = ref_name
3291
+
3292
+ # v4.9.2: Check for position syntax [index] (e.g., &name[-1] to place hook before last statement)
3293
+ if self._match(TokenType.BRACKET_START):
3294
+ # Parse the position expression (usually a number, can be negative)
3295
+ pos_expr = self._parse_expression()
3296
+ self._expect(TokenType.BRACKET_END)
3297
+ # Store the position expression - will be evaluated at runtime
3298
+ append_position = pos_expr
2715
3299
 
2716
3300
  # Check for ++ append operator
2717
3301
  if self._match(TokenType.PLUS_PLUS):
@@ -2740,6 +3324,9 @@ class CSSLParser:
2740
3324
  if supports_language:
2741
3325
  raw_body = self._extract_raw_block_body()
2742
3326
  # _extract_raw_block_body positions cursor at BLOCK_END
3327
+ # v4.7: Special parsing for bytearrayed functions
3328
+ elif modifiers and 'bytearrayed' in modifiers:
3329
+ children = self._parse_bytearrayed_body()
2743
3330
  else:
2744
3331
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2745
3332
  stmt = self._parse_statement()
@@ -2769,12 +3356,15 @@ class CSSLParser:
2769
3356
  'append_mode': append_mode,
2770
3357
  'append_ref_class': append_ref_class,
2771
3358
  'append_ref_member': append_ref_member,
3359
+ 'append_position': append_position, # v4.9.2: Position for hook placement
2772
3360
  # v4.1.0: Multi-language support
2773
3361
  'supports_language': supports_language,
2774
3362
  # v4.2.0: Raw body for language transformation
2775
3363
  'raw_body': raw_body,
2776
3364
  # v4.5.1: Function modifiers (private, const, static, etc.)
2777
- 'modifiers': modifiers or []
3365
+ 'modifiers': modifiers or [],
3366
+ # v4.9.0: Memory binding for deferred execution
3367
+ 'uses_memory': uses_memory
2778
3368
  }, children=children)
2779
3369
 
2780
3370
  return node
@@ -2801,16 +3391,38 @@ class CSSLParser:
2801
3391
  # v4.5.1: Add throw statement parsing
2802
3392
  elif self._match_keyword('throw'):
2803
3393
  return self._parse_throw()
3394
+ # v4.8: Add raise statement (Python-style: raise ExceptionType("message"))
3395
+ elif self._match_keyword('raise'):
3396
+ return self._parse_raise()
2804
3397
  elif self._match_keyword('try'):
2805
3398
  return self._parse_try()
2806
3399
  elif self._match_keyword('await'):
2807
3400
  return self._parse_await()
3401
+ elif self._match_keyword('yield'):
3402
+ return self._parse_yield()
2808
3403
  elif self._match_keyword('supports'):
2809
3404
  # v4.2.0: Standalone supports block for multi-language syntax
2810
3405
  return self._parse_supports_block()
2811
3406
  elif self._match_keyword('define'):
2812
3407
  # Nested define function
2813
3408
  return self._parse_define()
3409
+ elif self._match_keyword('global'):
3410
+ # v4.9.2: Global variable inside function: global int x = 1; or global x = 1;
3411
+ if self._looks_like_typed_variable():
3412
+ # global type varName = value;
3413
+ typed_node = self._parse_typed_variable()
3414
+ if typed_node and typed_node.type == 'typed_declaration':
3415
+ # Add 'global' to modifiers
3416
+ modifiers = typed_node.value.get('modifiers', [])
3417
+ modifiers.append('global')
3418
+ typed_node.value['modifiers'] = modifiers
3419
+ return typed_node
3420
+ else:
3421
+ # global varName = value; (dynamic type)
3422
+ stmt = self._parse_expression_statement()
3423
+ if stmt:
3424
+ return ASTNode('global_assignment', value=stmt)
3425
+ return None
2814
3426
  elif self._looks_like_typed_variable():
2815
3427
  # Typed variable declaration (e.g., stack<string> myStack;)
2816
3428
  return self._parse_typed_variable()
@@ -2826,11 +3438,15 @@ class CSSLParser:
2826
3438
  # super() or super::method() call - calls parent constructor/method
2827
3439
  return self._parse_super_call()
2828
3440
  # v4.2.1: Added LANG_INSTANCE_REF for lang$instance statements
3441
+ # v4.9.0: Allow KEYWORD tokens followed by ( to be treated as function calls (memory, uses, etc.)
3442
+ # v4.9.0: Added POINTER_REF for ?name = value pointer assignments
2829
3443
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
2830
3444
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
3445
+ self._check(TokenType.POINTER_REF) or
2831
3446
  self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
2832
3447
  self._check(TokenType.LANG_INSTANCE_REF) or
2833
3448
  (self._check(TokenType.KEYWORD) and self._current().value in ('this', 'new')) or
3449
+ (self._check(TokenType.KEYWORD) and self._peek(1) and self._peek(1).type == TokenType.PAREN_START) or
2834
3450
  self._looks_like_namespace_call()):
2835
3451
  return self._parse_expression_statement()
2836
3452
  else:
@@ -3539,12 +4155,83 @@ class CSSLParser:
3539
4155
  self._match(TokenType.SEMICOLON)
3540
4156
  return ASTNode('throw', value=expr)
3541
4157
 
4158
+ def _parse_raise(self) -> ASTNode:
4159
+ """Parse raise statement (Python-style exceptions).
4160
+
4161
+ v4.8: Added raise statement for Python-style exception raising.
4162
+
4163
+ Syntax:
4164
+ raise; # Re-raise current exception
4165
+ raise "Error message"; # Simple message
4166
+ raise ValueError("message"); # Python exception type
4167
+ raise CustomError("msg", code); # Custom exception with args
4168
+
4169
+ Supported Python exception types:
4170
+ ValueError, TypeError, KeyError, IndexError, AttributeError,
4171
+ RuntimeError, IOError, OSError, FileNotFoundError, NameError,
4172
+ ZeroDivisionError, OverflowError, StopIteration, AssertionError
4173
+ """
4174
+ # Check for re-raise (just raise;)
4175
+ if self._check(TokenType.SEMICOLON):
4176
+ self._advance()
4177
+ return ASTNode('raise', value={'type': None, 'message': None})
4178
+
4179
+ # Get the exception expression
4180
+ # This could be: "message", ExceptionType("message"), or variable
4181
+ expr = self._parse_expression()
4182
+
4183
+ self._match(TokenType.SEMICOLON)
4184
+
4185
+ # Check if it's a function call (ExceptionType("message"))
4186
+ if isinstance(expr, ASTNode) and expr.type == 'call':
4187
+ callee = expr.value.get('callee')
4188
+ args = expr.value.get('args', [])
4189
+ if isinstance(callee, ASTNode) and callee.type == 'identifier':
4190
+ exc_type = callee.value
4191
+ return ASTNode('raise', value={
4192
+ 'type': exc_type,
4193
+ 'args': args
4194
+ })
4195
+
4196
+ # Simple expression (string or variable)
4197
+ return ASTNode('raise', value={
4198
+ 'type': 'Error', # Default exception type
4199
+ 'message': expr
4200
+ })
4201
+
3542
4202
  def _parse_await(self) -> ASTNode:
3543
4203
  """Parse await statement: await expression;"""
3544
4204
  expr = self._parse_expression()
3545
4205
  self._match(TokenType.SEMICOLON)
3546
4206
  return ASTNode('await', value=expr)
3547
4207
 
4208
+ def _parse_yield(self) -> ASTNode:
4209
+ """Parse yield statement: yield expression; or yield;
4210
+
4211
+ v4.9.3: Generator yield statement for lazy iteration.
4212
+
4213
+ Syntax:
4214
+ yield value; // Yield a value and pause
4215
+ yield; // Yield None and pause
4216
+
4217
+ Example:
4218
+ generator<int> define CountUp(int limit) {
4219
+ int i = 0;
4220
+ while (i < limit) {
4221
+ yield i;
4222
+ i = i + 1;
4223
+ }
4224
+ }
4225
+ """
4226
+ # Check for yield with no value (yield;)
4227
+ if self._check(TokenType.SEMICOLON):
4228
+ self._advance()
4229
+ return ASTNode('yield', value=None)
4230
+
4231
+ expr = self._parse_expression()
4232
+ self._match(TokenType.SEMICOLON)
4233
+ return ASTNode('yield', value=expr)
4234
+
3548
4235
  def _parse_supports_block(self) -> ASTNode:
3549
4236
  """Parse standalone supports block for multi-language syntax.
3550
4237
 
@@ -3722,6 +4409,66 @@ class CSSLParser:
3722
4409
  self._expect(TokenType.BLOCK_END)
3723
4410
  return node
3724
4411
 
4412
+ def _parse_local_injection(self, local_node: ASTNode) -> ASTNode:
4413
+ """Parse local::func injection operations.
4414
+
4415
+ Syntax:
4416
+ local::func -<<== { code } // Remove matching code
4417
+ local::func +<<== { code } // Add code
4418
+ local::func -<<==[injection::innerline(3)] null; // Remove specific line
4419
+ local::func +<<==[injection::innerline(3)] code; // Add at specific line
4420
+
4421
+ Args:
4422
+ local_node: The local_ref ASTNode (e.g., local::func)
4423
+
4424
+ Returns:
4425
+ ASTNode for the local injection operation
4426
+ """
4427
+ local_name = local_node.value
4428
+
4429
+ # Determine injection mode
4430
+ mode = None
4431
+ if self._match(TokenType.INFUSE_MINUS_LEFT):
4432
+ mode = 'remove'
4433
+ elif self._match(TokenType.INFUSE_PLUS_LEFT):
4434
+ mode = 'add'
4435
+ elif self._match(TokenType.INFUSE_LEFT):
4436
+ mode = 'replace'
4437
+ else:
4438
+ raise CSSLSyntaxError("Expected -<<==, +<<==, or <<== after local::func")
4439
+
4440
+ # Parse optional filter: [injection::innerline(n)]
4441
+ filters = self._parse_injection_filter()
4442
+
4443
+ # Parse the value/code block
4444
+ code_block = None
4445
+ if self._check(TokenType.BLOCK_START):
4446
+ # Block form: local::func +<<== { code }
4447
+ self._advance()
4448
+ children = []
4449
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
4450
+ if self._check(TokenType.NEWLINE):
4451
+ self._advance()
4452
+ continue
4453
+ stmt = self._parse_statement()
4454
+ if stmt:
4455
+ children.append(stmt)
4456
+ self._expect(TokenType.BLOCK_END)
4457
+ code_block = ASTNode('block', children=children)
4458
+ elif self._match_keyword('null') or self._match_keyword('None'):
4459
+ # null; for removal without replacement
4460
+ code_block = None
4461
+ else:
4462
+ # Expression form: local::func +<<== expression;
4463
+ code_block = self._parse_expression()
4464
+
4465
+ return ASTNode('local_injection', value={
4466
+ 'target': local_name,
4467
+ 'mode': mode,
4468
+ 'filters': filters,
4469
+ 'code': code_block
4470
+ }, line=local_node.line, column=local_node.column)
4471
+
3725
4472
  def _parse_injection_filter(self) -> Optional[list]:
3726
4473
  """Parse injection filter(s): [type::helper=value] or [f1][f2][f3]...
3727
4474
 
@@ -3969,6 +4716,16 @@ class CSSLParser:
3969
4716
  elif self._match(TokenType.COMPARE_GE):
3970
4717
  right = self._parse_term()
3971
4718
  left = ASTNode('binary', value={'op': '>=', 'left': left, 'right': right})
4719
+ elif self._check(TokenType.KEYWORD) and self._peek().value == 'not':
4720
+ # Check for 'not in' compound operator: item not in list
4721
+ next_tok = self._peek(1)
4722
+ if next_tok and next_tok.type == TokenType.KEYWORD and next_tok.value == 'in':
4723
+ self._advance() # consume 'not'
4724
+ self._advance() # consume 'in'
4725
+ right = self._parse_term()
4726
+ left = ASTNode('binary', value={'op': 'not in', 'left': left, 'right': right})
4727
+ else:
4728
+ break
3972
4729
  elif self._check(TokenType.KEYWORD) and self._peek().value == 'in':
3973
4730
  # 'in' operator for containment: item in list
3974
4731
  self._advance() # consume 'in'
@@ -4016,6 +4773,10 @@ class CSSLParser:
4016
4773
  if self._match(TokenType.NOT) or self._match_keyword('not'):
4017
4774
  operand = self._parse_unary()
4018
4775
  return ASTNode('unary', value={'op': 'not', 'operand': operand})
4776
+ # v4.9.3: await as unary prefix for expressions
4777
+ if self._match_keyword('await'):
4778
+ operand = self._parse_unary()
4779
+ return ASTNode('await', value=operand)
4019
4780
  if self._match(TokenType.MINUS):
4020
4781
  operand = self._parse_unary()
4021
4782
  return ASTNode('unary', value={'op': '-', 'operand': operand})
@@ -4034,9 +4795,18 @@ class CSSLParser:
4034
4795
 
4035
4796
  # Non-null assertion: *$var, *@module, *identifier
4036
4797
  # Also type exclusion filter: *[type]expr - exclude type from return
4798
+ # v4.9.0: Pointer syntax: *<expr> to get address
4037
4799
  if self._check(TokenType.MULTIPLY):
4038
4800
  next_token = self._peek(1)
4039
4801
 
4802
+ # v4.9.0: Pointer address: *<expr> - get address of expression
4803
+ if next_token and next_token.type == TokenType.COMPARE_LT:
4804
+ self._advance() # consume *
4805
+ self._advance() # consume <
4806
+ operand = self._parse_expression()
4807
+ self._expect(TokenType.COMPARE_GT) # expect >
4808
+ return ASTNode('pointer_address', value={'operand': operand})
4809
+
4040
4810
  # Check for type exclusion filter: *[string], *[int], etc.
4041
4811
  if next_token and next_token.type == TokenType.BRACKET_START:
4042
4812
  self._advance() # consume *
@@ -4084,6 +4854,29 @@ class CSSLParser:
4084
4854
  else:
4085
4855
  break
4086
4856
  return node
4857
+ # v4.7: Handle this.member syntax (using DOT instead of ->)
4858
+ elif self._match(TokenType.DOT):
4859
+ member = self._advance().value
4860
+ node = ASTNode('member_access', value={
4861
+ 'object': ASTNode('identifier', value='this'),
4862
+ 'member': member
4863
+ })
4864
+ # Continue to check for chained calls, member access, indexing
4865
+ while True:
4866
+ if self._match(TokenType.PAREN_START):
4867
+ args, kwargs = self._parse_call_arguments()
4868
+ self._expect(TokenType.PAREN_END)
4869
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
4870
+ elif self._match(TokenType.DOT):
4871
+ member = self._advance().value
4872
+ node = ASTNode('member_access', value={'object': node, 'member': member})
4873
+ elif self._match(TokenType.BRACKET_START):
4874
+ index = self._parse_expression()
4875
+ self._expect(TokenType.BRACKET_END)
4876
+ node = ASTNode('index_access', value={'object': node, 'index': index})
4877
+ else:
4878
+ break
4879
+ return node
4087
4880
  else:
4088
4881
  # Just 'this' keyword alone - return as identifier for now
4089
4882
  return ASTNode('identifier', value='this')
@@ -4237,6 +5030,58 @@ class CSSLParser:
4237
5030
  break
4238
5031
  return node
4239
5032
 
5033
+ # v4.9.0: Pointer reference: ?name (dereferences pointer)
5034
+ if self._check(TokenType.POINTER_REF):
5035
+ token = self._advance()
5036
+ node = ASTNode('pointer_ref', value=token.value, line=token.line, column=token.column)
5037
+ # Check for member access, calls, indexing
5038
+ while True:
5039
+ if self._match(TokenType.PAREN_START):
5040
+ args, kwargs = self._parse_call_arguments()
5041
+ self._expect(TokenType.PAREN_END)
5042
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
5043
+ elif self._match(TokenType.DOT) or self._match(TokenType.FLOW_RIGHT):
5044
+ member = self._advance().value
5045
+ node = ASTNode('member_access', value={'object': node, 'member': member})
5046
+ elif self._match(TokenType.BRACKET_START):
5047
+ index = self._parse_expression()
5048
+ self._expect(TokenType.BRACKET_END)
5049
+ node = ASTNode('index_access', value={'object': node, 'index': index})
5050
+ else:
5051
+ break
5052
+ return node
5053
+
5054
+ # v4.9.2: Local reference for hook variable access: local::varname, local::func
5055
+ if self._check(TokenType.LOCAL_REF):
5056
+ token = self._advance()
5057
+ local_name = token.value # The local variable/function name
5058
+ node = ASTNode('local_ref', value=local_name, line=token.line, column=token.column)
5059
+ # Check for injection operations on local::func
5060
+ if self._check(TokenType.INFUSE_MINUS_LEFT) or self._check(TokenType.INFUSE_PLUS_LEFT) or \
5061
+ self._check(TokenType.INFUSE_LEFT):
5062
+ # local::func -<<== {...} or local::func +<<== {...}
5063
+ return self._parse_local_injection(node)
5064
+ # Check for assignment: local::varname = value
5065
+ if self._match(TokenType.EQUALS):
5066
+ value = self._parse_expression()
5067
+ return ASTNode('local_assign', value={'name': local_name, 'value': value})
5068
+ # Check for member access, calls, indexing
5069
+ while True:
5070
+ if self._match(TokenType.PAREN_START):
5071
+ args, kwargs = self._parse_call_arguments()
5072
+ self._expect(TokenType.PAREN_END)
5073
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
5074
+ elif self._match(TokenType.DOT) or self._match(TokenType.FLOW_RIGHT):
5075
+ member = self._advance().value
5076
+ node = ASTNode('member_access', value={'object': node, 'member': member})
5077
+ elif self._match(TokenType.BRACKET_START):
5078
+ index = self._parse_expression()
5079
+ self._expect(TokenType.BRACKET_END)
5080
+ node = ASTNode('index_access', value={'object': node, 'index': index})
5081
+ else:
5082
+ break
5083
+ return node
5084
+
4240
5085
  # v4.1.0: Cross-language instance reference: cpp$ClassName, py$Object
4241
5086
  if self._check(TokenType.LANG_INSTANCE_REF):
4242
5087
  token = self._advance()
@@ -4261,7 +5106,20 @@ class CSSLParser:
4261
5106
  return node
4262
5107
 
4263
5108
  if self._check(TokenType.NUMBER):
4264
- return ASTNode('literal', value=self._advance().value)
5109
+ num_token = self._advance()
5110
+ num_value = num_token.value
5111
+ # v4.9.0: Check for byte notation x^y (0^102, 1^250)
5112
+ if self._check(TokenType.CARET):
5113
+ self._advance() # consume ^
5114
+ if not self._check(TokenType.NUMBER):
5115
+ raise CSSLSyntaxError("Expected number after '^' in byte literal", num_token.line)
5116
+ weight = self._advance().value
5117
+ if num_value not in (0, 1):
5118
+ raise CSSLSyntaxError(f"Byte base must be 0 or 1, got {num_value}", num_token.line)
5119
+ if not (0 <= weight <= 255):
5120
+ raise CSSLSyntaxError(f"Byte weight must be 0-255, got {weight}", num_token.line)
5121
+ return ASTNode('byte_literal', value={'base': num_value, 'weight': weight})
5122
+ return ASTNode('literal', value=num_value)
4265
5123
 
4266
5124
  if self._check(TokenType.STRING):
4267
5125
  return ASTNode('literal', value=self._advance().value)
@@ -4279,16 +5137,66 @@ class CSSLParser:
4279
5137
  return ASTNode('type_literal', value=type_name)
4280
5138
 
4281
5139
  if self._match(TokenType.PAREN_START):
4282
- expr = self._parse_expression()
4283
- self._expect(TokenType.PAREN_END)
4284
- return expr
5140
+ # v4.8.9: Check for typed expression: (type name = value)
5141
+ # This creates a typed variable and returns its value
5142
+ # Used with snapshot assignment: %xyz = (int number = 200)
5143
+ saved_pos = self.pos
5144
+ is_typed_expr = False
5145
+
5146
+ # Check pattern: type identifier =
5147
+ if ((self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value)) or
5148
+ self._check(TokenType.IDENTIFIER)):
5149
+ potential_type = self._current().value
5150
+ self._advance() # consume type
5151
+
5152
+ # Check for generic type like vector<int>
5153
+ if self._check(TokenType.COMPARE_LT):
5154
+ self._advance() # consume <
5155
+ self._parse_generic_type_content() # consume generic content
5156
+ potential_type += '<...>' # mark as generic
5157
+
5158
+ if self._check(TokenType.IDENTIFIER):
5159
+ var_name = self._advance().value
5160
+ if self._check(TokenType.EQUALS):
5161
+ # This is a typed expression!
5162
+ is_typed_expr = True
5163
+ self._advance() # consume =
5164
+ value = self._parse_expression()
5165
+ self._expect(TokenType.PAREN_END)
5166
+ return ASTNode('typed_expression', value={
5167
+ 'type': potential_type.replace('<...>', ''), # clean generic marker
5168
+ 'name': var_name,
5169
+ 'value': value
5170
+ })
5171
+
5172
+ # Not a typed expression, restore position and parse normally
5173
+ if not is_typed_expr:
5174
+ self.pos = saved_pos
5175
+ expr = self._parse_expression()
5176
+ # v4.9.2: Check for tuple literal (expr, expr, ...)
5177
+ if self._check(TokenType.COMMA):
5178
+ # This is a tuple - collect all elements
5179
+ elements = [expr]
5180
+ while self._match(TokenType.COMMA):
5181
+ if self._check(TokenType.PAREN_END):
5182
+ # Trailing comma allowed: (a, b,)
5183
+ break
5184
+ elements.append(self._parse_expression())
5185
+ self._expect(TokenType.PAREN_END)
5186
+ return ASTNode('tuple', value=elements)
5187
+ self._expect(TokenType.PAREN_END)
5188
+ return expr
4285
5189
 
4286
5190
  if self._match(TokenType.BLOCK_START):
4287
- # Distinguish between object literal { key = value } and action block { expr; }
4288
- # Object literal: starts with IDENTIFIER = or STRING =
4289
- # Action block: starts with expression (captured_ref, call, literal, etc.)
5191
+ # Distinguish between:
5192
+ # 1. Object literal { key = value } - for dict-like initialization
5193
+ # 2. Array literal { 1, 2, 3 } - for vector/array initialization (v4.9.2)
5194
+ # 3. Action block { expr; } - for code blocks that return last value
4290
5195
  if self._is_object_literal():
4291
5196
  return self._parse_object()
5197
+ elif self._is_array_literal():
5198
+ # v4.9.2: Parse as array for vector<T> i = { 1, 2, 3 } initialization
5199
+ return self._parse_brace_array()
4292
5200
  else:
4293
5201
  return self._parse_action_block_expression()
4294
5202
 
@@ -4367,11 +5275,14 @@ class CSSLParser:
4367
5275
  def _parse_identifier_or_call(self) -> ASTNode:
4368
5276
  name = self._advance().value
4369
5277
 
4370
- # Check for namespace syntax: json::read, string::cut, etc.
4371
- if self._match(TokenType.DOUBLE_COLON):
5278
+ # Check for namespace syntax: json::read, string::cut, namespace::inner::func, etc.
5279
+ # v4.8: Support multiple levels of :: for nested namespace access
5280
+ while self._match(TokenType.DOUBLE_COLON):
4372
5281
  if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
4373
5282
  namespace_member = self._advance().value
4374
5283
  name = f"{name}::{namespace_member}"
5284
+ else:
5285
+ break
4375
5286
 
4376
5287
  # Check for instance<"name"> syntax - gets/creates shared instance
4377
5288
  if name == 'instance' and self._check(TokenType.COMPARE_LT):
@@ -4392,6 +5303,7 @@ class CSSLParser:
4392
5303
  self._advance() # consume <
4393
5304
  element_type = 'dynamic'
4394
5305
  value_type = None # For map<K, V>
5306
+ queue_size = 'dynamic' # v4.7: For queue<T, size>
4395
5307
 
4396
5308
  if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
4397
5309
  element_type = self._advance().value
@@ -4404,6 +5316,20 @@ class CSSLParser:
4404
5316
  else:
4405
5317
  value_type = 'dynamic'
4406
5318
 
5319
+ # v4.7: Check for second parameter for queue<T, size>
5320
+ if name == 'queue' and self._check(TokenType.COMMA):
5321
+ self._advance() # consume ,
5322
+ if self._check(TokenType.NUMBER):
5323
+ queue_size = int(self._advance().value)
5324
+ elif self._check(TokenType.KEYWORD) and self._current().value == 'dynamic':
5325
+ self._advance() # consume 'dynamic'
5326
+ queue_size = 'dynamic'
5327
+ elif self._check(TokenType.IDENTIFIER) and self._current().value == 'dynamic':
5328
+ self._advance() # consume 'dynamic'
5329
+ queue_size = 'dynamic'
5330
+ else:
5331
+ queue_size = 'dynamic'
5332
+
4407
5333
  self._expect(TokenType.COMPARE_GT) # consume >
4408
5334
 
4409
5335
  # Check for inline initialization: map<K,V>{"key": "value", ...}
@@ -4455,6 +5381,7 @@ class CSSLParser:
4455
5381
  'type': name,
4456
5382
  'element_type': element_type,
4457
5383
  'value_type': value_type,
5384
+ 'queue_size': queue_size, # v4.7: For queue<T, size>
4458
5385
  'init_values': init_values
4459
5386
  })
4460
5387
 
@@ -4500,7 +5427,8 @@ class CSSLParser:
4500
5427
  node = ASTNode('identifier', value=name)
4501
5428
 
4502
5429
  while True:
4503
- if self._match(TokenType.DOT):
5430
+ # v4.8.5: Support both . and -> for member access (C++ style)
5431
+ if self._match(TokenType.DOT) or self._match(TokenType.FLOW_RIGHT):
4504
5432
  member = self._advance().value
4505
5433
  node = ASTNode('member_access', value={'object': node, 'member': member})
4506
5434
  elif self._match(TokenType.PAREN_START):
@@ -4547,6 +5475,74 @@ class CSSLParser:
4547
5475
  self.pos = saved_pos
4548
5476
  return is_object
4549
5477
 
5478
+ def _is_array_literal(self) -> bool:
5479
+ """Check if current position is an array literal { 1, 2, 3 } for vector/array initialization.
5480
+
5481
+ v4.9.2: Array literal: { value, value, ... } - comma-separated values
5482
+ NOT array literal: { expr; } - semicolon-separated (action block)
5483
+ """
5484
+ # Empty block is not array literal
5485
+ if self._check(TokenType.BLOCK_END):
5486
+ return False
5487
+
5488
+ # Save position for lookahead
5489
+ saved_pos = self.pos
5490
+
5491
+ is_array = False
5492
+ # Try to parse first expression and check if followed by comma
5493
+ try:
5494
+ # Check for simple value followed by comma
5495
+ if (self._check(TokenType.NUMBER) or self._check(TokenType.STRING) or
5496
+ self._check(TokenType.BOOLEAN) or self._check(TokenType.IDENTIFIER) or
5497
+ self._check(TokenType.BRACKET_START) or self._check(TokenType.PAREN_START)):
5498
+ # Skip the first value (could be simple or complex)
5499
+ depth = 0
5500
+ while not self._is_at_end():
5501
+ if self._check(TokenType.PAREN_START) or self._check(TokenType.BRACKET_START) or self._check(TokenType.BLOCK_START):
5502
+ depth += 1
5503
+ self._advance()
5504
+ elif self._check(TokenType.PAREN_END) or self._check(TokenType.BRACKET_END) or self._check(TokenType.BLOCK_END):
5505
+ if depth > 0:
5506
+ depth -= 1
5507
+ self._advance()
5508
+ else:
5509
+ break
5510
+ elif self._check(TokenType.COMMA) and depth == 0:
5511
+ # Found comma at top level - this is an array literal
5512
+ is_array = True
5513
+ break
5514
+ elif self._check(TokenType.SEMICOLON) and depth == 0:
5515
+ # Found semicolon - this is an action block
5516
+ is_array = False
5517
+ break
5518
+ else:
5519
+ self._advance()
5520
+ except Exception:
5521
+ pass
5522
+
5523
+ # Restore position
5524
+ self.pos = saved_pos
5525
+ return is_array
5526
+
5527
+ def _parse_brace_array(self) -> ASTNode:
5528
+ """Parse brace-enclosed array literal { 1, 2, 3 } for vector/array initialization.
5529
+
5530
+ v4.9.2: Returns an 'array' node, same as [ 1, 2, 3 ] bracket arrays.
5531
+ """
5532
+ elements = []
5533
+
5534
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
5535
+ # Parse expression
5536
+ expr = self._parse_expression()
5537
+ elements.append(expr)
5538
+
5539
+ # Expect comma or end
5540
+ if not self._match(TokenType.COMMA):
5541
+ break
5542
+
5543
+ self._expect(TokenType.BLOCK_END)
5544
+ return ASTNode('array', value=elements)
5545
+
4550
5546
  def _parse_action_block_expression(self) -> ASTNode:
4551
5547
  """Parse an action block expression: { expr; expr2; } returns last value
4552
5548