sibil/lexer/src/number.rs

177 lines
4.4 KiB
Rust
Raw Normal View History

2016-12-26 13:58:17 -07:00
/* number.rs
* Eryn Wells <eryn@erynwells.me>
*/
2017-04-30 15:57:16 -07:00
use sibiltypes::Object;
2017-04-30 15:55:50 -07:00
use sibiltypes::number::{Number, Exact};
2017-04-30 15:56:21 -07:00
use char::FromChar;
2016-12-26 13:58:17 -07:00
#[derive(Debug)]
pub enum Radix { Bin, Oct, Dec, Hex }
2017-04-30 15:56:49 -07:00
#[derive(Eq, PartialEq, Debug)]
2016-12-26 18:41:42 -07:00
pub enum Sign { Pos, Neg }
2016-12-26 13:58:17 -07:00
#[derive(Debug)]
pub struct NumberBuilder {
2017-04-30 15:55:50 -07:00
exact: Exact,
2016-12-26 13:58:17 -07:00
radix: Radix,
2016-12-26 18:41:42 -07:00
sign: Sign,
2016-12-26 13:58:17 -07:00
value: f64,
2016-12-26 18:41:42 -07:00
point: u32,
2016-12-26 13:58:17 -07:00
}
impl NumberBuilder {
pub fn new() -> NumberBuilder {
NumberBuilder {
2017-04-30 15:55:50 -07:00
exact: Exact::Yes,
2016-12-26 13:58:17 -07:00
radix: Radix::Dec,
2016-12-26 18:41:42 -07:00
sign: Sign::Pos,
2016-12-26 13:58:17 -07:00
value: 0.0,
point: 0,
2016-12-26 13:58:17 -07:00
}
}
2017-04-30 15:55:50 -07:00
pub fn exact<'a>(&'a mut self, ex: Exact) -> &'a mut NumberBuilder {
self.exact = ex;
2016-12-26 13:58:17 -07:00
self
}
2016-12-26 18:41:42 -07:00
pub fn radix<'a>(&'a mut self, r: Radix) -> &'a mut NumberBuilder {
2016-12-26 13:58:17 -07:00
self.radix = r;
self
}
2016-12-26 18:41:42 -07:00
pub fn sign<'a>(&'a mut self, s: Sign) -> &'a mut NumberBuilder {
self.sign = s;
self
2016-12-26 13:58:17 -07:00
}
pub fn extend_value<'a>(&'a mut self, digit: char) -> &'a mut Self {
if let Some(place) = NumberBuilder::place_value(digit) {
self.value = self.radix.float_value() * self.value + place;
2016-12-26 13:58:17 -07:00
}
else {
// TODO: Indicate an error.
}
self
}
pub fn extend_decimal_value<'a>(&'a mut self, digit: char) -> &'a mut Self {
self.extend_value(digit);
self.point += 1;
self
}
2016-12-26 18:41:42 -07:00
pub fn resolve(&self) -> Number {
// TODO: Convert fields to Number type.
2017-04-30 15:56:32 -07:00
let value = if self.point > 0 { self.value / 10u32.pow(self.point) as f64 } else { self.value };
let value = if self.sign == Sign::Neg { value * -1.0 } else { value };
// TODO: Use an integer if we can.
2017-04-30 15:55:50 -07:00
Number::from_float(value, self.exact)
2016-12-26 18:41:42 -07:00
}
2016-12-26 13:58:17 -07:00
pub fn radix_value(&self) -> u32 {
self.radix.value()
2016-12-26 13:58:17 -07:00
}
fn place_value(digit: char) -> Option<f64> {
match digit {
'0' ... '9' => Some((digit as u32 - '0' as u32) as f64),
2016-12-27 09:52:26 -07:00
'a' ... 'f' => Some((digit as u32 - 'a' as u32 + 10) as f64),
'A' ... 'F' => Some((digit as u32 - 'A' as u32 + 10) as f64),
2016-12-26 13:58:17 -07:00
_ => None,
}
}
}
impl Radix {
pub fn value(&self) -> u32 {
2016-12-26 13:58:17 -07:00
match *self {
Radix::Bin => 2,
Radix::Oct => 8,
Radix::Dec => 10,
Radix::Hex => 16,
2016-12-26 13:58:17 -07:00
}
}
pub fn float_value(&self) -> f64 {
self.value() as f64
}
2016-12-26 13:58:17 -07:00
}
2016-12-26 18:41:42 -07:00
2017-04-30 15:56:21 -07:00
impl FromChar for Radix {
fn from_char(c: char) -> Option<Radix> {
match c {
'b' => Some(Radix::Bin),
'o' => Some(Radix::Oct),
'd' => Some(Radix::Dec),
'h' => Some(Radix::Hex),
_ => None,
}
}
}
impl FromChar for Sign {
fn from_char(c: char) -> Option<Sign> {
match c {
'+' => Some(Sign::Pos),
'-' => Some(Sign::Neg),
_ => None,
}
}
}
2016-12-26 18:41:42 -07:00
2017-04-30 15:56:21 -07:00
impl FromChar for Exact {
fn from_char(c: char) -> Option<Exact> {
2016-12-27 10:08:44 -07:00
match c {
2017-04-30 15:56:21 -07:00
'i' => Some(Exact::No),
'e' => Some(Exact::Yes),
2016-12-27 10:08:44 -07:00
_ => None,
}
}
}
2016-12-26 18:41:42 -07:00
#[cfg(test)]
mod tests {
use sibiltypes::Number;
2016-12-26 18:41:42 -07:00
use super::*;
#[test]
fn builds_integers() {
let mut b = NumberBuilder::new();
b.extend_value('3');
assert_eq!(b.resolve(), Number::from_int(3, true));
2016-12-26 18:41:42 -07:00
b.extend_value('4');
assert_eq!(b.resolve(), Number::from_int(34, true));
2016-12-26 18:41:42 -07:00
}
#[test]
fn builds_negative_integers() {
let num = NumberBuilder::new().sign(Sign::Neg).extend_value('3').resolve();
assert_eq!(num, Number::from_int(-3, true));
2016-12-26 18:41:42 -07:00
}
#[test]
fn builds_pointy_numbers() {
2016-12-26 18:41:42 -07:00
let mut b = NumberBuilder::new();
b.extend_value('5');
assert_eq!(b.resolve(), Number::from_int(5, true));
2016-12-26 18:41:42 -07:00
b.extend_decimal_value('3');
assert_eq!(b.resolve(), Number::from_float(5.3, false));
2016-12-26 18:41:42 -07:00
b.extend_decimal_value('4');
assert_eq!(b.resolve(), Number::from_float(5.34, false));
2016-12-26 18:41:42 -07:00
}
2016-12-27 09:52:26 -07:00
#[test]
fn builds_hex() {
let mut b = NumberBuilder::new();
b.radix(Radix::Hex).extend_value('4');
assert_eq!(b.resolve(), Number::from_int(0x4, true));
2016-12-27 09:52:26 -07:00
b.extend_value('A');
assert_eq!(b.resolve(), Number::from_int(0x4A, true));
2016-12-27 09:52:26 -07:00
b.extend_value('6');
assert_eq!(b.resolve(), Number::from_int(0x4A6, true));
2016-12-27 09:52:26 -07:00
}
2016-12-26 18:41:42 -07:00
}