Remove vm::package module, add object attribute shortcut methods

* vm::package is no longer needed since the compiler now creates
  UserFunRef objects
* Reserved object attributes can be accessed using get_* methods, e.g.
  get_plus for ease of use.
* Add some implementations for operator instructions in the VM

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-28 16:48:30 -07:00
parent 958a6caabb
commit 43c4a9c531
4 changed files with 79 additions and 57 deletions

View File

@@ -25,12 +25,21 @@ use std::{
}; };
use attrs::*; use attrs::*;
use reserved::*;
use sym::Sym; use sym::Sym;
// //
// trait Obj // trait Obj
// //
macro_rules! obj_attr {
($name:ident, $attr:ident) => {
fn $name(&self) -> Option<ObjRef> {
self.get_attr($attr.sym)
}
}
}
pub trait Obj: Scan + std::fmt::Debug { pub trait Obj: Scan + std::fmt::Debug {
fn vtable(&self) -> &Vtable; fn vtable(&self) -> &Vtable;
fn attrs(&self) -> &Attrs; fn attrs(&self) -> &Attrs;
@@ -44,6 +53,24 @@ pub trait Obj: Scan + std::fmt::Debug {
} }
fn as_any(&self) -> &dyn std::any::Any; 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);
} }
// //

View File

@@ -47,7 +47,7 @@ name!(FUNC_MEMBER_NAME, "__func__");
// //
// Predefined VM-aware symbols // Predefined VM-aware symbols
// //
name!(SCOPE_NAME, "__scope__"); //name!(SCOPE_NAME, "__scope__");
// //
// Builtin functions // Builtin functions
@@ -64,7 +64,8 @@ name!(FALSE_NAME, "false");
name!(NIL_NAME, "nil"); name!(NIL_NAME, "nil");
// Operator function names // 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!(LT_OP_NAME, "__lt__");
name!(GT_OP_NAME, "__gt__"); name!(GT_OP_NAME, "__gt__");
name!(LT_EQ_OP_NAME, "__le__"); name!(LT_EQ_OP_NAME, "__le__");

View File

@@ -2,39 +2,33 @@ pub mod consts;
pub mod error; // TODO : not needed? pub mod error; // TODO : not needed?
pub mod frame; pub mod frame;
pub mod inst; pub mod inst;
pub mod package;
pub(crate) mod signal; pub(crate) mod signal;
use crate::{ use crate::{
obj::{reserved::*, prelude::*}, obj::{reserved::*, prelude::*},
vm::{frame::*, inst::*, package::*, signal::*}, vm::{consts::ConstPool, frame::*, inst::*, signal::*},
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Vm<'p> { pub struct Vm<'c> {
stack: Vec<ObjRef>, stack: Vec<ObjRef>,
frames: Vec<Frame>, frames: Vec<Frame>,
pc: usize, pc: usize,
condition: bool, condition: bool,
package: &'p Package, const_pool: &'c ConstPool,
} }
impl<'p> Vm<'p> { impl<'c> Vm<'c> {
pub fn new(package: &'p Package) -> Self { pub fn new(const_pool: &'c ConstPool,) -> Self {
Self { Self {
stack: Default::default(), stack: Default::default(),
frames: vec![], frames: vec![],
pc: 0, pc: 0,
condition: false, 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. /// Gets the current stack frame, if any.
pub fn frame(&self) -> Option<&Frame> { pub fn frame(&self) -> Option<&Frame> {
self.frames.last() self.frames.last()
@@ -198,10 +192,7 @@ impl<'p> Vm<'p> {
self.push(sym_ref); self.push(sym_ref);
} }
Inst::PushConst(hdl) => { Inst::PushConst(hdl) => {
let obj_ref = self.package() let obj_ref = self.const_pool.get(hdl).clone();
.const_pool()
.get(hdl)
.clone();
self.push(obj_ref); self.push(obj_ref);
} }
Inst::LoadLocal(local) => { Inst::LoadLocal(local) => {
@@ -277,18 +268,54 @@ impl<'p> Vm<'p> {
Inst::Call(argc) => { Inst::Call(argc) => {
let stack_top = self.stack.len() - argc; let stack_top = self.stack.len() - argc;
let args = self.stack.split_off(stack_top); let args = self.stack.split_off(stack_top);
let caller = self.pop().unwrap(); let tos = self.pop()
signal = Some(Signal::Call(caller, args)); .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::Index => todo!(),
Inst::Return => { signal = Some(Signal::Return); } Inst::Return => { signal = Some(Signal::Return); }
Inst::UnNeg => todo!(), Inst::UnNeg => todo!(),
Inst::UnPos => todo!(), Inst::UnPos => todo!(),
Inst::BinPlus => todo!(), Inst::BinPlus => {
Inst::BinMinus => todo!(), let rhs = self.pop().unwrap();
Inst::BinMul => todo!(), 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::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::BinNeq => todo!(),
Inst::BinLt => todo!(), Inst::BinLt => todo!(),
Inst::BinLe => todo!(), Inst::BinLe => todo!(),

View File

@@ -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<Sym>, // local names mappings
const_pool: ConstPool,
code: Vec<Inst>,
}
impl Package {
/// Creates a new VM executable package with the given local name mappings, constant pool, and
/// executable code.
pub fn new(names: Vec<Sym>, const_pool: ConstPool, code: Vec<Inst>) -> Self {
Self { names, const_pool, code, }
}
/// Get the local name mappings for this package.
pub fn names(&self) -> &Vec<Sym> {
&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<Inst> {
&self.code
}
}