From d01700dfb6226fb206df98c2341cd418ce40f9db Mon Sep 17 00:00:00 2001 From: trivernis Date: Tue, 4 Aug 2020 16:50:07 +0200 Subject: [PATCH] Add group tree parsing --- src/elements/group.rs | 38 +++++++------- src/elements/literal.rs | 20 +++---- src/elements/mod.rs | 9 ++-- src/elements/special.rs | 29 +++++++---- src/lib.rs | 39 ++++++++++++-- src/parsing/tree_parser.rs | 104 ++++++++++++++++++++++++++++++++++--- src/tokens/mappings.rs | 8 +-- src/tokens/mod.rs | 5 +- src/utils.rs | 8 +++ 9 files changed, 198 insertions(+), 62 deletions(-) create mode 100644 src/utils.rs diff --git a/src/elements/group.rs b/src/elements/group.rs index 5c1009d..4b47cf2 100644 --- a/src/elements/group.rs +++ b/src/elements/group.rs @@ -1,6 +1,6 @@ use crate::elements::special::Expression; -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Group { Parentheses(Parentheses), Brackets(Brackets), @@ -13,47 +13,47 @@ pub enum Group { Norm(Norm), } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Parentheses { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Brackets { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Braces { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Angles { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct XGroup { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Abs { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Floor { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Ceil { - inner: Box, + pub inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Norm { - inner: Box, + pub inner: Box, } diff --git a/src/elements/literal.rs b/src/elements/literal.rs index 43c35d2..2521ed2 100644 --- a/src/elements/literal.rs +++ b/src/elements/literal.rs @@ -1,11 +1,11 @@ use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation}; -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Literal { Integer, - Text(TextNode), - Symbol(SymbolNode), - Number(NumberNode), + Text(PlainText), + Symbol(Symbol), + Number(Number), Greek(Greek), FontCommand(FontCommand), Relation(Relation), @@ -16,17 +16,17 @@ pub enum Literal { Operation(Operation), } -#[derive(Clone, Debug)] -pub struct TextNode { +#[derive(Debug, Clone, PartialOrd, PartialEq)] +pub struct PlainText { pub(crate) text: String, } -#[derive(Clone, Debug)] -pub struct SymbolNode { +#[derive(Debug, Clone, PartialOrd, PartialEq)] +pub struct Symbol { pub(crate) symbol: String, } -#[derive(Clone, Debug)] -pub struct NumberNode { +#[derive(Debug, Clone, PartialOrd, PartialEq)] +pub struct Number { pub(crate) number: String, } diff --git a/src/elements/mod.rs b/src/elements/mod.rs index ae8f24b..e102c7c 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -1,20 +1,17 @@ use crate::elements::group::Group; use crate::elements::literal::Literal; use crate::elements::special::Special; +use crate::utils::Boxed; pub mod group; pub mod literal; pub mod special; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Element { Literal(Literal), Special(Special), Group(Group), } -impl Element { - pub fn boxed(self) -> Box { - Box::new(self) - } -} +impl Boxed for Element {} diff --git a/src/elements/special.rs b/src/elements/special.rs index 8e39e7e..89ae407 100644 --- a/src/elements/special.rs +++ b/src/elements/special.rs @@ -1,63 +1,70 @@ use crate::elements::Element; +use crate::utils::Boxed; -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Expression { children: Vec, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Special { Sum(Sum), Prod(Prod), Frac(Frac), Pow(Pow), + Sub(Sub), Sqrt(Sqrt), Root(Root), Integral(Integral), OIntegral(OIntegral), } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Sum { pub top: Option>, pub bottom: Option>, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Prod { pub top: Option>, pub bottom: Option>, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Frac { pub(crate) top: Box, pub(crate) bottom: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Pow { pub(crate) exp: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] +pub struct Sub { + pub(crate) lower: Box, +} + +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Sqrt { pub(crate) inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Root { pub(crate) base: Box, pub(crate) inner: Box, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Integral { pub(crate) top: Option>, pub(crate) bottom: Option>, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct OIntegral { pub(crate) top: Option>, pub(crate) bottom: Option>, @@ -75,6 +82,8 @@ impl Expression { } } +impl Boxed for Expression {} + impl Sum { pub fn new() -> Self { Self { diff --git a/src/lib.rs b/src/lib.rs index db27fa1..1b51d89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,18 @@ extern crate lazy_static; pub mod elements; pub mod parsing; mod tokens; +mod utils; #[cfg(test)] mod tests { + use crate::elements::literal::{Literal, Number}; + use crate::elements::special::{Expression, Special, Sum}; + use crate::elements::Element; use crate::parsing::tokenizer::Tokenizer; use crate::parsing::tree_parser::TreeParser; + use crate::tokens::Function::Exp; use crate::tokens::{Function, Grouping, Misc, Operation, Relation, Text, Token}; + use crate::utils::Boxed; use std::fs; use test::Bencher; @@ -114,16 +120,41 @@ mod tests { ) } - //#[test] - fn it_parses_into_a_tree() { - let expression = "sum_2^3 + 4^4"; + #[test] + fn it_parses_into_a_tree1() { + let expression = "sum_2^3"; let mut tokenizer = Tokenizer::new(expression.to_string()); let tokens = tokenizer.parse(); let mut tree_parser = TreeParser::new(tokens.clone()); let expression = tree_parser.parse(); + let mut test_expression = Expression::new(); + test_expression.add_child(Element::Special(Special::Sum(Sum { + bottom: Some( + Element::Literal(Literal::Number(Number { + number: "2".to_string(), + })) + .boxed(), + ), + top: Some( + Element::Literal(Literal::Number(Number { + number: "3".to_string(), + })) + .boxed(), + ), + }))); + assert_eq!(expression, test_expression) + } + + #[test] + fn it_parses_into_a_tree2() { + let str_expression = "sum_2^3 + abs(4^4) - 1^(2*2)_2"; + let mut tokenizer = Tokenizer::new(str_expression.to_string()); + let tokens = tokenizer.parse(); + let mut tree_parser = TreeParser::new(tokens.clone()); + let expression = tree_parser.parse(); fs::write( "test-files/test.txt", - format!("{:?}\n\n{:?}", tokens, expression), + format!("{}\n\n{:?}\n\n{:#?}", str_expression, tokens, expression), ); } diff --git a/src/parsing/tree_parser.rs b/src/parsing/tree_parser.rs index f3a2166..0ba5296 100644 --- a/src/parsing/tree_parser.rs +++ b/src/parsing/tree_parser.rs @@ -1,18 +1,27 @@ -use crate::elements::literal::{Literal, NumberNode, SymbolNode, TextNode}; +use crate::elements::group::{ + Abs, Angles, Braces, Brackets, Ceil, Floor, Group, Norm, Parentheses, XGroup, +}; +use crate::elements::literal::{Literal, Number, PlainText, Symbol}; use crate::elements::special::{ - Expression, Frac, Integral, OIntegral, Pow, Prod, Root, Special, Sqrt, Sum, + Expression, Frac, Integral, OIntegral, Pow, Prod, Root, Special, Sqrt, Sub, Sum, }; use crate::elements::Element; -use crate::tokens::{Misc, Operation, Text, Token}; +use crate::tokens::{Grouping, Misc, Operation, Text, Token}; +use crate::utils::Boxed; pub struct TreeParser { tokens: Vec, index: usize, + group_return: bool, } impl TreeParser { pub fn new(tokens: Vec) -> Self { - Self { tokens, index: 0 } + Self { + tokens, + index: 0, + group_return: false, + } } pub fn parse(&mut self) -> Expression { @@ -32,6 +41,8 @@ impl TreeParser { } }) .collect(); + // add null end token to ensure that everything got parsed + self.tokens.push(Token::End) } fn step(&mut self) -> bool { @@ -63,8 +74,12 @@ impl TreeParser { if let Some(element) = self.parse_element() { expression.add_child(element); } + if self.group_return { + break; + } self.step(); } + self.group_return = false; expression } @@ -85,15 +100,22 @@ impl TreeParser { } Token::Operation(op) => Some(self.parse_operation(op)), Token::Misc(m) => Some(self.parse_misc(m)), + Token::Grouping(g) => { + if let Some(group) = self.parse_group(g) { + Some(Element::Group(group)) + } else { + None + } + } _ => None, } } fn parse_text(&self, token: Text) -> Option { match token { - Text::Symbol(s) => Some(Literal::Symbol(SymbolNode { symbol: s })), - Text::Number(n) => Some(Literal::Number(NumberNode { number: n })), - Text::Plain(p) => Some(Literal::Text(TextNode { text: p })), + Text::Symbol(s) => Some(Literal::Symbol(Symbol { symbol: s })), + Text::Number(n) => Some(Literal::Number(Number { number: n })), + Text::Plain(p) => Some(Literal::Text(PlainText { text: p })), _ => None, } } @@ -126,6 +148,12 @@ impl TreeParser { exp: self.parse_element().unwrap().boxed(), })) } + Misc::Sub => { + self.step(); + Element::Special(Special::Sub(Sub { + lower: self.parse_element().unwrap().boxed(), + })) + } Misc::LatexFrac => { self.step(); Element::Special(Special::Frac(Frac { @@ -158,6 +186,68 @@ impl TreeParser { } } + fn parse_group(&mut self, token: Grouping) -> Option { + match token { + Grouping::RParen => { + self.step(); + let inner = self.parse_expression().boxed(); + Some(Group::Parentheses(Parentheses { inner })) + } + Grouping::RBrace => { + self.step(); + let inner = self.parse_expression().boxed(); + + Some(Group::Braces(Braces { inner })) + } + Grouping::RBracket => { + self.step(); + let inner = self.parse_expression().boxed(); + + Some(Group::Brackets(Brackets { inner })) + } + Grouping::RAngle => { + self.step(); + let inner = self.parse_expression().boxed(); + + Some(Group::Angles(Angles { inner })) + } + Grouping::RXPar => { + self.step(); + let inner = self.parse_expression().boxed(); + + Some(Group::XGroup(XGroup { inner })) + } + Grouping::Abs => { + self.step(); + self.step(); + let inner = self.parse_expression().boxed(); + Some(Group::Abs(Abs { inner })) + } + Grouping::Floor => { + self.step(); + self.step(); + let inner = self.parse_expression().boxed(); + Some(Group::Floor(Floor { inner })) + } + Grouping::Ceil => { + self.step(); + self.step(); + let inner = self.parse_expression().boxed(); + Some(Group::Ceil(Ceil { inner })) + } + Grouping::Norm => { + self.step(); + self.step(); + let inner = self.parse_expression().boxed(); + Some(Group::Norm(Norm { inner })) + } + _ => { + self.group_return = true; + None + } + } + } + fn parse_sub(&mut self) -> Option> { if let Some(Token::Misc(Misc::Sub)) = self.peek() { self.step(); diff --git a/src/tokens/mappings.rs b/src/tokens/mappings.rs index f4e7179..db04e67 100644 --- a/src/tokens/mappings.rs +++ b/src/tokens/mappings.rs @@ -163,10 +163,10 @@ pub fn get_grouping_mappings() -> Vec> { hashmap! { G_RPAREN => Grouping::RParen, G_LPAREN => Grouping::LParen, - G_RBRAC => Grouping::RBrace, - G_LBRAC => Grouping::LBrace, - G_RCURL => Grouping::RCurl, - G_LCURL => Grouping::LCurl, + G_RBRAC => Grouping::RBracket, + G_LBRAC => Grouping::LBracket, + G_RCURL => Grouping::RBrace, + G_LCURL => Grouping::LBrace, G_ABS => Grouping::Abs, G_FLOOR => Grouping::Floor, G_CEIL => Grouping::Ceil, diff --git a/src/tokens/mod.rs b/src/tokens/mod.rs index 85b5ce4..b4eeff5 100644 --- a/src/tokens/mod.rs +++ b/src/tokens/mod.rs @@ -14,6 +14,7 @@ pub enum Token { Font(FontCommand), Function(Function), Text(Text), + End, } #[derive(Debug, Clone, PartialOrd, PartialEq)] @@ -139,10 +140,10 @@ pub enum Logical { pub enum Grouping { RParen, LParen, + RBracket, + LBracket, RBrace, LBrace, - RCurl, - LCurl, LAngle, RAngle, LXPar, diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..e667ee7 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,8 @@ +pub trait Boxed +where + Self: std::marker::Sized, +{ + fn boxed(self) -> Box { + Box::new(self) + } +}