1use runmat_hir::{CallableFallbackPolicy, CallableIdentity, FunctionId};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct StackEffect {
6 pub pops: usize,
7 pub pushes: usize,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub enum EmitLabel {
12 Ans,
13 Var(usize),
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum EndExpr {
18 End,
19 Const(f64),
20 Var(usize),
21 ResolvedCall {
22 identity: CallableIdentity,
23 fallback_policy: CallableFallbackPolicy,
24 args: Vec<EndExpr>,
25 },
26 Add(Box<EndExpr>, Box<EndExpr>),
27 Sub(Box<EndExpr>, Box<EndExpr>),
28 Mul(Box<EndExpr>, Box<EndExpr>),
29 Div(Box<EndExpr>, Box<EndExpr>),
30 LeftDiv(Box<EndExpr>, Box<EndExpr>),
31 Pow(Box<EndExpr>, Box<EndExpr>),
32 Neg(Box<EndExpr>),
33 Pos(Box<EndExpr>),
34 Floor(Box<EndExpr>),
35 Ceil(Box<EndExpr>),
36 Round(Box<EndExpr>),
37 Fix(Box<EndExpr>),
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub enum PropertyDefaultLiteral {
42 Num(f64),
43 Bool(bool),
44 String(String),
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub enum Instr {
49 LoadConst(f64),
51 LoadComplex(f64, f64),
52 LoadBool(bool),
53 LoadString(String),
54 LoadCharRow(String),
55 LoadVar(usize),
56 LoadVarForIndexAssignment(usize),
57 StoreVar(usize),
58
59 Add,
61 Sub,
62 Mul,
63 RightDiv,
64 LeftDiv,
65 Pow,
66 Neg,
67 UPlus,
68 Transpose,
69 ConjugateTranspose,
70 ElemMul,
71 ElemDiv,
72 ElemPow,
73 ElemLeftDiv,
74 LessEqual,
75 Less,
76 Greater,
77 GreaterEqual,
78 Equal,
79 NotEqual,
80 LogicalNot,
81 LogicalAnd,
82 LogicalOr,
83
84 AndAnd(usize),
86 OrOr(usize),
87 JumpIfFalse(usize),
88 Jump(usize),
89 Pop,
90
91 Unpack(usize),
93
94 StochasticEvolution,
96
97 CreateMatrix(usize, usize),
99 CreateMatrixDynamic(usize),
100 CreateRange(bool),
101 Index(usize),
102
103 IndexSlice(usize, usize, u32, u32),
105
106 IndexSliceExpr {
108 dims: usize,
109 numeric_count: usize,
110 colon_mask: u32,
111 end_mask: u32,
112 range_dims: Vec<usize>,
113 range_has_step: Vec<bool>,
114 range_start_exprs: Vec<Option<EndExpr>>,
115 range_step_exprs: Vec<Option<EndExpr>>,
116 range_end_exprs: Vec<EndExpr>,
117 end_numeric_exprs: Vec<(usize, EndExpr)>,
118 },
119
120 StoreSliceExpr {
122 dims: usize,
123 numeric_count: usize,
124 colon_mask: u32,
125 end_mask: u32,
126 range_dims: Vec<usize>,
127 range_has_step: Vec<bool>,
128 range_start_exprs: Vec<Option<EndExpr>>,
129 range_step_exprs: Vec<Option<EndExpr>>,
130 range_end_exprs: Vec<EndExpr>,
131 end_numeric_exprs: Vec<(usize, EndExpr)>,
132 },
133 StoreSliceExprDelete {
134 dims: usize,
135 numeric_count: usize,
136 colon_mask: u32,
137 end_mask: u32,
138 range_dims: Vec<usize>,
139 range_has_step: Vec<bool>,
140 range_start_exprs: Vec<Option<EndExpr>>,
141 range_step_exprs: Vec<Option<EndExpr>>,
142 range_end_exprs: Vec<EndExpr>,
143 end_numeric_exprs: Vec<(usize, EndExpr)>,
144 },
145
146 CreateCell2D(usize, usize),
148 CreateStructLiteral(Vec<String>),
149 CreateObjectLiteral {
150 class_name: String,
151 fields: Vec<String>,
152 },
153 IndexCell {
154 num_indices: usize,
155 end_offsets: Vec<(usize, isize)>,
156 end_exprs: Vec<(usize, EndExpr)>,
157 },
158
159 IndexCellExpand {
161 num_indices: usize,
162 out_count: usize,
163 end_offsets: Vec<(usize, isize)>,
164 end_exprs: Vec<(usize, EndExpr)>,
165 },
166
167 IndexCellList {
169 num_indices: usize,
170 end_offsets: Vec<(usize, isize)>,
171 end_exprs: Vec<(usize, EndExpr)>,
172 },
173
174 StoreIndex(usize),
176 StoreIndexCell {
177 num_indices: usize,
178 end_offsets: Vec<(usize, isize)>,
179 end_exprs: Vec<(usize, EndExpr)>,
180 },
181 StoreIndexDelete(usize),
182 StoreIndexCellDelete {
183 num_indices: usize,
184 end_offsets: Vec<(usize, isize)>,
185 end_exprs: Vec<(usize, EndExpr)>,
186 },
187
188 StoreSlice(usize, usize, u32, u32),
190 StoreSliceDelete(usize, usize, u32, u32),
191
192 LoadMember(String),
194 LoadMemberOrInit(String),
195 LoadMemberDynamic,
196 LoadMemberDynamicOrInit,
197 StoreMember(String),
198 StoreMemberOrInit(String),
199 StoreMemberDynamic,
200 StoreMemberDynamicOrInit,
201 LoadMethod(String),
202
203 CallMethodOrMemberIndexMulti {
205 identity: CallableIdentity,
206 fallback_policy: CallableFallbackPolicy,
207 arg_count: usize,
208 out_count: usize,
209 },
210 CallMethodOrMemberIndexExpandMultiOutput {
211 identity: CallableIdentity,
212 fallback_policy: CallableFallbackPolicy,
213 specs: Vec<ArgSpec>,
214 out_count: usize,
215 },
216
217 CreateFunctionHandle(String),
219 CreateExternalFunctionHandle(String),
220 CreateMethodFunctionHandle(String),
221 CreateBoundFunctionHandle(FunctionId, String),
222 CreateClosure(String, usize),
223 CreateSemanticClosure(FunctionId, String, usize),
224 LoadStaticProperty(String, String),
225
226 RegisterClass {
228 name: String,
229 super_class: Option<String>,
230 is_sealed: bool,
231 is_abstract: bool,
232 properties: Vec<(
233 String,
234 bool,
235 bool,
236 Option<PropertyDefaultLiteral>,
237 String,
238 String,
239 )>,
240 methods: Vec<(String, String, bool, bool, bool, String)>,
241 enumerations: Vec<String>,
242 },
243
244 CallFevalMulti(usize, usize),
246 CallFevalMultiUsingOutputSlot(usize, usize),
247 CallFevalExpandMultiOutput(Vec<ArgSpec>, usize),
248 CallFevalExpandMultiOutputUsingOutputSlot(Vec<ArgSpec>, usize),
249 CreateSemanticFuture(FunctionId, usize, usize),
251 CreateSemanticFutureExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
252 Spawn,
254 Await,
256
257 Swap,
259 EnterTry(usize, Option<usize>),
260 PopTry,
261 Return,
262 ReturnValue,
263
264 CallBuiltinMulti(String, usize, usize),
266 CallBuiltinMultiUsingOutputSlot(String, usize, usize),
267 CallSuperConstructorMulti {
268 current_class: String,
269 super_class: String,
270 arg_count: usize,
271 out_count: usize,
272 },
273 CallSuperMethodMulti {
274 current_class: String,
275 super_class: String,
276 method: String,
277 arg_count: usize,
278 out_count: usize,
279 },
280
281 CallFunctionMulti {
283 identity: CallableIdentity,
284 fallback_policy: CallableFallbackPolicy,
285 arg_count: usize,
286 out_count: usize,
287 },
288 CallFunctionMultiUsingOutputSlot {
289 identity: CallableIdentity,
290 fallback_policy: CallableFallbackPolicy,
291 arg_count: usize,
292 out_count_slot: usize,
293 },
294 CallSemanticFunctionMulti(FunctionId, usize, usize),
295 CallSemanticFunctionMultiUsingOutputSlot(FunctionId, usize, usize),
296 CallSemanticNestedFunctionMulti {
297 function: FunctionId,
298 capture_slots: Vec<usize>,
299 arg_count: usize,
300 out_count: usize,
301 },
302 CallSemanticNestedFunctionMultiUsingOutputSlot {
303 function: FunctionId,
304 capture_slots: Vec<usize>,
305 arg_count: usize,
306 out_count_slot: usize,
307 },
308
309 CallFunctionExpandMultiOutput {
310 identity: CallableIdentity,
311 fallback_policy: CallableFallbackPolicy,
312 specs: Vec<ArgSpec>,
313 out_count: usize,
314 },
315 CallSemanticFunctionExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
316 CallSemanticNestedFunctionExpandMultiOutput {
317 function: FunctionId,
318 capture_slots: Vec<usize>,
319 specs: Vec<ArgSpec>,
320 out_count: usize,
321 },
322 CallBuiltinExpandMultiOutput(String, Vec<ArgSpec>, usize),
323 CallSuperConstructorExpandMultiOutput {
324 current_class: String,
325 super_class: String,
326 specs: Vec<ArgSpec>,
327 out_count: usize,
328 },
329 CallSuperMethodExpandMultiOutput {
330 current_class: String,
331 super_class: String,
332 method: String,
333 specs: Vec<ArgSpec>,
334 out_count: usize,
335 },
336
337 PackToRow(usize),
339 PackToCol(usize),
340
341 EnterScope(usize),
343 ExitScope(usize),
344 LoadLocal(usize),
345 StoreLocal(usize),
346
347 RegisterImport {
349 path: Vec<String>,
350 wildcard: bool,
351 },
352
353 DeclareGlobal(Vec<usize>),
355 DeclarePersistent(Vec<usize>),
356 DeclareGlobalNamed(Vec<usize>, Vec<String>),
357 DeclarePersistentNamed(Vec<usize>, Vec<String>),
358
359 EmitStackTop {
361 label: EmitLabel,
362 },
363 EmitVar {
364 var_index: usize,
365 label: EmitLabel,
366 },
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize)]
370pub struct ArgSpec {
371 pub is_expand: bool,
372 pub num_indices: usize,
373 pub expand_all: bool,
374}
375
376impl Instr {
377 pub fn stack_effect(&self) -> Option<StackEffect> {
378 fn effect(pops: usize, pushes: usize) -> Option<StackEffect> {
379 Some(StackEffect { pops, pushes })
380 }
381
382 match self {
383 Instr::LoadConst(_)
384 | Instr::LoadComplex(_, _)
385 | Instr::LoadBool(_)
386 | Instr::LoadString(_)
387 | Instr::LoadCharRow(_)
388 | Instr::CreateFunctionHandle(_)
389 | Instr::CreateExternalFunctionHandle(_)
390 | Instr::CreateMethodFunctionHandle(_)
391 | Instr::CreateBoundFunctionHandle(_, _)
392 | Instr::LoadVar(_)
393 | Instr::LoadVarForIndexAssignment(_)
394 | Instr::LoadLocal(_) => effect(0, 1),
395 Instr::StoreVar(_)
396 | Instr::StoreLocal(_)
397 | Instr::Pop
398 | Instr::JumpIfFalse(_)
399 | Instr::AndAnd(_)
400 | Instr::OrOr(_) => effect(1, 0),
401 Instr::Add
402 | Instr::Sub
403 | Instr::Mul
404 | Instr::RightDiv
405 | Instr::LeftDiv
406 | Instr::Pow
407 | Instr::ElemMul
408 | Instr::ElemDiv
409 | Instr::ElemPow
410 | Instr::ElemLeftDiv
411 | Instr::LessEqual
412 | Instr::Less
413 | Instr::Greater
414 | Instr::GreaterEqual
415 | Instr::Equal
416 | Instr::NotEqual
417 | Instr::LogicalAnd
418 | Instr::LogicalOr => effect(2, 1),
419 Instr::Swap => effect(2, 2),
420 Instr::Neg
421 | Instr::UPlus
422 | Instr::LogicalNot
423 | Instr::Transpose
424 | Instr::ConjugateTranspose
425 | Instr::LoadMember(_)
426 | Instr::LoadMemberOrInit(_)
427 | Instr::LoadMethod(_) => effect(1, 1),
428 Instr::CallBuiltinMulti(_, argc, _) => effect(*argc, 1),
429 Instr::CallBuiltinMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
430 Instr::CallSuperConstructorMulti { arg_count, .. } => effect(*arg_count, 1),
431 Instr::CallSuperMethodMulti { arg_count, .. } => effect(*arg_count, 1),
432 Instr::CallFunctionMulti {
433 arg_count,
434 out_count,
435 ..
436 } => effect(*arg_count, *out_count),
437 Instr::CallFunctionMultiUsingOutputSlot { arg_count, .. } => effect(*arg_count, 1),
438 Instr::CallSemanticFunctionMulti(_, argc, out_count) => effect(*argc, *out_count),
439 Instr::CallSemanticFunctionMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
440 Instr::CallSemanticNestedFunctionMulti {
441 arg_count,
442 out_count,
443 ..
444 } => effect(*arg_count, *out_count),
445 Instr::CallSemanticNestedFunctionMultiUsingOutputSlot { arg_count, .. } => {
446 effect(*arg_count, 1)
447 }
448 Instr::CallMethodOrMemberIndexMulti { arg_count, .. } => effect(arg_count + 1, 1),
449 Instr::CallFevalMulti(argc, _) => effect(argc + 1, 1),
450 Instr::CallFevalMultiUsingOutputSlot(argc, _) => effect(argc + 1, 1),
451 Instr::CreateSemanticFuture(_, arg_count, _) => effect(*arg_count, 1),
452 Instr::CreateMatrix(rows, cols) | Instr::CreateCell2D(rows, cols) => {
453 effect(rows * cols, 1)
454 }
455 Instr::CreateStructLiteral(fields) => effect(fields.len(), 1),
456 Instr::CreateObjectLiteral { fields, .. } => effect(fields.len(), 1),
457 Instr::CreateMatrixDynamic(rows) => effect(*rows, 1),
458 Instr::CreateRange(has_step) => effect(if *has_step { 3 } else { 2 }, 1),
459 Instr::Unpack(n) => effect(1, *n),
460 Instr::Index(n) => effect(n + 1, 1),
461 Instr::IndexCell { num_indices, .. } | Instr::IndexCellList { num_indices, .. } => {
462 effect(num_indices + 1, 1)
463 }
464 Instr::IndexCellExpand {
465 num_indices,
466 out_count,
467 ..
468 } => effect(num_indices + 1, *out_count),
469 Instr::StoreIndex(n)
470 | Instr::StoreIndexDelete(n)
471 | Instr::StoreIndexCell { num_indices: n, .. }
472 | Instr::StoreIndexCellDelete { num_indices: n, .. } => effect(n + 2, 1),
473 Instr::IndexSlice(dims, numeric_count, _, _)
474 | Instr::StoreSlice(dims, numeric_count, _, _)
475 | Instr::StoreSliceDelete(dims, numeric_count, _, _) => {
476 let pops = 1 + numeric_count;
477 if matches!(
478 self,
479 Instr::StoreSlice(_, _, _, _) | Instr::StoreSliceDelete(_, _, _, _)
480 ) {
481 effect(pops + 1, 1)
482 } else {
483 let _ = dims;
484 effect(pops, 1)
485 }
486 }
487 Instr::IndexSliceExpr {
488 numeric_count,
489 range_dims,
490 ..
491 } => effect(1 + numeric_count + range_dims.len(), 1),
492 Instr::StoreSliceExpr {
493 numeric_count,
494 range_dims,
495 ..
496 }
497 | Instr::StoreSliceExprDelete {
498 numeric_count,
499 range_dims,
500 ..
501 } => effect(2 + numeric_count + range_dims.len(), 1),
502 Instr::StoreMember(_)
503 | Instr::StoreMemberOrInit(_)
504 | Instr::StoreMemberDynamic
505 | Instr::StoreMemberDynamicOrInit => effect(2, 1),
506 Instr::LoadMemberDynamic | Instr::LoadMemberDynamicOrInit => effect(2, 1),
507 Instr::CreateClosure(_, capture_count)
508 | Instr::CreateSemanticClosure(_, _, capture_count) => effect(*capture_count, 1),
509 Instr::LoadStaticProperty(_, _) => effect(0, 1),
510 Instr::RegisterClass { .. } => effect(0, 0),
511 Instr::CallFevalExpandMultiOutput(specs, _)
512 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(specs, _)
513 | Instr::CreateSemanticFutureExpandMultiOutput(_, specs, _)
514 | Instr::CallFunctionExpandMultiOutput { specs, .. }
515 | Instr::CallSemanticFunctionExpandMultiOutput(_, specs, _)
516 | Instr::CallSemanticNestedFunctionExpandMultiOutput { specs, .. }
517 | Instr::CallBuiltinExpandMultiOutput(_, specs, _)
518 | Instr::CallSuperConstructorExpandMultiOutput { specs, .. }
519 | Instr::CallSuperMethodExpandMultiOutput { specs, .. }
520 | Instr::CallMethodOrMemberIndexExpandMultiOutput { specs, .. } => {
521 let fixed = specs.iter().filter(|s| !s.is_expand).count();
522 let expanded: usize = specs
523 .iter()
524 .filter(|s| s.is_expand)
525 .map(|s| 1 + s.num_indices)
526 .sum();
527 let handle = usize::from(matches!(
528 self,
529 Instr::CallFevalExpandMultiOutput(_, _)
530 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(_, _)
531 ));
532 effect(handle + fixed + expanded, 1)
533 }
534 Instr::PackToRow(n) | Instr::PackToCol(n) => effect(*n, 1),
535 Instr::EnterScope(_) | Instr::ExitScope(_) | Instr::Jump(_) | Instr::PopTry => {
536 effect(0, 0)
537 }
538 Instr::EnterTry(_, _) => effect(0, 0),
539 Instr::Return => effect(0, 0),
540 Instr::ReturnValue => effect(1, 0),
541 Instr::RegisterImport { .. }
542 | Instr::DeclareGlobal(_)
543 | Instr::DeclarePersistent(_)
544 | Instr::DeclareGlobalNamed(_, _)
545 | Instr::DeclarePersistentNamed(_, _) => effect(0, 0),
546 Instr::Spawn => effect(1, 1),
547 Instr::Await => effect(1, 1),
548 Instr::EmitStackTop { .. } => effect(1, 1),
549 Instr::EmitVar { .. } => effect(0, 0),
550 Instr::StochasticEvolution => None,
551 }
552 }
553}