1mod block_data;
2pub mod frame;
3pub mod func;
4pub mod instr;
5
6use std::collections::hash_map::HashMap;
7use std::ops::Rem;
8use std::rc::Rc;
9use std::{fmt, vec};
10
11use crate::calx::Calx;
12use crate::syntax::CalxSyntax;
13use crate::vm::block_data::BlockStack;
14
15use self::block_data::BlockData;
16use self::frame::CalxFrame;
17use self::func::CalxFunc;
18use self::instr::CalxInstr;
19
20pub type CalxImportsDict = HashMap<String, (fn(xs: Vec<Calx>) -> Result<Calx, CalxError>, usize)>;
21
22#[derive(Clone)]
30pub struct CalxVM {
31 pub stack: Vec<Calx>,
32 pub globals: Vec<Calx>,
33 pub funcs: Vec<CalxFunc>,
34 pub frames: Vec<CalxFrame>,
35 pub top_frame: CalxFrame,
36 pub imports: CalxImportsDict,
37 pub finished: bool,
39 pub return_value: Calx,
40}
41
42impl std::fmt::Debug for CalxVM {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.write_str("CalxVM Instance")
45 }
46}
47
48impl CalxVM {
49 pub fn new(fns: Vec<CalxFunc>, globals: Vec<Calx>, imports: CalxImportsDict) -> Self {
50 let main_func = fns.iter().find(|x| *x.name == "main").expect("main function is required");
51 let main_frame = CalxFrame {
52 name: main_func.name.to_owned(),
53 initial_stack_size: 0,
54 instrs: Rc::new(vec![]),
56 pointer: 0,
57 locals: vec![],
58 ret_types: main_func.ret_types.clone(),
59 };
60 CalxVM {
61 stack: vec![],
62 globals,
63 funcs: fns,
64 frames: vec![],
65 top_frame: main_frame,
66 imports,
67 return_value: Calx::Nil,
68 finished: false,
69 }
70 }
71
72 pub fn setup_top_frame(&mut self) -> Result<(), String> {
73 self.top_frame.instrs = match self.find_func("main") {
74 Some(f) => match f.instrs.to_owned() {
75 Some(x) => x,
76 None => return Err("main function must have instrs".to_owned()),
77 },
78 None => return Err("main function is required".to_owned()),
79 };
80
81 Ok(())
82 }
83
84 pub fn make_return(&mut self, v: Calx) {
85 self.return_value = v;
86 self.finished = true;
87 }
88
89 pub fn inspect_display(&self, indent_size: u8) -> String {
90 let mut output = String::new();
91 let indent = "\n".to_owned() + &" ".repeat(indent_size as usize);
92 fmt::write(
93 &mut output,
94 format_args!(
95 "{indent}Internal frames: {:?}",
96 self.frames.iter().map(|x| x.name.to_owned()).collect::<Vec<_>>()
97 ),
98 )
99 .expect("inspect display");
100
101 fmt::write(&mut output, format_args!("{indent}Top frame: {}", self.top_frame.name)).expect("inspect display");
102 fmt::write(&mut output, format_args!("{indent}Locals: {:?}", self.top_frame.locals)).expect("inspect display");
103 fmt::write(&mut output, format_args!("{indent}Stack({}): {:?}", self.stack.len(), self.stack)).expect("inspect display");
104 fmt::write(
105 &mut output,
106 format_args!(
107 "{indent}Sizes: {} + {}",
108 self.top_frame.initial_stack_size,
109 self.top_frame.ret_types.len()
110 ),
111 )
112 .expect("inspect display");
113 fmt::write(&mut output, format_args!("{indent}Pointer: {}", self.top_frame.pointer)).expect("inspect display");
114 output
115 }
116
117 pub fn run(&mut self, args: Vec<Calx>) -> Result<Calx, CalxError> {
118 self.top_frame.locals = args;
120 self.stack.clear();
121 loop {
122 if self.finished {
126 return Ok(self.return_value.to_owned());
127 }
128
129 let quick_continue = self.step()?;
130 if quick_continue {
131 continue;
132 }
133
134 self.top_frame.pointer += 1;
135 }
136 }
137
138 #[inline(always)]
140 pub fn step(&mut self) -> Result<bool, CalxError> {
141 if self.top_frame.pointer >= self.top_frame.instrs.len() {
142 self.check_func_return()?;
144 if self.frames.is_empty() {
145 let v = self.stack.pop().unwrap_or(Calx::Nil);
146 self.make_return(v);
147 return Ok(false);
148 } else {
149 self.top_frame = self.frames.pop().unwrap();
151 }
152 self.top_frame.pointer += 1;
153 return Ok(true);
154 }
155 let instrs = self.top_frame.instrs.to_owned();
156
157 use instr::CalxInstr::*;
158
159 match &instrs[self.top_frame.pointer] {
160 Jmp(line) => {
161 self.top_frame.pointer = line.to_owned();
162 return Ok(true); }
164 JmpOffset(l) => {
165 self.top_frame.pointer = (self.top_frame.pointer as i32 + l) as usize;
166 return Ok(true); }
168 JmpIf(line) => {
169 let v = self.stack_pop()?;
170 if v == Calx::Bool(true) || v == Calx::I64(1) {
171 self.top_frame.pointer = line.to_owned();
172 return Ok(true); }
174 }
175 JmpOffsetIf(l) => {
176 let v = self.stack_pop()?;
177 if v == Calx::Bool(true) || v == Calx::I64(1) {
178 self.top_frame.pointer = (self.top_frame.pointer as i32 + l) as usize;
179 return Ok(true); }
181 }
182 LocalSet(idx) => {
183 let v = self.stack_pop()?;
184 if *idx >= self.top_frame.locals.len() {
185 return Err(self.gen_err(format!("out of bound in local.set {} for {:?}", idx, self.top_frame.locals)));
186 } else {
187 self.top_frame.locals[*idx] = v
188 }
189 }
190 LocalTee(idx) => {
191 let v = self.stack_pop()?;
192 if *idx >= self.top_frame.locals.len() {
193 return Err(self.gen_err(format!("out of bound in local.tee {}", idx)));
194 } else {
195 self.top_frame.locals[*idx] = v.to_owned()
196 }
197 self.stack_push(v);
198 }
199 LocalGet(idx) => {
200 if *idx < self.top_frame.locals.len() {
201 self.stack_push(self.top_frame.locals[*idx].to_owned())
202 } else {
203 return Err(self.gen_err(format!("invalid index for local.get {}", idx)));
204 }
205 }
206 Return => {
207 let mut ret_stack: Vec<Calx> = vec![];
209
210 let ret_size = self.top_frame.ret_types.len();
211 for _ in 0..ret_size {
212 let v = self.stack_pop()?;
213 ret_stack.insert(0, v);
214 }
215
216 self.check_func_return()?;
217
218 if self.frames.is_empty() {
219 return match ret_stack.first() {
221 Some(x) => {
222 self.make_return(x.to_owned());
223 Ok(false)
224 }
225 None => Err(self.gen_err("return without value".to_owned())),
226 };
227 } else {
228 self.top_frame = self.frames.pop().unwrap();
230 for v in ret_stack {
232 self.stack_push(v);
233 }
234 }
235 }
236 LocalNew => self.top_frame.locals.push(Calx::Nil),
237 GlobalSet(idx) => {
238 let v = self.stack_pop()?;
239 if self.globals.len() >= *idx {
240 return Err(self.gen_err(format!("out of bound in global.set {}", idx)));
241 } else {
242 self.globals[*idx] = v
243 }
244 }
245 GlobalGet(idx) => {
246 if *idx < self.globals.len() {
247 self.stack_push(self.globals[*idx].to_owned())
248 } else {
249 return Err(self.gen_err(format!("invalid index for global.get {}", idx)));
250 }
251 }
252 GlobalNew => self.globals.push(Calx::Nil),
253 Const(v) => self.stack_push(v.to_owned()),
254 Dup => {
255 self.stack_push(self.stack[self.stack.len() - 1].to_owned());
256 }
257 Drop => {
258 let _ = self.stack_pop()?;
259 }
260 IntAdd => {
261 let v2 = self.stack_pop()?;
263 let last_idx = self.stack.len() - 1;
264 match (&(self.stack[last_idx]), &v2) {
265 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 + n2),
266 (_, _) => return Err(self.gen_err(format!("expected 2 integers to add, {:?} {:?}", self.stack[last_idx], v2))),
267 }
268 }
269 IntMul => {
270 let v2 = self.stack_pop()?;
272 let last_idx = self.stack.len() - 1;
273 match (&self.stack[last_idx], &v2) {
274 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 * n2),
275 (_, _) => return Err(self.gen_err(format!("expected 2 integers to multiply, {:?} {:?}", self.stack[last_idx], v2))),
276 }
277 }
278 IntDiv => {
279 let v2 = self.stack_pop()?;
281 let last_idx = self.stack.len() - 1;
282 match (&self.stack[last_idx], &v2) {
283 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 / n2),
284 (_, _) => return Err(self.gen_err(format!("expected 2 integers to divide, {:?} {:?}", self.stack[last_idx], v2))),
285 }
286 }
287 IntRem => {
288 let v2 = self.stack_pop()?;
290 let last_idx = self.stack.len() - 1;
291 match (&self.stack[last_idx], &v2) {
292 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64((*n1).rem(n2)),
293 (_, _) => return Err(self.gen_err(format!("expected 2 integers to add, {:?} {:?}", self.stack[last_idx], v2))),
294 }
295 }
296 IntNeg => {
297 let last_idx = self.stack.len() - 1;
298 if let Calx::I64(n) = self.stack[last_idx] {
299 self.stack[last_idx] = Calx::I64(-n)
300 } else {
301 return Err(self.gen_err(format!("expected int, got {}", self.stack[last_idx])));
302 }
303 }
304 IntShr => {
305 let bits = self.stack_pop()?;
306 let last_idx = self.stack.len() - 1;
307 match (&self.stack[last_idx], &bits) {
308 (Calx::I64(n), Calx::I64(b)) => self.stack[last_idx] = Calx::I64(n.checked_shr(*b as u32).unwrap()),
309 (_, _) => return Err(self.gen_err(format!("invalid number for SHR, {:?} {:?}", self.stack[last_idx], bits))),
310 }
311 }
312 IntShl => {
313 let bits = self.stack_pop()?;
314 let last_idx = self.stack.len() - 1;
315 match (&self.stack[last_idx], &bits) {
316 (Calx::I64(n), Calx::I64(b)) => self.stack[last_idx] = Calx::I64(n.checked_shl(*b as u32).unwrap()),
317 (_, _) => return Err(self.gen_err(format!("invalid number for SHL, {:?} {:?}", self.stack[last_idx], bits))),
318 }
319 }
320 IntEq => {
321 let v2 = self.stack_pop()?;
323 let last_idx = self.stack.len() - 1;
324
325 match (&self.stack[last_idx], &v2) {
326 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 == n2),
327 (_, _) => return Err(self.gen_err(format!("expected 2 integers to eq compare, {:?} {:?}", self.stack[last_idx], v2))),
328 }
329 }
330
331 IntNe => {
332 let v2 = self.stack_pop()?;
334 let last_idx = self.stack.len() - 1;
335 match (&self.stack[last_idx], &v2) {
336 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 != n2),
337 (_, _) => return Err(self.gen_err(format!("expected 2 integers to ne compare, {:?} {:?}", self.stack[last_idx], v2))),
338 }
339 }
340 IntLt => {
341 let v2 = self.stack_pop()?;
343 let last_idx = self.stack.len() - 1;
344 match (&self.stack[last_idx], &v2) {
345 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 < n2),
346 (_, _) => return Err(self.gen_err(format!("expected 2 integers to le compare, {:?} {:?}", self.stack[last_idx], v2))),
347 }
348 }
349 IntLe => {
350 let v2 = self.stack_pop()?;
352 let last_idx = self.stack.len() - 1;
353 match (&self.stack[last_idx], &v2) {
354 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 <= n2),
355 (_, _) => return Err(self.gen_err(format!("expected 2 integers to le compare, {:?} {:?}", self.stack[last_idx], v2))),
356 }
357 }
358 IntGt => {
359 let v2 = self.stack_pop()?;
361 let last_idx = self.stack.len() - 1;
362
363 match (&self.stack[last_idx], &v2) {
364 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 > n2),
365 (_, _) => return Err(self.gen_err(format!("expected 2 integers to gt compare, {:?} {:?}", self.stack[last_idx], v2))),
366 }
367 }
368 IntGe => {
369 let v2 = self.stack_pop()?;
371 let last_idx = self.stack.len() - 1;
372
373 match (&self.stack[last_idx], &v2) {
374 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::Bool(n1 >= n2),
375 (_, _) => return Err(self.gen_err(format!("expected 2 integers to ge compare, {:?} {:?}", self.stack[last_idx], v2))),
376 }
377 }
378 Add => {
379 let v2 = self.stack_pop()?;
381 let last_idx = self.stack.len() - 1;
382
383 match (&self.stack[last_idx], &v2) {
384 (Calx::F64(n1), Calx::F64(n2)) => self.stack[last_idx] = Calx::F64(n1 + n2),
385 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 + n2),
386 (_, _) => return Err(self.gen_err(format!("expected 2 numbers to +, {:?} {:?}", self.stack[last_idx], v2))),
387 }
388 }
389 Mul => {
390 let v2 = self.stack_pop()?;
392 let last_idx = self.stack.len() - 1;
393
394 match (&self.stack[last_idx], &v2) {
395 (Calx::F64(n1), Calx::F64(n2)) => self.stack[last_idx] = Calx::F64(n1 * n2),
396 (Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 * n2),
397 (_, _) => return Err(self.gen_err(format!("expected 2 numbers to multiply, {:?} {:?}", self.stack[last_idx], v2))),
398 }
399 }
400 Div => {
401 let v2 = self.stack_pop()?;
403 let last_idx = self.stack.len() - 1;
404
405 match (&self.stack[last_idx], &v2) {
406 (Calx::F64(n1), Calx::F64(n2)) => self.stack[last_idx] = Calx::F64(n1 / n2),
407 (_, _) => return Err(self.gen_err(format!("expected 2 numbers to divide, {:?} {:?}", self.stack[last_idx], v2))),
408 }
409 }
410 Neg => {
411 let last_idx = self.stack.len() - 1;
412 if let Calx::F64(n) = self.stack[last_idx] {
413 self.stack[last_idx] = Calx::F64(-n)
414 } else {
415 return Err(self.gen_err(format!("expected float, got {}", self.stack[last_idx])));
416 }
417 }
418 NewList => {
419 todo!()
420 }
421 ListGet => {
422 todo!()
423 }
424 ListSet => {
425 todo!()
426 }
427 NewLink => {
428 todo!()
429 }
430 And => {
431 todo!()
432 }
433 Or => {
434 todo!()
435 }
436 Not => {
437 todo!()
438 }
439 Call(f_name) => {
440 match self.find_func(f_name) {
442 Some(f) => {
443 let instrs = f.instrs.to_owned();
444 let ret_types = f.ret_types.to_owned();
445 let f_name = f.name.to_owned();
446 let mut locals: Vec<Calx> = vec![];
447 for _ in 0..f.params_types.len() {
448 let v = self.stack_pop()?;
449 locals.insert(0, v);
450 }
451 self.frames.push(self.top_frame.to_owned());
452 self.top_frame = CalxFrame {
453 name: f_name,
454 initial_stack_size: self.stack.len(),
455 locals,
456 pointer: 0,
457 instrs: match instrs {
458 Some(x) => x.to_owned(),
459 None => unreachable!("function must have instrs"),
460 },
461 ret_types,
462 };
463
464 return Ok(true);
466 }
467 None => return Err(self.gen_err(format!("cannot find function named: {}", f_name))),
468 }
469 }
470 ReturnCall(f_name) => {
471 match self.find_func(f_name) {
473 Some(f) => {
474 let instrs = f.instrs.to_owned();
476 let ret_types = f.ret_types.to_owned();
477 let f_name = f.name.to_owned();
478 let mut locals: Vec<Calx> = vec![];
479 for _ in 0..f.params_types.len() {
480 let v = self.stack_pop()?;
481 locals.insert(0, v);
482 }
483 let prev_frame = &self.top_frame;
484 if prev_frame.initial_stack_size != self.stack.len() {
485 return Err(self.gen_err(format!(
486 "expected constant initial stack size: {}, got: {}",
487 prev_frame.initial_stack_size,
488 self.stack.len()
489 )));
490 }
491 self.top_frame = CalxFrame {
492 name: f_name,
493 initial_stack_size: self.stack.len(),
494 locals,
495 pointer: 0,
496 instrs: match instrs {
497 Some(x) => x.to_owned(),
498 None => panic!("function must have instrs"),
499 },
500 ret_types,
501 };
502
503 return Ok(true);
505 }
506 None => return Err(self.gen_err(format!("cannot find function named: {}", f_name))),
507 }
508 }
509 CallImport(f_name) => match self.imports.to_owned().get(f_name) {
510 None => return Err(self.gen_err(format!("missing imported function {}", f_name))),
511 Some((f, size)) => {
512 if self.stack.len() < *size {
513 return Err(self.gen_err(format!(
514 "imported function {} expected {} arguemtns, found {} on stack",
515 f_name,
516 size,
517 self.stack.len()
518 )));
519 }
520 let mut args: Vec<Calx> = vec![];
521 for _ in 0..*size {
522 let item = self.stack_pop()?;
523 args.insert(0, item);
524 }
525 let v = f(args.to_owned())?;
526 self.stack_push(v);
527 }
528 },
529 Unreachable => {
530 unreachable!("Unexpected from op")
531 }
532 Nop => {
533 }
535 Quit(code) => std::process::exit(*code as i32),
536 Echo => {
537 let v = self.stack_pop()?;
538 println!("{}", v);
539 }
540 Assert(message) => {
541 let v = self.stack_pop()?;
542 if v == Calx::Bool(true) || v == Calx::I64(1) {
543 } else {
545 return Err(self.gen_err(format!("Failed assertion: {}", message)));
546 }
547 }
548 Inspect => {
549 println!("[ ----------------{}", self.inspect_display(2));
550 println!(" -------------- ]");
551 }
552 }
553
554 Ok(false)
555 }
556
557 pub fn preprocess(&mut self, verbose: bool) -> Result<(), String> {
558 for i in 0..self.funcs.len() {
559 let mut stack_size = 0;
560 let mut ops: Vec<CalxInstr> = vec![];
561 let mut blocks_track = BlockStack::new();
562
563 let f = &self.funcs[i];
564
565 if verbose {
566 println!(
567 "\nFUNC {}\n initial stack size: {}\n ret_size {}",
568 f.name,
569 stack_size,
570 f.ret_types.len()
571 );
572 }
573
574 for j in 0..self.funcs[i].syntax.len() {
575 if verbose {
576 println!("{} * {:?}", stack_size, self.funcs[i].syntax[j].to_owned());
577 }
578 let syntax = &self.funcs[i].syntax;
579 match &syntax[j] {
580 CalxSyntax::Block {
581 looped,
582 params_types,
583 ret_types,
584 from,
585 to,
586 } => {
587 if stack_size < params_types.len() {
588 return Err(format!("insufficient params {} for block: {:?}", stack_size, params_types));
589 }
590 if *looped {
591 blocks_track.push(BlockData::Loop {
592 params_types: params_types.to_owned(),
593 ret_types: ret_types.to_owned(),
594 from: from.to_owned(),
595 to: to.to_owned(),
596 initial_stack_size: stack_size,
597 });
598 } else {
599 blocks_track.push(BlockData::Block {
600 params_types: params_types.to_owned(),
601 ret_types: ret_types.to_owned(),
602 to: to.to_owned(),
603 initial_stack_size: stack_size,
604 });
605 }
606 ops.push(CalxInstr::Nop);
607 }
608 CalxSyntax::Br(size) => {
609 if *size > blocks_track.len() {
610 return Err(format!("br {} too large", size));
611 }
612
613 let target_block = blocks_track.peek_block_level(*size)?;
614 let expected_size = target_block.expected_finish_size();
615 if stack_size != expected_size {
616 return Err(format!("br({size}) expected size {expected_size}, got {stack_size}"));
617 }
618
619 match target_block {
620 BlockData::Loop { from, .. } => ops.push(CalxInstr::Jmp(from.to_owned())),
621 BlockData::Block { to, .. } => ops.push(CalxInstr::Jmp(to.to_owned())),
622 _ => unreachable!("br target must be block or loop"),
623 }
624 }
625 CalxSyntax::BrIf(size) => {
626 if blocks_track.is_empty() {
627 return Err(format!("cannot branch with no blocks, {}", size));
628 }
629 if *size > blocks_track.len() {
630 return Err(format!("br {} too large", size));
631 }
632
633 let target_block = blocks_track.peek_block_level(*size)?;
634
635 match target_block {
636 BlockData::Loop { from, .. } => ops.push(CalxInstr::JmpIf(from.to_owned())),
637 BlockData::Block { to, .. } => ops.push(CalxInstr::JmpIf(to.to_owned())),
638 _ => unreachable!("br target must be block or loop"),
639 }
640 stack_size -= 1;
641
642 let expected_size = target_block.expected_finish_size();
643 if stack_size != expected_size {
644 return Err(format!("brIf({size}) expected size {expected_size}, got {stack_size}"));
645 }
646 }
647 CalxSyntax::BlockEnd(looped) => {
648 if blocks_track.is_empty() {
650 return Err(format!("invalid block end, {:?}", blocks_track));
651 }
652
653 let prev_block = blocks_track.pop_block()?;
654 if *looped {
655 } else if stack_size != prev_block.expected_finish_size() {
657 return Err(format!("size mismatch for block end: {} {:?}", stack_size, prev_block));
658 }
659
660 ops.push(CalxInstr::Nop)
661 }
662 CalxSyntax::Call(f_name) => match self.find_func(f_name) {
663 Some(f) => {
664 if stack_size < f.params_types.len() {
665 return Err(format!("insufficient size to call: {} {:?}", stack_size, f.params_types));
666 }
667 stack_size = stack_size - f.params_types.len() + f.ret_types.len();
668 ops.push(CalxInstr::Call(f_name.to_owned()))
669 }
670 None => return Err(format!("cannot find function named: {}", f_name)),
671 },
672 CalxSyntax::ReturnCall(f_name) => match self.find_func(f_name) {
673 Some(f) => {
674 if stack_size < f.params_types.len() {
675 return Err(format!("insufficient size to call: {} {:?}", stack_size, f.params_types));
676 }
677 stack_size = stack_size - f.params_types.len() + f.ret_types.len();
678 ops.push(CalxInstr::ReturnCall(f_name.to_owned()))
679 }
680 None => return Err(format!("cannot find function named: {}", f_name)),
681 },
682 CalxSyntax::CallImport(f_name) => match &self.imports.get(f_name) {
683 Some((_f, size)) => {
684 if stack_size < *size {
685 return Err(format!("insufficient size to call import: {} {:?}", stack_size, size));
686 }
687 stack_size = stack_size - size + 1;
688 ops.push(CalxInstr::CallImport(f_name.to_owned()))
689 }
690 None => return Err(format!("missing imported function {}", f_name)),
691 },
692 CalxSyntax::Return => {
693 let ret_size = self.funcs[i].ret_types.len();
694 stack_size -= ret_size;
695 if stack_size != 0 {
696 return Err(format!(
697 "invalid return size {} for {:?} in {}",
698 stack_size, self.funcs[i].ret_types, self.funcs[i].name
699 ));
700 }
701 ops.push(CalxInstr::Return);
702 }
703 CalxSyntax::If { ret_types, else_at, to } => {
704 if stack_size < 1 {
705 return Err(format!("insufficient stack {} to branch", stack_size));
706 }
707
708 blocks_track.push(BlockData::If {
709 ret_types: ret_types.to_owned(),
710 else_to: else_at.to_owned(),
711 to: to.to_owned(),
712 initial_stack_size: stack_size,
713 });
714
715 stack_size -= 1;
716 ops.push(CalxInstr::JmpIf(else_at.to_owned()));
717 }
718 CalxSyntax::ElseEnd => {
719 if blocks_track.is_empty() {
720 return Err(format!("invalid else end, {:?}", blocks_track));
721 }
722
723 let prev_block = blocks_track.peek_if()?;
724
725 if stack_size != prev_block.expected_finish_size() {
726 return Err(format!("size mismatch for else-end: {} {:?}", stack_size, prev_block));
727 }
728
729 match prev_block {
730 BlockData::If { to, .. } => ops.push(CalxInstr::Jmp(to.to_owned())),
731 _ => unreachable!("end inside if"),
732 }
733 }
734 CalxSyntax::ThenEnd => {
735 if blocks_track.is_empty() {
736 return Err(format!("invalid else end, {:?}", blocks_track));
737 }
738
739 let prev_block = blocks_track.pop_if()?;
740 if stack_size != prev_block.expected_finish_size() {
741 return Err(format!("size mismatch for then-end: {} {:?}", stack_size, prev_block));
742 }
743
744 match prev_block {
745 BlockData::If { to, .. } => ops.push(CalxInstr::Jmp(to.to_owned())),
746 _ => unreachable!("end inside if"),
747 }
748 }
749 a => {
750 let instr: CalxInstr = a.try_into()?;
751 let (params_size, ret_size) = instr.stack_arity();
753 if stack_size < params_size {
754 return Err(format!("insufficient stack {} to call {:?} of {}", stack_size, a, params_size));
755 }
756 stack_size = stack_size - params_size + ret_size;
757 ops.push(instr.to_owned());
762 }
763 }
764 }
765 if stack_size != 0 {
766 return Err(format!(
767 "invalid final size {} of {:?} in {}",
768 stack_size, self.funcs[i].ret_types, self.funcs[i].name
769 ));
770 }
771
772 self.funcs[i].instrs = Some(Rc::new(ops));
773 }
774
775 Ok(())
776 }
777
778 #[inline(always)]
779 fn check_func_return(&self) -> Result<(), CalxError> {
780 if self.stack.len() != self.top_frame.initial_stack_size {
781 return Err(self.gen_err(format!(
782 "stack size {} does not fit initial size {} plus {:?}",
783 self.stack.len(),
784 self.top_frame.initial_stack_size,
785 self.top_frame.ret_types
786 )));
787 }
788
789 Ok(())
790 }
791
792 #[inline(always)]
793 fn stack_pop(&mut self) -> Result<Calx, CalxError> {
794 if self.stack.is_empty() {
795 Err(self.gen_err(String::from("cannot pop from empty stack")))
796 } else if self.stack.len() <= self.top_frame.initial_stack_size {
797 Err(self.gen_err(String::from("cannot pop from parent stack")))
798 } else {
799 let v = self.stack.pop().unwrap();
800 Ok(v)
801 }
802 }
803
804 #[inline(always)]
805 fn stack_push(&mut self, x: Calx) {
806 self.stack.push(x)
807 }
808
809 fn gen_err(&self, s: String) -> CalxError {
810 CalxError {
811 message: s,
812 top_frame: self.top_frame.to_owned(),
813 stack: self.stack.to_owned(),
814 globals: self.globals.to_owned(),
815 }
816 }
817
818 fn find_func(&self, name: &str) -> Option<&CalxFunc> {
819 self.funcs.iter().find(|x| *x.name == name)
820 }
821}
822
823#[derive(Debug, Clone, PartialEq, PartialOrd)]
824pub struct CalxError {
825 pub message: String,
826 pub stack: Vec<Calx>,
827 pub top_frame: CalxFrame,
828 pub globals: Vec<Calx>,
829}
830
831impl fmt::Display for CalxError {
832 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
833 write!(f, "{}\n{:?}\n{}", self.message, self.stack, self.top_frame)
834 }
835}
836
837impl CalxError {
838 pub fn new_raw(s: String) -> Self {
839 CalxError {
840 message: s,
841 stack: vec![],
842 top_frame: CalxFrame::default(),
843 globals: vec![],
844 }
845 }
846}