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