IncludeCPP 3.9.2__py3-none-any.whl → 4.0.1__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/cli/commands.py +7 -14
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +48 -3
- includecpp/core/cssl/cssl_parser.py +272 -81
- includecpp/core/cssl/cssl_runtime.py +260 -18
- includecpp/core/cssl_bridge.py +4 -4
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/METADATA +2 -1
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/RECORD +12 -12
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/WHEEL +0 -0
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/entry_points.txt +0 -0
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.9.2.dist-info → includecpp-4.0.1.dist-info}/top_level.txt +0 -0
includecpp/__init__.py
CHANGED
includecpp/cli/commands.py
CHANGED
|
@@ -9,8 +9,12 @@ import re
|
|
|
9
9
|
import urllib.request
|
|
10
10
|
import urllib.error
|
|
11
11
|
from pathlib import Path
|
|
12
|
+
from colorama import init as colorama_init, Fore, Style
|
|
12
13
|
from .config_parser import CppProjectConfig
|
|
13
14
|
|
|
15
|
+
# Initialize colorama for Windows ANSI color support
|
|
16
|
+
colorama_init()
|
|
17
|
+
|
|
14
18
|
|
|
15
19
|
def _is_experimental_enabled() -> bool:
|
|
16
20
|
"""Check if experimental features (cppy, ai) are enabled."""
|
|
@@ -7320,7 +7324,6 @@ def exec_repl(lang, path, import_all):
|
|
|
7320
7324
|
code_lines = imports + [''] + lines if imports else lines
|
|
7321
7325
|
|
|
7322
7326
|
click.echo()
|
|
7323
|
-
click.secho("--- Output ---", fg='green')
|
|
7324
7327
|
|
|
7325
7328
|
if is_python:
|
|
7326
7329
|
# Execute Python code
|
|
@@ -7443,9 +7446,6 @@ def exec_repl(lang, path, import_all):
|
|
|
7443
7446
|
except Exception:
|
|
7444
7447
|
pass
|
|
7445
7448
|
|
|
7446
|
-
click.echo()
|
|
7447
|
-
click.secho("--------------", fg='green')
|
|
7448
|
-
|
|
7449
7449
|
|
|
7450
7450
|
# ============================================================================
|
|
7451
7451
|
# CSSL - Hidden Command Group
|
|
@@ -7526,19 +7526,12 @@ def _cssl_execute(path, code):
|
|
|
7526
7526
|
source = '\n'.join(lines)
|
|
7527
7527
|
|
|
7528
7528
|
# Execute
|
|
7529
|
-
click.secho("--- Output ---", fg='green')
|
|
7530
7529
|
try:
|
|
7531
7530
|
result = cssl_lang.run(source)
|
|
7532
|
-
|
|
7533
|
-
# Output is already printed to stdout during execution via runtime.output()
|
|
7534
|
-
# Don't print "Result:" automatically - users should use printl() for output
|
|
7535
|
-
# This prevents unwanted output for function calls like: Function();
|
|
7536
|
-
pass
|
|
7537
|
-
|
|
7538
7531
|
except Exception as e:
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7532
|
+
error_msg = str(e)
|
|
7533
|
+
# Clean display - single CSSL Error: prefix with colorama
|
|
7534
|
+
click.echo(f"{Fore.RED}CSSL Error: {error_msg}{Style.RESET_ALL}")
|
|
7542
7535
|
|
|
7543
7536
|
|
|
7544
7537
|
@cssl.command(name='makemodule')
|
|
@@ -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()
|
|
791
|
+
|
|
792
|
+
# Check for * prefix (non-null) or *[type] (type exclusion)
|
|
793
|
+
if self._check(TokenType.MULTIPLY):
|
|
794
|
+
self._advance()
|
|
795
|
+
# Check for type exclusion: *[string], *[int], etc.
|
|
796
|
+
if self._check(TokenType.BRACKET_START):
|
|
797
|
+
self._advance() # [
|
|
798
|
+
while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
|
|
799
|
+
self._advance()
|
|
800
|
+
if self._check(TokenType.BRACKET_END):
|
|
801
|
+
self._advance() # ]
|
|
802
|
+
|
|
803
|
+
# Check for @ prefix (global function)
|
|
804
|
+
if self._check(TokenType.AT):
|
|
805
|
+
self._advance()
|
|
762
806
|
|
|
763
|
-
#
|
|
807
|
+
# Now we should be at the function name (identifier)
|
|
764
808
|
if self._check(TokenType.IDENTIFIER):
|
|
765
809
|
self._advance()
|
|
766
|
-
is_func = self._check(TokenType.PAREN_START)
|
|
767
|
-
self.pos = saved_pos
|
|
768
|
-
return is_func
|
|
769
810
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
811
|
+
# Check if followed by (
|
|
812
|
+
# IMPORTANT: Only a function declaration if we have modifiers OR type
|
|
813
|
+
# Plain identifier() is a function CALL, not a declaration
|
|
814
|
+
if self._check(TokenType.PAREN_START):
|
|
815
|
+
if has_modifiers or has_type:
|
|
816
|
+
self.pos = saved_pos
|
|
817
|
+
return True
|
|
818
|
+
else:
|
|
819
|
+
# No modifiers/type = function call, not declaration
|
|
820
|
+
self.pos = saved_pos
|
|
821
|
+
return False
|
|
822
|
+
|
|
823
|
+
# If we have a type and identifier but no (, it's a variable
|
|
824
|
+
if has_type and not self._check(TokenType.PAREN_START):
|
|
825
|
+
self.pos = saved_pos
|
|
826
|
+
return False
|
|
827
|
+
|
|
775
828
|
self.pos = saved_pos
|
|
776
|
-
return
|
|
829
|
+
return False
|
|
777
830
|
|
|
778
|
-
|
|
779
|
-
|
|
831
|
+
except Exception:
|
|
832
|
+
self.pos = saved_pos
|
|
833
|
+
return False
|
|
780
834
|
|
|
781
835
|
def _looks_like_typed_variable(self) -> bool:
|
|
782
836
|
"""Check if current position looks like a typed variable declaration.
|
|
@@ -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,106 @@ 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 or &ClassName.member or &function reference
|
|
1088
|
+
if self._match(TokenType.AMPERSAND):
|
|
1089
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1090
|
+
append_ref_class = self._advance().value
|
|
1091
|
+
elif self._check(TokenType.AT):
|
|
1092
|
+
self._advance()
|
|
1093
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1094
|
+
append_ref_class = '@' + self._advance().value
|
|
1095
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1096
|
+
append_ref_class = f'${self._advance().value}'
|
|
1097
|
+
|
|
1098
|
+
# Check for ::member or .member (support both syntaxes)
|
|
1099
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
|
|
1100
|
+
if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
|
|
1101
|
+
append_ref_member = self._advance().value
|
|
1102
|
+
|
|
1103
|
+
# Check for ++ append operator
|
|
1104
|
+
if self._match(TokenType.PLUS_PLUS):
|
|
1105
|
+
append_mode = True
|
|
1106
|
+
|
|
1107
|
+
# Check for : or :: extends/overwrites
|
|
1108
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1109
|
+
while True:
|
|
1110
|
+
if self._match_keyword('extends'):
|
|
1111
|
+
# Parse target: @ModuleName, $PythonObject, Parent::method, Parent.method
|
|
1112
|
+
if self._check(TokenType.AT):
|
|
1113
|
+
self._advance()
|
|
1114
|
+
extends_func = '@' + self._advance().value
|
|
1115
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1116
|
+
extends_is_python = True
|
|
1117
|
+
extends_func = self._advance().value
|
|
1118
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1119
|
+
first_part = self._advance().value
|
|
1120
|
+
# Support both :: and . for class method access
|
|
1121
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
|
|
1122
|
+
extends_class_ref = first_part
|
|
1123
|
+
extends_method_ref = self._advance().value
|
|
1124
|
+
else:
|
|
1125
|
+
extends_func = first_part
|
|
1126
|
+
# Skip optional ()
|
|
1127
|
+
if self._match(TokenType.PAREN_START):
|
|
1128
|
+
self._expect(TokenType.PAREN_END)
|
|
1129
|
+
elif self._match_keyword('overwrites'):
|
|
1130
|
+
if self._check(TokenType.AT):
|
|
1131
|
+
self._advance()
|
|
1132
|
+
overwrites_func = '@' + self._advance().value
|
|
1133
|
+
elif self._check(TokenType.SHARED_REF):
|
|
1134
|
+
overwrites_is_python = True
|
|
1135
|
+
overwrites_func = self._advance().value
|
|
1136
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1137
|
+
first_part = self._advance().value
|
|
1138
|
+
# Support both :: and . for class method access
|
|
1139
|
+
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.DOT):
|
|
1140
|
+
overwrites_class_ref = first_part
|
|
1141
|
+
overwrites_method_ref = self._advance().value
|
|
1142
|
+
else:
|
|
1143
|
+
overwrites_func = first_part
|
|
1144
|
+
if self._match(TokenType.PAREN_START):
|
|
1145
|
+
self._expect(TokenType.PAREN_END)
|
|
1146
|
+
else:
|
|
1147
|
+
break
|
|
1148
|
+
if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
|
|
1149
|
+
break
|
|
1150
|
+
|
|
1151
|
+
# Phase 5: Parse function body
|
|
974
1152
|
node = ASTNode('function', value={
|
|
975
1153
|
'name': name,
|
|
976
1154
|
'is_global': is_global,
|
|
1155
|
+
'is_const': is_const,
|
|
977
1156
|
'params': params,
|
|
978
1157
|
'return_type': return_type,
|
|
979
1158
|
'generic_type': generic_type,
|
|
980
1159
|
'modifiers': modifiers,
|
|
981
1160
|
'non_null': non_null,
|
|
982
|
-
'exclude_type': exclude_type
|
|
1161
|
+
'exclude_type': exclude_type,
|
|
1162
|
+
'extends': extends_func,
|
|
1163
|
+
'extends_is_python': extends_is_python,
|
|
1164
|
+
'extends_class': extends_class_ref,
|
|
1165
|
+
'extends_method': extends_method_ref,
|
|
1166
|
+
'overwrites': overwrites_func,
|
|
1167
|
+
'overwrites_is_python': overwrites_is_python,
|
|
1168
|
+
'overwrites_class': overwrites_class_ref,
|
|
1169
|
+
'overwrites_method': overwrites_method_ref,
|
|
1170
|
+
'append_mode': append_mode,
|
|
1171
|
+
'append_ref_class': append_ref_class,
|
|
1172
|
+
'append_ref_member': append_ref_member,
|
|
1173
|
+
'enforce_return_type': return_type is not None and 'meta' not in modifiers
|
|
983
1174
|
}, children=[])
|
|
984
1175
|
|
|
985
1176
|
self._expect(TokenType.BLOCK_START)
|
|
@@ -68,11 +68,11 @@ class CSSLRuntimeError(Exception):
|
|
|
68
68
|
# Build detailed error message
|
|
69
69
|
error_parts = []
|
|
70
70
|
|
|
71
|
-
# Main error message
|
|
71
|
+
# Main error message (no "Error:" prefix - CLI handles that)
|
|
72
72
|
if line:
|
|
73
|
-
error_parts.append(f"
|
|
73
|
+
error_parts.append(f"Line {line}: {message}")
|
|
74
74
|
else:
|
|
75
|
-
error_parts.append(
|
|
75
|
+
error_parts.append(message)
|
|
76
76
|
|
|
77
77
|
# Add context if available
|
|
78
78
|
if context:
|
|
@@ -363,11 +363,11 @@ class CSSLRuntime:
|
|
|
363
363
|
"""Format a detailed error with source context"""
|
|
364
364
|
error_parts = []
|
|
365
365
|
|
|
366
|
-
# Main error header
|
|
366
|
+
# Main error header (no "Error:" prefix - CLI handles that)
|
|
367
367
|
if line and line > 0:
|
|
368
|
-
error_parts.append(f"
|
|
368
|
+
error_parts.append(f"Line {line} in {self._current_file}:")
|
|
369
369
|
else:
|
|
370
|
-
error_parts.append(f"
|
|
370
|
+
error_parts.append(f"In {self._current_file}:")
|
|
371
371
|
|
|
372
372
|
# Extract message without existing line info
|
|
373
373
|
clean_msg = message
|
|
@@ -1005,13 +1005,29 @@ class CSSLRuntime:
|
|
|
1005
1005
|
overwrites_func = func_info.get('overwrites')
|
|
1006
1006
|
overwrites_is_python = func_info.get('overwrites_is_python', False)
|
|
1007
1007
|
|
|
1008
|
+
# Get append/overwrite reference info (&Class::method syntax)
|
|
1009
|
+
append_mode = func_info.get('append_mode', False)
|
|
1010
|
+
append_ref_class = func_info.get('append_ref_class')
|
|
1011
|
+
append_ref_member = func_info.get('append_ref_member')
|
|
1012
|
+
|
|
1008
1013
|
# Store function extends info for runtime use
|
|
1009
1014
|
if extends_func:
|
|
1010
1015
|
node.value['_extends_resolved'] = self._resolve_function_target(
|
|
1011
1016
|
extends_func, extends_is_python
|
|
1012
1017
|
)
|
|
1013
1018
|
|
|
1014
|
-
# Handle
|
|
1019
|
+
# Handle &Class::method syntax
|
|
1020
|
+
# Without ++ = full replacement
|
|
1021
|
+
# With ++ = append (run original first, then new code)
|
|
1022
|
+
if append_ref_class:
|
|
1023
|
+
if append_mode:
|
|
1024
|
+
# Append mode: wrap original to run original + new
|
|
1025
|
+
self._append_to_target(append_ref_class, append_ref_member, node)
|
|
1026
|
+
else:
|
|
1027
|
+
# Full replacement
|
|
1028
|
+
self._overwrite_target(append_ref_class, append_ref_member, node)
|
|
1029
|
+
|
|
1030
|
+
# Handle overwrites keyword - replace the target function
|
|
1015
1031
|
if overwrites_func:
|
|
1016
1032
|
target = self._resolve_function_target(overwrites_func, overwrites_is_python)
|
|
1017
1033
|
if target is not None:
|
|
@@ -1054,6 +1070,142 @@ class CSSLRuntime:
|
|
|
1054
1070
|
return self._call_function(func_node, list(args), kwargs)
|
|
1055
1071
|
return wrapper
|
|
1056
1072
|
|
|
1073
|
+
def _overwrite_target(self, ref_class: str, ref_member: str, replacement_node: ASTNode):
|
|
1074
|
+
"""Overwrite a class method or function with the replacement.
|
|
1075
|
+
|
|
1076
|
+
Handles:
|
|
1077
|
+
- &ClassName::method - Overwrite method in CSSL class
|
|
1078
|
+
- &$PyObject.method - Overwrite method in Python shared object
|
|
1079
|
+
- &functionName - Overwrite standalone function
|
|
1080
|
+
"""
|
|
1081
|
+
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
1082
|
+
|
|
1083
|
+
# Handle Python shared objects
|
|
1084
|
+
if ref_class.startswith('$'):
|
|
1085
|
+
var_name = ref_class[1:]
|
|
1086
|
+
ref_obj = _live_objects.get(var_name)
|
|
1087
|
+
if ref_obj is None:
|
|
1088
|
+
ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
|
|
1089
|
+
|
|
1090
|
+
if ref_obj is None:
|
|
1091
|
+
return
|
|
1092
|
+
|
|
1093
|
+
# Unwrap SharedObjectProxy
|
|
1094
|
+
if isinstance(ref_obj, SharedObjectProxy):
|
|
1095
|
+
ref_obj = ref_obj._obj
|
|
1096
|
+
|
|
1097
|
+
# Overwrite Python object method
|
|
1098
|
+
if ref_member and hasattr(ref_obj, ref_member):
|
|
1099
|
+
wrapper = self._create_python_wrapper(replacement_node)
|
|
1100
|
+
try:
|
|
1101
|
+
setattr(ref_obj, ref_member, wrapper)
|
|
1102
|
+
except (AttributeError, TypeError):
|
|
1103
|
+
pass # Can't overwrite (immutable or builtin)
|
|
1104
|
+
return
|
|
1105
|
+
|
|
1106
|
+
# Handle CSSL class method overwrite
|
|
1107
|
+
target_class = self.scope.get(ref_class) or self.global_scope.get(ref_class)
|
|
1108
|
+
if target_class is None:
|
|
1109
|
+
# Maybe it's a standalone function reference (no ::member)
|
|
1110
|
+
if ref_member is None:
|
|
1111
|
+
# &functionName - overwrite the function
|
|
1112
|
+
self.scope.set(ref_class, replacement_node)
|
|
1113
|
+
self.global_scope.set(ref_class, replacement_node)
|
|
1114
|
+
return
|
|
1115
|
+
|
|
1116
|
+
if isinstance(target_class, CSSLClass) and ref_member:
|
|
1117
|
+
# Overwrite method in the class
|
|
1118
|
+
if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
|
|
1119
|
+
target_class.methods[ref_member] = replacement_node
|
|
1120
|
+
# Also check members list
|
|
1121
|
+
if hasattr(target_class, 'members'):
|
|
1122
|
+
for i, member in enumerate(target_class.members):
|
|
1123
|
+
if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
|
|
1124
|
+
target_class.members[i] = replacement_node
|
|
1125
|
+
break
|
|
1126
|
+
|
|
1127
|
+
def _append_to_target(self, ref_class: str, ref_member: str, append_node: ASTNode):
|
|
1128
|
+
"""Append new code to an existing class method or function.
|
|
1129
|
+
|
|
1130
|
+
Creates a wrapper that runs original first, then the appended code.
|
|
1131
|
+
Handles:
|
|
1132
|
+
- &ClassName::method ++ - Append to method in CSSL class
|
|
1133
|
+
- &$PyObject.method ++ - Append to method in Python shared object
|
|
1134
|
+
- &functionName ++ - Append to standalone function
|
|
1135
|
+
"""
|
|
1136
|
+
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
1137
|
+
|
|
1138
|
+
# Handle Python shared objects
|
|
1139
|
+
if ref_class.startswith('$'):
|
|
1140
|
+
var_name = ref_class[1:]
|
|
1141
|
+
ref_obj = _live_objects.get(var_name)
|
|
1142
|
+
if ref_obj is None:
|
|
1143
|
+
ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
|
|
1144
|
+
|
|
1145
|
+
if ref_obj is None:
|
|
1146
|
+
return
|
|
1147
|
+
|
|
1148
|
+
if isinstance(ref_obj, SharedObjectProxy):
|
|
1149
|
+
ref_obj = ref_obj._obj
|
|
1150
|
+
|
|
1151
|
+
# Create wrapper that calls original + new
|
|
1152
|
+
if ref_member and hasattr(ref_obj, ref_member):
|
|
1153
|
+
original_method = getattr(ref_obj, ref_member)
|
|
1154
|
+
runtime = self
|
|
1155
|
+
def appended_wrapper(*args, **kwargs):
|
|
1156
|
+
# Run original first
|
|
1157
|
+
result = None
|
|
1158
|
+
if callable(original_method):
|
|
1159
|
+
try:
|
|
1160
|
+
result = original_method(*args, **kwargs)
|
|
1161
|
+
except:
|
|
1162
|
+
pass
|
|
1163
|
+
# Then run appended code
|
|
1164
|
+
return runtime._call_function(append_node, list(args), kwargs)
|
|
1165
|
+
try:
|
|
1166
|
+
setattr(ref_obj, ref_member, appended_wrapper)
|
|
1167
|
+
except (AttributeError, TypeError):
|
|
1168
|
+
pass
|
|
1169
|
+
return
|
|
1170
|
+
|
|
1171
|
+
# Handle CSSL class method append
|
|
1172
|
+
target_class = self.scope.get(ref_class) or self.global_scope.get(ref_class)
|
|
1173
|
+
if target_class is None:
|
|
1174
|
+
# Standalone function append
|
|
1175
|
+
if ref_member is None:
|
|
1176
|
+
original_func = self.scope.get(ref_class) or self.global_scope.get(ref_class)
|
|
1177
|
+
if original_func:
|
|
1178
|
+
# Store original in append_node so it can run first
|
|
1179
|
+
append_node.value['_original_func'] = original_func
|
|
1180
|
+
self.scope.set(ref_class, append_node)
|
|
1181
|
+
self.global_scope.set(ref_class, append_node)
|
|
1182
|
+
return
|
|
1183
|
+
|
|
1184
|
+
if isinstance(target_class, CSSLClass) and ref_member:
|
|
1185
|
+
# Find original method
|
|
1186
|
+
original_method = None
|
|
1187
|
+
if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
|
|
1188
|
+
original_method = target_class.methods.get(ref_member)
|
|
1189
|
+
|
|
1190
|
+
if original_method is None and hasattr(target_class, 'members'):
|
|
1191
|
+
for member in target_class.members:
|
|
1192
|
+
if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
|
|
1193
|
+
original_method = member
|
|
1194
|
+
break
|
|
1195
|
+
|
|
1196
|
+
# Store original in append_node for runtime execution
|
|
1197
|
+
if original_method:
|
|
1198
|
+
append_node.value['_original_method'] = original_method
|
|
1199
|
+
|
|
1200
|
+
# Replace with append_node (which will call original first via _call_function)
|
|
1201
|
+
if hasattr(target_class, 'methods') and isinstance(target_class.methods, dict):
|
|
1202
|
+
target_class.methods[ref_member] = append_node
|
|
1203
|
+
if hasattr(target_class, 'members'):
|
|
1204
|
+
for i, member in enumerate(target_class.members):
|
|
1205
|
+
if member.type in ('function', 'FUNCTION') and member.value.get('name') == ref_member:
|
|
1206
|
+
target_class.members[i] = append_node
|
|
1207
|
+
break
|
|
1208
|
+
|
|
1057
1209
|
def _exec_typed_declaration(self, node: ASTNode) -> Any:
|
|
1058
1210
|
"""Execute typed variable declaration: type<T> varName = value;
|
|
1059
1211
|
|
|
@@ -1352,12 +1504,15 @@ class CSSLRuntime:
|
|
|
1352
1504
|
if not self._running:
|
|
1353
1505
|
break
|
|
1354
1506
|
self._execute_node(child)
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1507
|
+
except CSSLReturn:
|
|
1508
|
+
# Parent returned - that's fine, we just want the local vars
|
|
1509
|
+
pass
|
|
1358
1510
|
except:
|
|
1359
1511
|
pass
|
|
1360
1512
|
finally:
|
|
1513
|
+
# ALWAYS copy local vars (even if parent returned)
|
|
1514
|
+
for name, value in temp_scope.variables.items():
|
|
1515
|
+
new_scope.set(name, value)
|
|
1361
1516
|
self.scope = old_scope
|
|
1362
1517
|
|
|
1363
1518
|
# Bind parameters - handle both positional and named arguments
|
|
@@ -1420,7 +1575,7 @@ class CSSLRuntime:
|
|
|
1420
1575
|
|
|
1421
1576
|
# Check exclude_type: *[type] - must NOT return excluded type
|
|
1422
1577
|
exclude_type = func_info.get('exclude_type')
|
|
1423
|
-
if exclude_type:
|
|
1578
|
+
if exclude_type and isinstance(exclude_type, str):
|
|
1424
1579
|
type_map = {
|
|
1425
1580
|
'string': str, 'int': int, 'float': float, 'bool': bool,
|
|
1426
1581
|
'null': type(None), 'none': type(None),
|
|
@@ -1431,9 +1586,63 @@ class CSSLRuntime:
|
|
|
1431
1586
|
if isinstance(return_value, tuple):
|
|
1432
1587
|
for val in return_value:
|
|
1433
1588
|
if excluded_py_type and isinstance(val, excluded_py_type):
|
|
1434
|
-
raise
|
|
1589
|
+
raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}' values")
|
|
1435
1590
|
elif excluded_py_type and isinstance(return_value, excluded_py_type):
|
|
1436
|
-
raise
|
|
1591
|
+
raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}'")
|
|
1592
|
+
|
|
1593
|
+
# Enforce return type for typed functions (like C++)
|
|
1594
|
+
# Typed functions MUST return the declared type
|
|
1595
|
+
# Exception: 'meta' modifier allows any return type
|
|
1596
|
+
enforce_return_type = func_info.get('enforce_return_type', False)
|
|
1597
|
+
return_type = func_info.get('return_type')
|
|
1598
|
+
|
|
1599
|
+
if enforce_return_type and return_type and return_type != 'void':
|
|
1600
|
+
# Type mapping from CSSL types to Python types
|
|
1601
|
+
type_validate_map = {
|
|
1602
|
+
'string': str, 'int': int, 'float': (int, float), 'bool': bool,
|
|
1603
|
+
'list': list, 'array': list, 'dict': dict, 'json': dict,
|
|
1604
|
+
'dynamic': object, # Any type
|
|
1605
|
+
'void': type(None),
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
# Generic container types - accept lists/tuples
|
|
1609
|
+
container_types = {
|
|
1610
|
+
'vector', 'stack', 'datastruct', 'dataspace',
|
|
1611
|
+
'shuffled', 'iterator', 'combo', 'openquote', 'map'
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
if return_type in container_types:
|
|
1615
|
+
# Container types accept list, tuple, dict depending on type
|
|
1616
|
+
if return_type == 'map':
|
|
1617
|
+
expected = dict
|
|
1618
|
+
elif return_type == 'shuffled':
|
|
1619
|
+
expected = (list, tuple)
|
|
1620
|
+
else:
|
|
1621
|
+
expected = (list, tuple, object)
|
|
1622
|
+
|
|
1623
|
+
if not isinstance(return_value, expected):
|
|
1624
|
+
func_name = func_info.get('name', 'unknown')
|
|
1625
|
+
actual_type = type(return_value).__name__
|
|
1626
|
+
raise CSSLRuntimeError(
|
|
1627
|
+
f"Type error in '{func_name}': declared return type '{return_type}' "
|
|
1628
|
+
f"but returned '{actual_type}'. Typed functions must return declared type."
|
|
1629
|
+
)
|
|
1630
|
+
elif return_type in type_validate_map:
|
|
1631
|
+
expected = type_validate_map[return_type]
|
|
1632
|
+
if expected != object and return_value is not None:
|
|
1633
|
+
if not isinstance(return_value, expected):
|
|
1634
|
+
func_name = func_info.get('name', 'unknown')
|
|
1635
|
+
actual_type = type(return_value).__name__
|
|
1636
|
+
raise CSSLRuntimeError(
|
|
1637
|
+
f"Type error in '{func_name}': declared return type '{return_type}' "
|
|
1638
|
+
f"but returned '{actual_type}'. Typed functions must return declared type."
|
|
1639
|
+
)
|
|
1640
|
+
|
|
1641
|
+
# Check non_null: function must return a value (not None)
|
|
1642
|
+
non_null = func_info.get('non_null', False)
|
|
1643
|
+
if non_null and return_value is None:
|
|
1644
|
+
func_name = func_info.get('name', 'unknown')
|
|
1645
|
+
raise CSSLRuntimeError(f"Non-null function '{func_name}' returned null/None")
|
|
1437
1646
|
|
|
1438
1647
|
return return_value
|
|
1439
1648
|
except Exception as e:
|
|
@@ -3022,7 +3231,7 @@ class CSSLRuntime:
|
|
|
3022
3231
|
'json': dict,
|
|
3023
3232
|
}
|
|
3024
3233
|
|
|
3025
|
-
excluded_py_type = type_map.get(exclude_type.lower())
|
|
3234
|
+
excluded_py_type = type_map.get(exclude_type.lower() if isinstance(exclude_type, str) else exclude_type)
|
|
3026
3235
|
if excluded_py_type and isinstance(value, excluded_py_type):
|
|
3027
3236
|
raise self._format_error(
|
|
3028
3237
|
node.line if hasattr(node, 'line') else 0,
|
|
@@ -3574,12 +3783,34 @@ class CSSLRuntime:
|
|
|
3574
3783
|
|
|
3575
3784
|
# Resolve the class/instance reference
|
|
3576
3785
|
if ref_class.startswith('$'):
|
|
3577
|
-
# Dynamic instance reference: &$instanceVar::member
|
|
3786
|
+
# Dynamic instance reference: &$instanceVar::member or &$PyObject.method
|
|
3578
3787
|
var_name = ref_class[1:]
|
|
3579
|
-
|
|
3788
|
+
|
|
3789
|
+
# First check in _live_objects for Python shared objects
|
|
3790
|
+
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
3791
|
+
ref_obj = _live_objects.get(var_name)
|
|
3792
|
+
if ref_obj is None:
|
|
3793
|
+
ref_obj = self.scope.get(var_name) or self.global_scope.get(var_name)
|
|
3794
|
+
|
|
3580
3795
|
if ref_obj is None:
|
|
3581
3796
|
return # Instance not found, skip silently
|
|
3582
3797
|
|
|
3798
|
+
# Handle Python shared objects
|
|
3799
|
+
if isinstance(ref_obj, SharedObjectProxy):
|
|
3800
|
+
ref_obj = ref_obj._obj
|
|
3801
|
+
|
|
3802
|
+
# If it's a Python object (not CSSL), call the method directly
|
|
3803
|
+
if not isinstance(ref_obj, (CSSLInstance, CSSLClass)):
|
|
3804
|
+
if ref_member and hasattr(ref_obj, ref_member):
|
|
3805
|
+
method = getattr(ref_obj, ref_member)
|
|
3806
|
+
if callable(method):
|
|
3807
|
+
try:
|
|
3808
|
+
method(*args, **kwargs)
|
|
3809
|
+
except TypeError:
|
|
3810
|
+
# Try without args
|
|
3811
|
+
method()
|
|
3812
|
+
return
|
|
3813
|
+
|
|
3583
3814
|
if isinstance(ref_obj, CSSLInstance):
|
|
3584
3815
|
# Get the class definition from the instance
|
|
3585
3816
|
target_class = ref_obj.class_def
|
|
@@ -3799,9 +4030,19 @@ class CSSLRuntime:
|
|
|
3799
4030
|
self.scope = new_scope
|
|
3800
4031
|
self._current_instance = instance
|
|
3801
4032
|
|
|
4033
|
+
original_return = None
|
|
3802
4034
|
try:
|
|
4035
|
+
# Handle append mode via _append_to_target (stored original)
|
|
4036
|
+
original_method = func_info.get('_original_method')
|
|
4037
|
+
if original_method:
|
|
4038
|
+
# Execute original method first - capture return for fallback
|
|
4039
|
+
try:
|
|
4040
|
+
original_return = self._call_method(instance, original_method, args, kwargs)
|
|
4041
|
+
except CSSLReturn as ret:
|
|
4042
|
+
original_return = ret.value
|
|
4043
|
+
|
|
3803
4044
|
# Handle append mode (++) - execute referenced parent method first
|
|
3804
|
-
|
|
4045
|
+
elif append_mode and append_ref_class:
|
|
3805
4046
|
self._execute_append_reference(
|
|
3806
4047
|
instance, append_ref_class, append_ref_member,
|
|
3807
4048
|
args, kwargs, {}, is_constructor=False
|
|
@@ -3822,7 +4063,8 @@ class CSSLRuntime:
|
|
|
3822
4063
|
self.scope = old_scope
|
|
3823
4064
|
self._current_instance = old_instance
|
|
3824
4065
|
|
|
3825
|
-
return
|
|
4066
|
+
# If no return in appended code, use original's return
|
|
4067
|
+
return original_return
|
|
3826
4068
|
|
|
3827
4069
|
def _eval_member_access(self, node: ASTNode) -> Any:
|
|
3828
4070
|
"""Evaluate member access"""
|
includecpp/core/cssl_bridge.py
CHANGED
|
@@ -455,12 +455,12 @@ class CsslLang:
|
|
|
455
455
|
|
|
456
456
|
return result
|
|
457
457
|
except Exception as e:
|
|
458
|
-
# Format error message nicely
|
|
458
|
+
# Format error message nicely - don't add prefixes, let CLI handle that
|
|
459
459
|
error_msg = str(e)
|
|
460
|
-
#
|
|
460
|
+
# Strip any existing CSSL Error: prefix to avoid duplication
|
|
461
461
|
if error_msg.startswith("CSSL Error:"):
|
|
462
|
-
|
|
463
|
-
raise RuntimeError(
|
|
462
|
+
error_msg = error_msg[11:].strip()
|
|
463
|
+
raise RuntimeError(error_msg) from e
|
|
464
464
|
|
|
465
465
|
def exec(self, path_or_code: str, *args) -> Any:
|
|
466
466
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IncludeCPP
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.1
|
|
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
|
|
@@ -27,6 +27,7 @@ Requires-Dist: pybind11>=2.11.0
|
|
|
27
27
|
Requires-Dist: click>=8.0.0
|
|
28
28
|
Requires-Dist: typing-extensions>=4.0.0
|
|
29
29
|
Requires-Dist: requests>=2.28.0
|
|
30
|
+
Requires-Dist: colorama>=0.4.0
|
|
30
31
|
Dynamic: author-email
|
|
31
32
|
Dynamic: home-page
|
|
32
33
|
Dynamic: license-file
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
includecpp/__init__.py,sha256=
|
|
1
|
+
includecpp/__init__.py,sha256=sYebQW4N2qP2sozPh4X7krZm_jf0N1e1MB6UrncbLBY,1672
|
|
2
2
|
includecpp/__init__.pyi,sha256=uSDYlbqd2TinmrdepmE_zvN25jd3Co2cgyPzXgDpopM,7193
|
|
3
3
|
includecpp/__main__.py,sha256=d6QK0PkvUe1ENofpmHRAg3bwNbZr8PiRscfI3-WRfVg,72
|
|
4
4
|
includecpp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
includecpp/cli/__init__.py,sha256=Yda-4a5QJb_tKu35YQNfc5lu-LewTsM5abqNNkzS47M,113
|
|
6
|
-
includecpp/cli/commands.py,sha256=
|
|
6
|
+
includecpp/cli/commands.py,sha256=bSUVlj_LXiZJMxdZBg7pI35fICvVNoIRJdwrvXZsMFY,350247
|
|
7
7
|
includecpp/cli/config_parser.py,sha256=KveeYUg2TA9sC5hKVzYYfgdNm2WfLG5y7_yxgBWn9yM,4886
|
|
8
8
|
includecpp/core/__init__.py,sha256=L1bT6oikTjdto-6Px7DpjePtM07ymo3Bnov1saZzsGg,390
|
|
9
9
|
includecpp/core/ai_integration.py,sha256=PW6yFDqdXjfchpfKTKg59AOLhLry9kqJEGf_65BztrY,87603
|
|
@@ -11,7 +11,7 @@ includecpp/core/build_manager.py,sha256=uLuYsuiC6OsOGaU5wAJfl4M3IbdnIDgogfMd8VsV
|
|
|
11
11
|
includecpp/core/cpp_api.py,sha256=8y_B1L18rhSBZln654xPPzqO2PdvAlLpJrfEjzl7Wnc,14039
|
|
12
12
|
includecpp/core/cpp_api.pyi,sha256=IEiaKqaPItnn6rjL7aK32D3o9FYmRYCgCZbqiQNUwdc,3496
|
|
13
13
|
includecpp/core/cppy_converter.py,sha256=b7yqu-aoa0wShNY0GvQT67TnNhYya4GyYmG7oDdqDV4,156686
|
|
14
|
-
includecpp/core/cssl_bridge.py,sha256=
|
|
14
|
+
includecpp/core/cssl_bridge.py,sha256=AyYD-vFkxRtWy1LZv6OP_XJtPRWIPTf2YVHOiajmSY8,43016
|
|
15
15
|
includecpp/core/cssl_bridge.pyi,sha256=tQxb3lneufgVmXSAqDUwjoluUNo8Wa5QIOnaL8ai6q0,12055
|
|
16
16
|
includecpp/core/error_catalog.py,sha256=VS3N-P0yEbiHimsDPtcaYfrUb7mXQ-7pqw18PtSngaU,33869
|
|
17
17
|
includecpp/core/error_formatter.py,sha256=7-MzRIT8cM4uODxy0IZ9pu7pqR4Pq2I8Si0QQZHjmVc,39239
|
|
@@ -19,15 +19,15 @@ includecpp/core/exceptions.py,sha256=szeF4qdzi_q8hBBZi7mJxkliyQ0crplkLYe0ymlBGtk
|
|
|
19
19
|
includecpp/core/path_discovery.py,sha256=jI0oSq6Hsd4LKXmU4dOiGSrXcEO_KWMXfQ5_ylBmXvU,2561
|
|
20
20
|
includecpp/core/project_ui.py,sha256=la2EQZKmUkJGuJxnbs09hH1ZhBh9bfndo6okzZsk2dQ,141134
|
|
21
21
|
includecpp/core/settings_ui.py,sha256=B2SlwgdplF2KiBk5UYf2l8Jjifjd0F-FmBP0DPsVCEQ,11798
|
|
22
|
-
includecpp/core/cssl/CSSL_DOCUMENTATION.md,sha256=
|
|
22
|
+
includecpp/core/cssl/CSSL_DOCUMENTATION.md,sha256=0zutiYNa-ohTzZ5fWsEgMD5ThOvyTwuMgmkzSBr7yrA,32491
|
|
23
23
|
includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md,sha256=I_bVeKWlbcgHYkl2o9L2vk3r5sDvG44bGh__RJIYduw,28222
|
|
24
24
|
includecpp/core/cssl/__init__.py,sha256=scDXRBNK2L6A8qmlpNyaqQj6BFcSfPInBlucdeNfMF0,1975
|
|
25
25
|
includecpp/core/cssl/cssl_builtins.py,sha256=oPsPyQk5b0b1I02Y80oIaDX39GOeG32-nBPEqwbo_Pw,105110
|
|
26
26
|
includecpp/core/cssl/cssl_builtins.pyi,sha256=-yr9JbxHKFv9Vc1iufChcqCQvNQLL3-Ow_Hgg0YwQnc,135180
|
|
27
27
|
includecpp/core/cssl/cssl_events.py,sha256=nupIcXW_Vjdud7zCU6hdwkQRQ0MujlPM7Tk2u7eDAiY,21013
|
|
28
28
|
includecpp/core/cssl/cssl_modules.py,sha256=cUg0-zdymMnWWTsA_BUrW5dx4R04dHpKcUhm-Wfiwwo,103006
|
|
29
|
-
includecpp/core/cssl/cssl_parser.py,sha256=
|
|
30
|
-
includecpp/core/cssl/cssl_runtime.py,sha256=
|
|
29
|
+
includecpp/core/cssl/cssl_parser.py,sha256=4GHFcGa6jv7sgQxP0wWqCci8eS4E8Ie2t-qfJ2Ux9BU,154072
|
|
30
|
+
includecpp/core/cssl/cssl_runtime.py,sha256=eSmR1eq9by5VXjsYZp3x8ksJj4PaUR46iqsby2Y0bAI,209792
|
|
31
31
|
includecpp/core/cssl/cssl_syntax.py,sha256=bgo3NFehoPTQa5dqwNd_CstkVGVCNYAXbGYUcu5BEN0,16982
|
|
32
32
|
includecpp/core/cssl/cssl_types.py,sha256=7jbrtZf3xmVQJA_mnL9iYrmdjhjuc4--mxxNigi7fsk,53425
|
|
33
33
|
includecpp/generator/__init__.py,sha256=Rsy41bwimaEloD3gDRR_znPfIJzIsCFuWZgCTJBLJlc,62
|
|
@@ -45,9 +45,9 @@ includecpp/vscode/cssl/images/cssl.png,sha256=BxAGsnfS0ZzzCvqV6Zb1OAJAZpDUoXlR86
|
|
|
45
45
|
includecpp/vscode/cssl/images/cssl_pl.png,sha256=z4WMk7g6YCTbUUbSFk343BO6yi_OmNEVYkRenWGydwM,799
|
|
46
46
|
includecpp/vscode/cssl/snippets/cssl.snippets.json,sha256=uV3nHJyQ5f7Pr3FzfbQT2VZOEY3AlGs4wrmqe884jm4,37372
|
|
47
47
|
includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json,sha256=FZw1_VDz1ll4ZBZeGqo-935CK5RuF2kD75rNp5tVdC0,35068
|
|
48
|
-
includecpp-
|
|
49
|
-
includecpp-
|
|
50
|
-
includecpp-
|
|
51
|
-
includecpp-
|
|
52
|
-
includecpp-
|
|
53
|
-
includecpp-
|
|
48
|
+
includecpp-4.0.1.dist-info/licenses/LICENSE,sha256=fWCsGGsiWZir0UzDd20Hh-3wtRyk1zqUntvtVuAWhvc,1093
|
|
49
|
+
includecpp-4.0.1.dist-info/METADATA,sha256=D-S3OTYYEksZOF-tpxhFNXaBwFdUNxuI3HxIsNDj58Q,22542
|
|
50
|
+
includecpp-4.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
includecpp-4.0.1.dist-info/entry_points.txt,sha256=6A5Mif9gi0139Bf03W5plAb3wnAgbNaEVe1HJoGE-2o,59
|
|
52
|
+
includecpp-4.0.1.dist-info/top_level.txt,sha256=RFUaR1KG-M6mCYwP6w4ydP5Cgc8yNbP78jxGAvyjMa8,11
|
|
53
|
+
includecpp-4.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|