zexus 1.8.2 → 1.8.3
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 +89 -64
- package/package.json +1 -1
- package/rust_core/Cargo.lock +1 -1
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/builtin_modules.py +50 -13
- package/src/zexus/cli/main.py +46 -1
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/evaluator/bytecode_compiler.py +11 -2
- package/src/zexus/evaluator/core.py +4 -1
- package/src/zexus/evaluator/expressions.py +11 -2
- package/src/zexus/evaluator/functions.py +72 -0
- package/src/zexus/evaluator/resource_limiter.py +1 -1
- package/src/zexus/evaluator/statements.py +44 -4
- package/src/zexus/kernel/__init__.py +34 -0
- package/src/zexus/kernel/hooks.py +276 -0
- package/src/zexus/kernel/registry.py +203 -0
- package/src/zexus/kernel/zir/__init__.py +145 -0
- package/src/zexus/lexer.py +7 -0
- package/src/zexus/object.py +28 -5
- package/src/zexus/parser/parser.py +53 -11
- package/src/zexus/parser/strategy_context.py +179 -10
- package/src/zexus/security.py +26 -2
- package/src/zexus/stdlib/blockchain.py +84 -0
- package/src/zexus/stdlib/http_server.py +2 -2
- package/src/zexus/stdlib/math.py +25 -17
- package/src/zexus/stdlib_integration.py +119 -2
- package/src/zexus/type_checker.py +17 -12
- package/src/zexus/vm/compiler.py +57 -6
- package/src/zexus/vm/fastops.c +4704 -1263
- package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/fastops.pyx +81 -3
- package/src/zexus/vm/optimizer.py +65 -27
- package/src/zexus/vm/vm.py +871 -98
- package/src/zexus/zexus_ast.py +4 -1
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus.egg-info/PKG-INFO +90 -65
- package/src/zexus.egg-info/SOURCES.txt +51 -0
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://python.org)
|
|
8
8
|
[](https://github.com/Zaidux/zexus-interpreter)
|
|
9
9
|
|
|
10
10
|
**A modern, security-first programming language with built-in blockchain support, VM-accelerated execution, advanced memory management, and policy-as-code**
|
|
11
11
|
|
|
12
|
-
[What's New](#-whats-new-in-
|
|
12
|
+
[What's New](#-whats-new-in-v183) • [Features](#-key-features) • [Installation](#-installation) • [Quick Start](#-quick-start) • [Keywords](#-complete-keyword-reference) • [Documentation](#-documentation) • [Examples](#-examples) • [Troubleshooting](#-getting-help--troubleshooting)
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
## 📋 Table of Contents
|
|
19
19
|
|
|
20
20
|
- [What is Zexus?](#-what-is-zexus)
|
|
21
|
-
- [What's New](#-whats-new-in-
|
|
21
|
+
- [What's New](#-whats-new-in-v183)
|
|
22
22
|
- [Key Features](#-key-features)
|
|
23
23
|
- [VM-Accelerated Performance](#-vm-accelerated-performance-new)
|
|
24
24
|
- [Security & Policy-as-Code](#-security--policy-as-code--verify-enhanced)
|
|
@@ -67,71 +67,96 @@ Zexus is a next-generation, general-purpose programming language designed for se
|
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
|
-
## 🎉 What's New in v1.8.
|
|
71
|
-
|
|
72
|
-
###
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
70
|
+
## 🎉 What's New in v1.8.3
|
|
71
|
+
|
|
72
|
+
### v1.8.3 — Phase 0 Audit Fixes, Closure Scoping Overhaul & VM Hardening (2026-03-01)
|
|
73
|
+
|
|
74
|
+
19 issues from the [Ziver-Chain Phase 0 rewrite audit](issues/ISSUE8.md) resolved — including 3 VM-specific critical fixes. Key changes:
|
|
75
|
+
|
|
76
|
+
**VM Fixes & Hardening:**
|
|
77
|
+
- **R-001:** Entity field access on VM now works — proper `EntityDefinition`/`EntityInstance` construction from bytecode
|
|
78
|
+
- **R-002:** Contract `state` declarations now compile correctly (`_compile_StateStatement`)
|
|
79
|
+
- **R-010:** Complex programs no longer silently fail — added `_vm_warn()` diagnostics, replaced 15 silent error handlers
|
|
80
|
+
- Native fast-path (`_vm_native_call`) for `push`/`append`/`length`/`str`/`range` operations on VM-native types
|
|
81
|
+
- `VMRuntimeError(Exception)` replaces non-raisable `ZEvaluationError(Object)` in 15 raise sites
|
|
82
|
+
- Stack overflow protection, execution timeout (30s), opcode limit (100M), configurable VM pool sizing
|
|
83
|
+
- **Rust VM status indicator** — CLI/runner show "Rust VM: active", "available but disabled", or "not compiled"
|
|
84
|
+
|
|
85
|
+
**Closure & Scoping Fixes:**
|
|
86
|
+
- Entity/`let` declarations before a contract no longer break contract visibility — declaration order is now flexible
|
|
87
|
+
- Module-level helper functions called from contract methods now correctly propagate side-effects (`list.push()`, `map[k]=v`)
|
|
88
|
+
- `action protect` now works at module level (policy enforcement added to function call path)
|
|
89
|
+
- Storage sync-back in contract methods improved — `list.push()` after `map[key]=val` no longer silently ignored
|
|
90
|
+
- Exported entities can now be used as constructors in importing files
|
|
91
|
+
|
|
92
|
+
**Contract & Language Fixes:**
|
|
93
|
+
- `self` keyword works as alias for `this` inside contracts
|
|
94
|
+
- `init()` auto-called on `Contract()` construction
|
|
95
|
+
- `state { field1: val, field2: val }` multi-field blocks work correctly
|
|
96
|
+
- `for each i, item in list` (indexed) and `for each key, val in map` now supported
|
|
97
|
+
- `INTEGER * FLOAT` implicit coercion and `%` modulo on floats now work
|
|
98
|
+
- Added `range()`, `typeof()`, `abs()`, `str()`, `length()` builtins; 8 parser edge-case fixes
|
|
99
|
+
|
|
100
|
+
**Stats:** 1852 tests pass, 0 regressions. 5 new extreme test suites (83 tests across speed, stability, security, features, VM). See [CHANGELOG](CHANGELOG.md) for full details.
|
|
101
|
+
|
|
102
|
+
### v1.8.2 — Concurrency & Channel Support (2026-02-25)
|
|
103
|
+
|
|
104
|
+
- `watch =>` arrow-lambda fallback no longer hijacks the strategy parser
|
|
105
|
+
- Channel support in VM compiler (`_compile_ChannelStatement`, `_compile_SendStatement`, `_compile_ReceiveStatement`)
|
|
106
|
+
- SPAWN/AWAIT opcodes in sync path using `threading.Thread(daemon=True)`
|
|
107
|
+
- Strategy parser channel/async handlers added
|
|
108
|
+
- Fixed 10+ missing VM node types; zero VM fallbacks achieved
|
|
109
|
+
- All versions bumped to 1.8.2; Rust VM builds with `maturin develop --release`
|
|
110
|
+
|
|
111
|
+
### v1.8.1 — ISSUE7 Audit & Security Remediation (2026-02-23)
|
|
112
|
+
|
|
113
|
+
All 21 issues from the Phase 0 audit resolved:
|
|
114
|
+
- `emit`, `protocol`, `implements` keywords fully operational in all parsers
|
|
115
|
+
- Entity compilation crash in VM fixed; imported functions no longer return raw Action objects
|
|
116
|
+
- `map.has()` / `map.get()` key normalization fixed
|
|
117
|
+
- ExportStatement supported in VM; entity constructor arity validation relaxed
|
|
118
|
+
- `persistent storage` now wires to SQLite backend with `set_persistent`/`get_persistent`
|
|
119
|
+
- 5 new builtins: `track_memory()`, `cache()`, `throttle()`, `audit()`, `verify()`
|
|
120
|
+
- Complete security remediation Phases 0–5 (sandboxing, ReDoS, import sandboxing, compiler parity, dead-code removal, bounded logs)
|
|
121
|
+
- 1852 tests pass
|
|
122
|
+
|
|
123
|
+
### v1.8.0 — Rust VM Pipeline & Major Features (2026-02-23)
|
|
124
|
+
|
|
125
|
+
**Language Features:** Compound assignment (`+=`, `-=`, etc.), string interpolation (`"Hello ${name}"`), block comments (`/* */`), multiline strings, single-quoted strings, exponentiation (`**`), `finally` clause, destructuring assignment.
|
|
126
|
+
|
|
127
|
+
**Developer Tooling:** Circular import detection, LSP go-to-definition, remote ZPM registry, static type checker.
|
|
128
|
+
|
|
129
|
+
**Major Capabilities:** Debug Adapter Protocol (DAP) server, GUI backend (Tk + Web), true concurrent EventLoop, WASM compilation target.
|
|
130
|
+
|
|
131
|
+
**Rust-First Execution (Phases 0–6):** Complete migration achieving **102,000+ TPS** with zero Python fallbacks. Includes binary `.zxc` format, Rust bytecode interpreter (22 MIPS, 20.7x speedup), adaptive VM routing, `RustContractVM` orchestration, GIL-free batch execution (221,593 TPS peak), and 40+ Rust builtins.
|
|
132
|
+
|
|
133
|
+
### v1.7.x — FIND/LOAD Keywords & Performance (2026-01)
|
|
134
|
+
|
|
135
|
+
- **v1.7.2:** Major interpreter speed improvements, smart storage for lists, optimized stack traces, blockchain perf fix
|
|
136
|
+
- **v1.7.1:** FIND keyword (declarative module search), LOAD keyword (provider-aware config loader), VM bytecode support for both, regression tests
|
|
137
|
+
|
|
138
|
+
### v1.6.x — Database Ecosystem & Security (2025-12 – 2026-01)
|
|
139
|
+
|
|
140
|
+
- **v1.6.8:** Parser fix for indexed assignments on new lines; contract DATA member declarations
|
|
141
|
+
- **v1.6.7:** Semicolon handling fix, context-aware keyword recognition, standalone block statements
|
|
142
|
+
- **v1.6.6:** Repeated contract action calls, multiple indexed assignments
|
|
143
|
+
- **v1.6.5:** Entity property access, keyword restrictions (`from`/`to` as params), multiple map assignments
|
|
144
|
+
- **v1.6.3:** Comprehensive security remediation (10 OWASP categories), RBAC, bcrypt, input sanitization, resource limits, path traversal prevention
|
|
145
|
+
- **v1.6.2:** 4 database drivers (SQLite, PostgreSQL, MySQL, MongoDB), HTTP server, socket/TCP, testing framework, ZPM
|
|
146
|
+
|
|
147
|
+
### v1.5.0 — Error Reporting & Type System (2025-12)
|
|
148
|
+
|
|
149
|
+
World-class error messages (rivaling Rust), generic types, pattern matching, operator overloading, stack trace formatter, smart suggestions, CONTINUE keyword.
|
|
150
|
+
|
|
151
|
+
### v0.1.3 — Foundation (2025-11)
|
|
152
|
+
|
|
153
|
+
130+ keywords, dual-mode DEBUG, conditional print, multiple syntax styles, enterprise keywords, async/await, UI renderer, enhanced VERIFY, blockchain keywords, 100+ builtins.
|
|
129
154
|
|
|
130
155
|
---
|
|
131
156
|
|
|
132
|
-
## 🔒
|
|
157
|
+
## 🔒 Security Features
|
|
133
158
|
|
|
134
|
-
Zexus
|
|
159
|
+
Zexus includes **comprehensive security enhancements** and developer-friendly safety features, making it one of the most secure interpreted languages available with enterprise-grade protection built into the language itself.
|
|
135
160
|
|
|
136
161
|
### 🛡️ Security Features Added
|
|
137
162
|
|
package/package.json
CHANGED
package/rust_core/Cargo.lock
CHANGED
|
@@ -578,7 +578,7 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
|
578
578
|
|
|
579
579
|
[[package]]
|
|
580
580
|
name = "zeroize"
|
|
581
|
-
version = "1.8.
|
|
581
|
+
version = "1.8.3"
|
|
582
582
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
583
583
|
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
|
584
584
|
|
package/src/zexus/__init__.py
CHANGED
|
@@ -121,28 +121,65 @@ def create_builtin_modules(evaluator):
|
|
|
121
121
|
def _crypto_aes_encrypt(*args):
|
|
122
122
|
if len(args) != 2:
|
|
123
123
|
return EvaluationError("aes_encrypt() expects 2 arguments: data, key")
|
|
124
|
-
# Simplified AES - would need proper implementation
|
|
125
124
|
data = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
126
125
|
key = args[1].value if hasattr(args[1], 'value') else str(args[1])
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
try:
|
|
127
|
+
import hashlib, base64, os
|
|
128
|
+
# Derive 256-bit key from user key via SHA-256
|
|
129
|
+
aes_key = hashlib.sha256(key.encode('utf-8')).digest()
|
|
130
|
+
# Use AES-256-GCM for authenticated encryption
|
|
131
|
+
from Crypto.Cipher import AES as _AES
|
|
132
|
+
nonce = os.urandom(12)
|
|
133
|
+
cipher = _AES.new(aes_key, _AES.MODE_GCM, nonce=nonce)
|
|
134
|
+
ciphertext, tag = cipher.encrypt_and_digest(data.encode('utf-8'))
|
|
135
|
+
# Pack: nonce (12) + tag (16) + ciphertext, base64-encoded
|
|
136
|
+
packed = base64.b64encode(nonce + tag + ciphertext).decode('ascii')
|
|
137
|
+
return String(packed)
|
|
138
|
+
except ImportError:
|
|
139
|
+
# Fallback: if pycryptodome not available, use Fernet from cryptography
|
|
140
|
+
try:
|
|
141
|
+
import hashlib, base64
|
|
142
|
+
from cryptography.fernet import Fernet as _Fernet
|
|
143
|
+
fernet_key = base64.urlsafe_b64encode(hashlib.sha256(key.encode('utf-8')).digest())
|
|
144
|
+
f = _Fernet(fernet_key)
|
|
145
|
+
encrypted = f.encrypt(data.encode('utf-8'))
|
|
146
|
+
return String(encrypted.decode('ascii'))
|
|
147
|
+
except ImportError:
|
|
148
|
+
return EvaluationError("aes_encrypt() requires pycryptodome or cryptography package")
|
|
149
|
+
except Exception as e:
|
|
150
|
+
return EvaluationError(f"aes_encrypt() failed: {str(e)}")
|
|
131
151
|
|
|
132
152
|
# aes_decrypt(encrypted_data, key)
|
|
133
153
|
def _crypto_aes_decrypt(*args):
|
|
134
154
|
if len(args) != 2:
|
|
135
155
|
return EvaluationError("aes_decrypt() expects 2 arguments: encrypted_data, key")
|
|
136
|
-
# Simplified AES - would need proper implementation
|
|
137
156
|
encrypted = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
138
157
|
key = args[1].value if hasattr(args[1], 'value') else str(args[1])
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
try:
|
|
159
|
+
import hashlib, base64
|
|
160
|
+
aes_key = hashlib.sha256(key.encode('utf-8')).digest()
|
|
161
|
+
raw = base64.b64decode(encrypted)
|
|
162
|
+
if len(raw) < 28: # 12 nonce + 16 tag minimum
|
|
163
|
+
return EvaluationError("aes_decrypt() invalid ciphertext (too short)")
|
|
164
|
+
nonce = raw[:12]
|
|
165
|
+
tag = raw[12:28]
|
|
166
|
+
ciphertext = raw[28:]
|
|
167
|
+
from Crypto.Cipher import AES as _AES
|
|
168
|
+
cipher = _AES.new(aes_key, _AES.MODE_GCM, nonce=nonce)
|
|
169
|
+
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
|
|
170
|
+
return String(plaintext.decode('utf-8'))
|
|
171
|
+
except ImportError:
|
|
172
|
+
try:
|
|
173
|
+
import hashlib, base64
|
|
174
|
+
from cryptography.fernet import Fernet as _Fernet
|
|
175
|
+
fernet_key = base64.urlsafe_b64encode(hashlib.sha256(key.encode('utf-8')).digest())
|
|
176
|
+
f = _Fernet(fernet_key)
|
|
177
|
+
decrypted = f.decrypt(encrypted.encode('ascii'))
|
|
178
|
+
return String(decrypted.decode('utf-8'))
|
|
179
|
+
except ImportError:
|
|
180
|
+
return EvaluationError("aes_decrypt() requires pycryptodome or cryptography package")
|
|
181
|
+
except Exception as e:
|
|
182
|
+
return EvaluationError(f"aes_decrypt() failed: {str(e)}")
|
|
146
183
|
|
|
147
184
|
# Register all crypto functions
|
|
148
185
|
crypto_env.set("keccak256", Builtin(_crypto_keccak256, "keccak256"))
|
package/src/zexus/cli/main.py
CHANGED
|
@@ -81,6 +81,15 @@ from ..error_reporter import get_error_reporter, ZexusError, print_error
|
|
|
81
81
|
from ..vm.vm import VM, VMMode
|
|
82
82
|
from ..vm.compiler import compile_ast_to_bytecode, UnsupportedNodeError
|
|
83
83
|
|
|
84
|
+
# Kernel extension layer (opt-in, non-breaking)
|
|
85
|
+
try:
|
|
86
|
+
from ..kernel import get_kernel as _get_kernel
|
|
87
|
+
_kernel = _get_kernel().boot()
|
|
88
|
+
KERNEL_AVAILABLE = True
|
|
89
|
+
except Exception:
|
|
90
|
+
_kernel = None
|
|
91
|
+
KERNEL_AVAILABLE = False
|
|
92
|
+
|
|
84
93
|
console = Console()
|
|
85
94
|
|
|
86
95
|
def show_all_commands():
|
|
@@ -156,7 +165,7 @@ def show_all_commands():
|
|
|
156
165
|
console.print("\n[bold green]💡 Tip:[/bold green] Use 'zx <command> --help' for detailed command options\n")
|
|
157
166
|
|
|
158
167
|
@click.group(invoke_without_command=True)
|
|
159
|
-
@click.version_option(version="1.8.
|
|
168
|
+
@click.version_option(version="1.8.3", prog_name="Zexus")
|
|
160
169
|
@click.option('--syntax-style', type=click.Choice(['universal', 'tolerable', 'auto']),
|
|
161
170
|
default='auto', help='Syntax style to use (universal=strict, tolerable=flexible)')
|
|
162
171
|
@click.option('--advanced-parsing', is_flag=True, default=True,
|
|
@@ -556,6 +565,14 @@ def run(ctx, file, args, use_vm, vm_mode, no_optimize, precompile_modules):
|
|
|
556
565
|
vm.env["__PACKAGE__"] = package_name.value if hasattr(package_name, "value") else package_name
|
|
557
566
|
console.print(" [green]done[/green]")
|
|
558
567
|
|
|
568
|
+
# --- Rust VM status indicator ---
|
|
569
|
+
if getattr(vm, '_rust_vm_available', False) and getattr(vm, '_rust_vm_enabled', False):
|
|
570
|
+
console.print("[bold cyan]⚡ Rust VM:[/bold cyan] [green]active[/green] — native acceleration enabled")
|
|
571
|
+
elif getattr(vm, '_rust_vm_available', False):
|
|
572
|
+
console.print("[bold cyan]⚡ Rust VM:[/bold cyan] [yellow]available but disabled[/yellow]")
|
|
573
|
+
else:
|
|
574
|
+
console.print("[bold yellow]⚠️ Rust VM:[/bold yellow] [dim]not compiled — using Python VM (install zexus_core for native speed)[/dim]")
|
|
575
|
+
|
|
559
576
|
console.print("[dim]Executing on VM...[/dim]")
|
|
560
577
|
try:
|
|
561
578
|
result = vm.execute(bytecode, debug=ctx.obj.get('DEBUG', False))
|
|
@@ -1105,5 +1122,33 @@ def profile(ctx, file, memory, top, json_output):
|
|
|
1105
1122
|
traceback.print_exc()
|
|
1106
1123
|
sys.exit(1)
|
|
1107
1124
|
|
|
1125
|
+
|
|
1126
|
+
@cli.command(name="kernel")
|
|
1127
|
+
@click.pass_context
|
|
1128
|
+
def kernel_status(ctx):
|
|
1129
|
+
"""Show Zexus kernel status and registered domains"""
|
|
1130
|
+
if not KERNEL_AVAILABLE or _kernel is None:
|
|
1131
|
+
console.print("[yellow]Kernel not available[/yellow]")
|
|
1132
|
+
sys.exit(1)
|
|
1133
|
+
|
|
1134
|
+
status = _kernel.status()
|
|
1135
|
+
console.print("\n[bold cyan]⚙️ Zexus Kernel Status[/bold cyan]\n")
|
|
1136
|
+
console.print(f" Booted: [green]{status['booted']}[/green]")
|
|
1137
|
+
console.print(f" Domains: [green]{status['domain_count']}[/green]")
|
|
1138
|
+
console.print(f" Opcodes: [green]{status['opcode_handlers']}[/green] handlers")
|
|
1139
|
+
console.print(f" Middleware: [green]{status['middleware']}[/green]\n")
|
|
1140
|
+
|
|
1141
|
+
if status['domains']:
|
|
1142
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
1143
|
+
table.add_column("Domain", style="cyan")
|
|
1144
|
+
table.add_column("Version", style="white")
|
|
1145
|
+
table.add_column("Status", style="green")
|
|
1146
|
+
for name, version in status['domains'].items():
|
|
1147
|
+
domain = _kernel.registry.get_domain(name)
|
|
1148
|
+
n_ops = len(domain.opcodes) if domain else 0
|
|
1149
|
+
table.add_row(name, version, f"{n_ops} opcodes")
|
|
1150
|
+
console.print(table)
|
|
1151
|
+
|
|
1152
|
+
|
|
1108
1153
|
if __name__ == "__main__":
|
|
1109
1154
|
cli()
|
package/src/zexus/cli/zpm.py
CHANGED
|
@@ -813,12 +813,21 @@ class EvaluatorBytecodeCompiler:
|
|
|
813
813
|
|
|
814
814
|
def _compile_MapLiteral(self, node: zexus_ast.MapLiteral):
|
|
815
815
|
"""Compile map/dictionary literal"""
|
|
816
|
+
# node.pairs may be a dict (older parser) or a list of (key, value) tuples
|
|
817
|
+
pairs = node.pairs or []
|
|
818
|
+
if isinstance(pairs, dict):
|
|
819
|
+
iterable = pairs.items()
|
|
820
|
+
count = len(pairs)
|
|
821
|
+
else:
|
|
822
|
+
iterable = pairs
|
|
823
|
+
count = len(pairs)
|
|
824
|
+
|
|
816
825
|
# Push key-value pairs
|
|
817
|
-
for key_expr, value_expr in
|
|
826
|
+
for key_expr, value_expr in iterable:
|
|
818
827
|
self._compile_node(key_expr)
|
|
819
828
|
self._compile_node(value_expr)
|
|
820
829
|
# Build map from stack
|
|
821
|
-
self.builder.emit("BUILD_MAP",
|
|
830
|
+
self.builder.emit("BUILD_MAP", count)
|
|
822
831
|
|
|
823
832
|
# LI12: _compile_PropertyAccessExpression is defined later in this file.
|
|
824
833
|
# The earlier duplicate implementation was dead code (overridden).
|
|
@@ -494,7 +494,10 @@ class Evaluator(ExpressionEvaluatorMixin, StatementEvaluatorMixin, FunctionEvalu
|
|
|
494
494
|
enable_gas_metering=True,
|
|
495
495
|
gas_limit=1_000_000 # Default 1M gas limit
|
|
496
496
|
)
|
|
497
|
-
|
|
497
|
+
# Report Rust VM status
|
|
498
|
+
rust_active = getattr(self.vm_instance, '_rust_vm_available', False) and getattr(self.vm_instance, '_rust_vm_enabled', False)
|
|
499
|
+
rust_label = "Rust VM active" if rust_active else "Python VM"
|
|
500
|
+
debug_log("Evaluator", f"VM integration initialized successfully (cache + JIT + gas metering, {rust_label})")
|
|
498
501
|
except Exception as e:
|
|
499
502
|
debug_log("Evaluator", f"Failed to initialize VM: {e}")
|
|
500
503
|
self.use_vm = False
|
|
@@ -89,8 +89,9 @@ class ExpressionEvaluatorMixin:
|
|
|
89
89
|
if zexus_config.fast_debug_enabled:
|
|
90
90
|
debug_log("eval_identifier", f"Looking up: {name}")
|
|
91
91
|
|
|
92
|
-
# Special case: 'this'
|
|
93
|
-
|
|
92
|
+
# Special case: 'this' and 'self' keywords should be treated like ThisExpression
|
|
93
|
+
# R-003 fix: 'self' is now recognized as an alias for 'this'
|
|
94
|
+
if name == "this" or name == "self":
|
|
94
95
|
# Look for contract instance first
|
|
95
96
|
contract_instance = env.get("__contract_instance__")
|
|
96
97
|
if contract_instance is not None:
|
|
@@ -279,6 +280,11 @@ class ExpressionEvaluatorMixin:
|
|
|
279
280
|
return Float(left_val ** right_val)
|
|
280
281
|
except (OverflowError, ValueError) as e:
|
|
281
282
|
return EvaluationError(f"Exponentiation error: {e}")
|
|
283
|
+
# R-017 fix: Add modulo support for floats
|
|
284
|
+
elif operator == "%":
|
|
285
|
+
if right_val == 0:
|
|
286
|
+
return EvaluationError("Modulo by zero")
|
|
287
|
+
return Float(left_val % right_val)
|
|
282
288
|
|
|
283
289
|
return EvaluationError(f"Unknown float operator: {operator}")
|
|
284
290
|
|
|
@@ -388,6 +394,9 @@ class ExpressionEvaluatorMixin:
|
|
|
388
394
|
f"String repetition count {n} exceeds maximum ({_MAX_STRING_REPEAT})"
|
|
389
395
|
)
|
|
390
396
|
return String(right.value * n)
|
|
397
|
+
# R-016 fix: Handle mixed Integer/Float multiplication
|
|
398
|
+
elif isinstance(left, (Integer, Float)) and isinstance(right, (Integer, Float)):
|
|
399
|
+
return Float(float(left.value) * float(right.value))
|
|
391
400
|
|
|
392
401
|
# Array Concatenation
|
|
393
402
|
elif operator == "+" and isinstance(left, List) and isinstance(right, List):
|
|
@@ -348,6 +348,32 @@ class FunctionEvaluatorMixin:
|
|
|
348
348
|
# Synchronous function execution
|
|
349
349
|
new_env = Environment(outer=fn.env)
|
|
350
350
|
|
|
351
|
+
# R-008 fix: Enforce protection policies for module-level actions.
|
|
352
|
+
# When ``action protect`` is used at module level, the policy is
|
|
353
|
+
# stored in the environment as ``__policy_<name>__``. Check and
|
|
354
|
+
# enforce it before the action body runs.
|
|
355
|
+
_fn_name = getattr(fn, 'name', func_name)
|
|
356
|
+
if _fn_name and env is not None:
|
|
357
|
+
_policy_key = f"__policy_{_fn_name}__"
|
|
358
|
+
_policy = None
|
|
359
|
+
try:
|
|
360
|
+
_policy = env.get(_policy_key) if hasattr(env, 'get') else None
|
|
361
|
+
except Exception:
|
|
362
|
+
pass
|
|
363
|
+
if _policy is not None and _policy is not NULL:
|
|
364
|
+
try:
|
|
365
|
+
from ..policy_engine import get_policy_registry
|
|
366
|
+
registry = get_policy_registry()
|
|
367
|
+
violation = registry.check_policy(_fn_name, {
|
|
368
|
+
"args": args,
|
|
369
|
+
"env": env,
|
|
370
|
+
"caller": env.get("TX.caller") if hasattr(env, 'get') else None,
|
|
371
|
+
})
|
|
372
|
+
if violation:
|
|
373
|
+
return EvaluationError(f"Policy violation on '{_fn_name}': {violation}")
|
|
374
|
+
except (ImportError, AttributeError):
|
|
375
|
+
pass
|
|
376
|
+
|
|
351
377
|
param_names = []
|
|
352
378
|
for i, param in enumerate(fn.parameters):
|
|
353
379
|
if i < len(args):
|
|
@@ -2512,6 +2538,47 @@ class FunctionEvaluatorMixin:
|
|
|
2512
2538
|
return EvaluationError("filter(arr, fn)")
|
|
2513
2539
|
return self._array_filter(a[0], a[1])
|
|
2514
2540
|
|
|
2541
|
+
def _range(*a):
|
|
2542
|
+
"""range(end) or range(start, end) or range(start, end, step)"""
|
|
2543
|
+
if len(a) == 0:
|
|
2544
|
+
return EvaluationError("range() requires 1-3 arguments, got 0")
|
|
2545
|
+
if len(a) == 1:
|
|
2546
|
+
end_val = a[0].value if hasattr(a[0], 'value') else int(a[0])
|
|
2547
|
+
return List([Integer(i) for i in range(end_val)])
|
|
2548
|
+
elif len(a) >= 2:
|
|
2549
|
+
start_val = a[0].value if hasattr(a[0], 'value') else int(a[0])
|
|
2550
|
+
end_val = a[1].value if hasattr(a[1], 'value') else int(a[1])
|
|
2551
|
+
step_val = 1
|
|
2552
|
+
if len(a) >= 3:
|
|
2553
|
+
step_val = a[2].value if hasattr(a[2], 'value') else int(a[2])
|
|
2554
|
+
return List([Integer(i) for i in range(start_val, end_val, step_val)])
|
|
2555
|
+
|
|
2556
|
+
def _typeof(*a):
|
|
2557
|
+
"""typeof(value) - returns the type name as a string"""
|
|
2558
|
+
if len(a) != 1:
|
|
2559
|
+
return EvaluationError("typeof() requires exactly 1 argument")
|
|
2560
|
+
obj = a[0]
|
|
2561
|
+
if isinstance(obj, Integer): return String("integer")
|
|
2562
|
+
if isinstance(obj, Float): return String("float")
|
|
2563
|
+
if isinstance(obj, String): return String("string")
|
|
2564
|
+
if isinstance(obj, BooleanObj): return String("boolean")
|
|
2565
|
+
if obj is NULL or obj is None: return String("null")
|
|
2566
|
+
if isinstance(obj, List): return String("list")
|
|
2567
|
+
if isinstance(obj, Map): return String("map")
|
|
2568
|
+
if isinstance(obj, Action) or isinstance(obj, LambdaFunction): return String("function")
|
|
2569
|
+
from ..security import SmartContract
|
|
2570
|
+
if isinstance(obj, SmartContract): return String("contract")
|
|
2571
|
+
return String(type(obj).__name__.lower())
|
|
2572
|
+
|
|
2573
|
+
def _abs(*a):
|
|
2574
|
+
"""abs(number) - returns absolute value"""
|
|
2575
|
+
if len(a) != 1:
|
|
2576
|
+
return EvaluationError("abs() requires exactly 1 argument")
|
|
2577
|
+
val = a[0]
|
|
2578
|
+
if isinstance(val, Integer): return Integer(abs(val.value))
|
|
2579
|
+
if isinstance(val, Float): return Float(abs(val.value))
|
|
2580
|
+
return EvaluationError("abs() requires a number argument")
|
|
2581
|
+
|
|
2515
2582
|
def _vfs_stats(*a):
|
|
2516
2583
|
"""Return VFS file cache statistics as a Map: vfs_stats()"""
|
|
2517
2584
|
mgr = _get_vfs_manager()
|
|
@@ -2762,6 +2829,7 @@ class FunctionEvaluatorMixin:
|
|
|
2762
2829
|
"debug_log": Builtin(_debug_log, "debug_log"),
|
|
2763
2830
|
"debug_trace": Builtin(_debug_trace, "debug_trace"),
|
|
2764
2831
|
"string": Builtin(_string, "string"),
|
|
2832
|
+
"str": Builtin(_string, "str"), # alias for string()
|
|
2765
2833
|
"int": Builtin(_int, "int"),
|
|
2766
2834
|
"float": Builtin(_float, "float"),
|
|
2767
2835
|
"uppercase": Builtin(_uppercase, "uppercase"),
|
|
@@ -2770,6 +2838,7 @@ class FunctionEvaluatorMixin:
|
|
|
2770
2838
|
"persist_set": Builtin(_persist_set, "persist_set"),
|
|
2771
2839
|
"persist_get": Builtin(_persist_get, "persist_get"),
|
|
2772
2840
|
"len": Builtin(_len, "len"),
|
|
2841
|
+
"length": Builtin(_len, "length"), # alias for len()
|
|
2773
2842
|
"type": Builtin(_type, "type"),
|
|
2774
2843
|
"first": Builtin(_first, "first"),
|
|
2775
2844
|
"rest": Builtin(_rest, "rest"),
|
|
@@ -2785,6 +2854,9 @@ class FunctionEvaluatorMixin:
|
|
|
2785
2854
|
"values": Builtin(_values, "values"),
|
|
2786
2855
|
"entries": Builtin(_entries, "entries"),
|
|
2787
2856
|
"size": Builtin(_size, "size"),
|
|
2857
|
+
"range": Builtin(_range, "range"),
|
|
2858
|
+
"typeof": Builtin(_typeof, "typeof"),
|
|
2859
|
+
"abs": Builtin(_abs, "abs"),
|
|
2788
2860
|
})
|
|
2789
2861
|
|
|
2790
2862
|
# Register access control builtins
|
|
@@ -250,7 +250,7 @@ class ResourceLimiter:
|
|
|
250
250
|
stats['memory_mb'] = memory_mb
|
|
251
251
|
stats['max_memory_mb'] = self.max_memory_mb
|
|
252
252
|
stats['memory_percent'] = (memory_mb / self.max_memory_mb) * 100
|
|
253
|
-
except:
|
|
253
|
+
except (OSError, AttributeError, ZeroDivisionError):
|
|
254
254
|
pass
|
|
255
255
|
|
|
256
256
|
return stats
|