1use itertools::Itertools;
2
3use crate::{
4 ast::{Expression, Expressions, Literal, Table, TableRow, AST},
5 tokens::{
6 types::{
7 Arrow, BinaryOperator, Function, Greek, LBrace, Logical, Misc, Operation, RBrace,
8 Relational, TokenType, UnaryOperator,
9 },
10 Token,
11 },
12};
13
14pub fn to_mathml(ast: &AST) -> String {
15 format!(
16 "<math display=\"block\">{}</math>",
17 expressions_to_mathml(&ast.expressions)
18 )
19}
20
21fn expressions_to_mathml(expressions: &Expressions) -> String {
22 expressions
23 .expressions
24 .iter()
25 .map(|expression| expression_to_mathml(expression))
26 .join("")
27}
28
29fn expression_to_mathml(expr: &Expression) -> String {
30 match expr {
31 Expression::Frac(frac) => frac_to_mathml(frac),
32 Expression::Sub(bi_expression) => sub_to_mathml(bi_expression),
33 Expression::Pow(bi_expression) => pow_to_mathml(bi_expression),
34 Expression::SubPow(tri_expression) => sub_pow_to_mathml(tri_expression),
35 Expression::Group(group) => group_to_mathml(group),
36 Expression::Unary(unary) => unary_to_mathml(unary),
37 Expression::Binary(binary) => binary_to_mathml(binary),
38 Expression::Literal(literal) => literal_to_mathml(literal),
39 Expression::Expressions(expressions) => expressions_to_mathml(expressions),
40 Expression::Unit => unreachable!(),
41 }
42}
43
44fn binary_to_mathml(binary: &crate::ast::Binary) -> String {
45 match binary.operator.token_type {
46 crate::tokens::types::TokenType::BinaryOperator(BinaryOperator::Root) => format!(
47 "<mroot><mrow>{}</mrow><mrow>{}</mrow></mroot>",
48 match binary.expression_2.as_ref() {
49 Expression::Group(group) => expressions_to_mathml(&group.expressions),
50 _ => expression_to_mathml(&binary.expression_2),
51 },
52 match binary.expression_1.as_ref() {
53 Expression::Group(group) => expressions_to_mathml(&group.expressions),
54 _ => expression_to_mathml(&binary.expression_1),
55 }
56 ),
57 crate::tokens::types::TokenType::BinaryOperator(BinaryOperator::Overset) => format!(
58 "<mover><mrow>{}</mrow><mrow>{}</mrow></mover>",
59 match binary.expression_2.as_ref() {
60 Expression::Group(group) => expressions_to_mathml(&group.expressions),
61 _ => expression_to_mathml(&binary.expression_2),
62 },
63 match binary.expression_1.as_ref() {
64 Expression::Group(group) => expressions_to_mathml(&group.expressions),
65 _ => expression_to_mathml(&binary.expression_1),
66 }
67 ),
68 crate::tokens::types::TokenType::BinaryOperator(BinaryOperator::Underset) => format!(
69 "<munder><mrow>{}</mrow><mrow>{}</mrow></munder>",
70 match binary.expression_2.as_ref() {
71 Expression::Group(group) => expressions_to_mathml(&group.expressions),
72 _ => expression_to_mathml(&binary.expression_2),
73 },
74 match binary.expression_1.as_ref() {
75 Expression::Group(group) => expressions_to_mathml(&group.expressions),
76 _ => expression_to_mathml(&binary.expression_1),
77 }
78 ),
79 crate::tokens::types::TokenType::BinaryOperator(BinaryOperator::Color) => format!(
80 "<mstyle mathcolor=\"{}\">{}</mstyle>",
81 match binary.expression_1.as_ref() {
82 Expression::Group(group) => group
83 .expressions
84 .expressions
85 .iter()
86 .map(|expression| match expression {
87 Expression::Literal(Literal::Literal(literal)) => literal.span.text,
88 _ => "",
89 })
90 .join(""),
91 _ => "".to_string(),
92 },
93 match binary.expression_2.as_ref() {
94 Expression::Group(group) => expressions_to_mathml(&group.expressions),
95 _ => expression_to_mathml(&binary.expression_2),
96 },
97 ),
98 _ => format!(
99 "{}{}{}",
100 binary.operator.span.text,
101 expression_to_mathml(&binary.expression_1),
102 expression_to_mathml(&binary.expression_2),
103 ),
104 }
105}
106
107fn group_to_mathml(group: &crate::ast::Group) -> String {
108 format!(
109 "<mrow>{}{}{}</mrow>",
110 l_brace_to_math_ml(&group.l_brace),
111 group
112 .expressions
113 .expressions
114 .iter()
115 .map(|expr| expression_to_mathml(expr))
116 .join(""),
117 r_brace_to_math_ml(&group.r_brace),
118 )
119}
120
121fn sub_pow_to_mathml(tri_expression: &crate::ast::TriExpression) -> String {
122 if let Expression::Literal(Literal::Literal(literal)) = tri_expression.expression_1.as_ref() {
123 match &literal.token_type {
124 TokenType::Operation(op) => match op {
125 Operation::Sum
126 | Operation::Prod
127 | Operation::BigWedge
128 | Operation::BigCap
129 | Operation::BigCup => {
130 return format!(
131 "<munderover>{}{}{}</munderover>",
132 expression_to_mathml_braceless(&tri_expression.expression_1),
133 expression_to_mathml_braceless(&tri_expression.expression_2),
134 expression_to_mathml_braceless(&tri_expression.expression_3)
135 )
136 }
137 _ => {}
138 },
139 TokenType::Misc(Misc::Lim) => {
140 return format!(
141 "<munderover>{}{}{}</munderover>",
142 expression_to_mathml_braceless(&tri_expression.expression_1),
143 expression_to_mathml_braceless(&tri_expression.expression_2),
144 expression_to_mathml_braceless(&tri_expression.expression_3)
145 )
146 }
147 _ => {}
148 }
149 } else if let Expression::Unary(unary) = tri_expression.expression_1.as_ref() {
150 match unary.operator.token_type {
151 TokenType::UnaryOperator(UnaryOperator::UBrace) => {
152 return format!(
153 "<munderover><munder>{}</munder>{}{}</munderover>",
154 expression_to_mathml_braceless(&tri_expression.expression_1),
155 expression_to_mathml_braceless(&tri_expression.expression_2),
156 expression_to_mathml_braceless(&tri_expression.expression_3)
157 )
158 }
159 TokenType::UnaryOperator(UnaryOperator::OBrace) => {
160 return format!(
161 "<munderover><mover>{}</mover>{}{}</munderover>",
162 expression_to_mathml_braceless(&tri_expression.expression_1),
163 expression_to_mathml_braceless(&tri_expression.expression_2),
164 expression_to_mathml_braceless(&tri_expression.expression_3)
165 )
166 }
167 _ => {}
168 }
169 }
170 format!(
171 "<msubsup>{}{}{}</msubsup>",
172 expression_to_mathml(&tri_expression.expression_1),
173 expression_to_mathml(&tri_expression.expression_2),
174 expression_to_mathml(&tri_expression.expression_3)
175 )
176}
177
178fn pow_to_mathml(bi_expression: &crate::ast::BiExpression) -> String {
179 if let Expression::Literal(Literal::Literal(token)) = bi_expression.expression_1.as_ref() {
180 match &token.token_type {
181 TokenType::Operation(op) => match op {
182 Operation::Sum
183 | Operation::Prod
184 | Operation::BigWedge
185 | Operation::BigCap
186 | Operation::BigCup => {
187 return format!(
188 "<mover>{}{}</mover>",
189 expression_to_mathml_braceless(&bi_expression.expression_1),
190 expression_to_mathml_braceless(&bi_expression.expression_2)
191 )
192 }
193 _ => {}
194 },
195 TokenType::Misc(Misc::Lim) => {
196 return format!(
197 "<mover>{}{}</mover>",
198 expression_to_mathml_braceless(&bi_expression.expression_1),
199 expression_to_mathml_braceless(&bi_expression.expression_2)
200 )
201 }
202 _ => {}
203 }
204 } else if let Expression::Unary(unary) = bi_expression.expression_1.as_ref() {
205 if let TokenType::UnaryOperator(UnaryOperator::OBrace) = unary.operator.token_type {
206 return format!(
207 "<mover><mover>{}</mover>{}</mover>",
208 expression_to_mathml_braceless(&bi_expression.expression_1),
209 expression_to_mathml_braceless(&bi_expression.expression_2),
210 );
211 }
212 }
213
214 format!(
215 "<msup>{}{}</msup>",
216 expression_to_mathml(&bi_expression.expression_1),
217 expression_to_mathml(&bi_expression.expression_2)
218 )
219}
220
221fn sub_to_mathml(bi_expression: &crate::ast::BiExpression) -> String {
222 if let Expression::Literal(Literal::Literal(literal)) = bi_expression.expression_1.as_ref() {
223 match &literal.token_type {
224 TokenType::Operation(op) => match op {
225 Operation::Sum
226 | Operation::Prod
227 | Operation::BigWedge
228 | Operation::BigCap
229 | Operation::BigCup => {
230 return format!(
231 "<munder>{}{}</munder>",
232 expression_to_mathml_braceless(&bi_expression.expression_1),
233 expression_to_mathml_braceless(&bi_expression.expression_2)
234 )
235 }
236 _ => {}
237 },
238 TokenType::Misc(Misc::Lim) => {
239 return format!(
240 "<munder>{}{}</munder>",
241 expression_to_mathml_braceless(&bi_expression.expression_1),
242 expression_to_mathml_braceless(&bi_expression.expression_2)
243 )
244 }
245 _ => {}
246 }
247 } else if let Expression::Unary(unary) = bi_expression.expression_1.as_ref() {
248 if let TokenType::UnaryOperator(UnaryOperator::UBrace) = unary.operator.token_type {
249 return format!(
250 "<munder><munder>{}</munder>{}</munder>",
251 expression_to_mathml_braceless(&bi_expression.expression_1),
252 expression_to_mathml_braceless(&bi_expression.expression_2),
253 );
254 }
255 }
256
257 format!(
258 "<msub>{}{}</msub>",
259 expression_to_mathml(&bi_expression.expression_1),
260 expression_to_mathml(&bi_expression.expression_2)
261 )
262}
263
264fn expression_to_mathml_braceless(expression: &Expression) -> String {
265 match expression {
266 Expression::Group(group) => {
267 format!("<mrow>{}</mrow>", expressions_to_mathml(&group.expressions))
268 }
269 _ => expression_to_mathml(expression),
270 }
271}
272
273fn frac_to_mathml(frac: &crate::ast::BiExpression) -> String {
274 format!(
275 "<mfrac>{}{}</mfrac>",
276 expression_to_mathml_braceless(&frac.expression_1),
277 expression_to_mathml_braceless(&frac.expression_2)
278 )
279}
280
281fn unary_to_mathml(unary: &crate::ast::Unary) -> String {
282 match unary.operator.token_type {
283 TokenType::UnaryOperator(UnaryOperator::Hat)
284 | TokenType::UnaryOperator(UnaryOperator::Bar)
285 | TokenType::UnaryOperator(UnaryOperator::Vec)
286 | TokenType::UnaryOperator(UnaryOperator::Tilde)
287 | TokenType::UnaryOperator(UnaryOperator::Dot)
288 | TokenType::UnaryOperator(UnaryOperator::DDot)
289 | TokenType::UnaryOperator(UnaryOperator::OBrace) => {
290 let symbol = match unary.operator.token_type {
291 TokenType::UnaryOperator(UnaryOperator::Hat) => "^",
292 TokenType::UnaryOperator(UnaryOperator::Bar) => "¯",
293 TokenType::UnaryOperator(UnaryOperator::Vec) => "→",
294 TokenType::UnaryOperator(UnaryOperator::Tilde) => "~",
295 TokenType::UnaryOperator(UnaryOperator::Dot) => ".",
296 TokenType::UnaryOperator(UnaryOperator::DDot) => "..",
297 TokenType::UnaryOperator(UnaryOperator::OBrace) => "⏞",
298 _ => "",
299 };
300
301 format!(
302 "<mover>{}<mo>{}</mo></mover>",
303 expression_to_mathml_braceless(&unary.expression),
304 symbol
305 )
306 }
307 TokenType::UnaryOperator(UnaryOperator::Ul)
308 | TokenType::UnaryOperator(UnaryOperator::UBrace) => {
309 let symbol = match unary.operator.token_type {
310 TokenType::UnaryOperator(UnaryOperator::Ul) => "̲",
311 TokenType::UnaryOperator(UnaryOperator::UBrace) => "⏟",
312 _ => "",
313 };
314
315 format!(
316 "<munder>{}<mo>{}</mo></munder>",
317 expression_to_mathml_braceless(&unary.expression),
318 symbol
319 )
320 }
321 TokenType::UnaryOperator(UnaryOperator::Abs)
322 | TokenType::UnaryOperator(UnaryOperator::Floor)
323 | TokenType::UnaryOperator(UnaryOperator::Ceil)
324 | TokenType::UnaryOperator(UnaryOperator::Norm) => {
325 let (left_symbol, right_symbol) = match unary.operator.token_type {
326 TokenType::UnaryOperator(UnaryOperator::Abs) => ("|", "|"),
327 TokenType::UnaryOperator(UnaryOperator::Floor) => ("⌊", "⌋"),
328 TokenType::UnaryOperator(UnaryOperator::Ceil) => ("⌈", "⌉"),
329 TokenType::UnaryOperator(UnaryOperator::Norm) => ("∥", "∥"),
330 _ => ("", ""),
331 };
332
333 format!(
334 "<mo>{}</mo>{}<mo>{}</mo>",
335 left_symbol,
336 expression_to_mathml_braceless(&unary.expression),
337 right_symbol
338 )
339 }
340 TokenType::UnaryOperator(UnaryOperator::Cancel) => format!(
341 "<menclose notation=\"updiagonalstrike\">{}</menclose>",
342 expression_to_mathml_braceless(&unary.expression)
343 ),
344 TokenType::UnaryOperator(UnaryOperator::Sqrt) => {
345 format!(
346 "<msqrt>{}</msqrt>",
347 expression_to_mathml_braceless(&unary.expression)
348 )
349 }
350 TokenType::UnaryOperator(UnaryOperator::Text) => {
351 format!(
352 "<mtext>{}</mtext>",
353 expression_to_mathml_braceless(&unary.expression)
354 )
355 }
356 _ => "".to_string(),
357 }
358}
359
360fn literal_to_mathml(literal: &crate::ast::Literal) -> String {
361 match literal {
362 Literal::Literal(token) => token_to_mathml(token),
363 Literal::Table(table) => table_to_mathml(table),
364 }
365}
366
367fn table_to_mathml(table: &crate::ast::Table) -> String {
368 format!(
369 "<mrow>{}<mtable {}>{}</mtable>{}</mrow>",
370 l_brace_to_math_ml(&table.l_brace),
371 format_column_line(table),
372 expressions_to_mathml_table(&table.rows),
373 r_brace_to_math_ml(&table.r_brace)
374 )
375}
376
377fn format_column_line(table: &Table) -> String {
378 table
379 .rows
380 .first()
381 .map(|row| {
382 format!(
383 "columnlines=\"{}\"",
384 row.cols
385 .iter()
386 .enumerate()
387 .skip(1)
388 .map(|(index, _)| {
389 if table.seperators.contains(&index) {
390 "solid".to_string()
391 } else {
392 "none".to_string()
393 }
394 })
395 .join(" ")
396 )
397 })
398 .unwrap_or("".to_string())
399}
400
401fn expressions_to_mathml_table(rows: &[TableRow]) -> String {
402 rows.iter()
403 .map(|row| {
404 format!(
405 "<mtr>{}</mtr>",
406 row.cols
407 .iter()
408 .map(|col| format!("<mtd>{}</mtd>", expressions_to_mathml(col)))
409 .join("")
410 )
411 })
412 .join("")
413}
414
415fn l_brace_to_math_ml(token: &Token) -> String {
416 match &token.token_type {
417 TokenType::LBrace(lbrace) => match lbrace {
418 LBrace::LParen => "<mo>(</mo>".to_string(),
419 LBrace::LBracket => "<mo>[</mo>".to_string(),
420 LBrace::LBrace => "<mo>{</mo>".to_string(),
421 LBrace::LColonBrace => "".to_string(),
422 LBrace::LAngle => "<mo><</mo>".to_string(),
423 },
424 _ => token.span.text.to_string(),
425 }
426}
427
428fn r_brace_to_math_ml(token: &Token) -> String {
429 match &token.token_type {
430 TokenType::RBrace(rbrace) => match rbrace {
431 RBrace::RParen => "<mo>)</mo>".to_string(),
432 RBrace::RBracket => "<mo>]</mo>".to_string(),
433 RBrace::RBrace => "<mo>}</mo>".to_string(),
434 RBrace::RColonBrace => "".to_string(),
435 RBrace::RAngle => "<mo>></mo>".to_string(),
436 },
437 _ => token.span.text.to_string(),
438 }
439}
440
441fn token_to_mathml(token: &Token) -> String {
442 match &token.token_type {
443 TokenType::Symbol => format!("<mi>{}</mi>", token.span.text),
444 TokenType::Greek(greek) => greek_to_mathml(greek),
445 TokenType::Operation(op) => format!("<mo>{}</mo>", operation_to_mathml(op)),
446 TokenType::Misc(misc) => misc_to_mathml(misc),
447 TokenType::Relational(relational) => relational_to_mathml(relational),
448 TokenType::Arrow(arrow) => format!("<mo>{}</mo>", arrow_to_mathml(arrow)),
449 TokenType::Logical(logical) => logical_to_mathml(logical),
450 TokenType::Number => format!("<mn>{}</mn>", token.span.text),
451 TokenType::Text => format!("<mtext>{}</mtext>", token.span.text),
452 TokenType::Function(function) => format!("<mi>{}</mi>", function_to_mathml(function)),
453 TokenType::None => "".to_string(),
454 _ => format!("<mi>{}</mi>", token.span.text),
455 }
456}
457
458fn greek_to_mathml(greek: &Greek) -> String {
459 let symbol = match greek {
460 Greek::Alpha => "α",
461 Greek::Beta => "β",
462 Greek::Gamma => "β",
463 Greek::UGamma => "Γ",
464 Greek::Delta => "δ",
465 Greek::UDelta => "Δ",
466 Greek::Epsilon => "ε",
467 Greek::VarEpsilon => "ɛ",
468 Greek::Zeta => "ζ",
469 Greek::Eta => "η",
470 Greek::Theta => "θ",
471 Greek::UTheta => "Θ",
472 Greek::VarTheta => "ϑ",
473 Greek::Iota => "ι",
474 Greek::Kappa => "κ",
475 Greek::Lambda => "λ",
476 Greek::ULambda => "Λ",
477 Greek::Mu => "μ",
478 Greek::Nu => "ν",
479 Greek::Xi => "ξ",
480 Greek::UXi => "Ξ",
481 Greek::Pi => "π",
482 Greek::UPi => "Π",
483 Greek::Rho => "ρ",
484 Greek::Sigma => "σ",
485 Greek::USigma => "Σ",
486 Greek::Tau => "τ",
487 Greek::Upsilon => "υ",
488 Greek::Phi => "ϕ",
489 Greek::UPhi => "Φ",
490 Greek::VarPhi => "φ",
491 Greek::Chi => "χ",
492 Greek::Psi => "ψ",
493 Greek::UPsi => "Ψ",
494 Greek::Omega => "ω",
495 Greek::UOmega => "Ω",
496 };
497
498 format!("<mi>{symbol}</mi>")
499}
500
501fn logical_to_mathml(logical: &Logical) -> String {
502 match logical {
503 Logical::Not
504 | Logical::Implies
505 | Logical::Iff
506 | Logical::ForAll
507 | Logical::Exists
508 | Logical::Bot
509 | Logical::Top
510 | Logical::VDash
511 | Logical::Models => {
512 let symbol = match logical {
513 Logical::Not => "¬",
514 Logical::Implies => "⇒",
515 Logical::Iff => "⇔",
516 Logical::ForAll => "∀",
517 Logical::Exists => "∃",
518 Logical::Bot => "⊥",
519 Logical::Top => "⊤",
520 Logical::VDash => "⊢",
521 Logical::Models => "⊨",
522 _ => "",
523 };
524
525 format!("<mo>{symbol}</mo>")
526 }
527 Logical::And | Logical::Or | Logical::If => {
528 let symbol = match logical {
529 Logical::And => "and",
530 Logical::Or => "or",
531 Logical::If => "if",
532 _ => "",
533 };
534
535 format!("<mrow><mspace width=\"1ex\" /><mtext>{symbol}</mtext><msapce with=\"1ex\" /></mrow>")
536 }
537 }
538}
539
540fn function_to_mathml(function: &Function) -> &'static str {
541 match function {
542 Function::Sin => "sin",
543 Function::Cos => "cos",
544 Function::Tan => "tan",
545 Function::Sec => "sec",
546 Function::Csc => "csc",
547 Function::Cot => "cot",
548 Function::Arcsin => "arcsin",
549 Function::Arccos => "arccos",
550 Function::Arctan => "arctan",
551 Function::Sinh => "sinh",
552 Function::Cosh => "cosh",
553 Function::Tanh => "tanh",
554 Function::Sech => "sech",
555 Function::Csch => "csch",
556 Function::Coth => "coth",
557 Function::Exp => "exp",
558 Function::Log => "log",
559 Function::Ln => "ln",
560 Function::Det => "det",
561 Function::Dim => "dim",
562 Function::Mod => "mod",
563 Function::Gcd => "gcd",
564 Function::Lcm => "lcm",
565 Function::Lub => "lub",
566 Function::Glb => "glb",
567 Function::Min => "min",
568 Function::Max => "max",
569 Function::F => "f",
570 Function::G => "g",
571 }
572}
573
574fn arrow_to_mathml(arrow: &Arrow) -> &'static str {
575 match arrow {
576 Arrow::UpArrow => "↑",
577 Arrow::DownArrow => "↓",
578 Arrow::RightArrow => "→",
579 Arrow::ToArrow => "→",
580 Arrow::RightArrowTail => "↣",
581 Arrow::RightArrowTwoHead => "↠",
582 Arrow::RightArrowTwoHeadTail => "⤖",
583 Arrow::MapsTo => "↦",
584 Arrow::LeftArrow => "←",
585 Arrow::LeftRightArrow => "↔",
586 Arrow::DoubleRightArrow => "⇒",
587 Arrow::DoubleLeftArrow => "⇐",
588 Arrow::DoubleLeftRightArrow => "⇔",
589 }
590}
591
592fn relational_to_mathml(relational: &Relational) -> String {
593 match relational {
594 Relational::Equals
595 | Relational::NotEquals
596 | Relational::Lt
597 | Relational::Gt
598 | Relational::Lte
599 | Relational::Gte
600 | Relational::Prec
601 | Relational::PrecEq
602 | Relational::Succ
603 | Relational::SuccEq
604 | Relational::In
605 | Relational::NotIn
606 | Relational::Sub
607 | Relational::Sup
608 | Relational::SubEq
609 | Relational::SupEq
610 | Relational::Equiv
611 | Relational::Cong
612 | Relational::Approx
613 | Relational::Prop => {
614 let symbol = match relational {
615 Relational::Equals => "=",
616 Relational::NotEquals => "≠",
617 Relational::Lt => "<",
618 Relational::Gt => ">",
619 Relational::Lte => "≤",
620 Relational::Gte => "≥",
621 Relational::Prec => "≺",
622 Relational::PrecEq => "⪯",
623 Relational::Succ => "≻",
624 Relational::SuccEq => "⪰",
625 Relational::In => "∈",
626 Relational::NotIn => "∉",
627 Relational::Sub => "⊂",
628 Relational::SubEq => "⊆",
629 Relational::Sup => "⊃",
630 Relational::SupEq => "⊇",
631 Relational::Equiv => "≡",
632 Relational::Cong => "≅",
633 Relational::Approx => "≈",
634 Relational::Prop => "∝",
635 _ => "",
636 };
637
638 format!("<mo>{}</mo>", symbol)
639 }
640 Relational::Mlt => "<mi>m</mi><mo><</mo>".to_string(),
641 Relational::Mgt => "<mi>m</mi><mo>></mo>".to_string(),
642 }
643}
644
645fn misc_to_mathml(misc: &Misc) -> String {
646 match misc {
647 Misc::DoublePipes => {
648 return "<mrow><mo>∣</mo></mrow><mrow><mo>∣</mo></mrow>".to_string()
649 }
650 Misc::DoublePipesQuad => {
651 return "<mrow><mo>|</mo><mo>  </mo><mo>|</mo></mrow>".to_string()
652 }
653 _ => {}
654 }
655
656 let symbol = match misc {
657 Misc::Int => "∫",
658 Misc::OInt => "∮",
659 Misc::Del => "∂",
660 Misc::Grad => "∇",
661 Misc::PlusMinus => "±",
662 Misc::EmptySet => "∅",
663 Misc::Infinity => "∞",
664 Misc::Aleph => "ℵ",
665 Misc::Therefore => "∴",
666 Misc::Because => "∵",
667 Misc::LDots => "...",
668 Misc::CDots => "⋯",
669 Misc::VDots => "⋮",
670 Misc::DDots => "⋱",
671 Misc::Angle => "∠",
672 Misc::Frown => "⌢",
673 Misc::Triangle => "△",
674 Misc::Diamond => "⋄",
675 Misc::Square => "□",
676 Misc::LFloor => "⌊",
677 Misc::RFloor => "⌋",
678 Misc::LCeiling => "⌈",
679 Misc::RCeiling => "⌉",
680 Misc::CC => "ℂ",
681 Misc::NN => "ℕ",
682 Misc::QQ => "ℚ",
683 Misc::RR => "ℝ",
684 Misc::ZZ => "ℤ",
685 Misc::DoublePipes => "",
686 Misc::DoublePipesQuad => "",
687 Misc::Lim => "lim",
688 };
689
690 format!("<mo>{symbol}</mo>")
691}
692
693fn operation_to_mathml(op: &Operation) -> &'static str {
694 match op {
695 Operation::Plus => "+",
696 Operation::Minus => "-",
697 Operation::CDot => "⋅",
698 Operation::Ast => "∗",
699 Operation::Star => "⋆",
700 Operation::Slash => "/",
701 Operation::Backslash => "\\",
702 Operation::Times => "×",
703 Operation::Div => "÷",
704 Operation::LTimes => "⋉",
705 Operation::RTimes => "⋊",
706 Operation::Bowtie => "⋈",
707 Operation::Circ => "∘",
708 Operation::OPlus => "⊕",
709 Operation::OTimes => "⊗",
710 Operation::ODot => "⊙",
711 Operation::Sum => "∑",
712 Operation::Prod => "∏",
713 Operation::Wedge => "∧",
714 Operation::BigWedge => "⋀",
715 Operation::Vee => "∨",
716 Operation::BigVee => "⋁",
717 Operation::Cap => "∩",
718 Operation::BigCap => "⋂",
719 Operation::Cup => "∪",
720 Operation::BigCup => "⋃",
721 }
722}