Merge Value and ValueInner
This commit is contained in:
parent
2167b524ec
commit
61c42ae790
|
|
@ -313,10 +313,10 @@ trait Eval {
|
|||
impl Eval for ast::Constant {
|
||||
fn eval(&self, _ctx: &RunContext) -> types::Value {
|
||||
match self {
|
||||
ast::Constant::Nil => None,
|
||||
ast::Constant::Boolean(value) => Some(types::ValueInner::Boolean(*value)),
|
||||
ast::Constant::Number(value) => Some(types::ValueInner::Number(*value)),
|
||||
ast::Constant::String(value) => Some(types::ValueInner::String(value.clone())),
|
||||
ast::Constant::Nil => types::Value::Nil,
|
||||
ast::Constant::Boolean(value) => types::Value::Boolean(*value),
|
||||
ast::Constant::Number(value) => types::Value::Number(*value),
|
||||
ast::Constant::String(value) => types::Value::String(value.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -326,9 +326,9 @@ impl Eval for Location {
|
|||
match self {
|
||||
Location::Variable { id } => ctx.var(*id).get(),
|
||||
Location::Field { table, index } => {
|
||||
let table = table.eval(ctx).expect("attempt to index a nil value");
|
||||
let index = index.eval(ctx).expect("attempt to index with a nil value");
|
||||
let types::ValueInner::Table(table) = table else {
|
||||
let table = table.eval(ctx);
|
||||
let index = index.eval(ctx);
|
||||
let types::Value::Table(table) = table else {
|
||||
panic!("attempt to index a non-table");
|
||||
};
|
||||
table.get(index)
|
||||
|
|
@ -341,7 +341,7 @@ impl Eval for Call {
|
|||
fn eval(&self, ctx: &RunContext) -> types::Value {
|
||||
let callee = self.callee.eval(ctx);
|
||||
let args: Vec<_> = self.args.iter().map(|arg| arg.eval(ctx)).collect();
|
||||
let Some(types::ValueInner::Function(f)) = callee else {
|
||||
let types::Value::Function(f) = callee else {
|
||||
panic!("attempt to call a non-function");
|
||||
};
|
||||
f.call(&args)
|
||||
|
|
@ -356,9 +356,7 @@ impl Eval for Function {
|
|||
.map(|(_name, id)| ctx.var(*id))
|
||||
.collect();
|
||||
let self_ = self.clone(); // TODO reference, somehow
|
||||
Some(
|
||||
types::Function::new(self.name.clone(), move |args| self_.call(&upvalues, args)).into(),
|
||||
)
|
||||
types::Function::new(self.name.clone(), move |args| self_.call(&upvalues, args)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,11 +364,11 @@ impl Eval for Table {
|
|||
fn eval(&self, ctx: &RunContext) -> types::Value {
|
||||
let table = types::Table::default();
|
||||
for field in &self.fields {
|
||||
let key = field.key.eval(ctx).expect("attempt to set a nil index");
|
||||
let key = field.key.eval(ctx);
|
||||
let value = field.value.eval(ctx);
|
||||
table.set(key, value);
|
||||
}
|
||||
Some(table.into())
|
||||
table.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,9 +392,9 @@ impl Eval for Statement {
|
|||
match target {
|
||||
Location::Variable { id } => ctx.var(*id).set(source),
|
||||
Location::Field { table, index } => {
|
||||
let table = table.eval(ctx).expect("attempt to index a nil value");
|
||||
let index = index.eval(ctx).expect("attempt to index with a nil value");
|
||||
let types::ValueInner::Table(table) = table else {
|
||||
let table = table.eval(ctx);
|
||||
let index = index.eval(ctx);
|
||||
let types::Value::Table(table) = table else {
|
||||
panic!("attempt to index a non-table");
|
||||
};
|
||||
table.set(index, source)
|
||||
|
|
@ -407,7 +405,7 @@ impl Eval for Statement {
|
|||
call.eval(ctx);
|
||||
}
|
||||
};
|
||||
None
|
||||
types::Value::Nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +419,9 @@ impl Function {
|
|||
assert_eq!(args.len(), self.args.len());
|
||||
let ctx = RunContext {
|
||||
args: args.iter().map(new_var).collect(),
|
||||
locals: (0..self.locals.len()).map(|_| new_var(&None)).collect(),
|
||||
locals: (0..self.locals.len())
|
||||
.map(|_| new_var(&types::Value::Nil))
|
||||
.collect(),
|
||||
upvalues: upvalues.to_vec(),
|
||||
};
|
||||
for statement in &self.body {
|
||||
|
|
@ -443,29 +443,26 @@ impl OpenFunction {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
ast::*,
|
||||
types::{Value, ValueInner},
|
||||
};
|
||||
use crate::{ast::*, types::Nil, types::Value};
|
||||
|
||||
use super::build;
|
||||
|
||||
fn get(table: &Value, index: &str) -> Value {
|
||||
let Some(ValueInner::Table(table)) = table else {
|
||||
let Value::Table(table) = table else {
|
||||
panic!("a table expected");
|
||||
};
|
||||
table.get(index.into())
|
||||
}
|
||||
|
||||
fn set(table: &Value, index: &str, value: Value) {
|
||||
let Some(ValueInner::Table(table)) = table else {
|
||||
let Value::Table(table) = table else {
|
||||
panic!("a table expected");
|
||||
};
|
||||
table.set(index.into(), value);
|
||||
}
|
||||
|
||||
fn call(func: &Value, args: &[Value]) -> Value {
|
||||
let Some(ValueInner::Function(func)) = func else {
|
||||
let Value::Function(func) = func else {
|
||||
panic!("a function expected");
|
||||
};
|
||||
func.call(args)
|
||||
|
|
@ -494,9 +491,9 @@ mod tests {
|
|||
};
|
||||
let env = crate::types::Table::default();
|
||||
let testee = build(&testee);
|
||||
let ret = testee.call(Some(env.clone().into()), &[]);
|
||||
assert_eq!(ret, Some(3.into()));
|
||||
assert_eq!(env.get("x".into()), Some(1.into()));
|
||||
let ret = testee.call(env.clone().into(), &[]);
|
||||
assert_eq!(ret, 3.into());
|
||||
assert_eq!(env.get("x".into()), 1.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -526,9 +523,9 @@ mod tests {
|
|||
};
|
||||
let env = crate::types::Table::default();
|
||||
let testee = build(&testee);
|
||||
let ret = testee.call(Some(env.clone().into()), &[]);
|
||||
assert_eq!(ret, Some(42.into()));
|
||||
assert_eq!(env.get("x".into()), Some(666.into()));
|
||||
let ret = testee.call(env.clone().into(), &[]);
|
||||
assert_eq!(ret, 42.into());
|
||||
assert_eq!(env.get("x".into()), 666.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -545,8 +542,8 @@ mod tests {
|
|||
}))),
|
||||
};
|
||||
let remember = build(&remember);
|
||||
let the_answerer = remember.call(None, &[Some(42.into())]);
|
||||
assert_eq!(call(&the_answerer, &[]), Some(42.into()));
|
||||
let the_answerer = remember.call(Nil, &[42.into()]);
|
||||
assert_eq!(call(&the_answerer, &[]), 42.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -586,13 +583,13 @@ mod tests {
|
|||
))),
|
||||
};
|
||||
let make_cell = build(&make_cell);
|
||||
let cell1 = make_cell.call(None, &[]);
|
||||
let cell2 = make_cell.call(None, &[]);
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), None);
|
||||
call(&get(&cell1, "set"), &[Some(42.into())]);
|
||||
call(&get(&cell2, "set"), &[Some("foobar".into())]);
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), Some(42.into()));
|
||||
let cell1 = make_cell.call(Nil, &[]);
|
||||
let cell2 = make_cell.call(Nil, &[]);
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), Nil);
|
||||
call(&get(&cell1, "set"), &[42.into()]);
|
||||
call(&get(&cell2, "set"), &["foobar".into()]);
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), 42.into());
|
||||
call(&get(&cell1, "set"), &[call(&get(&cell2, "get"), &[])]);
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), Some("foobar".into()));
|
||||
assert_eq!(call(&get(&cell1, "get"), &[]), "foobar".into());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
src/types.rs
30
src/types.rs
|
|
@ -1,7 +1,9 @@
|
|||
use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ValueInner {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||
pub enum Value {
|
||||
#[default]
|
||||
Nil,
|
||||
Boolean(bool),
|
||||
Number(i64),
|
||||
String(String),
|
||||
|
|
@ -9,16 +11,18 @@ pub enum ValueInner {
|
|||
Function(Function),
|
||||
}
|
||||
|
||||
pub use Value::Nil;
|
||||
|
||||
macro_rules! impl_from {
|
||||
($as: ident, $from: ty) => {
|
||||
impl From<$from> for ValueInner {
|
||||
impl From<$from> for Value {
|
||||
fn from(value: $from) -> Self {
|
||||
Self::$as(value.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
(try $as: ident, $from: ty) => {
|
||||
impl TryFrom<$from> for ValueInner {
|
||||
impl TryFrom<$from> for Value {
|
||||
type Error = ::std::num::TryFromIntError;
|
||||
fn try_from(value: $from) -> Result<Self, Self::Error> {
|
||||
Ok(Self::$as(value.try_into()?))
|
||||
|
|
@ -39,11 +43,9 @@ impl_from!(String, &str);
|
|||
impl_from!(Table, Table);
|
||||
impl_from!(Function, Function);
|
||||
|
||||
pub type Value = Option<ValueInner>;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct TableInner {
|
||||
content: HashMap<ValueInner, ValueInner>,
|
||||
content: HashMap<Value, Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
@ -64,13 +66,19 @@ impl Hash for Table {
|
|||
}
|
||||
|
||||
impl Table {
|
||||
pub fn get(&self, key: ValueInner) -> Value {
|
||||
self.0.borrow().content.get(&key).cloned()
|
||||
pub fn get(&self, key: Value) -> Value {
|
||||
self.0
|
||||
.borrow()
|
||||
.content
|
||||
.get(&key)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn set(&self, key: ValueInner, value: Value) {
|
||||
pub fn set(&self, key: Value, value: Value) {
|
||||
assert!(key != Nil);
|
||||
let mut this = self.0.borrow_mut();
|
||||
if let Some(value) = value {
|
||||
if value != Nil {
|
||||
this.content.insert(key, value);
|
||||
} else {
|
||||
this.content.remove(&key);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user