zexus 1.6.8 → 1.7.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 (177) hide show
  1. package/README.md +12 -5
  2. package/package.json +1 -1
  3. package/src/__init__.py +7 -0
  4. package/src/zexus/__init__.py +1 -1
  5. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  6. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  7. package/src/zexus/__pycache__/debug_sanitizer.cpython-312.pyc +0 -0
  8. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  9. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  10. package/src/zexus/__pycache__/input_validation.cpython-312.pyc +0 -0
  11. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  12. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  13. package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
  14. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  15. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  16. package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
  17. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  18. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  19. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  20. package/src/zexus/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
  21. package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
  22. package/src/zexus/advanced_types.py +17 -2
  23. package/src/zexus/blockchain/__init__.py +411 -0
  24. package/src/zexus/blockchain/accelerator.py +1160 -0
  25. package/src/zexus/blockchain/chain.py +660 -0
  26. package/src/zexus/blockchain/consensus.py +821 -0
  27. package/src/zexus/blockchain/contract_vm.py +1019 -0
  28. package/src/zexus/blockchain/crypto.py +79 -14
  29. package/src/zexus/blockchain/events.py +526 -0
  30. package/src/zexus/blockchain/loadtest.py +721 -0
  31. package/src/zexus/blockchain/monitoring.py +350 -0
  32. package/src/zexus/blockchain/mpt.py +716 -0
  33. package/src/zexus/blockchain/multichain.py +951 -0
  34. package/src/zexus/blockchain/multiprocess_executor.py +338 -0
  35. package/src/zexus/blockchain/network.py +886 -0
  36. package/src/zexus/blockchain/node.py +666 -0
  37. package/src/zexus/blockchain/rpc.py +1203 -0
  38. package/src/zexus/blockchain/rust_bridge.py +421 -0
  39. package/src/zexus/blockchain/storage.py +423 -0
  40. package/src/zexus/blockchain/tokens.py +750 -0
  41. package/src/zexus/blockchain/upgradeable.py +1004 -0
  42. package/src/zexus/blockchain/verification.py +1602 -0
  43. package/src/zexus/blockchain/wallet.py +621 -0
  44. package/src/zexus/capability_system.py +184 -9
  45. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  46. package/src/zexus/cli/main.py +383 -34
  47. package/src/zexus/cli/zpm.py +1 -1
  48. package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
  49. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  50. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  51. package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
  52. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  53. package/src/zexus/compiler/bytecode.py +124 -7
  54. package/src/zexus/compiler/compat_runtime.py +6 -2
  55. package/src/zexus/compiler/lexer.py +16 -5
  56. package/src/zexus/compiler/parser.py +108 -7
  57. package/src/zexus/compiler/semantic.py +18 -19
  58. package/src/zexus/compiler/zexus_ast.py +26 -1
  59. package/src/zexus/concurrency_system.py +79 -0
  60. package/src/zexus/config.py +54 -0
  61. package/src/zexus/crypto_bridge.py +244 -8
  62. package/src/zexus/dap/__init__.py +10 -0
  63. package/src/zexus/dap/__main__.py +4 -0
  64. package/src/zexus/dap/dap_server.py +391 -0
  65. package/src/zexus/dap/debug_engine.py +298 -0
  66. package/src/zexus/environment.py +112 -9
  67. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  68. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  69. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  70. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  71. package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
  72. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  73. package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
  74. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  75. package/src/zexus/evaluator/bytecode_compiler.py +457 -37
  76. package/src/zexus/evaluator/core.py +644 -50
  77. package/src/zexus/evaluator/expressions.py +358 -62
  78. package/src/zexus/evaluator/functions.py +458 -20
  79. package/src/zexus/evaluator/resource_limiter.py +4 -4
  80. package/src/zexus/evaluator/statements.py +774 -122
  81. package/src/zexus/evaluator/unified_execution.py +573 -72
  82. package/src/zexus/evaluator/utils.py +14 -2
  83. package/src/zexus/evaluator_original.py +1 -1
  84. package/src/zexus/event_loop.py +186 -0
  85. package/src/zexus/lexer.py +742 -458
  86. package/src/zexus/lsp/__init__.py +1 -1
  87. package/src/zexus/lsp/definition_provider.py +163 -9
  88. package/src/zexus/lsp/server.py +22 -8
  89. package/src/zexus/lsp/symbol_provider.py +182 -9
  90. package/src/zexus/module_cache.py +239 -9
  91. package/src/zexus/module_manager.py +129 -1
  92. package/src/zexus/object.py +76 -6
  93. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  94. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  95. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  96. package/src/zexus/parser/parser.py +1349 -408
  97. package/src/zexus/parser/strategy_context.py +755 -58
  98. package/src/zexus/parser/strategy_structural.py +121 -21
  99. package/src/zexus/persistence.py +15 -1
  100. package/src/zexus/renderer/__init__.py +61 -0
  101. package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
  103. package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
  104. package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
  105. package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
  106. package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
  107. package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
  108. package/src/zexus/renderer/backend.py +261 -0
  109. package/src/zexus/renderer/canvas.py +78 -0
  110. package/src/zexus/renderer/color_system.py +201 -0
  111. package/src/zexus/renderer/graphics.py +31 -0
  112. package/src/zexus/renderer/layout.py +222 -0
  113. package/src/zexus/renderer/main_renderer.py +66 -0
  114. package/src/zexus/renderer/painter.py +30 -0
  115. package/src/zexus/renderer/tk_backend.py +208 -0
  116. package/src/zexus/renderer/web_backend.py +260 -0
  117. package/src/zexus/runtime/__init__.py +10 -2
  118. package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
  119. package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
  120. package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
  121. package/src/zexus/runtime/file_flags.py +137 -0
  122. package/src/zexus/runtime/load_manager.py +368 -0
  123. package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
  124. package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
  125. package/src/zexus/security.py +424 -34
  126. package/src/zexus/stdlib/fs.py +23 -18
  127. package/src/zexus/stdlib/http.py +289 -186
  128. package/src/zexus/stdlib/sockets.py +207 -163
  129. package/src/zexus/stdlib/websockets.py +282 -0
  130. package/src/zexus/stdlib_integration.py +369 -2
  131. package/src/zexus/strategy_recovery.py +6 -3
  132. package/src/zexus/type_checker.py +423 -0
  133. package/src/zexus/virtual_filesystem.py +189 -2
  134. package/src/zexus/vm/__init__.py +113 -3
  135. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  136. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  137. package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
  138. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  139. package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
  140. package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
  141. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  142. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  143. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  144. package/src/zexus/vm/async_optimizer.py +80 -6
  145. package/src/zexus/vm/binary_bytecode.py +659 -0
  146. package/src/zexus/vm/bytecode.py +59 -11
  147. package/src/zexus/vm/bytecode_converter.py +26 -12
  148. package/src/zexus/vm/cabi.c +1985 -0
  149. package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
  150. package/src/zexus/vm/cabi.h +127 -0
  151. package/src/zexus/vm/cache.py +561 -17
  152. package/src/zexus/vm/compiler.py +818 -51
  153. package/src/zexus/vm/fastops.c +15743 -0
  154. package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
  155. package/src/zexus/vm/fastops.pyx +288 -0
  156. package/src/zexus/vm/gas_metering.py +50 -9
  157. package/src/zexus/vm/jit.py +364 -20
  158. package/src/zexus/vm/native_jit_backend.py +1816 -0
  159. package/src/zexus/vm/native_runtime.cpp +1388 -0
  160. package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
  161. package/src/zexus/vm/optimizer.py +161 -11
  162. package/src/zexus/vm/parallel_vm.py +140 -45
  163. package/src/zexus/vm/peephole_optimizer.py +82 -4
  164. package/src/zexus/vm/profiler.py +38 -18
  165. package/src/zexus/vm/register_allocator.py +16 -5
  166. package/src/zexus/vm/register_vm.py +8 -5
  167. package/src/zexus/vm/vm.py +3581 -531
  168. package/src/zexus/vm/wasm_compiler.py +658 -0
  169. package/src/zexus/zexus_ast.py +137 -11
  170. package/src/zexus/zexus_token.py +16 -5
  171. package/src/zexus/zpm/installer.py +55 -15
  172. package/src/zexus/zpm/package_manager.py +1 -1
  173. package/src/zexus/zpm/registry.py +257 -28
  174. package/src/zexus.egg-info/PKG-INFO +16 -6
  175. package/src/zexus.egg-info/SOURCES.txt +129 -17
  176. package/src/zexus.egg-info/entry_points.txt +1 -0
  177. package/src/zexus.egg-info/requires.txt +4 -0
@@ -0,0 +1,208 @@
1
+ """
2
+ Tk GUI Backend for the Zexus Renderer.
3
+
4
+ Provides a real windowed GUI using Python's built-in ``tkinter``.
5
+ The backend translates the existing ``Screen`` / ``Canvas`` / ``Component``
6
+ model into Tk widgets.
7
+
8
+ Usage from Zexus::
9
+
10
+ @zexus gui_backend = "tk"
11
+
12
+ screen main {
13
+ title: "My App"
14
+ width: 400
15
+ height: 300
16
+ }
17
+
18
+ component greeting label {
19
+ text: "Hello from Zexus!"
20
+ x: 50
21
+ y: 30
22
+ }
23
+
24
+ add greeting to main
25
+ show main
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import threading
31
+ from typing import Any, Callable, Dict, List, Optional, Tuple
32
+
33
+ try:
34
+ import tkinter as tk
35
+ from tkinter import font as tkfont
36
+ TK_AVAILABLE = True
37
+ except ImportError:
38
+ TK_AVAILABLE = False
39
+
40
+ from .layout import Screen, ScreenComponent, ScreenRegistry, Button, Label, TextBox
41
+ from .canvas import Canvas, CanvasRegistry
42
+ from .color_system import RGBColor
43
+
44
+
45
+ def _rgb_hex(color: Optional[RGBColor]) -> str:
46
+ """Convert ``RGBColor`` to Tk hex string."""
47
+ if color is None:
48
+ return "#000000"
49
+ return f"#{color.r:02x}{color.g:02x}{color.b:02x}"
50
+
51
+
52
+ class TkBackend:
53
+ """Windowed GUI backend backed by tkinter.
54
+
55
+ The Tk event loop runs on a **dedicated thread** so the Zexus
56
+ evaluator thread isn't blocked.
57
+ """
58
+
59
+ def __init__(self, screen_registry: Optional[ScreenRegistry] = None,
60
+ canvas_registry: Optional[CanvasRegistry] = None) -> None:
61
+ if not TK_AVAILABLE:
62
+ raise RuntimeError(
63
+ "tkinter is not available. On Ubuntu: sudo apt install python3-tk"
64
+ )
65
+ self.screen_registry = screen_registry or ScreenRegistry()
66
+ self.canvas_registry = canvas_registry or CanvasRegistry()
67
+ self._root: Optional[tk.Tk] = None
68
+ self._windows: Dict[str, tk.Toplevel] = {}
69
+ self._tk_canvases: Dict[str, tk.Canvas] = {}
70
+ self._event_handlers: Dict[str, Callable] = {}
71
+ self._thread: Optional[threading.Thread] = None
72
+ self._ready = threading.Event()
73
+
74
+ # -- Lifecycle ---------------------------------------------------------
75
+
76
+ def start(self) -> None:
77
+ """Launch the Tk main loop on a background thread."""
78
+ if self._thread and self._thread.is_alive():
79
+ return
80
+ self._thread = threading.Thread(target=self._run_mainloop, daemon=True)
81
+ self._thread.start()
82
+ self._ready.wait(timeout=5)
83
+
84
+ def stop(self) -> None:
85
+ """Destroy all windows and shut down the Tk loop."""
86
+ if self._root:
87
+ self._root.after(0, self._root.destroy)
88
+
89
+ def _run_mainloop(self) -> None:
90
+ self._root = tk.Tk()
91
+ self._root.withdraw() # hide root window
92
+ self._ready.set()
93
+ self._root.mainloop()
94
+
95
+ # -- Screen rendering --------------------------------------------------
96
+
97
+ def show_screen(self, name: str) -> None:
98
+ """Render a registered ``Screen`` as a Tk window."""
99
+ screen = self.screen_registry.get_screen(name)
100
+ width = int(screen.get("width", 400))
101
+ height = int(screen.get("height", 300))
102
+ title = str(screen.get("title", name))
103
+ bg = str(screen.get("background", "#ffffff"))
104
+
105
+ def _create():
106
+ win = tk.Toplevel(self._root)
107
+ win.title(title)
108
+ win.geometry(f"{width}x{height}")
109
+ win.configure(bg=bg)
110
+ self._windows[name] = win
111
+
112
+ for child in screen.children:
113
+ self._render_component(win, child)
114
+
115
+ self._root.after(0, _create)
116
+
117
+ def close_screen(self, name: str) -> None:
118
+ win = self._windows.pop(name, None)
119
+ if win:
120
+ self._root.after(0, win.destroy)
121
+
122
+ # -- Component rendering -----------------------------------------------
123
+
124
+ def _render_component(self, parent: tk.Toplevel, comp: ScreenComponent) -> None:
125
+ x = int(comp.get("x", 10))
126
+ y = int(comp.get("y", 10))
127
+ fg = str(comp.get("color", "black"))
128
+ text = str(comp.get("text", comp.name))
129
+
130
+ if isinstance(comp, Button):
131
+ handler = self._event_handlers.get(f"{comp.name}:click")
132
+ btn = tk.Button(parent, text=text, fg=fg,
133
+ command=handler if handler else lambda: None)
134
+ btn.place(x=x, y=y)
135
+
136
+ elif isinstance(comp, TextBox):
137
+ w = int(comp.get("width", 20))
138
+ entry = tk.Entry(parent, width=w, fg=fg)
139
+ entry.insert(0, text)
140
+ entry.place(x=x, y=y)
141
+
142
+ elif isinstance(comp, Label):
143
+ size = int(comp.get("fontSize", 12))
144
+ lbl = tk.Label(parent, text=text, fg=fg,
145
+ font=("TkDefaultFont", size))
146
+ lbl.place(x=x, y=y)
147
+
148
+ else:
149
+ # Generic component → label
150
+ lbl = tk.Label(parent, text=text)
151
+ lbl.place(x=x, y=y)
152
+
153
+ # -- Canvas rendering --------------------------------------------------
154
+
155
+ def show_canvas(self, canvas_id: str) -> None:
156
+ """Render a ``Canvas`` in a new Tk window."""
157
+ canvas = self.canvas_registry.get(canvas_id)
158
+
159
+ def _create():
160
+ win = tk.Toplevel(self._root)
161
+ win.title(f"Canvas: {canvas_id}")
162
+ tk_c = tk.Canvas(win, width=canvas.width * 4,
163
+ height=canvas.height * 4, bg="white")
164
+ tk_c.pack()
165
+ self._tk_canvases[canvas_id] = tk_c
166
+ self._draw_canvas(tk_c, canvas)
167
+
168
+ self._root.after(0, _create)
169
+
170
+ def _draw_canvas(self, tk_c: tk.Canvas, canvas: Canvas) -> None:
171
+ scale = 4
172
+ for op_type, args in canvas.operations:
173
+ if op_type == "line":
174
+ x1, y1, x2, y2 = args
175
+ tk_c.create_line(
176
+ x1 * scale, y1 * scale,
177
+ x2 * scale, y2 * scale,
178
+ fill="black", width=2,
179
+ )
180
+ elif op_type == "text":
181
+ x, y, text = args
182
+ tk_c.create_text(x * scale, y * scale, text=text, anchor="nw")
183
+
184
+ # -- Event binding -----------------------------------------------------
185
+
186
+ def on(self, component_name: str, event: str, handler: Callable) -> None:
187
+ """Register an event handler for a component.
188
+
189
+ Example: ``backend.on("my_button", "click", my_handler)``
190
+ """
191
+ self._event_handlers[f"{component_name}:{event}"] = handler
192
+
193
+ # -- Utility -----------------------------------------------------------
194
+
195
+ def wait(self) -> None:
196
+ """Block until the Tk loop terminates (all windows closed)."""
197
+ if self._thread:
198
+ self._thread.join()
199
+
200
+
201
+ # ---------------------------------------------------------------------------
202
+ # Public factory
203
+ # ---------------------------------------------------------------------------
204
+
205
+ def create_tk_backend(**kwargs) -> TkBackend:
206
+ backend = TkBackend(**kwargs)
207
+ backend.start()
208
+ return backend
@@ -0,0 +1,260 @@
1
+ """
2
+ Web GUI Backend for the Zexus Renderer.
3
+
4
+ Serves the rendered UI as HTML over a local HTTP server. The evaluator
5
+ creates screens/components normally and then calls ``show_screen()`` which
6
+ opens a browser tab to ``http://localhost:<port>/``.
7
+
8
+ The server uses only the Python standard library (``http.server`` +
9
+ ``json``). No Flask/Django/etc. dependency.
10
+
11
+ Usage from Zexus::
12
+
13
+ @zexus gui_backend = "web"
14
+
15
+ screen dashboard {
16
+ title: "Dashboard"
17
+ width: 600
18
+ height: 400
19
+ }
20
+
21
+ component counter label {
22
+ text: "Count: 0"
23
+ x: 20
24
+ y: 30
25
+ }
26
+
27
+ add counter to dashboard
28
+ show dashboard
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import json
34
+ import os
35
+ import socket
36
+ import threading
37
+ import webbrowser
38
+ from http.server import HTTPServer, BaseHTTPRequestHandler
39
+ from typing import Any, Dict, List, Optional
40
+
41
+ from .layout import Screen, ScreenComponent, ScreenRegistry, Button, Label, TextBox
42
+ from .canvas import Canvas, CanvasRegistry
43
+ from .color_system import RGBColor
44
+
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # HTML generation
48
+ # ---------------------------------------------------------------------------
49
+
50
+ _HTML_TEMPLATE = """\
51
+ <!DOCTYPE html>
52
+ <html lang="en">
53
+ <head>
54
+ <meta charset="UTF-8">
55
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
56
+ <title>{title}</title>
57
+ <style>
58
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
59
+ body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
60
+ background: {bg}; }}
61
+ .zx-screen {{ position: relative; width: {width}px; height: {height}px;
62
+ margin: 20px auto; border: 1px solid #ddd; border-radius: 8px;
63
+ background: {bg}; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,.12); }}
64
+ .zx-label {{ position: absolute; }}
65
+ .zx-button {{ position: absolute; padding: 6px 16px; border: 1px solid #888;
66
+ border-radius: 4px; cursor: pointer; background: #f4f4f4; }}
67
+ .zx-button:hover {{ background: #e0e0e0; }}
68
+ .zx-textbox {{ position: absolute; padding: 4px 8px; border: 1px solid #aaa;
69
+ border-radius: 3px; }}
70
+ .zx-canvas {{ position: relative; }}
71
+ </style>
72
+ </head>
73
+ <body>
74
+ <div class="zx-screen">
75
+ {components}
76
+ </div>
77
+ {canvas_section}
78
+ <script>
79
+ // Event relay — POST click events back to /event
80
+ document.querySelectorAll('.zx-button').forEach(btn => {{
81
+ btn.addEventListener('click', () => {{
82
+ fetch('/event', {{
83
+ method: 'POST',
84
+ headers: {{'Content-Type': 'application/json'}},
85
+ body: JSON.stringify({{component: btn.dataset.name, event: 'click'}})
86
+ }});
87
+ }});
88
+ }});
89
+ </script>
90
+ </body>
91
+ </html>
92
+ """
93
+
94
+
95
+ def _component_html(comp: ScreenComponent) -> str:
96
+ x = int(comp.get("x", 10))
97
+ y = int(comp.get("y", 10))
98
+ color = comp.get("color", "black")
99
+ text = comp.get("text", comp.name)
100
+
101
+ if isinstance(comp, Button):
102
+ return (f'<button class="zx-button" data-name="{comp.name}" '
103
+ f'style="left:{x}px;top:{y}px;color:{color}">{text}</button>')
104
+ if isinstance(comp, TextBox):
105
+ w = int(comp.get("width", 20))
106
+ return (f'<input class="zx-textbox" '
107
+ f'style="left:{x}px;top:{y}px;width:{w*8}px;color:{color}" '
108
+ f'value="{text}" />')
109
+ # Default: Label
110
+ size = int(comp.get("fontSize", 14))
111
+ return (f'<span class="zx-label" '
112
+ f'style="left:{x}px;top:{y}px;font-size:{size}px;color:{color}">{text}</span>')
113
+
114
+
115
+ def _canvas_svg(canvas: Canvas) -> str:
116
+ """Render a ``Canvas`` as an inline SVG element."""
117
+ scale = 4
118
+ w, h = canvas.width * scale, canvas.height * scale
119
+ lines: List[str] = [f'<svg class="zx-canvas" width="{w}" height="{h}" '
120
+ f'style="margin:20px auto;display:block;border:1px solid #ddd">']
121
+ for op_type, args in canvas.operations:
122
+ if op_type == "line":
123
+ x1, y1, x2, y2 = args
124
+ lines.append(f'<line x1="{x1*scale}" y1="{y1*scale}" '
125
+ f'x2="{x2*scale}" y2="{y2*scale}" stroke="black" stroke-width="2"/>')
126
+ elif op_type == "text":
127
+ x, y, text = args
128
+ lines.append(f'<text x="{x*scale}" y="{y*scale+12}">{text}</text>')
129
+ lines.append("</svg>")
130
+ return "\n".join(lines)
131
+
132
+
133
+ def build_html(screen: Screen, canvases: Optional[Dict[str, Canvas]] = None) -> str:
134
+ title = str(screen.get("title", screen.name))
135
+ width = int(screen.get("width", 600))
136
+ height = int(screen.get("height", 400))
137
+ bg = str(screen.get("background", "#ffffff"))
138
+
139
+ components = "\n".join(_component_html(c) for c in screen.children)
140
+ canvas_section = ""
141
+ if canvases:
142
+ canvas_section = "\n".join(_canvas_svg(c) for c in canvases.values())
143
+
144
+ return _HTML_TEMPLATE.format(
145
+ title=title, width=width, height=height, bg=bg,
146
+ components=components, canvas_section=canvas_section,
147
+ )
148
+
149
+
150
+ # ---------------------------------------------------------------------------
151
+ # HTTP server
152
+ # ---------------------------------------------------------------------------
153
+
154
+ class _Handler(BaseHTTPRequestHandler):
155
+ """Serves the screen HTML and accepts event POSTs."""
156
+
157
+ backend: "WebBackend" # set on class before server starts
158
+
159
+ def do_GET(self):
160
+ html = self.backend._current_html or "<h1>No screen loaded</h1>"
161
+ self.send_response(200)
162
+ self.send_header("Content-Type", "text/html; charset=utf-8")
163
+ self.end_headers()
164
+ self.wfile.write(html.encode())
165
+
166
+ def do_POST(self):
167
+ length = int(self.headers.get("Content-Length", 0))
168
+ body = self.rfile.read(length)
169
+ try:
170
+ data = json.loads(body)
171
+ comp_name = data.get("component", "")
172
+ event = data.get("event", "")
173
+ handler = self.backend._event_handlers.get(f"{comp_name}:{event}")
174
+ if handler:
175
+ handler()
176
+ except Exception:
177
+ pass
178
+ self.send_response(200)
179
+ self.send_header("Content-Type", "application/json")
180
+ self.end_headers()
181
+ self.wfile.write(b'{"ok":true}')
182
+
183
+ def log_message(self, format, *args):
184
+ pass # silence request logs
185
+
186
+
187
+ # ---------------------------------------------------------------------------
188
+ # WebBackend
189
+ # ---------------------------------------------------------------------------
190
+
191
+ class WebBackend:
192
+ """Serves Zexus UI as HTML on a local HTTP port."""
193
+
194
+ def __init__(self, screen_registry: Optional[ScreenRegistry] = None,
195
+ canvas_registry: Optional[CanvasRegistry] = None,
196
+ port: int = 0) -> None:
197
+ self.screen_registry = screen_registry or ScreenRegistry()
198
+ self.canvas_registry = canvas_registry or CanvasRegistry()
199
+ self._port = port
200
+ self._server: Optional[HTTPServer] = None
201
+ self._thread: Optional[threading.Thread] = None
202
+ self._current_html: Optional[str] = None
203
+ self._event_handlers: Dict[str, Any] = {}
204
+
205
+ @property
206
+ def url(self) -> str:
207
+ if self._server:
208
+ return f"http://localhost:{self._server.server_address[1]}"
209
+ return ""
210
+
211
+ # -- Lifecycle ---------------------------------------------------------
212
+
213
+ def start(self) -> None:
214
+ handler_cls = type("H", (_Handler,), {"backend": self})
215
+ self._server = HTTPServer(("127.0.0.1", self._port), handler_cls)
216
+ self._port = self._server.server_address[1]
217
+ self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
218
+ self._thread.start()
219
+
220
+ def stop(self) -> None:
221
+ if self._server:
222
+ self._server.shutdown()
223
+
224
+ # -- Screen rendering --------------------------------------------------
225
+
226
+ def show_screen(self, name: str, open_browser: bool = True) -> str:
227
+ """Build HTML from a registered screen and serve it.
228
+
229
+ Returns the URL.
230
+ """
231
+ if self._server is None:
232
+ self.start()
233
+
234
+ screen = self.screen_registry.get_screen(name)
235
+ canvases = self.canvas_registry.snapshot() if self.canvas_registry else None
236
+ # Convert snapshot dicts back to Canvas objects for rendering
237
+ canvas_objs: Dict[str, Canvas] = {}
238
+ if self.canvas_registry:
239
+ canvas_objs = dict(self.canvas_registry.canvases)
240
+ self._current_html = build_html(screen, canvas_objs or None)
241
+
242
+ url = self.url
243
+ if open_browser:
244
+ webbrowser.open(url)
245
+ return url
246
+
247
+ # -- Event binding -----------------------------------------------------
248
+
249
+ def on(self, component_name: str, event: str, handler) -> None:
250
+ self._event_handlers[f"{component_name}:{event}"] = handler
251
+
252
+
253
+ # ---------------------------------------------------------------------------
254
+ # Factory
255
+ # ---------------------------------------------------------------------------
256
+
257
+ def create_web_backend(**kwargs) -> WebBackend:
258
+ backend = WebBackend(**kwargs)
259
+ backend.start()
260
+ return backend
@@ -8,7 +8,12 @@ from .async_runtime import (
8
8
  Task,
9
9
  get_event_loop,
10
10
  set_event_loop,
11
- new_event_loop
11
+ new_event_loop,
12
+ )
13
+ from .load_manager import (
14
+ get_load_manager,
15
+ register_provider,
16
+ clear_load_caches,
12
17
  )
13
18
 
14
19
  __all__ = [
@@ -16,5 +21,8 @@ __all__ = [
16
21
  'Task',
17
22
  'get_event_loop',
18
23
  'set_event_loop',
19
- 'new_event_loop'
24
+ 'new_event_loop',
25
+ 'get_load_manager',
26
+ 'register_provider',
27
+ 'clear_load_caches',
20
28
  ]
@@ -0,0 +1,137 @@
1
+ """Parse and apply inline file flags for Zexus execution.
2
+
3
+ Supported directive formats (first 25 lines):
4
+ - // @zexus: {"use_vm": true, "vm_mode": "stack", "no_optimize": false}
5
+ - # @zexus: use_vm=true; vm_mode=auto; debug=full
6
+
7
+ Values accept booleans, ints, floats, or strings.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any, Dict, Optional
13
+ import json
14
+ import re
15
+
16
+ _MAX_SCAN_LINES = 25
17
+
18
+
19
+ def parse_file_flags(source: str) -> Dict[str, Any]:
20
+ flags: Dict[str, Any] = {}
21
+ if not source:
22
+ return flags
23
+
24
+ lines = source.splitlines()[:_MAX_SCAN_LINES]
25
+ for line in lines:
26
+ stripped = line.strip()
27
+ if not stripped:
28
+ continue
29
+ if "@zexus" not in stripped:
30
+ continue
31
+
32
+ # Strip leading comment markers
33
+ directive = stripped
34
+ for prefix in ("//", "#", "/*", "*/"):
35
+ if directive.startswith(prefix):
36
+ directive = directive[len(prefix):].strip()
37
+ # Remove leading @zexus marker
38
+ if directive.lower().startswith("@zexus"):
39
+ directive = directive[len("@zexus"):].strip()
40
+ if directive.startswith(":"):
41
+ directive = directive[1:].strip()
42
+
43
+ # JSON object form
44
+ if "{" in directive:
45
+ json_part = directive[directive.find("{"):].strip()
46
+ try:
47
+ parsed = json.loads(json_part)
48
+ if isinstance(parsed, dict):
49
+ flags.update(parsed)
50
+ except Exception:
51
+ pass
52
+ continue
53
+
54
+ # key=value form (semicolon or comma separated)
55
+ for part in re.split(r"[;,]", directive):
56
+ part = part.strip()
57
+ if not part:
58
+ continue
59
+ if "=" not in part:
60
+ continue
61
+ key, raw_val = part.split("=", 1)
62
+ key = key.strip()
63
+ raw_val = raw_val.strip()
64
+ flags[key] = _parse_value(raw_val)
65
+
66
+ return flags
67
+
68
+
69
+ def _parse_value(raw: str) -> Any:
70
+ if not raw:
71
+ return raw
72
+ lowered = raw.lower()
73
+ if lowered in ("true", "yes", "on"):
74
+ return True
75
+ if lowered in ("false", "no", "off"):
76
+ return False
77
+ # numbers
78
+ try:
79
+ if "." in raw:
80
+ return float(raw)
81
+ return int(raw)
82
+ except Exception:
83
+ pass
84
+ # quoted string
85
+ if (raw.startswith("\"") and raw.endswith("\"")) or (raw.startswith("'") and raw.endswith("'")):
86
+ return raw[1:-1]
87
+ return raw
88
+
89
+
90
+ def apply_vm_config(vm, vm_config: Dict[str, Any]) -> None:
91
+ if not vm_config:
92
+ return
93
+
94
+ mode_value = vm_config.get("mode")
95
+ if isinstance(mode_value, str):
96
+ try:
97
+ from ..vm.vm import VMMode
98
+ vm.mode = VMMode(mode_value.lower())
99
+ except Exception:
100
+ pass
101
+
102
+ # Explicit gas metering disable
103
+ if vm_config.get("enable_gas_metering") is False:
104
+ try:
105
+ vm.enable_gas_metering = False
106
+ vm.gas_metering = None
107
+ except Exception:
108
+ pass
109
+
110
+ # perf fast dispatch
111
+ if vm_config.get("perf_fast_dispatch") is True:
112
+ try:
113
+ vm._perf_fast_dispatch = True
114
+ except Exception:
115
+ pass
116
+
117
+ if vm_config.get("prefer_register") is True:
118
+ try:
119
+ vm.prefer_register = True
120
+ except Exception:
121
+ pass
122
+
123
+ if vm_config.get("prefer_parallel") is True:
124
+ try:
125
+ vm.prefer_parallel = True
126
+ except Exception:
127
+ pass
128
+
129
+ # generic attribute setters
130
+ for key, value in vm_config.items():
131
+ if key == "mode":
132
+ continue
133
+ if hasattr(vm, key):
134
+ try:
135
+ setattr(vm, key, value)
136
+ except Exception:
137
+ continue