mathml_latex/codegen/
as_mathml.rs1use 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 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}