Skip to main content

mech_syntax/
formatter.rs

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 format_grammar(&mut self, tree: &Gramamr) -> String {
60    self.html = false;
61    self.grammar(tree)
62  }*/
63
64  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]; // up to h6 level
356        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::FsmSpecification(fsm_spec) => self.fsm_specification(fsm_spec),
458        //MechCode::FsmImplementation(fsm_impl) => self.fsm_implementation(fsm_impl),
459        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        // Print it, but give it a hidden class so it can be toggled visible via JS
501        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(&section_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    // Helper to render a row of Paragraphs as `| ... | ... |`
815    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    // Render header
826    let header_line = render_row(&node.header, &mut |p| self.paragraph(p));
827
828    // Render alignment row
829    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    // Render body rows
840    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    // Join everything
846    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    // Render the header
865    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", // Default alignment
873        };
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    // Render the rows
884    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", // Default alignment
894        };
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\">&gt;</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::FsmImplementation(fsm_impl) => self.fsm_implementation(fsm_impl),
1172        //MechCode::FsmSpecification(fsm_spec) => self.fsm_specification(fsm_spec),
1173        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\">-&gt;</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\">-&gt;</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      //Statement::FsmDeclare(fsm_decl) => self.fsm_declare(fsm_decl, src),
1619    };
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\">&lt;<span class=\"mech-enum-name\">{}</span>&gt;</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\">&lt;<span class=\"mech-kind\">{}</span>&gt;</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      //Expression::FsmPipe(fsm_pipe) => self.fsm_pipe(fsm_pipe, src),
1780    };
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\"> &lt;- </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(); // Assume all rows have the same number of columns
2245
2246    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\">&lt;{}&gt;</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\">&lt;{}&gt;</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!("{}&lt;{}&gt;", ident_s, k);
2402          } else {
2403            src = format!("{},{}&lt;{}&gt;", 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!("{}&lt;{}&gt;", ident_s, k);
2415          } else {
2416            src = format!("{},{}&lt;{}&gt;", 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      // Handle <pre> and <code> tags
2712      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        // Add the opening tag
2720        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        // Process content
2729        let start = i;
2730        while i < chars.len() && !matches_tag(&chars, i, &format!("</{}>", special_tag)) {
2731          i += 1;
2732        }
2733        
2734        // Add the content as is
2735        result.extend(chars[start..i].iter());
2736        
2737        // Add the closing tag
2738        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      // Open tag
2745      } 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        // Get tag name
2750        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        // Add newline and indentation
2758        result.push('\n');
2759        result.push_str(&"  ".repeat(indent_level));
2760        
2761        // Add the tag
2762        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      // Close tag
2773      } 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      // Regular text content
2786      } 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      // Inside <pre> or <code>
2799      } else {
2800        result.push(chars[i]);
2801        i += 1;
2802      }
2803    }
2804    result.push('\n');
2805    result
2806  }
2807}