IncludeCPP 3.8.9__py3-none-any.whl → 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/__init__.py +1 -1
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +869 -1872
- includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +1348 -0
- includecpp/core/cssl/cssl_builtins.pyi +231 -0
- includecpp/core/cssl/cssl_parser.py +363 -88
- includecpp/core/cssl/cssl_runtime.py +362 -27
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/METADATA +1 -1
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/RECORD +12 -11
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/WHEEL +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/entry_points.txt +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.8.9.dist-info → includecpp-4.0.0.dist-info}/top_level.txt +0 -0
|
@@ -99,6 +99,89 @@ ERROR_HINTS = {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
def _find_similar_names(name: str, candidates: list, max_distance: int = 2) -> list:
|
|
103
|
+
"""Find similar names for 'did you mean' suggestions using Levenshtein distance."""
|
|
104
|
+
if not candidates:
|
|
105
|
+
return []
|
|
106
|
+
|
|
107
|
+
def levenshtein(s1: str, s2: str) -> int:
|
|
108
|
+
if len(s1) < len(s2):
|
|
109
|
+
s1, s2 = s2, s1
|
|
110
|
+
if len(s2) == 0:
|
|
111
|
+
return len(s1)
|
|
112
|
+
prev_row = range(len(s2) + 1)
|
|
113
|
+
for i, c1 in enumerate(s1):
|
|
114
|
+
curr_row = [i + 1]
|
|
115
|
+
for j, c2 in enumerate(s2):
|
|
116
|
+
insertions = prev_row[j + 1] + 1
|
|
117
|
+
deletions = curr_row[j] + 1
|
|
118
|
+
substitutions = prev_row[j] + (c1.lower() != c2.lower())
|
|
119
|
+
curr_row.append(min(insertions, deletions, substitutions))
|
|
120
|
+
prev_row = curr_row
|
|
121
|
+
return prev_row[-1]
|
|
122
|
+
|
|
123
|
+
similar = []
|
|
124
|
+
name_lower = name.lower()
|
|
125
|
+
for candidate in candidates:
|
|
126
|
+
if candidate.startswith('_'):
|
|
127
|
+
continue
|
|
128
|
+
dist = levenshtein(name, candidate)
|
|
129
|
+
# Also check case-insensitive exact match
|
|
130
|
+
if name_lower == candidate.lower() and name != candidate:
|
|
131
|
+
similar.insert(0, candidate) # Exact case mismatch goes first
|
|
132
|
+
elif dist <= max_distance:
|
|
133
|
+
similar.append(candidate)
|
|
134
|
+
|
|
135
|
+
return similar[:3] # Return top 3 suggestions
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _get_available_classes(scope: 'Scope', global_scope: 'Scope', promoted_globals: dict) -> list:
|
|
139
|
+
"""Get list of all available class names."""
|
|
140
|
+
classes = []
|
|
141
|
+
# Check current scope chain
|
|
142
|
+
current = scope
|
|
143
|
+
while current:
|
|
144
|
+
for name, val in current.variables.items():
|
|
145
|
+
if isinstance(val, CSSLClass) and name not in classes:
|
|
146
|
+
classes.append(name)
|
|
147
|
+
current = current.parent
|
|
148
|
+
# Check global scope
|
|
149
|
+
for name, val in global_scope.variables.items():
|
|
150
|
+
if isinstance(val, CSSLClass) and name not in classes:
|
|
151
|
+
classes.append(name)
|
|
152
|
+
# Check promoted globals
|
|
153
|
+
for name, val in promoted_globals.items():
|
|
154
|
+
if isinstance(val, CSSLClass) and name not in classes:
|
|
155
|
+
classes.append(name)
|
|
156
|
+
return classes
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _get_available_functions(scope: 'Scope', global_scope: 'Scope', builtins) -> list:
|
|
160
|
+
"""Get list of all available function names."""
|
|
161
|
+
functions = []
|
|
162
|
+
# Check current scope chain
|
|
163
|
+
current = scope
|
|
164
|
+
while current:
|
|
165
|
+
for name, val in current.variables.items():
|
|
166
|
+
if callable(val) or (isinstance(val, ASTNode) and val.type == 'function'):
|
|
167
|
+
if name not in functions:
|
|
168
|
+
functions.append(name)
|
|
169
|
+
current = current.parent
|
|
170
|
+
# Check global scope
|
|
171
|
+
for name, val in global_scope.variables.items():
|
|
172
|
+
if callable(val) or (isinstance(val, ASTNode) and val.type == 'function'):
|
|
173
|
+
if name not in functions:
|
|
174
|
+
functions.append(name)
|
|
175
|
+
# Check builtins
|
|
176
|
+
if builtins:
|
|
177
|
+
for name in dir(builtins):
|
|
178
|
+
if name.startswith('builtin_'):
|
|
179
|
+
func_name = name[8:] # Remove 'builtin_' prefix
|
|
180
|
+
if func_name not in functions:
|
|
181
|
+
functions.append(func_name)
|
|
182
|
+
return functions
|
|
183
|
+
|
|
184
|
+
|
|
102
185
|
class CSSLBreak(Exception):
|
|
103
186
|
"""Break statement"""
|
|
104
187
|
pass
|
|
@@ -716,9 +799,12 @@ class CSSLRuntime:
|
|
|
716
799
|
Parses class members and methods, creating a CSSLClass object
|
|
717
800
|
that can be instantiated with 'new'.
|
|
718
801
|
Supports inheritance via 'extends' keyword and method overwriting via 'overwrites'.
|
|
802
|
+
|
|
803
|
+
Classes are local by default. Use 'global class' or 'class @Name' for global classes.
|
|
719
804
|
"""
|
|
720
805
|
class_info = node.value
|
|
721
806
|
class_name = class_info.get('name')
|
|
807
|
+
is_global = class_info.get('is_global', False)
|
|
722
808
|
extends_class_name = class_info.get('extends')
|
|
723
809
|
extends_is_python = class_info.get('extends_is_python', False)
|
|
724
810
|
overwrites_class_name = class_info.get('overwrites')
|
|
@@ -745,7 +831,22 @@ class CSSLRuntime:
|
|
|
745
831
|
parent_class = self.global_scope.get(extends_class_name)
|
|
746
832
|
|
|
747
833
|
if parent_class is None:
|
|
748
|
-
|
|
834
|
+
# Build detailed error for extends
|
|
835
|
+
available_classes = _get_available_classes(self.scope, self.global_scope, self._promoted_globals)
|
|
836
|
+
similar = _find_similar_names(extends_class_name, available_classes)
|
|
837
|
+
|
|
838
|
+
if similar:
|
|
839
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
840
|
+
elif extends_is_python:
|
|
841
|
+
hint = f"Python object '${extends_class_name}' not found. Use share() to share Python objects first."
|
|
842
|
+
else:
|
|
843
|
+
hint = f"Define class '{extends_class_name}' before this class, or use 'extends $PyObject' for Python objects"
|
|
844
|
+
|
|
845
|
+
raise self._format_error(
|
|
846
|
+
node.line,
|
|
847
|
+
f"Cannot extend unknown class '{extends_class_name}'",
|
|
848
|
+
hint
|
|
849
|
+
)
|
|
749
850
|
|
|
750
851
|
# Auto-wrap Python objects for inheritance
|
|
751
852
|
from .cssl_builtins import CSSLizedPythonObject
|
|
@@ -803,9 +904,11 @@ class CSSLRuntime:
|
|
|
803
904
|
class_def.class_params = class_params # Class-level constructor parameters
|
|
804
905
|
class_def.extends_args = extends_args # Arguments to pass to parent constructor
|
|
805
906
|
|
|
806
|
-
# Register class in scope
|
|
907
|
+
# Register class in scope (local by default, global if marked)
|
|
807
908
|
self.scope.set(class_name, class_def)
|
|
808
|
-
|
|
909
|
+
if is_global:
|
|
910
|
+
self.global_scope.set(class_name, class_def)
|
|
911
|
+
self._promoted_globals[class_name] = class_def
|
|
809
912
|
|
|
810
913
|
# Handle class overwrites - replace methods in target class
|
|
811
914
|
if overwrites_class_name:
|
|
@@ -888,12 +991,15 @@ class CSSLRuntime:
|
|
|
888
991
|
"""Execute function definition - registers it and handles extends/overwrites.
|
|
889
992
|
|
|
890
993
|
Syntax:
|
|
891
|
-
define func() { ... }
|
|
892
|
-
define func
|
|
893
|
-
define func
|
|
994
|
+
define func() { ... } - Local function
|
|
995
|
+
global define func() { ... } - Global function
|
|
996
|
+
define @func() { ... } - Global function (alternative)
|
|
997
|
+
define func : extends otherFunc() { ... } - Inherit local vars
|
|
998
|
+
define func : overwrites otherFunc() { ... } - Replace otherFunc
|
|
894
999
|
"""
|
|
895
1000
|
func_info = node.value
|
|
896
1001
|
func_name = func_info.get('name')
|
|
1002
|
+
is_global = func_info.get('is_global', False)
|
|
897
1003
|
extends_func = func_info.get('extends')
|
|
898
1004
|
extends_is_python = func_info.get('extends_is_python', False)
|
|
899
1005
|
overwrites_func = func_info.get('overwrites')
|
|
@@ -922,8 +1028,11 @@ class CSSLRuntime:
|
|
|
922
1028
|
self.scope.set(overwrites_func, node)
|
|
923
1029
|
self.global_scope.set(overwrites_func, node)
|
|
924
1030
|
|
|
925
|
-
# Register the function
|
|
1031
|
+
# Register the function (local by default, global if marked)
|
|
926
1032
|
self.scope.set(func_name, node)
|
|
1033
|
+
if is_global:
|
|
1034
|
+
self.global_scope.set(func_name, node)
|
|
1035
|
+
self._promoted_globals[func_name] = node
|
|
927
1036
|
return None
|
|
928
1037
|
|
|
929
1038
|
def _resolve_function_target(self, name: str, is_python: bool) -> Any:
|
|
@@ -1307,7 +1416,80 @@ class CSSLRuntime:
|
|
|
1307
1416
|
break
|
|
1308
1417
|
self._execute_node(child)
|
|
1309
1418
|
except CSSLReturn as ret:
|
|
1310
|
-
|
|
1419
|
+
return_value = ret.value
|
|
1420
|
+
|
|
1421
|
+
# Check exclude_type: *[type] - must NOT return excluded type
|
|
1422
|
+
exclude_type = func_info.get('exclude_type')
|
|
1423
|
+
if exclude_type:
|
|
1424
|
+
type_map = {
|
|
1425
|
+
'string': str, 'int': int, 'float': float, 'bool': bool,
|
|
1426
|
+
'null': type(None), 'none': type(None),
|
|
1427
|
+
'list': list, 'array': list, 'dict': dict, 'json': dict,
|
|
1428
|
+
}
|
|
1429
|
+
excluded_py_type = type_map.get(exclude_type.lower())
|
|
1430
|
+
# For shuffled returns (tuples), check each element
|
|
1431
|
+
if isinstance(return_value, tuple):
|
|
1432
|
+
for val in return_value:
|
|
1433
|
+
if excluded_py_type and isinstance(val, excluded_py_type):
|
|
1434
|
+
raise CSSLRuntimeError(f"Type exclusion: function must NOT return '{exclude_type}' values")
|
|
1435
|
+
elif excluded_py_type and isinstance(return_value, excluded_py_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")
|
|
1491
|
+
|
|
1492
|
+
return return_value
|
|
1311
1493
|
except Exception as e:
|
|
1312
1494
|
# If undefined modifier, suppress all errors
|
|
1313
1495
|
if is_undefined:
|
|
@@ -2715,7 +2897,21 @@ class CSSLRuntime:
|
|
|
2715
2897
|
scoped_val = self.global_scope.get(f'${name}')
|
|
2716
2898
|
if scoped_val is not None:
|
|
2717
2899
|
return scoped_val
|
|
2718
|
-
|
|
2900
|
+
# List available shared objects for helpful error
|
|
2901
|
+
available_shared = list(_live_objects.keys())
|
|
2902
|
+
similar = _find_similar_names(name, available_shared)
|
|
2903
|
+
if similar:
|
|
2904
|
+
hint = f"Did you mean: ${', $'.join(similar)}?"
|
|
2905
|
+
elif available_shared:
|
|
2906
|
+
hint = f"Available shared objects: ${', $'.join(available_shared[:5])}"
|
|
2907
|
+
else:
|
|
2908
|
+
hint = "Use share(name, object) from Python to share objects first."
|
|
2909
|
+
|
|
2910
|
+
raise self._format_error(
|
|
2911
|
+
node.line if hasattr(node, 'line') else 0,
|
|
2912
|
+
f"Shared object '${name}' not found",
|
|
2913
|
+
hint
|
|
2914
|
+
)
|
|
2719
2915
|
|
|
2720
2916
|
if node.type == 'captured_ref':
|
|
2721
2917
|
# %<name> captured reference - use value captured at infusion registration time
|
|
@@ -2742,7 +2938,13 @@ class CSSLRuntime:
|
|
|
2742
2938
|
value = self._original_functions.get(name)
|
|
2743
2939
|
if value is not None:
|
|
2744
2940
|
return value
|
|
2745
|
-
|
|
2941
|
+
# Build helpful error for captured reference
|
|
2942
|
+
hint = f"Variable '{name}' must exist when the infusion is registered. Check that '%{name}' is defined before the <<== operator."
|
|
2943
|
+
raise self._format_error(
|
|
2944
|
+
node.line if hasattr(node, 'line') else 0,
|
|
2945
|
+
f"Captured reference '%{name}' not found",
|
|
2946
|
+
hint
|
|
2947
|
+
)
|
|
2746
2948
|
|
|
2747
2949
|
if node.type == 'instance_ref':
|
|
2748
2950
|
# instance<"name"> - get shared instance by name
|
|
@@ -2831,6 +3033,58 @@ class CSSLRuntime:
|
|
|
2831
3033
|
if node.type == 'unary':
|
|
2832
3034
|
return self._eval_unary(node)
|
|
2833
3035
|
|
|
3036
|
+
if node.type == 'non_null_assert':
|
|
3037
|
+
# *$var, *@module, *identifier - assert value is not null/None
|
|
3038
|
+
operand = node.value.get('operand')
|
|
3039
|
+
value = self._evaluate(operand)
|
|
3040
|
+
if value is None:
|
|
3041
|
+
# Get name of the operand for better error message
|
|
3042
|
+
operand_name = "unknown"
|
|
3043
|
+
if isinstance(operand, ASTNode):
|
|
3044
|
+
if operand.type == 'identifier':
|
|
3045
|
+
operand_name = operand.value
|
|
3046
|
+
elif operand.type == 'shared_ref':
|
|
3047
|
+
operand_name = f"${operand.value}"
|
|
3048
|
+
elif operand.type == 'module_ref':
|
|
3049
|
+
operand_name = f"@{operand.value}"
|
|
3050
|
+
elif operand.type == 'global_ref':
|
|
3051
|
+
operand_name = f"r@{operand.value}"
|
|
3052
|
+
raise self._format_error(
|
|
3053
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3054
|
+
f"Non-null assertion failed: '{operand_name}' is null/None",
|
|
3055
|
+
f"The value accessed via '*{operand_name}' must not be null. Check that it is defined and initialized."
|
|
3056
|
+
)
|
|
3057
|
+
return value
|
|
3058
|
+
|
|
3059
|
+
if node.type == 'type_exclude_assert':
|
|
3060
|
+
# *[type]expr - assert value is NOT of excluded type
|
|
3061
|
+
exclude_type = node.value.get('exclude_type')
|
|
3062
|
+
operand = node.value.get('operand')
|
|
3063
|
+
value = self._evaluate(operand)
|
|
3064
|
+
|
|
3065
|
+
# Map CSSL types to Python types
|
|
3066
|
+
type_map = {
|
|
3067
|
+
'string': str,
|
|
3068
|
+
'int': int,
|
|
3069
|
+
'float': float,
|
|
3070
|
+
'bool': bool,
|
|
3071
|
+
'null': type(None),
|
|
3072
|
+
'none': type(None),
|
|
3073
|
+
'list': list,
|
|
3074
|
+
'array': list,
|
|
3075
|
+
'dict': dict,
|
|
3076
|
+
'json': dict,
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
excluded_py_type = type_map.get(exclude_type.lower())
|
|
3080
|
+
if excluded_py_type and isinstance(value, excluded_py_type):
|
|
3081
|
+
raise self._format_error(
|
|
3082
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3083
|
+
f"Type exclusion assertion failed: value is of excluded type '{exclude_type}'",
|
|
3084
|
+
f"The expression was marked *[{exclude_type}] meaning it must NOT return {exclude_type}, but it did."
|
|
3085
|
+
)
|
|
3086
|
+
return value
|
|
3087
|
+
|
|
2834
3088
|
if node.type == 'call':
|
|
2835
3089
|
return self._eval_call(node)
|
|
2836
3090
|
|
|
@@ -3108,12 +3362,33 @@ class CSSLRuntime:
|
|
|
3108
3362
|
return self._call_function(callee, args, kwargs)
|
|
3109
3363
|
|
|
3110
3364
|
callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3365
|
+
|
|
3366
|
+
# Build detailed error with suggestions
|
|
3367
|
+
available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
|
|
3368
|
+
similar = _find_similar_names(callee_name, available_funcs)
|
|
3369
|
+
|
|
3370
|
+
if callee is None:
|
|
3371
|
+
# Function not found at all
|
|
3372
|
+
if similar:
|
|
3373
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3374
|
+
else:
|
|
3375
|
+
hint = f"Function '{callee_name}' is not defined. Define it with: define {callee_name}() {{ }}"
|
|
3376
|
+
raise self._format_error(
|
|
3377
|
+
node.line,
|
|
3378
|
+
f"Function '{callee_name}' not found",
|
|
3379
|
+
hint
|
|
3380
|
+
)
|
|
3381
|
+
else:
|
|
3382
|
+
# Found something but it's not callable
|
|
3383
|
+
if similar:
|
|
3384
|
+
hint = f"'{callee_name}' is a {type(callee).__name__}, not a function. Did you mean: {', '.join(similar)}?"
|
|
3385
|
+
else:
|
|
3386
|
+
hint = f"'{callee_name}' is a {type(callee).__name__}. Functions must be defined with 'define' keyword."
|
|
3387
|
+
raise self._format_error(
|
|
3388
|
+
node.line,
|
|
3389
|
+
f"Cannot call '{callee_name}' - it is not a function",
|
|
3390
|
+
hint
|
|
3391
|
+
)
|
|
3117
3392
|
|
|
3118
3393
|
def _eval_typed_call(self, node: ASTNode) -> Any:
|
|
3119
3394
|
"""Evaluate typed function call like OpenFind<string>(0) or OpenFind<dynamic, "name">"""
|
|
@@ -3179,26 +3454,53 @@ class CSSLRuntime:
|
|
|
3179
3454
|
)
|
|
3180
3455
|
|
|
3181
3456
|
def _eval_new(self, node: ASTNode) -> CSSLInstance:
|
|
3182
|
-
"""Evaluate 'new ClassName(args)' expression.
|
|
3457
|
+
"""Evaluate 'new ClassName(args)' or 'new @ClassName(args)' expression.
|
|
3183
3458
|
|
|
3184
3459
|
Creates a new instance of a CSSL class and calls its constructor.
|
|
3185
3460
|
Supports multiple constructors (constr keyword), class parameters,
|
|
3186
3461
|
and automatic parent constructor calling.
|
|
3462
|
+
|
|
3463
|
+
With '@' prefix (new @ClassName), looks only in global scope.
|
|
3187
3464
|
"""
|
|
3188
3465
|
class_name = node.value.get('class')
|
|
3466
|
+
is_global_ref = node.value.get('is_global_ref', False)
|
|
3189
3467
|
args = [self._evaluate(arg) for arg in node.value.get('args', [])]
|
|
3190
3468
|
kwargs = {k: self._evaluate(v) for k, v in node.value.get('kwargs', {}).items()}
|
|
3191
3469
|
|
|
3192
3470
|
# Get class definition from scope
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
class_def = self.
|
|
3471
|
+
if is_global_ref:
|
|
3472
|
+
# With @ prefix, only look in global scope
|
|
3473
|
+
class_def = self._promoted_globals.get(class_name)
|
|
3474
|
+
if class_def is None:
|
|
3475
|
+
class_def = self.global_scope.get(class_name)
|
|
3476
|
+
else:
|
|
3477
|
+
# Normal lookup: local scope first, then global
|
|
3478
|
+
class_def = self.scope.get(class_name)
|
|
3479
|
+
if class_def is None:
|
|
3480
|
+
class_def = self.global_scope.get(class_name)
|
|
3196
3481
|
|
|
3197
3482
|
if class_def is None:
|
|
3198
|
-
|
|
3199
|
-
|
|
3483
|
+
# Build detailed error with suggestions
|
|
3484
|
+
source_line = self._get_source_line(node.line)
|
|
3485
|
+
available_classes = _get_available_classes(self.scope, self.global_scope, self._promoted_globals)
|
|
3486
|
+
similar = _find_similar_names(class_name, available_classes)
|
|
3487
|
+
|
|
3488
|
+
# Check if class exists in global scope (user forgot @)
|
|
3489
|
+
global_class = self._promoted_globals.get(class_name) or self.global_scope.get(class_name)
|
|
3490
|
+
if global_class and isinstance(global_class, CSSLClass) and not is_global_ref:
|
|
3491
|
+
hint = f"Class '{class_name}' exists in global scope. Use: new @{class_name}()"
|
|
3492
|
+
elif similar:
|
|
3493
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3494
|
+
elif available_classes:
|
|
3495
|
+
hint = f"Available classes: {', '.join(available_classes[:5])}"
|
|
3496
|
+
else:
|
|
3497
|
+
hint = "Define the class before instantiation, or use 'global class' / 'class @Name' for global classes"
|
|
3498
|
+
|
|
3499
|
+
context = f"in expression: {source_line.strip()}" if source_line else None
|
|
3500
|
+
raise self._format_error(
|
|
3200
3501
|
node.line,
|
|
3201
|
-
|
|
3502
|
+
f"Class '{class_name}' not found",
|
|
3503
|
+
hint
|
|
3202
3504
|
)
|
|
3203
3505
|
|
|
3204
3506
|
if not isinstance(class_def, CSSLClass):
|
|
@@ -3490,9 +3792,24 @@ class CSSLRuntime:
|
|
|
3490
3792
|
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
3491
3793
|
return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
|
|
3492
3794
|
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3795
|
+
# Build helpful error with available members
|
|
3796
|
+
class_name = instance._class.name
|
|
3797
|
+
available_members = list(instance._members.keys()) if hasattr(instance, '_members') else []
|
|
3798
|
+
available_methods = list(instance._methods.keys()) if hasattr(instance, '_methods') else []
|
|
3799
|
+
all_available = available_members + available_methods
|
|
3800
|
+
similar = _find_similar_names(member, all_available)
|
|
3801
|
+
|
|
3802
|
+
if similar:
|
|
3803
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3804
|
+
elif all_available:
|
|
3805
|
+
hint = f"Available: {', '.join(all_available[:5])}"
|
|
3806
|
+
else:
|
|
3807
|
+
hint = f"Class '{class_name}' has no accessible members. Check class definition."
|
|
3808
|
+
|
|
3809
|
+
raise self._format_error(
|
|
3810
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3811
|
+
f"'{class_name}' has no member or method '{member}'",
|
|
3812
|
+
hint
|
|
3496
3813
|
)
|
|
3497
3814
|
|
|
3498
3815
|
def _call_method(self, instance: CSSLInstance, method_node: ASTNode, args: list, kwargs: dict = None) -> Any:
|
|
@@ -3587,7 +3904,25 @@ class CSSLRuntime:
|
|
|
3587
3904
|
python_method = method_node[1]
|
|
3588
3905
|
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
3589
3906
|
return lambda *args, **kwargs: self._call_method(obj, method_node, list(args), kwargs)
|
|
3590
|
-
|
|
3907
|
+
# Build helpful error with available members
|
|
3908
|
+
class_name = obj._class.name
|
|
3909
|
+
available_members = list(obj._members.keys()) if hasattr(obj, '_members') else []
|
|
3910
|
+
available_methods = list(obj._methods.keys()) if hasattr(obj, '_methods') else []
|
|
3911
|
+
all_available = available_members + available_methods
|
|
3912
|
+
similar = _find_similar_names(member, all_available)
|
|
3913
|
+
|
|
3914
|
+
if similar:
|
|
3915
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3916
|
+
elif all_available:
|
|
3917
|
+
hint = f"Available: {', '.join(all_available[:5])}"
|
|
3918
|
+
else:
|
|
3919
|
+
hint = f"Class '{class_name}' has no accessible members."
|
|
3920
|
+
|
|
3921
|
+
raise self._format_error(
|
|
3922
|
+
node.line,
|
|
3923
|
+
f"'{class_name}' has no member or method '{member}'",
|
|
3924
|
+
hint
|
|
3925
|
+
)
|
|
3591
3926
|
|
|
3592
3927
|
# === STRING METHODS ===
|
|
3593
3928
|
if isinstance(obj, str):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
includecpp/__init__.py,sha256=
|
|
1
|
+
includecpp/__init__.py,sha256=8GF2-h-JB8QHeXVQnsZIwoXTxqOaUudycDZaivmIECw,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
|
|
@@ -19,14 +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
|
+
includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md,sha256=I_bVeKWlbcgHYkl2o9L2vk3r5sDvG44bGh__RJIYduw,28222
|
|
23
24
|
includecpp/core/cssl/__init__.py,sha256=scDXRBNK2L6A8qmlpNyaqQj6BFcSfPInBlucdeNfMF0,1975
|
|
24
25
|
includecpp/core/cssl/cssl_builtins.py,sha256=oPsPyQk5b0b1I02Y80oIaDX39GOeG32-nBPEqwbo_Pw,105110
|
|
25
|
-
includecpp/core/cssl/cssl_builtins.pyi,sha256
|
|
26
|
+
includecpp/core/cssl/cssl_builtins.pyi,sha256=-yr9JbxHKFv9Vc1iufChcqCQvNQLL3-Ow_Hgg0YwQnc,135180
|
|
26
27
|
includecpp/core/cssl/cssl_events.py,sha256=nupIcXW_Vjdud7zCU6hdwkQRQ0MujlPM7Tk2u7eDAiY,21013
|
|
27
28
|
includecpp/core/cssl/cssl_modules.py,sha256=cUg0-zdymMnWWTsA_BUrW5dx4R04dHpKcUhm-Wfiwwo,103006
|
|
28
|
-
includecpp/core/cssl/cssl_parser.py,sha256=
|
|
29
|
-
includecpp/core/cssl/cssl_runtime.py,sha256=
|
|
29
|
+
includecpp/core/cssl/cssl_parser.py,sha256=Ur_V-dymhR4uKARA0EhgUWSvb_OaImuMZGjQpMv6ztI,153752
|
|
30
|
+
includecpp/core/cssl/cssl_runtime.py,sha256=dwExfARMSIfB5_KDvSGFtgW3hHEDFWWfTMmPtzDCUZE,200849
|
|
30
31
|
includecpp/core/cssl/cssl_syntax.py,sha256=bgo3NFehoPTQa5dqwNd_CstkVGVCNYAXbGYUcu5BEN0,16982
|
|
31
32
|
includecpp/core/cssl/cssl_types.py,sha256=7jbrtZf3xmVQJA_mnL9iYrmdjhjuc4--mxxNigi7fsk,53425
|
|
32
33
|
includecpp/generator/__init__.py,sha256=Rsy41bwimaEloD3gDRR_znPfIJzIsCFuWZgCTJBLJlc,62
|
|
@@ -44,9 +45,9 @@ includecpp/vscode/cssl/images/cssl.png,sha256=BxAGsnfS0ZzzCvqV6Zb1OAJAZpDUoXlR86
|
|
|
44
45
|
includecpp/vscode/cssl/images/cssl_pl.png,sha256=z4WMk7g6YCTbUUbSFk343BO6yi_OmNEVYkRenWGydwM,799
|
|
45
46
|
includecpp/vscode/cssl/snippets/cssl.snippets.json,sha256=uV3nHJyQ5f7Pr3FzfbQT2VZOEY3AlGs4wrmqe884jm4,37372
|
|
46
47
|
includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json,sha256=FZw1_VDz1ll4ZBZeGqo-935CK5RuF2kD75rNp5tVdC0,35068
|
|
47
|
-
includecpp-
|
|
48
|
-
includecpp-
|
|
49
|
-
includecpp-
|
|
50
|
-
includecpp-
|
|
51
|
-
includecpp-
|
|
52
|
-
includecpp-
|
|
48
|
+
includecpp-4.0.0.dist-info/licenses/LICENSE,sha256=fWCsGGsiWZir0UzDd20Hh-3wtRyk1zqUntvtVuAWhvc,1093
|
|
49
|
+
includecpp-4.0.0.dist-info/METADATA,sha256=TNBirJeSnkl7V4PUESZSHJzkOboU8DGe_Qrykc-NmbQ,22510
|
|
50
|
+
includecpp-4.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
includecpp-4.0.0.dist-info/entry_points.txt,sha256=6A5Mif9gi0139Bf03W5plAb3wnAgbNaEVe1HJoGE-2o,59
|
|
52
|
+
includecpp-4.0.0.dist-info/top_level.txt,sha256=RFUaR1KG-M6mCYwP6w4ydP5Cgc8yNbP78jxGAvyjMa8,11
|
|
53
|
+
includecpp-4.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|