mech_syntax/
mechdown.rs

1#[macro_use]
2use crate::*;
3
4#[cfg(not(feature = "no-std"))] use core::fmt;
5#[cfg(feature = "no-std")] use alloc::fmt;
6#[cfg(feature = "no-std")] use alloc::string::String;
7#[cfg(feature = "no-std")] use alloc::vec::Vec;
8use nom::{
9  IResult,
10  branch::alt,
11  sequence::tuple as nom_tuple,
12  combinator::{opt, eof, peek},
13  multi::{many1, many_till, many0, separated_list1,separated_list0},
14  bytes::complete::{take_until, take_while},
15  Err,
16  Err::Failure
17};
18
19use std::collections::HashMap;
20use colored::*;
21
22use crate::*;
23
24// Mechdown
25// ============================================================================
26
27// title := text+, new_line, equal+, (space|tab)*, whitespace* ;
28pub fn title(input: ParseString) -> ParseResult<Title> {
29  let (input, mut text) = many1(text)(input)?;
30  let (input, _) = new_line(input)?;
31  let (input, _) = many1(equal)(input)?;
32  let (input, _) = many0(space_tab)(input)?;
33  let (input, _) = new_line(input)?;
34  let (input, _) = many0(space_tab)(input)?;
35  let (input, _) = whitespace0(input)?;
36  let mut title = Token::merge_tokens(&mut text).unwrap();
37  title.kind = TokenKind::Title;
38  Ok((input, Title{text: title}))
39}
40
41pub struct MarkdownTableHeader {
42  pub header: Vec<(Token, Token)>,
43}
44
45pub fn no_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
46  let (input, _) = many1(dash)(input)?;
47  Ok((input, ColumnAlignment::Left))
48}
49
50pub fn left_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
51  let (input, _) = colon(input)?;
52  let (input, _) = many1(dash)(input)?;
53  Ok((input, ColumnAlignment::Left))
54}
55
56pub fn right_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
57  let (input, _) = many1(dash)(input)?;
58  let (input, _) = colon(input)?;
59  Ok((input, ColumnAlignment::Right))
60}
61
62pub fn center_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
63  let (input, _) = colon(input)?;
64  let (input, _) = many1(dash)(input)?;
65  let (input, _) = colon(input)?;
66  Ok((input, ColumnAlignment::Center))
67}
68
69pub fn alignment_separator(input: ParseString) -> ParseResult<ColumnAlignment> {
70  let (input, _) = many0(space_tab)(input)?;
71  let (input, separator) = alt((center_alignment, left_alignment, right_alignment, no_alignment))(input)?;
72  let (input, _) = many0(space_tab)(input)?;
73  Ok((input, separator))
74}
75
76pub fn markdown_table(input: ParseString) -> ParseResult<MarkdownTable> {
77  let (input, _) = whitespace0(input)?;
78  let (input, table) = alt((markdown_table_with_header, markdown_table_no_header))(input)?;
79  Ok((input, table))
80}
81
82pub fn markdown_table_with_header(input: ParseString) -> ParseResult<MarkdownTable> {
83  let (input, (header,alignment)) = markdown_table_header(input)?;
84  let (input, rows) = many1(markdown_table_row)(input)?;
85  Ok((input, MarkdownTable{header, rows, alignment}))
86}
87
88pub fn markdown_table_no_header(input: ParseString) -> ParseResult<MarkdownTable> {
89  let (input, rows) = many1(markdown_table_row)(input)?;
90  let header = vec![];
91  let alignment = vec![];
92  Ok((input, MarkdownTable{header, rows, alignment}))
93}
94
95pub fn markdown_table_header(input: ParseString) -> ParseResult<(Vec<Paragraph>,Vec<ColumnAlignment>)> {
96  let (input, _) = whitespace0(input)?;
97  let (input, header) = many1(tuple((bar, tuple((many0(space_tab), paragraph)))))(input)?;
98  let (input, _) = bar(input)?;
99  let (input, _) = whitespace0(input)?;
100  let (input, alignment) = many1(tuple((bar, tuple((many0(space_tab), alignment_separator)))))(input)?;
101  let (input, _) = bar(input)?;
102  let (input, _) = whitespace0(input)?;
103  let column_names: Vec<Paragraph> = header.into_iter().map(|(_,(_,tkn))| tkn).collect();
104  let column_alignments = alignment.into_iter().map(|(_,(_,tkn))| tkn).collect();
105  Ok((input, (column_names,column_alignments)))
106}
107
108pub fn empty_paragraph(input: ParseString) -> ParseResult<Paragraph> {
109  Ok((input, Paragraph{elements: vec![]}))
110}
111
112// markdown_table_row := +(bar, paragraph), bar, *whitespace ;
113pub fn markdown_table_row(input: ParseString) -> ParseResult<Vec<Paragraph>> {
114  let (input, _) = whitespace0(input)?;
115  let (input, _) = bar(input)?;
116  let (input, row) = many1(tuple((alt((tuple((many0(space_tab), paragraph)),tuple((many1(space_tab), empty_paragraph)))),bar)))(input)?;
117  let (input, _) = whitespace0(input)?;
118  let row = row.into_iter().map(|((_,tkn),_)| tkn).collect();
119  Ok((input, row))
120}
121
122// subtitle := digit_token+, period, space*, text+, new_line, dash+, (space|tab)*, new_line, (space|tab)*, whitespace* ;
123pub fn ul_subtitle(input: ParseString) -> ParseResult<Subtitle> {
124  let (input, _) = many1(digit_token)(input)?;
125  let (input, _) = period(input)?;
126  let (input, _) = many0(space)(input)?;
127  let (input, text) = paragraph(input)?;
128  let (input, _) = new_line(input)?;
129  let (input, _) = many1(dash)(input)?;
130  let (input, _) = many0(space_tab)(input)?;
131  let (input, _) = new_line(input)?;
132  let (input, _) = many0(space_tab)(input)?;
133  let (input, _) = whitespace0(input)?;
134  Ok((input, Subtitle{text, level: 2}))
135}
136
137// alpha_subtitle := (space|tab)*, "(", alpha, ")", (space|tab)+, text+, (space|tab)*, whitespace* ;
138pub fn subtitle(input: ParseString) -> ParseResult<Subtitle> {
139  let (input, _) = many0(space_tab)(input)?;
140  let (input, _) = left_parenthesis(input)?;
141  let (input, num) = separated_list1(period,alt((many1(alpha),many1(digit))))(input)?;
142  let (input, _) = right_parenthesis(input)?;
143  let (input, _) = many0(space_tab)(input)?;
144  let (input, text) = paragraph(input)?;
145  let (input, _) = many0(space_tab)(input)?;
146  let (input, _) = whitespace0(input)?;
147  let level: u8 = if num.len() < 3 { 3 } else { num.len() as u8 + 1 };
148  Ok((input, Subtitle{text, level}))
149}
150
151// strong := (asterisk, asterisk), +paragraph_element, (asterisk, asterisk) ;
152pub fn strong(input: ParseString) -> ParseResult<ParagraphElement> {
153  let (input, _) = tuple((asterisk,asterisk))(input)?;
154  let (input, text) = paragraph_element(input)?;
155  let (input, _) = tuple((asterisk,asterisk))(input)?;
156  Ok((input, ParagraphElement::Strong(Box::new(text))))
157}
158
159/// emphasis := asterisk, +paragraph_element, asterisk ;
160pub fn emphasis(input: ParseString) -> ParseResult<ParagraphElement> {
161  let (input, _) = asterisk(input)?;
162  let (input, text) = paragraph_element(input)?;
163  let (input, _) = asterisk(input)?;
164  Ok((input, ParagraphElement::Emphasis(Box::new(text))))
165}
166
167// strikethrough := tilde, +paragraph_element, tilde ;
168pub fn strikethrough(input: ParseString) -> ParseResult<ParagraphElement> {
169  let (input, _) = tilde(input)?;
170  let (input, text) = paragraph_element(input)?;
171  let (input, _) = tilde(input)?;
172  Ok((input, ParagraphElement::Strikethrough(Box::new(text))))
173}
174
175/// underline := underscore, +paragraph_element, underscore ;
176pub fn underline(input: ParseString) -> ParseResult<ParagraphElement> {
177  let (input, _) = underscore(input)?;
178  let (input, text) = paragraph_element(input)?;
179  let (input, _) = underscore(input)?;
180  Ok((input, ParagraphElement::Underline(Box::new(text))))
181}
182
183/// highlight := "!!", +paragraph_element, "!!" ;
184pub fn highlight(input: ParseString) -> ParseResult<ParagraphElement> {
185  let (input, _) = highlight_sigil(input)?;
186  let (input, text) = paragraph_element(input)?;
187  let (input, _) = highlight_sigil(input)?;
188  Ok((input, ParagraphElement::Highlight(Box::new(text))))
189}
190
191// inline_code := grave, +text, grave ;
192pub fn inline_code(input: ParseString) -> ParseResult<ParagraphElement> {
193  let (input, _) = grave(input)?;
194  let (input, text) = many0(tuple((is_not(grave),text)))(input)?;
195  let (input, _) = grave(input)?;
196  let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
197  // return empty token if there's nothing between the graves
198  let mut text = match Token::merge_tokens(&mut text) {
199    Some(t) => t,
200    None => {
201      return Ok((input, ParagraphElement::InlineCode(Token::default())));
202    }
203  };
204  text.kind = TokenKind::Text;
205  Ok((input, ParagraphElement::InlineCode(text)))
206}
207
208// inline_code := grave, +text, grave ;
209pub fn inline_equation(input: ParseString) -> ParseResult<ParagraphElement> {
210  let (input, _) = equation_sigil(input)?;
211  let (input, txt) = many0(tuple((is_not(equation_sigil),alt((backslash,text)))))(input)?;
212  let (input, _) = equation_sigil(input)?;
213  let mut txt = txt.into_iter().map(|(_,tkn)| tkn).collect();
214  let mut eqn = Token::merge_tokens(&mut txt).unwrap();
215  eqn.kind = TokenKind::Text;
216  Ok((input, ParagraphElement::InlineEquation(eqn)))
217}
218
219// hyperlink := "[", +text, "]", "(", +text, ")" ;
220pub fn hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
221  let (input, _) = left_bracket(input)?;
222  let (input, link_text) = many1(tuple((is_not(right_bracket),text)))(input)?;
223  let (input, _) = right_bracket(input)?;
224  let (input, _) = left_parenthesis(input)?;
225  let (input, link) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
226  let (input, _) = right_parenthesis(input)?;
227  let mut tokens = link.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
228  let link_merged = Token::merge_tokens(&mut tokens).unwrap();
229  let mut tokens = link_text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
230  let text_merged = Token::merge_tokens(&mut tokens).unwrap();
231  Ok((input, ParagraphElement::Hyperlink((text_merged, link_merged))))
232}
233
234// raw-hyperlink := ("https" | "http" |)
235pub fn raw_hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
236  let (input, _) = peek(http_prefix)(input)?;
237  let (input, address) = many1(tuple((is_not(space), text)))(input)?;
238  let mut tokens = address.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
239  let url = Token::merge_tokens(&mut tokens).unwrap();
240  Ok((input, ParagraphElement::Hyperlink((url.clone(), url))))
241}
242
243// img := "![", paragraph, "]", "(", +text, ")" ;
244pub fn img(input: ParseString) -> ParseResult<Image> {
245  let (input, _) = img_prefix(input)?;
246  let (input, caption_text) = paragraph(input)?;
247  let (input, _) = right_bracket(input)?;
248  let (input, _) = left_parenthesis(input)?;
249  let (input, src) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
250  let (input, _) = right_parenthesis(input)?;
251  let merged_src = Token::merge_tokens(&mut src.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>()).unwrap();
252  Ok((input, Image{src: merged_src, caption: Some(caption_text)} ))
253}
254
255// paragraph_text := ¬(img_prefix | http_prefix | left_bracket | tilde | asterisk | underscore | grave | define_operator | bar), +text ;
256pub fn paragraph_text(input: ParseString) -> ParseResult<ParagraphElement> {
257  let (input, elements) = match many1(nom_tuple((is_not(alt((footnote_prefix, highlight_sigil, equation_sigil, img_prefix, http_prefix, left_brace, left_bracket, left_angle, right_bracket, tilde, asterisk, underscore, grave, define_operator, bar))),text)))(input) {
258    Ok((input, mut text)) => {
259      let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
260      let mut text = Token::merge_tokens(&mut text).unwrap();
261      text.kind = TokenKind::Text;
262      (input, ParagraphElement::Text(text))
263    }, 
264    Err(err) => {return Err(err);},
265  };
266  Ok((input, elements))
267}
268
269// eval-inline-mech-cdoe := "{", expression, "}" ;`
270pub fn eval_inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
271  let (input, _) = left_brace(input)?;
272  let (input, expr) = expression(input)?;
273  let (input, _) = right_brace(input)?;
274  Ok((input, ParagraphElement::EvalInlineMechCode(expr)))
275}
276
277// inline-mech-cdoe := "{{", expression, "}}" ;`
278pub fn inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
279  let (input, _) = left_brace(input)?;
280  let (input, _) = left_brace(input)?;
281  let (input, expr) = mech_code_alt(input)?;
282  let (input, _) = right_brace(input)?;
283  let (input, _) = right_brace(input)?;
284  Ok((input, ParagraphElement::InlineMechCode(expr)))
285}
286
287// footnote-reference := "[^", +text, "]" ;
288pub fn footnote_reference(input: ParseString) -> ParseResult<ParagraphElement> {
289  let (input, _) = footnote_prefix(input)?;
290  let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
291  let (input, _) = right_bracket(input)?;
292  let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
293  let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
294  Ok((input, ParagraphElement::FootnoteReference(footnote_text)))
295}
296
297// reference := "[", +alphanumeric, "]" ;
298pub fn reference(input: ParseString) -> ParseResult<ParagraphElement> {
299  let (input, _) = left_bracket(input)?;
300  let (input, mut txt) = many1(alphanumeric)(input)?;
301  let (input, _) = right_bracket(input)?;
302  let ref_text = Token::merge_tokens(&mut txt).unwrap();
303  Ok((input, ParagraphElement::Reference(ref_text)))
304}
305
306// paragraph-element := hyperlink | raw-hyperlink | footnote-reference | paragraph-text | strong | highlight | emphasis | inline-code | strikethrough | underline ;
307pub fn paragraph_element(input: ParseString) -> ParseResult<ParagraphElement> {
308  alt((hyperlink, reference, raw_hyperlink, highlight, footnote_reference, inline_mech_code, eval_inline_mech_code, inline_equation, paragraph_text, strong, highlight, emphasis, inline_code, strikethrough, underline))(input)
309}
310
311// paragraph := +paragraph_element ;
312pub fn paragraph(input: ParseString) -> ParseResult<Paragraph> {
313  let (input, elements) = many1(paragraph_element)(input)?;
314  Ok((input, Paragraph{elements}))
315}
316
317// indented-ordered-list-item := ws, number, ".", +text, new_line*; 
318pub fn ordered_list_item(input: ParseString) -> ParseResult<(Number,Paragraph)> {
319  let (input, number) = number(input)?;
320  let (input, _) = period(input)?;
321  let (input, list_item) = paragraph(input)?;
322  let (input, _) = new_line(input)?;
323  Ok((input, (number,list_item)))
324}
325
326// checked-item := "-", ("[", "x", "]"), paragraph ;
327pub fn checked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
328  let (input, _) = dash(input)?;
329  let (input, _) = left_bracket(input)?;
330  let (input, _) = alt((tag("x"),tag("✓"),tag("✗")))(input)?;
331  let (input, _) = right_bracket(input)?;
332  let (input, list_item) = paragraph(input)?;
333  let (input, _) = new_line(input)?;
334  Ok((input, (true,list_item)))
335}
336
337// unchecked-item := "-", ("[", whitespace0, "]"), paragraph ;
338pub fn unchecked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
339  let (input, _) = dash(input)?;
340  let (input, _) = left_bracket(input)?;
341  let (input, _) = whitespace0(input)?;
342  let (input, _) = right_bracket(input)?;
343  let (input, list_item) = paragraph(input)?;
344  let (input, _) = new_line(input)?;
345  Ok((input, (false,list_item)))
346}
347
348// check-list-item := checked-item | unchecked-item ;
349pub fn check_list_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
350  let (input, item) = alt((checked_item, unchecked_item))(input)?;
351  Ok((input, item))
352}
353
354pub fn check_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
355  let mut items = vec![];
356  loop {
357    // Calculate current line indent
358    let mut indent = 0;
359    let mut current = input.peek(indent);
360    while current == Some(" ") || current == Some("\t") {
361      indent += 1;
362      current = input.peek(indent);
363    }
364    // If indent is less than current level, we are done parsing this list level
365    if indent < level {
366      break;
367    }
368    // Consume whitespace
369    let (next_input, _) = many0(space_tab)(input.clone())?;
370    // Try parsing a checklist item
371    let (next_input, list_item) = match check_list_item(next_input.clone()) {
372      Ok((next_input, list_item)) => (next_input, list_item),
373      Err(err) => {
374        if !items.is_empty() {
375          break;
376        } else {
377          return Err(err);
378        }
379      }
380    };
381    // Look ahead to next line's indent
382    let mut lookahead_indent = 0;
383    let mut current = next_input.peek(lookahead_indent);
384    while current == Some(" ") || current == Some("\t") {
385      lookahead_indent += 1;
386      current = next_input.peek(lookahead_indent);
387    }
388    input = next_input;
389    if lookahead_indent < level {
390      // End of this list level
391      items.push((list_item, None));
392      break;
393    } else if lookahead_indent == level {
394      // Same level, continue
395      items.push((list_item, None));
396      continue;
397    } else {
398      // Nested sublist: parse recursively
399      let (next_input, sublist_md) = sublist(input.clone(), lookahead_indent)?;
400      items.push((list_item, Some(sublist_md)));
401      input = next_input;
402    }
403  }
404  Ok((input, MDList::Check(items)))
405}
406
407
408// unordered_list := +list_item, ?new_line, *whitespace ;
409pub fn unordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
410  let mut items = vec![];
411  loop {
412    let mut indent = 0;
413    let mut current = input.peek(indent);
414    while current == Some(" ") || current == Some("\t") {
415      indent += 1;
416      current = input.peek(indent);
417    }
418    // If indentation is less than the current level, return to parent list
419    if indent < level {
420      return Ok((input, MDList::Unordered(items)));
421    }
422    let (next_input, _) = many0(space_tab)(input.clone())?;
423    // Try to parse a list item
424    let (next_input, list_item) = match unordered_list_item(next_input.clone()) {
425      Ok((next_input, list_item)) => (next_input, list_item),
426      Err(err) => {
427        if !items.is_empty() {
428          return Ok((input, MDList::Unordered(items)));
429        } else {
430          return Err(err);
431        }
432      }
433    };
434    // Look ahead at the next line to determine indent
435    let mut lookahead_indent = 0;
436    let mut current = next_input.peek(lookahead_indent);
437    while current == Some(" ") || current == Some("\t") {
438      lookahead_indent += 1;
439      current = next_input.peek(lookahead_indent);
440    }
441    input = next_input;
442    if lookahead_indent < level {
443      // This is the last item at the current list level
444      items.push((list_item, None));
445      return Ok((input, MDList::Unordered(items)));
446    } else if lookahead_indent == level {
447      // Continue at the same level
448      items.push((list_item, None));
449      continue;
450    } else {
451      // Nested list detected
452      let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
453      items.push((list_item, Some(sub)));
454      input = next_input;
455    }
456  }
457}
458
459// ordered-list := +ordered-list-item, ?new-line, *whitespace ;
460pub fn ordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
461  let mut items = vec![];
462  loop {
463    let mut indent = 0;
464    let mut current = input.peek(indent);
465    while current == Some(" ") || current == Some("\t") {
466      indent += 1;
467      current = input.peek(indent);
468    }
469    // If indent drops below current level, return to parent
470    if indent < level {
471      let start = items.first()
472        .map(|item: &((Number, Paragraph), Option<MDList>)| item.0.0.clone())
473        .unwrap_or(Number::from_integer(1));
474      return Ok((input, MDList::Ordered(OrderedList { start, items })));
475    }
476    // Consume whitespace
477    let (next_input, _) = many0(space_tab)(input.clone())?;
478    // Try to parse an ordered list item
479    let (next_input, (list_item, _)) = match tuple((ordered_list_item, is_not(tuple((dash, dash)))))(next_input.clone()) {
480      Ok((next_input, res)) => (next_input, res),
481      Err(err) => {
482        if !items.is_empty() {
483          let start = items.first()
484            .map(|((number, _), _)| number.clone())
485            .unwrap_or(Number::from_integer(1));
486          return Ok((input, MDList::Ordered(OrderedList { start, items })));
487        } else {
488          return Err(err);
489        }
490      }
491    };
492
493    // Determine indentation of the next line
494    let mut lookahead_indent = 0;
495    let mut current = next_input.peek(lookahead_indent);
496    while current == Some(" ") || current == Some("\t") {
497      lookahead_indent += 1;
498      current = next_input.peek(lookahead_indent);
499    }
500
501    input = next_input;
502
503    if lookahead_indent < level {
504      items.push((list_item, None));
505      let start = items.first()
506        .map(|((number, _), _)| number.clone())
507        .unwrap_or(Number::from_integer(1));
508      return Ok((input, MDList::Ordered(OrderedList { start, items })));
509    } else if lookahead_indent == level {
510      items.push((list_item, None));
511      continue;
512    } else {
513      // Nested sublist
514      let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
515      items.push((list_item, Some(sub)));
516      input = next_input;
517    }
518  }
519}
520
521
522
523pub fn sublist(input: ParseString, level: usize) -> ParseResult<MDList> {
524  let (input, list) = match ordered_list(input.clone(), level) {
525    Ok((input, list)) => (input, list),
526    _ => match check_list(input.clone(), level) {
527      Ok((input, list)) => (input, list),
528      _ => match unordered_list(input.clone(), level) {
529        Ok((input, list)) => (input, list),
530        Err(err) => { return Err(err); }
531      }
532    }
533  };
534  Ok((input, list))
535}
536
537// mechdown-list := ordered-list | unordered-list ;
538pub fn mechdown_list(input: ParseString) -> ParseResult<MDList> {
539  let (input, list) = match ordered_list(input.clone(), 0) {
540    Ok((input, list)) => (input, list),
541    _ => match check_list(input.clone(), 0) {
542      Ok((input, list)) => (input, list),
543      _ => match unordered_list(input.clone(), 0) {
544        Ok((input, list)) => (input, list),
545        Err(err) => { return Err(err); }
546      }
547    }
548  };
549  Ok((input, list))
550}
551
552// list_item := dash, <space+>, <paragraph>, new_line* ;
553pub fn unordered_list_item(input: ParseString) -> ParseResult<(Option<Token>,Paragraph)> {
554  let msg1 = "Expects space after dash";
555  let msg2 = "Expects paragraph as list item";
556  let (input, _) = dash(input)?;
557  let (input, bullet) = opt(tuple((left_parenthesis, emoji, right_parenthesis)))(input)?;
558  let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
559  let (input, list_item) = label!(paragraph, msg2)(input)?;
560  let (input, _) = many0(new_line)(input)?;
561  let bullet = match bullet {
562    Some((_,b,_)) => Some(b),
563    None => None,
564  };
565  Ok((input,  (bullet, list_item)))
566}
567
568
569pub fn skip_till_eol(input: ParseString) -> ParseResult<()> {
570
571  Ok((input, ()))
572}
573
574// code_block := grave, <grave>, <grave>, <new_line>, any, <grave{3}, new_line, whitespace*> ;
575pub fn code_block(input: ParseString) -> ParseResult<SectionElement> {
576  let msg1 = "Expects 3 graves to start a code block";
577  let msg2 = "Expects new_line";
578  let msg3 = "Expects 3 graves followed by new_line to terminate a code block";
579  let (input, (_, r)) = range(nom_tuple((
580    grave,
581    label!(grave, msg1),
582    label!(grave, msg1),
583  )))(input)?;
584  let (input, code_id) = many0(text)(input)?;
585  let (input, _) = label!(new_line, msg2)(input)?;
586  let (input, (text,src_range)) = range(many0(nom_tuple((
587    is_not(nom_tuple((grave, grave, grave))),
588    any,
589  ))))(input)?;
590  let (input, _) = nom_tuple((grave, grave, grave))(input)?;
591  let (input, _) = many0(space_tab)(input)?;
592  let (input, _) = new_line(input)?;
593  let block_src: Vec<char> = text.into_iter().flat_map(|(_, s)| s.chars().collect::<Vec<char>>()).collect();
594  let code_token = Token::new(TokenKind::CodeBlock, src_range, block_src.clone());
595
596  let code_id = code_id.iter().flat_map(|tkn| tkn.chars.clone().into_iter().collect::<Vec<char>>()).collect::<String>();
597  match code_id.as_str() {
598    "ebnf" => {
599      let ebnf_text = block_src.iter().collect::<String>();
600      match parse_grammar(&ebnf_text) {
601        Ok(grammar_tree) => {return Ok((input, SectionElement::Grammar(grammar_tree)));},
602        Err(err) => {
603          println!("Error parsing EBNF grammar: {:?}", err);
604          todo!();
605        }
606      }
607    }
608    tag => {
609      // if x begins with mec, mech, or 🤖
610      if tag.starts_with("mech") || tag.starts_with("mec") || tag.starts_with("🤖") {
611
612        // get rid of the prefix and then treat the rest of the string after : as an identifier
613        let rest = tag.trim_start_matches("mech").trim_start_matches("mec").trim_start_matches("🤖").trim_start_matches(":");
614        
615        let config = if rest == "" {BlockConfig { namespace: 0, disabled: false}}
616        else if rest == "disabled" { BlockConfig { namespace: hash_str(rest), disabled: true }} 
617        else { BlockConfig { namespace: hash_str(rest), disabled: false} };
618
619        let mech_src = block_src.iter().collect::<String>();
620        let graphemes = graphemes::init_source(&mech_src);
621        let parse_string = ParseString::new(&graphemes);
622
623        match many1(mech_code)(parse_string) {
624          Ok((_, mech_tree)) => {
625            // TODO what if not all the input is parsed? Is that handled?
626            return Ok((input, SectionElement::FencedMechCode((mech_tree,config))));
627          },
628          Err(err) => {
629            println!("Error parsing Mech code: {:?}", err);
630            todo!();
631          }
632        };
633      } else if tag.starts_with("equation") || tag.starts_with("eq") || tag.starts_with("math") || tag.starts_with("latex") || tag.starts_with("tex") {
634          return Ok((input, SectionElement::Equation(code_token)));
635      } else if tag.starts_with("diagram") || tag.starts_with("chart") || tag.starts_with("mermaid") {
636          return Ok((input, SectionElement::Diagram(code_token)));          
637      } else {
638        // Some other code block, just keep moving although we might want to do something with it later
639      }
640    }
641  } 
642  Ok((input, SectionElement::CodeBlock(code_token)))
643}
644
645pub fn thematic_break(input: ParseString) -> ParseResult<SectionElement> {
646  let (input, _) = many1(asterisk)(input)?;
647  let (input, _) = many0(space_tab)(input)?;
648  let (input, _) = new_line(input)?;
649  Ok((input, SectionElement::ThematicBreak))
650}
651
652// footnote := "[^", +text, "]", ":", ws0, paragraph ;
653pub fn footnote(input: ParseString) -> ParseResult<Footnote> {
654  let (input, _) = footnote_prefix(input)?;
655  let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
656  let (input, _) = right_bracket(input)?;
657  let (input, _) = colon(input)?;
658  let (input, _) = whitespace0(input)?;
659  let (input, paragraph) = paragraph(input)?;
660  let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
661  let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
662  let footnote = (footnote_text, paragraph);
663  Ok((input, footnote))
664}
665
666pub fn blank_line(input: ParseString) -> ParseResult<Vec<Token>> {
667  let (input, mut st) = many0(space_tab)(input)?;
668  let (input, n) = new_line(input)?;
669  st.push(n);
670  Ok((input, st))
671}
672
673pub fn question_block(input: ParseString) -> ParseResult<SectionElement> {
674    let (input, _) = query_sigil(input)?;
675    let (input, _) = many0(space_tab)(input)?;
676    let (input, first_para) = paragraph(input)?;
677
678    // Parse *(newline, *space, paragraph)
679    let (input, mut rest_paras) = many0(|input| {
680        let (input, _) = new_line(input)?;
681        let (input, _) = many0(space_tab)(input)?;
682        let (input, para) = paragraph(input)?;
683        Ok((input, para))
684    })(input)?;
685
686    let mut all_paragraphs = vec![first_para];
687    all_paragraphs.append(&mut rest_paras);
688
689    Ok((input, SectionElement::QuestionBlock(all_paragraphs)))
690}
691
692pub fn info_block(input: ParseString) -> ParseResult<SectionElement> {
693    let (input, _) = info_sigil(input)?;
694    let (input, _) = many0(space_tab)(input)?;
695    let (input, first_para) = paragraph(input)?;
696
697    // Parse *(newline, *space, paragraph)
698    let (input, mut rest_paras) = many0(|input| {
699        let (input, _) = new_line(input)?;
700        let (input, _) = many0(space_tab)(input)?;
701        let (input, para) = paragraph(input)?;
702        Ok((input, para))
703    })(input)?;
704
705    let mut all_paragraphs = vec![first_para];
706    all_paragraphs.append(&mut rest_paras);
707
708    Ok((input, SectionElement::InfoBlock(all_paragraphs)))
709}
710
711pub fn quote_block(input: ParseString) -> ParseResult<SectionElement> {
712    let (input, _) = quote_sigil(input)?;
713    let (input, _) = many0(space_tab)(input)?;
714    let (input, first_para) = paragraph(input)?;
715
716    // Parse *(newline, *space, paragraph)
717    let (input, mut rest_paras) = many0(|input| {
718        let (input, _) = new_line(input)?;
719        let (input, _) = many0(space_tab)(input)?;
720        let (input, para) = paragraph(input)?;
721        Ok((input, para))
722    })(input)?;
723
724    let mut all_paragraphs = vec![first_para];
725    all_paragraphs.append(&mut rest_paras);
726
727    Ok((input, SectionElement::QuoteBlock(all_paragraphs)))
728}
729
730// abstract-element := abstract-sigil, *space, paragraph, *(new_line, *space, paragraph)));
731pub fn abstract_el(input: ParseString) -> ParseResult<SectionElement> {
732    let (input, _) = abstract_sigil(input)?;
733    let (input, _) = many0(space_tab)(input)?;
734    let (input, first_para) = paragraph(input)?;
735
736    // Parse *(newline, *space, paragraph)
737    let (input, mut rest_paras) = many0(|input| {
738        let (input, _) = new_line(input)?;
739        let (input, _) = many0(space_tab)(input)?;
740        let (input, para) = paragraph(input)?;
741        Ok((input, para))
742    })(input)?;
743
744    let mut all_paragraphs = vec![first_para];
745    all_paragraphs.append(&mut rest_paras);
746
747    Ok((input, SectionElement::Abstract(all_paragraphs)))
748}
749
750// equation := "$$" , +text ;
751pub fn equation(input: ParseString) -> ParseResult<Token> {
752  let (input, _) = equation_sigil(input)?;
753  let (input, mut txt) = many1(alt((backslash,text)))(input)?;
754  let mut eqn = Token::merge_tokens(&mut txt).unwrap();
755  Ok((input, eqn))
756}
757
758// citation := "[", (identifier | number), "]", ":", ws0, paragraph, ws0, ?("(", +text, ")") ;
759pub fn citation(input: ParseString) -> ParseResult<Citation> {
760  let (input, _) = left_bracket(input)?;
761  let (input, mut id) = many1(alphanumeric)(input)?;
762  let (input, _) = right_bracket(input)?;
763  let (input, _) = colon(input)?;
764  let (input, _) = whitespace0(input)?;
765  let (input, txt) = paragraph(input)?;
766  let (input, _) = whitespace0(input)?;
767  let id = Token::merge_tokens(&mut id).unwrap();
768  Ok((input, Citation{id, text: txt}))
769}
770
771// float-sigil := ">>" | "<<" ;
772pub fn float_sigil(input: ParseString) -> ParseResult<FloatDirection> {
773  let (input, d) = alt((float_left, float_right))(input)?;
774  let d = match d.kind {
775    TokenKind::FloatLeft => FloatDirection::Left,
776    TokenKind::FloatRight => FloatDirection::Right,
777    _ => unreachable!(),
778  };
779  Ok((input, d))
780}
781
782// float := float-sigil, section-element ;
783pub fn float(input: ParseString) -> ParseResult<(Box<SectionElement>,FloatDirection)> {
784  let (input, direction) = float_sigil(input)?;
785  let (input, _) = many0(space_tab)(input)?;
786  let (input, el) = section_element(input)?;
787  Ok((input, (Box::new(el), direction)))
788}
789
790// sectio-_element := mech-code | list | footnote | citation | abstract | img | equation | markdown-table | float | block-quote | code-block | thematic-break | subtitle | paragraph ;
791pub fn section_element(input: ParseString) -> ParseResult<SectionElement> {
792  let (input, section_element) = match many1(mech_code)(input.clone()) {
793    Ok((input, code)) => (input, SectionElement::MechCode(code)),
794    _ => match mechdown_list(input.clone()) {
795      Ok((input, lst)) => (input, SectionElement::List(lst)),
796      _ => match footnote(input.clone()) {
797        Ok((input, ftnote)) => (input, SectionElement::Footnote(ftnote)),
798        _ => match citation(input.clone()) {
799          Ok((input, citation)) => (input, SectionElement::Citation(citation)),
800          _ => match abstract_el(input.clone()) {
801            Ok((input, abstrct)) => (input, abstrct),
802            _ => match img(input.clone()) {
803              Ok((input, img)) => (input, SectionElement::Image(img)),
804              _ => match equation(input.clone()) {
805                Ok((input, eqn)) => (input, SectionElement::Equation(eqn)),
806                _ => match markdown_table(input.clone()) {
807                  Ok((input, table)) => (input, SectionElement::Table(table)),
808                  _ => match float(input.clone()) {
809                    Ok((input, flt)) => (input, SectionElement::Float(flt)),
810                    _ => match quote_block(input.clone()) {   
811                      Ok((input, quote)) => (input, quote),
812                      _ => match code_block(input.clone()) {
813                        Ok((input, m)) => (input,m),
814                        _ => match thematic_break(input.clone()) {
815                          Ok((input, _)) => (input, SectionElement::ThematicBreak),
816                          _ => match subtitle(input.clone()) {
817                            Ok((input, subtitle)) => (input, SectionElement::Subtitle(subtitle)),
818                            _ => match paragraph(input) {
819                              Ok((input, p)) => (input, SectionElement::Paragraph(p)),
820                              Err(err) => { return Err(err); }
821                            }
822                          }
823                        }
824                      }
825                    }
826                  }
827                }
828              }
829            }
830          }
831        }
832      }
833    }
834  };
835  let (input, _) = many0(blank_line)(input)?;
836  Ok((input, section_element))
837}
838
839// section := ul_subtitle, section_element* ;
840pub fn section(input: ParseString) -> ParseResult<Section> {
841  let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
842  let (input, subtitle) = ul_subtitle(input)?;
843  let (input, elements) = many0(tuple((is_not(ul_subtitle),section_element)))(input)?;
844  let elements = elements.into_iter().map(|(_,e)| e).collect();
845  Ok((input, Section{subtitle: Some(subtitle), elements}))
846}
847
848// section_elements := section_element+ ;
849pub fn section_elements(input: ParseString) -> ParseResult<Section> {
850  let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
851  let (input, elements) = many1(tuple((is_not(ul_subtitle),section_element)))(input)?;
852  let elements = elements.into_iter().map(|(_,e)| e).collect();
853  Ok((input, Section{subtitle: None, elements}))
854}
855
856// body := whitespace0, (section | section_elements)+, whitespace0 ;
857pub fn body(input: ParseString) -> ParseResult<Body> {
858  let (input, _) = whitespace0(input)?;
859  let (input, sections) = many0(alt((section,section_elements)))(input)?;
860  let (input, _) = whitespace0(input)?;
861  Ok((input, Body{sections}))
862}