From 0494c462442ff0e7e1977d07df65e39548395ef0 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 15:54:08 +0200 Subject: [PATCH 1/6] Add more literal mappings --- Cargo.toml | 3 +- src/format/mathml.rs | 188 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d58a2d..9887a2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ license-file = "LICENSE" [dependencies] charred = "0.3.0" maplit = "1.0.2" -lazy_static = "1.4.0" \ No newline at end of file +lazy_static = "1.4.0" +htmlescape = "0.3.1" \ No newline at end of file diff --git a/src/format/mathml.rs b/src/format/mathml.rs index 9051e4c..6f4af23 100644 --- a/src/format/mathml.rs +++ b/src/format/mathml.rs @@ -1,4 +1,6 @@ -use crate::tokens::Greek; +use crate::elements::literal::{Number, PlainText, Symbol}; +use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Relation}; +use htmlescape::encode_minimal; pub trait ToMathML { fn to_mathml(&self) -> String; @@ -48,3 +50,187 @@ impl ToMathML for Greek { format!("{}", inner) } } + +impl ToMathML for PlainText { + fn to_mathml(&self) -> String { + if let Some(formatting) = &self.formatting { + format!( + "{}", + formatting.to_mathml(), + encode_minimal(self.text.as_str()) + ) + } else { + format!("{}", encode_minimal(self.text.as_str())) + } + } +} + +impl ToMathML for FontCommand { + fn to_mathml(&self) -> String { + match self { + FontCommand::Big => "bold".to_string(), + FontCommand::BigOutline => "double-struck", + FontCommand::Cursive => "italic", + FontCommand::TText => "script", + FontCommand::Fr => "bold-fraktur", + FontCommand::SansSerif => "sans-serif", + } + } +} + +impl ToMathML for Symbol { + fn to_mathml(&self) -> String { + format!("{}", encode_minimal(self.symbol.as_str())) + } +} + +impl ToMathML for Number { + fn to_mathml(&self) -> String { + format!("{}", encode_minimal(self.number.as_str())) + } +} + +impl ToMathML for Relation { + fn to_mathml(&self) -> String { + let inner = match self { + Relation::Eq => "=", + Relation::Ne => "≠", + Relation::Lt => "<", + Relation::Gt => ">", + Relation::Le => "≤", + Relation::Ge => "≥", + Relation::Prec => "≺", + Relation::Succ => "≻", + Relation::PrecEq => "≼", + Relation::SuccEq => "≽", + Relation::In => "∈", + Relation::NotIn => "∉", + Relation::SubSet => "⊂", + Relation::SupSet => "⊃", + Relation::SubSetEq => "⊆", + Relation::SupSetEq => "⊇", + Relation::Equiv => "≡", + Relation::Cong => "≅", + Relation::Approx => "≈", + Relation::PropTo => "∝", + }; + + format!("{}", inner) + } +} + +impl ToMathML for Function { + fn to_mathml(&self) -> String { + let inner = match self { + Function::Exp => "exp", + Function::Sin => "sin", + Function::Max => "max", + Function::Min => "min", + Function::Glb => "glb", + Function::G => "g", + Function::Lub => "lub", + Function::Lcm => "lcm", + Function::Gcd => "gcd", + Function::Mod => "mod", + Function::Dim => "dim", + Function::Det => "det", + Function::Ln => "ln", + Function::Log => "log", + Function::Cot => "cot", + Function::Csc => "csc", + Function::Sech => "sech", + Function::Tanh => "tanh", + Function::Cosh => "cosh", + Function::ArcSin => "arcsin", + Function::ArcCos => "arccos", + Function::ArcTan => "arctan", + Function::Tan => "tan", + Function::Cos => "cos", + Function::F => "f", + Function::Sec => "sec", + Function::Sinh => "sinh", + Function::Csch => "csch", + Function::Coth => "coth", + }; + format!("{}", inner) + } +} + +impl ToMathML for Logical { + fn to_mathml(&self) -> String { + let inner = match self { + Logical::And => "and", + Logical::Or => "or", + Logical::Not => "¬", + Logical::Implies => "⇒", + Logical::If => "if", + Logical::Iff => "⇔", + Logical::ForAll => "∀", + Logical::Exists => "exists;", + Logical::Bot => "⊥", + Logical::Top => "⊤", + Logical::VDash => "⊢", + Logical::Models => "⊨", + }; + format!("{}", inner) + } +} + +impl ToMathML for Arrow { + fn to_mathml(&self) -> String { + let inner = match self { + Arrow::UpArrow => "↑", + Arrow::DownArrow => "↓", + Arrow::RightArrow => "→", + Arrow::To => "→", + Arrow::RightArrowTail => "↣", + Arrow::TwoHeadRightArrow => "↠", + Arrow::TwoHeadRightArrowTail => "⤖", + Arrow::MapsTo => "↦", + Arrow::LeftArrow => "←", + Arrow::LeftRightArrow => "⟷", + Arrow::BigRightArrow => "⇨", + Arrow::BigLeftArrow => "⇦", + Arrow::BigLeftRightArrow => "⬄", + }; + format!("{}", inner) + } +} + +impl ToMathML for Misc { + fn to_mathml(&self) -> String { + let inner = match self { + Misc::Del => "∂", + Misc::Grad => "∇", + Misc::PlusMinus => "±", + Misc::EmptySet => "∅", + Misc::Infty => "∞", + Misc::Aleph => "ℵ", + Misc::Therefore => "∴", + Misc::Because => "∵", + Misc::PLDots => "|…|", + Misc::PCDots => "|···|", + Misc::VDots => "︙", + Misc::DDots => "⋱", + Misc::EPipes => "||", + Misc::EQuad => "| |", + Misc::Angle => "∠", + Misc::Frown => "⌢", + Misc::Triangle => "△", + Misc::Diamond => "⋄", + Misc::Square => "□", + Misc::LFloor => "⌊", + Misc::RFloor => "⌋", + Misc::LCeiling => "⌈", + Misc::RCeiling => "⌉", + Misc::Complex => "ℂ", + Misc::Natural => "ℕ", + Misc::Rational => "ℚ", + Misc::Real => "ℝ", + Misc::Integer => "ℤ", + _ => "", + }; + + format!("{}", inner) + } +} From fe7a68da435098988caf6e3f9e2e6c45383e53f3 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 17:09:15 +0200 Subject: [PATCH 2/6] Add ToMathML for all Literals --- src/elements/literal.rs | 1 - src/format/mathml.rs | 55 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/elements/literal.rs b/src/elements/literal.rs index aca778d..76e81d0 100644 --- a/src/elements/literal.rs +++ b/src/elements/literal.rs @@ -2,7 +2,6 @@ use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Operatio #[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum Literal { - Integer, Text(PlainText), Symbol(Symbol), Number(Number), diff --git a/src/format/mathml.rs b/src/format/mathml.rs index 6f4af23..2371d51 100644 --- a/src/format/mathml.rs +++ b/src/format/mathml.rs @@ -1,11 +1,29 @@ -use crate::elements::literal::{Number, PlainText, Symbol}; -use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Relation}; +use crate::elements::literal::{Literal, Number, PlainText, Symbol}; +use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation}; use htmlescape::encode_minimal; pub trait ToMathML { fn to_mathml(&self) -> String; } +impl ToMathML for Literal { + fn to_mathml(&self) -> String { + match self { + Literal::Text(t) => t.to_mathml(), + Literal::Symbol(s) => s.to_mathml(), + Literal::Number(n) => n.to_mathml(), + Literal::Greek(g) => g.to_mathml(), + Literal::FontCommand(f) => f.to_mathml(), + Literal::Relation(r) => r.to_mathml(), + Literal::Function(f) => f.to_mathml(), + Literal::Logical(l) => l.to_mathml(), + Literal::Arrow(a) => a.to_mathml(), + Literal::Misc(m) => m.to_mathml(), + Literal::Operation(o) => o.to_mathml(), + } + } +} + impl ToMathML for Greek { fn to_mathml(&self) -> String { let inner = match self { @@ -234,3 +252,36 @@ impl ToMathML for Misc { format!("{}", inner) } } + +impl ToMathML for Operation { + fn to_mathml(&self) -> String { + let inner = match self { + Operation::Plus => "+", + Operation::Minus => "−", + Operation::CDot => "∙", + Operation::Ast => "∗", + Operation::Star => "⋆", + Operation::Slash => "/", + Operation::Backslash => "∖", + Operation::Times => "×", + Operation::Div => "÷", + Operation::LTimes => "⋉", + Operation::RTimes => "⋊", + Operation::Bowtie => "⋈", + Operation::Circ => "∘", + Operation::OPlus => "⊕", + Operation::OTimes => "⊗", + Operation::ODot => "⊙", + Operation::Wedge => "∧", + Operation::BidWedge => "⋀", + Operation::Vee => "∨", + Operation::BigVee => "⋁", + Operation::Cap => "∩", + Operation::BigCap => "⋂", + Operation::Cup => "∪", + Operation::BigCup => "⋃", + _ => "", + }; + format!("{}", inner) + } +} From a134bc49a4136452f0d0bb2898ae8111a3146776 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 21:00:00 +0200 Subject: [PATCH 3/6] Add ToMathML for all Accents --- src/format/mathml.rs | 94 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/src/format/mathml.rs b/src/format/mathml.rs index 2371d51..ee4d9cd 100644 --- a/src/format/mathml.rs +++ b/src/format/mathml.rs @@ -1,6 +1,10 @@ +use crate::elements::accent::{Color, ExpressionAccent, GenericAccent, OverSet, UnderSet}; use crate::elements::literal::{Literal, Number, PlainText, Symbol}; -use crate::tokens::{Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation}; -use htmlescape::encode_minimal; +use crate::elements::Element; +use crate::tokens::{ + Accent, Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation, +}; +use htmlescape::{encode_attribute, encode_minimal}; pub trait ToMathML { fn to_mathml(&self) -> String; @@ -87,11 +91,11 @@ impl ToMathML for FontCommand { fn to_mathml(&self) -> String { match self { FontCommand::Big => "bold".to_string(), - FontCommand::BigOutline => "double-struck", - FontCommand::Cursive => "italic", - FontCommand::TText => "script", - FontCommand::Fr => "bold-fraktur", - FontCommand::SansSerif => "sans-serif", + FontCommand::BigOutline => "double-struck".to_string(), + FontCommand::Cursive => "italic".to_string(), + FontCommand::TText => "script".to_string(), + FontCommand::Fr => "bold-fraktur".to_string(), + FontCommand::SansSerif => "sans-serif".to_string(), } } } @@ -285,3 +289,79 @@ impl ToMathML for Operation { format!("{}", inner) } } + +impl ToMathML for Accent { + fn to_mathml(&self) -> String { + match self { + Accent::Hat => "ˆ".to_string(), + Accent::Overline => "¯".to_string(), + Accent::Underline => "–".to_string(), + Accent::Vec => "→".to_string(), + Accent::Dot => ".".to_string(), + Accent::DDot => "..".to_string(), + Accent::UnderBrace => "⏟".to_string(), + Accent::OverBrace => "⏞".to_string(), + Accent::Cancel => "⟋".to_string(), + _ => "".to_string(), + } + } +} + +impl ToMathML for OverSet { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.bottom.to_mathml(), + self.top.to_mathml() + ) + } +} + +impl ToMathML for UnderSet { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.top.to_mathml(), + self.bottom.to_mathml(), + ) + } +} + +impl ToMathML for Color { + fn to_mathml(&self) -> String { + format!( + "{}", + encode_attribute(self.color.as_str()), + self.inner.to_mathml() + ) + } +} + +impl ToMathML for GenericAccent { + fn to_mathml(&self) -> String { + match self.accent { + Accent::Hat + | Accent::Overline + | Accent::Vec + | Accent::Dot + | Accent::DDot + | Accent::OverBrace => format!( + "{}{}", + self.inner.to_mathml(), + self.accent.to_mathml() + ), + Accent::Underline | Accent::UnderBrace => format!( + "{}{}", + self.inner.to_mathml(), + self.accent.to_mathml() + ), + _ => self.inner.to_mathml(), + } + } +} + +impl ToMathML for Element { + fn to_mathml(&self) -> String { + unimplemented!() + } +} From 1e7fc5ee218ffcb05fb2f14ed5e31584d78ed070 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 21:19:15 +0200 Subject: [PATCH 4/6] Add ToMathML for all Grouping elements --- src/format/mathml.rs | 149 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/format/mathml.rs b/src/format/mathml.rs index ee4d9cd..1e98cfe 100644 --- a/src/format/mathml.rs +++ b/src/format/mathml.rs @@ -1,5 +1,9 @@ use crate::elements::accent::{Color, ExpressionAccent, GenericAccent, OverSet, UnderSet}; +use crate::elements::group::{ + Abs, Angles, Braces, Brackets, Ceil, Floor, Group, Matrix, Norm, Parentheses, Vector, XGroup, +}; use crate::elements::literal::{Literal, Number, PlainText, Symbol}; +use crate::elements::special::Expression; use crate::elements::Element; use crate::tokens::{ Accent, Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation, @@ -360,6 +364,151 @@ impl ToMathML for GenericAccent { } } +impl ToMathML for Group { + fn to_mathml(&self) -> String { + match self { + Group::Vector(v) => v.to_mathml(), + Group::MSep => ",".to_string(), + Group::Parentheses(p) => p.to_mathml(), + Group::Brackets(b) => b.to_mathml(), + Group::Braces(b) => b.to_mathml(), + Group::Angles(a) => a.to_mathml(), + Group::XGroup(x) => x.to_mathml(), + Group::Abs(a) => a.to_mathml(), + Group::Floor(f) => f.to_mathml(), + Group::Ceil(c) => c.to_mathml(), + Group::Norm(n) => n.to_mathml(), + Group::Matrix(m) => m.to_mathml(), + } + } +} + +impl ToMathML for Parentheses { + fn to_mathml(&self) -> String { + format!( + "({})", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Brackets { + fn to_mathml(&self) -> String { + format!( + "[{}]", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Braces { + fn to_mathml(&self) -> String { + format!( + "{{}}", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Angles { + fn to_mathml(&self) -> String { + format!( + "{}", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for XGroup { + fn to_mathml(&self) -> String { + format!( + "(x{}x)", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Abs { + fn to_mathml(&self) -> String { + format!( + "|{}|", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Floor { + fn to_mathml(&self) -> String { + format!( + "{}", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Ceil { + fn to_mathml(&self) -> String { + format!( + "{}", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Norm { + fn to_mathml(&self) -> String { + format!( + "||{}||", + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Matrix { + fn to_mathml(&self) -> String { + format!( + "[{}]", + self.inner.iter().fold("".to_string(), |a, b| format!( + "{}{}", + a, + b.iter().fold("".to_string(), |a, b| format!( + "{}{}", + a, + b.to_mathml() + )) + )) + ) + } +} + +impl ToMathML for Vector { + fn to_mathml(&self) -> String { + format!( + "({})", + self.inner.iter().fold("".to_string(), |a, b| format!( + "{}{}", + a, + b.iter().fold("".to_string(), |a, b| format!( + "{}{}", + a, + b.to_mathml() + )) + )) + ) + } +} + +impl ToMathML for Expression { + fn to_mathml(&self) -> String { + format!( + "{}", + self.children + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_mathml())) + ) + } +} + impl ToMathML for Element { fn to_mathml(&self) -> String { unimplemented!() From b40485b3910d12e53b32430c560c3949d108496c Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 22:02:46 +0200 Subject: [PATCH 5/6] Add ToMathML for special elements and remaining enums --- src/elements/special.rs | 2 + src/format/mathml.rs | 166 ++++++++++++++++++++++++++++++++++++- src/lib.rs | 17 ++-- src/parsing/tree_parser.rs | 65 ++++++++++++--- 4 files changed, 228 insertions(+), 22 deletions(-) diff --git a/src/elements/special.rs b/src/elements/special.rs index d83616b..8352fb1 100644 --- a/src/elements/special.rs +++ b/src/elements/special.rs @@ -39,11 +39,13 @@ pub struct Frac { #[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Pow { + pub(crate) base: Box, pub(crate) exp: Box, } #[derive(Debug, Clone, PartialOrd, PartialEq)] pub struct Sub { + pub(crate) base: Box, pub(crate) lower: Box, } diff --git a/src/format/mathml.rs b/src/format/mathml.rs index 1e98cfe..ebcd1b0 100644 --- a/src/format/mathml.rs +++ b/src/format/mathml.rs @@ -3,7 +3,9 @@ use crate::elements::group::{ Abs, Angles, Braces, Brackets, Ceil, Floor, Group, Matrix, Norm, Parentheses, Vector, XGroup, }; use crate::elements::literal::{Literal, Number, PlainText, Symbol}; -use crate::elements::special::Expression; +use crate::elements::special::{ + Expression, Frac, Integral, OIntegral, Pow, Prod, Root, Special, Sqrt, Sub, Sum, +}; use crate::elements::Element; use crate::tokens::{ Accent, Arrow, FontCommand, Function, Greek, Logical, Misc, Operation, Relation, @@ -266,7 +268,7 @@ impl ToMathML for Operation { let inner = match self { Operation::Plus => "+", Operation::Minus => "−", - Operation::CDot => "∙", + Operation::CDot => "⋅", Operation::Ast => "∗", Operation::Star => "⋆", Operation::Slash => "/", @@ -498,6 +500,159 @@ impl ToMathML for Vector { } } +impl ToMathML for Special { + fn to_mathml(&self) -> String { + match self { + Special::Sum(s) => s.to_mathml(), + Special::Prod(p) => p.to_mathml(), + Special::Frac(f) => f.to_mathml(), + Special::Pow(p) => p.to_mathml(), + Special::Sub(s) => s.to_mathml(), + Special::Sqrt(s) => s.to_mathml(), + Special::Root(r) => r.to_mathml(), + Special::Integral(i) => i.to_mathml(), + Special::OIntegral(i) => i.to_mathml(), + } + } +} + +impl ToMathML for Sum { + fn to_mathml(&self) -> String { + if let Some(bottom) = &self.bottom { + if let Some(top) = &self.top { + format!( + "{}{}", + bottom.to_mathml(), + top.to_mathml() + ) + } else { + format!("{}", bottom.to_mathml()) + } + } else if let Some(top) = &self.top { + format!("{}", top.to_mathml()) + } else { + format!("") + } + } +} + +impl ToMathML for Prod { + fn to_mathml(&self) -> String { + if let Some(bottom) = &self.bottom { + if let Some(top) = &self.top { + format!( + "{}{}", + bottom.to_mathml(), + top.to_mathml() + ) + } else { + format!("{}", bottom.to_mathml()) + } + } else if let Some(top) = &self.top { + format!("{}", top.to_mathml()) + } else { + format!("") + } + } +} + +impl ToMathML for Frac { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.top.to_mathml(), + self.bottom.to_mathml() + ) + } +} + +impl ToMathML for Sqrt { + fn to_mathml(&self) -> String { + format!("{}", self.inner.to_mathml()) + } +} + +impl ToMathML for Root { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.base.to_mathml(), + self.inner.to_mathml() + ) + } +} + +impl ToMathML for Pow { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.base.to_mathml(), + self.exp.to_mathml() + ) + } +} + +impl ToMathML for Sub { + fn to_mathml(&self) -> String { + format!( + "{}{}", + self.base.to_mathml(), + self.lower.to_mathml() + ) + } +} + +impl ToMathML for Integral { + fn to_mathml(&self) -> String { + if let Some(bottom) = &self.bottom { + if let Some(top) = &self.top { + format!( + "{}{}", + bottom.to_mathml(), + top.to_mathml() + ) + } else { + format!("{}", bottom.to_mathml()) + } + } else if let Some(top) = &self.top { + format!("{}", top.to_mathml()) + } else { + format!("") + } + } +} + +impl ToMathML for OIntegral { + fn to_mathml(&self) -> String { + if let Some(bottom) = &self.bottom { + if let Some(top) = &self.top { + format!( + "{}{}", + bottom.to_mathml(), + top.to_mathml() + ) + } else { + format!("{}", bottom.to_mathml()) + } + } else if let Some(top) = &self.top { + format!("{}", top.to_mathml()) + } else { + format!("") + } + } +} + +impl ToMathML for ExpressionAccent { + fn to_mathml(&self) -> String { + match self { + ExpressionAccent::Generic(g) => g.to_mathml(), + ExpressionAccent::OverSet(o) => o.to_mathml(), + ExpressionAccent::UnderSet(u) => u.to_mathml(), + ExpressionAccent::Color(c) => c.to_mathml(), + } + } +} + impl ToMathML for Expression { fn to_mathml(&self) -> String { format!( @@ -511,6 +666,11 @@ impl ToMathML for Expression { impl ToMathML for Element { fn to_mathml(&self) -> String { - unimplemented!() + match self { + Element::Special(s) => s.to_mathml(), + Element::Literal(l) => l.to_mathml(), + Element::Group(g) => g.to_mathml(), + Element::Accent(a) => a.to_mathml(), + } } } diff --git a/src/lib.rs b/src/lib.rs index 138b74a..bd139de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ mod tests { use crate::elements::literal::{Literal, Number}; use crate::elements::special::{Expression, Special, Sum}; use crate::elements::Element; + use crate::format::mathml::ToMathML; use crate::parse; use crate::parsing::tokenizer::Tokenizer; use crate::parsing::tree_parser::TreeParser; @@ -347,15 +348,19 @@ mod tests { ) } + #[allow(dead_code)] //#[test] - fn it_parses_into_a_tree3() { + fn it_writes_mathml() { + let str_expression = + "sqrt 1 in NN implies 2^4 + sum_(k = 1)^3 - ((1),(2)) [[2, 3 + 3],[4, 5]]"; + let expression = parse(str_expression.to_string()); fs::write( - "test-files/test.txt", + "test-files/test.html", format!( - "{:#?}", - parse( - "color(red)(a) * b^4 - c(c-2) [[1, 3, 2 + 2],[3 - x, 4] ((2),(3))".to_string() - ) + "
{}
{}
{:#?}
", + str_expression, + expression.to_mathml(), + expression, ), ) .unwrap(); diff --git a/src/parsing/tree_parser.rs b/src/parsing/tree_parser.rs index 6ddf84b..f847749 100644 --- a/src/parsing/tree_parser.rs +++ b/src/parsing/tree_parser.rs @@ -73,7 +73,16 @@ impl TreeParser { while !self.end_reached() { if let Some(element) = self.parse_element() { - expression.add_child(element); + // parse elements that are based on the previous one + if let Some(pow) = self.parse_pow_element(&element) { + expression.add_child(Element::Special(Special::Pow(pow))) + } else if let Some(frac) = self.parse_frac_element(&element) { + expression.add_child(Element::Special(Special::Frac(frac))) + } else if let Some(sub) = self.parse_sub_element(&element) { + expression.add_child(Element::Special(Special::Sub(sub))) + } else { + expression.add_child(element); + } } if self.group_return { break; @@ -214,18 +223,6 @@ impl TreeParser { fn parse_misc(&mut self, token: Misc) -> Element { match token { - Misc::Pow => { - self.step(); - Element::Special(Special::Pow(Pow { - 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 { @@ -427,6 +424,48 @@ impl TreeParser { } } + // tries to parse a pow element + fn parse_pow_element(&mut self, previous: &Element) -> Option { + if let Some(Token::Misc(Misc::Pow)) = self.peek() { + self.step(); + self.step(); + Some(Pow { + base: previous.clone().boxed(), + exp: self.parse_element().unwrap().boxed(), + }) + } else { + None + } + } + + // tries to parse a sub element + fn parse_sub_element(&mut self, previous: &Element) -> Option { + if let Some(Token::Misc(Misc::Sub)) = self.peek() { + self.step(); + self.step(); + Some(Sub { + base: previous.clone().boxed(), + lower: self.parse_element().unwrap().boxed(), + }) + } else { + None + } + } + + // tries to parse an ascii frac + fn parse_frac_element(&mut self, previous: &Element) -> Option { + if let Some(Token::Misc(Misc::AsciiFrac)) = self.peek() { + self.step(); + self.step(); + Some(Frac { + top: previous.clone().boxed(), + bottom: self.parse_element().unwrap().boxed(), + }) + } else { + None + } + } + /// Remaps an expresion vector into a matrix of expressions by splitting on each MSep token fn transform_vec_to_matrix(&self, expressions: Vec) -> Vec> { expressions From 80c7bf0813d0c73c8eb59f73b283e9f241d10d21 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 5 Aug 2020 22:08:41 +0200 Subject: [PATCH 6/6] Update version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9887a2b..48df156 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "asciimath-rs" description = "AsciiMath parser" repository = "https://github.com/trivernis/asciimath-rs" -version = "0.3.0" +version = "0.4.0" authors = ["trivernis "] edition = "2018" readme = "README.md"