basic/mach/
val.rs

1use super::Address;
2use crate::error;
3use crate::lang::{Error, LineNumber, MaxValue};
4use std::convert::TryFrom;
5use std::rc::Rc;
6
7/// ## Runtime values for stack and variables
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum Val {
11    String(Rc<str>),
12    Single(f32),
13    Double(f64),
14    Integer(i16),
15    Return(Address),
16    Next(Address),
17}
18
19impl std::fmt::Display for Val {
20    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
21        use Val::*;
22        let mut s = match self {
23            String(s) => return write!(f, "{}", s),
24            Integer(num) => format!("{}", num),
25            Single(num) => {
26                let s = format!("{}", num);
27                if s.chars().filter(char::is_ascii_digit).count() > 9 {
28                    format!("{:E}", num)
29                } else {
30                    format!("{}", num)
31                }
32            }
33            Double(num) => {
34                let s = format!("{}", num);
35                if s.chars().filter(char::is_ascii_digit).count() > 17 {
36                    format!("{:E}", num)
37                } else {
38                    format!("{}", num)
39                }
40            }
41            Return(..) | Next(..) => {
42                debug_assert!(false);
43                return write!(f, "");
44            }
45        };
46        if !s.starts_with('-') {
47            s.insert(0, ' ');
48        }
49        write!(f, "{}", s)
50    }
51}
52
53impl TryFrom<LineNumber> for Val {
54    type Error = Error;
55    fn try_from(line_number: LineNumber) -> std::result::Result<Self, Self::Error> {
56        match line_number {
57            Some(num) => Ok(Val::Single(num as f32)),
58            None => Err(error!(UndefinedLine)),
59        }
60    }
61}
62
63impl TryFrom<Val> for LineNumber {
64    type Error = Error;
65    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
66        let num = u16::try_from(val)?;
67        if num <= LineNumber::max_value() {
68            Ok(Some(num))
69        } else {
70            Err(error!(UndefinedLine))
71        }
72    }
73}
74
75impl TryFrom<Val> for u16 {
76    type Error = Error;
77    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
78        match val {
79            Val::Integer(num) => {
80                if num >= 0 {
81                    Ok(num as u16)
82                } else {
83                    Err(error!(Overflow))
84                }
85            }
86            Val::Single(num) => {
87                let num = num.floor();
88                if num >= 0.0 && num <= u16::max_value() as f32 {
89                    Ok(num as u16)
90                } else {
91                    Err(error!(Overflow))
92                }
93            }
94            Val::Double(num) => {
95                let num = num.floor();
96                if num >= 0.0 && num <= u16::max_value() as f64 {
97                    Ok(num as u16)
98                } else {
99                    Err(error!(Overflow))
100                }
101            }
102            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
103        }
104    }
105}
106
107impl TryFrom<Val> for i16 {
108    type Error = Error;
109    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
110        match val {
111            Val::Integer(num) => Ok(num),
112            Val::Single(num) => {
113                let num = num.floor();
114                if num >= i16::min_value() as f32 && num <= i16::max_value() as f32 {
115                    Ok(num as i16)
116                } else {
117                    Err(error!(Overflow))
118                }
119            }
120            Val::Double(num) => {
121                let num = num.floor();
122                if num >= i16::min_value() as f64 && num <= i16::max_value() as f64 {
123                    Ok(num as i16)
124                } else {
125                    Err(error!(Overflow))
126                }
127            }
128            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
129        }
130    }
131}
132
133impl TryFrom<Val> for u32 {
134    type Error = Error;
135    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
136        match val {
137            Val::Integer(num) => {
138                if num >= 0 {
139                    Ok(num as u32)
140                } else {
141                    Err(error!(Overflow))
142                }
143            }
144            Val::Single(num) => {
145                let num = num.floor();
146                if num >= 0.0 && num <= u32::max_value() as f32 {
147                    Ok(num as u32)
148                } else {
149                    Err(error!(Overflow))
150                }
151            }
152            Val::Double(num) => {
153                let num = num.floor();
154                if num >= 0.0 && num <= u32::max_value() as f64 {
155                    Ok(num as u32)
156                } else {
157                    Err(error!(Overflow))
158                }
159            }
160            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
161        }
162    }
163}
164
165impl TryFrom<Val> for usize {
166    type Error = Error;
167    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
168        match val {
169            Val::Integer(num) => {
170                if num >= 0 {
171                    Ok(num as usize)
172                } else {
173                    Err(error!(Overflow))
174                }
175            }
176            Val::Single(num) => {
177                let num = num.floor();
178                if num >= 0.0 && num <= usize::max_value() as f32 {
179                    Ok(num as usize)
180                } else {
181                    Err(error!(Overflow))
182                }
183            }
184            Val::Double(num) => {
185                let num = num.floor();
186                if num >= 0.0 && num <= usize::max_value() as f64 {
187                    Ok(num as usize)
188                } else {
189                    Err(error!(Overflow))
190                }
191            }
192            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
193        }
194    }
195}
196
197impl TryFrom<Val> for f32 {
198    type Error = Error;
199    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
200        match val {
201            Val::Integer(num) => Ok(num as f32),
202            Val::Single(num) => Ok(num),
203            Val::Double(num) => Ok(num as f32),
204            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
205        }
206    }
207}
208
209impl TryFrom<Val> for f64 {
210    type Error = Error;
211    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
212        match val {
213            Val::Integer(num) => Ok(num as f64),
214            Val::Single(num) => Ok(num as f64),
215            Val::Double(num) => Ok(num),
216            Val::String(_) | Val::Return(_) | Val::Next(..) => Err(error!(TypeMismatch)),
217        }
218    }
219}
220
221impl TryFrom<Val> for Rc<str> {
222    type Error = Error;
223    fn try_from(val: Val) -> std::result::Result<Self, Self::Error> {
224        match val {
225            Val::String(s) => Ok(s),
226            _ => Err(error!(TypeMismatch)),
227        }
228    }
229}
230
231impl From<&str> for Val {
232    fn from(string: &str) -> Self {
233        if string.starts_with('&') {
234            let string = &string[1..];
235            if string.starts_with('H') || string.starts_with('h') {
236                if let Ok(num) = i16::from_str_radix(&string[1..], 16) {
237                    return Val::Integer(num);
238                }
239            } else if let Ok(num) = i16::from_str_radix(&string, 8) {
240                return Val::Integer(num);
241            }
242        }
243        let mut s = String::from(string).replace("D", "E").replace("d", "e");
244        match s.chars().last() {
245            Some('!') | Some('#') | Some('%') => {
246                s.pop();
247            }
248            _ => {}
249        };
250        if let Ok(num) = s.parse::<f64>() {
251            Val::Double(num)
252        } else {
253            Val::String(string.into())
254        }
255    }
256}
257
258impl TryFrom<usize> for Val {
259    type Error = Error;
260    fn try_from(num: usize) -> std::result::Result<Self, Self::Error> {
261        match i16::try_from(num) {
262            Ok(len) => Ok(Val::Integer(len)),
263            Err(_) => {
264                debug_assert!(false, "LEN VAL TOO BIG");
265                Err(error!(Overflow))
266            }
267        }
268    }
269}