blob: aad38e025319b2ad54fdcbd6f9c4226747b7a56f [file] [log] [blame]
use std::cmp::Ordering;
use std::borrow::Cow;
use errors;
use object::Object;
use object_pool::ObjectPool;
use object_info::ObjectHandle;
use opcode::{OpCode, RtOpCode};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Value {
Object(usize),
Null,
Bool(bool),
Int(i64),
Float(f64)
}
impl Value {
pub fn is_object(&self) -> bool {
if let Value::Object(_) = *self {
true
} else {
false
}
}
pub fn as_object_id(&self) -> usize {
if let Value::Object(obj) = *self {
obj
} else {
panic!(errors::VMError::from(errors::RuntimeError::new(
format!("Not an object: {:?}", self)
)));
}
}
pub fn to_opcode(&self) -> OpCode {
match *self {
Value::Object(id) => OpCode::Rt(RtOpCode::LoadObject(id)),
Value::Null => OpCode::LoadNull,
Value::Bool(v) => OpCode::LoadBool(v),
Value::Int(v) => OpCode::LoadInt(v),
Value::Float(v) => OpCode::LoadFloat(v)
}
}
}
pub struct ValueContext<'a, 'b> {
pub value: &'a Value,
pub pool: &'b ObjectPool
}
impl<'a, 'b> ValueContext<'a, 'b> {
pub fn new(v: &'a Value, pool: &'b ObjectPool) -> ValueContext<'a, 'b> {
ValueContext {
value: v,
pool: pool
}
}
pub fn is_object(&self) -> bool {
self.value.is_object()
}
pub fn as_object_id(&self) -> usize {
self.value.as_object_id()
}
pub fn as_object<'z>(&self) -> ObjectHandle<'z> {
self.pool.get(self.as_object_id())
}
pub fn as_object_direct(&self) -> &'b Object {
self.pool.get_direct(self.as_object_id())
}
pub fn to_i64(&self) -> i64 {
match *self.value {
Value::Object(id) => self.pool.get_direct(id).to_i64(),
Value::Null => 0,
Value::Bool(v) => if v {
1
} else {
0
},
Value::Int(v) => v,
Value::Float(v) => v as i64
}
}
pub fn to_f64(&self) -> f64 {
match *self.value {
Value::Object(id) => self.pool.get_direct(id).to_f64(),
Value::Null => 0.0,
Value::Bool(v) => if v {
1.0
} else {
0.0
},
Value::Int(v) => v as f64,
Value::Float(v) => v
}
}
pub fn to_bool(&self) -> bool {
match *self.value {
Value::Object(id) => self.pool.get_direct(id).to_bool(),
Value::Null => false,
Value::Bool(v) => v,
Value::Int(v) => if v != 0 {
true
} else {
false
},
Value::Float(v) => if v != 0.0 {
true
} else {
false
}
}
}
pub fn compare(&self, other: &ValueContext) -> Option<Ordering> {
if let Value::Object(_) = *self.value {
return self.as_object_direct().compare(other);
}
if let Value::Object(_) = *other.value {
return other.as_object_direct().compare(self);
}
match (*self.value, *other.value) {
(Value::Null, Value::Null) => Some(Ordering::Equal),
(Value::Bool(a), Value::Bool(b)) => a.partial_cmp(&b),
(Value::Int(a), Value::Int(b)) => a.partial_cmp(&b),
(Value::Float(a), Value::Float(b)) => a.partial_cmp(&b),
(Value::Int(a), Value::Float(b)) => (a as f64).partial_cmp(&b),
(Value::Float(a), Value::Int(b)) => a.partial_cmp(&(b as f64)),
_ => None
}
}
pub fn to_str<'z>(&'z self) -> Cow<'z, str> {
match *self.value {
Value::Object(_) => Cow::from(self.as_object_direct().to_str()),
Value::Null => Cow::from("(null)"),
Value::Bool(v) => Cow::from(if v {
"true"
} else {
"false"
}),
Value::Int(v) => Cow::from(format!("{}", v)),
Value::Float(v) => Cow::from(format!("{}", v))
}
}
}