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