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.
- package/README.md +12 -5
- package/package.json +1 -1
- package/src/__init__.py +7 -0
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/debug_sanitizer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/input_validation.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +17 -2
- package/src/zexus/blockchain/__init__.py +411 -0
- package/src/zexus/blockchain/accelerator.py +1160 -0
- package/src/zexus/blockchain/chain.py +660 -0
- package/src/zexus/blockchain/consensus.py +821 -0
- package/src/zexus/blockchain/contract_vm.py +1019 -0
- package/src/zexus/blockchain/crypto.py +79 -14
- package/src/zexus/blockchain/events.py +526 -0
- package/src/zexus/blockchain/loadtest.py +721 -0
- package/src/zexus/blockchain/monitoring.py +350 -0
- package/src/zexus/blockchain/mpt.py +716 -0
- package/src/zexus/blockchain/multichain.py +951 -0
- package/src/zexus/blockchain/multiprocess_executor.py +338 -0
- package/src/zexus/blockchain/network.py +886 -0
- package/src/zexus/blockchain/node.py +666 -0
- package/src/zexus/blockchain/rpc.py +1203 -0
- package/src/zexus/blockchain/rust_bridge.py +421 -0
- package/src/zexus/blockchain/storage.py +423 -0
- package/src/zexus/blockchain/tokens.py +750 -0
- package/src/zexus/blockchain/upgradeable.py +1004 -0
- package/src/zexus/blockchain/verification.py +1602 -0
- package/src/zexus/blockchain/wallet.py +621 -0
- package/src/zexus/capability_system.py +184 -9
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +383 -34
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +124 -7
- package/src/zexus/compiler/compat_runtime.py +6 -2
- package/src/zexus/compiler/lexer.py +16 -5
- package/src/zexus/compiler/parser.py +108 -7
- package/src/zexus/compiler/semantic.py +18 -19
- package/src/zexus/compiler/zexus_ast.py +26 -1
- package/src/zexus/concurrency_system.py +79 -0
- package/src/zexus/config.py +54 -0
- package/src/zexus/crypto_bridge.py +244 -8
- package/src/zexus/dap/__init__.py +10 -0
- package/src/zexus/dap/__main__.py +4 -0
- package/src/zexus/dap/dap_server.py +391 -0
- package/src/zexus/dap/debug_engine.py +298 -0
- package/src/zexus/environment.py +112 -9
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +457 -37
- package/src/zexus/evaluator/core.py +644 -50
- package/src/zexus/evaluator/expressions.py +358 -62
- package/src/zexus/evaluator/functions.py +458 -20
- package/src/zexus/evaluator/resource_limiter.py +4 -4
- package/src/zexus/evaluator/statements.py +774 -122
- package/src/zexus/evaluator/unified_execution.py +573 -72
- package/src/zexus/evaluator/utils.py +14 -2
- package/src/zexus/evaluator_original.py +1 -1
- package/src/zexus/event_loop.py +186 -0
- package/src/zexus/lexer.py +742 -458
- package/src/zexus/lsp/__init__.py +1 -1
- package/src/zexus/lsp/definition_provider.py +163 -9
- package/src/zexus/lsp/server.py +22 -8
- package/src/zexus/lsp/symbol_provider.py +182 -9
- package/src/zexus/module_cache.py +239 -9
- package/src/zexus/module_manager.py +129 -1
- package/src/zexus/object.py +76 -6
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/parser.py +1349 -408
- package/src/zexus/parser/strategy_context.py +755 -58
- package/src/zexus/parser/strategy_structural.py +121 -21
- package/src/zexus/persistence.py +15 -1
- package/src/zexus/renderer/__init__.py +61 -0
- package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
- package/src/zexus/renderer/backend.py +261 -0
- package/src/zexus/renderer/canvas.py +78 -0
- package/src/zexus/renderer/color_system.py +201 -0
- package/src/zexus/renderer/graphics.py +31 -0
- package/src/zexus/renderer/layout.py +222 -0
- package/src/zexus/renderer/main_renderer.py +66 -0
- package/src/zexus/renderer/painter.py +30 -0
- package/src/zexus/renderer/tk_backend.py +208 -0
- package/src/zexus/renderer/web_backend.py +260 -0
- package/src/zexus/runtime/__init__.py +10 -2
- package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
- package/src/zexus/runtime/file_flags.py +137 -0
- package/src/zexus/runtime/load_manager.py +368 -0
- package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
- package/src/zexus/security.py +424 -34
- package/src/zexus/stdlib/fs.py +23 -18
- package/src/zexus/stdlib/http.py +289 -186
- package/src/zexus/stdlib/sockets.py +207 -163
- package/src/zexus/stdlib/websockets.py +282 -0
- package/src/zexus/stdlib_integration.py +369 -2
- package/src/zexus/strategy_recovery.py +6 -3
- package/src/zexus/type_checker.py +423 -0
- package/src/zexus/virtual_filesystem.py +189 -2
- package/src/zexus/vm/__init__.py +113 -3
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +80 -6
- package/src/zexus/vm/binary_bytecode.py +659 -0
- package/src/zexus/vm/bytecode.py +59 -11
- package/src/zexus/vm/bytecode_converter.py +26 -12
- package/src/zexus/vm/cabi.c +1985 -0
- package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/cabi.h +127 -0
- package/src/zexus/vm/cache.py +561 -17
- package/src/zexus/vm/compiler.py +818 -51
- package/src/zexus/vm/fastops.c +15743 -0
- package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/fastops.pyx +288 -0
- package/src/zexus/vm/gas_metering.py +50 -9
- package/src/zexus/vm/jit.py +364 -20
- package/src/zexus/vm/native_jit_backend.py +1816 -0
- package/src/zexus/vm/native_runtime.cpp +1388 -0
- package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/optimizer.py +161 -11
- package/src/zexus/vm/parallel_vm.py +140 -45
- package/src/zexus/vm/peephole_optimizer.py +82 -4
- package/src/zexus/vm/profiler.py +38 -18
- package/src/zexus/vm/register_allocator.py +16 -5
- package/src/zexus/vm/register_vm.py +8 -5
- package/src/zexus/vm/vm.py +3581 -531
- package/src/zexus/vm/wasm_compiler.py +658 -0
- package/src/zexus/zexus_ast.py +137 -11
- package/src/zexus/zexus_token.py +16 -5
- package/src/zexus/zpm/installer.py +55 -15
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus/zpm/registry.py +257 -28
- package/src/zexus.egg-info/PKG-INFO +16 -6
- package/src/zexus.egg-info/SOURCES.txt +129 -17
- package/src/zexus.egg-info/entry_points.txt +1 -0
- package/src/zexus.egg-info/requires.txt +4 -0
|
@@ -28,6 +28,8 @@ class StructuralAnalyzer:
|
|
|
28
28
|
block_id = 0
|
|
29
29
|
n = len(tokens)
|
|
30
30
|
|
|
31
|
+
debug_enabled = zexus_config.enable_debug_logs
|
|
32
|
+
|
|
31
33
|
# helper sets for stopping heuristics (mirrors context parser)
|
|
32
34
|
stop_types = {SEMICOLON, RBRACE}
|
|
33
35
|
|
|
@@ -37,10 +39,11 @@ class StructuralAnalyzer:
|
|
|
37
39
|
# Statement starters (keywords that begin a new statement)
|
|
38
40
|
# NOTE: SEND and RECEIVE removed - they can be used as function calls in expressions
|
|
39
41
|
statement_starters = {
|
|
40
|
-
LET, CONST, DATA, PRINT, FOR, IF, WHILE, RETURN, CONTINUE, BREAK, THROW, ACTION, FUNCTION, TRY, EXTERNAL,
|
|
41
|
-
SCREEN,
|
|
42
|
+
LET, CONST, DATA, PRINT, FOR, IF, WHILE, RETURN, CONTINUE, BREAK, THROW, ACTION, FUNCTION, TRY, FINALLY, EXTERNAL,
|
|
43
|
+
SCREEN, COLOR, CANVAS, GRAPHICS, ANIMATION, CLOCK,
|
|
44
|
+
EXPORT, USE, DEBUG, ENTITY, CONTRACT, VERIFY, PROTECT, SEAL, PERSISTENT, AUDIT,
|
|
42
45
|
RESTRICT, SANDBOX, TRAIL, GC, BUFFER, SIMD,
|
|
43
|
-
DEFER, PATTERN, ENUM, STREAM, WATCH,
|
|
46
|
+
DEFER, PATTERN, ENUM, STREAM, WATCH, MATCH,
|
|
44
47
|
CAPABILITY, GRANT, REVOKE, VALIDATE, SANITIZE, IMMUTABLE,
|
|
45
48
|
INTERFACE, TYPE_ALIAS, MODULE, PACKAGE, USING,
|
|
46
49
|
CHANNEL, ATOMIC,
|
|
@@ -134,13 +137,44 @@ class StructuralAnalyzer:
|
|
|
134
137
|
declaration_type = tokens[i].type
|
|
135
138
|
export_tokens.append(tokens[i])
|
|
136
139
|
i += 1
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
|
|
141
|
+
# Track nesting counts so that braces/parentheses inside the value don't prematurely terminate the statement
|
|
142
|
+
paren_depth = 0
|
|
143
|
+
brace_depth = 0
|
|
144
|
+
bracket_depth = 0
|
|
145
|
+
|
|
146
|
+
while i < n:
|
|
147
|
+
current = tokens[i]
|
|
148
|
+
|
|
149
|
+
# Update nesting counters before applying boundary heuristics
|
|
150
|
+
if current.type == LPAREN:
|
|
151
|
+
paren_depth += 1
|
|
152
|
+
elif current.type == RPAREN:
|
|
153
|
+
paren_depth = max(paren_depth - 1, 0)
|
|
154
|
+
elif current.type == LBRACE:
|
|
155
|
+
brace_depth += 1
|
|
156
|
+
elif current.type == RBRACE:
|
|
157
|
+
brace_depth = max(brace_depth - 1, 0)
|
|
158
|
+
elif current.type == LBRACKET:
|
|
159
|
+
bracket_depth += 1
|
|
160
|
+
elif current.type == RBRACKET:
|
|
161
|
+
bracket_depth = max(bracket_depth - 1, 0)
|
|
162
|
+
|
|
163
|
+
export_tokens.append(current)
|
|
143
164
|
i += 1
|
|
165
|
+
|
|
166
|
+
in_nested_structure = (paren_depth > 0 or brace_depth > 0 or bracket_depth > 0)
|
|
167
|
+
|
|
168
|
+
# Stop if we reach a clear boundary at top level (first semicolon or closing brace outside of literal)
|
|
169
|
+
if not in_nested_structure and current.type in stop_types:
|
|
170
|
+
break
|
|
171
|
+
|
|
172
|
+
# Stop if we see another statement starter at top level (but not CONST/LET since we just saw it)
|
|
173
|
+
if not in_nested_structure and current.type in statement_starters and current.type not in [CONST, LET]:
|
|
174
|
+
# Remove the boundary token so the next statement sees it
|
|
175
|
+
export_tokens.pop()
|
|
176
|
+
i -= 1
|
|
177
|
+
break
|
|
144
178
|
elif i < n and tokens[i].type == CONTRACT:
|
|
145
179
|
# export contract Name { ... } - collect entire contract
|
|
146
180
|
export_tokens.append(tokens[i])
|
|
@@ -170,6 +204,30 @@ class StructuralAnalyzer:
|
|
|
170
204
|
elif tokens[i].type == RBRACE:
|
|
171
205
|
brace_count -= 1
|
|
172
206
|
i += 1
|
|
207
|
+
elif i < n and tokens[i].type == DATA:
|
|
208
|
+
# export data Name { ... } - collect entire data declaration
|
|
209
|
+
export_tokens.append(tokens[i])
|
|
210
|
+
i += 1
|
|
211
|
+
|
|
212
|
+
brace_count = 0
|
|
213
|
+
|
|
214
|
+
# Collect modifiers, type params, and until first brace
|
|
215
|
+
while i < n:
|
|
216
|
+
export_tokens.append(tokens[i])
|
|
217
|
+
if tokens[i].type == LBRACE:
|
|
218
|
+
brace_count = 1
|
|
219
|
+
i += 1
|
|
220
|
+
break
|
|
221
|
+
i += 1
|
|
222
|
+
|
|
223
|
+
# Collect body until matching closing brace
|
|
224
|
+
while i < n and brace_count > 0:
|
|
225
|
+
export_tokens.append(tokens[i])
|
|
226
|
+
if tokens[i].type == LBRACE:
|
|
227
|
+
brace_count += 1
|
|
228
|
+
elif tokens[i].type == RBRACE:
|
|
229
|
+
brace_count -= 1
|
|
230
|
+
i += 1
|
|
173
231
|
elif i < n and tokens[i].type == FUNCTION:
|
|
174
232
|
# export function name(...) { ... } - collect entire function
|
|
175
233
|
export_tokens.append(tokens[i])
|
|
@@ -450,8 +508,16 @@ class StructuralAnalyzer:
|
|
|
450
508
|
catch_tokens = [catch_token] + pre_brace_tokens + catch_block_tokens
|
|
451
509
|
final_idx = after_catch_idx
|
|
452
510
|
|
|
511
|
+
# Check for finally block
|
|
512
|
+
finally_tokens = []
|
|
513
|
+
if final_idx < n and tokens[final_idx].type == FINALLY:
|
|
514
|
+
finally_token = tokens[final_idx]
|
|
515
|
+
finally_block_tokens, after_finally_idx = self._collect_brace_block(tokens, final_idx + 1)
|
|
516
|
+
finally_tokens = [finally_token] + finally_block_tokens
|
|
517
|
+
final_idx = after_finally_idx
|
|
518
|
+
|
|
453
519
|
# Combine all tokens
|
|
454
|
-
full_tokens = [t] + try_block_tokens + catch_tokens
|
|
520
|
+
full_tokens = [t] + try_block_tokens + catch_tokens + finally_tokens
|
|
455
521
|
full_tokens = [tk for tk in full_tokens if not _is_empty_token(tk)]
|
|
456
522
|
|
|
457
523
|
# Create the main try-catch block
|
|
@@ -743,7 +809,27 @@ class StructuralAnalyzer:
|
|
|
743
809
|
# Break if we've already completed the LET/CONST and this is an indexed assignment
|
|
744
810
|
if is_indexed_assignment and in_assignment and seen_assign:
|
|
745
811
|
break
|
|
746
|
-
|
|
812
|
+
|
|
813
|
+
# Pattern 4: IDENT followed by LPAREN is a function call expression
|
|
814
|
+
# This is a NEW statement if we're in LET/CONST and have seen the main assign
|
|
815
|
+
# and the function call is on a new line (prevents absorbing next statement)
|
|
816
|
+
elif tj.type == IDENT and j + 1 < n and tokens[j + 1].type == LPAREN:
|
|
817
|
+
if stmt_tokens and in_assignment and seen_assign:
|
|
818
|
+
last_token = stmt_tokens[-1]
|
|
819
|
+
last_line = getattr(last_token, 'line', None)
|
|
820
|
+
current_line = getattr(tj, 'line', None)
|
|
821
|
+
if last_line is not None and current_line is not None and current_line > last_line:
|
|
822
|
+
# Safety: don't break if previous token is an infix operator
|
|
823
|
+
# (e.g., let x = foo() +\n bar() across two lines)
|
|
824
|
+
_infix_ops = {PLUS, MINUS, STAR, SLASH, MOD, AND, OR,
|
|
825
|
+
EQ, NOT_EQ, LT, GT, LTE, GTE, POWER,
|
|
826
|
+
DOT, COMMA, ASSIGN, QUESTION, NULLISH,
|
|
827
|
+
PLUS_ASSIGN, MINUS_ASSIGN, STAR_ASSIGN,
|
|
828
|
+
SLASH_ASSIGN, MOD_ASSIGN, POWER_ASSIGN,
|
|
829
|
+
APPEND, IMPORT_OP}
|
|
830
|
+
if last_token.type not in _infix_ops:
|
|
831
|
+
# New line after completed assignment - this is a new statement
|
|
832
|
+
break
|
|
747
833
|
|
|
748
834
|
# Detect colon-based block (tolerable syntax for action/function/if/while etc.)
|
|
749
835
|
if tj.type == COLON and nesting == 0 and t.type in {ACTION, FUNCTION, IF, WHILE, FOR}:
|
|
@@ -759,8 +845,10 @@ class StructuralAnalyzer:
|
|
|
759
845
|
# Track nesting level BEFORE dedent check (so we don't break inside {...} or [...] or (...))
|
|
760
846
|
if tj.type in {LPAREN, LBRACE, LBRACKET}:
|
|
761
847
|
# Only mark as brace block if NOT already in colon block (to distinguish code blocks from data literals)
|
|
848
|
+
# ALSO: Don't mark as brace block for destructuring patterns in LET/CONST before '='
|
|
762
849
|
if tj.type == LBRACE and not found_colon_block:
|
|
763
|
-
|
|
850
|
+
if not (in_assignment and not seen_assign):
|
|
851
|
+
found_brace_block = True
|
|
764
852
|
nesting += 1
|
|
765
853
|
elif tj.type in {RPAREN, RBRACE, RBRACKET}:
|
|
766
854
|
nesting -= 1
|
|
@@ -791,10 +879,16 @@ class StructuralAnalyzer:
|
|
|
791
879
|
# We're still parsing the condition - don't break yet
|
|
792
880
|
pass
|
|
793
881
|
else:
|
|
794
|
-
# For LET/CONST, allow FUNCTION, SANDBOX, SANITIZE as RHS (expressions)
|
|
882
|
+
# For LET/CONST, allow FUNCTION, SANDBOX, SANITIZE, MATCH as RHS (expressions)
|
|
795
883
|
# Also allow DEBUG when followed by ( for debug(x) function calls in assignments
|
|
796
884
|
# Also allow IF when followed by THEN (if-then-else expression)
|
|
797
|
-
allow_in_assignment = tj.type in {FUNCTION, SANDBOX, SANITIZE}
|
|
885
|
+
allow_in_assignment = tj.type in {FUNCTION, SANDBOX, SANITIZE, MATCH}
|
|
886
|
+
if in_assignment and allow_in_assignment and stmt_tokens:
|
|
887
|
+
prev_token = stmt_tokens[-1]
|
|
888
|
+
prev_line = getattr(prev_token, 'line', None)
|
|
889
|
+
current_line = getattr(tj, 'line', None)
|
|
890
|
+
if prev_line is not None and current_line is not None and current_line > prev_line:
|
|
891
|
+
allow_in_assignment = False
|
|
798
892
|
allow_debug_call = tj.type == DEBUG and j + 1 < n and tokens[j + 1].type == LPAREN
|
|
799
893
|
allow_if_then_else = False
|
|
800
894
|
if tj.type == IF:
|
|
@@ -964,10 +1058,12 @@ class StructuralAnalyzer:
|
|
|
964
1058
|
# CRITICAL FIX: Don't break if the previous token was ASSIGN
|
|
965
1059
|
# This means the IDENT is the RHS value, not a new statement
|
|
966
1060
|
prev_tok = run_tokens[-1] if run_tokens else None
|
|
967
|
-
|
|
1061
|
+
if debug_enabled:
|
|
1062
|
+
print(f" prev_tok={prev_tok.literal if prev_tok else None}, type={prev_tok.type if prev_tok else None}")
|
|
968
1063
|
if prev_tok and prev_tok.type == ASSIGN:
|
|
969
1064
|
# This IDENT is the RHS of the assignment, not a new statement
|
|
970
|
-
|
|
1065
|
+
if debug_enabled:
|
|
1066
|
+
print(" -> Continuing (RHS of assignment)")
|
|
971
1067
|
pass # Don't break, continue collecting
|
|
972
1068
|
else:
|
|
973
1069
|
# This is likely a new statement on a new line
|
|
@@ -1109,8 +1205,9 @@ class StructuralAnalyzer:
|
|
|
1109
1205
|
stop_types = {SEMICOLON, RBRACE}
|
|
1110
1206
|
# NOTE: SEND and RECEIVE removed - they can be used as function calls in expressions
|
|
1111
1207
|
statement_starters = {
|
|
1112
|
-
LET, CONST, DATA, PRINT, FOR, IF, WHILE, RETURN, CONTINUE, BREAK, THROW, ACTION, FUNCTION, TRY, EXTERNAL,
|
|
1113
|
-
SCREEN,
|
|
1208
|
+
LET, CONST, DATA, PRINT, FOR, IF, WHILE, RETURN, CONTINUE, BREAK, THROW, ACTION, FUNCTION, TRY, FINALLY, EXTERNAL,
|
|
1209
|
+
SCREEN, COLOR, CANVAS, GRAPHICS, ANIMATION, CLOCK,
|
|
1210
|
+
EXPORT, USE, DEBUG, ENTITY, CONTRACT, VERIFY, PROTECT, SEAL, AUDIT,
|
|
1114
1211
|
RESTRICT, SANDBOX, TRAIL, NATIVE, GC, INLINE, BUFFER, SIMD,
|
|
1115
1212
|
DEFER, PATTERN, ENUM, STREAM, WATCH,
|
|
1116
1213
|
CAPABILITY, GRANT, REVOKE, VALIDATE, SANITIZE, IMMUTABLE,
|
|
@@ -1167,7 +1264,8 @@ class StructuralAnalyzer:
|
|
|
1167
1264
|
|
|
1168
1265
|
# Export statement detection - collect export keyword + following declaration
|
|
1169
1266
|
if t.type == EXPORT:
|
|
1170
|
-
|
|
1267
|
+
if debug_enabled:
|
|
1268
|
+
print(f"[DEBUG STRUCT] Found EXPORT token at index {i}")
|
|
1171
1269
|
if cur:
|
|
1172
1270
|
results.append(cur)
|
|
1173
1271
|
cur = []
|
|
@@ -1177,9 +1275,11 @@ class StructuralAnalyzer:
|
|
|
1177
1275
|
i += 1
|
|
1178
1276
|
|
|
1179
1277
|
# Check if followed by const/let declaration (export const X = value)
|
|
1180
|
-
|
|
1278
|
+
if debug_enabled:
|
|
1279
|
+
print(f"[DEBUG STRUCT] Next token at {i}: {tokens[i].type if i < n else 'EOF'}, CONST={CONST}, LET={LET}")
|
|
1181
1280
|
if i < n and tokens[i].type in [CONST, LET]:
|
|
1182
|
-
|
|
1281
|
+
if debug_enabled:
|
|
1282
|
+
print(f"[DEBUG STRUCT] Export followed by CONST/LET, collecting declaration")
|
|
1183
1283
|
# Collect the entire declaration
|
|
1184
1284
|
while i < n and tokens[i].type not in stop_types:
|
|
1185
1285
|
export_tokens.append(tokens[i])
|
package/src/zexus/persistence.py
CHANGED
|
@@ -315,6 +315,19 @@ class PersistentStorage:
|
|
|
315
315
|
cursor = self.conn.cursor()
|
|
316
316
|
cursor.execute('DELETE FROM variables')
|
|
317
317
|
self.conn.commit()
|
|
318
|
+
|
|
319
|
+
def _key_to_str(self, key):
|
|
320
|
+
"""Convert a Zexus object key to a Python string for JSON serialization."""
|
|
321
|
+
if isinstance(key, String):
|
|
322
|
+
return key.value
|
|
323
|
+
if isinstance(key, Integer):
|
|
324
|
+
return str(key.value)
|
|
325
|
+
if isinstance(key, Float):
|
|
326
|
+
return str(key.value)
|
|
327
|
+
if isinstance(key, BooleanObj):
|
|
328
|
+
return str(key.value)
|
|
329
|
+
# Fallback for other types
|
|
330
|
+
return str(key)
|
|
318
331
|
|
|
319
332
|
def _serialize(self, obj: Object) -> Dict[str, str]:
|
|
320
333
|
"""Serialize Zexus object to JSON"""
|
|
@@ -330,7 +343,8 @@ class PersistentStorage:
|
|
|
330
343
|
serialized = [self._serialize(e) for e in obj.elements]
|
|
331
344
|
return {'type': 'list', 'value': json.dumps(serialized)}
|
|
332
345
|
elif isinstance(obj, Map):
|
|
333
|
-
|
|
346
|
+
# Convert Zexus String keys to Python strings for JSON compatibility
|
|
347
|
+
serialized = {self._key_to_str(k): self._serialize(v) for k, v in obj.pairs.items()}
|
|
334
348
|
return {'type': 'map', 'value': json.dumps(serialized)}
|
|
335
349
|
elif obj is Null or obj is NULL:
|
|
336
350
|
return {'type': 'null', 'value': json.dumps(None)}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Zexus renderer package.
|
|
2
|
+
|
|
3
|
+
This package exposes a cohesive rendering subsystem that can be consumed by
|
|
4
|
+
both the interpreter and the VM/compiler paths. The public API mirrors the
|
|
5
|
+
previous top-level ``renderer`` module so existing call sites remain
|
|
6
|
+
compatible while the implementation now lives alongside the core runtime.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .backend import (
|
|
11
|
+
RendererBackend,
|
|
12
|
+
add_to_screen,
|
|
13
|
+
create_canvas,
|
|
14
|
+
create_named_canvas,
|
|
15
|
+
define_color,
|
|
16
|
+
define_component,
|
|
17
|
+
define_screen,
|
|
18
|
+
draw_line,
|
|
19
|
+
draw_text,
|
|
20
|
+
inspect_registry,
|
|
21
|
+
mix,
|
|
22
|
+
register_animation,
|
|
23
|
+
register_clock,
|
|
24
|
+
register_graphics,
|
|
25
|
+
render_screen,
|
|
26
|
+
set_theme,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"RendererBackend",
|
|
31
|
+
"add_to_screen",
|
|
32
|
+
"create_canvas",
|
|
33
|
+
"create_named_canvas",
|
|
34
|
+
"define_color",
|
|
35
|
+
"define_component",
|
|
36
|
+
"define_screen",
|
|
37
|
+
"draw_line",
|
|
38
|
+
"draw_text",
|
|
39
|
+
"inspect_registry",
|
|
40
|
+
"mix",
|
|
41
|
+
"register_animation",
|
|
42
|
+
"register_clock",
|
|
43
|
+
"register_graphics",
|
|
44
|
+
"render_screen",
|
|
45
|
+
"set_theme",
|
|
46
|
+
# GUI backends
|
|
47
|
+
"TkBackend",
|
|
48
|
+
"WebBackend",
|
|
49
|
+
"create_tk_backend",
|
|
50
|
+
"create_web_backend",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
# Lazy imports for GUI backends (tkinter may not be installed)
|
|
54
|
+
def __getattr__(name: str):
|
|
55
|
+
if name in ("TkBackend", "create_tk_backend"):
|
|
56
|
+
from .tk_backend import TkBackend, create_tk_backend
|
|
57
|
+
return TkBackend if name == "TkBackend" else create_tk_backend
|
|
58
|
+
if name in ("WebBackend", "create_web_backend"):
|
|
59
|
+
from .web_backend import WebBackend, create_web_backend
|
|
60
|
+
return WebBackend if name == "WebBackend" else create_web_backend
|
|
61
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Renderer backend exposed to the evaluator and VM implementations."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
import re
|
|
6
|
+
from typing import Any, Dict, Iterable, Optional
|
|
7
|
+
|
|
8
|
+
from .canvas import CanvasRegistry
|
|
9
|
+
from .color_system import ColorPalette, RGBColor, Theme
|
|
10
|
+
from .layout import Screen, ScreenRegistry
|
|
11
|
+
from .main_renderer import ZexusScreenRenderer
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class RendererState:
|
|
16
|
+
screens: ScreenRegistry = field(default_factory=ScreenRegistry)
|
|
17
|
+
canvases: CanvasRegistry = field(default_factory=CanvasRegistry)
|
|
18
|
+
themes: Dict[str, Theme] = field(default_factory=dict)
|
|
19
|
+
current_theme: Optional[str] = None
|
|
20
|
+
colours: Dict[str, str] = field(default_factory=dict)
|
|
21
|
+
graphics: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
22
|
+
animations: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
23
|
+
clocks: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
24
|
+
canvas_aliases: Dict[str, str] = field(default_factory=dict)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RendererBackend:
|
|
28
|
+
def __init__(self) -> None:
|
|
29
|
+
self.palette = ColorPalette()
|
|
30
|
+
self.state = RendererState()
|
|
31
|
+
self.renderer = ZexusScreenRenderer(self.state.screens)
|
|
32
|
+
|
|
33
|
+
# ------------------------------------------------------------------
|
|
34
|
+
# Colour helpers
|
|
35
|
+
# ------------------------------------------------------------------
|
|
36
|
+
def mix(self, colour_a: str, colour_b: str, ratio: float = 0.5) -> RGBColor:
|
|
37
|
+
return self.palette.mix(colour_a, colour_b, ratio)
|
|
38
|
+
|
|
39
|
+
def define_color(self, name: str, spec: object) -> RGBColor:
|
|
40
|
+
colour = self._coerce_colour(spec)
|
|
41
|
+
self.palette.define(name, colour)
|
|
42
|
+
self.state.colours[name] = str(colour)
|
|
43
|
+
return colour
|
|
44
|
+
|
|
45
|
+
# ------------------------------------------------------------------
|
|
46
|
+
# Screen/component management
|
|
47
|
+
# ------------------------------------------------------------------
|
|
48
|
+
def define_screen(self, name: str, properties: Dict[str, Any] | None = None) -> None:
|
|
49
|
+
self.renderer.define_screen(name, **(properties or {}))
|
|
50
|
+
|
|
51
|
+
def define_component(self, name: str, properties: Dict[str, Any] | None = None) -> None:
|
|
52
|
+
props = dict(properties or {})
|
|
53
|
+
component_type = props.pop("type", None)
|
|
54
|
+
self.renderer.define_component(name, component_type, **props)
|
|
55
|
+
|
|
56
|
+
def add_to_screen(self, screen_name: str, component_name: str, overrides: Dict[str, Any] | None = None) -> None:
|
|
57
|
+
self.renderer.add_to_screen(screen_name, component_name, **(overrides or {}))
|
|
58
|
+
|
|
59
|
+
def render_screen(self, name: str, overrides: Dict[str, Any] | None = None) -> str:
|
|
60
|
+
return self.renderer.render_screen(name, **(overrides or {}))
|
|
61
|
+
|
|
62
|
+
# ------------------------------------------------------------------
|
|
63
|
+
# Theme handling
|
|
64
|
+
# ------------------------------------------------------------------
|
|
65
|
+
def set_theme(self, target_or_theme: str, theme_name: str | None = None) -> None:
|
|
66
|
+
if theme_name is None:
|
|
67
|
+
self.state.current_theme = target_or_theme
|
|
68
|
+
if target_or_theme not in self.state.themes:
|
|
69
|
+
self.state.themes[target_or_theme] = Theme(target_or_theme, self.palette)
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
if target_or_theme in self.state.screens.list_screens():
|
|
73
|
+
screen = self.state.screens.get_screen(target_or_theme)
|
|
74
|
+
screen.properties["theme"] = theme_name
|
|
75
|
+
if theme_name not in self.state.themes:
|
|
76
|
+
self.state.themes[theme_name] = Theme(theme_name, self.palette)
|
|
77
|
+
else:
|
|
78
|
+
if theme_name not in self.state.themes:
|
|
79
|
+
self.state.themes[theme_name] = Theme(theme_name, self.palette)
|
|
80
|
+
|
|
81
|
+
# ------------------------------------------------------------------
|
|
82
|
+
# Canvas helpers
|
|
83
|
+
# ------------------------------------------------------------------
|
|
84
|
+
def create_canvas(self, width: int, height: int) -> str:
|
|
85
|
+
return self.state.canvases.create(width=width, height=height)
|
|
86
|
+
|
|
87
|
+
def create_named_canvas(self, name: str, width: int, height: int) -> str:
|
|
88
|
+
identifier = self.create_canvas(width, height)
|
|
89
|
+
self.state.canvas_aliases[name] = identifier
|
|
90
|
+
return identifier
|
|
91
|
+
|
|
92
|
+
def draw_line(self, canvas_id: str, x1: int, y1: int, x2: int, y2: int) -> None:
|
|
93
|
+
canvas = self.state.canvases.get(self._resolve_canvas_identifier(canvas_id))
|
|
94
|
+
canvas.draw_line(x1, y1, x2, y2)
|
|
95
|
+
|
|
96
|
+
def draw_text(self, canvas_id: str, x: int, y: int, text: str) -> None:
|
|
97
|
+
canvas = self.state.canvases.get(self._resolve_canvas_identifier(canvas_id))
|
|
98
|
+
canvas.draw_text(x, y, text)
|
|
99
|
+
|
|
100
|
+
# ------------------------------------------------------------------
|
|
101
|
+
# Higher-level registries
|
|
102
|
+
# ------------------------------------------------------------------
|
|
103
|
+
def register_graphics(self, name: str, layers: Iterable[str] | Dict[str, Any]) -> None:
|
|
104
|
+
if isinstance(layers, dict):
|
|
105
|
+
payload = dict(layers)
|
|
106
|
+
else:
|
|
107
|
+
payload = {f"layer_{idx}": layer for idx, layer in enumerate(layers)}
|
|
108
|
+
self.state.graphics[name] = payload
|
|
109
|
+
|
|
110
|
+
def register_animation(self, name: str, frames: Dict[str, Any]) -> None:
|
|
111
|
+
self.state.animations[name] = dict(frames)
|
|
112
|
+
|
|
113
|
+
def register_clock(self, name: str, config: Dict[str, Any]) -> None:
|
|
114
|
+
self.state.clocks[name] = dict(config)
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------------
|
|
117
|
+
def inspect_registry(self) -> Dict[str, Any]:
|
|
118
|
+
return {
|
|
119
|
+
"screens": {
|
|
120
|
+
name: {
|
|
121
|
+
"properties": dict(screen.properties),
|
|
122
|
+
"children": [child.name for child in screen.children],
|
|
123
|
+
"theme": screen.properties.get("theme"),
|
|
124
|
+
}
|
|
125
|
+
for name, screen in self.state.screens.snapshot().items()
|
|
126
|
+
},
|
|
127
|
+
"components": {
|
|
128
|
+
name: dict(component.properties)
|
|
129
|
+
for name, component in self.state.screens.component_snapshot().items()
|
|
130
|
+
},
|
|
131
|
+
"themes": {name: theme.snapshot() for name, theme in self.state.themes.items()},
|
|
132
|
+
"canvases": self.state.canvases.snapshot(),
|
|
133
|
+
"canvas_aliases": dict(self.state.canvas_aliases),
|
|
134
|
+
"colours": dict(self.state.colours),
|
|
135
|
+
"graphics": {name: dict(data) for name, data in self.state.graphics.items()},
|
|
136
|
+
"animations": {name: dict(data) for name, data in self.state.animations.items()},
|
|
137
|
+
"clocks": {name: dict(data) for name, data in self.state.clocks.items()},
|
|
138
|
+
"current_theme": self.state.current_theme,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# ------------------------------------------------------------------
|
|
142
|
+
# Internal helpers
|
|
143
|
+
# ------------------------------------------------------------------
|
|
144
|
+
def _resolve_canvas_identifier(self, identifier: str) -> str:
|
|
145
|
+
if identifier in self.state.canvases.canvases:
|
|
146
|
+
return identifier
|
|
147
|
+
return self.state.canvas_aliases.get(identifier, identifier)
|
|
148
|
+
|
|
149
|
+
def _coerce_colour(self, spec: object) -> RGBColor:
|
|
150
|
+
if isinstance(spec, RGBColor):
|
|
151
|
+
return spec
|
|
152
|
+
|
|
153
|
+
if isinstance(spec, str):
|
|
154
|
+
text = spec.strip()
|
|
155
|
+
match = re.fullmatch(r"#?([0-9a-fA-F]{6})", text)
|
|
156
|
+
if match:
|
|
157
|
+
raw = match.group(1)
|
|
158
|
+
return RGBColor(int(raw[0:2], 16), int(raw[2:4], 16), int(raw[4:6], 16))
|
|
159
|
+
try:
|
|
160
|
+
return self.palette.get(text)
|
|
161
|
+
except KeyError as exc:
|
|
162
|
+
raise ValueError(str(exc)) from exc
|
|
163
|
+
|
|
164
|
+
if isinstance(spec, dict):
|
|
165
|
+
if {"r", "g", "b"}.issubset(spec):
|
|
166
|
+
return RGBColor(int(spec["r"]), int(spec["g"]), int(spec["b"]))
|
|
167
|
+
if {"red", "green", "blue"}.issubset(spec):
|
|
168
|
+
return RGBColor(int(spec["red"]), int(spec["green"]), int(spec["blue"]))
|
|
169
|
+
if "hex" in spec:
|
|
170
|
+
return self._coerce_colour(str(spec["hex"]))
|
|
171
|
+
raise ValueError("Colour map must include r/g/b values or hex")
|
|
172
|
+
|
|
173
|
+
if isinstance(spec, (list, tuple)) and len(spec) == 3:
|
|
174
|
+
r, g, b = spec
|
|
175
|
+
return RGBColor(int(r), int(g), int(b))
|
|
176
|
+
|
|
177
|
+
raise ValueError(f"Unsupported colour specification: {spec}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# Module level helper mirroring the legacy API -------------------------
|
|
181
|
+
_BACKEND = RendererBackend()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def mix(colour_a: str, colour_b: str, ratio: float = 0.5) -> RGBColor:
|
|
185
|
+
return _BACKEND.mix(colour_a, colour_b, ratio)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def define_color(name: str, spec: object) -> RGBColor:
|
|
189
|
+
return _BACKEND.define_color(name, spec)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def define_screen(name: str, properties: Dict[str, Any] | None = None) -> None:
|
|
193
|
+
_BACKEND.define_screen(name, properties)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def define_component(name: str, properties: Dict[str, Any] | None = None) -> None:
|
|
197
|
+
_BACKEND.define_component(name, properties)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def add_to_screen(screen_name: str, component_name: str, overrides: Dict[str, Any] | None = None) -> None:
|
|
201
|
+
_BACKEND.add_to_screen(screen_name, component_name, overrides)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def render_screen(name: str, overrides: Dict[str, Any] | None = None) -> str:
|
|
205
|
+
return _BACKEND.render_screen(name, overrides)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def set_theme(target_or_theme: str, theme_name: str | None = None) -> None:
|
|
209
|
+
_BACKEND.set_theme(target_or_theme, theme_name)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def create_canvas(width: int, height: int) -> str:
|
|
213
|
+
return _BACKEND.create_canvas(width, height)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def create_named_canvas(name: str, width: int, height: int) -> str:
|
|
217
|
+
return _BACKEND.create_named_canvas(name, width, height)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def draw_line(canvas_id: str, x1: int, y1: int, x2: int, y2: int) -> None:
|
|
221
|
+
_BACKEND.draw_line(canvas_id, x1, y1, x2, y2)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def draw_text(canvas_id: str, x: int, y: int, text: str) -> None:
|
|
225
|
+
_BACKEND.draw_text(canvas_id, x, y, text)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def register_graphics(name: str, data: Dict[str, Any] | Iterable[str]) -> None:
|
|
229
|
+
_BACKEND.register_graphics(name, data)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def register_animation(name: str, data: Dict[str, Any]) -> None:
|
|
233
|
+
_BACKEND.register_animation(name, data)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def register_clock(name: str, data: Dict[str, Any]) -> None:
|
|
237
|
+
_BACKEND.register_clock(name, data)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def inspect_registry() -> Dict[str, Any]:
|
|
241
|
+
return _BACKEND.inspect_registry()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
__all__ = [
|
|
245
|
+
"RendererBackend",
|
|
246
|
+
"add_to_screen",
|
|
247
|
+
"create_canvas",
|
|
248
|
+
"create_named_canvas",
|
|
249
|
+
"define_color",
|
|
250
|
+
"define_component",
|
|
251
|
+
"define_screen",
|
|
252
|
+
"draw_line",
|
|
253
|
+
"draw_text",
|
|
254
|
+
"inspect_registry",
|
|
255
|
+
"mix",
|
|
256
|
+
"register_animation",
|
|
257
|
+
"register_clock",
|
|
258
|
+
"register_graphics",
|
|
259
|
+
"render_screen",
|
|
260
|
+
"set_theme",
|
|
261
|
+
]
|