feat(lexer): add lexer
added basic lexer
This commit is contained in:
6 files changed
+650
-2
No files matched your search
+29
-2
@@ -1,3 +1,30 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::io::{self, IsTerminal, Write};
|
||||
|
||||
mod math;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
prompt()?;
|
||||
|
||||
for line in io::stdin().lines() {
|
||||
if let Err(err) = line {
|
||||
eprintln!("error reading line: {}", err);
|
||||
break;
|
||||
}
|
||||
|
||||
let line = line.unwrap();
|
||||
let parsed = math::parse(line.trim());
|
||||
println!("{:?}", parsed);
|
||||
|
||||
prompt()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prompt() -> io::Result<()> {
|
||||
if io::stdin().is_terminal() {
|
||||
print!("> ");
|
||||
io::stdout().flush()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::math::types::Operator;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Token {
|
||||
Number(Decimal),
|
||||
Identifier(String),
|
||||
Operator(Operator),
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
Eof,
|
||||
}
|
||||
|
||||
pub fn from(source: &str) -> Lexer<'_> {
|
||||
Lexer::new(source)
|
||||
}
|
||||
|
||||
pub struct Lexer<'a> {
|
||||
chars: std::iter::Peekable<std::str::Chars<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Lexer<'a> {
|
||||
fn new(source: &'a str) -> Self {
|
||||
Self {
|
||||
chars: source.chars().peekable(),
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_whitespace(&mut self) {
|
||||
while let Some(&ch) = self.chars.peek() {
|
||||
if ch.is_whitespace() {
|
||||
self.chars.next();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_number(&mut self, initial: char) -> Token {
|
||||
let mut number = String::from(initial);
|
||||
while let Some(&ch) = self.chars.peek() {
|
||||
if ch.is_numeric() || ch == '.' {
|
||||
number.push(ch);
|
||||
self.chars.next();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
let number = Decimal::from_str(&number).expect("unable to parse number");
|
||||
Token::Number(number)
|
||||
}
|
||||
|
||||
fn parse_identifier(&mut self, initial: char) -> Token {
|
||||
let mut identifier = String::from(initial);
|
||||
while let Some(&ch) = self.chars.peek() {
|
||||
if ch.is_alphabetic() {
|
||||
identifier.push(ch);
|
||||
self.chars.next();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Token::Identifier(identifier)
|
||||
}
|
||||
|
||||
pub fn next_token(&mut self) -> Token {
|
||||
self.skip_whitespace();
|
||||
|
||||
match self.chars.next() {
|
||||
Some('(') => Token::OpenParen,
|
||||
Some(')') => Token::CloseParen,
|
||||
Some('+') => Token::Operator(Operator::Add),
|
||||
Some('-') => Token::Operator(Operator::Subtract),
|
||||
Some('*') => Token::Operator(Operator::Multiply),
|
||||
Some('/') => Token::Operator(Operator::Divide),
|
||||
Some('%') => Token::Operator(Operator::Modulo),
|
||||
Some('^') => Token::Operator(Operator::Power),
|
||||
None => Token::Eof,
|
||||
Some(ch) => {
|
||||
if ch.is_numeric() || ch == '.' {
|
||||
self.parse_number(ch)
|
||||
} else if ch.is_alphabetic() {
|
||||
self.parse_identifier(ch)
|
||||
} else {
|
||||
panic!("unexpected character: {}", ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Lexer<'a> {
|
||||
type Item = Token;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let token = self.next_token();
|
||||
match token {
|
||||
Token::Eof => None,
|
||||
_ => Some(token),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
mod lexer;
|
||||
|
||||
pub mod types;
|
||||
|
||||
pub fn parse(source: &str) -> Vec<lexer::Token> {
|
||||
let lexer = lexer::from(source);
|
||||
lexer.collect()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expression {
|
||||
Number(Decimal),
|
||||
Fraction(Box<Expression>, Box<Expression>),
|
||||
Variable(String),
|
||||
Operation(Operator, Box<Expression>, Box<Expression>),
|
||||
Negative(Box<Expression>),
|
||||
Function(String, Vec<Expression>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Operator {
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Power,
|
||||
Modulo,
|
||||
}
|
||||
Reference in new issue
Block a user