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.
- includecpp/__init__.py +1 -1
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +877 -1781
- includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +1348 -0
- includecpp/core/cssl/cssl_builtins.pyi +231 -0
- includecpp/core/cssl/cssl_parser.py +439 -94
- includecpp/core/cssl/cssl_runtime.py +498 -27
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +25 -0
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/METADATA +1 -1
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/RECORD +13 -12
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/WHEEL +0 -0
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/entry_points.txt +0 -0
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.8.8.dist-info → includecpp-4.0.0.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
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
|
|
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(...)
|
|
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
|
-
|
|
736
|
-
|
|
737
|
-
self.
|
|
738
|
-
|
|
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
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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
|
-
#
|
|
745
|
-
if self._check(TokenType.
|
|
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
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
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
|
|
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
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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
|
|
829
|
+
return False
|
|
769
830
|
|
|
770
|
-
|
|
771
|
-
|
|
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
|
-
|
|
825
|
-
|
|
826
|
-
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
|
|
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
|
|
833
|
-
if self._check(TokenType.
|
|
834
|
-
self._advance()
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
1113
|
-
if
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
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)
|
|
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
|
|
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
|
-
|
|
1367
|
-
|
|
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
|
-
|
|
1498
|
-
|
|
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
|
|
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
|
-
|
|
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):
|