mediawiki_parser/
error.rs1use crate::ast::{Element, Position, Span};
4use crate::grammar;
5use crate::util::{get_source_lines, is_whitespace, shorten_str};
6use colored::*;
7use serde_derive::{Deserialize, Serialize};
8use std::error;
9use std::fmt;
10
11const ERROR_CONTEXT_LINES: usize = 5;
13
14#[derive(Debug, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "lowercase", deny_unknown_fields)]
17pub enum MWError {
18 ParseError(ParseError),
19 TransformationError(TransformationError),
20}
21
22#[derive(Debug, Serialize, Deserialize, PartialEq)]
24#[serde(rename_all = "lowercase", deny_unknown_fields)]
25pub struct ParseError {
26 pub position: Position,
27 pub expected: Vec<String>,
28 pub context: Vec<String>,
29 pub context_start: usize,
30 pub context_end: usize,
31}
32
33#[derive(Debug, Serialize, Deserialize, PartialEq)]
35#[serde(rename_all = "lowercase", deny_unknown_fields)]
36pub struct TransformationError {
37 pub cause: String,
38 pub position: Span,
39 pub transformation_name: String,
40 pub tree: Element,
41}
42
43impl ParseError {
44 pub fn from(err: &grammar::ParseError, input: &str) -> Self {
45 let source_lines = get_source_lines(input);
46 let line_count = source_lines.len();
47
48 let line = if err.line <= line_count {
49 err.line
50 } else {
51 source_lines.len()
52 } - 1;
53
54 let start = if line < ERROR_CONTEXT_LINES {
55 0
56 } else {
57 line - ERROR_CONTEXT_LINES
58 };
59
60 let end = if line + ERROR_CONTEXT_LINES >= line_count {
61 line_count - 1
62 } else {
63 line + ERROR_CONTEXT_LINES
64 };
65
66 let mut token_str = vec![];
67 for token in &err.expected {
68 token_str.push(String::from(*token));
69 }
70
71 let mut context = vec![];
72 for sloc in source_lines[start..=end].iter() {
73 context.push(String::from(sloc.content));
74 }
75
76 ParseError {
77 position: Position::new(err.offset, &source_lines),
78 context,
79 expected: token_str,
80 context_start: start,
81 context_end: end,
82 }
83 }
84}
85
86impl error::Error for ParseError {
87 fn description(&self) -> &str {
88 "Could not continue to parse, because no rules could be matched."
89 }
90}
91
92impl fmt::Display for ParseError {
93 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
94 let error_message = format!(
95 "ERROR in line {} at column {}: Could not continue to parse, expected one of: ",
96 self.position.line, self.position.col
97 )
98 .red()
99 .bold();
100
101 let mut token_str = vec![];
102 for token in &self.expected {
103 if is_whitespace(token) {
104 token_str.push(format!("{:?}", token));
105 } else {
106 token_str.push(token.to_string());
107 }
108 }
109
110 write!(f, "{}", error_message)?;
111 writeln!(f, "{}", token_str.join(", ").blue().bold())?;
112
113 for (i, content) in self.context.iter().enumerate() {
114 let lineno = format!("{} |", self.context_start + i + 1);
115 let lineno_col;
116
117 let formatted_content;
118 if self.context_start + i + 1 == self.position.line {
120 formatted_content = content.red();
121 lineno_col = lineno.red().bold();
122 } else {
123 formatted_content = shorten_str(content).normal();
124 lineno_col = lineno.blue().bold()
125 }
126
127 writeln!(f, "{} {}", lineno_col, formatted_content)?;
128 }
129
130 Ok(())
131 }
132}
133
134impl error::Error for TransformationError {
135 fn description(&self) -> &str {
136 &self.cause
137 }
138}
139
140impl fmt::Display for TransformationError {
141 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
142 let message = format!(
143 "ERROR applying transformation \"{}\" to Elemtn at {}:{} to {}:{}: {}",
144 self.transformation_name,
145 self.position.start.line,
146 self.position.start.col,
147 self.position.end.line,
148 self.position.end.col,
149 self.cause
150 );
151 writeln!(f, "{}", message.red().bold())
152 }
153}
154
155impl error::Error for MWError {
156 fn description(&self) -> &str {
157 match *self {
158 MWError::ParseError(ref e) => e.description(),
159 MWError::TransformationError(ref e) => e.description(),
160 }
161 }
162}
163
164impl fmt::Display for MWError {
165 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
166 match *self {
167 MWError::ParseError(ref e) => write!(f, "{}", e),
168 MWError::TransformationError(ref e) => write!(f, "{}", e),
169 }
170 }
171}