yatima_core/parse/
error.rs

1use crate::{
2  name::Name,
3  parse::{
4    base,
5    span::Span,
6  },
7  term::{
8    LitType,
9    Literal,
10  },
11};
12
13use nom::{
14  error::ErrorKind,
15  AsBytes,
16  Err,
17  IResult,
18  InputLength,
19};
20
21#[cfg(not(feature = "std"))]
22use sp_std::{
23  cmp::Ordering,
24  fmt,
25  fmt::Write,
26  num::ParseIntError,
27  vec::Vec,
28};
29#[cfg(feature = "std")]
30use std::{
31  cmp::Ordering,
32  fmt,
33  fmt::Write,
34  num::ParseIntError,
35  vec::Vec,
36};
37
38use sp_im::conslist::ConsList;
39
40use alloc::string::String;
41
42#[derive(PartialEq, Debug, Clone)]
43pub enum ParseErrorKind {
44  UndefinedReference(Name, ConsList<Name>),
45  TopLevelRedefinition(Name),
46  UnknownLiteralType(String),
47  InvalidBaseEncoding(base::LitBase),
48  UnknownBaseCode,
49  ExpectedSingleChar(Vec<char>),
50  InvalidBase16EscapeSequence(String),
51  MultibaseError(multibase::Error),
52  CidError,
53  ParseIntErr(ParseIntError),
54  ReservedKeyword(String),
55  NumericSyntax(String),
56  ReservedSyntax(String),
57  LiteralLacksWhitespaceTermination(Literal),
58  LitTypeLacksWhitespaceTermination(LitType),
59  UnknownNatOp(Name),
60  UnknownIntOp(Name),
61  UnknownBitsOp(Name),
62  UnknownBytesOp(Name),
63  UnknownBoolOp(Name),
64  UnknownTextOp(Name),
65  UnknownCharOp(Name),
66  UnknownU8Op(Name),
67  UnknownU16Op(Name),
68  UnknownU32Op(Name),
69  UnknownU64Op(Name),
70  UnknownU128Op(Name),
71  UnknownI8Op(Name),
72  UnknownI16Op(Name),
73  UnknownI32Op(Name),
74  UnknownI64Op(Name),
75  UnknownI128Op(Name),
76  TypeDefConstructorMustReturnItsType,
77  InvalidSymbol(String),
78  Nom(ErrorKind),
79}
80
81impl<'a> fmt::Display for ParseErrorKind {
82  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83    match self {
84      Self::UndefinedReference(name, _) => {
85        write!(f, "Undefined reference {}", name)
86      }
87      Self::TopLevelRedefinition(name) => {
88        write!(
89          f,
90          "Overlapping definition names, \"{}\" already defined or imported",
91          name
92        )
93      }
94      Self::ExpectedSingleChar(chrs) => {
95        write!(
96          f,
97          "Character literal syntax must contain one and only one character, \
98           but parsed {:?}",
99          chrs
100        )
101      }
102      Self::InvalidBase16EscapeSequence(seq) => {
103        write!(f, "Unknown base 16 string escape sequence {}.", seq)
104      }
105      Self::ParseIntErr(e) => {
106        write!(f, "Error parsing number: {}", e)
107      }
108      Self::ReservedKeyword(name) => {
109        write!(f, "{}` is a reserved language keyword", name)
110      }
111      Self::ReservedSyntax(_) => {
112        write!(f, "Symbols beginning with '#' are reserved")
113      }
114      Self::NumericSyntax(_) => {
115        write!(f, "Symbols beginning with digits are reserved")
116      }
117      Self::InvalidSymbol(name) => {
118        write!(
119          f,
120          "The symbol {} contains a reserved character ':', '(', ')', ',', or \
121           whitespace or control character.",
122          name
123        )
124      }
125      Self::LiteralLacksWhitespaceTermination(x) => {
126        write!(f, "Literal {} must be terminated by whitespace or eof", x)
127      }
128      Self::LitTypeLacksWhitespaceTermination(x) => {
129        write!(f, "Literal type {} must be terminated by whitespace or eof", x)
130      }
131      Self::UnknownNatOp(x) => {
132        write!(f, "Unknown primitive Nat operation #Nat.{}", x)
133      }
134      Self::UnknownIntOp(x) => {
135        write!(f, "Unknown primitive Int operation #Int.{}", x)
136      }
137      Self::UnknownBytesOp(x) => {
138        write!(f, "Unknown primitive Bytes operation #Bytes.{}", x)
139      }
140      Self::UnknownTextOp(x) => {
141        write!(f, "Unknown primitive Nat operation #Text.{}", x)
142      }
143      _ => write!(f, "internal parser error"),
144    }
145  }
146}
147
148impl ParseErrorKind {
149  pub fn is_nom_err(&self) -> bool { matches!(self, Self::Nom(_)) }
150}
151
152#[derive(PartialEq, Debug, Clone)]
153pub struct ParseError<I: AsBytes> {
154  pub input: I,
155  pub expected: Option<&'static str>,
156  pub errors: Vec<ParseErrorKind>,
157}
158
159impl<I: AsBytes> ParseError<I> {
160  pub fn new(input: I, error: ParseErrorKind) -> Self {
161    ParseError { input, expected: None, errors: vec![error] }
162  }
163}
164
165impl<'a> fmt::Display for ParseError<Span<'a>> {
166  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167    let mut res = String::new();
168
169    writeln!(
170      &mut res,
171      "at line {}:{}",
172      self.input.location_line(),
173      self.input.get_column()
174    )?;
175    let line = String::from_utf8_lossy(self.input.get_line_beginning());
176
177    writeln!(&mut res, "{} | {}", self.input.location_line(), line)?;
178
179    let cols = format!("{} | ", self.input.location_line()).len()
180      + self.input.get_column();
181    for _ in 0..(cols - 1) {
182      write!(&mut res, " ")?;
183    }
184    writeln!(&mut res, "^")?;
185
186    if let Some(exp) = self.expected {
187      writeln!(&mut res, "Expected {}", exp)?;
188    }
189
190    let mut errs = self.errors.iter().filter(|x| !x.is_nom_err()).peekable();
191    if errs.peek() == None {
192      // TODO: Nom verbose mode
193      writeln!(&mut res, "Internal parser error")?;
194    }
195    else {
196      writeln!(&mut res, "Reported errors:")?;
197      for kind in errs {
198        writeln!(&mut res, "- {}", kind)?;
199      }
200    }
201
202    write!(f, "{}", res)
203  }
204}
205
206impl<I: AsBytes> nom::error::ParseError<I> for ParseError<I>
207where
208  I: InputLength,
209  I: Clone,
210{
211  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
212    ParseError::new(input, ParseErrorKind::Nom(kind))
213  }
214
215  fn append(input: I, kind: ErrorKind, mut other: Self) -> Self {
216    match input.input_len().cmp(&other.input.input_len()) {
217      Ordering::Less => ParseError::new(input, ParseErrorKind::Nom(kind)),
218      Ordering::Equal => {
219        other.errors.push(ParseErrorKind::Nom(kind));
220        other
221      }
222      Ordering::Greater => other,
223    }
224  }
225
226  fn or(self, mut other: Self) -> Self {
227    match self.input.input_len().cmp(&other.input.input_len()) {
228      Ordering::Less => self,
229      Ordering::Equal => {
230        for x in self.errors {
231          other.errors.push(x);
232        }
233        other
234      }
235      Ordering::Greater => other,
236    }
237  }
238}
239
240impl<I: AsBytes> nom::error::ContextError<I> for ParseError<I>
241where
242  I: InputLength,
243  I: Clone,
244{
245  fn add_context(input: I, ctx: &'static str, other: Self) -> Self {
246    match input.input_len().cmp(&other.input.input_len()) {
247      Ordering::Less => {
248        ParseError { input, expected: Some(ctx), errors: vec![] }
249      }
250      Ordering::Equal => match other.expected {
251        None => ParseError { input, expected: Some(ctx), errors: other.errors },
252        _ => other,
253      },
254      Ordering::Greater => other,
255    }
256  }
257}
258
259pub fn throw_err<I: AsBytes, A, F: Fn(ParseError<I>) -> ParseError<I>>(
260  x: IResult<I, A, ParseError<I>>,
261  f: F,
262) -> IResult<I, A, ParseError<I>> {
263  match x {
264    Ok(res) => Ok(res),
265    Err(Err::Incomplete(n)) => Err(Err::Incomplete(n)),
266    Err(Err::Error(e)) => Err(Err::Error(f(e))),
267    Err(Err::Failure(e)) => Err(Err::Failure(f(e))),
268  }
269}