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