zexus 1.7.2 → 1.8.0

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.
@@ -59,7 +59,7 @@ class GasCost(IntEnum):
59
59
  CALL_TOP = 10
60
60
  CALL_METHOD = 10
61
61
  CALL_BUILTIN = 8
62
- STORE_FUNC = 5
62
+ STORE_FUNC = 3 # Aligned with Rust — function storage is a cheap memory op
63
63
  BUILD_LAMBDA = 5
64
64
 
65
65
  # Async operations
@@ -71,7 +71,7 @@ class GasCost(IntEnum):
71
71
  VERIFY_SIGNATURE = 100
72
72
  MERKLE_ROOT = 30 # Base cost, + per leaf
73
73
  STATE_READ = 20
74
- STATE_WRITE = 50
74
+ STATE_WRITE = 30 # Reduced: RustStateAdapter caching makes writes memory-local
75
75
  TX_BEGIN = 20
76
76
  TX_COMMIT = 30
77
77
  TX_REVERT = 20
@@ -136,6 +136,17 @@ except Exception:
136
136
  _FASTOPS_AVAILABLE = False
137
137
  _fastops = None
138
138
 
139
+ # Rust VM (Phase 3 — adaptive execution)
140
+ try:
141
+ from zexus_core import RustVMExecutor as _RustVMExecutor
142
+ _RUST_VM_AVAILABLE = True
143
+ except Exception:
144
+ _RUST_VM_AVAILABLE = False
145
+ _RustVMExecutor = None
146
+
147
+ # Sentinel returned when Rust VM signals needs_fallback
148
+ _RUST_VM_FALLBACK_SENTINEL = object()
149
+
139
150
  # Async Optimizer (Phase 8)
140
151
  try:
141
152
  from .async_optimizer import AsyncOptimizer, AsyncOptimizationLevel
@@ -425,6 +436,25 @@ class VM:
425
436
  self._in_execution = 0
426
437
  self._native_jit_auto_enabled = False
427
438
  self._native_jit_auto_threshold = 700
439
+
440
+ # --- Rust VM Adaptive Routing (Phase 3 + Phase 6) ---
441
+ self._rust_vm_available = _RUST_VM_AVAILABLE
442
+ self._rust_vm_executor = _RustVMExecutor() if _RUST_VM_AVAILABLE else None
443
+ self._rust_vm_threshold = 0 # Phase 6: route ALL programs through Rust by default
444
+ try:
445
+ _env_thresh = os.environ.get("ZEXUS_RUST_VM_THRESHOLD")
446
+ if _env_thresh is not None:
447
+ self._rust_vm_threshold = int(_env_thresh)
448
+ except (ValueError, TypeError):
449
+ pass
450
+ self._rust_vm_enabled = self._rust_vm_available # Can be disabled at runtime
451
+ self._rust_vm_stats = {
452
+ "rust_executions": 0,
453
+ "rust_fallbacks": 0,
454
+ "python_executions": 0,
455
+ "total_rust_ops": 0,
456
+ }
457
+
428
458
  self._env_version = 0
429
459
  self._name_cache: Dict[str, Tuple[Any, int]] = {}
430
460
  self._method_cache: Dict[Tuple[type, str], Any] = {}
@@ -1704,6 +1734,126 @@ class VM:
1704
1734
  if tag == "LIST": return [self._eval_hl_op(e) for e in op[1]]
1705
1735
  return None
1706
1736
 
1737
+ # ==================== Rust VM Adaptive Routing (Phase 3) ====================
1738
+
1739
+ def _execute_via_rust_vm(self, bytecode, debug=False):
1740
+ """Serialize bytecode to .zxc and execute via the Rust VM.
1741
+
1742
+ Returns the result value on success, or ``_RUST_VM_FALLBACK_SENTINEL``
1743
+ if the Rust VM signals it needs a Python fallback (e.g. for
1744
+ CALL_NAME / CALL_METHOD that need Python interop).
1745
+ """
1746
+ from .binary_bytecode import serialize as _serialize_zxc
1747
+
1748
+ # Serialize bytecode → .zxc binary
1749
+ zxc_data = _serialize_zxc(bytecode, include_checksum=True)
1750
+
1751
+ # Build env dict for Rust (only simple serializable values)
1752
+ rust_env = {}
1753
+ for k, v in self.env.items():
1754
+ if isinstance(v, (int, float, str, bool, type(None))):
1755
+ rust_env[k] = v
1756
+ elif isinstance(v, ZInteger):
1757
+ rust_env[k] = v.value
1758
+ elif isinstance(v, ZFloat):
1759
+ rust_env[k] = v.value
1760
+ elif isinstance(v, ZString):
1761
+ rust_env[k] = v.value
1762
+ elif isinstance(v, ZBoolean):
1763
+ rust_env[k] = v.value
1764
+ elif isinstance(v, (ZNull, type(None))):
1765
+ rust_env[k] = None
1766
+ # Skip non-serializable values (callables, AST nodes, etc.)
1767
+
1768
+ # Build state dict (if blockchain state exists)
1769
+ rust_state = {}
1770
+ bc_state = self.env.get("_blockchain_state")
1771
+ if bc_state and isinstance(bc_state, dict):
1772
+ for k, v in bc_state.items():
1773
+ if isinstance(v, (int, float, str, bool, type(None))):
1774
+ rust_state[k] = v
1775
+
1776
+ # Gas limit
1777
+ gas_limit = 0
1778
+ if self.gas_metering:
1779
+ remaining_fn = getattr(self.gas_metering, "remaining", None)
1780
+ if callable(remaining_fn):
1781
+ try:
1782
+ rem = remaining_fn()
1783
+ if isinstance(rem, (int, float)) and rem > 0:
1784
+ gas_limit = int(rem)
1785
+ except Exception:
1786
+ pass
1787
+ if gas_limit == 0:
1788
+ gas_limit_val = getattr(self.gas_metering, "gas_limit", 0) or 0
1789
+ gas_used_val = getattr(self.gas_metering, "gas_used", 0) or 0
1790
+ if isinstance(gas_limit_val, (int, float)) and isinstance(gas_used_val, (int, float)):
1791
+ if gas_limit_val > gas_used_val:
1792
+ gas_limit = int(gas_limit_val - gas_used_val)
1793
+
1794
+ # Execute via Rust VM
1795
+ result_dict = self._rust_vm_executor.execute(
1796
+ zxc_data,
1797
+ env=rust_env or None,
1798
+ state=rust_state or None,
1799
+ gas_limit=gas_limit,
1800
+ )
1801
+
1802
+ # Check for fallback
1803
+ if result_dict.get("needs_fallback", False):
1804
+ self._rust_vm_stats["rust_fallbacks"] += 1
1805
+ if debug:
1806
+ print("[VM] Rust VM needs Python fallback — delegating to Python VM")
1807
+ return _RUST_VM_FALLBACK_SENTINEL
1808
+
1809
+ # Check for errors
1810
+ error = result_dict.get("error")
1811
+ if error:
1812
+ if "OutOfGas" in str(error):
1813
+ if self.gas_metering:
1814
+ raise OutOfGasError(str(error))
1815
+ raise RuntimeError(str(error))
1816
+ if "RequireFailed" in str(error):
1817
+ raise RuntimeError(str(error))
1818
+ raise RuntimeError(f"Rust VM error: {error}")
1819
+
1820
+ # Success — update stats
1821
+ self._rust_vm_stats["rust_executions"] += 1
1822
+ self._rust_vm_stats["total_rust_ops"] += result_dict.get("instructions_executed", 0)
1823
+
1824
+ # Bridge gas usage back to Python metering
1825
+ if self.gas_metering:
1826
+ rust_gas = result_dict.get("gas_used", 0)
1827
+ if rust_gas > 0:
1828
+ gas_used_attr = getattr(self.gas_metering, "gas_used", None)
1829
+ if gas_used_attr is not None:
1830
+ self.gas_metering.gas_used = gas_used_attr + rust_gas
1831
+ add_gas = getattr(self.gas_metering, "add_gas", None)
1832
+ if add_gas:
1833
+ add_gas(rust_gas)
1834
+
1835
+ # Merge Rust env back into Python env
1836
+ rust_env_out = result_dict.get("env", {})
1837
+ if rust_env_out:
1838
+ for k, v in rust_env_out.items():
1839
+ self.env[k] = v
1840
+
1841
+ # Merge blockchain state back
1842
+ rust_state_out = result_dict.get("state", {})
1843
+ if rust_state_out and bc_state is not None:
1844
+ for k, v in rust_state_out.items():
1845
+ bc_state[k] = v
1846
+
1847
+ if debug:
1848
+ print(f"[VM] Rust VM executed: ops={result_dict.get('instructions_executed', 0)} "
1849
+ f"gas={result_dict.get('gas_used', 0)}")
1850
+
1851
+ return result_dict.get("result")
1852
+
1853
+ def get_rust_vm_stats(self):
1854
+ """Return statistics about Rust VM usage."""
1855
+ return dict(self._rust_vm_stats)
1856
+
1707
1857
  # ==================== Fast Synchronous Dispatch (Performance Mode) ====================
1708
1858
 
1709
1859
  def _run_stack_bytecode_sync(self, bytecode, debug=False):
@@ -1736,6 +1886,19 @@ class VM:
1736
1886
  except Exception:
1737
1887
  pass
1738
1888
 
1889
+ # Rust VM adaptive routing (Phase 3) — delegate to Rust when
1890
+ # the program is large enough to amortise serialisation overhead.
1891
+ if (self._rust_vm_enabled
1892
+ and self._rust_vm_executor is not None
1893
+ and len(instrs) >= self._rust_vm_threshold):
1894
+ try:
1895
+ rust_result = self._execute_via_rust_vm(bytecode, debug)
1896
+ if rust_result is not _RUST_VM_FALLBACK_SENTINEL:
1897
+ return rust_result
1898
+ # Rust signalled needs_fallback — continue to Python VM
1899
+ except Exception:
1900
+ self._rust_vm_stats["rust_fallbacks"] += 1
1901
+
1739
1902
  # Fast stack implementation
1740
1903
  stack: List[Any] = []
1741
1904
  stack_append = stack.append
@@ -23,7 +23,7 @@ class PackageManager:
23
23
  self.installer = PackageInstaller(self.zpm_dir)
24
24
  self.publisher = PackagePublisher(self.registry)
25
25
 
26
- def init(self, name: str = None, version: str = "1.7.2") -> Dict:
26
+ def init(self, name: str = None, version: str = "1.8.0") -> Dict:
27
27
  """Initialize a new Zexus project with package.json"""
28
28
  if self.config_file.exists():
29
29
  print(f"⚠️ {self.config_file} already exists")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zexus
3
- Version: 1.7.2
3
+ Version: 1.8.0
4
4
  Summary: A modern, security-first programming language with blockchain support
5
5
  Home-page: https://github.com/Zaidux/zexus-interpreter
6
6
  Author: Zaidux
@@ -53,7 +53,7 @@ Dynamic: requires-python
53
53
 
54
54
  <div align="center">
55
55
 
56
- ![Zexus Logo](https://img.shields.io/badge/Zexus-v1.7.2-FF6B35?style=for-the-badge)
56
+ ![Zexus Logo](https://img.shields.io/badge/Zexus-v1.8.0-FF6B35?style=for-the-badge)
57
57
  [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](LICENSE)
58
58
  [![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=for-the-badge&logo=python)](https://python.org)
59
59
  [![GitHub](https://img.shields.io/badge/GitHub-Zaidux/zexus--interpreter-181717?style=for-the-badge&logo=github)](https://github.com/Zaidux/zexus-interpreter)
@@ -118,9 +118,9 @@ Zexus is a next-generation, general-purpose programming language designed for se
118
118
 
119
119
  ---
120
120
 
121
- ## 🎉 What's New in v1.7.2
121
+ ## 🎉 What's New in v1.8.0
122
122
 
123
- ### Latest Features (v1.7.2)
123
+ ### Latest Features (v1.8.0)
124
124
 
125
125
  ✅ **FIND Keyword** - Declarative project search that resolves exact module paths with scope filtering and smart suggestions
126
126
  ✅ **LOAD Keyword & Manager** - Provider-aware configuration loader with built-in ENV, JSON, and YAML support plus caching
@@ -2643,6 +2643,29 @@ See [Ecosystem Strategy](docs/ECOSYSTEM_STRATEGY.md) for detailed roadmap.
2643
2643
  - Consider using `native` keyword for C/C++ FFI
2644
2644
  - Profile with `memory_stats()` to check for leaks
2645
2645
 
2646
+ #### PyPI upload fails on Termux with: "unsupported platform tag 'linux_aarch64'"
2647
+ - PyPI rejects wheels with generic `linux_*` platform tags (common when building on Termux).
2648
+ - **Fix**: upload an sdist (source distribution) and/or a pure-Python wheel:
2649
+ - `python -m pip install --upgrade build twine`
2650
+ - `python -m build` # creates `dist/*.tar.gz` and (by default) a `py3-none-any.whl`
2651
+ - `python -m twine upload dist/*.tar.gz dist/*-py3-none-any.whl`
2652
+ - `ZEXUS_BUILD_EXTENSIONS=1 python -m build` means: **build the optional native extensions** (Cython/C/C++) *in addition* to the Python code (it does not skip Python). This produces a **platform-specific** wheel.
2653
+ - If you want “everything compiled” locally, use:
2654
+ - `ZEXUS_BUILD_EXTENSIONS=1 python -m build`
2655
+ - or `ZEXUS_BUILD_EXTENSIONS=1 python -m pip install .`
2656
+ - For publishing native wheels to PyPI, build them in a manylinux environment (e.g. GitHub Actions + cibuildwheel). Wheels built on Termux are usually **not** PyPI-uploadable.
2657
+ - This repo includes a workflow you can run: `.github/workflows/wheels.yml` (builds manylinux `aarch64` + `x86_64`, plus macOS/Windows wheels).
2658
+ - To publish from GitHub Actions without API tokens, use **PyPI Trusted Publishing**:
2659
+ - PyPI → your project → **Settings** → **Publishing** → **Trusted publishers** → **Add a new trusted publisher**
2660
+ - Provider: **GitHub Actions**
2661
+ - Owner: `Zaidux` (or your GitHub org/user)
2662
+ - Repository: `zexus-interpreter`
2663
+ - Workflow: `.github/workflows/wheels.yml`
2664
+ - Environment: `pypi` (and optionally also add another trusted publisher entry for `testpypi`)
2665
+ - Then either:
2666
+ - Run **Actions → “Build wheels (cibuildwheel)” → Run workflow** and choose `testpypi` first, or
2667
+ - Push a release tag like `v1.7.3` to auto-build + publish
2668
+
2646
2669
  #### Blockchain/Contract issues
2647
2670
  - Remember `TX` is a global context object (uppercase)
2648
2671
  - Use `persistent storage` for contract state
@@ -28,6 +28,13 @@ VULNERABILITY_FINDINGS.md
28
28
  VULNERABILITY_TEST_RESULTS.md
29
29
  ZEXUS_BLOCKCHAIN_REFERENCE.md
30
30
  any.zx
31
+ bench_compare.py
32
+ bench_gas_stress.py
33
+ bench_phase3.py
34
+ bench_phase6.py
35
+ bench_quick.py
36
+ bench_vs.py
37
+ benchmark_rust_vm.py
31
38
  check_action_tokens.py
32
39
  check_tokens.py
33
40
  check_verify_ast.py
@@ -73,6 +80,7 @@ zx-dev
73
80
  zx-run
74
81
  zx.bin
75
82
  .github/linguist.yml
83
+ .github/workflows/wheels.yml
76
84
  .vscode/extensions.json
77
85
  .vscode/settings.json
78
86
  .vscode/extensions/zexus-language/README.md
@@ -264,6 +272,7 @@ docs/PERFORMANCE_FEATURES.md
264
272
  docs/PHILOSOPHY.md
265
273
  docs/PLUGIN_QUICK_REFERENCE.md
266
274
  docs/PLUGIN_SYSTEM.md
275
+ docs/PYPI_TRUSTED_PUBLISHING.md
267
276
  docs/QUICK_REFERENCE.md
268
277
  docs/QUICK_START.md
269
278
  docs/README.md
@@ -477,11 +486,14 @@ linguist-submission/samples/security.zx
477
486
  rust_core/Cargo.lock
478
487
  rust_core/Cargo.toml
479
488
  rust_core/src/binary_bytecode.rs
489
+ rust_core/src/contract_vm.rs
480
490
  rust_core/src/executor.rs
481
491
  rust_core/src/hasher.rs
482
492
  rust_core/src/lib.rs
483
493
  rust_core/src/merkle.rs
494
+ rust_core/src/rust_vm.rs
484
495
  rust_core/src/signature.rs
496
+ rust_core/src/state_adapter.rs
485
497
  rust_core/src/validator.rs
486
498
  samples/basic.zx
487
499
  samples/blockchain.zx
@@ -1088,9 +1100,14 @@ tests/vm/test_memory_pool.py
1088
1100
  tests/vm/test_optimizer.py
1089
1101
  tests/vm/test_parallel_vm.py
1090
1102
  tests/vm/test_peephole_optimizer.py
1103
+ tests/vm/test_phase3_adaptive.py
1104
+ tests/vm/test_phase4_contract_vm.py
1105
+ tests/vm/test_phase5_gil_free.py
1106
+ tests/vm/test_phase6_builtins.py
1091
1107
  tests/vm/test_profiler.py
1092
1108
  tests/vm/test_register_allocator.py
1093
1109
  tests/vm/test_register_vm.py
1110
+ tests/vm/test_rust_vm.py
1094
1111
  tests/vm/test_ssa_converter.py
1095
1112
  tests/vm/test_vm_async_integration.py
1096
1113
  tests/vm/test_vm_memory_pool_integration.py