1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::fmt::{Display};
use std::str::FromStr;
use std::ops::{Add, Sub, Mul, Div, Rem};

use crate::table::*;
use crate::object::*;

#[derive(Debug, Clone, PartialEq)]
pub struct Value {
    value_type: Type,
    function: fn(Self) -> Self,
    contents: Contents,
    list: Vec<Self>,
    attributes: Table<Self>,
}

impl Display for Value {
    fn fmt(&self, _fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        self.print();
        Ok(())
    }
}


impl Add for Value {
    type Output = Value;
    fn add(self, rhs: Self) -> Self::Output {
        if self.value_type != rhs.value_type {
            return Value::from_problem(Problem::IncompatibleTypes);
        }

        match self.value_type {
            Type::Num => Value::from_number(self.as_number() + rhs.as_number()),
            Type::Str => Value::from_string(self.as_string() + &rhs.as_string()),
            _ => Value::from_problem(Problem::ValueError)
        }
    }
}

impl Sub for Value {
    type Output = Value;
    fn sub(self, rhs: Self) -> Self::Output {
        if self.value_type != rhs.value_type {
            return Value::from_problem(Problem::IncompatibleTypes);
        }

        if self.value_type != Type::Num {
            return Value::from_problem(Problem::ValueError);
        }

        return Value::from_number(self.as_number() - rhs.as_number())
    }
}

impl Mul for Value {
    type Output = Value;
    fn mul(self, rhs: Self) -> Self::Output {
        if self.value_type != rhs.value_type {
            return Value::from_problem(Problem::IncompatibleTypes);
        }

        if self.value_type != Type::Num {
            return Value::from_problem(Problem::ValueError);
        }

        return Value::from_number(self.as_number() * rhs.as_number())
    }
}

impl Div for Value {
    type Output = Value;
    fn div(self, rhs: Self) -> Self::Output {
        if self.value_type != rhs.value_type {
            return Value::from_problem(Problem::IncompatibleTypes);
        }

        if self.value_type != Type::Num {
            return Value::from_problem(Problem::ValueError);
        }

        return Value::from_number(self.as_number() / rhs.as_number())
    }
}

impl Rem for Value {
    type Output = Value;
    fn rem(self, rhs: Self) -> Self::Output {
        if self.value_type != rhs.value_type {
            return Value::from_problem(Problem::IncompatibleTypes);
        }

        if self.value_type != Type::Num {
            return Value::from_problem(Problem::ValueError);
        }

        return Value::from_number(self.as_number() % rhs.as_number())
    }
}


impl Object for Value {
    fn new(value_type: Type, contents: Contents) -> Self {
        Self {
            value_type: value_type,
            contents: contents,
            function: |object: Self| object,
            list: vec![],
            attributes: Table::new()
        }
    }

    fn get_type(&self) -> Type {self.value_type.clone()}
    fn get_list(&self) -> Vec<Self> {self.list.clone()}
    fn get_contents(&self) -> Contents {self.contents.clone()}
    fn get_attributes(&self) -> Table<Self> {self.attributes.clone()}
    fn get_foreign_function(&self) -> fn(Self) -> Self {self.function.clone()}

    fn set_type(&mut self, value_type: Type) {self.value_type = value_type}
    fn set_list(&mut self, list: Vec<Self>) {self.list = list}
    fn set_contents(&mut self, contents: Contents) {self.contents = contents}
    fn set_attributes(&mut self, attributes: Table<Self>) {self.attributes = attributes}
    fn set_foreign_function(&mut self, function: fn(Self) -> Self) {self.function = function}
}