Author: Armin Rigo <[email protected]>
Branch: py3.5-fstring-pep498
Changeset: r89699:3cc879e93827
Date: 2017-01-22 23:30 +0100
http://bitbucket.org/pypy/pypy/changeset/3cc879e93827/
Log: better error checking; and found a more reasonable way to forbid
comments than CPython uses
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
@@ -1218,14 +1218,22 @@
# or even tokenized together with the rest of the source code!
from pypy.interpreter.pyparser import pyparse
+ # complain if 'source' is only whitespace or an empty string
+ for c in source:
+ if c not in ' \t\n\r\v\f':
+ break
+ else:
+ self.error("f-string: empty expression not allowed", atom_node)
+
if self.recursive_parser is None:
self.error("internal error: parser not available for parsing "
"the expressions inside the f-string", atom_node)
- source = source.encode('utf-8')
+ source = '(%s)' % source.encode('utf-8')
info = pyparse.CompileInfo("<fstring>", "eval",
consts.PyCF_SOURCE_IS_UTF8 |
- consts.PyCF_IGNORE_COOKIE,
+ consts.PyCF_IGNORE_COOKIE |
+ consts.PyCF_REFUSE_COMMENTS,
optimize=self.compile_info.optimize)
parse_tree = self.recursive_parser.parse_source(source, info)
return ast_from_node(self.space, parse_tree, info)
@@ -1247,7 +1255,6 @@
if ch == u'!' and p < len(u) and u[p] == u'=':
continue
break # normal way out of this loop
- # XXX forbid comment, but how?
else:
ch = u'\x00'
#
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,6 +33,7 @@
PyCF_IGNORE_COOKIE = 0x0800
PyCF_ACCEPT_NULL_BYTES = 0x10000000 # PyPy only, for compile()
PyCF_FOUND_ENCODING = 0x20000000 # PyPy only, for pytokenizer
+PyCF_REFUSE_COMMENTS = 0x40000000 # PyPy only, for f-strings
# Masks and values used by FORMAT_VALUE opcode
FVC_MASK = 0x3
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
@@ -1174,6 +1174,15 @@
yield self.st, """x = 'hi'; z = f'{x!r}'""", 'z', "'hi'"
yield self.st, """x = 'hi'; z = f'{x!a}'""", 'z', "'hi'"
+ yield self.st, """x = 'hi'; z = f'''{\nx}'''""", 'z', 'hi'
+
+ def test_fstring_error(self):
+ raises(SyntaxError, self.run, "f'{}'")
+ raises(SyntaxError, self.run, "f'{ \t }'")
+ raises(SyntaxError, self.run, "f'{5#}'")
+ raises(SyntaxError, self.run, "f'{5)#}'")
+ raises(SyntaxError, self.run, "f'''{5)\n#}'''")
+
class AppTestCompiler:
diff --git a/pypy/interpreter/pyparser/pytokenizer.py
b/pypy/interpreter/pyparser/pytokenizer.py
--- a/pypy/interpreter/pyparser/pytokenizer.py
+++ b/pypy/interpreter/pyparser/pytokenizer.py
@@ -187,6 +187,9 @@
continue
if line[pos] == '#':
# skip full-line comment, but still check that it is valid
utf-8
+ if flags & consts.PyCF_REFUSE_COMMENTS:
+ raise TokenError("comments not allowed here",
+ line, lnum, pos, token_list)
if not verify_utf8(line):
raise bad_utf8("comment",
line, lnum, pos, token_list, flags)
@@ -257,6 +260,9 @@
last_comment = ''
elif initial == '#':
# skip comment, but still check that it is valid utf-8
+ if flags & consts.PyCF_REFUSE_COMMENTS:
+ raise TokenError("comments not allowed here",
+ line, lnum, start, token_list)
if not verify_utf8(token):
raise bad_utf8("comment",
line, lnum, start, token_list, flags)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit