From 48c23d9041958e9824a81492c8628a2c5c52f963 Mon Sep 17 00:00:00 2001 From: tiye Date: Wed, 17 Jan 2024 01:31:04 +0800 Subject: [PATCH] add inspect instruction --- README.md | 12 ++++++++++++ demos/named.cirru | 3 +++ src/parser.rs | 5 +++-- src/primes.rs | 12 +++++++++--- src/vm.rs | 25 ++++++++++++++++++++++++- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 55682eb..57bcd2f 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ Calx Binary Edition `0.1`: | `return` | | TODO | | `fn $types $body` | | Global definition | | `assert` | `quit(1)` if not `true` | for testing | +| `inspect | println inspection information | | For `$types`, it can be `($t1 $t2 -> $t3 $t4)`, where supported types are: @@ -146,6 +147,17 @@ For `$types`, it can be `($t1 $t2 -> $t3 $t4)`, where supported types are: - list _TODO_ - link _TODO_ +### Preprocess + +Before Calx running the instructions, Calx performs preprocessing to them. There are several tasks: + +- `block` and `loop` are expanded since there are `block-end` instructions +- `br` and `br-if` also expanded to `jmp` and `jmp-if` instructions, internally +- stack size is checked to ensure it's consistent among branches, and tidied up at function end +- local variables are renamed to indexes + +these steps simplies debugging, although it's sure that's good features. + ### License MIT diff --git a/demos/named.cirru b/demos/named.cirru index 3f5a88a..09b99da 100644 --- a/demos/named.cirru +++ b/demos/named.cirru @@ -9,6 +9,9 @@ fn f-add (($a i64) ($b i64) -> i64) local.get $b local.get $c dup + + inspect + echo return diff --git a/src/parser.rs b/src/parser.rs index ce89eb9..6aa16c1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -63,8 +63,8 @@ pub fn parse_function(nodes: &[Cirru]) -> Result { } Ok(CalxFunc { - name: name.to_string(), - params_types, + name: Rc::new(name.to_string()), + params_types: params_types.into(), ret_types: Rc::new(ret_types), local_names: Rc::new(locals_collector.locals), instrs: Rc::new(body), @@ -259,6 +259,7 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru, collector: &mut LocalsCollecto Ok(vec![CalxInstr::Assert((*message).to_owned())]) } + "inspect" => Ok(vec![CalxInstr::Inspect]), _ => Err(format!("unknown instruction: {}", name)), }, } diff --git a/src/primes.rs b/src/primes.rs index 0bebfb2..984c419 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -73,8 +73,8 @@ impl fmt::Display for Calx { #[derive(Debug, Clone, PartialEq, PartialOrd, Encode, Decode)] pub struct CalxFunc { - pub name: String, - pub params_types: Vec, + pub name: Rc, + pub params_types: Rc>, pub ret_types: Rc>, pub instrs: Rc>, pub local_names: Rc>, @@ -83,7 +83,7 @@ pub struct CalxFunc { impl fmt::Display for CalxFunc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CalxFunc {} (", self.name)?; - for p in &self.params_types { + for p in &*self.params_types { write!(f, "{:?} ", p)?; } f.write_str("-> ")?; @@ -182,6 +182,8 @@ pub enum CalxInstr { Return, /// TODO might also be a foreign function instead Assert(String), + /// inspecting stack + Inspect, } impl CalxInstr { @@ -242,6 +244,8 @@ impl CalxInstr { CalxInstr::Quit(_) => (0, 0), CalxInstr::Return => (0, 0), // TODO CalxInstr::Assert(_) => (1, 0), + // debug + CalxInstr::Inspect => (0, 0), } } } @@ -292,6 +296,7 @@ impl BlockData { #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct CalxFrame { + pub name: Rc, pub locals: Vec, // params + added locals /** store return values */ pub instrs: Rc>, @@ -304,6 +309,7 @@ pub struct CalxFrame { impl Default for CalxFrame { fn default() -> Self { CalxFrame { + name: String::from("").into(), locals: vec![], instrs: Rc::new(vec![]), pointer: 0, diff --git a/src/vm.rs b/src/vm.rs index 2e6a22c..fbc544e 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -26,6 +26,7 @@ impl CalxVM { pub fn new(fns: Vec, globals: Vec, imports: CalxImportsDict) -> Self { let main_func = find_func(&fns, "main").expect("main function is required"); let main_frame = CalxFrame { + name: main_func.name.to_owned(), initial_stack_size: 0, blocks_track: vec![], instrs: main_func.instrs.clone(), @@ -399,6 +400,7 @@ impl CalxVM { Some(f) => { let instrs = f.instrs.to_owned(); let ret_types = f.ret_types.to_owned(); + let f_name = f.name.to_owned(); let mut locals: Vec = vec![]; for _ in 0..f.params_types.len() { let v = self.stack_pop()?; @@ -406,6 +408,7 @@ impl CalxVM { } self.frames.push(self.top_frame.to_owned()); self.top_frame = CalxFrame { + name: f_name, blocks_track: vec![], initial_stack_size: self.stack.len(), locals, @@ -427,6 +430,7 @@ impl CalxVM { // println!("examine stack: {:?}", self.stack); let instrs = f.instrs.to_owned(); let ret_types = f.ret_types.to_owned(); + let f_name = f.name.to_owned(); let mut locals: Vec = vec![]; for _ in 0..f.params_types.len() { let v = self.stack_pop()?; @@ -441,6 +445,7 @@ impl CalxVM { ))); } self.top_frame = CalxFrame { + name: f_name, blocks_track: vec![], initial_stack_size: self.stack.len(), locals, @@ -494,6 +499,24 @@ impl CalxVM { return Err(self.gen_err(format!("Failed assertion: {}", message))); } } + CalxInstr::Inspect => { + println!("[ ----------------"); + println!( + " Internal frames: {:?}", + self.frames.iter().map(|x| x.name.to_owned()).collect::>() + ); + println!(" Top frame: {}", self.top_frame.name); + println!(" Locals: {:?}", self.top_frame.locals); + println!(" Blocks: {:?}", self.top_frame.blocks_track); + println!(" Stack({}): {:?}", self.stack.len(), self.stack); + println!( + " Sizes: {} + {}", + self.top_frame.initial_stack_size, + self.top_frame.ret_types.len() + ); + println!(" Pointer: {}", self.top_frame.pointer); + println!(" -------------- ]"); + } } self.top_frame.pointer += 1; @@ -747,5 +770,5 @@ impl CalxVM { } pub fn find_func<'a>(funcs: &'a [CalxFunc], name: &str) -> Option<&'a CalxFunc> { - funcs.iter().find(|x| &*x.name == name) + funcs.iter().find(|x| *x.name == name) }