mirror of https://github.com/rm-dr/daisy
Reorganized code, added basic error handling
parent
b942e9dcf9
commit
2d9eeffb39
24
src/main.rs
24
src/main.rs
|
@ -4,6 +4,8 @@ use std::io::Write;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use termcolor::{
|
use termcolor::{
|
||||||
Color,
|
Color,
|
||||||
ColorChoice,
|
ColorChoice,
|
||||||
|
@ -13,6 +15,9 @@ use termcolor::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
|
use crate::parser::Token;
|
||||||
|
//use crate::parser::ParserError;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
|
|
||||||
const PROMPT_PREFIX: &str = "==> ";
|
const PROMPT_PREFIX: &str = "==> ";
|
||||||
|
|
||||||
|
@ -77,23 +82,26 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tokenize input.
|
// Parse input.
|
||||||
// Fail if we encounter invalid characters.
|
// Fail if we encounter invalid characters.
|
||||||
let mut g = match parser::tokenize::tokenize(&input) {
|
let g: Token = match parser::parse(&input) {
|
||||||
Ok(v) => v,
|
Ok(g) => g,
|
||||||
Err(_) => {
|
Err((l, e)) => {
|
||||||
|
let LineLocation{pos, len} = l;
|
||||||
|
|
||||||
|
let s = " ";
|
||||||
|
let m = "^";
|
||||||
|
println!("{}{} {:?}", s.repeat(pos + 4), m.repeat(len), e);
|
||||||
|
stdout.flush()?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
|
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
|
||||||
write!(stdout, "\n => ")?;
|
write!(stdout, "\n => ")?;
|
||||||
stdout.reset()?;
|
stdout.reset()?;
|
||||||
write!(stdout, "Got {input}\n\n\n")?;
|
write!(stdout, "Got {input}\n\n\n")?;
|
||||||
|
|
||||||
parser::parse(&mut g).expect("Could not parse");
|
|
||||||
|
|
||||||
writeln!(stdout, "Tokenized: {g:#?}")?;
|
writeln!(stdout, "Tokenized: {g:#?}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,67 @@
|
||||||
pub mod tokenize;
|
mod tokenize;
|
||||||
mod replace_pre;
|
mod replace_pre;
|
||||||
mod fold_operators;
|
mod fold_operators;
|
||||||
mod unwrap_groups;
|
mod unwrap_groups;
|
||||||
|
|
||||||
use crate::parser::tokenize::Token;
|
use crate::parser::tokenize::tokenize;
|
||||||
use crate::parser::replace_pre::replace_pre;
|
use crate::parser::replace_pre::replace_pre;
|
||||||
use crate::parser::fold_operators::fold_operators;
|
use crate::parser::fold_operators::fold_operators;
|
||||||
use crate::parser::unwrap_groups::unwrap_groups;
|
use crate::parser::unwrap_groups::unwrap_groups;
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub fn parse(g: &mut Token) -> Result<(), ()> {
|
|
||||||
replace_pre(g)?;
|
|
||||||
fold_operators(g)?;
|
|
||||||
unwrap_groups(g)?;
|
|
||||||
|
|
||||||
return Ok(());
|
#[derive(Debug)]
|
||||||
|
pub enum Token {
|
||||||
|
|
||||||
|
// Used only while tokenizing.
|
||||||
|
// All of these are replaced with one of the tokens below.
|
||||||
|
//
|
||||||
|
// If parsing is successful,
|
||||||
|
// - all PreGroups will vanish
|
||||||
|
// - all PreOperators will become Operators
|
||||||
|
// - all PreNumbers will become Numbers
|
||||||
|
PreGroup(LineLocation, VecDeque<Token>),
|
||||||
|
PreOperator(LineLocation, String),
|
||||||
|
PreNumber(LineLocation, String),
|
||||||
|
PreWord(LineLocation, String),
|
||||||
|
|
||||||
|
Number(f64),
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
Multiply(VecDeque<Token>),
|
||||||
|
Divide(VecDeque<Token>),
|
||||||
|
Add(VecDeque<Token>),
|
||||||
|
Subtract(VecDeque<Token>),
|
||||||
|
Factorial(VecDeque<Token>),
|
||||||
|
Negative(VecDeque<Token>),
|
||||||
|
Power(VecDeque<Token>),
|
||||||
|
Modulo(VecDeque<Token>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct LineLocation {
|
||||||
|
pub pos: usize,
|
||||||
|
pub len: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParserError {
|
||||||
|
InvalidChar,
|
||||||
|
MissingCloseParen,
|
||||||
|
Syntax,
|
||||||
|
BadNumber // Cannot parse a number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse(s: &String) -> Result<Token, (LineLocation, ParserError)> {
|
||||||
|
|
||||||
|
let mut g: Token = tokenize(s)?;
|
||||||
|
replace_pre(&mut g)?;
|
||||||
|
fold_operators(&mut g)?;
|
||||||
|
unwrap_groups(&mut g)?;
|
||||||
|
|
||||||
|
return Ok(g);
|
||||||
}
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use crate::parser::tokenize::Token;
|
|
||||||
|
use crate::parser::Token;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
|
use crate::parser::ParserError;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum OperatorType {
|
enum OperatorType {
|
||||||
Binary, // A binary operator, like a + b
|
Binary, // A binary operator, like a + b
|
||||||
|
@ -12,7 +17,7 @@ fn fold_operators_once(
|
||||||
op_type: &OperatorType,
|
op_type: &OperatorType,
|
||||||
check: fn(&str) -> bool,
|
check: fn(&str) -> bool,
|
||||||
new_token: fn(&str, VecDeque<Token>) -> Token,
|
new_token: fn(&str, VecDeque<Token>) -> Token,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), (LineLocation, ParserError)> {
|
||||||
|
|
||||||
// Groups to process
|
// Groups to process
|
||||||
let mut t_vec: VecDeque<&mut Token> = VecDeque::with_capacity(32);
|
let mut t_vec: VecDeque<&mut Token> = VecDeque::with_capacity(32);
|
||||||
|
@ -122,7 +127,7 @@ fn fold_operators_once(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fold_operators(exp: &mut Token) -> Result<(), ()> {
|
pub fn fold_operators(exp: &mut Token) -> Result<(), (LineLocation, ParserError)> {
|
||||||
fold_operators_once(
|
fold_operators_once(
|
||||||
exp, &OperatorType::UnaryLeft,
|
exp, &OperatorType::UnaryLeft,
|
||||||
|s| s=="!",
|
|s| s=="!",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::parser::tokenize::Token;
|
use crate::parser::Token;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
|
use crate::parser::ParserError;
|
||||||
|
|
||||||
pub fn replace_pre(g: &mut Token) -> Result<(), ()> {
|
|
||||||
|
pub fn replace_pre(g: &mut Token) -> Result<(), (LineLocation, ParserError)> {
|
||||||
|
|
||||||
match g {
|
match g {
|
||||||
Token::PreGroup(_, ref mut vec) => {
|
Token::PreGroup(_, ref mut vec) => {
|
||||||
|
@ -8,10 +11,10 @@ pub fn replace_pre(g: &mut Token) -> Result<(), ()> {
|
||||||
replace_pre(i)?;
|
replace_pre(i)?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::PreNumber(_, s) => {
|
Token::PreNumber(l, s) => {
|
||||||
let n = match s.parse() {
|
let n = match s.parse() {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(_) => panic!()
|
Err(_) => return Err((*l, ParserError::BadNumber))
|
||||||
};
|
};
|
||||||
*g = Token::Number(n);
|
*g = Token::Number(n);
|
||||||
}
|
}
|
||||||
|
@ -19,8 +22,7 @@ pub fn replace_pre(g: &mut Token) -> Result<(), ()> {
|
||||||
if s == "mod" {
|
if s == "mod" {
|
||||||
*g = Token::PreOperator(*l, String::from("mod"));
|
*g = Token::PreOperator(*l, String::from("mod"));
|
||||||
} else {
|
} else {
|
||||||
return Err(());
|
return Err((*l, ParserError::Syntax));
|
||||||
//new.push_back(t);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::PreOperator(_, _) => {},
|
Token::PreOperator(_, _) => {},
|
||||||
|
|
|
@ -1,44 +1,8 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
#[derive(Debug)]
|
use crate::parser::Token;
|
||||||
#[derive(Copy, Clone)]
|
use crate::parser::LineLocation;
|
||||||
pub struct LineLocation {
|
use crate::parser::ParserError;
|
||||||
pos: usize,
|
|
||||||
len: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Token {
|
|
||||||
|
|
||||||
// Only used after tokenizing
|
|
||||||
PreGroup(LineLocation, VecDeque<Token>),
|
|
||||||
PreOperator(LineLocation, String),
|
|
||||||
PreNumber(LineLocation, String),
|
|
||||||
PreWord(LineLocation, String),
|
|
||||||
|
|
||||||
// All PreGroups should vanish after operator folding
|
|
||||||
// All PreOperators should become Operators
|
|
||||||
// All PreNumbers should become Numbers
|
|
||||||
// All PreWords should become TODO.
|
|
||||||
|
|
||||||
// Only used in tree
|
|
||||||
|
|
||||||
Number(f64),
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
Multiply(VecDeque<Token>),
|
|
||||||
Divide(VecDeque<Token>),
|
|
||||||
Add(VecDeque<Token>),
|
|
||||||
Subtract(VecDeque<Token>),
|
|
||||||
Factorial(VecDeque<Token>),
|
|
||||||
Negative(VecDeque<Token>),
|
|
||||||
Power(VecDeque<Token>),
|
|
||||||
Modulo(VecDeque<Token>),
|
|
||||||
|
|
||||||
//Function(String, VecDeque<Token>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn update_line_location(mut t: Token, stop_i: usize) -> Token {
|
fn update_line_location(mut t: Token, stop_i: usize) -> Token {
|
||||||
|
@ -60,16 +24,8 @@ fn update_line_location(mut t: Token, stop_i: usize) -> Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Turn a string into a set of tokens.
|
|
||||||
/// Does not check syntax. Fails if `input` contains an invalid character.
|
pub fn tokenize(input: &String) -> Result<Token, (LineLocation, ParserError)> {
|
||||||
//
|
|
||||||
// # 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 t: Option<Token> = None; // The current token we're reading
|
||||||
let mut g: Vec<Token> = Vec::with_capacity(8); // Vector of "grouping levels"
|
let mut g: Vec<Token> = Vec::with_capacity(8); // Vector of "grouping levels"
|
||||||
g.push(Token::PreGroup(LineLocation{pos: 0, len: 0}, VecDeque::with_capacity(8)));
|
g.push(Token::PreGroup(LineLocation{pos: 0, len: 0}, VecDeque::with_capacity(8)));
|
||||||
|
@ -190,7 +146,7 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
};
|
};
|
||||||
|
|
||||||
g_now.push_back(update_line_location(new_group, i));
|
g_now.push_back(update_line_location(new_group, i+1));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Space. Basic seperator.
|
// Space. Basic seperator.
|
||||||
|
@ -199,7 +155,7 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid token
|
// Invalid token
|
||||||
_ => { return Err(()); }
|
_ => { return Err((LineLocation{pos: i, len: 1}, ParserError::InvalidChar)); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,5 +166,21 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
|
||||||
};
|
};
|
||||||
if t.is_some() { g_now.push_back(update_line_location(t.unwrap(), input.len())); }
|
if t.is_some() { g_now.push_back(update_line_location(t.unwrap(), input.len())); }
|
||||||
|
|
||||||
|
if g.len() != 1 {
|
||||||
|
let q: LineLocation = match g.last_mut().unwrap() {
|
||||||
|
Token::PreGroup(l, _) => *l,
|
||||||
|
_ => panic!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let LineLocation{pos:p, ..} = q;
|
||||||
|
return Err((
|
||||||
|
LineLocation{
|
||||||
|
pos: p,
|
||||||
|
len: input.len() - p
|
||||||
|
},
|
||||||
|
ParserError::MissingCloseParen
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(g.pop().unwrap());
|
return Ok(g.pop().unwrap());
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
use crate::parser::tokenize::Token;
|
use crate::parser::Token;
|
||||||
|
use crate::parser::ParserError;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
|
|
||||||
pub fn unwrap_groups(g: &mut Token) -> Result<(), ()> {
|
pub fn unwrap_groups(g: &mut Token) -> Result<(), (LineLocation, ParserError)> {
|
||||||
|
|
||||||
match g {
|
match g {
|
||||||
// If g is a PreGroup, unwrap it
|
// If g is a PreGroup, unwrap it
|
||||||
Token::PreGroup(_, ref mut vec) => {
|
Token::PreGroup(l, ref mut vec) => {
|
||||||
if vec.len() != 1 {
|
if vec.len() != 1 {
|
||||||
panic!();
|
return Err((*l, ParserError::Syntax));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut i = vec.pop_front().unwrap();
|
let mut i = vec.pop_front().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue