IncludeCPP 3.9.1__tar.gz → 3.9.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-3.9.1 → includecpp-3.9.2}/PKG-INFO +1 -1
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/__init__.py +1 -1
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +112 -4
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_parser.py +68 -25
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_runtime.py +257 -28
- {includecpp-3.9.1 → includecpp-3.9.2}/pyproject.toml +1 -1
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/LICENSE +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/MANIFEST.in +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/README.md +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/__init__.pyi +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/__main__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/cli/commands.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cppy_converter.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_builtins.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_events.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_modules.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_syntax.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl/cssl_types.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl_bridge.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/cssl_bridge.pyi +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/generator/parser.cpp +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/generator/parser.h +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/py.typed +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/__init__.py +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/extension.js +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/images/cssl.png +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/language-configuration.json +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/package.json +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/requirements.txt +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/setup.cfg +0 -0
- {includecpp-3.9.1 → includecpp-3.9.2}/setup.py +0 -0
|
@@ -168,6 +168,42 @@ isnull(null); // true
|
|
|
168
168
|
|
|
169
169
|
## Variables & Globals
|
|
170
170
|
|
|
171
|
+
### Scope Behavior
|
|
172
|
+
|
|
173
|
+
Variables are **local by default**. Each function/class has its own scope - variables defined inside a function only exist within that function.
|
|
174
|
+
|
|
175
|
+
```cssl
|
|
176
|
+
define myFunction() {
|
|
177
|
+
string name = "Alice"; // Local to myFunction
|
|
178
|
+
printl(name); // Works
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
myFunction();
|
|
182
|
+
// printl(name); // Error! 'name' doesn't exist here
|
|
183
|
+
|
|
184
|
+
// Same variable name in different scopes = different variables
|
|
185
|
+
string name = "Bob";
|
|
186
|
+
|
|
187
|
+
define otherFunction() {
|
|
188
|
+
string name = "Charlie"; // Different variable, local to otherFunction
|
|
189
|
+
printl(name); // "Charlie"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
otherFunction();
|
|
193
|
+
printl(name); // "Bob" - outer scope unchanged
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Everything is Local by Default
|
|
197
|
+
|
|
198
|
+
All elements (variables, functions, classes) are **local by default** and must be explicitly marked global.
|
|
199
|
+
|
|
200
|
+
| Element | Local (default) | Global |
|
|
201
|
+
|---------|-----------------|--------|
|
|
202
|
+
| **Variables** | `string x = "text";` | `global x = "text";` or `@x = "text";` |
|
|
203
|
+
| **Functions** | `define myFunc() { }` | `global define myFunc() { }` or `define @myFunc() { }` |
|
|
204
|
+
| **Typed functions** | `void myFunc() { }` | `global void myFunc() { }` or `void @myFunc() { }` |
|
|
205
|
+
| **Classes** | `class MyClass { }` | `global class MyClass { }` or `class @MyClass { }` |
|
|
206
|
+
|
|
171
207
|
### Local Variables
|
|
172
208
|
|
|
173
209
|
```cssl
|
|
@@ -179,6 +215,8 @@ bool active = true;
|
|
|
179
215
|
|
|
180
216
|
### Global Variables
|
|
181
217
|
|
|
218
|
+
Use `global` keyword or `@`/`r@` prefix to create/access global variables:
|
|
219
|
+
|
|
182
220
|
```cssl
|
|
183
221
|
// Declaration with 'global' keyword
|
|
184
222
|
global myGlobal = "visible everywhere";
|
|
@@ -186,11 +224,60 @@ global myGlobal = "visible everywhere";
|
|
|
186
224
|
// Access with '@' prefix
|
|
187
225
|
printl(@myGlobal);
|
|
188
226
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
227
|
+
// Direct global assignment with @ or r@
|
|
228
|
+
@anotherGlobal = "also global";
|
|
229
|
+
r@yetAnother = "and this too";
|
|
230
|
+
|
|
231
|
+
// Always read globals with @
|
|
232
|
+
printl(@x);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Global Functions
|
|
236
|
+
|
|
237
|
+
```cssl
|
|
238
|
+
// Global function with 'global' keyword
|
|
239
|
+
global define helper() {
|
|
240
|
+
printl("I'm global!");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Alternative: @ prefix syntax
|
|
244
|
+
define @anotherHelper() {
|
|
245
|
+
printl("Also global!");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Global typed function
|
|
249
|
+
global void @utilityFunc(string msg) {
|
|
250
|
+
printl(msg);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Global Classes
|
|
255
|
+
|
|
256
|
+
```cssl
|
|
257
|
+
// Global class with 'global' keyword
|
|
258
|
+
global class SharedClass {
|
|
259
|
+
string value;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Alternative: @ prefix syntax
|
|
263
|
+
class @AnotherShared {
|
|
264
|
+
int count;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Instantiate global class with @ prefix
|
|
268
|
+
instance = new @SharedClass();
|
|
192
269
|
```
|
|
193
270
|
|
|
271
|
+
### Prefix Reference
|
|
272
|
+
|
|
273
|
+
| Prefix | Name | Usage |
|
|
274
|
+
|--------|------|-------|
|
|
275
|
+
| `@` | Global/Module | Read global vars, access modules: `@myVar`, `@os.getcwd()` |
|
|
276
|
+
| `r@` | Global Ref | Assign to global scope: `r@name = value` |
|
|
277
|
+
| `$` | Shared | Access Python objects: `$counter.value` |
|
|
278
|
+
| `%` | Captured | Capture value at registration: `%version` |
|
|
279
|
+
| `s@` | Self-Ref | Access global structs: `s@Backend.config` |
|
|
280
|
+
|
|
194
281
|
### Shared Objects ($)
|
|
195
282
|
|
|
196
283
|
Access Python objects shared via `CSSL.share()`:
|
|
@@ -215,6 +302,20 @@ version = "2.0";
|
|
|
215
302
|
printl(savedVersion); // Still "1.0"
|
|
216
303
|
```
|
|
217
304
|
|
|
305
|
+
### Class Member Access (this->)
|
|
306
|
+
|
|
307
|
+
Inside classes, use `this->` to access instance members:
|
|
308
|
+
|
|
309
|
+
```cssl
|
|
310
|
+
class Person {
|
|
311
|
+
string name;
|
|
312
|
+
|
|
313
|
+
void setName(string n) {
|
|
314
|
+
this->name = n; // Instance member
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
218
319
|
---
|
|
219
320
|
|
|
220
321
|
## Operators
|
|
@@ -1332,7 +1433,9 @@ assert(x > 0, "x must be positive");
|
|
|
1332
1433
|
|
|
1333
1434
|
| Syntax | Description |
|
|
1334
1435
|
|--------|-------------|
|
|
1335
|
-
| `@name` | Global variable |
|
|
1436
|
+
| `@name` | Global variable access |
|
|
1437
|
+
| `@name = value` | Global variable assignment |
|
|
1438
|
+
| `r@name = value` | Global reference assignment |
|
|
1336
1439
|
| `$name` | Shared Python object |
|
|
1337
1440
|
| `%name` | Captured value |
|
|
1338
1441
|
| `this->` | Class member access |
|
|
@@ -1342,6 +1445,11 @@ assert(x > 0, "x must be positive");
|
|
|
1342
1445
|
| `&FunctionName ++` | Append to function |
|
|
1343
1446
|
| `*func()` | Non-null function |
|
|
1344
1447
|
| `*[type]func()` | Type exclusion filter |
|
|
1448
|
+
| `global class Name` | Global class declaration |
|
|
1449
|
+
| `class @Name` | Global class (alt syntax) |
|
|
1450
|
+
| `global define func()` | Global function declaration |
|
|
1451
|
+
| `define @func()` | Global function (alt syntax) |
|
|
1452
|
+
| `new @ClassName()` | Instantiate global class |
|
|
1345
1453
|
|
|
1346
1454
|
---
|
|
1347
1455
|
|
|
@@ -816,11 +816,13 @@ class CSSLParser:
|
|
|
816
816
|
self.pos = saved_pos
|
|
817
817
|
return False
|
|
818
818
|
|
|
819
|
-
def _parse_typed_function(self) -> ASTNode:
|
|
819
|
+
def _parse_typed_function(self, is_global: bool = False) -> ASTNode:
|
|
820
820
|
"""Parse C-style typed function declaration.
|
|
821
821
|
|
|
822
822
|
Patterns:
|
|
823
|
-
- int Add(int a, int b) { }
|
|
823
|
+
- int Add(int a, int b) { } // Local function
|
|
824
|
+
- global int Add(int a, int b) { } // Global function
|
|
825
|
+
- int @Add(int a, int b) { } // Global function (alternative)
|
|
824
826
|
- undefined int Func() { }
|
|
825
827
|
- open void Handler(open Params) { }
|
|
826
828
|
- vector<string> GetNames() { }
|
|
@@ -869,6 +871,11 @@ class CSSLParser:
|
|
|
869
871
|
else:
|
|
870
872
|
non_null = True
|
|
871
873
|
|
|
874
|
+
# Check for @ prefix (global function): void @FuncName()
|
|
875
|
+
if self._check(TokenType.AT):
|
|
876
|
+
self._advance() # consume @
|
|
877
|
+
is_global = True
|
|
878
|
+
|
|
872
879
|
# Get function name
|
|
873
880
|
name = self._advance().value
|
|
874
881
|
|
|
@@ -966,6 +973,7 @@ class CSSLParser:
|
|
|
966
973
|
# Parse function body
|
|
967
974
|
node = ASTNode('function', value={
|
|
968
975
|
'name': name,
|
|
976
|
+
'is_global': is_global,
|
|
969
977
|
'params': params,
|
|
970
978
|
'return_type': return_type,
|
|
971
979
|
'generic_type': generic_type,
|
|
@@ -1131,19 +1139,30 @@ class CSSLParser:
|
|
|
1131
1139
|
root.children.append(self._parse_package_includes())
|
|
1132
1140
|
# Handle global declarations
|
|
1133
1141
|
elif self._match_keyword('global'):
|
|
1134
|
-
|
|
1135
|
-
if
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
root.children.append(
|
|
1142
|
+
# Check if followed by class or define (global class/function)
|
|
1143
|
+
if self._match_keyword('class'):
|
|
1144
|
+
root.children.append(self._parse_class(is_global=True))
|
|
1145
|
+
elif self._match_keyword('define'):
|
|
1146
|
+
root.children.append(self._parse_define(is_global=True))
|
|
1147
|
+
elif self._looks_like_function_declaration():
|
|
1148
|
+
# global void MyFunc() { } or global int MyFunc() { }
|
|
1149
|
+
root.children.append(self._parse_typed_function(is_global=True))
|
|
1150
|
+
else:
|
|
1151
|
+
stmt = self._parse_expression_statement()
|
|
1152
|
+
if stmt:
|
|
1153
|
+
# Wrap in global_assignment to mark as global variable
|
|
1154
|
+
global_stmt = ASTNode('global_assignment', value=stmt)
|
|
1155
|
+
root.children.append(global_stmt)
|
|
1139
1156
|
elif self._check(TokenType.GLOBAL_REF):
|
|
1140
1157
|
stmt = self._parse_expression_statement()
|
|
1141
1158
|
if stmt:
|
|
1142
1159
|
# Wrap in global_assignment to mark as global variable (same as 'global' keyword)
|
|
1143
1160
|
global_stmt = ASTNode('global_assignment', value=stmt)
|
|
1144
1161
|
root.children.append(global_stmt)
|
|
1145
|
-
# Handle statements
|
|
1146
|
-
elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1162
|
+
# Handle statements - keywords like 'instance', 'list', 'map' can be variable names
|
|
1163
|
+
elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1164
|
+
self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
|
|
1165
|
+
self._check(TokenType.KEYWORD)):
|
|
1147
1166
|
stmt = self._parse_expression_statement()
|
|
1148
1167
|
if stmt:
|
|
1149
1168
|
root.children.append(stmt)
|
|
@@ -1380,20 +1399,14 @@ class CSSLParser:
|
|
|
1380
1399
|
self._expect(TokenType.BLOCK_END)
|
|
1381
1400
|
return node
|
|
1382
1401
|
|
|
1383
|
-
def _parse_class(self) -> ASTNode:
|
|
1402
|
+
def _parse_class(self, is_global: bool = False) -> ASTNode:
|
|
1384
1403
|
"""Parse class declaration with members and methods.
|
|
1385
1404
|
|
|
1386
1405
|
Syntax:
|
|
1387
|
-
class ClassName {
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
void ClassName(string n) { this->name = n; }
|
|
1392
|
-
|
|
1393
|
-
void sayHello() {
|
|
1394
|
-
printl("Hello " + this->name);
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1406
|
+
class ClassName { ... } // Local class
|
|
1407
|
+
global class ClassName { ... } // Global class
|
|
1408
|
+
class @ClassName { ... } // Global class (alternative)
|
|
1409
|
+
class *ClassName { ... } // Non-null class
|
|
1397
1410
|
|
|
1398
1411
|
Non-null class (all methods return non-null):
|
|
1399
1412
|
class *MyClass { ... }
|
|
@@ -1403,6 +1416,11 @@ class CSSLParser:
|
|
|
1403
1416
|
if self._match(TokenType.MULTIPLY):
|
|
1404
1417
|
non_null = True
|
|
1405
1418
|
|
|
1419
|
+
# Check for @ prefix (global class): class @ClassName
|
|
1420
|
+
if self._check(TokenType.AT):
|
|
1421
|
+
self._advance() # consume @
|
|
1422
|
+
is_global = True
|
|
1423
|
+
|
|
1406
1424
|
class_name = self._advance().value
|
|
1407
1425
|
|
|
1408
1426
|
# Check for class-level constructor parameters: class MyClass (int x, string y) { ... }
|
|
@@ -1459,6 +1477,7 @@ class CSSLParser:
|
|
|
1459
1477
|
|
|
1460
1478
|
node = ASTNode('class', value={
|
|
1461
1479
|
'name': class_name,
|
|
1480
|
+
'is_global': is_global,
|
|
1462
1481
|
'non_null': non_null,
|
|
1463
1482
|
'class_params': class_params,
|
|
1464
1483
|
'extends': extends_class,
|
|
@@ -1693,12 +1712,14 @@ class CSSLParser:
|
|
|
1693
1712
|
|
|
1694
1713
|
return params
|
|
1695
1714
|
|
|
1696
|
-
def _parse_define(self) -> ASTNode:
|
|
1715
|
+
def _parse_define(self, is_global: bool = False) -> ASTNode:
|
|
1697
1716
|
"""Parse define function declaration.
|
|
1698
1717
|
|
|
1699
1718
|
Syntax:
|
|
1700
|
-
define MyFunc(args) { }
|
|
1701
|
-
define
|
|
1719
|
+
define MyFunc(args) { } // Local function
|
|
1720
|
+
global define MyFunc(args) { } // Global function
|
|
1721
|
+
define @MyFunc(args) { } // Global function (alternative)
|
|
1722
|
+
define *MyFunc(args) { } // Non-null: must never return None
|
|
1702
1723
|
define MyFunc : extends OtherFunc() { } // Inherit local vars
|
|
1703
1724
|
define MyFunc : overwrites OtherFunc() { } // Replace OtherFunc
|
|
1704
1725
|
define MyFunc :: extends Parent::Method :: overwrites Parent::Method() { } // Method-level inheritance
|
|
@@ -1716,6 +1737,11 @@ class CSSLParser:
|
|
|
1716
1737
|
else:
|
|
1717
1738
|
non_null = True
|
|
1718
1739
|
|
|
1740
|
+
# Check for @ prefix (global function): define @FuncName
|
|
1741
|
+
if self._check(TokenType.AT):
|
|
1742
|
+
self._advance() # consume @
|
|
1743
|
+
is_global = True
|
|
1744
|
+
|
|
1719
1745
|
name = self._advance().value
|
|
1720
1746
|
|
|
1721
1747
|
# Check for extends/overwrites: define func : extends/overwrites target() { }
|
|
@@ -1859,6 +1885,7 @@ class CSSLParser:
|
|
|
1859
1885
|
|
|
1860
1886
|
node = ASTNode('function', value={
|
|
1861
1887
|
'name': name,
|
|
1888
|
+
'is_global': is_global,
|
|
1862
1889
|
'params': params,
|
|
1863
1890
|
'non_null': non_null,
|
|
1864
1891
|
'exclude_type': exclude_type, # *[type] - must NOT return this type
|
|
@@ -2791,16 +2818,21 @@ class CSSLParser:
|
|
|
2791
2818
|
# Just 'this' keyword alone - return as identifier for now
|
|
2792
2819
|
return ASTNode('identifier', value='this')
|
|
2793
2820
|
|
|
2794
|
-
# Handle 'new ClassName(args)' instantiation
|
|
2821
|
+
# Handle 'new ClassName(args)' or 'new @ClassName(args)' instantiation
|
|
2795
2822
|
if self._check(TokenType.KEYWORD) and self._current().value == 'new':
|
|
2796
2823
|
self._advance() # consume 'new'
|
|
2824
|
+
# Check for @ prefix (global class reference)
|
|
2825
|
+
is_global_ref = False
|
|
2826
|
+
if self._check(TokenType.AT):
|
|
2827
|
+
self._advance() # consume @
|
|
2828
|
+
is_global_ref = True
|
|
2797
2829
|
class_name = self._advance().value # get class name
|
|
2798
2830
|
args = []
|
|
2799
2831
|
kwargs = {}
|
|
2800
2832
|
if self._match(TokenType.PAREN_START):
|
|
2801
2833
|
args, kwargs = self._parse_call_arguments()
|
|
2802
2834
|
self._expect(TokenType.PAREN_END)
|
|
2803
|
-
node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs})
|
|
2835
|
+
node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs, 'is_global_ref': is_global_ref})
|
|
2804
2836
|
# Continue to check for member access, calls on the new object
|
|
2805
2837
|
while True:
|
|
2806
2838
|
if self._match(TokenType.DOT):
|
|
@@ -2819,7 +2851,18 @@ class CSSLParser:
|
|
|
2819
2851
|
return node
|
|
2820
2852
|
|
|
2821
2853
|
if self._match(TokenType.AT):
|
|
2854
|
+
# Check for @* (global non-null reference): @*name
|
|
2855
|
+
is_non_null = False
|
|
2856
|
+
if self._check(TokenType.MULTIPLY):
|
|
2857
|
+
self._advance() # consume *
|
|
2858
|
+
is_non_null = True
|
|
2859
|
+
|
|
2822
2860
|
node = self._parse_module_reference()
|
|
2861
|
+
|
|
2862
|
+
# Wrap in non_null_assert if @* was used
|
|
2863
|
+
if is_non_null:
|
|
2864
|
+
node = ASTNode('non_null_assert', value={'operand': node, 'is_global': True})
|
|
2865
|
+
|
|
2823
2866
|
# Continue to check for calls, indexing, member access on module refs
|
|
2824
2867
|
while True:
|
|
2825
2868
|
if self._match(TokenType.PAREN_START):
|
|
@@ -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:
|
|
@@ -2734,7 +2843,21 @@ class CSSLRuntime:
|
|
|
2734
2843
|
scoped_val = self.global_scope.get(f'${name}')
|
|
2735
2844
|
if scoped_val is not None:
|
|
2736
2845
|
return scoped_val
|
|
2737
|
-
|
|
2846
|
+
# List available shared objects for helpful error
|
|
2847
|
+
available_shared = list(_live_objects.keys())
|
|
2848
|
+
similar = _find_similar_names(name, available_shared)
|
|
2849
|
+
if similar:
|
|
2850
|
+
hint = f"Did you mean: ${', $'.join(similar)}?"
|
|
2851
|
+
elif available_shared:
|
|
2852
|
+
hint = f"Available shared objects: ${', $'.join(available_shared[:5])}"
|
|
2853
|
+
else:
|
|
2854
|
+
hint = "Use share(name, object) from Python to share objects first."
|
|
2855
|
+
|
|
2856
|
+
raise self._format_error(
|
|
2857
|
+
node.line if hasattr(node, 'line') else 0,
|
|
2858
|
+
f"Shared object '${name}' not found",
|
|
2859
|
+
hint
|
|
2860
|
+
)
|
|
2738
2861
|
|
|
2739
2862
|
if node.type == 'captured_ref':
|
|
2740
2863
|
# %<name> captured reference - use value captured at infusion registration time
|
|
@@ -2761,7 +2884,13 @@ class CSSLRuntime:
|
|
|
2761
2884
|
value = self._original_functions.get(name)
|
|
2762
2885
|
if value is not None:
|
|
2763
2886
|
return value
|
|
2764
|
-
|
|
2887
|
+
# Build helpful error for captured reference
|
|
2888
|
+
hint = f"Variable '{name}' must exist when the infusion is registered. Check that '%{name}' is defined before the <<== operator."
|
|
2889
|
+
raise self._format_error(
|
|
2890
|
+
node.line if hasattr(node, 'line') else 0,
|
|
2891
|
+
f"Captured reference '%{name}' not found",
|
|
2892
|
+
hint
|
|
2893
|
+
)
|
|
2765
2894
|
|
|
2766
2895
|
if node.type == 'instance_ref':
|
|
2767
2896
|
# instance<"name"> - get shared instance by name
|
|
@@ -2855,7 +2984,22 @@ class CSSLRuntime:
|
|
|
2855
2984
|
operand = node.value.get('operand')
|
|
2856
2985
|
value = self._evaluate(operand)
|
|
2857
2986
|
if value is None:
|
|
2858
|
-
|
|
2987
|
+
# Get name of the operand for better error message
|
|
2988
|
+
operand_name = "unknown"
|
|
2989
|
+
if isinstance(operand, ASTNode):
|
|
2990
|
+
if operand.type == 'identifier':
|
|
2991
|
+
operand_name = operand.value
|
|
2992
|
+
elif operand.type == 'shared_ref':
|
|
2993
|
+
operand_name = f"${operand.value}"
|
|
2994
|
+
elif operand.type == 'module_ref':
|
|
2995
|
+
operand_name = f"@{operand.value}"
|
|
2996
|
+
elif operand.type == 'global_ref':
|
|
2997
|
+
operand_name = f"r@{operand.value}"
|
|
2998
|
+
raise self._format_error(
|
|
2999
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3000
|
+
f"Non-null assertion failed: '{operand_name}' is null/None",
|
|
3001
|
+
f"The value accessed via '*{operand_name}' must not be null. Check that it is defined and initialized."
|
|
3002
|
+
)
|
|
2859
3003
|
return value
|
|
2860
3004
|
|
|
2861
3005
|
if node.type == 'type_exclude_assert':
|
|
@@ -2880,7 +3024,11 @@ class CSSLRuntime:
|
|
|
2880
3024
|
|
|
2881
3025
|
excluded_py_type = type_map.get(exclude_type.lower())
|
|
2882
3026
|
if excluded_py_type and isinstance(value, excluded_py_type):
|
|
2883
|
-
raise
|
|
3027
|
+
raise self._format_error(
|
|
3028
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3029
|
+
f"Type exclusion assertion failed: value is of excluded type '{exclude_type}'",
|
|
3030
|
+
f"The expression was marked *[{exclude_type}] meaning it must NOT return {exclude_type}, but it did."
|
|
3031
|
+
)
|
|
2884
3032
|
return value
|
|
2885
3033
|
|
|
2886
3034
|
if node.type == 'call':
|
|
@@ -3160,12 +3308,33 @@ class CSSLRuntime:
|
|
|
3160
3308
|
return self._call_function(callee, args, kwargs)
|
|
3161
3309
|
|
|
3162
3310
|
callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3311
|
+
|
|
3312
|
+
# Build detailed error with suggestions
|
|
3313
|
+
available_funcs = _get_available_functions(self.scope, self.global_scope, self.builtins)
|
|
3314
|
+
similar = _find_similar_names(callee_name, available_funcs)
|
|
3315
|
+
|
|
3316
|
+
if callee is None:
|
|
3317
|
+
# Function not found at all
|
|
3318
|
+
if similar:
|
|
3319
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3320
|
+
else:
|
|
3321
|
+
hint = f"Function '{callee_name}' is not defined. Define it with: define {callee_name}() {{ }}"
|
|
3322
|
+
raise self._format_error(
|
|
3323
|
+
node.line,
|
|
3324
|
+
f"Function '{callee_name}' not found",
|
|
3325
|
+
hint
|
|
3326
|
+
)
|
|
3327
|
+
else:
|
|
3328
|
+
# Found something but it's not callable
|
|
3329
|
+
if similar:
|
|
3330
|
+
hint = f"'{callee_name}' is a {type(callee).__name__}, not a function. Did you mean: {', '.join(similar)}?"
|
|
3331
|
+
else:
|
|
3332
|
+
hint = f"'{callee_name}' is a {type(callee).__name__}. Functions must be defined with 'define' keyword."
|
|
3333
|
+
raise self._format_error(
|
|
3334
|
+
node.line,
|
|
3335
|
+
f"Cannot call '{callee_name}' - it is not a function",
|
|
3336
|
+
hint
|
|
3337
|
+
)
|
|
3169
3338
|
|
|
3170
3339
|
def _eval_typed_call(self, node: ASTNode) -> Any:
|
|
3171
3340
|
"""Evaluate typed function call like OpenFind<string>(0) or OpenFind<dynamic, "name">"""
|
|
@@ -3231,26 +3400,53 @@ class CSSLRuntime:
|
|
|
3231
3400
|
)
|
|
3232
3401
|
|
|
3233
3402
|
def _eval_new(self, node: ASTNode) -> CSSLInstance:
|
|
3234
|
-
"""Evaluate 'new ClassName(args)' expression.
|
|
3403
|
+
"""Evaluate 'new ClassName(args)' or 'new @ClassName(args)' expression.
|
|
3235
3404
|
|
|
3236
3405
|
Creates a new instance of a CSSL class and calls its constructor.
|
|
3237
3406
|
Supports multiple constructors (constr keyword), class parameters,
|
|
3238
3407
|
and automatic parent constructor calling.
|
|
3408
|
+
|
|
3409
|
+
With '@' prefix (new @ClassName), looks only in global scope.
|
|
3239
3410
|
"""
|
|
3240
3411
|
class_name = node.value.get('class')
|
|
3412
|
+
is_global_ref = node.value.get('is_global_ref', False)
|
|
3241
3413
|
args = [self._evaluate(arg) for arg in node.value.get('args', [])]
|
|
3242
3414
|
kwargs = {k: self._evaluate(v) for k, v in node.value.get('kwargs', {}).items()}
|
|
3243
3415
|
|
|
3244
3416
|
# Get class definition from scope
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
class_def = self.
|
|
3417
|
+
if is_global_ref:
|
|
3418
|
+
# With @ prefix, only look in global scope
|
|
3419
|
+
class_def = self._promoted_globals.get(class_name)
|
|
3420
|
+
if class_def is None:
|
|
3421
|
+
class_def = self.global_scope.get(class_name)
|
|
3422
|
+
else:
|
|
3423
|
+
# Normal lookup: local scope first, then global
|
|
3424
|
+
class_def = self.scope.get(class_name)
|
|
3425
|
+
if class_def is None:
|
|
3426
|
+
class_def = self.global_scope.get(class_name)
|
|
3248
3427
|
|
|
3249
3428
|
if class_def is None:
|
|
3250
|
-
|
|
3251
|
-
|
|
3429
|
+
# Build detailed error with suggestions
|
|
3430
|
+
source_line = self._get_source_line(node.line)
|
|
3431
|
+
available_classes = _get_available_classes(self.scope, self.global_scope, self._promoted_globals)
|
|
3432
|
+
similar = _find_similar_names(class_name, available_classes)
|
|
3433
|
+
|
|
3434
|
+
# Check if class exists in global scope (user forgot @)
|
|
3435
|
+
global_class = self._promoted_globals.get(class_name) or self.global_scope.get(class_name)
|
|
3436
|
+
if global_class and isinstance(global_class, CSSLClass) and not is_global_ref:
|
|
3437
|
+
hint = f"Class '{class_name}' exists in global scope. Use: new @{class_name}()"
|
|
3438
|
+
elif similar:
|
|
3439
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3440
|
+
elif available_classes:
|
|
3441
|
+
hint = f"Available classes: {', '.join(available_classes[:5])}"
|
|
3442
|
+
else:
|
|
3443
|
+
hint = "Define the class before instantiation, or use 'global class' / 'class @Name' for global classes"
|
|
3444
|
+
|
|
3445
|
+
context = f"in expression: {source_line.strip()}" if source_line else None
|
|
3446
|
+
raise self._format_error(
|
|
3252
3447
|
node.line,
|
|
3253
|
-
|
|
3448
|
+
f"Class '{class_name}' not found",
|
|
3449
|
+
hint
|
|
3254
3450
|
)
|
|
3255
3451
|
|
|
3256
3452
|
if not isinstance(class_def, CSSLClass):
|
|
@@ -3542,9 +3738,24 @@ class CSSLRuntime:
|
|
|
3542
3738
|
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
3543
3739
|
return lambda *args, **kwargs: self._call_method(instance, method_node, list(args), kwargs)
|
|
3544
3740
|
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3741
|
+
# Build helpful error with available members
|
|
3742
|
+
class_name = instance._class.name
|
|
3743
|
+
available_members = list(instance._members.keys()) if hasattr(instance, '_members') else []
|
|
3744
|
+
available_methods = list(instance._methods.keys()) if hasattr(instance, '_methods') else []
|
|
3745
|
+
all_available = available_members + available_methods
|
|
3746
|
+
similar = _find_similar_names(member, all_available)
|
|
3747
|
+
|
|
3748
|
+
if similar:
|
|
3749
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3750
|
+
elif all_available:
|
|
3751
|
+
hint = f"Available: {', '.join(all_available[:5])}"
|
|
3752
|
+
else:
|
|
3753
|
+
hint = f"Class '{class_name}' has no accessible members. Check class definition."
|
|
3754
|
+
|
|
3755
|
+
raise self._format_error(
|
|
3756
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3757
|
+
f"'{class_name}' has no member or method '{member}'",
|
|
3758
|
+
hint
|
|
3548
3759
|
)
|
|
3549
3760
|
|
|
3550
3761
|
def _call_method(self, instance: CSSLInstance, method_node: ASTNode, args: list, kwargs: dict = None) -> Any:
|
|
@@ -3639,7 +3850,25 @@ class CSSLRuntime:
|
|
|
3639
3850
|
python_method = method_node[1]
|
|
3640
3851
|
return lambda *args, **kwargs: python_method(*args, **kwargs)
|
|
3641
3852
|
return lambda *args, **kwargs: self._call_method(obj, method_node, list(args), kwargs)
|
|
3642
|
-
|
|
3853
|
+
# Build helpful error with available members
|
|
3854
|
+
class_name = obj._class.name
|
|
3855
|
+
available_members = list(obj._members.keys()) if hasattr(obj, '_members') else []
|
|
3856
|
+
available_methods = list(obj._methods.keys()) if hasattr(obj, '_methods') else []
|
|
3857
|
+
all_available = available_members + available_methods
|
|
3858
|
+
similar = _find_similar_names(member, all_available)
|
|
3859
|
+
|
|
3860
|
+
if similar:
|
|
3861
|
+
hint = f"Did you mean: {', '.join(similar)}?"
|
|
3862
|
+
elif all_available:
|
|
3863
|
+
hint = f"Available: {', '.join(all_available[:5])}"
|
|
3864
|
+
else:
|
|
3865
|
+
hint = f"Class '{class_name}' has no accessible members."
|
|
3866
|
+
|
|
3867
|
+
raise self._format_error(
|
|
3868
|
+
node.line,
|
|
3869
|
+
f"'{class_name}' has no member or method '{member}'",
|
|
3870
|
+
hint
|
|
3871
|
+
)
|
|
3643
3872
|
|
|
3644
3873
|
# === STRING METHODS ===
|
|
3645
3874
|
if isinstance(obj, str):
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IncludeCPP"
|
|
7
|
-
version = "3.9.
|
|
7
|
+
version = "3.9.2"
|
|
8
8
|
description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|