diff --git a/src/obj/mod.rs b/src/obj/mod.rs index f338bc4..3d306ec 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -25,12 +25,21 @@ use std::{ }; use attrs::*; +use reserved::*; use sym::Sym; // // trait Obj // +macro_rules! obj_attr { + ($name:ident, $attr:ident) => { + fn $name(&self) -> Option { + self.get_attr($attr.sym) + } + } +} + pub trait Obj: Scan + std::fmt::Debug { fn vtable(&self) -> &Vtable; fn attrs(&self) -> &Attrs; @@ -44,6 +53,24 @@ pub trait Obj: Scan + std::fmt::Debug { } fn as_any(&self) -> &dyn std::any::Any; + + obj_attr!(get_ty, TY_MEMBER_NAME); + obj_attr!(get_call, CALL_MEMBER_NAME); + obj_attr!(get_name, NAME_MEMBER_NAME); + //obj_attr!(get_get_attr, GET_ATTR_NAME); + //obj_attr!(get_set_attr, SET_ATTR_NAME); + obj_attr!(get_self, SELF_MEMBER_NAME); + obj_attr!(get_func, FUNC_MEMBER_NAME); + obj_attr!(get_eq, EQ_OP_NAME); + obj_attr!(get_ne, NE_OP_NAME); + obj_attr!(get_lt, LT_OP_NAME); + obj_attr!(get_gt, GT_OP_NAME); + obj_attr!(get_le, LT_EQ_OP_NAME); + obj_attr!(get_ge, GT_EQ_OP_NAME); + obj_attr!(get_plus, PLUS_OP_NAME); + obj_attr!(get_minus, MINUS_OP_NAME); + obj_attr!(get_mul, TIMES_OP_NAME); + obj_attr!(get_div, DIV_OP_NAME); } // diff --git a/src/obj/reserved.rs b/src/obj/reserved.rs index 936ce6e..1897c39 100644 --- a/src/obj/reserved.rs +++ b/src/obj/reserved.rs @@ -47,7 +47,7 @@ name!(FUNC_MEMBER_NAME, "__func__"); // // Predefined VM-aware symbols // -name!(SCOPE_NAME, "__scope__"); +//name!(SCOPE_NAME, "__scope__"); // // Builtin functions @@ -64,7 +64,8 @@ name!(FALSE_NAME, "false"); name!(NIL_NAME, "nil"); // Operator function names -name!(EQ_EQ_OP_NAME, "__eq__"); +name!(EQ_OP_NAME, "__eq__"); +name!(NE_OP_NAME, "__ne__"); name!(LT_OP_NAME, "__lt__"); name!(GT_OP_NAME, "__gt__"); name!(LT_EQ_OP_NAME, "__le__"); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index c6c3130..4548f14 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -2,39 +2,33 @@ pub mod consts; pub mod error; // TODO : not needed? pub mod frame; pub mod inst; -pub mod package; pub(crate) mod signal; use crate::{ obj::{reserved::*, prelude::*}, - vm::{frame::*, inst::*, package::*, signal::*}, + vm::{consts::ConstPool, frame::*, inst::*, signal::*}, }; #[derive(Debug)] -pub struct Vm<'p> { +pub struct Vm<'c> { stack: Vec, frames: Vec, pc: usize, condition: bool, - package: &'p Package, + const_pool: &'c ConstPool, } -impl<'p> Vm<'p> { - pub fn new(package: &'p Package) -> Self { +impl<'c> Vm<'c> { + pub fn new(const_pool: &'c ConstPool,) -> Self { Self { stack: Default::default(), frames: vec![], pc: 0, condition: false, - package, + const_pool, } } - /// 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() @@ -198,10 +192,7 @@ impl<'p> Vm<'p> { self.push(sym_ref); } Inst::PushConst(hdl) => { - let obj_ref = self.package() - .const_pool() - .get(hdl) - .clone(); + let obj_ref = self.const_pool.get(hdl).clone(); self.push(obj_ref); } Inst::LoadLocal(local) => { @@ -277,18 +268,54 @@ impl<'p> Vm<'p> { Inst::Call(argc) => { let stack_top = self.stack.len() - argc; let args = self.stack.split_off(stack_top); - let caller = self.pop().unwrap(); - signal = Some(Signal::Call(caller, args)); + let tos = self.pop() + .expect("stack underflow"); + read_obj!(let tos = tos); + let callee = tos.get_call() + .expect("TODO: throw an error for missing __call__ attr"); + signal = Some(Signal::Call(callee, args)); } Inst::Index => todo!(), Inst::Return => { signal = Some(Signal::Return); } Inst::UnNeg => todo!(), Inst::UnPos => todo!(), - Inst::BinPlus => todo!(), - Inst::BinMinus => todo!(), - Inst::BinMul => todo!(), + Inst::BinPlus => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_plus().expect("TODO: throw an error for missing __plus__ attr") + }; + signal = Some(Signal::Call(fun, vec![lhs, rhs])); + } + Inst::BinMinus => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_minus().expect("TODO: throw an error for missing __minus__ attr") + }; + signal = Some(Signal::Call(fun, vec![lhs, rhs])); + } + Inst::BinMul => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_mul().expect("TODO: throw an error for missing __mul__ attr") + }; + signal = Some(Signal::Call(fun, vec![lhs, rhs])); + } Inst::BinDiv => todo!(), - Inst::BinEq => todo!(), + Inst::BinEq => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_eq().expect("TODO: throw an error for missing __eq__ attr") + }; + signal = Some(Signal::Call(fun, vec![lhs, rhs])); + } Inst::BinNeq => todo!(), Inst::BinLt => todo!(), Inst::BinLe => todo!(), diff --git a/src/vm/package.rs b/src/vm/package.rs deleted file mode 100644 index 584a936..0000000 --- a/src/vm/package.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{obj::prelude::*, vm::{consts::ConstPool, inst::Inst}}; -use shredder::Scan; - -/// A compiled package that can be executed by a VM. -#[derive(Scan, 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 - } -}