Skip to content

Commit d842f49

Browse files
authored
Add line and column number to TokenizerError (#194)
Addresses https://github.com/andygrove/sqlparser-rs/issues/179 for tokenize errors
1 parent 10b0b7f commit d842f49

File tree

2 files changed

+34
-25
lines changed

2 files changed

+34
-25
lines changed

src/parser.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ use IsLateral::*;
4949

5050
impl From<TokenizerError> for ParserError {
5151
fn from(e: TokenizerError) -> Self {
52-
ParserError::TokenizerError(format!("{:?}", e))
52+
ParserError::TokenizerError(format!(
53+
"{} at Line: {}, Column {}",
54+
e.message, e.line, e.col
55+
))
5356
}
5457
}
5558

src/tokenizer.rs

+30-24
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,11 @@ impl fmt::Display for Whitespace {
217217

218218
/// Tokenizer error
219219
#[derive(Debug, PartialEq)]
220-
pub struct TokenizerError(String);
220+
pub struct TokenizerError {
221+
pub message: String,
222+
pub line: u64,
223+
pub col: u64,
224+
}
221225

222226
/// SQL Tokenizer
223227
pub struct Tokenizer<'a> {
@@ -331,10 +335,10 @@ impl<'a> Tokenizer<'a> {
331335
if chars.next() == Some(quote_end) {
332336
Ok(Some(Token::make_word(&s, Some(quote_start))))
333337
} else {
334-
Err(TokenizerError(format!(
335-
"Expected close delimiter '{}' before EOF.",
336-
quote_end
337-
)))
338+
self.tokenizer_error(
339+
format!("Expected close delimiter '{}' before EOF.", quote_end)
340+
.as_str(),
341+
)
338342
}
339343
}
340344
// numbers
@@ -395,10 +399,7 @@ impl<'a> Tokenizer<'a> {
395399
chars.next(); // consume
396400
match chars.peek() {
397401
Some('=') => self.consume_and_return(chars, Token::Neq),
398-
_ => Err(TokenizerError(format!(
399-
"Tokenizer Error at Line: {}, Col: {}",
400-
self.line, self.col
401-
))),
402+
_ => self.tokenizer_error("Expected to see '=' after '!' character"),
402403
}
403404
}
404405
'<' => {
@@ -437,6 +438,14 @@ impl<'a> Tokenizer<'a> {
437438
}
438439
}
439440

441+
fn tokenizer_error<R>(&self, message: &str) -> Result<R, TokenizerError> {
442+
Err(TokenizerError {
443+
message: message.to_string(),
444+
col: self.col,
445+
line: self.line,
446+
})
447+
}
448+
440449
/// Tokenize an identifier or keyword, after the first char is already consumed.
441450
fn tokenize_word(&self, first_char: char, chars: &mut Peekable<Chars<'_>>) -> String {
442451
let mut s = first_char.to_string();
@@ -471,10 +480,7 @@ impl<'a> Tokenizer<'a> {
471480
}
472481
}
473482
}
474-
Err(TokenizerError(format!(
475-
"Unterminated string literal at Line: {}, Col: {}",
476-
self.line, self.col
477-
)))
483+
self.tokenizer_error("Unterminated string literal")
478484
}
479485

480486
fn tokenize_multiline_comment(
@@ -499,11 +505,7 @@ impl<'a> Tokenizer<'a> {
499505
s.push(ch);
500506
}
501507
}
502-
None => {
503-
break Err(TokenizerError(
504-
"Unexpected EOF while in a multi-line comment".to_string(),
505-
));
506-
}
508+
None => break self.tokenizer_error("Unexpected EOF while in a multi-line comment"),
507509
}
508510
}
509511
}
@@ -720,9 +722,11 @@ mod tests {
720722
let mut tokenizer = Tokenizer::new(&dialect, &sql);
721723
assert_eq!(
722724
tokenizer.tokenize(),
723-
Err(TokenizerError(
724-
"Unterminated string literal at Line: 1, Col: 8".to_string()
725-
))
725+
Err(TokenizerError {
726+
message: "Unterminated string literal".to_string(),
727+
line: 1,
728+
col: 8
729+
})
726730
);
727731
}
728732

@@ -843,9 +847,11 @@ mod tests {
843847
let mut tokenizer = Tokenizer::new(&dialect, &sql);
844848
assert_eq!(
845849
tokenizer.tokenize(),
846-
Err(TokenizerError(
847-
"Expected close delimiter '\"' before EOF.".to_string(),
848-
))
850+
Err(TokenizerError {
851+
message: "Expected close delimiter '\"' before EOF.".to_string(),
852+
line: 1,
853+
col: 1
854+
})
849855
);
850856
}
851857

0 commit comments

Comments
 (0)