Skip to main content

oni_comb_parser/
error.rs

1#[cfg(feature = "alloc")]
2use alloc::vec;
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5use core::fmt;
6
7/// `or` で左右の Backtrack エラーを合成するトレイト。
8pub trait MergeError: Sized {
9  fn merge(self, other: Self) -> Self;
10}
11
12/// `.context()` でコンテキストラベルを積むトレイト。
13pub trait ContextError: Sized {
14  fn add_context(self, context: &'static str) -> Self;
15}
16
17/// パーサーがエラーを生成するための trait。
18pub trait ExpectError: Sized {
19  fn from_expected(position: usize, expected: Expected) -> Self;
20}
21
22/// パース失敗時の期待トークン。
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum Expected {
25  /// 特定の文字を期待
26  Char(char),
27  /// 特定の文字列タグを期待
28  Tag(&'static str),
29  /// 特定のバイトを期待(将来の bytes 対応用)
30  Byte(u8),
31  /// 特定のバイト列タグを期待(将来の bytes 対応用)
32  ByteTag(&'static [u8]),
33  /// 説明的な期待("digit", "identifier" 等)
34  Description(&'static str),
35  /// 入力の終端を期待
36  Eof,
37}
38
39/// core-only 環境用の軽量エラー型。位置のみ保持。
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct MinimalError {
42  pub position: usize,
43}
44
45impl ExpectError for MinimalError {
46  #[inline]
47  fn from_expected(position: usize, _expected: Expected) -> Self {
48    Self { position }
49  }
50}
51
52impl MergeError for MinimalError {
53  #[inline]
54  fn merge(self, other: Self) -> Self {
55    if self.position >= other.position {
56      self
57    } else {
58      other
59    }
60  }
61}
62
63impl ContextError for MinimalError {
64  #[inline]
65  fn add_context(self, _context: &'static str) -> Self {
66    self
67  }
68}
69
70impl fmt::Display for MinimalError {
71  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72    write!(f, "parse error at position {}", self.position)
73  }
74}
75
76/// 構造化パースエラー。位置・期待トークン・コンテキストを保持する。
77#[cfg(feature = "alloc")]
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct ParseError {
80  /// 失敗した byte offset
81  pub position: usize,
82  /// 期待していたトークンの集合
83  pub expected: Vec<Expected>,
84  /// コンテキストスタック(外側から内側の順)
85  pub context: Vec<&'static str>,
86}
87
88#[cfg(feature = "alloc")]
89impl ExpectError for ParseError {
90  #[inline(always)]
91  fn from_expected(position: usize, expected: Expected) -> Self {
92    ParseError {
93      position,
94      expected: vec![expected],
95      context: Vec::new(),
96    }
97  }
98}
99
100#[cfg(feature = "alloc")]
101impl MergeError for ParseError {
102  fn merge(mut self, other: Self) -> Self {
103    use core::cmp::Ordering;
104    match self.position.cmp(&other.position) {
105      Ordering::Greater => self,
106      Ordering::Less => other,
107      Ordering::Equal => {
108        for e in other.expected {
109          if !self.expected.contains(&e) {
110            self.expected.push(e);
111          }
112        }
113        self
114      }
115    }
116  }
117}
118
119#[cfg(feature = "alloc")]
120impl ContextError for ParseError {
121  fn add_context(mut self, context: &'static str) -> Self {
122    self.context.push(context);
123    self
124  }
125}
126
127#[cfg(feature = "alloc")]
128impl fmt::Display for ParseError {
129  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130    write!(f, "parse error at position {}", self.position)?;
131
132    if !self.expected.is_empty() {
133      write!(f, ": expected ")?;
134      for (i, e) in self.expected.iter().enumerate() {
135        if i > 0 {
136          write!(f, " or ")?;
137        }
138        match e {
139          Expected::Char(c) => write!(f, "'{}'", c)?,
140          Expected::Tag(s) => write!(f, "\"{}\"", s)?,
141          Expected::Byte(b) => write!(f, "0x{:02X}", b)?,
142          Expected::ByteTag(bs) => write!(f, "{:?}", bs)?,
143          Expected::Description(d) => write!(f, "{}", d)?,
144          Expected::Eof => write!(f, "end of input")?,
145        }
146      }
147    }
148
149    if !self.context.is_empty() {
150      write!(f, " in ")?;
151      for (i, ctx) in self.context.iter().rev().enumerate() {
152        if i > 0 {
153          write!(f, " > ")?;
154        }
155        write!(f, "{}", ctx)?;
156      }
157    }
158
159    Ok(())
160  }
161}