mirror of https://github.com/rm-dr/daisy
Added support for scientific notation
parent
52a508cd98
commit
85a669e126
|
@ -176,6 +176,13 @@ fn main() -> Result<(), std::io::Error> {
|
|||
// Tests to add:
|
||||
// 3!+1
|
||||
// 3!3
|
||||
// 1e2
|
||||
// 1e-2
|
||||
// 1e0
|
||||
// 1e1.2
|
||||
// 1e(2)
|
||||
// e2e
|
||||
// 2 2e2
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -31,6 +31,24 @@ fn push_token(g: &mut VecDeque<PreToken>, t: Option<PreToken>, stop_i: usize) {
|
|||
};
|
||||
|
||||
|
||||
// `2e` isn't exponential notation, it's 2*e.
|
||||
// If a number ends in `e`, disconnect the `e` and make it a word.
|
||||
if let PreToken::PreNumber(l, s) = &t {
|
||||
let last = &s[s.len()-1..];
|
||||
if last == "e" {
|
||||
g.push_back(PreToken::PreNumber(
|
||||
LineLocation { pos: l.pos, len: l.len-1 },
|
||||
String::from(&s[0..s.len()-1])
|
||||
));
|
||||
g.push_back(PreToken::PreWord(
|
||||
LineLocation { pos: l.pos + l.len - 1, len: 1 },
|
||||
String::from("e")
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let PreToken::PreWord(l, s) = &t {
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_some() {
|
||||
|
@ -68,14 +86,50 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
};
|
||||
},
|
||||
|
||||
// The minus sign can be both a Negative and an Operator.
|
||||
// Needs special treatment, always starts a new token.
|
||||
// 'e' needs special treatment.
|
||||
// Can be both a word or a number.
|
||||
'e' => {
|
||||
match &mut t {
|
||||
Some(PreToken::PreWord(_, val)) => { val.push(c); },
|
||||
Some(PreToken::PreNumber(_, val)) => { val.push(c); },
|
||||
|
||||
_ => {
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreWord(LineLocation{pos: i, len: 0}, String::from(c)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The minus sign also needs special treatment.
|
||||
// It can be the `neg` operator, the `minus` operator,
|
||||
// or it can specify a negative exponent.
|
||||
'-' => {
|
||||
match &mut t {
|
||||
Some(PreToken::PreNumber(_, val)) => {
|
||||
if &val[val.len()-1..] == "e" {
|
||||
// If the current number ends in an `e`,
|
||||
// this negative specifies a negative exponent
|
||||
// like 2e-2 = 0.02.
|
||||
val.push(c);
|
||||
} else {
|
||||
// Otherwise, end the number.
|
||||
// We probably have a subtraction.
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreOperator(
|
||||
LineLocation{pos: i, len: 1},
|
||||
String::from("-")
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreOperator(
|
||||
LineLocation{pos: i, len: 1},
|
||||
String::from("-")
|
||||
));
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// Operator
|
||||
|
|
|
@ -137,20 +137,48 @@ impl Quantity {
|
|||
|
||||
pub fn new_rational_from_float_string(s: &str) -> Option<Quantity> {
|
||||
|
||||
let mut q = s.split(".");
|
||||
let a = q.next().unwrap();
|
||||
let b = q.next();
|
||||
// Scientific notation
|
||||
let mut sci = s.split("e");
|
||||
let num = sci.next().unwrap();
|
||||
let exp = sci.next();
|
||||
|
||||
let exp = if exp.is_some() {
|
||||
let r = exp.unwrap().parse::<isize>();
|
||||
match r {
|
||||
Ok(x) => x,
|
||||
Err(_) => return None
|
||||
}
|
||||
} else {0isize};
|
||||
|
||||
// Split integer and decimal parts
|
||||
let mut dec = num.split(".");
|
||||
let a = dec.next().unwrap();
|
||||
let b = dec.next();
|
||||
let b = if b.is_some() {b.unwrap()} else {""};
|
||||
|
||||
// Error conditions
|
||||
if {
|
||||
q.next().is_some() || // We should have at most one `.`
|
||||
dec.next().is_some() || // We should have at most one `.`
|
||||
sci.next().is_some() || // We should have at most one `e`
|
||||
a.len() == 0 // We need something in the numerator
|
||||
} { return None; }
|
||||
|
||||
return Some(Quantity::new_rational_from_string(
|
||||
&format!("{a}{b}/1{}", "0".repeat(b.len()))
|
||||
));
|
||||
let s: String;
|
||||
if exp < 0 {
|
||||
let exp: usize = (-exp).try_into().unwrap();
|
||||
s = format!("{a}{b}/1{}", "0".repeat(b.len() + exp));
|
||||
} else if exp > 0 {
|
||||
let exp: usize = exp.try_into().unwrap();
|
||||
s = format!(
|
||||
"{a}{b}{}/1{}",
|
||||
"0".repeat(exp),
|
||||
"0".repeat(b.len())
|
||||
);
|
||||
} else { // exp == 0
|
||||
s = format!("{a}{b}/1{}", "0".repeat(b.len()));
|
||||
};
|
||||
|
||||
return Quantity::new_rational_from_string(&s);
|
||||
}
|
||||
|
||||
pub fn to_float(&self) -> Float {
|
||||
|
|
Loading…
Reference in New Issue