Skip to main content

mech_syntax/
lib.rs

1// # Syntax
2
3#![cfg_attr(feature = "no-std", no_std)]
4#![cfg_attr(feature = "no-std", alloc)]
5#![feature(extract_if)]
6#![feature(get_mut_unchecked)]
7#![allow(dead_code)]
8#![allow(warnings)]
9#![feature(step_trait)]
10
11extern crate mech_core;
12#[cfg(feature="no-std")] #[macro_use] extern crate alloc;
13#[cfg(not(feature = "no-std"))] extern crate core;
14extern crate nom;
15extern crate nom_unicode;
16extern crate tabled;
17
18use mech_core::*;
19use mech_core::nodes::*;
20use std::cell::RefCell;
21use std::rc::Rc;
22use num_traits::*;
23
24#[cfg(feature = "serde")] use serde::{Serialize, Deserialize};
25
26#[cfg(not(feature = "no-std"))] use core::fmt;
27#[cfg(feature = "no-std")] use alloc::fmt;
28#[cfg(feature = "no-std")] use alloc::string::String;
29#[cfg(feature = "no-std")] use alloc::vec::Vec;
30use nom::{
31  IResult,
32  branch::alt,
33  sequence::tuple,
34  combinator::{opt, eof},
35  multi::{many1, many_till, many0, separated_list1},
36  Err,
37};
38use nom::Parser;
39
40use std::collections::HashMap;
41use colored::*;
42
43//#[cfg(feature = "mechdown")]
44pub mod mechdown;
45pub mod expressions;
46pub mod statements;
47pub mod structures;
48pub mod base;
49pub mod parser;
50#[cfg(feature = "formatter")]
51pub mod formatter;
52#[cfg(feature = "mika")]
53pub mod mika;
54pub mod grammar;
55pub mod literals;
56pub mod state_machines;
57pub mod functions;
58pub mod repl;
59
60pub use crate::parser::*;
61//#[cfg(feature = "mechdown")]
62pub use crate::mechdown::*;
63pub use crate::expressions::*;
64pub use crate::statements::*;
65pub use crate::structures::*;
66pub use crate::base::*;
67#[cfg(feature = "formatter")]
68pub use crate::formatter::*;
69#[cfg(feature = "mika")]
70pub use crate::mika::*;
71pub use crate::grammar::*;
72pub use crate::literals::*;
73pub use crate::state_machines::*;
74pub use crate::functions::*;
75pub use crate::repl::*;
76
77
78/// Unicode grapheme group utilities.
79/// Current implementation does not guarantee correct behavior for
80/// all possible unicode characters.
81pub mod graphemes {
82  use unicode_segmentation::UnicodeSegmentation;
83
84  /// Obtain unicode grapheme groups from input source, then make sure
85  /// it ends with new_line.  Many functions in the parser assume input
86  /// ends with new_line.
87  pub fn init_source(text: &str) -> Vec<&str> {
88    let mut graphemes = UnicodeSegmentation::graphemes(text, true).collect::<Vec<&str>>();
89    graphemes.push("\n");
90    graphemes
91  }
92
93  pub fn init_tag(tag: &str) -> Vec<&str> {
94    UnicodeSegmentation::graphemes(tag, true).collect::<Vec<&str>>()
95  }
96
97  pub fn is_new_line(grapheme: &str) -> bool {
98    match grapheme {
99      "\r" | "\n" | "\r\n" => true,
100      _ => false,
101    }
102  }
103
104  pub fn is_numeric(grapheme: &str) -> bool {
105    grapheme.chars().next().unwrap().is_numeric()
106  }
107
108  pub fn is_alpha(grapheme: &str) -> bool {
109    grapheme.chars().next().unwrap().is_alphabetic()
110  }
111
112  pub fn is_emoji(grapheme: &str) -> bool {
113    let ch = grapheme.chars().next().unwrap();
114    !(ch.is_alphanumeric() || ch.is_ascii())
115  }
116
117  pub fn width(grapheme: &str) -> usize {
118    // TODO: uniode width?
119    let ch = grapheme.chars().next().unwrap();
120    if ch == '\t' {
121      1
122    } else if ch.is_control() {
123      0
124    } else {
125      1
126    }
127  }
128}
129
130/// Just alias
131pub type ParseResult<'a, O> = IResult<ParseString<'a>, O, ParseError<'a>>;
132
133/// The input type for nom parsers. Instead of holding the actual input
134/// string, this struct only holds a reference to that string so that it
135/// can be cloned at much lower cost.
136#[derive(Clone, Debug)]
137pub struct ParseString<'a> {
138  /// Source code
139  pub graphemes: &'a Vec<&'a str>,
140  /// Error report, a list of (error_location, error_context)
141  pub error_log: Vec<(SourceRange, ParseErrorDetail)>,
142  /// Point at the next grapheme to consume
143  pub cursor: usize,
144  /// Location of the grapheme pointed by cursor
145  pub location: SourceLocation,
146}
147
148impl<'a> ParseString<'a> {
149  /// Must always point a an actual string
150  pub fn new(graphemes: &'a Vec<&'a str>) -> Self {
151    ParseString {
152      graphemes,
153      error_log: vec![],
154      cursor: 0,
155      location: SourceLocation { row: 1, col: 1 },
156    }
157  }
158
159  pub fn rest(&self) -> String {
160    // Return the rest of the string from current cursor
161    let mut s = String::new();
162    for i in self.cursor..self.graphemes.len() {
163      s.push_str(self.graphemes[i]);
164    }
165    s
166  }
167
168  pub fn peek(&self, n: usize) -> Option<&str> {
169    self.graphemes.get(self.cursor + n).copied()
170  }
171
172  pub fn current(&self) -> Option<&str> {
173    self.graphemes.get(self.cursor).copied()
174  }
175
176  pub fn next(&self) -> Option<&str> {
177    self.graphemes.get(self.cursor + 1).copied()
178  }
179
180  /// If current location matches the tag, consume the matched string.
181  fn consume_tag(&mut self, tag: &str) -> Option<String> {
182    if self.is_empty() {
183      return None;
184    }
185    let current = self.graphemes[self.cursor];
186
187    let gs = graphemes::init_tag(tag); 
188    let gs_len = gs.len();
189
190    // Must have enough remaining characters
191    if self.len() < gs_len {
192      return None;
193    }
194
195    // Try to match the tag
196    let mut tmp_location = self.location;
197    for i in 0..gs_len {
198      let c = self.cursor + i;
199      let g = self.graphemes[c];
200      if g != gs[i] {
201        return None;
202      }
203      if graphemes::is_new_line(g) {
204        if !self.is_last_grapheme(c) {
205          tmp_location.row += 1;
206          tmp_location.col = 1;
207        }
208      } else {
209        tmp_location.col += graphemes::width(g);
210      }
211    }
212    // Tag matched, commit change
213    self.cursor += gs_len;
214    self.location = tmp_location;
215    Some(tag.to_string())
216  }
217
218  /// Extract graphemes between two cursor indices without mutating self.
219  pub fn slice(&self, start_cursor: usize, end_cursor: usize) -> String {
220    let start = start_cursor.min(self.graphemes.len());
221    let end = end_cursor.min(self.graphemes.len());
222    self.graphemes[start..end].join("")
223  }
224
225  /// Mutate self by consuming one grapheme
226  fn consume_one(&mut self) -> Option<String> {
227    if self.is_empty() {
228      return None;
229    }
230    let g = self.graphemes[self.cursor];
231    if graphemes::is_new_line(g) {
232      if !self.is_last_grapheme(self.cursor) {
233        self.location.row += 1;
234        self.location.col = 1;
235      }
236    } else {
237      self.location.col += graphemes::width(g);
238    }
239    self.cursor += 1;
240    Some(g.to_string())
241  }
242
243
244  /// If current location matches any emoji, consume the matched string.
245  fn consume_emoji(&mut self) -> Option<String> {
246    if self.is_empty() {
247      return None;
248    }
249    let g = self.graphemes[self.cursor];
250    
251    if graphemes::is_emoji(g) {
252      self.cursor += 1;
253      self.location.col += graphemes::width(g);
254      Some(g.to_string())
255    } else {
256      None
257    }
258  }
259
260  /// If current location matches any alpha char, consume the matched string.
261  fn consume_alpha(&mut self) -> Option<String> {
262    if self.is_empty() {
263      return None;
264    }
265    let g = self.graphemes[self.cursor];
266    if graphemes::is_alpha(g) {
267      self.cursor += 1;
268      self.location.col += graphemes::width(g);
269      Some(g.to_string())
270    } else {
271      None
272    }
273  }
274
275  /// If current location matches any digit, consume the matched string.
276  fn consume_digit(&mut self) -> Option<String> {
277    if self.is_empty() {
278      return None;
279    }
280    let g = self.graphemes[self.cursor];
281    if graphemes::is_numeric(g) {
282      self.cursor += 1;
283      self.location.col += graphemes::width(g);
284      Some(g.to_string())
285    } else {
286      None
287    }
288  }
289
290  /// Get cursor's location in source code
291  fn loc(&self) -> SourceLocation {
292    self.location
293  }
294
295  /// Test whether the grapheme pointed by cursor is the last grapheme
296  fn is_last_grapheme(&self, c: usize) -> bool {
297    (self.graphemes.len() - 1 - c) == 0
298  }
299
300  /// Get remaining (unparsed) length
301  pub fn len(&self) -> usize {
302    self.graphemes.len() - self.cursor
303  }
304  
305  pub fn is_empty(&self) -> bool {
306    self.len() == 0
307  }
308
309  /// For debug purpose
310  fn output(&self) {
311              
312    println!("───────────────────{}", self.len());
313    for i in self.cursor..self.graphemes.len() {
314      print!("{}", self.graphemes[i]);
315    }
316    println!();
317    println!("───────────────────");
318  }
319}
320
321/// Required by nom
322impl<'a> nom::InputLength for ParseString<'a> {
323  fn input_len(&self) -> usize {
324    self.len()
325  }
326}
327
328/// The part of error context that's independent to its cause location.
329#[derive(Clone, Debug)]
330pub struct ParseErrorDetail {
331  pub message: &'static str,
332  pub annotation_rngs: Vec<SourceRange>,
333}
334
335/// The error type for the nom parser, which handles full error context
336/// (location + detail) and ownership of the input ParseString.
337///
338/// Eventually error context will be logged and ownership will be moved out.
339#[derive(Clone, Debug)]
340pub struct ParseError<'a> {
341  /// Cause range is defined as [start, end), where `start` points at the first
342  /// character that's catched by a label, and `end` points at the next 
343  /// character of the character that didn't match.
344  ///
345  /// Example:
346  ///   index:  1234567
347  ///   input:  abcdefg
348  ///   error:   ~~~^
349  ///   range:   |   |
350  ///           [2,  5)
351  ///
352  pub cause_range: SourceRange,
353  /// Hold ownership to the input ParseString
354  pub remaining_input: ParseString<'a>,
355  /// Detailed information about this error
356  pub error_detail: ParseErrorDetail,
357}
358
359impl<'a> ParseError<'a> {
360  /// Create a new error at current location of the input, with given message
361  /// and empty annotations.  Ownership of the input is also passed into this
362  /// error object.
363  pub fn new(input: ParseString<'a>, msg: &'static str) -> Self {
364    let start = input.loc();
365    let mut end = start;
366    end.col += 1;
367    ParseError {
368      cause_range: SourceRange { start, end },
369      remaining_input: input,
370      error_detail: ParseErrorDetail {
371        message: msg,
372        annotation_rngs: vec![],
373      }
374    }
375  }
376
377  /// Add self to the error log of input string.
378  fn log(&mut self) {
379    self.remaining_input.error_log.push((self.cause_range.clone(), self.error_detail.clone()));
380  }
381}
382
383/// Required by nom
384impl<'a> nom::error::ParseError<ParseString<'a>> for ParseError<'a> {
385  /// Not used, unless we have logical error
386  fn from_error_kind(input: ParseString<'a>,
387                      _kind: nom::error::ErrorKind) -> Self {
388    ParseError::new(input, format!("NomErrorKind: {:?}", _kind).leak())
389  }
390
391  /// Probably not used
392  fn append(_input: ParseString<'a>,
393            _kind: nom::error::ErrorKind,
394            other: Self) -> Self {
395    other
396  }
397
398  /// Barely used, but we do want to keep the error with larger depth.
399  fn or(self, other: Self) -> Self {
400    let self_start = self.cause_range.start;
401    let other_start = other.cause_range.start;
402    if self_start > other_start {
403      self
404    } else {
405      other
406    }
407  }
408}
409
410/// This struct is responsible for analysing text, interpreting indices
411/// and ranges, and producing formatted messages.
412pub struct TextFormatter<'a> {
413  graphemes: Vec<&'a str>,
414  line_beginnings: Vec<usize>,
415  end_index: usize,
416}
417
418impl<'a> TextFormatter<'a> {
419  pub fn new(text: &'a str) -> Self {
420    let graphemes = graphemes::init_source(text);
421    let mut line_beginnings = vec![0];
422    for i in 0..graphemes.len() {
423      if graphemes::is_new_line(graphemes[i]) {
424        line_beginnings.push(i + 1);
425      }
426    }
427    line_beginnings.pop();
428    TextFormatter {
429      end_index: graphemes.len(),
430      graphemes,
431      line_beginnings,
432    }
433  }
434
435  // Index interpreter
436
437  fn get_line_range(&self, linenum: usize) -> Option<(usize, usize)> {
438    let line_index = linenum - 1;
439    if line_index >= self.line_beginnings.len() {
440      return None;
441    }
442    if linenum == self.line_beginnings.len() {  // asking for the last line
443      return Some((self.line_beginnings[line_index], self.end_index));
444    }
445    Some((self.line_beginnings[line_index], self.line_beginnings[linenum]))
446  }
447
448  fn get_text_by_linenum(&self, linenum: usize) -> String {
449    let (start, end) = match self.get_line_range(linenum) {
450      Some(v) => v,
451      None => return "\n".to_string(),
452    };
453    let mut s = self.graphemes[start..end].iter().map(|s| *s).collect::<String>();
454    if !s.ends_with("\n") {
455      s.push('\n');
456    }
457    s
458  }
459
460  fn get_textlen_by_linenum(&self, linenum: usize) -> usize {
461    let (start, end) = match self.get_line_range(linenum) {
462      Some(v) => v,
463      None => return 1,
464    };
465    let mut len = 0;
466    for i in start..end {
467      len += graphemes::width(self.graphemes[i]);
468    }
469    len + 1
470  }
471
472  // FormattedString printer
473
474  fn heading_color(s: &str) -> String {
475    s.truecolor(246, 192, 78).bold().to_string()
476  }
477
478  fn location_color(s: &str) -> String {
479    s.truecolor(0,187,204).bold().to_string()
480  }
481
482  fn linenum_color(s: &str) -> String {
483    s.truecolor(0,187,204).bold().to_string()
484  }
485
486  fn text_color(s: &str) -> String {
487    s.to_string()
488  }
489
490  fn annotation_color(s: &str) -> String {
491    s.truecolor(102,51,153).bold().to_string()
492  }
493
494  fn error_color(s: &str) -> String {
495    s.truecolor(170,51,85).bold().to_string()
496  }
497
498  fn ending_color(s: &str) -> String {
499    s.truecolor(246, 192, 78).bold().to_string()
500  }
501
502  fn err_heading(index: usize) -> String {
503    let n = index + 1;
504    let d = "────────────────────────";
505    let s = format!("{} syntax error #{} {}\n", d, n, d);
506    Self::heading_color(&s)
507  }
508
509  fn err_location(&self, ctx: &ParserErrorContext) -> String {
510    let err_end = ctx.cause_rng.end;
511    // error range will not ends at first column, so `minus 1` here is safe
512    let (row, col) = (err_end.row, err_end.col - 1);
513    let s = format!("@location:{}:{}\n", row, col);
514    Self::location_color(&s)
515  }
516
517  fn err_context(&self, ctx: &ParserErrorContext) -> String {
518    let mut result = String::new();
519
520    let mut annotation_rngs = ctx.annotation_rngs.clone();
521    annotation_rngs.push(ctx.cause_rng.clone());
522
523    // the lines to print (1-indexed)
524    let mut lines_to_print: Vec<usize> = vec![];
525    for rng in &annotation_rngs {
526      let r1 = rng.start.row;
527      // if range ends at first column, it doesn't reach that row
528      let r2 = if rng.end.col == 1 {
529        usize::max(rng.start.row, rng.end.row - 1)
530      } else {
531        rng.end.row
532      };
533      for i in r1..=r2 {
534        lines_to_print.push(i);
535      }
536    }
537    lines_to_print.sort();
538    lines_to_print.dedup();
539
540    // the annotations on each line
541    // <linenum, Vec<(start_col, rng_len, is_major, is_cause)>>
542    let mut range_table: HashMap<usize, Vec<(usize, usize, bool, bool)>> = HashMap::new();
543    for linenum in &lines_to_print {
544      range_table.insert(*linenum, vec![]);
545    }
546    let n = annotation_rngs.len() - 1;  // if i == n, it's the last rng, i.e. the cause rng
547    for (i, rng) in annotation_rngs.iter().enumerate() {
548      // c2 might be 0
549      let (r1, c1) = (rng.start.row, rng.start.col);
550      let (r2, c2) = (rng.end.row, rng.end.col - 1);
551      if r1 == r2 {  // the entire range is on one line
552        if c2 >= c1 {  // and the range has non-zero length
553          range_table.get_mut(&r1).unwrap().push((c1, c2 - c1 + 1, true, i == n));
554        }
555      } else {  // the range spans over multiple lines
556        range_table.get_mut(&r1).unwrap().push((c1, usize::MAX, i != n, i == n));
557        for r in r1+1..r2 {
558          range_table.get_mut(&r).unwrap().push((1, usize::MAX, false, i == n));
559        }
560        if c2 != 0 {  // only add the last line if it hfnas non-zero length
561          range_table.get_mut(&r2).unwrap().push((1, c2, i == n, i == n));
562        }
563      }
564    }
565
566    // other data for printing
567    let dots = "...";
568    let indentation = " ";
569    let vert_split1 = " │";
570    let vert_split2 = "  ";
571    let arrow = "^";
572    let tilde = "~";
573    let lines_str: Vec<String> = lines_to_print.iter().map(|i| i.to_string()).collect();
574    let row_str_len = usize::max(lines_str.last().unwrap().len(), dots.len());
575
576    // print source code
577    for i in 0..lines_to_print.len() {
578      // [... | ]
579      if i != 0 && (lines_to_print[i] - lines_to_print[i-1] != 1) {
580        result.push_str(indentation);
581        for _ in 3..row_str_len { result.push(' '); }
582        result.push_str(&Self::linenum_color(dots));
583        result.push_str(&Self::linenum_color(vert_split1));
584        result.push('\n');
585      }
586
587      // [    | ]
588      result.push_str(indentation);
589      for _ in 0..row_str_len { result.push(' '); }
590      result.push_str(&Self::linenum_color(vert_split1));
591      result.push('\n');
592
593      // [row |  program text...]
594      let text = self.get_text_by_linenum(lines_to_print[i]);
595      result.push_str(indentation);
596      for _ in 0..row_str_len-lines_str[i].len() { result.push(' '); }
597      result.push_str(&Self::linenum_color(&lines_str[i]));
598      result.push_str(&Self::linenum_color(vert_split1));
599      result.push_str(&Self::text_color(&text));
600
601      // [    |    ^~~~]
602      result.push_str(indentation);
603      for _ in 0..row_str_len { result.push(' '); }
604      result.push_str(&Self::linenum_color(vert_split1));
605      let mut curr_col = 1;
606      let line_len = self.get_textlen_by_linenum(lines_to_print[i]);
607      let rngs = range_table.get(&lines_to_print[i]).unwrap();
608      for (start, len, major, cause) in rngs {
609        let max_len = usize::max(1, usize::min(*len, line_len - curr_col + 1));
610        for _ in curr_col..*start { result.push(' '); }
611        if *cause {
612          for _ in 0..max_len-1 {
613            result.push_str(&Self::error_color(tilde));
614          }
615          if *major {
616            result.push_str(&Self::error_color(arrow));
617          } else {
618            result.push_str(&Self::error_color(tilde));
619          }
620        } else {
621          if *major {
622            result.push_str(&Self::annotation_color(arrow));
623          } else {
624            result.push_str(&Self::annotation_color(tilde));
625          }
626          for _ in 0..max_len-1 {
627            result.push_str(&Self::annotation_color(tilde));
628          }
629        }
630        curr_col = start + max_len;
631      }
632      result.push('\n');
633    }
634
635    // print error message;
636    // error range never ends at first column, so it's safe to `minus 1` here
637    let cause_col = ctx.cause_rng.end.col - 1;
638    result.push_str(indentation);
639    for _ in 0..row_str_len { result.push(' '); }
640    result.push_str(vert_split2);
641    for _ in 0..cause_col-1 { result.push(' '); }
642    result.push_str(&Self::error_color(&ctx.err_message));
643    result.push('\n');
644
645    result
646  }
647
648  fn err_ending(d: usize) -> String {
649    let s = format!("... and {} other error{} not shown\n", d, if d == 1 {""} else {"s"});
650    Self::heading_color(&s)
651  }
652
653  /// Get formatted error message.
654  pub fn format_error(&self, errors: &ParserErrorReport) -> String {
655    let n = usize::min(errors.1.len(), 10);
656    let mut result = String::new();
657    result.push('\n');
658    for i in 0..n {
659      let ctx = &errors.1[i];
660      result.push_str(&Self::err_heading(i));
661      result.push_str(&self.err_location(ctx));
662      result.push_str(&self.err_context(ctx));
663      result.push_str("\n\n");
664    }
665    let d = errors.0.len() - n;
666    if d != 0 {
667      result.push_str(&Self::err_ending(d));
668    }
669    result
670  }
671}
672
673#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
674#[derive(Clone, Debug, Eq, PartialEq, Hash)]
675pub struct ParserErrorContext {
676  pub cause_rng: SourceRange,
677  pub err_message: String,
678  pub annotation_rngs: Vec<SourceRange>,
679}
680
681#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
682#[derive(Clone, Debug, PartialEq, Eq, Hash)]
683pub struct ParserErrorReport(pub String, pub Vec<ParserErrorContext>);
684
685impl MechErrorKind2 for ParserErrorReport {
686  fn name(&self) -> &str {
687    "ParserErrorContext"
688  }
689  fn message(&self) -> String {
690    let source = &self.0;
691    let lines: Vec<&str> = source.lines().collect();
692
693    self.1
694      .iter()
695      .map(|e| {
696        let cause_snippet = extract_snippet(&lines, &e.cause_rng);
697
698        let annotation_snippets = e.annotation_rngs
699          .iter()
700          .map(|rng| extract_snippet(&lines, rng))
701          .collect::<Vec<_>>()
702          .join("\n");
703
704        format!(
705          "{}: {} (Annotations: [{}])\n\nSource:\n{}\n\nAnnotations:\n{}",
706          format!(
707            "[{}:{}-{}:{}]",
708            e.cause_rng.start.row,
709            e.cause_rng.start.col,
710            e.cause_rng.end.row,
711            e.cause_rng.end.col
712          ),
713          e.err_message,
714          e.annotation_rngs.iter()
715            .map(|rng| format!(
716              "[{}:{}-{}:{}]",
717              rng.start.row, rng.start.col, rng.end.row, rng.end.col
718            ))
719            .collect::<Vec<_>>()
720            .join(", "),
721          indent(&cause_snippet),
722          indent(&annotation_snippets)
723        )
724      })
725      .collect::<Vec<_>>()
726      .join("\n\n---\n\n")
727  }
728}
729
730fn extract_snippet(lines: &[&str], range: &SourceRange) -> String {
731  let mut out = String::new();
732
733  for row in range.start.row..=range.end.row {
734    if let Some(line) = lines.get(row) {
735      let start = if row == range.start.row { range.start.col } else { 0 };
736      let end   = if row == range.end.row   { range.end.col } else { line.len() };
737
738      let end = end.min(line.len());
739
740      if start <= end {
741        out.push_str(&line[start..end]);
742      }
743      out.push('\n');
744    }
745  }
746
747  out
748}
749
750fn indent(s: &str) -> String {
751  s.lines()
752    .map(|line| format!("  {}", line))
753    .collect::<Vec<_>>()
754    .join("\n")
755}
756
757/// Try a list of parsers in order, tracking successes, failures, and errors.
758/// Returns the best success if any, else best failure, else best error.
759pub fn alt_best<'a, O>(
760  input: ParseString<'a>,
761  parsers: &[(&'static str, Box<dyn Fn(ParseString) -> ParseResult<O>>)],
762) -> ParseResult<'a, O> {
763  let start_cursor = input.cursor;
764
765  let mut best_success: Option<(ParseString, O, usize, &'static str)> = None;
766  let mut best_failure: Option<(nom::Err<ParseError>, usize, &'static str)> = None;
767  let mut best_error:   Option<(nom::Err<ParseError>, usize, &'static str)> = None;
768
769  for (name, parser) in parsers {
770    match parser(input.clone()) {
771      Ok((next_input, val)) => {
772        if *name == "mech_code" {
773          return Ok((next_input, val));
774        }
775        let consumed = next_input.cursor;
776        if best_success.is_none() || consumed > best_success.as_ref().unwrap().2 {
777          best_success = Some((next_input, val, consumed, name));
778        }
779      }
780
781      Err(nom::Err::Failure(e)) => {
782        let reached = e.remaining_input.cursor;
783        if best_failure.is_none() || reached > best_failure.as_ref().unwrap().1 {
784          best_failure = Some((nom::Err::Failure(e), reached, name));
785        }
786      }
787
788      Err(nom::Err::Error(e)) => {
789        let reached = e.remaining_input.cursor;
790        if best_error.is_none() || reached > best_error.as_ref().unwrap().1 {
791          best_error = Some((nom::Err::Error(e), reached, name));
792        }
793      }
794
795      Err(e @ nom::Err::Incomplete(_)) => {
796        return Err(e);
797      }
798    }
799  }
800
801  // Determine the best result based on the given conditions
802  if let Some((next_input, val, success_cursor, _)) = best_success {
803    if let Some((nom::Err::Failure(failure), failure_cursor, _)) = best_failure {
804      if success_cursor > failure_cursor {
805        Ok((next_input, val))
806      } else {
807        Err(nom::Err::Failure(failure))
808      }
809    } else {
810      Ok((next_input, val))
811    }
812  } else if let Some((nom::Err::Failure(failure), _, _)) = best_failure {
813    Err(nom::Err::Failure(failure))
814  } else if let Some((err, _, _)) = best_error {
815    Err(err)
816  } else {
817    Err(nom::Err::Error(ParseError::new(
818      input,
819      "No parser matched in alt_best",
820    )))
821  }
822}