Author: Armin Rigo <[email protected]>
Branch: py3.5-fstring-pep498
Changeset: r89698:19d22e69d149
Date: 2017-01-22 23:07 +0100
http://bitbucket.org/pypy/pypy/changeset/19d22e69d149/

Log:    conversions (!s, !r, !a)

diff --git a/pypy/interpreter/astcompiler/astbuilder.py 
b/pypy/interpreter/astcompiler/astbuilder.py
--- a/pypy/interpreter/astcompiler/astbuilder.py
+++ b/pypy/interpreter/astcompiler/astbuilder.py
@@ -1249,18 +1249,26 @@
                 break     # normal way out of this loop
             # XXX forbid comment, but how?
         else:
-            raise self.error("f-string: unterminated '{' expression")
+            ch = u'\x00'
+        #
         if nested_depth > 0:
-            self.error("f-string: mismatched '(', '{' or '['")
+            self.error("f-string: mismatched '(', '{' or '['", atom_node)
+        end_expression = p - 1
         if ch == u'!':
-            XXX
+            if p + 1 < len(u):
+                conversion = ord(u[p])
+                ch = u[p + 1]
+                p += 2
+            if conversion not in (ord('s'), ord('r'), ord('a')):
+                self.error("f-string: invalid conversion character: "
+                           "expected 's', 'r', or 'a'", atom_node)
         if ch == u':':
             XXX
-        assert ch == u'}'
+        if ch != u'}':
+            self.error("f-string: expecting '}'", atom_node)
         end_f_string = p
-        p -= 1      # drop the final '}'
-        assert p >= start
-        expr = self._f_string_compile(u[start:p], atom_node)
+        assert end_expression >= start
+        expr = self._f_string_compile(u[start:end_expression], atom_node)
         assert isinstance(expr, ast.Expression)
         fval = ast.FormattedValue(expr.body, conversion, format_spec,
                                   atom_node.get_lineno(),
@@ -1284,7 +1292,7 @@
                                             atom_node)
                     start = pn + 1
                 else:
-                    self.error("f-string: unexpected '}'", atom_node)
+                    self.error("f-string: single '}' is not allowed", 
atom_node)
                 continue
             self._f_constant_string(joined_pieces, u[start:p1], atom_node)
             if p1 == len(u):
diff --git a/pypy/interpreter/astcompiler/codegen.py 
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -1499,7 +1499,11 @@
 
     def visit_FormattedValue(self, fmt):
         fmt.value.walkabout(self)
-        self.emit_op_arg(ops.FORMAT_VALUE, 0)
+        arg = 0
+        if fmt.conversion == ord('s'): arg = consts.FVC_STR
+        if fmt.conversion == ord('r'): arg = consts.FVC_REPR
+        if fmt.conversion == ord('a'): arg = consts.FVC_ASCII
+        self.emit_op_arg(ops.FORMAT_VALUE, arg)
 
 
 class TopLevelCodeGenerator(PythonCodeGenerator):
diff --git a/pypy/interpreter/astcompiler/consts.py 
b/pypy/interpreter/astcompiler/consts.py
--- a/pypy/interpreter/astcompiler/consts.py
+++ b/pypy/interpreter/astcompiler/consts.py
@@ -33,3 +33,12 @@
 PyCF_IGNORE_COOKIE = 0x0800
 PyCF_ACCEPT_NULL_BYTES = 0x10000000   # PyPy only, for compile()
 PyCF_FOUND_ENCODING = 0x20000000      # PyPy only, for pytokenizer
+
+# Masks and values used by FORMAT_VALUE opcode
+FVC_MASK      = 0x3
+FVC_NONE      = 0x0
+FVC_STR       = 0x1
+FVC_REPR      = 0x2
+FVC_ASCII     = 0x3
+FVS_MASK      = 0x4
+FVS_HAVE_SPEC = 0x4
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py 
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -1164,6 +1164,15 @@
 
     def test_fstring(self):
         yield self.st, """x = 42; z = f'ab{x}cd'""", 'z', 'ab42cd'
+        yield self.st, """z = f'{{'""", 'z', '{'
+        yield self.st, """z = f'}}'""", 'z', '}'
+        yield self.st, """z = f'x{{y'""", 'z', 'x{y'
+        yield self.st, """z = f'x}}y'""", 'z', 'x}y'
+
+        yield self.st, """x = 'hi'; z = f'{x}'""", 'z', 'hi'
+        yield self.st, """x = 'hi'; z = f'{x!s}'""", 'z', 'hi'
+        yield self.st, """x = 'hi'; z = f'{x!r}'""", 'z', "'hi'"
+        yield self.st, """x = 'hi'; z = f'{x!a}'""", 'z', "'hi'"
 
 
 class AppTestCompiler:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1612,8 +1612,19 @@
         self.pushvalue(w_awaitable)
 
     def FORMAT_VALUE(self, oparg, next_instr):
+        from pypy.interpreter.astcompiler import consts
         space = self.space
         w_value = self.popvalue()
+        #
+        conversion = oparg & consts.FVC_MASK
+        if conversion == consts.FVC_STR:
+            w_value = space.str(w_value)
+        elif conversion == consts.FVC_REPR:
+            w_value = space.repr(w_value)
+        elif conversion == consts.FVC_ASCII:
+            from pypy.objspace.std.unicodeobject import ascii_from_object
+            w_value = ascii_from_object(space, w_value)
+        #
         w_res = space.format(w_value, space.newunicode(u''))
         self.pushvalue(w_res)
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to