IncludeCPP 3.5.8__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.
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-3.5.8 → includecpp-3.6.0}/PKG-INFO +1 -1
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/__init__.py +1 -1
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +351 -20
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_builtins.py +164 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_parser.py +41 -6
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_runtime.py +35 -9
- {includecpp-3.5.8 → includecpp-3.6.0}/pyproject.toml +1 -1
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/LICENSE +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/MANIFEST.in +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/README.md +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/__init__.pyi +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/__main__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/cli/commands.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cppy_converter.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_events.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_modules.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_syntax.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl/cssl_types.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl_bridge.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/cssl_bridge.pyi +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/generator/parser.cpp +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/generator/parser.h +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/py.typed +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/vscode/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/vscode/cssl/__init__.py +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/vscode/cssl/language-configuration.json +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/vscode/cssl/package.json +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/requirements.txt +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/setup.cfg +0 -0
- {includecpp-3.5.8 → includecpp-3.6.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CSSL - C-Style Scripting Language
|
|
2
2
|
|
|
3
|
-
> Version 3.
|
|
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. [
|
|
19
|
-
11. [
|
|
20
|
-
12. [
|
|
21
|
-
13. [
|
|
22
|
-
14. [
|
|
23
|
-
15. [
|
|
24
|
-
16. [
|
|
25
|
-
17. [
|
|
26
|
-
18. [
|
|
27
|
-
19. [
|
|
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
|
-
//
|
|
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
|
-
|
|
|
1464
|
-
|
|
|
1465
|
-
|
|
|
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.
|
|
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
|
|
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
|
-
|
|
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)
|
|
@@ -1681,9 +1693,17 @@ class CSSLRuntime:
|
|
|
1681
1693
|
return None
|
|
1682
1694
|
|
|
1683
1695
|
if node.type == 'identifier':
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1696
|
+
name = node.value
|
|
1697
|
+
value = self.scope.get(name)
|
|
1698
|
+
# Fallback to global scope
|
|
1699
|
+
if value is None:
|
|
1700
|
+
value = self.global_scope.get(name)
|
|
1701
|
+
# Fallback to promoted globals (from 'global' keyword)
|
|
1702
|
+
if value is None:
|
|
1703
|
+
value = self._promoted_globals.get(name)
|
|
1704
|
+
# Fallback to builtins
|
|
1705
|
+
if value is None and self.builtins.has_function(name):
|
|
1706
|
+
return self.builtins.get_function(name)
|
|
1687
1707
|
return value
|
|
1688
1708
|
|
|
1689
1709
|
if node.type == 'module_ref':
|
|
@@ -2017,10 +2037,14 @@ class CSSLRuntime:
|
|
|
2017
2037
|
return None
|
|
2018
2038
|
|
|
2019
2039
|
def _eval_call(self, node: ASTNode) -> Any:
|
|
2020
|
-
"""Evaluate function call"""
|
|
2040
|
+
"""Evaluate function call with optional named arguments"""
|
|
2021
2041
|
callee_node = node.value.get('callee')
|
|
2022
2042
|
args = [self._evaluate(a) for a in node.value.get('args', [])]
|
|
2023
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
|
+
|
|
2024
2048
|
# Get function name for injection check FIRST (before evaluating callee)
|
|
2025
2049
|
func_name = None
|
|
2026
2050
|
if isinstance(callee_node, ASTNode):
|
|
@@ -2048,10 +2072,12 @@ class CSSLRuntime:
|
|
|
2048
2072
|
|
|
2049
2073
|
# Execute original function
|
|
2050
2074
|
if callable(callee):
|
|
2075
|
+
if kwargs:
|
|
2076
|
+
return callee(*args, **kwargs)
|
|
2051
2077
|
return callee(*args)
|
|
2052
2078
|
|
|
2053
2079
|
if isinstance(callee, ASTNode) and callee.type == 'function':
|
|
2054
|
-
return self._call_function(callee, args)
|
|
2080
|
+
return self._call_function(callee, args, kwargs)
|
|
2055
2081
|
|
|
2056
2082
|
callee_name = callee_node.value if isinstance(callee_node, ASTNode) and hasattr(callee_node, 'value') else str(callee_node)
|
|
2057
2083
|
raise CSSLRuntimeError(
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IncludeCPP"
|
|
7
|
-
version = "3.
|
|
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
|
|
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
|