diff --git a/src/main.rs b/src/main.rs index dfb060a..f07d248 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,6 @@ pub enum Operator { Divide, Modulo, Caret, - // Percent, - // Factorial, LeftParen, // lexer only RightParen, // lexer only } @@ -84,20 +82,22 @@ fn main() { match lexer::lex(s) { Ok(tokens) => { let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32; - // println!("Lexed TokenVector: {:?}", tokens); let parse_start = Instant::now(); match parser::parse(&tokens) { Ok(ast) => { let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32; - // println!("Parsed AstNode: {:#?}", ast); let eval_start = Instant::now(); match evaluator::evaluate(&ast) { Ok(answer) => { let eval_time = Instant::now().duration_since(eval_start).as_nanos() as f32; - println!("Evaluated answer: {:#?}", answer); + println!("Lexed TokenVector: {:?}", tokens); + println!("Parsed AstNode: {:#?}", ast); + + println!("Evaluated value: {} {:?}", answer.value, answer.unit); + println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0); println!("\u{23f1} {:.3}ms parsing", parse_time/1000.0/1000.0); println!("\u{23f1} {:.3}ms evaluation", eval_time/1000.0/1000.0); @@ -108,6 +108,7 @@ fn main() { }, Err(e) => println!("Parsing error: {}", e), } + }, Err(e) => println!("Lexing error: {}", e), } diff --git a/src/parser.rs b/src/parser.rs index 9f777cb..d1328cf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -77,6 +77,7 @@ fn parse_level_2(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S // level 3 precedence: *, /, modulo fn parse_level_3(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), String> { let (mut node, mut pos) = parse_level_4(tokens, pos)?; + loop { let token = tokens.get(pos); match token { @@ -88,6 +89,84 @@ fn parse_level_3(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S node = new_node; pos = next_pos; }, + + // Below is implicative multiplication, for example '2pi'. Constants and + // such will only end up here if they were unable to be parsed as part of + // other operators. + // Note that this match statement matches an AstNode token, but the + // matches nested inside check the TokenVector. That's why we for example + // match a FunctionIdentifier, and inside that, a RightParen. + + // pi2, )2 + Some(&Token::Number(_)) => { + let last_token = tokens.get(pos - 1); + match last_token { + Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => { + let (right_node, next_pos) = parse_level_4(tokens, pos)?; + let mut new_node = AstNode::new(Token::Operator(Multiply)); + new_node.children.push(node); + new_node.children.push(right_node); + node = new_node; + pos = next_pos; + }, + _ => { + return Ok((node, pos)); + }, + } + }, + // 2pi, )pi + Some(&Token::Constant(_)) => { + let last_token = tokens.get(pos - 1); + match last_token { + Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => { + let (right_node, next_pos) = parse_level_4(tokens, pos)?; + let mut new_node = AstNode::new(Token::Operator(Multiply)); + new_node.children.push(node); + new_node.children.push(right_node); + node = new_node; + pos = next_pos; + }, + _ => { + return Ok((node, pos)); + }, + } + }, + // 2log(1), )log(1) + Some(&Token::FunctionIdentifier(_)) => { + let last_token = tokens.get(pos - 1); + match last_token { + Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => { + let (right_node, next_pos) = parse_level_4(tokens, pos)?; + let mut new_node = AstNode::new(Token::Operator(Multiply)); + new_node.children.push(node); + new_node.children.push(right_node); + node = new_node; + pos = next_pos; + }, + _ => { + return Ok((node, pos)); + }, + } + }, + // 2(3), pi(3), )(3) + Some(&Token::Operator(LeftParen)) => { + let last_token = tokens.get(pos - 1); + println!("{:?}", token); + println!("{:?}", last_token); + match last_token { + Some(&Token::Number(_)) | Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => { + let (right_node, next_pos) = parse_level_4(tokens, pos)?; + let mut new_node = AstNode::new(Token::Operator(Multiply)); + new_node.children.push(node); + new_node.children.push(right_node); + node = new_node; + pos = next_pos; + }, + _ => { + return Ok((node, pos)); + }, + } + }, _ => { return Ok((node, pos)); }, @@ -121,10 +200,10 @@ fn parse_level_5(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S // Here we parse the negative unary operator. If the current token // is a minus, we wrap the right_node inside a Negative AstNode. // - // Why doesn't this parse 4-5? First, we will first get a 4. - // In which case, we just return the result of parse_level_6(), which will - // include the pos of +. This will then go down to level 2 and be parsed as - // a normal minus operator. + // Why doesn't this parse 4-5? First, we will first get a 4. In which case, + // we just return the result of parse_level_6(), which will include the pos + // of +. This will then go down to level 2 and be parsed as a normal minus + // operator. // The difference is that in other levels, we parse higher priorities // immediately, while in this one we instead check if the current token // is a minus, and if not, we then return the higher priority as normal. @@ -215,9 +294,9 @@ fn parse_level_7(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S Token::Operator(LeftParen) => { parse_level_1(tokens, pos + 1).and_then(|(node, next_pos)| { if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) { - let mut paren = AstNode::new(Token::Paren); - paren.children.push(node); - Ok((paren, next_pos + 1)) + let mut paren_node = AstNode::new(Token::Paren); + paren_node.children.push(node); + Ok((paren_node, next_pos + 1)) } else { Err(format!("Expected closing paren at {} but found {:?}", next_pos, tokens.get(next_pos))) }