IncludeCPP 3.8.8__py3-none-any.whl → 4.0.0__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.
@@ -110,6 +110,9 @@ class TokenType(Enum):
110
110
  EOF = auto()
111
111
  # Super-functions for .cssl-pl payload files (v3.8.0)
112
112
  SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
113
+ # Append operator for constructor/function extension
114
+ PLUS_PLUS = auto() # ++ for constructor/function append (keeps old + adds new)
115
+ MINUS_MINUS = auto() # -- for potential future use
113
116
 
114
117
 
115
118
  KEYWORDS = {
@@ -141,16 +144,25 @@ KEYWORDS = {
141
144
  'structure', # Advanced C++/Py Class
142
145
  'openquote', # SQL openquote container
143
146
  # CSSL Function Modifiers
147
+ 'const', # Immutable function (like C++)
144
148
  'meta', # Source function (must return)
145
149
  'super', # Force execution (no exceptions)
146
150
  'closed', # Protect from external injection
147
151
  'private', # Disable all injections
148
152
  'virtual', # Import cycle safe
149
153
  'sqlbased', # SQL-based function
154
+ 'public', # Explicitly public (default)
155
+ 'static', # Static method/function
150
156
  # CSSL Include Keywords
151
157
  'include', 'get',
152
158
  }
153
159
 
160
+ # Function modifiers that can appear in any order before function name
161
+ FUNCTION_MODIFIERS = {
162
+ 'undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual',
163
+ 'sqlbased', 'const', 'public', 'static', 'global', 'shuffled'
164
+ }
165
+
154
166
  # Type literals that create empty instances
155
167
  TYPE_LITERALS = {'list', 'dict'}
156
168
 
@@ -307,8 +319,13 @@ class CSSLLexer:
307
319
  self._add_token(TokenType.DOT, '.')
308
320
  self._advance()
309
321
  elif char == '+':
322
+ # Check for ++ (append operator for constructor/function extension)
323
+ if self._peek(1) == '+':
324
+ self._add_token(TokenType.PLUS_PLUS, '++')
325
+ self._advance()
326
+ self._advance()
310
327
  # Check for BruteForce Injection: +<== or +<<==
311
- if self._peek(1) == '<' and self._peek(2) == '<' and self._peek(3) == '=' and self._peek(4) == '=':
328
+ elif self._peek(1) == '<' and self._peek(2) == '<' and self._peek(3) == '=' and self._peek(4) == '=':
312
329
  self._add_token(TokenType.INFUSE_PLUS_LEFT, '+<<==')
313
330
  for _ in range(5): self._advance()
314
331
  elif self._peek(1) == '<' and self._peek(2) == '=' and self._peek(3) == '=':
@@ -711,7 +728,7 @@ class CSSLParser:
711
728
 
712
729
  def _is_function_modifier(self, value: str) -> bool:
713
730
  """Check if a keyword is a function modifier"""
714
- return value in ('undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual', 'sqlbased')
731
+ return value in FUNCTION_MODIFIERS
715
732
 
716
733
  def _is_type_keyword(self, value: str) -> bool:
717
734
  """Check if a keyword is a type declaration"""
@@ -722,53 +739,98 @@ class CSSLParser:
722
739
  def _looks_like_function_declaration(self) -> bool:
723
740
  """Check if current position looks like a C-style function declaration.
724
741
 
742
+ Supports flexible ordering of modifiers, types, non-null (*), and global (@):
743
+
725
744
  Patterns:
726
745
  - int funcName(...)
727
746
  - undefined int funcName(...)
728
747
  - vector<string> funcName(...)
729
748
  - undefined void funcName(...)
730
- - private super virtual meta FuncName(...) <- modifiers without return type
749
+ - private super virtual meta FuncName(...)
750
+ - private string *@Myfunc(...)
751
+ - const define myFunc(...)
752
+ - global private const void @Func(...)
753
+ - shuffled *[string] getNumbers(...)
754
+ - datastruct<dynamic> HelloCode(...)
755
+ - datastruct<dynamic> HelloCode() : extends @MyFunc { }
756
+
757
+ Distinguishes functions from variables:
758
+ - datastruct<dynamic> MyVar; <- variable (no () { })
759
+ - datastruct<dynamic> HelloCode() { } <- function (has () { })
731
760
  """
732
761
  saved_pos = self.pos
733
762
  has_modifiers = False
763
+ has_type = False
734
764
 
735
- # Skip modifiers (undefined, open, meta, super, closed, private, virtual)
736
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
737
- self._advance()
738
- has_modifiers = True
765
+ try:
766
+ # Skip modifiers in any order (global, private, const, undefined, etc.)
767
+ while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
768
+ self._advance()
769
+ has_modifiers = True
739
770
 
740
- # Check for type keyword (optional if modifiers present)
741
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
742
- self._advance()
771
+ # Check for 'define' keyword (special case: const define myFunc())
772
+ if self._check(TokenType.KEYWORD) and self._current().value == 'define':
773
+ self.pos = saved_pos
774
+ return False # Let _parse_define handle this
743
775
 
744
- # Skip generic type parameters <T>
745
- if self._check(TokenType.COMPARE_LT):
746
- depth = 1
776
+ # Check for type keyword (int, string, void, vector, datastruct, etc.)
777
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
747
778
  self._advance()
748
- while depth > 0 and not self._is_at_end():
749
- if self._check(TokenType.COMPARE_LT):
750
- depth += 1
751
- elif self._check(TokenType.COMPARE_GT):
752
- depth -= 1
779
+ has_type = True
780
+
781
+ # Skip generic type parameters <T> or <T, U>
782
+ if self._check(TokenType.COMPARE_LT):
783
+ depth = 1
753
784
  self._advance()
785
+ while depth > 0 and not self._is_at_end():
786
+ if self._check(TokenType.COMPARE_LT):
787
+ depth += 1
788
+ elif self._check(TokenType.COMPARE_GT):
789
+ depth -= 1
790
+ self._advance()
791
+
792
+ # Check for * prefix (non-null) or *[type] (type exclusion)
793
+ if self._check(TokenType.MULTIPLY):
794
+ self._advance()
795
+ # Check for type exclusion: *[string], *[int], etc.
796
+ if self._check(TokenType.BRACKET_START):
797
+ self._advance() # [
798
+ while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
799
+ self._advance()
800
+ if self._check(TokenType.BRACKET_END):
801
+ self._advance() # ]
754
802
 
755
- # Check for identifier followed by (
803
+ # Check for @ prefix (global function)
804
+ if self._check(TokenType.AT):
805
+ self._advance()
806
+
807
+ # Now we should be at the function name (identifier)
756
808
  if self._check(TokenType.IDENTIFIER):
757
809
  self._advance()
758
- is_func = self._check(TokenType.PAREN_START)
759
- self.pos = saved_pos
760
- return is_func
761
810
 
762
- # If we have modifiers and the next token is an identifier followed by (
763
- # This handles: private super virtual meta FuncName()
764
- elif has_modifiers and self._check(TokenType.IDENTIFIER):
765
- self._advance()
766
- is_func = self._check(TokenType.PAREN_START)
811
+ # Check if followed by (
812
+ # IMPORTANT: Only a function declaration if we have modifiers OR type
813
+ # Plain identifier() is a function CALL, not a declaration
814
+ if self._check(TokenType.PAREN_START):
815
+ if has_modifiers or has_type:
816
+ self.pos = saved_pos
817
+ return True
818
+ else:
819
+ # No modifiers/type = function call, not declaration
820
+ self.pos = saved_pos
821
+ return False
822
+
823
+ # If we have a type and identifier but no (, it's a variable
824
+ if has_type and not self._check(TokenType.PAREN_START):
825
+ self.pos = saved_pos
826
+ return False
827
+
767
828
  self.pos = saved_pos
768
- return is_func
829
+ return False
769
830
 
770
- self.pos = saved_pos
771
- return False
831
+ except Exception:
832
+ self.pos = saved_pos
833
+ return False
772
834
 
773
835
  def _looks_like_typed_variable(self) -> bool:
774
836
  """Check if current position looks like a typed variable declaration.
@@ -808,51 +870,110 @@ class CSSLParser:
808
870
  self.pos = saved_pos
809
871
  return False
810
872
 
811
- def _parse_typed_function(self) -> ASTNode:
812
- """Parse C-style typed function declaration.
873
+ def _parse_typed_function(self, is_global: bool = False) -> ASTNode:
874
+ """Parse C-style typed function declaration with flexible modifier ordering.
875
+
876
+ Supports any order of modifiers, types, non-null (*), and global (@):
813
877
 
814
878
  Patterns:
815
879
  - int Add(int a, int b) { }
880
+ - global int Add(int a, int b) { }
881
+ - int @Add(int a, int b) { }
816
882
  - undefined int Func() { }
817
883
  - open void Handler(open Params) { }
818
884
  - vector<string> GetNames() { }
885
+ - private string *@Myfunc() { }
886
+ - const define myFunc() { }
887
+ - global private const void @Func() { }
888
+ - shuffled *[string] getNumbers() { }
889
+ - datastruct<dynamic> HelloCode() { }
890
+ - meta datastruct<string> MyData() { } // meta allows any returns
891
+ - datastruct<dynamic> HelloCode() : extends @MyFunc { }
892
+
893
+ Typed functions (with return type like int, string, void) MUST return that type.
894
+ Functions with 'meta' modifier can return any type regardless of declaration.
895
+ Functions with 'define' are dynamic (any return type allowed).
819
896
  """
820
897
  modifiers = []
821
898
  return_type = None
822
899
  generic_type = None
900
+ non_null = False
901
+ exclude_type = None
902
+ is_const = False
903
+
904
+ # Phase 1: Collect all modifiers, type, non-null, and global indicators
905
+ # These can appear in any order before the function name
906
+
907
+ parsing_prefix = True
908
+ while parsing_prefix and not self._is_at_end():
909
+ # Check for modifiers (global, private, const, undefined, etc.)
910
+ if self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
911
+ mod = self._advance().value
912
+ if mod == 'global':
913
+ is_global = True
914
+ elif mod == 'const':
915
+ is_const = True
916
+ modifiers.append(mod)
917
+ else:
918
+ modifiers.append(mod)
919
+ continue
823
920
 
824
- # Collect modifiers (undefined, open, meta, super, closed, private, virtual)
825
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
826
- modifiers.append(self._advance().value)
921
+ # Check for type keyword (int, string, void, vector, datastruct, etc.)
922
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value) and return_type is None:
923
+ return_type = self._advance().value
827
924
 
828
- # Get return type
829
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
830
- return_type = self._advance().value
925
+ # Check for generic type <T> or <T, U>
926
+ if self._check(TokenType.COMPARE_LT):
927
+ self._advance() # skip <
928
+ generic_parts = []
929
+ depth = 1
930
+ while depth > 0 and not self._is_at_end():
931
+ if self._check(TokenType.COMPARE_LT):
932
+ depth += 1
933
+ generic_parts.append('<')
934
+ elif self._check(TokenType.COMPARE_GT):
935
+ depth -= 1
936
+ if depth > 0:
937
+ generic_parts.append('>')
938
+ elif self._check(TokenType.COMMA):
939
+ generic_parts.append(',')
940
+ else:
941
+ generic_parts.append(str(self._current().value))
942
+ self._advance()
943
+ generic_type = ''.join(generic_parts)
944
+ continue
831
945
 
832
- # Check for generic type <T>
833
- if self._check(TokenType.COMPARE_LT):
834
- self._advance() # skip <
835
- generic_parts = []
836
- depth = 1
837
- while depth > 0 and not self._is_at_end():
838
- if self._check(TokenType.COMPARE_LT):
839
- depth += 1
840
- generic_parts.append('<')
841
- elif self._check(TokenType.COMPARE_GT):
842
- depth -= 1
843
- if depth > 0:
844
- generic_parts.append('>')
845
- elif self._check(TokenType.COMMA):
846
- generic_parts.append(',')
847
- else:
848
- generic_parts.append(self._current().value)
849
- self._advance()
850
- generic_type = ''.join(generic_parts)
946
+ # Check for * prefix (non-null) or *[type] (type exclusion)
947
+ if self._check(TokenType.MULTIPLY):
948
+ self._advance()
949
+ # Check for type exclusion filter: *[string], *[int], etc.
950
+ if self._check(TokenType.BRACKET_START):
951
+ self._advance() # consume [
952
+ exclude_type = self._advance().value # get type name
953
+ self._expect(TokenType.BRACKET_END)
954
+ else:
955
+ non_null = True
956
+ continue
957
+
958
+ # Check for @ prefix (global function)
959
+ if self._check(TokenType.AT):
960
+ self._advance()
961
+ is_global = True
962
+ continue
963
+
964
+ # If we've reached an identifier, we're at the function name
965
+ if self._check(TokenType.IDENTIFIER):
966
+ parsing_prefix = False
967
+ else:
968
+ # Unknown token in prefix, break out
969
+ parsing_prefix = False
851
970
 
852
- # Get function name
971
+ # Phase 2: Get function name
972
+ if not self._check(TokenType.IDENTIFIER):
973
+ self.error(f"Expected function name, got {self._current().type.name}")
853
974
  name = self._advance().value
854
975
 
855
- # Parse parameters
976
+ # Phase 3: Parse parameters
856
977
  params = []
857
978
  self._expect(TokenType.PAREN_START)
858
979
 
@@ -863,6 +984,10 @@ class CSSLParser:
863
984
  if self._match_keyword('open'):
864
985
  param_info['open'] = True
865
986
 
987
+ # Handle const parameters
988
+ if self._match_keyword('const'):
989
+ param_info['const'] = True
990
+
866
991
  # Handle type annotations (builtin types like int, string, etc.)
867
992
  if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
868
993
  param_info['type'] = self._advance().value
@@ -883,13 +1008,12 @@ class CSSLParser:
883
1008
  elif self._check(TokenType.COMMA):
884
1009
  generic_parts.append(',')
885
1010
  else:
886
- generic_parts.append(self._current().value)
1011
+ generic_parts.append(str(self._current().value))
887
1012
  self._advance()
888
1013
  param_info['generic'] = ''.join(generic_parts)
889
1014
 
890
1015
  # Handle custom class types (identifier followed by another identifier = type + name)
891
1016
  elif self._check(TokenType.IDENTIFIER):
892
- # Look ahead: if next token is also an identifier, current is the type
893
1017
  saved_pos = self.pos
894
1018
  potential_type = self._advance().value
895
1019
 
@@ -909,7 +1033,7 @@ class CSSLParser:
909
1033
  elif self._check(TokenType.COMMA):
910
1034
  generic_parts.append(',')
911
1035
  else:
912
- generic_parts.append(self._current().value)
1036
+ generic_parts.append(str(self._current().value))
913
1037
  self._advance()
914
1038
  param_info['generic'] = ''.join(generic_parts)
915
1039
 
@@ -920,6 +1044,10 @@ class CSSLParser:
920
1044
  # Not a type, restore position - this is just a param name
921
1045
  self.pos = saved_pos
922
1046
 
1047
+ # Handle * prefix for non-null parameters
1048
+ if self._match(TokenType.MULTIPLY):
1049
+ param_info['non_null'] = True
1050
+
923
1051
  # Handle reference operator &
924
1052
  if self._match(TokenType.AMPERSAND):
925
1053
  param_info['ref'] = True
@@ -932,7 +1060,7 @@ class CSSLParser:
932
1060
  else:
933
1061
  params.append(param_name)
934
1062
  elif self._check(TokenType.KEYWORD):
935
- # Parameter name could be a keyword
1063
+ # Parameter name could be a keyword like 'Params'
936
1064
  param_name = self._advance().value
937
1065
  if param_info:
938
1066
  params.append({'name': param_name, **param_info})
@@ -943,13 +1071,104 @@ class CSSLParser:
943
1071
 
944
1072
  self._expect(TokenType.PAREN_END)
945
1073
 
946
- # Parse function body
1074
+ # Phase 4: Check for extends/overwrites and append mode
1075
+ extends_func = None
1076
+ extends_is_python = False
1077
+ extends_class_ref = None
1078
+ extends_method_ref = None
1079
+ overwrites_func = None
1080
+ overwrites_is_python = False
1081
+ overwrites_class_ref = None
1082
+ overwrites_method_ref = None
1083
+ append_mode = False
1084
+ append_ref_class = None
1085
+ append_ref_member = None
1086
+
1087
+ # Check for &ClassName::member reference
1088
+ if self._match(TokenType.AMPERSAND):
1089
+ if self._check(TokenType.IDENTIFIER):
1090
+ append_ref_class = self._advance().value
1091
+ elif self._check(TokenType.AT):
1092
+ self._advance()
1093
+ if self._check(TokenType.IDENTIFIER):
1094
+ append_ref_class = '@' + self._advance().value
1095
+ elif self._check(TokenType.SHARED_REF):
1096
+ append_ref_class = f'${self._advance().value}'
1097
+
1098
+ # Check for ::member
1099
+ if self._match(TokenType.DOUBLE_COLON):
1100
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
1101
+ append_ref_member = self._advance().value
1102
+
1103
+ # Check for ++ append operator
1104
+ if self._match(TokenType.PLUS_PLUS):
1105
+ append_mode = True
1106
+
1107
+ # Check for : or :: extends/overwrites
1108
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1109
+ while True:
1110
+ if self._match_keyword('extends'):
1111
+ # Parse target: @ModuleName, $PythonObject, Parent::method
1112
+ if self._check(TokenType.AT):
1113
+ self._advance()
1114
+ extends_func = '@' + self._advance().value
1115
+ elif self._check(TokenType.SHARED_REF):
1116
+ extends_is_python = True
1117
+ extends_func = self._advance().value
1118
+ elif self._check(TokenType.IDENTIFIER):
1119
+ first_part = self._advance().value
1120
+ if self._match(TokenType.DOUBLE_COLON):
1121
+ extends_class_ref = first_part
1122
+ extends_method_ref = self._advance().value
1123
+ else:
1124
+ extends_func = first_part
1125
+ # Skip optional ()
1126
+ if self._match(TokenType.PAREN_START):
1127
+ self._expect(TokenType.PAREN_END)
1128
+ elif self._match_keyword('overwrites'):
1129
+ if self._check(TokenType.AT):
1130
+ self._advance()
1131
+ overwrites_func = '@' + self._advance().value
1132
+ elif self._check(TokenType.SHARED_REF):
1133
+ overwrites_is_python = True
1134
+ overwrites_func = self._advance().value
1135
+ elif self._check(TokenType.IDENTIFIER):
1136
+ first_part = self._advance().value
1137
+ if self._match(TokenType.DOUBLE_COLON):
1138
+ overwrites_class_ref = first_part
1139
+ overwrites_method_ref = self._advance().value
1140
+ else:
1141
+ overwrites_func = first_part
1142
+ if self._match(TokenType.PAREN_START):
1143
+ self._expect(TokenType.PAREN_END)
1144
+ else:
1145
+ break
1146
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1147
+ break
1148
+
1149
+ # Phase 5: Parse function body
947
1150
  node = ASTNode('function', value={
948
1151
  'name': name,
1152
+ 'is_global': is_global,
1153
+ 'is_const': is_const,
949
1154
  'params': params,
950
1155
  'return_type': return_type,
951
1156
  'generic_type': generic_type,
952
- 'modifiers': modifiers
1157
+ 'modifiers': modifiers,
1158
+ 'non_null': non_null,
1159
+ 'exclude_type': exclude_type,
1160
+ 'extends': extends_func,
1161
+ 'extends_is_python': extends_is_python,
1162
+ 'extends_class': extends_class_ref,
1163
+ 'extends_method': extends_method_ref,
1164
+ 'overwrites': overwrites_func,
1165
+ 'overwrites_is_python': overwrites_is_python,
1166
+ 'overwrites_class': overwrites_class_ref,
1167
+ 'overwrites_method': overwrites_method_ref,
1168
+ 'append_mode': append_mode,
1169
+ 'append_ref_class': append_ref_class,
1170
+ 'append_ref_member': append_ref_member,
1171
+ 'enforce_return_type': return_type is not None and 'meta' not in modifiers
953
1172
  }, children=[])
954
1173
 
955
1174
  self._expect(TokenType.BLOCK_START)
@@ -1109,19 +1328,30 @@ class CSSLParser:
1109
1328
  root.children.append(self._parse_package_includes())
1110
1329
  # Handle global declarations
1111
1330
  elif self._match_keyword('global'):
1112
- stmt = self._parse_expression_statement()
1113
- if stmt:
1114
- # Wrap in global_assignment to mark as global variable
1115
- global_stmt = ASTNode('global_assignment', value=stmt)
1116
- root.children.append(global_stmt)
1331
+ # Check if followed by class or define (global class/function)
1332
+ if self._match_keyword('class'):
1333
+ root.children.append(self._parse_class(is_global=True))
1334
+ elif self._match_keyword('define'):
1335
+ root.children.append(self._parse_define(is_global=True))
1336
+ elif self._looks_like_function_declaration():
1337
+ # global void MyFunc() { } or global int MyFunc() { }
1338
+ root.children.append(self._parse_typed_function(is_global=True))
1339
+ else:
1340
+ stmt = self._parse_expression_statement()
1341
+ if stmt:
1342
+ # Wrap in global_assignment to mark as global variable
1343
+ global_stmt = ASTNode('global_assignment', value=stmt)
1344
+ root.children.append(global_stmt)
1117
1345
  elif self._check(TokenType.GLOBAL_REF):
1118
1346
  stmt = self._parse_expression_statement()
1119
1347
  if stmt:
1120
1348
  # Wrap in global_assignment to mark as global variable (same as 'global' keyword)
1121
1349
  global_stmt = ASTNode('global_assignment', value=stmt)
1122
1350
  root.children.append(global_stmt)
1123
- # Handle statements
1124
- elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF):
1351
+ # Handle statements - keywords like 'instance', 'list', 'map' can be variable names
1352
+ elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1353
+ self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
1354
+ self._check(TokenType.KEYWORD)):
1125
1355
  stmt = self._parse_expression_statement()
1126
1356
  if stmt:
1127
1357
  root.children.append(stmt)
@@ -1358,20 +1588,14 @@ class CSSLParser:
1358
1588
  self._expect(TokenType.BLOCK_END)
1359
1589
  return node
1360
1590
 
1361
- def _parse_class(self) -> ASTNode:
1591
+ def _parse_class(self, is_global: bool = False) -> ASTNode:
1362
1592
  """Parse class declaration with members and methods.
1363
1593
 
1364
1594
  Syntax:
1365
- class ClassName {
1366
- string name;
1367
- int age;
1368
-
1369
- void ClassName(string n) { this->name = n; }
1370
-
1371
- void sayHello() {
1372
- printl("Hello " + this->name);
1373
- }
1374
- }
1595
+ class ClassName { ... } // Local class
1596
+ global class ClassName { ... } // Global class
1597
+ class @ClassName { ... } // Global class (alternative)
1598
+ class *ClassName { ... } // Non-null class
1375
1599
 
1376
1600
  Non-null class (all methods return non-null):
1377
1601
  class *MyClass { ... }
@@ -1381,6 +1605,11 @@ class CSSLParser:
1381
1605
  if self._match(TokenType.MULTIPLY):
1382
1606
  non_null = True
1383
1607
 
1608
+ # Check for @ prefix (global class): class @ClassName
1609
+ if self._check(TokenType.AT):
1610
+ self._advance() # consume @
1611
+ is_global = True
1612
+
1384
1613
  class_name = self._advance().value
1385
1614
 
1386
1615
  # Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
@@ -1437,6 +1666,7 @@ class CSSLParser:
1437
1666
 
1438
1667
  node = ASTNode('class', value={
1439
1668
  'name': class_name,
1669
+ 'is_global': is_global,
1440
1670
  'non_null': non_null,
1441
1671
  'class_params': class_params,
1442
1672
  'extends': extends_class,
@@ -1491,11 +1721,13 @@ class CSSLParser:
1491
1721
 
1492
1722
  Syntax:
1493
1723
  constr ConstructorName() { ... }
1724
+ constr ConstructorName() ++ { ... } // Append: keeps parent constructor + adds new code
1725
+ constr ConstructorName() &ParentClass::constructors ++ { ... } // Append specific parent constructor
1494
1726
  constr ConstructorName() : extends ParentClass::ConstructorName { ... }
1495
1727
  constr ConstructorName() : extends ParentClass::ConstructorName : overwrites ParentClass::ConstructorName { ... }
1496
1728
 
1497
- Multiple constructors are allowed and executed in order.
1498
- Constructors can access parent constructor via super().
1729
+ The ++ operator means: execute parent's version first, then execute this code (append mode).
1730
+ The &ClassName::member syntax references a specific member from the overwritten class.
1499
1731
  """
1500
1732
  # Get constructor name
1501
1733
  if not self._check(TokenType.IDENTIFIER):
@@ -1503,7 +1735,6 @@ class CSSLParser:
1503
1735
  constr_name = self._advance().value
1504
1736
 
1505
1737
  # Parse method-level extends/overwrites with :: syntax
1506
- # constr Name() :: extends Parent::Name :: overwrites Parent::Name { ... }
1507
1738
  extends_target = None
1508
1739
  extends_class_ref = None
1509
1740
  extends_method_ref = None
@@ -1511,12 +1742,39 @@ class CSSLParser:
1511
1742
  overwrites_class_ref = None
1512
1743
  overwrites_method_ref = None
1513
1744
 
1745
+ # New: Append mode and reference tracking
1746
+ append_mode = False # ++ operator: keep parent code + add new
1747
+ append_ref_class = None # &ClassName part
1748
+ append_ref_member = None # ::member part (constructors, functionName, etc.)
1749
+
1514
1750
  # Parse parameters
1515
1751
  params = []
1516
1752
  if self._match(TokenType.PAREN_START):
1517
1753
  params = self._parse_parameter_list()
1518
1754
  self._expect(TokenType.PAREN_END)
1519
1755
 
1756
+ # Check for &ClassName::member reference (for targeting specific parent member)
1757
+ # Syntax: constr Name() &ParentClass::constructors ++ { ... }
1758
+ if self._match(TokenType.AMPERSAND):
1759
+ # Parse the class reference
1760
+ if self._check(TokenType.IDENTIFIER):
1761
+ append_ref_class = self._advance().value
1762
+ elif self._check(TokenType.SHARED_REF):
1763
+ append_ref_class = f'${self._advance().value}'
1764
+ else:
1765
+ raise CSSLSyntaxError("Expected class name after '&' in constructor reference")
1766
+
1767
+ # Check for ::member
1768
+ if self._match(TokenType.DOUBLE_COLON):
1769
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
1770
+ append_ref_member = self._advance().value
1771
+ else:
1772
+ raise CSSLSyntaxError("Expected member name after '::' in constructor reference")
1773
+
1774
+ # Check for ++ append operator
1775
+ if self._match(TokenType.PLUS_PLUS):
1776
+ append_mode = True
1777
+
1520
1778
  # Check for method-level extends/overwrites with :: or :
1521
1779
  if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1522
1780
  while True:
@@ -1563,7 +1821,11 @@ class CSSLParser:
1563
1821
  'extends_method': extends_method_ref,
1564
1822
  'overwrites_target': overwrites_target,
1565
1823
  'overwrites_class': overwrites_class_ref,
1566
- 'overwrites_method': overwrites_method_ref
1824
+ 'overwrites_method': overwrites_method_ref,
1825
+ # New append mode fields
1826
+ 'append_mode': append_mode,
1827
+ 'append_ref_class': append_ref_class,
1828
+ 'append_ref_member': append_ref_member
1567
1829
  }, children=body)
1568
1830
 
1569
1831
  def _parse_qualified_method_ref(self) -> str:
@@ -1639,20 +1901,35 @@ class CSSLParser:
1639
1901
 
1640
1902
  return params
1641
1903
 
1642
- def _parse_define(self) -> ASTNode:
1904
+ def _parse_define(self, is_global: bool = False) -> ASTNode:
1643
1905
  """Parse define function declaration.
1644
1906
 
1645
1907
  Syntax:
1646
- define MyFunc(args) { }
1647
- define *MyFunc(args) { } // Non-null: must never return None
1908
+ define MyFunc(args) { } // Local function
1909
+ global define MyFunc(args) { } // Global function
1910
+ define @MyFunc(args) { } // Global function (alternative)
1911
+ define *MyFunc(args) { } // Non-null: must never return None
1648
1912
  define MyFunc : extends OtherFunc() { } // Inherit local vars
1649
1913
  define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
1650
1914
  define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
1651
1915
  """
1652
1916
  # Check for * prefix (non-null function - must return non-null)
1917
+ # Also *[type] for type exclusion (must NOT return that type)
1653
1918
  non_null = False
1919
+ exclude_type = None
1654
1920
  if self._match(TokenType.MULTIPLY):
1655
- non_null = True
1921
+ # Check for type exclusion filter: *[string], *[int], etc.
1922
+ if self._check(TokenType.BRACKET_START):
1923
+ self._advance() # consume [
1924
+ exclude_type = self._advance().value # get type name
1925
+ self._expect(TokenType.BRACKET_END)
1926
+ else:
1927
+ non_null = True
1928
+
1929
+ # Check for @ prefix (global function): define @FuncName
1930
+ if self._check(TokenType.AT):
1931
+ self._advance() # consume @
1932
+ is_global = True
1656
1933
 
1657
1934
  name = self._advance().value
1658
1935
 
@@ -1769,10 +2046,38 @@ class CSSLParser:
1769
2046
  break
1770
2047
  self._expect(TokenType.PAREN_END)
1771
2048
 
2049
+ # New: Append mode and reference tracking for functions
2050
+ # Syntax: define XYZ(int zahl) &overwrittenclass::functionyouwanttokeep ++ { ... }
2051
+ append_mode = False
2052
+ append_ref_class = None
2053
+ append_ref_member = None
2054
+
2055
+ # Check for &ClassName::member reference
2056
+ if self._match(TokenType.AMPERSAND):
2057
+ if self._check(TokenType.IDENTIFIER):
2058
+ append_ref_class = self._advance().value
2059
+ elif self._check(TokenType.SHARED_REF):
2060
+ append_ref_class = f'${self._advance().value}'
2061
+ else:
2062
+ raise CSSLSyntaxError("Expected class name after '&' in function reference")
2063
+
2064
+ # Check for ::member
2065
+ if self._match(TokenType.DOUBLE_COLON):
2066
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
2067
+ append_ref_member = self._advance().value
2068
+ else:
2069
+ raise CSSLSyntaxError("Expected member name after '::' in function reference")
2070
+
2071
+ # Check for ++ append operator
2072
+ if self._match(TokenType.PLUS_PLUS):
2073
+ append_mode = True
2074
+
1772
2075
  node = ASTNode('function', value={
1773
2076
  'name': name,
2077
+ 'is_global': is_global,
1774
2078
  'params': params,
1775
2079
  'non_null': non_null,
2080
+ 'exclude_type': exclude_type, # *[type] - must NOT return this type
1776
2081
  'extends': extends_func,
1777
2082
  'extends_is_python': extends_is_python,
1778
2083
  'overwrites': overwrites_func,
@@ -1781,7 +2086,11 @@ class CSSLParser:
1781
2086
  'extends_class': extends_class_ref,
1782
2087
  'extends_method': extends_method_ref,
1783
2088
  'overwrites_class': overwrites_class_ref,
1784
- 'overwrites_method': overwrites_method_ref
2089
+ 'overwrites_method': overwrites_method_ref,
2090
+ # New append mode fields
2091
+ 'append_mode': append_mode,
2092
+ 'append_ref_class': append_ref_class,
2093
+ 'append_ref_member': append_ref_member
1785
2094
  }, children=[])
1786
2095
  self._expect(TokenType.BLOCK_START)
1787
2096
 
@@ -2642,6 +2951,26 @@ class CSSLParser:
2642
2951
  operand = self._parse_unary()
2643
2952
  return ASTNode('reference', value=operand)
2644
2953
 
2954
+ # Non-null assertion: *$var, *@module, *identifier
2955
+ # Also type exclusion filter: *[type]expr - exclude type from return
2956
+ if self._check(TokenType.MULTIPLY):
2957
+ next_token = self._peek(1)
2958
+
2959
+ # Check for type exclusion filter: *[string], *[int], etc.
2960
+ if next_token and next_token.type == TokenType.BRACKET_START:
2961
+ self._advance() # consume *
2962
+ self._advance() # consume [
2963
+ exclude_type = self._advance().value # get type name
2964
+ self._expect(TokenType.BRACKET_END)
2965
+ operand = self._parse_unary()
2966
+ return ASTNode('type_exclude_assert', value={'exclude_type': exclude_type, 'operand': operand})
2967
+
2968
+ # Non-null assertion when followed by $ (shared ref), @ (global), or identifier
2969
+ if next_token and next_token.type in (TokenType.SHARED_REF, TokenType.AT, TokenType.IDENTIFIER):
2970
+ self._advance() # consume *
2971
+ operand = self._parse_unary()
2972
+ return ASTNode('non_null_assert', value={'operand': operand})
2973
+
2645
2974
  return self._parse_primary()
2646
2975
 
2647
2976
  def _parse_primary(self) -> ASTNode:
@@ -2678,16 +3007,21 @@ class CSSLParser:
2678
3007
  # Just 'this' keyword alone - return as identifier for now
2679
3008
  return ASTNode('identifier', value='this')
2680
3009
 
2681
- # Handle 'new ClassName(args)' instantiation
3010
+ # Handle 'new ClassName(args)' or 'new @ClassName(args)' instantiation
2682
3011
  if self._check(TokenType.KEYWORD) and self._current().value == 'new':
2683
3012
  self._advance() # consume 'new'
3013
+ # Check for @ prefix (global class reference)
3014
+ is_global_ref = False
3015
+ if self._check(TokenType.AT):
3016
+ self._advance() # consume @
3017
+ is_global_ref = True
2684
3018
  class_name = self._advance().value # get class name
2685
3019
  args = []
2686
3020
  kwargs = {}
2687
3021
  if self._match(TokenType.PAREN_START):
2688
3022
  args, kwargs = self._parse_call_arguments()
2689
3023
  self._expect(TokenType.PAREN_END)
2690
- node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs})
3024
+ node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs, 'is_global_ref': is_global_ref})
2691
3025
  # Continue to check for member access, calls on the new object
2692
3026
  while True:
2693
3027
  if self._match(TokenType.DOT):
@@ -2706,7 +3040,18 @@ class CSSLParser:
2706
3040
  return node
2707
3041
 
2708
3042
  if self._match(TokenType.AT):
3043
+ # Check for @* (global non-null reference): @*name
3044
+ is_non_null = False
3045
+ if self._check(TokenType.MULTIPLY):
3046
+ self._advance() # consume *
3047
+ is_non_null = True
3048
+
2709
3049
  node = self._parse_module_reference()
3050
+
3051
+ # Wrap in non_null_assert if @* was used
3052
+ if is_non_null:
3053
+ node = ASTNode('non_null_assert', value={'operand': node, 'is_global': True})
3054
+
2710
3055
  # Continue to check for calls, indexing, member access on module refs
2711
3056
  while True:
2712
3057
  if self._match(TokenType.PAREN_START):