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