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