zexus 1.6.2

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 (227) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +2513 -0
  3. package/bin/zexus +2 -0
  4. package/bin/zpics +2 -0
  5. package/bin/zpm +2 -0
  6. package/bin/zx +2 -0
  7. package/bin/zx-deploy +2 -0
  8. package/bin/zx-dev +2 -0
  9. package/bin/zx-run +2 -0
  10. package/package.json +66 -0
  11. package/scripts/README.md +24 -0
  12. package/scripts/postinstall.js +44 -0
  13. package/shared_config.json +24 -0
  14. package/src/README.md +1525 -0
  15. package/src/tests/run_zexus_tests.py +117 -0
  16. package/src/tests/test_all_phases.zx +346 -0
  17. package/src/tests/test_blockchain_features.zx +306 -0
  18. package/src/tests/test_complexity_features.zx +321 -0
  19. package/src/tests/test_core_integration.py +185 -0
  20. package/src/tests/test_phase10_ecosystem.zx +177 -0
  21. package/src/tests/test_phase1_modifiers.zx +87 -0
  22. package/src/tests/test_phase2_plugins.zx +80 -0
  23. package/src/tests/test_phase3_security.zx +97 -0
  24. package/src/tests/test_phase4_vfs.zx +116 -0
  25. package/src/tests/test_phase5_types.zx +117 -0
  26. package/src/tests/test_phase6_metaprogramming.zx +125 -0
  27. package/src/tests/test_phase7_optimization.zx +132 -0
  28. package/src/tests/test_phase9_advanced_types.zx +157 -0
  29. package/src/tests/test_security_features.py +419 -0
  30. package/src/tests/test_security_features.zx +276 -0
  31. package/src/tests/test_simple_zx.zx +1 -0
  32. package/src/tests/test_verification_simple.zx +69 -0
  33. package/src/zexus/__init__.py +28 -0
  34. package/src/zexus/__main__.py +5 -0
  35. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  36. package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
  37. package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
  38. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  39. package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
  40. package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
  41. package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
  42. package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
  43. package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
  44. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  45. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  46. package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
  47. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  48. package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
  49. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  50. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  51. package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
  52. package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
  53. package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
  54. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  55. package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
  56. package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
  57. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  58. package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
  59. package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
  60. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  61. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  62. package/src/zexus/advanced_types.py +401 -0
  63. package/src/zexus/blockchain/__init__.py +40 -0
  64. package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
  65. package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
  66. package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
  67. package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
  68. package/src/zexus/blockchain/crypto.py +463 -0
  69. package/src/zexus/blockchain/ledger.py +255 -0
  70. package/src/zexus/blockchain/transaction.py +267 -0
  71. package/src/zexus/builtin_modules.py +284 -0
  72. package/src/zexus/builtin_plugins.py +317 -0
  73. package/src/zexus/capability_system.py +372 -0
  74. package/src/zexus/cli/__init__.py +2 -0
  75. package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  76. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  77. package/src/zexus/cli/main.py +707 -0
  78. package/src/zexus/cli/zpm.py +203 -0
  79. package/src/zexus/compare_interpreter_compiler.py +146 -0
  80. package/src/zexus/compiler/__init__.py +169 -0
  81. package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  83. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  84. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  85. package/src/zexus/compiler/bytecode.py +266 -0
  86. package/src/zexus/compiler/compat_runtime.py +277 -0
  87. package/src/zexus/compiler/lexer.py +257 -0
  88. package/src/zexus/compiler/parser.py +779 -0
  89. package/src/zexus/compiler/semantic.py +118 -0
  90. package/src/zexus/compiler/zexus_ast.py +454 -0
  91. package/src/zexus/complexity_system.py +575 -0
  92. package/src/zexus/concurrency_system.py +493 -0
  93. package/src/zexus/config.py +201 -0
  94. package/src/zexus/crypto_bridge.py +19 -0
  95. package/src/zexus/dependency_injection.py +423 -0
  96. package/src/zexus/ecosystem.py +434 -0
  97. package/src/zexus/environment.py +101 -0
  98. package/src/zexus/environment_manager.py +119 -0
  99. package/src/zexus/error_reporter.py +314 -0
  100. package/src/zexus/evaluator/__init__.py +12 -0
  101. package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  103. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  104. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  105. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  106. package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
  107. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  108. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  109. package/src/zexus/evaluator/bytecode_compiler.py +700 -0
  110. package/src/zexus/evaluator/core.py +891 -0
  111. package/src/zexus/evaluator/expressions.py +827 -0
  112. package/src/zexus/evaluator/functions.py +3989 -0
  113. package/src/zexus/evaluator/integration.py +396 -0
  114. package/src/zexus/evaluator/statements.py +4303 -0
  115. package/src/zexus/evaluator/utils.py +126 -0
  116. package/src/zexus/evaluator_original.py +2041 -0
  117. package/src/zexus/external_bridge.py +16 -0
  118. package/src/zexus/find_affected_imports.sh +155 -0
  119. package/src/zexus/hybrid_orchestrator.py +152 -0
  120. package/src/zexus/input_validation.py +259 -0
  121. package/src/zexus/lexer.py +571 -0
  122. package/src/zexus/logging.py +89 -0
  123. package/src/zexus/lsp/__init__.py +9 -0
  124. package/src/zexus/lsp/completion_provider.py +207 -0
  125. package/src/zexus/lsp/definition_provider.py +22 -0
  126. package/src/zexus/lsp/hover_provider.py +71 -0
  127. package/src/zexus/lsp/server.py +269 -0
  128. package/src/zexus/lsp/symbol_provider.py +31 -0
  129. package/src/zexus/metaprogramming.py +321 -0
  130. package/src/zexus/module_cache.py +89 -0
  131. package/src/zexus/module_manager.py +107 -0
  132. package/src/zexus/object.py +973 -0
  133. package/src/zexus/optimization.py +424 -0
  134. package/src/zexus/parser/__init__.py +31 -0
  135. package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
  136. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  137. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  138. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  139. package/src/zexus/parser/integration.py +86 -0
  140. package/src/zexus/parser/parser.py +3977 -0
  141. package/src/zexus/parser/strategy_context.py +7254 -0
  142. package/src/zexus/parser/strategy_structural.py +1033 -0
  143. package/src/zexus/persistence.py +391 -0
  144. package/src/zexus/plugin_system.py +290 -0
  145. package/src/zexus/policy_engine.py +365 -0
  146. package/src/zexus/profiler/__init__.py +5 -0
  147. package/src/zexus/profiler/profiler.py +233 -0
  148. package/src/zexus/purity_system.py +398 -0
  149. package/src/zexus/runtime/__init__.py +20 -0
  150. package/src/zexus/runtime/async_runtime.py +324 -0
  151. package/src/zexus/search_old_imports.sh +65 -0
  152. package/src/zexus/security.py +1407 -0
  153. package/src/zexus/stack_trace.py +233 -0
  154. package/src/zexus/stdlib/__init__.py +27 -0
  155. package/src/zexus/stdlib/blockchain.py +341 -0
  156. package/src/zexus/stdlib/compression.py +167 -0
  157. package/src/zexus/stdlib/crypto.py +124 -0
  158. package/src/zexus/stdlib/datetime.py +163 -0
  159. package/src/zexus/stdlib/db_mongo.py +199 -0
  160. package/src/zexus/stdlib/db_mysql.py +162 -0
  161. package/src/zexus/stdlib/db_postgres.py +163 -0
  162. package/src/zexus/stdlib/db_sqlite.py +133 -0
  163. package/src/zexus/stdlib/encoding.py +230 -0
  164. package/src/zexus/stdlib/fs.py +195 -0
  165. package/src/zexus/stdlib/http.py +219 -0
  166. package/src/zexus/stdlib/http_server.py +248 -0
  167. package/src/zexus/stdlib/json_module.py +61 -0
  168. package/src/zexus/stdlib/math.py +360 -0
  169. package/src/zexus/stdlib/os_module.py +265 -0
  170. package/src/zexus/stdlib/regex.py +148 -0
  171. package/src/zexus/stdlib/sockets.py +253 -0
  172. package/src/zexus/stdlib/test_framework.zx +208 -0
  173. package/src/zexus/stdlib/test_runner.zx +119 -0
  174. package/src/zexus/stdlib_integration.py +341 -0
  175. package/src/zexus/strategy_recovery.py +256 -0
  176. package/src/zexus/syntax_validator.py +356 -0
  177. package/src/zexus/testing/zpics.py +407 -0
  178. package/src/zexus/testing/zpics_runtime.py +369 -0
  179. package/src/zexus/type_system.py +374 -0
  180. package/src/zexus/validation_system.py +569 -0
  181. package/src/zexus/virtual_filesystem.py +355 -0
  182. package/src/zexus/vm/__init__.py +8 -0
  183. package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
  184. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  185. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  186. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  187. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  188. package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
  189. package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
  190. package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
  191. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  192. package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
  193. package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
  194. package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
  195. package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
  196. package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
  197. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  198. package/src/zexus/vm/async_optimizer.py +420 -0
  199. package/src/zexus/vm/bytecode.py +428 -0
  200. package/src/zexus/vm/bytecode_converter.py +297 -0
  201. package/src/zexus/vm/cache.py +532 -0
  202. package/src/zexus/vm/jit.py +720 -0
  203. package/src/zexus/vm/memory_manager.py +520 -0
  204. package/src/zexus/vm/memory_pool.py +511 -0
  205. package/src/zexus/vm/optimizer.py +478 -0
  206. package/src/zexus/vm/parallel_vm.py +899 -0
  207. package/src/zexus/vm/peephole_optimizer.py +452 -0
  208. package/src/zexus/vm/profiler.py +527 -0
  209. package/src/zexus/vm/register_allocator.py +462 -0
  210. package/src/zexus/vm/register_vm.py +520 -0
  211. package/src/zexus/vm/ssa_converter.py +757 -0
  212. package/src/zexus/vm/vm.py +1392 -0
  213. package/src/zexus/zexus_ast.py +1782 -0
  214. package/src/zexus/zexus_token.py +253 -0
  215. package/src/zexus/zpm/__init__.py +15 -0
  216. package/src/zexus/zpm/installer.py +116 -0
  217. package/src/zexus/zpm/package_manager.py +208 -0
  218. package/src/zexus/zpm/publisher.py +98 -0
  219. package/src/zexus/zpm/registry.py +110 -0
  220. package/src/zexus.egg-info/PKG-INFO +2235 -0
  221. package/src/zexus.egg-info/SOURCES.txt +876 -0
  222. package/src/zexus.egg-info/dependency_links.txt +1 -0
  223. package/src/zexus.egg-info/entry_points.txt +3 -0
  224. package/src/zexus.egg-info/not-zip-safe +1 -0
  225. package/src/zexus.egg-info/requires.txt +14 -0
  226. package/src/zexus.egg-info/top_level.txt +2 -0
  227. package/zexus.json +14 -0
@@ -0,0 +1,391 @@
1
+ # src/zexus/persistence.py
2
+ """
3
+ Persistent Memory Management for Zexus
4
+ Extends persistent storage beyond contracts to all storage keywords (LET, CONST, ENTITY, etc.)
5
+ """
6
+
7
+ import os
8
+ import json
9
+ import sqlite3
10
+ import weakref
11
+ from threading import Lock
12
+ from typing import Dict, Any, Optional, Set
13
+ from .object import (
14
+ Object, Integer, Float, String, Boolean as BooleanObj,
15
+ Null, NULL, List, Map, EntityInstance
16
+ )
17
+
18
+ # Storage directory for persistent data
19
+ PERSISTENCE_DIR = os.path.expanduser("~/.zexus/persistence")
20
+ os.makedirs(PERSISTENCE_DIR, exist_ok=True)
21
+
22
+
23
+ # ===============================================
24
+ # MEMORY LEAK TRACKING
25
+ # ===============================================
26
+
27
+ class MemoryTracker:
28
+ """Track object allocations and detect potential memory leaks"""
29
+
30
+ def __init__(self):
31
+ self.allocations: Dict[int, Dict[str, Any]] = {}
32
+ self.weak_refs: Dict[int, weakref.ref] = {}
33
+ self.lock = Lock()
34
+ self.enabled = True
35
+ self.allocation_count = 0
36
+ self.max_allocations = 100000 # Alert threshold
37
+
38
+ def track(self, obj: Object, context: str = "unknown"):
39
+ """Track an object allocation"""
40
+ if not self.enabled:
41
+ return
42
+
43
+ with self.lock:
44
+ obj_id = id(obj)
45
+ self.allocation_count += 1
46
+
47
+ # Create weak reference to detect when object is garbage collected
48
+ def cleanup(ref):
49
+ with self.lock:
50
+ if obj_id in self.allocations:
51
+ del self.allocations[obj_id]
52
+ if obj_id in self.weak_refs:
53
+ del self.weak_refs[obj_id]
54
+
55
+ self.weak_refs[obj_id] = weakref.ref(obj, cleanup)
56
+ self.allocations[obj_id] = {
57
+ 'type': obj.type() if hasattr(obj, 'type') else type(obj).__name__,
58
+ 'context': context,
59
+ 'allocation_number': self.allocation_count
60
+ }
61
+
62
+ # Check for potential memory leak
63
+ if len(self.allocations) > self.max_allocations:
64
+ self._report_potential_leak()
65
+
66
+ def untrack(self, obj: Object):
67
+ """Manually untrack an object"""
68
+ with self.lock:
69
+ obj_id = id(obj)
70
+ if obj_id in self.allocations:
71
+ del self.allocations[obj_id]
72
+ if obj_id in self.weak_refs:
73
+ del self.weak_refs[obj_id]
74
+
75
+ def get_stats(self) -> Dict[str, Any]:
76
+ """Get memory usage statistics"""
77
+ with self.lock:
78
+ type_counts = {}
79
+ for alloc in self.allocations.values():
80
+ obj_type = alloc['type']
81
+ type_counts[obj_type] = type_counts.get(obj_type, 0) + 1
82
+
83
+ return {
84
+ 'total_tracked': len(self.allocations),
85
+ 'total_allocated': self.allocation_count,
86
+ 'by_type': type_counts
87
+ }
88
+
89
+ def _report_potential_leak(self):
90
+ """Report potential memory leak"""
91
+ stats = self.get_stats()
92
+ print(f"⚠️ MEMORY WARNING: {stats['total_tracked']} objects tracked (threshold: {self.max_allocations})")
93
+ print(f" Breakdown: {stats['by_type']}")
94
+
95
+ def clear(self):
96
+ """Clear all tracking data"""
97
+ with self.lock:
98
+ self.allocations.clear()
99
+ self.weak_refs.clear()
100
+ self.allocation_count = 0
101
+
102
+
103
+ # Global memory tracker instance
104
+ _memory_tracker = MemoryTracker()
105
+
106
+
107
+ def track_allocation(obj: Object, context: str = "unknown"):
108
+ """Track an object allocation"""
109
+ _memory_tracker.track(obj, context)
110
+
111
+
112
+ def get_memory_stats() -> Dict[str, Any]:
113
+ """Get current memory statistics"""
114
+ return _memory_tracker.get_stats()
115
+
116
+
117
+ def enable_memory_tracking():
118
+ """Enable memory tracking"""
119
+ _memory_tracker.enabled = True
120
+
121
+
122
+ def disable_memory_tracking():
123
+ """Disable memory tracking"""
124
+ _memory_tracker.enabled = False
125
+
126
+
127
+ # ===============================================
128
+ # PERSISTENT STORAGE BACKEND
129
+ # ===============================================
130
+
131
+ class PersistentStorage:
132
+ """Persistent storage for variables using SQLite"""
133
+
134
+ def __init__(self, scope_id: str, storage_dir: str = PERSISTENCE_DIR):
135
+ self.scope_id = scope_id
136
+ self.db_path = os.path.join(storage_dir, f"{scope_id}.sqlite")
137
+ self.conn = None
138
+ self.lock = Lock()
139
+ self._init_db()
140
+
141
+ def _init_db(self):
142
+ """Initialize SQLite database"""
143
+ self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
144
+ cursor = self.conn.cursor()
145
+ cursor.execute('''
146
+ CREATE TABLE IF NOT EXISTS variables (
147
+ name TEXT PRIMARY KEY,
148
+ type TEXT NOT NULL,
149
+ value TEXT NOT NULL,
150
+ is_const INTEGER DEFAULT 0,
151
+ created_at REAL NOT NULL,
152
+ updated_at REAL NOT NULL
153
+ )
154
+ ''')
155
+ cursor.execute('''
156
+ CREATE INDEX IF NOT EXISTS idx_name ON variables(name)
157
+ ''')
158
+ self.conn.commit()
159
+
160
+ def set(self, name: str, value: Object, is_const: bool = False):
161
+ """Persist a variable"""
162
+ with self.lock:
163
+ serialized = self._serialize(value)
164
+ cursor = self.conn.cursor()
165
+
166
+ import time
167
+ timestamp = time.time()
168
+
169
+ cursor.execute('''
170
+ INSERT OR REPLACE INTO variables (name, type, value, is_const, created_at, updated_at)
171
+ VALUES (?, ?, ?, ?,
172
+ COALESCE((SELECT created_at FROM variables WHERE name = ?), ?),
173
+ ?)
174
+ ''', (name, serialized['type'], serialized['value'], 1 if is_const else 0,
175
+ name, timestamp, timestamp))
176
+
177
+ self.conn.commit()
178
+
179
+ def get(self, name: str) -> Optional[Object]:
180
+ """Retrieve a persisted variable"""
181
+ with self.lock:
182
+ cursor = self.conn.cursor()
183
+ cursor.execute('SELECT type, value FROM variables WHERE name = ?', (name,))
184
+ row = cursor.fetchone()
185
+
186
+ if row is None:
187
+ return None
188
+
189
+ return self._deserialize({'type': row[0], 'value': row[1]})
190
+
191
+ def delete(self, name: str):
192
+ """Delete a persisted variable"""
193
+ with self.lock:
194
+ cursor = self.conn.cursor()
195
+ cursor.execute('DELETE FROM variables WHERE name = ?', (name,))
196
+ self.conn.commit()
197
+
198
+ def is_const(self, name: str) -> bool:
199
+ """Check if a variable is const"""
200
+ with self.lock:
201
+ cursor = self.conn.cursor()
202
+ cursor.execute('SELECT is_const FROM variables WHERE name = ?', (name,))
203
+ row = cursor.fetchone()
204
+ return bool(row[0]) if row else False
205
+
206
+ def list_variables(self) -> list:
207
+ """List all persisted variables"""
208
+ with self.lock:
209
+ cursor = self.conn.cursor()
210
+ cursor.execute('SELECT name, type, is_const FROM variables')
211
+ return [{'name': row[0], 'type': row[1], 'const': bool(row[2])} for row in cursor.fetchall()]
212
+
213
+ def clear(self):
214
+ """Clear all persisted variables"""
215
+ with self.lock:
216
+ cursor = self.conn.cursor()
217
+ cursor.execute('DELETE FROM variables')
218
+ self.conn.commit()
219
+
220
+ def _serialize(self, obj: Object) -> Dict[str, str]:
221
+ """Serialize Zexus object to JSON"""
222
+ if isinstance(obj, String):
223
+ return {'type': 'string', 'value': json.dumps(obj.value)}
224
+ elif isinstance(obj, Integer):
225
+ return {'type': 'integer', 'value': json.dumps(obj.value)}
226
+ elif isinstance(obj, Float):
227
+ return {'type': 'float', 'value': json.dumps(obj.value)}
228
+ elif isinstance(obj, BooleanObj):
229
+ return {'type': 'boolean', 'value': json.dumps(obj.value)}
230
+ elif isinstance(obj, List):
231
+ serialized = [self._serialize(e) for e in obj.elements]
232
+ return {'type': 'list', 'value': json.dumps(serialized)}
233
+ elif isinstance(obj, Map):
234
+ serialized = {k: self._serialize(v) for k, v in obj.pairs.items()}
235
+ return {'type': 'map', 'value': json.dumps(serialized)}
236
+ elif obj is Null or obj is NULL:
237
+ return {'type': 'null', 'value': json.dumps(None)}
238
+ elif isinstance(obj, EntityInstance):
239
+ serialized_values = {k: self._serialize(v) for k, v in obj.values.items()}
240
+ return {
241
+ 'type': 'entity_instance',
242
+ 'value': json.dumps({
243
+ 'entity_name': obj.entity_def.name,
244
+ 'values': serialized_values
245
+ })
246
+ }
247
+ else:
248
+ # Fallback: convert to string
249
+ return {'type': 'string', 'value': json.dumps(str(obj.inspect() if hasattr(obj, 'inspect') else obj))}
250
+
251
+ def _deserialize(self, data: Dict[str, str]) -> Object:
252
+ """Deserialize JSON to Zexus object"""
253
+ obj_type = data['type']
254
+ value = json.loads(data['value'])
255
+
256
+ if obj_type == 'string':
257
+ return String(value)
258
+ elif obj_type == 'integer':
259
+ return Integer(value)
260
+ elif obj_type == 'float':
261
+ return Float(value)
262
+ elif obj_type == 'boolean':
263
+ return BooleanObj(value)
264
+ elif obj_type == 'null':
265
+ return NULL
266
+ elif obj_type == 'list':
267
+ elements = [self._deserialize(e) for e in value]
268
+ return List(elements)
269
+ elif obj_type == 'map':
270
+ pairs = {k: self._deserialize(v) for k, v in value.items()}
271
+ return Map(pairs)
272
+ elif obj_type == 'entity_instance':
273
+ # Note: This creates a basic EntityInstance without full EntityDefinition
274
+ # For production, you'd need to store/restore the entity definition
275
+ from .object import EntityDefinition
276
+ entity_name = value['entity_name']
277
+ serialized_values = value['values']
278
+ deserialized_values = {k: self._deserialize(v) for k, v in serialized_values.items()}
279
+
280
+ # Create minimal entity definition
281
+ entity_def = EntityDefinition(entity_name, [])
282
+ return EntityInstance(entity_def, deserialized_values)
283
+ else:
284
+ return String(str(value))
285
+
286
+ def close(self):
287
+ """Close database connection"""
288
+ if self.conn:
289
+ self.conn.close()
290
+
291
+
292
+ # ===============================================
293
+ # PERSISTENT ENVIRONMENT MIXIN
294
+ # ===============================================
295
+
296
+ class PersistentEnvironmentMixin:
297
+ """Mixin to add persistence to Environment class"""
298
+
299
+ def __init__(self, *args, persistence_scope: Optional[str] = None, enable_persistence: bool = False, **kwargs):
300
+ super().__init__(*args, **kwargs)
301
+ self.persistence_enabled = enable_persistence
302
+ self.persistence_scope = persistence_scope
303
+ self.persistent_storage = None
304
+ self.persisted_vars: Set[str] = set() # Track which vars are persisted
305
+
306
+ if enable_persistence and persistence_scope:
307
+ self.persistent_storage = PersistentStorage(persistence_scope)
308
+ self._load_persisted_vars()
309
+
310
+ def _load_persisted_vars(self):
311
+ """Load persisted variables into environment"""
312
+ if not self.persistent_storage:
313
+ return
314
+
315
+ for var_info in self.persistent_storage.list_variables():
316
+ name = var_info['name']
317
+ value = self.persistent_storage.get(name)
318
+ if value is not None:
319
+ self.store[name] = value
320
+ self.persisted_vars.add(name)
321
+ if var_info['const']:
322
+ self.const_vars.add(name)
323
+
324
+ def set_persistent(self, name: str, val: Object, is_const: bool = False):
325
+ """Set a variable with persistence"""
326
+ # Set in memory
327
+ if is_const:
328
+ self.set_const(name, val)
329
+ else:
330
+ self.set(name, val)
331
+
332
+ # Persist to storage
333
+ if self.persistence_enabled and self.persistent_storage:
334
+ self.persistent_storage.set(name, val, is_const)
335
+ self.persisted_vars.add(name)
336
+ track_allocation(val, f"persistent:{name}")
337
+
338
+ return val
339
+
340
+ def get_persistent(self, name: str) -> Optional[Object]:
341
+ """Get a variable, checking persistence if not in memory"""
342
+ # Check memory first
343
+ val = self.get(name)
344
+ if val is not None:
345
+ return val
346
+
347
+ # Check persistent storage
348
+ if self.persistence_enabled and self.persistent_storage:
349
+ val = self.persistent_storage.get(name)
350
+ if val is not None:
351
+ self.store[name] = val
352
+ self.persisted_vars.add(name)
353
+ return val
354
+
355
+ return None
356
+
357
+ def clear_persistence(self):
358
+ """Clear all persisted variables"""
359
+ if self.persistent_storage:
360
+ self.persistent_storage.clear()
361
+ self.persisted_vars.clear()
362
+
363
+
364
+ # ===============================================
365
+ # UTILITY FUNCTIONS
366
+ # ===============================================
367
+
368
+ def create_persistent_scope(scope_name: str) -> PersistentStorage:
369
+ """Create a new persistent storage scope"""
370
+ return PersistentStorage(scope_name)
371
+
372
+
373
+ def list_persistent_scopes() -> list:
374
+ """List all persistent storage scopes"""
375
+ if not os.path.exists(PERSISTENCE_DIR):
376
+ return []
377
+
378
+ scopes = []
379
+ for filename in os.listdir(PERSISTENCE_DIR):
380
+ if filename.endswith('.sqlite'):
381
+ scope_name = filename[:-7] # Remove .sqlite extension
382
+ scopes.append(scope_name)
383
+
384
+ return scopes
385
+
386
+
387
+ def delete_persistent_scope(scope_name: str):
388
+ """Delete a persistent storage scope"""
389
+ db_path = os.path.join(PERSISTENCE_DIR, f"{scope_name}.sqlite")
390
+ if os.path.exists(db_path):
391
+ os.remove(db_path)
@@ -0,0 +1,290 @@
1
+ """
2
+ Plugin system for Zexus interpreter.
3
+
4
+ Enables third-party extensions through hooks and capability declarations.
5
+ Plugins are self-contained modules that extend the language without
6
+ modifying core functionality.
7
+ """
8
+
9
+ from typing import Dict, List, Callable, Any, Optional, Set
10
+ from dataclasses import dataclass, field
11
+ from collections import defaultdict
12
+ import os
13
+ import sys
14
+
15
+
16
+ @dataclass
17
+ class PluginMetadata:
18
+ """Metadata for a plugin."""
19
+ name: str
20
+ version: str
21
+ author: str = ""
22
+ description: str = ""
23
+ requires: List[str] = field(default_factory=list) # Capabilities required
24
+ provides: List[str] = field(default_factory=list) # Capabilities provided
25
+ hooks: List[str] = field(default_factory=list) # Hook names registered
26
+ config: Dict[str, Any] = field(default_factory=dict) # Configuration schema
27
+
28
+ @classmethod
29
+ def from_dict(cls, data: dict) -> 'PluginMetadata':
30
+ """Create metadata from dictionary."""
31
+ return cls(
32
+ name=data.get('name', ''),
33
+ version=data.get('version', '1.0.0'),
34
+ author=data.get('author', ''),
35
+ description=data.get('description', ''),
36
+ requires=data.get('requires', []),
37
+ provides=data.get('provides', []),
38
+ hooks=data.get('hooks', []),
39
+ config=data.get('config', {})
40
+ )
41
+
42
+
43
+ @dataclass
44
+ class Hook:
45
+ """A registered hook handler."""
46
+ name: str
47
+ handler: Callable
48
+ plugin_name: str
49
+ priority: int = 0 # Higher priority executes first
50
+
51
+
52
+ class PluginManager:
53
+ """
54
+ Manages plugin loading, registration, and execution.
55
+
56
+ Handles:
57
+ - Plugin discovery and loading
58
+ - Hook registration and execution
59
+ - Capability tracking and validation
60
+ - Dependency resolution
61
+ - Sandbox enforcement
62
+ """
63
+
64
+ def __init__(self):
65
+ """Initialize the plugin manager."""
66
+ self.loaded_plugins: Dict[str, PluginMetadata] = {}
67
+ self.hooks: Dict[str, List[Hook]] = defaultdict(list)
68
+ self.capabilities: Set[str] = set()
69
+ self.plugin_modules: Dict[str, Any] = {} # Loaded plugin modules
70
+ self.config: Dict[str, Dict[str, Any]] = {} # Per-plugin config
71
+
72
+ # Builtin capabilities always available
73
+ self.capabilities.add("core")
74
+
75
+ def load_plugin(self, module_path: str, config: Optional[Dict[str, Any]] = None) -> PluginMetadata:
76
+ """
77
+ Load a plugin from a module path.
78
+
79
+ Args:
80
+ module_path: Path to plugin module (.zx file or directory)
81
+ config: Configuration dictionary for the plugin
82
+
83
+ Returns:
84
+ PluginMetadata object
85
+
86
+ Raises:
87
+ FileNotFoundError: If plugin module not found
88
+ ValueError: If plugin metadata invalid or dependencies unmet
89
+ """
90
+ if not os.path.exists(module_path):
91
+ raise FileNotFoundError(f"Plugin module not found: {module_path}")
92
+
93
+ # Note: Actual implementation will parse .zx module
94
+ # For now, this is the interface
95
+ metadata = PluginMetadata(
96
+ name="placeholder",
97
+ version="1.0.0"
98
+ )
99
+
100
+ # Validate dependencies
101
+ for required_cap in metadata.requires:
102
+ if required_cap not in self.capabilities:
103
+ raise ValueError(f"Plugin {metadata.name} requires unavailable capability: {required_cap}")
104
+
105
+ # Store metadata and config
106
+ self.loaded_plugins[metadata.name] = metadata
107
+ if config:
108
+ self.config[metadata.name] = config
109
+
110
+ # Add provided capabilities
111
+ for cap in metadata.provides:
112
+ self.capabilities.add(cap)
113
+
114
+ return metadata
115
+
116
+ def register_hook(self, hook_name: str, handler: Callable,
117
+ plugin_name: str, priority: int = 0) -> None:
118
+ """
119
+ Register a hook handler.
120
+
121
+ Args:
122
+ hook_name: Name of the hook (e.g., "pre_eval", "import_resolver")
123
+ handler: Callable that handles the hook
124
+ plugin_name: Name of plugin registering the hook
125
+ priority: Execution priority (higher = earlier)
126
+ """
127
+ hook = Hook(name=hook_name, handler=handler, plugin_name=plugin_name, priority=priority)
128
+ self.hooks[hook_name].append(hook)
129
+
130
+ # Sort by priority (descending)
131
+ self.hooks[hook_name].sort(key=lambda h: h.priority, reverse=True)
132
+
133
+ def call_hooks(self, hook_name: str, *args, **kwargs) -> Any:
134
+ """
135
+ Call all registered handlers for a hook.
136
+
137
+ Handlers are called in priority order (highest first).
138
+ If a handler returns non-None, stop and return that value.
139
+ Otherwise, return the first argument (usually the transformed input).
140
+
141
+ Args:
142
+ hook_name: Name of the hook to call
143
+ *args: Arguments to pass to handlers
144
+ **kwargs: Keyword arguments to pass to handlers
145
+
146
+ Returns:
147
+ Result from first non-None handler return, or first argument
148
+ """
149
+ if hook_name not in self.hooks:
150
+ # No handlers registered, return first arg unchanged
151
+ return args[0] if args else None
152
+
153
+ result = args[0] if args else None
154
+
155
+ for hook in self.hooks[hook_name]:
156
+ try:
157
+ # Call handler with arguments
158
+ handler_result = hook.handler(*args, **kwargs)
159
+ if handler_result is not None:
160
+ # Handler returned a value, update result
161
+ result = handler_result
162
+ # Update args[0] for next handler
163
+ if args:
164
+ args = (result,) + args[1:]
165
+ except Exception as e:
166
+ # Log hook error but continue
167
+ print(f"Error in hook {hook_name} from {hook.plugin_name}: {e}",
168
+ file=sys.stderr)
169
+
170
+ return result
171
+
172
+ def check_capability(self, capability: str) -> bool:
173
+ """
174
+ Check if a capability is available.
175
+
176
+ Args:
177
+ capability: Capability name to check
178
+
179
+ Returns:
180
+ True if capability is available, False otherwise
181
+ """
182
+ return capability in self.capabilities
183
+
184
+ def grant_capability(self, capability: str) -> None:
185
+ """
186
+ Manually grant a capability.
187
+
188
+ Args:
189
+ capability: Capability name to grant
190
+ """
191
+ self.capabilities.add(capability)
192
+
193
+ def has_plugin(self, plugin_name: str) -> bool:
194
+ """Check if a plugin is loaded."""
195
+ return plugin_name in self.loaded_plugins
196
+
197
+ def get_plugin_metadata(self, plugin_name: str) -> Optional[PluginMetadata]:
198
+ """Get metadata for a loaded plugin."""
199
+ return self.loaded_plugins.get(plugin_name)
200
+
201
+ def get_capabilities(self) -> List[str]:
202
+ """Get list of available capabilities."""
203
+ return sorted(list(self.capabilities))
204
+
205
+ def get_loaded_plugins(self) -> List[str]:
206
+ """Get list of loaded plugin names."""
207
+ return sorted(list(self.loaded_plugins.keys()))
208
+
209
+ def get_hooks(self, hook_name: Optional[str] = None) -> Dict[str, List[str]]:
210
+ """
211
+ Get registered hooks.
212
+
213
+ Args:
214
+ hook_name: If specified, return handlers for specific hook
215
+
216
+ Returns:
217
+ Dict of hook_name -> [plugin_names] or filtered results
218
+ """
219
+ if hook_name:
220
+ return {hook_name: [h.plugin_name for h in self.hooks.get(hook_name, [])]}
221
+
222
+ result = {}
223
+ for name, hooks_list in self.hooks.items():
224
+ result[name] = [h.plugin_name for h in hooks_list]
225
+ return result
226
+
227
+
228
+ class PluginGlobalObject:
229
+ """
230
+ The `plugin` global object exposed to plugin code.
231
+
232
+ Provides interface for:
233
+ - Registering hooks
234
+ - Declaring capabilities
235
+ - Accessing metadata
236
+ - Introspection
237
+ """
238
+
239
+ def __init__(self, manager: PluginManager, current_plugin: str):
240
+ """
241
+ Initialize the plugin global.
242
+
243
+ Args:
244
+ manager: PluginManager instance
245
+ current_plugin: Name of the currently-executing plugin
246
+ """
247
+ self.manager = manager
248
+ self.current_plugin = current_plugin
249
+
250
+ def register_hook(self, hook_name: str, handler: Callable) -> None:
251
+ """Register a hook handler for the current plugin."""
252
+ self.manager.register_hook(hook_name, handler, self.current_plugin)
253
+
254
+ def grant_capability(self, capability: str) -> None:
255
+ """Declare that this plugin grants a capability."""
256
+ self.manager.grant_capability(capability)
257
+
258
+ def has_capability(self, capability: str) -> bool:
259
+ """Check if a capability is available."""
260
+ return self.manager.check_capability(capability)
261
+
262
+ def get_hooks(self) -> Dict[str, List[str]]:
263
+ """Get all registered hooks."""
264
+ return self.manager.get_hooks()
265
+
266
+ def get_capabilities(self) -> List[str]:
267
+ """Get all available capabilities."""
268
+ return self.manager.get_capabilities()
269
+
270
+ def get_loaded_plugins(self) -> List[str]:
271
+ """Get list of loaded plugins."""
272
+ return self.manager.get_loaded_plugins()
273
+
274
+ def metadata(self) -> PluginMetadata:
275
+ """Get metadata for current plugin."""
276
+ return self.manager.get_plugin_metadata(self.current_plugin)
277
+
278
+ def load(self, plugin_name: str, config: Optional[Dict[str, Any]] = None) -> bool:
279
+ """
280
+ Load another plugin by name.
281
+
282
+ Returns:
283
+ True if loaded, False if already loaded
284
+ """
285
+ if self.manager.has_plugin(plugin_name):
286
+ return False
287
+
288
+ # Would resolve plugin path and load
289
+ # Simplified for now
290
+ return True