1use mech_core::*;
2use mech_core::nodes::{Kind, Matrix};
3use std::collections::{HashMap, HashSet};
4use colored::Colorize;
5use std::io::{Read, Write, Cursor};
6use crate::*;
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct Formatter{
10 identifiers: HashMap<u64, String>,
11 rows: usize,
12 cols: usize,
13 indent: usize,
14 pub html: bool,
15 nested: bool,
16 toc: bool,
17 figure_num: usize,
18 h2_num: usize,
19 h3_num: usize,
20 h4_num: usize,
21 h5_num: usize,
22 h6_num: usize,
23 citation_num: usize,
24 citation_map: HashMap<u64, usize>,
25 citations: Vec<String>,
26 interpreter_id: u64,
27}
28
29
30impl Formatter {
31
32 pub fn new() -> Formatter {
33 Formatter {
34 identifiers: HashMap::new(),
35 rows: 0,
36 cols: 0,
37 indent: 0,
38 h2_num: 0,
39 h3_num: 0,
40 h4_num: 0,
41 h5_num: 0,
42 h6_num: 0,
43 citation_num: 0,
44 citation_map: HashMap::new(),
45 citations: Vec::new(),
46 figure_num: 0,
47 html: false,
48 nested: false,
49 toc: false,
50 interpreter_id: 0,
51 }
52 }
53
54 pub fn format(&mut self, tree: &Program) -> String {
55 self.html = false;
56 self.program(tree)
57 }
58
59 pub fn reset_numbering(&mut self) {
65 self.h2_num = 0;
66 self.h3_num = 0;
67 self.h4_num = 0;
68 self.h5_num = 0;
69 self.h6_num = 0;
70 self.figure_num = 0;
71 }
72
73 pub fn works_cited(&mut self) -> String {
74 if self.citation_num == 0 {
75 return "".to_string();
76 }
77 let id = hash_str("works-cited");
78
79 let gs = graphemes::init_source("Works Cited");
80 let (_,text) = paragraph(ParseString::new(&gs)).unwrap();
81 let h2 = self.subtitle(&Subtitle { level: 2, text });
82
83 let mut src = format!(r#"<section id="67320967384727436" class="mech-works-cited">"#);
84 src.push_str(&h2);
85 for citation in &self.citations {
86 src.push_str(citation);
87 }
88 src.push_str("</section>\n");
89 src
90 }
91
92 pub fn format_html(&mut self, tree: &Program, style: String, shim: String) -> String {
93 self.html = true;
94
95 let toc = tree.table_of_contents();
96 let formatted_src = self.program(tree);
97 self.reset_numbering();
98 let formatted_toc = self.table_of_contents(&toc);
99
100 let title = match toc.title {
101 Some(title) => title.to_string(),
102 None => "Mech Program".to_string(),
103 };
104
105 #[cfg(feature = "serde")]
106 let encoded_tree = match compress_and_encode(&tree) {
107 Ok(encoded) => encoded,
108 Err(e) => todo!(),
109 };
110 #[cfg(not(feature = "serde"))]
111 let encoded_tree = String::new();
112
113 shim.replace("{{STYLESHEET}}", &style)
114 .replace("{{TOC}}", &formatted_toc)
115 .replace("{{CONTENT}}", &formatted_src)
116 .replace("{{CODE}}", &encoded_tree)
117 .replace("{{TITLE}}", &title)
118 }
119
120 pub fn table_of_contents(&mut self, toc: &TableOfContents) -> String {
121 self.toc = true;
122 let title = match &toc.title {
123 Some(title) => self.title(&title),
124 None => "".to_string(),
125 };
126 let sections = self.sections(&toc.sections);
127 self.toc = false;
128 let section_id = hash_str(&format!("section-{}",self.h2_num + 1));
129 let formatted_works_cited = if self.html && self.citation_num > 0 {
130 format!("<section id=\"\" section=\"{}\" class=\"mech-program-section toc\">
131 <h2 id=\"\" section=\"{}\" class=\"mech-program-subtitle toc active\">
132 <a class=\"mech-program-subtitle-link toc\" href=\"#67320967384727436\">Works Cited</a>
133 </h2>
134</section>", section_id, self.h2_num + 1)
135 } else {
136 "".to_string()
137 };
138 format!("<div class=\"mech-toc\">{}{}{}</div>",title,sections,formatted_works_cited)
139 }
140
141 pub fn sections(&mut self, sections: &Vec<Section>) -> String {
142 let mut src = "".to_string();
143 let section_count = sections.len();
144 for (i, section) in sections.iter().enumerate() {
145 let s = self.section(section);
146 src = format!("{}{}", src, s);
147 }
148 format!("<section class=\"mech-toc-sections\">{}</section>",src)
149 }
150
151 pub fn program(&mut self, node: &Program) -> String {
152 let title = match &node.title {
153 Some(title) => self.title(&title),
154 None => "".to_string(),
155 };
156 let body = self.body(&node.body);
157 let formatted_works_cited = self.works_cited();
158 if self.html {
159 format!("<div class=\"mech-content\"><div class=\"mech-program\">{}{}{}</div></div>",title,body,formatted_works_cited)
160 } else {
161 format!("{}{}{}",title,body,formatted_works_cited)
162 }
163 }
164
165 pub fn title(&mut self, node: &Title) -> String {
166 if self.html {
167 format!("<h1 class=\"mech-program-title\">{}</h1>",node.to_string())
168 } else {
169 format!("{}\n===============================================================================\n",node.to_string())
170 }
171 }
172
173 pub fn subtitle(&mut self, node: &Subtitle) -> String {
174 let level = node.level;
175 if level == 2 {
176 self.h2_num += 1;
177 self.h3_num = 0;
178 self.h4_num = 0;
179 self.h5_num = 0;
180 self.h6_num = 0;
181 self.figure_num = 0;
182 } else if level == 3 {
183 self.h3_num += 1;
184 } else if level == 4 {
185 self.h4_num += 1;
186 } else if level == 5 {
187 self.h5_num += 1;
188 } else if level == 6 {
189 self.h6_num += 1;
190 }
191
192 let toc = if self.toc { "toc" } else { "" };
193 let title_id = hash_str(&format!("{}.{}.{}.{}.{}{}",self.h2_num,self.h3_num,self.h4_num,self.h5_num,self.h6_num,toc));
194
195 let link_str = format!("{}.{}.{}.{}.{}",self.h2_num,self.h3_num,self.h4_num,self.h5_num,self.h6_num);
196 let link_id = hash_str(&link_str);
197
198 let section = if level == 2 { format!("section=\"{}.{}\"", self.h2_num, self.h3_num) }
199 else if level == 3 { format!("section=\"{}.{}\"", self.h2_num, self.h3_num) }
200 else if level == 4 { format!("section=\"{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num) }
201 else if level == 5 { format!("section=\"{}.{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num, self.h5_num) }
202 else if level == 6 { format!("section=\"{}.{}.{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num, self.h5_num, self.h6_num) }
203 else { "".to_string() };
204
205 if self.html {
206 format!("<h{} id=\"{}\" {} class=\"mech-program-subtitle {}\"><a class=\"mech-program-subtitle-link {}\" href=\"#{}\">{}</a></h{}>", level, title_id, section, toc, toc, link_id, node.to_string(), level)
207 } else {
208 format!("{}\n-------------------------------------------------------------------------------\n",node.to_string())
209 }
210 }
211
212 pub fn body(&mut self, node: &Body) -> String {
213 let mut src = "".to_string();
214 let section_count = node.sections.len();
215 for (i, section) in node.sections.iter().enumerate() {
216 let s = self.section(section);
217 src = format!("{}{}", src, s);
218 }
219 if self.html {
220 format!("<div class=\"mech-program-body\">{}</div>",src)
221 } else {
222 src
223 }
224 }
225
226 pub fn section(&mut self, node: &Section) -> String {
227 let mut src = match &node.subtitle {
228 Some(title) => self.subtitle(title),
229 None => "".to_string(),
230 };
231 for el in node.elements.iter() {
232 let el_str = self.section_element(el);
233 src = format!("{}{}", src, el_str);
234 }
235 let toc = if self.toc { "toc" } else { "" };
236 let section_id = hash_str(&format!("section-{}",self.h2_num + 1));
237 let id = hash_str(&format!("section-{}{}",self.h2_num + 1, toc));
238 if self.html {
239 format!("<section id=\"{}\" section=\"{}\" class=\"mech-program-section {}\">{}</section>",id,section_id,toc,src)
240 } else {
241 src
242 }
243 }
244
245 pub fn paragraph(&mut self, node: &Paragraph) -> String {
246 let mut src = "".to_string();
247 for el in node.elements.iter() {
248 let el_str = self.paragraph_element(el);
249 src = format!("{}{}", src, el_str);
250 }
251 let result = if self.html {
252 format!("<p class=\"mech-paragraph\">{}</p>",src)
253 } else {
254 format!("{}\n",src)
255 };
256 result
257 }
258
259 fn footnote_reference(&mut self, node: &Token) -> String {
260 let id_string = node.to_string();
261 let id_hash = hash_str(&format!("footnote-{}",id_string));
262 if self.html {
263 format!("<a href=\"#{}\" class=\"mech-footnote-reference\">{}</a>",id_hash, id_string)
264 } else {
265 format!("[^{}]",id_string)
266 }
267 }
268
269 fn inline_equation(&mut self, node: &Token) -> String {
270 let id = hash_str(&format!("inline-equation-{}",node.to_string()));
271 if self.html {
272 format!("<span id=\"{}\" equation=\"{}\" class=\"mech-inline-equation\"></span>",id, node.to_string())
273 } else {
274 format!("$${}$$", node.to_string())
275 }
276 }
277
278 fn highlight(&mut self, node: &Token) -> String {
279 if self.html {
280 format!("<mark class=\"mech-highlight\">{}</mark>", node.to_string())
281 } else {
282 format!("!!{}!!", node.to_string())
283 }
284 }
285
286 fn reference(&mut self, node: &Token) -> String {
287 self.citation_num += 1;
288 let id = hash_str(&format!("reference-{}",node.to_string()));
289 let ref_id = hash_str(&format!("{}",node.to_string()));
290 self.citation_map.insert(ref_id, self.citation_num);
291 if self.html {
292 format!("<span id=\"{}\" class=\"mech-reference\">[<a href=\"#{}\" class=\"mech-reference-link\">{}</a>]</span>",id, ref_id, self.citation_num)
293 } else {
294 format!("[{}]",node.to_string())
295 }
296 }
297
298 pub fn paragraph_element(&mut self, node: &ParagraphElement) -> String {
299 match node {
300 ParagraphElement::Highlight(n) => {
301 if self.html {
302 format!("<mark class=\"mech-highlight\">{}</mark>", n.to_string())
303 } else {
304 format!("!!{}!!", n.to_string())
305 }
306 },
307 ParagraphElement::SectionReference(n) => {
308 let section_id_str = n.to_string();
309 let parts: Vec<&str> = section_id_str.split('.').collect();
310 let mut nums = vec!["0"; 5]; for (i, part) in parts.iter().enumerate() {
312 nums[i] = part;
313 }
314 let id_str = format!("{}.{}.{}.{}.{}",nums[0], nums[1], nums[2], nums[3], nums[4]);
315 let id = hash_str(&id_str);
316
317 if self.html {
318 format!(
319 "<span class=\"mech-section-reference\">
320 <a href=\"#{}\" class=\"mech-section-reference-link\">§{}</a>
321 </span>",
322 id, n.to_string()
323 )
324 } else {
325 format!("§{}", n.to_string())
326 }
327 }
328 ParagraphElement::Reference(n) => self.reference(n),
329 ParagraphElement::InlineEquation(exq) => self.inline_equation(exq),
330 ParagraphElement::Text(n) => {
331 if self.html {
332 format!("<span class=\"mech-text\">{}</span>", n.to_string())
333 } else {
334 n.to_string()
335 }
336 }
337 ParagraphElement::FootnoteReference(n) => self.footnote_reference(n),
338 ParagraphElement::Strong(n) => {
339 let p = self.paragraph_element(n);
340 if self.html {
341 format!("<strong class=\"mech-strong\">{}</strong>", p)
342 } else {
343 format!("**{}**", p)
344 }
345 },
346 ParagraphElement::Hyperlink((text, url)) => {
347 let url_str = url.to_string();
348 let text_str = text.to_string();
349 if self.html {
350 format!("<a href=\"{}\" class=\"mech-hyperlink\">{}</a>",url_str,text_str)
351 } else {
352 format!("[{}]({})",text_str,url_str)
353 }
354 },
355 ParagraphElement::Emphasis(n) => {
356 if self.html {
357 format!("<em class=\"mech-em\">{}</em>", n.to_string())
358 } else {
359 format!("*{}*", n.to_string())
360 }
361 },
362 ParagraphElement::Underline(n) => {
363 if self.html {
364 format!("<u class=\"mech-u\">{}</u>", n.to_string())
365 } else {
366 format!("_{}_", n.to_string())
367 }
368 },
369 ParagraphElement::Strikethrough(n) => {
370 if self.html {
371 format!("<del class=\"mech-del\">{}</del>", n.to_string())
372 } else {
373 format!("~{}~", n.to_string())
374 }
375 },
376 ParagraphElement::InlineCode(n) => {
377 if self.html {
378 format!("<code class=\"mech-inline-code\">{}</code>", n.to_string().trim())
379 } else {
380 format!("`{}`", n.to_string())
381 }
382 },
383 ParagraphElement::InlineMechCode(code) => {
384 let result = self.mech_code(&vec![(code.clone(),None)]);
385 if self.html {
386 format!("<span class=\"mech-inline-mech-code-formatted\">{}</span>", result)
387 } else {
388 format!("{{{}}}", result)
389 }
390 },
391 ParagraphElement::EvalInlineMechCode(expr) => {
392 let code_id = hash_str(&format!("{:?}", expr));
393 let result = self.expression(expr);
394 if self.html {
395 format!("<code id=\"{}\" class=\"mech-inline-mech-code\">{}</code>", code_id, result)
396 } else {
397 format!("{{{}}}", result)
398 }
399 },
400 }
401 }
402
403 pub fn fenced_mech_code(&mut self, block: &FencedMechCode) -> String {
404 self.interpreter_id = block.config.namespace;
405 let mut src = String::new();
406 for (code,cmmnt) in &block.code {
407 let c = match code {
408 MechCode::Comment(cmnt) => self.comment(cmnt),
409 MechCode::Expression(expr) => self.expression(expr),
410 MechCode::Statement(stmt) => self.statement(stmt),
414 _ => todo!(),
415 };
416 let formatted_comment = match cmmnt {
417 Some(cmmt) => self.comment(cmmt),
418 None => String::new(),
419 };
420 if self.html {
421 src.push_str(&format!("<span class=\"mech-code\">{}{}</span>", c, formatted_comment));
422 } else {
423 src.push_str(&format!("{}{}\n", c, formatted_comment));
424 }
425 }
426 let intrp_id = self.interpreter_id;
427 self.interpreter_id = 0;
428 let disabled_tag = match block.config.disabled {
429 true => "disabled".to_string(),
430 false => "".to_string(),
431 };
432 if self.html {
433 let (out_node,_) = block.code.last().unwrap();
434 let output_id = hash_str(&format!("{:?}", out_node));
435 let style_attr = match &block.options {
436 Some(option_map) if !option_map.elements.is_empty() => {
437 let style_str = option_map
438 .elements
439 .iter()
440 .map(|(k, v)| {
441 let clean_value = v.to_string().trim_matches('"').to_string();
442 format!("{}: {}", k.to_string(), clean_value)
443 })
444 .collect::<Vec<_>>()
445 .join("; ");
446 format!(" style=\"{}\"", style_str)
447 }
448 _ => "".to_string(),
449 };
450 if block.config.disabled {
451 format!("<pre class=\"mech-code-block disabled\"{}>{}</pre>", style_attr, src)
452 } else if block.config.hidden {
453 format!("<pre class=\"mech-code-block hidden\"{}>{}</pre>", style_attr, src)
455 } else {
456 format!("<div class=\"mech-fenced-mech-block\"{}>
457 <div class=\"mech-code-block\">{}</div>
458 <div class=\"mech-block-output\" id=\"{}:{}\"></div>
459 </div>", style_attr, src, output_id, intrp_id)
460 }
461 } else {
462 format!("```mech{}\n{}\n```", src, format!(":{}", disabled_tag))
463 }
464 }
465
466 pub fn image(&mut self, node: &Image) -> String {
467 self.figure_num += 1;
468
469 let src = node.src.to_string();
470 let caption_p = match &node.caption {
471 Some(caption) => self.paragraph(caption),
472 None => "".to_string(),
473 };
474
475 let figure_label = format!("Fig {}.{}", self.h2_num, self.figure_num);
476 let image_id = hash_str(&src);
477 let figure_id = hash_str(&figure_label);
478
479 if self.html {
480 let style_attr = match &node.style {
481 Some(option_map) if !option_map.elements.is_empty() => {
482 let style_str = option_map
483 .elements
484 .iter()
485 .map(|(k, v)| {
486 let clean_value = v.to_string().trim_matches('"').to_string();
487 format!("{}: {}", k.to_string(), clean_value)
488 })
489 .collect::<Vec<_>>()
490 .join("; ");
491 format!(" style=\"{}\"", style_str)
492 }
493 _ => "".to_string(),
494 };
495 format!(
496"<figure id=\"{}\" class=\"mech-figure\">
497 <img id=\"{}\" class=\"mech-image\" src=\"{}\"{} />
498 <figcaption class=\"mech-figure-caption\">
499 <strong class=\"mech-figure-label\">{}</strong> {}
500 </figcaption>
501</figure>",figure_id, image_id, src, style_attr, figure_label, caption_p)
502 } else {
503 let style_str = match &node.style {
504 Some(option_map) if !option_map.elements.is_empty() => {
505 let inner = option_map
506 .elements
507 .iter()
508 .map(|(k, v)| {
509 let clean_value = v.to_string().trim_matches('"').to_string();
510 format!("{}: \"{}\"", k.to_string(), clean_value)
511 })
512 .collect::<Vec<_>>()
513 .join(", ");
514 format!("{{{}}}", inner)
515 }
516 _ => "".to_string(),
517 };
518
519 format!("{}", caption_p, src, style_str)
520 }
521 }
522
523
524 pub fn abstract_el(&mut self, node: &Vec<Paragraph>) -> String {
525 let abstract_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
526 if self.html {
527 format!("<div id=\"abstract\" class=\"mech-abstract\">{}</div>", abstract_paragraph)
528 } else {
529 format!("{}\n", abstract_paragraph)
530 }
531 }
532
533 pub fn equation(&mut self, node: &Token) -> String {
534 let id = hash_str(&format!("equation-{}",node.to_string()));
535 if self.html {
536 format!("<div id=\"{}\" equation=\"{}\" class=\"mech-equation\"></div>",id, node.to_string())
537 } else {
538 format!("$$ {}\n", node.to_string())
539 }
540 }
541
542 pub fn diagram(&mut self, node: &Token) -> String {
543 let id = hash_str(&format!("diagram-{}",node.to_string()));
544 if self.html {
545 format!("<div id=\"{}\" class=\"mech-diagram mermaid\">{}</div>",id, node.to_string())
546 } else {
547 format!("```{{diagram}}\n{}\n```", node.to_string())
548 }
549 }
550
551 pub fn citation(&mut self, node: &Citation) -> String {
552 let id = hash_str(&format!("{}",node.id.to_string()));
553 self.citations.resize(self.citation_num, String::new());
554 let citation_text = self.paragraph(&node.text);
555 let citation_num = match self.citation_map.get(&id) {
556 Some(&num) => num,
557 None => {
558 return format!("Citation {} not found in citation map.", node.id.to_string());
559 }
560 };
561 let formatted_citation = if self.html {
562 format!("<div id=\"{}\" class=\"mech-citation\">
563 <div class=\"mech-citation-id\">[{}]:</div>
564 {}
565 </div>",id, citation_num, citation_text)
566 } else {
567 format!("[{}]: {}",node.id.to_string(), citation_text)
568 };
569 self.citations[citation_num - 1] = formatted_citation;
570 String::new()
571 }
572
573 pub fn float(&mut self, node: &Box<SectionElement>, float_dir: &FloatDirection) -> String {
574 let mut src = "".to_string();
575 let id = hash_str(&format!("float-{:?}",*node));
576 let (float_class,float_sigil) = match float_dir {
577 FloatDirection::Left => ("mech-float left","<<"),
578 FloatDirection::Right => ("mech-float right",">>"),
579 };
580 let el = self.section_element(node);
581 if self.html {
582 format!("<div id=\"{}\" class=\"{}\">{}</div>",id,float_class,el)
583 } else {
584 format!("{}{}\n",float_sigil, el)
585 }
586 }
587
588 pub fn info_block(&mut self, node: &Vec<Paragraph>) -> String {
589 let info_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
590 if self.html {
591 format!("<div class=\"mech-info-block\">{}</div>",info_paragraph)
592 } else {
593 format!("(!)> {}\n",info_paragraph)
594 }
595 }
596
597 pub fn question_block(&mut self, node: &Vec<Paragraph>) -> String {
598 let question_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
599 if self.html {
600 format!("<div class=\"mech-question-block\">{}</div>",question_paragraph)
601 } else {
602 format!("(?)> {}\n",question_paragraph)
603 }
604 }
605
606 pub fn section_element(&mut self, node: &SectionElement) -> String {
607 match node {
608 SectionElement::Abstract(n) => self.abstract_el(n),
609 SectionElement::QuoteBlock(n) => self.quote_block(n),
610 SectionElement::InfoBlock(n) => self.info_block(n),
611 SectionElement::QuestionBlock(n) => self.question_block(n),
612 SectionElement::Citation(n) => self.citation(n),
613 SectionElement::CodeBlock(n) => self.code_block(n),
614 SectionElement::Comment(n) => self.comment(n),
615 SectionElement::Diagram(n) => self.diagram(n),
616 SectionElement::Equation(n) => self.equation(n),
617 SectionElement::FencedMechCode(n) => self.fenced_mech_code(n),
618 SectionElement::Float((n,f)) => self.float(n,f),
619 SectionElement::Footnote(n) => self.footnote(n),
620 SectionElement::Grammar(n) => self.grammar(n),
621 SectionElement::Image(n) => self.image(n),
622 SectionElement::List(n) => self.list(n),
623 SectionElement::MechCode(n) => self.mech_code(n),
624 SectionElement::Paragraph(n) => self.paragraph(n),
625 SectionElement::Subtitle(n) => self.subtitle(n),
626 SectionElement::Table(n) => self.mechdown_table(n),
627 SectionElement::ThematicBreak => self.thematic_break(),
628 }
629 }
630
631 pub fn footnote(&mut self, node: &Footnote) -> String {
632 let (id_name, p) = node;
633 let note_paragraph = self.paragraph(p);
634 let id: u64 = hash_str(&format!("footnote-{}",id_name.to_string()));
635 if self.html {
636 format!("<div class=\"mech-footnote\" id=\"{}\">
637 <div class=\"mech-footnote-id\">{}:</div>
638 {}
639 </div>",id, id_name.to_string(), note_paragraph)
640 } else {
641 format!("[^{}]: {}\n",id_name.to_string(), note_paragraph)
642 }
643 }
644
645 pub fn quote_block(&mut self, node: &Vec<Paragraph>) -> String {
646 let quote_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
647 if self.html {
648 format!("<blockquote class=\"mech-block-quote\">{}</blockquote>",quote_paragraph)
649 } else {
650 format!("> {}\n",quote_paragraph)
651 }
652 }
653
654 pub fn thematic_break(&mut self) -> String {
655 if self.html {
656 format!("<hr class=\"mech-thematic-break\"/>")
657 } else {
658 format!("***\n")
659 }
660 }
661
662 pub fn mechdown_table(&mut self, node: &MarkdownTable) -> String {
663 if self.html {
664 self.mechdown_table_html(node)
665 } else {
666 self.mechdown_table_string(node)
667 }
668 }
669
670
671 pub fn mechdown_table_string(&mut self, node: &MarkdownTable) -> String {
672 fn render_row(cells: &[Paragraph], f: &mut impl FnMut(&Paragraph) -> String) -> String {
674 let mut row = String::from("|");
675 for cell in cells {
676 row.push_str(" ");
677 row.push_str(&f(cell));
678 row.push_str(" |");
679 }
680 row
681 }
682
683 let header_line = render_row(&node.header, &mut |p| self.paragraph(p));
685
686 let mut align_line = String::from("|");
688 for align in &node.alignment {
689 let spec = match align {
690 ColumnAlignment::Left => ":---",
691 ColumnAlignment::Center => ":---:",
692 ColumnAlignment::Right => "---:",
693 };
694 align_line.push_str(&format!(" {} |", spec));
695 }
696
697 let mut body_lines = vec![];
699 for row in &node.rows {
700 body_lines.push(render_row(row, &mut |p| self.paragraph(p)));
701 }
702
703 let mut markdown = String::new();
705 markdown.push_str(&header_line);
706 markdown.push('\n');
707 markdown.push_str(&align_line);
708 markdown.push('\n');
709 for line in body_lines {
710 markdown.push_str(&line);
711 markdown.push('\n');
712 }
713
714 markdown
715}
716
717
718 pub fn mechdown_table_html(&mut self, node: &MarkdownTable) -> String {
719 let mut html = String::new();
720 html.push_str("<table class=\"mech-table\">");
721
722 if !node.header.is_empty() {
724 html.push_str("<thead><tr class=\"mech-table-header\">");
725 for (i, cell) in node.header.iter().enumerate() {
726 let align = match node.alignment.get(i) {
727 Some(ColumnAlignment::Left) => "left",
728 Some(ColumnAlignment::Center) => "center",
729 Some(ColumnAlignment::Right) => "right",
730 None => "left", };
732 let cell_html = self.paragraph(cell);
733 html.push_str(&format!(
734 "<th class=\"mech-table-header-cell {}\">{}</th>",
735 align, cell_html
736 ));
737 }
738 html.push_str("</tr></thead>");
739 }
740
741 html.push_str("<tbody>");
743 for (row_index, row) in node.rows.iter().enumerate() {
744 let row_class = if row_index % 2 == 0 { "mech-table-row-even" } else { "mech-table-row-odd" };
745 html.push_str(&format!("<tr class=\"mech-table-row {}\">", row_class));
746 for (i, cell) in row.iter().enumerate() {
747 let align = match node.alignment.get(i) {
748 Some(ColumnAlignment::Left) => "left",
749 Some(ColumnAlignment::Center) => "center",
750 Some(ColumnAlignment::Right) => "right",
751 None => "left", };
753 let cell_html = self.paragraph(cell);
754 html.push_str(&format!(
755 "<td class=\"mech-table-cell {}\">{}</td>",
756 align, cell_html
757 ));
758 }
759 html.push_str("</tr>");
760 }
761 html.push_str("</tbody>");
762 html.push_str("</table>");
763 html
764 }
765
766 pub fn grammar(&mut self, node: &Grammar) -> String {
767 let mut src = "".to_string();
768 for rule in node.rules.iter() {
769 let id = self.grammar_identifier(&rule.name);
770 let rule_str = format!("{} <span class=\"mech-grammar-define-op\">:=</span>{}", id, self.grammar_expression(&rule.expr));
771 if self.html {
772 src = format!("{}<div class=\"mech-grammar-rule\">{} ;</div>",src,rule_str);
773 } else {
774 src = format!("{}{};\n",src,rule_str);
775 }
776 }
777 if self.html {
778 format!("<div class=\"mech-grammar\">{}</div>",src)
779 } else {
780 src
781 }
782 }
783
784 fn grammar_identifier(&mut self, node: &GrammarIdentifier) -> String {
785 let name = node.name.to_string();
786 if self.html {
787 format!("<span id=\"{}\" class=\"mech-grammar-identifier\">{}</span>",hash_str(&name), name)
788 } else {
789 name
790 }
791 }
792
793 fn grammar_expression(&mut self, node: &GrammarExpression) -> String {
794 let expr = match node {
795 GrammarExpression::List(element,deliniator) => {
796 let el = self.grammar_expression(element);
797 let del = self.grammar_expression(deliniator);
798 if self.html {
799 format!("<span class=\"mech-grammar-list\">[<span class=\"mech-grammar-list-element\">{}</span>,<span class=\"mech-grammar-list-deliniator\">{}</span>]</span>",el,del)
800 } else {
801 format!("[{},{}]",el,del)
802 }
803 },
804 GrammarExpression::Range(start,end) => {
805 if self.html {
806 format!("<span class=\"mech-grammar-range\"><span class=\"mech-grammar-terminal\">\"{}\"</span><span class=\"mech-grammar-range-op\">..</span><span class=\"mech-grammar-terminal\">\"{}\"</span></span>", start.to_string(), end.to_string())
807 } else {
808 format!("{}..{}", start.to_string(), end.to_string())
809 }
810 }
811 GrammarExpression::Choice(choices) => {
812 let mut src = "".to_string();
813 let inline = choices.len() <= 3;
814 for (i, choice) in choices.iter().enumerate() {
815 let choice_str = self.grammar_expression(choice);
816 if i == 0 {
817 src = format!("{}", choice_str);
818 } else {
819 if self.html {
820 src = if inline {
821 format!("{} <span class=\"mech-grammar-choice-op\">|</span> {}", src, choice_str)
822 } else {
823 format!("{}<div class=\"mech-grammar-choice\"><span class=\"mech-grammar-choice-op\">|</span> {}</div>", src, choice_str)
824 };
825 } else {
826 src = format!("{} | {}", src, choice_str);
827 }
828 }
829 }
830 src
831 },
832 GrammarExpression::Sequence(seq) => {
833 let mut src = "".to_string();
834 let inline = seq.len() <= 3;
835 for (i, factor) in seq.iter().enumerate() {
836 let factor_str = self.grammar_expression(factor);
837 if i == 0 {
838 src = format!("{}", factor_str);
839 } else {
840 if self.html {
841 src = if inline {
842 format!("{}, {}", src, factor_str)
843 } else {
844 format!("{}<div class=\"mech-grammar-sequence\"><span class=\"mech-grammar-sequence-op\">,</span> {}</div>", src, factor_str)
845 };
846 } else {
847 src = format!("{}, {}", src, factor_str);
848 }
849 }
850 }
851 src
852 },
853 GrammarExpression::Repeat0(expr) => {
854 let inner_expr = self.grammar_expression(expr);
855 if self.html {
856 format!("<span class=\"mech-grammar-repeat0-op\">*</span>{}", inner_expr)
857 } else {
858 format!("*{}", inner_expr)
859 }
860 },
861 GrammarExpression::Repeat1(expr) => {
862 let inner_expr = self.grammar_expression(expr);
863 if self.html {
864 format!("<span class=\"mech-grammar-repeat1-op\">+</span>{}", inner_expr)
865 } else {
866 format!("+{}", inner_expr)
867 }
868 },
869 GrammarExpression::Optional(expr) => {
870 let inner_expr = self.grammar_expression(expr);
871 if self.html {
872 format!("<span class=\"mech-grammar-optional-op\">?</span>{}", inner_expr)
873 } else {
874 format!("?{}", inner_expr)
875 }
876 },
877 GrammarExpression::Peek(expr) => {
878 let inner_expr = self.grammar_expression(expr);
879 if self.html {
880 format!("<span class=\"mech-grammar-peek-op\">></span>{}", inner_expr)
881 } else {
882 format!(">{}", inner_expr)
883 }
884 },
885 GrammarExpression::Not(expr) => {
886 let inner_expr = self.grammar_expression(expr);
887 if self.html {
888 format!("<span class=\"mech-grammar-not-op\">¬</span>{}", inner_expr)
889 } else {
890 format!("¬{}", inner_expr)
891 }
892 },
893 GrammarExpression::Terminal(token) => {
894 if self.html {
895 format!("<span class=\"mech-grammar-terminal\">\"{}\"</span>", token.to_string())
896 } else {
897 format!("\"{}\"", token.to_string())
898 }
899 },
900 GrammarExpression::Group(expr) => {
901 let inner_expr = self.grammar_expression(expr);
902 if self.html {
903 format!("<span class=\"mech-grammar-group\">(<span class=\"mech-grammar-group-content\">{}</span>)</span>", inner_expr)
904 } else {
905 format!("({})", inner_expr)
906 }
907 },
908 GrammarExpression::Definition(id) => {
909 let name = id.name.to_string();
910 if self.html {
911 format!("<span class=\"mech-grammar-definition\"><a href=\"#{}\">{}</a></span>",hash_str(&name), name)
912 } else {
913 name
914 }
915 },
916 };
917
918 if self.html {
919 format!("<span class=\"mech-grammar-expression\">{}</span>", expr)
920 } else {
921 expr
922 }
923 }
924
925 pub fn code_block(&mut self, node: &Token) -> String {
926 let code = node.to_string();
927 if self.html {
928 format!("<pre class=\"mech-code-block\">{}</pre>",code)
929 } else {
930 format!("{}\n",code)
931 }
932 }
933
934 pub fn comment(&mut self, node: &Comment) -> String {
935 let comment_text = self.paragraph(&node.paragraph);
936 if self.html {
937 format!("<span class=\"mech-comment\"><span class=\"mech-comment-sigil\">--</span>{}</span>", comment_text)
938 } else {
939 format!("{}\n",comment_text)
940 }
941 }
942
943 pub fn list(&mut self, node: &MDList) -> String {
944 match node {
945 MDList::Ordered(ordered_list) => self.ordered_list(ordered_list),
946 MDList::Unordered(unordered_list) => self.unordered_list(unordered_list),
947 MDList::Check(check_list) => self.check_list(check_list),
948 }
949 }
950
951 pub fn check_list(&mut self, node: &CheckList) -> String {
952 let mut lis = "".to_string();
953 for (i, ((checked, item), sublist)) in node.iter().enumerate() {
954 let it = self.paragraph(item);
955 if self.html {
956 lis = format!("{}<li class=\"mech-check-list-item\"><input type=\"checkbox\" {}>{}</li>", lis, if *checked { "checked" } else { "" }, it);
957 } else {
958 lis = format!("{}* [{}] {}\n", lis, if *checked { "x" } else { " " }, it);
959 }
960 match sublist {
961 Some(sublist) => {
962 let sublist_str = self.list(sublist);
963 lis = format!("{}{}", lis, sublist_str);
964 },
965 None => {},
966 }
967 }
968 if self.html {
969 format!("<ul class=\"mech-check-list\">{}</ul>", lis)
970 } else {
971 lis
972 }
973 }
974
975 pub fn ordered_list(&mut self, node: &OrderedList) -> String {
976 let mut lis = "".to_string();
977 for (i, ((num,item),sublist)) in node.items.iter().enumerate() {
978 let it = self.paragraph(item);
979 if self.html {
980 lis = format!("{}<li class=\"mech-ol-list-item\">{}</li>",lis,it);
981 } else {
982 lis = format!("{}{}. {}\n",lis,i+1,it);
983 }
984 match sublist {
985 Some(sublist) => {
986 let sublist_str = self.list(sublist);
987 lis = format!("{}{}",lis,sublist_str);
988 },
989 None => {},
990 }
991 }
992 if self.html {
993 format!("<ol start=\"{}\" class=\"mech-ordered-list\">{}</ol>",node.start.to_string(),lis)
994 } else {
995 lis
996 }
997 }
998
999 pub fn unordered_list(&mut self, node: &UnorderedList) -> String {
1000 let mut lis = "".to_string();
1001 for (i, ((bullet, item),sublist)) in node.iter().enumerate() {
1002 let it = self.paragraph(item);
1003 match (bullet, self.html) {
1004 (Some(bullet_tok),true) => lis = format!("{}<li data-bullet=\"{}\" class=\"mech-list-item-emoji\">{}</li>",lis,bullet_tok.to_string(),it),
1005 (None,true) => lis = format!("{}<li class=\"mech-ul-list-item\">{}</li>",lis,it),
1006 (_,false) => lis = format!("{}* {}\n",lis,it),
1007 }
1008 match sublist {
1009 Some(sublist) => {
1010 let sublist_str = self.list(sublist);
1011 lis = format!("{}{}",lis,sublist_str);
1012 },
1013 None => {},
1014 }
1015 }
1016 if self.html {
1017 format!("<ul class=\"mech-unordered-list\">{}</ul>",lis)
1018 } else {
1019 lis
1020 }
1021 }
1022
1023 pub fn mech_code(&mut self, node: &Vec<(MechCode,Option<Comment>)>) -> String {
1024 let mut src = String::new();
1025 for (code,cmmnt) in node {
1026 let c = match code {
1027 MechCode::Comment(cmnt) => self.comment(cmnt),
1028 MechCode::Expression(expr) => self.expression(expr),
1029 MechCode::Statement(stmt) => self.statement(stmt),
1033 _ => todo!(),
1034 };
1035 let formatted_comment = match cmmnt {
1036 Some(cmmt) => self.comment(cmmt),
1037 None => String::new(),
1038 };
1039 if self.html {
1040 src.push_str(&format!("<span class=\"mech-code\">{}{}</span>", c, formatted_comment));
1041 } else {
1042 src.push_str(&format!("{}{}\n", c, formatted_comment));
1043 }
1044 }
1045 if self.html {
1046 format!("<span class=\"mech-code-block\">{}</span>",src)
1047 } else {
1048 src
1049 }
1050 }
1051
1052 pub fn fsm_implementation(&mut self, node: &FsmImplementation) -> String {
1053 let name = node.name.to_string();
1054 let mut input = "".to_string();
1055 for (i, ident) in node.input.iter().enumerate() {
1056 let v = ident.to_string();
1057 if i == 0 {
1058 input = format!("{}", v);
1059 } else {
1060 input = format!("{}, {}", input, v);
1061 }
1062 }
1063 let start = self.pattern(&node.start);
1064 let mut arms = "".to_string();
1065 for (i, arm) in node.arms.iter().enumerate() {
1066 let a = self.fsm_arm(arm, i == node.arms.len() - 1);
1067 if i == 0 {
1068 arms = format!("{}", a);
1069 } else {
1070 arms = format!("{}{}", arms, a);
1071 }
1072 }
1073 if self.html {
1074 format!("<div class=\"mech-fsm-implementation\">
1075 <div class=\"mech-fsm-implementation-header\">
1076 <span class=\"mech-fsm-sigil\">#</span>
1077 <span class=\"mech-fsm-name\">{}</span>
1078 <span class=\"mech-left-paren\">(</span>
1079 <span class=\"mech-fsm-input\">{}</span>
1080 <span class=\"mech-right-paren\">)</span>
1081 <span class=\"mech-fsm-define-op\">→</span>
1082 <span class=\"mech-fsm-start\">{}</span>
1083 </div>
1084 <div class=\"mech-fsm-arms\">
1085 {}
1086 </div>
1087 </div>",name,input,start,arms)
1088 } else {
1089 format!("#{}({}) {} {}\n{}", name, input, "->" , start, arms)
1090 }
1091 }
1092
1093 pub fn fsm_arm(&mut self, node: &FsmArm, last: bool) -> String {
1094 let arm = match node {
1095 FsmArm::Guard(pattern, guards) => {
1096 let p = self.pattern(pattern);
1097 let mut gs = "".to_string();
1098 for (i, guard) in guards.iter().enumerate() {
1099 let g = self.guard(guard);
1100 if i == 0 {
1101 if self.html {
1102 gs = format!("<div class=\"mech-fsm-guard-arm\">├ {}</div>", g);
1103 } else {
1104 gs = format!(" ├ {}\n", g);
1105 }
1106 } else if i == guards.len() - 1 {
1107 if self.html {
1108 gs = format!("{}<div class=\"mech-fsm-guard-arm\">└ {}</div>", gs, g);
1109 } else {
1110 gs = format!("{} └ {}", gs, g);
1111 }
1112 } else {
1113 if self.html {
1114 gs = format!("{}<div class=\"mech-fsm-guard-arm\">├ {}</div>", gs, g);
1115 } else {
1116 gs = format!("{} ├ {}\n", gs, g);
1117 }
1118 }
1119 }
1120 if self.html {
1121 format!("<div class=\"mech-fsm-arm-guard\">
1122 <span class=\"mech-fsm-start\">{}</span>
1123 <span class=\"mech-fsm-guards\">{}</span>
1124 </div>",p,gs)
1125 } else {
1126 format!(" {}\n{}", p, gs)
1127 }
1128 },
1129 FsmArm::Transition(pattern, transitions) => {
1130 let p = self.pattern(pattern);
1131 let mut ts = "".to_string();
1132 for (i, transition) in transitions.iter().enumerate() {
1133 let t = self.transition(transition);
1134 if i == 0 {
1135 ts = format!("{}", t);
1136 } else {
1137 ts = format!("{}{}", ts, t);
1138 }
1139 }
1140 if self.html {
1141 format!("<div class=\"mech-fsm-arm\">
1142 <span class=\"mech-fsm-arm-pattern\">{}</span>
1143 <span class=\"mech-fsm-arm-transitions\">{}</span>
1144 </div>",p,ts)
1145 } else {
1146 format!(" {}{}", p, ts)
1147 }
1148 },
1149 };
1150 if self.html {
1151 if last {
1152 format!("<div class=\"mech-fsm-arm-last\">{}.</div>",arm)
1153 } else {
1154 format!("<div class=\"mech-fsm-arm\">{}</div>",arm)
1155 }
1156 } else {
1157 if last {
1158 format!("{}.", arm)
1159 } else {
1160 format!("{}\n", arm)
1161 }
1162 }
1163 }
1164
1165 pub fn guard(&mut self, node: &Guard) -> String {
1166 let condition = self.pattern(&node.condition);
1167 let mut transitions = "".to_string();
1168 for (i, transition) in node.transitions.iter().enumerate() {
1169 let t = self.transition(transition);
1170 if i == 0 {
1171 transitions = format!("{}", t);
1172 } else {
1173 transitions = format!("{}{}", transitions, t);
1174 }
1175 }
1176 if self.html {
1177 format!("<div class=\"mech-guard\">
1178 <span class=\"mech-guard-condition\">{}</span>
1179 <span class=\"mech-guard-transitions\">{}</span>
1180 </div>",condition,transitions)
1181 } else {
1182 format!("{}{}", condition, transitions)
1183 }
1184 }
1185
1186
1187 pub fn pattern(&mut self, node: &Pattern) -> String {
1188 let p = match node {
1189 Pattern::Wildcard => {
1190 if self.html {
1191 format!("<span class=\"mech-pattern-wildcard\">*</span>")
1192 } else {
1193 format!("*")
1194 }
1195 },
1196 Pattern::Formula(factor) => self.factor(factor),
1197 Pattern::Expression(expr) => self.expression(expr),
1198 Pattern::TupleStruct(tuple_struct) => self.pattern_tuple_struct(tuple_struct),
1199 };
1200 if self.html {
1201 format!("<span class=\"mech-pattern\">{}</span>",p)
1202 } else {
1203 p
1204 }
1205 }
1206
1207 pub fn pattern_tuple_struct(&mut self, node: &PatternTupleStruct) -> String {
1208 let name = node.name.to_string();
1209 let mut patterns = "".to_string();
1210 for (i, pattern) in node.patterns.iter().enumerate() {
1211 let p = self.pattern(pattern);
1212 if i == 0 {
1213 patterns = format!("{}", p);
1214 } else {
1215 patterns = format!("{}, {}", patterns, p);
1216 }
1217 }
1218 if self.html {
1219 format!("<span class=\"mech-tuple-struct\">
1220 `
1221 <span class=\"mech-tuple-struct-name\">{}</span>
1222 <span class=\"mech-left-paren\">(</span>
1223 <span class=\"mech-tuple-struct-patterns\">{}</span>
1224 <span class=\"mech-right-paren\">)</span>
1225 </span>",name,patterns)
1226 } else {
1227 format!("`{}({})", name, patterns)
1228 }
1229 }
1230
1231 pub fn transition(&mut self, node: &Transition) -> String {
1232 match node {
1233 Transition::Next(pattern) => {
1234 if self.html {
1235 format!("<span class=\"mech-transition-next\">→ {}</span>",self.pattern(pattern))
1236 } else {
1237 format!(" {} {}", "->", self.pattern(pattern))
1238 }
1239 }
1240 Transition::Output(pattern) => {
1241 if self.html {
1242 format!("<span class=\"mech-transition-output\">⇒ {}</span>",self.pattern(pattern))
1243 } else {
1244 format!(" {} {}", "=>", self.pattern(pattern))
1245 }
1246 }
1247 Transition::Async(pattern) => {
1248 if self.html {
1249 format!("<span class=\"mech-transition-async\">↝ {}</span>",self.pattern(pattern))
1250 } else {
1251 format!(" {} {}", "~>", self.pattern(pattern))
1252
1253 }
1254 }
1255 Transition::Statement(stmt) => {
1256 if self.html {
1257 format!("<span class=\"mech-transition-statement\">→ {}</span>",self.statement(stmt))
1258 } else {
1259 format!(" {} {}", "->", self.statement(stmt))
1260 }
1261 }
1262 Transition::CodeBlock(code) => {
1263 let mut code_str = "".to_string();
1264 let formatted = self.mech_code(code);
1265 if self.html {
1266 code_str.push_str(&format!("<span class=\"mech-transition-code\">→ {}</span>", formatted));
1267 } else {
1268 code_str.push_str(&format!(" {} {}", "->", formatted));
1269 }
1270 code_str
1271 }
1272 }
1273 }
1274
1275 pub fn fsm_specification(&mut self, node: &FsmSpecification) -> String {
1276 let name = node.name.to_string();
1277 let mut input = "".to_string();
1278 for (i, var) in node.input.iter().enumerate() {
1279 let v = self.var(var);
1280 if i == 0 {
1281 input = format!("{}", v);
1282 } else {
1283 input = format!("{}, {}", input, v);
1284 }
1285 }
1286 let output = match &node.output {
1287 Some(kind) => format!(" {} {}", "⇒", self.kind_annotation(&kind.kind)),
1288 None => "".to_string(),
1289 };
1290 let mut states = "".to_string();
1291 for (i, state) in node.states.iter().enumerate() {
1292 let v = self.state_definition(state);
1293 let state_arm = if node.states.len() == 1 {
1294 format!("{} {}", "└", v)
1295 } else if i == 0 {
1296 format!("{} {}", "├", v)
1297 } else if i == node.states.len() - 1 {
1298 format!("{} {}{}", "└", v, ".")
1299 } else {
1300 format!("{} {}", "├", v)
1301 };
1302 if self.html {
1303 states = format!("{}<span class=\"mech-fsm-state\">{}</span>",states,state_arm);
1304 } else {
1305 states = format!("{} {}\n",states,state_arm);
1306 }
1307 }
1308 if self.html {
1309 format!("<div class=\"mech-fsm-specification\">
1310 <div class=\"mech-fsm-specification-header\">
1311 <span class=\"mech-fsm-sigil\">#</span>
1312 <span class=\"mech-fsm-name\">{}</span>
1313 <span class=\"mech-left-paren\">(</span>
1314 <span class=\"mech-fsm-input\">{}</span>
1315 <span class=\"mech-right-paren\">)</span>
1316 <span class=\"mech-fsm-output\">{}</span>
1317 <span class=\"mech-fsm-define-op\">:=</span>
1318 </div>
1319 <div class=\"mech-fsm-states\">{}</div>
1320 </div>",name,input,output,states)
1321 } else {
1322 format!("#{}({}){} {}\n{}", name, input, output, ":=", states)
1323 }
1324 }
1325
1326 pub fn state_definition(&mut self, node: &StateDefinition) -> String {
1327 let name = node.name.to_string();
1328 let mut state_variables = "".to_string();
1329 match &node.state_variables {
1330 Some(vars) => {
1331 for (i, var) in vars.iter().enumerate() {
1332 let v = self.var(var);
1333 if i == 0 {
1334 state_variables = format!("{}", v);
1335 } else {
1336 state_variables = format!("{}, {}", state_variables, v);
1337 }
1338 }
1339 },
1340 None => {}
1341 }
1342 if self.html {
1343 format!("<div class=\"mech-state-definition\">
1344 <span class=\"mech-state-name\">`{}</span>
1345 <span class=\"mech-left-paren\">(</span>
1346 <span class=\"mech-state-variables\">{}</span>
1347 <span class=\"mech-right-paren\">)</span>
1348 </div>",name,state_variables)
1349 } else {
1350 format!("{}({})", name, state_variables)
1351 }
1352 }
1353
1354 pub fn variable_define(&mut self, node: &VariableDefine) -> String {
1355 let mut mutable = if node.mutable {
1356 "~".to_string()
1357 } else {
1358 "".to_string()
1359 };
1360 let var = self.var(&node.var);
1361 let expression = self.expression(&node.expression);
1362 if self.html {
1363 format!("<span class=\"mech-variable-define\"><span class=\"mech-variable-mutable\">{}</span>{}<span class=\"mech-variable-assign-op\">:=</span>{}</span>",mutable, var, expression)
1364 } else {
1365 format!("{}{} {} {}", mutable, var, ":=", expression)
1366 }
1367 }
1368
1369 pub fn statement(&mut self, node: &Statement) -> String {
1370 let s = match node {
1371 Statement::VariableDefine(var_def) => self.variable_define(var_def),
1372 Statement::OpAssign(op_asgn) => self.op_assign(op_asgn),
1373 Statement::VariableAssign(var_asgn) => self.variable_assign(var_asgn),
1374 Statement::TupleDestructure(tpl_dstrct) => self.tuple_destructure(tpl_dstrct),
1375 Statement::KindDefine(kind_def) => self.kind_define(kind_def),
1376 _ => todo!(),
1377 };
1380 if self.html {
1381 format!("<span class=\"mech-statement\">{}</span>",s)
1382 } else {
1383 format!("{}", s)
1384 }
1385 }
1386
1387 pub fn kind_define(&mut self, node: &KindDefine) -> String {
1388 let name = node.name.to_string();
1389 let kind = self.kind_annotation(&node.kind.kind);
1390 if self.html {
1391 format!("<span class=\"mech-kind-define\"><span class=\"mech-kind-annotation\"><<span class=\"mech-kind\">{}</span>></span><span class=\"mech-kind-define-op\">:=</span><span class=\"mech-kind-annotation\">{}</span></span>",name,kind)
1392 } else {
1393 format!("<{}> := {}", name, kind)
1394 }
1395 }
1396
1397
1398 pub fn tuple_destructure(&mut self, node: &TupleDestructure) -> String {
1407 let mut vars = "".to_string();
1408 for (i, var) in node.vars.iter().enumerate() {
1409 let v = var.to_string();
1410 if i == 0 {
1411 vars = format!("{}", v);
1412 } else {
1413 vars = format!("{}, {}", vars, v);
1414 }
1415 }
1416 let expression = self.expression(&node.expression);
1417 if self.html {
1418 format!("<span class=\"mech-tuple-destructure\"><span class=\"mech-tuple-vars\">({})</span><span class=\"mech-assign-op\">:=</span><span class=\"mech-tuple-expression\">{}</span></span>",vars,expression)
1419 } else {
1420 format!("({}) := {}", vars, expression)
1421 }
1422 }
1423
1424 pub fn variable_assign(&mut self, node: &VariableAssign) -> String {
1425 let target = self.slice_ref(&node.target);
1426 let expression = self.expression(&node.expression);
1427 if self.html {
1428 format!("<span class=\"mech-variable-assign\">
1429 <span class=\"mech-target\">{}</span>
1430 <span class=\"mech-assign-op\">=</span>
1431 <span class=\"mech-expression\">{}</span>
1432 </span>",target,expression)
1433 } else {
1434 format!("{} = {}", target, expression)
1435 }
1436 }
1437
1438 pub fn op_assign(&mut self, node: &OpAssign) -> String {
1439 let target = self.slice_ref(&node.target);
1440 let op = self.op_assign_op(&node.op);
1441 let expression = self.expression(&node.expression);
1442 if self.html {
1443 format!("<span class=\"mech-op-assign\"><span class=\"mech-target\">{}</span><span class=\"mech-op\">{}</span><span class=\"mech-expression\">{}</span></span>",target,op,expression)
1444 } else {
1445 format!("{} {} {}", target, op, expression)
1446 }
1447 }
1448
1449 pub fn op_assign_op(&mut self, node: &OpAssignOp) -> String {
1450 let op = match node {
1451 OpAssignOp::Add => "+=".to_string(),
1452 OpAssignOp::Div => "/=".to_string(),
1453 OpAssignOp::Exp => "^=".to_string(),
1454 OpAssignOp::Mod => "%=".to_string(),
1455 OpAssignOp::Mul => "*=".to_string(),
1456 OpAssignOp::Sub => "-=".to_string(),
1457 };
1458 if self.html {
1459 format!("<span class=\"mech-op-assign-op\">{}</span>",op)
1460 } else {
1461 format!("{}", op)
1462 }
1463 }
1464
1465 pub fn slice_ref(&mut self, node: &SliceRef) -> String {
1466 let name = node.name.to_string();
1467 let mut subscript = "".to_string();
1468 match &node.subscript {
1469 Some(subs) => {
1470 for sub in subs.iter() {
1471 let s = self.subscript(sub);
1472 subscript = format!("{}{}", subscript, s);
1473 }
1474 },
1475 None => {},
1476 }
1477 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1478 if self.html {
1479 format!("<span class=\"mech-slice-ref\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
1480 } else {
1481 format!("{}{}", name, subscript)
1482 }
1483 }
1484
1485 pub fn expression(&mut self, node: &Expression) -> String {
1486 let e = match node {
1487 Expression::Var(var) => self.var(var),
1488 Expression::Formula(factor) => self.factor(factor),
1489 Expression::Literal(literal) => self.literal(literal),
1490 Expression::Structure(structure) => self.structure(structure),
1491 Expression::Slice(slice) => self.slice(slice),
1492 Expression::FunctionCall(function_call) => self.function_call(function_call),
1493 Expression::Range(range) => self.range_expression(range),
1494 _ => todo!(),
1495 };
1497 if self.html {
1498 format!("<span class=\"mech-expression\">{}</span>",e)
1499 } else {
1500 format!("{}", e)
1501 }
1502 }
1503
1504 pub fn range_expression(&mut self, node: &RangeExpression) -> String {
1505 let start = self.factor(&node.start);
1506 let operator = match &node.operator {
1507 RangeOp::Inclusive => "..=".to_string(),
1508 RangeOp::Exclusive => "..".to_string(),
1509 };
1510 let terminal = self.factor(&node.terminal);
1511 let increment = match &node.increment {
1512 Some((op, factor)) => {
1513 let o = match op {
1514 RangeOp::Inclusive => "..=".to_string(),
1515 RangeOp::Exclusive => "..".to_string(),
1516 };
1517 let f = self.factor(factor);
1518 if self.html {
1519 format!("<span class=\"mech-range-increment\">{}{}</span>",o,f)
1520 } else {
1521 format!("{}{}", o, f)
1522 }
1523 },
1524 None => "".to_string(),
1525 };
1526 if self.html {
1527 format!("<span class=\"mech-range-expression\"><span class=\"mech-range-start\">{}</span><span class=\"mech-range-operator\">{}</span><span class=\"mech-range-terminal\">{}</span>{}</span>",start,operator,terminal,increment)
1528 } else {
1529 format!("{}{}{}{}", start, operator, terminal, increment)
1530 }
1531 }
1532
1533 pub fn function_call(&mut self, node: &FunctionCall) -> String {
1534 let name = node.name.to_string();
1535 let mut args = "".to_string();
1536 for (i, arg) in node.args.iter().enumerate() {
1537 let a = self.argument(arg);
1538 if i == 0 {
1539 args = format!("{}", a);
1540 } else {
1541 args = format!("{}, {}", args, a);
1542 }
1543 }
1544 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1545 if self.html {
1546 format!("<span class=\"mech-function-call\"><span id=\"{}\" class=\"mech-function-name mech-clickable\">{}</span><span class=\"mech-left-paren\">(</span><span class=\"mech-argument-list\">{}</span><span class=\"mech-right-paren\">)</span></span>",id,name,args)
1547 } else {
1548 format!("{}({})", name, args)
1549 }
1550 }
1551
1552 pub fn argument(&mut self, node: &(Option<Identifier>, Expression)) -> String {
1553 let (name, expr) = node;
1554 let n = match name {
1555 Some(ident) => ident.to_string(),
1556 None => "".to_string(),
1557 };
1558 let e = self.expression(expr);
1559 if self.html {
1560 format!("<span class=\"mech-argument\"><span class=\"mech-argument-name\">{}</span><span class=\"mech-argument-expression\">{}</span></span>",n,e)
1561 } else {
1562 format!("{}{}", n, e)
1563 }
1564 }
1565
1566 pub fn slice(&mut self, node: &Slice) -> String {
1567 let name = node.name.to_string();
1568 let mut subscript = "".to_string();
1569 for (i, sub) in node.subscript.iter().enumerate() {
1570 let s = self.subscript(sub);
1571 subscript = format!("{}{}", subscript, s);
1572 }
1573 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1574 if self.html {
1575 format!("<span class=\"mech-slice\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
1576 } else {
1577 format!("{}{}", name, subscript)
1578 }
1579 }
1580
1581 pub fn subscript(&mut self, node: &Subscript) -> String {
1582 match node {
1583 Subscript::Bracket(subs) => self.bracket(subs),
1584 Subscript::Formula(factor) => self.factor(factor),
1585 Subscript::All => self.all(),
1586 Subscript::Dot(ident) => self.dot(ident),
1587 Subscript::Swizzle(idents) => self.swizzle(idents),
1588 Subscript::Range(range) => self.range_expression(range),
1589 Subscript::Brace(subs) => self.brace(subs),
1590 Subscript::DotInt(real) => self.dot_int(real),
1591 }
1592 }
1593
1594 pub fn brace(&mut self, node: &Vec<Subscript>) -> String {
1595 let mut src = "".to_string();
1596 for (i, sub) in node.iter().enumerate() {
1597 let s = self.subscript(sub);
1598 if i == 0 {
1599 src = format!("{}", s);
1600 } else {
1601 src = format!("{},{}", src, s);
1602 }
1603 }
1604 if self.html {
1605 format!("<span class=\"mech-brace\">{{{}}}</span>",src)
1606 } else {
1607 format!("{{{}}}",src)
1608 }
1609 }
1610
1611 pub fn swizzle(&mut self, node: &Vec<Identifier>) -> String {
1612 let mut src = "".to_string();
1613 for (i, ident) in node.iter().enumerate() {
1614 let s = self.dot(ident);
1615 if i == 0 {
1616 src = format!("{}", s);
1617 } else {
1618 src = format!("{},{}", src, s);
1619 }
1620 }
1621 if self.html {
1622 format!("<span class=\"mech-swizzle\">{}</span>",src)
1623 } else {
1624 format!("{}",src)
1625 }
1626 }
1627
1628 pub fn dot_int(&mut self, node: &RealNumber) -> String {
1629 let node_str = match node {
1630 RealNumber::Integer(tkn) => tkn.to_string(),
1631 _ => "".to_string(),
1632 };
1633 if self.html {
1634 format!(".<span class=\"mech-dot-int\">{}</span>",node_str)
1635 } else {
1636 format!(".{}",node_str)
1637 }
1638 }
1639
1640 pub fn dot(&mut self, node: &Identifier) -> String {
1641 if self.html {
1642 format!(".<span class=\"mech-dot\">{}</span>",node.to_string())
1643 } else {
1644 format!(".{}",node.to_string())
1645 }
1646 }
1647
1648 pub fn all(&mut self) -> String {
1649 if self.html {
1650 format!("<span class=\"mech-all\">:</span>")
1651 } else {
1652 ":".to_string()
1653 }
1654 }
1655
1656 pub fn bracket(&mut self, node: &Vec<Subscript>) -> String {
1657 let mut src = "".to_string();
1658 for (i, sub) in node.iter().enumerate() {
1659 let s = self.subscript(sub);
1660 if i == 0 {
1661 src = format!("{}", s);
1662 } else {
1663 src = format!("{},{}", src, s);
1664 }
1665 }
1666 if self.html {
1667 format!("<span class=\"mech-bracket\">[{}]</span>",src)
1668 } else {
1669 format!("[{}]",src)
1670 }
1671 }
1672
1673 pub fn structure(&mut self, node: &Structure) -> String {
1674 let s = match node {
1675 Structure::Matrix(matrix) => self.matrix(matrix),
1676 Structure::Record(record) => self.record(record),
1677 Structure::Empty => "_".to_string(),
1678 Structure::Table(table) => self.table(table),
1679 Structure::Tuple(tuple) => self.tuple(tuple),
1680 Structure::TupleStruct(tuple_struct) => self.tuple_struct(tuple_struct),
1681 Structure::Set(set) => self.set(set),
1682 Structure::Map(map) => self.map(map),
1683 };
1684 if self.html {
1685 format!("<span class=\"mech-structure\">{}</span>",s)
1686 } else {
1687 format!("{}", s)
1688 }
1689 }
1690
1691 pub fn map(&mut self, node: &Map) -> String {
1692 let mut src = "".to_string();
1693 for (i, mapping) in node.elements.iter().enumerate() {
1694 let m = self.mapping(mapping);
1695 if i == 0 {
1696 src = format!("{}", m);
1697 } else {
1698 src = format!("{}, {}", src, m);
1699 }
1700 }
1701 if self.html {
1702 format!("<span class=\"mech-map\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
1703 } else {
1704 format!("{{{}}}", src)
1705 }
1706 }
1707
1708 pub fn mapping(&mut self, node: &Mapping) -> String {
1709 let key = self.expression(&node.key);
1710 let value = self.expression(&node.value);
1711 if self.html {
1712 format!("<span class=\"mech-mapping\"><span class=\"mech-key\">{}</span><span class=\"mech-colon-op\">:</span><span class=\"mech-value\">{}</span></span>",key,value)
1713 } else {
1714 format!("{}: {}", key, value)
1715 }
1716 }
1717
1718 pub fn set(&mut self, node: &Set) -> String {
1719 let mut src = "".to_string();
1720 for (i, element) in node.elements.iter().enumerate() {
1721 let e = self.expression(element);
1722 if i == 0 {
1723 src = format!("{}", e);
1724 } else {
1725 src = format!("{}, {}", src, e);
1726 }
1727 }
1728 if self.html {
1729 format!("<span class=\"mech-set\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
1730 } else {
1731 format!("{{{}}}", src)
1732 }
1733 }
1734
1735 pub fn tuple_struct(&mut self, node: &TupleStruct) -> String {
1736 let name = node.name.to_string();
1737 let value = self.expression(&node.value);
1738 if self.html {
1739 format!("<span class=\"mech-tuple-struct\"><span class=\"mech-tuple-struct-name\">{}</span><span class=\"mech-tuple-struct-value\">{}</span></span>",name,value)
1740 } else {
1741 format!("{}{}", name, value)
1742 }
1743 }
1744
1745 pub fn table(&mut self, node: &Table) -> String {
1746 let header = self.table_header(&node.header);
1747 let mut rows = "".to_string();
1748 for (i, row) in node.rows.iter().enumerate() {
1749 let r = self.table_row(row);
1750 if i == 0 {
1751 rows = format!("{}", r);
1752 } else {
1753 rows = format!("{}{}", rows, r);
1754 }
1755 }
1756 if self.html {
1757 format!("<table class=\"mech-table\">{}<tbody class=\"mech-table-body\">{}</tbody></table>",header,rows)
1758 } else {
1759 format!("{}{}", header, rows)
1760 }
1761 }
1762
1763 pub fn table_header(&mut self, node: &TableHeader) -> String {
1764 let mut src = "".to_string();
1765 for (i, field) in node.iter().enumerate() {
1766 let f = self.field(field);
1767 if self.html {
1768 src = format!("{}<th class=\"mech-table-field\">{}</th>",src, f);
1769 } else {
1770 src = format!("{}{}",src, f);
1771 }
1772 }
1773 if self.html {
1774 format!("<thead class=\"mech-table-header\"><tr>{}</tr></thead>",src)
1775 } else {
1776 src
1777 }
1778 }
1779
1780 pub fn table_row(&mut self, node: &TableRow) -> String {
1781 let mut src = "".to_string();
1782 for (i, column) in node.columns.iter().enumerate() {
1783 let c = self.table_column(column);
1784 if i == 0 {
1785 src = format!("{}", c);
1786 } else {
1787 src = format!("{} {}", src, c);
1788 }
1789 }
1790 if self.html {
1791 format!("<tr class=\"mech-table-row\">{}</tr>",src)
1792 } else {
1793 src
1794 }
1795 }
1796
1797 pub fn table_column(&mut self, node: &TableColumn) -> String {
1798 let element = self.expression(&node.element);
1799 if self.html {
1800 format!("<td class=\"mech-table-column\">{}</td>",element)
1801 } else {
1802 element
1803 }
1804 }
1805
1806 pub fn field(&mut self, node: &Field) -> String {
1807 let name = node.name.to_string();
1808 let kind = if let Some(kind) = &node.kind {
1809 self.kind_annotation(&kind.kind)
1810 } else {
1811 "".to_string()
1812 };
1813 if self.html {
1814 format!("<div class=\"mech-field\"><span class=\"mech-field-name\">{}</span><span class=\"mech-field-kind\">{}</span></div>",name,kind)
1815 } else {
1816 format!("{}: {}", name, kind)
1817 }
1818 }
1819
1820 pub fn tuple(&mut self, node: &Tuple) -> String {
1821 let mut src = "".to_string();
1822 for (i, element) in node.elements.iter().enumerate() {
1823 let e = self.expression(element);
1824 if i == 0 {
1825 src = format!("{}", e);
1826 } else {
1827 src = format!("{},{}", src, e);
1828 }
1829 }
1830 if self.html {
1831 format!("<span class=\"mech-tuple\"><span class=\"mech-start-paren\">(</span>{}<span class=\"mech-end-paren\">)</span></span>",src)
1832 } else {
1833 format!("({})", src)
1834 }
1835 }
1836
1837 pub fn record(&mut self, node: &Record) -> String {
1838 let mut src = "".to_string();
1839 for (i, binding) in node.bindings.iter().enumerate() {
1840 let b = self.binding(binding);
1841 if i == 0 {
1842 src = format!("{}", b);
1843 } else {
1844 src = format!("{}, {}", src, b);
1845 }
1846 }
1847 if self.html {
1848 format!("<span class=\"mech-record\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
1849 } else {
1850 format!("{{{}}}",src)
1851 }
1852 }
1853
1854 pub fn binding(&mut self, node: &Binding) -> String {
1855 let name = node.name.to_string();
1856 let value = self.expression(&node.value);
1857 if self.html {
1858 format!("<span class=\"mech-binding\"><span class=\"mech-binding-name\">{}</span><span class=\"mech-binding-colon-op\">:</span><span class=\"mech-binding-value\">{}</span></span>",name,value)
1859 } else {
1860 format!("{}: {}", name, value)
1861 }
1862 }
1863
1864 pub fn matrix(&mut self, node: &Matrix) -> String {
1865 let mut src = "".to_string();
1866 if node.rows.len() == 0 {
1867 if self.html {
1868 return format!("<span class=\"mech-matrix empty\"><span class=\"mech-bracket start\">[</span><span class=\"mech-bracket end\">]</span></span>");
1869 } else {
1870 return format!("[]");
1871 }
1872 }
1873 let column_count = node.rows[0].columns.len(); for col_index in 0..column_count {
1876 let mut column_elements = Vec::new();
1877 for row in &node.rows {
1878 column_elements.push(&row.columns[col_index]);
1879 }
1880 let c = self.matrix_column_elements(&column_elements);
1881
1882 if col_index == 0 {
1883 src = format!("{}", c);
1884 } else {
1885 src = format!("{} {}", src, c);
1886 }
1887 }
1888
1889 if self.html {
1890 format!("<span class=\"mech-matrix\"><span class=\"mech-bracket start\">[</span>{}<span class=\"mech-bracket end\">]</span></span>", src)
1891 } else {
1892 format!("[{}]", src)
1893 }
1894}
1895
1896pub fn matrix_column_elements(&mut self, column_elements: &[&MatrixColumn]) -> String {
1897 let mut src = "".to_string();
1898 for (i, cell) in column_elements.iter().enumerate() {
1899 let c = self.matrix_column(cell);
1900 if i == 0 {
1901 src = format!("{}", c);
1902 } else {
1903 src = format!("{} {}", src, c);
1904 }
1905 }
1906 if self.html {
1907 format!("<div class=\"mech-matrix-column\">{}</div>", src)
1908 } else {
1909 src
1910 }
1911}
1912
1913
1914 pub fn matrix_row(&mut self, node: &MatrixRow) -> String {
1915 let mut src = "".to_string();
1916 for (i, cell) in node.columns.iter().enumerate() {
1917 let c = self.matrix_column(cell);
1918 if i == 0 {
1919 src = format!("{}", c);
1920 } else {
1921 src = format!("{} {}", src, c);
1922 }
1923 }
1924 if self.html {
1925 format!("<div class=\"mech-matrix-row\">{}</div>",src)
1926 } else {
1927 src
1928 }
1929 }
1930
1931 pub fn matrix_column(&mut self, node: &MatrixColumn) -> String {
1932 let element = self.expression(&node.element);
1933 if self.html {
1934 format!("<span class=\"mech-matrix-element\">{}</span>",element)
1935 } else {
1936 element
1937 }
1938 }
1939
1940 pub fn var(&mut self, node: &Var) -> String {
1941 let annotation = if let Some(kind) = &node.kind {
1942 self.kind_annotation(&kind.kind)
1943 } else {
1944 "".to_string()
1945 };
1946 let name = &node.name.to_string();
1947 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1948 if self.html {
1949 format!("<span class=\"mech-var-name mech-clickable\" id=\"{}\">{}</span>{}", id, node.name.to_string(), annotation)
1950 } else {
1951 format!("{}{}", node.name.to_string(), annotation)
1952 }
1953 }
1954
1955 pub fn kind_annotation(&mut self, node: &Kind) -> String {
1956 let kind = self.kind(node);
1957 if self.html {
1958 format!("<span class=\"mech-kind-annotation\"><{}></span>",kind)
1959 } else {
1960 format!("<{}>", kind)
1961 }
1962 }
1963
1964 pub fn kind(&mut self, node: &Kind) -> String {
1965 let annotation = match node {
1966 Kind::Option(kind) => {
1967 let k = self.kind(kind);
1968 if self.html {
1969 format!("{}<span class=\"mech-option-question\">?</span>", k)
1970 } else {
1971 format!("{}?", k)
1972 }
1973 },
1974 Kind::Set(kind,size) => {
1975 let k = self.kind(kind);
1976 let size_str = match size{
1977 Some(size) => {
1978 let size_ltrl = self.literal(size);
1979 format!(":{}", size_ltrl)
1980 }
1981 None => "".to_string(),
1982 };
1983 format!("{{{}}}{}", k, size_str)
1984 },
1985 Kind::Any => "*".to_string(),
1986 Kind::Scalar(ident) => ident.to_string(),
1987 Kind::Empty => "_".to_string(),
1988 Kind::Atom(ident) => format!("`{}",ident.to_string()),
1989 Kind::Tuple(kinds) => {
1990 let mut src = "".to_string();
1991 for (i, kind) in kinds.iter().enumerate() {
1992 let k = self.kind(kind);
1993 if i == 0 {
1994 src = format!("{}", k);
1995 } else {
1996 src = format!("{},{}", src, k);
1997 }
1998 }
1999 format!("({})", src)
2000 },
2001 Kind::Matrix((kind, literals)) => {
2002 let mut src = "".to_string();
2003 let k = self.kind(kind);
2004 src = format!("{}", k);
2005 let mut src2 = "".to_string();
2006 for (i, literal) in literals.iter().enumerate() {
2007 let l = self.literal(literal);
2008 if i == 0 {
2009 src2 = format!(":{}", l);
2010 } else {
2011 src2 = format!("{},{}", src2, l);
2012 }
2013 }
2014 format!("[{}]{}", src, src2)
2015 },
2016 Kind::Record(kinds) => {
2017 let mut src = "".to_string();
2018 for (i, (ident, kind)) in kinds.iter().enumerate() {
2019 let k = self.kind(kind);
2020 let ident_s = ident.to_string();
2021 if i == 0 {
2022 src = format!("{}<{}>", ident_s, k);
2023 } else {
2024 src = format!("{},{}<{}>", src, ident_s, k);
2025 }
2026 }
2027 format!("{{{}}}", src)
2028 },
2029 Kind::Table((kinds, literal)) => {
2030 let mut src = "".to_string();
2031 for (i, (ident,kind)) in kinds.iter().enumerate() {
2032 let k = self.kind(kind);
2033 let ident_s = ident.to_string();
2034 if i == 0 {
2035 src = format!("{}<{}>", ident_s, k);
2036 } else {
2037 src = format!("{},{}<{}>", src, ident_s, k);
2038 }
2039 }
2040 let mut src2 = "".to_string();
2041 let sz = match &**literal {
2042 Literal::Empty(_) => "".to_string(),
2043 _ => format!(":{}", self.literal(literal)),
2044 };
2045 format!("|{}|{}", src, sz)
2046 },
2047 Kind::Map(kind1, kind2) => {
2048 let k1 = self.kind(kind1);
2049 let k2 = self.kind(kind2);
2050 format!("{{{}:{}}}", k1, k2)
2051 },
2052 };
2053 if self.html {
2054 format!("<span class=\"mech-kind\">{}</span>",annotation)
2055 } else {
2056 annotation
2057 }
2058 }
2059
2060 pub fn factor(&mut self, node: &Factor) -> String {
2061 let f = match node {
2062 Factor::Term(term) => self.term(term),
2063 Factor::Expression(expr) => self.expression(expr),
2064 Factor::Parenthetical(paren) => {
2065 if self.html {
2066 format!("<span class=\"mech-parenthetical\">({})</span>", self.factor(paren))
2067 } else {
2068 format!("({})", self.factor(&paren))
2069 }
2070 }
2071 Factor::Negate(factor) => {
2072 if self.html {
2073 format!("<span class=\"mech-negate-op\">-</span><span class=\"mech-negate\">{}</span>", self.factor(factor))
2074 } else {
2075 format!("-{}", self.factor(factor))
2076 }
2077 }
2078 Factor::Not(factor) => {
2079 if self.html {
2080 format!("<span class=\"mech-not-op\">¬</span><span class=\"mech-not\">{}</span>", self.factor(factor))
2081 } else {
2082 format!("¬{}", self.factor(factor))
2083 }
2084 }
2085 Factor::Transpose(factor) => {
2086 if self.html {
2087 format!("<span class=\"mech-transpose\">{}</span><span class=\"mech-transpose-op\">'</span>", self.factor(factor))
2088 } else {
2089 format!("{}'", self.factor(factor))
2090 }
2091 }
2092 };
2093 if self.html {
2094 format!("<span class=\"mech-factor\">{}</span>",f)
2095 } else {
2096 f
2097 }
2098 }
2099
2100 pub fn term(&mut self, node: &Term) -> String {
2101 let mut src = self.factor(&node.lhs);
2102 for (formula_operator, rhs) in &node.rhs {
2103 let op = self.formula_operator(formula_operator);
2104 let rhs = self.factor(rhs);
2105 src = format!("{}{}{}", src, op, rhs);
2106 }
2107 if self.html {
2108 format!("<span class=\"mech-term\">{}</span>",src)
2109 } else {
2110 src
2111 }
2112 }
2113
2114 pub fn formula_operator(&mut self, node: &FormulaOperator) -> String {
2115 let f = match node {
2116 FormulaOperator::AddSub(op) => self.add_sub_op(op),
2117 FormulaOperator::MulDiv(op) => self.mul_div_op(op),
2118 FormulaOperator::Exponent(op) => self.exponent_op(op),
2119 FormulaOperator::Vec(op) => self.vec_op(op),
2120 FormulaOperator::Comparison(op) => self.comparison_op(op),
2121 FormulaOperator::Logic(op) => self.logic_op(op),
2122 FormulaOperator::Table(op) => self.table_op(op),
2123 FormulaOperator::Set(op) => self.set_op(op),
2124 };
2125 if self.html {
2126 format!("<span class=\"mech-formula-operator\">{}</span>",f)
2127 } else {
2128 format!(" {} ", f)
2129 }
2130 }
2131
2132 pub fn table_op(&mut self, node: &TableOp) -> String {
2133 match node {
2134 TableOp::InnerJoin => "⋈".to_string(),
2135 TableOp::LeftOuterJoin => "⟕".to_string(),
2136 TableOp::RightOuterJoin => "⟖".to_string(),
2137 TableOp::FullOuterJoin => "⟗".to_string(),
2138 TableOp::LeftSemiJoin => "⋉".to_string(),
2139 TableOp::LeftAntiJoin => "▷".to_string(),
2140 }
2141 }
2142
2143 pub fn set_op(&mut self, node: &SetOp) -> String {
2144 match node {
2145 SetOp::Union => "∪".to_string(),
2146 SetOp::Intersection => "∩".to_string(),
2147 SetOp::Difference => "∖".to_string(),
2148 SetOp::Complement => "∁".to_string(),
2149 SetOp::Subset => "⊂".to_string(),
2150 SetOp::Superset => "⊃".to_string(),
2151 SetOp::ProperSubset => "⊊".to_string(),
2152 SetOp::ProperSuperset => "⊋".to_string(),
2153 SetOp::ElementOf => "∈".to_string(),
2154 SetOp::NotElementOf => "∉".to_string(),
2155 }
2156 }
2157
2158 pub fn add_sub_op(&mut self, node: &AddSubOp) -> String {
2159 match node {
2160 AddSubOp::Add => "+".to_string(),
2161 AddSubOp::Sub => "-".to_string(),
2162 }
2163 }
2164
2165 pub fn mul_div_op(&mut self, node: &MulDivOp) -> String {
2166 match node {
2167 MulDivOp::Div => "/".to_string(),
2168 MulDivOp::Mod => "%".to_string(),
2169 MulDivOp::Mul => "*".to_string(),
2170 }
2171 }
2172
2173 pub fn exponent_op(&mut self, node: &ExponentOp) -> String {
2174 match node {
2175 ExponentOp::Exp => "^".to_string(),
2176 }
2177 }
2178
2179 pub fn vec_op(&mut self, node: &VecOp) -> String {
2180 match node {
2181 VecOp::MatMul => "**".to_string(),
2182 VecOp::Solve => "\\".to_string(),
2183 VecOp::Cross => "×".to_string(),
2184 VecOp::Dot => "·".to_string(),
2185 }
2186 }
2187
2188 pub fn comparison_op(&mut self, node: &ComparisonOp) -> String {
2189 match node {
2190 ComparisonOp::Equal => "⩵".to_string(),
2191 ComparisonOp::StrictEqual => "=:=".to_string(),
2192 ComparisonOp::StrictNotEqual => "=/=".to_string(),
2193 ComparisonOp::NotEqual => "≠".to_string(),
2194 ComparisonOp::GreaterThan => ">".to_string(),
2195 ComparisonOp::GreaterThanEqual => "≥".to_string(),
2196 ComparisonOp::LessThan => "<".to_string(),
2197 ComparisonOp::LessThanEqual => "≤".to_string(),
2198 }
2199 }
2200
2201 pub fn logic_op(&mut self, node: &LogicOp) -> String {
2202 match node {
2203 LogicOp::And => "&&".to_string(),
2204 LogicOp::Or => "||".to_string(),
2205 LogicOp::Xor => "⊻".to_string(),
2206 LogicOp::Not => "¬".to_string(),
2207 }
2208 }
2209
2210 pub fn boolean(&mut self, node: &Token) -> String {
2211 let b = node.to_string();
2212 if self.html {
2213 format!("<span class=\"mech-boolean\">{}</span>", b)
2214 } else {
2215 b
2216 }
2217 }
2218
2219 pub fn empty(&mut self, node: &Token) -> String {
2220 let e = node.to_string();
2221 if self.html {
2222 format!("<span class=\"mech-empty\">{}</span>", e)
2223 } else {
2224 e
2225 }
2226 }
2227
2228 pub fn literal(&mut self, node: &Literal) -> String {
2229 let l = match node {
2230 Literal::Empty(tkn) => self.empty(tkn),
2231 Literal::Boolean(tkn) => self.boolean(tkn),
2232 Literal::Number(num) => self.number(num),
2233 Literal::String(mech_string) => self.string(mech_string),
2234 Literal::Atom(atm) => self.atom(atm),
2235 Literal::Kind(knd) => self.kind_annotation(knd),
2236 Literal::TypedLiteral((boxed_literal, kind_annotation)) => {
2237 let literal = self.literal(boxed_literal);
2238 let annotation = self.kind_annotation(&kind_annotation.kind);
2239 format!("{}{}", literal, annotation)
2240 }
2241 };
2242 if self.html {
2243 format!("<span class=\"mech-literal\">{}</span>",l)
2244 } else {
2245 l
2246 }
2247 }
2248
2249 pub fn atom(&mut self, node: &Atom) -> String {
2250 if self.html {
2251 format!("<span class=\"mech-atom\"><span class=\"mech-atom-grave\">`</span><span class=\"mech-atom-name\">{}</span></span>",node.name.to_string())
2252 } else {
2253 format!("`{}", node.name.to_string())
2254 }
2255 }
2256
2257 pub fn string(&mut self, node: &MechString) -> String {
2258 if self.html {
2259 format!("<span class=\"mech-string\">\"{}\"</span>", node.text.to_string())
2260 } else {
2261 format!("\"{}\"", node.text.to_string())
2262 }
2263 }
2264
2265 pub fn number(&mut self, node: &Number) -> String {
2266 let n = match node {
2267 Number::Real(real) => self.real_number(real),
2268 Number::Complex(complex) => self.complex_numer(complex),
2269 };
2270 if self.html {
2271 format!("<span class=\"mech-number\">{}</span>",n)
2272 } else {
2273 n
2274 }
2275 }
2276
2277 pub fn real_number(&mut self, node: &RealNumber) -> String {
2278 match node {
2279 RealNumber::Negated(real_number) => format!("-{}", self.real_number(real_number)),
2280 RealNumber::Integer(token) => token.to_string(),
2281 RealNumber::Float((whole, part)) => format!("{}.{}", whole.to_string(), part.to_string()),
2282 RealNumber::Decimal(token) => token.to_string(),
2283 RealNumber::Hexadecimal(token) => format!("0x{}", token.to_string()),
2284 RealNumber::Octal(token) => format!("0o{}", token.to_string()),
2285 RealNumber::Binary(token) => format!("0b{}", token.to_string()),
2286 RealNumber::Scientific(((whole, part), (sign, ewhole, epart))) => format!("{}.{}e{}{}.{}", whole.to_string(), part.to_string(), if *sign { "-" } else { "+" }, ewhole.to_string(), epart.to_string()),
2287 RealNumber::Rational((numerator, denominator)) => format!("{}/{}", numerator.to_string(), denominator.to_string()),
2288 }
2289 }
2290
2291 pub fn complex_numer(&mut self, node: &C64Node) -> String {
2292 let real = if let Some(real) = &node.real {
2293 let num = self.real_number(&real);
2294 format!("{}+", num)
2295 } else {
2296 "".to_string()
2297 };
2298 let im = self.imaginary_number(&node.imaginary);
2299 format!("{}{}", real, im)
2300 }
2301
2302 pub fn imaginary_number(&mut self, node: &ImaginaryNumber) -> String {
2303 let real = self.real_number(&node.number);
2304 format!("{}i", real)
2305 }
2306
2307 pub fn humanize_html(input: String) -> String {
2308 let mut result = String::new();
2309 let mut indent_level = 0;
2310 let mut in_special_tag = false;
2311 let mut special_tag = "";
2312 let chars: Vec<char> = input.chars().collect();
2313 let mut i = 0;
2314
2315 let self_closing_tags = HashSet::from([
2316 "area", "base", "br", "col", "embed", "hr", "img", "input",
2317 "link", "meta", "param", "source", "track", "wbr"
2318 ]);
2319
2320 fn matches_tag(chars: &[char], pos: usize, tag: &str) -> bool {
2321 let tag_chars: Vec<char> = tag.chars().collect();
2322 pos + tag_chars.len() <= chars.len() && chars[pos..pos+tag_chars.len()] == tag_chars[..]
2323 }
2324
2325 while i < chars.len() {
2326 if !in_special_tag && (matches_tag(&chars, i, "<pre") || matches_tag(&chars, i, "<code")) {
2328 in_special_tag = true;
2329 special_tag = if matches_tag(&chars, i, "<pre") { "pre" } else { "code" };
2330
2331 result.push('\n');
2332 result.push_str(&" ".repeat(indent_level));
2333
2334 while i < chars.len() && chars[i] != '>' {
2336 result.push(chars[i]);
2337 i += 1;
2338 }
2339 result.push('>');
2340 i += 1;
2341 indent_level += 1;
2342
2343 let start = i;
2345 while i < chars.len() && !matches_tag(&chars, i, &format!("</{}>", special_tag)) {
2346 i += 1;
2347 }
2348
2349 result.extend(chars[start..i].iter());
2351
2352 if i < chars.len() {
2354 result.push_str(&format!("</{}>", special_tag));
2355 i += special_tag.len() + 3;
2356 in_special_tag = false;
2357 indent_level -= 1;
2358 }
2359 } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] != '/' {
2361 let tag_start = i + 1;
2362 let mut j = tag_start;
2363
2364 while j < chars.len() && chars[j].is_alphanumeric() {
2366 j += 1;
2367 }
2368
2369 let tag_name: String = chars[tag_start..j].iter().collect();
2370 let is_self_closing = self_closing_tags.contains(tag_name.as_str());
2371
2372 result.push('\n');
2374 result.push_str(&" ".repeat(indent_level));
2375
2376 while i < chars.len() && chars[i] != '>' {
2378 result.push(chars[i]);
2379 i += 1;
2380 }
2381 result.push('>');
2382 i += 1;
2383
2384 if !is_self_closing {
2385 indent_level += 1;
2386 }
2387 } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] == '/' {
2389 indent_level = indent_level.saturating_sub(1);
2390
2391 result.push('\n');
2392 result.push_str(&" ".repeat(indent_level));
2393
2394 while i < chars.len() && chars[i] != '>' {
2395 result.push(chars[i]);
2396 i += 1;
2397 }
2398 result.push('>');
2399 i += 1;
2400 } else if !in_special_tag {
2402 let start = i;
2403 while i < chars.len() && chars[i] != '<' {
2404 i += 1;
2405 }
2406
2407 let content: String = chars[start..i].iter().collect();
2408 if !content.trim().is_empty() {
2409 result.push('\n');
2410 result.push_str(&" ".repeat(indent_level));
2411 result.push_str(&content);
2412 }
2413 } else {
2415 result.push(chars[i]);
2416 i += 1;
2417 }
2418 }
2419
2420 result.push('\n');
2421 result
2422}
2423
2424}