IncludeCPP 3.3.20__py3-none-any.whl → 3.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/__init__.py +4 -3
- includecpp/cli/commands.py +400 -21
- includecpp/core/cppy_converter.py +143 -18
- includecpp/core/cssl/__init__.py +40 -0
- includecpp/core/cssl/cssl_builtins.py +1693 -0
- includecpp/core/cssl/cssl_events.py +621 -0
- includecpp/core/cssl/cssl_modules.py +2803 -0
- includecpp/core/cssl/cssl_parser.py +1493 -0
- includecpp/core/cssl/cssl_runtime.py +1549 -0
- includecpp/core/cssl/cssl_syntax.py +488 -0
- includecpp/core/cssl/cssl_types.py +390 -0
- includecpp/core/cssl_bridge.py +132 -0
- includecpp/core/project_ui.py +684 -34
- includecpp/generator/parser.cpp +81 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/METADATA +48 -4
- includecpp-3.4.2.dist-info/RECORD +40 -0
- includecpp-3.3.20.dist-info/RECORD +0 -31
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/WHEEL +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/entry_points.txt +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CSSL Data Types - Advanced container types for CSO Service Script Language
|
|
3
|
+
|
|
4
|
+
Types:
|
|
5
|
+
- datastruct<T>: Universal container (lazy declarator) - can hold any type
|
|
6
|
+
- shuffled<T>: Unorganized fast storage for multiple returns
|
|
7
|
+
- iterator<T>: Advanced iterator with programmable tasks
|
|
8
|
+
- combo<T>: Filter/search spaces for open parameter matching
|
|
9
|
+
- dataspace<T>: SQL/data storage container
|
|
10
|
+
- openquote<T>: SQL openquote container
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any, Dict, List, Optional, Callable, Union, TypeVar, Generic
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
import copy
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
T = TypeVar('T')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DataStruct(list):
|
|
22
|
+
"""Universal container - lazy declarator that can hold any type.
|
|
23
|
+
|
|
24
|
+
Like a vector but more flexible. Can hold strings, ints, floats,
|
|
25
|
+
objects, etc. at the cost of performance.
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
datastruct<dynamic> myData;
|
|
29
|
+
myData +<== someValue;
|
|
30
|
+
myData.content() # Returns all elements
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, element_type: str = 'dynamic'):
|
|
34
|
+
super().__init__()
|
|
35
|
+
self._element_type = element_type
|
|
36
|
+
self._metadata: Dict[str, Any] = {}
|
|
37
|
+
|
|
38
|
+
def content(self) -> list:
|
|
39
|
+
"""Return all elements as a list"""
|
|
40
|
+
return list(self)
|
|
41
|
+
|
|
42
|
+
def add(self, item: Any) -> 'DataStruct':
|
|
43
|
+
"""Add an item to the datastruct"""
|
|
44
|
+
self.append(item)
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def remove_where(self, predicate: Callable[[Any], bool]) -> 'DataStruct':
|
|
48
|
+
"""Remove items matching predicate"""
|
|
49
|
+
to_remove = [item for item in self if predicate(item)]
|
|
50
|
+
for item in to_remove:
|
|
51
|
+
self.remove(item)
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def find_where(self, predicate: Callable[[Any], bool]) -> Optional[Any]:
|
|
55
|
+
"""Find first item matching predicate"""
|
|
56
|
+
for item in self:
|
|
57
|
+
if predicate(item):
|
|
58
|
+
return item
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def convert(self, target_type: type) -> Any:
|
|
62
|
+
"""Convert first element to target type"""
|
|
63
|
+
if len(self) > 0:
|
|
64
|
+
return target_type(self[0])
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Shuffled(list):
|
|
69
|
+
"""Unorganized fast storage for multiple returns.
|
|
70
|
+
|
|
71
|
+
Stores data unorganized for fast and efficient access.
|
|
72
|
+
Supports receiving multiple return values from functions.
|
|
73
|
+
|
|
74
|
+
Usage:
|
|
75
|
+
shuffled<string> results;
|
|
76
|
+
results +<== someFunc(); # Catches all returns
|
|
77
|
+
results.read() # Returns all content as list
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, element_type: str = 'dynamic'):
|
|
81
|
+
super().__init__()
|
|
82
|
+
self._element_type = element_type
|
|
83
|
+
|
|
84
|
+
def read(self) -> list:
|
|
85
|
+
"""Return all content as a list"""
|
|
86
|
+
return list(self)
|
|
87
|
+
|
|
88
|
+
def collect(self, func: Callable, *args) -> 'Shuffled':
|
|
89
|
+
"""Collect all returns from a function"""
|
|
90
|
+
result = func(*args)
|
|
91
|
+
if isinstance(result, (list, tuple)):
|
|
92
|
+
self.extend(result)
|
|
93
|
+
else:
|
|
94
|
+
self.append(result)
|
|
95
|
+
return self
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class Iterator:
|
|
99
|
+
"""Advanced iterator with programmable tasks.
|
|
100
|
+
|
|
101
|
+
Provides iterator positions within a data container with
|
|
102
|
+
the ability to attach tasks (functions) to iterators.
|
|
103
|
+
|
|
104
|
+
Usage:
|
|
105
|
+
iterator<int, 16> Map; # Create 16-element iterator space
|
|
106
|
+
Map::iterator::set(0, 5); # Set iterator 0 to position 5
|
|
107
|
+
Map::iterator::task(0, myFunc); # Attach task to iterator
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(self, element_type: str = 'int', size: int = 16):
|
|
111
|
+
self._element_type = element_type
|
|
112
|
+
self._size = size
|
|
113
|
+
self._data: List[Any] = [None] * size
|
|
114
|
+
self._iterators: Dict[int, int] = {0: 0, 1: 1} # Default: 2 iterators at positions 0 and 1
|
|
115
|
+
self._tasks: Dict[int, Callable] = {}
|
|
116
|
+
|
|
117
|
+
def insert(self, index: int, value: Any) -> 'Iterator':
|
|
118
|
+
"""Insert value at index"""
|
|
119
|
+
if 0 <= index < self._size:
|
|
120
|
+
self._data[index] = value
|
|
121
|
+
return self
|
|
122
|
+
|
|
123
|
+
def fill(self, value: Any) -> 'Iterator':
|
|
124
|
+
"""Fill all positions with value"""
|
|
125
|
+
self._data = [value] * self._size
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
def at(self, index: int) -> Any:
|
|
129
|
+
"""Get value at index"""
|
|
130
|
+
if 0 <= index < self._size:
|
|
131
|
+
return self._data[index]
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
def is_all(self, check_value: bool) -> bool:
|
|
135
|
+
"""Check if all values are 1 (True) or 0 (False)"""
|
|
136
|
+
expected = 1 if check_value else 0
|
|
137
|
+
return all(v == expected for v in self._data if v is not None)
|
|
138
|
+
|
|
139
|
+
def end(self) -> int:
|
|
140
|
+
"""Return last index"""
|
|
141
|
+
return self._size - 1
|
|
142
|
+
|
|
143
|
+
class IteratorControl:
|
|
144
|
+
"""Static methods for iterator control"""
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def set(iterator_obj: 'Iterator', iterator_id: int, position: int):
|
|
148
|
+
"""Set iterator position"""
|
|
149
|
+
iterator_obj._iterators[iterator_id] = position
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def move(iterator_obj: 'Iterator', iterator_id: int, steps: int):
|
|
153
|
+
"""Move iterator by steps"""
|
|
154
|
+
if iterator_id in iterator_obj._iterators:
|
|
155
|
+
iterator_obj._iterators[iterator_id] += steps
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def insert(iterator_obj: 'Iterator', iterator_id: int, value: Any):
|
|
159
|
+
"""Insert value at current iterator position"""
|
|
160
|
+
if iterator_id in iterator_obj._iterators:
|
|
161
|
+
pos = iterator_obj._iterators[iterator_id]
|
|
162
|
+
if 0 <= pos < iterator_obj._size:
|
|
163
|
+
iterator_obj._data[pos] = value
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def pop(iterator_obj: 'Iterator', iterator_id: int):
|
|
167
|
+
"""Delete value at current iterator position"""
|
|
168
|
+
if iterator_id in iterator_obj._iterators:
|
|
169
|
+
pos = iterator_obj._iterators[iterator_id]
|
|
170
|
+
if 0 <= pos < iterator_obj._size:
|
|
171
|
+
iterator_obj._data[pos] = None
|
|
172
|
+
|
|
173
|
+
@staticmethod
|
|
174
|
+
def task(iterator_obj: 'Iterator', iterator_id: int, func: Callable):
|
|
175
|
+
"""Attach a task function to iterator"""
|
|
176
|
+
iterator_obj._tasks[iterator_id] = func
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def dtask(iterator_obj: 'Iterator', iterator_id: int):
|
|
180
|
+
"""Clear task from iterator"""
|
|
181
|
+
if iterator_id in iterator_obj._tasks:
|
|
182
|
+
del iterator_obj._tasks[iterator_id]
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def run_task(iterator_obj: 'Iterator', iterator_id: int):
|
|
186
|
+
"""Run the task at current iterator position"""
|
|
187
|
+
if iterator_id in iterator_obj._tasks and iterator_id in iterator_obj._iterators:
|
|
188
|
+
pos = iterator_obj._iterators[iterator_id]
|
|
189
|
+
task = iterator_obj._tasks[iterator_id]
|
|
190
|
+
# Create a position wrapper
|
|
191
|
+
class IteratorPos:
|
|
192
|
+
def __init__(self, data, idx):
|
|
193
|
+
self._data = data
|
|
194
|
+
self._idx = idx
|
|
195
|
+
def read(self):
|
|
196
|
+
return self._data[self._idx]
|
|
197
|
+
def write(self, value):
|
|
198
|
+
self._data[self._idx] = value
|
|
199
|
+
|
|
200
|
+
task(IteratorPos(iterator_obj._data, pos))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class Combo:
|
|
204
|
+
"""Filter/search space for open parameter matching.
|
|
205
|
+
|
|
206
|
+
Creates a search/filter space that can match parameters
|
|
207
|
+
based on filter databases and similarity.
|
|
208
|
+
|
|
209
|
+
Usage:
|
|
210
|
+
combo<open&string> nameSpace;
|
|
211
|
+
nameSpace +<== [combo::filterdb] filterDB;
|
|
212
|
+
special_name = OpenFind(&nameSpace);
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
def __init__(self, element_type: str = 'dynamic'):
|
|
216
|
+
self._element_type = element_type
|
|
217
|
+
self._filterdb: List[Any] = []
|
|
218
|
+
self._blocked: List[Any] = []
|
|
219
|
+
self._data: List[Any] = []
|
|
220
|
+
self._like_pattern: Optional[str] = None
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def filterdb(self) -> List[Any]:
|
|
224
|
+
return self._filterdb
|
|
225
|
+
|
|
226
|
+
@filterdb.setter
|
|
227
|
+
def filterdb(self, value: List[Any]):
|
|
228
|
+
self._filterdb = value
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def blocked(self) -> List[Any]:
|
|
232
|
+
return self._blocked
|
|
233
|
+
|
|
234
|
+
@blocked.setter
|
|
235
|
+
def blocked(self, value: List[Any]):
|
|
236
|
+
self._blocked = value
|
|
237
|
+
|
|
238
|
+
def like(self, pattern: str) -> 'Combo':
|
|
239
|
+
"""Set similarity pattern (94-100% match)"""
|
|
240
|
+
self._like_pattern = pattern
|
|
241
|
+
return self
|
|
242
|
+
|
|
243
|
+
def matches(self, value: Any) -> bool:
|
|
244
|
+
"""Check if value matches combo criteria"""
|
|
245
|
+
# Check if blocked
|
|
246
|
+
if value in self._blocked:
|
|
247
|
+
return False
|
|
248
|
+
|
|
249
|
+
# Check filterdb if present
|
|
250
|
+
if self._filterdb:
|
|
251
|
+
if value not in self._filterdb:
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
# Check like pattern if present
|
|
255
|
+
if self._like_pattern and isinstance(value, str):
|
|
256
|
+
similarity = self._calculate_similarity(value, self._like_pattern)
|
|
257
|
+
if similarity < 0.94:
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
return True
|
|
261
|
+
|
|
262
|
+
def _calculate_similarity(self, s1: str, s2: str) -> float:
|
|
263
|
+
"""Calculate string similarity (simple Levenshtein-based)"""
|
|
264
|
+
if s1 == s2:
|
|
265
|
+
return 1.0
|
|
266
|
+
if not s1 or not s2:
|
|
267
|
+
return 0.0
|
|
268
|
+
|
|
269
|
+
# Simple character-based similarity
|
|
270
|
+
s1_lower = s1.lower()
|
|
271
|
+
s2_lower = s2.lower()
|
|
272
|
+
|
|
273
|
+
matching = sum(c1 == c2 for c1, c2 in zip(s1_lower, s2_lower))
|
|
274
|
+
return matching / max(len(s1), len(s2))
|
|
275
|
+
|
|
276
|
+
def find_match(self, items: List[Any]) -> Optional[Any]:
|
|
277
|
+
"""Find first matching item from list"""
|
|
278
|
+
for item in items:
|
|
279
|
+
if self.matches(item):
|
|
280
|
+
return item
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class DataSpace(dict):
|
|
285
|
+
"""SQL/data storage container for structured data.
|
|
286
|
+
|
|
287
|
+
Used for SQL table definitions and structured data storage.
|
|
288
|
+
|
|
289
|
+
Usage:
|
|
290
|
+
dataspace<sql::table> table = { ... };
|
|
291
|
+
@Sql.Structured(&table);
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
def __init__(self, space_type: str = 'dynamic'):
|
|
295
|
+
super().__init__()
|
|
296
|
+
self._space_type = space_type
|
|
297
|
+
self._sections: Dict[str, Any] = {}
|
|
298
|
+
|
|
299
|
+
def content(self) -> dict:
|
|
300
|
+
"""Return all content"""
|
|
301
|
+
return dict(self)
|
|
302
|
+
|
|
303
|
+
def section(self, name: str, *types) -> 'DataSpace':
|
|
304
|
+
"""Create a section with specified types"""
|
|
305
|
+
self._sections[name] = {
|
|
306
|
+
'types': types,
|
|
307
|
+
'data': []
|
|
308
|
+
}
|
|
309
|
+
return self
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class OpenQuote:
|
|
313
|
+
"""SQL openquote container for organized data handling.
|
|
314
|
+
|
|
315
|
+
Creates a datastruct together with sql::db.oqt() for easy
|
|
316
|
+
data organization and retrieval.
|
|
317
|
+
|
|
318
|
+
Usage:
|
|
319
|
+
openquote<datastruct<dynamic>&@sql::db.oqt(@db)> Queue;
|
|
320
|
+
Queue.save("Section", "data1", "data2", 123);
|
|
321
|
+
Queue.where(Section="value", KEY="match");
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
def __init__(self, db_reference: Any = None):
|
|
325
|
+
self._data: List[Dict[str, Any]] = []
|
|
326
|
+
self._db_ref = db_reference
|
|
327
|
+
|
|
328
|
+
def save(self, section: str, *values) -> 'OpenQuote':
|
|
329
|
+
"""Save data to a section"""
|
|
330
|
+
self._data.append({
|
|
331
|
+
'section': section,
|
|
332
|
+
'values': list(values)
|
|
333
|
+
})
|
|
334
|
+
return self
|
|
335
|
+
|
|
336
|
+
def where(self, **kwargs) -> Optional[Any]:
|
|
337
|
+
"""Find data matching criteria"""
|
|
338
|
+
for entry in self._data:
|
|
339
|
+
if all(entry.get(k) == v or (k == 'Section' and entry.get('section') == v)
|
|
340
|
+
for k, v in kwargs.items()):
|
|
341
|
+
return entry
|
|
342
|
+
return None
|
|
343
|
+
|
|
344
|
+
def all(self) -> List[Dict[str, Any]]:
|
|
345
|
+
"""Return all data"""
|
|
346
|
+
return self._data
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def OpenFind(combo_or_type: Union[Combo, type], index: int = 0) -> Optional[Any]:
|
|
350
|
+
"""Find open parameter by type or combo space.
|
|
351
|
+
|
|
352
|
+
Usage:
|
|
353
|
+
string name = OpenFind<string>(0); # Find string at index 0
|
|
354
|
+
string special = OpenFind(&@comboSpace); # Find by combo
|
|
355
|
+
"""
|
|
356
|
+
if isinstance(combo_or_type, Combo):
|
|
357
|
+
# Find by combo space
|
|
358
|
+
return combo_or_type.find_match([]) # Would need open params context
|
|
359
|
+
elif isinstance(combo_or_type, type):
|
|
360
|
+
# Find by type at index - needs open params context
|
|
361
|
+
pass
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# Type factory functions for CSSL
|
|
366
|
+
def create_datastruct(element_type: str = 'dynamic') -> DataStruct:
|
|
367
|
+
return DataStruct(element_type)
|
|
368
|
+
|
|
369
|
+
def create_shuffled(element_type: str = 'dynamic') -> Shuffled:
|
|
370
|
+
return Shuffled(element_type)
|
|
371
|
+
|
|
372
|
+
def create_iterator(element_type: str = 'int', size: int = 16) -> Iterator:
|
|
373
|
+
return Iterator(element_type, size)
|
|
374
|
+
|
|
375
|
+
def create_combo(element_type: str = 'dynamic') -> Combo:
|
|
376
|
+
return Combo(element_type)
|
|
377
|
+
|
|
378
|
+
def create_dataspace(space_type: str = 'dynamic') -> DataSpace:
|
|
379
|
+
return DataSpace(space_type)
|
|
380
|
+
|
|
381
|
+
def create_openquote(db_ref: Any = None) -> OpenQuote:
|
|
382
|
+
return OpenQuote(db_ref)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
__all__ = [
|
|
386
|
+
'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
|
|
387
|
+
'OpenFind',
|
|
388
|
+
'create_datastruct', 'create_shuffled', 'create_iterator',
|
|
389
|
+
'create_combo', 'create_dataspace', 'create_openquote'
|
|
390
|
+
]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CSSL Bridge - Python API for CSSL Language
|
|
3
|
+
Provides CsslLang class for executing CSSL code from Python.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import threading
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, List, Optional, Callable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CsslLang:
|
|
12
|
+
"""
|
|
13
|
+
CSSL Language interface for Python.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
from includecpp import CSSL
|
|
17
|
+
cssl = CSSL.CsslLang()
|
|
18
|
+
result = cssl.exec("script.cssl", arg1, arg2)
|
|
19
|
+
cssl.T_exec("async_script.cssl", arg1) # Threaded
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, output_callback: Optional[Callable[[str, str], None]] = None):
|
|
23
|
+
"""
|
|
24
|
+
Initialize CSSL runtime.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
output_callback: Optional callback for output (text, level)
|
|
28
|
+
"""
|
|
29
|
+
self._output_callback = output_callback
|
|
30
|
+
self._runtime = None
|
|
31
|
+
self._threads: List[threading.Thread] = []
|
|
32
|
+
|
|
33
|
+
def _get_runtime(self):
|
|
34
|
+
"""Lazy load CSSL runtime."""
|
|
35
|
+
if self._runtime is None:
|
|
36
|
+
from .cssl import CSSLRuntime
|
|
37
|
+
self._runtime = CSSLRuntime(output_callback=self._output_callback)
|
|
38
|
+
return self._runtime
|
|
39
|
+
|
|
40
|
+
def exec(self, path_or_code: str, *args) -> Any:
|
|
41
|
+
"""
|
|
42
|
+
Execute CSSL code or file.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
path_or_code: Path to .cssl file or CSSL code string
|
|
46
|
+
*args: Arguments to pass to the script
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Execution result
|
|
50
|
+
"""
|
|
51
|
+
runtime = self._get_runtime()
|
|
52
|
+
|
|
53
|
+
# Check if it's a file path
|
|
54
|
+
path = Path(path_or_code)
|
|
55
|
+
if path.exists() and path.suffix in ('.cssl', '.cssl-mod'):
|
|
56
|
+
source = path.read_text(encoding='utf-8')
|
|
57
|
+
else:
|
|
58
|
+
source = path_or_code
|
|
59
|
+
|
|
60
|
+
# Set arguments in runtime scope
|
|
61
|
+
runtime.global_scope.set('args', list(args))
|
|
62
|
+
runtime.global_scope.set('argc', len(args))
|
|
63
|
+
|
|
64
|
+
# Execute as standalone program
|
|
65
|
+
try:
|
|
66
|
+
result = runtime.execute_program(source)
|
|
67
|
+
return result
|
|
68
|
+
except Exception as e:
|
|
69
|
+
raise RuntimeError(f"CSSL Error: {e}") from e
|
|
70
|
+
|
|
71
|
+
def T_exec(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
|
|
72
|
+
"""
|
|
73
|
+
Execute CSSL code asynchronously in a thread.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
path_or_code: Path to .cssl file or CSSL code string
|
|
77
|
+
*args: Arguments to pass to the script
|
|
78
|
+
callback: Optional callback when execution completes
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Thread object
|
|
82
|
+
"""
|
|
83
|
+
def _run():
|
|
84
|
+
try:
|
|
85
|
+
result = self.exec(path_or_code, *args)
|
|
86
|
+
if callback:
|
|
87
|
+
callback(result)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
if callback:
|
|
90
|
+
callback(e)
|
|
91
|
+
|
|
92
|
+
thread = threading.Thread(target=_run, daemon=True)
|
|
93
|
+
thread.start()
|
|
94
|
+
self._threads.append(thread)
|
|
95
|
+
return thread
|
|
96
|
+
|
|
97
|
+
def wait_all(self, timeout: Optional[float] = None):
|
|
98
|
+
"""Wait for all async executions to complete."""
|
|
99
|
+
for thread in self._threads:
|
|
100
|
+
thread.join(timeout=timeout)
|
|
101
|
+
self._threads.clear()
|
|
102
|
+
|
|
103
|
+
def get_output(self) -> List[str]:
|
|
104
|
+
"""Get output buffer from last execution."""
|
|
105
|
+
runtime = self._get_runtime()
|
|
106
|
+
return list(runtime.output_buffer)
|
|
107
|
+
|
|
108
|
+
def clear_output(self):
|
|
109
|
+
"""Clear output buffer."""
|
|
110
|
+
runtime = self._get_runtime()
|
|
111
|
+
runtime.output_buffer.clear()
|
|
112
|
+
|
|
113
|
+
def set_global(self, name: str, value: Any):
|
|
114
|
+
"""Set a global variable in CSSL runtime."""
|
|
115
|
+
runtime = self._get_runtime()
|
|
116
|
+
runtime.global_scope.set(name, value)
|
|
117
|
+
|
|
118
|
+
def get_global(self, name: str) -> Any:
|
|
119
|
+
"""Get a global variable from CSSL runtime."""
|
|
120
|
+
runtime = self._get_runtime()
|
|
121
|
+
return runtime.global_scope.get(name)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Singleton for convenience
|
|
125
|
+
_default_instance: Optional[CsslLang] = None
|
|
126
|
+
|
|
127
|
+
def get_cssl() -> CsslLang:
|
|
128
|
+
"""Get default CSSL instance."""
|
|
129
|
+
global _default_instance
|
|
130
|
+
if _default_instance is None:
|
|
131
|
+
_default_instance = CsslLang()
|
|
132
|
+
return _default_instance
|