use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone)]
pub enum Primitive {
Int(i64),
Float(f64),
Bool(bool),
Str(String),
}
use self::Primitive::*;
impl fmt::Display for Primitive {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Int(i) => write!(f, "{}", i),
Float(fl) => write!(f, "{}", fl),
Bool(b) => write!(f, "{}", b),
Str(s) => write!(f, "\"{}\"", s),
}
}
}
pub type OpResult = Result<Primitive, String>;
impl Primitive {
pub fn is_int(&self) -> bool {
match self {
Int(_) => true,
_ => false,
}
}
pub fn unwrap_int(&self) -> i64 {
match self {
Int(i) => {
return *i;
}
_ => panic!("Data is not an integer."),
}
}
pub fn is_float(&self) -> bool {
match self {
Float(_) => true,
_ => false,
}
}
pub fn unwrap_float(&self) -> f64 {
match self {
Float(f) => {
return *f;
}
_ => panic!("Data is not a floating point number."),
}
}
pub fn is_bool(&self) -> bool {
match self {
Bool(_) => true,
_ => false,
}
}
pub fn unwrap_bool(&self) -> bool {
match self {
Bool(b) => {
return *b;
}
_ => panic!("Data is not boolean."),
}
}
pub fn is_string(&self) -> bool {
match self {
Str(_) => true,
_ => false,
}
}
pub fn unwrap_string(&self) -> &str {
match self {
Str(s) => &s,
_ => panic!("Data is not a string."),
}
}
pub fn definition(&self) -> String {
match self {
Int(i) => format!("integer({})", i),
Float(f) => format!("float({})", f),
Bool(b) => format!("boolean({})", b),
Str(s) => format!("string(\"{}\")", s),
}
}
pub fn parse_int(s: &str) -> Primitive {
Int(i64::from_str(s).unwrap_or(0))
}
pub fn parse_hex(s: &str) -> Primitive {
let no_prefix = s.trim_left_matches("0x");
Int(i64::from_str_radix(no_prefix, 16).unwrap_or(0))
}
pub fn parse_oct(s: &str) -> Primitive {
let no_prefix = s.trim_left_matches("0o");
Int(i64::from_str_radix(no_prefix, 8).unwrap_or(0))
}
pub fn parse_bin(s: &str) -> Primitive {
let no_prefix = s.trim_left_matches("0b");
Int(i64::from_str_radix(no_prefix, 2).unwrap_or(0))
}
pub fn parse_bool(s: &str) -> Primitive {
match s {
"true" => Bool(true),
_ => Bool(false),
}
}
pub fn parse_float(s: &str) -> Primitive {
Float(f64::from_str(s).unwrap_or(0.0))
}
pub fn parse_string(s: &str) -> Primitive {
let mut chrs = s.chars().peekable();
let mut ret = String::new();
chrs.next();
let mut c = chrs.next();
while let Some(ch) = c {
if chrs.peek().is_none() {
break;
}
ret.push(ch);
c = chrs.next();
}
Str(ret)
}
pub fn add(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l + r)),
(Int(l), Float(r)) => Ok(Float(*l as f64 + r)),
(Float(l), Int(r)) => Ok(Float(l + *r as f64)),
(Float(l), Float(r)) => Ok(Float(l + r)),
(Str(l), Str(r)) => {
let mut s = l.clone();
s.push_str(&r);
Ok(Str(s))
}
(l, r) => Err(format!(
"Operator '+' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn sub(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l - r)),
(Int(l), Float(r)) => Ok(Float(*l as f64 - r)),
(Float(l), Int(r)) => Ok(Float(l - *r as f64)),
(Float(l), Float(r)) => Ok(Float(l - r)),
(l, r) => Err(format!(
"Operator '-' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn mul(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l * r)),
(Int(l), Float(r)) => Ok(Float(*l as f64 * r)),
(Float(l), Int(r)) => Ok(Float(l * *r as f64)),
(Float(l), Float(r)) => Ok(Float(l * r)),
(Str(l), Int(i)) => Ok(Str(l.as_str().repeat(*i as usize))),
(l, r) => Err(format!(
"Operator '*' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn div(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) if l % r == 0 => Ok(Int(l / r)),
(Int(l), Int(r)) => Ok(Float(*l as f64 / *r as f64)),
(Int(l), Float(r)) => Ok(Float(*l as f64 / r)),
(Float(l), Int(r)) => Ok(Float(l / *r as f64)),
(Float(l), Float(r)) => Ok(Float(l / r)),
(l, r) => Err(format!(
"Operator '/' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn modulo(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l % r)),
(Int(l), Float(r)) => Ok(Int(l % *r as i64)),
(Float(l), Int(r)) => Ok(Int(*l as i64 % r)),
(Float(l), Float(r)) => Ok(Int(*l as i64 % *r as i64)),
(l, r) => Err(format!(
"Operator '%' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn pow(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l.pow(*r as u32))),
(Float(l), Int(r)) => Ok(Float(l.powi(*r as i32))),
(l, r) => Err(format!(
"Operator '**' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn shl(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l << r)),
(l, r) => Err(format!(
"Operator '<<' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn shr(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l >> r)),
(l, r) => Err(format!(
"Operator '>>' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn bitand(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l & r)),
(l, r) => Err(format!(
"Operator '&' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn bitor(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l | r)),
(l, r) => Err(format!(
"Operator '|' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn bitxor(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Int(l ^ r)),
(l, r) => Err(format!(
"Operator '^' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn greater(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l > r)),
(Int(l), Float(r)) => Ok(Bool(*l as f64 > *r)),
(Float(l), Int(r)) => Ok(Bool(*l > *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l > r)),
(Str(l), Str(r)) => Ok(Bool(l > r)),
(l, r) => Err(format!(
"Operator '>' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn greater_equals(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l >= r)),
(Int(l), Float(r)) => Ok(Bool(*l as f64 >= *r)),
(Float(l), Int(r)) => Ok(Bool(*l >= *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l >= r)),
(Str(l), Str(r)) => Ok(Bool(l >= r)),
(l, r) => Err(format!(
"Operator '>=' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn less(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l < r)),
(Int(l), Float(r)) => Ok(Bool((*l as f64) < *r)),
(Float(l), Int(r)) => Ok(Bool(*l < *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l < r)),
(Str(l), Str(r)) => Ok(Bool(l < r)),
(l, r) => Err(format!(
"Operator '<' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn less_equals(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l <= r)),
(Int(l), Float(r)) => Ok(Bool(*l as f64 <= *r)),
(Float(l), Int(r)) => Ok(Bool(*l <= *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l <= r)),
(Str(l), Str(r)) => Ok(Bool(l <= r)),
(l, r) => Err(format!(
"Operator '<=' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn equals(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l == r)),
(Int(l), Float(r)) => Ok(Bool(*l as f64 == *r)),
(Float(l), Int(r)) => Ok(Bool(*l == *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l == r)),
(Str(l), Str(r)) => Ok(Bool(l == r)),
(l, r) => Err(format!(
"Operator '==' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn not_equals(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Int(l), Int(r)) => Ok(Bool(l != r)),
(Int(l), Float(r)) => Ok(Bool(*l as f64 != *r)),
(Float(l), Int(r)) => Ok(Bool(*l != *r as f64)),
(Float(l), Float(r)) => Ok(Bool(l != r)),
(Str(l), Str(r)) => Ok(Bool(l != r)),
(l, r) => Err(format!(
"Operator '!=' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn and(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Bool(l), Bool(r)) => Ok(Bool(*l && *r)),
(l, r) => Err(format!(
"Operator '&&' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn or(&self, other: &Primitive) -> OpResult {
match (self, other) {
(Bool(l), Bool(r)) => Ok(Bool(*l || *r)),
(l, r) => Err(format!(
"Operator '||' is not defined for values {} and {}",
l.definition(),
r.definition()
)),
}
}
pub fn not(&self) -> OpResult {
match self {
Bool(b) => Ok(Bool(!b)),
Int(i) => Ok(Int(!i)),
t => Err(format!(
"Unary operator '!' is not defined for value {}",
t.definition()
)),
}
}
pub fn inverse(&self) -> OpResult {
match self {
Int(i) => Ok(Int(-i)),
Float(f) => Ok(Float(-f)),
t => Err(format!(
"Unary operator '-' is not defined for value {}",
t.definition()
)),
}
}
}
#[cfg(test)]
mod tests {
use super::Primitive;
use super::Primitive::*;
#[test]
fn parsing() {
assert_eq!(Primitive::parse_int("12").unwrap_int(), 12);
assert_eq!(Primitive::parse_hex("0x12").unwrap_int(), 18);
assert_eq!(Primitive::parse_oct("0o12").unwrap_int(), 10);
assert_eq!(Primitive::parse_bin("0b101").unwrap_int(), 5);
assert_eq!(Primitive::parse_float("0.12").unwrap_float(), 0.12);
assert_eq!(Primitive::parse_float("1.2e2").unwrap_float(), 120.0);
assert!(Primitive::parse_bool("true").unwrap_bool());
assert!(!Primitive::parse_bool("false").unwrap_bool());
assert_eq!(
Primitive::parse_string("\"Hello world!\"").unwrap_string(),
"Hello world!".to_string()
);
}
#[test]
fn additon() {
let a = Int(2);
let b = Int(3);
assert_eq!(a.add(&b).unwrap().unwrap_int(), 5);
let f = Float(0.5);
assert_eq!(a.add(&f).unwrap().unwrap_float(), 2.5);
let s1 = Str("Hello".to_string());
let s2 = Str(" world!".to_string());
assert_eq!(
s1.add(&s2).unwrap().unwrap_string(),
"Hello world!".to_string()
);
let b = Bool(true);
assert!(a.add(&b).is_err());
}
#[test]
fn subtraction() {
let a = Int(2);
let b = Int(3);
assert_eq!(a.sub(&b).unwrap().unwrap_int(), -1);
let f = Float(0.5);
assert_eq!(a.sub(&f).unwrap().unwrap_float(), 1.5);
let s1 = Str("Hello".to_string());
let s2 = Str(" world!".to_string());
assert!(s1.sub(&s2).is_err());
}
}