@@ -5485,6 +5485,111 @@ def testNestedExpressionDoesNotOverwriteParseActions(self):
5485
5485
expr = pp .nested_expr (content = content )
5486
5486
assert content .parseAction [0 ] is orig_pa
5487
5487
5488
+ def testNestedExpressionRandom (self ):
5489
+ import random
5490
+
5491
+ word_chars = pp .alphanums
5492
+
5493
+ def get_random_character (_charset = word_chars + " " ):
5494
+ return random .choice (_charset )
5495
+
5496
+ def create_random_quoted_string ():
5497
+ quote_char = random .choice (('"' , "'" ))
5498
+ yield quote_char
5499
+ yield from (get_random_character () for _ in range (random .randint (0 , 12 )))
5500
+ yield quote_char
5501
+
5502
+ def create_random_nested_expression ():
5503
+ yield "["
5504
+
5505
+ if random .random () < 0.25 :
5506
+ yield from create_random_quoted_string ()
5507
+
5508
+ for _ in range (random .randint (0 , 16 )):
5509
+ rnd = random .random ()
5510
+ if rnd < 0.25 :
5511
+ yield from create_random_quoted_string ()
5512
+ elif rnd < 0.3 :
5513
+ yield from create_random_nested_expression ()
5514
+ else :
5515
+ yield from (get_random_character () for _ in range (random .randint (1 , 4 )))
5516
+
5517
+ if random .random () < 0.25 :
5518
+ yield from create_random_quoted_string ()
5519
+
5520
+ yield "]"
5521
+
5522
+ num_reps = 150
5523
+
5524
+ # simulate nested_expr
5525
+ LBRACK , RBRACK = pp .Suppress .using_each ("[]" )
5526
+ wd = pp .Word (word_chars )
5527
+ qs = pp .quoted_string ()
5528
+ ls = pp .Forward ()
5529
+ ls <<= pp .Group (LBRACK + (qs | ls | wd )[...] + RBRACK )
5530
+
5531
+ def crack_nested_string (s ) -> list :
5532
+ return ls .parse_string (s , parse_all = True ).as_list ()
5533
+
5534
+ expr = pp .nested_expr ('[' , ']' )
5535
+ for _ in range (num_reps ):
5536
+ nested_str = '' .join (create_random_nested_expression ())
5537
+ # print(nested_str)
5538
+ cracked_result = crack_nested_string (nested_str )
5539
+ self .assertParseAndCheckList (
5540
+ expr ,
5541
+ nested_str ,
5542
+ cracked_result ,
5543
+ f"Failed: { nested_str } , expected { cracked_result } " ,
5544
+ verbose = False ,
5545
+ )
5546
+
5547
+ # test multi-character nesting delimiters
5548
+ expr = pp .nested_expr ('<<' , '>>' )
5549
+ for _ in range (num_reps ):
5550
+ nested_str = '' .join (create_random_nested_expression ())
5551
+ # print(nested_str)
5552
+ cracked_result = crack_nested_string (nested_str )
5553
+ nested_str = nested_str .replace ("[" , "<<" ).replace ("]" , ">>" )
5554
+ self .assertParseAndCheckList (
5555
+ expr ,
5556
+ nested_str ,
5557
+ cracked_result ,
5558
+ f"Failed: { nested_str } , expected { cracked_result } " ,
5559
+ verbose = False ,
5560
+ )
5561
+
5562
+ # test with no ignore_expr (no quoted string handling)
5563
+ expr = pp .nested_expr ('[' , ']' , ignore_expr = None )
5564
+ for _ in range (num_reps ):
5565
+ nested_str = '' .join (create_random_nested_expression ())
5566
+ nested_str = nested_str .replace ('"' , "" ).replace ("'" , "" )
5567
+ # print(nested_str)
5568
+ cracked_result = crack_nested_string (nested_str )
5569
+ self .assertParseAndCheckList (
5570
+ expr ,
5571
+ nested_str ,
5572
+ cracked_result ,
5573
+ f"Failed: { nested_str } , expected { cracked_result } " ,
5574
+ verbose = False ,
5575
+ )
5576
+
5577
+ # test multi-character nesting delimiters, with no ignore_expr
5578
+ expr = pp .nested_expr ('<<' , '>>' , ignore_expr = None )
5579
+ for _ in range (num_reps ):
5580
+ nested_str = '' .join (create_random_nested_expression ())
5581
+ nested_str = nested_str .replace ('"' , "" ).replace ("'" , "" )
5582
+ # print(nested_str)
5583
+ cracked_result = crack_nested_string (nested_str )
5584
+ nested_str = nested_str .replace ("[" , "<<" ).replace ("]" , ">>" )
5585
+ self .assertParseAndCheckList (
5586
+ expr ,
5587
+ nested_str ,
5588
+ cracked_result ,
5589
+ f"Failed: { nested_str } , expected { cracked_result } " ,
5590
+ verbose = False ,
5591
+ )
5592
+
5488
5593
def testWordMinMaxArgs (self ):
5489
5594
parsers = [
5490
5595
"A" + pp .Word (pp .nums ),
0 commit comments