164 lines
4.4 KiB
Rust
164 lines
4.4 KiB
Rust
use std::{cell::RefCell, fmt::Display, rc::Rc};
|
|
|
|
use super::{
|
|
class::{Class, ClassRef, Instance},
|
|
functions::Function,
|
|
native_fn::NativeFunction,
|
|
Callable,
|
|
};
|
|
|
|
/// A value being handled by the interpreter.
|
|
#[derive(Debug, Clone)]
|
|
pub enum Value {
|
|
Nil,
|
|
Boolean(bool),
|
|
String(String),
|
|
Number(f64),
|
|
Object(Rc<RefCell<Object>>),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Object {
|
|
NativeFunction(NativeFunction),
|
|
LoxFunction(Function),
|
|
Class(ClassRef),
|
|
Instance(Instance),
|
|
}
|
|
|
|
/* -------------------- *
|
|
* Value implementation *
|
|
* -------------------- */
|
|
|
|
impl Value {
|
|
/// Check whether a value is truthy or not.
|
|
pub fn is_truthy(&self) -> bool {
|
|
match self {
|
|
Self::Nil => false,
|
|
Self::Boolean(b) => *b,
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
/// Run some code using the callable object wrapped inside a value.
|
|
/// If the value is not callable, an error function will be called
|
|
/// instead.
|
|
pub fn with_callable<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
|
|
where
|
|
Fok: FnOnce(&dyn Callable) -> Rt,
|
|
Ferr: FnOnce() -> Rt,
|
|
{
|
|
let obj = match self {
|
|
Value::Object(obj_ref) => obj_ref.borrow(),
|
|
_ => return ferr(),
|
|
};
|
|
match &*obj {
|
|
Object::NativeFunction(func) => fok(func),
|
|
Object::LoxFunction(func) => fok(func),
|
|
Object::Class(class) => fok(class),
|
|
Object::Instance(_) => ferr(),
|
|
}
|
|
}
|
|
|
|
/// Run some code against an instance value. If the value does not
|
|
/// contain an instance, an error function will be called instead.
|
|
pub fn with_instance<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
|
|
where
|
|
Fok: FnOnce(&Instance) -> Rt,
|
|
Ferr: FnOnce() -> Rt,
|
|
{
|
|
let obj = match self {
|
|
Value::Object(obj_ref) => obj_ref.borrow(),
|
|
_ => return ferr(),
|
|
};
|
|
match &*obj {
|
|
Object::Instance(inst) => fok(inst),
|
|
_ => ferr(),
|
|
}
|
|
}
|
|
|
|
/// Run some code against a mutable instance value. If the value does
|
|
/// not contain an instance, an error function will be called instead.
|
|
pub fn with_instance_mut<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
|
|
where
|
|
Fok: FnOnce(&mut Instance) -> Rt,
|
|
Ferr: FnOnce() -> Rt,
|
|
{
|
|
let mut obj = match self {
|
|
Value::Object(obj_ref) => obj_ref.borrow_mut(),
|
|
_ => return ferr(),
|
|
};
|
|
match &mut *obj {
|
|
Object::Instance(inst) => fok(inst),
|
|
_ => ferr(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Value {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::Nil, Self::Nil) => true,
|
|
(Self::Boolean(a), Self::Boolean(b)) => a == b,
|
|
(Self::String(a), Self::String(b)) => a == b,
|
|
(Self::Number(a), Self::Number(b)) => a == b,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Value::Nil => f.write_str("nil"),
|
|
Value::Boolean(b) => b.fmt(f),
|
|
Value::String(s) => s.fmt(f),
|
|
Value::Number(n) => n.fmt(f),
|
|
Value::Object(obj) => obj.borrow().fmt(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NativeFunction> for Value {
|
|
fn from(value: NativeFunction) -> Self {
|
|
Value::Object(Rc::new(RefCell::new(Object::NativeFunction(value))))
|
|
}
|
|
}
|
|
|
|
impl From<Function> for Value {
|
|
fn from(value: Function) -> Self {
|
|
Value::Object(Rc::new(RefCell::new(Object::LoxFunction(value))))
|
|
}
|
|
}
|
|
|
|
impl From<Class> for Value {
|
|
fn from(value: Class) -> Self {
|
|
Value::from(Rc::new(RefCell::new(value)))
|
|
}
|
|
}
|
|
|
|
impl From<ClassRef> for Value {
|
|
fn from(value: ClassRef) -> Self {
|
|
Value::Object(Rc::new(RefCell::new(Object::Class(value))))
|
|
}
|
|
}
|
|
|
|
impl From<Instance> for Value {
|
|
fn from(value: Instance) -> Self {
|
|
Value::Object(Rc::new(RefCell::new(Object::Instance(value))))
|
|
}
|
|
}
|
|
|
|
/* --------------------- *
|
|
* Object implementation *
|
|
* --------------------- */
|
|
|
|
impl Display for Object {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Object::NativeFunction(func) => func.fmt(f),
|
|
Object::LoxFunction(func) => func.fmt(f),
|
|
Object::Class(cls) => cls.borrow().fmt(f),
|
|
Object::Instance(inst) => inst.fmt(f),
|
|
}
|
|
}
|
|
}
|