1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! Opcode definitions and compiled op array structures
use crate::engine::types::Val;
/// Opcode types
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Opcode {
Nop = 0,
Add = 1,
Sub = 2,
Mul = 3,
Div = 4,
Mod = 5,
Sl = 6, // Shift left
Sr = 7, // Shift right
Concat = 8,
BwOr = 9,
BwAnd = 10,
BwXor = 11,
Pow = 12,
BwNot = 13,
BoolNot = 14,
BoolAnd = 15,
BoolOr = 16,
BoolXor = 17,
IsIdentical = 18,
IsNotIdentical = 19,
IsEqual = 20,
IsNotEqual = 21,
IsSmaller = 22,
IsSmallerOrEqual = 23,
Assign = 24,
AssignDim = 25,
AssignObj = 26,
AssignStaticProp = 27,
AssignOp = 28,
Echo = 29,
Return = 30,
Jmp = 31,
JmpZ = 32,
JmpNZ = 33,
InitFCall = 34, // Initialize function call
DoFCall = 35, // Execute function call
TryCatchBegin = 36, // Begin try block
TryCatchEnd = 37, // End try block
CatchBegin = 38, // Begin catch block
CatchEnd = 39, // End catch block
FinallyBegin = 40, // Begin finally block
FinallyEnd = 41, // End finally block
Throw = 42, // Throw exception
FetchVar = 43, // Load variable from symbol table into temp
SendVal = 44, // Push argument for function call
Include = 45, // include/require
InitArray = 46, // Create empty array in temp slot
AddArrayElement = 47, // Add element to array (op1=array temp, op2=value, extended_value for key)
FetchDim = 48, // Fetch array element by index/key
NewObj = 49, // Create new object instance (op1=class name, result=temp)
FetchObjProp = 50, // Fetch object property (op1=obj, op2=prop name, result=temp)
AssignObjProp = 51, // Assign to object property (op1=obj var, op2=prop name, result=value)
InitMethodCall = 52, // Init method call (op1=obj, op2=method name)
DoMethodCall = 53, // Execute method call (op1=method name, result=temp)
TypeCheck = 54, // Check type of operand
IsSet = 55, // Check if variable is set
Empty = 56, // Check if variable is empty
Unset = 57, // Unset a variable
Count = 58, // Count elements in array/string
Keys = 59, // Get array keys
Values = 60, // Get array values
ArrayDiff = 61, // Compare arrays
Coalesce = 62, // Null coalescing: if op1 is not null, result=op1, else result=op2
JmpNullZ = 63, // Jump if op1 is null (for ?? short-circuit)
QmAssign = 64, // Ternary assign: resolve op1, store in result temp slot
FeReset = 65, // Reset array iterator for foreach
FeFetch = 66, // Fetch next element from array iterator
}
/// Operation structure
#[derive(Debug, Clone)]
pub struct Op {
pub opcode: Opcode,
pub op1: Val,
pub op2: Val,
pub result: Val,
pub extended_value: u32,
}
impl Op {
pub fn new(opcode: Opcode, op1: Val, op2: Val, result: Val, extended_value: u32) -> Self {
Self {
opcode,
op1,
op2,
result,
extended_value,
}
}
}
/// Op array (compiled script)
#[derive(Debug)]
pub struct OpArray {
pub ops: Vec<Op>,
pub vars: Vec<Val>, // Variables
pub filename: Option<String>,
pub line_start: u32,
pub line_end: u32,
pub function_name: Option<String>,
pub class_table: std::collections::HashMap<String, crate::engine::types::ClassEntry>,
pub variadic_param: Option<String>,
}
impl OpArray {
pub fn new(filename: String) -> Self {
Self {
ops: Vec::new(),
vars: Vec::new(),
filename: Some(filename),
line_start: 0,
line_end: 0,
class_table: std::collections::HashMap::new(),
function_name: None,
variadic_param: None,
}
}
/// Create OpArray with pre-allocated capacity for performance
pub fn with_capacity(capacity: usize, filename: String) -> Self {
Self {
ops: Vec::with_capacity(capacity),
vars: Vec::new(),
filename: Some(filename),
line_start: 0,
line_end: 0,
class_table: std::collections::HashMap::new(),
function_name: None,
variadic_param: None,
}
}
#[inline]
pub fn add_op(&mut self, op: Op) {
self.ops.push(op);
}
}
/// Get opcode name for debugging/display
pub fn get_opcode_name(opcode: Opcode) -> &'static str {
match opcode {
Opcode::Nop => "NOP",
Opcode::Add => "ADD",
Opcode::Sub => "SUB",
Opcode::Mul => "MUL",
Opcode::Div => "DIV",
Opcode::Mod => "MOD",
Opcode::Concat => "CONCAT",
Opcode::Assign => "ASSIGN",
Opcode::InitFCall => "INIT_FCALL",
Opcode::DoFCall => "DO_FCALL",
Opcode::IsSet => "ISSET",
Opcode::Empty => "EMPTY",
Opcode::Unset => "UNSET",
Opcode::Count => "COUNT",
Opcode::Keys => "KEYS",
Opcode::Values => "VALUES",
Opcode::ArrayDiff => "ARRAY_DIFF",
Opcode::Coalesce => "COALESCE",
Opcode::JmpNullZ => "JMP_NULLZ",
Opcode::BoolAnd => "BOOL_AND",
Opcode::BoolOr => "BOOL_OR",
Opcode::FeReset => "FE_RESET",
Opcode::FeFetch => "FE_FETCH",
_ => "UNKNOWN",
}
}