@@ -217,7 +217,11 @@ impl fmt::Display for Whitespace {
217
217
218
218
/// Tokenizer error
219
219
#[ 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
+ }
221
225
222
226
/// SQL Tokenizer
223
227
pub struct Tokenizer < ' a > {
@@ -331,10 +335,10 @@ impl<'a> Tokenizer<'a> {
331
335
if chars. next ( ) == Some ( quote_end) {
332
336
Ok ( Some ( Token :: make_word ( & s, Some ( quote_start) ) ) )
333
337
} 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
+ )
338
342
}
339
343
}
340
344
// numbers
@@ -395,10 +399,7 @@ impl<'a> Tokenizer<'a> {
395
399
chars. next ( ) ; // consume
396
400
match chars. peek ( ) {
397
401
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" ) ,
402
403
}
403
404
}
404
405
'<' => {
@@ -437,6 +438,14 @@ impl<'a> Tokenizer<'a> {
437
438
}
438
439
}
439
440
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
+
440
449
/// Tokenize an identifier or keyword, after the first char is already consumed.
441
450
fn tokenize_word ( & self , first_char : char , chars : & mut Peekable < Chars < ' _ > > ) -> String {
442
451
let mut s = first_char. to_string ( ) ;
@@ -471,10 +480,7 @@ impl<'a> Tokenizer<'a> {
471
480
}
472
481
}
473
482
}
474
- Err ( TokenizerError ( format ! (
475
- "Unterminated string literal at Line: {}, Col: {}" ,
476
- self . line, self . col
477
- ) ) )
483
+ self . tokenizer_error ( "Unterminated string literal" )
478
484
}
479
485
480
486
fn tokenize_multiline_comment (
@@ -499,11 +505,7 @@ impl<'a> Tokenizer<'a> {
499
505
s. push ( ch) ;
500
506
}
501
507
}
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" ) ,
507
509
}
508
510
}
509
511
}
@@ -720,9 +722,11 @@ mod tests {
720
722
let mut tokenizer = Tokenizer :: new ( & dialect, & sql) ;
721
723
assert_eq ! (
722
724
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
+ } )
726
730
) ;
727
731
}
728
732
@@ -843,9 +847,11 @@ mod tests {
843
847
let mut tokenizer = Tokenizer :: new ( & dialect, & sql) ;
844
848
assert_eq ! (
845
849
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
+ } )
849
855
) ;
850
856
}
851
857
0 commit comments