Support for using "in" as To operator (like "5in in cm")
This commit is contained in:
parent
efa76e93c5
commit
02e74806e1
54
src/lexer.rs
54
src/lexer.rs
@ -5,6 +5,7 @@ use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, R
|
|||||||
use crate::UnaryOperator::{Percent, Factorial};
|
use crate::UnaryOperator::{Percent, Factorial};
|
||||||
use crate::TextOperator::{Of, To};
|
use crate::TextOperator::{Of, To};
|
||||||
use crate::Constant::{E, Pi};
|
use crate::Constant::{E, Pi};
|
||||||
|
use crate::LexerKeyword::{In, PercentChar, Per};
|
||||||
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::*;
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ pub fn lex(input: &str) -> Result<TokenVector, String> {
|
|||||||
'-' => tokens.push(Token::Operator(Minus)),
|
'-' => tokens.push(Token::Operator(Minus)),
|
||||||
'*' => tokens.push(Token::Operator(Multiply)),
|
'*' => tokens.push(Token::Operator(Multiply)),
|
||||||
'/' => tokens.push(Token::Operator(Divide)),
|
'/' => tokens.push(Token::Operator(Divide)),
|
||||||
'%' => tokens.push(Token::Operator(Modulo)),
|
'%' => tokens.push(Token::LexerKeyword(PercentChar)),
|
||||||
'^' => tokens.push(Token::Operator(Caret)),
|
'^' => tokens.push(Token::Operator(Caret)),
|
||||||
'!' => tokens.push(Token::UnaryOperator(Factorial)),
|
'!' => tokens.push(Token::UnaryOperator(Factorial)),
|
||||||
'(' => {
|
'(' => {
|
||||||
@ -100,7 +101,7 @@ pub fn lex(input: &str) -> Result<TokenVector, String> {
|
|||||||
"cos" => tokens.push(Token::FunctionIdentifier(Cos)),
|
"cos" => tokens.push(Token::FunctionIdentifier(Cos)),
|
||||||
"tan" => tokens.push(Token::FunctionIdentifier(Tan)),
|
"tan" => tokens.push(Token::FunctionIdentifier(Tan)),
|
||||||
|
|
||||||
"per" => tokens.push(Token::Per),
|
"per" => tokens.push(Token::LexerKeyword(Per)),
|
||||||
|
|
||||||
"ns" | "nanosec" | "nanosecs" | "nanosecond" | "nanoseconds" => tokens.push(Token::Unit(Nanosecond)),
|
"ns" | "nanosec" | "nanosecs" | "nanosecond" | "nanoseconds" => tokens.push(Token::Unit(Nanosecond)),
|
||||||
"μs" | "microsec" | "microsecs" | "microsecond" | "microseconds" => tokens.push(Token::Unit(Microsecond)),
|
"μs" | "microsec" | "microsecs" | "microsecond" | "microseconds" => tokens.push(Token::Unit(Microsecond)),
|
||||||
@ -122,7 +123,8 @@ pub fn lex(input: &str) -> Result<TokenVector, String> {
|
|||||||
"dm" | "decimeter" | "decimeters" => tokens.push(Token::Unit(Centimeter)),
|
"dm" | "decimeter" | "decimeters" => tokens.push(Token::Unit(Centimeter)),
|
||||||
"m" | "meter" | "meters" => tokens.push(Token::Unit(Meter)),
|
"m" | "meter" | "meters" => tokens.push(Token::Unit(Meter)),
|
||||||
"km" | "kilometer" | "kilometers" => tokens.push(Token::Unit(Kilometer)),
|
"km" | "kilometer" | "kilometers" => tokens.push(Token::Unit(Kilometer)),
|
||||||
"in" | "inch" | "inches" => tokens.push(Token::Unit(Inch)),
|
"in" => tokens.push(Token::LexerKeyword(In)),
|
||||||
|
"inch" | "inches" => tokens.push(Token::Unit(Inch)),
|
||||||
"ft" | "foot" | "feet" => tokens.push(Token::Unit(Foot)),
|
"ft" | "foot" | "feet" => tokens.push(Token::Unit(Foot)),
|
||||||
"yd" | "yard" | "yards" => tokens.push(Token::Unit(Yard)),
|
"yd" | "yard" | "yards" => tokens.push(Token::Unit(Yard)),
|
||||||
"mi" | "mile" | "miles" => tokens.push(Token::Unit(Mile)),
|
"mi" | "mile" | "miles" => tokens.push(Token::Unit(Mile)),
|
||||||
@ -309,60 +311,76 @@ pub fn lex(input: &str) -> Result<TokenVector, String> {
|
|||||||
|
|
||||||
let mut token_index = 0;
|
let mut token_index = 0;
|
||||||
for _i in 1..tokens.len() {
|
for _i in 1..tokens.len() {
|
||||||
// the lexer parses percentages as modulo, so here modulos become percentages
|
// decide if % is percent or modulo
|
||||||
match tokens[token_index] {
|
match tokens[token_index] {
|
||||||
Token::Operator(Modulo) => {
|
Token::LexerKeyword(PercentChar) => {
|
||||||
match &tokens[token_index + 1] {
|
match &tokens[token_index + 1] {
|
||||||
Token::TextOperator(Of) => {
|
Token::TextOperator(Of) => {
|
||||||
// for example "10% of 1km" should be a percentage, not modulo
|
// "10% of 1km" should be percentage
|
||||||
tokens[token_index] = Token::UnaryOperator(Percent);
|
tokens[token_index] = Token::UnaryOperator(Percent);
|
||||||
},
|
},
|
||||||
Token::Operator(operator) => {
|
Token::Operator(operator) => {
|
||||||
match operator {
|
match operator {
|
||||||
LeftParen => {},
|
LeftParen => {
|
||||||
|
// "10%(2)" should be modulo
|
||||||
|
tokens[token_index] = Token::Operator(Modulo);
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// for example "10%*2" should be a percentage, but "10%(2)" should be modulo
|
// "10%*2" should be a percentage
|
||||||
tokens[token_index] = Token::UnaryOperator(Percent);
|
tokens[token_index] = Token::UnaryOperator(Percent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::UnaryOperator(_operator) => {
|
Token::UnaryOperator(_operator) => {
|
||||||
// for example "10%!" should be a percentage, but "10%(2)" should be modulo
|
// "10%!" should be a percentage
|
||||||
tokens[token_index] = Token::UnaryOperator(Percent);
|
tokens[token_index] = Token::UnaryOperator(Percent);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {
|
||||||
|
// "10%2" should be modulo
|
||||||
|
tokens[token_index] = Token::Operator(Modulo);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Token::LexerKeyword(In) => {
|
||||||
|
match &tokens[token_index + 1] {
|
||||||
|
Token::Unit(_) => {
|
||||||
|
tokens[token_index] = Token::TextOperator(To);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
tokens[token_index] = Token::Unit(Inch);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
token_index += 1;
|
token_index += 1;
|
||||||
// parse units like km per h
|
// parse units like km/h, km per h
|
||||||
if token_index >= 2 {
|
if token_index >= 2 {
|
||||||
let token1 = &tokens[token_index-2];
|
let token1 = &tokens[token_index-2];
|
||||||
let token2 = match &tokens[token_index-1] {
|
let token2 = match &tokens[token_index-1] {
|
||||||
// treat km/h the same as km per h
|
// treat km/h the same as km per h
|
||||||
Token::Operator(Divide) => &Token::Per,
|
Token::Operator(Divide) => &Token::LexerKeyword(Per),
|
||||||
_ => &tokens[token_index-1],
|
_ => &tokens[token_index-1],
|
||||||
};
|
};
|
||||||
let token3 = &tokens[token_index];
|
let token3 = &tokens[token_index];
|
||||||
let mut replaced = true;
|
let mut replaced = true;
|
||||||
match (token1, token2, token3) {
|
match (token1, token2, token3) {
|
||||||
(Token::Unit(Kilometer), Token::Per, Token::Unit(Hour)) => {
|
(Token::Unit(Kilometer), Token::LexerKeyword(Per), Token::Unit(Hour)) => {
|
||||||
tokens[token_index-2] = Token::Unit(KilometersPerHour);
|
tokens[token_index-2] = Token::Unit(KilometersPerHour);
|
||||||
},
|
},
|
||||||
(Token::Unit(Mile), Token::Per, Token::Unit(Hour)) => {
|
(Token::Unit(Mile), Token::LexerKeyword(Per), Token::Unit(Hour)) => {
|
||||||
tokens[token_index-2] = Token::Unit(MilesPerHour);
|
tokens[token_index-2] = Token::Unit(MilesPerHour);
|
||||||
},
|
},
|
||||||
(Token::Unit(Meter), Token::Per, Token::Unit(Second)) => {
|
(Token::Unit(Meter), Token::LexerKeyword(Per), Token::Unit(Second)) => {
|
||||||
tokens[token_index-2] = Token::Unit(MetersPerSecond);
|
tokens[token_index-2] = Token::Unit(MetersPerSecond);
|
||||||
},
|
},
|
||||||
(Token::Unit(Foot), Token::Per, Token::Unit(Second)) => {
|
(Token::Unit(Foot), Token::LexerKeyword(Per), Token::Unit(Second)) => {
|
||||||
tokens[token_index-2] = Token::Unit(FeetPerSecond);
|
tokens[token_index-2] = Token::Unit(FeetPerSecond);
|
||||||
},
|
},
|
||||||
(Token::Unit(BritishThermalUnit), Token::Per, Token::Unit(Minute)) => {
|
(Token::Unit(BritishThermalUnit), Token::LexerKeyword(Per), Token::Unit(Minute)) => {
|
||||||
tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerMinute);
|
tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerMinute);
|
||||||
},
|
},
|
||||||
(Token::Unit(BritishThermalUnit), Token::Per, Token::Unit(Hour)) => {
|
(Token::Unit(BritishThermalUnit), Token::LexerKeyword(Per), Token::Unit(Hour)) => {
|
||||||
tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerHour);
|
tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerHour);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@ -50,6 +50,13 @@ pub enum FunctionIdentifier {
|
|||||||
Tan,
|
Tan,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum LexerKeyword {
|
||||||
|
Per,
|
||||||
|
PercentChar,
|
||||||
|
In,
|
||||||
|
}
|
||||||
|
|
||||||
mod units;
|
mod units;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -61,6 +68,7 @@ pub enum Token {
|
|||||||
Constant(Constant),
|
Constant(Constant),
|
||||||
Paren, // parser only
|
Paren, // parser only
|
||||||
Per, // lexer only
|
Per, // lexer only
|
||||||
|
LexerKeyword(LexerKeyword),
|
||||||
TextOperator(TextOperator),
|
TextOperator(TextOperator),
|
||||||
Negative, // parser only
|
Negative, // parser only
|
||||||
Unit(units::Unit),
|
Unit(units::Unit),
|
||||||
|
|||||||
@ -263,7 +263,7 @@ fn parse_level_7(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S
|
|||||||
&Token::Unit(_unit) => {
|
&Token::Unit(_unit) => {
|
||||||
let node = AstNode::new(token.clone());
|
let node = AstNode::new(token.clone());
|
||||||
Ok((node, pos + 1))
|
Ok((node, pos + 1))
|
||||||
}
|
},
|
||||||
Token::Constant(_constant) => {
|
Token::Constant(_constant) => {
|
||||||
let node = AstNode::new(token.clone());
|
let node = AstNode::new(token.clone());
|
||||||
Ok((node, pos + 1))
|
Ok((node, pos + 1))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user