forked from asklyphe-public/asklyphe
initial calculator stuff
This commit is contained in:
parent
0c10b15447
commit
de1d9931b1
3 changed files with 143 additions and 0 deletions
|
@ -14,6 +14,7 @@
|
||||||
pub mod searchbot;
|
pub mod searchbot;
|
||||||
pub mod wikipedia;
|
pub mod wikipedia;
|
||||||
pub mod unit_converter;
|
pub mod unit_converter;
|
||||||
|
pub mod math;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
|
||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
|
|
133
asklyphe-frontend/src/math.rs
Normal file
133
asklyphe-frontend/src/math.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
use tracing::{debug, error};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Calculation {
|
||||||
|
pub equation: String,
|
||||||
|
pub result: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate(query: &str) -> Option<Calculation> {
|
||||||
|
debug!("Got query {}", query);
|
||||||
|
let mut parser = Parser::new(Lexer::new(query));
|
||||||
|
// debug!("final token was: {:?}", lexer.next());
|
||||||
|
// debug!("Tokens: {:?}", lexer.lex_all());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than f64
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Token {
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
Multiply,
|
||||||
|
Divide,
|
||||||
|
Exponent,
|
||||||
|
LParen,
|
||||||
|
RParen,
|
||||||
|
Number(f64),
|
||||||
|
Func(Func),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Func {
|
||||||
|
Sine,
|
||||||
|
Cosine,
|
||||||
|
Tangent,
|
||||||
|
// sin-1, cos-1, tan-1
|
||||||
|
ArcSine,
|
||||||
|
ArcCosine,
|
||||||
|
ArcTangent,
|
||||||
|
Log2,
|
||||||
|
Log10,
|
||||||
|
LogN,
|
||||||
|
Square,
|
||||||
|
SquareRoot,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Fault {
|
||||||
|
Eof,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
// this can probably be swapped out with a lexer generator like Logos if needed
|
||||||
|
|
||||||
|
struct Lexer<'a> {
|
||||||
|
data: &'a str,
|
||||||
|
data_ptr: &'a str,
|
||||||
|
idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: refactor with iterator that returns Option(Token) where one token option is Eof (or a enum of Token(Token) and Eof, or just Option(Option(Token)))
|
||||||
|
impl Lexer<'_> {
|
||||||
|
|
||||||
|
fn new(data: &str) -> Lexer { Lexer {data, data_ptr: data, idx: 0} }
|
||||||
|
|
||||||
|
fn next(&mut self) -> Result<Token, Fault> {
|
||||||
|
match self.data.chars().nth(self.idx) {
|
||||||
|
Some(val) => {
|
||||||
|
debug!("lexing char '{}' at idx {}", val, self.idx);
|
||||||
|
// debug!("current char '{}'", self.data.chars().nth(0).unwrap());
|
||||||
|
self.idx += 1;
|
||||||
|
// TODO: make more efficient
|
||||||
|
self.data_ptr = &self.data[self.idx..];
|
||||||
|
match val {
|
||||||
|
'+' => Ok(Token::Add),
|
||||||
|
'-' => Ok(Token::Subtract),
|
||||||
|
'×' | '*' => Ok(Token::Multiply),
|
||||||
|
'÷' | '/' => Ok(Token::Divide),
|
||||||
|
'^' => Ok(Token::Exponent),
|
||||||
|
'(' => Ok(Token::LParen),
|
||||||
|
')' => Ok(Token::RParen),
|
||||||
|
_ if val.is_whitespace() => self.next(),
|
||||||
|
// TODO: parse - as part of number so I can do '1 + -1' and similar
|
||||||
|
_ if val.is_digit(10) => {
|
||||||
|
let start = self.idx - 1;
|
||||||
|
|
||||||
|
self.data_ptr.chars().take_while(|c| c.is_digit(10)).for_each(|_| self.idx += 1);//.next().unwrap_or(' ').is_digit(10) {self.idx += 1;}
|
||||||
|
|
||||||
|
match self.data[start..self.idx].parse() {
|
||||||
|
Ok(val) => Ok(Token::Number(val)),
|
||||||
|
Err(e) => Err(Fault::Invalid),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
debug!("got invalid char '{}'", val);
|
||||||
|
Err(Fault::Invalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(Fault::Eof),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace with iterator so I can do parser.parse(lexer.iter()) and parse does lex_iter.next() & such
|
||||||
|
fn lex_all(&mut self) -> Option<Vec<Token>> {
|
||||||
|
let mut tokens: Vec<Token> = vec![];
|
||||||
|
loop {
|
||||||
|
match self.next() {
|
||||||
|
Err(Fault::Eof) => return Some(tokens),
|
||||||
|
Err(Fault::Invalid) => return None,
|
||||||
|
Ok(tok) => tokens.push(tok),
|
||||||
|
}
|
||||||
|
// debug!("tokens: {:?}", tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Parser<'a> {
|
||||||
|
lex: Lexer<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser<'_> {
|
||||||
|
fn new(lex: Lexer) -> Parser { Parser {lex} }
|
||||||
|
|
||||||
|
fn parse(&mut self) -> Option<TokenTree>
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: look at that parser video again
|
||||||
|
enum TokenTree {
|
||||||
|
Leaf(Token),
|
||||||
|
Thingy(TokenTree, TokenTree)
|
||||||
|
}
|
|
@ -18,6 +18,8 @@ use crate::unit_converter;
|
||||||
use crate::unit_converter::UnitConversion;
|
use crate::unit_converter::UnitConversion;
|
||||||
use crate::wikipedia::WikipediaSummary;
|
use crate::wikipedia::WikipediaSummary;
|
||||||
use crate::{wikipedia, Opts, ALPHA, BUILT_ON, GIT_COMMIT, VERSION, YEAR};
|
use crate::{wikipedia, Opts, ALPHA, BUILT_ON, GIT_COMMIT, VERSION, YEAR};
|
||||||
|
use crate::math;
|
||||||
|
use crate::math::Calculation;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use asklyphe_common::nats;
|
use asklyphe_common::nats;
|
||||||
use asklyphe_common::nats::bingservice::{
|
use asklyphe_common::nats::bingservice::{
|
||||||
|
@ -68,6 +70,7 @@ pub struct Complications {
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
wikipedia: Option<WikipediaSummary>,
|
wikipedia: Option<WikipediaSummary>,
|
||||||
unit_converter: Option<UnitConversion>,
|
unit_converter: Option<UnitConversion>,
|
||||||
|
math: Option<Calculation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn search(
|
pub async fn search(
|
||||||
|
@ -170,6 +173,12 @@ pub async fn search_js(
|
||||||
unit_query = unit_query.replace("metre", "meter");
|
unit_query = unit_query.replace("metre", "meter");
|
||||||
let unit_comp = unit_converter::convert_unit(&unit_query);
|
let unit_comp = unit_converter::convert_unit(&unit_query);
|
||||||
complications.unit_converter = unit_comp;
|
complications.unit_converter = unit_comp;
|
||||||
|
|
||||||
|
let mut calc_query = query.clone().to_lowercase();
|
||||||
|
calc_query = calc_query.replace("calculate", "").replace("what is", "");
|
||||||
|
let math = math::calculate(&calc_query);
|
||||||
|
complications.math = math;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
complications.disabled = true;
|
complications.disabled = true;
|
||||||
query = query.replace("-complications", "");
|
query = query.replace("-complications", "");
|
||||||
|
|
Loading…
Add table
Reference in a new issue