diff --git a/src/bin/not.rs b/src/bin/not.rs index 284ddce..fb0a875 100644 --- a/src/bin/not.rs +++ b/src/bin/not.rs @@ -32,14 +32,16 @@ fn main() -> Result<()> { return Err("errors reported, exiting".into()); } }.unwrap(); - println!("{:#?}", ast); + //println!("{:#?}", ast); - let mut compile = Compile::new(); - let (inst, const_pool) = compile.compile(&ast)?; + let package = Compile::new().compile(&ast)?; //println!("{:#?}", inst); //println!("{:#?}", const_pool); - not_python::vm::inst::dump_inst_body(&inst, &const_pool); + { + let mut stdout = std::io::stdout(); + package.dump(&mut stdout)?; + } Ok(()) } diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 4a17346..ac7d800 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -3,7 +3,7 @@ pub mod error; mod locals; pub mod thunk; -use crate::{syn::ast::Body, obj::prelude::*, vm::{consts::*, inst::Inst}}; +use crate::{syn::ast::Body, obj::prelude::*, vm::{consts::*, package::Package}}; use std::collections::{BTreeMap, HashMap}; #[derive(Default)] @@ -22,12 +22,12 @@ impl Compile { } /// Compiles the given AST body. - pub fn compile<'c>(&'c mut self, body: &Body) -> error::Result<(Vec, &'c ConstPool)> { - let main = thunk::CompileBody::new(self) + pub fn compile(mut self, body: &Body) -> error::Result { + let main = thunk::CompileBody::new(&mut self) .compile(body)? .flatten() .to_vec(); - Ok((main, &self.const_data.const_pool)) + Ok(Package::new(self.names, self.const_data.const_pool, main)) } /// Gets the constant data that is interned in this compile session. @@ -119,6 +119,9 @@ impl Compile { } } +/// Constant data pool used for building the const pool. +/// +/// This distinguishes between the different types while building a const pool to avoid duplicates. #[derive(Debug, Default)] pub struct ConstData { ints: HashMap, diff --git a/src/syn/lexer.l b/src/syn/lexer.l index 8e5a409..28365cb 100644 --- a/src/syn/lexer.l +++ b/src/syn/lexer.l @@ -25,5 +25,5 @@ \. "." , "," -#.+$ ; -[\t ]+ ; +#[^\n]*$ ; +[\t ]+ ; diff --git a/src/vm/inst.rs b/src/vm/inst.rs index e6b3116..d1a2627 100644 --- a/src/vm/inst.rs +++ b/src/vm/inst.rs @@ -1,5 +1,4 @@ use crate::{obj::prelude::*, vm::consts::*}; -use std::fmt::{self, Display, Formatter}; #[derive(Debug, PartialEq, Clone, Copy)] pub enum Inst { @@ -145,90 +144,3 @@ impl Inst { } } } - -pub fn dump_inst_body(insts: &Vec, const_pool: &ConstPool) { - println!("{}", InstFormatter::new(insts, const_pool)) -} - -// -// struct InstFormatter -// - -pub struct InstFormatter<'i, 'c> { - insts: &'i Vec, - const_pool: &'c ConstPool, -} - -impl<'i, 'c> InstFormatter<'i, 'c> { - pub fn new(insts: &'i Vec, const_pool: &'c ConstPool) -> Self { - Self { insts, const_pool, } - } -} - -impl Display for InstFormatter<'_, '_> { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - // column widths - let addr_w = num_digits(self.insts.len(), 16).max(4); - let inst_col = 16 - addr_w; - let inst_w = 16; - - for (addr, inst) in self.insts.iter().enumerate() { - let (param_val, mut param_name) = match inst { - Inst::PushSym(sym) | Inst::GetAttr(sym) | Inst::SetAttr(sym) => ( - sym.index().to_string(), - global_sym_lookup(*sym).unwrap().to_string(), - ), - Inst::PushConst(hdl) => ( - hdl.index().to_string(), - { - let obj_ref = self.const_pool.get(*hdl); - read_obj!(let obj = obj_ref); - // XXX weirdness with coercion, can't deref as a &dyn Obj because - // RwReadLockGuard is not Obj - but using Deref::deref works - let obj: &dyn Obj = std::ops::Deref::deref(obj); - format!("{:?}", obj) - }, - ), - Inst::LoadName(local) => ( - local.index().to_string(), - "TODO: local name".to_string(), - ), - Inst::Pop(local) => ( - format!("{:?}", local), - "TODO: local name".to_string(), - ), - Inst::Jump(addr) | Inst::JumpTrue(addr) => ( - addr.to_string(), - String::new(), - ), - Inst::Call(argc) => ( - argc.to_string(), - String::new(), - ), - _ => (String::new(), String::new()), - }; - - if !param_name.is_empty() { - param_name = format!("({})", param_name); - } - - writeln!( - fmt, - "{:0addr_w$x}{space: >inst_col$}{: usize { - ((n as f64) + 1.0).log(radix as f64).ceil() as usize -} diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 32e1a8a..00077c5 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -2,20 +2,21 @@ pub mod consts; pub mod error; pub mod frame; pub mod inst; +pub mod package; use crate::{ obj::{reserved::*, prelude::*}, - vm::{consts::*, error::*, frame::*, inst::*}, + vm::{error::*, frame::*, inst::*, package::*}, }; use shredder::{GcSafe, Scanner, Scan}; #[derive(Debug)] -pub struct Vm<'c> { +pub struct Vm<'p> { stack: Vec, frames: Vec, pc: usize, condition: bool, - const_pool: &'c ConstPool, + package: &'p Package, } unsafe impl Scan for Vm<'_> { @@ -27,17 +28,22 @@ unsafe impl Scan for Vm<'_> { unsafe impl GcSafe for Vm<'_> {} -impl<'c> Vm<'c> { - pub fn new(const_pool: &'c ConstPool) -> Self { +impl<'p> Vm<'p> { + pub fn new(package: &'p Package) -> Self { Self { stack: Default::default(), frames: vec![], pc: 0, condition: false, - const_pool, + package, } } + /// Gets the package that is currently loaded by this VM. + pub fn package(&self) -> &'p Package { + self.package + } + /// Gets the current stack frame, if any. pub fn frame(&self) -> Option<&Frame> { self.frames.last() @@ -126,7 +132,10 @@ impl<'c> Vm<'c> { self.push(sym_ref); } Inst::PushConst(hdl) => { - let obj_ref = self.const_pool.get(hdl).clone(); + let obj_ref = self.package() + .const_pool() + .get(hdl) + .clone(); self.push(obj_ref); } Inst::LoadName(_sym) => todo!(), diff --git a/src/vm/package.rs b/src/vm/package.rs new file mode 100644 index 0000000..3ca98ad --- /dev/null +++ b/src/vm/package.rs @@ -0,0 +1,105 @@ +use crate::{obj::prelude::*, vm::{consts::ConstPool, inst::Inst}}; +use std::io::{self, Write}; + +/// A compiled package that can be executed by a VM. +#[derive(Debug)] +pub struct Package { + names: Vec, // local names mappings + const_pool: ConstPool, + code: Vec, +} + +impl Package { + /// Creates a new VM executable package with the given local name mappings, constant pool, and + /// executable code. + pub fn new(names: Vec, const_pool: ConstPool, code: Vec) -> Self { + Self { names, const_pool, code, } + } + + /// Get the local name mappings for this package. + pub fn names(&self) -> &Vec { + &self.names + } + + /// Gets the constant pool that is used by this package. + pub fn const_pool(&self) -> &ConstPool { + &self.const_pool + } + + /// Gets the executable code that was compiled for this package. + pub fn code(&self) -> &Vec { + &self.code + } + + pub fn dump(&self, writer: &mut dyn Write) -> io::Result<()> { + // column widths + let addr_w = num_digits(self.code().len(), 16).max(4); + let inst_col = 16 - addr_w; + let inst_w = 16; + + for (addr, inst) in self.code().iter().enumerate() { + let (param_val, mut param_name) = match inst { + Inst::PushSym(sym) | Inst::GetAttr(sym) | Inst::SetAttr(sym) => ( + sym.index().to_string(), + global_sym_lookup(*sym).unwrap().to_string(), + ), + Inst::PushConst(hdl) => ( + hdl.index().to_string(), + { + let obj_ref = self.const_pool().get(*hdl); + read_obj!(let obj = obj_ref); + // XXX weirdness with coercion, can't deref as a &dyn Obj because + // RwReadLockGuard is not Obj - but using Deref::deref works + let obj: &dyn Obj = std::ops::Deref::deref(obj); + format!("{:?}", obj) + }, + ), + Inst::LoadName(local) => ( + local.index().to_string(), + global_sym_lookup(self.names()[local.index()]).unwrap().to_string(), + ), + Inst::Pop(local) => { + if let Some(local) = local { + let index = local.index(); + let sym = self.names()[index]; + let name = global_sym_lookup(sym).unwrap().to_string(); + (index.to_string(), name) + } else { + ("(discarded)".to_string(), String::new()) + } + } + Inst::Jump(addr) | Inst::JumpTrue(addr) => ( + addr.to_string(), + String::new(), + ), + Inst::Call(argc) => ( + argc.to_string(), + String::new(), + ), + _ => (String::new(), String::new()), + }; + + if !param_name.is_empty() { + param_name = format!("({})", param_name); + } + + writeln!( + writer, + "{:0addr_w$x}{space: >inst_col$}{: usize { + ((n as f64) + 1.0).log(radix as f64).ceil() as usize +}