Merge pull request #8 from Trivernis/develop

Bugfixes
pull/9/head
Trivernis 3 years ago committed by GitHub
commit 43577debda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,7 +2,7 @@
name = "asciimath-rs"
description = "AsciiMath parser"
repository = "https://github.com/trivernis/asciimath-rs"
version = "0.5.7"
version = "0.5.8"
authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018"
readme = "README.md"

@ -15,6 +15,7 @@ pub enum Element {
Special(Special),
Group(Group),
Accent(ExpressionAccent),
Null,
}
impl Boxed for Element {}

@ -586,8 +586,8 @@ impl ToMathML for Root {
fn to_mathml(&self) -> String {
format!(
"<mroot>{}{}</mroot>",
self.inner.to_mathml(),
self.base.to_mathml(),
self.inner.to_mathml()
)
}
}
@ -696,6 +696,7 @@ impl ToMathML for Element {
Element::Literal(l) => l.to_mathml(),
Element::Group(g) => g.to_mathml(),
Element::Accent(a) => a.to_mathml(),
Element::Null => "".to_string(),
}
}
}

@ -36,363 +36,4 @@ pub fn parse(content: String) -> Expression {
}
#[cfg(test)]
mod tests {
use crate::elements::group::{Brackets, Group, Matrix, Parentheses, Vector};
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;
use crate::tokens::{Function, Grouping, Misc, Operation, Relation, Text, Token};
use crate::utils::Boxed;
use std::fs;
#[test]
fn it_tokenizes_expressions1() {
let expression = "sum_(i=1)^n*sin(x)";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Operation(Operation::Sum),
Token::Misc(Misc::Sub),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Symbol("i".to_string())),
Token::Relation(Relation::Eq),
Token::Text(Text::Number("1".to_string())),
Token::Grouping(Grouping::LParen),
Token::Misc(Misc::Pow),
Token::Text(Text::Symbol("n".to_string())),
Token::Operation(Operation::CDot),
Token::Function(Function::Sin),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Symbol("x".to_string())),
Token::Grouping(Grouping::LParen),
]
);
}
#[test]
fn it_tokenizes_expressions2() {
let expression = "G_(11) = 5.16e6 € * (215)/(170) = 6.53e6";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Text(Text::Symbol("G".to_string())),
Token::Misc(Misc::Sub),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("11".to_string())),
Token::Grouping(Grouping::LParen),
Token::Text(Text::Whitespace),
Token::Relation(Relation::Eq),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("5.16e6".to_string())),
Token::Text(Text::Whitespace),
Token::Text(Text::Symbol("€".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::CDot),
Token::Text(Text::Whitespace),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("215".to_string())),
Token::Grouping(Grouping::LParen),
Token::Misc(Misc::AsciiFrac),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("170".to_string())),
Token::Grouping(Grouping::LParen),
Token::Text(Text::Whitespace),
Token::Relation(Relation::Eq),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("6.53e6".to_string()))
]
);
}
#[test]
fn it_tokenizes_expressions3() {
let expression = "[[1, 2],[3, 4]] // \\\n";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Grouping(Grouping::RBracket),
Token::Grouping(Grouping::RBracket),
Token::Text(Text::Number("1".to_string())),
Token::Grouping(Grouping::MSep),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("2".to_string())),
Token::Grouping(Grouping::LBracket),
Token::Grouping(Grouping::MSep),
Token::Grouping(Grouping::RBracket),
Token::Text(Text::Number("3".to_string())),
Token::Grouping(Grouping::MSep),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("4".to_string())),
Token::Grouping(Grouping::LBracket),
Token::Grouping(Grouping::LBracket),
Token::Text(Text::Whitespace),
Token::Operation(Operation::Slash),
Token::Text(Text::Whitespace),
Token::Text(Text::NewLine),
]
);
}
#[test]
fn it_tokenizes_text1() {
let expression = "\"just plain text\"";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![Token::Text(Text::Plain("just plain text".to_string()))]
)
}
#[test]
fn it_tokenizes_text2() {
let expression = "\"plain text\" * \"plain text 2\" + a";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Text(Text::Plain("plain text".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::CDot),
Token::Text(Text::Whitespace),
Token::Text(Text::Plain("plain text 2".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::Plus),
Token::Text(Text::Whitespace),
Token::Text(Text::Symbol("a".to_string()))
]
)
}
#[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_matrices() {
assert_eq!(
parse("[[1, 2],[3,4]]".to_string()),
Expression {
children: vec![Element::Group(Group::Matrix(Matrix {
inner: vec![
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
})),]
}
],
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "4".to_string()
})),]
}
]
]
}))]
}
);
}
#[test]
fn it_rejects_invalid_matrices() {
assert_eq!(
parse("[[1, 3, 4],[3,4]]".to_string()),
Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "4".to_string()
}))
]
}
.boxed()
})),
Element::Group(Group::MSep),
Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "4".to_string()
}))
]
}
.boxed()
}))
]
}
.boxed()
}))]
}
);
assert_eq!(
parse("[[1]]".to_string()),
Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),]
}
.boxed()
})),]
}
.boxed()
}))]
}
);
}
#[test]
fn it_parses_vectors() {
assert_eq!(
parse("((1), (2))(1,2) - f".to_string()),
Expression {
children: vec![
Element::Group(Group::Vector(Vector {
inner: vec![
vec![Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
}))]
}],
vec![Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))]
}]
]
})),
Element::Group(Group::Parentheses(Parentheses {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))
]
}
.boxed()
})),
Element::Literal(Literal::Operation(Operation::Minus)),
Element::Literal(Literal::Function(Function::F))
]
}
);
assert_eq!(
parse("((1, 3), (2, 5))".to_string()),
Expression {
children: vec![Element::Group(Group::Vector(Vector {
inner: vec![
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
}))]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "3".to_string()
}))]
}
],
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "5".to_string()
}))]
}
]
]
}))]
}
)
}
#[allow(dead_code)]
//#[test]
fn it_writes_mathml() {
let str_expression =
"alpha sqrt 1 in NN implies 2^4 + \\\n<=> sum_(k = 1)^3 - ((1),(2))[[2, 3 + 3],[4, 5]] + alpha";
let expression = parse(str_expression.to_string());
fs::write(
"test-files/test.html",
format!(
"<html><body><pre>{}</pre><math>{}</math><pre>{:#?}</pre></body></html>",
str_expression,
expression.to_mathml(),
expression,
),
)
.unwrap();
}
}
mod tests;

@ -228,21 +228,21 @@ impl TreeParser {
Misc::LatexFrac => {
self.step();
Element::Special(Special::Frac(Frac {
top: self.parse_element().unwrap().boxed(),
bottom: self.parse_element().unwrap().boxed(),
top: self.parse_element().unwrap_or(Element::Null).boxed(),
bottom: self.parse_element().unwrap_or(Element::Null).boxed(),
}))
}
Misc::Sqrt => {
self.step();
Element::Special(Special::Sqrt(Sqrt {
inner: self.parse_element().unwrap().boxed(),
inner: self.parse_element().unwrap_or(Element::Null).boxed(),
}))
}
Misc::Root => {
self.step();
let base = self.parse_element().unwrap().boxed();
let base = self.parse_element().unwrap_or(Element::Null).boxed();
self.step();
let inner = self.parse_element().unwrap().boxed();
let inner = self.parse_element().unwrap_or(Element::Null).boxed();
Element::Special(Special::Root(Root { inner, base }))
}
Misc::Int => Element::Special(Special::Integral(Integral {
@ -432,7 +432,11 @@ impl TreeParser {
self.step();
Some(Pow {
base: previous.clone().boxed(),
exp: self.parse_element().unwrap().to_non_enclosed().boxed(),
exp: self
.parse_element()
.unwrap_or(Element::Null)
.to_non_enclosed()
.boxed(),
})
} else {
None
@ -446,7 +450,11 @@ impl TreeParser {
self.step();
Some(Sub {
base: previous.clone().boxed(),
lower: self.parse_element().unwrap().to_non_enclosed().boxed(),
lower: self
.parse_element()
.unwrap_or(Element::Null)
.to_non_enclosed()
.boxed(),
})
} else {
None

@ -0,0 +1,11 @@
use crate::format::mathml::ToMathML;
use crate::parse;
#[test]
fn it_renders_roots() {
let expr = parse("root 3 16".to_string());
assert_eq!(
expr.to_mathml(),
"<mrow><mroot><mn>16</mn><mn>3</mn></mroot></mrow>"
)
}

@ -0,0 +1,3 @@
mod mathml;
mod parsing;
mod tokenization;

@ -0,0 +1,250 @@
use crate::elements::group::{Brackets, Group, Matrix, Parentheses, Vector};
use crate::elements::literal::{Literal, Number};
use crate::elements::special::{Expression, Root, Special, Sum};
use crate::elements::Element;
use crate::parse;
use crate::parsing::tokenizer::Tokenizer;
use crate::parsing::tree_parser::TreeParser;
use crate::tokens::{Function, Operation};
use crate::utils::Boxed;
#[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_matrices() {
assert_eq!(
parse("[[1, 2],[3,4]]".to_string()),
Expression {
children: vec![Element::Group(Group::Matrix(Matrix {
inner: vec![
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
})),]
}
],
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "4".to_string()
})),]
}
]
]
}))]
}
);
}
#[test]
fn it_rejects_invalid_matrices() {
assert_eq!(
parse("[[1, 3, 4],[3,4]]".to_string()),
Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "4".to_string()
}))
]
}
.boxed()
})),
Element::Group(Group::MSep),
Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "3".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "4".to_string()
}))
]
}
.boxed()
}))
]
}
.boxed()
}))]
}
);
assert_eq!(
parse("[[1]]".to_string()),
Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![Element::Group(Group::Brackets(Brackets {
inner: Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),]
}
.boxed()
})),]
}
.boxed()
}))]
}
);
}
#[test]
fn it_parses_vectors() {
assert_eq!(
parse("((1), (2))(1,2) - f".to_string()),
Expression {
children: vec![
Element::Group(Group::Vector(Vector {
inner: vec![
vec![Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
}))]
}],
vec![Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))]
}]
]
})),
Element::Group(Group::Parentheses(Parentheses {
inner: Expression {
children: vec![
Element::Literal(Literal::Number(Number {
number: "1".to_string()
})),
Element::Group(Group::MSep),
Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))
]
}
.boxed()
})),
Element::Literal(Literal::Operation(Operation::Minus)),
Element::Literal(Literal::Function(Function::F))
]
}
);
assert_eq!(
parse("((1, 3), (2, 5))".to_string()),
Expression {
children: vec![Element::Group(Group::Vector(Vector {
inner: vec![
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "1".to_string()
}))]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "3".to_string()
}))]
}
],
vec![
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "2".to_string()
}))]
},
Expression {
children: vec![Element::Literal(Literal::Number(Number {
number: "5".to_string()
}))]
}
]
]
}))]
}
)
}
#[test]
fn it_parses_roots() {
let expr = parse("root 3 16".to_string());
assert_eq!(
expr,
Expression {
children: vec![Element::Special(Special::Root(Root {
base: Element::Literal(Literal::Number(Number {
number: "3".to_string()
}))
.boxed(),
inner: Element::Literal(Literal::Number(Number {
number: "16".to_string()
}))
.boxed(),
}))]
}
);
// test no fail
parse("root 3".to_string());
}
#[test]
fn it_parses_functions() {
let expr = parse("sin 10".to_string());
assert_eq!(
expr,
Expression {
children: vec![
Element::Literal(Literal::Function(Function::Sin)),
Element::Literal(Literal::Number(Number {
number: "10".to_string()
}))
]
}
)
}

@ -0,0 +1,128 @@
use crate::parsing::tokenizer::Tokenizer;
use crate::tokens::{Function, Grouping, Misc, Operation, Relation, Text, Token};
#[test]
fn it_tokenizes_expressions1() {
let expression = "sum_(i=1)^n*sin(x)";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Operation(Operation::Sum),
Token::Misc(Misc::Sub),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Symbol("i".to_string())),
Token::Relation(Relation::Eq),
Token::Text(Text::Number("1".to_string())),
Token::Grouping(Grouping::LParen),
Token::Misc(Misc::Pow),
Token::Text(Text::Symbol("n".to_string())),
Token::Operation(Operation::CDot),
Token::Function(Function::Sin),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Symbol("x".to_string())),
Token::Grouping(Grouping::LParen),
]
);
}
#[test]
fn it_tokenizes_expressions2() {
let expression = "G_(11) = 5.16e6 € * (215)/(170) = 6.53e6";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Text(Text::Symbol("G".to_string())),
Token::Misc(Misc::Sub),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("11".to_string())),
Token::Grouping(Grouping::LParen),
Token::Text(Text::Whitespace),
Token::Relation(Relation::Eq),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("5.16e6".to_string())),
Token::Text(Text::Whitespace),
Token::Text(Text::Symbol("€".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::CDot),
Token::Text(Text::Whitespace),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("215".to_string())),
Token::Grouping(Grouping::LParen),
Token::Misc(Misc::AsciiFrac),
Token::Grouping(Grouping::RParen),
Token::Text(Text::Number("170".to_string())),
Token::Grouping(Grouping::LParen),
Token::Text(Text::Whitespace),
Token::Relation(Relation::Eq),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("6.53e6".to_string()))
]
);
}
#[test]
fn it_tokenizes_expressions3() {
let expression = "[[1, 2],[3, 4]] // \\\n";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Grouping(Grouping::RBracket),
Token::Grouping(Grouping::RBracket),
Token::Text(Text::Number("1".to_string())),
Token::Grouping(Grouping::MSep),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("2".to_string())),
Token::Grouping(Grouping::LBracket),
Token::Grouping(Grouping::MSep),
Token::Grouping(Grouping::RBracket),
Token::Text(Text::Number("3".to_string())),
Token::Grouping(Grouping::MSep),
Token::Text(Text::Whitespace),
Token::Text(Text::Number("4".to_string())),
Token::Grouping(Grouping::LBracket),
Token::Grouping(Grouping::LBracket),
Token::Text(Text::Whitespace),
Token::Operation(Operation::Slash),
Token::Text(Text::Whitespace),
Token::Text(Text::NewLine),
]
);
}
#[test]
fn it_tokenizes_text1() {
let expression = "\"just plain text\"";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![Token::Text(Text::Plain("just plain text".to_string()))]
)
}
#[test]
fn it_tokenizes_text2() {
let expression = "\"plain text\" * \"plain text 2\" + a";
let mut tokenizer = Tokenizer::new(expression.to_string());
let tokens = tokenizer.parse();
assert_eq!(
tokens,
vec![
Token::Text(Text::Plain("plain text".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::CDot),
Token::Text(Text::Whitespace),
Token::Text(Text::Plain("plain text 2".to_string())),
Token::Text(Text::Whitespace),
Token::Operation(Operation::Plus),
Token::Text(Text::Whitespace),
Token::Text(Text::Symbol("a".to_string()))
]
)
}
Loading…
Cancel
Save