IncludeCPP 3.8.9__py3-none-any.whl → 4.0.2__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.
@@ -144,16 +144,25 @@ KEYWORDS = {
144
144
  'structure', # Advanced C++/Py Class
145
145
  'openquote', # SQL openquote container
146
146
  # CSSL Function Modifiers
147
+ 'const', # Immutable function (like C++)
147
148
  'meta', # Source function (must return)
148
149
  'super', # Force execution (no exceptions)
149
150
  'closed', # Protect from external injection
150
151
  'private', # Disable all injections
151
152
  'virtual', # Import cycle safe
152
153
  'sqlbased', # SQL-based function
154
+ 'public', # Explicitly public (default)
155
+ 'static', # Static method/function
153
156
  # CSSL Include Keywords
154
157
  'include', 'get',
155
158
  }
156
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
+
157
166
  # Type literals that create empty instances
158
167
  TYPE_LITERALS = {'list', 'dict'}
159
168
 
@@ -719,7 +728,7 @@ class CSSLParser:
719
728
 
720
729
  def _is_function_modifier(self, value: str) -> bool:
721
730
  """Check if a keyword is a function modifier"""
722
- return value in ('undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual', 'sqlbased')
731
+ return value in FUNCTION_MODIFIERS
723
732
 
724
733
  def _is_type_keyword(self, value: str) -> bool:
725
734
  """Check if a keyword is a type declaration"""
@@ -730,53 +739,98 @@ class CSSLParser:
730
739
  def _looks_like_function_declaration(self) -> bool:
731
740
  """Check if current position looks like a C-style function declaration.
732
741
 
742
+ Supports flexible ordering of modifiers, types, non-null (*), and global (@):
743
+
733
744
  Patterns:
734
745
  - int funcName(...)
735
746
  - undefined int funcName(...)
736
747
  - vector<string> funcName(...)
737
748
  - undefined void funcName(...)
738
- - 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 () { })
739
760
  """
740
761
  saved_pos = self.pos
741
762
  has_modifiers = False
763
+ has_type = False
742
764
 
743
- # Skip modifiers (undefined, open, meta, super, closed, private, virtual)
744
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
745
- self._advance()
746
- 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
747
770
 
748
- # Check for type keyword (optional if modifiers present)
749
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
750
- 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
751
775
 
752
- # Skip generic type parameters <T>
753
- if self._check(TokenType.COMPARE_LT):
754
- 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):
755
778
  self._advance()
756
- while depth > 0 and not self._is_at_end():
757
- if self._check(TokenType.COMPARE_LT):
758
- depth += 1
759
- elif self._check(TokenType.COMPARE_GT):
760
- 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
761
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() # ]
762
802
 
763
- # 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)
764
808
  if self._check(TokenType.IDENTIFIER):
765
809
  self._advance()
766
- is_func = self._check(TokenType.PAREN_START)
767
- self.pos = saved_pos
768
- return is_func
769
810
 
770
- # If we have modifiers and the next token is an identifier followed by (
771
- # This handles: private super virtual meta FuncName()
772
- elif has_modifiers and self._check(TokenType.IDENTIFIER):
773
- self._advance()
774
- 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
+
775
828
  self.pos = saved_pos
776
- return is_func
829
+ return False
777
830
 
778
- self.pos = saved_pos
779
- return False
831
+ except Exception:
832
+ self.pos = saved_pos
833
+ return False
780
834
 
781
835
  def _looks_like_typed_variable(self) -> bool:
782
836
  """Check if current position looks like a typed variable declaration.
@@ -816,51 +870,110 @@ class CSSLParser:
816
870
  self.pos = saved_pos
817
871
  return False
818
872
 
819
- def _parse_typed_function(self) -> ASTNode:
820
- """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 (@):
821
877
 
822
878
  Patterns:
823
879
  - int Add(int a, int b) { }
880
+ - global int Add(int a, int b) { }
881
+ - int @Add(int a, int b) { }
824
882
  - undefined int Func() { }
825
883
  - open void Handler(open Params) { }
826
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).
827
896
  """
828
897
  modifiers = []
829
898
  return_type = None
830
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
831
920
 
832
- # Collect modifiers (undefined, open, meta, super, closed, private, virtual)
833
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
834
- 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
835
924
 
836
- # Get return type
837
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
838
- 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
839
945
 
840
- # Check for generic type <T>
841
- if self._check(TokenType.COMPARE_LT):
842
- self._advance() # skip <
843
- generic_parts = []
844
- depth = 1
845
- while depth > 0 and not self._is_at_end():
846
- if self._check(TokenType.COMPARE_LT):
847
- depth += 1
848
- generic_parts.append('<')
849
- elif self._check(TokenType.COMPARE_GT):
850
- depth -= 1
851
- if depth > 0:
852
- generic_parts.append('>')
853
- elif self._check(TokenType.COMMA):
854
- generic_parts.append(',')
855
- else:
856
- generic_parts.append(self._current().value)
857
- self._advance()
858
- 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
859
970
 
860
- # 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}")
861
974
  name = self._advance().value
862
975
 
863
- # Parse parameters
976
+ # Phase 3: Parse parameters
864
977
  params = []
865
978
  self._expect(TokenType.PAREN_START)
866
979
 
@@ -871,6 +984,10 @@ class CSSLParser:
871
984
  if self._match_keyword('open'):
872
985
  param_info['open'] = True
873
986
 
987
+ # Handle const parameters
988
+ if self._match_keyword('const'):
989
+ param_info['const'] = True
990
+
874
991
  # Handle type annotations (builtin types like int, string, etc.)
875
992
  if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
876
993
  param_info['type'] = self._advance().value
@@ -891,13 +1008,12 @@ class CSSLParser:
891
1008
  elif self._check(TokenType.COMMA):
892
1009
  generic_parts.append(',')
893
1010
  else:
894
- generic_parts.append(self._current().value)
1011
+ generic_parts.append(str(self._current().value))
895
1012
  self._advance()
896
1013
  param_info['generic'] = ''.join(generic_parts)
897
1014
 
898
1015
  # Handle custom class types (identifier followed by another identifier = type + name)
899
1016
  elif self._check(TokenType.IDENTIFIER):
900
- # Look ahead: if next token is also an identifier, current is the type
901
1017
  saved_pos = self.pos
902
1018
  potential_type = self._advance().value
903
1019
 
@@ -917,7 +1033,7 @@ class CSSLParser:
917
1033
  elif self._check(TokenType.COMMA):
918
1034
  generic_parts.append(',')
919
1035
  else:
920
- generic_parts.append(self._current().value)
1036
+ generic_parts.append(str(self._current().value))
921
1037
  self._advance()
922
1038
  param_info['generic'] = ''.join(generic_parts)
923
1039
 
@@ -928,6 +1044,10 @@ class CSSLParser:
928
1044
  # Not a type, restore position - this is just a param name
929
1045
  self.pos = saved_pos
930
1046
 
1047
+ # Handle * prefix for non-null parameters
1048
+ if self._match(TokenType.MULTIPLY):
1049
+ param_info['non_null'] = True
1050
+
931
1051
  # Handle reference operator &
932
1052
  if self._match(TokenType.AMPERSAND):
933
1053
  param_info['ref'] = True
@@ -940,7 +1060,7 @@ class CSSLParser:
940
1060
  else:
941
1061
  params.append(param_name)
942
1062
  elif self._check(TokenType.KEYWORD):
943
- # Parameter name could be a keyword
1063
+ # Parameter name could be a keyword like 'Params'
944
1064
  param_name = self._advance().value
945
1065
  if param_info:
946
1066
  params.append({'name': param_name, **param_info})
@@ -951,13 +1071,106 @@ class CSSLParser:
951
1071
 
952
1072
  self._expect(TokenType.PAREN_END)
953
1073
 
954
- # 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 or &ClassName.member or &function 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 or .member (support both syntaxes)
1099
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
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, 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
+ # Support both :: and . for class method access
1121
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
1122
+ extends_class_ref = first_part
1123
+ extends_method_ref = self._advance().value
1124
+ else:
1125
+ extends_func = first_part
1126
+ # Skip optional ()
1127
+ if self._match(TokenType.PAREN_START):
1128
+ self._expect(TokenType.PAREN_END)
1129
+ elif self._match_keyword('overwrites'):
1130
+ if self._check(TokenType.AT):
1131
+ self._advance()
1132
+ overwrites_func = '@' + self._advance().value
1133
+ elif self._check(TokenType.SHARED_REF):
1134
+ overwrites_is_python = True
1135
+ overwrites_func = self._advance().value
1136
+ elif self._check(TokenType.IDENTIFIER):
1137
+ first_part = self._advance().value
1138
+ # Support both :: and . for class method access
1139
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
1140
+ overwrites_class_ref = first_part
1141
+ overwrites_method_ref = self._advance().value
1142
+ else:
1143
+ overwrites_func = first_part
1144
+ if self._match(TokenType.PAREN_START):
1145
+ self._expect(TokenType.PAREN_END)
1146
+ else:
1147
+ break
1148
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1149
+ break
1150
+
1151
+ # Phase 5: Parse function body
955
1152
  node = ASTNode('function', value={
956
1153
  'name': name,
1154
+ 'is_global': is_global,
1155
+ 'is_const': is_const,
957
1156
  'params': params,
958
1157
  'return_type': return_type,
959
1158
  'generic_type': generic_type,
960
- 'modifiers': modifiers
1159
+ 'modifiers': modifiers,
1160
+ 'non_null': non_null,
1161
+ 'exclude_type': exclude_type,
1162
+ 'extends': extends_func,
1163
+ 'extends_is_python': extends_is_python,
1164
+ 'extends_class': extends_class_ref,
1165
+ 'extends_method': extends_method_ref,
1166
+ 'overwrites': overwrites_func,
1167
+ 'overwrites_is_python': overwrites_is_python,
1168
+ 'overwrites_class': overwrites_class_ref,
1169
+ 'overwrites_method': overwrites_method_ref,
1170
+ 'append_mode': append_mode,
1171
+ 'append_ref_class': append_ref_class,
1172
+ 'append_ref_member': append_ref_member,
1173
+ 'enforce_return_type': return_type is not None and 'meta' not in modifiers
961
1174
  }, children=[])
962
1175
 
963
1176
  self._expect(TokenType.BLOCK_START)
@@ -1117,19 +1330,30 @@ class CSSLParser:
1117
1330
  root.children.append(self._parse_package_includes())
1118
1331
  # Handle global declarations
1119
1332
  elif self._match_keyword('global'):
1120
- stmt = self._parse_expression_statement()
1121
- if stmt:
1122
- # Wrap in global_assignment to mark as global variable
1123
- global_stmt = ASTNode('global_assignment', value=stmt)
1124
- root.children.append(global_stmt)
1333
+ # Check if followed by class or define (global class/function)
1334
+ if self._match_keyword('class'):
1335
+ root.children.append(self._parse_class(is_global=True))
1336
+ elif self._match_keyword('define'):
1337
+ root.children.append(self._parse_define(is_global=True))
1338
+ elif self._looks_like_function_declaration():
1339
+ # global void MyFunc() { } or global int MyFunc() { }
1340
+ root.children.append(self._parse_typed_function(is_global=True))
1341
+ else:
1342
+ stmt = self._parse_expression_statement()
1343
+ if stmt:
1344
+ # Wrap in global_assignment to mark as global variable
1345
+ global_stmt = ASTNode('global_assignment', value=stmt)
1346
+ root.children.append(global_stmt)
1125
1347
  elif self._check(TokenType.GLOBAL_REF):
1126
1348
  stmt = self._parse_expression_statement()
1127
1349
  if stmt:
1128
1350
  # Wrap in global_assignment to mark as global variable (same as 'global' keyword)
1129
1351
  global_stmt = ASTNode('global_assignment', value=stmt)
1130
1352
  root.children.append(global_stmt)
1131
- # Handle statements
1132
- elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF):
1353
+ # Handle statements - keywords like 'instance', 'list', 'map' can be variable names
1354
+ elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1355
+ self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
1356
+ self._check(TokenType.KEYWORD)):
1133
1357
  stmt = self._parse_expression_statement()
1134
1358
  if stmt:
1135
1359
  root.children.append(stmt)
@@ -1366,20 +1590,14 @@ class CSSLParser:
1366
1590
  self._expect(TokenType.BLOCK_END)
1367
1591
  return node
1368
1592
 
1369
- def _parse_class(self) -> ASTNode:
1593
+ def _parse_class(self, is_global: bool = False) -> ASTNode:
1370
1594
  """Parse class declaration with members and methods.
1371
1595
 
1372
1596
  Syntax:
1373
- class ClassName {
1374
- string name;
1375
- int age;
1376
-
1377
- void ClassName(string n) { this->name = n; }
1378
-
1379
- void sayHello() {
1380
- printl("Hello " + this->name);
1381
- }
1382
- }
1597
+ class ClassName { ... } // Local class
1598
+ global class ClassName { ... } // Global class
1599
+ class @ClassName { ... } // Global class (alternative)
1600
+ class *ClassName { ... } // Non-null class
1383
1601
 
1384
1602
  Non-null class (all methods return non-null):
1385
1603
  class *MyClass { ... }
@@ -1389,6 +1607,11 @@ class CSSLParser:
1389
1607
  if self._match(TokenType.MULTIPLY):
1390
1608
  non_null = True
1391
1609
 
1610
+ # Check for @ prefix (global class): class @ClassName
1611
+ if self._check(TokenType.AT):
1612
+ self._advance() # consume @
1613
+ is_global = True
1614
+
1392
1615
  class_name = self._advance().value
1393
1616
 
1394
1617
  # Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
@@ -1445,6 +1668,7 @@ class CSSLParser:
1445
1668
 
1446
1669
  node = ASTNode('class', value={
1447
1670
  'name': class_name,
1671
+ 'is_global': is_global,
1448
1672
  'non_null': non_null,
1449
1673
  'class_params': class_params,
1450
1674
  'extends': extends_class,
@@ -1679,20 +1903,35 @@ class CSSLParser:
1679
1903
 
1680
1904
  return params
1681
1905
 
1682
- def _parse_define(self) -> ASTNode:
1906
+ def _parse_define(self, is_global: bool = False) -> ASTNode:
1683
1907
  """Parse define function declaration.
1684
1908
 
1685
1909
  Syntax:
1686
- define MyFunc(args) { }
1687
- define *MyFunc(args) { } // Non-null: must never return None
1910
+ define MyFunc(args) { } // Local function
1911
+ global define MyFunc(args) { } // Global function
1912
+ define @MyFunc(args) { } // Global function (alternative)
1913
+ define *MyFunc(args) { } // Non-null: must never return None
1688
1914
  define MyFunc : extends OtherFunc() { } // Inherit local vars
1689
1915
  define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
1690
1916
  define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
1691
1917
  """
1692
1918
  # Check for * prefix (non-null function - must return non-null)
1919
+ # Also *[type] for type exclusion (must NOT return that type)
1693
1920
  non_null = False
1921
+ exclude_type = None
1694
1922
  if self._match(TokenType.MULTIPLY):
1695
- non_null = True
1923
+ # Check for type exclusion filter: *[string], *[int], etc.
1924
+ if self._check(TokenType.BRACKET_START):
1925
+ self._advance() # consume [
1926
+ exclude_type = self._advance().value # get type name
1927
+ self._expect(TokenType.BRACKET_END)
1928
+ else:
1929
+ non_null = True
1930
+
1931
+ # Check for @ prefix (global function): define @FuncName
1932
+ if self._check(TokenType.AT):
1933
+ self._advance() # consume @
1934
+ is_global = True
1696
1935
 
1697
1936
  name = self._advance().value
1698
1937
 
@@ -1837,8 +2076,10 @@ class CSSLParser:
1837
2076
 
1838
2077
  node = ASTNode('function', value={
1839
2078
  'name': name,
2079
+ 'is_global': is_global,
1840
2080
  'params': params,
1841
2081
  'non_null': non_null,
2082
+ 'exclude_type': exclude_type, # *[type] - must NOT return this type
1842
2083
  'extends': extends_func,
1843
2084
  'extends_is_python': extends_is_python,
1844
2085
  'overwrites': overwrites_func,
@@ -2712,6 +2953,26 @@ class CSSLParser:
2712
2953
  operand = self._parse_unary()
2713
2954
  return ASTNode('reference', value=operand)
2714
2955
 
2956
+ # Non-null assertion: *$var, *@module, *identifier
2957
+ # Also type exclusion filter: *[type]expr - exclude type from return
2958
+ if self._check(TokenType.MULTIPLY):
2959
+ next_token = self._peek(1)
2960
+
2961
+ # Check for type exclusion filter: *[string], *[int], etc.
2962
+ if next_token and next_token.type == TokenType.BRACKET_START:
2963
+ self._advance() # consume *
2964
+ self._advance() # consume [
2965
+ exclude_type = self._advance().value # get type name
2966
+ self._expect(TokenType.BRACKET_END)
2967
+ operand = self._parse_unary()
2968
+ return ASTNode('type_exclude_assert', value={'exclude_type': exclude_type, 'operand': operand})
2969
+
2970
+ # Non-null assertion when followed by $ (shared ref), @ (global), or identifier
2971
+ if next_token and next_token.type in (TokenType.SHARED_REF, TokenType.AT, TokenType.IDENTIFIER):
2972
+ self._advance() # consume *
2973
+ operand = self._parse_unary()
2974
+ return ASTNode('non_null_assert', value={'operand': operand})
2975
+
2715
2976
  return self._parse_primary()
2716
2977
 
2717
2978
  def _parse_primary(self) -> ASTNode:
@@ -2748,16 +3009,21 @@ class CSSLParser:
2748
3009
  # Just 'this' keyword alone - return as identifier for now
2749
3010
  return ASTNode('identifier', value='this')
2750
3011
 
2751
- # Handle 'new ClassName(args)' instantiation
3012
+ # Handle 'new ClassName(args)' or 'new @ClassName(args)' instantiation
2752
3013
  if self._check(TokenType.KEYWORD) and self._current().value == 'new':
2753
3014
  self._advance() # consume 'new'
3015
+ # Check for @ prefix (global class reference)
3016
+ is_global_ref = False
3017
+ if self._check(TokenType.AT):
3018
+ self._advance() # consume @
3019
+ is_global_ref = True
2754
3020
  class_name = self._advance().value # get class name
2755
3021
  args = []
2756
3022
  kwargs = {}
2757
3023
  if self._match(TokenType.PAREN_START):
2758
3024
  args, kwargs = self._parse_call_arguments()
2759
3025
  self._expect(TokenType.PAREN_END)
2760
- node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs})
3026
+ node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs, 'is_global_ref': is_global_ref})
2761
3027
  # Continue to check for member access, calls on the new object
2762
3028
  while True:
2763
3029
  if self._match(TokenType.DOT):
@@ -2776,7 +3042,18 @@ class CSSLParser:
2776
3042
  return node
2777
3043
 
2778
3044
  if self._match(TokenType.AT):
3045
+ # Check for @* (global non-null reference): @*name
3046
+ is_non_null = False
3047
+ if self._check(TokenType.MULTIPLY):
3048
+ self._advance() # consume *
3049
+ is_non_null = True
3050
+
2779
3051
  node = self._parse_module_reference()
3052
+
3053
+ # Wrap in non_null_assert if @* was used
3054
+ if is_non_null:
3055
+ node = ASTNode('non_null_assert', value={'operand': node, 'is_global': True})
3056
+
2780
3057
  # Continue to check for calls, indexing, member access on module refs
2781
3058
  while True:
2782
3059
  if self._match(TokenType.PAREN_START):