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