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 +1 -1
- package/package.json +1 -1
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/cli/main.py +57 -4
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/evaluator/bytecode_compiler.py +296 -12
- package/src/zexus/evaluator/core.py +175 -4
- package/src/zexus/evaluator/functions.py +106 -1
- package/src/zexus/evaluator/jit_integration.py +346 -0
- package/src/zexus/evaluator/statements.py +30 -7
- package/src/zexus/evaluator/unified_execution.py +488 -0
- package/src/zexus/evaluator/utils.py +4 -1
- package/src/zexus/lexer.py +83 -0
- package/src/zexus/object.py +126 -0
- package/src/zexus/parser/parser.py +32 -2
- package/src/zexus/parser/strategy_context.py +515 -14
- package/src/zexus/parser/strategy_structural.py +246 -2
- package/src/zexus/safety/__init__.py +42 -0
- package/src/zexus/safety/memory_safety.py +499 -0
- package/src/zexus/security.py +488 -49
- package/src/zexus/vm/bytecode.py +14 -6
- package/src/zexus/vm/compiler.py +407 -0
- package/src/zexus/vm/gas_metering.py +235 -0
- package/src/zexus/vm/vm.py +456 -50
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus.egg-info/PKG-INFO +2 -2
- package/src/zexus.egg-info/SOURCES.txt +105 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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)
|
package/package.json
CHANGED
package/src/zexus/__init__.py
CHANGED
package/src/zexus/cli/main.py
CHANGED
|
@@ -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.
|
|
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
|
-
#
|
|
225
|
-
|
|
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()}")
|
package/src/zexus/cli/zpm.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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
|