mathml_latex/codegen/
as_mathml.rs

1use super::*;
2use crate::{block::LaTeXCommand, LaTeXBlock};
3use mathml_core::{
4    helpers::{binom, bmatrix, cases, dfrac, frac, matrix, pmatrix, vmatrix, Bmatrix, Vmatrix},
5    MathFunction, MathIdentifier, MathML, MathMultiScript, MathNumber, MathOperator, MathRoot, MathRow, MathSpace,
6};
7
8impl<'i> LaTeXNode<'i> {
9    /// Converts the LaTeX node into a MathML node.
10    pub fn as_mathml(&self, context: &LaTeXEngine) -> MathML {
11        match self {
12            LaTeXNode::MathRoot { children } => MathRoot::new(children.iter().map(|node| node.as_mathml(context))).into(),
13            LaTeXNode::Row { children } => MathRow::new(children.iter().map(|node| node.as_mathml(context))).into(),
14            LaTeXNode::Block(block) => block.as_mathml(context),
15            LaTeXNode::Command(cmd) => cmd.as_mathml(context),
16            LaTeXNode::MathText { .. } => {
17                todo!()
18            }
19            LaTeXNode::Number { number } => MathML::Number(Box::new(MathNumber::new(number))),
20
21            LaTeXNode::Letter { identifier } => MathIdentifier::italic(identifier).into(),
22            LaTeXNode::Operation { operator } => MathOperator::new(operator).into(),
23            LaTeXNode::Superscript { lhs, rhs } => {
24                MathMultiScript::super_script(lhs.as_mathml(context), rhs.as_mathml(context)).into()
25            }
26            LaTeXNode::NewLine => MathML::NewLine,
27            LaTeXNode::Ampersand => MathML::Ampersand,
28            LaTeXNode::ArticleRoot { .. } => {
29                todo!()
30            }
31            LaTeXNode::ArticleText { .. } => {
32                todo!()
33            }
34        }
35    }
36}
37
38impl<'i> LaTeXBlock<'i> {
39    pub fn as_mathml(&self, context: &LaTeXEngine) -> MathML {
40        let stream = self.children.iter().map(|node| node.as_mathml(context));
41        match self.kind {
42            "matrix" => matrix(stream),
43            "Bmatrix" => Bmatrix(stream),
44            "bmatrix" => bmatrix(stream),
45            "pmatrix" => pmatrix(stream),
46            "Vmatrix" => Vmatrix(stream),
47            "vmatrix" => vmatrix(stream),
48            "cases" => cases(stream),
49            name => todo!("unknown block: {}", name),
50        }
51    }
52}
53
54impl<'i> LaTeXCommand<'i> {
55    pub fn as_mathml(&self, context: &LaTeXEngine) -> MathML {
56        match self.name {
57            "usepackage" => return MathML::Nothing,
58            "operatorname" => match self.children.as_slice() {
59                [] => panic!("operatorname command must have exactly one argument"),
60                [head, rest @ ..] => {
61                    return MathFunction::new(head.as_identifier(), rest.iter().map(|node| node.as_mathml(context))).into();
62                }
63            },
64            kind @ ("frac" | "dfrac") => match self.children.as_slice() {
65                [] => panic!("frac command must have at least two arguments"),
66                [numerator] => panic!("frac command must have at least two arguments"),
67                [numerator, denominator, rest @ ..] => {
68                    let term = match kind {
69                        "frac" => frac(numerator.as_mathml(context), denominator.as_mathml(context)),
70                        "dfrac" => dfrac(numerator.as_mathml(context), denominator.as_mathml(context)),
71                        _ => unreachable!(),
72                    };
73                    if rest.len() == 0 {
74                        return term;
75                    }
76                    let mut terms = MathRow::new(vec![term]);
77                    terms.mut_items().extend(rest.iter().map(|node| node.as_mathml(context)));
78                    return terms.into();
79                }
80            },
81            "binom" => match self.children.as_slice() {
82                [numerator, denominator, rest @ ..] => {
83                    let term = binom(numerator.as_mathml(context), denominator.as_mathml(context));
84                    if rest.len() == 0 {
85                        return term;
86                    }
87                    let mut terms = MathRow::new(vec![term]);
88                    terms.mut_items().extend(rest.iter().map(|node| node.as_mathml(context)));
89                    return terms.into();
90                }
91                _ => panic!("binom command must have exactly two arguments"),
92            },
93            _ => {}
94        }
95        if let Some(s) = context.get_function(&self.name) {
96            return MathFunction::new(s, self.children.iter().map(|node| node.as_mathml(context))).into();
97        }
98        if let Some(s) = context.get_operator(&self.name) {
99            return MathOperator::new(s).into();
100        }
101        if let Some(s) = context.get_letters(&self.name) {
102            return MathIdentifier::normal(s).into();
103        }
104        if let Some(s) = context.get_space(&self.name) {
105            return MathSpace::new(s).into();
106        }
107
108        todo!()
109    }
110}