IncludeCPP 3.8.3__py3-none-any.whl → 3.8.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/__init__.py +1 -1
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +312 -1
- includecpp/core/cssl/cssl_builtins.py +133 -0
- includecpp/core/cssl/cssl_parser.py +314 -7
- includecpp/core/cssl/cssl_runtime.py +414 -6
- includecpp/core/cssl/cssl_types.py +58 -9
- includecpp/vscode/cssl/package.json +1 -1
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +173 -5
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/METADATA +1 -1
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/RECORD +14 -14
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/WHEEL +0 -0
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/entry_points.txt +0 -0
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.8.3.dist-info → includecpp-3.8.5.dist-info}/top_level.txt +0 -0
|
@@ -715,17 +715,60 @@ class CSSLRuntime:
|
|
|
715
715
|
|
|
716
716
|
Parses class members and methods, creating a CSSLClass object
|
|
717
717
|
that can be instantiated with 'new'.
|
|
718
|
+
Supports inheritance via 'extends' keyword and method overwriting via 'overwrites'.
|
|
718
719
|
"""
|
|
719
720
|
class_info = node.value
|
|
720
721
|
class_name = class_info.get('name')
|
|
722
|
+
extends_class_name = class_info.get('extends')
|
|
723
|
+
extends_is_python = class_info.get('extends_is_python', False)
|
|
724
|
+
overwrites_class_name = class_info.get('overwrites')
|
|
725
|
+
overwrites_is_python = class_info.get('overwrites_is_python', False)
|
|
726
|
+
|
|
727
|
+
# Resolve parent class if extends is specified
|
|
728
|
+
parent_class = None
|
|
729
|
+
if extends_class_name:
|
|
730
|
+
if extends_is_python:
|
|
731
|
+
# extends $PythonObject - look up in shared objects
|
|
732
|
+
from ..cssl_bridge import _live_objects, SharedObjectProxy
|
|
733
|
+
if extends_class_name in _live_objects:
|
|
734
|
+
parent_class = _live_objects[extends_class_name]
|
|
735
|
+
# Unwrap SharedObjectProxy if needed
|
|
736
|
+
if isinstance(parent_class, SharedObjectProxy):
|
|
737
|
+
parent_class = parent_class._obj
|
|
738
|
+
else:
|
|
739
|
+
# Also check scope with $ prefix
|
|
740
|
+
parent_class = self.global_scope.get(f'${extends_class_name}')
|
|
741
|
+
else:
|
|
742
|
+
# Try to resolve from scope (could be CSSL class or variable holding Python object)
|
|
743
|
+
parent_class = self.scope.get(extends_class_name)
|
|
744
|
+
if parent_class is None:
|
|
745
|
+
parent_class = self.global_scope.get(extends_class_name)
|
|
746
|
+
|
|
747
|
+
if parent_class is None:
|
|
748
|
+
raise ValueError(f"Cannot extend unknown class '{extends_class_name}'")
|
|
749
|
+
|
|
750
|
+
# Auto-wrap Python objects for inheritance
|
|
751
|
+
from .cssl_builtins import CSSLizedPythonObject
|
|
752
|
+
if not isinstance(parent_class, (CSSLClass, CSSLizedPythonObject)):
|
|
753
|
+
# Wrap raw Python object
|
|
754
|
+
parent_class = CSSLizedPythonObject(parent_class, self)
|
|
721
755
|
|
|
722
756
|
members = {} # Member variable defaults/types
|
|
723
757
|
methods = {} # Method AST nodes
|
|
724
|
-
|
|
758
|
+
constructors = [] # List of constructors (multiple allowed with constr keyword)
|
|
759
|
+
constructor = None # Primary constructor (backward compatibility)
|
|
760
|
+
|
|
761
|
+
# Get class parameters and extends args
|
|
762
|
+
class_params = class_info.get('class_params', [])
|
|
763
|
+
extends_args = class_info.get('extends_args', [])
|
|
725
764
|
|
|
726
765
|
for child in node.children:
|
|
727
|
-
if child.type == '
|
|
728
|
-
#
|
|
766
|
+
if child.type == 'constructor':
|
|
767
|
+
# New-style constructor from 'constr' keyword
|
|
768
|
+
constructors.append(child)
|
|
769
|
+
|
|
770
|
+
elif child.type == 'function':
|
|
771
|
+
# This is a method or old-style constructor
|
|
729
772
|
func_info = child.value
|
|
730
773
|
method_name = func_info.get('name')
|
|
731
774
|
|
|
@@ -752,22 +795,156 @@ class CSSLRuntime:
|
|
|
752
795
|
name=class_name,
|
|
753
796
|
members=members,
|
|
754
797
|
methods=methods,
|
|
755
|
-
constructor=constructor
|
|
798
|
+
constructor=constructor,
|
|
799
|
+
parent=parent_class
|
|
756
800
|
)
|
|
801
|
+
# Store additional constructor info
|
|
802
|
+
class_def.constructors = constructors # Multiple constructors from 'constr' keyword
|
|
803
|
+
class_def.class_params = class_params # Class-level constructor parameters
|
|
804
|
+
class_def.extends_args = extends_args # Arguments to pass to parent constructor
|
|
757
805
|
|
|
758
806
|
# Register class in scope
|
|
759
807
|
self.scope.set(class_name, class_def)
|
|
760
808
|
self.global_scope.set(class_name, class_def)
|
|
761
809
|
|
|
810
|
+
# Handle class overwrites - replace methods in target class
|
|
811
|
+
if overwrites_class_name:
|
|
812
|
+
self._apply_class_overwrites(
|
|
813
|
+
class_def, overwrites_class_name, overwrites_is_python
|
|
814
|
+
)
|
|
815
|
+
|
|
762
816
|
return class_def
|
|
763
817
|
|
|
818
|
+
def _apply_class_overwrites(self, new_class: CSSLClass, target_name: str, is_python: bool):
|
|
819
|
+
"""Apply method overwrites from new_class to target class/object.
|
|
820
|
+
|
|
821
|
+
When a class has 'overwrites' specified, all methods defined in new_class
|
|
822
|
+
will replace the corresponding methods in the target.
|
|
823
|
+
"""
|
|
824
|
+
from .cssl_builtins import CSSLizedPythonObject
|
|
825
|
+
|
|
826
|
+
# Resolve target
|
|
827
|
+
target = None
|
|
828
|
+
if is_python:
|
|
829
|
+
from ..cssl_bridge import _live_objects
|
|
830
|
+
if target_name in _live_objects:
|
|
831
|
+
target = _live_objects[target_name]
|
|
832
|
+
else:
|
|
833
|
+
target = self.scope.get(target_name)
|
|
834
|
+
if target is None:
|
|
835
|
+
target = self.global_scope.get(target_name)
|
|
836
|
+
|
|
837
|
+
if target is None:
|
|
838
|
+
return # Target not found, silently skip
|
|
839
|
+
|
|
840
|
+
# Get methods to overwrite
|
|
841
|
+
methods_to_overwrite = new_class.methods
|
|
842
|
+
|
|
843
|
+
if is_python and hasattr(target, '__class__'):
|
|
844
|
+
# Python object - overwrite methods on the object/class
|
|
845
|
+
for method_name, method_node in methods_to_overwrite.items():
|
|
846
|
+
# Create a Python-callable wrapper for the CSSL method
|
|
847
|
+
wrapper = self._create_method_wrapper(method_node, target)
|
|
848
|
+
# Set on the object
|
|
849
|
+
try:
|
|
850
|
+
setattr(target, method_name, wrapper)
|
|
851
|
+
except AttributeError:
|
|
852
|
+
# Try setting on class instead
|
|
853
|
+
try:
|
|
854
|
+
setattr(target.__class__, method_name, wrapper)
|
|
855
|
+
except:
|
|
856
|
+
pass
|
|
857
|
+
elif isinstance(target, CSSLClass):
|
|
858
|
+
# CSSL class - directly replace methods
|
|
859
|
+
for method_name, method_node in methods_to_overwrite.items():
|
|
860
|
+
target.methods[method_name] = method_node
|
|
861
|
+
elif isinstance(target, CSSLizedPythonObject):
|
|
862
|
+
# CSSLized Python object - get underlying object and overwrite
|
|
863
|
+
py_obj = target.get_python_obj()
|
|
864
|
+
for method_name, method_node in methods_to_overwrite.items():
|
|
865
|
+
wrapper = self._create_method_wrapper(method_node, py_obj)
|
|
866
|
+
try:
|
|
867
|
+
setattr(py_obj, method_name, wrapper)
|
|
868
|
+
except AttributeError:
|
|
869
|
+
try:
|
|
870
|
+
setattr(py_obj.__class__, method_name, wrapper)
|
|
871
|
+
except:
|
|
872
|
+
pass
|
|
873
|
+
|
|
874
|
+
def _create_method_wrapper(self, method_node: ASTNode, instance: Any):
|
|
875
|
+
"""Create a Python-callable wrapper for a CSSL method that works with an instance."""
|
|
876
|
+
def wrapper(*args, **kwargs):
|
|
877
|
+
# Set up instance context for this->
|
|
878
|
+
old_instance = self._current_instance
|
|
879
|
+
# Create a fake CSSLInstance-like wrapper if needed
|
|
880
|
+
self._current_instance = instance
|
|
881
|
+
try:
|
|
882
|
+
return self._call_function(method_node, list(args), kwargs)
|
|
883
|
+
finally:
|
|
884
|
+
self._current_instance = old_instance
|
|
885
|
+
return wrapper
|
|
886
|
+
|
|
764
887
|
def _exec_function(self, node: ASTNode) -> Any:
|
|
765
|
-
"""Execute function definition -
|
|
888
|
+
"""Execute function definition - registers it and handles extends/overwrites.
|
|
889
|
+
|
|
890
|
+
Syntax:
|
|
891
|
+
define func() { ... }
|
|
892
|
+
define func : extends otherFunc() { ... } - Inherit local vars
|
|
893
|
+
define func : overwrites otherFunc() { ... } - Replace otherFunc
|
|
894
|
+
"""
|
|
766
895
|
func_info = node.value
|
|
767
896
|
func_name = func_info.get('name')
|
|
897
|
+
extends_func = func_info.get('extends')
|
|
898
|
+
extends_is_python = func_info.get('extends_is_python', False)
|
|
899
|
+
overwrites_func = func_info.get('overwrites')
|
|
900
|
+
overwrites_is_python = func_info.get('overwrites_is_python', False)
|
|
901
|
+
|
|
902
|
+
# Store function extends info for runtime use
|
|
903
|
+
if extends_func:
|
|
904
|
+
node.value['_extends_resolved'] = self._resolve_function_target(
|
|
905
|
+
extends_func, extends_is_python
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
# Handle overwrites - replace the target function
|
|
909
|
+
if overwrites_func:
|
|
910
|
+
target = self._resolve_function_target(overwrites_func, overwrites_is_python)
|
|
911
|
+
if target is not None:
|
|
912
|
+
# Store original for reference
|
|
913
|
+
node.value['_overwrites_original'] = target
|
|
914
|
+
# Replace the target function with this one
|
|
915
|
+
if overwrites_is_python:
|
|
916
|
+
from ..cssl_bridge import _live_objects
|
|
917
|
+
if overwrites_func in _live_objects:
|
|
918
|
+
# Create a wrapper that calls the CSSL function
|
|
919
|
+
_live_objects[overwrites_func] = self._create_python_wrapper(node)
|
|
920
|
+
else:
|
|
921
|
+
# Replace in CSSL scope
|
|
922
|
+
self.scope.set(overwrites_func, node)
|
|
923
|
+
self.global_scope.set(overwrites_func, node)
|
|
924
|
+
|
|
925
|
+
# Register the function
|
|
768
926
|
self.scope.set(func_name, node)
|
|
769
927
|
return None
|
|
770
928
|
|
|
929
|
+
def _resolve_function_target(self, name: str, is_python: bool) -> Any:
|
|
930
|
+
"""Resolve a function target for extends/overwrites."""
|
|
931
|
+
if is_python:
|
|
932
|
+
from ..cssl_bridge import _live_objects
|
|
933
|
+
if name in _live_objects:
|
|
934
|
+
return _live_objects[name]
|
|
935
|
+
return self.global_scope.get(f'${name}')
|
|
936
|
+
else:
|
|
937
|
+
target = self.scope.get(name)
|
|
938
|
+
if target is None:
|
|
939
|
+
target = self.global_scope.get(name)
|
|
940
|
+
return target
|
|
941
|
+
|
|
942
|
+
def _create_python_wrapper(self, func_node: ASTNode):
|
|
943
|
+
"""Create a Python-callable wrapper for a CSSL function."""
|
|
944
|
+
def wrapper(*args, **kwargs):
|
|
945
|
+
return self._call_function(func_node, list(args), kwargs)
|
|
946
|
+
return wrapper
|
|
947
|
+
|
|
771
948
|
def _exec_typed_declaration(self, node: ASTNode) -> Any:
|
|
772
949
|
"""Execute typed variable declaration: type<T> varName = value;
|
|
773
950
|
|
|
@@ -1031,6 +1208,9 @@ class CSSLRuntime:
|
|
|
1031
1208
|
func_node: The function AST node
|
|
1032
1209
|
args: List of positional arguments
|
|
1033
1210
|
kwargs: Dict of named arguments (param_name -> value)
|
|
1211
|
+
|
|
1212
|
+
Supports:
|
|
1213
|
+
define func : extends otherFunc() { ... } - Inherit local vars from otherFunc
|
|
1034
1214
|
"""
|
|
1035
1215
|
func_info = func_node.value
|
|
1036
1216
|
params = func_info.get('params', [])
|
|
@@ -1043,6 +1223,34 @@ class CSSLRuntime:
|
|
|
1043
1223
|
# Create new scope
|
|
1044
1224
|
new_scope = Scope(parent=self.scope)
|
|
1045
1225
|
|
|
1226
|
+
# Handle function extends - inherit local vars from extended function
|
|
1227
|
+
extends_resolved = func_info.get('_extends_resolved')
|
|
1228
|
+
if extends_resolved:
|
|
1229
|
+
if callable(extends_resolved):
|
|
1230
|
+
# Python function - call it first to populate any state
|
|
1231
|
+
try:
|
|
1232
|
+
extends_resolved(*args, **kwargs)
|
|
1233
|
+
except:
|
|
1234
|
+
pass
|
|
1235
|
+
elif hasattr(extends_resolved, 'value'):
|
|
1236
|
+
# CSSL function - execute it in a temporary scope to get local vars
|
|
1237
|
+
old_scope = self.scope
|
|
1238
|
+
temp_scope = Scope(parent=self.scope)
|
|
1239
|
+
self.scope = temp_scope
|
|
1240
|
+
try:
|
|
1241
|
+
# Execute extended function body to populate local vars
|
|
1242
|
+
for child in extends_resolved.children:
|
|
1243
|
+
if not self._running:
|
|
1244
|
+
break
|
|
1245
|
+
self._execute(child)
|
|
1246
|
+
# Copy all local vars to new scope
|
|
1247
|
+
for name, value in temp_scope._vars.items():
|
|
1248
|
+
new_scope.set(name, value)
|
|
1249
|
+
except:
|
|
1250
|
+
pass
|
|
1251
|
+
finally:
|
|
1252
|
+
self.scope = old_scope
|
|
1253
|
+
|
|
1046
1254
|
# Bind parameters - handle both positional and named arguments
|
|
1047
1255
|
for i, param in enumerate(params):
|
|
1048
1256
|
# Extract param name and type from dict format: {'name': 'a', 'type': 'int'}
|
|
@@ -1302,6 +1510,78 @@ class CSSLRuntime:
|
|
|
1302
1510
|
"""Execute continue statement"""
|
|
1303
1511
|
raise CSSLContinue()
|
|
1304
1512
|
|
|
1513
|
+
def _exec_constructor(self, node: ASTNode) -> Any:
|
|
1514
|
+
"""Execute constructor node - only called when encountered directly.
|
|
1515
|
+
|
|
1516
|
+
Normally constructors are executed through _call_constructor in _eval_new.
|
|
1517
|
+
This handles cases where a constructor node is executed in other contexts.
|
|
1518
|
+
"""
|
|
1519
|
+
# Constructor nodes should be handled during class instantiation
|
|
1520
|
+
# If we reach here, it's in a context where the constructor is stored but not executed
|
|
1521
|
+
return None
|
|
1522
|
+
|
|
1523
|
+
def _exec_super_call(self, node: ASTNode) -> Any:
|
|
1524
|
+
"""Execute super() call to invoke parent constructor or method.
|
|
1525
|
+
|
|
1526
|
+
Syntax:
|
|
1527
|
+
super() - Call parent constructor with no args
|
|
1528
|
+
super(arg1, arg2) - Call parent constructor with args
|
|
1529
|
+
super::method() - Call specific parent method
|
|
1530
|
+
super::method(args) - Call specific parent method with args
|
|
1531
|
+
"""
|
|
1532
|
+
if self._current_instance is None:
|
|
1533
|
+
raise CSSLRuntimeError(
|
|
1534
|
+
"super() called outside of class context",
|
|
1535
|
+
node.line if hasattr(node, 'line') else 0,
|
|
1536
|
+
hint="super() can only be used inside class constructors and methods"
|
|
1537
|
+
)
|
|
1538
|
+
|
|
1539
|
+
instance = self._current_instance
|
|
1540
|
+
parent = getattr(instance, '_parent_class', None)
|
|
1541
|
+
|
|
1542
|
+
if parent is None:
|
|
1543
|
+
raise CSSLRuntimeError(
|
|
1544
|
+
"super() called but class has no parent",
|
|
1545
|
+
node.line if hasattr(node, 'line') else 0,
|
|
1546
|
+
hint="super() requires the class to extend another class"
|
|
1547
|
+
)
|
|
1548
|
+
|
|
1549
|
+
method_name = node.value.get('method')
|
|
1550
|
+
args = [self._evaluate(arg) for arg in node.value.get('args', [])]
|
|
1551
|
+
|
|
1552
|
+
from .cssl_builtins import CSSLizedPythonObject
|
|
1553
|
+
|
|
1554
|
+
if method_name:
|
|
1555
|
+
# super::method() - call specific parent method
|
|
1556
|
+
if isinstance(parent, CSSLClass):
|
|
1557
|
+
method = parent.methods.get(method_name)
|
|
1558
|
+
if method:
|
|
1559
|
+
return self._call_method(instance, method, args, {})
|
|
1560
|
+
else:
|
|
1561
|
+
raise CSSLRuntimeError(
|
|
1562
|
+
f"Parent class has no method '{method_name}'",
|
|
1563
|
+
node.line if hasattr(node, 'line') else 0
|
|
1564
|
+
)
|
|
1565
|
+
elif isinstance(parent, CSSLizedPythonObject):
|
|
1566
|
+
py_obj = parent.get_python_obj()
|
|
1567
|
+
if hasattr(py_obj, method_name):
|
|
1568
|
+
method = getattr(py_obj, method_name)
|
|
1569
|
+
return method(*args)
|
|
1570
|
+
else:
|
|
1571
|
+
raise CSSLRuntimeError(
|
|
1572
|
+
f"Parent Python object has no method '{method_name}'",
|
|
1573
|
+
node.line if hasattr(node, 'line') else 0
|
|
1574
|
+
)
|
|
1575
|
+
elif hasattr(parent, method_name):
|
|
1576
|
+
method = getattr(parent, method_name)
|
|
1577
|
+
return method(*args)
|
|
1578
|
+
else:
|
|
1579
|
+
# super() - call parent constructor
|
|
1580
|
+
self._call_parent_constructor(instance, args)
|
|
1581
|
+
instance._parent_constructor_called = True
|
|
1582
|
+
|
|
1583
|
+
return None
|
|
1584
|
+
|
|
1305
1585
|
def _exec_try(self, node: ASTNode) -> Any:
|
|
1306
1586
|
"""Execute try/catch block"""
|
|
1307
1587
|
try:
|
|
@@ -2887,6 +3167,8 @@ class CSSLRuntime:
|
|
|
2887
3167
|
"""Evaluate 'new ClassName(args)' expression.
|
|
2888
3168
|
|
|
2889
3169
|
Creates a new instance of a CSSL class and calls its constructor.
|
|
3170
|
+
Supports multiple constructors (constr keyword), class parameters,
|
|
3171
|
+
and automatic parent constructor calling.
|
|
2890
3172
|
"""
|
|
2891
3173
|
class_name = node.value.get('class')
|
|
2892
3174
|
args = [self._evaluate(arg) for arg in node.value.get('args', [])]
|
|
@@ -2914,12 +3196,130 @@ class CSSLRuntime:
|
|
|
2914
3196
|
# Create new instance
|
|
2915
3197
|
instance = CSSLInstance(class_def)
|
|
2916
3198
|
|
|
2917
|
-
#
|
|
3199
|
+
# Store parent class reference for super() calls
|
|
3200
|
+
instance._parent_class = class_def.parent
|
|
3201
|
+
instance._parent_constructor_called = False
|
|
3202
|
+
|
|
3203
|
+
# Get class params and extends args
|
|
3204
|
+
class_params = getattr(class_def, 'class_params', [])
|
|
3205
|
+
extends_args = getattr(class_def, 'extends_args', [])
|
|
3206
|
+
constructors = getattr(class_def, 'constructors', [])
|
|
3207
|
+
|
|
3208
|
+
# Bind class_params to instance scope (they receive values from constructor args)
|
|
3209
|
+
# These are the implicit constructor parameters defined in class declaration
|
|
3210
|
+
param_values = {}
|
|
3211
|
+
for i, param in enumerate(class_params):
|
|
3212
|
+
param_name = param.get('name') if isinstance(param, dict) else param
|
|
3213
|
+
if i < len(args):
|
|
3214
|
+
param_values[param_name] = args[i]
|
|
3215
|
+
else:
|
|
3216
|
+
param_values[param_name] = None
|
|
3217
|
+
|
|
3218
|
+
# Call parent constructor with extends_args if parent exists and args specified
|
|
3219
|
+
if class_def.parent and extends_args:
|
|
3220
|
+
evaluated_extends_args = [self._evaluate(arg) for arg in extends_args]
|
|
3221
|
+
self._call_parent_constructor(instance, evaluated_extends_args)
|
|
3222
|
+
instance._parent_constructor_called = True
|
|
3223
|
+
|
|
3224
|
+
# Execute all constructors defined with 'constr' keyword (in order)
|
|
3225
|
+
for constr in constructors:
|
|
3226
|
+
self._call_constructor(instance, constr, args, kwargs, param_values)
|
|
3227
|
+
|
|
3228
|
+
# Call primary constructor (old-style) if defined
|
|
2918
3229
|
if class_def.constructor:
|
|
2919
3230
|
self._call_method(instance, class_def.constructor, args, kwargs)
|
|
2920
3231
|
|
|
2921
3232
|
return instance
|
|
2922
3233
|
|
|
3234
|
+
def _call_parent_constructor(self, instance: CSSLInstance, args: list, kwargs: dict = None):
|
|
3235
|
+
"""Call the parent class constructor on an instance.
|
|
3236
|
+
|
|
3237
|
+
Used for automatic parent constructor calling and super() calls.
|
|
3238
|
+
"""
|
|
3239
|
+
kwargs = kwargs or {}
|
|
3240
|
+
parent = instance._parent_class
|
|
3241
|
+
|
|
3242
|
+
if parent is None:
|
|
3243
|
+
return
|
|
3244
|
+
|
|
3245
|
+
from .cssl_builtins import CSSLizedPythonObject
|
|
3246
|
+
|
|
3247
|
+
if isinstance(parent, CSSLClass):
|
|
3248
|
+
# CSSL parent class
|
|
3249
|
+
if parent.constructor:
|
|
3250
|
+
self._call_method(instance, parent.constructor, args, kwargs)
|
|
3251
|
+
# Also call parent's constr constructors
|
|
3252
|
+
for constr in getattr(parent, 'constructors', []):
|
|
3253
|
+
self._call_constructor(instance, constr, args, kwargs, {})
|
|
3254
|
+
elif isinstance(parent, CSSLizedPythonObject):
|
|
3255
|
+
# Python parent - call __init__ if it's a class
|
|
3256
|
+
py_obj = parent.get_python_obj()
|
|
3257
|
+
if isinstance(py_obj, type):
|
|
3258
|
+
# It's a class - we need to initialize it
|
|
3259
|
+
try:
|
|
3260
|
+
py_obj.__init__(instance, *args, **kwargs)
|
|
3261
|
+
except TypeError:
|
|
3262
|
+
pass # Initialization might not be needed
|
|
3263
|
+
elif isinstance(parent, type):
|
|
3264
|
+
# Raw Python class
|
|
3265
|
+
try:
|
|
3266
|
+
parent.__init__(instance, *args, **kwargs)
|
|
3267
|
+
except TypeError:
|
|
3268
|
+
pass
|
|
3269
|
+
|
|
3270
|
+
def _call_constructor(self, instance: CSSLInstance, constr_node: ASTNode,
|
|
3271
|
+
args: list, kwargs: dict, param_values: dict):
|
|
3272
|
+
"""Call a constructor defined with 'constr' keyword.
|
|
3273
|
+
|
|
3274
|
+
Handles constructor extends/overwrites and sets up the instance scope.
|
|
3275
|
+
"""
|
|
3276
|
+
constr_info = constr_node.value
|
|
3277
|
+
constr_params = constr_info.get('params', [])
|
|
3278
|
+
extends_class = constr_info.get('extends_class')
|
|
3279
|
+
extends_method = constr_info.get('extends_method')
|
|
3280
|
+
|
|
3281
|
+
# Save previous instance context
|
|
3282
|
+
prev_instance = self._current_instance
|
|
3283
|
+
self._current_instance = instance
|
|
3284
|
+
|
|
3285
|
+
# Create new scope for constructor
|
|
3286
|
+
new_scope = Scope(parent=self.scope)
|
|
3287
|
+
|
|
3288
|
+
# Bind param_values (from class params) to constructor scope
|
|
3289
|
+
for name, value in param_values.items():
|
|
3290
|
+
new_scope.set(name, value)
|
|
3291
|
+
|
|
3292
|
+
# Bind constructor parameters
|
|
3293
|
+
for i, param in enumerate(constr_params):
|
|
3294
|
+
param_name = param.get('name') if isinstance(param, dict) else param
|
|
3295
|
+
if i < len(args):
|
|
3296
|
+
new_scope.set(param_name, args[i])
|
|
3297
|
+
elif param_name in kwargs:
|
|
3298
|
+
new_scope.set(param_name, kwargs[param_name])
|
|
3299
|
+
else:
|
|
3300
|
+
new_scope.set(param_name, None)
|
|
3301
|
+
|
|
3302
|
+
# If constructor extends another constructor, inherit its local vars
|
|
3303
|
+
if extends_class and extends_method:
|
|
3304
|
+
parent_class = self.scope.get(extends_class) or self.global_scope.get(extends_class)
|
|
3305
|
+
if parent_class and isinstance(parent_class, CSSLClass):
|
|
3306
|
+
for constr in getattr(parent_class, 'constructors', []):
|
|
3307
|
+
if constr.value.get('name') == extends_method:
|
|
3308
|
+
# Execute parent constructor first to get local vars
|
|
3309
|
+
self._call_constructor(instance, constr, args, kwargs, param_values)
|
|
3310
|
+
break
|
|
3311
|
+
|
|
3312
|
+
# Execute constructor body
|
|
3313
|
+
prev_scope = self.scope
|
|
3314
|
+
self.scope = new_scope
|
|
3315
|
+
|
|
3316
|
+
try:
|
|
3317
|
+
for stmt in constr_node.children:
|
|
3318
|
+
self._execute(stmt)
|
|
3319
|
+
finally:
|
|
3320
|
+
self.scope = prev_scope
|
|
3321
|
+
self._current_instance = prev_instance
|
|
3322
|
+
|
|
2923
3323
|
def _eval_this_access(self, node: ASTNode) -> Any:
|
|
2924
3324
|
"""Evaluate 'this->member' access.
|
|
2925
3325
|
|
|
@@ -2957,6 +3357,10 @@ class CSSLRuntime:
|
|
|
2957
3357
|
if instance.has_method(member):
|
|
2958
3358
|
# Return a callable that will invoke the method with instance context
|
|
2959
3359
|
method_node = instance.get_method(member)
|
|
3360
|
+
# Check if this is an inherited Python method
|
|
3361
|
+
if isinstance(method_node, tuple) and method_node[0] == 'python_method':
|
|
3362
|
+
python_method = method_node[1]
|
|
3363
|
+
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
2960
3364
|
return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
|
|
2961
3365
|
|
|
2962
3366
|
raise CSSLRuntimeError(
|
|
@@ -3038,6 +3442,10 @@ class CSSLRuntime:
|
|
|
3038
3442
|
# Check for method
|
|
3039
3443
|
if obj.has_method(member):
|
|
3040
3444
|
method_node = obj.get_method(member)
|
|
3445
|
+
# Check if this is an inherited Python method
|
|
3446
|
+
if isinstance(method_node, tuple) and method_node[0] == 'python_method':
|
|
3447
|
+
python_method = method_node[1]
|
|
3448
|
+
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
3041
3449
|
return lambda *args, **kwargs: self._call_method(obj, method_node, list(args), kwargs)
|
|
3042
3450
|
raise CSSLRuntimeError(f"'{obj._class.name}' has no member or method '{member}'")
|
|
3043
3451
|
|
|
@@ -1448,17 +1448,62 @@ class CSSLClass:
|
|
|
1448
1448
|
|
|
1449
1449
|
Stores class name, member variables, methods, and constructor.
|
|
1450
1450
|
Used by the runtime to instantiate CSSLInstance objects.
|
|
1451
|
+
Supports inheritance via the 'parent' attribute.
|
|
1451
1452
|
"""
|
|
1452
1453
|
|
|
1453
1454
|
def __init__(self, name: str, members: Dict[str, Any] = None,
|
|
1454
|
-
methods: Dict[str, Any] = None, constructor: Any = None
|
|
1455
|
+
methods: Dict[str, Any] = None, constructor: Any = None,
|
|
1456
|
+
parent: Any = None):
|
|
1455
1457
|
self.name = name
|
|
1456
1458
|
self.members = members or {} # Default member values/types
|
|
1457
1459
|
self.methods = methods or {} # Method AST nodes
|
|
1458
1460
|
self.constructor = constructor # Constructor AST node
|
|
1461
|
+
self.parent = parent # Parent class (CSSLClass or CSSLizedPythonObject)
|
|
1462
|
+
|
|
1463
|
+
def get_all_members(self) -> Dict[str, Any]:
|
|
1464
|
+
"""Get all members including inherited ones."""
|
|
1465
|
+
all_members = {}
|
|
1466
|
+
# First add parent members (can be overridden)
|
|
1467
|
+
if self.parent:
|
|
1468
|
+
if hasattr(self.parent, 'get_all_members'):
|
|
1469
|
+
all_members.update(self.parent.get_all_members())
|
|
1470
|
+
elif hasattr(self.parent, 'members'):
|
|
1471
|
+
all_members.update(self.parent.members)
|
|
1472
|
+
elif hasattr(self.parent, '_python_obj'):
|
|
1473
|
+
# CSSLizedPythonObject - get attributes from Python object
|
|
1474
|
+
py_obj = self.parent._python_obj
|
|
1475
|
+
if hasattr(py_obj, '__dict__'):
|
|
1476
|
+
for key, val in py_obj.__dict__.items():
|
|
1477
|
+
if not key.startswith('_'):
|
|
1478
|
+
all_members[key] = {'type': 'dynamic', 'default': val}
|
|
1479
|
+
# Then add own members (override parent)
|
|
1480
|
+
all_members.update(self.members)
|
|
1481
|
+
return all_members
|
|
1482
|
+
|
|
1483
|
+
def get_all_methods(self) -> Dict[str, Any]:
|
|
1484
|
+
"""Get all methods including inherited ones."""
|
|
1485
|
+
all_methods = {}
|
|
1486
|
+
# First add parent methods (can be overridden)
|
|
1487
|
+
if self.parent:
|
|
1488
|
+
if hasattr(self.parent, 'get_all_methods'):
|
|
1489
|
+
all_methods.update(self.parent.get_all_methods())
|
|
1490
|
+
elif hasattr(self.parent, 'methods'):
|
|
1491
|
+
all_methods.update(self.parent.methods)
|
|
1492
|
+
elif hasattr(self.parent, '_python_obj'):
|
|
1493
|
+
# CSSLizedPythonObject - get methods from Python object
|
|
1494
|
+
py_obj = self.parent._python_obj
|
|
1495
|
+
for name in dir(py_obj):
|
|
1496
|
+
if not name.startswith('_'):
|
|
1497
|
+
attr = getattr(py_obj, name, None)
|
|
1498
|
+
if callable(attr):
|
|
1499
|
+
all_methods[name] = ('python_method', attr)
|
|
1500
|
+
# Then add own methods (override parent)
|
|
1501
|
+
all_methods.update(self.methods)
|
|
1502
|
+
return all_methods
|
|
1459
1503
|
|
|
1460
1504
|
def __repr__(self):
|
|
1461
|
-
|
|
1505
|
+
parent_info = f" extends {self.parent.name}" if self.parent and hasattr(self.parent, 'name') else ""
|
|
1506
|
+
return f"<CSSLClass '{self.name}'{parent_info} with {len(self.methods)} methods>"
|
|
1462
1507
|
|
|
1463
1508
|
|
|
1464
1509
|
class CSSLInstance:
|
|
@@ -1471,8 +1516,9 @@ class CSSLInstance:
|
|
|
1471
1516
|
def __init__(self, class_def: CSSLClass):
|
|
1472
1517
|
self._class = class_def
|
|
1473
1518
|
self._members: Dict[str, Any] = {}
|
|
1474
|
-
# Initialize members with defaults from class definition
|
|
1475
|
-
|
|
1519
|
+
# Initialize members with defaults from class definition (including inherited)
|
|
1520
|
+
all_members = class_def.get_all_members() if hasattr(class_def, 'get_all_members') else class_def.members
|
|
1521
|
+
for name, default in all_members.items():
|
|
1476
1522
|
if isinstance(default, dict):
|
|
1477
1523
|
# Type declaration with optional default
|
|
1478
1524
|
member_type = default.get('type')
|
|
@@ -1541,14 +1587,17 @@ class CSSLInstance:
|
|
|
1541
1587
|
return name in self._members
|
|
1542
1588
|
|
|
1543
1589
|
def get_method(self, name: str) -> Any:
|
|
1544
|
-
"""Get method AST node by name"""
|
|
1545
|
-
|
|
1546
|
-
|
|
1590
|
+
"""Get method AST node by name (including inherited methods)"""
|
|
1591
|
+
# Use get_all_methods to include inherited methods
|
|
1592
|
+
all_methods = self._class.get_all_methods() if hasattr(self._class, 'get_all_methods') else self._class.methods
|
|
1593
|
+
if name in all_methods:
|
|
1594
|
+
return all_methods[name]
|
|
1547
1595
|
raise AttributeError(f"'{self._class.name}' has no method '{name}'")
|
|
1548
1596
|
|
|
1549
1597
|
def has_method(self, name: str) -> bool:
|
|
1550
|
-
"""Check if method exists"""
|
|
1551
|
-
|
|
1598
|
+
"""Check if method exists (including inherited methods)"""
|
|
1599
|
+
all_methods = self._class.get_all_methods() if hasattr(self._class, 'get_all_methods') else self._class.methods
|
|
1600
|
+
return name in all_methods
|
|
1552
1601
|
|
|
1553
1602
|
def __getattr__(self, name: str) -> Any:
|
|
1554
1603
|
"""Allow direct attribute access for members"""
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "cssl",
|
|
3
3
|
"displayName": "CSSL Language",
|
|
4
4
|
"description": "Professional syntax highlighting, snippets, and language support for CSSL scripts (.cssl, .cssl-pl, .cssl-mod)",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.6.0",
|
|
6
6
|
"publisher": "IncludeCPP",
|
|
7
7
|
"icon": "images/cssl.png",
|
|
8
8
|
"engines": {
|