IncludeCPP 3.5.9__tar.gz → 3.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.5.9 → includecpp-3.6.0}/PKG-INFO +1 -1
  3. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/__init__.py +1 -1
  4. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +351 -20
  5. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_builtins.py +164 -0
  6. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_parser.py +41 -6
  7. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_runtime.py +24 -6
  8. {includecpp-3.5.9 → includecpp-3.6.0}/pyproject.toml +1 -1
  9. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/SOURCES.txt +0 -0
  10. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  11. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/entry_points.txt +0 -0
  12. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/requires.txt +0 -0
  13. {includecpp-3.5.9 → includecpp-3.6.0}/IncludeCPP.egg-info/top_level.txt +0 -0
  14. {includecpp-3.5.9 → includecpp-3.6.0}/LICENSE +0 -0
  15. {includecpp-3.5.9 → includecpp-3.6.0}/MANIFEST.in +0 -0
  16. {includecpp-3.5.9 → includecpp-3.6.0}/README.md +0 -0
  17. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/__init__.pyi +0 -0
  18. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/__main__.py +0 -0
  19. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/cli/__init__.py +0 -0
  20. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/cli/commands.py +0 -0
  21. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/cli/config_parser.py +0 -0
  22. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/__init__.py +0 -0
  23. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/ai_integration.py +0 -0
  24. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/build_manager.py +0 -0
  25. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cpp_api.py +0 -0
  26. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cpp_api.pyi +0 -0
  27. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cppy_converter.py +0 -0
  28. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/__init__.py +0 -0
  29. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_events.py +0 -0
  30. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_modules.py +0 -0
  31. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_syntax.py +0 -0
  32. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl/cssl_types.py +0 -0
  33. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl_bridge.py +0 -0
  34. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/cssl_bridge.pyi +0 -0
  35. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/error_catalog.py +0 -0
  36. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/error_formatter.py +0 -0
  37. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/exceptions.py +0 -0
  38. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/path_discovery.py +0 -0
  39. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/project_ui.py +0 -0
  40. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/core/settings_ui.py +0 -0
  41. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/generator/__init__.py +0 -0
  42. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/generator/parser.cpp +0 -0
  43. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/generator/parser.h +0 -0
  44. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/generator/type_resolver.cpp +0 -0
  45. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/generator/type_resolver.h +0 -0
  46. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/py.typed +0 -0
  47. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/templates/cpp.proj.template +0 -0
  48. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/vscode/__init__.py +0 -0
  49. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/vscode/cssl/__init__.py +0 -0
  50. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/vscode/cssl/language-configuration.json +0 -0
  51. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/vscode/cssl/package.json +0 -0
  52. {includecpp-3.5.9 → includecpp-3.6.0}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
  53. {includecpp-3.5.9 → includecpp-3.6.0}/requirements.txt +0 -0
  54. {includecpp-3.5.9 → includecpp-3.6.0}/setup.cfg +0 -0
  55. {includecpp-3.5.9 → includecpp-3.6.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.5.9
3
+ Version: 3.6.0
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.5.9
3
+ Version: 3.6.0
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "3.5.9"
5
+ __version__ = "3.6.0"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -1,6 +1,6 @@
1
1
  # CSSL - C-Style Scripting Language
2
2
 
3
- > Version 3.4.20 | A modern scripting language with C++-style syntax and unique features like CodeInfusion and BruteInjection.
3
+ > Version 3.6.0 | A modern scripting language with C++-style syntax and unique features like CodeInfusion and BruteInjection.
4
4
 
5
5
  ---
6
6
 
@@ -15,16 +15,19 @@
15
15
  7. [Functions](#functions)
16
16
  8. [Function Keywords](#function-keywords)
17
17
  9. [String Methods](#string-methods)
18
- 10. [Live Object Sharing](#live-object-sharing)
19
- 11. [CodeInfusion](#codeinfusion)
20
- 12. [BruteInjection](#bruteinjection)
21
- 13. [Filter Syntax](#filter-syntax)
22
- 14. [Module System](#module-system)
23
- 15. [Parameter Bridge](#parameter-bridge)
24
- 16. [Structures](#structures)
25
- 17. [Error Handling](#error-handling)
26
- 18. [CLI Commands](#cli-commands)
27
- 19. [Examples](#examples)
18
+ 10. [File I/O](#file-io)
19
+ 11. [JSON Functions](#json-functions)
20
+ 12. [Live Object Sharing](#live-object-sharing)
21
+ 13. [CodeInfusion](#codeinfusion)
22
+ 14. [Value Capture](#value-capture)
23
+ 15. [BruteInjection](#bruteinjection)
24
+ 16. [Filter Syntax](#filter-syntax)
25
+ 17. [Module System](#module-system)
26
+ 18. [Parameter Bridge](#parameter-bridge)
27
+ 19. [Structures](#structures)
28
+ 20. [Error Handling](#error-handling)
29
+ 21. [CLI Commands](#cli-commands)
30
+ 22. [Examples](#examples)
28
31
 
29
32
  ---
30
33
 
@@ -336,14 +339,26 @@ int number = 42;
336
339
  // Declaration with 'global'
337
340
  global myGlobal = "visible everywhere";
338
341
 
339
- // Access with '@'
342
+ // Access with '@' prefix
340
343
  printl(@myGlobal);
341
344
 
342
- // Alternative: r@ syntax
345
+ // Or access directly without '@' (since v3.5.9)
346
+ printl(myGlobal); // Works the same!
347
+
348
+ // Alternative: r@ syntax for declaration
343
349
  r@anotherGlobal = "also global";
344
350
  printl(@anotherGlobal);
351
+ printl(anotherGlobal); // Also works
345
352
  ```
346
353
 
354
+ ### Lookup Order
355
+
356
+ When accessing a variable, CSSL checks in order:
357
+ 1. Local scope
358
+ 2. Global scope
359
+ 3. Promoted globals
360
+ 4. Built-in functions
361
+
347
362
  ### Usage in Functions
348
363
 
349
364
  ```cssl
@@ -539,6 +554,29 @@ string n = getName();
539
554
  int sum = add(5, 3);
540
555
  ```
541
556
 
557
+ ### Named Parameters
558
+
559
+ Functions can be called with named parameters for clarity.
560
+
561
+ ```cssl
562
+ // Define function
563
+ int calculate(int base, int multiplier, int offset) {
564
+ return base * multiplier + offset;
565
+ }
566
+
567
+ // Call with positional arguments
568
+ int r1 = calculate(10, 5, 3); // 53
569
+
570
+ // Call with named parameters
571
+ int r2 = calculate(base=10, multiplier=5, offset=3); // 53
572
+
573
+ // Mix positional and named (positional must come first)
574
+ int r3 = calculate(10, multiplier=5, offset=3); // 53
575
+
576
+ // Named parameters can be in any order
577
+ int r4 = calculate(offset=3, base=10, multiplier=5); // 53
578
+ ```
579
+
542
580
  ### Nested Functions
543
581
 
544
582
  ```cssl
@@ -798,6 +836,170 @@ string padded2 = num.padEnd(5, "."); // "42..."
798
836
 
799
837
  ---
800
838
 
839
+ ## File I/O
840
+
841
+ CSSL provides built-in functions for file operations.
842
+
843
+ ### Basic File Operations
844
+
845
+ ```cssl
846
+ // Read entire file
847
+ string content = read("/path/to/file.txt");
848
+ printl(content);
849
+
850
+ // Read specific line (1-indexed)
851
+ string line5 = readline(5, "/path/to/file.txt");
852
+ printl(line5);
853
+
854
+ // Write to file (overwrites)
855
+ write("/path/to/file.txt", "Hello World");
856
+
857
+ // Write/replace specific line
858
+ writeline(3, "New line content", "/path/to/file.txt");
859
+ ```
860
+
861
+ ### Extended File Functions
862
+
863
+ ```cssl
864
+ // Read all lines as array
865
+ stack<string> lines = readlines("/path/to/file.txt");
866
+
867
+ // Append to file
868
+ appendfile("/path/to/file.txt", "\nNew content");
869
+
870
+ // File checks
871
+ bool exists = pathexists("/path/to/file.txt");
872
+ bool isFile = isfile("/path/to/file.txt");
873
+ bool isDir = isdir("/path/to/folder");
874
+
875
+ // File size
876
+ int size = filesize("/path/to/file.txt");
877
+
878
+ // Directory listing
879
+ stack<string> files = listdir("/path/to/folder");
880
+ ```
881
+
882
+ ### Path Functions
883
+
884
+ ```cssl
885
+ // Path manipulation
886
+ string base = basename("/path/to/file.txt"); // "file.txt"
887
+ string dir = dirname("/path/to/file.txt"); // "/path/to"
888
+ string full = joinpath("/path", "to", "file.txt"); // "/path/to/file.txt"
889
+ string abs = abspath("./file.txt"); // "/current/dir/file.txt"
890
+ ```
891
+
892
+ ### All File I/O Functions
893
+
894
+ | Function | Description |
895
+ |----------|-------------|
896
+ | `read(path)` | Read entire file content |
897
+ | `readline(line, path)` | Read specific line (1-indexed) |
898
+ | `write(path, content)` | Write content to file |
899
+ | `writeline(line, content, path)` | Write/replace specific line |
900
+ | `readfile(path)` | Read file (alias for read) |
901
+ | `writefile(path, content)` | Write file (alias for write) |
902
+ | `readlines(path)` | Read all lines as array |
903
+ | `appendfile(path, content)` | Append to file |
904
+ | `pathexists(path)` | Check if path exists |
905
+ | `isfile(path)` | Check if is file |
906
+ | `isdir(path)` | Check if is directory |
907
+ | `filesize(path)` | Get file size in bytes |
908
+ | `listdir(path)` | List directory contents |
909
+ | `makedirs(path)` | Create directories |
910
+ | `removefile(path)` | Delete file |
911
+ | `removedir(path)` | Delete empty directory |
912
+ | `copyfile(src, dst)` | Copy file |
913
+ | `movefile(src, dst)` | Move file |
914
+
915
+ ---
916
+
917
+ ## JSON Functions
918
+
919
+ CSSL provides namespace-style JSON functions with the `json::` prefix.
920
+
921
+ ### Reading & Writing JSON Files
922
+
923
+ ```cssl
924
+ // Read and parse JSON file
925
+ json data = json::read("/path/to/config.json");
926
+ printl(data.name);
927
+
928
+ // Write data to JSON file
929
+ json::write("/path/to/output.json", data);
930
+ ```
931
+
932
+ ### JSON Parsing & Stringifying
933
+
934
+ ```cssl
935
+ // Parse JSON string
936
+ string jsonStr = '{"name": "Alice", "age": 30}';
937
+ json obj = json::parse(jsonStr);
938
+
939
+ // Convert to JSON string
940
+ string str = json::stringify(obj);
941
+
942
+ // Pretty print with indentation
943
+ string pretty = json::pretty(obj);
944
+ printl(pretty);
945
+ ```
946
+
947
+ ### JSON Path Operations
948
+
949
+ ```cssl
950
+ json data = json::read("config.json");
951
+
952
+ // Get value by dot-path
953
+ string name = json::get(data, "user.name");
954
+ int age = json::get(data, "user.profile.age");
955
+ string city = json::get(data, "address.city", "Unknown"); // with default
956
+
957
+ // Set value by dot-path
958
+ data = json::set(data, "user.name", "Bob");
959
+ data = json::set(data, "settings.theme", "dark");
960
+
961
+ // Check if path exists
962
+ if (json::has(data, "user.email")) {
963
+ printl("Email exists");
964
+ }
965
+ ```
966
+
967
+ ### JSON Object Operations
968
+
969
+ ```cssl
970
+ json obj = json::read("data.json");
971
+
972
+ // Get all keys
973
+ stack<string> keys = json::keys(obj);
974
+ foreach (key in keys) {
975
+ printl(key);
976
+ }
977
+
978
+ // Get all values
979
+ stack<dynamic> values = json::values(obj);
980
+
981
+ // Deep merge objects
982
+ json merged = json::merge(obj1, obj2, obj3);
983
+ ```
984
+
985
+ ### All JSON Functions
986
+
987
+ | Function | Description |
988
+ |----------|-------------|
989
+ | `json::read(path)` | Read and parse JSON file |
990
+ | `json::write(path, data)` | Write data to JSON file |
991
+ | `json::parse(str)` | Parse JSON string to object |
992
+ | `json::stringify(data)` | Convert to JSON string |
993
+ | `json::pretty(data)` | Pretty print JSON |
994
+ | `json::get(data, path, default)` | Get value by dot-path |
995
+ | `json::set(data, path, value)` | Set value by dot-path |
996
+ | `json::has(data, path)` | Check if path exists |
997
+ | `json::keys(data)` | Get all keys |
998
+ | `json::values(data)` | Get all values |
999
+ | `json::merge(obj1, obj2, ...)` | Deep merge objects |
1000
+
1001
+ ---
1002
+
801
1003
  ## Live Object Sharing
802
1004
 
803
1005
  Share Python objects with CSSL. Changes in CSSL reflect back to Python.
@@ -934,6 +1136,74 @@ exit(); // Executes injection
934
1136
 
935
1137
  ---
936
1138
 
1139
+ ## Value Capture
1140
+
1141
+ The `%identifier` syntax captures values at registration time, useful for saving original functions before replacement.
1142
+
1143
+ ### Capturing Variables
1144
+
1145
+ ```cssl
1146
+ string version = "1.0.0";
1147
+
1148
+ // Capture current value
1149
+ v <== { %version; }
1150
+ printl(v); // "1.0.0"
1151
+
1152
+ // Even if version changes later, v keeps captured value
1153
+ version = "2.0.0";
1154
+ printl(v); // Still "1.0.0"
1155
+ ```
1156
+
1157
+ ### Capturing Functions
1158
+
1159
+ ```cssl
1160
+ // Save original exit function before replacing
1161
+ originalExit <<== { %exit(); }
1162
+
1163
+ // Replace exit with custom behavior
1164
+ exit() <<== {
1165
+ printl("Custom cleanup...");
1166
+ originalExit(); // Call saved original
1167
+ }
1168
+
1169
+ exit();
1170
+ // Output:
1171
+ // Custom cleanup...
1172
+ // (original exit behavior)
1173
+ ```
1174
+
1175
+ ### Use Cases
1176
+
1177
+ ```cssl
1178
+ // 1. Preserving original behavior
1179
+ void myFunc() {
1180
+ printl("Original");
1181
+ }
1182
+
1183
+ savedFunc <<== { %myFunc(); }
1184
+
1185
+ myFunc() <<== {
1186
+ printl("Modified");
1187
+ }
1188
+
1189
+ myFunc(); // "Modified"
1190
+ savedFunc(); // "Original"
1191
+
1192
+ // 2. Capturing configuration at startup
1193
+ global config = loadConfig();
1194
+ startupConfig <== { %config; }
1195
+
1196
+ // 3. Snapshot values for later comparison
1197
+ int counter = 0;
1198
+ initial <== { %counter; }
1199
+ // ... operations ...
1200
+ if (counter != initial) {
1201
+ printl("Counter changed!");
1202
+ }
1203
+ ```
1204
+
1205
+ ---
1206
+
937
1207
  ## BruteInjection
938
1208
 
939
1209
  BruteInjection copies/moves data between containers.
@@ -981,6 +1251,26 @@ container ==> data;
981
1251
 
982
1252
  ---
983
1253
 
1254
+ ### ==>- (Receive Minus)
1255
+
1256
+ Removes matching items from target.
1257
+
1258
+ ```cssl
1259
+ stack<string> names;
1260
+ names.push("Alice");
1261
+ names.push("Bob");
1262
+ names.push("Alice");
1263
+
1264
+ stack<string> toRemove;
1265
+ toRemove.push("Alice");
1266
+
1267
+ // Remove all "Alice" from names
1268
+ names ==>- toRemove;
1269
+ printl(names); // ["Bob"]
1270
+ ```
1271
+
1272
+ ---
1273
+
984
1274
  ## Filter Syntax
985
1275
 
986
1276
  Filters enable targeted data operations in BruteInjection.
@@ -1014,6 +1304,30 @@ result +<== [string::contains="App"] fruits; // Apple, Apricot
1014
1304
  result +<== [string::length=5] fruits; // Apple
1015
1305
  ```
1016
1306
 
1307
+ ### String Cutting Filters
1308
+
1309
+ Cut strings at specific positions or substrings.
1310
+
1311
+ ```cssl
1312
+ string version = "1.0.0-beta";
1313
+
1314
+ // Cut at position (integer index)
1315
+ x = <==[string::cut=3] version;
1316
+ printl(x); // "1.0" (first 3 chars)
1317
+
1318
+ // Cut at substring position
1319
+ x = <==[string::cut="0-"] version;
1320
+ printl(x); // "1.0." (before "0-")
1321
+
1322
+ // Get everything after substring
1323
+ x = <==[string::cutAfter=".0."] version;
1324
+ printl(x); // "0-beta" (after ".0.")
1325
+
1326
+ // Cut after at position
1327
+ x = <==[string::cutAfter=4] version;
1328
+ printl(x); // ".0-beta" (after index 4)
1329
+ ```
1330
+
1017
1331
  ### All Filters
1018
1332
 
1019
1333
  | Filter | Description |
@@ -1022,6 +1336,10 @@ result +<== [string::length=5] fruits; // Apple
1022
1336
  | `string::not=VALUE` | Everything except this value |
1023
1337
  | `string::contains=VALUE` | Contains substring |
1024
1338
  | `string::length=LENGTH` | Exact string length |
1339
+ | `string::cut=INDEX` | Cut at index (returns first N chars) |
1340
+ | `string::cut="SUBSTR"` | Cut at substring position |
1341
+ | `string::cutAfter=INDEX` | Get everything after index |
1342
+ | `string::cutAfter="SUBSTR"` | Get everything after substring |
1025
1343
  | `integer::where=VALUE` | Exact int match |
1026
1344
  | `json::key=KEYNAME` | Filter by JSON key |
1027
1345
  | `json::value=VALUE` | Filter by JSON value |
@@ -1457,12 +1775,25 @@ print(result) # ["Missing colon after def"]
1457
1775
 
1458
1776
  | Operator | Type | Description |
1459
1777
  |----------|------|-------------|
1460
- | `<<==` | CodeInfusion | Replace |
1461
- | `+<<==` | CodeInfusion | Add |
1462
- | `-<<==` | CodeInfusion | Remove |
1463
- | `+<==` | BruteInjection | Copy |
1464
- | `-<==` | BruteInjection | Move |
1465
- | `==>` | BruteInjection | Replace |
1778
+ | `<<==` | CodeInfusion | Replace function |
1779
+ | `+<<==` | CodeInfusion | Add code (before) |
1780
+ | `-<<==` | CodeInfusion | Remove code |
1781
+ | `<==` | ValueCapture | Capture/assign value |
1782
+ | `+<==` | BruteInjection | Copy data |
1783
+ | `-<==` | BruteInjection | Move data |
1784
+ | `==>` | BruteInjection | Replace data |
1785
+ | `==>-` | BruteInjection | Remove matching items |
1786
+
1787
+ ### Special Syntax
1788
+
1789
+ | Syntax | Description |
1790
+ |--------|-------------|
1791
+ | `%identifier` | Capture value at registration time |
1792
+ | `json::func()` | Namespace function call |
1793
+ | `@name` | Access global variable |
1794
+ | `$name` | Access shared Python object |
1795
+ | `s@name` | Self-reference to struct |
1796
+ | `r@name` | Global variable declaration |
1466
1797
 
1467
1798
  ---
1468
1799
 
@@ -1479,4 +1810,4 @@ print(result) # ["Missing colon after def"]
1479
1810
 
1480
1811
  ---
1481
1812
 
1482
- *CSSL v3.4.20 - Developed as part of IncludeCPP*
1813
+ *CSSL v3.6.0 - Developed as part of IncludeCPP*
@@ -162,6 +162,10 @@ class CSSLBuiltins:
162
162
  self._functions['abspath'] = self.builtin_abspath
163
163
  self._functions['normpath'] = self.builtin_normpath
164
164
  # File I/O functions
165
+ self._functions['read'] = self.builtin_read
166
+ self._functions['readline'] = self.builtin_readline
167
+ self._functions['write'] = self.builtin_write
168
+ self._functions['writeline'] = self.builtin_writeline
165
169
  self._functions['readfile'] = self.builtin_readfile
166
170
  self._functions['writefile'] = self.builtin_writefile
167
171
  self._functions['appendfile'] = self.builtin_appendfile
@@ -177,6 +181,18 @@ class CSSLBuiltins:
177
181
  # JSON functions
178
182
  self._functions['tojson'] = self.builtin_tojson
179
183
  self._functions['fromjson'] = self.builtin_fromjson
184
+ # JSON namespace functions (json::read, json::write, etc.)
185
+ self._functions['json::read'] = self.builtin_json_read
186
+ self._functions['json::write'] = self.builtin_json_write
187
+ self._functions['json::parse'] = self.builtin_fromjson
188
+ self._functions['json::stringify'] = self.builtin_tojson
189
+ self._functions['json::pretty'] = self.builtin_json_pretty
190
+ self._functions['json::keys'] = self.builtin_json_keys
191
+ self._functions['json::values'] = self.builtin_json_values
192
+ self._functions['json::get'] = self.builtin_json_get
193
+ self._functions['json::set'] = self.builtin_json_set
194
+ self._functions['json::has'] = self.builtin_json_has
195
+ self._functions['json::merge'] = self.builtin_json_merge
180
196
 
181
197
  # Regex functions
182
198
  self._functions['match'] = self.builtin_match
@@ -801,6 +817,54 @@ class CSSLBuiltins:
801
817
 
802
818
  # ============= File I/O Functions =============
803
819
 
820
+ def builtin_read(self, path: str, encoding: str = 'utf-8') -> str:
821
+ """Read entire file content.
822
+ Usage: read('/path/to/file.txt')
823
+ """
824
+ with open(path, 'r', encoding=encoding) as f:
825
+ return f.read()
826
+
827
+ def builtin_readline(self, line: int, path: str, encoding: str = 'utf-8') -> str:
828
+ """Read specific line from file (1-indexed).
829
+ Usage: readline(5, '/path/to/file.txt') -> returns line 5
830
+ """
831
+ with open(path, 'r', encoding=encoding) as f:
832
+ for i, file_line in enumerate(f, 1):
833
+ if i == line:
834
+ return file_line.rstrip('\n\r')
835
+ return "" # Line not found
836
+
837
+ def builtin_write(self, path: str, content: str, encoding: str = 'utf-8') -> int:
838
+ """Write content to file, returns chars written.
839
+ Usage: write('/path/to/file.txt', 'Hello World')
840
+ """
841
+ with open(path, 'w', encoding=encoding) as f:
842
+ return f.write(content)
843
+
844
+ def builtin_writeline(self, line: int, content: str, path: str, encoding: str = 'utf-8') -> bool:
845
+ """Write/replace specific line in file (1-indexed).
846
+ Usage: writeline(5, 'New content', '/path/to/file.txt')
847
+ """
848
+ # Read all lines
849
+ lines = []
850
+ if os.path.exists(path):
851
+ with open(path, 'r', encoding=encoding) as f:
852
+ lines = f.readlines()
853
+
854
+ # Ensure we have enough lines
855
+ while len(lines) < line:
856
+ lines.append('\n')
857
+
858
+ # Replace the specific line (1-indexed)
859
+ if not content.endswith('\n'):
860
+ content = content + '\n'
861
+ lines[line - 1] = content
862
+
863
+ # Write back
864
+ with open(path, 'w', encoding=encoding) as f:
865
+ f.writelines(lines)
866
+ return True
867
+
804
868
  def builtin_readfile(self, path: str, encoding: str = 'utf-8') -> str:
805
869
  """Read entire file content"""
806
870
  with open(path, 'r', encoding=encoding) as f:
@@ -862,6 +926,106 @@ class CSSLBuiltins:
862
926
  def builtin_fromjson(self, s: str) -> Any:
863
927
  return json.loads(s)
864
928
 
929
+ # JSON namespace functions (json::read, json::write, etc.)
930
+ def builtin_json_read(self, path: str, encoding: str = 'utf-8') -> Any:
931
+ """Read and parse JSON file.
932
+ Usage: json::read('/path/to/file.json')
933
+ """
934
+ with open(path, 'r', encoding=encoding) as f:
935
+ return json.load(f)
936
+
937
+ def builtin_json_write(self, path: str, data: Any, indent: int = 2, encoding: str = 'utf-8') -> bool:
938
+ """Write data to JSON file.
939
+ Usage: json::write('/path/to/file.json', data)
940
+ """
941
+ with open(path, 'w', encoding=encoding) as f:
942
+ json.dump(data, f, indent=indent, ensure_ascii=False)
943
+ return True
944
+
945
+ def builtin_json_pretty(self, value: Any, indent: int = 2) -> str:
946
+ """Pretty print JSON.
947
+ Usage: json::pretty(data)
948
+ """
949
+ return json.dumps(value, indent=indent, ensure_ascii=False)
950
+
951
+ def builtin_json_keys(self, data: Any) -> list:
952
+ """Get all keys from JSON object.
953
+ Usage: json::keys(data)
954
+ """
955
+ if isinstance(data, dict):
956
+ return list(data.keys())
957
+ return []
958
+
959
+ def builtin_json_values(self, data: Any) -> list:
960
+ """Get all values from JSON object.
961
+ Usage: json::values(data)
962
+ """
963
+ if isinstance(data, dict):
964
+ return list(data.values())
965
+ return []
966
+
967
+ def builtin_json_get(self, data: Any, path: str, default: Any = None) -> Any:
968
+ """Get value by dot-path from JSON.
969
+ Usage: json::get(data, 'user.name')
970
+ """
971
+ if not isinstance(data, dict):
972
+ return default
973
+ keys = path.split('.')
974
+ current = data
975
+ for key in keys:
976
+ if isinstance(current, dict) and key in current:
977
+ current = current[key]
978
+ elif isinstance(current, list):
979
+ try:
980
+ current = current[int(key)]
981
+ except (ValueError, IndexError):
982
+ return default
983
+ else:
984
+ return default
985
+ return current
986
+
987
+ def builtin_json_set(self, data: Any, path: str, value: Any) -> Any:
988
+ """Set value by dot-path in JSON object.
989
+ Usage: json::set(data, 'user.name', 'John')
990
+ """
991
+ if not isinstance(data, dict):
992
+ return data
993
+ data = dict(data) # Copy
994
+ keys = path.split('.')
995
+ current = data
996
+ for i, key in enumerate(keys[:-1]):
997
+ if key not in current or not isinstance(current[key], dict):
998
+ current[key] = {}
999
+ current = current[key]
1000
+ current[keys[-1]] = value
1001
+ return data
1002
+
1003
+ def builtin_json_has(self, data: Any, path: str) -> bool:
1004
+ """Check if path exists in JSON.
1005
+ Usage: json::has(data, 'user.name')
1006
+ """
1007
+ result = self.builtin_json_get(data, path, _MISSING := object())
1008
+ return result is not _MISSING
1009
+
1010
+ def builtin_json_merge(self, *dicts) -> dict:
1011
+ """Deep merge multiple JSON objects.
1012
+ Usage: json::merge(obj1, obj2, obj3)
1013
+ """
1014
+ def deep_merge(base, update):
1015
+ result = dict(base)
1016
+ for key, value in update.items():
1017
+ if key in result and isinstance(result[key], dict) and isinstance(value, dict):
1018
+ result[key] = deep_merge(result[key], value)
1019
+ else:
1020
+ result[key] = value
1021
+ return result
1022
+
1023
+ result = {}
1024
+ for d in dicts:
1025
+ if isinstance(d, dict):
1026
+ result = deep_merge(result, d)
1027
+ return result
1028
+
865
1029
  # ============= Regex Functions =============
866
1030
 
867
1031
  def builtin_match(self, pattern: str, string: str) -> Optional[dict]:
@@ -2178,9 +2178,48 @@ class CSSLParser:
2178
2178
 
2179
2179
  return node
2180
2180
 
2181
+ def _parse_call_arguments(self) -> tuple:
2182
+ """Parse function call arguments, supporting both positional and named (key=value).
2183
+
2184
+ Returns: (args, kwargs) where:
2185
+ args = list of positional argument expressions
2186
+ kwargs = dict of {name: expression} for named arguments
2187
+ """
2188
+ args = []
2189
+ kwargs = {}
2190
+
2191
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
2192
+ # Check for named argument: identifier = expression
2193
+ if self._check(TokenType.IDENTIFIER):
2194
+ saved_pos = self._current
2195
+ name_token = self._advance()
2196
+
2197
+ if self._check(TokenType.EQUALS):
2198
+ # Named argument: name=value
2199
+ self._advance() # consume =
2200
+ value = self._parse_expression()
2201
+ kwargs[name_token.value] = value
2202
+ else:
2203
+ # Not named, restore and parse as expression
2204
+ self._current = saved_pos
2205
+ args.append(self._parse_expression())
2206
+ else:
2207
+ args.append(self._parse_expression())
2208
+
2209
+ if not self._check(TokenType.PAREN_END):
2210
+ self._expect(TokenType.COMMA)
2211
+
2212
+ return args, kwargs
2213
+
2181
2214
  def _parse_identifier_or_call(self) -> ASTNode:
2182
2215
  name = self._advance().value
2183
2216
 
2217
+ # Check for namespace syntax: json::read, string::cut, etc.
2218
+ if self._match(TokenType.DOUBLE_COLON):
2219
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
2220
+ namespace_member = self._advance().value
2221
+ name = f"{name}::{namespace_member}"
2222
+
2184
2223
  # Check for type generic instantiation: stack<string>, vector<int>, etc.
2185
2224
  # This creates a new instance of the type with the specified element type
2186
2225
  if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
@@ -2226,13 +2265,9 @@ class CSSLParser:
2226
2265
  member = self._advance().value
2227
2266
  node = ASTNode('member_access', value={'object': node, 'member': member})
2228
2267
  elif self._match(TokenType.PAREN_START):
2229
- args = []
2230
- while not self._check(TokenType.PAREN_END):
2231
- args.append(self._parse_expression())
2232
- if not self._check(TokenType.PAREN_END):
2233
- self._expect(TokenType.COMMA)
2268
+ args, kwargs = self._parse_call_arguments()
2234
2269
  self._expect(TokenType.PAREN_END)
2235
- node = ASTNode('call', value={'callee': node, 'args': args})
2270
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2236
2271
  elif self._match(TokenType.BRACKET_START):
2237
2272
  index = self._parse_expression()
2238
2273
  self._expect(TokenType.BRACKET_END)
@@ -775,11 +775,18 @@ class CSSLRuntime:
775
775
  # Fallback: execute normally
776
776
  return self._execute_node(inner)
777
777
 
778
- def _call_function(self, func_node: ASTNode, args: List[Any]) -> Any:
779
- """Call a function node with arguments"""
778
+ def _call_function(self, func_node: ASTNode, args: List[Any], kwargs: Dict[str, Any] = None) -> Any:
779
+ """Call a function node with arguments (positional and named)
780
+
781
+ Args:
782
+ func_node: The function AST node
783
+ args: List of positional arguments
784
+ kwargs: Dict of named arguments (param_name -> value)
785
+ """
780
786
  func_info = func_node.value
781
787
  params = func_info.get('params', [])
782
788
  modifiers = func_info.get('modifiers', [])
789
+ kwargs = kwargs or {}
783
790
 
784
791
  # Check for undefined modifier - suppress errors if present
785
792
  is_undefined = 'undefined' in modifiers
@@ -787,11 +794,16 @@ class CSSLRuntime:
787
794
  # Create new scope
788
795
  new_scope = Scope(parent=self.scope)
789
796
 
790
- # Bind parameters - handle both string and dict formats
797
+ # Bind parameters - handle both positional and named arguments
791
798
  for i, param in enumerate(params):
792
799
  # Extract param name from dict format: {'name': 'a', 'type': 'int'}
793
800
  param_name = param['name'] if isinstance(param, dict) else param
794
- if i < len(args):
801
+
802
+ if param_name in kwargs:
803
+ # Named argument takes priority
804
+ new_scope.set(param_name, kwargs[param_name])
805
+ elif i < len(args):
806
+ # Positional argument
795
807
  new_scope.set(param_name, args[i])
796
808
  else:
797
809
  new_scope.set(param_name, None)
@@ -2025,10 +2037,14 @@ class CSSLRuntime:
2025
2037
  return None
2026
2038
 
2027
2039
  def _eval_call(self, node: ASTNode) -> Any:
2028
- """Evaluate function call"""
2040
+ """Evaluate function call with optional named arguments"""
2029
2041
  callee_node = node.value.get('callee')
2030
2042
  args = [self._evaluate(a) for a in node.value.get('args', [])]
2031
2043
 
2044
+ # Evaluate named arguments (kwargs)
2045
+ kwargs_raw = node.value.get('kwargs', {})
2046
+ kwargs = {k: self._evaluate(v) for k, v in kwargs_raw.items()} if kwargs_raw else {}
2047
+
2032
2048
  # Get function name for injection check FIRST (before evaluating callee)
2033
2049
  func_name = None
2034
2050
  if isinstance(callee_node, ASTNode):
@@ -2056,10 +2072,12 @@ class CSSLRuntime:
2056
2072
 
2057
2073
  # Execute original function
2058
2074
  if callable(callee):
2075
+ if kwargs:
2076
+ return callee(*args, **kwargs)
2059
2077
  return callee(*args)
2060
2078
 
2061
2079
  if isinstance(callee, ASTNode) and callee.type == 'function':
2062
- return self._call_function(callee, args)
2080
+ return self._call_function(callee, args, kwargs)
2063
2081
 
2064
2082
  callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
2065
2083
  raise CSSLRuntimeError(
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "IncludeCPP"
7
- version = "3.5.9"
7
+ version = "3.6.0"
8
8
  description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes