Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
262c55b91a |
|||
|
704ef81816 |
|||
|
0dc140909f |
|||
|
4dcbc94e0f |
|||
|
442dc5fd91 |
|||
|
431ea5b67e |
3 changed files with 54 additions and 7 deletions
40
src/main.rs
40
src/main.rs
|
|
@ -18,9 +18,47 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("{}", parse_and_calc_humanreadable(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_and_calc_humanreadable(mut input: String) -> String {
|
||||||
|
let should_add_back_equals = if let Some((i, _)) = input
|
||||||
|
.chars()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, c)| !matches!(c, ' ' | '&' | '\n'))
|
||||||
|
.find(|(_, c)| *c == '=')
|
||||||
|
{
|
||||||
|
input.remove(i);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
// no need to remove the character here,
|
||||||
|
// as we ignore the ampersand in all other logic already
|
||||||
|
let should_add_back_alignment = input.contains('&');
|
||||||
|
|
||||||
let result = parse_and_calc(&input);
|
let result = parse_and_calc(&input);
|
||||||
|
|
||||||
println!("{result:.0$}", get_significant_digits(&result));
|
format!(
|
||||||
|
"{0}{result:.1$}",
|
||||||
|
if should_add_back_equals && should_add_back_alignment {
|
||||||
|
"& = "
|
||||||
|
} else if should_add_back_equals {
|
||||||
|
"= "
|
||||||
|
} else if should_add_back_alignment {
|
||||||
|
"& "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
|
get_significant_digits(&result),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_equals_readdition() {
|
||||||
|
assert_eq!(parse_and_calc_humanreadable(" = 11".into()), "= 11");
|
||||||
|
assert_eq!(parse_and_calc_humanreadable(" &= 11".into()), "& = 11");
|
||||||
|
assert_eq!(parse_and_calc_humanreadable(" & 11".into()), "& 11");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_and_calc(s: &str) -> Float {
|
pub fn parse_and_calc(s: &str) -> Float {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ impl TryFrom<char> for Operator {
|
||||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
'+' => Ok(Self::Plus),
|
'+' => Ok(Self::Plus),
|
||||||
'-' => Ok(Self::Minus),
|
'-' | '−' => Ok(Self::Minus),
|
||||||
'*' | '×' => Ok(Self::Mult),
|
'*' | '×' => Ok(Self::Mult),
|
||||||
'/' | '÷' => Ok(Self::Div),
|
'/' | '÷' => Ok(Self::Div),
|
||||||
'^' => Ok(Self::Exp),
|
'^' => Ok(Self::Exp),
|
||||||
|
|
@ -79,11 +79,12 @@ impl FromStr for Nodes {
|
||||||
}
|
}
|
||||||
/// A function to check if the given `char` should be used by the parser.
|
/// A function to check if the given `char` should be used by the parser.
|
||||||
///
|
///
|
||||||
/// We ignore whitespace since it has no semantic significance in typst aside from variables,
|
/// We ignore whitespace since it has no semantic significance in typst
|
||||||
/// (which are not implemented)
|
/// (aside from variables, which are not implemented)
|
||||||
/// and `&` because it is only used for visual alignment.
|
/// and `&` because it is only used for visual alignment.
|
||||||
///
|
///
|
||||||
/// Newlines are also ignored because they're likely accidental; like in the case of `echo 1+1 | tylc`.
|
/// Newlines are also ignored because they're likely accidental;
|
||||||
|
/// like in the case of `echo 1+1 | tylc`.
|
||||||
fn is_not_ignored_char(c: &char) -> bool {
|
fn is_not_ignored_char(c: &char) -> bool {
|
||||||
!matches!(c, ' ' | '&' | '\n')
|
!matches!(c, ' ' | '&' | '\n')
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +113,10 @@ impl FromStr for Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParsingState::ReadingNumber(start_index) => {
|
ParsingState::ReadingNumber(start_index) => {
|
||||||
if !is_number_char(c) {
|
if !is_number_char(c)
|
||||||
|
// don't stop reading number on a special case, eg "1e-1"
|
||||||
|
&& !(filtered_string.chars().nth(i - 1) == Some('e') && c == '-')
|
||||||
|
{
|
||||||
nodes.push(Node::Number(
|
nodes.push(Node::Number(
|
||||||
Float::parse(&filtered_string[start_index..i])
|
Float::parse(&filtered_string[start_index..i])
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|
@ -181,6 +185,6 @@ impl FromStr for Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Nodes(nodes))
|
Ok(Self(nodes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@ use rug::Float;
|
||||||
|
|
||||||
use crate::nodes::{Function, Node, Nodes, Operator, PREC};
|
use crate::nodes::{Function, Node, Nodes, Operator, PREC};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn e_edge_case() {
|
||||||
|
assert_eq!(Nodes::from_str("1e-1").unwrap().evaluate().to_f64(), 0.1)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn implicit_mult() {
|
fn implicit_mult() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue