Author: Carl Friedrich Bolz-Tereick <[email protected]>
Branch: py3.7
Changeset: r98454:1758bd2014d8
Date: 2020-01-06 13:47 +0100
http://bitbucket.org/pypy/pypy/changeset/1758bd2014d8/

Log:    fstring support

diff --git a/pypy/interpreter/astcompiler/test/test_unparse.py 
b/pypy/interpreter/astcompiler/test/test_unparse.py
--- a/pypy/interpreter/astcompiler/test/test_unparse.py
+++ b/pypy/interpreter/astcompiler/test/test_unparse.py
@@ -154,6 +154,17 @@
         self.check('lambda **foo: 1')
         self.check('lambda a, **b: 45')
 
+    def test_fstrings(self):
+        #self.check('f"abc"', '"abc"')
+        self.check("f'{{{a}'", "f'{{{a}'")
+        self.check("f'{{{a}'", "f'{{{a}'")
+        self.check("f'{x+1!a}'", "f'{x + 1!a}'")
+        self.check("f'{x+1:x}'", "f'{x + 1:x}'")
+        self.check("f'some f-string with {a} {few():.2f} 
{formatted.values!r}'")
+        self.check('''f"{f'{nested} inner'} outer"''')
+        self.check("f'space between opening braces: { {a for a in (1, 2, 
3)}}'")
+        self.check("f'{(lambda x: x)}'")
+        self.check("f'{(None if a else lambda x: x)}'")
 
 class TestAstUnparseAnnotations(object):
     def setup_class(cls):
diff --git a/pypy/interpreter/astcompiler/unparse.py 
b/pypy/interpreter/astcompiler/unparse.py
--- a/pypy/interpreter/astcompiler/unparse.py
+++ b/pypy/interpreter/astcompiler/unparse.py
@@ -23,6 +23,7 @@
 PRIORITY_AWAIT = 15                 # 'await'
 PRIORITY_ATOM = 16
 
+
 class Parenthesizer(object):
     def __init__(self, visitor, priority):
         self.visitor = visitor
@@ -40,16 +41,10 @@
         if level > self.priority:
             visitor.append_ascii(")")
 
-
-
-class UnparseVisitor(ast.ASTVisitor):
+class Utf8BuilderVisitor(ast.ASTVisitor):
     def __init__(self, space):
         self.space = space
         self.builder = Utf8StringBuilder()
-        self.level = PRIORITY_TEST
-
-    def maybe_parenthesize(self, priority):
-        return Parenthesizer(self, priority)
 
     def append_w_str(self, w_s):
         s, l = self.space.utf8_len_w(w_s)
@@ -61,6 +56,15 @@
     def append_utf8(self, s):
         self.builder.append(s)
 
+
+class UnparseVisitor(Utf8BuilderVisitor):
+    def __init__(self, space, startlevel=PRIORITY_TEST):
+        Utf8BuilderVisitor.__init__(self, space)
+        self.level = startlevel
+
+    def maybe_parenthesize(self, priority):
+        return Parenthesizer(self, priority)
+
     def append_expr(self, node, priority=PRIORITY_TEST):
         level = self.level
         self.level = priority
@@ -175,7 +179,7 @@
             self.append_expr(node.left, priority + right_associative)
             self.append_ascii(op)
             self.append_expr(node.right, priority + (not right_associative))
-            
+
     def visit_BoolOp(self, node):
         if node.op == ast.And:
             op = " and "
@@ -448,14 +452,66 @@
                 self.append_ascii(': ')
             self.append_expr(node.body)
 
+    def visit_JoinedStr(self, node):
+        # mess
+        subvisitor = FstringVisitor(self.space)
+        for i, elt in enumerate(node.values):
+            elt.walkabout(subvisitor)
+        s = subvisitor.builder.build()
+        l = subvisitor.builder.getlength()
+        self.append_ascii("f")
+        self.append_w_str(self.space.repr(self.space.newutf8(s, l)))
 
-def unparse(space, ast):
-    visitor = UnparseVisitor(space)
+
+class FstringVisitor(Utf8BuilderVisitor):
+
+    def default_visitor(self, node):
+        raise OperationError(self.space.w_SystemError,
+                self.space.newtext("expression type not supported yet:" + 
str(node)))
+
+    def visit_Str(self, node):
+        s, l = self.space.utf8_len_w(node.s)
+        s = s.replace("{", "{{")
+        s = s.replace("}", "}}")
+        self.append_utf8(s)
+
+    def visit_FormattedValue(self, node):
+        outer_brace = "{"
+        s = unparse(self.space, node.value, PRIORITY_TEST + 1)
+        if s.startswith("{"):
+            outer_brace = "{ "
+        self.append_ascii(outer_brace)
+        self.append_utf8(s)
+        conversion = node.conversion
+        if conversion >= 0:
+            if conversion == ord('a'):
+                conversion = '!a'
+            elif conversion == ord('r'):
+                conversion = '!r'
+            elif conversion == ord('s'):
+                conversion = '!s'
+            else:
+                raise oefmt(self.space.w_SystemError,
+                    "unknown f-string conversion kind %s", chr(conversion))
+            self.append_ascii(conversion)
+
+        if node.format_spec:
+            self.append_ascii(":")
+            node.format_spec.walkabout(self)
+        self.append_ascii("}")
+
+    def visit_JoinedStr(self, node):
+        for i, elt in enumerate(node.values):
+            elt.walkabout(self)
+
+
+def unparse(space, ast, level=PRIORITY_TEST):
+    visitor = UnparseVisitor(space, level)
     ast.walkabout(visitor)
     return visitor.builder.build()
 
-def w_unparse(space, ast):
-    visitor = UnparseVisitor(space)
+def w_unparse(space, ast, level=PRIORITY_TEST):
+    visitor = UnparseVisitor(space, level)
     ast.walkabout(visitor)
     return space.newutf8(visitor.builder.build(), visitor.builder.getlength())
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to