Add matrices parsing

pull/1/head
trivernis 4 years ago
parent 1308360780
commit afe8169f5d

@ -2,6 +2,7 @@ use crate::elements::special::Expression;
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub enum Group {
MSep,
Parentheses(Parentheses),
Brackets(Brackets),
Braces(Braces),
@ -11,6 +12,7 @@ pub enum Group {
Floor(Floor),
Ceil(Ceil),
Norm(Norm),
Matrix(Matrix),
}
#[derive(Debug, Clone, PartialOrd, PartialEq)]
@ -57,3 +59,8 @@ pub struct Ceil {
pub struct Norm {
pub inner: Box<Expression>,
}
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Matrix {
pub inner: Vec<Vec<Expression>>,
}

@ -3,7 +3,7 @@ use crate::utils::Boxed;
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Expression {
children: Vec<Element>,
pub children: Vec<Element>,
}
#[derive(Debug, Clone, PartialOrd, PartialEq)]

@ -28,12 +28,14 @@ pub fn parse(content: String) -> Expression {
#[cfg(test)]
mod tests {
use crate::elements::group::{Brackets, Group, Matrix};
use crate::elements::literal::{Literal, Number};
use crate::elements::special::{Expression, Special, Sum};
use crate::elements::Element;
use crate::parse;
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;
@ -186,11 +188,100 @@ mod tests {
assert_eq!(expression, test_expression)
}
//#[test]
fn it_parses_into_a_tree2() {
#[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()
}))]
}
);
}
#[test]
fn it_parses_into_a_tree3() {
fs::write(
"test-files/test.txt",
format!("{:#?}", parse("color(red)(a) * b^4 - c(c-2)".to_string())),
format!(
"{:#?}",
parse("color(red)(a) * b^4 - c(c-2) [[1, 3, 2 + 2],[3 - x, 4]".to_string())
),
);
}

@ -1,6 +1,6 @@
use crate::elements::accent::{Color, ExpressionAccent, GenericAccent, OverSet, UnderSet};
use crate::elements::group::{
Abs, Angles, Braces, Brackets, Ceil, Floor, Group, Norm, Parentheses, XGroup,
Abs, Angles, Braces, Brackets, Ceil, Floor, Group, Matrix, Norm, Parentheses, XGroup,
};
use crate::elements::literal::{Literal, Number, PlainText, Symbol};
use crate::elements::special::{
@ -102,7 +102,9 @@ 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) {
if let Some(group) = self.parse_matrix() {
Some(Element::Group(group))
} else if let Some(group) = self.parse_group(g) {
Some(Element::Group(group))
} else {
None
@ -254,6 +256,65 @@ impl TreeParser {
}
}
fn parse_matrix(&mut self) -> Option<Group> {
let token = self.current_token().clone();
let start_index = self.index;
if let Token::Grouping(Grouping::RBracket) = token {
let mut expressions = Vec::new();
while !self.end_reached() {
if let Some(Token::Grouping(Grouping::RBracket)) = self.peek() {
self.step();
self.step();
expressions.push(self.parse_expression());
self.step();
if let Token::Grouping(Grouping::LBracket) = self.current_token() {
self.step();
}
if let Token::Grouping(Grouping::LBracket) = self.current_token() {
break;
}
} else {
break;
}
}
// Remapping the expression into a matrix
let expression_matrix = expressions
.iter()
.map(|e| {
let children = e.children.clone();
let mut expressions = Vec::new();
for elements in children.split(|e| e == &Element::Group(Group::MSep)) {
expressions.push(Expression {
children: elements.to_vec(),
})
}
expressions
})
.collect::<Vec<Vec<Expression>>>();
// a matrix with no elements is invalid
if expression_matrix.len() == 0 {
self.index = start_index;
return None;
}
/// a matrix with rows of different lengths is invalid
let first_length = expression_matrix.first().unwrap().len();
if !expression_matrix.iter().all(|e| e.len() == first_length) {
self.index = start_index;
return None;
}
Some(Group::Matrix(Matrix {
inner: expression_matrix,
}))
} else {
None
}
}
fn parse_group(&mut self, token: Grouping) -> Option<Group> {
match token {
Grouping::RParen => {
@ -309,6 +370,7 @@ impl TreeParser {
let inner = self.parse_expression().boxed();
Some(Group::Norm(Norm { inner }))
}
Grouping::MSep => Some(Group::MSep),
_ => {
self.group_return = true;
None

Loading…
Cancel
Save