IncludeCPP 3.9.2__tar.gz → 4.0.0__tar.gz
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-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-3.9.2 → includecpp-4.0.0}/PKG-INFO +1 -1
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__init__.py +1 -1
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +48 -3
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_parser.py +270 -81
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_runtime.py +56 -2
- {includecpp-3.9.2 → includecpp-4.0.0}/pyproject.toml +1 -1
- {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/LICENSE +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/MANIFEST.in +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/README.md +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__init__.pyi +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__main__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/commands.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cppy_converter.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_builtins.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_events.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_modules.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_syntax.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_types.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl_bridge.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl_bridge.pyi +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/parser.cpp +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/parser.h +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/py.typed +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/__init__.py +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/extension.js +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/images/cssl.png +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/language-configuration.json +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/package.json +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/requirements.txt +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/setup.cfg +0 -0
- {includecpp-3.9.2 → includecpp-4.0.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CSSL - C-Style Scripting Language
|
|
2
2
|
|
|
3
|
-
> Version
|
|
3
|
+
> Version 4.0.0 | A modern scripting language with C++-style syntax and unique features like CodeInfusion, BruteInjection, and Python Interop.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -513,10 +513,16 @@ define greet(string name) {
|
|
|
513
513
|
| `closed` | Block external CodeInfusion |
|
|
514
514
|
| `private` | Block all CodeInfusion |
|
|
515
515
|
| `virtual` | Import-cycle safe |
|
|
516
|
-
| `meta` | Source function (
|
|
516
|
+
| `meta` | Source function (any return type allowed) |
|
|
517
517
|
| `super` | Force execution (no exceptions) |
|
|
518
518
|
| `open` | Accept any parameters |
|
|
519
519
|
| `shuffled` | Return multiple values |
|
|
520
|
+
| `const` | Immutable function (like C++) |
|
|
521
|
+
| `static` | Static method/function |
|
|
522
|
+
| `public` | Explicitly public (default) |
|
|
523
|
+
| `global` | Makes function globally accessible |
|
|
524
|
+
|
|
525
|
+
**Flexible Modifier Order**: Modifiers can appear in any order before the function declaration.
|
|
520
526
|
|
|
521
527
|
```cssl
|
|
522
528
|
// Ignore errors
|
|
@@ -535,6 +541,45 @@ shuffled string getNames() {
|
|
|
535
541
|
}
|
|
536
542
|
|
|
537
543
|
a, b, c = getNames();
|
|
544
|
+
|
|
545
|
+
// Any order of modifiers works
|
|
546
|
+
private string *@Myfunc() {
|
|
547
|
+
println("Hello from global private non-null function!");
|
|
548
|
+
return "Hey";
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Const function
|
|
552
|
+
const void immutableFunc() {
|
|
553
|
+
printl("I'm constant");
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Global private const
|
|
557
|
+
global private const void @MyGlobalFunc() {
|
|
558
|
+
printl("Complex modifiers in any order");
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Typed Functions (Enforced Returns)
|
|
563
|
+
|
|
564
|
+
Functions with a return type (like `int`, `string`, `vector<T>`) MUST return that type:
|
|
565
|
+
|
|
566
|
+
```cssl
|
|
567
|
+
// MUST return string
|
|
568
|
+
string getName() {
|
|
569
|
+
return "Alice"; // OK
|
|
570
|
+
// return 42; // Error! Expected string
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// MUST return int
|
|
574
|
+
int getAge() {
|
|
575
|
+
return 30; // OK
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// meta modifier bypasses type checking
|
|
579
|
+
meta datastruct<string> getData() {
|
|
580
|
+
return "just a string"; // OK despite declared type
|
|
581
|
+
return 42; // Also OK - meta allows any type
|
|
582
|
+
}
|
|
538
583
|
```
|
|
539
584
|
|
|
540
585
|
### Non-Null Functions (*)
|
|
@@ -1453,4 +1498,4 @@ assert(x > 0, "x must be positive");
|
|
|
1453
1498
|
|
|
1454
1499
|
---
|
|
1455
1500
|
|
|
1456
|
-
*CSSL
|
|
1501
|
+
*CSSL v4.0.0 - Developed as part of IncludeCPP*
|
|
@@ -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()
|
|
762
791
|
|
|
763
|
-
# Check for
|
|
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()
|
|
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
|
-
|
|
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.
|
|
@@ -817,69 +871,109 @@ class CSSLParser:
|
|
|
817
871
|
return False
|
|
818
872
|
|
|
819
873
|
def _parse_typed_function(self, is_global: bool = False) -> ASTNode:
|
|
820
|
-
"""Parse C-style typed function declaration.
|
|
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
|
-
- int Add(int a, int b) { }
|
|
824
|
-
- global int Add(int a, int b) { }
|
|
825
|
-
- int @Add(int a, int b) { }
|
|
879
|
+
- int Add(int a, int b) { }
|
|
880
|
+
- global int Add(int a, int b) { }
|
|
881
|
+
- int @Add(int a, int b) { }
|
|
826
882
|
- undefined int Func() { }
|
|
827
883
|
- open void Handler(open Params) { }
|
|
828
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).
|
|
829
896
|
"""
|
|
830
897
|
modifiers = []
|
|
831
898
|
return_type = None
|
|
832
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
|
|
833
920
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
|
837
924
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
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
|
|
841
945
|
|
|
842
|
-
# Check for
|
|
843
|
-
if self._check(TokenType.
|
|
844
|
-
self._advance()
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
if depth > 0:
|
|
854
|
-
generic_parts.append('>')
|
|
855
|
-
elif self._check(TokenType.COMMA):
|
|
856
|
-
generic_parts.append(',')
|
|
857
|
-
else:
|
|
858
|
-
generic_parts.append(self._current().value)
|
|
859
|
-
self._advance()
|
|
860
|
-
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
|
|
861
957
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
if self._check(TokenType.BRACKET_START):
|
|
868
|
-
self._advance() # consume [
|
|
869
|
-
exclude_type = self._advance().value # get type name
|
|
870
|
-
self._expect(TokenType.BRACKET_END)
|
|
871
|
-
else:
|
|
872
|
-
non_null = True
|
|
958
|
+
# Check for @ prefix (global function)
|
|
959
|
+
if self._check(TokenType.AT):
|
|
960
|
+
self._advance()
|
|
961
|
+
is_global = True
|
|
962
|
+
continue
|
|
873
963
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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
|
|
878
970
|
|
|
879
|
-
# 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}")
|
|
880
974
|
name = self._advance().value
|
|
881
975
|
|
|
882
|
-
# Parse parameters
|
|
976
|
+
# Phase 3: Parse parameters
|
|
883
977
|
params = []
|
|
884
978
|
self._expect(TokenType.PAREN_START)
|
|
885
979
|
|
|
@@ -890,6 +984,10 @@ class CSSLParser:
|
|
|
890
984
|
if self._match_keyword('open'):
|
|
891
985
|
param_info['open'] = True
|
|
892
986
|
|
|
987
|
+
# Handle const parameters
|
|
988
|
+
if self._match_keyword('const'):
|
|
989
|
+
param_info['const'] = True
|
|
990
|
+
|
|
893
991
|
# Handle type annotations (builtin types like int, string, etc.)
|
|
894
992
|
if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
|
|
895
993
|
param_info['type'] = self._advance().value
|
|
@@ -910,13 +1008,12 @@ class CSSLParser:
|
|
|
910
1008
|
elif self._check(TokenType.COMMA):
|
|
911
1009
|
generic_parts.append(',')
|
|
912
1010
|
else:
|
|
913
|
-
generic_parts.append(self._current().value)
|
|
1011
|
+
generic_parts.append(str(self._current().value))
|
|
914
1012
|
self._advance()
|
|
915
1013
|
param_info['generic'] = ''.join(generic_parts)
|
|
916
1014
|
|
|
917
1015
|
# Handle custom class types (identifier followed by another identifier = type + name)
|
|
918
1016
|
elif self._check(TokenType.IDENTIFIER):
|
|
919
|
-
# Look ahead: if next token is also an identifier, current is the type
|
|
920
1017
|
saved_pos = self.pos
|
|
921
1018
|
potential_type = self._advance().value
|
|
922
1019
|
|
|
@@ -936,7 +1033,7 @@ class CSSLParser:
|
|
|
936
1033
|
elif self._check(TokenType.COMMA):
|
|
937
1034
|
generic_parts.append(',')
|
|
938
1035
|
else:
|
|
939
|
-
generic_parts.append(self._current().value)
|
|
1036
|
+
generic_parts.append(str(self._current().value))
|
|
940
1037
|
self._advance()
|
|
941
1038
|
param_info['generic'] = ''.join(generic_parts)
|
|
942
1039
|
|
|
@@ -947,6 +1044,10 @@ class CSSLParser:
|
|
|
947
1044
|
# Not a type, restore position - this is just a param name
|
|
948
1045
|
self.pos = saved_pos
|
|
949
1046
|
|
|
1047
|
+
# Handle * prefix for non-null parameters
|
|
1048
|
+
if self._match(TokenType.MULTIPLY):
|
|
1049
|
+
param_info['non_null'] = True
|
|
1050
|
+
|
|
950
1051
|
# Handle reference operator &
|
|
951
1052
|
if self._match(TokenType.AMPERSAND):
|
|
952
1053
|
param_info['ref'] = True
|
|
@@ -959,7 +1060,7 @@ class CSSLParser:
|
|
|
959
1060
|
else:
|
|
960
1061
|
params.append(param_name)
|
|
961
1062
|
elif self._check(TokenType.KEYWORD):
|
|
962
|
-
# Parameter name could be a keyword
|
|
1063
|
+
# Parameter name could be a keyword like 'Params'
|
|
963
1064
|
param_name = self._advance().value
|
|
964
1065
|
if param_info:
|
|
965
1066
|
params.append({'name': param_name, **param_info})
|
|
@@ -970,16 +1071,104 @@ class CSSLParser:
|
|
|
970
1071
|
|
|
971
1072
|
self._expect(TokenType.PAREN_END)
|
|
972
1073
|
|
|
973
|
-
#
|
|
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
|
|
974
1150
|
node = ASTNode('function', value={
|
|
975
1151
|
'name': name,
|
|
976
1152
|
'is_global': is_global,
|
|
1153
|
+
'is_const': is_const,
|
|
977
1154
|
'params': params,
|
|
978
1155
|
'return_type': return_type,
|
|
979
1156
|
'generic_type': generic_type,
|
|
980
1157
|
'modifiers': modifiers,
|
|
981
1158
|
'non_null': non_null,
|
|
982
|
-
'exclude_type': exclude_type
|
|
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
|
|
983
1172
|
}, children=[])
|
|
984
1173
|
|
|
985
1174
|
self._expect(TokenType.BLOCK_START)
|
|
@@ -1431,9 +1431,63 @@ class CSSLRuntime:
|
|
|
1431
1431
|
if isinstance(return_value, tuple):
|
|
1432
1432
|
for val in return_value:
|
|
1433
1433
|
if excluded_py_type and isinstance(val, excluded_py_type):
|
|
1434
|
-
raise
|
|
1434
|
+
raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}' values")
|
|
1435
1435
|
elif excluded_py_type and isinstance(return_value, excluded_py_type):
|
|
1436
|
-
raise
|
|
1436
|
+
raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}'")
|
|
1437
|
+
|
|
1438
|
+
# Enforce return type for typed functions (like C++)
|
|
1439
|
+
# Typed functions MUST return the declared type
|
|
1440
|
+
# Exception: 'meta' modifier allows any return type
|
|
1441
|
+
enforce_return_type = func_info.get('enforce_return_type', False)
|
|
1442
|
+
return_type = func_info.get('return_type')
|
|
1443
|
+
|
|
1444
|
+
if enforce_return_type and return_type and return_type != 'void':
|
|
1445
|
+
# Type mapping from CSSL types to Python types
|
|
1446
|
+
type_validate_map = {
|
|
1447
|
+
'string': str, 'int': int, 'float': (int, float), 'bool': bool,
|
|
1448
|
+
'list': list, 'array': list, 'dict': dict, 'json': dict,
|
|
1449
|
+
'dynamic': object, # Any type
|
|
1450
|
+
'void': type(None),
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
# Generic container types - accept lists/tuples
|
|
1454
|
+
container_types = {
|
|
1455
|
+
'vector', 'stack', 'datastruct', 'dataspace',
|
|
1456
|
+
'shuffled', 'iterator', 'combo', 'openquote', 'map'
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if return_type in container_types:
|
|
1460
|
+
# Container types accept list, tuple, dict depending on type
|
|
1461
|
+
if return_type == 'map':
|
|
1462
|
+
expected = dict
|
|
1463
|
+
elif return_type == 'shuffled':
|
|
1464
|
+
expected = (list, tuple)
|
|
1465
|
+
else:
|
|
1466
|
+
expected = (list, tuple, object)
|
|
1467
|
+
|
|
1468
|
+
if not isinstance(return_value, expected):
|
|
1469
|
+
func_name = func_info.get('name', 'unknown')
|
|
1470
|
+
actual_type = type(return_value).__name__
|
|
1471
|
+
raise CSSLRuntimeError(
|
|
1472
|
+
f"Type error in '{func_name}': declared return type '{return_type}' "
|
|
1473
|
+
f"but returned '{actual_type}'. Typed functions must return declared type."
|
|
1474
|
+
)
|
|
1475
|
+
elif return_type in type_validate_map:
|
|
1476
|
+
expected = type_validate_map[return_type]
|
|
1477
|
+
if expected != object and return_value is not None:
|
|
1478
|
+
if not isinstance(return_value, expected):
|
|
1479
|
+
func_name = func_info.get('name', 'unknown')
|
|
1480
|
+
actual_type = type(return_value).__name__
|
|
1481
|
+
raise CSSLRuntimeError(
|
|
1482
|
+
f"Type error in '{func_name}': declared return type '{return_type}' "
|
|
1483
|
+
f"but returned '{actual_type}'. Typed functions must return declared type."
|
|
1484
|
+
)
|
|
1485
|
+
|
|
1486
|
+
# Check non_null: function must return a value (not None)
|
|
1487
|
+
non_null = func_info.get('non_null', False)
|
|
1488
|
+
if non_null and return_value is None:
|
|
1489
|
+
func_name = func_info.get('name', 'unknown')
|
|
1490
|
+
raise CSSLRuntimeError(f"Non-null function '{func_name}' returned null/None")
|
|
1437
1491
|
|
|
1438
1492
|
return return_value
|
|
1439
1493
|
except Exception as e:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IncludeCPP"
|
|
7
|
-
version = "
|
|
7
|
+
version = "4.0.0"
|
|
8
8
|
description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|