Skip to content

Commit 4f1ce14

Browse files
committed
BUG: fixed unexpected decimal error and empty calculation errors
1 parent 553d6e6 commit 4f1ce14

File tree

4 files changed

+66
-26
lines changed

4 files changed

+66
-26
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## A simple math interpreter
2+
Currently supports `PLUS`, `MINUS`, `MULTIPLY`, `DIVIDE`, `POWER`
3+
4+
I'd like to add functions such as `sin(x)` into the interpreter but this code is messy and all over the place. Maybe one day when I learn more I can redo this project.

src/lexer.rs

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,33 @@ use crate::{
66
};
77

88
const DIGITS: &str = ".0123456789";
9+
const LETTERS: &str = "abcdefghijklmnopqrstuvwxyz";
910

10-
pub struct Lexer {
11-
source: String,
11+
pub struct Lexer<I: Iterator<Item = char> + Clone> {
12+
// source: String,
13+
iter: Peekable<I>,
1214
}
1315

14-
impl Lexer {
15-
pub fn new(source: String) -> Self {
16-
Self { source }
16+
impl<I: Iterator<Item = char> + Clone> Lexer<I> {
17+
pub fn new(source: I) -> Self {
18+
Self {
19+
// source,
20+
iter: source.peekable(),
21+
}
1722
}
1823

19-
pub fn tokenize(&self) -> Result<Vec<Token>, ErrorReason> {
24+
pub fn tokenize(&mut self) -> Result<Vec<Token>, ErrorReason> {
2025
let mut tokens: Vec<Token> = Vec::new();
21-
let mut chars = self
22-
.source
23-
.chars()
24-
.filter(|c| !c.is_whitespace())
25-
.peekable();
26-
27-
while let Some(&current) = chars.peek() {
28-
// Best solution i could find to making sure it doesn't skip
26+
27+
// Best solution i could find to making sure it doesn't skip
28+
while let Some(&current) = self.iter.peek() {
29+
if current.is_ascii_whitespace() {
30+
self.iter.next();
31+
continue;
32+
}
33+
2934
if DIGITS.contains(current) {
30-
tokens.push(self.generate_number(&mut chars)?);
35+
tokens.push(self.generate_number()?);
3136
} else {
3237
let token = match current {
3338
'+' => Token::new(TokenKind::Plus, None),
@@ -37,44 +42,67 @@ impl Lexer {
3742
'^' => Token::new(TokenKind::Power, None),
3843
'(' => Token::new(TokenKind::LParen, None),
3944
')' => Token::new(TokenKind::RParen, None),
45+
// 'a'..='z' => {}
4046
_ => Token::new(
4147
TokenKind::Unknown,
4248
Some(TokenValue::StrValue(current.to_string())),
4349
),
4450
};
4551
tokens.push(token);
46-
chars.next();
52+
self.iter.next();
4753
}
4854
}
4955

5056
Ok(tokens)
5157
}
5258

53-
fn generate_number<I>(&self, chars: &mut Peekable<I>) -> Result<Token, ErrorReason>
59+
fn read_function(&mut self) -> Token {
60+
// TODO: read the parameters of function
61+
// bruh i cant figure this out rn i do later
62+
let mut name = String::new();
63+
64+
while let Some(&current) = self.iter.peek() {
65+
if LETTERS.contains(current) {
66+
name.push(current);
67+
}
68+
69+
if current == '(' {
70+
self.iter.next(); // Consume '('
71+
72+
}
73+
self.iter.next();
74+
}
75+
Token::new(TokenKind::Function, Some(TokenValue::FuncParams(name, 0))) // change params later
76+
}
77+
78+
fn generate_number(&mut self) -> Result<Token, ErrorReason>
5479
where
5580
I: Iterator<Item = char>,
5681
{
5782
let mut decimal_point_counter = 0;
5883
let mut number = String::new();
5984

60-
while let Some(&current) = chars.peek() {
85+
while let Some(&current) = self.iter.peek() {
6186
if current == '.' {
6287
decimal_point_counter += 1;
6388
if decimal_point_counter > 1 {
6489
return Err(ErrorReason::Error("Too many decimal points".into()));
6590
}
6691
}
6792
number.push(current);
68-
chars.next();
93+
self.iter.next();
6994

7095
// Peek the next character and check if it's valid for a number
71-
if let Some(&next_char) = chars.peek() {
96+
if let Some(&next_char) = self.iter.peek() {
7297
if !DIGITS.contains(next_char) {
7398
if number.trim() == "." {
74-
return Err(ErrorReason::Error("Random decimal place found ".into()));
99+
return Err(ErrorReason::Error("Invalid sequence".into()));
75100
}
76101
break;
77102
}
103+
} else {
104+
// this is PROBABLY the error but i cbf actually finding the bugs
105+
return Err(ErrorReason::Error("Invalid sequence".into()));
78106
}
79107
}
80108

src/main.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::io::{stdin, stdout, Write};
99
use colored::Colorize;
1010
use errors::{ErrorReason, ParserError};
1111
use lexer::Lexer;
12-
use parser::Parser;
12+
use parser::{ASTNode, Parser};
1313
use token::{Token, TokenKind, TokenValue};
1414

1515
/// Prompts user for input and returns trimmed result
@@ -30,7 +30,7 @@ fn main() {
3030
loop {
3131
let input = prompt_input("> ");
3232

33-
let lexer = Lexer::new(input);
33+
let mut lexer = Lexer::new(input.chars());
3434
let tokens_result = lexer.tokenize();
3535
if let Err(err) = tokens_result {
3636
println!("{}", err);
@@ -43,16 +43,23 @@ fn main() {
4343
for err in token_errors {
4444
println!(
4545
"{}",
46-
ParserError::new(ErrorReason::Error(format!("Invalid sequence: '{}'", err)))
47-
.description
46+
ParserError::new(ErrorReason::Error(format!(
47+
"Invalid sequence: '{}'",
48+
err
49+
)))
50+
.description
4851
);
4952
}
5053
println!();
5154
} else {
5255
pretty_print_tokens(tokens.clone());
5356
let mut parser = Parser::new(tokens.into_iter());
5457
let result = parser.parse_expr();
55-
println!("{:?}", result);
58+
// println!("{:?}", result);
59+
if result.is_err() {
60+
println!("{}", result.unwrap_err().description);
61+
continue;
62+
}
5663
println!(
5764
"{} {}",
5865
"RESULT:".bright_green(),

src/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub enum TokenKind {
1818

1919
#[derive(Debug, PartialEq, Clone)]
2020
pub enum TokenValue {
21+
FuncParams(String, u8), // function_name, num_of_params
2122
StrValue(String),
2223
NumValue(f64),
2324
None,

0 commit comments

Comments
 (0)