Small tweaks
This commit is contained in:
parent
bfc418a55e
commit
93d6f6a886
4 changed files with 175 additions and 119 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
232
src/vm.rs
232
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<String> 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<str>, pub(crate) Hashed);
|
||||
pub struct HashedString(Rc<str>, 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<CachedString>);
|
||||
struct CachedStringEntry(Option<HashedString>);
|
||||
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<str>, Hashed),
|
||||
CachedString(HashedString),
|
||||
String(HashedString),
|
||||
Table(Id<Table>),
|
||||
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<str> {
|
||||
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<HashedString> {
|
||||
match self {
|
||||
Value::CachedString(hashed) => Some(hashed),
|
||||
Value::String(hashed) => Some(hashed),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub(crate) fn traverse<C>(&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<Closure>, // 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<V> Equivalent<HashedString> 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<S> = fn(
|
||||
&mut Machine<S>,
|
||||
id: AnyId,
|
||||
index: Value,
|
||||
value: Value,
|
||||
needle: Needle,
|
||||
) -> Result<Value, RunError>;
|
||||
type MetaFieldGet<S> = fn(&mut Machine<S>, id: AnyId, index: Value, needle: Needle) -> Result<(), RunError>;
|
||||
pub struct MetaField<S> {
|
||||
set: MetaFieldSet<S>,
|
||||
get: MetaFieldGet<S>,
|
||||
#[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<MapEntry<&'static str,$crate::MetaInFn<$state>>>] = &$($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<S> = fn(&mut Machine<S>, AnyId, Value, Needle) -> Result<Value, RunError>;
|
||||
pub type MetaSetFn<S> = fn(&mut Machine<S>, AnyId, Value, Value, Needle) -> Result<(), RunError>;
|
||||
pub type MetaInFn<S> = fn(&mut Machine<S>, AnyId, Value, Needle) -> Result<(), RunError>;
|
||||
pub type MetaOutFn<S> = fn(&mut Machine<S>, AnyId, Needle) -> Result<Value, RunError>;
|
||||
pub type MetaTraverseFn<S> = fn(&mut Machine<S>, AnyId) -> Result<(), RunError>;
|
||||
|
||||
pub struct Meta<S> {
|
||||
pub string: fn(&mut Machine<S>, id: AnyId, needle: Needle) -> Result<Value, RunError>,
|
||||
pub number: fn(&mut Machine<S>, id: AnyId, needle: Needle) -> Result<Value, RunError>,
|
||||
pub get: fn(&mut Machine<S>, id: AnyId, index: Value, needle: Needle) -> Result<Value, RunError>,
|
||||
pub set: fn(&mut Machine<S>, id: AnyId, index: Value, value: Value, needle: Needle) -> Result<(), RunError>,
|
||||
pub traverse: fn(&mut Machine<S>, id: AnyId) -> Result<(), RunError>,
|
||||
pub fields: Map<Value, MetaField<S>>,
|
||||
pub constants: Map<Value, Value>,
|
||||
pub string: MetaOutFn<S>,
|
||||
pub number: MetaOutFn<S>,
|
||||
pub get: MetaGetFn<S>,
|
||||
pub set: MetaSetFn<S>,
|
||||
pub traverse: MetaTraverseFn<S>,
|
||||
}
|
||||
|
||||
impl<S> Default for Meta<S> {
|
||||
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<S> = fn(&mut Machine<S>, needle: Needle) -> Result<(),
|
|||
|
||||
// Machine for executing functions
|
||||
pub struct Machine<S> {
|
||||
state: S,
|
||||
pub state: S,
|
||||
global: Id<Table>,
|
||||
tables: FreeList<Table>,
|
||||
closures: FreeList<Closure>,
|
||||
|
|
@ -637,13 +700,13 @@ impl<S> Machine<S> {
|
|||
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<S> Machine<S> {
|
|||
// todo: object-table equality
|
||||
fn meta_equal(&mut self, lhs: &mut Value, rhs: &mut Value) -> Result<bool, RunError> {
|
||||
// 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<Id<Closure>, MarsError> {
|
||||
pub fn load(&mut self, source: &str) -> Result<Id<Closure>, MarsError> {
|
||||
let chunk = match parse(source) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(error) => return Err(MarsError(error.msg(source))),
|
||||
|
|
@ -1286,7 +1290,7 @@ impl<S> Machine<S> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn enter(&mut self, closure: Id<Closure>) -> Result<(), RunError> {
|
||||
pub fn enter(&mut self, closure: Id<Closure>) -> Result<(), RunError> {
|
||||
let mut needle = Dispatch {
|
||||
frames: vec![Frame {
|
||||
vararg: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue