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