@@ -11,7 +11,9 @@ use pest::pratt_parser::Assoc as AssocNew;
1111use pest:: pratt_parser:: { Op , PrattParser } ;
1212use pest:: Parser ;
1313use regex:: Regex ;
14+ use std:: collections:: HashMap ;
1415use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr } ;
16+ use std:: rc:: Rc ;
1517
1618type ParseResult < T > = Result < T , ParseError < Rule > > ;
1719
@@ -61,12 +63,16 @@ impl ATCParser {
6163 }
6264 // matcher = { SOI ~ expression ~ EOI }
6365 #[ allow( clippy:: result_large_err) ] // it's fine as parsing is not the hot path
64- fn parse_matcher ( & mut self , source : & str ) -> ParseResult < Expression > {
66+ fn parse_matcher (
67+ & mut self ,
68+ source : & str ,
69+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
70+ ) -> ParseResult < Expression > {
6571 let pairs = ATCParser :: parse ( Rule :: matcher, source) ?;
6672 let expr_pair = pairs. peek ( ) . unwrap ( ) . into_inner ( ) . peek ( ) . unwrap ( ) ;
6773 let rule = expr_pair. as_rule ( ) ;
6874 match rule {
69- Rule :: expression => parse_expression ( expr_pair, & self . pratt_parser ) ,
75+ Rule :: expression => parse_expression ( expr_pair, & self . pratt_parser , regex_cache ) ,
7076 _ => unreachable ! ( ) ,
7177 }
7278 }
@@ -204,7 +210,10 @@ fn parse_int_literal(pair: Pair<Rule>) -> ParseResult<i64> {
204210
205211// predicate = { lhs ~ binary_operator ~ rhs }
206212#[ allow( clippy:: result_large_err) ] // it's fine as parsing is not the hot path
207- fn parse_predicate ( pair : Pair < Rule > ) -> ParseResult < Predicate > {
213+ fn parse_predicate (
214+ pair : Pair < Rule > ,
215+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
216+ ) -> ParseResult < Predicate > {
208217 let mut pairs = pair. into_inner ( ) ;
209218 let lhs = parse_lhs ( pairs. next ( ) . unwrap ( ) ) ?;
210219 let op = parse_binary_operator ( pairs. next ( ) . unwrap ( ) ) ;
@@ -222,16 +231,19 @@ fn parse_predicate(pair: Pair<Rule>) -> ParseResult<Predicate> {
222231 ) ) ;
223232 } ;
224233
225- let r = Regex :: new ( & s) . map_err ( |e| {
226- ParseError :: new_from_span (
227- ErrorVariant :: CustomError {
228- message : e. to_string ( ) ,
229- } ,
230- rhs_pair. as_span ( ) ,
231- )
232- } ) ?;
234+ let regex_rc = match regex_cache. get ( & s) {
235+ Some ( stored_regex_rc) => stored_regex_rc. clone ( ) ,
236+ None => {
237+ let r = Regex :: new ( & s) . into_parse_result ( & rhs_pair) ?;
238+
239+ let rc = Rc :: new ( r) ;
233240
234- Value :: Regex ( r)
241+ regex_cache. insert ( s, rc. clone ( ) ) ;
242+ rc
243+ }
244+ } ;
245+
246+ Value :: Regex ( regex_rc)
235247 } else {
236248 rhs
237249 } ,
@@ -290,39 +302,53 @@ fn parse_binary_operator(pair: Pair<Rule>) -> BinaryOperator {
290302fn parse_parenthesised_expression (
291303 pair : Pair < Rule > ,
292304 pratt : & PrattParser < Rule > ,
305+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
293306) -> ParseResult < Expression > {
294307 let mut pairs = pair. into_inner ( ) ;
295308 let pair = pairs. next ( ) . unwrap ( ) ;
296309 let rule = pair. as_rule ( ) ;
297310 match rule {
298- Rule :: expression => parse_expression ( pair, pratt) ,
311+ Rule :: expression => parse_expression ( pair, pratt, regex_cache ) ,
299312 Rule :: not_op => Ok ( Expression :: Logical ( Box :: new ( LogicalExpression :: Not (
300- parse_expression ( pairs. next ( ) . unwrap ( ) , pratt) ?,
313+ parse_expression ( pairs. next ( ) . unwrap ( ) , pratt, regex_cache ) ?,
301314 ) ) ) ) ,
302315 _ => unreachable ! ( ) ,
303316 }
304317}
305318
306319// term = { predicate | parenthesised_expression }
307320#[ allow( clippy:: result_large_err) ] // it's fine as parsing is not the hot path
308- fn parse_term ( pair : Pair < Rule > , pratt : & PrattParser < Rule > ) -> ParseResult < Expression > {
321+ fn parse_term (
322+ pair : Pair < Rule > ,
323+ pratt : & PrattParser < Rule > ,
324+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
325+ ) -> ParseResult < Expression > {
309326 let pairs = pair. into_inner ( ) ;
310327 let inner_rule = pairs. peek ( ) . unwrap ( ) ;
311328 let rule = inner_rule. as_rule ( ) ;
312329 match rule {
313- Rule :: predicate => Ok ( Expression :: Predicate ( parse_predicate ( inner_rule) ?) ) ,
314- Rule :: parenthesised_expression => parse_parenthesised_expression ( inner_rule, pratt) ,
330+ Rule :: predicate => Ok ( Expression :: Predicate ( parse_predicate (
331+ inner_rule,
332+ regex_cache,
333+ ) ?) ) ,
334+ Rule :: parenthesised_expression => {
335+ parse_parenthesised_expression ( inner_rule, pratt, regex_cache)
336+ }
315337 _ => unreachable ! ( ) ,
316338 }
317339}
318340
319341// expression = { term ~ ( logical_operator ~ term )* }
320342#[ allow( clippy:: result_large_err) ] // it's fine as parsing is not the hot path
321- fn parse_expression ( pair : Pair < Rule > , pratt : & PrattParser < Rule > ) -> ParseResult < Expression > {
343+ fn parse_expression (
344+ pair : Pair < Rule > ,
345+ pratt : & PrattParser < Rule > ,
346+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
347+ ) -> ParseResult < Expression > {
322348 let pairs = pair. into_inner ( ) ;
323349 pratt
324350 . map_primary ( |operand| match operand. as_rule ( ) {
325- Rule :: term => parse_term ( operand, pratt) ,
351+ Rule :: term => parse_term ( operand, pratt, regex_cache ) ,
326352 _ => unreachable ! ( ) ,
327353 } )
328354 . map_infix ( |lhs, op, rhs| {
@@ -336,8 +362,11 @@ fn parse_expression(pair: Pair<Rule>, pratt: &PrattParser<Rule>) -> ParseResult<
336362}
337363
338364#[ allow( clippy:: result_large_err) ] // it's fine as parsing is not the hot path
339- pub fn parse ( source : & str ) -> ParseResult < Expression > {
340- ATCParser :: new ( ) . parse_matcher ( source)
365+ pub fn parse (
366+ source : & str ,
367+ regex_cache : & mut HashMap < String , Rc < Regex > > ,
368+ ) -> ParseResult < Expression > {
369+ ATCParser :: new ( ) . parse_matcher ( source, regex_cache)
341370}
342371
343372#[ cfg( test) ]
@@ -346,16 +375,19 @@ mod tests {
346375
347376 #[ test]
348377 fn test_bad_syntax ( ) {
378+ let mut regex_cache = HashMap :: new ( ) ;
349379 assert_eq ! (
350- parse( "! a == 1" ) . unwrap_err( ) . to_string( ) ,
380+ parse( "! a == 1" , & mut regex_cache ) . unwrap_err( ) . to_string( ) ,
351381 " --> 1:1\n |\n 1 | ! a == 1\n | ^---\n |\n = expected term"
352382 ) ;
353383 assert_eq ! (
354- parse( "a == 1 || ! b == 2" ) . unwrap_err( ) . to_string( ) ,
384+ parse( "a == 1 || ! b == 2" , & mut regex_cache)
385+ . unwrap_err( )
386+ . to_string( ) ,
355387 " --> 1:11\n |\n 1 | a == 1 || ! b == 2\n | ^---\n |\n = expected term"
356388 ) ;
357389 assert_eq ! (
358- parse( "(a == 1 || b == 2) && ! c == 3" )
390+ parse( "(a == 1 || b == 2) && ! c == 3" , & mut regex_cache )
359391 . unwrap_err( )
360392 . to_string( ) ,
361393 " --> 1:23\n |\n 1 | (a == 1 || b == 2) && ! c == 3\n | ^---\n |\n = expected term"
0 commit comments