zexus 1.6.6 → 1.6.8

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
- ![Zexus Logo](https://img.shields.io/badge/Zexus-v1.6.6-FF6B35?style=for-the-badge)
5
+ ![Zexus Logo](https://img.shields.io/badge/Zexus-v1.6.8-FF6B35?style=for-the-badge)
6
6
  [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](LICENSE)
7
7
  [![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=for-the-badge&logo=python)](https://python.org)
8
8
  [![GitHub](https://img.shields.io/badge/GitHub-Zaidux/zexus--interpreter-181717?style=for-the-badge&logo=github)](https://github.com/Zaidux/zexus-interpreter)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zexus",
3
- "version": "1.6.6",
3
+ "version": "1.6.8",
4
4
  "description": "A modern, security-first programming language with blockchain support",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -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.6.6"
7
+ __version__ = "1.6.8"
8
8
  __author__ = "Ziver Labs"
9
9
  __email__ = "ziverofficial567@gmail.com"
10
10
 
@@ -20,6 +20,9 @@ from ..hybrid_orchestrator import orchestrator
20
20
  from ..config import config
21
21
  # Import error handling
22
22
  from ..error_reporter import get_error_reporter, ZexusError, print_error
23
+ # VM and Compiler for high-performance execution
24
+ from ..vm.vm import VM, VMMode
25
+ from ..vm.compiler import compile_ast_to_bytecode
23
26
 
24
27
  console = Console()
25
28
 
@@ -91,7 +94,7 @@ def show_all_commands():
91
94
  console.print("\n[bold green]💡 Tip:[/bold green] Use 'zx <command> --help' for detailed command options\n")
92
95
 
93
96
  @click.group(invoke_without_command=True)
94
- @click.version_option(version="1.6.6", prog_name="Zexus")
97
+ @click.version_option(version="1.6.8", prog_name="Zexus")
95
98
  @click.option('--syntax-style', type=click.Choice(['universal', 'tolerable', 'auto']),
96
99
  default='auto', help='Syntax style to use (universal=strict, tolerable=flexible)')
97
100
  @click.option('--advanced-parsing', is_flag=True, default=True,
@@ -133,8 +136,12 @@ def cli(ctx, syntax_style, advanced_parsing, execution_mode, debug, zexus):
133
136
  @cli.command()
134
137
  @click.argument('file', type=click.Path(exists=True))
135
138
  @click.argument('args', nargs=-1) # Accept any number of additional arguments
139
+ @click.option('--use-vm', is_flag=True, default=True, help='Use VM for execution (default: enabled for performance)')
140
+ @click.option('--vm-mode', type=click.Choice(['auto', 'stack', 'register', 'parallel']),
141
+ default='auto', help='VM execution mode (auto=best performance)')
142
+ @click.option('--no-optimize', is_flag=True, default=False, help='Disable bytecode optimizations')
136
143
  @click.pass_context
137
- def run(ctx, file, args):
144
+ def run(ctx, file, args, use_vm, vm_mode, no_optimize):
138
145
  """Run a Zexus program with hybrid execution"""
139
146
  # Register source for error reporting
140
147
  error_reporter = get_error_reporter()
@@ -155,6 +162,8 @@ def run(ctx, file, args):
155
162
  console.print(f"🔧 [bold blue]Execution mode:[/bold blue] {execution_mode}")
156
163
  console.print(f"📝 [bold blue]Syntax style:[/bold blue] {syntax_style}")
157
164
  console.print(f"🎯 [bold blue]Advanced parsing:[/bold blue] {'Enabled' if advanced_parsing else 'Disabled'}")
165
+ if use_vm:
166
+ console.print(f"⚡ [bold magenta]VM Mode:[/bold magenta] {vm_mode.upper()} | Optimizations: {'OFF' if no_optimize else 'ON'}")
158
167
 
159
168
  # Auto-detect syntax style if needed
160
169
  if syntax_style == 'auto':
@@ -221,8 +230,52 @@ def run(ctx, file, args):
221
230
  pass # Unable to determine package name
222
231
  env.set("__PACKAGE__", package_name)
223
232
 
224
- # UPDATED: Use the evaluate function from the evaluator package
225
- result = evaluate(program, env, debug_mode=ctx.obj['DEBUG'])
233
+ # Execute based on mode
234
+ if use_vm:
235
+ # VM EXECUTION PATH (High Performance)
236
+ console.print("[dim]Compiling to bytecode...[/dim]", end="")
237
+ try:
238
+ bytecode = compile_ast_to_bytecode(program, optimize=not no_optimize)
239
+ console.print(" [green]done[/green]")
240
+ console.print(f"[dim]Bytecode: {len(bytecode.instructions)} instructions, {len(bytecode.constants)} constants[/dim]")
241
+ except Exception as e:
242
+ console.print(f" [red]failed[/red]")
243
+ console.print(f"[bold red]Bytecode compilation error:[/bold red] {str(e)}")
244
+ if ctx.obj.get('DEBUG'):
245
+ import traceback
246
+ traceback.print_exc()
247
+ sys.exit(1)
248
+
249
+ # Initialize VM
250
+ vm_mode_enum = {
251
+ 'auto': VMMode.AUTO,
252
+ 'stack': VMMode.STACK,
253
+ 'register': VMMode.REGISTER,
254
+ 'parallel': VMMode.PARALLEL
255
+ }[vm_mode]
256
+
257
+ console.print(f"[dim]Initializing VM ({vm_mode} mode)...[/dim]", end="")
258
+ vm = VM(
259
+ mode=vm_mode_enum,
260
+ use_jit=not no_optimize,
261
+ max_heap_mb=1000, # 1GB heap limit
262
+ debug=ctx.obj.get('DEBUG', False)
263
+ )
264
+ console.print(" [green]done[/green]")
265
+
266
+ # Execute on VM
267
+ console.print("[dim]Executing on VM...[/dim]")
268
+ try:
269
+ result = vm.execute(bytecode, debug=ctx.obj.get('DEBUG', False))
270
+ except Exception as e:
271
+ console.print(f"[bold red]VM Execution error:[/bold red] {str(e)}")
272
+ if ctx.obj.get('DEBUG'):
273
+ import traceback
274
+ traceback.print_exc()
275
+ sys.exit(1)
276
+ else:
277
+ # INTERPRETER EXECUTION PATH (Standard)
278
+ result = evaluate(program, env, debug_mode=ctx.obj['DEBUG'])
226
279
 
227
280
  if result and hasattr(result, 'inspect') and result.inspect() != 'null':
228
281
  console.print(f"\n✅ [bold green]Result:[/bold green] {result.inspect()}")
@@ -18,7 +18,7 @@ console = Console()
18
18
 
19
19
 
20
20
  @click.group()
21
- @click.version_option(version="1.6.6", prog_name="ZPM")
21
+ @click.version_option(version="1.6.8", prog_name="ZPM")
22
22
  def cli():
23
23
  """ZPM - Zexus Package Manager
24
24
 
@@ -4,6 +4,7 @@ Bytecode Compiler for Evaluator
4
4
  This module allows the evaluator to compile AST nodes to bytecode
5
5
  for VM execution when performance is critical.
6
6
  """
7
+ import os
7
8
  from typing import Dict, List, Optional
8
9
  from .. import zexus_ast
9
10
  from ..vm.bytecode import Bytecode, BytecodeBuilder
@@ -145,13 +146,15 @@ class EvaluatorBytecodeCompiler:
145
146
  # Compile the value expression
146
147
  self._compile_node(node.value)
147
148
  # Store it
148
- self.builder.emit_store(node.name.value)
149
+ name = str(node.name.value).strip()
150
+ self.builder.emit_store(name)
149
151
 
150
152
  def _compile_ConstStatement(self, node: zexus_ast.ConstStatement):
151
153
  """Compile const statement"""
152
154
  # Similar to let for now
153
155
  self._compile_node(node.value)
154
- self.builder.emit_store(node.name.value)
156
+ name = str(node.name.value).strip()
157
+ self.builder.emit_store(name)
155
158
 
156
159
  def _compile_ReturnStatement(self, node: zexus_ast.ReturnStatement):
157
160
  """Compile return statement"""
@@ -314,7 +317,7 @@ class EvaluatorBytecodeCompiler:
314
317
 
315
318
  # Store function descriptor
316
319
  func_const_idx = self.builder.bytecode.add_constant(func_desc)
317
- name_idx = self.builder.bytecode.add_constant(node.name.value)
320
+ name_idx = self.builder.bytecode.add_constant(str(node.name.value).strip())
318
321
  self.builder.emit("STORE_FUNC", (name_idx, func_const_idx))
319
322
 
320
323
  def _compile_FunctionStatement(self, node: zexus_ast.FunctionStatement):
@@ -426,7 +429,15 @@ class EvaluatorBytecodeCompiler:
426
429
 
427
430
  def _compile_Identifier(self, node: zexus_ast.Identifier):
428
431
  """Compile identifier (variable load)"""
429
- self.builder.emit_load(node.value)
432
+ name = str(node.value).strip()
433
+ profile_flag = os.environ.get("ZEXUS_VM_PROFILE_OPS")
434
+ verbose_flag = os.environ.get("ZEXUS_VM_PROFILE_VERBOSE")
435
+ if (
436
+ profile_flag and profile_flag.lower() not in ("0", "false", "off")
437
+ and verbose_flag and verbose_flag.lower() not in ("0", "false", "off")
438
+ ):
439
+ print(f"[VM DEBUG] compile identifier raw={node.value!r} normalized={name!r}")
440
+ self.builder.emit_load(name)
430
441
 
431
442
  def _compile_IntegerLiteral(self, node: zexus_ast.IntegerLiteral):
432
443
  """Compile integer literal"""
@@ -558,6 +569,21 @@ class EvaluatorBytecodeCompiler:
558
569
  self._compile_node(node.expression)
559
570
  # Emit await
560
571
  self.builder.emit("AWAIT")
572
+
573
+ def _compile_MethodCallExpression(self, node: zexus_ast.MethodCallExpression):
574
+ """Compile method call (object.method(...))"""
575
+ if self.builder is None:
576
+ return
577
+
578
+ # Load object first so it sits below the arguments on the stack
579
+ self._compile_node(node.object)
580
+
581
+ # Compile arguments in order
582
+ for arg in node.arguments:
583
+ self._compile_node(arg)
584
+
585
+ method_name = node.method.value if hasattr(node.method, 'value') else str(node.method)
586
+ self.builder.emit_call_method(method_name, len(node.arguments))
561
587
 
562
588
  def _compile_SpawnExpression(self, node):
563
589
  """Compile spawn expression"""
@@ -573,7 +599,8 @@ class EvaluatorBytecodeCompiler:
573
599
  # Store to name
574
600
  if isinstance(node.name, zexus_ast.Identifier):
575
601
  self.builder.emit("DUP") # Keep value on stack
576
- self.builder.emit_store(node.name.value)
602
+ name = str(node.name.value).strip()
603
+ self.builder.emit_store(name)
577
604
  else:
578
605
  self.errors.append(
579
606
  "Complex assignment targets not yet supported in bytecode")
@@ -587,6 +614,53 @@ class EvaluatorBytecodeCompiler:
587
614
  # Emit index operation
588
615
  self.builder.emit("INDEX")
589
616
 
617
+ def _compile_PropertyAccessExpression(self, node):
618
+ """Compile property access (obj.property or obj[property])"""
619
+ # Compile the object
620
+ self._compile_node(node.object)
621
+
622
+ # Check if computed (obj[expr]) or literal (obj.prop)
623
+ if hasattr(node, 'computed') and node.computed:
624
+ # Computed property - evaluate the expression
625
+ self._compile_node(node.property)
626
+ self.builder.emit("INDEX")
627
+ else:
628
+ # Literal property - emit as constant string and use GET_ATTR
629
+ if hasattr(node.property, 'value'):
630
+ prop_name = node.property.value
631
+ else:
632
+ # Fallback - evaluate it
633
+ self._compile_node(node.property)
634
+ self.builder.emit("INDEX")
635
+ return
636
+
637
+ # Emit property name as constant
638
+ self.builder.emit_constant(prop_name)
639
+ self.builder.emit("GET_ATTR")
640
+
641
+ def _compile_LambdaExpression(self, node):
642
+ """Compile lambda/anonymous function"""
643
+ # Create nested bytecode for lambda body
644
+ inner_compiler = EvaluatorBytecodeCompiler()
645
+ func_bytecode = inner_compiler.compile(node.body, optimize=False)
646
+
647
+ if inner_compiler.errors:
648
+ self.errors.extend(inner_compiler.errors)
649
+ self.builder.emit_constant(None)
650
+ return
651
+
652
+ # Build lambda descriptor
653
+ params = [p.value if hasattr(p, 'value') else str(p) for p in node.parameters] if hasattr(node, 'parameters') else []
654
+ lambda_desc = {
655
+ "bytecode": func_bytecode,
656
+ "params": params,
657
+ "is_lambda": True
658
+ }
659
+
660
+ # Push lambda descriptor as constant
661
+ self.builder.emit_constant(lambda_desc)
662
+ self.builder.emit("BUILD_LAMBDA")
663
+
590
664
  # === Optimization ===
591
665
 
592
666
  def _optimize(self, bytecode: Bytecode) -> Bytecode:
@@ -595,12 +669,218 @@ class EvaluatorBytecodeCompiler:
595
669
 
596
670
  Optimizations:
597
671
  - Remove unnecessary POP instructions
598
- - Constant folding
599
- - Dead code elimination
672
+ - Constant folding (compile-time evaluation)
673
+ - Dead code elimination
674
+ - Algebraic simplifications
675
+ - Redundant operation removal
600
676
  """
601
- # For now, return as-is
602
- # Future: implement optimization passes
603
- return bytecode
677
+ from zexus.vm.bytecode import Bytecode, Opcode
678
+
679
+ instructions = bytecode.instructions
680
+ if not instructions:
681
+ return bytecode
682
+
683
+ # Multiple optimization passes for better results
684
+ optimized = instructions
685
+ optimized = self._constant_folding(optimized, bytecode.constants)
686
+ optimized = self._dead_code_elimination(optimized)
687
+ optimized = self._peephole_patterns(optimized)
688
+ optimized = self._remove_redundant_jumps(optimized)
689
+
690
+ # Create new bytecode with optimized instructions
691
+ new_bytecode = Bytecode()
692
+ new_bytecode.instructions = optimized
693
+ new_bytecode.constants = bytecode.constants.copy()
694
+ new_bytecode.names = bytecode.names.copy()
695
+ new_bytecode.labels = bytecode.labels.copy()
696
+
697
+ return new_bytecode
698
+
699
+ def _constant_folding(self, instructions, constants):
700
+ """
701
+ Fold constant expressions at compile time.
702
+ Example: LOAD_CONST 2, LOAD_CONST 3, ADD → LOAD_CONST 5
703
+ """
704
+ optimized = []
705
+ i = 0
706
+
707
+ while i < len(instructions):
708
+ inst = instructions[i]
709
+
710
+ # Look for pattern: LOAD_CONST, LOAD_CONST, <BINARY_OP>
711
+ if (i + 2 < len(instructions) and
712
+ inst[0] == 'LOAD_CONST' and
713
+ instructions[i+1][0] == 'LOAD_CONST'):
714
+
715
+ op = instructions[i+2][0]
716
+
717
+ # Get constant values
718
+ const1 = constants[inst[1]] if inst[1] < len(constants) else None
719
+ const2 = constants[instructions[i+1][1]] if instructions[i+1][1] < len(constants) else None
720
+
721
+ if const1 is not None and const2 is not None:
722
+ result = self._try_constant_operation(const1, const2, op)
723
+
724
+ if result is not None:
725
+ # Add result as new constant
726
+ const_idx = len(constants)
727
+ constants.append(result)
728
+
729
+ # Replace three instructions with one
730
+ optimized.append(('LOAD_CONST', const_idx))
731
+ i += 3
732
+ continue
733
+
734
+ # No optimization possible, keep instruction
735
+ optimized.append(inst)
736
+ i += 1
737
+
738
+ return optimized
739
+
740
+ def _try_constant_operation(self, val1, val2, op):
741
+ """Try to evaluate constant operation, return None if not possible"""
742
+ try:
743
+ # Import Zexus object types
744
+ from zexus.objects import Integer, Float, String, Boolean as BooleanObj
745
+
746
+ # Extract Python values
747
+ v1 = val1.value if hasattr(val1, 'value') else val1
748
+ v2 = val2.value if hasattr(val2, 'value') else val2
749
+
750
+ # Arithmetic operations
751
+ if op == 'ADD':
752
+ if isinstance(v1, str) or isinstance(v2, str):
753
+ return String(str(v1) + str(v2))
754
+ return Integer(v1 + v2) if isinstance(v1, int) and isinstance(v2, int) else Float(v1 + v2)
755
+ elif op == 'SUB':
756
+ return Integer(v1 - v2) if isinstance(v1, int) and isinstance(v2, int) else Float(v1 - v2)
757
+ elif op == 'MUL':
758
+ return Integer(v1 * v2) if isinstance(v1, int) and isinstance(v2, int) else Float(v1 * v2)
759
+ elif op == 'DIV':
760
+ if v2 == 0:
761
+ return None # Don't fold division by zero
762
+ result = v1 / v2
763
+ return Integer(int(result)) if result == int(result) else Float(result)
764
+
765
+ # Comparison operations
766
+ elif op == 'EQ':
767
+ return BooleanObj(v1 == v2)
768
+ elif op == 'NE':
769
+ return BooleanObj(v1 != v2)
770
+ elif op == 'LT':
771
+ return BooleanObj(v1 < v2)
772
+ elif op == 'GT':
773
+ return BooleanObj(v1 > v2)
774
+ elif op == 'LTE':
775
+ return BooleanObj(v1 <= v2)
776
+ elif op == 'GTE':
777
+ return BooleanObj(v1 >= v2)
778
+
779
+ # Logical operations
780
+ elif op == 'AND':
781
+ return BooleanObj(bool(v1) and bool(v2))
782
+ elif op == 'OR':
783
+ return BooleanObj(bool(v1) or bool(v2))
784
+
785
+ except:
786
+ pass
787
+
788
+ return None
789
+
790
+ def _dead_code_elimination(self, instructions):
791
+ """Remove unreachable code (code after RETURN, unconditional jumps to next instruction, etc.)"""
792
+ optimized = []
793
+ skip_until_label = False
794
+
795
+ for i, inst in enumerate(instructions):
796
+ # If we're skipping dead code, only stop at labels
797
+ if skip_until_label:
798
+ if inst[0] == 'LABEL':
799
+ skip_until_label = False
800
+ else:
801
+ continue # Skip this instruction
802
+
803
+ # After a RETURN or unconditional JUMP, skip until next label
804
+ if inst[0] == 'RETURN' or inst[0] == 'JUMP':
805
+ optimized.append(inst)
806
+ skip_until_label = True
807
+ continue
808
+
809
+ optimized.append(inst)
810
+
811
+ return optimized
812
+
813
+ def _peephole_patterns(self, instructions):
814
+ """Match and optimize common instruction patterns"""
815
+ optimized = []
816
+ i = 0
817
+
818
+ while i < len(instructions):
819
+ inst = instructions[i]
820
+
821
+ # Pattern: LOAD_CONST x, POP → (remove both)
822
+ if (i + 1 < len(instructions) and
823
+ inst[0] == 'LOAD_CONST' and
824
+ instructions[i+1][0] == 'POP'):
825
+ i += 2 # Skip both instructions
826
+ continue
827
+
828
+ # Pattern: LOAD_NAME x, STORE_NAME x → (remove both - noop)
829
+ if (i + 1 < len(instructions) and
830
+ inst[0] == 'LOAD_NAME' and
831
+ instructions[i+1][0] == 'STORE_NAME' and
832
+ inst[1] == instructions[i+1][1]): # Same variable
833
+ i += 2 # Skip both instructions
834
+ continue
835
+
836
+ # Pattern: DUP, POP → (remove both)
837
+ if (i + 1 < len(instructions) and
838
+ inst[0] == 'DUP' and
839
+ instructions[i+1][0] == 'POP'):
840
+ i += 2
841
+ continue
842
+
843
+ # Algebraic simplifications with LOAD_CONST
844
+ # Pattern: LOAD_NAME x, LOAD_CONST 0, ADD → LOAD_NAME x (adding 0 is noop)
845
+ if (i + 2 < len(instructions) and
846
+ inst[0] == 'LOAD_NAME' and
847
+ instructions[i+1][0] == 'LOAD_CONST' and
848
+ instructions[i+2][0] == 'ADD'):
849
+
850
+ const_val = instructions[i+1][1]
851
+ # Check if constant is 0 (would need to look up in constants array, skip for now)
852
+ # This is a more complex optimization
853
+ pass
854
+
855
+ # Pattern: LOAD_NAME x, LOAD_CONST 1, MUL → LOAD_NAME x (multiplying by 1 is noop)
856
+ # Similar to above, needs constant value lookup
857
+
858
+ # No optimization, keep instruction
859
+ optimized.append(inst)
860
+ i += 1
861
+
862
+ return optimized
863
+
864
+ def _remove_redundant_jumps(self, instructions):
865
+ """Remove jumps to the immediately next instruction"""
866
+ optimized = []
867
+
868
+ for i, inst in enumerate(instructions):
869
+ # Check if this is a JUMP instruction
870
+ if inst[0] in ('JUMP', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE'):
871
+ # Check if it jumps to the next instruction
872
+ target = inst[1]
873
+
874
+ # Look ahead to see if next instruction is the target label
875
+ if i + 1 < len(instructions):
876
+ next_inst = instructions[i+1]
877
+ if next_inst[0] == 'LABEL' and next_inst[1] == target:
878
+ # Skip this jump, it's redundant
879
+ continue
880
+
881
+ optimized.append(inst)
882
+
883
+ return optimized
604
884
 
605
885
  def can_compile(self, node) -> bool:
606
886
  """
@@ -618,9 +898,13 @@ class EvaluatorBytecodeCompiler:
618
898
  'ReturnStatement', 'ContinueStatement', 'IfStatement', 'WhileStatement', 'ForEachStatement',
619
899
  'BlockStatement', 'ActionStatement', 'FunctionStatement', 'PrintStatement',
620
900
  'Identifier', 'IntegerLiteral', 'FloatLiteral',
621
- 'StringLiteral', 'Boolean', 'ListLiteral', 'MapLiteral',
901
+ 'StringLiteral', 'Boolean', 'ListLiteral', 'MapLiteral', 'NullLiteral',
622
902
  'InfixExpression', 'PrefixExpression', 'CallExpression',
623
- 'AwaitExpression', 'AssignmentExpression', 'IndexExpression'
903
+ 'AwaitExpression', 'SpawnExpression', 'AssignmentExpression', 'IndexExpression',
904
+ 'PropertyAccessExpression', 'LambdaExpression',
905
+ # Blockchain nodes
906
+ 'TxStatement', 'RevertStatement', 'RequireStatement',
907
+ 'StateAccessExpression', 'LedgerAppendStatement', 'GasChargeStatement'
624
908
  }
625
909
 
626
910
  return node_type in supported