use std::fmt;
use std::ops::Add;
use std::cmp::Ordering;
use sindra;
use sindra::value::{Coerce, Cast, Extract};
use ast::Literal;
use PType;
use psk_std::complex::Complex;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
String(String),
Float(f64),
Int(i64),
Boolean(bool),
Complex(f64, f64),
Set(Box<ValueSet>),
Return(Box<Value>),
Break(Box<Value>),
Empty
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
match *self {
Value::String(ref s) => write!(f, "{}", s),
Value::Float(ref fl) => write!(f, "{}", fl),
Value::Int(ref i) => write!(f, "{}", i),
Value::Boolean(ref b) => write!(f, "{}", b),
Value::Complex(ref re, ref im)
=> write!(f, "{}+{}i", re, im),
Value::Set(ref s) => write!(f, "{}", s),
Value::Return(ref v) => write!(f, "{}", *v),
Value::Break(ref v) => write!(f, "{}", *v),
Value::Empty => write!(f, "<null>")
}
}
}
impl sindra::Value for Value {}
impl From<Literal> for Value {
fn from(lit: Literal) -> Value {
match lit {
Literal::String(s) => Value::String(s),
Literal::Float(f) => Value::Float(f),
Literal::Int(i) => Value::Int(i),
Literal::Boolean(b) => Value::Boolean(b),
}
}
}
impl<'a> From<&'a Value> for PType {
fn from(v: &'a Value) -> PType {
match *v {
Value::String(_) => PType::String,
Value::Float(_) => PType::Float,
Value::Int(_) => PType::Int,
Value::Boolean(_) => PType::Boolean,
Value::Complex(_, _) => PType::Complex,
Value::Set(_) => PType::Set,
Value::Return(ref v) => PType::from(v.as_ref()),
Value::Break(ref v) => PType::from(v.as_ref()),
Value::Empty => PType::Void,
}
}
}
impl Cast<PType> for Value {
fn cast(self, dest_ty: PType) -> Value {
match dest_ty {
PType::Float => {
match self {
Value::Int(i) => Value::Float(i as f64),
_ => self
}
},
PType::Complex => {
match self {
Value::Int(i) => Value::Complex(i as f64, 0.0),
Value::Float(f) => Value::Complex(f, 0.0),
_ => self
}
}
_ => self
}
}
}
impl Cast<PType> for PType {
fn cast(self, dest_ty: PType) -> PType {
match dest_ty {
PType::Float => {
match self {
PType::Int => PType::Float,
_ => self
}
},
PType::Complex => {
match self {
PType::Int => PType::Complex,
PType::Float => PType::Complex,
_ => self
}
},
_ => self
}
}
}
impl Coerce<PType> for Value {
fn coerce(self, dest_ty: Option<PType>) -> Value {
match dest_ty {
Some(dest) => {
self.cast(dest)
},
None => self
}
}
}
impl Coerce<PType> for PType {
fn coerce(self, dest_ty: Option<PType>) -> PType {
match dest_ty {
Some(dest) => {
self.cast(dest)
},
None => self
}
}
}
impl<'a> Add for &'a Value {
type Output = Value;
fn add(self, rhs: &Value) -> Value {
match (self, rhs) {
(&Value::Float(ref left), &Value::Float(ref right)) => {
Value::Float(left + right)
},
(&Value::Int(ref left), &Value::Int(ref right)) => {
Value::Int(left + right)
},
_ => panic!("unable to add value of type '{}' with a rhs of type '{}'",
PType::from(self), PType::from(rhs))
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) {
(&Value::Float(ref left), &Value::Float(ref right)) => {
left.partial_cmp(&right)
},
(&Value::Int(ref left), &Value::Int(ref right)) => {
left.partial_cmp(&right)
},
_ => panic!("unable to add value of type '{}' with a rhs of type '{}'",
PType::from(self), PType::from(other))
}
}
}
impl Value {
pub fn has_same_type(&self, other: &Value) -> bool {
PType::from(self) == PType::from(other)
}
}
impl Extract<u64> for Value {
fn extract(&self) -> Result<u64, String> {
match *self {
Value::Int(i) => {
Ok(i as u64)
},
_ => Err(format!("unable to extract unsigned int from type {}", PType::from(self)))
}
}
}
impl Extract<usize> for Value {
fn extract(&self) -> Result<usize, String> {
match *self {
Value::Int(i) => {
Ok(i as usize)
},
_ => Err(format!("unable to extract unsigned int from type {}", PType::from(self)))
}
}
}
impl Extract<i64> for Value {
fn extract(&self) -> Result<i64, String> {
match *self {
Value::Int(i) => {
Ok(i)
},
_ => Err(format!("unable to extract int from type {}", PType::from(self)))
}
}
}
impl Extract<String> for Value {
fn extract(&self) -> Result<String, String> {
match *self {
Value::String(ref s) => {
Ok(s.clone())
},
_ => Err(format!("unable to extract string from type {}", PType::from(self)))
}
}
}
impl Extract<f64> for Value {
fn extract(&self) -> Result<f64, String> {
match *self {
Value::Float(f) => {
Ok(f)
},
_ => Err(format!("unable to extract float from type {}", PType::from(self)))
}
}
}
impl Extract<Complex> for Value {
fn extract(&self) -> Result<Complex, String> {
match *self {
Value::Complex(re, im) => {
Ok(Complex::new(re, im))
},
_ => Err(format!("unable to extract complex from type {}", PType::from(self)))
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ValueSet {
Interval(SetInterval)
}
impl ValueSet {
pub fn iter<'a>(&'a self) -> Result<SetIter<'a>, String> {
let iter = match *self {
ValueSet::Interval(ref interval) => {
if !interval.start.has_same_type(&interval.end) ||
!interval.start.has_same_type(&interval.step) {
return Err("interval must have same value type for start, end, and step \
to be iterated".to_string())
}
SetIter::Interval {
set: interval,
prev: None
}
}
};
Ok(iter)
}
}
impl fmt::Display for ValueSet {
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
match *self {
ValueSet::Interval(ref set) => write!(f, "{}", set),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SetInterval {
pub start: Value,
pub end: Value,
pub end_inclusive: bool,
pub step: Value,
}
impl fmt::Display for SetInterval {
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
write!(f, "{}..{}..{}", self.start, self.step, self.end)
}
}
pub enum SetIter<'a> {
Interval {
set: &'a SetInterval,
prev: Option<Value>,
}
}
impl<'a> Iterator for SetIter<'a> {
type Item = Value;
fn next(&mut self) -> Option<Value> {
match *self {
SetIter::Interval { ref set, ref mut prev } => {
let next = match *prev {
Some(ref prev) => {
prev + &set.step
},
None => {
set.start.clone()
}
};
let terminate = if set.end_inclusive {
next > set.end
} else {
next >= set.end
};
if terminate {
None
} else {
*prev = Some(next.clone());
Some(next)
}
}
}
}
}