@@ -47,8 +47,8 @@ def parse(source, filename='<unknown>', mode='exec', *,
4747 elif feature_version is None :
4848 feature_version = - 1
4949 # Else it should be an int giving the minor version for 3.x.
50- return compile (source , filename , mode , flags )
51- # _feature_version=feature_version)
50+ return compile (source , filename , mode , flags ,
51+ _feature_version = feature_version )
5252
5353
5454def literal_eval (node_or_string ):
@@ -59,11 +59,14 @@ def literal_eval(node_or_string):
5959 sets, booleans, and None.
6060 """
6161 if isinstance (node_or_string , str ):
62- node_or_string = parse (node_or_string , mode = 'eval' )
62+ node_or_string = parse (node_or_string . lstrip ( " \t " ) , mode = 'eval' )
6363 if isinstance (node_or_string , Expression ):
6464 node_or_string = node_or_string .body
6565 def _raise_malformed_node (node ):
66- raise ValueError (f'malformed node or string: { node !r} ' )
66+ msg = "malformed node or string"
67+ if lno := getattr (node , 'lineno' , None ):
68+ msg += f' on line { lno } '
69+ raise ValueError (msg + f': { node !r} ' )
6770 def _convert_num (node ):
6871 if not isinstance (node , Constant ) or type (node .value ) not in (int , float , complex ):
6972 _raise_malformed_node (node )
@@ -794,6 +797,9 @@ def traverse(self, node):
794797 else :
795798 super ().visit (node )
796799
800+ # Note: as visit() resets the output text, do NOT rely on
801+ # NodeVisitor.generic_visit to handle any nodes (as it calls back in to
802+ # the subclass visit() method, which resets self._source to an empty list)
797803 def visit (self , node ):
798804 """Outputs a source code string that, if converted back to an ast
799805 (using ast.parse) will generate an AST equivalent to *node*"""
@@ -1483,6 +1489,13 @@ def visit_Slice(self, node):
14831489 self .write (":" )
14841490 self .traverse (node .step )
14851491
1492+ def visit_Match (self , node ):
1493+ self .fill ("match " )
1494+ self .traverse (node .subject )
1495+ with self .block ():
1496+ for case in node .cases :
1497+ self .traverse (case )
1498+
14861499 def visit_arg (self , node ):
14871500 self .write (node .arg )
14881501 if node .annotation :
@@ -1567,6 +1580,94 @@ def visit_withitem(self, node):
15671580 self .write (" as " )
15681581 self .traverse (node .optional_vars )
15691582
1583+ def visit_match_case (self , node ):
1584+ self .fill ("case " )
1585+ self .traverse (node .pattern )
1586+ if node .guard :
1587+ self .write (" if " )
1588+ self .traverse (node .guard )
1589+ with self .block ():
1590+ self .traverse (node .body )
1591+
1592+ def visit_MatchValue (self , node ):
1593+ self .traverse (node .value )
1594+
1595+ def visit_MatchSingleton (self , node ):
1596+ self ._write_constant (node .value )
1597+
1598+ def visit_MatchSequence (self , node ):
1599+ with self .delimit ("[" , "]" ):
1600+ self .interleave (
1601+ lambda : self .write (", " ), self .traverse , node .patterns
1602+ )
1603+
1604+ def visit_MatchStar (self , node ):
1605+ name = node .name
1606+ if name is None :
1607+ name = "_"
1608+ self .write (f"*{ name } " )
1609+
1610+ def visit_MatchMapping (self , node ):
1611+ def write_key_pattern_pair (pair ):
1612+ k , p = pair
1613+ self .traverse (k )
1614+ self .write (": " )
1615+ self .traverse (p )
1616+
1617+ with self .delimit ("{" , "}" ):
1618+ keys = node .keys
1619+ self .interleave (
1620+ lambda : self .write (", " ),
1621+ write_key_pattern_pair ,
1622+ zip (keys , node .patterns , strict = True ),
1623+ )
1624+ rest = node .rest
1625+ if rest is not None :
1626+ if keys :
1627+ self .write (", " )
1628+ self .write (f"**{ rest } " )
1629+
1630+ def visit_MatchClass (self , node ):
1631+ self .set_precedence (_Precedence .ATOM , node .cls )
1632+ self .traverse (node .cls )
1633+ with self .delimit ("(" , ")" ):
1634+ patterns = node .patterns
1635+ self .interleave (
1636+ lambda : self .write (", " ), self .traverse , patterns
1637+ )
1638+ attrs = node .kwd_attrs
1639+ if attrs :
1640+ def write_attr_pattern (pair ):
1641+ attr , pattern = pair
1642+ self .write (f"{ attr } =" )
1643+ self .traverse (pattern )
1644+
1645+ if patterns :
1646+ self .write (", " )
1647+ self .interleave (
1648+ lambda : self .write (", " ),
1649+ write_attr_pattern ,
1650+ zip (attrs , node .kwd_patterns , strict = True ),
1651+ )
1652+
1653+ def visit_MatchAs (self , node ):
1654+ name = node .name
1655+ pattern = node .pattern
1656+ if name is None :
1657+ self .write ("_" )
1658+ elif pattern is None :
1659+ self .write (node .name )
1660+ else :
1661+ with self .require_parens (_Precedence .TEST , node ):
1662+ self .set_precedence (_Precedence .BOR , node .pattern )
1663+ self .traverse (node .pattern )
1664+ self .write (f" as { node .name } " )
1665+
1666+ def visit_MatchOr (self , node ):
1667+ with self .require_parens (_Precedence .BOR , node ):
1668+ self .set_precedence (_Precedence .BOR .next (), * node .patterns )
1669+ self .interleave (lambda : self .write (" | " ), self .traverse , node .patterns )
1670+
15701671def unparse (ast_obj ):
15711672 unparser = _Unparser ()
15721673 return unparser .visit (ast_obj )
0 commit comments