zexus 1.8.0 → 1.8.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 (51) hide show
  1. package/README.md +34 -6
  2. package/bin/zexus +12 -2
  3. package/bin/zpics +12 -2
  4. package/bin/zpm +12 -2
  5. package/bin/zx +12 -2
  6. package/bin/zx-deploy +12 -2
  7. package/bin/zx-dev +12 -2
  8. package/bin/zx-run +12 -2
  9. package/package.json +2 -1
  10. package/rust_core/Cargo.lock +603 -0
  11. package/rust_core/Cargo.toml +26 -0
  12. package/rust_core/README.md +15 -0
  13. package/rust_core/pyproject.toml +25 -0
  14. package/rust_core/src/binary_bytecode.rs +543 -0
  15. package/rust_core/src/contract_vm.rs +643 -0
  16. package/rust_core/src/executor.rs +847 -0
  17. package/rust_core/src/hasher.rs +90 -0
  18. package/rust_core/src/lib.rs +71 -0
  19. package/rust_core/src/merkle.rs +128 -0
  20. package/rust_core/src/rust_vm.rs +2313 -0
  21. package/rust_core/src/signature.rs +79 -0
  22. package/rust_core/src/state_adapter.rs +281 -0
  23. package/rust_core/src/validator.rs +116 -0
  24. package/scripts/postinstall.js +204 -21
  25. package/src/zexus/__init__.py +1 -1
  26. package/src/zexus/cli/main.py +1 -1
  27. package/src/zexus/cli/zpm.py +1 -1
  28. package/src/zexus/evaluator/bytecode_compiler.py +150 -52
  29. package/src/zexus/evaluator/core.py +151 -809
  30. package/src/zexus/evaluator/expressions.py +27 -22
  31. package/src/zexus/evaluator/functions.py +171 -126
  32. package/src/zexus/evaluator/statements.py +55 -112
  33. package/src/zexus/module_cache.py +20 -9
  34. package/src/zexus/object.py +330 -38
  35. package/src/zexus/parser/parser.py +103 -23
  36. package/src/zexus/parser/strategy_context.py +318 -6
  37. package/src/zexus/parser/strategy_structural.py +2 -2
  38. package/src/zexus/persistence.py +46 -17
  39. package/src/zexus/security.py +140 -234
  40. package/src/zexus/type_checker.py +44 -5
  41. package/src/zexus/vm/binary_bytecode.py +7 -3
  42. package/src/zexus/vm/bytecode.py +6 -0
  43. package/src/zexus/vm/cache.py +24 -46
  44. package/src/zexus/vm/compiler.py +549 -68
  45. package/src/zexus/vm/memory_pool.py +21 -9
  46. package/src/zexus/vm/vm.py +609 -95
  47. package/src/zexus/zpm/package_manager.py +1 -1
  48. package/src/zexus.egg-info/PKG-INFO +56 -12
  49. package/src/zexus.egg-info/SOURCES.txt +14 -0
  50. package/src/zexus.egg-info/entry_points.txt +5 -1
  51. package/src/zexus.egg-info/requires.txt +26 -0
@@ -3,42 +3,225 @@
3
3
  const { execSync } = require('child_process');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
+ const os = require('os');
6
7
 
7
8
  console.log('\nšŸš€ Installing Zexus Programming Language...\n');
8
9
 
9
- // Check if Python is available
10
- try {
11
- const pythonVersion = execSync('python3 --version', { encoding: 'utf-8' });
12
- console.log(`āœ“ Found ${pythonVersion.trim()}`);
13
- } catch (error) {
14
- console.error('āŒ Python 3.8+ is required but not found.');
15
- console.error('Please install Python 3.8 or higher: https://www.python.org/downloads/');
16
- process.exit(1);
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+
14
+ function hasCommand(cmd) {
15
+ try {
16
+ execSync(`${cmd} --version`, { stdio: 'ignore' });
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
17
21
  }
18
22
 
19
- // Check Python version
20
- try {
21
- const versionCheck = execSync('python3 -c "import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"');
22
- console.log('āœ“ Python version is 3.8 or higher');
23
- } catch (error) {
24
- console.error('āŒ Python 3.8 or higher is required.');
23
+ function run(cmd, opts = {}) {
24
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'inherit', ...opts });
25
+ }
26
+
27
+ function runQuiet(cmd) {
28
+ return execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
29
+ }
30
+
31
+ const isWin = os.platform() === 'win32';
32
+ const pip = isWin ? 'pip' : 'pip3';
33
+ const python = isWin ? 'python' : 'python3';
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // 1. Python — check or install
37
+ // ---------------------------------------------------------------------------
38
+
39
+ let pythonAvailable = false;
40
+
41
+ if (hasCommand(python)) {
42
+ try {
43
+ const ver = runQuiet(`${python} --version`).trim();
44
+ console.log(`āœ“ Found ${ver}`);
45
+ // Verify >= 3.8
46
+ runQuiet(`${python} -c "import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"`);
47
+ console.log('āœ“ Python version is 3.8 or higher');
48
+ pythonAvailable = true;
49
+ } catch {
50
+ console.error('āŒ Python was found but version is below 3.8.');
51
+ console.error(' Please upgrade to Python 3.8+: https://www.python.org/downloads/');
52
+ }
53
+ } else {
54
+ console.warn('āš ļø python3 not found on PATH.');
55
+ // Attempt auto-install on common platforms
56
+ if (os.platform() === 'linux') {
57
+ console.log(' Attempting to install python3 via apt...');
58
+ try {
59
+ run('sudo apt-get update -qq && sudo apt-get install -y -qq python3 python3-pip python3-venv');
60
+ pythonAvailable = true;
61
+ console.log('āœ“ Python 3 installed via apt');
62
+ } catch {
63
+ console.warn(' Could not auto-install Python. Please install manually:');
64
+ console.warn(' https://www.python.org/downloads/');
65
+ }
66
+ } else if (os.platform() === 'darwin') {
67
+ if (hasCommand('brew')) {
68
+ console.log(' Attempting to install python3 via Homebrew...');
69
+ try {
70
+ run('brew install python@3');
71
+ pythonAvailable = true;
72
+ console.log('āœ“ Python 3 installed via Homebrew');
73
+ } catch {
74
+ console.warn(' Could not auto-install Python. Please install manually:');
75
+ console.warn(' https://www.python.org/downloads/');
76
+ }
77
+ } else {
78
+ console.warn(' Please install Python 3.8+: https://www.python.org/downloads/');
79
+ }
80
+ } else {
81
+ console.warn(' Please install Python 3.8+: https://www.python.org/downloads/');
82
+ }
83
+ }
84
+
85
+ if (!pythonAvailable) {
86
+ console.error('\nāŒ Python 3.8+ is required but could not be found or installed.');
87
+ console.error(' Install it from: https://www.python.org/downloads/');
88
+ console.error(' Then re-run: npm rebuild zexus');
25
89
  process.exit(1);
26
90
  }
27
91
 
28
- // Install Zexus Python package
92
+ // ---------------------------------------------------------------------------
93
+ // 2. pip — ensure available
94
+ // ---------------------------------------------------------------------------
95
+
96
+ if (!hasCommand(pip) && !hasCommand('pip')) {
97
+ console.log(' pip not found — bootstrapping...');
98
+ try {
99
+ run(`${python} -m ensurepip --upgrade`);
100
+ } catch {
101
+ try {
102
+ run(`${python} -m pip install --upgrade pip`);
103
+ } catch {
104
+ console.warn('āš ļø Could not bootstrap pip. Python package install may fail.');
105
+ }
106
+ }
107
+ }
108
+
109
+ // ---------------------------------------------------------------------------
110
+ // 3. Install Zexus Python package
111
+ // ---------------------------------------------------------------------------
112
+
29
113
  console.log('\nšŸ“¦ Installing Zexus Python package...');
114
+
115
+ // Check if zexus is already installed and up-to-date
116
+ let zexusInstalled = false;
30
117
  try {
31
- execSync('pip3 install zexus', { stdio: 'inherit' });
32
- console.log('\nāœ“ Zexus Python package installed successfully');
33
- } catch (error) {
34
- console.error('\nāŒ Failed to install Zexus Python package.');
35
- console.error('Please run manually: pip3 install zexus');
36
- process.exit(1);
118
+ runQuiet(`${python} -c "import zexus"`);
119
+ zexusInstalled = true;
120
+ console.log('āœ“ Zexus Python package already installed');
121
+ } catch {
122
+ // Not installed yet
123
+ }
124
+
125
+ if (!zexusInstalled) {
126
+ try {
127
+ run(`${python} -m pip install --user "zexus[full]"`);
128
+ console.log('āœ“ Zexus Python package installed successfully');
129
+ } catch {
130
+ // Retry without --user (some environments like venvs don't need it)
131
+ try {
132
+ run(`${python} -m pip install "zexus[full]"`);
133
+ console.log('āœ“ Zexus Python package installed successfully');
134
+ } catch {
135
+ console.error('āŒ Failed to install Zexus Python package.');
136
+ console.error(` Please run manually: ${python} -m pip install "zexus[full]"`);
137
+ // Don't exit — commands that don't need Python may still work
138
+ }
139
+ }
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // 4. Rust toolchain — check or install, then build rust_core
144
+ // ---------------------------------------------------------------------------
145
+
146
+ const pkgRoot = path.resolve(__dirname, '..');
147
+ const cargoToml = path.join(pkgRoot, 'rust_core', 'Cargo.toml');
148
+
149
+ if (fs.existsSync(cargoToml)) {
150
+ let cargoReady = hasCommand('cargo');
151
+
152
+ if (!cargoReady) {
153
+ console.log('\nšŸ¦€ Rust toolchain (cargo) not found.');
154
+ console.log(' Attempting to install Rust via rustup...');
155
+ try {
156
+ if (isWin) {
157
+ // On Windows, download and run rustup-init
158
+ console.log(' Please install Rust manually: https://rustup.rs');
159
+ } else {
160
+ // Unix: install rustup non-interactively
161
+ run('curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y');
162
+ // Source the cargo env so it's available in this session
163
+ const cargoEnv = path.join(os.homedir(), '.cargo', 'env');
164
+ if (fs.existsSync(cargoEnv)) {
165
+ // Read the cargo bin path and add to PATH for child processes
166
+ const cargoBin = path.join(os.homedir(), '.cargo', 'bin');
167
+ process.env.PATH = `${cargoBin}${path.delimiter}${process.env.PATH}`;
168
+ }
169
+ cargoReady = hasCommand('cargo');
170
+ if (cargoReady) {
171
+ console.log('āœ“ Rust toolchain installed via rustup');
172
+ }
173
+ }
174
+ } catch (err) {
175
+ console.warn('āš ļø Could not auto-install Rust. Continuing with pure-Python VM.');
176
+ console.warn(' To install manually: https://rustup.rs');
177
+ }
178
+ } else {
179
+ console.log('\nāœ“ Rust toolchain detected');
180
+ }
181
+
182
+ if (cargoReady) {
183
+ // Check if zexus_core is already importable
184
+ let rustVmInstalled = false;
185
+ try {
186
+ runQuiet(`${python} -c "import zexus_core"`);
187
+ rustVmInstalled = true;
188
+ console.log('āœ“ Rust VM extension (zexus_core) already installed');
189
+ } catch {
190
+ // Need to build
191
+ }
192
+
193
+ if (!rustVmInstalled) {
194
+ console.log('šŸ”Ø Building Rust VM extension (zexus_core)...');
195
+ try {
196
+ // Ensure maturin is available
197
+ try {
198
+ runQuiet(`${python} -m maturin --version`);
199
+ } catch {
200
+ console.log(' Installing maturin build tool...');
201
+ run(`${python} -m pip install --user --upgrade maturin`);
202
+ }
203
+ run(`${python} -m maturin develop -m "${cargoToml}" --release`);
204
+ runQuiet(`${python} -c "import zexus_core"`);
205
+ console.log('āœ“ Rust VM extension built and installed');
206
+ } catch (error) {
207
+ console.warn('\nāš ļø Rust VM build failed; continuing with pure-Python VM.');
208
+ console.warn(' To retry manually:');
209
+ console.warn(` ${python} -m pip install maturin && ${python} -m maturin develop -m rust_core/Cargo.toml --release`);
210
+ }
211
+ }
212
+ }
213
+ } else {
214
+ console.log('\nā„¹ļø rust_core/Cargo.toml not bundled; skipping Rust VM build.');
37
215
  }
38
216
 
217
+ // ---------------------------------------------------------------------------
218
+ // Done
219
+ // ---------------------------------------------------------------------------
220
+
39
221
  console.log('\nāœ… Zexus installed successfully!\n');
40
222
  console.log('Get started:');
41
223
  console.log(' zexus --help # Show help');
42
224
  console.log(' zx --version # Check version');
225
+ console.log(' zx run file.zx # Run a Zexus file');
43
226
  console.log(' zexus examples/ # Explore examples\n');
44
227
  console.log('Documentation: https://github.com/Zaidux/zexus-interpreter\n');
@@ -4,7 +4,7 @@ Zexus Programming Language
4
4
  A declarative, intent-based programming language for modern applications.
5
5
  """
6
6
 
7
- __version__ = "1.8.0"
7
+ __version__ = "1.8.2"
8
8
  __author__ = "Ziver Labs"
9
9
  __email__ = "ziverofficial567@gmail.com"
10
10
 
@@ -156,7 +156,7 @@ def show_all_commands():
156
156
  console.print("\n[bold green]šŸ’” Tip:[/bold green] Use 'zx <command> --help' for detailed command options\n")
157
157
 
158
158
  @click.group(invoke_without_command=True)
159
- @click.version_option(version="1.8.0", prog_name="Zexus")
159
+ @click.version_option(version="1.8.2", prog_name="Zexus")
160
160
  @click.option('--syntax-style', type=click.Choice(['universal', 'tolerable', 'auto']),
161
161
  default='auto', help='Syntax style to use (universal=strict, tolerable=flexible)')
162
162
  @click.option('--advanced-parsing', is_flag=True, default=True,
@@ -18,7 +18,7 @@ console = Console()
18
18
 
19
19
 
20
20
  @click.group()
21
- @click.version_option(version="1.8.0", prog_name="ZPM")
21
+ @click.version_option(version="1.8.2", prog_name="ZPM")
22
22
  def cli():
23
23
  """ZPM - Zexus Package Manager
24
24
 
@@ -41,13 +41,26 @@ _SHARED_CACHE: Optional[BytecodeCache] = None
41
41
 
42
42
 
43
43
  def get_shared_cache() -> BytecodeCache:
44
- """Get the global shared bytecode cache (persistent across runs)"""
44
+ """Get the global shared bytecode cache.
45
+
46
+ Note: The compiler stores AST objects (e.g., LoadExpression/FindExpression) inside
47
+ bytecode constants for VM keyword builtins.
48
+
49
+ Persisting these bytecodes to disk can cause order-dependent behavior during tests
50
+ because the same codebase is imported under multiple module namespaces (e.g.
51
+ `zexus.*` and `src.zexus.*`), producing distinct AST classes that are not
52
+ interchangeable at runtime.
53
+ """
45
54
  global _SHARED_CACHE
46
55
  if _SHARED_CACHE is None:
56
+ # Default to in-memory only under pytest to avoid cross-test contamination.
57
+ is_pytest = bool(os.environ.get("PYTEST_CURRENT_TEST"))
58
+ persist_env = os.environ.get("ZEXUS_BYTECODE_CACHE_PERSISTENT")
59
+ persist_requested = bool(persist_env) and persist_env.lower() not in ("0", "false", "off")
47
60
  _SHARED_CACHE = BytecodeCache(
48
61
  max_size=2000,
49
62
  max_memory_mb=100,
50
- persistent=True, # Enable disk persistence
63
+ persistent=(persist_requested and not is_pytest),
51
64
  debug=False
52
65
  )
53
66
  return _SHARED_CACHE
@@ -161,11 +174,6 @@ class EvaluatorBytecodeCompiler:
161
174
  cached = self.cache.get(node)
162
175
  if cached:
163
176
  return cached
164
-
165
- # Check pattern cache (similar code structure)
166
- pattern_cached = self.cache.get_by_pattern(node)
167
- if pattern_cached:
168
- return pattern_cached
169
177
 
170
178
  # Cache miss - compile
171
179
  self.builder = BytecodeBuilder()
@@ -184,10 +192,12 @@ class EvaluatorBytecodeCompiler:
184
192
 
185
193
  bytecode.set_metadata('created_by', 'evaluator')
186
194
 
187
- # Store in caches
195
+ # Store in cache
196
+ # NOTE: Pattern-cache reuse is intentionally disabled here because the current
197
+ # pattern hashing ignores literal/name fields, which can return bytecode with
198
+ # incorrect embedded constants/identifiers for ā€œsimilarā€ nodes.
188
199
  if use_cache and self.cache:
189
200
  self.cache.put(node, bytecode)
190
- self.cache.put_by_pattern(node, bytecode)
191
201
 
192
202
  return bytecode
193
203
 
@@ -261,15 +271,51 @@ class EvaluatorBytecodeCompiler:
261
271
 
262
272
  def _compile_LetStatement(self, node: zexus_ast.LetStatement):
263
273
  """Compile let statement"""
264
- # Compile the value expression
274
+ # Support destructuring patterns: let {a, b: x} = expr; let [x, y, ..rest] = expr
275
+ if isinstance(getattr(node, "name", None), zexus_ast.DestructurePattern):
276
+ self._compile_node(node.value)
277
+ pattern = node.name
278
+ if pattern.kind == 'map':
279
+ for source_key, target_name in pattern.bindings:
280
+ self.builder.emit("DUP")
281
+ self.builder.emit_constant(source_key)
282
+ self.builder.emit("INDEX")
283
+ self.builder.emit_store(target_name)
284
+ self.builder.emit("POP")
285
+ return
286
+ if pattern.kind == 'list':
287
+ for idx, target_name in pattern.bindings:
288
+ self.builder.emit("DUP")
289
+ self.builder.emit_constant(idx)
290
+ self.builder.emit("INDEX")
291
+ self.builder.emit_store(target_name)
292
+ if pattern.rest:
293
+ rest_start = len(pattern.bindings)
294
+ self.builder.emit("DUP")
295
+ self.builder.emit_constant(rest_start)
296
+ self.builder.emit_constant(None)
297
+ self.builder.emit("SLICE")
298
+ self.builder.emit_store(pattern.rest)
299
+ self.builder.emit("POP")
300
+ return
301
+
302
+ self.errors.append(f"Unsupported destructure pattern kind: {pattern.kind}")
303
+ self.builder.emit("POP")
304
+ return
305
+
306
+ # Regular identifier assignment
265
307
  self._compile_node(node.value)
266
- # Store it
267
308
  name = str(node.name.value).strip()
268
309
  self.builder.emit_store(name)
269
310
 
270
311
  def _compile_ConstStatement(self, node: zexus_ast.ConstStatement):
271
312
  """Compile const statement"""
272
- # Similar to let for now
313
+ # Const supports the same destructuring patterns as let.
314
+ if isinstance(getattr(node, "name", None), zexus_ast.DestructurePattern):
315
+ # Reuse let destructuring behavior
316
+ fake_let = node
317
+ return self._compile_LetStatement(fake_let)
318
+
273
319
  self._compile_node(node.value)
274
320
  name = str(node.name.value).strip()
275
321
  self.builder.emit_store(name)
@@ -283,10 +329,18 @@ class EvaluatorBytecodeCompiler:
283
329
  self.builder.emit("RETURN")
284
330
 
285
331
  def _compile_ContinueStatement(self, node: zexus_ast.ContinueStatement):
286
- """Compile continue statement - enables error recovery mode"""
287
- # Emit a special instruction or constant to signal continue mode
288
- # For now, emit a CONTINUE instruction that the VM can handle
289
- self.builder.emit("CONTINUE")
332
+ """Compile continue statement.
333
+
334
+ Behavior (mirrors VM compiler):
335
+ - Inside a loop: jump to the loop's continue target
336
+ - Outside a loop: enable continue-on-error mode
337
+ """
338
+ if self._loop_stack:
339
+ continue_label = self._loop_stack[-1].get('continue')
340
+ if continue_label:
341
+ self.builder.emit_jump(continue_label)
342
+ return
343
+ self.builder.emit("ENABLE_ERROR_MODE")
290
344
 
291
345
  def _compile_BreakStatement(self, node: zexus_ast.BreakStatement):
292
346
  """Compile break statement by jumping to loop end label"""
@@ -350,6 +404,53 @@ class EvaluatorBytecodeCompiler:
350
404
 
351
405
  # While statements don't return values by default
352
406
  self.builder.emit_constant(None)
407
+
408
+ def _compile_ForStatement(self, node):
409
+ """Compile classic for loop (initializer; condition; increment) { body }.
410
+
411
+ Note: The core parser currently focuses on for-each loops, but other
412
+ parsing strategies / legacy ASTs may still produce ForStatement nodes.
413
+ This keeps the evaluator bytecode compiler aligned with the VM compiler.
414
+ """
415
+ start_label = f"for_start_{id(node)}"
416
+ end_label = f"for_end_{id(node)}"
417
+ continue_label = start_label if getattr(node, "increment", None) is None else f"for_continue_{id(node)}"
418
+
419
+ # Initializer
420
+ initializer = getattr(node, "initializer", None)
421
+ if initializer is not None:
422
+ self._compile_node(initializer)
423
+
424
+ # Track loop labels for break/continue
425
+ self._loop_stack.append({'start': start_label, 'end': end_label, 'continue': continue_label})
426
+
427
+ # Condition
428
+ self.builder.mark_label(start_label)
429
+ condition = getattr(node, "condition", None)
430
+ if condition is not None:
431
+ self._compile_node(condition)
432
+ self.builder.emit_jump_if_false(end_label)
433
+
434
+ # Body
435
+ body = getattr(node, "body", None)
436
+ if body is not None:
437
+ self._compile_node(body)
438
+
439
+ # Increment
440
+ increment = getattr(node, "increment", None)
441
+ if increment is not None:
442
+ self.builder.mark_label(continue_label)
443
+ self._compile_node(increment)
444
+ self.builder.emit("POP")
445
+
446
+ # Jump back to condition
447
+ self.builder.emit_jump(start_label)
448
+
449
+ # End
450
+ self.builder.mark_label(end_label)
451
+ self._loop_stack.pop()
452
+
453
+ self.builder.emit_constant(None)
353
454
 
354
455
  def _compile_ForEachStatement(self, node: zexus_ast.ForEachStatement):
355
456
  """Compile for-each loop"""
@@ -458,14 +559,18 @@ class EvaluatorBytecodeCompiler:
458
559
 
459
560
  def _compile_PrintStatement(self, node: zexus_ast.PrintStatement):
460
561
  """Compile print statement"""
461
- # Compile the value to print
562
+ # PrintStatement can have value (single) or values (multiple)
563
+ if hasattr(node, 'values') and node.values:
564
+ for val in node.values:
565
+ self._compile_node(val)
566
+ self.builder.emit("PRINT")
567
+ return
568
+
462
569
  if hasattr(node, 'value') and node.value:
463
570
  self._compile_node(node.value)
464
571
  else:
465
- # Empty print
466
572
  self.builder.emit_constant("")
467
-
468
- # Emit PRINT opcode
573
+
469
574
  self.builder.emit("PRINT")
470
575
 
471
576
  def _compile_UseStatement(self, node: zexus_ast.UseStatement):
@@ -547,6 +652,24 @@ class EvaluatorBytecodeCompiler:
547
652
  def _compile_PatternStatement(self, node: zexus_ast.PatternStatement):
548
653
  """Compile pattern matching directives to VM builtins."""
549
654
  self._emit_vm_builtin_call("__vm_pattern_statement__", node, discard_result=False)
655
+
656
+ def _compile_ExportStatement(self, node):
657
+ """Compile export statement - no-op for bytecode.
658
+
659
+ Export is a declaration/annotation; the names being exported
660
+ are already defined by their own declarations (contract, action, etc.).
661
+ The evaluator handles export registration at module level.
662
+ """
663
+ # Export names are registered by the evaluator, not bytecode
664
+ pass
665
+
666
+ def _compile_EmitStatement(self, node):
667
+ """Compile emit statement to VM builtin call."""
668
+ self._emit_vm_builtin_call("__vm_emit_statement__", node, discard_result=False)
669
+
670
+ def _compile_ProtocolStatement(self, node):
671
+ """Compile protocol statement to VM builtin call."""
672
+ self._emit_vm_builtin_call("__vm_protocol_statement__", node, discard_result=False)
550
673
 
551
674
  # === Blockchain Statement Compilation ===
552
675
 
@@ -582,7 +705,7 @@ class EvaluatorBytecodeCompiler:
582
705
 
583
706
  # Jump if true (condition passes)
584
707
  pass_label = f"require_pass_{id(node)}"
585
- self.builder.emit("JUMP_IF_TRUE", None)
708
+ self.builder.emit_jump_if_true(pass_label)
586
709
 
587
710
  # Condition failed - revert
588
711
  if hasattr(node, 'message') and node.message:
@@ -697,34 +820,8 @@ class EvaluatorBytecodeCompiler:
697
820
  # Build map from stack
698
821
  self.builder.emit("BUILD_MAP", len(node.pairs))
699
822
 
700
- def _compile_PropertyAccessExpression(self, node: zexus_ast.PropertyAccessExpression):
701
- """Compile property access"""
702
- if self.builder is None:
703
- return
704
-
705
- # Compile object
706
- self._compile_node(node.object)
707
-
708
- if node.computed:
709
- # Bracket notation: obj[expr]
710
- self._compile_node(node.property)
711
- self._builder_emit("INDEX")
712
- else:
713
- # Dot notation: obj.prop
714
- if hasattr(node.property, 'value'):
715
- name = node.property.value
716
- else:
717
- name = str(node.property)
718
-
719
- # Push property name as constant
720
- self.builder.emit_constant(name)
721
- self._builder_emit("GET_ATTR")
722
-
723
- def _builder_emit(self, opcode):
724
- """Helper to emit opcode string or enum"""
725
- # If builder has emit, use it. Some builders might use emit(opcode, operand).
726
- # Wrapper to handle potential string usage if enum not fully refreshed
727
- self.builder.emit(opcode)
823
+ # LI12: _compile_PropertyAccessExpression is defined later in this file.
824
+ # The earlier duplicate implementation was dead code (overridden).
728
825
 
729
826
  def _compile_InfixExpression(self, node: zexus_ast.InfixExpression):
730
827
  """Compile infix expression"""
@@ -1165,7 +1262,8 @@ class EvaluatorBytecodeCompiler:
1165
1262
  elif op == 'OR':
1166
1263
  return BooleanObj(bool(v1) or bool(v2))
1167
1264
 
1168
- except:
1265
+ except Exception:
1266
+ # SECURITY (H11): Narrowed from bare except: to Exception
1169
1267
  pass
1170
1268
 
1171
1269
  return None
@@ -1278,7 +1376,7 @@ class EvaluatorBytecodeCompiler:
1278
1376
  # List of supported node types
1279
1377
  supported = {
1280
1378
  'Program', 'ExpressionStatement', 'LetStatement', 'ConstStatement',
1281
- 'ReturnStatement', 'ContinueStatement', 'IfStatement', 'WhileStatement', 'ForEachStatement',
1379
+ 'ReturnStatement', 'ContinueStatement', 'IfStatement', 'WhileStatement', 'ForStatement', 'ForEachStatement',
1282
1380
  'BlockStatement', 'ActionStatement', 'FunctionStatement', 'PrintStatement',
1283
1381
  'Identifier', 'IntegerLiteral', 'FloatLiteral',
1284
1382
  'StringLiteral', 'Boolean', 'ListLiteral', 'MapLiteral', 'NullLiteral',
@@ -1386,7 +1484,7 @@ def should_use_vm_for_node(node) -> bool:
1386
1484
  node_type = type(node).__name__
1387
1485
 
1388
1486
  # Always use VM for loops
1389
- if node_type in ['WhileStatement', 'ForEachStatement']:
1487
+ if node_type in ['WhileStatement', 'ForStatement', 'ForEachStatement']:
1390
1488
  return True
1391
1489
 
1392
1490
  # Use VM for complex functions