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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//! The Rurtle type/value system
//!
//! Rurtle is dynamically typed and has 4 different types of values:
//!
//! `Number`: Rurtle doesn't differentiate between integers and floats, there is
//! just a single number type. Internally numbers are represented by floats.
//!
//! `String`: A chain of characters, also known as a text. Like Python, Rurtle
//! has no special datatype for a single character. A `String` of length 1 may
//! thus considered as a character.
//!
//! `List`: A list is a list of other Rurtle Values, possibly even nested
//! Lists. A list is heterogenous, which means that it may contain values of
//! different types.
//!
//! `Nothing`: Something like Python's `None`, this is the default value for
//! everything that doesn't explicitely return something else.
use std::ops;
use std::fmt;
/// Enum combining the possible Rurtle value types
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Value {
    Nothing,
    Number(f32),
    String(String),
    List(Vec<Value>),
}

impl Value {
    /// Return the given `Value`'s boolean value. Objects considered `true` are
    ///
    /// * `Numbers` different from 0
    /// * nonempty `String`s and `List`s
    ///
    /// Everything else is considered to be "falsy"
    pub fn boolean(&self) -> bool {
        match *self {
            Value::Number(f) => f != 0.0,
            Value::String(ref s) => !s.is_empty(),
            Value::List(ref l) => !l.is_empty(),
            _ => false,
        }
    }

    /// Return the stringified type of the value
    pub fn type_string(&self) -> &'static str {
        match *self {
            Value::Number(_) => "number",
            Value::String(_) => "string",
            Value::List(_) => "list",
            Value::Nothing => "nothing",
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Value::Number(x) => x.fmt(fmt),
            Value::String(ref s) => s.fmt(fmt),
            Value::List(ref l) => {
                try!(fmt.pad("["));
                let mut first = true;
                for value in l {
                    if !first { try!(fmt.pad(" ")) };
                    first = false;
                    try!(value.fmt(fmt));
                }
                fmt.pad("]")
            },
            Value::Nothing => fmt.pad("Nothing"),
        }
    }
}

impl<'a> ops::Add for &'a Value {
    type Output = Option<Value>;
    /// Add two values together. Not every pair of values may be
    /// combined. Currently the following operations are supported:
    ///
    /// * Number + Number = Number: normal addition
    /// * String + String = String: string concatenation
    /// * String + Number = String: append stringified Number to String
    /// * List + List = List: list concatenation
    /// * List + Other = List: append to list
    ///
    /// May return None if the types can not be added.
    fn add(self, other: &Value) -> Option<Value> {
        match *self {
            Value::Number(a) => {
                match *other {
                    Value::Number(b) => Some(Value::Number(a + b)),
                    _ => None,
                }
            },

            Value::String(ref a) => {
                match *other {
                    Value::String(ref b) => Some(Value::String(format!("{}{}", a, b))),
                    Value::Number(b) => Some(Value::String(format!("{}{}", a, b))),
                    _ => None,
                }
            },

            Value::List(ref a) => {
                match *other {
                    Value::List(ref b) => Some(Value::List(a.iter().chain(b).cloned().collect())),
                    ref b => Some(Value::List({
                        let mut temp = a.clone();
                        temp.push(b.clone());
                        temp
                    })),
                }
            }

            _ => None,
        }
    }
}

impl<'a> ops::Sub for &'a Value {
    type Output = Option<Value>;
    /// Subtracts the second value from the first. This is currently only
    /// meaningful for a `Number` pair. Every other combination will return
    /// `None`
    fn sub(self, other: &Value) -> Option<Value> {
        match *self {
            Value::Number(a) => {
                match *other {
                    Value::Number(b) => Some(Value::Number(a - b)),
                    _ => None,
                }
            },

            _ => None,
        }
    }
}

impl<'a> ops::Mul for &'a Value {
    type Output = Option<Value>;
    /// Multiply two `Values` together. Multiplication is currently defined for
    ///
    /// * Number * Number = Number: normal multiplication
    /// * String * Number = String: replicate the String n times
    /// * List * Number = List: replicate the List n times
    fn mul(self, other: &Value) -> Option<Value> {
        match *self {
            Value::Number(a) => {
                match *other {
                    Value::Number(b) => Some(Value::Number(a * b)),
                    _ => None,
                }
            },

            Value::String(ref a) => {
                match *other {
                    Value::Number(b) => Some(Value::String({
                        let mut temp = String::new();
                        for _ in (0..b as i32) {
                            temp.push_str(a);
                        }
                        temp
                    })),
                    _ => None,
                }
            },

            Value::List(ref a) => {
                match *other {
                    Value::Number(b) => Some(Value::List({
                        let mut temp = Vec::new();
                        for _ in (0..b as i32) {
                            for elem in a.iter() {
                                temp.push(elem.clone());
                            }
                        }
                        temp
                    })),
                    _ => None,
                }
            },

            _ => None,
        }
    }
}

impl<'a> ops::Div for &'a Value {
    type Output = Option<Value>;
    /// Divide one value by another value. Only defined for a pair of `Number`s
    fn div(self, other: &Value) -> Option<Value> {
        match *self {
            Value::Number(a) => {
                match *other {
                    Value::Number(b) => Some(Value::Number(a / b)),
                    _ => None,
                }
            },

            _ => None,
        }
    }
}