Cleanup, added more operators

This commit is contained in:
2023-03-19 20:32:49 -07:00
parent a4506e775a
commit 579f7f2ece
4 changed files with 159 additions and 99 deletions

158
src/parser/tokenize.rs Normal file
View File

@ -0,0 +1,158 @@
use std::collections::VecDeque;
#[derive(Debug)]
#[derive(Clone)]
pub enum Token {
// Only used after tokenizing
Negative,
Factorial,
Group(VecDeque<Token>), // Will be expanded during tree folding
Operator(String), // Will become Ops during tree folding
// Used in both
Number(String),
Word(String),
// Only used in tree
Multiply(VecDeque<Token>),
Divide(VecDeque<Token>),
Add(VecDeque<Token>),
Subtract(VecDeque<Token>),
Fac(VecDeque<Token>),
Neg(VecDeque<Token>)
}
/// Turn a string into a set of tokens.
/// Does not check syntax. Fails if `input` contains an invalid character.
//
// # Arguments:
// `input`: A string like `(-3*2.2)/3`
//
// # Returns:
// * `Ok(Vec<token>)` if we were successful.
// * `Err(())` if we couldn't tokenize this string.
pub fn tokenize(input: &String) -> Result<Token, ()> {
let mut t: Option<Token> = None; // The current token we're reading
let mut g: Vec<Token> = Vec::with_capacity(8); // Vector of "grouping levels"
g.push(Token::Group(VecDeque::with_capacity(8)));
for c in input.chars() {
// The grouping level we're on now
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x,
_ => panic!()
};
match c {
'!' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
g_now.push_back(Token::Factorial);
},
// Minus sign can be both a Negative and an Operator.
// Needs special treatment.
'-' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
match g_now.back() {
// If previous token was any of the following,
// this is the "minus" operator
Some(Token::Number(_)) |
Some(Token::Group(_)) |
Some(Token::Word(_)) => {
g_now.push_back(Token::Operator(String::from(c)));
},
// Otherwise, this is a negative sign.
_ => { g_now.push_back(Token::Negative); }
};
},
// Number.
// Commas act just like dots.
',' | '.' | '0'..='9' => {
match &mut t {
// If we're already building a number,
// append.
Some(Token::Number(val)) => {
val.push(if c == ',' {'.'} else {c});
},
// If we're not building a number, finalize
// previous token and start one.
_ => {
if t.is_some() { g_now.push_back(t.unwrap()); }
t = Some(Token::Number(String::from(c)));
}
};
},
// Word
'A'..='Z' |
'a'..='z' => {
match &mut t {
// If we're already building a number,
// append.
Some(Token::Word(val)) => {
val.push(c);
},
// If we're not building a number, finalize
// previous token and start one.
_ => {
if t.is_some() { g_now.push_back(t.unwrap()); }
t = Some(Token::Word(String::from(c)));
}
};
},
// Operation
// Always one character
'+' | '*' | '/' | '^' => {
// Finalize previous token
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
g_now.push_back(Token::Operator(String::from(c)));
}
// Groups
// Always one character
'(' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
g.push(Token::Group(VecDeque::with_capacity(8)));
},
')' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
let new_group: Token = g.pop().unwrap();
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x,
_ => panic!()
};
g_now.push_back(new_group);
},
// Space. Basic seperator.
' ' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
}
// Invalid token
_ => { return Err(()); }
};
}
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x,
_ => panic!()
};
if t.is_some() { g_now.push_back(t.unwrap()); }
return Ok(g.pop().unwrap());
}

145
src/parser/treefold.rs Normal file
View File

@ -0,0 +1,145 @@
use std::collections::VecDeque;
use crate::parser::tokenize::Token;
fn treefold_one(
exp: &mut Token, // Must be a group
check: fn(&Token) -> bool,
op_type: u8,
new_token: fn(VecDeque<Token>) -> Token,
) -> Result<(), ()> {
// Groups to process
let mut t_vec: VecDeque<&mut Token> = VecDeque::with_capacity(32);
t_vec.push_back(exp);
while t_vec.len() > 0 {
// The group we're currently working with
let g: &mut Token = t_vec.pop_front().unwrap();
let g_inner: &mut VecDeque<Token> = match g {
Token::Group(ref mut x) => x,
_ => panic!()
};
let mut new: VecDeque<Token> = VecDeque::with_capacity(8);
// Build new group array
while g_inner.len() > 0 {
let t: Token = match g_inner.pop_front() {
Some(o) => o,
None => break
};
if check(&t) {
match op_type {
0 => {
let mut last: Token = new.pop_back().unwrap();
if let Token::Group(_) = last {
treefold_one(&mut last, check, op_type, new_token).unwrap();
}
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(1);
new_token_args.push_back(last);
new.push_back(new_token(new_token_args));
},
1 => {
let mut next: Token = g_inner.pop_front().unwrap().clone();
if let Token::Group(_) = next {
treefold_one(&mut next, check, op_type, new_token).unwrap();
}
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(1);
new_token_args.push_back(next);
new.push_back(new_token(new_token_args));
},
2 => {
let mut last: Token = new.pop_back().unwrap();
let mut next: Token = g_inner.pop_front().unwrap().clone();
// TODO: append to t_vec, do this without recursion.
if let Token::Group(_) = last {
treefold_one(&mut last, check, op_type, new_token).unwrap();
}
if let Token::Group(_) = next {
treefold_one(&mut next, check, op_type, new_token).unwrap();
}
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(2);
new_token_args.push_back(last);
new_token_args.push_back(next);
new.push_back(new_token(new_token_args));
},
_ => panic!()
};
} else {
new.push_back(t.clone());
}
}
*g_inner = new;
}
Ok(())
}
fn is_mult(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "*"},
_ => false
}
}
fn new_mult(v: VecDeque<Token>) -> Token { Token::Multiply(v) }
fn is_add(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "+"},
_ => false
}
}
fn new_add(v: VecDeque<Token>) -> Token { Token::Add(v) }
fn is_div(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "/"},
_ => false
}
}
fn new_div(v: VecDeque<Token>) -> Token { Token::Divide(v) }
fn is_sub(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "-"},
_ => false
}
}
fn new_sub(v: VecDeque<Token>) -> Token { Token::Subtract(v) }
fn is_fac(t: &Token) -> bool {
match t {
Token::Factorial => true,
_ => false
}
}
fn new_fac(v: VecDeque<Token>) -> Token { Token::Fac(v) }
fn is_neg(t: &Token) -> bool {
match t {
Token::Negative => true,
_ => false
}
}
fn new_neg(v: VecDeque<Token>) -> Token { Token::Neg(v) }
pub fn treefold(exp: &mut Token) -> Result<(), ()> {
treefold_one(exp, is_fac, 0, new_fac)?;
treefold_one(exp, is_neg, 1, new_neg)?;
treefold_one(exp, is_mult, 2, new_mult)?;
treefold_one(exp, is_div, 2, new_div)?;
treefold_one(exp, is_add, 2, new_add)?;
treefold_one(exp, is_sub, 2, new_sub)?;
Ok(())
}