Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
5b1fdc1e
Kaydet (Commit)
5b1fdc1e
authored
Haz 16, 2014
tarafından
Nick Coghlan
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Issue #21669: Special case print & exec syntax errors
üst
b6d1f48c
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
165 additions
and
0 deletions
+165
-0
test_grammar.py
Lib/test/test_grammar.py
+25
-0
NEWS
Misc/NEWS
+5
-0
exceptions.c
Objects/exceptions.c
+135
-0
No files found.
Lib/test/test_grammar.py
Dosyayı görüntüle @
5b1fdc1e
...
...
@@ -390,6 +390,31 @@ class GrammarTests(unittest.TestCase):
check_syntax_error
(
self
,
"x + 1 = 1"
)
check_syntax_error
(
self
,
"a + 1 = b + 2"
)
# Check the heuristic for print & exec covers significant cases
# As well as placing some limits on false positives
def
test_former_statements_refer_to_builtins
(
self
):
keywords
=
"print"
,
"exec"
# Cases where we want the custom error
cases
=
[
"{} foo"
,
"{} {{1:foo}}"
,
"if 1: {} foo"
,
"if 1: {} {{1:foo}}"
,
"if 1:
\n
{} foo"
,
"if 1:
\n
{} {{1:foo}}"
,
]
for
keyword
in
keywords
:
custom_msg
=
"call to '{}'"
.
format
(
keyword
)
for
case
in
cases
:
source
=
case
.
format
(
keyword
)
with
self
.
subTest
(
source
=
source
):
with
self
.
assertRaisesRegex
(
SyntaxError
,
custom_msg
):
exec
(
source
)
source
=
source
.
replace
(
"foo"
,
"(foo.)"
)
with
self
.
subTest
(
source
=
source
):
with
self
.
assertRaisesRegex
(
SyntaxError
,
"invalid syntax"
):
exec
(
source
)
def
test_del_stmt
(
self
):
# 'del' exprlist
abc
=
[
1
,
2
,
3
]
...
...
Misc/NEWS
Dosyayı görüntüle @
5b1fdc1e
...
...
@@ -10,6 +10,11 @@ Release date: XXXX-XX-XX
Core and Builtins
-----------------
- Issue #21669: With the aid of heuristics in SyntaxError.__init__, the
parser now attempts to generate more meaningful (or at least more search
engine friendly) error messages when "exec" and "print" are used as
statements.
- Issue #21642: If the conditional if-else expression, allow an integer written
with no space between itself and the ``else`` keyword (e.g. ``True if 42else
False``) to be valid syntax.
...
...
Objects/exceptions.c
Dosyayı görüntüle @
5b1fdc1e
...
...
@@ -1254,6 +1254,9 @@ SimpleExtendsException(PyExc_Exception, AttributeError,
* SyntaxError extends Exception
*/
/* Helper function to customise error message for some syntax errors */
static
int
_report_missing_parentheses
(
PySyntaxErrorObject
*
self
);
static
int
SyntaxError_init
(
PySyntaxErrorObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
...
...
@@ -1298,6 +1301,13 @@ SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds)
Py_INCREF
(
self
->
text
);
Py_DECREF
(
info
);
/* Issue #21669: Custom error for 'print' & 'exec' as statements */
if
(
self
->
text
&&
PyUnicode_Check
(
self
->
text
))
{
if
(
_report_missing_parentheses
(
self
)
<
0
)
{
return
-
1
;
}
}
}
return
0
;
}
...
...
@@ -2783,3 +2793,128 @@ _PyErr_TrySetFromCause(const char *format, ...)
PyErr_Restore
(
new_exc
,
new_val
,
new_tb
);
return
new_val
;
}
/* To help with migration from Python 2, SyntaxError.__init__ applies some
* heuristics to try to report a more meaningful exception when print and
* exec are used like statements.
*
* The heuristics are currently expected to detect the following cases:
* - top level statement
* - statement in a nested suite
* - trailing section of a one line complex statement
*
* They're currently known not to trigger:
* - after a semi-colon
*
* The error message can be a bit odd in cases where the "arguments" are
* completely illegal syntactically, but that isn't worth the hassle of
* fixing.
*
* We also can't do anything about cases that are legal Python 3 syntax
* but mean something entirely different from what they did in Python 2
* (omitting the arguments entirely, printing items preceded by a unary plus
* or minus, using the stream redirection syntax).
*/
static
int
_check_for_legacy_statements
(
PySyntaxErrorObject
*
self
,
Py_ssize_t
start
)
{
/* Return values:
* -1: an error occurred
* 0: nothing happened
* 1: the check triggered & the error message was changed
*/
static
PyObject
*
print_prefix
=
NULL
;
static
PyObject
*
exec_prefix
=
NULL
;
Py_ssize_t
text_len
=
PyUnicode_GET_LENGTH
(
self
->
text
);
int
kind
=
PyUnicode_KIND
(
self
->
text
);
void
*
data
=
PyUnicode_DATA
(
self
->
text
);
/* Ignore leading whitespace */
while
(
start
<
text_len
)
{
Py_UCS4
ch
=
PyUnicode_READ
(
kind
,
data
,
start
);
if
(
!
Py_UNICODE_ISSPACE
(
ch
))
break
;
start
++
;
}
/* Checking against an empty or whitespace-only part of the string */
if
(
start
==
text_len
)
{
return
0
;
}
/* Check for legacy print statements */
if
(
print_prefix
==
NULL
)
{
print_prefix
=
PyUnicode_InternFromString
(
"print "
);
if
(
print_prefix
==
NULL
)
{
return
-
1
;
}
}
if
(
PyUnicode_Tailmatch
(
self
->
text
,
print_prefix
,
start
,
text_len
,
-
1
))
{
Py_CLEAR
(
self
->
msg
);
self
->
msg
=
PyUnicode_FromString
(
"Missing parentheses in call to 'print'"
);
return
1
;
}
/* Check for legacy exec statements */
if
(
exec_prefix
==
NULL
)
{
exec_prefix
=
PyUnicode_InternFromString
(
"exec "
);
if
(
exec_prefix
==
NULL
)
{
return
-
1
;
}
}
if
(
PyUnicode_Tailmatch
(
self
->
text
,
exec_prefix
,
start
,
text_len
,
-
1
))
{
Py_CLEAR
(
self
->
msg
);
self
->
msg
=
PyUnicode_FromString
(
"Missing parentheses in call to 'exec'"
);
return
1
;
}
/* Fall back to the default error message */
return
0
;
}
static
int
_report_missing_parentheses
(
PySyntaxErrorObject
*
self
)
{
Py_UCS4
left_paren
=
40
;
Py_ssize_t
left_paren_index
;
Py_ssize_t
text_len
=
PyUnicode_GET_LENGTH
(
self
->
text
);
int
legacy_check_result
=
0
;
/* Skip entirely if there is an opening parenthesis */
left_paren_index
=
PyUnicode_FindChar
(
self
->
text
,
left_paren
,
0
,
text_len
,
1
);
if
(
left_paren_index
<
-
1
)
{
return
-
1
;
}
if
(
left_paren_index
!=
-
1
)
{
/* Use default error message for any line with an opening paren */
return
0
;
}
/* Handle the simple statement case */
legacy_check_result
=
_check_for_legacy_statements
(
self
,
0
);
if
(
legacy_check_result
<
0
)
{
return
-
1
;
}
if
(
legacy_check_result
==
0
)
{
/* Handle the one-line complex statement case */
Py_UCS4
colon
=
58
;
Py_ssize_t
colon_index
;
colon_index
=
PyUnicode_FindChar
(
self
->
text
,
colon
,
0
,
text_len
,
1
);
if
(
colon_index
<
-
1
)
{
return
-
1
;
}
if
(
colon_index
>=
0
&&
colon_index
<
text_len
)
{
/* Check again, starting from just after the colon */
if
(
_check_for_legacy_statements
(
self
,
colon_index
+
1
)
<
0
)
{
return
-
1
;
}
}
}
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment