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