1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub struct StackEffect {
5 pub pops: usize,
6 pub pushes: usize,
7}
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub enum EmitLabel {
11 Ans,
12 Var(usize),
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub enum EndExpr {
17 End,
18 Const(f64),
19 Var(usize),
20 Call(String, Vec<EndExpr>),
21 Add(Box<EndExpr>, Box<EndExpr>),
22 Sub(Box<EndExpr>, Box<EndExpr>),
23 Mul(Box<EndExpr>, Box<EndExpr>),
24 Div(Box<EndExpr>, Box<EndExpr>),
25 LeftDiv(Box<EndExpr>, Box<EndExpr>),
26 Pow(Box<EndExpr>, Box<EndExpr>),
27 Neg(Box<EndExpr>),
28 Pos(Box<EndExpr>),
29 Floor(Box<EndExpr>),
30 Ceil(Box<EndExpr>),
31 Round(Box<EndExpr>),
32 Fix(Box<EndExpr>),
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub enum Instr {
37 LoadConst(f64),
39 LoadComplex(f64, f64),
40 LoadBool(bool),
41 LoadString(String),
42 LoadCharRow(String),
43 LoadVar(usize),
44 StoreVar(usize),
45
46 Add,
48 Sub,
49 Mul,
50 RightDiv,
51 LeftDiv,
52 Pow,
53 Neg,
54 UPlus,
55 Transpose,
56 ConjugateTranspose,
57 ElemMul,
58 ElemDiv,
59 ElemPow,
60 ElemLeftDiv,
61 LessEqual,
62 Less,
63 Greater,
64 GreaterEqual,
65 Equal,
66 NotEqual,
67
68 AndAnd(usize),
70 OrOr(usize),
71 JumpIfFalse(usize),
72 Jump(usize),
73 Pop,
74
75 Unpack(usize),
77
78 CallBuiltin(String, usize),
80
81 StochasticEvolution,
83
84 CreateMatrix(usize, usize),
86 CreateMatrixDynamic(usize),
87 CreateRange(bool),
88 Index(usize),
89
90 IndexSlice(usize, usize, u32, u32),
92
93 IndexSliceExpr {
95 dims: usize,
96 numeric_count: usize,
97 colon_mask: u32,
98 end_mask: u32,
99 range_dims: Vec<usize>,
100 range_has_step: Vec<bool>,
101 range_start_exprs: Vec<Option<EndExpr>>,
102 range_step_exprs: Vec<Option<EndExpr>>,
103 range_end_exprs: Vec<EndExpr>,
104 end_numeric_exprs: Vec<(usize, EndExpr)>,
105 },
106
107 StoreSliceExpr {
109 dims: usize,
110 numeric_count: usize,
111 colon_mask: u32,
112 end_mask: u32,
113 range_dims: Vec<usize>,
114 range_has_step: Vec<bool>,
115 range_start_exprs: Vec<Option<EndExpr>>,
116 range_step_exprs: Vec<Option<EndExpr>>,
117 range_end_exprs: Vec<EndExpr>,
118 end_numeric_exprs: Vec<(usize, EndExpr)>,
119 },
120
121 CreateCell2D(usize, usize),
123 IndexCell(usize),
124
125 IndexCellExpand(usize, usize),
127
128 StoreIndex(usize),
130 StoreIndexCell(usize),
131
132 StoreSlice(usize, usize, u32, u32),
134
135 LoadMember(String),
137 LoadMemberOrInit(String),
138 LoadMemberDynamic,
139 LoadMemberDynamicOrInit,
140 StoreMember(String),
141 StoreMemberOrInit(String),
142 StoreMemberDynamic,
143 StoreMemberDynamicOrInit,
144 LoadMethod(String),
145 CallMethod(String, usize),
146
147 CallMethodOrMemberIndex(String, usize),
149
150 CreateClosure(String, usize),
152 LoadStaticProperty(String, String),
153 CallStaticMethod(String, String, usize),
154
155 RegisterClass {
157 name: String,
158 super_class: Option<String>,
159 properties: Vec<(String, bool, String, String)>,
160 methods: Vec<(String, String, bool, String)>,
161 },
162
163 CallFeval(usize),
165 CallFevalExpandMulti(Vec<ArgSpec>),
166
167 Swap,
169 EnterTry(usize, Option<usize>),
170 PopTry,
171 Return,
172 ReturnValue,
173
174 CallFunction(String, usize),
176
177 CallFunctionMulti(String, usize, usize),
179
180 CallFunctionExpandAt(String, usize, usize, usize),
182 CallBuiltinExpandLast(String, usize, usize),
183 CallBuiltinExpandAt(String, usize, usize, usize),
184 CallFunctionExpandMulti(String, Vec<ArgSpec>),
185 CallBuiltinExpandMulti(String, Vec<ArgSpec>),
186
187 PackToRow(usize),
189 PackToCol(usize),
190
191 EnterScope(usize),
193 ExitScope(usize),
194 LoadLocal(usize),
195 StoreLocal(usize),
196
197 RegisterImport {
199 path: Vec<String>,
200 wildcard: bool,
201 },
202
203 DeclareGlobal(Vec<usize>),
205 DeclarePersistent(Vec<usize>),
206 DeclareGlobalNamed(Vec<usize>, Vec<String>),
207 DeclarePersistentNamed(Vec<usize>, Vec<String>),
208
209 EmitStackTop {
211 label: EmitLabel,
212 },
213 EmitVar {
214 var_index: usize,
215 label: EmitLabel,
216 },
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct ArgSpec {
221 pub is_expand: bool,
222 pub num_indices: usize,
223 pub expand_all: bool,
224}
225
226impl Instr {
227 pub fn stack_effect(&self) -> Option<StackEffect> {
228 fn effect(pops: usize, pushes: usize) -> Option<StackEffect> {
229 Some(StackEffect { pops, pushes })
230 }
231
232 match self {
233 Instr::LoadConst(_)
234 | Instr::LoadComplex(_, _)
235 | Instr::LoadBool(_)
236 | Instr::LoadString(_)
237 | Instr::LoadCharRow(_)
238 | Instr::LoadVar(_)
239 | Instr::LoadLocal(_) => effect(0, 1),
240 Instr::StoreVar(_)
241 | Instr::StoreLocal(_)
242 | Instr::Pop
243 | Instr::JumpIfFalse(_)
244 | Instr::AndAnd(_)
245 | Instr::OrOr(_) => effect(1, 0),
246 Instr::Add
247 | Instr::Sub
248 | Instr::Mul
249 | Instr::RightDiv
250 | Instr::LeftDiv
251 | Instr::Pow
252 | Instr::ElemMul
253 | Instr::ElemDiv
254 | Instr::ElemPow
255 | Instr::ElemLeftDiv
256 | Instr::LessEqual
257 | Instr::Less
258 | Instr::Greater
259 | Instr::GreaterEqual
260 | Instr::Equal
261 | Instr::NotEqual => effect(2, 1),
262 Instr::Swap => effect(2, 2),
263 Instr::Neg
264 | Instr::UPlus
265 | Instr::Transpose
266 | Instr::ConjugateTranspose
267 | Instr::LoadMember(_)
268 | Instr::LoadMemberOrInit(_)
269 | Instr::LoadMethod(_) => effect(1, 1),
270 Instr::CallBuiltin(_, argc) | Instr::CallFunction(_, argc) => effect(*argc, 1),
271 Instr::CallFunctionMulti(_, argc, out_count) => effect(*argc, *out_count),
272 Instr::CallMethod(_, argc) | Instr::CallMethodOrMemberIndex(_, argc) => {
273 effect(argc + 1, 1)
274 }
275 Instr::CallStaticMethod(_, _, argc) => effect(*argc, 1),
276 Instr::CallFeval(argc) => effect(argc + 1, 1),
277 Instr::CreateMatrix(rows, cols) | Instr::CreateCell2D(rows, cols) => {
278 effect(rows * cols, 1)
279 }
280 Instr::CreateMatrixDynamic(rows) => effect(*rows, 1),
281 Instr::CreateRange(has_step) => effect(if *has_step { 3 } else { 2 }, 1),
282 Instr::Unpack(n) => effect(1, *n),
283 Instr::Index(n) | Instr::IndexCell(n) => effect(n + 1, 1),
284 Instr::IndexCellExpand(n, out_count) => effect(n + 1, *out_count),
285 Instr::StoreIndex(n) | Instr::StoreIndexCell(n) => effect(n + 2, 1),
286 Instr::IndexSlice(dims, numeric_count, _, _)
287 | Instr::StoreSlice(dims, numeric_count, _, _) => {
288 let pops = 1 + numeric_count;
289 if matches!(self, Instr::StoreSlice(_, _, _, _)) {
290 effect(pops + 1, 1)
291 } else {
292 let _ = dims;
293 effect(pops, 1)
294 }
295 }
296 Instr::IndexSliceExpr {
297 numeric_count,
298 range_dims,
299 ..
300 } => effect(1 + numeric_count + range_dims.len(), 1),
301 Instr::StoreSliceExpr {
302 numeric_count,
303 range_dims,
304 ..
305 } => effect(2 + numeric_count + range_dims.len(), 1),
306 Instr::StoreMember(_)
307 | Instr::StoreMemberOrInit(_)
308 | Instr::StoreMemberDynamic
309 | Instr::StoreMemberDynamicOrInit => effect(2, 1),
310 Instr::LoadMemberDynamic | Instr::LoadMemberDynamicOrInit => effect(2, 1),
311 Instr::CreateClosure(_, capture_count) => effect(*capture_count, 1),
312 Instr::LoadStaticProperty(_, _) => effect(0, 1),
313 Instr::RegisterClass { .. } => effect(0, 0),
314 Instr::CallFevalExpandMulti(specs)
315 | Instr::CallFunctionExpandMulti(_, specs)
316 | Instr::CallBuiltinExpandMulti(_, specs) => {
317 let fixed = specs.iter().filter(|s| !s.is_expand).count();
318 let expanded: usize = specs
319 .iter()
320 .filter(|s| s.is_expand)
321 .map(|s| 1 + s.num_indices)
322 .sum();
323 let handle = usize::from(matches!(self, Instr::CallFevalExpandMulti(_)));
324 effect(handle + fixed + expanded, 1)
325 }
326 Instr::CallFunctionExpandAt(_, before, num_indices, after)
327 | Instr::CallBuiltinExpandAt(_, before, num_indices, after) => {
328 effect(before + after + 1 + num_indices, 1)
329 }
330 Instr::CallBuiltinExpandLast(_, fixed_argc, num_indices) => {
331 effect(fixed_argc + 1 + num_indices, 1)
332 }
333 Instr::PackToRow(n) | Instr::PackToCol(n) => effect(*n, 1),
334 Instr::EnterScope(_) | Instr::ExitScope(_) | Instr::Jump(_) | Instr::PopTry => {
335 effect(0, 0)
336 }
337 Instr::EnterTry(_, _) => effect(0, 0),
338 Instr::Return => effect(0, 0),
339 Instr::ReturnValue => effect(1, 0),
340 Instr::RegisterImport { .. }
341 | Instr::DeclareGlobal(_)
342 | Instr::DeclarePersistent(_)
343 | Instr::DeclareGlobalNamed(_, _)
344 | Instr::DeclarePersistentNamed(_, _) => effect(0, 0),
345 Instr::EmitStackTop { .. } => effect(1, 1),
346 Instr::EmitVar { .. } => effect(0, 0),
347 Instr::StochasticEvolution => None,
348 }
349 }
350}