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