1use lalrpop_util::lalrpop_mod;
2use ownable::{IntoOwned, traits::IntoOwned};
3use std::borrow::Cow;
4
5use crate::lexer::{LexicalError, Token};
6
7pub mod ast;
8mod lexer;
9
10lalrpop_mod!(
11 #[allow(clippy::ptr_arg)]
12 #[rustfmt::skip]
13 java
14);
15
16#[derive(Debug, Clone, PartialEq, IntoOwned)]
17pub struct ErrorLocation {
18 raw: usize,
19
20 row: usize,
21 column: usize,
22}
23
24impl ErrorLocation {
25 pub fn new(str: &str, loc: usize) -> Self {
26 let row = str[..loc].chars().filter(|&ch| ch == '\n').count() + 1;
27 let column = loc - str[..loc].rfind("\n").unwrap_or(0);
28
29 ErrorLocation {
30 raw: loc,
31 row,
32 column,
33 }
34 }
35}
36
37#[derive(Debug, Clone)]
38pub enum Error<'a> {
39 InvalidToken {
40 location: ErrorLocation,
41 },
42
43 UnrecognizedEof {
44 location: ErrorLocation,
45 expected: Vec<String>,
46 },
47
48 UnrecognizedToken {
49 token: (ErrorLocation, Token<'a>, ErrorLocation),
50 expected: Vec<String>,
51 },
52
53 ExtraToken {
54 token: (ErrorLocation, Token<'a>, ErrorLocation),
55 },
56
57 User {
58 error: LexicalError,
59 },
60}
61
62impl<'a> IntoOwned for Error<'a> {
63 type Owned = Error<'static>;
64
65 fn into_owned(self) -> Self::Owned {
66 match self {
67 Error::UnrecognizedToken {
68 token: (l, t, r),
69 expected,
70 } => Error::UnrecognizedToken {
71 token: (l, t.into_owned(), r),
72 expected,
73 },
74 Error::ExtraToken { token: (l, t, r) } => Error::ExtraToken {
75 token: (l, t.into_owned(), r),
76 },
77 Error::InvalidToken { location } => Error::InvalidToken { location },
78 Error::UnrecognizedEof { location, expected } => {
79 Error::UnrecognizedEof { location, expected }
80 }
81 Error::User { error } => Error::User { error },
82 }
83 }
84}
85
86#[derive(Clone, IntoOwned)]
87pub struct ErrorCell<'a> {
88 pub owner: Cow<'a, str>,
89 pub inner: Error<'a>,
90}
91
92impl<'a> ErrorCell<'a> {
93 fn new(
94 owner: &'a str,
95 error: lalrpop_util::ParseError<usize, Token<'a>, LexicalError>,
96 ) -> Self {
97 Self {
98 owner: Cow::from(owner),
99 inner: match error {
100 lalrpop_util::ParseError::InvalidToken { location } => Error::InvalidToken {
101 location: ErrorLocation::new(owner, location),
102 },
103 lalrpop_util::ParseError::UnrecognizedEof { location, expected } => {
104 Error::UnrecognizedEof {
105 location: ErrorLocation::new(owner, location),
106 expected,
107 }
108 }
109 lalrpop_util::ParseError::UnrecognizedToken {
110 token: (l, t, r),
111 expected,
112 } => Error::UnrecognizedToken {
113 token: (
114 ErrorLocation::new(owner, l),
115 t,
116 ErrorLocation::new(owner, r),
117 ),
118 expected,
119 },
120 lalrpop_util::ParseError::ExtraToken { token: (l, t, r) } => Error::ExtraToken {
121 token: (
122 ErrorLocation::new(owner, l),
123 t,
124 ErrorLocation::new(owner, r),
125 ),
126 },
127 lalrpop_util::ParseError::User { error } => Error::User { error },
128 },
129 }
130 }
131}
132
133impl<'a> std::fmt::Display for ErrorCell<'a> {
134 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
135 match &self.inner {
136 Error::InvalidToken { location } => {
137 write!(f, "Invalid token at {}:{}", location.row, location.column)?
138 }
139 Error::UnrecognizedEof { location, expected } => write!(
140 f,
141 "Unrecognized end of file at {}:{}, expected '{}'",
142 location.row,
143 location.column,
144 expected.join("', '")
145 )?,
146 Error::UnrecognizedToken { token, expected } => write!(
147 f,
148 "Unrecognized token '{}' from {}:{} to {}:{}, expected '{}'",
149 token.1,
150 token.0.row,
151 token.0.column,
152 token.2.row,
153 token.2.column,
154 expected.join("', '")
155 )?,
156 Error::ExtraToken { token } => write!(
157 f,
158 "Unexpected token '{}' at the end of file from {}:{} to {}:{}",
159 token.1, token.0.row, token.0.column, token.2.row, token.2.column
160 )?,
161 Error::User { error } => {
162 let start = ErrorLocation::new(self.owner.as_ref(), error.span.start);
163 let end = ErrorLocation::new(self.owner.as_ref(), error.span.end);
164
165 match &error.kind {
166 lexer::LexicalErrorKind::InvalidToken => write!(
167 f,
168 "Invalid token '{}' from {}:{} to {}:{}",
169 &self.owner[error.span.start..error.span.end],
170 start.row,
171 start.column,
172 end.row,
173 end.column
174 )?,
175 lexer::LexicalErrorKind::InvalidInteger(parse_int_error) => write!(
176 f,
177 "Invalid integer '{}' from {}:{} to {}:{}: {}",
178 &self.owner[error.span.start..error.span.end],
179 start.row,
180 start.column,
181 end.row,
182 end.column,
183 &parse_int_error
184 )?,
185 lexer::LexicalErrorKind::InvalidFloat(parse_float_error) => write!(
186 f,
187 "Invalid float '{}' from {}:{} to {}:{}: {}",
188 &self.owner[error.span.start..error.span.end],
189 start.row,
190 start.column,
191 end.row,
192 end.column,
193 &parse_float_error
194 )?,
195 }
196 }
197 };
198
199 Ok(())
200 }
201}
202
203pub fn parse<'a>(data: &'a str) -> Result<ast::Root, Box<ErrorCell<'a>>> {
204 let lexer = lexer::Lexer::new(data);
205 let parser = java::RootParser::new();
206
207 parser
208 .parse(data, lexer)
209 .map_err(|e| Box::new(ErrorCell::new(data, e)))
210}