zexus 1.7.1 → 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 (159) hide show
  1. package/README.md +3 -3
  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/cli/__pycache__/main.cpython-312.pyc +0 -0
  45. package/src/zexus/cli/main.py +300 -20
  46. package/src/zexus/cli/zpm.py +1 -1
  47. package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
  48. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  49. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  50. package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
  51. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  52. package/src/zexus/compiler/lexer.py +10 -5
  53. package/src/zexus/concurrency_system.py +79 -0
  54. package/src/zexus/config.py +54 -0
  55. package/src/zexus/crypto_bridge.py +244 -8
  56. package/src/zexus/dap/__init__.py +10 -0
  57. package/src/zexus/dap/__main__.py +4 -0
  58. package/src/zexus/dap/dap_server.py +391 -0
  59. package/src/zexus/dap/debug_engine.py +298 -0
  60. package/src/zexus/environment.py +10 -1
  61. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  62. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  63. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  64. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  65. package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
  66. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  67. package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
  68. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  69. package/src/zexus/evaluator/bytecode_compiler.py +441 -37
  70. package/src/zexus/evaluator/core.py +560 -49
  71. package/src/zexus/evaluator/expressions.py +122 -49
  72. package/src/zexus/evaluator/functions.py +417 -16
  73. package/src/zexus/evaluator/statements.py +521 -118
  74. package/src/zexus/evaluator/unified_execution.py +573 -72
  75. package/src/zexus/evaluator/utils.py +14 -2
  76. package/src/zexus/event_loop.py +186 -0
  77. package/src/zexus/lexer.py +742 -486
  78. package/src/zexus/lsp/__init__.py +1 -1
  79. package/src/zexus/lsp/definition_provider.py +163 -9
  80. package/src/zexus/lsp/server.py +22 -8
  81. package/src/zexus/lsp/symbol_provider.py +182 -9
  82. package/src/zexus/module_cache.py +237 -9
  83. package/src/zexus/object.py +64 -6
  84. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  85. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  86. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  87. package/src/zexus/parser/parser.py +786 -285
  88. package/src/zexus/parser/strategy_context.py +407 -66
  89. package/src/zexus/parser/strategy_structural.py +117 -19
  90. package/src/zexus/persistence.py +15 -1
  91. package/src/zexus/renderer/__init__.py +15 -0
  92. package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
  93. package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
  94. package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
  95. package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
  96. package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
  97. package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
  98. package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
  99. package/src/zexus/renderer/tk_backend.py +208 -0
  100. package/src/zexus/renderer/web_backend.py +260 -0
  101. package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
  103. package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
  104. package/src/zexus/runtime/file_flags.py +137 -0
  105. package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
  106. package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
  107. package/src/zexus/security.py +424 -34
  108. package/src/zexus/stdlib/fs.py +23 -18
  109. package/src/zexus/stdlib/http.py +289 -186
  110. package/src/zexus/stdlib/sockets.py +207 -163
  111. package/src/zexus/stdlib/websockets.py +282 -0
  112. package/src/zexus/stdlib_integration.py +369 -2
  113. package/src/zexus/strategy_recovery.py +6 -3
  114. package/src/zexus/type_checker.py +423 -0
  115. package/src/zexus/virtual_filesystem.py +189 -2
  116. package/src/zexus/vm/__init__.py +113 -3
  117. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  118. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  119. package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
  120. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  121. package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
  122. package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
  123. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  124. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  125. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  126. package/src/zexus/vm/async_optimizer.py +14 -1
  127. package/src/zexus/vm/binary_bytecode.py +659 -0
  128. package/src/zexus/vm/bytecode.py +28 -1
  129. package/src/zexus/vm/bytecode_converter.py +26 -12
  130. package/src/zexus/vm/cabi.c +1985 -0
  131. package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
  132. package/src/zexus/vm/cabi.h +127 -0
  133. package/src/zexus/vm/cache.py +557 -17
  134. package/src/zexus/vm/compiler.py +703 -5
  135. package/src/zexus/vm/fastops.c +15743 -0
  136. package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
  137. package/src/zexus/vm/fastops.pyx +288 -0
  138. package/src/zexus/vm/gas_metering.py +50 -9
  139. package/src/zexus/vm/jit.py +83 -2
  140. package/src/zexus/vm/native_jit_backend.py +1816 -0
  141. package/src/zexus/vm/native_runtime.cpp +1388 -0
  142. package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
  143. package/src/zexus/vm/optimizer.py +161 -11
  144. package/src/zexus/vm/parallel_vm.py +118 -42
  145. package/src/zexus/vm/peephole_optimizer.py +82 -4
  146. package/src/zexus/vm/profiler.py +38 -18
  147. package/src/zexus/vm/register_allocator.py +16 -5
  148. package/src/zexus/vm/register_vm.py +8 -5
  149. package/src/zexus/vm/vm.py +3411 -573
  150. package/src/zexus/vm/wasm_compiler.py +658 -0
  151. package/src/zexus/zexus_ast.py +63 -11
  152. package/src/zexus/zexus_token.py +13 -5
  153. package/src/zexus/zpm/installer.py +55 -15
  154. package/src/zexus/zpm/package_manager.py +1 -1
  155. package/src/zexus/zpm/registry.py +257 -28
  156. package/src/zexus.egg-info/PKG-INFO +7 -4
  157. package/src/zexus.egg-info/SOURCES.txt +116 -9
  158. package/src/zexus.egg-info/entry_points.txt +1 -0
  159. package/src/zexus.egg-info/requires.txt +4 -0
@@ -54,18 +54,44 @@ class BytecodeCompiler:
54
54
 
55
55
  self._compile_node(node)
56
56
 
57
+ self._resolve_labels()
58
+
57
59
  return Bytecode(self.instructions, self.constants)
58
60
 
61
+ def _resolve_labels(self):
62
+ """Resolve label strings to instruction indices"""
63
+ labels = {}
64
+
65
+ # 1. Map labels
66
+ for i, (op, operand) in enumerate(self.instructions):
67
+ if op == Opcode.NOP and isinstance(operand, str) and operand.startswith('L'):
68
+ labels[operand] = i
69
+
70
+ # 2. Update jumps
71
+ for i, (op, operand) in enumerate(self.instructions):
72
+ if op in (Opcode.JUMP, Opcode.JUMP_IF_FALSE, Opcode.JUMP_IF_TRUE):
73
+ if isinstance(operand, str) and operand in labels:
74
+ self.instructions[i] = (op, labels[operand])
75
+
59
76
  def _add_constant(self, value) -> int:
60
77
  """Add constant to pool, return index"""
61
- # Deduplicate constants
62
- key = (type(value).__name__, str(value))
63
- if key in self.constant_map:
78
+ # Deduplicate only cheap, stable primitive constants.
79
+ # Avoid calling str(value) for large/complex values (AST nodes, dicts,
80
+ # bytecode specs) because that can be expensive on large programs and
81
+ # can balloon memory.
82
+ key = None
83
+ if value is None or isinstance(value, (bool, int, float, str)):
84
+ if isinstance(value, str) and len(value) > 256:
85
+ key = None
86
+ else:
87
+ key = (type(value), value)
88
+ if key is not None and key in self.constant_map:
64
89
  return self.constant_map[key]
65
90
 
66
91
  idx = len(self.constants)
67
92
  self.constants.append(value)
68
- self.constant_map[key] = idx
93
+ if key is not None:
94
+ self.constant_map[key] = idx
69
95
  return idx
70
96
 
71
97
  def _emit(self, opcode: Opcode, *args):
@@ -117,6 +143,7 @@ class BytecodeCompiler:
117
143
  """Return a friendly message for unsupported nodes."""
118
144
  hints = {
119
145
  "UseStatement": "Module imports",
146
+ "FromStatement": "Module imports",
120
147
  "EntityStatement": "Entity declarations",
121
148
  "ContractStatement": "Contract declarations",
122
149
  "ActionStatement": "Action/function declarations",
@@ -170,7 +197,53 @@ class BytecodeCompiler:
170
197
  self._emit(Opcode.PRINT)
171
198
 
172
199
  def _compile_LetStatement(self, node):
173
- """Compile let/const declaration"""
200
+ """Compile let/const declaration, including destructuring patterns."""
201
+ from ..zexus_ast import DestructurePattern
202
+
203
+ if isinstance(node.name, DestructurePattern):
204
+ # Compile the RHS value expression — leaves it on the stack
205
+ self._compile_node(node.value)
206
+ pattern = node.name
207
+
208
+ if pattern.kind == 'map':
209
+ for source_key, target_name in pattern.bindings:
210
+ # DUP the map on the stack so we can index multiple times
211
+ self._emit(Opcode.DUP)
212
+ # Push the key string
213
+ key_idx = self._add_constant(source_key)
214
+ self._emit(Opcode.LOAD_CONST, key_idx)
215
+ # Index into the map: map[key]
216
+ self._emit(Opcode.INDEX)
217
+ # Store to local name
218
+ name_idx = self._add_constant(target_name)
219
+ self._emit(Opcode.STORE_NAME, name_idx)
220
+ # Pop the original map off the stack
221
+ self._emit(Opcode.POP)
222
+ elif pattern.kind == 'list':
223
+ for idx, target_name in pattern.bindings:
224
+ self._emit(Opcode.DUP)
225
+ idx_const = self._add_constant(idx)
226
+ self._emit(Opcode.LOAD_CONST, idx_const)
227
+ self._emit(Opcode.INDEX)
228
+ name_idx = self._add_constant(target_name)
229
+ self._emit(Opcode.STORE_NAME, name_idx)
230
+ # Handle rest element: ..rest captures remaining items
231
+ if pattern.rest:
232
+ rest_start = len(pattern.bindings)
233
+ # SLICE expects stack: [obj, start, end]
234
+ self._emit(Opcode.DUP) # list
235
+ start_idx = self._add_constant(rest_start)
236
+ self._emit(Opcode.LOAD_CONST, start_idx) # start
237
+ none_idx = self._add_constant(None)
238
+ self._emit(Opcode.LOAD_CONST, none_idx) # end (None = to end)
239
+ self._emit(Opcode.SLICE)
240
+ rest_name_idx = self._add_constant(pattern.rest)
241
+ self._emit(Opcode.STORE_NAME, rest_name_idx)
242
+ # Pop the original list off the stack
243
+ self._emit(Opcode.POP)
244
+ return
245
+
246
+ # Normal (non-destructuring) let/const
174
247
  # Compile value
175
248
  self._compile_node(node.value)
176
249
 
@@ -224,6 +297,30 @@ class BytecodeCompiler:
224
297
  """Load boolean constant"""
225
298
  const_idx = self._add_constant(node.value)
226
299
  self._emit(Opcode.LOAD_CONST, const_idx)
300
+
301
+ def _compile_NullLiteral(self, node):
302
+ """Load null constant"""
303
+ const_idx = self._add_constant(None)
304
+ self._emit(Opcode.LOAD_CONST, const_idx)
305
+
306
+ def _compile_PropertyAccessExpression(self, node):
307
+ """Compile property access"""
308
+ # Compile object
309
+ self._compile_node(node.object)
310
+
311
+ if node.computed:
312
+ # Bracket notation: obj[expr]
313
+ self._compile_node(node.property)
314
+ self._emit(Opcode.INDEX)
315
+ else:
316
+ # Dot notation: obj.prop
317
+ if hasattr(node.property, 'value'):
318
+ name = node.property.value
319
+ else:
320
+ name = str(node.property)
321
+ const_idx = self._add_constant(name)
322
+ self._emit(Opcode.LOAD_CONST, const_idx)
323
+ self._emit(Opcode.GET_ATTR)
227
324
 
228
325
  # ==================== Binary Operations ====================
229
326
 
@@ -300,6 +397,29 @@ class BytecodeCompiler:
300
397
  self._emit(Opcode.NOP)
301
398
  self.instructions[-1] = (Opcode.NOP, end_label)
302
399
 
400
+ _compile_IfStatement = _compile_IfExpression
401
+
402
+ def _compile_TernaryExpression(self, node):
403
+ """Compile ternary expression (cond ? true : false)"""
404
+ # Compile condition
405
+ self._compile_node(node.condition)
406
+
407
+ # Jump if false
408
+ else_label = self._make_label()
409
+ end_label = self._make_label()
410
+
411
+ self._emit(Opcode.JUMP_IF_FALSE, else_label)
412
+
413
+ # True branch
414
+ self._compile_node(node.true_value)
415
+ self._emit(Opcode.JUMP, end_label)
416
+
417
+ # False branch
418
+ self._mark_label(else_label)
419
+ self._compile_node(node.false_value)
420
+
421
+ self._mark_label(end_label)
422
+
303
423
  def _compile_WhileStatement(self, node):
304
424
  """Compile while loop"""
305
425
  start_label = self._make_label()
@@ -423,6 +543,8 @@ class BytecodeCompiler:
423
543
  count = len(node.elements)
424
544
  self._emit(Opcode.BUILD_LIST, count)
425
545
 
546
+ _compile_ListLiteral = _compile_ArrayLiteral
547
+
426
548
  def _compile_MapLiteral(self, node):
427
549
  """Compile map/dictionary literal"""
428
550
  # Compile key-value pairs
@@ -447,7 +569,583 @@ class BytecodeCompiler:
447
569
  self._compile_node(node.left)
448
570
  self._compile_node(node.index)
449
571
  self._emit(Opcode.INDEX)
572
+
573
+ def _compile_PropertyAccessExpression(self, node):
574
+ """Compile property access (obj.prop or obj[expr])."""
575
+ self._compile_node(node.object)
576
+
577
+ if getattr(node, "computed", False):
578
+ self._compile_node(node.property)
579
+ else:
580
+ prop_name = node.property.value if hasattr(node.property, 'value') else str(node.property)
581
+ prop_idx = self._add_constant(prop_name)
582
+ self._emit(Opcode.LOAD_CONST, prop_idx)
583
+
584
+ self._emit(Opcode.INDEX)
585
+
586
+ def _compile_SliceExpression(self, node):
587
+ """Compile slice expression: obj[start:end]"""
588
+ self._compile_node(node.object)
589
+
590
+ if node.start is not None:
591
+ self._compile_node(node.start)
592
+ else:
593
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
594
+
595
+ if node.end is not None:
596
+ self._compile_node(node.end)
597
+ else:
598
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
599
+
600
+ self._emit(Opcode.SLICE)
601
+
602
+ # ==================== Advanced Control Flow & Declarations ====================
603
+
604
+ def _compile_ActionStatement(self, node):
605
+ """Compile action/function definition"""
606
+ # Create a new compiler for the function body
607
+ func_compiler = self.__class__()
608
+
609
+ # Compile body
610
+ func_compiler._compile_node(node.body)
611
+
612
+ # Ensure implicit return (null) if execution flows off the end
613
+ null_idx = func_compiler._add_constant(None)
614
+ func_compiler._emit(Opcode.LOAD_CONST, null_idx)
615
+ func_compiler._emit(Opcode.RETURN)
616
+
617
+ # Get bytecode
618
+ from .bytecode import Bytecode
619
+ func_compiler._resolve_labels()
620
+ func_bytecode = Bytecode(func_compiler.instructions, func_compiler.constants)
621
+
622
+ # Prepare function descriptor
623
+ params = [p.value if hasattr(p, 'value') else str(p) for p in node.parameters]
624
+ func_desc = {
625
+ "bytecode": func_bytecode,
626
+ "params": params,
627
+ "is_async": getattr(node, 'is_async', False),
628
+ "name": node.name.value if hasattr(node.name, 'value') else str(node.name)
629
+ }
630
+
631
+ # Store using STORE_FUNC
632
+ # Operand: (name_idx, func_const_idx)
633
+ func_idx = self._add_constant(func_desc)
634
+ name_idx = self._add_constant(func_desc["name"])
635
+
636
+ self._emit(Opcode.STORE_FUNC, (name_idx, func_idx))
637
+
638
+ # Aliases for other function types
639
+ _compile_FunctionStatement = _compile_ActionStatement
640
+ _compile_PureFunctionStatement = _compile_ActionStatement
641
+
642
+ def _compile_ConstStatement(self, node):
643
+ """Compile const declaration (same as Let for current VM)"""
644
+ self._compile_LetStatement(node)
645
+
646
+ def _compile_FileImportExpression(self, node):
647
+ """Compile file import expression (<<)"""
648
+ self._compile_node(node.filepath)
649
+ self._emit(Opcode.READ)
650
+
651
+ def _compile_AssignmentExpression(self, node):
652
+ """Compile variable or property assignment"""
653
+
654
+ # Check target type
655
+ target = node.name
656
+
657
+ # 1. Variable Assignment (target is Identifier or string)
658
+ if isinstance(target, (zexus_ast.Identifier, str)):
659
+ self._compile_node(node.value)
660
+ self._emit(Opcode.DUP)
661
+ name = target.value if hasattr(target, 'value') else str(target)
662
+ name_idx = self._add_constant(name)
663
+ self._emit(Opcode.STORE_NAME, name_idx)
664
+ return
665
+
666
+ # 2. Property/Index Assignment (target[key] = value, target.prop = value)
667
+ if hasattr(zexus_ast, 'IndexExpression') and isinstance(target, zexus_ast.IndexExpression) or \
668
+ isinstance(target, zexus_ast.PropertyAccessExpression):
669
+ # Transform to obj.set(key, value)
670
+
671
+ # 2a. Compile object
672
+ obj = target.object if isinstance(target, zexus_ast.PropertyAccessExpression) else target.left
673
+ self._compile_node(obj)
674
+
675
+ # 2b. Compile key
676
+ if isinstance(target, zexus_ast.PropertyAccessExpression):
677
+ if target.computed:
678
+ self._compile_node(target.property)
679
+ else:
680
+ if hasattr(target.property, 'value'):
681
+ prop_name = target.property.value
682
+ else:
683
+ prop_name = str(target.property)
684
+ idx = self._add_constant(prop_name)
685
+ self._emit(Opcode.LOAD_CONST, idx)
686
+ else: # IndexExpression
687
+ self._compile_node(target.index)
688
+
689
+ # 2c. Compile value
690
+ self._compile_node(node.value)
691
+
692
+ # 2d. Call set(key, value)
693
+ method_idx = self._add_constant("set")
694
+ self._emit(Opcode.CALL_METHOD, (method_idx, 2))
695
+ return
696
+
697
+ raise UnsupportedNodeError(type(target).__name__, "Assignment target not supported")
698
+
699
+ def _compile_UseStatement(self, node):
700
+ """Compile module import via VM import helper."""
701
+ file_path_attr = getattr(node, 'file_path', None) or getattr(node, 'embedded_ref', None)
702
+ path = file_path_attr.value if hasattr(file_path_attr, 'value') else str(file_path_attr or "")
703
+ alias = node.alias.value if node.alias and hasattr(node.alias, 'value') else (node.alias or "")
704
+
705
+ names_list = []
706
+ if getattr(node, 'names', None):
707
+ for entry in node.names:
708
+ if entry is None:
709
+ continue
710
+ names_list.append(entry.value if hasattr(entry, 'value') else str(entry))
711
+
712
+ spec = {
713
+ "file": path,
714
+ "alias": alias,
715
+ "names": names_list,
716
+ "is_named": bool(getattr(node, 'is_named_import', False)) and len(names_list) > 0,
717
+ }
718
+
719
+ spec_idx = self._add_constant(spec)
720
+ self._emit(Opcode.LOAD_CONST, spec_idx)
721
+ name_idx = self._add_constant("__vm_use_module__")
722
+ self._emit(Opcode.CALL_NAME, (name_idx, 1))
723
+ self._emit(Opcode.POP)
724
+
725
+ def _compile_FromStatement(self, node):
726
+ """Compile from-import statements into VM helper calls."""
727
+ file_path_attr = getattr(node, 'file_path', None) or getattr(node, 'embedded_ref', None)
728
+ file_path = file_path_attr.value if hasattr(file_path_attr, 'value') else str(file_path_attr or "")
729
+ entries = []
730
+ for entry in getattr(node, 'imports', []) or []:
731
+ if isinstance(entry, (list, tuple)):
732
+ base = entry[0] if len(entry) > 0 else None
733
+ alias = entry[1] if len(entry) > 1 else None
734
+ else:
735
+ base = entry
736
+ alias = None
737
+ if base is None:
738
+ continue
739
+ entries.append({
740
+ "name": base.value if hasattr(base, 'value') else str(base),
741
+ "alias": alias.value if hasattr(alias, 'value') else (str(alias) if alias else ""),
742
+ })
743
+
744
+ spec = {
745
+ "file": file_path,
746
+ "imports": entries,
747
+ }
748
+
749
+ spec_idx = self._add_constant(spec)
750
+ self._emit(Opcode.LOAD_CONST, spec_idx)
751
+ name_idx = self._add_constant("__vm_from_module__")
752
+ self._emit(Opcode.CALL_NAME, (name_idx, 1))
753
+ self._emit(Opcode.POP)
754
+
755
+ def _compile_TxStatement(self, node):
756
+ """Compile transaction block with automatic revert on error.
757
+
758
+ Emits:
759
+ TX_BEGIN
760
+ SETUP_TRY catch_label
761
+ <body>
762
+ POP_TRY
763
+ TX_COMMIT
764
+ JUMP end_label
765
+ catch_label:
766
+ POP ; discard exception value
767
+ TX_REVERT
768
+ THROW ; re-raise so callers see the error
769
+ end_label:
770
+ """
771
+ catch_label = self._make_label()
772
+ end_label = self._make_label()
773
+
774
+ self._emit(Opcode.TX_BEGIN)
775
+ self._emit(Opcode.SETUP_TRY, catch_label)
776
+ self._compile_node(node.body)
777
+ self._emit(Opcode.POP_TRY)
778
+ self._emit(Opcode.TX_COMMIT)
779
+ self._emit(Opcode.JUMP, end_label)
780
+
781
+ # Exception handler — revert and re-raise
782
+ self._mark_label(catch_label)
783
+ self._emit(Opcode.TX_REVERT)
784
+ self._emit(Opcode.THROW)
785
+
786
+ self._mark_label(end_label)
787
+
788
+ def _compile_GCStatement(self, node):
789
+ """Compile GC statement"""
790
+ # Call builtin gc(action)
791
+ action = node.action.value if hasattr(node.action, 'value') else str(node.action)
792
+
793
+ # Load 'gc' function name
794
+ gc_idx = self._add_constant("gc")
795
+
796
+ # Load action argument
797
+ action_idx = self._add_constant(action)
798
+ self._emit(Opcode.LOAD_CONST, action_idx)
799
+
800
+ # Call gc(action)
801
+ self._emit(Opcode.CALL_NAME, (gc_idx, 1))
802
+ self._emit(Opcode.POP)
803
+
450
804
 
805
+ def _compile_ContractStatement(self, node):
806
+ """Compile smart contract definition into bytecode that creates a real
807
+ SmartContract object at runtime.
808
+
809
+ Stack layout at DEFINE_CONTRACT execution (top → bottom):
810
+ contract_name
811
+ value_N, name_N ← last storage var
812
+ ...
813
+ value_1, name_1 ← first storage var
814
+
815
+ The AST node is stored in the constants pool so the VM can create
816
+ Action objects (which hold the AST body + closure environment) and
817
+ access storage_vars metadata for SmartContract construction.
818
+ """
819
+ contract_name = node.name.value
820
+
821
+ # Store the full AST node in constants so the VM has access to
822
+ # action definitions (parameters, body) and storage_vars metadata.
823
+ ast_idx = self._add_constant(node)
824
+
825
+ # Compile storage initial values to bytecode.
826
+ # Each var pushes (name, value) onto the stack.
827
+ storage_vars = getattr(node, 'storage_vars', [])
828
+ for sv in storage_vars:
829
+ # Push var name
830
+ var_name = sv.name.value if hasattr(sv, 'name') and hasattr(sv.name, 'value') else str(getattr(sv, 'name', ''))
831
+ self._emit(Opcode.LOAD_CONST, self._add_constant(var_name))
832
+ # Push initial value (or None)
833
+ if getattr(sv, 'initial_value', None):
834
+ self._compile_node(sv.initial_value)
835
+ else:
836
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
837
+
838
+ # Push contract name
839
+ name_idx = self._add_constant(contract_name)
840
+ self._emit(Opcode.LOAD_CONST, name_idx)
841
+
842
+ # Emit DEFINE_CONTRACT with (ast_idx, storage_count) so the VM can
843
+ # reconstruct the full SmartContract.
844
+ self._emit(Opcode.DEFINE_CONTRACT, (ast_idx, len(storage_vars)))
845
+
846
+ # Store the contract in the environment
847
+ self._emit(Opcode.STORE_NAME, name_idx)
848
+
849
+ def _compile_BreakStatement(self, node):
850
+ """Compile break statement"""
851
+ if not self.loop_stack:
852
+ raise BytecodeCompilationError("Break statement outside loop")
853
+ self._emit(Opcode.JUMP, self.loop_stack[-1]['end'])
854
+
855
+ def _compile_ContinueStatement(self, node):
856
+ """Compile continue statement
857
+
858
+ Behavior:
859
+ - If inside a loop: Jump to loop start (next iteration).
860
+ - If outside a loop: Enable 'Continue On Error' mode globally.
861
+ """
862
+ if self.loop_stack:
863
+ # Inside loop: Standard control flow
864
+ self._emit(Opcode.JUMP, self.loop_stack[-1]['continue'])
865
+ else:
866
+ # Outside loop: Enable error resilience
867
+ self._emit(Opcode.ENABLE_ERROR_MODE)
868
+
869
+ def _compile_RequireStatement(self, node):
870
+ """Compile require(condition, message)"""
871
+ self._compile_node(node.condition)
872
+
873
+ if node.message:
874
+ self._compile_node(node.message)
875
+ else:
876
+ self._emit(Opcode.LOAD_CONST, self._add_constant("Requirement failed"))
877
+
878
+ self._emit(Opcode.REQUIRE)
879
+
880
+ def _compile_RevertStatement(self, node):
881
+ """Compile revert(reason)"""
882
+ if node.reason:
883
+ self._compile_node(node.reason)
884
+ else:
885
+ self._emit(Opcode.LOAD_CONST, self._add_constant("Transaction reverted"))
886
+
887
+ self._emit(Opcode.TX_REVERT)
888
+
889
+ def _compile_TryCatchStatement(self, node):
890
+ """Compile try-catch block"""
891
+ catch_label = self._make_label()
892
+ end_label = self._make_label()
893
+
894
+ # SETUP_TRY catch_label
895
+ # (Assuming SETUP_TRY takes a jump target)
896
+ # Note: Opcode must handle jump target resolution.
897
+ # Typically JUMP opcodes use labels. Here we treat SETUP_TRY like a jump-setup.
898
+ self._emit(Opcode.SETUP_TRY, catch_label)
899
+
900
+ self._compile_node(node.try_block)
901
+
902
+ self._emit(Opcode.POP_TRY)
903
+ self._emit(Opcode.JUMP, end_label)
904
+
905
+ # Catch block
906
+ self._mark_label(catch_label)
907
+
908
+ # Exception provided on stack?
909
+ if node.error_variable:
910
+ self._emit(Opcode.STORE_NAME, self._add_constant(node.error_variable.value))
911
+ else:
912
+ self._emit(Opcode.POP)
913
+
914
+ self._compile_node(node.catch_block)
915
+
916
+ self._mark_label(end_label)
917
+
918
+ def _unsupported_message(self, node_type):
919
+ """Helper for unsupported messages"""
920
+ return f"Node type '{node_type}' is not currently supported by the bytecode compiler."
921
+
922
+ def _compile_AwaitExpression(self, node):
923
+ """Compile await expression"""
924
+ self._compile_node(node.argument)
925
+ self._emit(Opcode.AWAIT)
926
+
927
+ def _compile_ThisExpression(self, node):
928
+ """Compile 'this' expression"""
929
+ # Load 'this' from environment (it's passed as implicit argument in methods)
930
+ name_idx = self._add_constant("this")
931
+ self._emit(Opcode.LOAD_NAME, name_idx)
932
+
933
+ def _compile_EntityStatement(self, node):
934
+ """Compile Entity definition"""
935
+ # Similar to Contract, but uses DEFINE_ENTITY
936
+ entity_name = node.name.value
937
+ name_idx = self._add_constant(entity_name)
938
+
939
+ # Push name
940
+ self._emit(Opcode.LOAD_CONST, name_idx)
941
+
942
+ # Compile body members
943
+ member_count = 0
944
+ if hasattr(node.body, 'statements'):
945
+ for stmt in node.body.statements:
946
+ stmt_type = type(stmt).__name__
947
+ # Reuse state/action compilation
948
+ if stmt_type in ('StateStatement', 'ActionStatement'):
949
+ if stmt_type == 'StateStatement':
950
+ # Value
951
+ if getattr(stmt, 'initial_value', None):
952
+ self._compile_node(stmt.initial_value)
953
+ else:
954
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
955
+ # Name
956
+ self._emit(Opcode.LOAD_CONST, self._add_constant(stmt.name.value))
957
+ elif stmt_type == 'ActionStatement':
958
+ self._compile_node(stmt)
959
+ self._emit(Opcode.LOAD_NAME, self._add_constant(stmt.name.value))
960
+ self._emit(Opcode.LOAD_CONST, self._add_constant(stmt.name.value))
961
+
962
+ member_count += 1
963
+
964
+ self._emit(Opcode.DEFINE_ENTITY, member_count)
965
+ self._emit(Opcode.STORE_NAME, name_idx)
966
+
967
+ def _compile_DataStatement(self, node):
968
+ """Compile Data/Dataclass definition"""
969
+ # Data objects are simpler entities
970
+ # For now, map to Entity logic or simple Struct
971
+ # We'll use DEFINE_ENTITY for now to keep it uniform
972
+
973
+ data_name = node.name.value
974
+ name_idx = self._add_constant(data_name)
975
+ self._emit(Opcode.LOAD_CONST, name_idx)
976
+
977
+ member_count = 0
978
+ if node.fields:
979
+ for field in node.fields:
980
+ # Default value
981
+ if field.default_value:
982
+ self._compile_node(field.default_value)
983
+ else:
984
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
985
+
986
+ # Field name
987
+ field_name = field.name.value if hasattr(field.name, 'value') else str(field.name)
988
+ self._emit(Opcode.LOAD_CONST, self._add_constant(field_name))
989
+ member_count += 1
990
+
991
+ self._emit(Opcode.DEFINE_ENTITY, member_count)
992
+ self._emit(Opcode.STORE_NAME, name_idx)
993
+
994
+ def _compile_CapabilityStatement(self, node):
995
+ """Compile capability definition"""
996
+ # Load definition map
997
+ if node.definition:
998
+ self._compile_node(node.definition)
999
+ else:
1000
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
1001
+
1002
+ # Load name
1003
+ name = node.name.value if hasattr(node.name, 'value') else str(node.name)
1004
+ self._emit(Opcode.LOAD_CONST, self._add_constant(name))
1005
+
1006
+ self._emit(Opcode.DEFINE_CAPABILITY)
1007
+
1008
+ def _compile_GrantStatement(self, node):
1009
+ """Compile grant capability"""
1010
+ # Logic: Push Entity (or name), Push Caps... Emit GRANT
1011
+
1012
+ # Push entity name (string)
1013
+ entity = node.entity_name.value if hasattr(node.entity_name, 'value') else str(node.entity_name)
1014
+ self._emit(Opcode.LOAD_CONST, self._add_constant(entity))
1015
+
1016
+ # Traverse capabilities
1017
+ count = 0
1018
+ for cap in node.capabilities:
1019
+ cap_name = cap.value if hasattr(cap, 'value') else str(cap)
1020
+ self._emit(Opcode.LOAD_CONST, self._add_constant(cap_name))
1021
+ count += 1
1022
+
1023
+ self._emit(Opcode.GRANT_CAPABILITY, count)
1024
+
1025
+ def _compile_RevokeStatement(self, node):
1026
+ """Compile revoke capability"""
1027
+ # Push entity name
1028
+ entity = node.entity_name.value if hasattr(node.entity_name, 'value') else str(node.entity_name)
1029
+ self._emit(Opcode.LOAD_CONST, self._add_constant(entity))
1030
+
1031
+ # Traverse capabilities
1032
+ count = 0
1033
+ for cap in node.capabilities:
1034
+ cap_name = cap.value if hasattr(cap, 'value') else str(cap)
1035
+ self._emit(Opcode.LOAD_CONST, self._add_constant(cap_name))
1036
+ count += 1
1037
+
1038
+ self._emit(Opcode.REVOKE_CAPABILITY, count)
1039
+
1040
+ def _compile_AuditStatement(self, node):
1041
+ """Compile audit log"""
1042
+ # AuditStatement(data_name, action_type, timestamp)
1043
+
1044
+ # Load data name (variable being audited)
1045
+ data_name = node.data_name.value if hasattr(node.data_name, 'value') else str(node.data_name)
1046
+ self._emit(Opcode.LOAD_CONST, self._add_constant(data_name))
1047
+
1048
+ # Load action type
1049
+ if hasattr(node.action_type, 'value'):
1050
+ self._emit(Opcode.LOAD_CONST, self._add_constant(node.action_type.value))
1051
+ else:
1052
+ self._emit(Opcode.LOAD_CONST, self._add_constant(str(node.action_type)))
1053
+
1054
+ # Load timestamp (if any)
1055
+ if node.timestamp:
1056
+ self._compile_node(node.timestamp)
1057
+ else:
1058
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None))
1059
+
1060
+ self._emit(Opcode.AUDIT_LOG)
1061
+
1062
+ def _compile_RestrictStatement(self, node):
1063
+ """Compile restrict access"""
1064
+ # RestrictStatement(target, restriction_type)
1065
+ # target is PropertyAccessExpression usually (obj.field) or Identifier
1066
+
1067
+ if hasattr(node.target, 'object'):
1068
+ # Property access: obj.field
1069
+ self._compile_node(node.target.object) # Push object
1070
+
1071
+ # Helper to get property name
1072
+ prop_name = node.target.property.value if hasattr(node.target.property, 'value') else str(node.target.property)
1073
+ self._emit(Opcode.LOAD_CONST, self._add_constant(prop_name))
1074
+ else:
1075
+ # Just identifier
1076
+ self._emit(Opcode.LOAD_NAME, self._add_constant(node.target.value))
1077
+ self._emit(Opcode.LOAD_CONST, self._add_constant(None)) # No property
1078
+
1079
+ # Load restriction string
1080
+ res_type = node.restriction_type if isinstance(node.restriction_type, str) else str(node.restriction_type)
1081
+ self._emit(Opcode.LOAD_CONST, self._add_constant(res_type))
1082
+
1083
+ self._emit(Opcode.RESTRICT_ACCESS)
1084
+
1085
+
1086
+ def _compile_PatternStatement(self, node):
1087
+ """Compile pattern matching (match statement)"""
1088
+ # Logic:
1089
+ # evaluate value -> store in temp
1090
+ # for each case:
1091
+ # load value
1092
+ # evaluate pattern
1093
+ # check match (simulated EQ)
1094
+ # jump_if_false -> next_case
1095
+ # execute action
1096
+ # jump -> end
1097
+
1098
+ # Evaluate match subject
1099
+ self._compile_node(node.value if hasattr(node, 'value') else node.expression)
1100
+
1101
+ end_label = self._make_label()
1102
+
1103
+ # Iterate cases
1104
+ for case in node.cases:
1105
+ next_case_lbl = self._make_label()
1106
+
1107
+ # Duplicate Subject (Stack: [..., subj, subj])
1108
+ self._emit(Opcode.DUP)
1109
+
1110
+ # Evaluate Pattern
1111
+ # Note: AST might call it 'pattern' or something else depending on Case node type
1112
+ pattern_node = getattr(case, 'pattern', None)
1113
+ if pattern_node:
1114
+ # LiteralPattern holds a literal node in .value
1115
+ if isinstance(pattern_node, zexus_ast.LiteralPattern):
1116
+ self._compile_node(pattern_node.value)
1117
+ # Wildcard/Variable patterns always match; skip pattern compilation
1118
+ elif isinstance(pattern_node, (zexus_ast.WildcardPattern, zexus_ast.VariablePattern)):
1119
+ pass
1120
+ else:
1121
+ self._compile_node(pattern_node)
1122
+
1123
+ # Equality check
1124
+ self._emit(Opcode.EQ)
1125
+
1126
+ # Jump if False
1127
+ self._emit(Opcode.JUMP_IF_FALSE, next_case_lbl)
1128
+
1129
+ # Match!
1130
+ # Pop subject
1131
+ self._emit(Opcode.POP)
1132
+
1133
+ # Execute Action/Consequence
1134
+ # MatchExpression uses 'consequence', PatternStatement uses 'action', MatchCase uses 'result'
1135
+ body = getattr(case, 'consequence', getattr(case, 'action', getattr(case, 'result', None)))
1136
+ self._compile_node(body)
1137
+ self._emit(Opcode.JUMP, end_label)
1138
+
1139
+ # Next Case
1140
+ self._mark_label(next_case_lbl)
1141
+
1142
+ # No match? Pop subject
1143
+ self._emit(Opcode.POP)
1144
+ self._mark_label(end_label)
1145
+
1146
+ # Alias MatchExpression to logic (it's similar enough for basic cases)
1147
+ _compile_MatchExpression = _compile_PatternStatement
1148
+
451
1149
  # ==================== Fallback for unsupported nodes ====================
452
1150
 
453
1151
  def __getattr__(self, name):