@@ -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
223227pub 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