2021-11-04 14:22:35 +01:00
use std ::fmt ::Display ;
2021-11-04 16:12:17 +01:00
use nom ::error ::{ self , ParseError } ;
use nom ::Parser ;
2021-11-04 14:22:35 +01:00
use crate ::{ IResult , Span } ;
2021-11-09 00:50:15 +01:00
pub trait NomErrorExt < E > {
2021-11-04 14:22:35 +01:00
fn is_failure ( & self ) -> bool ;
fn map_err < O : FnOnce ( E ) -> E > ( self , op : O ) -> nom ::Err < E > ;
fn map_fail < O : FnOnce ( E ) -> E > ( self , op : O ) -> nom ::Err < E > ;
}
2021-11-09 00:50:15 +01:00
impl < E > NomErrorExt < E > for nom ::Err < E > {
2021-11-04 14:22:35 +01:00
fn is_failure ( & self ) -> bool {
matches! ( self , Self ::Failure ( _ ) )
}
fn map_err < O : FnOnce ( E ) -> E > ( self , op : O ) -> nom ::Err < E > {
match self {
e @ Self ::Failure ( _ ) = > e ,
2022-01-10 15:59:04 +01:00
e = > e . map ( op ) ,
2021-11-04 14:22:35 +01:00
}
}
fn map_fail < O : FnOnce ( E ) -> E > ( self , op : O ) -> nom ::Err < E > {
match self {
e @ Self ::Error ( _ ) = > e ,
2022-01-10 15:59:04 +01:00
e = > e . map ( op ) ,
2021-11-04 14:22:35 +01:00
}
}
}
/// cut a parser and map the error
2021-11-04 16:12:17 +01:00
pub fn cut_with_err < ' a , O > (
mut parser : impl FnMut ( Span < ' a > ) -> IResult < O > ,
mut with : impl FnMut ( Error < ' a > ) -> Error < ' a > ,
) -> impl FnMut ( Span < ' a > ) -> IResult < O > {
move | input | match parser . parse ( input ) {
Err ( nom ::Err ::Error ( e ) ) = > Err ( nom ::Err ::Failure ( with ( e ) ) ) ,
rest = > rest ,
}
2021-11-04 14:22:35 +01:00
}
#[ derive(Debug) ]
pub struct Error < ' a > {
context : Span < ' a > ,
kind : ErrorKind < ' a > ,
}
#[ derive(Debug) ]
pub enum ErrorKind < ' a > {
ReservedGeo ( & ' a str ) ,
Geo ,
MisusedGeo ,
InvalidPrimary ,
ExpectedEof ,
ExpectedValue ,
2021-12-20 16:18:15 +01:00
MalformedValue ,
2021-11-04 14:22:35 +01:00
MissingClosingDelimiter ( char ) ,
Char ( char ) ,
2021-11-04 16:12:17 +01:00
InternalError ( error ::ErrorKind ) ,
External ( String ) ,
2021-11-04 14:22:35 +01:00
}
impl < ' a > Error < ' a > {
2021-11-04 16:20:53 +01:00
pub fn kind ( & self ) -> & ErrorKind < ' a > {
& self . kind
}
2021-11-08 15:30:26 +01:00
pub fn context ( & self ) -> & Span < ' a > {
& self . context
}
2021-11-04 16:20:53 +01:00
pub fn new_from_kind ( context : Span < ' a > , kind : ErrorKind < ' a > ) -> Self {
2021-11-04 14:22:35 +01:00
Self { context , kind }
}
2021-11-04 16:20:53 +01:00
2021-11-04 17:24:55 +01:00
pub fn new_from_external ( context : Span < ' a > , error : impl std ::error ::Error ) -> Self {
Self ::new_from_kind ( context , ErrorKind ::External ( error . to_string ( ) ) )
}
2021-11-04 14:22:35 +01:00
pub fn char ( self ) -> char {
match self . kind {
ErrorKind ::Char ( c ) = > c ,
2021-12-20 16:18:15 +01:00
error = > panic! ( " Internal filter parser error: {:?} " , error ) ,
2021-11-04 14:22:35 +01:00
}
2021-11-04 16:12:17 +01:00
}
2021-11-04 14:22:35 +01:00
}
impl < ' a > ParseError < Span < ' a > > for Error < ' a > {
fn from_error_kind ( input : Span < ' a > , kind : error ::ErrorKind ) -> Self {
let kind = match kind {
error ::ErrorKind ::Eof = > ErrorKind ::ExpectedEof ,
2021-11-04 16:12:17 +01:00
kind = > ErrorKind ::InternalError ( kind ) ,
2021-11-04 14:22:35 +01:00
} ;
Self { context : input , kind }
}
fn append ( _input : Span < ' a > , _kind : error ::ErrorKind , other : Self ) -> Self {
other
}
fn from_char ( input : Span < ' a > , c : char ) -> Self {
Self { context : input , kind : ErrorKind ::Char ( c ) }
}
}
impl < ' a > Display for Error < ' a > {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
let input = self . context . fragment ( ) ;
2021-11-09 11:19:30 +01:00
// When printing our error message we want to escape all `\n` to be sure we keep our format with the
// first line being the diagnostic and the second line being the incriminated filter.
let escaped_input = input . escape_debug ( ) ;
2021-11-04 14:22:35 +01:00
match self . kind {
ErrorKind ::ExpectedValue if input . trim ( ) . is_empty ( ) = > {
writeln! ( f , " Was expecting a value but instead got nothing. " ) ?
}
2021-12-20 16:18:15 +01:00
ErrorKind ::MalformedValue = > {
writeln! ( f , " Malformed value: `{}`. " , escaped_input ) ?
}
2021-11-04 16:12:17 +01:00
ErrorKind ::MissingClosingDelimiter ( c ) = > {
2021-11-09 11:19:30 +01:00
writeln! ( f , " Expression `{}` is missing the following closing delimiter: `{}`. " , escaped_input , c ) ?
2021-11-04 14:22:35 +01:00
}
ErrorKind ::ExpectedValue = > {
2021-11-09 11:19:30 +01:00
writeln! ( f , " Was expecting a value but instead got `{}`. " , escaped_input ) ?
2021-11-04 14:22:35 +01:00
}
ErrorKind ::InvalidPrimary if input . trim ( ) . is_empty ( ) = > {
writeln! ( f , " Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `TO` or `_geoRadius` but instead got nothing. " ) ?
}
ErrorKind ::InvalidPrimary = > {
2021-11-09 11:19:30 +01:00
writeln! ( f , " Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `TO` or `_geoRadius` at `{}`. " , escaped_input ) ?
2021-11-04 14:22:35 +01:00
}
ErrorKind ::ExpectedEof = > {
2021-11-09 11:19:30 +01:00
writeln! ( f , " Found unexpected characters at the end of the filter: `{}`. You probably forgot an `OR` or an `AND` rule. " , escaped_input ) ?
2021-11-04 14:22:35 +01:00
}
ErrorKind ::Geo = > {
writeln! ( f , " The `_geoRadius` filter expects three arguments: `_geoRadius(latitude, longitude, radius)`. " ) ?
}
ErrorKind ::ReservedGeo ( name ) = > {
2021-11-09 11:19:30 +01:00
writeln! ( f , " `{}` is a reserved keyword and thus can't be used as a filter expression. Use the `_geoRadius(latitude, longitude, distance) built-in rule to filter on `_geo` coordinates. " , name . escape_debug ( ) ) ?
2021-11-04 14:22:35 +01:00
}
ErrorKind ::MisusedGeo = > {
writeln! ( f , " The `_geoRadius` filter is an operation and can't be used as a value. " ) ?
}
ErrorKind ::Char ( c ) = > {
panic! ( " Tried to display a char error with ` {} ` " , c )
}
2021-11-04 16:12:17 +01:00
ErrorKind ::InternalError ( kind ) = > writeln! (
2021-11-04 14:22:35 +01:00
f ,
2021-11-04 16:12:17 +01:00
" Encountered an internal `{:?}` error while parsing your filter. Please fill an issue " , kind
2021-11-04 14:22:35 +01:00
) ? ,
2021-11-04 16:12:17 +01:00
ErrorKind ::External ( ref error ) = > writeln! ( f , " {} " , error ) ? ,
2021-11-04 14:22:35 +01:00
}
2021-11-09 10:27:29 +01:00
let base_column = self . context . get_utf8_column ( ) ;
let size = self . context . fragment ( ) . chars ( ) . count ( ) ;
2021-11-09 11:19:30 +01:00
write! ( f , " {}:{} {} " , base_column , base_column + size , self . context . extra )
2021-11-04 14:22:35 +01:00
}
}