Split up src/obj.rs
* common macros are in their own private module * functions are in their own obj::function module Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
293
src/obj.rs
293
src/obj.rs
@@ -1,15 +1,20 @@
|
||||
// TODO obj.rs - remove the warning suppression
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod macros;
|
||||
// Leave this comment here - macros must come first
|
||||
pub mod function;
|
||||
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
use gc::{Finalize, Gc, GcCell, Trace};
|
||||
|
||||
use crate::vm::{Argc, Chunk, Frame, Vm};
|
||||
use crate::obj::function::*;
|
||||
use crate::obj::macros::*;
|
||||
use crate::vm::{Argc, Chunk, Vm};
|
||||
|
||||
pub type Ptr<T> = Gc<GcCell<T>>;
|
||||
pub type ObjP = Ptr<dyn Obj>;
|
||||
@@ -459,47 +464,6 @@ impl Obj for BaseObjInst {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_base_obj {
|
||||
($base_name:ident) => {
|
||||
fn instantiate(&mut self, ty: ObjP) {
|
||||
self.$base_name.instantiate(ty);
|
||||
}
|
||||
|
||||
fn is_instantiated(&self) -> bool {
|
||||
self.$base_name.is_instantiated()
|
||||
}
|
||||
|
||||
fn attrs(&self) -> &Attrs {
|
||||
self.$base_name.attrs()
|
||||
}
|
||||
|
||||
fn attrs_mut(&mut self) -> &mut Attrs {
|
||||
self.$base_name.attrs_mut()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
};
|
||||
() => {
|
||||
impl_base_obj! { base }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_create {
|
||||
($($arg:ident : $ty:ty),* $(,)?) => {
|
||||
pub fn create(ty: ObjP $(, $arg : $ty )*) -> ObjP {
|
||||
let ptr = make_ptr(Self::new($($arg),*));
|
||||
ptr.borrow_mut().instantiate(ty);
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ObjInst
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -861,249 +825,6 @@ impl Obj for NilInst {
|
||||
impl_base_obj!();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// BuiltinFunctionInst
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub type BuiltinFunctionPtr = fn(vm: &mut Vm, args: Vec<ObjP>) -> ObjP;
|
||||
|
||||
#[derive(Debug, Trace)]
|
||||
pub struct BuiltinFunctionInst {
|
||||
base: BaseObjInst,
|
||||
name: String,
|
||||
#[unsafe_ignore_trace]
|
||||
function: BuiltinFunctionPtr,
|
||||
arity: Argc,
|
||||
}
|
||||
|
||||
impl BuiltinFunctionInst {
|
||||
pub fn new(name: impl ToString, function: BuiltinFunctionPtr, arity: Argc) -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
name: name.to_string(),
|
||||
function,
|
||||
arity,
|
||||
}
|
||||
}
|
||||
|
||||
impl_create!(
|
||||
name: impl ToString,
|
||||
function: BuiltinFunctionPtr,
|
||||
arity: Argc,
|
||||
);
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Finalize for BuiltinFunctionInst {
|
||||
fn finalize(&self) {}
|
||||
}
|
||||
|
||||
impl Display for BuiltinFunctionInst {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
fmt,
|
||||
"<BuiltinFunction {}/{} at 0x{:x}>",
|
||||
self.name(),
|
||||
self.arity().unwrap(),
|
||||
self.function as *const BuiltinFunctionPtr as usize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Obj for BuiltinFunctionInst {
|
||||
fn arity(&self) -> Option<Argc> {
|
||||
Some(self.arity)
|
||||
}
|
||||
|
||||
fn call(&self, vm: &mut Vm, argc: Argc) {
|
||||
// args
|
||||
let mut args = Vec::with_capacity(argc as usize);
|
||||
for _ in 0..argc {
|
||||
args.push(vm.pop());
|
||||
}
|
||||
args.reverse();
|
||||
// callee (self)
|
||||
vm.pop();
|
||||
let result = (self.function)(vm, args);
|
||||
vm.push(result);
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn Obj) -> bool {
|
||||
// TODO BuiltinFunctionInst::equals : need something more robust than checking addr_eq,
|
||||
// maybe check the self_binding pointer too?
|
||||
if let Some(other) = other.as_any().downcast_ref::<BuiltinFunctionInst>() {
|
||||
ptr::addr_eq(self, other)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl_base_obj!();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserFunctionInst
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Debug, Clone, Trace)]
|
||||
pub struct UserFunctionInst {
|
||||
base: BaseObjInst,
|
||||
#[unsafe_ignore_trace]
|
||||
name: Rc<String>,
|
||||
#[unsafe_ignore_trace]
|
||||
chunk: Rc<Chunk>,
|
||||
arity: Argc,
|
||||
captures: Vec<ObjP>,
|
||||
}
|
||||
|
||||
impl UserFunctionInst {
|
||||
pub fn new(chunk: Chunk, arity: Argc) -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
name: Rc::new("(anonymous)".to_string()),
|
||||
chunk: Rc::new(chunk),
|
||||
arity,
|
||||
captures: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl_create!(chunk: Chunk, arity: Argc);
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: Rc<String>) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
pub fn chunk(&self) -> &Chunk {
|
||||
&self.chunk
|
||||
}
|
||||
|
||||
pub fn push_capture(&mut self, value: ObjP) {
|
||||
self.captures.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Finalize for UserFunctionInst {
|
||||
fn finalize(&self) {}
|
||||
}
|
||||
|
||||
impl Display for UserFunctionInst {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
fmt,
|
||||
"<UserFunction {}/{} at 0x{:x}>",
|
||||
self.name(),
|
||||
self.arity().unwrap(),
|
||||
self as *const _ as usize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Obj for UserFunctionInst {
|
||||
fn arity(&self) -> Option<Argc> {
|
||||
Some(self.arity)
|
||||
}
|
||||
|
||||
fn call(&self, vm: &mut Vm, argc: Argc) {
|
||||
assert_eq!(argc, self.arity, "argc must match arity");
|
||||
let new_frame = Frame {
|
||||
name: Rc::clone(&self.name),
|
||||
chunk: Rc::clone(&self.chunk),
|
||||
ip: 0,
|
||||
stack_base: vm.stack().len() - (argc as usize),
|
||||
};
|
||||
vm.push_frame(new_frame);
|
||||
for capture in &self.captures {
|
||||
vm.push(Ptr::clone(&capture));
|
||||
}
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn Obj) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<UserFunctionInst>() {
|
||||
// TODO UserFunctionInst::equals : need something more robust than checking addr_eq.
|
||||
ptr::addr_eq(self, other)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl_base_obj!();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MethodInst
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Debug, Trace)]
|
||||
pub struct MethodInst {
|
||||
base: BaseObjInst,
|
||||
self_binding: ObjP,
|
||||
function: ObjP,
|
||||
}
|
||||
|
||||
impl MethodInst {
|
||||
pub fn new(self_binding: ObjP, function: ObjP) -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
self_binding,
|
||||
function,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(ty: ObjP, self_binding: ObjP, function: ObjP) -> ObjP {
|
||||
let ptr = make_ptr(Self::new(self_binding, function));
|
||||
ptr.borrow_mut().instantiate(ty.clone());
|
||||
ptr
|
||||
}
|
||||
|
||||
pub fn self_binding(&self) -> &ObjP {
|
||||
&self.self_binding
|
||||
}
|
||||
}
|
||||
|
||||
impl Finalize for MethodInst {
|
||||
fn finalize(&self) {}
|
||||
}
|
||||
|
||||
impl Display for MethodInst {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.function.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl Obj for MethodInst {
|
||||
fn arity(&self) -> Option<Argc> {
|
||||
// Subtract one from the arity - this is because the VM uses arity() to check against the
|
||||
// number of arguments passed.
|
||||
self.function.borrow().arity().map(|arity| arity - 1)
|
||||
}
|
||||
|
||||
fn call(&self, vm: &mut Vm, mut argc: Argc) {
|
||||
let self_pos = vm.stack().len() - (argc as usize);
|
||||
vm.stack_mut().insert(self_pos, self.self_binding.clone());
|
||||
argc += 1;
|
||||
|
||||
self.function.borrow().call(vm, argc)
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn Obj) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<MethodInst>() {
|
||||
ptr::addr_eq(&*self.self_binding, &*other.self_binding)
|
||||
&& ptr::addr_eq(&*self.function, &*other.function)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl_base_obj!();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user