16
16
*
17
17
*/
18
18
19
- use std:: str:: FromStr ;
19
+ use std:: { borrow :: Cow , str:: FromStr } ;
20
20
21
21
use nom:: {
22
22
branch:: alt,
23
- bytes:: complete:: { tag , take_until , take_while1} ,
23
+ bytes:: complete:: { is_not , tag , take_while1} ,
24
24
character:: complete:: { char, multispace0, multispace1} ,
25
- combinator:: map,
26
- sequence:: { delimited, separated_pair} ,
27
- IResult ,
25
+ combinator:: { cut, map, value} ,
26
+ error:: { convert_error, VerboseError } ,
27
+ sequence:: { delimited, preceded, separated_pair} ,
28
+ IResult as NomIResult , Parser ,
28
29
} ;
29
30
30
31
use super :: rule:: {
@@ -35,7 +36,69 @@ use super::rule::{
35
36
CompositeRule ,
36
37
} ;
37
38
38
- fn parse_numeric_op ( input : & str ) -> IResult < & str , NumericOperator > {
39
+ type IResult < ' a , O > = NomIResult < & ' a str , O , VerboseError < & ' a str > > ;
40
+
41
+ enum StrFragment < ' a > {
42
+ Escaped ( char ) ,
43
+ Unescaped ( & ' a str ) ,
44
+ }
45
+
46
+ fn parse_escaped_char ( input : & str ) -> IResult < char > {
47
+ preceded (
48
+ char ( '\\' ) ,
49
+ alt ( (
50
+ value ( '"' , char ( '"' ) ) ,
51
+ value ( '\\' , char ( '\\' ) ) ,
52
+ value ( '/' , char ( '/' ) ) ,
53
+ value ( '\n' , char ( 'n' ) ) ,
54
+ value ( '\r' , char ( 'r' ) ) ,
55
+ value ( '\t' , char ( 't' ) ) ,
56
+ value ( '\u{08}' , char ( 'b' ) ) ,
57
+ value ( '\u{0C}' , char ( 'f' ) ) ,
58
+ ) ) ,
59
+ )
60
+ . parse ( input)
61
+ }
62
+
63
+ fn parse_str_char ( input : & str ) -> IResult < StrFragment > {
64
+ alt ( (
65
+ map ( parse_escaped_char, StrFragment :: Escaped ) ,
66
+ map ( is_not ( r#""\"# ) , StrFragment :: Unescaped ) ,
67
+ ) )
68
+ . parse ( input)
69
+ }
70
+
71
+ fn parse_string ( input : & str ) -> IResult < Cow < str > > {
72
+ let mut res = Cow :: Borrowed ( "" ) ;
73
+ let ( mut input, _) = char ( '"' ) . parse ( input) ?;
74
+
75
+ loop {
76
+ match char ( '"' ) . parse ( input) {
77
+ // If it is terminating double quotes then we can return the ok value
78
+ Ok ( ( tail, _) ) => return Ok ( ( tail, res) ) ,
79
+ // Fail to parsing in recoverable variant can mean it is a valid char that is not double quote
80
+ Err ( nom:: Err :: Error ( _) ) => { }
81
+ Err ( err) => return Err ( err) ,
82
+ } ;
83
+
84
+ input = match cut ( parse_str_char) ( input) ? {
85
+ ( tail, StrFragment :: Escaped ( ch) ) => {
86
+ res. to_mut ( ) . push ( ch) ;
87
+ tail
88
+ }
89
+ ( tail, StrFragment :: Unescaped ( s) ) => {
90
+ if res. is_empty ( ) {
91
+ res = Cow :: Borrowed ( s)
92
+ } else {
93
+ res. to_mut ( ) . push_str ( s)
94
+ }
95
+ tail
96
+ }
97
+ } ;
98
+ }
99
+ }
100
+
101
+ fn parse_numeric_op ( input : & str ) -> IResult < NumericOperator > {
39
102
alt ( (
40
103
map ( tag ( "<=" ) , |_| NumericOperator :: LessThanEquals ) ,
41
104
map ( tag ( ">=" ) , |_| NumericOperator :: GreaterThanEquals ) ,
@@ -46,7 +109,7 @@ fn parse_numeric_op(input: &str) -> IResult<&str, NumericOperator> {
46
109
) ) ( input)
47
110
}
48
111
49
- fn parse_string_op ( input : & str ) -> IResult < & str , StringOperator > {
112
+ fn parse_string_op ( input : & str ) -> IResult < StringOperator > {
50
113
alt ( (
51
114
map ( tag ( "!=" ) , |_| StringOperator :: NotExact ) ,
52
115
map ( tag ( "=%" ) , |_| StringOperator :: Contains ) ,
@@ -56,7 +119,7 @@ fn parse_string_op(input: &str) -> IResult<&str, StringOperator> {
56
119
) ) ( input)
57
120
}
58
121
59
- fn parse_numeric_rule ( input : & str ) -> IResult < & str , CompositeRule > {
122
+ fn parse_numeric_rule ( input : & str ) -> IResult < CompositeRule > {
60
123
let ( remaining, key) = map ( parse_identifier, |s : & str | s. to_string ( ) ) ( input) ?;
61
124
let ( remaining, op) = delimited ( multispace0, parse_numeric_op, multispace0) ( remaining) ?;
62
125
let ( remaining, value) = map ( take_while1 ( |c : char | c. is_ascii_digit ( ) ) , |x| {
@@ -73,84 +136,92 @@ fn parse_numeric_rule(input: &str) -> IResult<&str, CompositeRule> {
73
136
) )
74
137
}
75
138
76
- fn parse_string_rule ( input : & str ) -> IResult < & str , CompositeRule > {
139
+ fn parse_string_rule ( input : & str ) -> IResult < CompositeRule > {
77
140
let ( remaining, key) = map ( parse_identifier, |s : & str | s. to_string ( ) ) ( input) ?;
78
141
let ( remaining, op) = delimited ( multispace0, parse_string_op, multispace0) ( remaining) ?;
79
- let ( remaining, value) = map (
80
- delimited ( char ( '"' ) , take_until ( "\" " ) , char ( '"' ) ) ,
81
- |x : & str | x. to_string ( ) ,
82
- ) ( remaining) ?;
142
+ let ( remaining, value) = parse_string ( remaining) ?;
83
143
84
144
Ok ( (
85
145
remaining,
86
146
CompositeRule :: String ( StringRule {
87
147
column : key,
88
148
operator : op,
89
- value,
149
+ value : value . into_owned ( ) ,
90
150
ignore_case : None ,
91
151
} ) ,
92
152
) )
93
153
}
94
154
95
- fn parse_identifier ( input : & str ) -> IResult < & str , & str > {
155
+ fn parse_identifier ( input : & str ) -> IResult < & str > {
96
156
take_while1 ( |c : char | c. is_alphanumeric ( ) || c == '-' || c == '_' ) ( input)
97
157
}
98
158
99
- fn parse_unary_expr ( input : & str ) -> IResult < & str , CompositeRule > {
100
- map ( delimited ( tag ( "!(" ) , parse_expression, char ( ')' ) ) , |x| {
101
- CompositeRule :: Not ( Box :: new ( x) )
102
- } ) ( input)
159
+ fn parse_unary_expr ( input : & str ) -> IResult < CompositeRule > {
160
+ map (
161
+ delimited ( tag ( "!(" ) , cut ( parse_expression) , char ( ')' ) ) ,
162
+ |x| CompositeRule :: Not ( Box :: new ( x) ) ,
163
+ ) ( input)
103
164
}
104
165
105
- fn parse_bracket_expr ( input : & str ) -> IResult < & str , CompositeRule > {
166
+ fn parse_bracket_expr ( input : & str ) -> IResult < CompositeRule > {
106
167
delimited (
107
168
char ( '(' ) ,
108
- delimited ( multispace0, parse_expression, multispace0) ,
109
- char ( ')' ) ,
169
+ delimited ( multispace0, cut ( parse_expression) , multispace0) ,
170
+ cut ( char ( ')' ) ) ,
110
171
) ( input)
111
172
}
112
173
113
- fn parse_and ( input : & str ) -> IResult < & str , CompositeRule > {
174
+ fn parse_and ( input : & str ) -> IResult < CompositeRule > {
114
175
let ( remaining, ( lhs, rhs) ) = separated_pair (
115
176
parse_atom,
116
177
delimited ( multispace1, tag ( "and" ) , multispace1) ,
117
- parse_term,
178
+ cut ( parse_term) ,
118
179
) ( input) ?;
119
180
120
181
Ok ( ( remaining, CompositeRule :: And ( vec ! [ lhs, rhs] ) ) )
121
182
}
122
183
123
- fn parse_or ( input : & str ) -> IResult < & str , CompositeRule > {
184
+ fn parse_or ( input : & str ) -> IResult < CompositeRule > {
124
185
let ( remaining, ( lhs, rhs) ) = separated_pair (
125
186
parse_term,
126
187
delimited ( multispace1, tag ( "or" ) , multispace1) ,
127
- parse_expression,
188
+ cut ( parse_expression) ,
128
189
) ( input) ?;
129
190
130
191
Ok ( ( remaining, CompositeRule :: Or ( vec ! [ lhs, rhs] ) ) )
131
192
}
132
193
133
- fn parse_expression ( input : & str ) -> IResult < & str , CompositeRule > {
194
+ fn parse_expression ( input : & str ) -> IResult < CompositeRule > {
134
195
alt ( ( parse_or, parse_term) ) ( input)
135
196
}
136
- fn parse_term ( input : & str ) -> IResult < & str , CompositeRule > {
197
+
198
+ fn parse_term ( input : & str ) -> IResult < CompositeRule > {
137
199
alt ( ( parse_and, parse_atom) ) ( input)
138
200
}
139
- fn parse_atom ( input : & str ) -> IResult < & str , CompositeRule > {
201
+
202
+ fn parse_atom ( input : & str ) -> IResult < CompositeRule > {
140
203
alt ( (
141
- alt ( ( parse_numeric_rule , parse_string_rule ) ) ,
204
+ alt ( ( parse_string_rule , parse_numeric_rule ) ) ,
142
205
parse_unary_expr,
143
206
parse_bracket_expr,
144
207
) ) ( input)
145
208
}
146
209
147
210
impl FromStr for CompositeRule {
148
- type Err = Box < dyn std :: error :: Error > ;
211
+ type Err = String ;
149
212
150
213
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
151
- parse_expression ( s)
152
- . map ( |( _, x) | x)
153
- . map_err ( |x| x. to_string ( ) . into ( ) )
214
+ let s = s. trim ( ) ;
215
+ let ( remaining, parsed) = parse_expression ( s) . map_err ( |err| match err {
216
+ nom:: Err :: Incomplete ( _) => "Needed more data" . to_string ( ) ,
217
+ nom:: Err :: Error ( err) | nom:: Err :: Failure ( err) => convert_error ( s, err) ,
218
+ } ) ?;
219
+
220
+ if remaining. is_empty ( ) {
221
+ Ok ( parsed)
222
+ } else {
223
+ Err ( format ! ( "Could not parse input \n {}" , remaining) )
224
+ }
154
225
}
155
226
}
156
227
0 commit comments