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.
Files changed (61) hide show
  1. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.9.2 → includecpp-4.0.0}/PKG-INFO +1 -1
  3. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__init__.py +1 -1
  4. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +48 -3
  5. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_parser.py +270 -81
  6. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_runtime.py +56 -2
  7. {includecpp-3.9.2 → includecpp-4.0.0}/pyproject.toml +1 -1
  8. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/SOURCES.txt +0 -0
  9. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  10. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/entry_points.txt +0 -0
  11. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/requires.txt +0 -0
  12. {includecpp-3.9.2 → includecpp-4.0.0}/IncludeCPP.egg-info/top_level.txt +0 -0
  13. {includecpp-3.9.2 → includecpp-4.0.0}/LICENSE +0 -0
  14. {includecpp-3.9.2 → includecpp-4.0.0}/MANIFEST.in +0 -0
  15. {includecpp-3.9.2 → includecpp-4.0.0}/README.md +0 -0
  16. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__init__.pyi +0 -0
  17. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/__main__.py +0 -0
  18. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/__init__.py +0 -0
  19. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/commands.py +0 -0
  20. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/cli/config_parser.py +0 -0
  21. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/__init__.py +0 -0
  22. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/ai_integration.py +0 -0
  23. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/build_manager.py +0 -0
  24. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cpp_api.py +0 -0
  25. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cpp_api.pyi +0 -0
  26. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cppy_converter.py +0 -0
  27. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +0 -0
  28. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/__init__.py +0 -0
  29. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_builtins.py +0 -0
  30. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
  31. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_events.py +0 -0
  32. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_modules.py +0 -0
  33. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_syntax.py +0 -0
  34. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl/cssl_types.py +0 -0
  35. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl_bridge.py +0 -0
  36. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/cssl_bridge.pyi +0 -0
  37. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/error_catalog.py +0 -0
  38. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/error_formatter.py +0 -0
  39. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/exceptions.py +0 -0
  40. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/path_discovery.py +0 -0
  41. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/project_ui.py +0 -0
  42. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/core/settings_ui.py +0 -0
  43. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/__init__.py +0 -0
  44. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/parser.cpp +0 -0
  45. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/parser.h +0 -0
  46. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/type_resolver.cpp +0 -0
  47. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/generator/type_resolver.h +0 -0
  48. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/py.typed +0 -0
  49. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/templates/cpp.proj.template +0 -0
  50. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/__init__.py +0 -0
  51. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/__init__.py +0 -0
  52. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/extension.js +0 -0
  53. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/images/cssl.png +0 -0
  54. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
  55. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/language-configuration.json +0 -0
  56. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/package.json +0 -0
  57. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
  58. {includecpp-3.9.2 → includecpp-4.0.0}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
  59. {includecpp-3.9.2 → includecpp-4.0.0}/requirements.txt +0 -0
  60. {includecpp-3.9.2 → includecpp-4.0.0}/setup.cfg +0 -0
  61. {includecpp-3.9.2 → includecpp-4.0.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.9.2
3
+ Version: 4.0.0
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.9.2
3
+ Version: 4.0.0
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "3.9.2"
5
+ __version__ = "4.0.0"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -1,6 +1,6 @@
1
1
  # CSSL - C-Style Scripting Language
2
2
 
3
- > Version 3.9.1 | A modern scripting language with C++-style syntax and unique features like CodeInfusion, BruteInjection, and Python Interop.
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 (must return) |
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 v3.9.1 - Developed as part of IncludeCPP*
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 ('undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual', 'sqlbased')
731
+ return value in FUNCTION_MODIFIERS
723
732
 
724
733
  def _is_type_keyword(self, value: str) -> bool:
725
734
  """Check if a keyword is a type declaration"""
@@ -730,53 +739,98 @@ class CSSLParser:
730
739
  def _looks_like_function_declaration(self) -> bool:
731
740
  """Check if current position looks like a C-style function declaration.
732
741
 
742
+ Supports flexible ordering of modifiers, types, non-null (*), and global (@):
743
+
733
744
  Patterns:
734
745
  - int funcName(...)
735
746
  - undefined int funcName(...)
736
747
  - vector<string> funcName(...)
737
748
  - undefined void funcName(...)
738
- - private super virtual meta FuncName(...) <- modifiers without return type
749
+ - private super virtual meta FuncName(...)
750
+ - private string *@Myfunc(...)
751
+ - const define myFunc(...)
752
+ - global private const void @Func(...)
753
+ - shuffled *[string] getNumbers(...)
754
+ - datastruct<dynamic> HelloCode(...)
755
+ - datastruct<dynamic> HelloCode() : extends @MyFunc { }
756
+
757
+ Distinguishes functions from variables:
758
+ - datastruct<dynamic> MyVar; <- variable (no () { })
759
+ - datastruct<dynamic> HelloCode() { } <- function (has () { })
739
760
  """
740
761
  saved_pos = self.pos
741
762
  has_modifiers = False
763
+ has_type = False
742
764
 
743
- # Skip modifiers (undefined, open, meta, super, closed, private, virtual)
744
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
745
- self._advance()
746
- has_modifiers = True
765
+ try:
766
+ # Skip modifiers in any order (global, private, const, undefined, etc.)
767
+ while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
768
+ self._advance()
769
+ has_modifiers = True
747
770
 
748
- # Check for type keyword (optional if modifiers present)
749
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
750
- self._advance()
771
+ # Check for 'define' keyword (special case: const define myFunc())
772
+ if self._check(TokenType.KEYWORD) and self._current().value == 'define':
773
+ self.pos = saved_pos
774
+ return False # Let _parse_define handle this
751
775
 
752
- # Skip generic type parameters <T>
753
- if self._check(TokenType.COMPARE_LT):
754
- depth = 1
776
+ # Check for type keyword (int, string, void, vector, datastruct, etc.)
777
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
755
778
  self._advance()
756
- while depth > 0 and not self._is_at_end():
757
- if self._check(TokenType.COMPARE_LT):
758
- depth += 1
759
- elif self._check(TokenType.COMPARE_GT):
760
- depth -= 1
779
+ has_type = True
780
+
781
+ # Skip generic type parameters <T> or <T, U>
782
+ if self._check(TokenType.COMPARE_LT):
783
+ depth = 1
761
784
  self._advance()
785
+ while depth > 0 and not self._is_at_end():
786
+ if self._check(TokenType.COMPARE_LT):
787
+ depth += 1
788
+ elif self._check(TokenType.COMPARE_GT):
789
+ depth -= 1
790
+ self._advance()
762
791
 
763
- # Check for identifier followed by (
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
- # If we have modifiers and the next token is an identifier followed by (
771
- # This handles: private super virtual meta FuncName()
772
- elif has_modifiers and self._check(TokenType.IDENTIFIER):
773
- self._advance()
774
- is_func = self._check(TokenType.PAREN_START)
811
+ # Check if followed by (
812
+ # IMPORTANT: Only a function declaration if we have modifiers OR type
813
+ # Plain identifier() is a function CALL, not a declaration
814
+ if self._check(TokenType.PAREN_START):
815
+ if has_modifiers or has_type:
816
+ self.pos = saved_pos
817
+ return True
818
+ else:
819
+ # No modifiers/type = function call, not declaration
820
+ self.pos = saved_pos
821
+ return False
822
+
823
+ # If we have a type and identifier but no (, it's a variable
824
+ if has_type and not self._check(TokenType.PAREN_START):
825
+ self.pos = saved_pos
826
+ return False
827
+
775
828
  self.pos = saved_pos
776
- return is_func
829
+ return False
777
830
 
778
- self.pos = saved_pos
779
- return False
831
+ except Exception:
832
+ self.pos = saved_pos
833
+ return False
780
834
 
781
835
  def _looks_like_typed_variable(self) -> bool:
782
836
  """Check if current position looks like a typed variable declaration.
@@ -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) { } // Local function
824
- - global int Add(int a, int b) { } // Global function
825
- - int @Add(int a, int b) { } // Global function (alternative)
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
- # Collect modifiers (undefined, open, meta, super, closed, private, virtual)
835
- while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
836
- modifiers.append(self._advance().value)
921
+ # Check for type keyword (int, string, void, vector, datastruct, etc.)
922
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value) and return_type is None:
923
+ return_type = self._advance().value
837
924
 
838
- # Get return type
839
- if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
840
- return_type = self._advance().value
925
+ # Check for generic type <T> or <T, U>
926
+ if self._check(TokenType.COMPARE_LT):
927
+ self._advance() # skip <
928
+ generic_parts = []
929
+ depth = 1
930
+ while depth > 0 and not self._is_at_end():
931
+ if self._check(TokenType.COMPARE_LT):
932
+ depth += 1
933
+ generic_parts.append('<')
934
+ elif self._check(TokenType.COMPARE_GT):
935
+ depth -= 1
936
+ if depth > 0:
937
+ generic_parts.append('>')
938
+ elif self._check(TokenType.COMMA):
939
+ generic_parts.append(',')
940
+ else:
941
+ generic_parts.append(str(self._current().value))
942
+ self._advance()
943
+ generic_type = ''.join(generic_parts)
944
+ continue
841
945
 
842
- # Check for generic type <T>
843
- if self._check(TokenType.COMPARE_LT):
844
- self._advance() # skip <
845
- generic_parts = []
846
- depth = 1
847
- while depth > 0 and not self._is_at_end():
848
- if self._check(TokenType.COMPARE_LT):
849
- depth += 1
850
- generic_parts.append('<')
851
- elif self._check(TokenType.COMPARE_GT):
852
- depth -= 1
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
- # Check for * prefix (non-null function) or *[type] (type exclusion)
863
- non_null = False
864
- exclude_type = None
865
- if self._match(TokenType.MULTIPLY):
866
- # Check for type exclusion filter: *[string], *[int], etc.
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
- # Check for @ prefix (global function): void @FuncName()
875
- if self._check(TokenType.AT):
876
- self._advance() # consume @
877
- is_global = True
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
- # Parse function body
1074
+ # Phase 4: Check for extends/overwrites and append mode
1075
+ extends_func = None
1076
+ extends_is_python = False
1077
+ extends_class_ref = None
1078
+ extends_method_ref = None
1079
+ overwrites_func = None
1080
+ overwrites_is_python = False
1081
+ overwrites_class_ref = None
1082
+ overwrites_method_ref = None
1083
+ append_mode = False
1084
+ append_ref_class = None
1085
+ append_ref_member = None
1086
+
1087
+ # Check for &ClassName::member reference
1088
+ if self._match(TokenType.AMPERSAND):
1089
+ if self._check(TokenType.IDENTIFIER):
1090
+ append_ref_class = self._advance().value
1091
+ elif self._check(TokenType.AT):
1092
+ self._advance()
1093
+ if self._check(TokenType.IDENTIFIER):
1094
+ append_ref_class = '@' + self._advance().value
1095
+ elif self._check(TokenType.SHARED_REF):
1096
+ append_ref_class = f'${self._advance().value}'
1097
+
1098
+ # Check for ::member
1099
+ if self._match(TokenType.DOUBLE_COLON):
1100
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
1101
+ append_ref_member = self._advance().value
1102
+
1103
+ # Check for ++ append operator
1104
+ if self._match(TokenType.PLUS_PLUS):
1105
+ append_mode = True
1106
+
1107
+ # Check for : or :: extends/overwrites
1108
+ if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
1109
+ while True:
1110
+ if self._match_keyword('extends'):
1111
+ # Parse target: @ModuleName, $PythonObject, Parent::method
1112
+ if self._check(TokenType.AT):
1113
+ self._advance()
1114
+ extends_func = '@' + self._advance().value
1115
+ elif self._check(TokenType.SHARED_REF):
1116
+ extends_is_python = True
1117
+ extends_func = self._advance().value
1118
+ elif self._check(TokenType.IDENTIFIER):
1119
+ first_part = self._advance().value
1120
+ if self._match(TokenType.DOUBLE_COLON):
1121
+ extends_class_ref = first_part
1122
+ extends_method_ref = self._advance().value
1123
+ else:
1124
+ extends_func = first_part
1125
+ # Skip optional ()
1126
+ if self._match(TokenType.PAREN_START):
1127
+ self._expect(TokenType.PAREN_END)
1128
+ elif self._match_keyword('overwrites'):
1129
+ if self._check(TokenType.AT):
1130
+ self._advance()
1131
+ overwrites_func = '@' + self._advance().value
1132
+ elif self._check(TokenType.SHARED_REF):
1133
+ overwrites_is_python = True
1134
+ overwrites_func = self._advance().value
1135
+ elif self._check(TokenType.IDENTIFIER):
1136
+ first_part = self._advance().value
1137
+ if self._match(TokenType.DOUBLE_COLON):
1138
+ overwrites_class_ref = first_part
1139
+ overwrites_method_ref = self._advance().value
1140
+ else:
1141
+ overwrites_func = first_part
1142
+ if self._match(TokenType.PAREN_START):
1143
+ self._expect(TokenType.PAREN_END)
1144
+ else:
1145
+ break
1146
+ if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
1147
+ break
1148
+
1149
+ # Phase 5: Parse function body
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 # *[type] - must NOT return this 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 CSSLError(f"Type exclusion: function must NOT return '{exclude_type}' values")
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 CSSLError(f"Type exclusion: function must NOT return '{exclude_type}'")
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 = "3.9.2"
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