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