1use crate::report::Report;
7use crate::*;
8use core::ops::Range;
9use lexer::Token;
10use scarf_syntax::*;
11use std::fmt;
12use std::fs;
13use winnow::{
14 error::{AddContext, ParserError},
15 stream::Stream,
16};
17
18pub(crate) trait DisplayShort {
20 fn to_short_string(&self) -> String;
21}
22
23#[derive(Debug, Clone, PartialEq)]
26pub enum Expectation<'s> {
27 Token(Token<'s>),
29 Label(&'s str),
31 EOI,
33}
34
35impl<'a> std::fmt::Display for Expectation<'a> {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 Expectation::Token(token) => token.fmt(f),
39 Expectation::Label(label) => write!(f, "{}", label),
40 Expectation::EOI => write!(f, "end of input"),
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq)]
48pub struct VerboseError<'s> {
49 pub span: Span<'s>,
51 pub found: Option<Token<'s>>,
53 pub expected: Vec<Expectation<'s>>,
55}
56
57impl<'s> ParserError<Tokens<'s>> for VerboseError<'s> {
58 type Inner = Self;
59 fn from_input(input: &Tokens<'s>) -> Self {
60 match input.peek_token() {
61 Some(token) => VerboseError {
62 span: token.1.clone(),
63 found: Some(token.0),
64 expected: vec![],
65 },
66 None => {
67 match input.previous_tokens().next() {
69 Some(token) => {
70 let mut curr_span: &Span = &token.1;
71 let root_file = loop {
72 if let Some(included_from_span) =
73 curr_span.included_from
74 {
75 curr_span = included_from_span;
76 } else {
77 break curr_span.file;
78 }
79 };
80 VerboseError {
81 span: Span {
82 file: root_file,
83 bytes: Range {
84 start: token.1.bytes.end,
85 end: token.1.bytes.end,
86 },
87 expanded_from: None,
88 included_from: None,
89 },
90 found: None,
91 expected: vec![],
92 }
93 }
94 None => {
95 VerboseError {
97 span: Span::default(),
98 found: None,
99 expected: vec![],
100 }
101 }
102 }
103 }
104 }
105 }
106 fn into_inner(self) -> winnow::Result<Self::Inner, Self> {
107 Ok(self)
108 }
109 fn or(mut self, mut other: Self) -> Self {
110 match (self.found, other.found) {
112 (None, Some(_)) => self,
113 (Some(_), None) => other,
114 (None, None) => {
115 self.expected.append(&mut other.expected);
116 self
117 }
118 (Some(_), Some(_)) => {
119 match self.span.compare(&other.span) {
121 SpanRelation::Later => self,
122 SpanRelation::Earlier => other,
123 SpanRelation::Same => {
124 self.expected.append(&mut other.expected);
125 self
126 }
127 }
128 }
129 }
130 }
131}
132
133impl<'s> VerboseError<'s> {
134 pub(crate) fn or_in_place(&mut self, mut other: Self) {
137 match (self.found, other.found) {
139 (None, Some(_)) => (),
140 (Some(_), None) => *self = other,
141 (None, None) => {
142 self.expected.append(&mut other.expected);
143 }
144 (Some(_), Some(_)) => {
145 match self.span.compare(&other.span) {
147 SpanRelation::Later => (),
148 SpanRelation::Earlier => *self = other,
149 SpanRelation::Same => {
150 self.expected.append(&mut other.expected);
151 }
152 }
153 }
154 }
155 }
156}
157
158impl<'s> AddContext<Tokens<'s>, Token<'s>> for VerboseError<'s> {
159 fn add_context(
160 mut self,
161 _input: &Tokens<'s>,
162 _token_start: &<Tokens<'s> as Stream>::Checkpoint,
163 _context: Token<'s>,
164 ) -> Self {
165 self.expected.push(Expectation::Token(_context));
166 self
167 }
168}
169impl<'s> AddContext<Tokens<'s>, &'s str> for VerboseError<'s> {
170 fn add_context(
171 mut self,
172 _input: &Tokens<'s>,
173 _token_start: &<Tokens<'s> as Stream>::Checkpoint,
174 _context: &'s str,
175 ) -> Self {
176 self.expected.push(Expectation::Label(_context));
177 self
178 }
179}
180
181impl<'a> fmt::Display for VerboseError<'a> {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(f, "found ")?;
184 match self.found {
185 Some(tok) => tok.fmt(f)?,
186 None => write!(f, "end of input")?,
187 };
188 write!(f, ", expected ")?;
189 let mut dedup_expected: Vec<Expectation<'a>> = vec![];
190 for expected in self.expected.iter() {
191 if !dedup_expected.contains(expected) {
192 dedup_expected.push(expected.clone());
193 }
194 }
195 match &dedup_expected[..] {
196 [] => write!(f, "something else"),
197 [expected] => expected.fmt(f),
198 _ => {
199 for expected in &dedup_expected[..dedup_expected.len() - 1] {
200 expected.fmt(f)?;
201 write!(f, ", ")?;
202 }
203 write!(f, "or ")?;
204 dedup_expected.last().unwrap().fmt(f)
205 }
206 }
207 }
208}
209
210impl<'a> DisplayShort for VerboseError<'a> {
211 fn to_short_string(&self) -> String {
212 match self.found {
213 Some(tok) => format!("Didn't expect {}", tok),
214 None => "Didn't expect end of input".to_owned(),
215 }
216 }
217}
218
219impl<'s> VerboseError<'s> {
220 pub fn report<C>(&self, code: C) -> Report
222 where
223 C: fmt::Display,
224 {
225 let error_span = if self.found.is_none() {
226 let file_len = fs::metadata(self.span.file)
227 .expect("TODO: Handle file read error")
228 .len();
229 let byte_span = Range {
230 start: file_len as usize,
231 end: file_len as usize,
232 };
233 Span {
234 file: self.span.file,
235 bytes: byte_span,
236 expanded_from: None,
237 included_from: self.span.included_from,
238 }
239 } else {
240 self.span.clone()
241 };
242 Report::new(
243 report::ReportKind::Error,
244 &error_span,
245 code,
246 self.to_string(),
247 )
248 .with_label(
249 &error_span,
250 report::ReportKind::Error,
251 self.to_short_string(),
252 )
253 }
254}