diff --git a/Cargo.lock b/Cargo.lock index 1e6659c..54eaf62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,27 @@ dependencies = [ "vec_map", ] +[[package]] +name = "gc" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edaac0f5832202ebc99520cb77c932248010c4645d20be1dc62d6579f5b3752" +dependencies = [ + "gc_derive", +] + +[[package]] +name = "gc_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60df8444f094ff7885631d80e78eb7d88c3c2361a98daaabb06256e4500db941" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "heck" version = "0.3.3" @@ -181,6 +202,7 @@ dependencies = [ name = "sybil" version = "0.1.0" dependencies = [ + "gc", "lazy_static", "regex", "structopt", @@ -198,6 +220,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "textwrap" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 1dd4d24..a7deb8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" thiserror = "1.0" structopt = "0.3" regex = "1.5" -lazy_static = "1.4" \ No newline at end of file +lazy_static = "1.4" +gc = { version = "0.4", features = ["derive"] } \ No newline at end of file diff --git a/src/object.rs b/src/object.rs index e992dbe..3886693 100644 --- a/src/object.rs +++ b/src/object.rs @@ -4,24 +4,25 @@ #![allow(dead_code)] use crate::syn::ast::SpStmt; -use crate::vm::{error::Result, machine::Machine}; +use crate::vm::{error::*, machine::Machine}; use crate::{scope::Scope, syn::span::Span, vm::inst::SpInst}; -use std::cell::RefCell; -use std::collections::{BTreeMap, HashMap}; +use gc::{unsafe_empty_trace, Finalize, Gc, Trace}; +use std::collections::HashMap; use std::fmt::{self, Debug, Display}; -use std::rc::{Rc, Weak}; +use std::rc::Rc; +pub type ObjPtr = Gc; pub type Str = String; pub type Int = i64; pub type Float = f64; -pub type VTable = HashMap; +pub type VTable = HashMap; // ///////////////////////////////////////////////////////////////////////////// // Quote // ///////////////////////////////////////////////////////////////////////////// /// A handle to a quote pointing to an element in a `QuoteTable`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Finalize)] pub struct Quote(usize); impl Quote { @@ -30,6 +31,10 @@ impl Quote { } } +unsafe impl Trace for Quote { + unsafe_empty_trace!(); +} + /// A table of compiled quotes, their expression trees, and their spans. #[derive(Debug, Clone, Default)] pub struct QuoteTable { @@ -135,12 +140,16 @@ pub enum BuiltinExit { Return, } -#[derive(Clone)] +#[derive(Clone, Finalize)] pub struct BuiltinFn { name: Rc, fun: Rc, } +unsafe impl Trace for BuiltinFn { + unsafe_empty_trace!(); +} + impl PartialEq for BuiltinFn { fn eq(&self, other: &Self) -> bool { (&self.fun as *const _ as usize) == (&other.fun as *const _ as usize) @@ -172,3 +181,179 @@ impl Debug for BuiltinFn { ) } } + +/// An object that has a vtable and common functions. +pub trait Obj: Trace + Finalize { + /// Gets the vtable for this object. + fn vtable(&self) -> &VTable; + + /// Gets the vtable for this object, mutably. + fn vtable_mut(&mut self) -> &mut VTable; + + /// Calls this object. + fn call(&self, machine: &mut Machine) -> Result<()>; + + /// Gets a value in the vtable. + /// + /// This has a default implementation, so it probably doesn't need to be + /// implemented. + fn get(&self, key: &str) -> Option { + self.vtable().get(key).cloned() + } + + /// Sets a value in the vtable. + /// + /// This has a default implementation, so it probably doesn't need to be + /// implemented. + fn set(&mut self, key: String, value: ObjPtr) -> Option { + self.vtable_mut().insert(key, value) + } +} + +macro_rules! vtable { + ($($key:expr => $value:expr),* $(,)?) => {{ + VTable::from( + [ + $( + ($key.to_string(), $value) + ),* + ] + ) + }}; +} + +#[derive(Trace, Finalize)] +pub struct FloatObj { + value: Float, + vtable: VTable, +} + +impl Obj for FloatObj { + fn vtable(&self) -> &VTable { + &self.vtable + } + + fn vtable_mut(&mut self) -> &mut VTable { + &mut self.vtable + } + + fn call(&self, _: &mut Machine) -> Result<()> { + Err(RuntimeError::CannotCall("float value".to_string())) + } +} + +#[derive(Trace, Finalize)] +pub struct IntObj { + value: Int, + vtable: VTable, +} + +impl IntObj { + pub fn new(value: Int) -> Self { + IntObj { + value, + vtable: vtable! {}, + } + } +} + +impl Obj for IntObj { + fn vtable(&self) -> &VTable { + &self.vtable + } + + fn vtable_mut(&mut self) -> &mut VTable { + &mut self.vtable + } + + fn call(&self, _: &mut Machine) -> Result<()> { + Err(RuntimeError::CannotCall("int value".to_string())) + } +} + +#[derive(Trace, Finalize)] +pub struct StrObj { + value: String, + vtable: VTable, +} + +impl StrObj { + pub fn new(value: String) -> Self { + StrObj { + value, + vtable: vtable! {}, + } + } +} + +impl Obj for StrObj { + fn vtable(&self) -> &VTable { + &self.vtable + } + + fn vtable_mut(&mut self) -> &mut VTable { + &mut self.vtable + } + + fn call(&self, _: &mut Machine) -> Result<()> { + Err(RuntimeError::CannotCall("string value".to_string())) + } +} + +#[derive(Trace, Finalize)] +pub struct QuoteObj { + value: Quote, + vtable: VTable, +} + +impl QuoteObj { + pub fn new(value: Quote) -> Self { + QuoteObj { + value, + vtable: vtable! {}, + } + } +} + +impl Obj for QuoteObj { + fn vtable(&self) -> &VTable { + &self.vtable + } + + fn vtable_mut(&mut self) -> &mut VTable { + &mut self.vtable + } + + fn call(&self, _: &mut Machine) -> Result<()> { + Err(RuntimeError::CannotCall("quote value".to_string())) + } +} + +#[derive(Trace, Finalize)] +pub struct BuiltinFnObj { + value: BuiltinFn, + vtable: VTable, +} + +impl BuiltinFnObj { + pub fn new(value: BuiltinFn) -> Self { + BuiltinFnObj { + value, + vtable: vtable! {}, + } + } +} + +impl Obj for BuiltinFnObj { + fn vtable(&self) -> &VTable { + &self.vtable + } + + fn vtable_mut(&mut self) -> &mut VTable { + &mut self.vtable + } + + fn call(&self, _: &mut Machine) -> Result<()> { + Err(RuntimeError::CannotCall("quote value".to_string())) + } +}