Remove degrees keyword
This commit is contained in:
parent
0dcd13f775
commit
be51ec4ff0
@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Next
|
||||||
|
- Remove the `degrees` keyword which referred to `celcius` by default
|
||||||
|
- Remove the `default_degrees` argument from `eval()` and `lex()`. Not necessary now that the `degrees` keyword is removed
|
||||||
|
|
||||||
## 1.9.3 - 2023 sep 20
|
## 1.9.3 - 2023 sep 20
|
||||||
- Fix negative unary `-` always having higher precedence than `^`. This resulted in `-3^2` returning `9` instead of `-9`
|
- Fix negative unary `-` always having higher precedence than `^`. This resulted in `-3^2` returning `9` instead of `-9`
|
||||||
|
|
||||||
|
|||||||
16
src/lexer.rs
16
src/lexer.rs
@ -9,7 +9,6 @@ use crate::NamedNumber::*;
|
|||||||
use crate::Constant::{E, Pi};
|
use crate::Constant::{E, Pi};
|
||||||
use crate::LexerKeyword::{In, PercentChar, Per, Mercury, Hg, PoundForce, Force, DoubleQuotes, Revolution};
|
use crate::LexerKeyword::{In, PercentChar, Per, Mercury, Hg, PoundForce, Force, DoubleQuotes, Revolution};
|
||||||
use crate::FunctionIdentifier::{Cbrt, Ceil, Cos, Exp, Abs, Floor, Ln, Log, Round, Sin, Sqrt, Tan};
|
use crate::FunctionIdentifier::{Cbrt, Ceil, Cos, Exp, Abs, Floor, Ln, Log, Round, Sin, Sqrt, Tan};
|
||||||
use crate::units::Unit;
|
|
||||||
use crate::units::Unit::*;
|
use crate::units::Unit::*;
|
||||||
use unicode_segmentation::{Graphemes, UnicodeSegmentation};
|
use unicode_segmentation::{Graphemes, UnicodeSegmentation};
|
||||||
|
|
||||||
@ -595,7 +594,6 @@ fn parse_word(word: &str, lexer: &mut Lexer) -> Result<(), String> {
|
|||||||
"k" | "kelvin" | "kelvins" => Token::Unit(Kelvin),
|
"k" | "kelvin" | "kelvins" => Token::Unit(Kelvin),
|
||||||
"c" | "celsius" => Token::Unit(Celsius),
|
"c" | "celsius" => Token::Unit(Celsius),
|
||||||
"f" | "fahrenheit" | "fahrenheits" => Token::Unit(Fahrenheit),
|
"f" | "fahrenheit" | "fahrenheits" => Token::Unit(Fahrenheit),
|
||||||
"deg" | "degree" | "degrees" => Token::Unit(lexer.default_degree),
|
|
||||||
|
|
||||||
string => {
|
string => {
|
||||||
return Err(format!("Invalid string: {}", string));
|
return Err(format!("Invalid string: {}", string));
|
||||||
@ -610,11 +608,10 @@ struct Lexer<'a> {
|
|||||||
right_paren_count: u16,
|
right_paren_count: u16,
|
||||||
chars: Peekable<Graphemes<'a>>,
|
chars: Peekable<Graphemes<'a>>,
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
default_degree: Unit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lex an input string and returns [`Token`]s
|
/// Lex an input string and returns [`Token`]s
|
||||||
pub fn lex(input: &str, remove_trailing_operator: bool, default_degree: Unit) -> Result<Vec<Token>, String> {
|
pub fn lex(input: &str, remove_trailing_operator: bool) -> Result<Vec<Token>, String> {
|
||||||
let mut input = input.replace(',', "").to_ascii_lowercase();
|
let mut input = input.replace(',', "").to_ascii_lowercase();
|
||||||
|
|
||||||
if remove_trailing_operator {
|
if remove_trailing_operator {
|
||||||
@ -631,7 +628,6 @@ pub fn lex(input: &str, remove_trailing_operator: bool, default_degree: Unit) ->
|
|||||||
right_paren_count: 0,
|
right_paren_count: 0,
|
||||||
chars: UnicodeSegmentation::graphemes(input.as_str(), true).peekable(),
|
chars: UnicodeSegmentation::graphemes(input.as_str(), true).peekable(),
|
||||||
tokens: Vec::new(),
|
tokens: Vec::new(),
|
||||||
default_degree,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(c) = lexer.chars.next() {
|
while let Some(c) = lexer.chars.next() {
|
||||||
@ -945,7 +941,7 @@ mod tests {
|
|||||||
let nonplural_data_units = Regex::new(r"(bit|byte)s").unwrap();
|
let nonplural_data_units = Regex::new(r"(bit|byte)s").unwrap();
|
||||||
|
|
||||||
let run_lex = |input: &str, expected_tokens: Vec<Token>| {
|
let run_lex = |input: &str, expected_tokens: Vec<Token>| {
|
||||||
let tokens = match lex(input, false, Unit::Celsius) {
|
let tokens = match lex(input, false) {
|
||||||
Ok(tokens) => tokens,
|
Ok(tokens) => tokens,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("lex error: {}\nrun_lex input: {}", e, input);
|
panic!("lex error: {}\nrun_lex input: {}", e, input);
|
||||||
@ -956,17 +952,17 @@ mod tests {
|
|||||||
|
|
||||||
// Prove we can handle multiple spaces wherever we handle a single space
|
// Prove we can handle multiple spaces wherever we handle a single space
|
||||||
let input_extra_spaces = input.replace(" ", " ");
|
let input_extra_spaces = input.replace(" ", " ");
|
||||||
let tokens_extra_spaces = lex(&input_extra_spaces, false, Unit::Celsius).unwrap();
|
let tokens_extra_spaces = lex(&input_extra_spaces, false).unwrap();
|
||||||
assert!(tokens_extra_spaces == expected_tokens, "{info_msg}");
|
assert!(tokens_extra_spaces == expected_tokens, "{info_msg}");
|
||||||
|
|
||||||
// Prove we don't need spaces around operators
|
// Prove we don't need spaces around operators
|
||||||
let input_stripped_spaces = strip_operator_spacing.replace_all(input, "$1");
|
let input_stripped_spaces = strip_operator_spacing.replace_all(input, "$1");
|
||||||
let tokens_stripped_spaces = lex(&input_stripped_spaces, false, Unit::Celsius).unwrap();
|
let tokens_stripped_spaces = lex(&input_stripped_spaces, false).unwrap();
|
||||||
assert!(tokens_stripped_spaces == expected_tokens, "{info_msg}");
|
assert!(tokens_stripped_spaces == expected_tokens, "{info_msg}");
|
||||||
|
|
||||||
// Prove we don't need a space after a digit
|
// Prove we don't need a space after a digit
|
||||||
let input_afterdigit_stripped_spaces = strip_afterdigit_spacing.replace_all(input, "$1");
|
let input_afterdigit_stripped_spaces = strip_afterdigit_spacing.replace_all(input, "$1");
|
||||||
let tokens_afterdigit_stripped_spaces = lex(&input_afterdigit_stripped_spaces, false, Unit::Celsius).unwrap();
|
let tokens_afterdigit_stripped_spaces = lex(&input_afterdigit_stripped_spaces, false).unwrap();
|
||||||
assert!(tokens_afterdigit_stripped_spaces == expected_tokens, "{info_msg}");
|
assert!(tokens_afterdigit_stripped_spaces == expected_tokens, "{info_msg}");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -975,7 +971,7 @@ mod tests {
|
|||||||
|
|
||||||
// Prove plural and non-plural data units behave identically
|
// Prove plural and non-plural data units behave identically
|
||||||
let input_nonplural_units = nonplural_data_units.replace_all(input, "$1");
|
let input_nonplural_units = nonplural_data_units.replace_all(input, "$1");
|
||||||
let tokens_nonplural_units = lex(&input_nonplural_units, false, Unit::Celsius).unwrap();
|
let tokens_nonplural_units = lex(&input_nonplural_units, false).unwrap();
|
||||||
let info_msg = format!("run_datarate_lex input: {}\nexpected: {:?}\nreceived: {:?}", input, expected_tokens, tokens_nonplural_units);
|
let info_msg = format!("run_datarate_lex input: {}\nexpected: {:?}\nreceived: {:?}", input, expected_tokens, tokens_nonplural_units);
|
||||||
assert!(tokens_nonplural_units == expected_tokens, "{info_msg}");
|
assert!(tokens_nonplural_units == expected_tokens, "{info_msg}");
|
||||||
};
|
};
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
//! use cpc::eval;
|
//! use cpc::eval;
|
||||||
//! use cpc::units::Unit;
|
//! use cpc::units::Unit;
|
||||||
//!
|
//!
|
||||||
//! match eval("3m + 1cm", true, Unit::Celsius, false) {
|
//! match eval("3m + 1cm", true, false) {
|
||||||
//! Ok(answer) => {
|
//! Ok(answer) => {
|
||||||
//! // answer: Number { value: 301, unit: Unit::Centimeter }
|
//! // answer: Number { value: 301, unit: Unit::Centimeter }
|
||||||
//! println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
//! println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
||||||
@ -230,7 +230,7 @@ macro_rules! numtok {
|
|||||||
/// use cpc::eval;
|
/// use cpc::eval;
|
||||||
/// use cpc::units::Unit;
|
/// use cpc::units::Unit;
|
||||||
///
|
///
|
||||||
/// match eval("3m + 1cm", true, Unit::Celsius, false) {
|
/// match eval("3m + 1cm", true, false) {
|
||||||
/// Ok(answer) => {
|
/// Ok(answer) => {
|
||||||
/// // answer: Number { value: 301, unit: Unit::Centimeter }
|
/// // answer: Number { value: 301, unit: Unit::Centimeter }
|
||||||
/// println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
/// println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
||||||
@ -243,12 +243,11 @@ macro_rules! numtok {
|
|||||||
pub fn eval(
|
pub fn eval(
|
||||||
input: &str,
|
input: &str,
|
||||||
allow_trailing_operators: bool,
|
allow_trailing_operators: bool,
|
||||||
default_degree: Unit,
|
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
) -> Result<Number, String> {
|
) -> Result<Number, String> {
|
||||||
let lex_start = Instant::now();
|
let lex_start = Instant::now();
|
||||||
|
|
||||||
match lexer::lex(input, allow_trailing_operators, default_degree) {
|
match lexer::lex(input, allow_trailing_operators) {
|
||||||
Ok(tokens) => {
|
Ok(tokens) => {
|
||||||
let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32;
|
let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32;
|
||||||
if verbose {
|
if verbose {
|
||||||
@ -296,7 +295,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn default_eval(input: &str) -> Number {
|
fn default_eval(input: &str) -> Number {
|
||||||
eval(input, true, units::Unit::Celsius, false).unwrap()
|
eval(input, true, false).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use cpc::eval;
|
use cpc::eval;
|
||||||
use cpc::units::Unit;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match eval(&expression, true, Unit::Celsius, verbose) {
|
match eval(&expression, true, verbose) {
|
||||||
Ok(answer) => {
|
Ok(answer) => {
|
||||||
if !verbose {
|
if !verbose {
|
||||||
println!("{answer}");
|
println!("{answer}");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user