daisy/src/parser/mod.rs

231 lines
4.9 KiB
Rust
Raw Normal View History

2023-03-27 21:22:29 -07:00
use std::collections::VecDeque;
2023-03-27 09:47:02 -07:00
mod tokenize;
mod treeify;
mod groupify;
mod find_subs;
2023-03-27 21:22:29 -07:00
use crate::parser::tokenize::tokenize;
use crate::parser::groupify::groupify;
use crate::parser::treeify::treeify;
use crate::parser::find_subs::find_subs;
2023-04-09 08:39:36 -07:00
use crate::quantity::Quantity;
2023-04-13 08:05:52 -07:00
use crate::quantity::Unit;
2023-04-01 13:50:52 -07:00
2023-03-27 21:22:29 -07:00
use crate::tokens::Token;
/// Specifies the location of a token in an input string.
/// Used to locate ParserErrors.
#[derive(Debug)]
#[derive(Copy, Clone)]
pub struct LineLocation {
pub pos: usize,
pub len: usize
}
2023-03-27 21:22:29 -07:00
#[derive(Debug)]
enum PreToken {
PreNumber(LineLocation, String),
PreWord(LineLocation, String),
PreOperator(LineLocation, String),
PreGroupStart(LineLocation),
PreGroupEnd(LineLocation),
PreGroup(LineLocation, VecDeque<PreToken>),
Container(Token)
}
impl PreToken {
#[inline(always)]
pub fn get_line_location(&self) -> &LineLocation {
match self {
PreToken::PreNumber(l, _)
| PreToken::PreWord(l, _)
| PreToken::PreOperator(l, _)
| PreToken::PreGroupStart(l)
| PreToken::PreGroupEnd(l)
| PreToken::PreGroup(l, _)
=> l,
_ => panic!()
}
}
#[inline(always)]
pub fn get_mut_line_location(&mut self) -> &mut LineLocation {
match self {
PreToken::PreNumber(l, _)
| PreToken::PreWord(l, _)
| PreToken::PreOperator(l, _)
| PreToken::PreGroupStart(l)
| PreToken::PreGroupEnd(l)
| PreToken::PreGroup(l, _)
=> l,
_ => panic!()
}
}
#[inline(always)]
pub fn to_token(self) -> Result<Token, (LineLocation, ParserError)>{
match self {
2023-04-07 09:33:55 -07:00
PreToken::PreNumber(l, mut s) => {
// The length check here ensures that
// `.` is not parsed as `0.`
// That should be a syntax error.
if s.len() != 1 && &s[0..1] == "." {
s.insert(0, '0');
}
2023-04-01 14:20:11 -07:00
2023-04-07 18:11:20 -07:00
let r = Quantity::new_rational_from_string(&s);
2023-04-01 14:20:11 -07:00
if r.is_none() {
return Err((l, ParserError::BadNumber))
}
return Ok(Token::Number(r.unwrap()));
2023-03-27 21:22:29 -07:00
},
2023-04-01 14:20:11 -07:00
2023-03-27 21:22:29 -07:00
PreToken::PreWord(l, s) => {
2023-04-09 08:39:36 -07:00
let c = match &s[..] {
2023-03-27 21:22:29 -07:00
// Mathematical constants
2023-04-01 13:50:52 -07:00
// 100 digits of each.
2023-04-10 21:03:16 -07:00
"π"|"pi" => { Some((Quantity::new_float_from_string(
2023-04-09 08:39:36 -07:00
"3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"
).unwrap(), String::from("π")))},
2023-04-10 21:03:16 -07:00
"e" => { Some((Quantity::new_float_from_string(
2023-04-09 08:39:36 -07:00
"2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"
).unwrap(), String::from("e"))) },
2023-04-10 21:03:16 -07:00
"phi"|"φ" => { Some((Quantity::new_float_from_string(
2023-04-09 08:39:36 -07:00
"1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137"
).unwrap(), String::from("φ"))) },
_ => { None }
};
if c.is_some() {
2023-04-10 21:03:16 -07:00
let (a, b) = c.unwrap();
return Ok(Token::Constant(a, b));
2023-04-09 08:39:36 -07:00
}
2023-04-13 08:05:52 -07:00
let c = Unit::from_string(&s);
2023-04-10 21:03:16 -07:00
if c.is_some() { return Ok(Token::Number(c.unwrap())); }
2023-04-09 08:39:36 -07:00
return Err((l, ParserError::Undefined(s)));
2023-03-27 21:22:29 -07:00
}
2023-04-01 13:50:52 -07:00
2023-03-27 21:22:29 -07:00
PreToken::Container(v) => { return Ok(v); }
PreToken::PreOperator(_,_)
| PreToken::PreGroupStart(_)
| PreToken::PreGroupEnd(_)
| PreToken::PreGroup(_, _)
=> panic!()
};
}
}
2023-03-27 09:47:02 -07:00
/// Types of parser errors.
/// If we cannot parse a string, one of these is returned.
#[derive(Debug)]
pub enum ParserError {
//MissingCloseParen,
ExtraCloseParen,
EmptyGroup,
Syntax,
Undefined(String),
BadNumber
}
impl ParserError {
pub fn to_message(&self) -> String {
match self {
//ParserError::MissingCloseParen => {
// String::from("This group is never closed")
//},
ParserError::ExtraCloseParen => {
String::from("Extra close parenthesis")
},
ParserError::EmptyGroup => {
String::from("Groups can't be empty")
},
ParserError::Syntax => {
String::from("Syntax")
},
ParserError::Undefined(s) => {
format!("\"{s}\" isn't defined")
},
ParserError::BadNumber => {
String::from("Invalid number")
}
}
}
}
pub fn parse(
s: &String
) -> Result<
2023-03-27 21:22:29 -07:00
Token,
(LineLocation, ParserError)
2023-03-27 09:47:02 -07:00
> {
2023-03-27 21:22:29 -07:00
let tokens = tokenize(s);
let (_, tokens) = find_subs(tokens);
let g = groupify(tokens)?;
2023-03-29 10:39:15 -07:00
let g = treeify(g)?;
2023-03-27 09:47:02 -07:00
2023-03-29 10:39:15 -07:00
return Ok(g);
2023-03-27 09:47:02 -07:00
}
2023-03-27 22:13:14 -07:00
pub fn substitute(
2023-04-04 10:22:32 -07:00
s: &String, // The string to substitute
2023-03-27 22:13:14 -07:00
c: usize // Location of the cursor right now
2023-04-04 10:22:32 -07:00
) -> (
usize, // Location of cursor in substituted string
String // String with substitutions
) {
if s == "" { return (c, s.clone()) }
2023-03-27 09:47:02 -07:00
let mut new_s = s.clone();
2023-04-04 10:22:32 -07:00
let l = s.chars().count();
2023-03-27 21:22:29 -07:00
let tokens = tokenize(s);
let (subs, _) = find_subs(tokens);
2023-04-04 10:22:32 -07:00
let mut new_c = l - c;
2023-03-27 09:47:02 -07:00
for r in subs.iter() {
2023-04-04 10:22:32 -07:00
// find_subs gives substitutions in reverse order.
if { // Don't substitute if our cursor is inside the substitution
2023-03-27 22:13:14 -07:00
c >= r.0.pos &&
c < r.0.pos+r.0.len
} { continue; }
2023-04-04 10:22:32 -07:00
if c < r.0.pos {
let ct = r.1.chars().count();
if ct >= r.0.len {
if new_c >= ct - r.0.len {
new_c += ct - r.0.len
}
} else {
new_c -= r.0.len - ct
}
}
2023-03-27 09:47:02 -07:00
new_s.replace_range(
r.0.pos..r.0.pos+r.0.len,
&r.1[..]
)
}
2023-04-04 10:22:32 -07:00
return (new_c, new_s);
2023-03-27 09:47:02 -07:00
}