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!("<div class=\"mech-code-block disabled\"{}>{}</div>", 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!("<div class=\"mech-code-block hidden\"{}>{}</div>", 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  pub fn figures(&mut self, node: &FigureTable) -> String {
577    self.figure_num += 1;
578    let figure_label = format!("Fig {}.{}", self.h2_num, self.figure_num);
579    let figure_id = hash_str(&format!("{}-{:?}", figure_label, node.rows));
580
581    let mut figure_ix = 0usize;
582    let mut captions: Vec<String> = vec![];
583
584    if self.html {
585      let mut rows_html = String::new();
586      for row in &node.rows {
587        rows_html.push_str(&format!(
588          "<div class=\"mech-figure-table-row\" style=\"grid-template-columns: repeat({}, minmax(0, 1fr));\">",
589          row.len().max(1)
590        ));
591        for figure in row {
592          let label = ((b'a' + (figure_ix as u8)) as char).to_string();
593          let img_id = hash_str(&format!("{}-{}-{}", figure_label, figure_ix, figure.src.to_string()));
594          rows_html.push_str(&format!(
595            "<div class=\"mech-figure-table-cell\"><div class=\"mech-figure-panel\"><span class=\"mech-figure-subfigure-label\">{}</span><img id=\"{}\" class=\"mech-image mech-figure-grid-image\" src=\"{}\" /></div></div>",
596            label,
597            img_id,
598            figure.src.to_string(),
599          ));
600          captions.push(format!(
601            "<span class=\"mech-figure-caption-ref\">({})</span> <span class=\"mech-figure-caption-text\">{}</span>",
602            label,
603            figure.caption.to_string()
604          ));
605          figure_ix += 1;
606        }
607        rows_html.push_str("</div>");
608      }
609      let caption_block = captions.join(" ");
610      format!(
611        "<figure id=\"{}\" class=\"mech-figure-table\"><div class=\"mech-figure-grid\">{}</div><figcaption class=\"mech-figure-caption mech-figure-table-caption\"><strong class=\"mech-figure-label\">{}</strong> {}</figcaption></figure>",
612        figure_id, rows_html, figure_label, caption_block
613      )
614    } else {
615      let mut lines: Vec<String> = vec![];
616      for row in &node.rows {
617        let mut line = String::from("|");
618        for figure in row {
619          line.push(' ');
620          line.push_str(&format!("![{}]({})", self.paragraph(&figure.caption), figure.src.to_string()));
621          line.push_str(" |");
622          let label = ((b'a' + (figure_ix as u8)) as char).to_string();
623          captions.push(format!("({}) {}", label, self.paragraph(&figure.caption)));
624          figure_ix += 1;
625        }
626        lines.push(line);
627      }
628      format!("{}\n{} {}\n", lines.join("\n"), figure_label, captions.join(" "))
629    }
630  }
631
632
633  pub fn abstract_el(&mut self, node: &Vec<Paragraph>) -> String {
634    let abstract_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
635    if self.html {
636      format!("<div id=\"abstract\" class=\"mech-abstract\">{}</div>", abstract_paragraph)
637    } else {
638      format!("{}\n", abstract_paragraph)
639    }
640  }
641
642  pub fn equation(&mut self, node: &Token) -> String {
643    let id = hash_str(&format!("equation-{}",node.to_string()));
644    if self.html {
645      format!("<div id=\"{}\" equation=\"{}\" class=\"mech-equation\"></div>",id, node.to_string())
646    } else {
647      format!("$$ {}\n", node.to_string())
648    }
649  }
650
651  pub fn diagram(&mut self, node: &Token) -> String {
652    let id = hash_str(&format!("diagram-{}",node.to_string()));
653    if self.html {
654      format!("<div id=\"{}\" class=\"mech-diagram mermaid\">{}</div>",id, node.to_string())
655    } else {
656      format!("```{{diagram}}\n{}\n```", node.to_string())
657    }
658  }
659
660  pub fn citation(&mut self, node: &Citation) -> String {
661    let id = hash_str(&format!("{}",node.id.to_string()));
662    self.citations.resize(self.citation_num, String::new());
663    let citation_text = self.paragraph(&node.text);
664    let citation_num = match self.citation_map.get(&id) {
665      Some(&num) => num,
666      None => {
667        return format!("Citation {} not found in citation map.", node.id.to_string());
668      }
669    };
670    let formatted_citation = if self.html {
671      format!("<div id=\"{}\" class=\"mech-citation\">
672      <div class=\"mech-citation-id\">[{}]:</div>
673      {}
674    </div>",id, citation_num, citation_text)
675    } else {
676      format!("[{}]: {}",node.id.to_string(), citation_text)
677    };
678    self.citations[citation_num - 1] = formatted_citation;
679    String::new()
680  }
681
682  pub fn float(&mut self, node: &Box<SectionElement>, float_dir: &FloatDirection) -> String {
683    let mut src = "".to_string();
684    let id = hash_str(&format!("float-{:?}",*node));
685    let (float_class,float_sigil) = match float_dir {
686      FloatDirection::Left => ("mech-float left","<<"),
687      FloatDirection::Right => ("mech-float right",">>"),
688    };
689    let el = self.section_element(node);
690    if self.html {
691      format!("<div id=\"{}\" class=\"{}\">{}</div>",id,float_class,el)
692    } else {
693      format!("{}{}\n",float_sigil, el)
694    }
695  }
696
697  pub fn info_block(&mut self, node: &Vec<Paragraph>) -> String {
698    let info_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
699    if self.html {
700      format!("<div class=\"mech-info-block\">{}</div>",info_paragraph)
701    } else {
702      format!("(i)> {}\n",info_paragraph)
703    }
704  }
705
706  pub fn question_block(&mut self, node: &Vec<Paragraph>) -> String {
707    let question_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
708    if self.html {
709      format!("<div class=\"mech-question-block\">{}</div>",question_paragraph)
710    } else {
711      format!("(?)> {}\n",question_paragraph)
712    }
713  }
714
715  pub fn success_block(&mut self, node: &Vec<Paragraph>) -> String {
716    let success_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
717    if self.html {
718      format!("<div class=\"mech-success-block\">{}</div>",success_paragraph)
719    } else {
720      format!("(✓)>> {}\n",success_paragraph)
721    }
722  }
723
724  pub fn warning_block(&mut self, node: &Vec<Paragraph>) -> String {
725    let warning_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
726    if self.html {
727      format!("<div class=\"mech-warning-block\">{}</div>",warning_paragraph)
728    } else {
729      format!("(!)>> {}\n",warning_paragraph)
730    }
731  }
732
733  pub fn idea_block(&mut self, node: &Vec<Paragraph>) -> String {
734    let idea_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
735    if self.html {
736      format!("<div class=\"mech-idea-block\">{}</div>",idea_paragraph)
737    } else {
738      format!("(*)> {}\n",idea_paragraph)
739    }
740  }
741
742  pub fn error_block(&mut self, node: &Vec<Paragraph>) -> String {
743    let error_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
744    if self.html {
745      format!("<div class=\"mech-error-block\">{}</div>",error_paragraph)
746    } else {
747      format!("(✗)>> {}\n",error_paragraph)
748    }
749  }
750
751  pub fn mika(&mut self, node: &(Mika, Option<MikaSection>)) -> String {
752    let (mika, section) = node;
753    let mika_str = format!("<div class=\"mech-mika\">{}</div>", mika.to_string());
754    if self.html {
755      match section {
756        Some(sec) => {
757          let mut sec_str = "".to_string();
758          for el in &sec.elements.elements {
759            let section_element = self.section_element(el);
760            sec_str.push_str(&section_element);
761          }
762          format!("<div class=\"mech-mika-section\">{} {}</div>", mika_str, sec_str)
763        },
764        None => mika_str,
765      }
766    } else {
767      mika_str
768    }
769  }
770
771  pub fn prompt(&mut self, node: &SectionElement) -> String {
772    let prompt_str = self.section_element(node);
773    if self.html {
774      format!("<div class=\"mech-prompt\"><span class=\"mech-prompt-sigil\">>:</span>{}</div>", prompt_str)
775    } else {
776      format!(">: {}\n", prompt_str)
777    }
778  }
779    
780  pub fn section_element(&mut self, node: &SectionElement) -> String {
781    match node {
782      SectionElement::Abstract(n) => self.abstract_el(n),
783      SectionElement::QuoteBlock(n) => self.quote_block(n),
784      SectionElement::SuccessBlock(n) => self.success_block(n),
785      SectionElement::IdeaBlock(n) => self.idea_block(n),
786      SectionElement::InfoBlock(n) => self.info_block(n),
787      SectionElement::WarningBlock(n) => self.warning_block(n),
788      SectionElement::ErrorBlock(n) => self.error_block(n),
789      SectionElement::QuestionBlock(n) => self.question_block(n),
790      SectionElement::Citation(n) => self.citation(n),
791      SectionElement::CodeBlock(n) => self.code_block(n),
792      SectionElement::Comment(n) => self.comment(n),
793      SectionElement::Diagram(n) => self.diagram(n),
794      SectionElement::Equation(n) => self.equation(n),
795      SectionElement::Prompt(n) => self.prompt(n),
796      SectionElement::FencedMechCode(n) => self.fenced_mech_code(n),
797      SectionElement::Float((n,f)) => self.float(n,f),
798      SectionElement::Footnote(n) => self.footnote(n),
799      SectionElement::Grammar(n) => self.grammar(n),
800      SectionElement::FigureTable(n) => self.figures(n),
801      SectionElement::Image(n) => self.image(n),
802      SectionElement::List(n) => self.list(n),
803      SectionElement::MechCode(n) => self.mech_code(n),
804      SectionElement::Mika(n) => self.mika(n),
805      SectionElement::Paragraph(n) => self.paragraph(n),
806      SectionElement::Subtitle(n) => self.subtitle(n),
807      SectionElement::Table(n) => self.mechdown_table(n),
808      SectionElement::ThematicBreak => self.thematic_break(),
809      SectionElement::Error(src, range) => self.section_error(src.clone(), range),
810    }
811  }
812
813  pub fn section_error(&mut self, src: Token, range: &SourceRange) -> String {
814    if self.html {
815      let mut error_str = String::new();
816      error_str.push_str(&format!("<div class=\"mech-section-error\">\n"));
817      error_str.push_str(&format!("<strong>Error in section at range {:?}-{:?}:</strong>\n", range.start, range.end));
818      error_str.push_str(&format!("<pre class=\"mech-error-source\">{}</pre>\n", src.to_string()));
819      error_str.push_str("</div>\n");
820      error_str  
821    } else {
822      let mut error_str = String::new();
823      error_str.push_str(&format!("Error in section at range {:?}-{:?}:\n", range.start, range.end));
824      error_str.push_str(&format!("{} ", src.to_string()));
825      error_str.push_str("\n");
826      error_str
827    }
828  }
829
830  pub fn footnote(&mut self, node: &Footnote) -> String {
831    let (id_name, paragraphs) = node;
832    let note_paragraph = paragraphs.iter().map(|p| self.paragraph(p)).collect::<String>();
833    let id: u64 = hash_str(&format!("footnote-{}",id_name.to_string()));
834    if self.html {
835      format!("<div class=\"mech-footnote\" id=\"{}\">
836        <div class=\"mech-footnote-id\">{}:</div>
837        {}
838      </div>",id, id_name.to_string(), note_paragraph)  
839    } else {
840      format!("[^{}]: {}\n",id_name.to_string(), note_paragraph)
841    }
842  }
843
844  pub fn quote_block(&mut self, node: &Vec<Paragraph>) -> String {
845    let quote_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
846    if self.html {
847      format!("<blockquote class=\"mech-block-quote\">{}</blockquote>",quote_paragraph)
848    } else {
849      format!("> {}\n",quote_paragraph)
850    }
851  }
852
853  pub fn thematic_break(&mut self) -> String {
854    if self.html {
855      format!("<hr class=\"mech-thematic-break\"/>")
856    } else {
857      format!("***\n")
858    }
859  }
860
861  pub fn mechdown_table(&mut self, node: &MarkdownTable) -> String {
862    if self.html {
863      self.mechdown_table_html(node)
864    } else {
865      self.mechdown_table_string(node)
866    }
867  }
868
869
870  pub fn mechdown_table_string(&mut self, node: &MarkdownTable) -> String {
871    // Helper to render a row of Paragraphs as `| ... | ... |`
872    fn render_row(cells: &[Paragraph], f: &mut impl FnMut(&Paragraph) -> String) -> String {
873        let mut row = String::from("|");
874        for cell in cells {
875            row.push_str(" ");
876            row.push_str(&f(cell));
877            row.push_str(" |");
878        }
879        row
880    }
881
882    // Render header
883    let header_line = render_row(&node.header, &mut |p| self.paragraph(p));
884
885    // Render alignment row
886    let mut align_line = String::from("|");
887    for align in &node.alignment {
888        let spec = match align {
889            ColumnAlignment::Left => ":---",
890            ColumnAlignment::Center => ":---:",
891            ColumnAlignment::Right => "---:",
892        };
893        align_line.push_str(&format!(" {} |", spec));
894    }
895
896    // Render body rows
897    let mut body_lines = vec![];
898    for row in &node.rows {
899        body_lines.push(render_row(row, &mut |p| self.paragraph(p)));
900    }
901
902    // Join everything
903    let mut markdown = String::new();
904    markdown.push_str(&header_line);
905    markdown.push('\n');
906    markdown.push_str(&align_line);
907    markdown.push('\n');
908    for line in body_lines {
909        markdown.push_str(&line);
910        markdown.push('\n');
911    }
912
913    markdown
914}
915
916
917  pub fn mechdown_table_html(&mut self, node: &MarkdownTable) -> String {
918    let mut html = String::new();
919    html.push_str("<table class=\"mech-table\">");
920
921    // Render the header
922    if !node.header.is_empty() {
923      html.push_str("<thead><tr class=\"mech-table-header\">");
924      for (i, cell) in node.header.iter().enumerate() {
925        let align = match node.alignment.get(i) {
926          Some(ColumnAlignment::Left) => "left",
927          Some(ColumnAlignment::Center) => "center",
928          Some(ColumnAlignment::Right) => "right",
929          None => "left", // Default alignment
930        };
931        let cell_html = self.paragraph(cell);
932        html.push_str(&format!(
933          "<th class=\"mech-table-header-cell {}\">{}</th>", 
934          align, cell_html
935        ));
936      }
937      html.push_str("</tr></thead>");
938    }
939
940    // Render the rows
941    html.push_str("<tbody>");
942    for (row_index, row) in node.rows.iter().enumerate() {
943      let row_class = if row_index % 2 == 0 { "mech-table-row-even" } else { "mech-table-row-odd" };
944      html.push_str(&format!("<tr class=\"mech-table-row {}\">", row_class));
945      for (i, cell) in row.iter().enumerate() {
946        let align = match node.alignment.get(i) {
947          Some(ColumnAlignment::Left) => "left",
948          Some(ColumnAlignment::Center) => "center",
949          Some(ColumnAlignment::Right) => "right",
950          None => "left", // Default alignment
951        };
952        let cell_html = self.paragraph(cell);
953        html.push_str(&format!(
954          "<td class=\"mech-table-cell {}\">{}</td>", 
955          align, cell_html
956        ));
957      }
958      html.push_str("</tr>");
959    }
960    html.push_str("</tbody>");
961    html.push_str("</table>");
962    html
963  }
964
965  pub fn grammar(&mut self, node: &Grammar) -> String {
966    let mut src = "".to_string();
967    for rule in node.rules.iter() {
968      let id = self.grammar_identifier(&rule.name);
969      let rule_str = format!("{} <span class=\"mech-grammar-define-op\">:=</span>{}", id, self.grammar_expression(&rule.expr));
970      if self.html {
971        src = format!("{}<div class=\"mech-grammar-rule\">{} ;</div>",src,rule_str);
972      } else {
973        src = format!("{}{};\n",src,rule_str); 
974      }
975    }
976    if self.html {
977      format!("<div class=\"mech-grammar\">{}</div>",src)
978    } else {
979      src
980    }
981  }
982
983  fn grammar_identifier(&mut self, node: &GrammarIdentifier) -> String {
984    let name = node.name.to_string();
985    if self.html {
986      format!("<span id=\"{}\" class=\"mech-grammar-identifier\">{}</span>",hash_str(&name), name)
987    } else {
988      name
989    }
990  }
991
992  fn grammar_expression(&mut self, node: &GrammarExpression) -> String {
993    let expr = match node {
994      GrammarExpression::List(element,deliniator) => {
995        let el = self.grammar_expression(element);
996        let del = self.grammar_expression(deliniator);
997        if self.html {
998          format!("<span class=\"mech-grammar-list\">[<span class=\"mech-grammar-list-element\">{}</span>,<span class=\"mech-grammar-list-deliniator\">{}</span>]</span>",el,del)
999        } else {
1000          format!("[{},{}]",el,del)
1001        }
1002      },
1003      GrammarExpression::Range(start,end) => {
1004        if self.html {
1005          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())
1006        } else {
1007          format!("{}..{}", start.to_string(), end.to_string())
1008        }
1009      }
1010      GrammarExpression::Choice(choices) => {
1011        let mut src = "".to_string();
1012        let inline = choices.len() <= 3;
1013        for (i, choice) in choices.iter().enumerate() {
1014          let choice_str = self.grammar_expression(choice);
1015          if i == 0 {
1016            src = format!("{}", choice_str);
1017          } else {
1018            if self.html {
1019              src = if inline {
1020                format!("{} <span class=\"mech-grammar-choice-op\">|</span> {}", src, choice_str)
1021              } else {
1022                format!("{}<div class=\"mech-grammar-choice\"><span class=\"mech-grammar-choice-op\">|</span> {}</div>", src, choice_str)
1023              };
1024            } else {
1025              src = format!("{} | {}", src, choice_str);
1026            }
1027          }
1028        }
1029        src
1030      },
1031      GrammarExpression::Sequence(seq) => {
1032        let mut src = "".to_string();
1033        let inline = seq.len() <= 3;
1034        for (i, factor) in seq.iter().enumerate() {
1035          let factor_str = self.grammar_expression(factor);
1036          if i == 0 {
1037        src = format!("{}", factor_str);
1038          } else {
1039        if self.html {
1040          src = if inline {
1041            format!("{}, {}", src, factor_str)
1042          } else {
1043            format!("{}<div class=\"mech-grammar-sequence\"><span class=\"mech-grammar-sequence-op\">,</span> {}</div>", src, factor_str)
1044          };
1045        } else {
1046          src = format!("{}, {}", src, factor_str);
1047        }
1048          }
1049        }
1050        src
1051      },
1052      GrammarExpression::Repeat0(expr) => {
1053        let inner_expr = self.grammar_expression(expr);
1054        if self.html {
1055          format!("<span class=\"mech-grammar-repeat0-op\">*</span>{}", inner_expr)
1056        } else {
1057          format!("*{}", inner_expr)
1058        }
1059      },
1060      GrammarExpression::Repeat1(expr) => {
1061        let inner_expr = self.grammar_expression(expr);
1062        if self.html {
1063          format!("<span class=\"mech-grammar-repeat1-op\">+</span>{}", inner_expr)
1064        } else {
1065          format!("+{}", inner_expr)
1066        }
1067      },
1068      GrammarExpression::Optional(expr) => {
1069        let inner_expr = self.grammar_expression(expr);
1070        if self.html {
1071          format!("<span class=\"mech-grammar-optional-op\">?</span>{}", inner_expr)
1072        } else {
1073          format!("?{}", inner_expr)
1074        }
1075      },
1076      GrammarExpression::Peek(expr) => {
1077        let inner_expr = self.grammar_expression(expr);
1078        if self.html {
1079          format!("<span class=\"mech-grammar-peek-op\">&gt;</span>{}", inner_expr)
1080        } else {
1081          format!(">{}", inner_expr)
1082        }
1083      },
1084      GrammarExpression::Not(expr) => {
1085        let inner_expr = self.grammar_expression(expr);
1086        if self.html {
1087          format!("<span class=\"mech-grammar-not-op\">¬</span>{}", inner_expr)
1088        } else {
1089          format!("¬{}", inner_expr)
1090        }
1091      },
1092      GrammarExpression::Terminal(token) => {
1093        if self.html {
1094          format!("<span class=\"mech-grammar-terminal\">\"{}\"</span>", token.to_string())
1095        } else {
1096          format!("\"{}\"", token.to_string())
1097        }
1098      },
1099      GrammarExpression::Group(expr) => {
1100        let inner_expr = self.grammar_expression(expr);
1101        if self.html {
1102          format!("<span class=\"mech-grammar-group\">(<span class=\"mech-grammar-group-content\">{}</span>)</span>", inner_expr)
1103        } else {
1104          format!("({})", inner_expr)
1105        }
1106      },
1107      GrammarExpression::Definition(id) => {
1108        let name = id.name.to_string();
1109        if self.html {
1110          format!("<span class=\"mech-grammar-definition\"><a href=\"#{}\">{}</a></span>",hash_str(&name), name)
1111        } else {
1112          name
1113        }
1114      },
1115    };
1116    
1117    if self.html {
1118      format!("<span class=\"mech-grammar-expression\">{}</span>", expr)
1119    } else {
1120      expr
1121    }
1122  }
1123
1124  pub fn code_block(&mut self, node: &Token) -> String {
1125    let code = node.to_string();
1126    if self.html {
1127      format!("<div class=\"mech-code-block\">{}</div>",code)
1128    } else {
1129      format!("{}\n",code)
1130    }
1131  }
1132
1133  pub fn comment(&mut self, node: &Comment) -> String {
1134    let comment_text = self.paragraph(&node.paragraph);
1135    if self.html {
1136      format!("<span class=\"mech-comment\"><span class=\"mech-comment-sigil\">--</span>{}</span>", comment_text)
1137    } else {
1138      format!("{}\n",comment_text)
1139    }
1140  }
1141
1142  pub fn list(&mut self, node: &MDList) -> String {
1143    match node {
1144      MDList::Ordered(ordered_list) => self.ordered_list(ordered_list),
1145      MDList::Unordered(unordered_list) => self.unordered_list(unordered_list),
1146      MDList::Check(check_list) => self.check_list(check_list),
1147    }
1148  }
1149
1150  pub fn check_list(&mut self, node: &CheckList) -> String {
1151    let mut lis = "".to_string();
1152    for (i, ((checked, item), sublist)) in node.iter().enumerate() {
1153      let it = self.paragraph(item);
1154      if self.html {
1155        lis = format!("{}<li class=\"mech-check-list-item\"><input type=\"checkbox\" {}>{}</li>", lis, if *checked { "checked" } else { "" }, it);
1156      } else {
1157        lis = format!("{}* [{}] {}\n", lis, if *checked { "x" } else { " " }, it);
1158      }
1159      match sublist {
1160        Some(sublist) => {
1161          let sublist_str = self.list(sublist);
1162          lis = format!("{}{}", lis, sublist_str);
1163        },
1164        None => {},
1165      }
1166    }
1167    if self.html {
1168      format!("<ul class=\"mech-check-list\">{}</ul>", lis)
1169    } else {
1170      lis
1171    }
1172  }
1173
1174  pub fn ordered_list(&mut self, node: &OrderedList) -> String {
1175    let mut lis = "".to_string();
1176    for (i, ((num,item),sublist)) in node.items.iter().enumerate() {
1177      let it = self.paragraph(item);
1178      if self.html {
1179        lis = format!("{}<li class=\"mech-ol-list-item\">{}</li>",lis,it);
1180      } else {
1181        lis = format!("{}{}. {}\n",lis,i+1,it);
1182      }
1183      match sublist {
1184        Some(sublist) => {
1185          let sublist_str = self.list(sublist);
1186          lis = format!("{}{}",lis,sublist_str);
1187        },
1188        None => {},
1189      }
1190    }
1191    if self.html {
1192      format!("<ol start=\"{}\" class=\"mech-ordered-list\">{}</ol>",node.start.to_string(),lis)
1193    } else {
1194      lis
1195    }
1196  }
1197
1198  pub fn unordered_list(&mut self, node: &UnorderedList) -> String {
1199    let mut lis = "".to_string();
1200    for (i, ((bullet, item),sublist)) in node.iter().enumerate() {
1201      let it = self.paragraph(item);
1202      match (bullet, self.html) {
1203        (Some(bullet_tok),true) => lis = format!("{}<li data-bullet=\"{}\" class=\"mech-list-item-emoji\">{}</li>",lis,bullet_tok.to_string(),it),
1204        (None,true) => lis = format!("{}<li class=\"mech-ul-list-item\">{}</li>",lis,it),
1205        (_,false) => lis = format!("{}* {}\n",lis,it),
1206      }
1207      match sublist {
1208        Some(sublist) => {
1209          let sublist_str = self.list(sublist);
1210          lis = format!("{}{}",lis,sublist_str);
1211        },
1212        None => {},
1213      }
1214    }
1215    if self.html {
1216      format!("<ul class=\"mech-unordered-list\">{}</ul>",lis)
1217    } else {
1218      lis
1219    }
1220  }
1221
1222  pub fn mech_code(&mut self, node: &Vec<(MechCode,Option<Comment>)>) -> String {
1223    let mut src = String::new();
1224    for (code,cmmnt) in node {
1225      let c = match code {
1226        MechCode::Comment(cmnt) => self.comment(cmnt),
1227        MechCode::Expression(expr) => self.expression(expr),
1228        MechCode::FsmImplementation(fsm_impl) => self.fsm_implementation(fsm_impl),
1229        MechCode::FsmSpecification(fsm_spec) => self.fsm_specification(fsm_spec),
1230        MechCode::FunctionDefine(func_def) => self.function_define(func_def),
1231        MechCode::Statement(stmt) => self.statement(stmt),
1232        x => todo!("Unhandled MechCode: {:#?}", x),
1233      };
1234      let formatted_comment = match cmmnt {
1235        Some(cmmt) => self.comment(cmmt),
1236        None => String::new(),
1237      };
1238      if self.html {
1239        src.push_str(&format!("<span class=\"mech-code\">{}{}</span>", c, formatted_comment));
1240      } else {
1241        src.push_str(&format!("{}{}\n", c, formatted_comment));
1242      }
1243    }
1244    if self.html {
1245      format!("<span class=\"mech-code-block\">{}</span>",src)
1246    } else {
1247      src
1248    }
1249  }
1250
1251  pub fn fsm_implementation(&mut self, node: &FsmImplementation) -> String {
1252    let name = node.name.to_string();
1253    let mut input = "".to_string();
1254    for (i, ident) in node.input.iter().enumerate() {
1255      let v = self.var(ident);
1256      if i == 0 {
1257        input = format!("{}", v);
1258      } else {
1259        input = format!("{}, {}", input, v);
1260      }
1261    }
1262    let start = self.pattern(&node.start);
1263    let mut arms = "".to_string();
1264    for (i, arm) in node.arms.iter().enumerate() {
1265      let a = self.fsm_arm(arm, i == node.arms.len() - 1);
1266      if i == 0 {
1267        arms = format!("{}", a);
1268      } else {
1269        arms = format!("{}{}", arms, a);
1270      }
1271    }
1272    if self.html {
1273      format!("<div class=\"mech-fsm-implementation\">
1274        <div class=\"mech-fsm-implementation-header\">
1275          <span class=\"mech-fsm-sigil\">#</span>
1276          <span class=\"mech-fsm-name\">{}</span>
1277          <span class=\"mech-left-paren\">(</span>
1278          <span class=\"mech-fsm-input\">{}</span>
1279          <span class=\"mech-right-paren\">)</span>
1280          <span class=\"mech-fsm-define-op\">→</span>
1281          <span class=\"mech-fsm-start\">{}</span>
1282        </div>
1283        <div class=\"mech-fsm-arms\">
1284          {}
1285        </div>
1286      </div>",name,input,start,arms)
1287    } else {
1288      format!("#{}({}) {} {}\n{}", name, input, "->" , start, arms)
1289    }
1290  }
1291
1292  pub fn fsm_arm(&mut self, node: &FsmArm, last: bool) -> String {
1293    let arm = match node {
1294      FsmArm::Comment(comment) => self.comment(comment),
1295      FsmArm::Guard(pattern, guards) => {
1296        let p = self.pattern(pattern);
1297        let mut gs = "".to_string();
1298        for (i, guard) in guards.iter().enumerate() {
1299          let g = self.guard(guard);
1300          if i == 0 {
1301            if self.html {
1302              gs = format!("<div class=\"mech-fsm-guard-arm\">├ {}</div>", g);
1303            } else {
1304              gs = format!("    ├ {}\n", g);
1305            }
1306          } else if i == guards.len() - 1 {
1307            if self.html {
1308              gs = format!("{}<div class=\"mech-fsm-guard-arm\">└ {}</div>", gs, g);
1309            } else {
1310              gs = format!("{}    └ {}", gs, g); 
1311            }
1312          } else {  
1313            if self.html {
1314              gs = format!("{}<div class=\"mech-fsm-guard-arm\">├ {}</div>", gs, g);
1315            } else {
1316              gs = format!("{}    ├ {}\n", gs, g);
1317            }
1318          }
1319        }
1320        if self.html {
1321          format!("<div class=\"mech-fsm-arm-guard\">
1322            <span class=\"mech-fsm-start\">{}</span>
1323            <span class=\"mech-fsm-guards\">{}</span>
1324          </div>",p,gs)
1325        } else {
1326          format!("  {}\n{}", p, gs)
1327        }
1328      },
1329      FsmArm::Transition(pattern, transitions) => {
1330        let p = self.pattern(pattern);
1331        let mut ts = "".to_string();
1332        for (i, transition) in transitions.iter().enumerate() {
1333          let t = self.transition(transition);
1334          if i == 0 {
1335            ts = format!("{}", t);
1336          } else {
1337            ts = format!("{}{}", ts, t);
1338          }
1339        }
1340        if self.html {
1341          format!("<div class=\"mech-fsm-arm\">
1342            <span class=\"mech-fsm-arm-pattern\">{}</span>
1343            <span class=\"mech-fsm-arm-transitions\">{}</span>
1344          </div>",p,ts)
1345        } else {
1346          format!("  {}{}", p, ts)
1347        }
1348      },
1349    };
1350    if self.html {
1351      if last {
1352        format!("<div class=\"mech-fsm-arm-last\">{}.</div>",arm)
1353      } else {
1354        format!("<div class=\"mech-fsm-arm\">{}</div>",arm)
1355      }
1356    } else {
1357      if last { 
1358        format!("{}.", arm)
1359      } else {
1360        format!("{}\n", arm)
1361      }
1362    }
1363  }
1364
1365  pub fn guard(&mut self, node: &Guard) -> String {
1366    let condition = self.pattern(&node.condition);
1367    let mut transitions = "".to_string();
1368    for (i, transition) in node.transitions.iter().enumerate() {
1369      let t = self.transition(transition);
1370      if i == 0 {
1371        transitions = format!("{}", t);
1372      } else {
1373        transitions = format!("{}{}", transitions, t);
1374      }
1375    }
1376    if self.html {
1377      format!("<div class=\"mech-guard\">
1378        <span class=\"mech-guard-condition\">{}</span>
1379        <span class=\"mech-guard-transitions\">{}</span>
1380      </div>",condition,transitions)
1381    } else {
1382      format!("{}{}", condition, transitions)
1383    }
1384  }
1385 
1386
1387  pub fn pattern(&mut self, node: &Pattern) -> String {
1388    let p = match node {
1389      Pattern::Wildcard => {
1390        if self.html {
1391          format!("<span class=\"mech-pattern-wildcard\">*</span>")
1392        } else {
1393          format!("*")
1394        }
1395      },
1396      Pattern::Tuple(tpl) => self.pattern_tuple(tpl),
1397      Pattern::Array(arr) => self.pattern_array(arr),
1398      Pattern::Expression(expr) => self.expression(expr),
1399      Pattern::TupleStruct(tuple_struct) => self.pattern_tuple_struct(tuple_struct),
1400    };
1401    if self.html {
1402      format!("<span class=\"mech-pattern\">{}</span>",p)
1403    } else {
1404      p
1405    }
1406  }
1407
1408  pub fn pattern_tuple_struct(&mut self, node: &PatternTupleStruct) -> String {
1409    let name = node.name.to_string();
1410    let mut patterns = "".to_string();
1411    for (i, pattern) in node.patterns.iter().enumerate() {
1412      let p = self.pattern(pattern);
1413      if i == 0 {
1414        patterns = format!("{}", p);
1415      } else {
1416        patterns = format!("{}, {}", patterns, p);
1417      }
1418    }
1419    if self.html {
1420      format!("<span class=\"mech-tuple-struct\">
1421        <span class=\"mech-tuple-struct-sigil\">:</span>
1422        <span class=\"mech-tuple-struct-name\">{}</span>
1423        <span class=\"mech-left-paren\">(</span>
1424        <span class=\"mech-tuple-struct-patterns\">{}</span>
1425        <span class=\"mech-right-paren\">)</span>
1426      </span>",name,patterns)
1427    } else {
1428      format!(":{}({})", name, patterns)
1429    }
1430  }
1431
1432  pub fn pattern_tuple(&mut self, node: &PatternTuple) -> String {
1433    let mut patterns = "".to_string();
1434    for (i, pattern) in node.0.iter().enumerate() {
1435      let p = self.pattern(pattern);
1436      if i == 0 {
1437        patterns = format!("{}", p);
1438      } else {
1439        patterns = format!("{}, {}", patterns, p);
1440      }
1441    }
1442    if self.html {
1443      format!("<span class=\"mech-pattern-tuple\">
1444        <span class=\"mech-left-paren\">(</span>
1445        <span class=\"mech-patterns\">{}</span>
1446        <span class=\"mech-right-paren\">)</span>
1447      </span>",patterns)
1448    } else {
1449      format!("({})", patterns)
1450    }
1451  }
1452
1453  pub fn transition(&mut self, node: &Transition) -> String {
1454    match node {
1455      Transition::Next(pattern) => {
1456        if self.html {
1457          format!("<span class=\"mech-transition-next\">→ {}</span>",self.pattern(pattern))
1458        } else {
1459          format!(" {} {}", "->", self.pattern(pattern))
1460        }
1461      }
1462      Transition::Output(pattern) => {
1463        if self.html {
1464          format!("<span class=\"mech-transition-output\">⇒ {}</span>",self.pattern(pattern))
1465        } else {
1466          format!(" {} {}", "=>", self.pattern(pattern))
1467        }
1468      }
1469      Transition::Async(pattern) => {
1470        if self.html {
1471          format!("<span class=\"mech-transition-async\">↝ {}</span>",self.pattern(pattern))
1472        } else {
1473          format!(" {} {}", "~>", self.pattern(pattern))
1474
1475        }
1476      }
1477      Transition::Statement(stmt) => {
1478        if self.html {
1479          format!("<span class=\"mech-transition-statement\">→ {}</span>",self.statement(stmt))
1480        } else {
1481          format!(" {} {}", "->", self.statement(stmt))
1482        }
1483      }
1484      Transition::CodeBlock(code) => {
1485        let mut code_str = "".to_string();
1486        let formatted = self.mech_code(code);
1487        if self.html {
1488          code_str.push_str(&format!("<span class=\"mech-transition-code\">→ {}</span>", formatted));
1489        } else {
1490          code_str.push_str(&format!(" {} {}", "->", formatted));
1491        }
1492        code_str
1493      }
1494    }
1495  }
1496
1497  pub fn fsm_specification(&mut self, node: &FsmSpecification) -> String {
1498    let name = node.name.to_string();
1499    let mut input = "".to_string();
1500    for (i, var) in node.input.iter().enumerate() {
1501      let v = self.var(var);
1502      if i == 0 {
1503        input = format!("{}", v);
1504      } else {
1505        input = format!("{}, {}", input, v);
1506      }
1507    }
1508    let output = match &node.output {
1509      Some(kind) => format!(" {} {}", "⇒", self.kind_annotation(&kind.kind)),
1510      None => "".to_string(),
1511    };
1512    let mut states = "".to_string();
1513    for (i, state) in node.states.iter().enumerate() {
1514      let v = self.state_definition(state);
1515      let state_arm = if node.states.len() == 1 {
1516        format!("{} {}", "└", v)
1517      } else if i == 0 {
1518        format!("{} {}", "├", v)
1519      } else if i == node.states.len() - 1 {
1520        format!("{} {}{}", "└", v, ".")
1521      } else {
1522        format!("{} {}", "├", v)
1523      };
1524      if self.html {
1525        states = format!("{}<span class=\"mech-fsm-state\">{}</span>",states,state_arm);
1526      } else {
1527        states = format!("{}    {}\n",states,state_arm);
1528      }
1529    }
1530    if self.html {
1531      format!("<div class=\"mech-fsm-specification\">
1532      <div class=\"mech-fsm-specification-header\">
1533        <span class=\"mech-fsm-sigil\">#</span>
1534        <span class=\"mech-fsm-name\">{}</span>
1535        <span class=\"mech-left-paren\">(</span>
1536        <span class=\"mech-fsm-input\">{}</span>
1537        <span class=\"mech-right-paren\">)</span>
1538        <span class=\"mech-fsm-output\">{}</span>
1539        <span class=\"mech-fsm-define-op\">:=</span>
1540      </div>
1541      <div class=\"mech-fsm-states\">{}</div>
1542      </div>",name,input,output,states)
1543    } else {
1544      format!("#{}({}){} {}\n{}", name, input, output, ":=", states)
1545    }
1546  }
1547
1548  pub fn function_define(&mut self, node: &FunctionDefine) -> String {
1549    let name = node.name.to_string();
1550    let input = node
1551      .input
1552      .iter()
1553      .map(|arg| self.function_argument(arg))
1554      .collect::<Vec<_>>()
1555      .join(", ");
1556
1557    if !node.match_arms.is_empty() {
1558      let output_kind = node
1559        .output
1560        .first()
1561        .map(|arg| self.kind_annotation(&arg.kind.kind))
1562        .unwrap_or_else(|| "<_>".to_string());
1563
1564      let arms = node
1565        .match_arms
1566        .iter()
1567        .enumerate()
1568        .map(|(ix, arm)| {
1569          let branch = if ix + 1 == node.match_arms.len() { "└" } else { "├" };
1570          let pattern = self.pattern(&arm.pattern);
1571          let expression = self.expression(&arm.expression);
1572          if self.html {
1573            format!("<div class=\"mech-function-match-arm\"><span class=\"mech-function-branch\">{}</span><span class=\"mech-function-pattern\">{}</span> <span class=\"mech-function-arrow\">⇒</span><span class=\"mech-function-expression\">{}</span></div>", branch, pattern, expression)
1574          } else {
1575            format!("  {} {} => {}", branch, pattern, expression)
1576          }
1577        })
1578        .collect::<Vec<_>>()
1579        .join(if self.html { "" } else { "\n" });
1580
1581      if self.html {
1582        format!("<div class=\"mech-function-define\"><div class=\"mech-function-signature\"><span class=\"mech-function-name\">{}</span><span class=\"mech-left-paren\">(</span><span class=\"mech-function-input\">{}</span><span class=\"mech-right-paren\">)</span> <span class=\"mech-function-arrow\">⇒</span> <span class=\"mech-function-output\">{}</span></div><div class=\"mech-function-match-arms\">{}<span class=\"mech-function-period\">.</span></div></div>", name, input, output_kind, arms)
1583      } else {
1584        format!("{}({}) => {}\n{}.", name, input, output_kind, arms)
1585      }
1586    } else {
1587      let output = if node.output.len() == 1 {
1588        self.function_argument(&node.output[0])
1589      } else {
1590        format!(
1591          "({})",
1592          node.output
1593            .iter()
1594            .map(|arg| self.function_argument(arg))
1595            .collect::<Vec<_>>()
1596            .join(", ")
1597        )
1598      };
1599
1600      let statements = node
1601        .statements
1602        .iter()
1603        .map(|stmt| self.statement(stmt))
1604        .collect::<Vec<_>>()
1605        .join(if self.html { "" } else { "\n" });
1606
1607      if self.html {
1608        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)
1609      } else {
1610        format!("{}({}) = {} :=\n{}.", name, input, output, statements)
1611      }
1612    }
1613  }
1614
1615  pub fn function_argument(&mut self, node: &FunctionArgument) -> String {
1616    let name = node.name.to_string();
1617    let kind = self.kind_annotation(&node.kind.kind);
1618    if self.html {
1619      format!("<span class=\"mech-function-argument\"><span class=\"mech-function-argument-name\">{}</span><span class=\"mech-function-argument-kind\">{}</span></span>", name, kind)
1620    } else {
1621      format!("{}{}", name, kind)
1622    }
1623  }
1624
1625  pub fn state_definition(&mut self, node: &StateDefinition) -> String {
1626    let name = node.name.to_string();
1627    let mut state_variables = "".to_string();
1628    match &node.state_variables {
1629      Some(vars) => {
1630        for (i, var) in vars.iter().enumerate() {
1631          let v = self.var(var);
1632          if i == 0 {
1633            state_variables = format!("{}", v);
1634          } else {
1635            state_variables = format!("{}, {}", state_variables, v);
1636          }
1637        }
1638      },
1639      None => {}
1640    }
1641    if self.html {
1642      format!("<div class=\"mech-state-definition\">
1643      <span class=\"mech-state-name\"><span class=\"mech-state-name-sigil\">:</span>{}</span>
1644      <span class=\"mech-left-paren\">(</span>
1645      <span class=\"mech-state-variables\">{}</span>
1646      <span class=\"mech-right-paren\">)</span>
1647      </div>",name,state_variables)
1648    } else {
1649      format!("{}({})", name, state_variables)
1650    }
1651  }
1652
1653  pub fn variable_define(&mut self, node: &VariableDefine) -> String {
1654    let mut mutable = if node.mutable {
1655      "~".to_string()
1656    } else {
1657      "".to_string()
1658    };
1659    let var = self.var(&node.var);
1660    let expression = self.expression(&node.expression);
1661    if self.html {
1662      format!("<span class=\"mech-variable-define\"><span class=\"mech-variable-mutable\">{}</span>{}<span class=\"mech-variable-assign-op\">:=</span>{}</span>",mutable, var, expression)
1663    } else {
1664      format!("{}{} {} {}", mutable, var, ":=", expression)
1665    }
1666  }
1667
1668  pub fn statement(&mut self, node: &Statement) -> String {
1669    let s = match node {
1670      Statement::VariableDefine(var_def) => self.variable_define(var_def),
1671      Statement::OpAssign(op_asgn) => self.op_assign(op_asgn),
1672      Statement::VariableAssign(var_asgn) => self.variable_assign(var_asgn),
1673      Statement::TupleDestructure(tpl_dstrct) => self.tuple_destructure(tpl_dstrct),
1674      Statement::KindDefine(kind_def) => self.kind_define(kind_def),
1675      Statement::EnumDefine(enum_def) => self.enum_define(enum_def),
1676      _ => todo!(),
1677      //Statement::FsmDeclare(fsm_decl) => self.fsm_declare(fsm_decl, src),
1678    };
1679    if self.html {
1680      format!("<span class=\"mech-statement\">{}</span>",s)
1681    } else {
1682      format!("{}", s)
1683    }
1684  }
1685
1686  pub fn enum_define(&mut self, node: &EnumDefine) -> String {
1687    let name = node.name.to_string();
1688    let mut variants = "".to_string();
1689    for (i, variant) in node.variants.iter().enumerate() {
1690      if i == 0 {
1691        if self.html {
1692          variants = format!("<span class=\"mech-enum-variant\">{}</span>", self.enum_variant(variant));
1693        } else {
1694          variants = format!("{}", self.enum_variant(variant));
1695        }
1696      } else {
1697        if self.html {
1698          variants = format!("{}<span class=\"mech-enum-variant-sep\">|</span><span class=\"mech-enum-variant\">{}</span>", variants, self.enum_variant(variant));
1699        } else {
1700          variants = format!("{} | {}", variants, self.enum_variant(variant));
1701        }
1702      }
1703    }
1704    if self.html {
1705      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)
1706    } else {
1707      format!("<{}> := {}", name, variants)
1708    }
1709  }
1710
1711  pub fn enum_variant(&mut self, node: &EnumVariant) -> String {
1712    let name = node.name.to_string();
1713    let mut kind = "".to_string();
1714    match &node.value {
1715      Some(k) => {
1716        kind = self.kind_annotation(&k.kind);
1717      },
1718      None => {},
1719    }
1720    if self.html {
1721      format!("<span class=\"mech-enum-variant\"><span class=\"mech-enum-variant-name\">:{}</span><span class=\"mech-enum-variant-kind\">{}</span></span>",name,kind)
1722    } else {
1723      format!("{}{}", name, kind)
1724    }
1725  }
1726
1727  pub fn kind_define(&mut self, node: &KindDefine) -> String {
1728    let name = node.name.to_string();
1729    let kind = self.kind_annotation(&node.kind.kind);
1730    if self.html {
1731      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)
1732    } else {
1733      format!("<{}> := {}", name, kind)
1734    }
1735  }
1736
1737  pub fn tuple_destructure(&mut self, node: &TupleDestructure) -> String {
1738    let mut vars = "".to_string();
1739    for (i, var) in node.vars.iter().enumerate() {
1740      let v = var.to_string();
1741      if i == 0 {
1742        if self.html {
1743          let id = format!("{}:{}",hash_str(&v),self.interpreter_id);
1744          vars = format!("<span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span>",id,v);
1745        } else {
1746          vars = format!("{}", v);
1747        }
1748      } else {
1749        if self.html {
1750          let id = format!("{}:{}",hash_str(&v),self.interpreter_id);
1751          vars = format!("{}, <span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span>", vars, id, v);
1752        } else {
1753          vars = format!("{}, {}", vars, v);
1754        }
1755      }
1756    }
1757    let expression = self.expression(&node.expression);
1758    if self.html {
1759      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)
1760    } else {
1761      format!("({}) := {}", vars, expression)
1762    }
1763  }
1764
1765  pub fn variable_assign(&mut self, node: &VariableAssign) -> String {
1766    let target = self.slice_ref(&node.target);
1767    let expression = self.expression(&node.expression);
1768    if self.html {
1769      format!("<span class=\"mech-variable-assign\">
1770        <span class=\"mech-target\">{}</span>
1771        <span class=\"mech-assign-op\">=</span>
1772        <span class=\"mech-expression\">{}</span>
1773      </span>",target,expression)
1774    } else {
1775      format!("{} = {}", target, expression)
1776    }
1777  }
1778
1779  pub fn op_assign(&mut self, node: &OpAssign) -> String {
1780    let target = self.slice_ref(&node.target);
1781    let op = self.op_assign_op(&node.op);
1782    let expression = self.expression(&node.expression);
1783    if self.html {
1784      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)
1785    } else {
1786      format!("{} {} {}", target, op, expression)
1787    }
1788  }
1789
1790  pub fn op_assign_op(&mut self, node: &OpAssignOp) -> String {
1791    let op = match node {
1792      OpAssignOp::Add => "+=".to_string(),
1793      OpAssignOp::Div => "/=".to_string(),
1794      OpAssignOp::Exp => "^=".to_string(),
1795      OpAssignOp::Mod => "%=".to_string(),
1796      OpAssignOp::Mul => "*=".to_string(),
1797      OpAssignOp::Sub => "-=".to_string(),
1798    };
1799    if self.html {
1800      format!("<span class=\"mech-op-assign-op\">{}</span>",op)
1801    } else {
1802      format!("{}", op)
1803    }
1804  }
1805
1806  pub fn slice_ref(&mut self, node: &SliceRef) -> String {
1807    let name = node.name.to_string();
1808    let mut subscript = "".to_string();
1809    match &node.subscript {
1810      Some(subs) => {
1811        for sub in subs.iter() {
1812          let s = self.subscript(sub);
1813          subscript = format!("{}{}", subscript, s);
1814        }
1815      },
1816      None => {},
1817    }
1818    let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1819    if self.html {
1820      format!("<span class=\"mech-slice-ref\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
1821    } else {
1822      format!("{}{}", name, subscript)
1823    }
1824  }
1825
1826  pub fn expression(&mut self, node: &Expression) -> String {
1827    let e = match node {
1828      Expression::Var(var) => self.var(var),
1829      Expression::Formula(factor) => self.factor(factor),
1830      Expression::Literal(literal) => self.literal(literal),
1831      Expression::Structure(structure) => self.structure(structure),
1832      Expression::Slice(slice) => self.slice(slice),
1833      Expression::FunctionCall(function_call) => self.function_call(function_call),
1834      Expression::Range(range) => self.range_expression(range),
1835      Expression::SetComprehension(set_comp) => self.set_comprehension(set_comp),
1836      Expression::MatrixComprehension(matrix_comp) => self.matrix_comprehension(matrix_comp),
1837      Expression::Match(match_expr) => self.match_expression(match_expr),
1838      Expression::FsmPipe(fsm_pipe) => self.fsm_pipe(fsm_pipe),
1839      x => todo!("Unhandled Expression: {:#?}", x),
1840    };
1841    if self.html {
1842      format!("<span class=\"mech-expression\">{}</span>",e)
1843    } else {
1844      format!("{}", e)
1845    }
1846  }
1847
1848  pub fn pattern_array(&mut self, node: &PatternArray) -> String {
1849    let mut parts: Vec<String> = vec![];
1850    for p in &node.prefix {
1851      parts.push(self.pattern(p));
1852    }
1853    if let Some(spread) = &node.spread {
1854      parts.push("...".to_string());
1855      if let Some(binding) = &spread.binding {
1856        parts.push(self.pattern(binding));
1857      }
1858    }
1859    for p in &node.suffix {
1860      parts.push(self.pattern(p));
1861    }
1862    format!("[{}]", parts.join(" "))
1863  }
1864
1865  pub fn match_expression(&mut self, node: &MatchExpression) -> String {
1866    let source = self.expression(&node.source);
1867    let mut lines = vec![format!("{}?", source)];
1868    lines.push(if self.html {
1869      "<div class=\"mech-match-arms\">".to_string()
1870    } else {
1871      "".to_string()
1872    });
1873    for (ix, arm) in node.arms.iter().enumerate() {
1874      let last_arm = ix + 1 == node.arms.len();
1875      let (branch, terminal) = if last_arm {("└", ".")} else {("├", "")};
1876      let pattern = self.pattern(&arm.pattern);
1877      let guard = arm
1878        .guard
1879        .as_ref()
1880        .map(|expr| format!(", {}", self.expression(expr)))
1881        .unwrap_or_default();
1882      let expr = self.expression(&arm.expression);
1883      if self.html {
1884        lines.push(format!(
1885          "<div class=\"mech-match-arm\">\
1886            <span class=\"mech-match-branch\">{}</span> \
1887            <span class=\"mech-match-pattern\">{}{}</span> \
1888            <span class=\"mech-match-arrow\">⇒</span> \
1889            <span class=\"mech-match-expression\">{}</span>\
1890            <span class=\"mech-match-terminal\">{}</span>\
1891          </div>",
1892          branch, pattern, guard, expr, terminal
1893        ));
1894      } else {
1895        lines.push(format!("{}{}{} ⇒ {}{}", branch, pattern, guard, expr, terminal));
1896      }
1897    }
1898    lines.push(if self.html {
1899      "</div>".to_string()
1900    } else {
1901      "".to_string()
1902    });
1903    if self.html {
1904      format!(
1905        "<span class=\"mech-match-expression\">\
1906          <span class=\"mech-match-source\">{}<span class=\"mech-match-op\">?</span></span>{}\
1907          </span>",
1908        source,
1909        lines.iter().skip(1).cloned().collect::<Vec<_>>().join("")
1910      )
1911    } else {
1912      lines.join("\n")
1913    }
1914  }
1915
1916  pub fn fsm_instance(&mut self, node: &FsmInstance) -> String {
1917    let name = node.name.to_string();
1918    let mut args = "".to_string();
1919    match &node.args {
1920      Some(arguments) => {
1921        for (i, (ident, expr)) in arguments.iter().enumerate() {
1922          let e = self.expression(expr);
1923          let arg_str = match ident {
1924            Some(id) => format!("{}: {}", id.to_string(), e),
1925            None => e,
1926          };
1927          if i == 0 {
1928            args = format!("{}", arg_str);
1929          } else {
1930            args = format!("{}, {}", args, arg_str);
1931          }
1932        }
1933        if self.html {
1934          format!("<span class=\"mech-fsm-instance\"><span class=\"mech-fsm-name\">#{}</span><span class=\"mech-left-paren\">(</span><span class=\"mech-fsm-args\">{}</span><span class=\"mech-right-paren\">)</span></span>",name,args)
1935        } else {
1936          format!("#{}({})", name, args)
1937        }
1938      },
1939      None => {
1940        if self.html {
1941          format!("<span class=\"mech-fsm-instance\"><span class=\"mech-fsm-name\">#{}</span></span>",name)
1942        } else {
1943          format!("#{}", name)
1944        }
1945      },
1946    }
1947  }
1948
1949  pub fn fsm_pipe(&mut self, node: &FsmPipe) -> String {
1950    let start = self.fsm_instance(&node.start);
1951    let mut transitions = "".to_string();
1952    for (i, transition) in node.transitions.iter().enumerate() {
1953      let t = self.transition(transition);
1954      if i == 0 {
1955        transitions = format!("{}", t);
1956      } else {
1957        transitions = format!("{}{}", transitions, t);
1958      }
1959    }
1960    if self.html {
1961      format!("<span class=\"mech-fsm-pipe\"><span class=\"mech-fsm-pipe-start\">{}</span><span class=\"mech-fsm-pipe-transitions\">{}</span></span>",start,transitions)
1962    } else {
1963      format!("{}{}", start, transitions)
1964    }
1965  }
1966
1967  pub fn set_comprehension(&mut self, node: &SetComprehension) -> String {
1968    let expr = self.expression(&node.expression);
1969
1970    let qualifiers = node
1971      .qualifiers
1972      .iter()
1973      .map(|q| self.comprehension_qualifier(q))
1974      .collect::<Vec<_>>()
1975      .join(", ");
1976
1977    if self.html {
1978      format!(
1979        "<span class=\"mech-set-comprehension\">\
1980          <span class=\"mech-set-open\">{{</span>\
1981          <span class=\"mech-set-expression\">{}</span>\
1982          <span class=\"mech-set-bar\"> | </span>\
1983          <span class=\"mech-set-qualifiers\">{}</span>\
1984          <span class=\"mech-set-close\">}}</span>\
1985        </span>",
1986        expr, qualifiers
1987      )
1988    } else {
1989      format!("{{ {} | {} }}", expr, qualifiers)
1990    }
1991  }
1992
1993  pub fn matrix_comprehension(&mut self, node: &MatrixComprehension) -> String {
1994    let expr = self.expression(&node.expression);
1995    let quals = node.qualifiers
1996      .iter()
1997      .map(|q| self.comprehension_qualifier(q))
1998      .collect::<Vec<_>>()
1999      .join(", ");
2000
2001    if self.html {
2002      format!(
2003        "<span class=\"mech-matrix-comprehension\">\\
2004          <span class=\"mech-bracket start\">[</span>\\
2005          <span class=\"mech-comp-expr\">{}</span> \\
2006          <span class=\"mech-comp-bar\">|</span> \\
2007          <span class=\"mech-comp-quals\">{}</span>\\
2008          <span class=\"mech-bracket end\">]</span>\\
2009        </span>",
2010        expr, quals
2011      )
2012    } else {
2013      format!("[ {} | {} ]", expr, quals)
2014    }
2015  }
2016
2017  pub fn comprehension_qualifier(&mut self, node: &ComprehensionQualifier) -> String {
2018    match node {
2019      ComprehensionQualifier::Generator((pattern, expr)) => {
2020        self.generator(pattern, expr)
2021      }
2022      ComprehensionQualifier::Let(var_def) => {
2023        self.variable_define(var_def)
2024      }
2025      ComprehensionQualifier::Filter(expr) => {
2026        self.expression(expr)
2027      }
2028    }
2029  }
2030
2031  pub fn generator(&mut self, pattern: &Pattern, expr: &Expression) -> String {
2032    let p = self.pattern(pattern);
2033    let e = self.expression(expr);
2034
2035    if self.html {
2036      format!(
2037        "<span class=\"mech-generator\">\
2038          <span class=\"mech-generator-pattern\">{}</span>\
2039          <span class=\"mech-generator-arrow\"> &lt;- </span>\
2040          <span class=\"mech-generator-expression\">{}</span>\
2041        </span>",
2042        p, e
2043      )
2044    } else {
2045      format!("{} <- {}", p, e)
2046    }
2047  }
2048
2049  pub fn range_expression(&mut self, node: &RangeExpression) -> String {
2050    let start = self.factor(&node.start);
2051    let operator = match &node.operator {
2052      RangeOp::Inclusive => "..=".to_string(),
2053      RangeOp::Exclusive => "..".to_string(),
2054    };
2055    let terminal = self.factor(&node.terminal);
2056    let increment = match &node.increment {
2057      Some((op, factor)) => {
2058        let o = match op {
2059          RangeOp::Inclusive => "..=".to_string(),
2060          RangeOp::Exclusive => "..".to_string(),
2061        };
2062        let f = self.factor(factor);
2063        if self.html {
2064          format!("<span class=\"mech-range-increment\">{}{}</span>",o,f)
2065        } else {
2066          format!("{}{}", o, f)
2067        }
2068      },
2069      None => "".to_string(),
2070    };
2071    if self.html {
2072      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)
2073    } else {
2074      format!("{}{}{}{}", start, operator, terminal, increment)
2075    }
2076  }
2077
2078  pub fn function_call(&mut self, node: &FunctionCall) -> String {
2079    let name = node.name.to_string();
2080    let mut args = "".to_string();
2081    for (i, arg) in node.args.iter().enumerate() {
2082      let a = self.argument(arg);
2083      if i == 0 {
2084        args = format!("{}", a);
2085      } else {
2086        args = format!("{}, {}", args, a);
2087      }
2088    }
2089    let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
2090    if self.html {
2091      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)
2092    } else {
2093      format!("{}({})", name, args)
2094    }
2095  }
2096
2097  pub fn argument(&mut self, node: &(Option<Identifier>, Expression)) -> String {
2098    let (name, expr) = node;
2099    let n = match name {
2100      Some(ident) => ident.to_string(),
2101      None => "".to_string(),
2102    };
2103    let e = self.expression(expr);
2104    if self.html {
2105      format!("<span class=\"mech-argument\"><span class=\"mech-argument-name\">{}</span><span class=\"mech-argument-expression\">{}</span></span>",n,e)
2106    } else {
2107      format!("{}{}", n, e)
2108    }
2109  }
2110
2111  pub fn slice(&mut self, node: &Slice) -> String {
2112    let name = node.name.to_string();
2113    let mut subscript = "".to_string();
2114    for (i, sub) in node.subscript.iter().enumerate() {
2115      let s = self.subscript(sub);
2116      subscript = format!("{}{}", subscript, s);
2117    }
2118    let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
2119    if self.html {
2120      format!("<span class=\"mech-slice\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
2121    } else {
2122      format!("{}{}", name, subscript)
2123    }
2124  }
2125
2126  pub fn subscript(&mut self, node: &Subscript) -> String {
2127    match node {
2128      Subscript::Bracket(subs) => self.bracket(subs),
2129      Subscript::Formula(factor) => self.factor(factor),
2130      Subscript::All => self.all(),
2131      Subscript::Dot(ident) => self.dot(ident),
2132      Subscript::Swizzle(idents) => self.swizzle(idents),
2133      Subscript::Range(range) => self.range_expression(range),
2134      Subscript::Brace(subs) => self.brace(subs),
2135      Subscript::DotInt(real) => self.dot_int(real),
2136    }
2137  }
2138
2139  pub fn brace(&mut self, node: &Vec<Subscript>) -> String {
2140    let mut src = "".to_string();
2141    for (i, sub) in node.iter().enumerate() {
2142      let s = self.subscript(sub);
2143      if i == 0 {
2144        src = format!("{}", s);
2145      } else {
2146        src = format!("{},{}", src, s);
2147      }
2148    }
2149    if self.html {
2150      format!("<span class=\"mech-brace\">{{{}}}</span>",src)
2151    } else {
2152      format!("{{{}}}",src)
2153    }
2154  }
2155
2156  pub fn swizzle(&mut self, node: &Vec<Identifier>) -> String {
2157    let mut src = "".to_string();
2158    for (i, ident) in node.iter().enumerate() {
2159      let s = self.dot(ident);
2160      if i == 0 {
2161        src = format!("{}", s);
2162      } else {
2163        src = format!("{},{}", src, s);
2164      }
2165    }
2166    if self.html {
2167      format!("<span class=\"mech-swizzle\">{}</span>",src)
2168    } else {
2169      format!("{}",src)
2170    }
2171  }
2172
2173  pub fn dot_int(&mut self, node: &RealNumber) -> String {
2174    let node_str = match node {
2175      RealNumber::Integer(tkn) => tkn.to_string(),
2176      _ => "".to_string(),
2177    };
2178    if self.html {
2179      format!(".<span class=\"mech-dot-int\">{}</span>",node_str)
2180    } else {
2181      format!(".{}",node_str)
2182    }
2183  } 
2184
2185  pub fn dot(&mut self, node: &Identifier) -> String {
2186    if self.html {
2187      format!(".<span class=\"mech-dot\">{}</span>",node.to_string())
2188    } else {
2189      format!(".{}",node.to_string())
2190    }
2191  }
2192
2193  pub fn all(&mut self) -> String {
2194    if self.html {
2195      format!("<span class=\"mech-all\">:</span>")
2196    } else {
2197      ":".to_string()
2198    }
2199  }
2200
2201  pub fn bracket(&mut self, node: &Vec<Subscript>) -> String {
2202    let mut src = "".to_string();
2203    for (i, sub) in node.iter().enumerate() {
2204      let s = self.subscript(sub);
2205      if i == 0 {
2206        src = format!("{}", s);
2207      } else {
2208        src = format!("{},{}", src, s);
2209      }
2210    }
2211    if self.html {
2212      format!("<span class=\"mech-bracket\">[{}]</span>",src)
2213    } else {
2214      format!("[{}]",src)
2215    }
2216  }
2217
2218  pub fn structure(&mut self, node: &Structure) -> String {
2219    let s = match node {
2220      Structure::Matrix(matrix) => self.matrix(matrix),
2221      Structure::Record(record) => self.record(record),
2222      Structure::Empty => "_".to_string(),
2223      Structure::Table(table) => self.table(table),
2224      Structure::Tuple(tuple) => self.tuple(tuple),
2225      Structure::TupleStruct(tuple_struct) => self.tuple_struct(tuple_struct),
2226      Structure::Set(set) => self.set(set),
2227      Structure::Map(map) => self.map(map),
2228    };
2229    if self.html {
2230      format!("<span class=\"mech-structure\">{}</span>",s)
2231    } else {
2232      format!("{}", s)
2233    }
2234  }
2235
2236  pub fn map(&mut self, node: &Map) -> String {
2237    let mut src = "".to_string();
2238    for (i, mapping) in node.elements.iter().enumerate() {
2239      let m = self.mapping(mapping);
2240      if i == 0 {
2241        src = format!("{}", m);
2242      } else {
2243        src = format!("{}, {}", src, m);
2244      }
2245    }
2246    if self.html {
2247      format!("<span class=\"mech-map\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
2248    } else {
2249      format!("{{{}}}", src)
2250    }
2251  }
2252
2253  pub fn mapping(&mut self, node: &Mapping) -> String {
2254    let key = self.expression(&node.key);
2255    let value = self.expression(&node.value);
2256    if self.html {
2257      format!("<span class=\"mech-mapping\"><span class=\"mech-key\">{}</span><span class=\"mech-colon-op\">:</span><span class=\"mech-value\">{}</span></span>",key,value)
2258    } else {
2259      format!("{}: {}", key, value)
2260    }
2261  }
2262
2263  pub fn set(&mut self, node: &Set) -> String {
2264    let mut src = "".to_string();
2265    for (i, element) in node.elements.iter().enumerate() {
2266      let e = self.expression(element);
2267      if i == 0 {
2268        src = format!("{}", e);
2269      } else {
2270        src = format!("{}, {}", src, e);
2271      }
2272    }
2273    if self.html {
2274      format!("<span class=\"mech-set\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
2275    } else {
2276      format!("{{{}}}", src)
2277    }
2278  }
2279
2280  pub fn tuple_struct(&mut self, node: &TupleStruct) -> String {
2281    let name = node.name.to_string();
2282    let value = self.expression(&node.value);
2283    if self.html {
2284      format!("
2285        <span class=\"mech-tuple-struct\">
2286        <span class=\"mech-tuple-struct-sigil\">:</span>
2287        <span class=\"mech-tuple-struct-name\">{}</span>
2288        <span class=\"mech-left-paren\">(</span>
2289        <span class=\"mech-tuple-struct-value\">{}</span>
2290        <span class=\"mech-right-paren\">)</span>
2291      </span>", name, value)
2292    } else {
2293      format!("{}{}", name, value)
2294    }
2295  }
2296
2297  pub fn table(&mut self, node: &Table) -> String {
2298    let header = self.table_header(&node.header);
2299    let mut rows = "".to_string();
2300    for (i, row) in node.rows.iter().enumerate() {
2301      let r = self.table_row(row);
2302      if i == 0 {
2303        rows = format!("{}", r);
2304      } else {
2305        rows = format!("{}{}", rows, r);
2306      }
2307    }
2308    if self.html {
2309      format!("<table class=\"mech-table\">{}<tbody class=\"mech-table-body\">{}</tbody></table>",header,rows)
2310    } else {
2311      format!("{}{}", header, rows)
2312    }
2313  }
2314
2315  pub fn table_header(&mut self, node: &TableHeader) -> String {
2316    let mut src = "".to_string();
2317    for (i, field) in node.0.iter().enumerate() {
2318      let f = self.field(field);
2319      if self.html {
2320        src = format!("{}<th class=\"mech-table-field\">{}</th>",src, f);
2321      } else {
2322        src = format!("{}{}",src, f);
2323      }
2324    }
2325    if self.html {
2326      format!("<thead class=\"mech-table-header\"><tr>{}</tr></thead>",src)
2327    } else {
2328      src
2329    }
2330  }
2331
2332  pub fn table_row(&mut self, node: &TableRow) -> String {
2333    let mut src = "".to_string();
2334    for (i, column) in node.columns.iter().enumerate() {
2335      let c = self.table_column(column);
2336      if i == 0 {
2337        src = format!("{}", c);
2338      } else {
2339        src = format!("{} {}", src, c);
2340      }
2341    }
2342    if self.html {
2343      format!("<tr class=\"mech-table-row\">{}</tr>",src)
2344    } else {
2345      src
2346    }
2347  }
2348
2349  pub fn table_column(&mut self, node: &TableColumn) -> String {
2350    let element = self.expression(&node.element);
2351    if self.html {
2352      format!("<td class=\"mech-table-column\">{}</td>",element)
2353    } else {
2354      element
2355    }
2356  }
2357
2358  pub fn field(&mut self, node: &Field) -> String {
2359    let name = node.name.to_string();
2360    let kind = if let Some(kind) = &node.kind {
2361      self.kind_annotation(&kind.kind)
2362    } else {
2363      "".to_string()
2364    };
2365    if self.html {
2366      format!("<div class=\"mech-field\"><span class=\"mech-field-name\">{}</span><span class=\"mech-field-kind\">{}</span></div>",name,kind)
2367    } else {
2368      format!("{}: {}", name, kind)
2369    }
2370  }
2371
2372  pub fn tuple(&mut self, node: &Tuple) -> String {
2373    let mut src = "".to_string();
2374    for (i, element) in node.elements.iter().enumerate() {
2375      let e = self.expression(element);
2376      if i == 0 {
2377        src = format!("{}", e);
2378      } else {
2379        src = format!("{},{}", src, e);
2380      }
2381    }
2382    if self.html {
2383      format!("<span class=\"mech-tuple\"><span class=\"mech-start-paren\">(</span>{}<span class=\"mech-end-paren\">)</span></span>",src)
2384    } else {
2385      format!("({})", src)
2386    }
2387  }
2388
2389  pub fn record(&mut self, node: &Record) -> String {
2390    let mut src = "".to_string();
2391    for (i, binding) in node.bindings.iter().enumerate() {
2392      let b = self.binding(binding);
2393      if i == 0 {
2394        src = format!("{}", b);
2395      } else {
2396        src = format!("{}, {}", src, b);
2397      }
2398    }
2399    if self.html {
2400      format!("<span class=\"mech-record\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
2401    } else {
2402      format!("{{{}}}",src)
2403    }
2404  }
2405
2406  pub fn binding(&mut self, node: &Binding) -> String {
2407    let name = node.name.to_string();
2408    let kind = if let Some(kind) = &node.kind {
2409      self.kind_annotation(&kind.kind)
2410    } else {
2411      "".to_string()
2412    };
2413    let value = self.expression(&node.value);
2414    if self.html {
2415      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)
2416    } else {
2417      format!("{}{}: {}", name, kind, value)
2418    }
2419  }
2420
2421  pub fn matrix(&mut self, node: &Matrix) -> String {
2422    let mut src = "".to_string();
2423    if node.rows.len() == 0 {
2424      if self.html {
2425        return format!("<span class=\"mech-matrix empty\"><span class=\"mech-bracket start\">[</span><span class=\"mech-bracket end\">]</span></span>");
2426      } else {
2427        return format!("[]");
2428      }
2429    }
2430    let column_count = node.rows[0].columns.len(); // Assume all rows have the same number of columns
2431
2432    for col_index in 0..column_count {
2433        let mut column_elements = Vec::new();
2434        for row in &node.rows {
2435            column_elements.push(&row.columns[col_index]);
2436        }
2437        let c = self.matrix_column_elements(&column_elements);
2438
2439        if col_index == 0 {
2440            src = format!("{}", c);
2441        } else {
2442            src = format!("{} {}", src, c);
2443        }
2444    }
2445
2446    if self.html {
2447        format!("<span class=\"mech-matrix\"><span class=\"mech-bracket start\">[</span>{}<span class=\"mech-bracket end\">]</span></span>", src)
2448    } else {
2449        format!("[{}]", src)
2450    }
2451}
2452
2453pub fn matrix_column_elements(&mut self, column_elements: &[&MatrixColumn]) -> String {
2454    let mut src = "".to_string();
2455    for (i, cell) in column_elements.iter().enumerate() {
2456        let c = self.matrix_column(cell);
2457        if i == 0 {
2458            src = format!("{}", c);
2459        } else {
2460            src = format!("{} {}", src, c);
2461        }
2462    }
2463    if self.html {
2464        format!("<div class=\"mech-matrix-column\">{}</div>", src)
2465    } else {
2466        src
2467    }
2468}
2469
2470
2471  pub fn matrix_row(&mut self, node: &MatrixRow) -> String {
2472    let mut src = "".to_string();
2473    for (i, cell) in node.columns.iter().enumerate() {
2474      let c = self.matrix_column(cell);
2475      if i == 0 {
2476        src = format!("{}", c);
2477      } else { 
2478        src = format!("{} {}", src, c);
2479      }
2480    }
2481    if self.html {
2482      format!("<div class=\"mech-matrix-row\">{}</div>",src)
2483    } else {
2484      src
2485    }
2486  }
2487
2488  pub fn matrix_column(&mut self, node: &MatrixColumn) -> String {
2489    let element = self.expression(&node.element);
2490    if self.html {
2491      format!("<span class=\"mech-matrix-element\">{}</span>",element)
2492    } else {
2493      element
2494    }    
2495  }  
2496
2497  pub fn var(&mut self, node: &Var) -> String {
2498    let annotation = if let Some(kind) = &node.kind {
2499      self.kind_annotation(&kind.kind)
2500    } else {
2501      "".to_string()
2502    };
2503    let name = &node.name.to_string();
2504    let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
2505    if self.html {
2506      format!("<span class=\"mech-var-name mech-clickable\" id=\"{}\">{}</span>{}", id, node.name.to_string(), annotation)
2507    } else {
2508      format!("{}{}", node.name.to_string(), annotation)
2509    }
2510  }
2511
2512  pub fn kind_annotation(&mut self, node: &Kind) -> String {
2513    let kind = self.kind(node);
2514    if self.html {
2515      format!("<span class=\"mech-kind-annotation\">&lt;{}&gt;</span>",kind)
2516    } else {
2517      format!("<{}>", kind)
2518    }
2519  }
2520
2521  pub fn kind(&mut self, node: &Kind) -> String {
2522    let annotation = match node {
2523      Kind::Kind(kind) => {
2524        let kind_kind = self.kind(kind);
2525        if self.html {
2526          format!("<span class=\"mech-kind-annotation\">&lt;{}&gt;</span>",kind_kind)
2527        } else {
2528          format!("<{}>", kind_kind)
2529        }
2530      },
2531      Kind::Option(kind) => {
2532        let k = self.kind(kind);
2533        if self.html {
2534          format!("{}<span class=\"mech-option-question\">?</span>", k)
2535        } else {
2536          format!("{}?", k)
2537        }
2538      },
2539      Kind::Set(kind,size) => {
2540        let k = self.kind(kind);
2541        let size_str = match size{
2542          Some(size) => {
2543            let size_ltrl = self.literal(size);
2544            format!(":{}", size_ltrl)
2545          }
2546          None => "".to_string(),
2547        };
2548        format!("{{{}}}{}", k, size_str)
2549      },
2550      Kind::Any => "*".to_string(),
2551      Kind::Scalar(ident) => ident.to_string(),
2552      Kind::Empty => "_".to_string(),
2553      Kind::Atom(ident) => format!(":{}",ident.to_string()),
2554      Kind::Tuple(kinds) => {
2555        let mut src = "".to_string();
2556        for (i, kind) in kinds.iter().enumerate() {
2557          let k = self.kind(kind);
2558          if i == 0 {
2559            src = format!("{}", k);
2560          } else {
2561            src = format!("{},{}", src, k);
2562          }
2563        }
2564        format!("({})", src)
2565      },
2566      Kind::Matrix((kind, literals)) => {
2567        let mut src = "".to_string();
2568        let k = self.kind(kind);
2569        src = format!("{}", k);
2570        let mut src2 = "".to_string();
2571        for (i, literal) in literals.iter().enumerate() {
2572          let l = self.literal(literal);
2573          if i == 0 {
2574            src2 = format!(":{}", l);
2575          } else {
2576            src2 = format!("{},{}", src2, l);
2577          }
2578        }
2579        format!("[{}]{}", src, src2)
2580      },
2581      Kind::Record(kinds) => {
2582        let mut src = "".to_string();
2583        for (i, (ident, kind)) in kinds.iter().enumerate() {
2584          let k = self.kind(kind);
2585          let ident_s = ident.to_string();
2586          if i == 0 {
2587            src = format!("{}&lt;{}&gt;", ident_s, k);
2588          } else {
2589            src = format!("{},{}&lt;{}&gt;", src, ident_s, k);
2590          }
2591        }
2592        format!("{{{}}}", src)
2593      },
2594      Kind::Table((kinds, literal)) => {
2595        let mut src = "".to_string();
2596        for (i, (ident,kind)) in kinds.iter().enumerate() {
2597          let k = self.kind(kind);
2598          let ident_s = ident.to_string();
2599          if i == 0 {
2600            src = format!("{}&lt;{}&gt;", ident_s, k);
2601          } else {
2602            src = format!("{},{}&lt;{}&gt;", src, ident_s, k);
2603          }
2604        }
2605        let mut src2 = "".to_string();
2606        let sz = match &**literal {
2607          Literal::Empty(_) => "".to_string(),
2608          _ => format!(":{}", self.literal(literal)),
2609        };
2610        format!("|{}|{}", src, sz)
2611      },
2612      Kind::Map(kind1, kind2) => {
2613        let k1 = self.kind(kind1);
2614        let k2 = self.kind(kind2);
2615        format!("{{{}:{}}}", k1, k2)
2616      },
2617    };
2618    if self.html {
2619      format!("<span class=\"mech-kind\">{}</span>",annotation)
2620    } else {
2621      annotation
2622    }
2623  }
2624
2625  pub fn factor(&mut self, node: &Factor) -> String {
2626    let f = match node {
2627      Factor::Term(term) => self.term(term),
2628      Factor::Expression(expr) => self.expression(expr),
2629      Factor::Parenthetical(paren) => {
2630        if self.html {
2631          format!("<span class=\"mech-parenthetical\">({})</span>", self.factor(paren))
2632        } else {
2633          format!("({})", self.factor(&paren))
2634        }
2635      }
2636      Factor::Negate(factor) => {
2637        if self.html {
2638          format!("<span class=\"mech-negate-op\">-</span><span class=\"mech-negate\">{}</span>", self.factor(factor))
2639        } else {
2640          format!("-{}", self.factor(factor))
2641        }
2642      }
2643      Factor::Not(factor) => {
2644        if self.html {
2645          format!("<span class=\"mech-not-op\">¬</span><span class=\"mech-not\">{}</span>", self.factor(factor))
2646        } else {
2647          format!("¬{}", self.factor(factor))
2648        }
2649      }
2650      Factor::Transpose(factor) => {
2651        if self.html {
2652          format!("<span class=\"mech-transpose\">{}</span><span class=\"mech-transpose-op\">'</span>", self.factor(factor))
2653        } else {
2654          format!("{}'", self.factor(factor))
2655        }
2656      }
2657    };
2658    if self.html {
2659      format!("<span class=\"mech-factor\">{}</span>",f)
2660    } else {
2661      f
2662    }
2663  }
2664
2665  pub fn term(&mut self, node: &Term) -> String {
2666    let mut src = self.factor(&node.lhs);
2667    for (formula_operator, rhs) in &node.rhs {
2668      let op = self.formula_operator(formula_operator);
2669      let rhs = self.factor(rhs);
2670      src = format!("{}{}{}", src, op, rhs);
2671    }
2672    if self.html {
2673      format!("<span class=\"mech-term\">{}</span>",src)
2674    } else {
2675      src
2676    }
2677  }
2678
2679  pub fn formula_operator(&mut self, node: &FormulaOperator) -> String {
2680    let f = match node {
2681      FormulaOperator::AddSub(op) => self.add_sub_op(op),
2682      FormulaOperator::MulDiv(op) => self.mul_div_op(op),
2683      FormulaOperator::Power(op) => self.power_op(op),
2684      FormulaOperator::Vec(op) => self.vec_op(op),
2685      FormulaOperator::Comparison(op) => self.comparison_op(op),
2686      FormulaOperator::Logic(op) => self.logic_op(op),
2687      FormulaOperator::Table(op) => self.table_op(op),
2688      FormulaOperator::Set(op) => self.set_op(op),
2689    };
2690    if self.html {
2691      format!("<span class=\"mech-formula-operator\">{}</span>",f)
2692    } else {
2693      format!(" {} ", f)
2694    }
2695  }
2696
2697  pub fn table_op(&mut self, node: &TableOp) -> String {
2698    match node {
2699      TableOp::InnerJoin => "⋈".to_string(),
2700      TableOp::LeftOuterJoin => "⟕".to_string(),
2701      TableOp::RightOuterJoin => "⟖".to_string(),
2702      TableOp::FullOuterJoin => "⟗".to_string(),
2703      TableOp::LeftSemiJoin => "⋉".to_string(),
2704      TableOp::LeftAntiJoin => "▷".to_string(),
2705    }
2706  }
2707
2708  pub fn set_op(&mut self, node: &SetOp) -> String {
2709    match node {
2710      SetOp::Union => "∪".to_string(),
2711      SetOp::Intersection => "∩".to_string(),
2712      SetOp::Difference => "∖".to_string(),
2713      SetOp::Complement => "∁".to_string(),
2714      SetOp::Subset => "⊂".to_string(),
2715      SetOp::Superset => "⊃".to_string(),
2716      SetOp::ProperSubset => "⊊".to_string(),
2717      SetOp::ProperSuperset => "⊋".to_string(),
2718      SetOp::ElementOf => "∈".to_string(),
2719      SetOp::NotElementOf => "∉".to_string(),
2720      SetOp::SymmetricDifference => "Δ".to_string(),
2721    }
2722  }
2723
2724  pub fn add_sub_op(&mut self, node: &AddSubOp) -> String {
2725    match node {
2726      AddSubOp::Add => "+".to_string(),
2727      AddSubOp::Sub => "-".to_string(),
2728    }
2729  }
2730
2731  pub fn mul_div_op(&mut self, node: &MulDivOp) -> String {
2732    match node {
2733      MulDivOp::Div => "/".to_string(),
2734      MulDivOp::Mod => "%".to_string(),
2735      MulDivOp::Mul => "*".to_string(),
2736    }
2737  }
2738
2739  pub fn power_op(&mut self, node: &PowerOp) -> String {
2740    match node {
2741      PowerOp::Pow => "^".to_string(),
2742    }
2743  }
2744
2745  pub fn vec_op(&mut self, node: &VecOp) -> String {
2746    match node {
2747      VecOp::MatMul => "**".to_string(),
2748      VecOp::Solve => "\\".to_string(),
2749      VecOp::Cross => "×".to_string(),
2750      VecOp::Dot => "·".to_string(),
2751    }
2752  }
2753
2754  pub fn comparison_op(&mut self, node: &ComparisonOp) -> String {
2755    match node {
2756      ComparisonOp::Equal => "⩵".to_string(),
2757      ComparisonOp::StrictEqual => "=:=".to_string(),
2758      ComparisonOp::StrictNotEqual => "=/=".to_string(),
2759      ComparisonOp::NotEqual => "≠".to_string(),
2760      ComparisonOp::GreaterThan => ">".to_string(),
2761      ComparisonOp::GreaterThanEqual => "≥".to_string(),
2762      ComparisonOp::LessThan => "<".to_string(),
2763      ComparisonOp::LessThanEqual => "≤".to_string(),
2764    }
2765  }
2766
2767  pub fn logic_op(&mut self, node: &LogicOp) -> String {
2768    match node {
2769      LogicOp::And => "&&".to_string(),
2770      LogicOp::Or => "||".to_string(),
2771      LogicOp::Xor => "⊻".to_string(),
2772      LogicOp::Not => "¬".to_string(),
2773    }
2774  }
2775
2776  pub fn boolean(&mut self, node: &Token) -> String {
2777    let b = node.to_string();
2778    if self.html {
2779      format!("<span class=\"mech-boolean\">{}</span>", b)
2780    } else {
2781      b
2782    }
2783  }
2784
2785  pub fn empty(&mut self, node: &Token) -> String {
2786    let e = node.to_string();
2787    if self.html {
2788      format!("<span class=\"mech-empty\">{}</span>", e)
2789    } else {
2790      e
2791    }
2792  }
2793
2794  pub fn literal(&mut self, node: &Literal) -> String {
2795    let l = match node {
2796      Literal::Empty(tkn) => self.empty(tkn),
2797      Literal::Boolean(tkn) => self.boolean(tkn),
2798      Literal::Number(num) => self.number(num),
2799      Literal::String(mech_string) => self.string(mech_string),
2800      Literal::Atom(atm) => self.atom(atm),
2801      Literal::Kind(knd) => self.kind_annotation(knd),
2802      Literal::TypedLiteral((boxed_literal, kind_annotation)) => {
2803        let literal = self.literal(boxed_literal);
2804        let annotation = self.kind_annotation(&kind_annotation.kind);
2805        format!("{}{}", literal, annotation)
2806      }
2807    };
2808    if self.html {
2809      format!("<span class=\"mech-literal\">{}</span>",l)
2810    } else {
2811      l
2812    }
2813  }
2814
2815  pub fn atom(&mut self, node: &Atom) -> String {
2816    if self.html {
2817      format!("<span class=\"mech-atom\"><span class=\"mech-atom-name\">:{}</span></span>",node.name.to_string())
2818    } else {
2819      format!(":{}", node.name.to_string())
2820    }
2821  }
2822
2823  pub fn string(&mut self, node: &MechString) -> String {
2824    if self.html {
2825      format!("<span class=\"mech-string\">\"{}\"</span>", node.text.to_string())
2826    } else {
2827      format!("\"{}\"", node.text.to_string())
2828    }
2829  }
2830
2831  pub fn number(&mut self, node: &Number) -> String {
2832    let n = match node {
2833      Number::Real(real) => self.real_number(real),
2834      Number::Complex(complex) => self.complex_numer(complex),
2835    };
2836    if self.html {
2837      format!("<span class=\"mech-number\">{}</span>",n)
2838    } else {
2839      n
2840    }
2841  }
2842
2843  pub fn real_number(&mut self, node: &RealNumber) -> String {
2844    match node {
2845      RealNumber::Negated(real_number) => format!("-{}", self.real_number(real_number)),
2846      RealNumber::Integer(token) => token.to_string(),
2847      RealNumber::Float((whole, part)) => format!("{}.{}", whole.to_string(), part.to_string()),
2848      RealNumber::Decimal(token) => format!("0d{}", token.to_string()),
2849      RealNumber::Hexadecimal(token) => format!("0x{}", token.to_string()),
2850      RealNumber::Octal(token) => format!("0o{}", token.to_string()),
2851      RealNumber::Binary(token) => format!("0b{}", token.to_string()),
2852      RealNumber::Scientific(((whole, part), (sign, ewhole, epart))) => format!("{}.{}e{}{}.{}", whole.to_string(), part.to_string(), if *sign { "-" } else { "+" }, ewhole.to_string(), epart.to_string()),
2853      RealNumber::Rational((numerator, denominator)) => format!("{}/{}", numerator.to_string(), denominator.to_string()),
2854      RealNumber::TypedInteger((token, kind_annotation)) => {
2855        let num = token.to_string();
2856        let annotation = &kind_annotation.kind.tokens().iter().map(|tkn| tkn.to_string()).collect::<Vec<String>>().join("");
2857        format!("{}{}", num, annotation)
2858      }
2859    }
2860  }
2861
2862  pub fn complex_numer(&mut self, node: &C64Node) -> String {
2863    let real = if let Some(real) = &node.real {
2864      let num = self.real_number(&real);
2865      format!("{}+", num)
2866    } else {
2867      "".to_string()
2868    };
2869    let im = self.imaginary_number(&node.imaginary);
2870    format!("{}{}", real, im)
2871  }
2872
2873  pub fn imaginary_number(&mut self, node: &ImaginaryNumber) -> String {
2874    let real = self.real_number(&node.number);
2875    format!("{}i", real)
2876  }
2877
2878  pub fn humanize_html(input: String) -> String {
2879    let mut result = String::new();
2880    let mut indent_level = 0;
2881    let mut in_special_tag = false;
2882    let mut special_tag = "";
2883    let chars: Vec<char> = input.chars().collect();
2884    let mut i = 0;
2885    
2886    let self_closing_tags = HashSet::from([
2887      "area", "base", "br", "col", "embed", "hr", "img", "input", 
2888      "link", "meta", "param", "source", "track", "wbr"
2889    ]);
2890    
2891    fn matches_tag(chars: &[char], pos: usize, tag: &str) -> bool {
2892      let tag_chars: Vec<char> = tag.chars().collect();
2893      pos + tag_chars.len() <= chars.len() && chars[pos..pos+tag_chars.len()] == tag_chars[..]
2894    }
2895    
2896    while i < chars.len() {
2897      // Handle <pre> and <code> tags
2898      if !in_special_tag && (matches_tag(&chars, i, "<pre") || matches_tag(&chars, i, "<code")) {
2899        in_special_tag = true;
2900        special_tag = if matches_tag(&chars, i, "<pre") { "pre" } else { "code" };
2901        
2902        result.push('\n');
2903        result.push_str(&"  ".repeat(indent_level));
2904        
2905        // Add the opening tag
2906        while i < chars.len() && chars[i] != '>' {
2907          result.push(chars[i]);
2908          i += 1;
2909        }
2910        result.push('>');
2911        i += 1;
2912        indent_level += 1;
2913        
2914        // Process content
2915        let start = i;
2916        while i < chars.len() && !matches_tag(&chars, i, &format!("</{}>", special_tag)) {
2917          i += 1;
2918        }
2919        
2920        // Add the content as is
2921        result.extend(chars[start..i].iter());
2922        
2923        // Add the closing tag
2924        if i < chars.len() {
2925          result.push_str(&format!("</{}>", special_tag));
2926          i += special_tag.len() + 3;
2927          in_special_tag = false;
2928          indent_level -= 1;
2929        }
2930      // Open tag
2931      } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] != '/' {
2932        let tag_start = i + 1;
2933        let mut j = tag_start;
2934        
2935        // Get tag name
2936        while j < chars.len() && chars[j].is_alphanumeric() {
2937          j += 1;
2938      }
2939        
2940        let tag_name: String = chars[tag_start..j].iter().collect();
2941        let is_self_closing = self_closing_tags.contains(tag_name.as_str());
2942        
2943        // Add newline and indentation
2944        result.push('\n');
2945        result.push_str(&"  ".repeat(indent_level));
2946        
2947        // Add the tag
2948        while i < chars.len() && chars[i] != '>' {
2949          result.push(chars[i]);
2950          i += 1;
2951        }
2952        result.push('>');
2953        i += 1;
2954        
2955        if !is_self_closing {
2956          indent_level += 1;
2957        }
2958      // Close tag
2959      } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] == '/' {
2960        indent_level = indent_level.saturating_sub(1);
2961        
2962        result.push('\n');
2963        result.push_str(&"  ".repeat(indent_level));
2964        
2965        while i < chars.len() && chars[i] != '>' {
2966            result.push(chars[i]);
2967            i += 1;
2968        }
2969        result.push('>');
2970        i += 1;
2971      // Regular text content
2972      } else if !in_special_tag {
2973        let start = i;
2974        while i < chars.len() && chars[i] != '<' {
2975          i += 1;
2976        }
2977        
2978        let content: String = chars[start..i].iter().collect();
2979        if !content.trim().is_empty() {
2980          result.push('\n');
2981          result.push_str(&"  ".repeat(indent_level));
2982          result.push_str(&content);
2983      }
2984      // Inside <pre> or <code>
2985      } else {
2986        result.push(chars[i]);
2987        i += 1;
2988      }
2989    }
2990    result.push('\n');
2991    result
2992  }
2993}