diff --git a/Cargo.lock b/Cargo.lock index 7521c1e..efcbff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,10 @@ version = 4 [[package]] name = "deimos" version = "0.1.0" +dependencies = [ + "macros", + "map", +] [[package]] name = "glam" @@ -12,6 +16,20 @@ version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360bd2cd76e0cd9032d42cf2922155cecea2685b0cfa4630c3246df030bcfd6" +[[package]] +name = "macros" +version = "0.0.0" +dependencies = [ + "map", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "map" +version = "0.1.0" + [[package]] name = "mars" version = "0.1.0" @@ -19,3 +37,38 @@ dependencies = [ "deimos", "glam", ] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" diff --git a/src/lib.rs b/src/lib.rs index a6c1463..1a38f56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,6 @@ mod tests { let closure = match machine.load(include_str!("tests/script.lua")) { Err(error) => panic!("{}", error), Ok(closure) => closure, - _ => panic!(), }; println!("{:?}", machine.freelist().get(&closure).prototype); match machine.enter(closure) { diff --git a/src/table.rs b/src/table.rs index 49e7b76..71cc1cc 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,6 +1,6 @@ use crate::vm::{Callable, MarsAllocator, RunError, Value}; -use deimos::gc::{Allocates, Id, MaybeId, Traverse}; -use deimos::map::{DisplacementSet, Entry, Equivalent, Hashed, Hashes, Map, TableEntry}; +use deimos::gc::{Id, MaybeId, Traverse}; +use deimos::map::{DisplacementSet, Equivalent, Hashed, Hashes, TableEntry}; #[derive(Debug, Clone)] struct KeyValue { @@ -47,8 +47,8 @@ impl Hashes for Value { 0 } } - Value::CachedString(cached) => cached.1, - Value::String(_string, hash) => *hash, + Value::CachedString(hashed) => hashed.1, + Value::String(hashed) => hashed.1, Value::Function(callable) => match callable { Callable::Rust(native) => native.hashed(), Callable::Mars(closure) => closure.hashed(), diff --git a/src/vm.rs b/src/vm.rs index 7b78abb..d50323a 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -2,7 +2,7 @@ use crate::parser::{BinaryOp, Piece, UnaryOp, parse}; use deimos::gc::{Allocates, AnyId, FreeList, Id, MaybeId, Traverse}; -use deimos::map::{DisplacementSet, Equivalent, Hashed, Hashes, Map, TableEntry}; +use deimos::map::{DisplacementSet, Equivalent, Hashed, Hashes, MapEntry, TableEntry}; use std::fmt::{Debug, Display, Formatter}; use std::ops::Deref; use std::rc::Rc; @@ -157,7 +157,7 @@ impl std::fmt::Debug for Callable { } #[derive(Debug)] -pub struct RunError(pub(crate) String); +pub struct RunError(pub String); impl RunError { pub fn new(string: &str) -> RunError { @@ -165,36 +165,50 @@ impl RunError { } } +impl From for RunError { + fn from(value: String) -> Self { + RunError(value) + } +} + impl Display for RunError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } +impl std::error::Error for RunError {} + use crate::compiler::compile; use crate::core::load; use crate::table::Table; #[cfg(feature = "vector3")] use glam::Vec3; -// Any value in the language const SHORT_STRING_LEN: usize = 40; #[derive(Clone, Debug)] -pub(crate) struct CachedString(Rc, pub(crate) Hashed); +pub struct HashedString(Rc, pub(crate) Hashed); -impl Hashes for CachedString { +impl Hashes for HashedString { fn hashed(&self) -> Hashed { self.1 } } -impl PartialEq for CachedString { +impl PartialEq for HashedString { fn eq(&self, other: &Self) -> bool { self.1 == other.1 && self.0 == other.0 } } + +impl HashedString { + pub fn as_str(&self) -> &str { + self.0.deref() + } +} + #[derive(Clone, Debug)] -struct CachedStringEntry(Option); +struct CachedStringEntry(Option); impl Hashes for CachedStringEntry { fn hashed(&self) -> Hashed { self.0.as_ref().unwrap().0.deref().hashed() @@ -227,15 +241,14 @@ impl Equivalent<&str> for CachedStringEntry { } } -const PHRASE_LEN: usize = 16; #[derive(Clone)] pub enum Value { Nil, // Empty value Bool(bool), Number(f64), Integer(u64), // 64 maybe we should use signed integers... - CachedString(CachedString), - String(Rc, Hashed), + CachedString(HashedString), + String(HashedString), Table(Id), Object(AnyId, AnyId), Function(Callable), @@ -257,7 +270,7 @@ impl Debug for Value { Value::Number(number) => write!(f, "{}", number), Value::Integer(integer) => write!(f, "{}", integer), Value::CachedString(string) => write!(f, "{}", string.0.deref()), - Value::String(string, _hash) => write!(f, "{}", string.deref()), + Value::String(string) => write!(f, "{}", string.0.deref()), Value::Table(it) => write!(f, "{:?}", it), Value::Object(it, meta) => write!(f, "{:?}:{:?}", it, meta), Value::Function(it) => write!(f, "{:?}", it), @@ -275,11 +288,18 @@ impl Value { } pub(crate) fn unwrap_str(&mut self) -> Rc { match self { - Value::CachedString(cached) => cached.0.clone(), - Value::String(string, _hash) => string.clone(), + Value::CachedString(hashed) => hashed.0.clone(), + Value::String(hashed) => hashed.0.clone(), _ => panic!(), } } + pub fn try_string(self) -> Option { + match self { + Value::CachedString(hashed) => Some(hashed), + Value::String(hashed) => Some(hashed), + _ => None, + } + } pub(crate) fn traverse(&self, context: &mut C) where C: MarsAllocator, @@ -313,17 +333,17 @@ impl PartialEq for Value { Value::Integer(other) => this == other, _ => false, }, - Value::String(string, hash) => match other { + Value::String(string) => match other { Value::CachedString(other) => { - if *hash == other.1 { - other.0.deref() == string.deref() + if string.1 == other.1 { + other.0.deref() == string.0.deref() } else { false } } - Value::String(other_string, other_hash) => { - if hash == other_hash { - string == other_string + Value::String(other) => { + if string.1 == other.1 { + string.0.deref() == other.0.deref() } else { false } @@ -332,9 +352,9 @@ impl PartialEq for Value { }, Value::CachedString(string) => match other { Value::CachedString(other) => other.0 == string.0, // pointer equality - Value::String(other_string, other_hash) => { - if string.1 == *other_hash { - string.0.deref() == other_string.deref() + Value::String(other) => { + if string.1 == other.1 { + string.0.deref() == other.0.deref() } else { false } @@ -366,43 +386,86 @@ pub struct Frame { closure: Id, // The function that was called on this frame } -macro_rules! read_only { - () => { - |machine, id, needle| Err(RunError(format!("Field {} is read only", needle.pop()))) - }; +impl Equivalent for MapEntry<&str,V> { // For the constant maps + fn matches(&self, other: &HashedString) -> bool { + self.0.as_ref().unwrap().0 == other.as_str() + } } -type MetaFieldSet = fn( - &mut Machine, - id: AnyId, - index: Value, - value: Value, - needle: Needle, -) -> Result; -type MetaFieldGet = fn(&mut Machine, id: AnyId, index: Value, needle: Needle) -> Result<(), RunError>; -pub struct MetaField { - set: MetaFieldSet, - get: MetaFieldGet, +#[macro_export] +macro_rules! getter { + (@$state:ident,$index:literal=>$f:expr,$($x:literal=>$y:expr),*) => { + let temp: MetaOutFn<$state> = $f; + $crate::getter!(@$($x=>$y)*) + }; + (@$state:ident,$index:literal=>$f:expr) => { + let temp: MetaOutFn<$state> = $f; + }; + (@) => { + + }; + ($ident:tt,$state:ident,{$($map:tt)*}) => { + |machine,id,index,needle| { + use $crate::deimos::map::Entry; + use $crate::deimos::map::MapEntry; + $crate::getter!(@$state,$($map)*); + static MAP: &[ + $crate::deimos::map::Entry< + $crate::deimos::map::MapEntry<&'static str,$crate::MetaOutFn<$state>> + >] = &$crate::deimos::macros::map!{$($map)*}; + if let Some(string) = index.clone().try_string() { + if let Some(func) = $crate::deimos::map::get(MAP,string) { + (func.0.unwrap().1)(machine,id,needle) + } else { + Err(RunError::from(format!("No field {:?} for {}",index,stringify!($ident)))) + } + } else { + Err(RunError::from(format!("No field {:?} for {}",index,stringify!($ident)))) + } + } + } } +#[macro_export] +macro_rules! setter { + ($ident:tt,$state:tt,$($map:tt)*) => { + |machine,id,index,value,needle| { + static MAP: &[Entry>>] = &$($map)*; + if let Some(string) = index.clone().try_string() { + if let Some(func) = $crate::deimos::map::get(MAP,string) { + (func.0.unwrap().1)(machine,id,value,needle) + } else { + Err(RunError::from(format!("No field {:?} for {}",index,stringify!($ident)))) + } + } else { + Err(RunError::from(format!("No field {:?} for {}",index,stringify!($ident)))) + } + } + } +} + +pub type MetaGetFn = fn(&mut Machine, AnyId, Value, Needle) -> Result; +pub type MetaSetFn = fn(&mut Machine, AnyId, Value, Value, Needle) -> Result<(), RunError>; +pub type MetaInFn = fn(&mut Machine, AnyId, Value, Needle) -> Result<(), RunError>; +pub type MetaOutFn = fn(&mut Machine, AnyId, Needle) -> Result; +pub type MetaTraverseFn = fn(&mut Machine, AnyId) -> Result<(), RunError>; + pub struct Meta { - pub string: fn(&mut Machine, id: AnyId, needle: Needle) -> Result, - pub number: fn(&mut Machine, id: AnyId, needle: Needle) -> Result, - pub get: fn(&mut Machine, id: AnyId, index: Value, needle: Needle) -> Result, - pub set: fn(&mut Machine, id: AnyId, index: Value, value: Value, needle: Needle) -> Result<(), RunError>, - pub traverse: fn(&mut Machine, id: AnyId) -> Result<(), RunError>, - pub fields: Map>, - pub constants: Map, + pub string: MetaOutFn, + pub number: MetaOutFn, + pub get: MetaGetFn, + pub set: MetaSetFn, + pub traverse: MetaTraverseFn, } impl Default for Meta { fn default() -> Self { Meta { - string: |machine, id, needle| Err(RunError::new("Type does not implement to string.")), - number: |machine, id, needle| Err(RunError::new("Type does not implement to number.")), - get: |machine, id, index, needle|, - set: |machine, id, index, value, needle| (), - traverse: |machine, id| (), + string: |_machine, _id, _needle| Err(RunError::new("Type does not implement to string")), + number: |_machine, _id, _needle| Err(RunError::new("Type does not implement to number")), + get: |_machine, _id, _index, _needle| Err(RunError::new("Type does not implement get")), + set: |_machine, _id, _index, _value, _needle| Err(RunError::new("Type does not implement set")), + traverse: |_machine, _id| Err(RunError::new("Type did not subscribe to traversal")), } } } @@ -411,7 +474,7 @@ pub type ForeignFunction = fn(&mut Machine, needle: Needle) -> Result<(), // Machine for executing functions pub struct Machine { - state: S, + pub state: S, global: Id
, tables: FreeList
, closures: FreeList, @@ -637,13 +700,13 @@ impl Machine { match self.cache.get(string) { Some(ref entry) => Ok(Value::CachedString(entry.0.as_ref().unwrap().clone())), None => { - let cached = CachedString(Rc::from(string), string.hashed()); + let cached = HashedString(Rc::from(string), string.hashed()); self.cache.set(CachedStringEntry(Some(cached.clone()))); Ok(Value::CachedString(cached)) } } } else { - Ok(Value::String(Rc::from(string), string.hashed())) + Ok(Value::String(HashedString(Rc::from(string), string.hashed()))) } } fn meta_call( @@ -831,68 +894,9 @@ impl Machine { // todo: object-table equality fn meta_equal(&mut self, lhs: &mut Value, rhs: &mut Value) -> Result { // with respect to metamethods - Ok(match lhs { - Value::Nil => match rhs { - Value::Nil => true, - _ => false, - }, - Value::Bool(this) => match rhs { - Value::Bool(other) => this == other, - _ => false, - }, - Value::Number(this) => match rhs { - Value::Number(other) => this == other, - Value::Integer(other) => *this == *other as f64, - _ => false, - }, - Value::Integer(this) => match rhs { - Value::Number(other) => *this as f64 == *other, // are these conversions ok? - Value::Integer(other) => this == other, - _ => false, - }, - Value::String(string, hash) => match rhs { - Value::CachedString(other) => { - if *hash == other.1 { - other.0.deref() == (*string).deref() - } else { - false - } - } - Value::String(other_string, other_hash) => { - if hash == other_hash { - string == other_string - } else { - false - } - } - _ => false, - }, - Value::CachedString(string) => match rhs { - Value::CachedString(other) => other.0 == string.0, // pointer equality - Value::String(other_string, other_hash) => { - if string.1 == *other_hash { - string.0.deref() == (*other_string).deref() - } else { - false - } - } - _ => false, - }, - Value::Table(this) => match rhs { - Value::Table(other) => other == this, - _ => false, - }, - Value::Object(this, meta) => match rhs { - Value::Object(other, meta) => other == this, - _ => false, - }, - Value::Function(this) => match rhs { - Value::Function(other) => other == this, - _ => false, - }, - }) + Ok(false) } - pub(crate) fn load(&mut self, source: &str) -> Result, MarsError> { + pub fn load(&mut self, source: &str) -> Result, MarsError> { let chunk = match parse(source) { Ok(parsed) => parsed, Err(error) => return Err(MarsError(error.msg(source))), @@ -1286,7 +1290,7 @@ impl Machine { } Ok(()) } - pub(crate) fn enter(&mut self, closure: Id) -> Result<(), RunError> { + pub fn enter(&mut self, closure: Id) -> Result<(), RunError> { let mut needle = Dispatch { frames: vec![Frame { vararg: 0,