IncludeCPP 3.7.3__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.
Files changed (49) hide show
  1. includecpp/__init__.py +59 -0
  2. includecpp/__init__.pyi +255 -0
  3. includecpp/__main__.py +4 -0
  4. includecpp/cli/__init__.py +4 -0
  5. includecpp/cli/commands.py +8270 -0
  6. includecpp/cli/config_parser.py +127 -0
  7. includecpp/core/__init__.py +19 -0
  8. includecpp/core/ai_integration.py +2132 -0
  9. includecpp/core/build_manager.py +2416 -0
  10. includecpp/core/cpp_api.py +376 -0
  11. includecpp/core/cpp_api.pyi +95 -0
  12. includecpp/core/cppy_converter.py +3448 -0
  13. includecpp/core/cssl/CSSL_DOCUMENTATION.md +2075 -0
  14. includecpp/core/cssl/__init__.py +42 -0
  15. includecpp/core/cssl/cssl_builtins.py +2271 -0
  16. includecpp/core/cssl/cssl_builtins.pyi +1393 -0
  17. includecpp/core/cssl/cssl_events.py +621 -0
  18. includecpp/core/cssl/cssl_modules.py +2803 -0
  19. includecpp/core/cssl/cssl_parser.py +2575 -0
  20. includecpp/core/cssl/cssl_runtime.py +3051 -0
  21. includecpp/core/cssl/cssl_syntax.py +488 -0
  22. includecpp/core/cssl/cssl_types.py +1512 -0
  23. includecpp/core/cssl_bridge.py +882 -0
  24. includecpp/core/cssl_bridge.pyi +488 -0
  25. includecpp/core/error_catalog.py +802 -0
  26. includecpp/core/error_formatter.py +1016 -0
  27. includecpp/core/exceptions.py +97 -0
  28. includecpp/core/path_discovery.py +77 -0
  29. includecpp/core/project_ui.py +3370 -0
  30. includecpp/core/settings_ui.py +326 -0
  31. includecpp/generator/__init__.py +1 -0
  32. includecpp/generator/parser.cpp +1903 -0
  33. includecpp/generator/parser.h +281 -0
  34. includecpp/generator/type_resolver.cpp +363 -0
  35. includecpp/generator/type_resolver.h +68 -0
  36. includecpp/py.typed +0 -0
  37. includecpp/templates/cpp.proj.template +18 -0
  38. includecpp/vscode/__init__.py +1 -0
  39. includecpp/vscode/cssl/__init__.py +1 -0
  40. includecpp/vscode/cssl/language-configuration.json +38 -0
  41. includecpp/vscode/cssl/package.json +50 -0
  42. includecpp/vscode/cssl/snippets/cssl.snippets.json +1080 -0
  43. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +341 -0
  44. includecpp-3.7.3.dist-info/METADATA +1076 -0
  45. includecpp-3.7.3.dist-info/RECORD +49 -0
  46. includecpp-3.7.3.dist-info/WHEEL +5 -0
  47. includecpp-3.7.3.dist-info/entry_points.txt +2 -0
  48. includecpp-3.7.3.dist-info/licenses/LICENSE +21 -0
  49. includecpp-3.7.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2271 @@
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['read'] = self.builtin_read
166
+ self._functions['readline'] = self.builtin_readline
167
+ self._functions['write'] = self.builtin_write
168
+ self._functions['writeline'] = self.builtin_writeline
169
+ self._functions['readfile'] = self.builtin_readfile
170
+ self._functions['writefile'] = self.builtin_writefile
171
+ self._functions['appendfile'] = self.builtin_appendfile
172
+ self._functions['readlines'] = self.builtin_readlines
173
+ self._functions['listdir'] = self.builtin_listdir
174
+ self._functions['makedirs'] = self.builtin_makedirs
175
+ self._functions['removefile'] = self.builtin_removefile
176
+ self._functions['removedir'] = self.builtin_removedir
177
+ self._functions['copyfile'] = self.builtin_copyfile
178
+ self._functions['movefile'] = self.builtin_movefile
179
+ self._functions['filesize'] = self.builtin_filesize
180
+
181
+ # JSON functions
182
+ self._functions['tojson'] = self.builtin_tojson
183
+ self._functions['fromjson'] = self.builtin_fromjson
184
+ # JSON namespace functions (json::read, json::write, etc.)
185
+ self._functions['json::read'] = self.builtin_json_read
186
+ self._functions['json::write'] = self.builtin_json_write
187
+ self._functions['json::parse'] = self.builtin_fromjson
188
+ self._functions['json::stringify'] = self.builtin_tojson
189
+ self._functions['json::pretty'] = self.builtin_json_pretty
190
+ self._functions['json::keys'] = self.builtin_json_keys
191
+ self._functions['json::values'] = self.builtin_json_values
192
+ self._functions['json::get'] = self.builtin_json_get
193
+ self._functions['json::set'] = self.builtin_json_set
194
+ self._functions['json::has'] = self.builtin_json_has
195
+ self._functions['json::merge'] = self.builtin_json_merge
196
+
197
+ # Instance introspection functions (instance::getMethods, etc.)
198
+ self._functions['instance::getMethods'] = self.builtin_instance_getMethods
199
+ self._functions['instance::getClasses'] = self.builtin_instance_getClasses
200
+ self._functions['instance::getVars'] = self.builtin_instance_getVars
201
+ self._functions['instance::getAll'] = self.builtin_instance_getAll
202
+ self._functions['instance::call'] = self.builtin_instance_call
203
+ self._functions['instance::has'] = self.builtin_instance_has
204
+ self._functions['instance::type'] = self.builtin_instance_type
205
+ self._functions['isavailable'] = self.builtin_isavailable
206
+ self._functions['instance::exists'] = self.builtin_isavailable # Alias
207
+
208
+ # Regex functions
209
+ self._functions['match'] = self.builtin_match
210
+ self._functions['search'] = self.builtin_search
211
+ self._functions['findall'] = self.builtin_findall
212
+ self._functions['sub'] = self.builtin_sub
213
+
214
+ # Hash functions
215
+ self._functions['md5'] = self.builtin_md5
216
+ self._functions['sha1'] = self.builtin_sha1
217
+ self._functions['sha256'] = self.builtin_sha256
218
+
219
+ # Utility functions
220
+ self._functions['copy'] = self.builtin_copy
221
+ self._functions['deepcopy'] = self.builtin_deepcopy
222
+ self._functions['assert'] = self.builtin_assert
223
+ self._functions['exit'] = self.builtin_exit
224
+ self._functions['env'] = self.builtin_env
225
+ self._functions['setenv'] = self.builtin_setenv
226
+ self._functions['input'] = self.builtin_input
227
+ self._functions['clear'] = self.builtin_clear
228
+ self._functions['cls'] = self.builtin_clear # Alias
229
+ self._functions['color'] = self.builtin_color
230
+ self._functions['delay'] = self.builtin_delay
231
+ self._functions['pyimport'] = self.builtin_pyimport
232
+
233
+ # Extended string functions
234
+ self._functions['sprintf'] = self.builtin_sprintf
235
+ self._functions['chars'] = self.builtin_chars
236
+ self._functions['ord'] = self.builtin_ord
237
+ self._functions['chr'] = self.builtin_chr
238
+ self._functions['capitalize'] = self.builtin_capitalize
239
+ self._functions['title'] = self.builtin_title
240
+ self._functions['swapcase'] = self.builtin_swapcase
241
+ self._functions['center'] = self.builtin_center
242
+ self._functions['zfill'] = self.builtin_zfill
243
+ self._functions['isalpha'] = self.builtin_isalpha
244
+ self._functions['isdigit'] = self.builtin_isdigit
245
+ self._functions['isalnum'] = self.builtin_isalnum
246
+ self._functions['isspace'] = self.builtin_isspace
247
+
248
+ # Extended list functions
249
+ self._functions['enumerate'] = self.builtin_enumerate
250
+ self._functions['zip'] = self.builtin_zip
251
+ self._functions['reversed'] = self.builtin_reversed
252
+ self._functions['sorted'] = self.builtin_sorted
253
+ self._functions['count'] = self.builtin_count
254
+ self._functions['first'] = self.builtin_first
255
+ self._functions['last'] = self.builtin_last
256
+ self._functions['take'] = self.builtin_take
257
+ self._functions['drop'] = self.builtin_drop
258
+ self._functions['chunk'] = self.builtin_chunk
259
+ self._functions['groupby'] = self.builtin_groupby
260
+ self._functions['shuffle'] = self.builtin_shuffle
261
+ self._functions['sample'] = self.builtin_sample
262
+
263
+ # Extended dict functions
264
+ self._functions['update'] = self.builtin_update
265
+ self._functions['fromkeys'] = self.builtin_fromkeys
266
+ self._functions['invert'] = self.builtin_invert
267
+ self._functions['pick'] = self.builtin_pick
268
+ self._functions['omit'] = self.builtin_omit
269
+
270
+ # CSSL-specific system functions
271
+ self._functions['createcmd'] = self.builtin_createcmd
272
+ self._functions['signal'] = self.builtin_signal
273
+ self._functions['appexec'] = self.builtin_appexec
274
+ self._functions['initpy'] = self.builtin_initpy
275
+ self._functions['initsh'] = self.builtin_initsh
276
+ self._functions['wait_for'] = self.builtin_wait_for
277
+ self._functions['wait_for_event'] = self.builtin_wait_for_event
278
+ self._functions['wait_for_booted'] = self.builtin_wait_for_booted
279
+ self._functions['emit'] = self.builtin_emit
280
+ self._functions['on_event'] = self.builtin_on_event
281
+
282
+ # CSSL Import System Functions
283
+ self._functions['cso_root'] = self.builtin_cso_root
284
+ self._functions['include'] = self.builtin_include
285
+ self._functions['payload'] = self.builtin_payload
286
+ self._functions['get'] = self.builtin_get
287
+
288
+ # NEW: Extended OS Functions
289
+ self._functions['Listdir'] = self.builtin_listdir # Alias with capital L
290
+ self._functions['ReadFile'] = self.builtin_readfile # Alias with capitals
291
+ self._functions['WriteFile'] = self.builtin_writefile # Alias with capitals
292
+ self._functions['isLinux'] = self.builtin_islinux
293
+ self._functions['isWindows'] = self.builtin_iswindows
294
+ self._functions['isMac'] = self.builtin_ismac
295
+
296
+ # NEW: Extended Time Functions
297
+ self._functions['CurrentTime'] = self.builtin_currenttime
298
+
299
+ # NEW: Scope/Global Functions
300
+ self._functions['global'] = self.builtin_global
301
+
302
+ # CSSL Data Type Constructors
303
+ self._functions['datastruct'] = self.builtin_datastruct
304
+ self._functions['shuffled'] = self.builtin_shuffled
305
+ self._functions['iterator'] = self.builtin_iterator
306
+ self._functions['combo'] = self.builtin_combo
307
+ self._functions['dataspace'] = self.builtin_dataspace
308
+ self._functions['openquote'] = self.builtin_openquote
309
+ self._functions['OpenFind'] = self.builtin_openfind
310
+
311
+ # Print aliases for CSSL
312
+ self._functions['printl'] = self.builtin_println # CSSL uses printl for println
313
+
314
+ # Shared object functions
315
+ self._functions['delete'] = self.builtin_delete # Delete shared object ($Name)
316
+
317
+ def get_function(self, name: str) -> Optional[Callable]:
318
+ """Get a built-in function by name"""
319
+ return self._functions.get(name)
320
+
321
+ def has_function(self, name: str) -> bool:
322
+ """Check if a built-in function exists"""
323
+ return name in self._functions
324
+
325
+ def call(self, name: str, *args, **kwargs) -> Any:
326
+ """Call a built-in function"""
327
+ func = self._functions.get(name)
328
+ if not func:
329
+ raise CSSLBuiltinError(f"Unknown builtin function: {name}")
330
+ return func(*args, **kwargs)
331
+
332
+ def list_functions(self) -> List[str]:
333
+ """List all available built-in functions"""
334
+ return sorted(self._functions.keys())
335
+
336
+ # ============= Output Functions =============
337
+
338
+ def builtin_print(self, *args, **kwargs) -> None:
339
+ """Print without newline"""
340
+ sep = kwargs.get('sep', ' ')
341
+ end = kwargs.get('end', '')
342
+ output = sep.join(str(a) for a in args) + end
343
+ if self.runtime and hasattr(self.runtime, 'output'):
344
+ self.runtime.output(output)
345
+ else:
346
+ print(output, end='')
347
+
348
+ def builtin_println(self, *args, **kwargs) -> None:
349
+ """Print with newline"""
350
+ sep = kwargs.get('sep', ' ')
351
+ output = sep.join(str(a) for a in args)
352
+ if self.runtime and hasattr(self.runtime, 'output'):
353
+ self.runtime.output(output + '\n')
354
+ else:
355
+ print(output)
356
+
357
+ def builtin_debug(self, *args) -> None:
358
+ """Debug output"""
359
+ msg = ' '.join(str(a) for a in args)
360
+ if self.runtime and hasattr(self.runtime, 'debug'):
361
+ self.runtime.debug(msg)
362
+ else:
363
+ print(f"[DEBUG] {msg}")
364
+
365
+ def builtin_error(self, *args) -> None:
366
+ """Error output"""
367
+ msg = ' '.join(str(a) for a in args)
368
+ if self.runtime and hasattr(self.runtime, 'error'):
369
+ self.runtime.error(msg)
370
+ else:
371
+ print(f"[ERROR] {msg}")
372
+
373
+ def builtin_warn(self, *args) -> None:
374
+ """Warning output"""
375
+ msg = ' '.join(str(a) for a in args)
376
+ if self.runtime and hasattr(self.runtime, 'warn'):
377
+ self.runtime.warn(msg)
378
+ else:
379
+ print(f"[WARN] {msg}")
380
+
381
+ def builtin_log(self, level: str, *args) -> None:
382
+ """Log with level"""
383
+ msg = ' '.join(str(a) for a in args)
384
+ if self.runtime and hasattr(self.runtime, 'log'):
385
+ self.runtime.log(level, msg)
386
+ else:
387
+ print(f"[{level.upper()}] {msg}")
388
+
389
+ # ============= Type Conversion =============
390
+
391
+ def builtin_int(self, value: Any, base: int = 10) -> int:
392
+ """Convert to integer"""
393
+ if isinstance(value, str):
394
+ return int(value, base)
395
+ return int(value)
396
+
397
+ def builtin_float(self, value: Any) -> float:
398
+ """Convert to float"""
399
+ return float(value)
400
+
401
+ def builtin_str(self, value: Any) -> str:
402
+ """Convert to string"""
403
+ return str(value)
404
+
405
+ def builtin_bool(self, value: Any) -> bool:
406
+ """Convert to boolean"""
407
+ if isinstance(value, str):
408
+ return value.lower() not in ('', '0', 'false', 'no', 'null', 'none')
409
+ return bool(value)
410
+
411
+ def builtin_list(self, value: Any = None) -> list:
412
+ """Convert to list"""
413
+ if value is None:
414
+ return []
415
+ if isinstance(value, (list, tuple)):
416
+ return list(value)
417
+ if isinstance(value, dict):
418
+ return list(value.items())
419
+ if isinstance(value, str):
420
+ return list(value)
421
+ return [value]
422
+
423
+ def builtin_dict(self, value: Any = None) -> dict:
424
+ """Convert to dict"""
425
+ if value is None:
426
+ return {}
427
+ if isinstance(value, dict):
428
+ return dict(value)
429
+ if isinstance(value, (list, tuple)):
430
+ return dict(value)
431
+ raise CSSLBuiltinError(f"Cannot convert {type(value).__name__} to dict")
432
+
433
+ # ============= Type Checking =============
434
+
435
+ def builtin_typeof(self, value: Any) -> str:
436
+ """Get type name"""
437
+ if value is None:
438
+ return 'null'
439
+ type_map = {
440
+ int: 'int',
441
+ float: 'float',
442
+ str: 'str',
443
+ bool: 'bool',
444
+ list: 'list',
445
+ dict: 'dict',
446
+ tuple: 'tuple'
447
+ }
448
+ return type_map.get(type(value), type(value).__name__)
449
+
450
+ def builtin_isinstance(self, value: Any, type_name: str) -> bool:
451
+ """Check if value is of type"""
452
+ type_map = {
453
+ 'int': int,
454
+ 'float': float,
455
+ 'str': str,
456
+ 'bool': bool,
457
+ 'list': list,
458
+ 'dict': dict,
459
+ 'tuple': tuple,
460
+ 'null': type(None)
461
+ }
462
+ check_type = type_map.get(type_name)
463
+ if check_type:
464
+ return isinstance(value, check_type)
465
+ return False
466
+
467
+ def builtin_isint(self, value: Any) -> bool:
468
+ return isinstance(value, int) and not isinstance(value, bool)
469
+
470
+ def builtin_isfloat(self, value: Any) -> bool:
471
+ return isinstance(value, float)
472
+
473
+ def builtin_isstr(self, value: Any) -> bool:
474
+ return isinstance(value, str)
475
+
476
+ def builtin_isbool(self, value: Any) -> bool:
477
+ return isinstance(value, bool)
478
+
479
+ def builtin_islist(self, value: Any) -> bool:
480
+ return isinstance(value, list)
481
+
482
+ def builtin_isdict(self, value: Any) -> bool:
483
+ return isinstance(value, dict)
484
+
485
+ def builtin_isnull(self, value: Any) -> bool:
486
+ return value is None
487
+
488
+ # ============= String Functions =============
489
+
490
+ def builtin_len(self, value: Union[str, list, dict]) -> int:
491
+ """Get length"""
492
+ return len(value)
493
+
494
+ def builtin_upper(self, s: str) -> str:
495
+ return str(s).upper()
496
+
497
+ def builtin_lower(self, s: str) -> str:
498
+ return str(s).lower()
499
+
500
+ def builtin_trim(self, s: str, chars: str = None) -> str:
501
+ return str(s).strip(chars)
502
+
503
+ def builtin_ltrim(self, s: str, chars: str = None) -> str:
504
+ return str(s).lstrip(chars)
505
+
506
+ def builtin_rtrim(self, s: str, chars: str = None) -> str:
507
+ return str(s).rstrip(chars)
508
+
509
+ def builtin_split(self, s: str, sep: str = None, maxsplit: int = -1) -> list:
510
+ return str(s).split(sep, maxsplit)
511
+
512
+ def builtin_join(self, sep: str, items: list) -> str:
513
+ return str(sep).join(str(i) for i in items)
514
+
515
+ def builtin_replace(self, s: str, old: str, new: str, count: int = -1) -> str:
516
+ return str(s).replace(old, new, count)
517
+
518
+ def builtin_substr(self, s: str, start: int, length: int = None) -> str:
519
+ s = str(s)
520
+ if length is None:
521
+ return s[start:]
522
+ return s[start:start + length]
523
+
524
+ def builtin_contains(self, s: str, sub: str) -> bool:
525
+ return sub in str(s)
526
+
527
+ def builtin_startswith(self, s: str, prefix: str) -> bool:
528
+ return str(s).startswith(prefix)
529
+
530
+ def builtin_endswith(self, s: str, suffix: str) -> bool:
531
+ return str(s).endswith(suffix)
532
+
533
+ def builtin_format(self, template: str, *args, **kwargs) -> str:
534
+ return template.format(*args, **kwargs)
535
+
536
+ def builtin_concat(self, *args) -> str:
537
+ return ''.join(str(a) for a in args)
538
+
539
+ def builtin_repeat(self, s: str, count: int) -> str:
540
+ return str(s) * count
541
+
542
+ def builtin_reverse(self, value: Union[str, list]) -> Union[str, list]:
543
+ if isinstance(value, str):
544
+ return value[::-1]
545
+ if isinstance(value, list):
546
+ return value[::-1]
547
+ raise CSSLBuiltinError("reverse requires string or list")
548
+
549
+ def builtin_indexof(self, s: str, sub: str, start: int = 0) -> int:
550
+ return str(s).find(sub, start)
551
+
552
+ def builtin_lastindexof(self, s: str, sub: str) -> int:
553
+ return str(s).rfind(sub)
554
+
555
+ def builtin_padleft(self, s: str, width: int, char: str = ' ') -> str:
556
+ return str(s).rjust(width, char)
557
+
558
+ def builtin_padright(self, s: str, width: int, char: str = ' ') -> str:
559
+ return str(s).ljust(width, char)
560
+
561
+ # ============= List Functions =============
562
+
563
+ def builtin_push(self, lst: list, *items) -> list:
564
+ lst = list(lst)
565
+ lst.extend(items)
566
+ return lst
567
+
568
+ def builtin_pop(self, lst: list, index: int = -1) -> Any:
569
+ lst = list(lst)
570
+ return lst.pop(index)
571
+
572
+ def builtin_shift(self, lst: list) -> Any:
573
+ lst = list(lst)
574
+ return lst.pop(0) if lst else None
575
+
576
+ def builtin_unshift(self, lst: list, *items) -> list:
577
+ lst = list(lst)
578
+ for item in reversed(items):
579
+ lst.insert(0, item)
580
+ return lst
581
+
582
+ def builtin_slice(self, value: Union[str, list], start: int, end: int = None) -> Union[str, list]:
583
+ if end is None:
584
+ return value[start:]
585
+ return value[start:end]
586
+
587
+ def builtin_sort(self, lst: list, key: str = None) -> list:
588
+ lst = list(lst)
589
+ if key:
590
+ lst.sort(key=lambda x: x.get(key) if isinstance(x, dict) else x)
591
+ else:
592
+ lst.sort()
593
+ return lst
594
+
595
+ def builtin_rsort(self, lst: list, key: str = None) -> list:
596
+ lst = list(lst)
597
+ if key:
598
+ lst.sort(key=lambda x: x.get(key) if isinstance(x, dict) else x, reverse=True)
599
+ else:
600
+ lst.sort(reverse=True)
601
+ return lst
602
+
603
+ def builtin_unique(self, lst: list) -> list:
604
+ seen = []
605
+ result = []
606
+ for item in lst:
607
+ key = json.dumps(item, sort_keys=True) if isinstance(item, (dict, list)) else item
608
+ if key not in seen:
609
+ seen.append(key)
610
+ result.append(item)
611
+ return result
612
+
613
+ def builtin_flatten(self, lst: list, depth: int = 1) -> list:
614
+ result = []
615
+ for item in lst:
616
+ if isinstance(item, list) and depth > 0:
617
+ result.extend(self.builtin_flatten(item, depth - 1))
618
+ else:
619
+ result.append(item)
620
+ return result
621
+
622
+ def builtin_filter(self, lst: list, condition: Callable) -> list:
623
+ return [item for item in lst if condition(item)]
624
+
625
+ def builtin_map(self, lst: list, func: Callable) -> list:
626
+ return [func(item) for item in lst]
627
+
628
+ def builtin_reduce(self, lst: list, func: Callable, initial: Any = None) -> Any:
629
+ from functools import reduce
630
+ if initial is not None:
631
+ return reduce(func, lst, initial)
632
+ return reduce(func, lst)
633
+
634
+ def builtin_find(self, lst: list, condition: Callable) -> Any:
635
+ for item in lst:
636
+ if condition(item):
637
+ return item
638
+ return None
639
+
640
+ def builtin_findindex(self, lst: list, condition: Callable) -> int:
641
+ for i, item in enumerate(lst):
642
+ if condition(item):
643
+ return i
644
+ return -1
645
+
646
+ def builtin_every(self, lst: list, condition: Callable) -> bool:
647
+ return all(condition(item) for item in lst)
648
+
649
+ def builtin_some(self, lst: list, condition: Callable) -> bool:
650
+ return any(condition(item) for item in lst)
651
+
652
+ def builtin_range(self, *args) -> list:
653
+ return list(range(*args))
654
+
655
+ # ============= Dict Functions =============
656
+
657
+ def builtin_keys(self, d: dict) -> list:
658
+ return list(d.keys())
659
+
660
+ def builtin_values(self, d: dict) -> list:
661
+ return list(d.values())
662
+
663
+ def builtin_items(self, d: dict) -> list:
664
+ return list(d.items())
665
+
666
+ def builtin_haskey(self, d: dict, key: str) -> bool:
667
+ return key in d
668
+
669
+ def builtin_getkey(self, d: dict, key: str, default: Any = None) -> Any:
670
+ return d.get(key, default)
671
+
672
+ def builtin_setkey(self, d: dict, key: str, value: Any) -> dict:
673
+ d = dict(d)
674
+ d[key] = value
675
+ return d
676
+
677
+ def builtin_delkey(self, d: dict, key: str) -> dict:
678
+ d = dict(d)
679
+ d.pop(key, None)
680
+ return d
681
+
682
+ def builtin_merge(self, *dicts) -> dict:
683
+ result = {}
684
+ for d in dicts:
685
+ if isinstance(d, dict):
686
+ result.update(d)
687
+ return result
688
+
689
+ # ============= Math Functions =============
690
+
691
+ def builtin_abs(self, x: Union[int, float]) -> Union[int, float]:
692
+ return abs(x)
693
+
694
+ def builtin_min(self, *args) -> Any:
695
+ if len(args) == 1 and isinstance(args[0], (list, tuple)):
696
+ return min(args[0])
697
+ return min(args)
698
+
699
+ def builtin_max(self, *args) -> Any:
700
+ if len(args) == 1 and isinstance(args[0], (list, tuple)):
701
+ return max(args[0])
702
+ return max(args)
703
+
704
+ def builtin_sum(self, items: list, start: Union[int, float] = 0) -> Union[int, float]:
705
+ return sum(items, start)
706
+
707
+ def builtin_avg(self, items: list) -> float:
708
+ if not items:
709
+ return 0.0
710
+ return sum(items) / len(items)
711
+
712
+ def builtin_round(self, x: float, digits: int = 0) -> float:
713
+ return round(x, digits)
714
+
715
+ def builtin_floor(self, x: float) -> int:
716
+ import math
717
+ return math.floor(x)
718
+
719
+ def builtin_ceil(self, x: float) -> int:
720
+ import math
721
+ return math.ceil(x)
722
+
723
+ def builtin_pow(self, base: Union[int, float], exp: Union[int, float]) -> Union[int, float]:
724
+ return pow(base, exp)
725
+
726
+ def builtin_sqrt(self, x: Union[int, float]) -> float:
727
+ import math
728
+ return math.sqrt(x)
729
+
730
+ def builtin_mod(self, a: int, b: int) -> int:
731
+ return a % b
732
+
733
+ def builtin_random(self) -> float:
734
+ return random.random()
735
+
736
+ def builtin_randint(self, a: int, b: int) -> int:
737
+ return random.randint(a, b)
738
+
739
+ def builtin_sin(self, x: float) -> float:
740
+ return math.sin(x)
741
+
742
+ def builtin_cos(self, x: float) -> float:
743
+ return math.cos(x)
744
+
745
+ def builtin_tan(self, x: float) -> float:
746
+ return math.tan(x)
747
+
748
+ def builtin_asin(self, x: float) -> float:
749
+ return math.asin(x)
750
+
751
+ def builtin_acos(self, x: float) -> float:
752
+ return math.acos(x)
753
+
754
+ def builtin_atan(self, x: float) -> float:
755
+ return math.atan(x)
756
+
757
+ def builtin_atan2(self, y: float, x: float) -> float:
758
+ return math.atan2(y, x)
759
+
760
+ def builtin_log(self, x: float, base: float = math.e) -> float:
761
+ return math.log(x, base)
762
+
763
+ def builtin_log10(self, x: float) -> float:
764
+ return math.log10(x)
765
+
766
+ def builtin_exp(self, x: float) -> float:
767
+ return math.exp(x)
768
+
769
+ def builtin_radians(self, degrees: float) -> float:
770
+ return math.radians(degrees)
771
+
772
+ def builtin_degrees(self, radians: float) -> float:
773
+ return math.degrees(radians)
774
+
775
+ # ============= Time Functions =============
776
+
777
+ def builtin_now(self) -> float:
778
+ return time.time()
779
+
780
+ def builtin_timestamp(self) -> int:
781
+ return int(time.time())
782
+
783
+ def builtin_sleep(self, seconds: float) -> None:
784
+ time.sleep(seconds)
785
+
786
+ def builtin_date(self, format_str: str = '%Y-%m-%d') -> str:
787
+ return datetime.now().strftime(format_str)
788
+
789
+ def builtin_time(self, format_str: str = '%H:%M:%S') -> str:
790
+ return datetime.now().strftime(format_str)
791
+
792
+ def builtin_datetime(self, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
793
+ return datetime.now().strftime(format_str)
794
+
795
+ def builtin_strftime(self, format_str: str, timestamp: float = None) -> str:
796
+ if timestamp is None:
797
+ return datetime.now().strftime(format_str)
798
+ return datetime.fromtimestamp(timestamp).strftime(format_str)
799
+
800
+ # ============= File/Path Functions =============
801
+
802
+ def builtin_pathexists(self, path: str) -> bool:
803
+ return os.path.exists(path)
804
+
805
+ def builtin_isfile(self, path: str) -> bool:
806
+ return os.path.isfile(path)
807
+
808
+ def builtin_isdir(self, path: str) -> bool:
809
+ return os.path.isdir(path)
810
+
811
+ def builtin_basename(self, path: str) -> str:
812
+ return os.path.basename(path)
813
+
814
+ def builtin_dirname(self, path: str) -> str:
815
+ return os.path.dirname(path)
816
+
817
+ def builtin_joinpath(self, *parts) -> str:
818
+ return os.path.join(*parts)
819
+
820
+ def builtin_splitpath(self, path: str) -> list:
821
+ return list(os.path.split(path))
822
+
823
+ def builtin_abspath(self, path: str) -> str:
824
+ return os.path.abspath(path)
825
+
826
+ def builtin_normpath(self, path: str) -> str:
827
+ return os.path.normpath(path)
828
+
829
+ # ============= File I/O Functions =============
830
+
831
+ def builtin_read(self, path: str, encoding: str = 'utf-8') -> str:
832
+ """Read entire file content.
833
+ Usage: read('/path/to/file.txt')
834
+ """
835
+ with open(path, 'r', encoding=encoding) as f:
836
+ return f.read()
837
+
838
+ def builtin_readline(self, line: int, path: str, encoding: str = 'utf-8') -> str:
839
+ """Read specific line from file (1-indexed).
840
+ Usage: readline(5, '/path/to/file.txt') -> returns line 5
841
+ """
842
+ with open(path, 'r', encoding=encoding) as f:
843
+ for i, file_line in enumerate(f, 1):
844
+ if i == line:
845
+ return file_line.rstrip('\n\r')
846
+ return "" # Line not found
847
+
848
+ def builtin_write(self, path: str, content: str, encoding: str = 'utf-8') -> int:
849
+ """Write content to file, returns chars written.
850
+ Usage: write('/path/to/file.txt', 'Hello World')
851
+ """
852
+ with open(path, 'w', encoding=encoding) as f:
853
+ return f.write(content)
854
+
855
+ def builtin_writeline(self, line: int, content: str, path: str, encoding: str = 'utf-8') -> bool:
856
+ """Write/replace specific line in file (1-indexed).
857
+ Usage: writeline(5, 'New content', '/path/to/file.txt')
858
+ """
859
+ # Read all lines
860
+ lines = []
861
+ if os.path.exists(path):
862
+ with open(path, 'r', encoding=encoding) as f:
863
+ lines = f.readlines()
864
+
865
+ # Ensure we have enough lines
866
+ while len(lines) < line:
867
+ lines.append('\n')
868
+
869
+ # Replace the specific line (1-indexed)
870
+ if not content.endswith('\n'):
871
+ content = content + '\n'
872
+ lines[line - 1] = content
873
+
874
+ # Write back
875
+ with open(path, 'w', encoding=encoding) as f:
876
+ f.writelines(lines)
877
+ return True
878
+
879
+ def builtin_readfile(self, path: str, encoding: str = 'utf-8') -> str:
880
+ """Read entire file content"""
881
+ with open(path, 'r', encoding=encoding) as f:
882
+ return f.read()
883
+
884
+ def builtin_writefile(self, path: str, content: str, encoding: str = 'utf-8') -> int:
885
+ """Write content to file, returns bytes written"""
886
+ with open(path, 'w', encoding=encoding) as f:
887
+ return f.write(content)
888
+
889
+ def builtin_appendfile(self, path: str, content: str, encoding: str = 'utf-8') -> int:
890
+ """Append content to file, returns bytes written"""
891
+ with open(path, 'a', encoding=encoding) as f:
892
+ return f.write(content)
893
+
894
+ def builtin_readlines(self, path: str, encoding: str = 'utf-8') -> list:
895
+ """Read file lines into list"""
896
+ with open(path, 'r', encoding=encoding) as f:
897
+ return f.readlines()
898
+
899
+ def builtin_listdir(self, path: str = '.') -> list:
900
+ """List directory contents"""
901
+ return os.listdir(path)
902
+
903
+ def builtin_makedirs(self, path: str, exist_ok: bool = True) -> bool:
904
+ """Create directories recursively"""
905
+ os.makedirs(path, exist_ok=exist_ok)
906
+ return True
907
+
908
+ def builtin_removefile(self, path: str) -> bool:
909
+ """Remove a file"""
910
+ os.remove(path)
911
+ return True
912
+
913
+ def builtin_removedir(self, path: str) -> bool:
914
+ """Remove an empty directory"""
915
+ os.rmdir(path)
916
+ return True
917
+
918
+ def builtin_copyfile(self, src: str, dst: str) -> str:
919
+ """Copy a file, returns destination path"""
920
+ import shutil
921
+ return shutil.copy2(src, dst)
922
+
923
+ def builtin_movefile(self, src: str, dst: str) -> str:
924
+ """Move a file, returns destination path"""
925
+ import shutil
926
+ return shutil.move(src, dst)
927
+
928
+ def builtin_filesize(self, path: str) -> int:
929
+ """Get file size in bytes"""
930
+ return os.path.getsize(path)
931
+
932
+ # ============= JSON Functions =============
933
+
934
+ def builtin_tojson(self, value: Any, indent: int = None) -> str:
935
+ return json.dumps(value, indent=indent, ensure_ascii=False)
936
+
937
+ def builtin_fromjson(self, s: str) -> Any:
938
+ return json.loads(s)
939
+
940
+ # JSON namespace functions (json::read, json::write, etc.)
941
+ def builtin_json_read(self, path: str, encoding: str = 'utf-8') -> Any:
942
+ """Read and parse JSON file.
943
+ Usage: json::read('/path/to/file.json')
944
+ """
945
+ with open(path, 'r', encoding=encoding) as f:
946
+ return json.load(f)
947
+
948
+ def builtin_json_write(self, path: str, data: Any, indent: int = 2, encoding: str = 'utf-8') -> bool:
949
+ """Write data to JSON file.
950
+ Usage: json::write('/path/to/file.json', data)
951
+ """
952
+ with open(path, 'w', encoding=encoding) as f:
953
+ json.dump(data, f, indent=indent, ensure_ascii=False)
954
+ return True
955
+
956
+ def builtin_json_pretty(self, value: Any, indent: int = 2) -> str:
957
+ """Pretty print JSON.
958
+ Usage: json::pretty(data)
959
+ """
960
+ return json.dumps(value, indent=indent, ensure_ascii=False)
961
+
962
+ def builtin_json_keys(self, data: Any) -> list:
963
+ """Get all keys from JSON object.
964
+ Usage: json::keys(data)
965
+ """
966
+ if isinstance(data, dict):
967
+ return list(data.keys())
968
+ return []
969
+
970
+ def builtin_json_values(self, data: Any) -> list:
971
+ """Get all values from JSON object.
972
+ Usage: json::values(data)
973
+ """
974
+ if isinstance(data, dict):
975
+ return list(data.values())
976
+ return []
977
+
978
+ def builtin_json_get(self, data: Any, path: str, default: Any = None) -> Any:
979
+ """Get value by dot-path from JSON.
980
+ Usage: json::get(data, 'user.name')
981
+ """
982
+ if not isinstance(data, dict):
983
+ return default
984
+ keys = path.split('.')
985
+ current = data
986
+ for key in keys:
987
+ if isinstance(current, dict) and key in current:
988
+ current = current[key]
989
+ elif isinstance(current, list):
990
+ try:
991
+ current = current[int(key)]
992
+ except (ValueError, IndexError):
993
+ return default
994
+ else:
995
+ return default
996
+ return current
997
+
998
+ def builtin_json_set(self, data: Any, path: str, value: Any) -> Any:
999
+ """Set value by dot-path in JSON object.
1000
+ Usage: json::set(data, 'user.name', 'John')
1001
+ """
1002
+ if not isinstance(data, dict):
1003
+ return data
1004
+ data = dict(data) # Copy
1005
+ keys = path.split('.')
1006
+ current = data
1007
+ for i, key in enumerate(keys[:-1]):
1008
+ if key not in current or not isinstance(current[key], dict):
1009
+ current[key] = {}
1010
+ current = current[key]
1011
+ current[keys[-1]] = value
1012
+ return data
1013
+
1014
+ def builtin_json_has(self, data: Any, path: str) -> bool:
1015
+ """Check if path exists in JSON.
1016
+ Usage: json::has(data, 'user.name')
1017
+ """
1018
+ result = self.builtin_json_get(data, path, _MISSING := object())
1019
+ return result is not _MISSING
1020
+
1021
+ def builtin_json_merge(self, *dicts) -> dict:
1022
+ """Deep merge multiple JSON objects.
1023
+ Usage: json::merge(obj1, obj2, obj3)
1024
+ """
1025
+ def deep_merge(base, update):
1026
+ result = dict(base)
1027
+ for key, value in update.items():
1028
+ if key in result and isinstance(result[key], dict) and isinstance(value, dict):
1029
+ result[key] = deep_merge(result[key], value)
1030
+ else:
1031
+ result[key] = value
1032
+ return result
1033
+
1034
+ result = {}
1035
+ for d in dicts:
1036
+ if isinstance(d, dict):
1037
+ result = deep_merge(result, d)
1038
+ return result
1039
+
1040
+ # ============= Instance Introspection Functions =============
1041
+
1042
+ def builtin_instance_getMethods(self, obj: Any) -> list:
1043
+ """Get all methods from an object/module.
1044
+ Usage: instance::getMethods(@module) or instance::getMethods($obj)
1045
+ Returns list of method names.
1046
+ """
1047
+ import inspect
1048
+ methods = []
1049
+ for name in dir(obj):
1050
+ if not name.startswith('_'):
1051
+ attr = getattr(obj, name, None)
1052
+ if callable(attr):
1053
+ methods.append(name)
1054
+ return methods
1055
+
1056
+ def builtin_instance_getClasses(self, obj: Any) -> list:
1057
+ """Get all classes from an object/module.
1058
+ Usage: instance::getClasses(@module)
1059
+ Returns list of class names.
1060
+ """
1061
+ import inspect
1062
+ classes = []
1063
+ for name in dir(obj):
1064
+ if not name.startswith('_'):
1065
+ attr = getattr(obj, name, None)
1066
+ if inspect.isclass(attr):
1067
+ classes.append(name)
1068
+ return classes
1069
+
1070
+ def builtin_instance_getVars(self, obj: Any) -> list:
1071
+ """Get all variables/attributes (non-callable) from an object.
1072
+ Usage: instance::getVars(@module)
1073
+ Returns list of variable names.
1074
+ """
1075
+ vars_list = []
1076
+ for name in dir(obj):
1077
+ if not name.startswith('_'):
1078
+ attr = getattr(obj, name, None)
1079
+ if not callable(attr):
1080
+ vars_list.append(name)
1081
+ return vars_list
1082
+
1083
+ def builtin_instance_getAll(self, obj: Any) -> dict:
1084
+ """Get all attributes from an object, categorized.
1085
+ Usage: instance::getAll(@module)
1086
+ Returns dict with 'methods', 'classes', 'vars' keys.
1087
+ """
1088
+ import inspect
1089
+ result = {
1090
+ 'methods': [],
1091
+ 'classes': [],
1092
+ 'vars': []
1093
+ }
1094
+ for name in dir(obj):
1095
+ if not name.startswith('_'):
1096
+ attr = getattr(obj, name, None)
1097
+ if inspect.isclass(attr):
1098
+ result['classes'].append(name)
1099
+ elif callable(attr):
1100
+ result['methods'].append(name)
1101
+ else:
1102
+ result['vars'].append(name)
1103
+ return result
1104
+
1105
+ def builtin_instance_call(self, obj: Any, method_name: str, *args, **kwargs) -> Any:
1106
+ """Dynamically call a method on an object.
1107
+ Usage: instance::call(@module, 'methodName', arg1, arg2)
1108
+ """
1109
+ method = getattr(obj, method_name, None)
1110
+ if method and callable(method):
1111
+ return method(*args, **kwargs)
1112
+ raise RuntimeError(f"Method '{method_name}' not found on object")
1113
+
1114
+ def builtin_instance_has(self, obj: Any, name: str) -> bool:
1115
+ """Check if object has an attribute.
1116
+ Usage: instance::has(@module, 'methodName')
1117
+ """
1118
+ return hasattr(obj, name)
1119
+
1120
+ def builtin_instance_type(self, obj: Any) -> str:
1121
+ """Get the type name of an object.
1122
+ Usage: instance::type(@module)
1123
+ """
1124
+ return type(obj).__name__
1125
+
1126
+ def builtin_isavailable(self, name_or_obj: Any) -> bool:
1127
+ """Check if a shared instance exists.
1128
+ Usage:
1129
+ isavailable("MyInstance") - check by name string
1130
+ isavailable($MyInstance) - check shared ref (returns True if not None)
1131
+ instance::exists("MyInstance") - alias
1132
+ """
1133
+ from ..cssl_bridge import _live_objects
1134
+
1135
+
1136
+ # If it's a string, check by name
1137
+ if isinstance(name_or_obj, str):
1138
+ return name_or_obj in _live_objects
1139
+
1140
+ # Otherwise, check if the object is not None (for $name or instance<"name">)
1141
+ return name_or_obj is not None
1142
+
1143
+ # ============= Regex Functions =============
1144
+
1145
+ def builtin_match(self, pattern: str, string: str) -> Optional[dict]:
1146
+ m = re.match(pattern, string)
1147
+ if m:
1148
+ return {'match': m.group(), 'groups': m.groups(), 'start': m.start(), 'end': m.end()}
1149
+ return None
1150
+
1151
+ def builtin_search(self, pattern: str, string: str) -> Optional[dict]:
1152
+ m = re.search(pattern, string)
1153
+ if m:
1154
+ return {'match': m.group(), 'groups': m.groups(), 'start': m.start(), 'end': m.end()}
1155
+ return None
1156
+
1157
+ def builtin_findall(self, pattern: str, string: str) -> list:
1158
+ return re.findall(pattern, string)
1159
+
1160
+ def builtin_sub(self, pattern: str, repl: str, string: str, count: int = 0) -> str:
1161
+ return re.sub(pattern, repl, string, count)
1162
+
1163
+ # ============= Hash Functions =============
1164
+
1165
+ def builtin_md5(self, s: str) -> str:
1166
+ return hashlib.md5(s.encode()).hexdigest()
1167
+
1168
+ def builtin_sha1(self, s: str) -> str:
1169
+ return hashlib.sha1(s.encode()).hexdigest()
1170
+
1171
+ def builtin_sha256(self, s: str) -> str:
1172
+ return hashlib.sha256(s.encode()).hexdigest()
1173
+
1174
+ # ============= Utility Functions =============
1175
+
1176
+ def builtin_copy(self, value: Any) -> Any:
1177
+ import copy
1178
+ return copy.copy(value)
1179
+
1180
+ def builtin_deepcopy(self, value: Any) -> Any:
1181
+ import copy
1182
+ return copy.deepcopy(value)
1183
+
1184
+ def builtin_assert(self, condition: bool, message: str = "Assertion failed") -> None:
1185
+ if not condition:
1186
+ raise CSSLBuiltinError(message)
1187
+
1188
+ def builtin_exit(self, code: int = 0) -> None:
1189
+ if self.runtime and hasattr(self.runtime, 'exit'):
1190
+ self.runtime.exit(code)
1191
+ else:
1192
+ raise SystemExit(code)
1193
+
1194
+ def builtin_original(self, func_name: str, *args) -> Any:
1195
+ """Call the original version of a replaced function.
1196
+
1197
+ Usage:
1198
+ exit <<== { printl("custom exit"); }
1199
+ original("exit"); // Calls the ORIGINAL exit, not the replacement
1200
+
1201
+ // In an injection that was defined BEFORE replacement:
1202
+ old_exit <<== { original("exit"); } // Calls original exit
1203
+ """
1204
+ if self.runtime and hasattr(self.runtime, '_original_functions'):
1205
+ original_func = self.runtime._original_functions.get(func_name)
1206
+ if original_func is not None:
1207
+ if callable(original_func):
1208
+ return original_func(*args)
1209
+ elif isinstance(original_func, type(lambda: None).__class__.__bases__[0]): # Check if bound method
1210
+ return original_func(*args)
1211
+ # Fallback: try to call builtin directly
1212
+ builtin_method = getattr(self, f'builtin_{func_name}', None)
1213
+ if builtin_method:
1214
+ return builtin_method(*args)
1215
+ raise CSSLBuiltinError(f"No original function '{func_name}' found")
1216
+
1217
+ def builtin_env(self, name: str, default: str = None) -> Optional[str]:
1218
+ return os.environ.get(name, default)
1219
+
1220
+ def builtin_setenv(self, name: str, value: str) -> None:
1221
+ """Set environment variable"""
1222
+ os.environ[name] = value
1223
+
1224
+ def builtin_input(self, prompt: str = '') -> str:
1225
+ """Read user input"""
1226
+ return input(prompt)
1227
+
1228
+ def builtin_clear(self) -> None:
1229
+ """Clear console screen"""
1230
+ if os.name == 'nt':
1231
+ os.system('cls')
1232
+ else:
1233
+ print('\033[2J\033[H', end='')
1234
+
1235
+ def builtin_color(self, text: str, color: str) -> str:
1236
+ """Apply ANSI color to text"""
1237
+ colors = {
1238
+ 'black': '30', 'red': '31', 'green': '32', 'yellow': '33',
1239
+ 'blue': '34', 'magenta': '35', 'cyan': '36', 'white': '37',
1240
+ 'bright_black': '90', 'bright_red': '91', 'bright_green': '92',
1241
+ 'bright_yellow': '93', 'bright_blue': '94', 'bright_magenta': '95',
1242
+ 'bright_cyan': '96', 'bright_white': '97',
1243
+ 'reset': '0', 'bold': '1', 'dim': '2', 'italic': '3',
1244
+ 'underline': '4', 'blink': '5', 'reverse': '7'
1245
+ }
1246
+ code = colors.get(color.lower(), color)
1247
+ return f'\033[{code}m{text}\033[0m'
1248
+
1249
+ def builtin_delay(self, ms: float) -> None:
1250
+ """Delay execution by milliseconds"""
1251
+ time.sleep(ms / 1000.0)
1252
+
1253
+ def builtin_pyimport(self, module_name: str) -> Any:
1254
+ """Import a Python module for use in CSSL"""
1255
+ return __import__(module_name)
1256
+
1257
+ # ============= Extended String Functions =============
1258
+
1259
+ def builtin_sprintf(self, fmt: str, *args) -> str:
1260
+ """C-style format string"""
1261
+ return fmt % args
1262
+
1263
+ def builtin_chars(self, s: str) -> list:
1264
+ """Convert string to list of characters"""
1265
+ return list(s)
1266
+
1267
+ def builtin_ord(self, c: str) -> int:
1268
+ """Get ASCII/Unicode code of character"""
1269
+ return ord(c[0] if c else '\0')
1270
+
1271
+ def builtin_chr(self, n: int) -> str:
1272
+ """Convert ASCII/Unicode code to character"""
1273
+ return chr(n)
1274
+
1275
+ def builtin_capitalize(self, s: str) -> str:
1276
+ return str(s).capitalize()
1277
+
1278
+ def builtin_title(self, s: str) -> str:
1279
+ return str(s).title()
1280
+
1281
+ def builtin_swapcase(self, s: str) -> str:
1282
+ return str(s).swapcase()
1283
+
1284
+ def builtin_center(self, s: str, width: int, fillchar: str = ' ') -> str:
1285
+ return str(s).center(width, fillchar)
1286
+
1287
+ def builtin_zfill(self, s: str, width: int) -> str:
1288
+ return str(s).zfill(width)
1289
+
1290
+ def builtin_isalpha(self, s: str) -> bool:
1291
+ return str(s).isalpha()
1292
+
1293
+ def builtin_isdigit(self, s: str) -> bool:
1294
+ return str(s).isdigit()
1295
+
1296
+ def builtin_isalnum(self, s: str) -> bool:
1297
+ return str(s).isalnum()
1298
+
1299
+ def builtin_isspace(self, s: str) -> bool:
1300
+ return str(s).isspace()
1301
+
1302
+ # ============= Extended List Functions =============
1303
+
1304
+ def builtin_enumerate(self, lst: list, start: int = 0) -> list:
1305
+ """Return list of (index, value) pairs"""
1306
+ return list(enumerate(lst, start))
1307
+
1308
+ def builtin_zip(self, *lists) -> list:
1309
+ """Zip multiple lists together"""
1310
+ return list(zip(*lists))
1311
+
1312
+ def builtin_reversed(self, lst: list) -> list:
1313
+ """Return reversed list"""
1314
+ return list(reversed(lst))
1315
+
1316
+ def builtin_sorted(self, lst: list, key: str = None, reverse: bool = False) -> list:
1317
+ """Return sorted list"""
1318
+ if key:
1319
+ return sorted(lst, key=lambda x: x.get(key) if isinstance(x, dict) else x, reverse=reverse)
1320
+ return sorted(lst, reverse=reverse)
1321
+
1322
+ def builtin_count(self, collection: Union[list, str], item: Any) -> int:
1323
+ """Count occurrences of item"""
1324
+ return collection.count(item)
1325
+
1326
+ def builtin_first(self, lst: list, default: Any = None) -> Any:
1327
+ """Get first element or default"""
1328
+ return lst[0] if lst else default
1329
+
1330
+ def builtin_last(self, lst: list, default: Any = None) -> Any:
1331
+ """Get last element or default"""
1332
+ return lst[-1] if lst else default
1333
+
1334
+ def builtin_take(self, lst: list, n: int) -> list:
1335
+ """Take first n elements"""
1336
+ return lst[:n]
1337
+
1338
+ def builtin_drop(self, lst: list, n: int) -> list:
1339
+ """Drop first n elements"""
1340
+ return lst[n:]
1341
+
1342
+ def builtin_chunk(self, lst: list, size: int) -> list:
1343
+ """Split list into chunks of given size"""
1344
+ return [lst[i:i + size] for i in range(0, len(lst), size)]
1345
+
1346
+ def builtin_groupby(self, lst: list, key: str) -> dict:
1347
+ """Group list of dicts by key"""
1348
+ result = {}
1349
+ for item in lst:
1350
+ k = item.get(key) if isinstance(item, dict) else getattr(item, key, None)
1351
+ if k not in result:
1352
+ result[k] = []
1353
+ result[k].append(item)
1354
+ return result
1355
+
1356
+ def builtin_shuffle(self, lst: list) -> list:
1357
+ """Return shuffled copy of list"""
1358
+ result = list(lst)
1359
+ random.shuffle(result)
1360
+ return result
1361
+
1362
+ def builtin_sample(self, lst: list, k: int) -> list:
1363
+ """Return k random elements from list"""
1364
+ return random.sample(lst, min(k, len(lst)))
1365
+
1366
+ # ============= Extended Dict Functions =============
1367
+
1368
+ def builtin_update(self, d: dict, other: dict) -> dict:
1369
+ """Update dict with another dict, return new dict"""
1370
+ result = dict(d)
1371
+ result.update(other)
1372
+ return result
1373
+
1374
+ def builtin_fromkeys(self, keys: list, value: Any = None) -> dict:
1375
+ """Create dict from keys with default value"""
1376
+ return dict.fromkeys(keys, value)
1377
+
1378
+ def builtin_invert(self, d: dict) -> dict:
1379
+ """Swap keys and values"""
1380
+ return {v: k for k, v in d.items()}
1381
+
1382
+ def builtin_pick(self, d: dict, *keys) -> dict:
1383
+ """Pick only specified keys from dict"""
1384
+ return {k: d[k] for k in keys if k in d}
1385
+
1386
+ def builtin_omit(self, d: dict, *keys) -> dict:
1387
+ """Omit specified keys from dict"""
1388
+ return {k: v for k, v in d.items() if k not in keys}
1389
+
1390
+ # ============= CSSL System Functions =============
1391
+
1392
+ def builtin_createcmd(self, cmd_name: str, handler: Callable = None) -> bool:
1393
+ """
1394
+ Create a custom console command
1395
+ Usage: createcmd('mycommand') <== { ... handler code ... }
1396
+ """
1397
+ if not self.runtime:
1398
+ print(f"Cannot create command '{cmd_name}': No runtime available")
1399
+ return False
1400
+
1401
+ # Store the command handler in runtime
1402
+ if not hasattr(self.runtime, '_custom_commands'):
1403
+ self.runtime._custom_commands = {}
1404
+
1405
+ self.runtime._custom_commands[cmd_name] = handler
1406
+
1407
+ # Find Console via multiple paths
1408
+ console = None
1409
+
1410
+ # Try 1: Direct _console reference on runtime
1411
+ if hasattr(self.runtime, '_console') and self.runtime._console:
1412
+ console = self.runtime._console
1413
+
1414
+ # Try 2: Via service_engine.Console
1415
+ elif self.runtime.service_engine and hasattr(self.runtime.service_engine, 'Console'):
1416
+ console = self.runtime.service_engine.Console
1417
+
1418
+ # Register with Console if found
1419
+ if console and hasattr(console, 'register_custom_command'):
1420
+ console.register_custom_command(cmd_name, handler)
1421
+ else:
1422
+ print(f"Custom command '{cmd_name}' stored (Console not yet available)")
1423
+
1424
+ return True
1425
+
1426
+ def builtin_signal(self, event_ref: Any, action: str = '+') -> bool:
1427
+ """
1428
+ Send or register a signal/event
1429
+ Usage: signal(@event.CustomEvent, '+') to emit, '-' to unregister
1430
+ """
1431
+ try:
1432
+ from .cssl_events import get_event_manager, EventType
1433
+
1434
+ event_manager = get_event_manager()
1435
+
1436
+ # Handle event reference (could be string or module ref)
1437
+ event_name = str(event_ref) if not isinstance(event_ref, str) else event_ref
1438
+
1439
+ if action == '+':
1440
+ # Emit the event
1441
+ event_manager.emit_custom(event_name, source="cssl_signal")
1442
+ print(f"Signal emitted: {event_name}")
1443
+ return True
1444
+ elif action == '-':
1445
+ # Unregister handlers for this event
1446
+ # This would need custom implementation
1447
+ print(f"Signal handlers cleared: {event_name}")
1448
+ return True
1449
+ else:
1450
+ print(f"Unknown signal action: {action}")
1451
+ return False
1452
+
1453
+ except Exception as e:
1454
+ print(f"Signal error: {e}")
1455
+ return False
1456
+
1457
+ def builtin_appexec(self, app_name: str, *args) -> bool:
1458
+ """
1459
+ Start a desktop application (visually)
1460
+ Usage: appexec('xface')
1461
+ """
1462
+ if not self.runtime or not self.runtime.service_engine:
1463
+ print(f"Cannot execute app '{app_name}': No service engine available")
1464
+ return False
1465
+
1466
+ try:
1467
+ kernel = self.runtime.service_engine.KernelClient
1468
+
1469
+ # Check if desktop environment is available
1470
+ if hasattr(kernel, 'start_desktop_app'):
1471
+ return kernel.start_desktop_app(app_name, *args)
1472
+
1473
+ # Try to find and launch the app
1474
+ app_paths = [
1475
+ os.path.join(kernel.RootDirectory, 'apps', app_name),
1476
+ os.path.join(kernel.RootDirectory, 'apps', f'{app_name}.py'),
1477
+ os.path.join(kernel.RootDirectory, 'desktop', 'apps', app_name),
1478
+ os.path.join(kernel.RootDirectory, 'desktop', 'apps', f'{app_name}.py'),
1479
+ ]
1480
+
1481
+ for app_path in app_paths:
1482
+ if os.path.exists(app_path):
1483
+ print(f"Launching app: {app_name}")
1484
+ if app_path.endswith('.py'):
1485
+ return self.builtin_initpy(app_path)
1486
+ return True
1487
+
1488
+ print(f"App not found: {app_name}")
1489
+ return False
1490
+
1491
+ except Exception as e:
1492
+ print(f"App execution error: {e}")
1493
+ return False
1494
+
1495
+ def builtin_initpy(self, path: str, *args, **kwargs) -> Any:
1496
+ """
1497
+ Execute a Python file
1498
+ Usage: initpy('/path/to/script.py')
1499
+ """
1500
+ if not os.path.isabs(path) and self.runtime and self.runtime.service_engine:
1501
+ path = os.path.join(self.runtime.service_engine.KernelClient.RootDirectory, path)
1502
+
1503
+ if not os.path.exists(path):
1504
+ raise CSSLBuiltinError(f"Python file not found: {path}")
1505
+
1506
+ try:
1507
+ # Prepare execution context
1508
+ exec_globals = {
1509
+ '__file__': path,
1510
+ '__name__': '__main__',
1511
+ }
1512
+
1513
+ # Add kernel and service engine if available
1514
+ if self.runtime and self.runtime.service_engine:
1515
+ exec_globals['kernel'] = self.runtime.service_engine.KernelClient
1516
+ exec_globals['service'] = self.runtime.service_engine
1517
+ exec_globals['args'] = args
1518
+ exec_globals['kwargs'] = kwargs
1519
+
1520
+ with open(path, 'r', encoding='utf-8') as f:
1521
+ code = f.read()
1522
+
1523
+ exec(compile(code, path, 'exec'), exec_globals)
1524
+ return exec_globals.get('result', True)
1525
+
1526
+ except Exception as e:
1527
+ print(f"Python execution error [{path}]: {e}")
1528
+ raise CSSLBuiltinError(f"initpy failed: {e}")
1529
+
1530
+ def builtin_initsh(self, path: str, *args) -> int:
1531
+ """
1532
+ Execute a shell script
1533
+ Usage: initsh('/path/to/script.sh')
1534
+ """
1535
+ import subprocess
1536
+
1537
+ if not os.path.isabs(path) and self.runtime and self.runtime.service_engine:
1538
+ path = os.path.join(self.runtime.service_engine.KernelClient.RootDirectory, path)
1539
+
1540
+ if not os.path.exists(path):
1541
+ raise CSSLBuiltinError(f"Shell script not found: {path}")
1542
+
1543
+ try:
1544
+ # Determine shell based on platform
1545
+ import platform
1546
+ if platform.system() == 'Windows':
1547
+ # Use cmd or powershell on Windows
1548
+ cmd = ['cmd', '/c', path] + list(args)
1549
+ else:
1550
+ cmd = ['bash', path] + list(args)
1551
+
1552
+ result = subprocess.run(cmd, capture_output=True, text=True)
1553
+
1554
+ if result.stdout:
1555
+ print(result.stdout)
1556
+ if result.stderr:
1557
+ print(f"STDERR: {result.stderr}")
1558
+
1559
+ return result.returncode
1560
+
1561
+ except Exception as e:
1562
+ print(f"Shell execution error [{path}]: {e}")
1563
+ raise CSSLBuiltinError(f"initsh failed: {e}")
1564
+
1565
+ def builtin_wait_for(self, condition: Callable, timeout: float = 30.0, interval: float = 0.1) -> bool:
1566
+ """
1567
+ Wait for a condition to become true
1568
+ Usage: wait_for(lambda: some_condition, timeout=30)
1569
+ """
1570
+ import time
1571
+ start = time.time()
1572
+
1573
+ while time.time() - start < timeout:
1574
+ try:
1575
+ if callable(condition):
1576
+ if condition():
1577
+ return True
1578
+ elif condition:
1579
+ return True
1580
+ except Exception:
1581
+ pass
1582
+ time.sleep(interval)
1583
+
1584
+ return False
1585
+
1586
+ def builtin_wait_for_event(self, event_name: str, timeout: float = 30.0) -> bool:
1587
+ """
1588
+ Wait for a specific event to occur
1589
+ Usage: wait_for_event('@event.Booted', timeout=60)
1590
+ """
1591
+ try:
1592
+ from .cssl_events import get_event_manager
1593
+
1594
+ event_manager = get_event_manager()
1595
+ event_occurred = [False]
1596
+
1597
+ def handler(event_data):
1598
+ event_occurred[0] = True
1599
+
1600
+ # Register temporary handler
1601
+ handler_id = event_manager.register_custom(
1602
+ event_name,
1603
+ handler,
1604
+ once=True
1605
+ )
1606
+
1607
+ # Wait for event
1608
+ import time
1609
+ start = time.time()
1610
+ while not event_occurred[0] and (time.time() - start) < timeout:
1611
+ time.sleep(0.1)
1612
+
1613
+ # Cleanup if not occurred
1614
+ if not event_occurred[0]:
1615
+ event_manager.unregister(handler_id)
1616
+
1617
+ return event_occurred[0]
1618
+
1619
+ except Exception as e:
1620
+ print(f"wait_for_event error: {e}")
1621
+ return False
1622
+
1623
+ def builtin_wait_for_booted(self, timeout: float = 60.0) -> bool:
1624
+ """
1625
+ Wait until the system is fully booted
1626
+ Usage: await wait_for_booted()
1627
+ """
1628
+ if not self.runtime or not self.runtime.service_engine:
1629
+ return False
1630
+
1631
+ import time
1632
+ start = time.time()
1633
+
1634
+ while time.time() - start < timeout:
1635
+ try:
1636
+ wheel = self.runtime.service_engine.KernelClient.WheelKernel
1637
+ booted = wheel.ReadWheelParam('boot', 'BOOTED')
1638
+ if booted == '1':
1639
+ return True
1640
+ except Exception:
1641
+ pass
1642
+ time.sleep(0.5)
1643
+
1644
+ return False
1645
+
1646
+ def builtin_emit(self, event_name: str, data: Any = None) -> bool:
1647
+ """
1648
+ Emit a custom event
1649
+ Usage: emit('MyCustomEvent', {data: 'value'})
1650
+ """
1651
+ try:
1652
+ from .cssl_events import get_event_manager
1653
+
1654
+ event_manager = get_event_manager()
1655
+ event_manager.emit_custom(event_name, source="cssl", data=data or {})
1656
+ return True
1657
+
1658
+ except Exception as e:
1659
+ print(f"emit error: {e}")
1660
+ return False
1661
+
1662
+ def builtin_on_event(self, event_name: str, handler: Callable) -> str:
1663
+ """
1664
+ Register an event handler
1665
+ Usage: on_event('MyEvent', handler_function)
1666
+ Returns: handler_id for later removal
1667
+ """
1668
+ try:
1669
+ from .cssl_events import get_event_manager
1670
+
1671
+ event_manager = get_event_manager()
1672
+ handler_id = event_manager.register_custom(event_name, handler)
1673
+ return handler_id
1674
+
1675
+ except Exception as e:
1676
+ print(f"on_event error: {e}")
1677
+ return ""
1678
+
1679
+ # ============= CSSL Import System Functions =============
1680
+
1681
+ def builtin_cso_root(self, path: str = "") -> str:
1682
+ """
1683
+ Get absolute path relative to CSO root directory
1684
+ Usage: cso_root('/services/myservice.cssl')
1685
+ Returns: Full absolute path to the file
1686
+ """
1687
+ base = os.getcwd()
1688
+
1689
+ # Try to get base from kernel parameters
1690
+ if self.runtime and self.runtime.service_engine:
1691
+ try:
1692
+ kernel = self.runtime.service_engine.KernelClient
1693
+ if hasattr(kernel, 'WheelKernel'):
1694
+ wheel = kernel.WheelKernel
1695
+ if hasattr(wheel, 'KernelParam'):
1696
+ base = wheel.KernelParam.get('@base', base)
1697
+ if hasattr(kernel, 'RootDirectory'):
1698
+ base = kernel.RootDirectory
1699
+ except Exception:
1700
+ pass
1701
+
1702
+ # Clean path and join
1703
+ if path:
1704
+ clean_path = path.lstrip('/').lstrip('\\')
1705
+ return os.path.normpath(os.path.join(base, clean_path))
1706
+
1707
+ return base
1708
+
1709
+ def builtin_include(self, filepath: str) -> Any:
1710
+ """
1711
+ Load and execute a CSSL file or .cssl-mod module, returning its ServiceDefinition
1712
+ Usage: include(cso_root('/services/utils.cssl'))
1713
+ include('modules/math_utils.cssl-mod')
1714
+ include('C:/absolute/path/module.cssl-mod')
1715
+ Returns: ServiceDefinition with structs, functions, etc.
1716
+ """
1717
+ if not self.runtime:
1718
+ raise CSSLBuiltinError("include requires runtime context")
1719
+
1720
+ # Normalize path separators (support both / and \)
1721
+ filepath = filepath.replace('\\', '/')
1722
+
1723
+ # Handle absolute paths (Windows: C:/, D:/, etc. and Unix: /)
1724
+ is_absolute = os.path.isabs(filepath) or (len(filepath) > 2 and filepath[1] == ':')
1725
+
1726
+ if not is_absolute:
1727
+ # Try relative to current working directory first
1728
+ cwd_path = os.path.join(os.getcwd(), filepath)
1729
+ if os.path.exists(cwd_path):
1730
+ filepath = cwd_path
1731
+ else:
1732
+ # Fall back to cso_root for CSO service context
1733
+ filepath = self.builtin_cso_root(filepath)
1734
+
1735
+ # Check file exists
1736
+ if not os.path.exists(filepath):
1737
+ raise CSSLBuiltinError(f"Include file not found: {filepath}")
1738
+
1739
+ # Check include cache to prevent circular imports
1740
+ if not hasattr(self.runtime, '_include_cache'):
1741
+ self.runtime._include_cache = {}
1742
+
1743
+ if filepath in self.runtime._include_cache:
1744
+ return self.runtime._include_cache[filepath]
1745
+
1746
+ try:
1747
+ # Read the file
1748
+ with open(filepath, 'r', encoding='utf-8') as f:
1749
+ source = f.read()
1750
+
1751
+ # Check if this is a .cssl-mod file
1752
+ if filepath.endswith('.cssl-mod') or source.startswith('CSSLMOD1'):
1753
+ result = self._load_cssl_module(filepath, source)
1754
+ self.runtime._include_cache[filepath] = result
1755
+ return result
1756
+
1757
+ # Regular CSSL file
1758
+ from .cssl_parser import parse_cssl
1759
+
1760
+ ast = parse_cssl(source)
1761
+
1762
+ # Execute the service to get definitions
1763
+ service_def = self.runtime._exec_service(ast)
1764
+
1765
+ # Cache the result
1766
+ self.runtime._include_cache[filepath] = service_def
1767
+
1768
+ return service_def
1769
+
1770
+ except Exception as e:
1771
+ raise CSSLBuiltinError(f"Failed to include '{filepath}': {e}")
1772
+
1773
+ def _load_cssl_module(self, filepath: str, source: str) -> Any:
1774
+ """
1775
+ Load a .cssl-mod module file and return a callable module object.
1776
+ Handles Python and C++ modules.
1777
+ """
1778
+ import base64
1779
+ import pickle
1780
+
1781
+ # Parse the module format: CSSLMOD1\n<base64-encoded-pickle>
1782
+ lines = source.strip().split('\n', 1)
1783
+ if len(lines) < 2 or lines[0] != 'CSSLMOD1':
1784
+ raise CSSLBuiltinError(f"Invalid .cssl-mod format: {filepath}")
1785
+
1786
+ # Decode the module data
1787
+ try:
1788
+ encoded_data = lines[1].strip()
1789
+ module_data = pickle.loads(base64.b64decode(encoded_data))
1790
+ except Exception as e:
1791
+ raise CSSLBuiltinError(f"Failed to decode .cssl-mod: {e}")
1792
+
1793
+ module_name = module_data.get('name', 'unknown')
1794
+ module_type = module_data.get('type', 'python')
1795
+ module_source = module_data.get('source', '')
1796
+
1797
+ if module_type == 'python':
1798
+ return self._execute_python_module(module_name, module_source, filepath)
1799
+ elif module_type == 'cpp':
1800
+ return self._load_cpp_module(module_name, module_source, filepath)
1801
+ else:
1802
+ raise CSSLBuiltinError(f"Unsupported module type: {module_type}")
1803
+
1804
+ def _execute_python_module(self, name: str, source: str, filepath: str) -> Any:
1805
+ """
1806
+ Execute Python source and return a module-like object with all functions.
1807
+ """
1808
+ # Create a namespace for the module
1809
+ module_namespace = {
1810
+ '__name__': name,
1811
+ '__file__': filepath,
1812
+ '__builtins__': __builtins__,
1813
+ }
1814
+
1815
+ # Execute the Python source
1816
+ try:
1817
+ exec(source, module_namespace)
1818
+ except Exception as e:
1819
+ raise CSSLBuiltinError(f"Failed to execute Python module '{name}': {e}")
1820
+
1821
+ # Create a callable module wrapper
1822
+ class CSSLModuleWrapper:
1823
+ """Wrapper that makes Python functions callable from CSSL"""
1824
+ def __init__(self, namespace, mod_name):
1825
+ self._namespace = namespace
1826
+ self._name = mod_name
1827
+ self._functions = {}
1828
+
1829
+ # Extract all callable functions (not dunder methods)
1830
+ for key, value in namespace.items():
1831
+ if callable(value) and not key.startswith('_'):
1832
+ self._functions[key] = value
1833
+ # Also set as attribute for @Module.func() syntax
1834
+ setattr(self, key, value)
1835
+
1836
+ def __getattr__(self, name):
1837
+ if name.startswith('_'):
1838
+ raise AttributeError(f"'{self._name}' has no attribute '{name}'")
1839
+ if name in self._functions:
1840
+ return self._functions[name]
1841
+ if name in self._namespace:
1842
+ return self._namespace[name]
1843
+ raise AttributeError(f"Module '{self._name}' has no function '{name}'")
1844
+
1845
+ def __repr__(self):
1846
+ funcs = list(self._functions.keys())
1847
+ return f"<CSSLModule '{self._name}' functions={funcs}>"
1848
+
1849
+ def __dir__(self):
1850
+ return list(self._functions.keys())
1851
+
1852
+ return CSSLModuleWrapper(module_namespace, name)
1853
+
1854
+ def _load_cpp_module(self, name: str, source: str, filepath: str) -> Any:
1855
+ """
1856
+ Load a C++ module (stub for future implementation).
1857
+ For now, returns a placeholder with the source available.
1858
+ """
1859
+ class CppModuleStub:
1860
+ def __init__(self, mod_name, cpp_source):
1861
+ self._name = mod_name
1862
+ self._source = cpp_source
1863
+
1864
+ def __repr__(self):
1865
+ return f"<CppModule '{self._name}' (not compiled)>"
1866
+
1867
+ def compile(self):
1868
+ """Future: Compile and load the C++ module"""
1869
+ raise NotImplementedError("C++ module compilation not yet implemented")
1870
+
1871
+ return CppModuleStub(name, source)
1872
+
1873
+ def builtin_payload(self, filepath: str) -> None:
1874
+ """
1875
+ Load a CSSL payload file (.cssl-pl) and execute it in the current scope.
1876
+
1877
+ Payloads are like header files but for CSSL:
1878
+ - Define global variables (accessible via @name)
1879
+ - Define helper functions (globally callable)
1880
+ - Inject code into builtins (like exit() <<== {...})
1881
+ - Set configuration values
1882
+
1883
+ Usage in .cssl file:
1884
+ payload("myconfig.cssl-pl");
1885
+ // Now all globals, functions, and injections are active
1886
+
1887
+ Usage in Python:
1888
+ cssl = CSSL.CsslLang()
1889
+ cssl.code("myhelper", "... cssl code ...") # Creates inline payload
1890
+ cssl.exec('payload("myhelper");') # Loads the inline payload
1891
+
1892
+ .cssl-pl file format:
1893
+ // Variables
1894
+ global version = "1.0.0";
1895
+ global debug = true;
1896
+
1897
+ // Injections
1898
+ exit() <<== {
1899
+ printl("Cleanup...");
1900
+ }
1901
+
1902
+ // Helper functions
1903
+ void log(string msg) {
1904
+ if (@debug) printl("[LOG] " + msg);
1905
+ }
1906
+ """
1907
+ if not self.runtime:
1908
+ raise CSSLBuiltinError("payload requires runtime context")
1909
+
1910
+ # Normalize path separators
1911
+ filepath = filepath.replace('\\', '/')
1912
+
1913
+ # Check if this is an inline payload (registered via cssl.code())
1914
+ if hasattr(self.runtime, '_inline_payloads') and filepath in self.runtime._inline_payloads:
1915
+ source = self.runtime._inline_payloads[filepath]
1916
+ else:
1917
+ # Handle absolute paths
1918
+ is_absolute = os.path.isabs(filepath) or (len(filepath) > 2 and filepath[1] == ':')
1919
+
1920
+ if not is_absolute:
1921
+ # Try relative to current working directory first
1922
+ cwd_path = os.path.join(os.getcwd(), filepath)
1923
+ if os.path.exists(cwd_path):
1924
+ filepath = cwd_path
1925
+ else:
1926
+ # Fall back to cso_root for CSO service context
1927
+ filepath = self.builtin_cso_root(filepath)
1928
+
1929
+ # Check file exists
1930
+ if not os.path.exists(filepath):
1931
+ raise CSSLBuiltinError(f"Payload file not found: {filepath}")
1932
+
1933
+ # Check payload cache to prevent double loading
1934
+ if not hasattr(self.runtime, '_payload_cache'):
1935
+ self.runtime._payload_cache = set()
1936
+
1937
+ if filepath in self.runtime._payload_cache:
1938
+ return # Already loaded
1939
+
1940
+ # Read the payload file
1941
+ with open(filepath, 'r', encoding='utf-8') as f:
1942
+ source = f.read()
1943
+
1944
+ self.runtime._payload_cache.add(filepath)
1945
+
1946
+ # Parse and execute the payload in current scope
1947
+ # This makes all globals, functions, and injections available
1948
+ try:
1949
+ from .cssl_parser import parse_cssl_program
1950
+
1951
+ ast = parse_cssl_program(source)
1952
+
1953
+ # Execute the payload - this will:
1954
+ # - Register global variables (accessible via @name)
1955
+ # - Define functions in current scope
1956
+ # - Set up any code injections
1957
+ self.runtime._execute_node(ast)
1958
+
1959
+ except Exception as e:
1960
+ raise CSSLBuiltinError(f"Failed to load payload '{filepath}': {e}")
1961
+
1962
+ def builtin_get(self, source: Any, key: str = None) -> Any:
1963
+ """
1964
+ Get value from module, ServiceDefinition, or dict
1965
+ Usage:
1966
+ get('list') - Get list module (returns empty list creator)
1967
+ get('os') - Get OS module
1968
+ get('time') - Get Time module
1969
+ get(@Time) - Get standard module
1970
+ get(service_def, 'funcName') - Get function from included service
1971
+ get(dict_obj, 'key') - Get key from dict
1972
+ Returns: The requested value or None
1973
+ """
1974
+ # Single argument - return module reference directly
1975
+ if key is None:
1976
+ if isinstance(source, str):
1977
+ # NEW: Handle standard module names
1978
+ module_map = {
1979
+ 'list': self._get_list_module(),
1980
+ 'dict': self._get_dict_module(),
1981
+ 'os': self._get_os_module(),
1982
+ 'time': self._get_time_module(),
1983
+ 'vsramsdk': self._get_vsram_module(),
1984
+ 'kernel': self._get_kernel_module(),
1985
+ }
1986
+ if source.lower() in module_map:
1987
+ return module_map[source.lower()]
1988
+
1989
+ # Treat as module path
1990
+ if self.runtime:
1991
+ return self.runtime.get_module(source)
1992
+ return source
1993
+
1994
+ # Two arguments - extract from source
1995
+ if hasattr(source, key):
1996
+ return getattr(source, key)
1997
+
1998
+ if isinstance(source, dict):
1999
+ return source.get(key)
2000
+
2001
+ # Check if source is a ServiceDefinition-like object
2002
+ if hasattr(source, 'structs') and key in source.structs:
2003
+ return source.structs[key]
2004
+
2005
+ if hasattr(source, 'functions') and key in source.functions:
2006
+ return source.functions[key]
2007
+
2008
+ return None
2009
+
2010
+ # NEW: Module factories for get()
2011
+ def _get_list_module(self):
2012
+ """Return a list module proxy"""
2013
+ class ListModule:
2014
+ @staticmethod
2015
+ def create():
2016
+ return []
2017
+ @staticmethod
2018
+ def add(lst, item):
2019
+ if isinstance(lst, list):
2020
+ lst.append(item)
2021
+ return lst
2022
+ return ListModule()
2023
+
2024
+ def _get_dict_module(self):
2025
+ """Return a dict module proxy"""
2026
+ class DictModule:
2027
+ @staticmethod
2028
+ def create():
2029
+ return {}
2030
+ return DictModule()
2031
+
2032
+ def _get_os_module(self):
2033
+ """Return OS module proxy"""
2034
+ class OSModule:
2035
+ @staticmethod
2036
+ def Listdir(path='.'):
2037
+ return os.listdir(path)
2038
+ @staticmethod
2039
+ def ReadFile(path, encoding='utf-8'):
2040
+ with open(path, 'r', encoding=encoding) as f:
2041
+ return f.read()
2042
+ @staticmethod
2043
+ def WriteFile(path, content, encoding='utf-8'):
2044
+ with open(path, 'w', encoding=encoding) as f:
2045
+ return f.write(content)
2046
+ @staticmethod
2047
+ def isLinux():
2048
+ import platform
2049
+ return platform.system() == 'Linux'
2050
+ @staticmethod
2051
+ def isWindows():
2052
+ import platform
2053
+ return platform.system() == 'Windows'
2054
+ @staticmethod
2055
+ def isMac():
2056
+ import platform
2057
+ return platform.system() == 'Darwin'
2058
+ return OSModule()
2059
+
2060
+ def _get_time_module(self):
2061
+ """Return Time module proxy"""
2062
+ class TimeModule:
2063
+ @staticmethod
2064
+ def CurrentTime(format_str='%Y-%m-%d %H:%M:%S'):
2065
+ return datetime.now().strftime(format_str)
2066
+ @staticmethod
2067
+ def Now():
2068
+ return time.time()
2069
+ @staticmethod
2070
+ def Sleep(seconds):
2071
+ time.sleep(seconds)
2072
+ return TimeModule()
2073
+
2074
+ def _get_vsram_module(self):
2075
+ """Return VSRAM module proxy from runtime"""
2076
+ if self.runtime and hasattr(self.runtime, '_modules'):
2077
+ return self.runtime._modules.get('VSRam') or self.runtime._modules.get('VSRAM')
2078
+ return None
2079
+
2080
+ def _get_kernel_module(self):
2081
+ """Return Kernel module proxy from runtime"""
2082
+ if self.runtime and hasattr(self.runtime, '_modules'):
2083
+ return self.runtime._modules.get('Kernel') or self.runtime._modules.get('KernelClient')
2084
+ return None
2085
+
2086
+ # NEW: Platform Detection Functions
2087
+ def builtin_islinux(self) -> bool:
2088
+ """Check if running on Linux"""
2089
+ import platform
2090
+ return platform.system() == 'Linux'
2091
+
2092
+ def builtin_iswindows(self) -> bool:
2093
+ """Check if running on Windows"""
2094
+ import platform
2095
+ return platform.system() == 'Windows'
2096
+
2097
+ def builtin_ismac(self) -> bool:
2098
+ """Check if running on macOS"""
2099
+ import platform
2100
+ return platform.system() == 'Darwin'
2101
+
2102
+ # NEW: CurrentTime function
2103
+ def builtin_currenttime(self, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
2104
+ """Get current time as formatted string"""
2105
+ return datetime.now().strftime(format_str)
2106
+
2107
+ # NEW: Global function for scope promotion
2108
+ def builtin_global(self, s_ref: Any) -> None:
2109
+ """
2110
+ Promote s@<name> to @<name> (make globally accessible)
2111
+ Usage: global(s@cache) - makes @cache available
2112
+
2113
+ This takes the value referenced by s@<name> and registers it
2114
+ as a module reference accessible via @<name>
2115
+ """
2116
+ if not self.runtime:
2117
+ return
2118
+
2119
+ # The argument could be:
2120
+ # 1. A direct value from s@<name> reference
2121
+ # 2. A string path like "MyStruct.cache"
2122
+
2123
+ if isinstance(s_ref, str):
2124
+ # It's a path - promote it
2125
+ self.runtime.promote_to_global(s_ref)
2126
+ else:
2127
+ # It's a value - we need the original s@<name> reference
2128
+ # This is handled by the runtime which passes the path
2129
+ pass
2130
+
2131
+ def builtin_delete(self, name: str) -> bool:
2132
+ """
2133
+ Delete a shared object by name.
2134
+ Usage: delete("MyLib") - removes the $MyLib shared object
2135
+
2136
+ Args:
2137
+ name: Name of the shared object (without the $ prefix)
2138
+
2139
+ Returns:
2140
+ True if deleted, False if not found
2141
+ """
2142
+ from ..cssl_bridge import _live_objects
2143
+
2144
+ # Remove from live objects registry
2145
+ if name in _live_objects:
2146
+ del _live_objects[name]
2147
+ # Also remove from runtime's global scope if present
2148
+ if self.runtime:
2149
+ try:
2150
+ self.runtime.global_scope.delete(f'${name}')
2151
+ except Exception:
2152
+ pass
2153
+ return True
2154
+ return False
2155
+
2156
+ # ============= CSSL Data Type Constructors =============
2157
+
2158
+ def builtin_datastruct(self, element_type: str = 'dynamic') -> Any:
2159
+ """Create a datastruct container.
2160
+
2161
+ Usage: datastruct<string> myData; or datastruct('string')
2162
+ """
2163
+ from .cssl_types import DataStruct
2164
+ return DataStruct(element_type)
2165
+
2166
+ def builtin_shuffled(self, element_type: str = 'dynamic') -> Any:
2167
+ """Create a shuffled container for multiple returns.
2168
+
2169
+ Usage: shuffled<string> results;
2170
+ """
2171
+ from .cssl_types import Shuffled
2172
+ return Shuffled(element_type)
2173
+
2174
+ def builtin_iterator(self, element_type: str = 'int', size: int = 16) -> Any:
2175
+ """Create an advanced iterator.
2176
+
2177
+ Usage: iterator<int, 16> Map;
2178
+ """
2179
+ from .cssl_types import Iterator
2180
+ return Iterator(element_type, size)
2181
+
2182
+ def builtin_combo(self, element_type: str = 'dynamic') -> Any:
2183
+ """Create a combo filter/search space.
2184
+
2185
+ Usage: combo<open&string> myCombo;
2186
+ """
2187
+ from .cssl_types import Combo
2188
+ return Combo(element_type)
2189
+
2190
+ def builtin_dataspace(self, space_type: str = 'dynamic') -> Any:
2191
+ """Create a dataspace for SQL/structured data.
2192
+
2193
+ Usage: dataspace<sql::table> table;
2194
+ """
2195
+ from .cssl_types import DataSpace
2196
+ return DataSpace(space_type)
2197
+
2198
+ def builtin_openquote(self, db_ref: Any = None) -> Any:
2199
+ """Create an openquote container for SQL operations.
2200
+
2201
+ Usage: openquote<datastruct<dynamic>&@sql::db.oqt(@db)> Queue;
2202
+ """
2203
+ from .cssl_types import OpenQuote
2204
+ return OpenQuote(db_ref)
2205
+
2206
+ def builtin_openfind(self, combo_or_type: Any, index: int = 0, params: list = None) -> Any:
2207
+ """Find open parameter by type or combo space.
2208
+
2209
+ Usage:
2210
+ OpenFind<string>(0) # Find first string at position 0
2211
+ OpenFind(&@comboSpace) # Find using combo filter
2212
+
2213
+ When using with open parameters:
2214
+ open define myFunc(open Params) {
2215
+ string name = OpenFind<string>(0); // Find nearest string at index 0
2216
+ int age = OpenFind<int>(1); // Find nearest int at index 1
2217
+ }
2218
+ """
2219
+ from .cssl_types import Combo
2220
+
2221
+ if isinstance(combo_or_type, Combo):
2222
+ # Find by combo space
2223
+ if params:
2224
+ return combo_or_type.find_match(params)
2225
+ return combo_or_type.find_match([])
2226
+
2227
+ # Type-based search
2228
+ target_type = combo_or_type
2229
+ if params is None:
2230
+ params = []
2231
+
2232
+ # Map type names to Python types
2233
+ type_map = {
2234
+ 'string': str, 'str': str,
2235
+ 'int': int, 'integer': int,
2236
+ 'float': float, 'double': float,
2237
+ 'bool': bool, 'boolean': bool,
2238
+ 'list': list, 'array': list,
2239
+ 'dict': dict, 'dictionary': dict
2240
+ }
2241
+
2242
+ python_type = type_map.get(str(target_type).lower(), None)
2243
+ if python_type is None:
2244
+ return None
2245
+
2246
+ # Find the nearest matching type from index position
2247
+ matches_found = 0
2248
+ for i, param in enumerate(params):
2249
+ if isinstance(param, python_type):
2250
+ if matches_found == index:
2251
+ return param
2252
+ matches_found += 1
2253
+
2254
+ return None
2255
+
2256
+
2257
+ # Module-level convenience functions
2258
+ _default_builtins: Optional[CSSLBuiltins] = None
2259
+
2260
+
2261
+ def get_builtins(runtime=None) -> CSSLBuiltins:
2262
+ """Get default builtins instance"""
2263
+ global _default_builtins
2264
+ if _default_builtins is None or runtime is not None:
2265
+ _default_builtins = CSSLBuiltins(runtime)
2266
+ return _default_builtins
2267
+
2268
+
2269
+ def call_builtin(name: str, *args, **kwargs) -> Any:
2270
+ """Call a builtin function"""
2271
+ return get_builtins().call(name, *args, **kwargs)