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.
@@ -0,0 +1,1693 @@
1
+ """
2
+ CSSL Built-in Functions
3
+ Provides standard functions available in all CSSL scripts
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import time
9
+ import random
10
+ import hashlib
11
+ import json
12
+ import re
13
+ import math
14
+ from typing import Any, Dict, List, Optional, Callable, Union
15
+ from datetime import datetime
16
+
17
+
18
+ class CSSLBuiltinError(Exception):
19
+ """Error in builtin function execution"""
20
+ pass
21
+
22
+
23
+ class CSSLBuiltins:
24
+ """
25
+ Built-in functions for CSSL runtime
26
+ These functions are available in all CSSL scripts without imports
27
+ """
28
+
29
+ def __init__(self, runtime=None):
30
+ self.runtime = runtime
31
+ self._functions: Dict[str, Callable] = {}
32
+ self._register_all()
33
+
34
+ def _register_all(self):
35
+ """Register all built-in functions"""
36
+ # Output functions
37
+ self._functions['print'] = self.builtin_print
38
+ self._functions['println'] = self.builtin_println
39
+ self._functions['debug'] = self.builtin_debug
40
+ self._functions['error'] = self.builtin_error
41
+ self._functions['warn'] = self.builtin_warn
42
+ self._functions['log'] = self.builtin_log
43
+
44
+ # Type conversion
45
+ self._functions['int'] = self.builtin_int
46
+ self._functions['float'] = self.builtin_float
47
+ self._functions['str'] = self.builtin_str
48
+ self._functions['bool'] = self.builtin_bool
49
+ self._functions['list'] = self.builtin_list
50
+ self._functions['dict'] = self.builtin_dict
51
+
52
+ # Type checking
53
+ self._functions['typeof'] = self.builtin_typeof
54
+ self._functions['isinstance'] = self.builtin_isinstance
55
+ self._functions['isint'] = self.builtin_isint
56
+ self._functions['isfloat'] = self.builtin_isfloat
57
+ self._functions['isstr'] = self.builtin_isstr
58
+ self._functions['isbool'] = self.builtin_isbool
59
+ self._functions['islist'] = self.builtin_islist
60
+ self._functions['isdict'] = self.builtin_isdict
61
+ self._functions['isnull'] = self.builtin_isnull
62
+
63
+ # String functions
64
+ self._functions['len'] = self.builtin_len
65
+ self._functions['upper'] = self.builtin_upper
66
+ self._functions['lower'] = self.builtin_lower
67
+ self._functions['trim'] = self.builtin_trim
68
+ self._functions['ltrim'] = self.builtin_ltrim
69
+ self._functions['rtrim'] = self.builtin_rtrim
70
+ self._functions['split'] = self.builtin_split
71
+ self._functions['join'] = self.builtin_join
72
+ self._functions['replace'] = self.builtin_replace
73
+ self._functions['substr'] = self.builtin_substr
74
+ self._functions['contains'] = self.builtin_contains
75
+ self._functions['startswith'] = self.builtin_startswith
76
+ self._functions['endswith'] = self.builtin_endswith
77
+ self._functions['format'] = self.builtin_format
78
+ self._functions['concat'] = self.builtin_concat
79
+ self._functions['repeat'] = self.builtin_repeat
80
+ self._functions['reverse'] = self.builtin_reverse
81
+ self._functions['indexof'] = self.builtin_indexof
82
+ self._functions['lastindexof'] = self.builtin_lastindexof
83
+ self._functions['padleft'] = self.builtin_padleft
84
+ self._functions['padright'] = self.builtin_padright
85
+
86
+ # List functions
87
+ self._functions['push'] = self.builtin_push
88
+ self._functions['pop'] = self.builtin_pop
89
+ self._functions['shift'] = self.builtin_shift
90
+ self._functions['unshift'] = self.builtin_unshift
91
+ self._functions['slice'] = self.builtin_slice
92
+ self._functions['sort'] = self.builtin_sort
93
+ self._functions['rsort'] = self.builtin_rsort
94
+ self._functions['unique'] = self.builtin_unique
95
+ self._functions['flatten'] = self.builtin_flatten
96
+ self._functions['filter'] = self.builtin_filter
97
+ self._functions['map'] = self.builtin_map
98
+ self._functions['reduce'] = self.builtin_reduce
99
+ self._functions['find'] = self.builtin_find
100
+ self._functions['findindex'] = self.builtin_findindex
101
+ self._functions['every'] = self.builtin_every
102
+ self._functions['some'] = self.builtin_some
103
+ self._functions['range'] = self.builtin_range
104
+
105
+ # Dict functions
106
+ self._functions['keys'] = self.builtin_keys
107
+ self._functions['values'] = self.builtin_values
108
+ self._functions['items'] = self.builtin_items
109
+ self._functions['haskey'] = self.builtin_haskey
110
+ self._functions['getkey'] = self.builtin_getkey
111
+ self._functions['setkey'] = self.builtin_setkey
112
+ self._functions['delkey'] = self.builtin_delkey
113
+ self._functions['merge'] = self.builtin_merge
114
+
115
+ # Math functions
116
+ self._functions['abs'] = self.builtin_abs
117
+ self._functions['min'] = self.builtin_min
118
+ self._functions['max'] = self.builtin_max
119
+ self._functions['sum'] = self.builtin_sum
120
+ self._functions['avg'] = self.builtin_avg
121
+ self._functions['round'] = self.builtin_round
122
+ self._functions['floor'] = self.builtin_floor
123
+ self._functions['ceil'] = self.builtin_ceil
124
+ self._functions['pow'] = self.builtin_pow
125
+ self._functions['sqrt'] = self.builtin_sqrt
126
+ self._functions['mod'] = self.builtin_mod
127
+ self._functions['random'] = self.builtin_random
128
+ self._functions['randint'] = self.builtin_randint
129
+ # Extended math functions
130
+ self._functions['sin'] = self.builtin_sin
131
+ self._functions['cos'] = self.builtin_cos
132
+ self._functions['tan'] = self.builtin_tan
133
+ self._functions['asin'] = self.builtin_asin
134
+ self._functions['acos'] = self.builtin_acos
135
+ self._functions['atan'] = self.builtin_atan
136
+ self._functions['atan2'] = self.builtin_atan2
137
+ self._functions['log'] = self.builtin_log
138
+ self._functions['log10'] = self.builtin_log10
139
+ self._functions['exp'] = self.builtin_exp
140
+ self._functions['pi'] = lambda: math.pi
141
+ self._functions['e'] = lambda: math.e
142
+ self._functions['radians'] = self.builtin_radians
143
+ self._functions['degrees'] = self.builtin_degrees
144
+
145
+ # Time functions
146
+ self._functions['now'] = self.builtin_now
147
+ self._functions['timestamp'] = self.builtin_timestamp
148
+ self._functions['sleep'] = self.builtin_sleep
149
+ self._functions['date'] = self.builtin_date
150
+ self._functions['time'] = self.builtin_time
151
+ self._functions['datetime'] = self.builtin_datetime
152
+ self._functions['strftime'] = self.builtin_strftime
153
+
154
+ # File/Path functions
155
+ self._functions['pathexists'] = self.builtin_pathexists
156
+ self._functions['isfile'] = self.builtin_isfile
157
+ self._functions['isdir'] = self.builtin_isdir
158
+ self._functions['basename'] = self.builtin_basename
159
+ self._functions['dirname'] = self.builtin_dirname
160
+ self._functions['joinpath'] = self.builtin_joinpath
161
+ self._functions['splitpath'] = self.builtin_splitpath
162
+ self._functions['abspath'] = self.builtin_abspath
163
+ self._functions['normpath'] = self.builtin_normpath
164
+ # File I/O functions
165
+ self._functions['readfile'] = self.builtin_readfile
166
+ self._functions['writefile'] = self.builtin_writefile
167
+ self._functions['appendfile'] = self.builtin_appendfile
168
+ self._functions['readlines'] = self.builtin_readlines
169
+ self._functions['listdir'] = self.builtin_listdir
170
+ self._functions['makedirs'] = self.builtin_makedirs
171
+ self._functions['removefile'] = self.builtin_removefile
172
+ self._functions['removedir'] = self.builtin_removedir
173
+ self._functions['copyfile'] = self.builtin_copyfile
174
+ self._functions['movefile'] = self.builtin_movefile
175
+ self._functions['filesize'] = self.builtin_filesize
176
+
177
+ # JSON functions
178
+ self._functions['tojson'] = self.builtin_tojson
179
+ self._functions['fromjson'] = self.builtin_fromjson
180
+
181
+ # Regex functions
182
+ self._functions['match'] = self.builtin_match
183
+ self._functions['search'] = self.builtin_search
184
+ self._functions['findall'] = self.builtin_findall
185
+ self._functions['sub'] = self.builtin_sub
186
+
187
+ # Hash functions
188
+ self._functions['md5'] = self.builtin_md5
189
+ self._functions['sha1'] = self.builtin_sha1
190
+ self._functions['sha256'] = self.builtin_sha256
191
+
192
+ # Utility functions
193
+ self._functions['copy'] = self.builtin_copy
194
+ self._functions['deepcopy'] = self.builtin_deepcopy
195
+ self._functions['assert'] = self.builtin_assert
196
+ self._functions['exit'] = self.builtin_exit
197
+ self._functions['env'] = self.builtin_env
198
+ self._functions['setenv'] = self.builtin_setenv
199
+ self._functions['input'] = self.builtin_input
200
+ self._functions['clear'] = self.builtin_clear
201
+ self._functions['cls'] = self.builtin_clear # Alias
202
+ self._functions['color'] = self.builtin_color
203
+ self._functions['delay'] = self.builtin_delay
204
+ self._functions['pyimport'] = self.builtin_pyimport
205
+
206
+ # Extended string functions
207
+ self._functions['sprintf'] = self.builtin_sprintf
208
+ self._functions['chars'] = self.builtin_chars
209
+ self._functions['ord'] = self.builtin_ord
210
+ self._functions['chr'] = self.builtin_chr
211
+ self._functions['capitalize'] = self.builtin_capitalize
212
+ self._functions['title'] = self.builtin_title
213
+ self._functions['swapcase'] = self.builtin_swapcase
214
+ self._functions['center'] = self.builtin_center
215
+ self._functions['zfill'] = self.builtin_zfill
216
+ self._functions['isalpha'] = self.builtin_isalpha
217
+ self._functions['isdigit'] = self.builtin_isdigit
218
+ self._functions['isalnum'] = self.builtin_isalnum
219
+ self._functions['isspace'] = self.builtin_isspace
220
+
221
+ # Extended list functions
222
+ self._functions['enumerate'] = self.builtin_enumerate
223
+ self._functions['zip'] = self.builtin_zip
224
+ self._functions['reversed'] = self.builtin_reversed
225
+ self._functions['sorted'] = self.builtin_sorted
226
+ self._functions['count'] = self.builtin_count
227
+ self._functions['first'] = self.builtin_first
228
+ self._functions['last'] = self.builtin_last
229
+ self._functions['take'] = self.builtin_take
230
+ self._functions['drop'] = self.builtin_drop
231
+ self._functions['chunk'] = self.builtin_chunk
232
+ self._functions['groupby'] = self.builtin_groupby
233
+ self._functions['shuffle'] = self.builtin_shuffle
234
+ self._functions['sample'] = self.builtin_sample
235
+
236
+ # Extended dict functions
237
+ self._functions['update'] = self.builtin_update
238
+ self._functions['fromkeys'] = self.builtin_fromkeys
239
+ self._functions['invert'] = self.builtin_invert
240
+ self._functions['pick'] = self.builtin_pick
241
+ self._functions['omit'] = self.builtin_omit
242
+
243
+ # CSSL-specific system functions
244
+ self._functions['createcmd'] = self.builtin_createcmd
245
+ self._functions['signal'] = self.builtin_signal
246
+ self._functions['appexec'] = self.builtin_appexec
247
+ self._functions['initpy'] = self.builtin_initpy
248
+ self._functions['initsh'] = self.builtin_initsh
249
+ self._functions['wait_for'] = self.builtin_wait_for
250
+ self._functions['wait_for_event'] = self.builtin_wait_for_event
251
+ self._functions['wait_for_booted'] = self.builtin_wait_for_booted
252
+ self._functions['emit'] = self.builtin_emit
253
+ self._functions['on_event'] = self.builtin_on_event
254
+
255
+ # CSSL Import System Functions
256
+ self._functions['cso_root'] = self.builtin_cso_root
257
+ self._functions['include'] = self.builtin_include
258
+ self._functions['get'] = self.builtin_get
259
+
260
+ # NEW: Extended OS Functions
261
+ self._functions['Listdir'] = self.builtin_listdir # Alias with capital L
262
+ self._functions['ReadFile'] = self.builtin_readfile # Alias with capitals
263
+ self._functions['WriteFile'] = self.builtin_writefile # Alias with capitals
264
+ self._functions['isLinux'] = self.builtin_islinux
265
+ self._functions['isWindows'] = self.builtin_iswindows
266
+ self._functions['isMac'] = self.builtin_ismac
267
+
268
+ # NEW: Extended Time Functions
269
+ self._functions['CurrentTime'] = self.builtin_currenttime
270
+
271
+ # NEW: Scope/Global Functions
272
+ self._functions['global'] = self.builtin_global
273
+
274
+ # CSSL Data Type Constructors
275
+ self._functions['datastruct'] = self.builtin_datastruct
276
+ self._functions['shuffled'] = self.builtin_shuffled
277
+ self._functions['iterator'] = self.builtin_iterator
278
+ self._functions['combo'] = self.builtin_combo
279
+ self._functions['dataspace'] = self.builtin_dataspace
280
+ self._functions['openquote'] = self.builtin_openquote
281
+ self._functions['OpenFind'] = self.builtin_openfind
282
+
283
+ # Print aliases for CSSL
284
+ self._functions['printl'] = self.builtin_println # CSSL uses printl for println
285
+
286
+ def get_function(self, name: str) -> Optional[Callable]:
287
+ """Get a built-in function by name"""
288
+ return self._functions.get(name)
289
+
290
+ def has_function(self, name: str) -> bool:
291
+ """Check if a built-in function exists"""
292
+ return name in self._functions
293
+
294
+ def call(self, name: str, *args, **kwargs) -> Any:
295
+ """Call a built-in function"""
296
+ func = self._functions.get(name)
297
+ if not func:
298
+ raise CSSLBuiltinError(f"Unknown builtin function: {name}")
299
+ return func(*args, **kwargs)
300
+
301
+ def list_functions(self) -> List[str]:
302
+ """List all available built-in functions"""
303
+ return sorted(self._functions.keys())
304
+
305
+ # ============= Output Functions =============
306
+
307
+ def builtin_print(self, *args, **kwargs) -> None:
308
+ """Print without newline"""
309
+ sep = kwargs.get('sep', ' ')
310
+ end = kwargs.get('end', '')
311
+ output = sep.join(str(a) for a in args) + end
312
+ if self.runtime and hasattr(self.runtime, 'output'):
313
+ self.runtime.output(output)
314
+ else:
315
+ print(output, end='')
316
+
317
+ def builtin_println(self, *args, **kwargs) -> None:
318
+ """Print with newline"""
319
+ sep = kwargs.get('sep', ' ')
320
+ output = sep.join(str(a) for a in args)
321
+ if self.runtime and hasattr(self.runtime, 'output'):
322
+ self.runtime.output(output + '\n')
323
+ else:
324
+ print(output)
325
+
326
+ def builtin_debug(self, *args) -> None:
327
+ """Debug output"""
328
+ msg = ' '.join(str(a) for a in args)
329
+ if self.runtime and hasattr(self.runtime, 'debug'):
330
+ self.runtime.debug(msg)
331
+ else:
332
+ print(f"[DEBUG] {msg}")
333
+
334
+ def builtin_error(self, *args) -> None:
335
+ """Error output"""
336
+ msg = ' '.join(str(a) for a in args)
337
+ if self.runtime and hasattr(self.runtime, 'error'):
338
+ self.runtime.error(msg)
339
+ else:
340
+ print(f"[ERROR] {msg}")
341
+
342
+ def builtin_warn(self, *args) -> None:
343
+ """Warning output"""
344
+ msg = ' '.join(str(a) for a in args)
345
+ if self.runtime and hasattr(self.runtime, 'warn'):
346
+ self.runtime.warn(msg)
347
+ else:
348
+ print(f"[WARN] {msg}")
349
+
350
+ def builtin_log(self, level: str, *args) -> None:
351
+ """Log with level"""
352
+ msg = ' '.join(str(a) for a in args)
353
+ if self.runtime and hasattr(self.runtime, 'log'):
354
+ self.runtime.log(level, msg)
355
+ else:
356
+ print(f"[{level.upper()}] {msg}")
357
+
358
+ # ============= Type Conversion =============
359
+
360
+ def builtin_int(self, value: Any, base: int = 10) -> int:
361
+ """Convert to integer"""
362
+ if isinstance(value, str):
363
+ return int(value, base)
364
+ return int(value)
365
+
366
+ def builtin_float(self, value: Any) -> float:
367
+ """Convert to float"""
368
+ return float(value)
369
+
370
+ def builtin_str(self, value: Any) -> str:
371
+ """Convert to string"""
372
+ return str(value)
373
+
374
+ def builtin_bool(self, value: Any) -> bool:
375
+ """Convert to boolean"""
376
+ if isinstance(value, str):
377
+ return value.lower() not in ('', '0', 'false', 'no', 'null', 'none')
378
+ return bool(value)
379
+
380
+ def builtin_list(self, value: Any = None) -> list:
381
+ """Convert to list"""
382
+ if value is None:
383
+ return []
384
+ if isinstance(value, (list, tuple)):
385
+ return list(value)
386
+ if isinstance(value, dict):
387
+ return list(value.items())
388
+ if isinstance(value, str):
389
+ return list(value)
390
+ return [value]
391
+
392
+ def builtin_dict(self, value: Any = None) -> dict:
393
+ """Convert to dict"""
394
+ if value is None:
395
+ return {}
396
+ if isinstance(value, dict):
397
+ return dict(value)
398
+ if isinstance(value, (list, tuple)):
399
+ return dict(value)
400
+ raise CSSLBuiltinError(f"Cannot convert {type(value).__name__} to dict")
401
+
402
+ # ============= Type Checking =============
403
+
404
+ def builtin_typeof(self, value: Any) -> str:
405
+ """Get type name"""
406
+ if value is None:
407
+ return 'null'
408
+ type_map = {
409
+ int: 'int',
410
+ float: 'float',
411
+ str: 'str',
412
+ bool: 'bool',
413
+ list: 'list',
414
+ dict: 'dict',
415
+ tuple: 'tuple'
416
+ }
417
+ return type_map.get(type(value), type(value).__name__)
418
+
419
+ def builtin_isinstance(self, value: Any, type_name: str) -> bool:
420
+ """Check if value is of type"""
421
+ type_map = {
422
+ 'int': int,
423
+ 'float': float,
424
+ 'str': str,
425
+ 'bool': bool,
426
+ 'list': list,
427
+ 'dict': dict,
428
+ 'tuple': tuple,
429
+ 'null': type(None)
430
+ }
431
+ check_type = type_map.get(type_name)
432
+ if check_type:
433
+ return isinstance(value, check_type)
434
+ return False
435
+
436
+ def builtin_isint(self, value: Any) -> bool:
437
+ return isinstance(value, int) and not isinstance(value, bool)
438
+
439
+ def builtin_isfloat(self, value: Any) -> bool:
440
+ return isinstance(value, float)
441
+
442
+ def builtin_isstr(self, value: Any) -> bool:
443
+ return isinstance(value, str)
444
+
445
+ def builtin_isbool(self, value: Any) -> bool:
446
+ return isinstance(value, bool)
447
+
448
+ def builtin_islist(self, value: Any) -> bool:
449
+ return isinstance(value, list)
450
+
451
+ def builtin_isdict(self, value: Any) -> bool:
452
+ return isinstance(value, dict)
453
+
454
+ def builtin_isnull(self, value: Any) -> bool:
455
+ return value is None
456
+
457
+ # ============= String Functions =============
458
+
459
+ def builtin_len(self, value: Union[str, list, dict]) -> int:
460
+ """Get length"""
461
+ return len(value)
462
+
463
+ def builtin_upper(self, s: str) -> str:
464
+ return str(s).upper()
465
+
466
+ def builtin_lower(self, s: str) -> str:
467
+ return str(s).lower()
468
+
469
+ def builtin_trim(self, s: str, chars: str = None) -> str:
470
+ return str(s).strip(chars)
471
+
472
+ def builtin_ltrim(self, s: str, chars: str = None) -> str:
473
+ return str(s).lstrip(chars)
474
+
475
+ def builtin_rtrim(self, s: str, chars: str = None) -> str:
476
+ return str(s).rstrip(chars)
477
+
478
+ def builtin_split(self, s: str, sep: str = None, maxsplit: int = -1) -> list:
479
+ return str(s).split(sep, maxsplit)
480
+
481
+ def builtin_join(self, sep: str, items: list) -> str:
482
+ return str(sep).join(str(i) for i in items)
483
+
484
+ def builtin_replace(self, s: str, old: str, new: str, count: int = -1) -> str:
485
+ return str(s).replace(old, new, count)
486
+
487
+ def builtin_substr(self, s: str, start: int, length: int = None) -> str:
488
+ s = str(s)
489
+ if length is None:
490
+ return s[start:]
491
+ return s[start:start + length]
492
+
493
+ def builtin_contains(self, s: str, sub: str) -> bool:
494
+ return sub in str(s)
495
+
496
+ def builtin_startswith(self, s: str, prefix: str) -> bool:
497
+ return str(s).startswith(prefix)
498
+
499
+ def builtin_endswith(self, s: str, suffix: str) -> bool:
500
+ return str(s).endswith(suffix)
501
+
502
+ def builtin_format(self, template: str, *args, **kwargs) -> str:
503
+ return template.format(*args, **kwargs)
504
+
505
+ def builtin_concat(self, *args) -> str:
506
+ return ''.join(str(a) for a in args)
507
+
508
+ def builtin_repeat(self, s: str, count: int) -> str:
509
+ return str(s) * count
510
+
511
+ def builtin_reverse(self, value: Union[str, list]) -> Union[str, list]:
512
+ if isinstance(value, str):
513
+ return value[::-1]
514
+ if isinstance(value, list):
515
+ return value[::-1]
516
+ raise CSSLBuiltinError("reverse requires string or list")
517
+
518
+ def builtin_indexof(self, s: str, sub: str, start: int = 0) -> int:
519
+ return str(s).find(sub, start)
520
+
521
+ def builtin_lastindexof(self, s: str, sub: str) -> int:
522
+ return str(s).rfind(sub)
523
+
524
+ def builtin_padleft(self, s: str, width: int, char: str = ' ') -> str:
525
+ return str(s).rjust(width, char)
526
+
527
+ def builtin_padright(self, s: str, width: int, char: str = ' ') -> str:
528
+ return str(s).ljust(width, char)
529
+
530
+ # ============= List Functions =============
531
+
532
+ def builtin_push(self, lst: list, *items) -> list:
533
+ lst = list(lst)
534
+ lst.extend(items)
535
+ return lst
536
+
537
+ def builtin_pop(self, lst: list, index: int = -1) -> Any:
538
+ lst = list(lst)
539
+ return lst.pop(index)
540
+
541
+ def builtin_shift(self, lst: list) -> Any:
542
+ lst = list(lst)
543
+ return lst.pop(0) if lst else None
544
+
545
+ def builtin_unshift(self, lst: list, *items) -> list:
546
+ lst = list(lst)
547
+ for item in reversed(items):
548
+ lst.insert(0, item)
549
+ return lst
550
+
551
+ def builtin_slice(self, value: Union[str, list], start: int, end: int = None) -> Union[str, list]:
552
+ if end is None:
553
+ return value[start:]
554
+ return value[start:end]
555
+
556
+ def builtin_sort(self, lst: list, key: str = None) -> list:
557
+ lst = list(lst)
558
+ if key:
559
+ lst.sort(key=lambda x: x.get(key) if isinstance(x, dict) else x)
560
+ else:
561
+ lst.sort()
562
+ return lst
563
+
564
+ def builtin_rsort(self, lst: list, key: str = None) -> list:
565
+ lst = list(lst)
566
+ if key:
567
+ lst.sort(key=lambda x: x.get(key) if isinstance(x, dict) else x, reverse=True)
568
+ else:
569
+ lst.sort(reverse=True)
570
+ return lst
571
+
572
+ def builtin_unique(self, lst: list) -> list:
573
+ seen = []
574
+ result = []
575
+ for item in lst:
576
+ key = json.dumps(item, sort_keys=True) if isinstance(item, (dict, list)) else item
577
+ if key not in seen:
578
+ seen.append(key)
579
+ result.append(item)
580
+ return result
581
+
582
+ def builtin_flatten(self, lst: list, depth: int = 1) -> list:
583
+ result = []
584
+ for item in lst:
585
+ if isinstance(item, list) and depth > 0:
586
+ result.extend(self.builtin_flatten(item, depth - 1))
587
+ else:
588
+ result.append(item)
589
+ return result
590
+
591
+ def builtin_filter(self, lst: list, condition: Callable) -> list:
592
+ return [item for item in lst if condition(item)]
593
+
594
+ def builtin_map(self, lst: list, func: Callable) -> list:
595
+ return [func(item) for item in lst]
596
+
597
+ def builtin_reduce(self, lst: list, func: Callable, initial: Any = None) -> Any:
598
+ from functools import reduce
599
+ if initial is not None:
600
+ return reduce(func, lst, initial)
601
+ return reduce(func, lst)
602
+
603
+ def builtin_find(self, lst: list, condition: Callable) -> Any:
604
+ for item in lst:
605
+ if condition(item):
606
+ return item
607
+ return None
608
+
609
+ def builtin_findindex(self, lst: list, condition: Callable) -> int:
610
+ for i, item in enumerate(lst):
611
+ if condition(item):
612
+ return i
613
+ return -1
614
+
615
+ def builtin_every(self, lst: list, condition: Callable) -> bool:
616
+ return all(condition(item) for item in lst)
617
+
618
+ def builtin_some(self, lst: list, condition: Callable) -> bool:
619
+ return any(condition(item) for item in lst)
620
+
621
+ def builtin_range(self, *args) -> list:
622
+ return list(range(*args))
623
+
624
+ # ============= Dict Functions =============
625
+
626
+ def builtin_keys(self, d: dict) -> list:
627
+ return list(d.keys())
628
+
629
+ def builtin_values(self, d: dict) -> list:
630
+ return list(d.values())
631
+
632
+ def builtin_items(self, d: dict) -> list:
633
+ return list(d.items())
634
+
635
+ def builtin_haskey(self, d: dict, key: str) -> bool:
636
+ return key in d
637
+
638
+ def builtin_getkey(self, d: dict, key: str, default: Any = None) -> Any:
639
+ return d.get(key, default)
640
+
641
+ def builtin_setkey(self, d: dict, key: str, value: Any) -> dict:
642
+ d = dict(d)
643
+ d[key] = value
644
+ return d
645
+
646
+ def builtin_delkey(self, d: dict, key: str) -> dict:
647
+ d = dict(d)
648
+ d.pop(key, None)
649
+ return d
650
+
651
+ def builtin_merge(self, *dicts) -> dict:
652
+ result = {}
653
+ for d in dicts:
654
+ if isinstance(d, dict):
655
+ result.update(d)
656
+ return result
657
+
658
+ # ============= Math Functions =============
659
+
660
+ def builtin_abs(self, x: Union[int, float]) -> Union[int, float]:
661
+ return abs(x)
662
+
663
+ def builtin_min(self, *args) -> Any:
664
+ if len(args) == 1 and isinstance(args[0], (list, tuple)):
665
+ return min(args[0])
666
+ return min(args)
667
+
668
+ def builtin_max(self, *args) -> Any:
669
+ if len(args) == 1 and isinstance(args[0], (list, tuple)):
670
+ return max(args[0])
671
+ return max(args)
672
+
673
+ def builtin_sum(self, items: list, start: Union[int, float] = 0) -> Union[int, float]:
674
+ return sum(items, start)
675
+
676
+ def builtin_avg(self, items: list) -> float:
677
+ if not items:
678
+ return 0.0
679
+ return sum(items) / len(items)
680
+
681
+ def builtin_round(self, x: float, digits: int = 0) -> float:
682
+ return round(x, digits)
683
+
684
+ def builtin_floor(self, x: float) -> int:
685
+ import math
686
+ return math.floor(x)
687
+
688
+ def builtin_ceil(self, x: float) -> int:
689
+ import math
690
+ return math.ceil(x)
691
+
692
+ def builtin_pow(self, base: Union[int, float], exp: Union[int, float]) -> Union[int, float]:
693
+ return pow(base, exp)
694
+
695
+ def builtin_sqrt(self, x: Union[int, float]) -> float:
696
+ import math
697
+ return math.sqrt(x)
698
+
699
+ def builtin_mod(self, a: int, b: int) -> int:
700
+ return a % b
701
+
702
+ def builtin_random(self) -> float:
703
+ return random.random()
704
+
705
+ def builtin_randint(self, a: int, b: int) -> int:
706
+ return random.randint(a, b)
707
+
708
+ def builtin_sin(self, x: float) -> float:
709
+ return math.sin(x)
710
+
711
+ def builtin_cos(self, x: float) -> float:
712
+ return math.cos(x)
713
+
714
+ def builtin_tan(self, x: float) -> float:
715
+ return math.tan(x)
716
+
717
+ def builtin_asin(self, x: float) -> float:
718
+ return math.asin(x)
719
+
720
+ def builtin_acos(self, x: float) -> float:
721
+ return math.acos(x)
722
+
723
+ def builtin_atan(self, x: float) -> float:
724
+ return math.atan(x)
725
+
726
+ def builtin_atan2(self, y: float, x: float) -> float:
727
+ return math.atan2(y, x)
728
+
729
+ def builtin_log(self, x: float, base: float = math.e) -> float:
730
+ return math.log(x, base)
731
+
732
+ def builtin_log10(self, x: float) -> float:
733
+ return math.log10(x)
734
+
735
+ def builtin_exp(self, x: float) -> float:
736
+ return math.exp(x)
737
+
738
+ def builtin_radians(self, degrees: float) -> float:
739
+ return math.radians(degrees)
740
+
741
+ def builtin_degrees(self, radians: float) -> float:
742
+ return math.degrees(radians)
743
+
744
+ # ============= Time Functions =============
745
+
746
+ def builtin_now(self) -> float:
747
+ return time.time()
748
+
749
+ def builtin_timestamp(self) -> int:
750
+ return int(time.time())
751
+
752
+ def builtin_sleep(self, seconds: float) -> None:
753
+ time.sleep(seconds)
754
+
755
+ def builtin_date(self, format_str: str = '%Y-%m-%d') -> str:
756
+ return datetime.now().strftime(format_str)
757
+
758
+ def builtin_time(self, format_str: str = '%H:%M:%S') -> str:
759
+ return datetime.now().strftime(format_str)
760
+
761
+ def builtin_datetime(self, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
762
+ return datetime.now().strftime(format_str)
763
+
764
+ def builtin_strftime(self, format_str: str, timestamp: float = None) -> str:
765
+ if timestamp is None:
766
+ return datetime.now().strftime(format_str)
767
+ return datetime.fromtimestamp(timestamp).strftime(format_str)
768
+
769
+ # ============= File/Path Functions =============
770
+
771
+ def builtin_pathexists(self, path: str) -> bool:
772
+ return os.path.exists(path)
773
+
774
+ def builtin_isfile(self, path: str) -> bool:
775
+ return os.path.isfile(path)
776
+
777
+ def builtin_isdir(self, path: str) -> bool:
778
+ return os.path.isdir(path)
779
+
780
+ def builtin_basename(self, path: str) -> str:
781
+ return os.path.basename(path)
782
+
783
+ def builtin_dirname(self, path: str) -> str:
784
+ return os.path.dirname(path)
785
+
786
+ def builtin_joinpath(self, *parts) -> str:
787
+ return os.path.join(*parts)
788
+
789
+ def builtin_splitpath(self, path: str) -> list:
790
+ return list(os.path.split(path))
791
+
792
+ def builtin_abspath(self, path: str) -> str:
793
+ return os.path.abspath(path)
794
+
795
+ def builtin_normpath(self, path: str) -> str:
796
+ return os.path.normpath(path)
797
+
798
+ # ============= File I/O Functions =============
799
+
800
+ def builtin_readfile(self, path: str, encoding: str = 'utf-8') -> str:
801
+ """Read entire file content"""
802
+ with open(path, 'r', encoding=encoding) as f:
803
+ return f.read()
804
+
805
+ def builtin_writefile(self, path: str, content: str, encoding: str = 'utf-8') -> int:
806
+ """Write content to file, returns bytes written"""
807
+ with open(path, 'w', encoding=encoding) as f:
808
+ return f.write(content)
809
+
810
+ def builtin_appendfile(self, path: str, content: str, encoding: str = 'utf-8') -> int:
811
+ """Append content to file, returns bytes written"""
812
+ with open(path, 'a', encoding=encoding) as f:
813
+ return f.write(content)
814
+
815
+ def builtin_readlines(self, path: str, encoding: str = 'utf-8') -> list:
816
+ """Read file lines into list"""
817
+ with open(path, 'r', encoding=encoding) as f:
818
+ return f.readlines()
819
+
820
+ def builtin_listdir(self, path: str = '.') -> list:
821
+ """List directory contents"""
822
+ return os.listdir(path)
823
+
824
+ def builtin_makedirs(self, path: str, exist_ok: bool = True) -> bool:
825
+ """Create directories recursively"""
826
+ os.makedirs(path, exist_ok=exist_ok)
827
+ return True
828
+
829
+ def builtin_removefile(self, path: str) -> bool:
830
+ """Remove a file"""
831
+ os.remove(path)
832
+ return True
833
+
834
+ def builtin_removedir(self, path: str) -> bool:
835
+ """Remove an empty directory"""
836
+ os.rmdir(path)
837
+ return True
838
+
839
+ def builtin_copyfile(self, src: str, dst: str) -> str:
840
+ """Copy a file, returns destination path"""
841
+ import shutil
842
+ return shutil.copy2(src, dst)
843
+
844
+ def builtin_movefile(self, src: str, dst: str) -> str:
845
+ """Move a file, returns destination path"""
846
+ import shutil
847
+ return shutil.move(src, dst)
848
+
849
+ def builtin_filesize(self, path: str) -> int:
850
+ """Get file size in bytes"""
851
+ return os.path.getsize(path)
852
+
853
+ # ============= JSON Functions =============
854
+
855
+ def builtin_tojson(self, value: Any, indent: int = None) -> str:
856
+ return json.dumps(value, indent=indent, ensure_ascii=False)
857
+
858
+ def builtin_fromjson(self, s: str) -> Any:
859
+ return json.loads(s)
860
+
861
+ # ============= Regex Functions =============
862
+
863
+ def builtin_match(self, pattern: str, string: str) -> Optional[dict]:
864
+ m = re.match(pattern, string)
865
+ if m:
866
+ return {'match': m.group(), 'groups': m.groups(), 'start': m.start(), 'end': m.end()}
867
+ return None
868
+
869
+ def builtin_search(self, pattern: str, string: str) -> Optional[dict]:
870
+ m = re.search(pattern, string)
871
+ if m:
872
+ return {'match': m.group(), 'groups': m.groups(), 'start': m.start(), 'end': m.end()}
873
+ return None
874
+
875
+ def builtin_findall(self, pattern: str, string: str) -> list:
876
+ return re.findall(pattern, string)
877
+
878
+ def builtin_sub(self, pattern: str, repl: str, string: str, count: int = 0) -> str:
879
+ return re.sub(pattern, repl, string, count)
880
+
881
+ # ============= Hash Functions =============
882
+
883
+ def builtin_md5(self, s: str) -> str:
884
+ return hashlib.md5(s.encode()).hexdigest()
885
+
886
+ def builtin_sha1(self, s: str) -> str:
887
+ return hashlib.sha1(s.encode()).hexdigest()
888
+
889
+ def builtin_sha256(self, s: str) -> str:
890
+ return hashlib.sha256(s.encode()).hexdigest()
891
+
892
+ # ============= Utility Functions =============
893
+
894
+ def builtin_copy(self, value: Any) -> Any:
895
+ import copy
896
+ return copy.copy(value)
897
+
898
+ def builtin_deepcopy(self, value: Any) -> Any:
899
+ import copy
900
+ return copy.deepcopy(value)
901
+
902
+ def builtin_assert(self, condition: bool, message: str = "Assertion failed") -> None:
903
+ if not condition:
904
+ raise CSSLBuiltinError(message)
905
+
906
+ def builtin_exit(self, code: int = 0) -> None:
907
+ if self.runtime and hasattr(self.runtime, 'exit'):
908
+ self.runtime.exit(code)
909
+ else:
910
+ raise SystemExit(code)
911
+
912
+ def builtin_env(self, name: str, default: str = None) -> Optional[str]:
913
+ return os.environ.get(name, default)
914
+
915
+ def builtin_setenv(self, name: str, value: str) -> None:
916
+ """Set environment variable"""
917
+ os.environ[name] = value
918
+
919
+ def builtin_input(self, prompt: str = '') -> str:
920
+ """Read user input"""
921
+ return input(prompt)
922
+
923
+ def builtin_clear(self) -> None:
924
+ """Clear console screen"""
925
+ if os.name == 'nt':
926
+ os.system('cls')
927
+ else:
928
+ print('\033[2J\033[H', end='')
929
+
930
+ def builtin_color(self, text: str, color: str) -> str:
931
+ """Apply ANSI color to text"""
932
+ colors = {
933
+ 'black': '30', 'red': '31', 'green': '32', 'yellow': '33',
934
+ 'blue': '34', 'magenta': '35', 'cyan': '36', 'white': '37',
935
+ 'bright_black': '90', 'bright_red': '91', 'bright_green': '92',
936
+ 'bright_yellow': '93', 'bright_blue': '94', 'bright_magenta': '95',
937
+ 'bright_cyan': '96', 'bright_white': '97',
938
+ 'reset': '0', 'bold': '1', 'dim': '2', 'italic': '3',
939
+ 'underline': '4', 'blink': '5', 'reverse': '7'
940
+ }
941
+ code = colors.get(color.lower(), color)
942
+ return f'\033[{code}m{text}\033[0m'
943
+
944
+ def builtin_delay(self, ms: float) -> None:
945
+ """Delay execution by milliseconds"""
946
+ time.sleep(ms / 1000.0)
947
+
948
+ def builtin_pyimport(self, module_name: str) -> Any:
949
+ """Import a Python module for use in CSSL"""
950
+ return __import__(module_name)
951
+
952
+ # ============= Extended String Functions =============
953
+
954
+ def builtin_sprintf(self, fmt: str, *args) -> str:
955
+ """C-style format string"""
956
+ return fmt % args
957
+
958
+ def builtin_chars(self, s: str) -> list:
959
+ """Convert string to list of characters"""
960
+ return list(s)
961
+
962
+ def builtin_ord(self, c: str) -> int:
963
+ """Get ASCII/Unicode code of character"""
964
+ return ord(c[0] if c else '\0')
965
+
966
+ def builtin_chr(self, n: int) -> str:
967
+ """Convert ASCII/Unicode code to character"""
968
+ return chr(n)
969
+
970
+ def builtin_capitalize(self, s: str) -> str:
971
+ return str(s).capitalize()
972
+
973
+ def builtin_title(self, s: str) -> str:
974
+ return str(s).title()
975
+
976
+ def builtin_swapcase(self, s: str) -> str:
977
+ return str(s).swapcase()
978
+
979
+ def builtin_center(self, s: str, width: int, fillchar: str = ' ') -> str:
980
+ return str(s).center(width, fillchar)
981
+
982
+ def builtin_zfill(self, s: str, width: int) -> str:
983
+ return str(s).zfill(width)
984
+
985
+ def builtin_isalpha(self, s: str) -> bool:
986
+ return str(s).isalpha()
987
+
988
+ def builtin_isdigit(self, s: str) -> bool:
989
+ return str(s).isdigit()
990
+
991
+ def builtin_isalnum(self, s: str) -> bool:
992
+ return str(s).isalnum()
993
+
994
+ def builtin_isspace(self, s: str) -> bool:
995
+ return str(s).isspace()
996
+
997
+ # ============= Extended List Functions =============
998
+
999
+ def builtin_enumerate(self, lst: list, start: int = 0) -> list:
1000
+ """Return list of (index, value) pairs"""
1001
+ return list(enumerate(lst, start))
1002
+
1003
+ def builtin_zip(self, *lists) -> list:
1004
+ """Zip multiple lists together"""
1005
+ return list(zip(*lists))
1006
+
1007
+ def builtin_reversed(self, lst: list) -> list:
1008
+ """Return reversed list"""
1009
+ return list(reversed(lst))
1010
+
1011
+ def builtin_sorted(self, lst: list, key: str = None, reverse: bool = False) -> list:
1012
+ """Return sorted list"""
1013
+ if key:
1014
+ return sorted(lst, key=lambda x: x.get(key) if isinstance(x, dict) else x, reverse=reverse)
1015
+ return sorted(lst, reverse=reverse)
1016
+
1017
+ def builtin_count(self, collection: Union[list, str], item: Any) -> int:
1018
+ """Count occurrences of item"""
1019
+ return collection.count(item)
1020
+
1021
+ def builtin_first(self, lst: list, default: Any = None) -> Any:
1022
+ """Get first element or default"""
1023
+ return lst[0] if lst else default
1024
+
1025
+ def builtin_last(self, lst: list, default: Any = None) -> Any:
1026
+ """Get last element or default"""
1027
+ return lst[-1] if lst else default
1028
+
1029
+ def builtin_take(self, lst: list, n: int) -> list:
1030
+ """Take first n elements"""
1031
+ return lst[:n]
1032
+
1033
+ def builtin_drop(self, lst: list, n: int) -> list:
1034
+ """Drop first n elements"""
1035
+ return lst[n:]
1036
+
1037
+ def builtin_chunk(self, lst: list, size: int) -> list:
1038
+ """Split list into chunks of given size"""
1039
+ return [lst[i:i + size] for i in range(0, len(lst), size)]
1040
+
1041
+ def builtin_groupby(self, lst: list, key: str) -> dict:
1042
+ """Group list of dicts by key"""
1043
+ result = {}
1044
+ for item in lst:
1045
+ k = item.get(key) if isinstance(item, dict) else getattr(item, key, None)
1046
+ if k not in result:
1047
+ result[k] = []
1048
+ result[k].append(item)
1049
+ return result
1050
+
1051
+ def builtin_shuffle(self, lst: list) -> list:
1052
+ """Return shuffled copy of list"""
1053
+ result = list(lst)
1054
+ random.shuffle(result)
1055
+ return result
1056
+
1057
+ def builtin_sample(self, lst: list, k: int) -> list:
1058
+ """Return k random elements from list"""
1059
+ return random.sample(lst, min(k, len(lst)))
1060
+
1061
+ # ============= Extended Dict Functions =============
1062
+
1063
+ def builtin_update(self, d: dict, other: dict) -> dict:
1064
+ """Update dict with another dict, return new dict"""
1065
+ result = dict(d)
1066
+ result.update(other)
1067
+ return result
1068
+
1069
+ def builtin_fromkeys(self, keys: list, value: Any = None) -> dict:
1070
+ """Create dict from keys with default value"""
1071
+ return dict.fromkeys(keys, value)
1072
+
1073
+ def builtin_invert(self, d: dict) -> dict:
1074
+ """Swap keys and values"""
1075
+ return {v: k for k, v in d.items()}
1076
+
1077
+ def builtin_pick(self, d: dict, *keys) -> dict:
1078
+ """Pick only specified keys from dict"""
1079
+ return {k: d[k] for k in keys if k in d}
1080
+
1081
+ def builtin_omit(self, d: dict, *keys) -> dict:
1082
+ """Omit specified keys from dict"""
1083
+ return {k: v for k, v in d.items() if k not in keys}
1084
+
1085
+ # ============= CSSL System Functions =============
1086
+
1087
+ def builtin_createcmd(self, cmd_name: str, handler: Callable = None) -> bool:
1088
+ """
1089
+ Create a custom console command
1090
+ Usage: createcmd('mycommand') <== { ... handler code ... }
1091
+ """
1092
+ if not self.runtime:
1093
+ print(f"Cannot create command '{cmd_name}': No runtime available")
1094
+ return False
1095
+
1096
+ # Store the command handler in runtime
1097
+ if not hasattr(self.runtime, '_custom_commands'):
1098
+ self.runtime._custom_commands = {}
1099
+
1100
+ self.runtime._custom_commands[cmd_name] = handler
1101
+
1102
+ # Find Console via multiple paths
1103
+ console = None
1104
+
1105
+ # Try 1: Direct _console reference on runtime
1106
+ if hasattr(self.runtime, '_console') and self.runtime._console:
1107
+ console = self.runtime._console
1108
+
1109
+ # Try 2: Via service_engine.Console
1110
+ elif self.runtime.service_engine and hasattr(self.runtime.service_engine, 'Console'):
1111
+ console = self.runtime.service_engine.Console
1112
+
1113
+ # Register with Console if found
1114
+ if console and hasattr(console, 'register_custom_command'):
1115
+ console.register_custom_command(cmd_name, handler)
1116
+ else:
1117
+ print(f"Custom command '{cmd_name}' stored (Console not yet available)")
1118
+
1119
+ return True
1120
+
1121
+ def builtin_signal(self, event_ref: Any, action: str = '+') -> bool:
1122
+ """
1123
+ Send or register a signal/event
1124
+ Usage: signal(@event.CustomEvent, '+') to emit, '-' to unregister
1125
+ """
1126
+ try:
1127
+ from .cssl_events import get_event_manager, EventType
1128
+
1129
+ event_manager = get_event_manager()
1130
+
1131
+ # Handle event reference (could be string or module ref)
1132
+ event_name = str(event_ref) if not isinstance(event_ref, str) else event_ref
1133
+
1134
+ if action == '+':
1135
+ # Emit the event
1136
+ event_manager.emit_custom(event_name, source="cssl_signal")
1137
+ print(f"Signal emitted: {event_name}")
1138
+ return True
1139
+ elif action == '-':
1140
+ # Unregister handlers for this event
1141
+ # This would need custom implementation
1142
+ print(f"Signal handlers cleared: {event_name}")
1143
+ return True
1144
+ else:
1145
+ print(f"Unknown signal action: {action}")
1146
+ return False
1147
+
1148
+ except Exception as e:
1149
+ print(f"Signal error: {e}")
1150
+ return False
1151
+
1152
+ def builtin_appexec(self, app_name: str, *args) -> bool:
1153
+ """
1154
+ Start a desktop application (visually)
1155
+ Usage: appexec('xface')
1156
+ """
1157
+ if not self.runtime or not self.runtime.service_engine:
1158
+ print(f"Cannot execute app '{app_name}': No service engine available")
1159
+ return False
1160
+
1161
+ try:
1162
+ kernel = self.runtime.service_engine.KernelClient
1163
+
1164
+ # Check if desktop environment is available
1165
+ if hasattr(kernel, 'start_desktop_app'):
1166
+ return kernel.start_desktop_app(app_name, *args)
1167
+
1168
+ # Try to find and launch the app
1169
+ app_paths = [
1170
+ os.path.join(kernel.RootDirectory, 'apps', app_name),
1171
+ os.path.join(kernel.RootDirectory, 'apps', f'{app_name}.py'),
1172
+ os.path.join(kernel.RootDirectory, 'desktop', 'apps', app_name),
1173
+ os.path.join(kernel.RootDirectory, 'desktop', 'apps', f'{app_name}.py'),
1174
+ ]
1175
+
1176
+ for app_path in app_paths:
1177
+ if os.path.exists(app_path):
1178
+ print(f"Launching app: {app_name}")
1179
+ if app_path.endswith('.py'):
1180
+ return self.builtin_initpy(app_path)
1181
+ return True
1182
+
1183
+ print(f"App not found: {app_name}")
1184
+ return False
1185
+
1186
+ except Exception as e:
1187
+ print(f"App execution error: {e}")
1188
+ return False
1189
+
1190
+ def builtin_initpy(self, path: str, *args, **kwargs) -> Any:
1191
+ """
1192
+ Execute a Python file
1193
+ Usage: initpy('/path/to/script.py')
1194
+ """
1195
+ if not os.path.isabs(path) and self.runtime and self.runtime.service_engine:
1196
+ path = os.path.join(self.runtime.service_engine.KernelClient.RootDirectory, path)
1197
+
1198
+ if not os.path.exists(path):
1199
+ raise CSSLBuiltinError(f"Python file not found: {path}")
1200
+
1201
+ try:
1202
+ # Prepare execution context
1203
+ exec_globals = {
1204
+ '__file__': path,
1205
+ '__name__': '__main__',
1206
+ }
1207
+
1208
+ # Add kernel and service engine if available
1209
+ if self.runtime and self.runtime.service_engine:
1210
+ exec_globals['kernel'] = self.runtime.service_engine.KernelClient
1211
+ exec_globals['service'] = self.runtime.service_engine
1212
+ exec_globals['args'] = args
1213
+ exec_globals['kwargs'] = kwargs
1214
+
1215
+ with open(path, 'r', encoding='utf-8') as f:
1216
+ code = f.read()
1217
+
1218
+ exec(compile(code, path, 'exec'), exec_globals)
1219
+ return exec_globals.get('result', True)
1220
+
1221
+ except Exception as e:
1222
+ print(f"Python execution error [{path}]: {e}")
1223
+ raise CSSLBuiltinError(f"initpy failed: {e}")
1224
+
1225
+ def builtin_initsh(self, path: str, *args) -> int:
1226
+ """
1227
+ Execute a shell script
1228
+ Usage: initsh('/path/to/script.sh')
1229
+ """
1230
+ import subprocess
1231
+
1232
+ if not os.path.isabs(path) and self.runtime and self.runtime.service_engine:
1233
+ path = os.path.join(self.runtime.service_engine.KernelClient.RootDirectory, path)
1234
+
1235
+ if not os.path.exists(path):
1236
+ raise CSSLBuiltinError(f"Shell script not found: {path}")
1237
+
1238
+ try:
1239
+ # Determine shell based on platform
1240
+ import platform
1241
+ if platform.system() == 'Windows':
1242
+ # Use cmd or powershell on Windows
1243
+ cmd = ['cmd', '/c', path] + list(args)
1244
+ else:
1245
+ cmd = ['bash', path] + list(args)
1246
+
1247
+ result = subprocess.run(cmd, capture_output=True, text=True)
1248
+
1249
+ if result.stdout:
1250
+ print(result.stdout)
1251
+ if result.stderr:
1252
+ print(f"STDERR: {result.stderr}")
1253
+
1254
+ return result.returncode
1255
+
1256
+ except Exception as e:
1257
+ print(f"Shell execution error [{path}]: {e}")
1258
+ raise CSSLBuiltinError(f"initsh failed: {e}")
1259
+
1260
+ def builtin_wait_for(self, condition: Callable, timeout: float = 30.0, interval: float = 0.1) -> bool:
1261
+ """
1262
+ Wait for a condition to become true
1263
+ Usage: wait_for(lambda: some_condition, timeout=30)
1264
+ """
1265
+ import time
1266
+ start = time.time()
1267
+
1268
+ while time.time() - start < timeout:
1269
+ try:
1270
+ if callable(condition):
1271
+ if condition():
1272
+ return True
1273
+ elif condition:
1274
+ return True
1275
+ except Exception:
1276
+ pass
1277
+ time.sleep(interval)
1278
+
1279
+ return False
1280
+
1281
+ def builtin_wait_for_event(self, event_name: str, timeout: float = 30.0) -> bool:
1282
+ """
1283
+ Wait for a specific event to occur
1284
+ Usage: wait_for_event('@event.Booted', timeout=60)
1285
+ """
1286
+ try:
1287
+ from .cssl_events import get_event_manager
1288
+
1289
+ event_manager = get_event_manager()
1290
+ event_occurred = [False]
1291
+
1292
+ def handler(event_data):
1293
+ event_occurred[0] = True
1294
+
1295
+ # Register temporary handler
1296
+ handler_id = event_manager.register_custom(
1297
+ event_name,
1298
+ handler,
1299
+ once=True
1300
+ )
1301
+
1302
+ # Wait for event
1303
+ import time
1304
+ start = time.time()
1305
+ while not event_occurred[0] and (time.time() - start) < timeout:
1306
+ time.sleep(0.1)
1307
+
1308
+ # Cleanup if not occurred
1309
+ if not event_occurred[0]:
1310
+ event_manager.unregister(handler_id)
1311
+
1312
+ return event_occurred[0]
1313
+
1314
+ except Exception as e:
1315
+ print(f"wait_for_event error: {e}")
1316
+ return False
1317
+
1318
+ def builtin_wait_for_booted(self, timeout: float = 60.0) -> bool:
1319
+ """
1320
+ Wait until the system is fully booted
1321
+ Usage: await wait_for_booted()
1322
+ """
1323
+ if not self.runtime or not self.runtime.service_engine:
1324
+ return False
1325
+
1326
+ import time
1327
+ start = time.time()
1328
+
1329
+ while time.time() - start < timeout:
1330
+ try:
1331
+ wheel = self.runtime.service_engine.KernelClient.WheelKernel
1332
+ booted = wheel.ReadWheelParam('boot', 'BOOTED')
1333
+ if booted == '1':
1334
+ return True
1335
+ except Exception:
1336
+ pass
1337
+ time.sleep(0.5)
1338
+
1339
+ return False
1340
+
1341
+ def builtin_emit(self, event_name: str, data: Any = None) -> bool:
1342
+ """
1343
+ Emit a custom event
1344
+ Usage: emit('MyCustomEvent', {data: 'value'})
1345
+ """
1346
+ try:
1347
+ from .cssl_events import get_event_manager
1348
+
1349
+ event_manager = get_event_manager()
1350
+ event_manager.emit_custom(event_name, source="cssl", data=data or {})
1351
+ return True
1352
+
1353
+ except Exception as e:
1354
+ print(f"emit error: {e}")
1355
+ return False
1356
+
1357
+ def builtin_on_event(self, event_name: str, handler: Callable) -> str:
1358
+ """
1359
+ Register an event handler
1360
+ Usage: on_event('MyEvent', handler_function)
1361
+ Returns: handler_id for later removal
1362
+ """
1363
+ try:
1364
+ from .cssl_events import get_event_manager
1365
+
1366
+ event_manager = get_event_manager()
1367
+ handler_id = event_manager.register_custom(event_name, handler)
1368
+ return handler_id
1369
+
1370
+ except Exception as e:
1371
+ print(f"on_event error: {e}")
1372
+ return ""
1373
+
1374
+ # ============= CSSL Import System Functions =============
1375
+
1376
+ def builtin_cso_root(self, path: str = "") -> str:
1377
+ """
1378
+ Get absolute path relative to CSO root directory
1379
+ Usage: cso_root('/services/myservice.cssl')
1380
+ Returns: Full absolute path to the file
1381
+ """
1382
+ base = os.getcwd()
1383
+
1384
+ # Try to get base from kernel parameters
1385
+ if self.runtime and self.runtime.service_engine:
1386
+ try:
1387
+ kernel = self.runtime.service_engine.KernelClient
1388
+ if hasattr(kernel, 'WheelKernel'):
1389
+ wheel = kernel.WheelKernel
1390
+ if hasattr(wheel, 'KernelParam'):
1391
+ base = wheel.KernelParam.get('@base', base)
1392
+ if hasattr(kernel, 'RootDirectory'):
1393
+ base = kernel.RootDirectory
1394
+ except Exception:
1395
+ pass
1396
+
1397
+ # Clean path and join
1398
+ if path:
1399
+ clean_path = path.lstrip('/').lstrip('\\')
1400
+ return os.path.normpath(os.path.join(base, clean_path))
1401
+
1402
+ return base
1403
+
1404
+ def builtin_include(self, filepath: str) -> Any:
1405
+ """
1406
+ Load and execute a CSSL file, returning its ServiceDefinition
1407
+ Usage: include(cso_root('/services/utils.cssl'))
1408
+ Returns: ServiceDefinition with structs, functions, etc.
1409
+ """
1410
+ if not self.runtime:
1411
+ raise CSSLBuiltinError("include requires runtime context")
1412
+
1413
+ # Resolve relative paths
1414
+ if not os.path.isabs(filepath):
1415
+ filepath = self.builtin_cso_root(filepath)
1416
+
1417
+ # Check file exists
1418
+ if not os.path.exists(filepath):
1419
+ raise CSSLBuiltinError(f"Include file not found: {filepath}")
1420
+
1421
+ # Check include cache to prevent circular imports
1422
+ if not hasattr(self.runtime, '_include_cache'):
1423
+ self.runtime._include_cache = {}
1424
+
1425
+ if filepath in self.runtime._include_cache:
1426
+ return self.runtime._include_cache[filepath]
1427
+
1428
+ try:
1429
+ # Read and parse the file
1430
+ with open(filepath, 'r', encoding='utf-8') as f:
1431
+ source = f.read()
1432
+
1433
+ from .cssl_parser import parse_cssl
1434
+
1435
+ ast = parse_cssl(source)
1436
+
1437
+ # Execute the service to get definitions
1438
+ service_def = self.runtime._exec_service(ast)
1439
+
1440
+ # Cache the result
1441
+ self.runtime._include_cache[filepath] = service_def
1442
+
1443
+ return service_def
1444
+
1445
+ except Exception as e:
1446
+ raise CSSLBuiltinError(f"Failed to include '{filepath}': {e}")
1447
+
1448
+ def builtin_get(self, source: Any, key: str = None) -> Any:
1449
+ """
1450
+ Get value from module, ServiceDefinition, or dict
1451
+ Usage:
1452
+ get('list') - Get list module (returns empty list creator)
1453
+ get('os') - Get OS module
1454
+ get('time') - Get Time module
1455
+ get(@Time) - Get standard module
1456
+ get(service_def, 'funcName') - Get function from included service
1457
+ get(dict_obj, 'key') - Get key from dict
1458
+ Returns: The requested value or None
1459
+ """
1460
+ # Single argument - return module reference directly
1461
+ if key is None:
1462
+ if isinstance(source, str):
1463
+ # NEW: Handle standard module names
1464
+ module_map = {
1465
+ 'list': self._get_list_module(),
1466
+ 'dict': self._get_dict_module(),
1467
+ 'os': self._get_os_module(),
1468
+ 'time': self._get_time_module(),
1469
+ 'vsramsdk': self._get_vsram_module(),
1470
+ 'kernel': self._get_kernel_module(),
1471
+ }
1472
+ if source.lower() in module_map:
1473
+ return module_map[source.lower()]
1474
+
1475
+ # Treat as module path
1476
+ if self.runtime:
1477
+ return self.runtime.get_module(source)
1478
+ return source
1479
+
1480
+ # Two arguments - extract from source
1481
+ if hasattr(source, key):
1482
+ return getattr(source, key)
1483
+
1484
+ if isinstance(source, dict):
1485
+ return source.get(key)
1486
+
1487
+ # Check if source is a ServiceDefinition-like object
1488
+ if hasattr(source, 'structs') and key in source.structs:
1489
+ return source.structs[key]
1490
+
1491
+ if hasattr(source, 'functions') and key in source.functions:
1492
+ return source.functions[key]
1493
+
1494
+ return None
1495
+
1496
+ # NEW: Module factories for get()
1497
+ def _get_list_module(self):
1498
+ """Return a list module proxy"""
1499
+ class ListModule:
1500
+ @staticmethod
1501
+ def create():
1502
+ return []
1503
+ @staticmethod
1504
+ def add(lst, item):
1505
+ if isinstance(lst, list):
1506
+ lst.append(item)
1507
+ return lst
1508
+ return ListModule()
1509
+
1510
+ def _get_dict_module(self):
1511
+ """Return a dict module proxy"""
1512
+ class DictModule:
1513
+ @staticmethod
1514
+ def create():
1515
+ return {}
1516
+ return DictModule()
1517
+
1518
+ def _get_os_module(self):
1519
+ """Return OS module proxy"""
1520
+ class OSModule:
1521
+ @staticmethod
1522
+ def Listdir(path='.'):
1523
+ return os.listdir(path)
1524
+ @staticmethod
1525
+ def ReadFile(path, encoding='utf-8'):
1526
+ with open(path, 'r', encoding=encoding) as f:
1527
+ return f.read()
1528
+ @staticmethod
1529
+ def WriteFile(path, content, encoding='utf-8'):
1530
+ with open(path, 'w', encoding=encoding) as f:
1531
+ return f.write(content)
1532
+ @staticmethod
1533
+ def isLinux():
1534
+ import platform
1535
+ return platform.system() == 'Linux'
1536
+ @staticmethod
1537
+ def isWindows():
1538
+ import platform
1539
+ return platform.system() == 'Windows'
1540
+ @staticmethod
1541
+ def isMac():
1542
+ import platform
1543
+ return platform.system() == 'Darwin'
1544
+ return OSModule()
1545
+
1546
+ def _get_time_module(self):
1547
+ """Return Time module proxy"""
1548
+ class TimeModule:
1549
+ @staticmethod
1550
+ def CurrentTime(format_str='%Y-%m-%d %H:%M:%S'):
1551
+ return datetime.now().strftime(format_str)
1552
+ @staticmethod
1553
+ def Now():
1554
+ return time.time()
1555
+ @staticmethod
1556
+ def Sleep(seconds):
1557
+ time.sleep(seconds)
1558
+ return TimeModule()
1559
+
1560
+ def _get_vsram_module(self):
1561
+ """Return VSRAM module proxy from runtime"""
1562
+ if self.runtime and hasattr(self.runtime, '_modules'):
1563
+ return self.runtime._modules.get('VSRam') or self.runtime._modules.get('VSRAM')
1564
+ return None
1565
+
1566
+ def _get_kernel_module(self):
1567
+ """Return Kernel module proxy from runtime"""
1568
+ if self.runtime and hasattr(self.runtime, '_modules'):
1569
+ return self.runtime._modules.get('Kernel') or self.runtime._modules.get('KernelClient')
1570
+ return None
1571
+
1572
+ # NEW: Platform Detection Functions
1573
+ def builtin_islinux(self) -> bool:
1574
+ """Check if running on Linux"""
1575
+ import platform
1576
+ return platform.system() == 'Linux'
1577
+
1578
+ def builtin_iswindows(self) -> bool:
1579
+ """Check if running on Windows"""
1580
+ import platform
1581
+ return platform.system() == 'Windows'
1582
+
1583
+ def builtin_ismac(self) -> bool:
1584
+ """Check if running on macOS"""
1585
+ import platform
1586
+ return platform.system() == 'Darwin'
1587
+
1588
+ # NEW: CurrentTime function
1589
+ def builtin_currenttime(self, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
1590
+ """Get current time as formatted string"""
1591
+ return datetime.now().strftime(format_str)
1592
+
1593
+ # NEW: Global function for scope promotion
1594
+ def builtin_global(self, s_ref: Any) -> None:
1595
+ """
1596
+ Promote s@<name> to @<name> (make globally accessible)
1597
+ Usage: global(s@cache) - makes @cache available
1598
+
1599
+ This takes the value referenced by s@<name> and registers it
1600
+ as a module reference accessible via @<name>
1601
+ """
1602
+ if not self.runtime:
1603
+ return
1604
+
1605
+ # The argument could be:
1606
+ # 1. A direct value from s@<name> reference
1607
+ # 2. A string path like "MyStruct.cache"
1608
+
1609
+ if isinstance(s_ref, str):
1610
+ # It's a path - promote it
1611
+ self.runtime.promote_to_global(s_ref)
1612
+ else:
1613
+ # It's a value - we need the original s@<name> reference
1614
+ # This is handled by the runtime which passes the path
1615
+ pass
1616
+
1617
+ # ============= CSSL Data Type Constructors =============
1618
+
1619
+ def builtin_datastruct(self, element_type: str = 'dynamic') -> Any:
1620
+ """Create a datastruct container.
1621
+
1622
+ Usage: datastruct<string> myData; or datastruct('string')
1623
+ """
1624
+ from .cssl_types import DataStruct
1625
+ return DataStruct(element_type)
1626
+
1627
+ def builtin_shuffled(self, element_type: str = 'dynamic') -> Any:
1628
+ """Create a shuffled container for multiple returns.
1629
+
1630
+ Usage: shuffled<string> results;
1631
+ """
1632
+ from .cssl_types import Shuffled
1633
+ return Shuffled(element_type)
1634
+
1635
+ def builtin_iterator(self, element_type: str = 'int', size: int = 16) -> Any:
1636
+ """Create an advanced iterator.
1637
+
1638
+ Usage: iterator<int, 16> Map;
1639
+ """
1640
+ from .cssl_types import Iterator
1641
+ return Iterator(element_type, size)
1642
+
1643
+ def builtin_combo(self, element_type: str = 'dynamic') -> Any:
1644
+ """Create a combo filter/search space.
1645
+
1646
+ Usage: combo<open&string> myCombo;
1647
+ """
1648
+ from .cssl_types import Combo
1649
+ return Combo(element_type)
1650
+
1651
+ def builtin_dataspace(self, space_type: str = 'dynamic') -> Any:
1652
+ """Create a dataspace for SQL/structured data.
1653
+
1654
+ Usage: dataspace<sql::table> table;
1655
+ """
1656
+ from .cssl_types import DataSpace
1657
+ return DataSpace(space_type)
1658
+
1659
+ def builtin_openquote(self, db_ref: Any = None) -> Any:
1660
+ """Create an openquote container for SQL operations.
1661
+
1662
+ Usage: openquote<datastruct<dynamic>&@sql::db.oqt(@db)> Queue;
1663
+ """
1664
+ from .cssl_types import OpenQuote
1665
+ return OpenQuote(db_ref)
1666
+
1667
+ def builtin_openfind(self, combo_or_type: Any, index: int = 0) -> Any:
1668
+ """Find open parameter by type or combo space.
1669
+
1670
+ Usage: OpenFind<string>(0) or OpenFind(&@comboSpace)
1671
+ """
1672
+ from .cssl_types import Combo
1673
+
1674
+ if isinstance(combo_or_type, Combo):
1675
+ return combo_or_type.find_match([])
1676
+ return None
1677
+
1678
+
1679
+ # Module-level convenience functions
1680
+ _default_builtins: Optional[CSSLBuiltins] = None
1681
+
1682
+
1683
+ def get_builtins(runtime=None) -> CSSLBuiltins:
1684
+ """Get default builtins instance"""
1685
+ global _default_builtins
1686
+ if _default_builtins is None or runtime is not None:
1687
+ _default_builtins = CSSLBuiltins(runtime)
1688
+ return _default_builtins
1689
+
1690
+
1691
+ def call_builtin(name: str, *args, **kwargs) -> Any:
1692
+ """Call a builtin function"""
1693
+ return get_builtins().call(name, *args, **kwargs)