IncludeCPP 3.8.9__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.
- includecpp/__init__.py +1 -1
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +869 -1872
- includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +1348 -0
- includecpp/core/cssl/cssl_builtins.pyi +231 -0
- includecpp/core/cssl/cssl_parser.py +363 -88
- includecpp/core/cssl/cssl_runtime.py +362 -27
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/METADATA +1 -1
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/RECORD +12 -11
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/WHEEL +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/entry_points.txt +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
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(...)
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
self.
|
|
746
|
-
|
|
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
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
-
#
|
|
753
|
-
if self._check(TokenType.
|
|
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
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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() # ]
|
|
802
|
+
|
|
803
|
+
# Check for @ prefix (global function)
|
|
804
|
+
if self._check(TokenType.AT):
|
|
805
|
+
self._advance()
|
|
762
806
|
|
|
763
|
-
#
|
|
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
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
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
|
|
829
|
+
return False
|
|
777
830
|
|
|
778
|
-
|
|
779
|
-
|
|
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
|
-
|
|
833
|
-
|
|
834
|
-
|
|
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
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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
|
|
841
|
-
if self._check(TokenType.
|
|
842
|
-
self._advance()
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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
|
|
859
963
|
|
|
860
|
-
|
|
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
|
|
970
|
+
|
|
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,104 @@ class CSSLParser:
|
|
|
951
1071
|
|
|
952
1072
|
self._expect(TokenType.PAREN_END)
|
|
953
1073
|
|
|
954
|
-
#
|
|
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
|
|
955
1150
|
node = ASTNode('function', value={
|
|
956
1151
|
'name': name,
|
|
1152
|
+
'is_global': is_global,
|
|
1153
|
+
'is_const': is_const,
|
|
957
1154
|
'params': params,
|
|
958
1155
|
'return_type': return_type,
|
|
959
1156
|
'generic_type': generic_type,
|
|
960
|
-
'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
|
|
961
1172
|
}, children=[])
|
|
962
1173
|
|
|
963
1174
|
self._expect(TokenType.BLOCK_START)
|
|
@@ -1117,19 +1328,30 @@ class CSSLParser:
|
|
|
1117
1328
|
root.children.append(self._parse_package_includes())
|
|
1118
1329
|
# Handle global declarations
|
|
1119
1330
|
elif self._match_keyword('global'):
|
|
1120
|
-
|
|
1121
|
-
if
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
root.children.append(
|
|
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)
|
|
1125
1345
|
elif self._check(TokenType.GLOBAL_REF):
|
|
1126
1346
|
stmt = self._parse_expression_statement()
|
|
1127
1347
|
if stmt:
|
|
1128
1348
|
# Wrap in global_assignment to mark as global variable (same as 'global' keyword)
|
|
1129
1349
|
global_stmt = ASTNode('global_assignment', value=stmt)
|
|
1130
1350
|
root.children.append(global_stmt)
|
|
1131
|
-
# Handle statements
|
|
1132
|
-
elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
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)):
|
|
1133
1355
|
stmt = self._parse_expression_statement()
|
|
1134
1356
|
if stmt:
|
|
1135
1357
|
root.children.append(stmt)
|
|
@@ -1366,20 +1588,14 @@ class CSSLParser:
|
|
|
1366
1588
|
self._expect(TokenType.BLOCK_END)
|
|
1367
1589
|
return node
|
|
1368
1590
|
|
|
1369
|
-
def _parse_class(self) -> ASTNode:
|
|
1591
|
+
def _parse_class(self, is_global: bool = False) -> ASTNode:
|
|
1370
1592
|
"""Parse class declaration with members and methods.
|
|
1371
1593
|
|
|
1372
1594
|
Syntax:
|
|
1373
|
-
class ClassName {
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
void ClassName(string n) { this->name = n; }
|
|
1378
|
-
|
|
1379
|
-
void sayHello() {
|
|
1380
|
-
printl("Hello " + this->name);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1595
|
+
class ClassName { ... } // Local class
|
|
1596
|
+
global class ClassName { ... } // Global class
|
|
1597
|
+
class @ClassName { ... } // Global class (alternative)
|
|
1598
|
+
class *ClassName { ... } // Non-null class
|
|
1383
1599
|
|
|
1384
1600
|
Non-null class (all methods return non-null):
|
|
1385
1601
|
class *MyClass { ... }
|
|
@@ -1389,6 +1605,11 @@ class CSSLParser:
|
|
|
1389
1605
|
if self._match(TokenType.MULTIPLY):
|
|
1390
1606
|
non_null = True
|
|
1391
1607
|
|
|
1608
|
+
# Check for @ prefix (global class): class @ClassName
|
|
1609
|
+
if self._check(TokenType.AT):
|
|
1610
|
+
self._advance() # consume @
|
|
1611
|
+
is_global = True
|
|
1612
|
+
|
|
1392
1613
|
class_name = self._advance().value
|
|
1393
1614
|
|
|
1394
1615
|
# Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
|
|
@@ -1445,6 +1666,7 @@ class CSSLParser:
|
|
|
1445
1666
|
|
|
1446
1667
|
node = ASTNode('class', value={
|
|
1447
1668
|
'name': class_name,
|
|
1669
|
+
'is_global': is_global,
|
|
1448
1670
|
'non_null': non_null,
|
|
1449
1671
|
'class_params': class_params,
|
|
1450
1672
|
'extends': extends_class,
|
|
@@ -1679,20 +1901,35 @@ class CSSLParser:
|
|
|
1679
1901
|
|
|
1680
1902
|
return params
|
|
1681
1903
|
|
|
1682
|
-
def _parse_define(self) -> ASTNode:
|
|
1904
|
+
def _parse_define(self, is_global: bool = False) -> ASTNode:
|
|
1683
1905
|
"""Parse define function declaration.
|
|
1684
1906
|
|
|
1685
1907
|
Syntax:
|
|
1686
|
-
define MyFunc(args) { }
|
|
1687
|
-
define
|
|
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
|
|
1688
1912
|
define MyFunc : extends OtherFunc() { } // Inherit local vars
|
|
1689
1913
|
define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
|
|
1690
1914
|
define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
|
|
1691
1915
|
"""
|
|
1692
1916
|
# Check for * prefix (non-null function - must return non-null)
|
|
1917
|
+
# Also *[type] for type exclusion (must NOT return that type)
|
|
1693
1918
|
non_null = False
|
|
1919
|
+
exclude_type = None
|
|
1694
1920
|
if self._match(TokenType.MULTIPLY):
|
|
1695
|
-
|
|
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
|
|
1696
1933
|
|
|
1697
1934
|
name = self._advance().value
|
|
1698
1935
|
|
|
@@ -1837,8 +2074,10 @@ class CSSLParser:
|
|
|
1837
2074
|
|
|
1838
2075
|
node = ASTNode('function', value={
|
|
1839
2076
|
'name': name,
|
|
2077
|
+
'is_global': is_global,
|
|
1840
2078
|
'params': params,
|
|
1841
2079
|
'non_null': non_null,
|
|
2080
|
+
'exclude_type': exclude_type, # *[type] - must NOT return this type
|
|
1842
2081
|
'extends': extends_func,
|
|
1843
2082
|
'extends_is_python': extends_is_python,
|
|
1844
2083
|
'overwrites': overwrites_func,
|
|
@@ -2712,6 +2951,26 @@ class CSSLParser:
|
|
|
2712
2951
|
operand = self._parse_unary()
|
|
2713
2952
|
return ASTNode('reference', value=operand)
|
|
2714
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
|
+
|
|
2715
2974
|
return self._parse_primary()
|
|
2716
2975
|
|
|
2717
2976
|
def _parse_primary(self) -> ASTNode:
|
|
@@ -2748,16 +3007,21 @@ class CSSLParser:
|
|
|
2748
3007
|
# Just 'this' keyword alone - return as identifier for now
|
|
2749
3008
|
return ASTNode('identifier', value='this')
|
|
2750
3009
|
|
|
2751
|
-
# Handle 'new ClassName(args)' instantiation
|
|
3010
|
+
# Handle 'new ClassName(args)' or 'new @ClassName(args)' instantiation
|
|
2752
3011
|
if self._check(TokenType.KEYWORD) and self._current().value == 'new':
|
|
2753
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
|
|
2754
3018
|
class_name = self._advance().value # get class name
|
|
2755
3019
|
args = []
|
|
2756
3020
|
kwargs = {}
|
|
2757
3021
|
if self._match(TokenType.PAREN_START):
|
|
2758
3022
|
args, kwargs = self._parse_call_arguments()
|
|
2759
3023
|
self._expect(TokenType.PAREN_END)
|
|
2760
|
-
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})
|
|
2761
3025
|
# Continue to check for member access, calls on the new object
|
|
2762
3026
|
while True:
|
|
2763
3027
|
if self._match(TokenType.DOT):
|
|
@@ -2776,7 +3040,18 @@ class CSSLParser:
|
|
|
2776
3040
|
return node
|
|
2777
3041
|
|
|
2778
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
|
+
|
|
2779
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
|
+
|
|
2780
3055
|
# Continue to check for calls, indexing, member access on module refs
|
|
2781
3056
|
while True:
|
|
2782
3057
|
if self._match(TokenType.PAREN_START):
|