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