use crate::Constant::*;
use crate::FunctionIdentifier::*;
use crate::LexerKeyword::*;
use crate::NamedNumber::*;
use crate::Operator::*;
use crate::TextOperator::*;
use crate::Token;
use crate::UnaryOperator::*;
use crate::currency::currency_code_to_unit;
use crate::units::Unit::*;
use fastnum::D128;
use fastnum::decimal::Context;
use std::iter::Peekable;
use unicode_segmentation::{GraphemeIndices, UnicodeSegmentation};
fn is_word_char_str(input: &str) -> bool {
match input {
"A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O"
| "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" => true,
"a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o"
| "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" => true,
"Ω" | "Ω" | "µ" | "μ" => true,
_ => false,
}
}
fn is_numeric_str(input: &str) -> bool {
matches!(
input,
"." | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
)
}
fn read_immediate_grapheme(infix: &str, lexer: &mut Lexer) -> bool {
if let Some((_i, grapheme)) = lexer.graphemes.peek() {
if *grapheme == infix {
lexer.graphemes.next();
return true;
}
}
false
}
fn read_immediate_word(lexer: &mut Lexer) -> String {
let graphemes = &mut lexer.graphemes;
let mut word = String::new();
while let Some((_i, grapheme)) = graphemes.peek() {
if is_word_char_str(grapheme) {
word += graphemes.next().unwrap().1;
} else {
break;
}
}
word
}
fn read_word(lexer: &mut Lexer) -> String {
let graphemes = &mut lexer.graphemes;
while let Some((_i, grapheme)) = graphemes.peek() {
if grapheme.trim_start().is_empty() {
graphemes.next();
} else {
break;
}
}
let mut word = "".to_string();
while let Some((_i, grapheme)) = graphemes.peek() {
if is_word_char_str(grapheme) {
word += graphemes.next().unwrap().1;
} else {
break;
}
}
if !word.is_empty() {
match *graphemes.peek().map(|(_i, g)| g).unwrap_or(&"") {
"2" | "²" => {
word += "2";
graphemes.next();
}
"3" | "³" => {
word += "3";
graphemes.next();
}
_ => {}
}
}
word
}
fn lex_token(lexer: &mut Lexer) -> Result<(), String> {
let (start_i, first_grapheme) = match lexer.graphemes.peek() {
Some(c) => *c,
None => return Ok(()),
};
let token = match first_grapheme.to_ascii_lowercase().as_str() {
grapheme if grapheme.trim_start().is_empty() => {
lexer.graphemes.next();
return Ok(());
}
grapheme if is_word_char_str(grapheme) => {
lex_word(read_word(lexer).as_str(), lexer)?;
return Ok(());
}
grapheme if is_numeric_str(grapheme) => {
let mut end_i = start_i + grapheme.len();
lexer.graphemes.next();
while let Some((_, grapheme)) = lexer.graphemes.peek() {
if is_numeric_str(grapheme) {
end_i += grapheme.len();
lexer.graphemes.next();
} else {
break;
}
}
let number_string = &lexer.input[start_i..end_i];
let token = match D128::from_str(&number_string, Context::default()) {
Ok(number) => Token::Number(number),
Err(_e) => {
return Err(format!("Error lexing d128 number: {}", number_string));
}
};
lexer.tokens.push(token);
return Ok(());
}
"+" => Token::Operator(Plus),
"-" => Token::Operator(Minus),
"*" => Token::Operator(Multiply),
"/" | "÷" => Token::Operator(Divide),
"%" => Token::LexerKeyword(PercentChar),
"^" => Token::Operator(Caret),
"!" => Token::UnaryOperator(Factorial),
"(" => {
lexer.left_paren_count += 1;
Token::Operator(LeftParen)
}
")" => {
lexer.right_paren_count += 1;
Token::Operator(RightParen)
}
"π" => Token::Constant(Pi),
"'" => Token::unit(Foot),
"\"" | "“" | "”" | "″" => Token::LexerKeyword(DoubleQuotes),
grapheme => {
return Err(format!("Invalid character: {}", grapheme));
}
};
lexer.graphemes.next();
lexer.tokens.push(token);
Ok(())
}
fn lex_word_if_non_empty(word: &str, lexer: &mut Lexer) -> Result<(), String> {
match word {
"" => Ok(()),
_ => lex_word(word, lexer),
}
}
fn lex_word(word: &str, lexer: &mut Lexer) -> Result<(), String> {
let token = match word.to_ascii_lowercase().as_str() {
"to" => Token::TextOperator(To),
"of" => Token::TextOperator(Of),
"hundred" => Token::NamedNumber(Hundred),
"thousand" => Token::NamedNumber(Thousand),
"mil" | "mill" | "million" => Token::NamedNumber(Million),
"bil" | "bill" | "billion" => Token::NamedNumber(Billion),
"tri" | "tril" | "trillion" => Token::NamedNumber(Trillion),
"quadrillion" => Token::NamedNumber(Quadrillion),
"quintillion" => Token::NamedNumber(Quintillion),
"sextillion" => Token::NamedNumber(Sextillion),
"septillion" => Token::NamedNumber(Septillion),
"octillion" => Token::NamedNumber(Octillion),
"nonillion" => Token::NamedNumber(Nonillion),
"decillion" => Token::NamedNumber(Decillion),
"undecillion" => Token::NamedNumber(Undecillion),
"duodecillion" => Token::NamedNumber(Duodecillion),
"tredecillion" => Token::NamedNumber(Tredecillion),
"quattuordecillion" => Token::NamedNumber(Quattuordecillion),
"quindecillion" => Token::NamedNumber(Quindecillion),
"sexdecillion" => Token::NamedNumber(Sexdecillion),
"septendecillion" => Token::NamedNumber(Septendecillion),
"octodecillion" => Token::NamedNumber(Octodecillion),
"novemdecillion" => Token::NamedNumber(Novemdecillion),
"vigintillion" => Token::NamedNumber(Vigintillion),
"centillion" => Token::NamedNumber(Centillion),
"googol" => Token::NamedNumber(Googol),
"pi" => Token::Constant(Pi),
"e" => Token::Constant(E),
"plus" => Token::Operator(Plus),
"minus" => Token::Operator(Minus),
"times" => Token::Operator(Multiply),
"multiplied" => match read_word(lexer).as_str() {
"by" => Token::Operator(Multiply),
string => return Err(format!("Invalid string: {}", string)),
},
"divided" => match read_word(lexer).as_str() {
"by" => Token::Operator(Divide),
string => return Err(format!("Invalid string: {}", string)),
},
"mod" => Token::Operator(Modulo),
"sqrt" => Token::FunctionIdentifier(Sqrt),
"cbrt" => Token::FunctionIdentifier(Cbrt),
"log" => Token::FunctionIdentifier(Log),
"ln" => Token::FunctionIdentifier(Ln),
"exp" => Token::FunctionIdentifier(Exp),
"round" | "rint" => Token::FunctionIdentifier(Round),
"ceil" => Token::FunctionIdentifier(Ceil),
"floor" => Token::FunctionIdentifier(Floor),
"abs" | "fabs" => Token::FunctionIdentifier(Abs),
"sin" => Token::FunctionIdentifier(Sin),
"cos" => Token::FunctionIdentifier(Cos),
"tan" => Token::FunctionIdentifier(Tan),
"per" => Token::TextOperator(Per),
"hg" => Token::LexerKeyword(Hg),
"ns" | "nanosec" | "nanosecs" | "nanosecond" | "nanoseconds" => Token::unit(Nanosecond),
"µs" | "μs" | "microsec" | "microsecs" | "microsecond" | "microseconds" => {
Token::unit(Microsecond)
}
"ms" | "millisec" | "millisecs" | "millisecond" | "milliseconds" => {
Token::unit(Millisecond)
}
"s" | "sec" | "secs" | "second" | "seconds" => Token::unit(Second),
"min" | "mins" | "minute" | "minutes" => Token::unit(Minute),
"h" | "hr" | "hrs" | "hour" | "hours" => Token::unit(Hour),
"day" | "days" => Token::unit(Day),
"wk" | "wks" | "week" | "weeks" => Token::unit(Week),
"mo" | "mos" | "month" | "months" => Token::unit(Month),
"q" | "quarter" | "quarters" => Token::unit(Quarter),
"yr" | "yrs" | "year" | "years" => Token::unit(Year),
"decade" | "decades" => Token::unit(Decade),
"century" | "centuries" => Token::unit(Century),
"millenium" | "millenia" | "milleniums" => Token::unit(Millennium),
"mm" | "millimeter" | "millimeters" | "millimetre" | "millimetres" => {
Token::unit(Millimeter)
}
"cm" | "centimeter" | "centimeters" | "centimetre" | "centimetres" => {
Token::unit(Centimeter)
}
"dm" | "decimeter" | "decimeters" | "decimetre" | "decimetres" => Token::unit(Decimeter),
"m" | "meter" | "meters" | "metre" | "metres" => Token::unit(Meter),
"km" | "kilometer" | "kilometers" | "kilometre" | "kilometres" => Token::unit(Kilometer),
"in" => Token::LexerKeyword(In),
"inch" | "inches" => Token::unit(Inch),
"ft" | "foot" | "feet" => Token::unit(Foot),
"yd" | "yard" | "yards" => Token::unit(Yard),
"mi" | "mile" | "miles" => Token::unit(Mile),
"marathon" | "marathons" => Token::unit(Marathon),
"nmi" => Token::unit(NauticalMile),
"nautical" => match read_word(lexer).as_str() {
"mile" | "miles" => Token::unit(NauticalMile),
string => return Err(format!("Invalid string: {}", string)),
},
"ly" | "lightyear" | "lightyears" => Token::unit(LightYear),
"lightsec" | "lightsecs" | "lightsecond" | "lightseconds" => Token::unit(LightSecond),
"light" => match read_word(lexer).as_str() {
"yr" | "yrs" | "year" | "years" => Token::unit(LightYear),
"sec" | "secs" | "second" | "seconds" => Token::unit(LightSecond),
string => return Err(format!("Invalid string: {}", string)),
},
"sqmm" | "mm2" | "millimeter2" | "millimeters2" | "millimetre2" | "millimetres2" => {
Token::unit(SquareMillimeter)
}
"sqcm" | "cm2" | "centimeter2" | "centimeters2" | "centimetre2" | "centimetres2" => {
Token::unit(SquareCentimeter)
}
"sqdm" | "dm2" | "decimeter2" | "decimeters2" | "decimetre2" | "decimetres2" => {
Token::unit(SquareDecimeter)
}
"sqm" | "m2" | "meter2" | "meters2" | "metre2" | "metres2" => Token::unit(SquareMeter),
"sqkm" | "km2" | "kilometer2" | "kilometers2" | "kilometre2" | "kilometres2" => {
Token::unit(SquareKilometer)
}
"sqin" | "in2" | "inch2" | "inches2" => Token::unit(SquareInch),
"sqft" | "ft2" | "foot2" | "feet2" => Token::unit(SquareFoot),
"sqyd" | "yd2" | "yard2" | "yards2" => Token::unit(SquareYard),
"sqmi" | "mi2" | "mile2" | "miles2" => Token::unit(SquareMile),
"sq" | "square" => match read_word(lexer).as_str() {
"mm" | "millimeter" | "millimeters" | "millimetre" | "millimetres" => {
Token::unit(SquareMillimeter)
}
"cm" | "centimeter" | "centimeters" | "centimetre" | "centimetres" => {
Token::unit(SquareCentimeter)
}
"dm" | "decimeter" | "decimeters" | "decimetre" | "decimetres" => {
Token::unit(SquareDecimeter)
}
"m" | "meter" | "meters" | "metre" | "metres" => Token::unit(SquareMeter),
"km" | "kilometer" | "kilometers" | "kilometre" | "kilometres" => {
Token::unit(SquareKilometer)
}
"in" | "inch" | "inches" => Token::unit(SquareInch),
"ft" | "foot" | "feet" => Token::unit(SquareFoot),
"yd" | "yard" | "yards" => Token::unit(SquareYard),
"mi" | "mile" | "miles" => Token::unit(SquareMile),
string => return Err(format!("Invalid string: {}", string)),
},
"are" | "ares" => Token::unit(Are),
"decare" | "decares" => Token::unit(Decare),
"ha" | "hectare" | "hectares" => Token::unit(Hectare),
"acre" | "acres" => Token::unit(Acre),
"mm3" | "millimeter3" | "millimeters3" | "millimetre3" | "millimetres3" => {
Token::unit(CubicMillimeter)
}
"cm3" | "centimeter3" | "centimeters3" | "centimetre3" | "centimetres3" => {
Token::unit(CubicCentimeter)
}
"dm3" | "decimeter3" | "decimeters3" | "decimetre3" | "decimetres3" => {
Token::unit(CubicDecimeter)
}
"m3" | "meter3" | "meters3" | "metre3" | "metres3" => Token::unit(CubicMeter),
"km3" | "kilometer3" | "kilometers3" | "kilometre3" | "kilometres3" => {
Token::unit(CubicKilometer)
}
"inc3" | "inch3" | "inches3" => Token::unit(CubicInch),
"ft3" | "foot3" | "feet3" => Token::unit(CubicFoot),
"yd3" | "yard3" | "yards3" => Token::unit(CubicYard),
"mi3" | "mile3" | "miles3" => Token::unit(CubicMile),
"cubic" => match read_word(lexer).as_str() {
"mm" | "millimeter" | "millimeters" | "millimetre" | "millimetres" => {
Token::unit(CubicMillimeter)
}
"cm" | "centimeter" | "centimeters" | "centimetre" | "centimetres" => {
Token::unit(CubicCentimeter)
}
"dm" | "decimeter" | "decimeters" | "decimetre" | "decimetres" => {
Token::unit(CubicDecimeter)
}
"m" | "meter" | "meters" | "metre" | "metres" => Token::unit(CubicMeter),
"km" | "kilometer" | "kilometers" | "kilometre" | "kilometres" => {
Token::unit(CubicKilometer)
}
"in" | "inch" | "inches" => Token::unit(CubicInch),
"ft" | "foot" | "feet" => Token::unit(CubicFoot),
"yd" | "yard" | "yards" => Token::unit(CubicYard),
"mi" | "mile" | "miles" => Token::unit(CubicMile),
string => return Err(format!("Invalid string: {}", string)),
},
"ml" | "milliliter" | "milliliters" | "millilitre" | "millilitres" => {
Token::unit(Milliliter)
}
"cl" | "centiliter" | "centiliters" | "centilitre" | "centilitres" => {
Token::unit(Centiliter)
}
"dl" | "deciliter" | "deciliters" | "decilitre" | "decilitres" => Token::unit(Deciliter),
"l" | "liter" | "liters" | "litre" | "litres" => Token::unit(Liter),
"ts" | "tsp" | "tspn" | "tspns" | "teaspoon" | "teaspoons" => Token::unit(Teaspoon),
"tbs" | "tbsp" | "tablespoon" | "tablespoons" => Token::unit(Tablespoon),
"floz" => Token::unit(FluidOunce),
"fl" | "fluid" => match read_word(lexer).as_str() {
"oz" | "ounce" | "ounces" => Token::unit(FluidOunce),
string => return Err(format!("Invalid string: {}", string)),
},
"cup" | "cups" => Token::unit(Cup),
"pt" | "pint" | "pints" => Token::unit(Pint),
"qt" | "quart" | "quarts" => Token::unit(Quart),
"gal" | "gallon" | "gallons" => Token::unit(Gallon),
"bbl" => Token::unit(OilBarrel),
"oil" => match read_word(lexer).as_str() {
"barrel" | "barrels" => Token::unit(OilBarrel),
string => return Err(format!("Invalid string: {}", string)),
},
"metric" => match read_word(lexer).as_str() {
"ton" | "tons" | "tonne" | "tonnes" => Token::unit(MetricTon),
"hp" | "hps" | "horsepower" | "horsepowers" => Token::unit(MetricHorsepower),
string => return Err(format!("Invalid string: {}", string)),
},
"mg" | "milligram" | "milligrams" => Token::unit(Milligram),
"g" | "gram" | "grams" => Token::unit(Gram),
"hectogram" | "hectograms" => Token::unit(Hectogram),
"kg" | "kilo" | "kilos" | "kilogram" | "kilograms" => Token::unit(Kilogram),
"t" | "tonne" | "tonnes" => Token::unit(MetricTon),
"oz" | "ounces" => Token::unit(Ounce),
"lb" | "lbs" => Token::unit(Pound),
"pound" | "pounds" => match read_immediate_grapheme("-", lexer) {
true => match lexer.read_immediate_word().as_str() {
"force" => Token::LexerKeyword(PoundForce),
other => {
lexer.tokens.push(Token::unit(Pound));
lexer.tokens.push(Token::Operator(Minus));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
false => Token::unit(Pound),
},
"stone" | "stones" => Token::unit(Stone),
"st" | "ton" | "tons" => Token::unit(ShortTon),
"short" => match read_word(lexer).as_str() {
"ton" | "tons" | "tonne" | "tonnes" => Token::unit(ShortTon),
string => return Err(format!("Invalid string: {}", string)),
},
"lt" => Token::unit(LongTon),
"long" => match read_word(lexer).as_str() {
"ton" | "tons" | "tonne" | "tonnes" => Token::unit(LongTon),
string => return Err(format!("Invalid string: {}", string)),
},
"bit" | "bits" => Token::unit(Bit),
"kbit" | "kilobit" | "kilobits" => Token::unit(Kilobit),
"mbit" | "megabit" | "megabits" => Token::unit(Megabit),
"gbit" | "gigabit" | "gigabits" => Token::unit(Gigabit),
"tbit" | "terabit" | "terabits" => Token::unit(Terabit),
"pbit" | "petabit" | "petabits" => Token::unit(Petabit),
"ebit" | "exabit" | "exabits" => Token::unit(Exabit),
"zbit" | "zettabit" | "zettabits" => Token::unit(Zettabit),
"ybit" | "yottabit" | "yottabits" => Token::unit(Yottabit),
"kibit" | "kibibit" | "kibibits" => Token::unit(Kibibit),
"mibit" | "mebibit" | "mebibits" => Token::unit(Mebibit),
"gibit" | "gibibit" | "gibibits" => Token::unit(Gibibit),
"tibit" | "tebibit" | "tebibits" => Token::unit(Tebibit),
"pibit" | "pebibit" | "pebibits" => Token::unit(Pebibit),
"eibit" | "exbibit" | "exbibits" => Token::unit(Exbibit),
"zibit" | "zebibit" | "zebibits" => Token::unit(Zebibit),
"yibit" | "yobibit" | "yobibits" => Token::unit(Yobibit),
"byte" | "bytes" => Token::unit(Byte),
"kb" | "kilobyte" | "kilobytes" => Token::unit(Kilobyte),
"mb" | "megabyte" | "megabytes" => Token::unit(Megabyte),
"gb" | "gigabyte" | "gigabytes" => Token::unit(Gigabyte),
"tb" | "terabyte" | "terabytes" => Token::unit(Terabyte),
"pb" | "petabyte" | "petabytes" => Token::unit(Petabyte),
"eb" | "exabyte" | "exabytes" => Token::unit(Exabyte),
"zb" | "zettabyte" | "zettabytes" => Token::unit(Zettabyte),
"yb" | "yottabyte" | "yottabytes" => Token::unit(Yottabyte),
"kib" | "kibibyte" | "kibibytes" => Token::unit(Kibibyte),
"mib" | "mebibyte" | "mebibytes" => Token::unit(Mebibyte),
"gib" | "gibibyte" | "gibibytes" => Token::unit(Gibibyte),
"tib" | "tebibyte" | "tebibytes" => Token::unit(Tebibyte),
"pib" | "pebibyte" | "pebibytes" => Token::unit(Pebibyte),
"eib" | "exbibyte" | "exbibytes" => Token::unit(Exbibyte),
"zib" | "zebibyte" | "zebibytes" => Token::unit(Zebibyte),
"yib" | "yobibyte" | "yobibytes" => Token::unit(Yobibyte),
"bps" if word.as_bytes()[0] == b'B' => Token::unit(BytesPerSecond),
"kbps" if word.as_bytes()[1] == b'B' => Token::unit(KilobytesPerSecond),
"mbps" if word.as_bytes()[1] == b'B' => Token::unit(MegabytesPerSecond),
"gbps" if word.as_bytes()[1] == b'B' => Token::unit(GigabytesPerSecond),
"tbps" if word.as_bytes()[1] == b'B' => Token::unit(TerabytesPerSecond),
"pbps" if word.as_bytes()[1] == b'B' => Token::unit(PetabytesPerSecond),
"ebps" if word.as_bytes()[1] == b'B' => Token::unit(ExabytesPerSecond),
"zbps" if word.as_bytes()[1] == b'B' => Token::unit(ZettabytesPerSecond),
"ybps" if word.as_bytes()[1] == b'B' => Token::unit(YottabytesPerSecond),
"bps" => Token::unit(BitsPerSecond),
"kbps" => Token::unit(KilobitsPerSecond),
"mbps" => Token::unit(MegabitsPerSecond),
"gbps" => Token::unit(GigabitsPerSecond),
"tbps" => Token::unit(TerabitsPerSecond),
"pbps" => Token::unit(PetabitsPerSecond),
"ebps" => Token::unit(ExabitsPerSecond),
"zbps" => Token::unit(ZettabitsPerSecond),
"ybps" => Token::unit(YottabitsPerSecond),
"flop" => Token::unit(Flop),
"kflop" | "kiloflop" => Token::unit(KiloFlop),
"mflop" | "megaflop" => Token::unit(MegaFlop),
"gflop" | "gigaflop" => Token::unit(GigaFlop),
"tflop" | "teraflop" => Token::unit(TeraFlop),
"pflop" | "petaflop" => Token::unit(PetaFlop),
"eflop" | "exaflop" => Token::unit(ExaFlop),
"zflop" | "zettaflop" => Token::unit(ZettaFlop),
"yflop" | "yottaflop" => Token::unit(YottaFlop),
"rflop" | "ronnaflop" => Token::unit(RonnaFlop),
"qflop" | "quettaflop" => Token::unit(QuettaFlop),
"flops" => Token::unit(FlopPerSecond),
"kflops" | "kiloflops" => Token::unit(KiloFlopPerSecond),
"mflops" | "megaflops" => Token::unit(MegaFlopPerSecond),
"gflops" | "gigaflops" => Token::unit(GigaFlopPerSecond),
"tflops" | "teraflops" => Token::unit(TeraFlopPerSecond),
"pflops" | "petaflops" => Token::unit(PetaFlopPerSecond),
"eflops" | "exaflops" => Token::unit(ExaFlopPerSecond),
"zflops" | "zettaflops" => Token::unit(ZettaFlopPerSecond),
"yflops" | "yottaflops" => Token::unit(YottaFlopPerSecond),
"rflops" | "ronnaflops" => Token::unit(RonnaFlopPerSecond),
"qflops" | "quettaflops" => Token::unit(QuettaFlopPerSecond),
"millijoule" | "millijoules" => Token::unit(Millijoule),
"j" | "joule" | "joules" => Token::unit(Joule),
"nm" => Token::unit(NewtonMeter),
"newton" => match read_immediate_grapheme("-", lexer) {
true => match lexer.read_immediate_word().as_str() {
"meter" | "meters" | "metre" | "metres" => Token::unit(NewtonMeter),
string => return Err(format!("Invalid string: {}", string)),
},
false => match lexer.read_word().as_str() {
"meter" | "meters" | "metre" | "metres" => Token::unit(NewtonMeter),
string => return Err(format!("Invalid string: {}", string)),
},
},
"kj" | "kilojoule" | "kilojoules" => Token::unit(Kilojoule),
"mj" | "megajoule" | "megajoules" => Token::unit(Megajoule),
"gj" | "gigajoule" | "gigajoules" => Token::unit(Gigajoule),
"tj" | "terajoule" | "terajoules" => Token::unit(Terajoule),
"cal" | "calorie" | "calories" => Token::unit(Calorie),
"kcal" | "kilocalorie" | "kilocalories" => Token::unit(KiloCalorie),
"btu" => Token::unit(BritishThermalUnit),
"british" => match read_word(lexer).as_str() {
"thermal" => match read_word(lexer).as_str() {
"unit" | "units" => Token::unit(BritishThermalUnit),
string => return Err(format!("Invalid string: {}", string)),
},
string => return Err(format!("Invalid string: {}", string)),
},
"wh" => Token::unit(WattHour),
"kwh" => Token::unit(KilowattHour),
"mwh" => Token::unit(MegawattHour),
"gwh" => Token::unit(GigawattHour),
"twh" => Token::unit(TerawattHour),
"pwh" => Token::unit(PetawattHour),
"milliwatt" | "milliwatts" => Token::unit(Milliwatt),
"w" | "watts" => Token::unit(Watt),
"kw" | "kilowatts" => Token::unit(Kilowatt),
"mw" | "megawatts" => Token::unit(Megawatt),
"gw" | "gigawatts" => Token::unit(Gigawatt),
"tw" | "terawatts" => Token::unit(Terawatt),
"pw" | "petawatts" => Token::unit(Petawatt),
"hp" | "hps" | "horsepower" | "horsepowers" => Token::unit(Horsepower),
"mhp" | "hpm" => Token::unit(MetricHorsepower),
"watt" => match read_word(lexer).as_str() {
"hr" | "hrs" | "hour" | "hours" => Token::unit(WattHour),
other => {
lexer.tokens.push(Token::unit(Watt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"kilowatt" => match read_word(lexer).as_str() {
"hr" | "hrs" | "hour" | "hours" => Token::unit(KilowattHour),
other => {
lexer.tokens.push(Token::unit(Kilowatt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"megawatt" => match read_word(lexer).as_str() {
"hr" | "hrs" | "hour" | "hours" => Token::unit(MegawattHour),
other => {
lexer.tokens.push(Token::unit(Megawatt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"gigawatt" => match read_word(lexer).as_str() {
"hr" | "hrs" | "hour" | "hours" => Token::unit(GigawattHour),
other => {
lexer.tokens.push(Token::unit(Gigawatt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"terawatt" => match read_word(lexer).as_str() {
"hr" | "hrs" | "hour" | "hours" => Token::unit(TerawattHour),
other => {
lexer.tokens.push(Token::unit(Terawatt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"petawatt" => match &*read_word(lexer) {
"hr" | "hrs" | "hour" | "hours" => Token::unit(PetawattHour),
other => {
lexer.tokens.push(Token::unit(Petawatt));
lex_word_if_non_empty(other, lexer)?;
return Ok(());
}
},
"ma" | "milliamp" | "milliamps" | "milliampere" | "milliamperes" => {
Token::unit(Milliampere)
}
"a" | "amp" | "amps" | "ampere" | "amperes" => Token::unit(Ampere),
"ka" | "kiloamp" | "kiloamps" | "kiloampere" | "kiloamperes" => Token::unit(Kiloampere),
"bi" | "biot" | "biots" | "aba" | "abampere" | "abamperes" => Token::unit(Abampere),
"mΩ" | "mΩ" | "milliohm" | "milliohms" => Token::unit(Milliohm),
"Ω" | "Ω" | "ohm" | "ohms" => Token::unit(Ohm),
"kΩ" | "kΩ" | "kiloohm" | "kiloohms" => Token::unit(Kiloohm),
"mv" | "millivolt" | "millivolts" => Token::unit(Millivolt),
"v" | "volt" | "volts" => Token::unit(Volt),
"kv" | "kilovolt" | "kilovolts" => Token::unit(Kilovolt),
"lbf" => Token::LexerKeyword(PoundForce),
"force" => Token::LexerKeyword(Force),
"pa" | "pascal" | "pascals" => Token::unit(Pascal),
"kpa" | "kilopascal" | "kilopascals" => Token::unit(Kilopascal),
"atm" | "atms" | "atmosphere" | "atmospheres" => Token::unit(Atmosphere),
"mbar" | "mbars" | "millibar" | "millibars" => Token::unit(Millibar),
"bar" | "bars" => Token::unit(Bar),
"inhg" => Token::unit(InchOfMercury),
"mercury" => Token::LexerKeyword(Mercury),
"psi" => Token::unit(PoundsPerSquareInch),
"torr" | "torrs" => Token::unit(Torr),
"hz" | "hertz" => Token::unit(Hertz),
"khz" | "kilohertz" => Token::unit(Kilohertz),
"mhz" | "megahertz" => Token::unit(Megahertz),
"ghz" | "gigahertz" => Token::unit(Gigahertz),
"thz" | "terahertz" => Token::unit(Terahertz),
"phz" | "petahertz" => Token::unit(Petahertz),
"rpm" => Token::unit(RevolutionsPerMinute),
"r" | "rev" | "revolution" | "revolutions" => Token::LexerKeyword(Revolution),
"kph" | "kmh" => Token::unit(KilometersPerHour),
"mps" => Token::unit(MetersPerSecond),
"mph" => Token::unit(MilesPerHour),
"fps" => Token::unit(FeetPerSecond),
"kn" | "kt" | "knot" | "knots" => Token::unit(Knot),
"k" | "kelvin" | "kelvins" => Token::unit(Kelvin),
"c" | "celsius" => Token::unit(Celsius),
"f" | "fahrenheit" | "fahrenheits" => Token::unit(Fahrenheit),
"AU$" => Token::unit(AUD),
"R$" => Token::unit(BRL),
"CA$" | "C$" => Token::unit(CAD),
"€" | "euro" | "euros" => Token::unit(EUR),
"£" => Token::unit(GBP),
"HK$" => Token::unit(HKD),
"₹" | "Rs" => Token::unit(INR),
"₪" => Token::unit(ILS),
"¥" => Token::unit(JPY),
"₩" => Token::unit(KRW),
"MX$" => Token::unit(MXN),
"NZ$" => Token::unit(NZD),
"₱" => Token::unit(PHP),
"zl" | "zł" => Token::unit(PLN),
"S$" => Token::unit(SGD),
"฿" => Token::unit(THB),
"tl" | "₺" => Token::unit(TRY),
"₴" => Token::unit(UAH),
"$" | "US$" => Token::unit(USD),
"₫" => Token::unit(VND),
string if let Ok(unit) = currency_code_to_unit(string) => Token::unit(unit),
string => {
return Err(format!("Invalid string: {}", string));
}
};
lexer.tokens.push(token);
Ok(())
}
struct Lexer<'a> {
left_paren_count: u16,
right_paren_count: u16,
input: &'a str,
graphemes: Peekable<GraphemeIndices<'a>>,
tokens: Vec<Token>,
}
impl<'a> Lexer<'a> {
fn read_word(&mut self) -> String {
read_word(self)
}
fn read_immediate_word(&mut self) -> String {
read_immediate_word(self)
}
fn lex_token(&mut self) -> Result<(), String> {
lex_token(self)
}
}
pub fn lex(input: &str, remove_trailing_operator: bool) -> Result<Vec<Token>, String> {
let mut input = input.replace(',', "");
if remove_trailing_operator {
match &input.chars().last().unwrap_or('x') {
'+' | '-' | '*' | '/' | '^' | '(' => {
input.pop();
}
_ => {}
}
}
let mut lexer = Lexer {
left_paren_count: 0,
right_paren_count: 0,
input: &input,
graphemes: UnicodeSegmentation::grapheme_indices(input.as_str(), true).peekable(),
tokens: Vec::new(),
};
while let Some(_) = lexer.graphemes.peek() {
lexer.lex_token()?;
}
let tokens = &mut lexer.tokens;
if lexer.left_paren_count > lexer.right_paren_count {
let missing_right_parens = lexer.left_paren_count - lexer.right_paren_count;
for _ in 0..missing_right_parens {
tokens.push(Token::Operator(RightParen));
}
} else if lexer.left_paren_count < lexer.right_paren_count {
let missing_left_parens = lexer.right_paren_count - lexer.left_paren_count;
for _ in 0..missing_left_parens {
tokens.insert(0, Token::Operator(LeftParen));
}
}
if tokens.is_empty() {
return Err("Input was empty".to_string());
}
let mut token_index = 0;
loop {
match tokens[token_index] {
Token::LexerKeyword(PercentChar) => {
match tokens.get(token_index + 1) {
Some(Token::TextOperator(Of)) => {
tokens[token_index] = Token::UnaryOperator(Percent);
}
Some(Token::Operator(operator)) => {
match operator {
LeftParen => {
tokens[token_index] = Token::Operator(Modulo);
}
_ => {
tokens[token_index] = Token::UnaryOperator(Percent);
}
}
}
Some(Token::UnaryOperator(_)) => {
tokens[token_index] = Token::UnaryOperator(Percent);
}
Some(Token::LexerKeyword(PercentChar)) => {
tokens[token_index] = Token::UnaryOperator(Percent);
}
None => {
tokens[token_index] = Token::UnaryOperator(Percent);
}
_ => {
tokens[token_index] = Token::Operator(Modulo);
}
}
}
Token::LexerKeyword(DoubleQuotes) => {
match tokens.get(token_index + 1) {
Some(Token::LexerKeyword(Hg)) => {
tokens[token_index] = Token::unit(InchOfMercury);
tokens.remove(token_index + 1);
}
_ => {
tokens[token_index] = Token::unit(Inch);
}
}
}
Token::LexerKeyword(Hg) => {
tokens[token_index] = Token::unit(Hectogram);
}
Token::LexerKeyword(In) => {
match tokens.get(token_index + 1) {
Some(Token::Unit(_)) => {
tokens[token_index] = Token::TextOperator(To);
}
_ => {
tokens[token_index] = Token::unit(Inch);
}
}
}
_ => {}
}
if token_index == tokens.len() - 1 {
break;
} else {
token_index += 1;
}
}
Ok(lexer.tokens)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::numtok;
use regex::Regex;
#[test]
fn test_lex() {
let strip_operator_spacing = Regex::new(r" ([+\-*/]) ").unwrap();
let strip_afterdigit_spacing = Regex::new(r"(\d) ").unwrap();
let nonplural_data_units = Regex::new(r"(bit|byte)s").unwrap();
let run_lex = |input: &str, expected_tokens: Vec<Token>| {
let tokens = match lex(input, false) {
Ok(tokens) => tokens,
Err(e) => {
panic!("lex error: {}\nrun_lex input: {}", e, input);
}
};
let info_msg = format!(
"run_lex assertion failed.\n input: {}\n left: {:?}\n right: {:?}",
input, expected_tokens, tokens
);
assert!(tokens == expected_tokens, "{info_msg}");
let input_extra_spaces = input.replace(" ", " ");
let tokens_extra_spaces = lex(&input_extra_spaces, false).unwrap();
assert!(tokens_extra_spaces == expected_tokens, "{info_msg}");
let input_stripped_spaces = strip_operator_spacing.replace_all(input, "$1");
let tokens_stripped_spaces = lex(&input_stripped_spaces, false).unwrap();
assert!(tokens_stripped_spaces == expected_tokens, "{info_msg}");
let input_afterdigit_stripped_spaces =
strip_afterdigit_spacing.replace_all(input, "$1");
let tokens_afterdigit_stripped_spaces =
lex(&input_afterdigit_stripped_spaces, false).unwrap();
assert!(
tokens_afterdigit_stripped_spaces == expected_tokens,
"{info_msg}"
);
};
let run_datarate_lex = |input: &str, expected_tokens: Vec<Token>| {
run_lex(input, (*expected_tokens).to_vec());
let input_nonplural_units = nonplural_data_units.replace_all(input, "$1");
let tokens_nonplural_units = lex(&input_nonplural_units, false).unwrap();
let info_msg = format!(
"run_datarate_lex input: {}\n left: {:?}\n right: {:?}",
input, expected_tokens, tokens_nonplural_units
);
assert!(tokens_nonplural_units == expected_tokens, "{info_msg}");
};
run_lex(
"88 kilometres * 2",
vec![
numtok!(88),
Token::unit(Kilometer),
Token::Operator(Multiply),
numtok!(2),
],
);
run_lex("0.5 marathon", vec![numtok!(0.5), Token::unit(Marathon)]);
run_lex("100 nmi", vec![numtok!(100), Token::unit(NauticalMile)]);
run_lex(
"101 nautical miles",
vec![numtok!(101), Token::unit(NauticalMile)],
);
run_lex("2 lightyears", vec![numtok!(2), Token::unit(LightYear)]);
run_lex("1 light year", vec![numtok!(1), Token::unit(LightYear)]);
run_lex("10 lightsec", vec![numtok!(10), Token::unit(LightSecond)]);
run_lex("12 light secs", vec![numtok!(12), Token::unit(LightSecond)]);
run_lex(
"33.3 square meters",
vec![numtok!(33.3), Token::unit(SquareMeter)],
);
run_lex("54 m2", vec![numtok!(54), Token::unit(SquareMeter)]);
run_lex("87 sq miles", vec![numtok!(87), Token::unit(SquareMile)]);
run_lex("500 feet2", vec![numtok!(500), Token::unit(SquareFoot)]);
run_lex("500 feet²", vec![numtok!(500), Token::unit(SquareFoot)]);
run_lex("4 cubic metres", vec![numtok!(4), Token::unit(CubicMeter)]);
run_lex(
"34 cubic feet + 23 cubic yards",
vec![
numtok!(34),
Token::unit(CubicFoot),
Token::Operator(Plus),
numtok!(23),
Token::unit(CubicYard),
],
);
run_lex(
"66 inches3 + 65 millimetre³",
vec![
numtok!(66),
Token::unit(CubicInch),
Token::Operator(Plus),
numtok!(65),
Token::unit(CubicMillimeter),
],
);
run_lex(
"66 inches³ + 65 millimetre3",
vec![
numtok!(66),
Token::unit(CubicInch),
Token::Operator(Plus),
numtok!(65),
Token::unit(CubicMillimeter),
],
);
run_lex("42 millilitres", vec![numtok!(42), Token::unit(Milliliter)]);
run_lex("3 tbs", vec![numtok!(3), Token::unit(Tablespoon)]);
run_lex("6 floz", vec![numtok!(6), Token::unit(FluidOunce)]);
run_lex("6 fl oz", vec![numtok!(6), Token::unit(FluidOunce)]);
run_lex("6 fluid ounces", vec![numtok!(6), Token::unit(FluidOunce)]);
run_lex("3 oil barrels", vec![numtok!(3), Token::unit(OilBarrel)]);
run_lex("67 kg", vec![numtok!(67), Token::unit(Kilogram)]);
run_lex("34 oz", vec![numtok!(34), Token::unit(Ounce)]);
run_lex("34 ounces", vec![numtok!(34), Token::unit(Ounce)]);
run_lex("210 lb", vec![numtok!(210), Token::unit(Pound)]);
run_lex("210 lbs", vec![numtok!(210), Token::unit(Pound)]);
run_lex("210 pound", vec![numtok!(210), Token::unit(Pound)]);
run_lex("210 pounds", vec![numtok!(210), Token::unit(Pound)]);
run_lex(
"210 pounds-force",
vec![numtok!(210), Token::LexerKeyword(PoundForce)],
);
run_lex("3 ton", vec![numtok!(3), Token::unit(ShortTon)]);
run_lex("3 short tons", vec![numtok!(3), Token::unit(ShortTon)]);
run_lex("4 lt", vec![numtok!(4), Token::unit(LongTon)]);
run_lex("4 long tonnes", vec![numtok!(4), Token::unit(LongTon)]);
run_datarate_lex("1 bit", vec![numtok!(1), Token::unit(Bit)]);
run_datarate_lex("8 bits", vec![numtok!(8), Token::unit(Bit)]);
run_datarate_lex("63 kilobits", vec![numtok!(63), Token::unit(Kilobit)]);
run_datarate_lex("32 megabits", vec![numtok!(32), Token::unit(Megabit)]);
run_datarate_lex("3.5 gigabits", vec![numtok!(3.5), Token::unit(Gigabit)]);
run_datarate_lex("2.1 terabits", vec![numtok!(2.1), Token::unit(Terabit)]);
run_datarate_lex("1.08 petabits", vec![numtok!(1.08), Token::unit(Petabit)]);
run_datarate_lex("0.73 exabits", vec![numtok!(0.73), Token::unit(Exabit)]);
run_datarate_lex("0.49 zettabits", vec![numtok!(0.49), Token::unit(Zettabit)]);
run_datarate_lex("0.23 yottabits", vec![numtok!(0.23), Token::unit(Yottabit)]);
run_datarate_lex("63 kibibits", vec![numtok!(63), Token::unit(Kibibit)]);
run_datarate_lex("32 mebibits", vec![numtok!(32), Token::unit(Mebibit)]);
run_datarate_lex("3.5 gibibits", vec![numtok!(3.5), Token::unit(Gibibit)]);
run_datarate_lex("2.1 tebibits", vec![numtok!(2.1), Token::unit(Tebibit)]);
run_datarate_lex("1.08 pebibits", vec![numtok!(1.08), Token::unit(Pebibit)]);
run_datarate_lex("0.73 exbibits", vec![numtok!(0.73), Token::unit(Exbibit)]);
run_datarate_lex("0.49 zebibits", vec![numtok!(0.49), Token::unit(Zebibit)]);
run_datarate_lex("0.23 yobibits", vec![numtok!(0.23), Token::unit(Yobibit)]);
run_datarate_lex("1 byte", vec![numtok!(1), Token::unit(Byte)]);
run_datarate_lex("3 bytes", vec![numtok!(3), Token::unit(Byte)]);
run_datarate_lex("63 kilobytes", vec![numtok!(63), Token::unit(Kilobyte)]);
run_datarate_lex("32 megabytes", vec![numtok!(32), Token::unit(Megabyte)]);
run_datarate_lex("3.5 gigabytes", vec![numtok!(3.5), Token::unit(Gigabyte)]);
run_datarate_lex("2.1 terabytes", vec![numtok!(2.1), Token::unit(Terabyte)]);
run_datarate_lex("1.08 petabytes", vec![numtok!(1.08), Token::unit(Petabyte)]);
run_datarate_lex("0.73 exabytes", vec![numtok!(0.73), Token::unit(Exabyte)]);
run_datarate_lex(
"0.49 zettabytes",
vec![numtok!(0.49), Token::unit(Zettabyte)],
);
run_datarate_lex(
"0.23 yottabytes",
vec![numtok!(0.23), Token::unit(Yottabyte)],
);
run_datarate_lex("63 kibibytes", vec![numtok!(63), Token::unit(Kibibyte)]);
run_datarate_lex("32 mebibytes", vec![numtok!(32), Token::unit(Mebibyte)]);
run_datarate_lex("3.5 gibibytes", vec![numtok!(3.5), Token::unit(Gibibyte)]);
run_datarate_lex("2.1 tebibytes", vec![numtok!(2.1), Token::unit(Tebibyte)]);
run_datarate_lex("1.08 pebibytes", vec![numtok!(1.08), Token::unit(Pebibyte)]);
run_datarate_lex("0.73 exbibytes", vec![numtok!(0.73), Token::unit(Exbibyte)]);
run_datarate_lex("0.49 zebibytes", vec![numtok!(0.49), Token::unit(Zebibyte)]);
run_datarate_lex("0.23 yobibytes", vec![numtok!(0.23), Token::unit(Yobibyte)]);
run_lex("432 Bps", vec![numtok!(432), Token::unit(BytesPerSecond)]);
run_lex(
"56 kBps",
vec![numtok!(56), Token::unit(KilobytesPerSecond)],
);
run_lex("432 bps", vec![numtok!(432), Token::unit(BitsPerSecond)]);
run_lex("56 kbps", vec![numtok!(56), Token::unit(KilobitsPerSecond)]);
run_lex("12 mbps", vec![numtok!(12), Token::unit(MegabitsPerSecond)]);
run_lex(
"4.2 gbps",
vec![numtok!(4.2), Token::unit(GigabitsPerSecond)],
);
run_lex(
"2.2 tbps",
vec![numtok!(2.2), Token::unit(TerabitsPerSecond)],
);
run_lex(
"1.7 pbps",
vec![numtok!(1.7), Token::unit(PetabitsPerSecond)],
);
run_lex(
"0.99 ebps",
vec![numtok!(0.99), Token::unit(ExabitsPerSecond)],
);
run_lex(
"0.64 zbps",
vec![numtok!(0.64), Token::unit(ZettabitsPerSecond)],
);
run_lex(
"0.278 ybps",
vec![numtok!(0.278), Token::unit(YottabitsPerSecond)],
);
run_datarate_lex(
"4 bits per second",
vec![
numtok!(4),
Token::unit(Bit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"5 kilobits per second",
vec![
numtok!(5),
Token::unit(Kilobit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"6 megabits per second",
vec![
numtok!(6),
Token::unit(Megabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"7 gigabits per second",
vec![
numtok!(7),
Token::unit(Gigabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"8 terabits per second",
vec![
numtok!(8),
Token::unit(Terabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"9 petabits per second",
vec![
numtok!(9),
Token::unit(Petabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"10 exabits per second",
vec![
numtok!(10),
Token::unit(Exabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"11 zettabits per second",
vec![
numtok!(11),
Token::unit(Zettabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"12 yottabits per second",
vec![
numtok!(12),
Token::unit(Yottabit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"13 kibibits per second",
vec![
numtok!(13),
Token::unit(Kibibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"14 mebibits per second",
vec![
numtok!(14),
Token::unit(Mebibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"15 gibibits per second",
vec![
numtok!(15),
Token::unit(Gibibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"16 tebibits per second",
vec![
numtok!(16),
Token::unit(Tebibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"17 pebibits per second",
vec![
numtok!(17),
Token::unit(Pebibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"18 exbibits per second",
vec![
numtok!(18),
Token::unit(Exbibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"19 zebibits per second",
vec![
numtok!(19),
Token::unit(Zebibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"20 yobibits per second",
vec![
numtok!(20),
Token::unit(Yobibit),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"4 bytes per second",
vec![
numtok!(4),
Token::unit(Byte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"5 kilobytes per second",
vec![
numtok!(5),
Token::unit(Kilobyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"6 megabytes per second",
vec![
numtok!(6),
Token::unit(Megabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"7 gigabytes per second",
vec![
numtok!(7),
Token::unit(Gigabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"8 terabytes per second",
vec![
numtok!(8),
Token::unit(Terabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"9 petabytes per second",
vec![
numtok!(9),
Token::unit(Petabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"10 exabytes per second",
vec![
numtok!(10),
Token::unit(Exabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"11 zettabytes per second",
vec![
numtok!(11),
Token::unit(Zettabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"12 yottabytes per second",
vec![
numtok!(12),
Token::unit(Yottabyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"13 kibibytes per second",
vec![
numtok!(13),
Token::unit(Kibibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"14 mebibytes per second",
vec![
numtok!(14),
Token::unit(Mebibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"15 gibibytes per second",
vec![
numtok!(15),
Token::unit(Gibibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"16 tebibytes per second",
vec![
numtok!(16),
Token::unit(Tebibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"17 pebibytes per second",
vec![
numtok!(17),
Token::unit(Pebibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"18 exbibytes per second",
vec![
numtok!(18),
Token::unit(Exbibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"19 zebibytes per second",
vec![
numtok!(19),
Token::unit(Zebibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_datarate_lex(
"20 yobibytes per second",
vec![
numtok!(20),
Token::unit(Yobibyte),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex("1 flop", vec![numtok!(1), Token::unit(Flop)]);
run_lex("2 kflop", vec![numtok!(2), Token::unit(KiloFlop)]);
run_lex("3 mflop", vec![numtok!(3), Token::unit(MegaFlop)]);
run_lex("4 gflop", vec![numtok!(4), Token::unit(GigaFlop)]);
run_lex("5 tflop", vec![numtok!(5), Token::unit(TeraFlop)]);
run_lex("6 pflop", vec![numtok!(6), Token::unit(PetaFlop)]);
run_lex("7 eflop", vec![numtok!(7), Token::unit(ExaFlop)]);
run_lex("8 zflop", vec![numtok!(8), Token::unit(ZettaFlop)]);
run_lex("9 yflop", vec![numtok!(9), Token::unit(YottaFlop)]);
run_lex("10 rflop", vec![numtok!(10), Token::unit(RonnaFlop)]);
run_lex("11 qflop", vec![numtok!(11), Token::unit(QuettaFlop)]);
run_lex(
"1 flop/s",
vec![
numtok!(1),
Token::unit(Flop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"2 kflop/s",
vec![
numtok!(2),
Token::unit(KiloFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"3 mflop/s",
vec![
numtok!(3),
Token::unit(MegaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"4 gflop/s",
vec![
numtok!(4),
Token::unit(GigaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"5 tflop/s",
vec![
numtok!(5),
Token::unit(TeraFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"6 pflop/s",
vec![
numtok!(6),
Token::unit(PetaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"7 eflop/s",
vec![
numtok!(7),
Token::unit(ExaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"8 zflop/s",
vec![
numtok!(8),
Token::unit(ZettaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"9 yflop/s",
vec![
numtok!(9),
Token::unit(YottaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"10 rflop/s",
vec![
numtok!(10),
Token::unit(RonnaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"11 qflop/s",
vec![
numtok!(11),
Token::unit(QuettaFlop),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"1 flop per second",
vec![
numtok!(1),
Token::unit(Flop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"2 kflop per second",
vec![
numtok!(2),
Token::unit(KiloFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"3 mflop per second",
vec![
numtok!(3),
Token::unit(MegaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"4 gflop per second",
vec![
numtok!(4),
Token::unit(GigaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"5 tflop per second",
vec![
numtok!(5),
Token::unit(TeraFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"6 pflop per second",
vec![
numtok!(6),
Token::unit(PetaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"7 eflop per second",
vec![
numtok!(7),
Token::unit(ExaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"8 zflop per second",
vec![
numtok!(8),
Token::unit(ZettaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"9 yflop per second",
vec![
numtok!(9),
Token::unit(YottaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"10 rflop per second",
vec![
numtok!(10),
Token::unit(RonnaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"11 qflop per second",
vec![
numtok!(11),
Token::unit(QuettaFlop),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex("1 flops", vec![numtok!(1), Token::unit(FlopPerSecond)]);
run_lex("2 kflops", vec![numtok!(2), Token::unit(KiloFlopPerSecond)]);
run_lex("3 mflops", vec![numtok!(3), Token::unit(MegaFlopPerSecond)]);
run_lex("4 gflops", vec![numtok!(4), Token::unit(GigaFlopPerSecond)]);
run_lex("5 tflops", vec![numtok!(5), Token::unit(TeraFlopPerSecond)]);
run_lex("6 pflops", vec![numtok!(6), Token::unit(PetaFlopPerSecond)]);
run_lex("7 eflops", vec![numtok!(7), Token::unit(ExaFlopPerSecond)]);
run_lex(
"8 zflops",
vec![numtok!(8), Token::unit(ZettaFlopPerSecond)],
);
run_lex(
"9 yflops",
vec![numtok!(9), Token::unit(YottaFlopPerSecond)],
);
run_lex(
"10 rflops",
vec![numtok!(10), Token::unit(RonnaFlopPerSecond)],
);
run_lex(
"11 qflops",
vec![numtok!(11), Token::unit(QuettaFlopPerSecond)],
);
run_lex("234 wh", vec![numtok!(234), Token::unit(WattHour)]);
run_lex("1 w", vec![numtok!(1), Token::unit(Watt)]);
run_lex("1 watt", vec![numtok!(1), Token::unit(Watt)]);
run_lex("1 watts", vec![numtok!(1), Token::unit(Watt)]);
run_lex("1 watt hour", vec![numtok!(1), Token::unit(WattHour)]);
run_lex(
"0 watt + 1 watts",
vec![
numtok!(0),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(1),
Token::unit(Watt),
],
);
run_lex(
"0 watt * 1",
vec![
numtok!(0),
Token::unit(Watt),
Token::Operator(Multiply),
numtok!(1),
],
);
run_lex(
"2 watts + 3 watts",
vec![
numtok!(2),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 watts * 3",
vec![
numtok!(2),
Token::unit(Watt),
Token::Operator(Multiply),
numtok!(3),
],
);
run_lex(
"4 watt plus 5 watts",
vec![
numtok!(4),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Watt),
],
);
run_lex(
"4 watt times 5",
vec![
numtok!(4),
Token::unit(Watt),
Token::Operator(Multiply),
numtok!(5),
],
);
run_lex(
"6 watts plus 7 watts",
vec![
numtok!(6),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Watt),
],
);
run_lex(
"6 watts times 7",
vec![
numtok!(6),
Token::unit(Watt),
Token::Operator(Multiply),
numtok!(7),
],
);
run_lex("2.3 kwh", vec![numtok!(2.3), Token::unit(KilowattHour)]);
run_lex("1 kw", vec![numtok!(1), Token::unit(Kilowatt)]);
run_lex("1 kilowatt", vec![numtok!(1), Token::unit(Kilowatt)]);
run_lex("1 kilowatts", vec![numtok!(1), Token::unit(Kilowatt)]);
run_lex(
"1 kilowatt hour",
vec![numtok!(1), Token::unit(KilowattHour)],
);
run_lex(
"2 kilowatt + 3 watt",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatt * 4",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Multiply),
numtok!(4),
],
);
run_lex(
"2 kilowatt times 4",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Multiply),
numtok!(4),
],
);
run_lex(
"2 kilowatt + 3 watts",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatts + 3 watt",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatts + 3 watts",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatt plus 3 watt",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatt plus 3 watts",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatts plus 3 watt",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 kilowatts plus 3 watts",
vec![
numtok!(2),
Token::unit(Kilowatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"6.6 watts + 4 kilowatts",
vec![
numtok!(6.6),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(4),
Token::unit(Kilowatt),
],
);
run_lex(
"6.6 watts plus 4 kilowatts",
vec![
numtok!(6.6),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(4),
Token::unit(Kilowatt),
],
);
run_lex("2.3 mwh", vec![numtok!(2.3), Token::unit(MegawattHour)]);
run_lex("1 mw", vec![numtok!(1), Token::unit(Megawatt)]);
run_lex("1 megawatt", vec![numtok!(1), Token::unit(Megawatt)]);
run_lex(
"1 megawatt hour",
vec![numtok!(1), Token::unit(MegawattHour)],
);
run_lex(
"2 megawatt + 3 watt",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatt * 6",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Multiply),
numtok!(6),
],
);
run_lex(
"2 megawatt times 6",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Multiply),
numtok!(6),
],
);
run_lex(
"2 megawatt + 3 watts",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatts + 3 watt",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatts + 3 watts",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatt plus 3 watt",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatt plus 3 watts",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatts plus 3 watt",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"2 megawatts plus 3 watts",
vec![
numtok!(2),
Token::unit(Megawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Watt),
],
);
run_lex(
"6.6 watts + 4 megawatts",
vec![
numtok!(6.6),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(4),
Token::unit(Megawatt),
],
);
run_lex(
"6.6 watts plus 4 megawatts",
vec![
numtok!(6.6),
Token::unit(Watt),
Token::Operator(Plus),
numtok!(4),
Token::unit(Megawatt),
],
);
run_lex("234 gwh", vec![numtok!(234), Token::unit(GigawattHour)]);
run_lex("1 gw", vec![numtok!(1), Token::unit(Gigawatt)]);
run_lex("1 gigawatt", vec![numtok!(1), Token::unit(Gigawatt)]);
run_lex("1 gigawatts", vec![numtok!(1), Token::unit(Gigawatt)]);
run_lex(
"1 gigawatt hour",
vec![numtok!(1), Token::unit(GigawattHour)],
);
run_lex(
"0 gigawatt + 1 gigawatts",
vec![
numtok!(0),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(1),
Token::unit(Gigawatt),
],
);
run_lex(
"0 gigawatt * 1",
vec![
numtok!(0),
Token::unit(Gigawatt),
Token::Operator(Multiply),
numtok!(1),
],
);
run_lex(
"2 gigawatts + 3 gigawatts",
vec![
numtok!(2),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(3),
Token::unit(Gigawatt),
],
);
run_lex(
"2 gigawatts * 3",
vec![
numtok!(2),
Token::unit(Gigawatt),
Token::Operator(Multiply),
numtok!(3),
],
);
run_lex(
"4 gigawatt plus 5 watt",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Watt),
],
);
run_lex(
"4 gigawatt plus 5 megawatt",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Megawatt),
],
);
run_lex(
"4 gigawatt plus 5 gigawatt",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Gigawatt),
],
);
run_lex(
"4 gigawatt plus 5 watts",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Watt),
],
);
run_lex(
"4 gigawatt plus 5 megawatts",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Megawatt),
],
);
run_lex(
"4 gigawatt plus 5 gigawatts",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(5),
Token::unit(Gigawatt),
],
);
run_lex(
"4 gigawatt times 5",
vec![
numtok!(4),
Token::unit(Gigawatt),
Token::Operator(Multiply),
numtok!(5),
],
);
run_lex(
"6 gigawatts plus 7 watt",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Watt),
],
);
run_lex(
"6 gigawatts plus 7 megawatt",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Megawatt),
],
);
run_lex(
"6 gigawatts plus 7 gigawatt",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Gigawatt),
],
);
run_lex(
"6 gigawatts plus 7 watts",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Watt),
],
);
run_lex(
"6 gigawatts plus 7 megawatts",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Megawatt),
],
);
run_lex(
"6 gigawatts plus 7 gigawatts",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Plus),
numtok!(7),
Token::unit(Gigawatt),
],
);
run_lex(
"6 gigawatts times 7",
vec![
numtok!(6),
Token::unit(Gigawatt),
Token::Operator(Multiply),
numtok!(7),
],
);
run_lex(
"88 mw * 3",
vec![
numtok!(88),
Token::unit(Megawatt),
Token::Operator(Multiply),
numtok!(3),
],
);
run_lex(
"88 mw times 3",
vec![
numtok!(88),
Token::unit(Megawatt),
Token::Operator(Multiply),
numtok!(3),
],
);
run_lex("999 kb", vec![numtok!(999), Token::unit(Kilobyte)]);
run_lex(
"200 gb - 100 mb",
vec![
numtok!(200),
Token::unit(Gigabyte),
Token::Operator(Minus),
numtok!(100),
Token::unit(Megabyte),
],
);
run_lex("999 kib", vec![numtok!(999), Token::unit(Kibibyte)]);
run_lex(
"200 gib - 100 mib",
vec![
numtok!(200),
Token::unit(Gibibyte),
Token::Operator(Minus),
numtok!(100),
Token::unit(Mebibyte),
],
);
run_lex("45 btu", vec![numtok!(45), Token::unit(BritishThermalUnit)]);
run_lex(
"45.5 british thermal unit",
vec![numtok!(45.5), Token::unit(BritishThermalUnit)],
);
run_lex(
"46 british thermal units",
vec![numtok!(46), Token::unit(BritishThermalUnit)],
);
run_lex(
"5432 newton metres",
vec![numtok!(5432), Token::unit(NewtonMeter)],
);
run_lex(
"2345 newton-meters",
vec![numtok!(2345), Token::unit(NewtonMeter)],
);
run_lex("20 lbf", vec![numtok!(20), Token::LexerKeyword(PoundForce)]);
run_lex("60 hz", vec![numtok!(60), Token::unit(Hertz)]);
run_lex(
"1100 rpm",
vec![numtok!(1100), Token::unit(RevolutionsPerMinute)],
);
run_lex(
"1150 revolutions per minute",
vec![
numtok!(1150),
Token::LexerKeyword(Revolution),
Token::TextOperator(Per),
Token::unit(Minute),
],
);
run_lex(
"1 revolution per min",
vec![
numtok!(1),
Token::LexerKeyword(Revolution),
Token::TextOperator(Per),
Token::unit(Minute),
],
);
run_lex(
"4 revolution / mins",
vec![
numtok!(4),
Token::LexerKeyword(Revolution),
Token::Operator(Divide),
Token::unit(Minute),
],
);
run_lex(
"1250 r / min",
vec![
numtok!(1250),
Token::LexerKeyword(Revolution),
Token::Operator(Divide),
Token::unit(Minute),
],
);
run_lex(
"1300 rev / min",
vec![
numtok!(1300),
Token::LexerKeyword(Revolution),
Token::Operator(Divide),
Token::unit(Minute),
],
);
run_lex(
"1350 rev / minute",
vec![
numtok!(1350),
Token::LexerKeyword(Revolution),
Token::Operator(Divide),
Token::unit(Minute),
],
);
run_lex(
"1250 r per min",
vec![
numtok!(1250),
Token::LexerKeyword(Revolution),
Token::TextOperator(Per),
Token::unit(Minute),
],
);
run_lex(
"1300 rev per min",
vec![
numtok!(1300),
Token::LexerKeyword(Revolution),
Token::TextOperator(Per),
Token::unit(Minute),
],
);
run_lex(
"1350 rev per minute",
vec![
numtok!(1350),
Token::LexerKeyword(Revolution),
Token::TextOperator(Per),
Token::unit(Minute),
],
);
run_lex(
"100 kph",
vec![numtok!(100), Token::unit(KilometersPerHour)],
);
run_lex(
"100 kmh",
vec![numtok!(100), Token::unit(KilometersPerHour)],
);
run_lex(
"100 kilometers per hour",
vec![
numtok!(100),
Token::unit(Kilometer),
Token::TextOperator(Per),
Token::unit(Hour),
],
);
run_lex(
"100 kilometre / hrs",
vec![
numtok!(100),
Token::unit(Kilometer),
Token::Operator(Divide),
Token::unit(Hour),
],
);
run_lex("3.6 mps", vec![numtok!(3.6), Token::unit(MetersPerSecond)]);
run_lex(
"3.6 meters per second",
vec![
numtok!(3.6),
Token::unit(Meter),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"3.6 metre / secs",
vec![
numtok!(3.6),
Token::unit(Meter),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex("60 mph", vec![numtok!(60), Token::unit(MilesPerHour)]);
run_lex(
"60 miles per hour",
vec![
numtok!(60),
Token::unit(Mile),
Token::TextOperator(Per),
Token::unit(Hour),
],
);
run_lex(
"60 mile / hr",
vec![
numtok!(60),
Token::unit(Mile),
Token::Operator(Divide),
Token::unit(Hour),
],
);
run_lex("35 fps", vec![numtok!(35), Token::unit(FeetPerSecond)]);
run_lex(
"35 ft / sec",
vec![
numtok!(35),
Token::unit(Foot),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"35 ft per seconds",
vec![
numtok!(35),
Token::unit(Foot),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"35 foot / secs",
vec![
numtok!(35),
Token::unit(Foot),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"35 foot per seconds",
vec![
numtok!(35),
Token::unit(Foot),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex(
"35 feet / sec",
vec![
numtok!(35),
Token::unit(Foot),
Token::Operator(Divide),
Token::unit(Second),
],
);
run_lex(
"35 feet per second",
vec![
numtok!(35),
Token::unit(Foot),
Token::TextOperator(Per),
Token::unit(Second),
],
);
run_lex("30 pa", vec![numtok!(30), Token::unit(Pascal)]);
run_lex(
"23 celsius + 4 celsius",
vec![
numtok!(23),
Token::unit(Celsius),
Token::Operator(Plus),
numtok!(4),
Token::unit(Celsius),
],
);
run_lex(
"54 f - 1.5 fahrenheit",
vec![
numtok!(54),
Token::unit(Fahrenheit),
Token::Operator(Minus),
numtok!(1.5),
Token::unit(Fahrenheit),
],
);
run_lex(
"50 metric tonnes",
vec![numtok!(50), Token::unit(MetricTon)],
);
run_lex(
"77 metric hps",
vec![numtok!(77), Token::unit(MetricHorsepower)],
);
run_lex(
"100 + 99",
vec![numtok!(100), Token::Operator(Plus), numtok!(99)],
);
run_lex(
"100 plus 99",
vec![numtok!(100), Token::Operator(Plus), numtok!(99)],
);
run_lex(
"12 - 4",
vec![numtok!(12), Token::Operator(Minus), numtok!(4)],
);
run_lex(
"12 minus 4",
vec![numtok!(12), Token::Operator(Minus), numtok!(4)],
);
run_lex(
"50.5 * 2",
vec![numtok!(50.5), Token::Operator(Multiply), numtok!(2)],
);
run_lex(
"50.5 times 2",
vec![numtok!(50.5), Token::Operator(Multiply), numtok!(2)],
);
run_lex(
"50.5 multiplied by 2",
vec![numtok!(50.5), Token::Operator(Multiply), numtok!(2)],
);
run_lex(
"6 / 3",
vec![numtok!(6), Token::Operator(Divide), numtok!(3)],
);
run_lex(
"50 / 10",
vec![numtok!(50), Token::Operator(Divide), numtok!(10)],
);
run_lex(
"52 ÷ 12",
vec![numtok!(52), Token::Operator(Divide), numtok!(12)],
);
run_lex(
"6 divided by 3",
vec![numtok!(6), Token::Operator(Divide), numtok!(3)],
);
run_lex(
"7 mod 5",
vec![numtok!(7), Token::Operator(Modulo), numtok!(5)],
);
run_lex(
"(2 + 3) * 4",
vec![
Token::Operator(LeftParen),
numtok!(2),
Token::Operator(Plus),
numtok!(3),
Token::Operator(RightParen),
Token::Operator(Multiply),
numtok!(4),
],
);
run_lex(
"52 weeks * (12 hrs + 12 hours)",
vec![
numtok!(52),
Token::unit(Week),
Token::Operator(Multiply),
Token::Operator(LeftParen),
numtok!(12),
Token::unit(Hour),
Token::Operator(Plus),
numtok!(12),
Token::unit(Hour),
Token::Operator(RightParen),
],
);
run_lex(
"12 pound+",
vec![numtok!(12), Token::unit(Pound), Token::Operator(Plus)],
);
run_lex(
"5 π m",
vec![numtok!(5), Token::Constant(Pi), Token::unit(Meter)],
);
run_lex(
"5 Ω + 2 mΩ",
vec![
numtok!(5),
Token::unit(Ohm),
Token::Operator(Plus),
numtok!(2),
Token::unit(Milliohm),
],
);
}
}