From 078aef70ead536796e0008d65134bc58733ff724 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Tue, 24 Sep 2024 09:03:34 -0700 Subject: [PATCH] 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 --- src/compiler.rs | 1 + src/disassemble.rs | 3 +- src/obj.rs | 293 ++------------------------------------------ src/obj/function.rs | 252 +++++++++++++++++++++++++++++++++++++ src/obj/macros.rs | 43 +++++++ src/vm.rs | 1 + 6 files changed, 306 insertions(+), 287 deletions(-) create mode 100644 src/obj/function.rs create mode 100644 src/obj/macros.rs diff --git a/src/compiler.rs b/src/compiler.rs index 22b7bd3..97e2ae2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -8,6 +8,7 @@ use common_macros::hash_map; use thiserror::Error; use crate::ast::*; +use crate::obj::function::UserFunctionInst; use crate::obj::*; use crate::token::TokenKind; use crate::vm::*; diff --git a/src/disassemble.rs b/src/disassemble.rs index 864d10d..76e0984 100644 --- a/src/disassemble.rs +++ b/src/disassemble.rs @@ -1,4 +1,5 @@ -use crate::obj::{ObjP, UserFunctionInst}; +use crate::obj::function::UserFunctionInst; +use crate::obj::ObjP; use crate::vm::{Chunk, JumpOpArg, Op}; type Row = (String, String, &'static str, String, String); diff --git a/src/obj.rs b/src/obj.rs index d615577..ad890c6 100644 --- a/src/obj.rs +++ b/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 = Gc>; pub type ObjP = Ptr; @@ -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; - -#[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, - "", - self.name(), - self.arity().unwrap(), - self.function as *const BuiltinFunctionPtr as usize - ) - } -} - -impl Obj for BuiltinFunctionInst { - fn arity(&self) -> Option { - 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::() { - 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, - #[unsafe_ignore_trace] - chunk: Rc, - arity: Argc, - captures: Vec, -} - -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) { - 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, - "", - self.name(), - self.arity().unwrap(), - self as *const _ as usize - ) - } -} - -impl Obj for UserFunctionInst { - fn arity(&self) -> Option { - 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::() { - // 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 { - // 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::() { - ptr::addr_eq(&*self.self_binding, &*other.self_binding) - && ptr::addr_eq(&*self.function, &*other.function) - } else { - false - } - } - - impl_base_obj!(); -} - //////////////////////////////////////////////////////////////////////////////// // Tests //////////////////////////////////////////////////////////////////////////////// diff --git a/src/obj/function.rs b/src/obj/function.rs new file mode 100644 index 0000000..92981c6 --- /dev/null +++ b/src/obj/function.rs @@ -0,0 +1,252 @@ +use std::fmt::{self, Debug, Display}; +use std::ptr; +use std::rc::Rc; + +use gc::{Finalize, Trace}; + +use crate::obj::macros::*; +use crate::obj::{make_ptr, BaseObjInst, Obj, ObjP}; +use crate::vm::{Argc, Chunk, Frame, Vm}; + +//////////////////////////////////////////////////////////////////////////////// +// BuiltinFunctionInst +//////////////////////////////////////////////////////////////////////////////// + +pub type BuiltinFunctionPtr = fn(vm: &mut Vm, args: Vec) -> 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, + "", + self.name(), + self.arity().unwrap(), + self.function as *const BuiltinFunctionPtr as usize + ) + } +} + +impl Obj for BuiltinFunctionInst { + fn arity(&self) -> Option { + 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::() { + 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, + #[unsafe_ignore_trace] + chunk: Rc, + arity: Argc, + captures: Vec, +} + +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) { + 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, + "", + self.name(), + self.arity().unwrap(), + self as *const _ as usize + ) + } +} + +impl Obj for UserFunctionInst { + fn arity(&self) -> Option { + 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(capture.clone()); + } + } + + fn equals(&self, other: &dyn Obj) -> bool { + if let Some(other) = other.as_any().downcast_ref::() { + // 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 { + // 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::() { + ptr::addr_eq(&*self.self_binding, &*other.self_binding) + && ptr::addr_eq(&*self.function, &*other.function) + } else { + false + } + } + + impl_base_obj!(); +} diff --git a/src/obj/macros.rs b/src/obj/macros.rs new file mode 100644 index 0000000..14e16de --- /dev/null +++ b/src/obj/macros.rs @@ -0,0 +1,43 @@ +macro_rules! impl_base_obj { + ($base_name:ident) => { + fn instantiate(&mut self, ty: $crate::obj::ObjP) { + self.$base_name.instantiate(ty); + } + + fn is_instantiated(&self) -> bool { + self.$base_name.is_instantiated() + } + + fn attrs(&self) -> &$crate::obj::Attrs { + self.$base_name.attrs() + } + + fn attrs_mut(&mut self) -> &mut $crate::obj::Attrs { + self.$base_name.attrs_mut() + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + }; + () => { + impl_base_obj! { base } + }; +} + +macro_rules! impl_create { + ($($arg:ident : $ty:ty),* $(,)?) => { + pub fn create(ty: $crate::obj::ObjP $(, $arg : $ty )*) -> $crate::obj::ObjP { + let ptr = make_ptr(Self::new($($arg),*)); + ptr.borrow_mut().instantiate(ty); + ptr + } + } +} + +pub(crate) use impl_base_obj; +pub(crate) use impl_create; diff --git a/src/vm.rs b/src/vm.rs index ac2c13c..9e0f9b2 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::rc::Rc; +use crate::obj::function::*; use crate::obj::*; #[derive(Debug, Clone, Copy, PartialEq)]