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:
@@ -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<ObjRef> {
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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__");
|
||||
|
||||
@@ -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<ObjRef>,
|
||||
frames: Vec<Frame>,
|
||||
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!(),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user