@@ -196,9 +196,9 @@ def pairs(self, prod):
196196 def pairs (self , prod ):
197197 return [prod .pair ]
198198
199- @_ ('ident COLON expr' )
199+ @_ ('ident COLON expr' , 'ident EQUALS expr' )
200200 def pair (self , prod ):
201- return (prod .ident , prod .expr )
201+ return (prod .ident , MapValue ( prod [ 1 ], prod .expr ) )
202202
203203 @_ ('ident' , 'binary_operator' , 'map' , 'list' , 'string' , 'integer' , 'bool' )
204204 def expr (self , prod ):
@@ -272,6 +272,9 @@ def is_map(self):
272272 def is_list (self ):
273273 return False
274274
275+ def is_map_value (self ):
276+ return False
277+
275278 def is_ident (self ):
276279 return False
277280
@@ -390,6 +393,12 @@ def to_str(self, pretty=True, indent=4, depth=0):
390393 def is_binary_operator (self ):
391394 return True
392395
396+ def str_op (self , cmp ):
397+ return (
398+ (self .lhs .is_string () and self .lhs .str_op (cmp ))
399+ or (self .rhs .is_string () and self .rhs .str_op (cmp ))
400+ )
401+
393402 def __eq__ (self , other ):
394403 return (self .lhs , self .op , self .rhs ) == (other .lhs , other .op , other .rhs )
395404
@@ -434,7 +443,7 @@ def __str__(self):
434443 def to_str (self , pretty = True , indent = 4 , depth = 0 ):
435444 fmt = lambda x : x .to_str (pretty , indent , depth + 1 )
436445 result = '{'
437- pairs = [f'{ fmt (k )} : { fmt (v )} ' for k , v in self .items ()]
446+ pairs = [f'{ fmt (k )} { fmt (v )} ' for k , v in self .items ()]
438447 if len (self ) == 0 :
439448 result += '}'
440449 elif pretty :
@@ -454,13 +463,13 @@ def is_test(self):
454463 name = self .get ('name' )
455464 if name is None :
456465 return False
457- return 'test' in name .lower ()
466+ return 'test' in name .value . lower ()
458467
459468 def is_benchmark (self ):
460469 name = self .get ('name' )
461470 if name is None :
462471 return False
463- return 'benchmark' in name .lower ()
472+ return 'benchmark' in name .value . lower ()
464473
465474 def is_dev (self ):
466475 return self .is_test () or self .is_benchmark ()
@@ -475,8 +484,8 @@ def recurse(self, max_depth=-1, depth=0):
475484 if depth != max_depth :
476485 for key , value in self .items ():
477486 yield (key , value , depth + 1 , self )
478- if value .is_map ():
479- yield from value .recurse (max_depth , depth + 1 )
487+ if value .value . is_map ():
488+ yield from value .value . recurse (max_depth , depth + 1 )
480489
481490
482491class List (list , Node ):
@@ -507,6 +516,41 @@ def filter(self, op):
507516 self [:] = [i for i in self if op (i )]
508517
509518
519+ class MapValue (Node ):
520+ def __init__ (self , delimiter , value ):
521+ # map key/value separators can be `:` or `=`.
522+ assert delimiter in (':' , '=' )
523+ self .delimiter = delimiter
524+ self .value = value
525+
526+ def __repr__ (self ):
527+ return f'MapValue({ str (self )} )'
528+
529+ def __str__ (self ):
530+ return self .to_str (False )
531+
532+ def __eq__ (self , other ):
533+ # delimiter doesn't matter for equality comparison
534+ if isinstance (other , MapValue ):
535+ return self .value == other .value
536+ return self .value == other
537+
538+ def __len__ (self ):
539+ return len (self .value )
540+
541+ def to_str (self , pretty = True , indent = 4 , depth = 0 ):
542+ value = self .value .to_str (pretty , indent , depth )
543+ if self .delimiter == '=' :
544+ return f' = { value } '
545+ return f': { value } '
546+
547+ def is_map_value (self ):
548+ return True
549+
550+ def filter (self , op ):
551+ self .value .filter (op )
552+
553+
510554class Ident (str , Node ):
511555 def __repr__ (self ):
512556 return f'Ident({ str (self )} )'
@@ -528,6 +572,9 @@ def __repr__(self):
528572 def to_str (self , * _ , ** __ ):
529573 return f'{ super ().__str__ ()} '
530574
575+ def str_op (self , cmp ):
576+ return cmp (self )
577+
531578 def __str__ (self ):
532579 # `"target"` should be shown as `'target'`, not `'"target"'`
533580 return super ().__str__ ()[1 :- 1 ]
0 commit comments