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