IncludeCPP 3.7.17__tar.gz → 3.7.23__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.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/PKG-INFO +1 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/__init__.py +1 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/cli/commands.py +7 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/__init__.py +6 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_builtins.py +143 -8
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_builtins.pyi +79 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_parser.py +93 -27
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_runtime.py +446 -25
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_types.py +70 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl_bridge.py +64 -6
- {includecpp-3.7.17 → includecpp-3.7.23}/pyproject.toml +1 -1
- {includecpp-3.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/LICENSE +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/MANIFEST.in +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/README.md +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/__init__.pyi +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/__main__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/__init__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cppy_converter.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_events.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_modules.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl/cssl_syntax.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/cssl_bridge.pyi +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/generator/parser.cpp +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/generator/parser.h +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/py.typed +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/__init__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/__init__.py +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/images/cssl.png +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/language-configuration.json +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/package.json +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/requirements.txt +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/setup.cfg +0 -0
- {includecpp-3.7.17 → includecpp-3.7.23}/setup.py +0 -0
|
@@ -7720,7 +7720,13 @@ def cssl_doc(search, list_sections):
|
|
|
7720
7720
|
click.echo("Or use: includecpp cssl doc --list")
|
|
7721
7721
|
else:
|
|
7722
7722
|
# Full documentation mode
|
|
7723
|
-
|
|
7723
|
+
# Replace Unicode characters that may not be supported on all terminals
|
|
7724
|
+
safe_content = content.replace('✓', '[OK]').replace('✗', '[X]').replace('→', '->').replace('←', '<-').replace('•', '*').replace('─', '-').replace('│', '|').replace('└', '+').replace('├', '+').replace('▸', '>').replace('▾', 'v')
|
|
7725
|
+
try:
|
|
7726
|
+
click.echo_via_pager(safe_content)
|
|
7727
|
+
except UnicodeEncodeError:
|
|
7728
|
+
# Fallback: encode with errors='replace'
|
|
7729
|
+
click.echo(safe_content.encode('ascii', errors='replace').decode('ascii'))
|
|
7724
7730
|
else:
|
|
7725
7731
|
click.secho("Documentation file not found.", fg='yellow')
|
|
7726
7732
|
click.echo("Looking for: CSSL_DOCUMENTATION.md")
|
|
@@ -16,7 +16,10 @@ from .cssl_parser import (
|
|
|
16
16
|
CSSLSyntaxError, CSSLLexer, CSSLParser, ASTNode,
|
|
17
17
|
KEYWORDS, TYPE_GENERICS, TYPE_PARAM_FUNCTIONS, INJECTION_HELPERS
|
|
18
18
|
)
|
|
19
|
-
from .cssl_runtime import
|
|
19
|
+
from .cssl_runtime import (
|
|
20
|
+
CSSLRuntime, CSSLRuntimeError, CSSLServiceRunner, run_cssl, run_cssl_file,
|
|
21
|
+
register_filter, unregister_filter, get_custom_filters
|
|
22
|
+
)
|
|
20
23
|
from .cssl_types import (
|
|
21
24
|
DataStruct, Shuffled, Iterator, Combo, DataSpace, OpenQuote,
|
|
22
25
|
OpenFind, Parameter, Stack, Vector, Array,
|
|
@@ -33,6 +36,8 @@ __all__ = [
|
|
|
33
36
|
# Runtime
|
|
34
37
|
'CSSLRuntime', 'CSSLRuntimeError', 'CSSLServiceRunner',
|
|
35
38
|
'run_cssl', 'run_cssl_file',
|
|
39
|
+
# Filter Registration
|
|
40
|
+
'register_filter', 'unregister_filter', 'get_custom_filters',
|
|
36
41
|
# Data Types
|
|
37
42
|
'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
|
|
38
43
|
'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array',
|
|
@@ -307,6 +307,10 @@ class CSSLBuiltins:
|
|
|
307
307
|
self._functions['dataspace'] = self.builtin_dataspace
|
|
308
308
|
self._functions['openquote'] = self.builtin_openquote
|
|
309
309
|
self._functions['OpenFind'] = self.builtin_openfind
|
|
310
|
+
self._functions['vector'] = self.builtin_vector
|
|
311
|
+
self._functions['array'] = self.builtin_array
|
|
312
|
+
self._functions['stack'] = self.builtin_stack
|
|
313
|
+
self._functions['map'] = self.builtin_map
|
|
310
314
|
|
|
311
315
|
# Print aliases for CSSL
|
|
312
316
|
self._functions['printl'] = self.builtin_println # CSSL uses printl for println
|
|
@@ -433,13 +437,50 @@ class CSSLBuiltins:
|
|
|
433
437
|
# ============= Type Checking =============
|
|
434
438
|
|
|
435
439
|
def builtin_typeof(self, value: Any) -> str:
|
|
436
|
-
"""Get type name"""
|
|
440
|
+
"""Get type name - returns CSSL-specific type names for CSSL types"""
|
|
437
441
|
if value is None:
|
|
438
442
|
return 'null'
|
|
443
|
+
|
|
444
|
+
# Check CSSL-specific types first
|
|
445
|
+
from .cssl_types import (Vector, Array, Stack, DataStruct,
|
|
446
|
+
List as CSSLList, Dictionary, Map,
|
|
447
|
+
Shuffled, Iterator, Combo, DataSpace,
|
|
448
|
+
OpenQuote, Parameter, CSSLInstance)
|
|
449
|
+
|
|
450
|
+
if isinstance(value, Vector):
|
|
451
|
+
return 'vector'
|
|
452
|
+
elif isinstance(value, Array):
|
|
453
|
+
return 'array'
|
|
454
|
+
elif isinstance(value, Stack):
|
|
455
|
+
return 'stack'
|
|
456
|
+
elif isinstance(value, DataStruct):
|
|
457
|
+
return 'datastruct'
|
|
458
|
+
elif isinstance(value, CSSLList):
|
|
459
|
+
return 'list'
|
|
460
|
+
elif isinstance(value, Dictionary):
|
|
461
|
+
return 'dictionary'
|
|
462
|
+
elif isinstance(value, Map):
|
|
463
|
+
return 'map'
|
|
464
|
+
elif isinstance(value, Shuffled):
|
|
465
|
+
return 'shuffled'
|
|
466
|
+
elif isinstance(value, Iterator):
|
|
467
|
+
return 'iterator'
|
|
468
|
+
elif isinstance(value, Combo):
|
|
469
|
+
return 'combo'
|
|
470
|
+
elif isinstance(value, DataSpace):
|
|
471
|
+
return 'dataspace'
|
|
472
|
+
elif isinstance(value, OpenQuote):
|
|
473
|
+
return 'openquote'
|
|
474
|
+
elif isinstance(value, Parameter):
|
|
475
|
+
return 'parameter'
|
|
476
|
+
elif isinstance(value, CSSLInstance):
|
|
477
|
+
return value._class.name
|
|
478
|
+
|
|
479
|
+
# Python types as fallback
|
|
439
480
|
type_map = {
|
|
440
481
|
int: 'int',
|
|
441
482
|
float: 'float',
|
|
442
|
-
str: '
|
|
483
|
+
str: 'string',
|
|
443
484
|
bool: 'bool',
|
|
444
485
|
list: 'list',
|
|
445
486
|
dict: 'dict',
|
|
@@ -1063,13 +1104,18 @@ class CSSLBuiltins:
|
|
|
1063
1104
|
def builtin_instance_getClasses(self, obj: Any) -> list:
|
|
1064
1105
|
"""Get all classes from an object/module.
|
|
1065
1106
|
Usage: instance::getClasses(@module)
|
|
1066
|
-
Returns list of class names.
|
|
1107
|
+
Returns list of class names (including merged classes).
|
|
1067
1108
|
"""
|
|
1068
1109
|
from .cssl_types import CSSLInstance
|
|
1069
1110
|
|
|
1070
|
-
# Handle CSSL class instances
|
|
1111
|
+
# Handle CSSL class instances
|
|
1071
1112
|
if isinstance(obj, CSSLInstance):
|
|
1072
|
-
|
|
1113
|
+
classes = [obj._class.name] # Primary class
|
|
1114
|
+
# Check for merged class instances in members
|
|
1115
|
+
for name, member in obj._members.items():
|
|
1116
|
+
if isinstance(member, CSSLInstance):
|
|
1117
|
+
classes.append(member._class.name)
|
|
1118
|
+
return classes
|
|
1073
1119
|
|
|
1074
1120
|
# Handle Python objects
|
|
1075
1121
|
import inspect
|
|
@@ -1084,13 +1130,18 @@ class CSSLBuiltins:
|
|
|
1084
1130
|
def builtin_instance_getVars(self, obj: Any) -> list:
|
|
1085
1131
|
"""Get all variables/attributes (non-callable) from an object.
|
|
1086
1132
|
Usage: instance::getVars(@module)
|
|
1087
|
-
Returns list of variable names.
|
|
1133
|
+
Returns list of variable names (excludes merged class instances).
|
|
1088
1134
|
"""
|
|
1089
1135
|
from .cssl_types import CSSLInstance
|
|
1090
1136
|
|
|
1091
1137
|
# Handle CSSL class instances
|
|
1092
1138
|
if isinstance(obj, CSSLInstance):
|
|
1093
|
-
|
|
1139
|
+
vars_list = []
|
|
1140
|
+
for name, member in obj._members.items():
|
|
1141
|
+
# Exclude merged class instances
|
|
1142
|
+
if not isinstance(member, CSSLInstance):
|
|
1143
|
+
vars_list.append(name)
|
|
1144
|
+
return vars_list
|
|
1094
1145
|
|
|
1095
1146
|
# Handle Python objects
|
|
1096
1147
|
vars_list = []
|
|
@@ -1118,7 +1169,15 @@ class CSSLBuiltins:
|
|
|
1118
1169
|
if isinstance(obj, CSSLInstance):
|
|
1119
1170
|
result['methods'] = list(obj._class.methods.keys())
|
|
1120
1171
|
result['classes'] = [obj._class.name]
|
|
1121
|
-
|
|
1172
|
+
|
|
1173
|
+
# Separate regular vars from merged class instances
|
|
1174
|
+
for name, member in obj._members.items():
|
|
1175
|
+
if isinstance(member, CSSLInstance):
|
|
1176
|
+
# Merged class - add to classes list
|
|
1177
|
+
result['classes'].append(member._class.name)
|
|
1178
|
+
else:
|
|
1179
|
+
# Regular variable
|
|
1180
|
+
result['vars'].append(name)
|
|
1122
1181
|
return result
|
|
1123
1182
|
|
|
1124
1183
|
# Handle Python objects
|
|
@@ -1197,6 +1256,50 @@ class CSSLBuiltins:
|
|
|
1197
1256
|
# Otherwise, check if the object is not None (for $name or instance<"name">)
|
|
1198
1257
|
return name_or_obj is not None
|
|
1199
1258
|
|
|
1259
|
+
# ============= Filter Registration Functions =============
|
|
1260
|
+
|
|
1261
|
+
def builtin_filter_register(self, filter_type: str, helper: str, callback: Any) -> bool:
|
|
1262
|
+
"""Register a custom filter.
|
|
1263
|
+
Usage: filter::register("mytype", "where", myCallback)
|
|
1264
|
+
|
|
1265
|
+
The callback receives (source, filter_value, runtime) and returns filtered result.
|
|
1266
|
+
Use "*" as helper for catch-all.
|
|
1267
|
+
|
|
1268
|
+
Example:
|
|
1269
|
+
define myFilter(source, value, runtime) {
|
|
1270
|
+
return source + value;
|
|
1271
|
+
}
|
|
1272
|
+
filter::register("custom", "add", myFilter);
|
|
1273
|
+
|
|
1274
|
+
result <==[custom::add=10] 5; // result = 15
|
|
1275
|
+
"""
|
|
1276
|
+
from .cssl_runtime import register_filter
|
|
1277
|
+
register_filter(filter_type, helper, callback)
|
|
1278
|
+
return True
|
|
1279
|
+
|
|
1280
|
+
def builtin_filter_unregister(self, filter_type: str, helper: str) -> bool:
|
|
1281
|
+
"""Unregister a custom filter.
|
|
1282
|
+
Usage: filter::unregister("mytype", "where")
|
|
1283
|
+
"""
|
|
1284
|
+
from .cssl_runtime import unregister_filter
|
|
1285
|
+
return unregister_filter(filter_type, helper)
|
|
1286
|
+
|
|
1287
|
+
def builtin_filter_list(self) -> list:
|
|
1288
|
+
"""List all registered custom filters.
|
|
1289
|
+
Usage: filter::list()
|
|
1290
|
+
Returns list of filter keys like ["mytype::where", "custom::*"]
|
|
1291
|
+
"""
|
|
1292
|
+
from .cssl_runtime import get_custom_filters
|
|
1293
|
+
return list(get_custom_filters().keys())
|
|
1294
|
+
|
|
1295
|
+
def builtin_filter_exists(self, filter_type: str, helper: str) -> bool:
|
|
1296
|
+
"""Check if a custom filter exists.
|
|
1297
|
+
Usage: filter::exists("mytype", "where")
|
|
1298
|
+
"""
|
|
1299
|
+
from .cssl_runtime import get_custom_filters
|
|
1300
|
+
key = f"{filter_type}::{helper}"
|
|
1301
|
+
return key in get_custom_filters()
|
|
1302
|
+
|
|
1200
1303
|
# ============= Regex Functions =============
|
|
1201
1304
|
|
|
1202
1305
|
def builtin_match(self, pattern: str, string: str) -> Optional[dict]:
|
|
@@ -2260,6 +2363,38 @@ class CSSLBuiltins:
|
|
|
2260
2363
|
from .cssl_types import OpenQuote
|
|
2261
2364
|
return OpenQuote(db_ref)
|
|
2262
2365
|
|
|
2366
|
+
def builtin_vector(self, element_type: str = 'dynamic') -> Any:
|
|
2367
|
+
"""Create a vector container.
|
|
2368
|
+
|
|
2369
|
+
Usage: vector<int> myVector; or vector('int')
|
|
2370
|
+
"""
|
|
2371
|
+
from .cssl_types import Vector
|
|
2372
|
+
return Vector(element_type)
|
|
2373
|
+
|
|
2374
|
+
def builtin_array(self, element_type: str = 'dynamic') -> Any:
|
|
2375
|
+
"""Create an array container.
|
|
2376
|
+
|
|
2377
|
+
Usage: array<string> myArray; or array('string')
|
|
2378
|
+
"""
|
|
2379
|
+
from .cssl_types import Array
|
|
2380
|
+
return Array(element_type)
|
|
2381
|
+
|
|
2382
|
+
def builtin_stack(self, element_type: str = 'dynamic') -> Any:
|
|
2383
|
+
"""Create a stack container.
|
|
2384
|
+
|
|
2385
|
+
Usage: stack<int> myStack; or stack('int')
|
|
2386
|
+
"""
|
|
2387
|
+
from .cssl_types import Stack
|
|
2388
|
+
return Stack(element_type)
|
|
2389
|
+
|
|
2390
|
+
def builtin_map(self, key_type: str = 'dynamic', value_type: str = 'dynamic') -> Any:
|
|
2391
|
+
"""Create a map container.
|
|
2392
|
+
|
|
2393
|
+
Usage: map<string, int> myMap; or map('string', 'int')
|
|
2394
|
+
"""
|
|
2395
|
+
from .cssl_types import Map
|
|
2396
|
+
return Map(key_type, value_type)
|
|
2397
|
+
|
|
2263
2398
|
def builtin_openfind(self, combo_or_type: Any, index: int = 0, params: list = None) -> Any:
|
|
2264
2399
|
"""Find open parameter by type or combo space.
|
|
2265
2400
|
|
|
@@ -2082,6 +2082,85 @@ def isavailable(name_or_obj: Any) -> bool:
|
|
|
2082
2082
|
"""
|
|
2083
2083
|
...
|
|
2084
2084
|
|
|
2085
|
+
# =============================================================================
|
|
2086
|
+
# FILTER REGISTRATION FUNCTIONS (filter:: namespace)
|
|
2087
|
+
# =============================================================================
|
|
2088
|
+
# Custom filters allow extending the BruteInjection system with user-defined
|
|
2089
|
+
# filter types. Register filters that can then be used in injection syntax:
|
|
2090
|
+
# result <==[mytype::myhelper="value"] source;
|
|
2091
|
+
|
|
2092
|
+
def filter_register(filter_type: str, helper: str, callback: Callable[[Any, Any, Any], Any]) -> bool:
|
|
2093
|
+
"""Register a custom filter.
|
|
2094
|
+
|
|
2095
|
+
Usage in CSSL: filter::register("mytype", "helper", callback)
|
|
2096
|
+
|
|
2097
|
+
Args:
|
|
2098
|
+
filter_type: The filter type name (e.g., "custom", "mytype")
|
|
2099
|
+
helper: The helper name (e.g., "where", "add") or "*" for catch-all
|
|
2100
|
+
callback: Function(source, filter_value, runtime) -> filtered_result
|
|
2101
|
+
|
|
2102
|
+
Example:
|
|
2103
|
+
// Define a custom filter callback
|
|
2104
|
+
define addFilter(source, value, runtime) {
|
|
2105
|
+
return source + value;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// Register the filter
|
|
2109
|
+
filter::register("math", "add", addFilter);
|
|
2110
|
+
|
|
2111
|
+
// Use the filter
|
|
2112
|
+
result <==[math::add=10] 5; // result = 15
|
|
2113
|
+
|
|
2114
|
+
// Register a catch-all filter
|
|
2115
|
+
define catchAll(source, value, runtime) {
|
|
2116
|
+
printl("Filter called with: " + str(value));
|
|
2117
|
+
return source;
|
|
2118
|
+
}
|
|
2119
|
+
filter::register("debug", "*", catchAll);
|
|
2120
|
+
"""
|
|
2121
|
+
...
|
|
2122
|
+
|
|
2123
|
+
def filter_unregister(filter_type: str, helper: str) -> bool:
|
|
2124
|
+
"""Unregister a custom filter.
|
|
2125
|
+
|
|
2126
|
+
Usage in CSSL: filter::unregister("mytype", "helper")
|
|
2127
|
+
|
|
2128
|
+
Returns:
|
|
2129
|
+
True if filter was found and removed, False otherwise
|
|
2130
|
+
|
|
2131
|
+
Example:
|
|
2132
|
+
filter::unregister("math", "add");
|
|
2133
|
+
"""
|
|
2134
|
+
...
|
|
2135
|
+
|
|
2136
|
+
def filter_list() -> List[str]:
|
|
2137
|
+
"""List all registered custom filters.
|
|
2138
|
+
|
|
2139
|
+
Usage in CSSL: filter::list()
|
|
2140
|
+
|
|
2141
|
+
Returns:
|
|
2142
|
+
List of filter keys like ["math::add", "debug::*"]
|
|
2143
|
+
|
|
2144
|
+
Example:
|
|
2145
|
+
stack<string> filters = filter::list();
|
|
2146
|
+
foreach (f in filters) {
|
|
2147
|
+
printl("Registered filter: " + f);
|
|
2148
|
+
}
|
|
2149
|
+
"""
|
|
2150
|
+
...
|
|
2151
|
+
|
|
2152
|
+
def filter_exists(filter_type: str, helper: str) -> bool:
|
|
2153
|
+
"""Check if a custom filter exists.
|
|
2154
|
+
|
|
2155
|
+
Usage in CSSL: filter::exists("mytype", "helper")
|
|
2156
|
+
|
|
2157
|
+
Example:
|
|
2158
|
+
if (filter::exists("math", "add")) {
|
|
2159
|
+
result <==[math::add=5] 10;
|
|
2160
|
+
}
|
|
2161
|
+
"""
|
|
2162
|
+
...
|
|
2163
|
+
|
|
2085
2164
|
# =============================================================================
|
|
2086
2165
|
# REGEX FUNCTIONS
|
|
2087
2166
|
# =============================================================================
|
|
@@ -252,8 +252,15 @@ class CSSLLexer:
|
|
|
252
252
|
# $<name> shared object reference
|
|
253
253
|
self._read_shared_ref()
|
|
254
254
|
elif char == '%':
|
|
255
|
-
# %<name> captured reference
|
|
256
|
-
self.
|
|
255
|
+
# Check if this is %<name> captured reference or % modulo operator
|
|
256
|
+
next_char = self._peek(1)
|
|
257
|
+
if next_char and (next_char.isalpha() or next_char == '_'):
|
|
258
|
+
# %<name> captured reference (for infusion)
|
|
259
|
+
self._read_captured_ref()
|
|
260
|
+
else:
|
|
261
|
+
# % modulo operator
|
|
262
|
+
self._add_token(TokenType.MODULO, '%')
|
|
263
|
+
self._advance()
|
|
257
264
|
elif char == '&':
|
|
258
265
|
# & for references
|
|
259
266
|
if self._peek(1) == '&':
|
|
@@ -321,9 +328,6 @@ class CSSLLexer:
|
|
|
321
328
|
else:
|
|
322
329
|
# Already handled by // comment check above, but just in case
|
|
323
330
|
self._skip_comment()
|
|
324
|
-
elif char == '%':
|
|
325
|
-
self._add_token(TokenType.MODULO, '%')
|
|
326
|
-
self._advance()
|
|
327
331
|
elif char == '<':
|
|
328
332
|
self._read_less_than()
|
|
329
333
|
elif char == '>':
|
|
@@ -848,7 +852,7 @@ class CSSLParser:
|
|
|
848
852
|
if self._match_keyword('open'):
|
|
849
853
|
param_info['open'] = True
|
|
850
854
|
|
|
851
|
-
# Handle type annotations
|
|
855
|
+
# Handle type annotations (builtin types like int, string, etc.)
|
|
852
856
|
if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
|
|
853
857
|
param_info['type'] = self._advance().value
|
|
854
858
|
|
|
@@ -872,6 +876,39 @@ class CSSLParser:
|
|
|
872
876
|
self._advance()
|
|
873
877
|
param_info['generic'] = ''.join(generic_parts)
|
|
874
878
|
|
|
879
|
+
# Handle custom class types (identifier followed by another identifier = type + name)
|
|
880
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
881
|
+
# Look ahead: if next token is also an identifier, current is the type
|
|
882
|
+
saved_pos = self.pos
|
|
883
|
+
potential_type = self._advance().value
|
|
884
|
+
|
|
885
|
+
# Check for generic type parameter <T> on custom type
|
|
886
|
+
if self._check(TokenType.COMPARE_LT):
|
|
887
|
+
self._advance()
|
|
888
|
+
generic_parts = []
|
|
889
|
+
depth = 1
|
|
890
|
+
while depth > 0 and not self._is_at_end():
|
|
891
|
+
if self._check(TokenType.COMPARE_LT):
|
|
892
|
+
depth += 1
|
|
893
|
+
generic_parts.append('<')
|
|
894
|
+
elif self._check(TokenType.COMPARE_GT):
|
|
895
|
+
depth -= 1
|
|
896
|
+
if depth > 0:
|
|
897
|
+
generic_parts.append('>')
|
|
898
|
+
elif self._check(TokenType.COMMA):
|
|
899
|
+
generic_parts.append(',')
|
|
900
|
+
else:
|
|
901
|
+
generic_parts.append(self._current().value)
|
|
902
|
+
self._advance()
|
|
903
|
+
param_info['generic'] = ''.join(generic_parts)
|
|
904
|
+
|
|
905
|
+
# If followed by identifier, this is "Type name" pattern
|
|
906
|
+
if self._check(TokenType.IDENTIFIER):
|
|
907
|
+
param_info['type'] = potential_type
|
|
908
|
+
else:
|
|
909
|
+
# Not a type, restore position - this is just a param name
|
|
910
|
+
self.pos = saved_pos
|
|
911
|
+
|
|
875
912
|
# Handle reference operator &
|
|
876
913
|
if self._match(TokenType.AMPERSAND):
|
|
877
914
|
param_info['ref'] = True
|
|
@@ -1882,32 +1919,42 @@ class CSSLParser:
|
|
|
1882
1919
|
self._expect(TokenType.BLOCK_END)
|
|
1883
1920
|
return node
|
|
1884
1921
|
|
|
1885
|
-
def _parse_injection_filter(self) -> Optional[
|
|
1886
|
-
"""Parse injection filter: [type::helper=value]
|
|
1887
|
-
|
|
1922
|
+
def _parse_injection_filter(self) -> Optional[list]:
|
|
1923
|
+
"""Parse injection filter(s): [type::helper=value] or [f1][f2][f3]...
|
|
1924
|
+
|
|
1925
|
+
Returns a list of filter dictionaries to support chained filters.
|
|
1926
|
+
"""
|
|
1927
|
+
if not self._check(TokenType.BRACKET_START):
|
|
1888
1928
|
return None
|
|
1889
1929
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1930
|
+
filters = []
|
|
1931
|
+
|
|
1932
|
+
# Parse multiple consecutive filter brackets
|
|
1933
|
+
while self._match(TokenType.BRACKET_START):
|
|
1934
|
+
filter_info = {}
|
|
1935
|
+
# Parse type::helper=value patterns within this bracket
|
|
1936
|
+
while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
|
|
1937
|
+
if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
|
|
1938
|
+
filter_type = self._advance().value
|
|
1939
|
+
if self._match(TokenType.DOUBLE_COLON):
|
|
1940
|
+
helper = self._advance().value
|
|
1941
|
+
if self._match(TokenType.EQUALS):
|
|
1942
|
+
value = self._parse_expression()
|
|
1943
|
+
filter_info[f'{filter_type}::{helper}'] = value
|
|
1944
|
+
else:
|
|
1945
|
+
filter_info[f'{filter_type}::{helper}'] = True
|
|
1900
1946
|
else:
|
|
1901
|
-
filter_info[
|
|
1947
|
+
filter_info['type'] = filter_type
|
|
1948
|
+
elif self._check(TokenType.COMMA):
|
|
1949
|
+
self._advance()
|
|
1902
1950
|
else:
|
|
1903
|
-
|
|
1904
|
-
elif self._check(TokenType.COMMA):
|
|
1905
|
-
self._advance()
|
|
1906
|
-
else:
|
|
1907
|
-
break
|
|
1951
|
+
break
|
|
1908
1952
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1953
|
+
self._expect(TokenType.BRACKET_END)
|
|
1954
|
+
if filter_info:
|
|
1955
|
+
filters.append(filter_info)
|
|
1956
|
+
|
|
1957
|
+
return filters if filters else None
|
|
1911
1958
|
|
|
1912
1959
|
def _parse_expression_statement(self) -> Optional[ASTNode]:
|
|
1913
1960
|
expr = self._parse_expression()
|
|
@@ -2118,6 +2165,11 @@ class CSSLParser:
|
|
|
2118
2165
|
elif self._match(TokenType.COMPARE_GE):
|
|
2119
2166
|
right = self._parse_term()
|
|
2120
2167
|
left = ASTNode('binary', value={'op': '>=', 'left': left, 'right': right})
|
|
2168
|
+
elif self._check(TokenType.KEYWORD) and self._peek().value == 'in':
|
|
2169
|
+
# 'in' operator for containment: item in list
|
|
2170
|
+
self._advance() # consume 'in'
|
|
2171
|
+
right = self._parse_term()
|
|
2172
|
+
left = ASTNode('binary', value={'op': 'in', 'left': left, 'right': right})
|
|
2121
2173
|
else:
|
|
2122
2174
|
break
|
|
2123
2175
|
|
|
@@ -2504,6 +2556,20 @@ class CSSLParser:
|
|
|
2504
2556
|
|
|
2505
2557
|
self._expect(TokenType.BLOCK_END) # consume }
|
|
2506
2558
|
|
|
2559
|
+
# Check for array-style initialization: vector<int>[1, 2, 3], array<string>["a", "b"]
|
|
2560
|
+
elif self._check(TokenType.BRACKET_START):
|
|
2561
|
+
self._advance() # consume [
|
|
2562
|
+
init_values = []
|
|
2563
|
+
|
|
2564
|
+
while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
|
|
2565
|
+
init_values.append(self._parse_expression())
|
|
2566
|
+
|
|
2567
|
+
# Optional comma
|
|
2568
|
+
if self._check(TokenType.COMMA):
|
|
2569
|
+
self._advance()
|
|
2570
|
+
|
|
2571
|
+
self._expect(TokenType.BRACKET_END) # consume ]
|
|
2572
|
+
|
|
2507
2573
|
return ASTNode('type_instantiation', value={
|
|
2508
2574
|
'type': name,
|
|
2509
2575
|
'element_type': element_type,
|