| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -848,9 +848,10 @@ expression_without_invalid[expr_ty]: | |||
| 848 | 848 | | disjunction | |
| 849 | 849 | | lambdef | |
| 850 | 850 | invalid_legacy_expression: | |
| 851 | - | a=NAME b=expression_without_invalid { | ||
| 852 | - _PyPegen_check_legacy_stmt(p, a) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Missing parentheses in call to '%U'.", a->v.Name.id) : NULL} | ||
| 853 | - | ||
| 851 | + | a=NAME b=star_expressions { | ||
| 852 | + _PyPegen_check_legacy_stmt(p, a) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, | ||
| 853 | + "Missing parentheses in call to '%U'. Did you mean %U(...)?", a->v.Name.id, a->v.Name.id) : NULL} | ||
| 854 | + | ||
| 854 | 855 | invalid_expression: | |
| 855 | 856 | | invalid_legacy_expression | |
| 856 | 857 | # !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf" | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -168,21 +168,19 @@ def ckmsg(src, msg, exception=SyntaxError): | |||
| 168 | 168 | self.fail("failed to get expected SyntaxError") | |
| 169 | 169 | ||
| 170 | 170 | s = '''print "old style"''' | |
| 171 | - ckmsg(s, "Missing parentheses in call to 'print'. " | ||
| 172 | - "Did you mean print(\"old style\")?") | ||
| 171 | + ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?") | ||
| 173 | 172 | ||
| 174 | 173 | s = '''print "old style",''' | |
| 175 | - ckmsg(s, "Missing parentheses in call to 'print'. " | ||
| 176 | - "Did you mean print(\"old style\", end=\" \")?") | ||
| 174 | + ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?") | ||
| 177 | 175 | ||
| 178 | 176 | s = 'print f(a+b,c)' | |
| 179 | - ckmsg(s, "Missing parentheses in call to 'print'.") | ||
| 177 | + ckmsg(s, "Missing parentheses in call to 'print'. Did you mean print(...)?") | ||
| 180 | 178 | ||
| 181 | 179 | s = '''exec "old style"''' | |
| 182 | - ckmsg(s, "Missing parentheses in call to 'exec'") | ||
| 180 | + ckmsg(s, "Missing parentheses in call to 'exec'. Did you mean exec(...)?") | ||
| 183 | 181 | ||
| 184 | 182 | s = 'exec f(a+b,c)' | |
| 185 | - ckmsg(s, "Missing parentheses in call to 'exec'.") | ||
| 183 | + ckmsg(s, "Missing parentheses in call to 'exec'. Did you mean exec(...)?") | ||
| 186 | 184 | ||
| 187 | 185 | # should not apply to subclasses, see issue #31161 | |
| 188 | 186 | s = '''if True:\nprint "No indent"''' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -140,21 +140,24 @@ def test_normal_string(self): | |||
| 140 | 140 | with self.assertRaises(SyntaxError) as context: | |
| 141 | 141 | exec(python2_print_str) | |
| 142 | 142 | ||
| 143 | - self.assertIn('print("Hello World")', str(context.exception)) | ||
| 143 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 144 | + str(context.exception)) | ||
| 144 | 145 | ||
| 145 | 146 | def test_string_with_soft_space(self): | |
| 146 | 147 | python2_print_str = 'print "Hello World",' | |
| 147 | 148 | with self.assertRaises(SyntaxError) as context: | |
| 148 | 149 | exec(python2_print_str) | |
| 149 | 150 | ||
| 150 | - self.assertIn('print("Hello World", end=" ")', str(context.exception)) | ||
| 151 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 152 | + str(context.exception)) | ||
| 151 | 153 | ||
| 152 | 154 | def test_string_with_excessive_whitespace(self): | |
| 153 | 155 | python2_print_str = 'print "Hello World", ' | |
| 154 | 156 | with self.assertRaises(SyntaxError) as context: | |
| 155 | 157 | exec(python2_print_str) | |
| 156 | 158 | ||
| 157 | - self.assertIn('print("Hello World", end=" ")', str(context.exception)) | ||
| 159 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 160 | + str(context.exception)) | ||
| 158 | 161 | ||
| 159 | 162 | def test_string_with_leading_whitespace(self): | |
| 160 | 163 | python2_print_str = '''if 1: | |
@@ -163,7 +166,8 @@ def test_string_with_leading_whitespace(self): | |||
| 163 | 166 | with self.assertRaises(SyntaxError) as context: | |
| 164 | 167 | exec(python2_print_str) | |
| 165 | 168 | ||
| 166 | - self.assertIn('print("Hello World")', str(context.exception)) | ||
| 169 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 170 | + str(context.exception)) | ||
| 167 | 171 | ||
| 168 | 172 | # bpo-32685: Suggestions for print statement should be proper when | |
| 169 | 173 | # it is in the same line as the header of a compound statement | |
@@ -173,14 +177,16 @@ def test_string_with_semicolon(self): | |||
| 173 | 177 | with self.assertRaises(SyntaxError) as context: | |
| 174 | 178 | exec(python2_print_str) | |
| 175 | 179 | ||
| 176 | - self.assertIn('print(p)', str(context.exception)) | ||
| 180 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 181 | + str(context.exception)) | ||
| 177 | 182 | ||
| 178 | 183 | def test_string_in_loop_on_same_line(self): | |
| 179 | 184 | python2_print_str = 'for i in s: print i' | |
| 180 | 185 | with self.assertRaises(SyntaxError) as context: | |
| 181 | 186 | exec(python2_print_str) | |
| 182 | 187 | ||
| 183 | - self.assertIn('print(i)', str(context.exception)) | ||
| 188 | + self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", | ||
| 189 | + str(context.exception)) | ||
| 184 | 190 | ||
| 185 | 191 | def test_stream_redirection_hint_for_py2_migration(self): | |
| 186 | 192 | # Test correct hint produced for Py2 redirection syntax | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1475,9 +1475,6 @@ ComplexExtendsException(PyExc_Exception, AttributeError, | |||
| 1475 | 1475 | * SyntaxError extends Exception | |
| 1476 | 1476 | */ | |
| 1477 | 1477 | ||
| 1478 | - /* Helper function to customize error message for some syntax errors */ | ||
| 1479 | - static int _report_missing_parentheses(PySyntaxErrorObject *self); | ||
| 1480 | - | ||
| 1481 | 1478 | static int | |
| 1482 | 1479 | SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) | |
| 1483 | 1480 | { | |
@@ -1520,18 +1517,6 @@ SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) | |||
| 1520 | 1517 | PyErr_SetString(PyExc_TypeError, "end_offset must be provided when end_lineno is provided"); | |
| 1521 | 1518 | return -1; | |
| 1522 | 1519 | } | |
| 1523 | - | ||
| 1524 | - /* | ||
| 1525 | - * Issue #21669: Custom error for 'print' & 'exec' as statements | ||
| 1526 | - * | ||
| 1527 | - * Only applies to SyntaxError instances, not to subclasses such | ||
| 1528 | - * as TabError or IndentationError (see issue #31161) | ||
| 1529 | - */ | ||
| 1530 | - if (Py_IS_TYPE(self, (PyTypeObject *)PyExc_SyntaxError) && | ||
| 1531 | - self->text && PyUnicode_Check(self->text) && | ||
| 1532 | - _report_missing_parentheses(self) < 0) { | ||
| 1533 | - return -1; | ||
| 1534 | - } | ||
| 1535 | 1520 | } | |
| 1536 | 1521 | return 0; | |
| 1537 | 1522 | } | |
@@ -3033,189 +3018,3 @@ _PyErr_TrySetFromCause(const char *format, ...) | |||
| 3033 | 3018 | PyErr_Restore(new_exc, new_val, new_tb); | |
| 3034 | 3019 | return new_val; | |
| 3035 | 3020 | } | |
| 3036 | - | ||
| 3037 | - | ||
| 3038 | - /* To help with migration from Python 2, SyntaxError.__init__ applies some | ||
| 3039 | - * heuristics to try to report a more meaningful exception when print and | ||
| 3040 | - * exec are used like statements. | ||
| 3041 | - * | ||
| 3042 | - * The heuristics are currently expected to detect the following cases: | ||
| 3043 | - * - top level statement | ||
| 3044 | - * - statement in a nested suite | ||
| 3045 | - * - trailing section of a one line complex statement | ||
| 3046 | - * | ||
| 3047 | - * They're currently known not to trigger: | ||
| 3048 | - * - after a semi-colon | ||
| 3049 | - * | ||
| 3050 | - * The error message can be a bit odd in cases where the "arguments" are | ||
| 3051 | - * completely illegal syntactically, but that isn't worth the hassle of | ||
| 3052 | - * fixing. | ||
| 3053 | - * | ||
| 3054 | - * We also can't do anything about cases that are legal Python 3 syntax | ||
| 3055 | - * but mean something entirely different from what they did in Python 2 | ||
| 3056 | - * (omitting the arguments entirely, printing items preceded by a unary plus | ||
| 3057 | - * or minus, using the stream redirection syntax). | ||
| 3058 | - */ | ||
| 3059 | - | ||
| 3060 | - | ||
| 3061 | - // Static helper for setting legacy print error message | ||
| 3062 | - static int | ||
| 3063 | - _set_legacy_print_statement_msg(PySyntaxErrorObject *self, Py_ssize_t start) | ||
| 3064 | - { | ||
| 3065 | - // PRINT_OFFSET is to remove the `print ` prefix from the data. | ||
| 3066 | - const int PRINT_OFFSET = 6; | ||
| 3067 | - const int STRIP_BOTH = 2; | ||
| 3068 | - Py_ssize_t start_pos = start + PRINT_OFFSET; | ||
| 3069 | - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text); | ||
| 3070 | - Py_UCS4 semicolon = ';'; | ||
| 3071 | - Py_ssize_t end_pos = PyUnicode_FindChar(self->text, semicolon, | ||
| 3072 | - start_pos, text_len, 1); | ||
| 3073 | - if (end_pos < -1) { | ||
| 3074 | - return -1; | ||
| 3075 | - } else if (end_pos == -1) { | ||
| 3076 | - end_pos = text_len; | ||
| 3077 | - } | ||
| 3078 | - | ||
| 3079 | - PyObject *data = PyUnicode_Substring(self->text, start_pos, end_pos); | ||
| 3080 | - if (data == NULL) { | ||
| 3081 | - return -1; | ||
| 3082 | - } | ||
| 3083 | - | ||
| 3084 | - PyObject *strip_sep_obj = PyUnicode_FromString(" \t\r\n"); | ||
| 3085 | - if (strip_sep_obj == NULL) { | ||
| 3086 | - Py_DECREF(data); | ||
| 3087 | - return -1; | ||
| 3088 | - } | ||
| 3089 | - | ||
| 3090 | - PyObject *new_data = _PyUnicode_XStrip(data, STRIP_BOTH, strip_sep_obj); | ||
| 3091 | - Py_DECREF(data); | ||
| 3092 | - Py_DECREF(strip_sep_obj); | ||
| 3093 | - if (new_data == NULL) { | ||
| 3094 | - return -1; | ||
| 3095 | - } | ||
| 3096 | - // gets the modified text_len after stripping `print ` | ||
| 3097 | - text_len = PyUnicode_GET_LENGTH(new_data); | ||
| 3098 | - const char *maybe_end_arg = ""; | ||
| 3099 | - if (text_len > 0 && PyUnicode_READ_CHAR(new_data, text_len-1) == ',') { | ||
| 3100 | - maybe_end_arg = " end=\" \""; | ||
| 3101 | - } | ||
| 3102 | - PyObject *error_msg = PyUnicode_FromFormat( | ||
| 3103 | - "Missing parentheses in call to 'print'. Did you mean print(%U%s)?", | ||
| 3104 | - new_data, maybe_end_arg | ||
| 3105 | - ); | ||
| 3106 | - Py_DECREF(new_data); | ||
| 3107 | - if (error_msg == NULL) | ||
| 3108 | - return -1; | ||
| 3109 | - | ||
| 3110 | - Py_XSETREF(self->msg, error_msg); | ||
| 3111 | - return 1; | ||
| 3112 | - } | ||
| 3113 | - | ||
| 3114 | - static int | ||
| 3115 | - _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start) | ||
| 3116 | - { | ||
| 3117 | - /* Return values: | ||
| 3118 | - * -1: an error occurred | ||
| 3119 | - * 0: nothing happened | ||
| 3120 | - * 1: the check triggered & the error message was changed | ||
| 3121 | - */ | ||
| 3122 | - static PyObject *print_prefix = NULL; | ||
| 3123 | - static PyObject *exec_prefix = NULL; | ||
| 3124 | - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text), match; | ||
| 3125 | - int kind = PyUnicode_KIND(self->text); | ||
| 3126 | - const void *data = PyUnicode_DATA(self->text); | ||
| 3127 | - | ||
| 3128 | - /* Ignore leading whitespace */ | ||
| 3129 | - while (start < text_len) { | ||
| 3130 | - Py_UCS4 ch = PyUnicode_READ(kind, data, start); | ||
| 3131 | - if (!Py_UNICODE_ISSPACE(ch)) | ||
| 3132 | - break; | ||
| 3133 | - start++; | ||
| 3134 | - } | ||
| 3135 | - /* Checking against an empty or whitespace-only part of the string */ | ||
| 3136 | - if (start == text_len) { | ||
| 3137 | - return 0; | ||
| 3138 | - } | ||
| 3139 | - | ||
| 3140 | - /* Check for legacy print statements */ | ||
| 3141 | - if (print_prefix == NULL) { | ||
| 3142 | - print_prefix = PyUnicode_InternFromString("print "); | ||
| 3143 | - if (print_prefix == NULL) { | ||
| 3144 | - return -1; | ||
| 3145 | - } | ||
| 3146 | - } | ||
| 3147 | - match = PyUnicode_Tailmatch(self->text, print_prefix, | ||
| 3148 | - start, text_len, -1); | ||
| 3149 | - if (match == -1) { | ||
| 3150 | - return -1; | ||
| 3151 | - } | ||
| 3152 | - if (match) { | ||
| 3153 | - return _set_legacy_print_statement_msg(self, start); | ||
| 3154 | - } | ||
| 3155 | - | ||
| 3156 | - /* Check for legacy exec statements */ | ||
| 3157 | - if (exec_prefix == NULL) { | ||
| 3158 | - exec_prefix = PyUnicode_InternFromString("exec "); | ||
| 3159 | - if (exec_prefix == NULL) { | ||
| 3160 | - return -1; | ||
| 3161 | - } | ||
| 3162 | - } | ||
| 3163 | - match = PyUnicode_Tailmatch(self->text, exec_prefix, start, text_len, -1); | ||
| 3164 | - if (match == -1) { | ||
| 3165 | - return -1; | ||
| 3166 | - } | ||
| 3167 | - if (match) { | ||
| 3168 | - PyObject *msg = PyUnicode_FromString("Missing parentheses in call " | ||
| 3169 | - "to 'exec'"); | ||
| 3170 | - if (msg == NULL) { | ||
| 3171 | - return -1; | ||
| 3172 | - } | ||
| 3173 | - Py_XSETREF(self->msg, msg); | ||
| 3174 | - return 1; | ||
| 3175 | - } | ||
| 3176 | - /* Fall back to the default error message */ | ||
| 3177 | - return 0; | ||
| 3178 | - } | ||
| 3179 | - | ||
| 3180 | - static int | ||
| 3181 | - _report_missing_parentheses(PySyntaxErrorObject *self) | ||
| 3182 | - { | ||
| 3183 | - Py_UCS4 left_paren = 40; | ||
| 3184 | - Py_ssize_t left_paren_index; | ||
| 3185 | - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text); | ||
| 3186 | - int legacy_check_result = 0; | ||
| 3187 | - | ||
| 3188 | - /* Skip entirely if there is an opening parenthesis */ | ||
| 3189 | - left_paren_index = PyUnicode_FindChar(self->text, left_paren, | ||
| 3190 | - 0, text_len, 1); | ||
| 3191 | - if (left_paren_index < -1) { | ||
| 3192 | - return -1; | ||
| 3193 | - } | ||
| 3194 | - if (left_paren_index != -1) { | ||
| 3195 | - /* Use default error message for any line with an opening paren */ | ||
| 3196 | - return 0; | ||
| 3197 | - } | ||
| 3198 | - /* Handle the simple statement case */ | ||
| 3199 | - legacy_check_result = _check_for_legacy_statements(self, 0); | ||
| 3200 | - if (legacy_check_result < 0) { | ||
| 3201 | - return -1; | ||
| 3202 | - | ||
| 3203 | - } | ||
| 3204 | - if (legacy_check_result == 0) { | ||
| 3205 | - /* Handle the one-line complex statement case */ | ||
| 3206 | - Py_UCS4 colon = 58; | ||
| 3207 | - Py_ssize_t colon_index; | ||
| 3208 | - colon_index = PyUnicode_FindChar(self->text, colon, | ||
| 3209 | - 0, text_len, 1); | ||
| 3210 | - if (colon_index < -1) { | ||
| 3211 | - return -1; | ||
| 3212 | - } | ||
| 3213 | - if (colon_index >= 0 && colon_index < text_len) { | ||
| 3214 | - /* Check again, starting from just after the colon */ | ||
| 3215 | - if (_check_for_legacy_statements(self, colon_index+1) < 0) { | ||
| 3216 | - return -1; | ||
| 3217 | - } | ||
| 3218 | - } | ||
| 3219 | - } | ||
| 3220 | - return 0; | ||
| 3221 | - } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18158,7 +18158,7 @@ expression_without_invalid_rule(Parser *p) | |||
| 18158 | 18158 | return _res; | |
| 18159 | 18159 | } | |
| 18160 | 18160 | ||
| 18161 | - // invalid_legacy_expression: NAME expression_without_invalid | ||
| 18161 | + // invalid_legacy_expression: NAME star_expressions | ||
| 18162 | 18162 | static void * | |
| 18163 | 18163 | invalid_legacy_expression_rule(Parser *p) | |
| 18164 | 18164 | { | |
@@ -18169,22 +18169,22 @@ invalid_legacy_expression_rule(Parser *p) | |||
| 18169 | 18169 | } | |
| 18170 | 18170 | void * _res = NULL; | |
| 18171 | 18171 | int _mark = p->mark; | |
| 18172 | - { // NAME expression_without_invalid | ||
| 18172 | + { // NAME star_expressions | ||
| 18173 | 18173 | if (p->error_indicator) { | |
| 18174 | 18174 | D(p->level--); | |
| 18175 | 18175 | return NULL; | |
| 18176 | 18176 | } | |
| 18177 | - D(fprintf(stderr, "%*c> invalid_legacy_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME expression_without_invalid")); | ||
| 18177 | + D(fprintf(stderr, "%*c> invalid_legacy_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME star_expressions")); | ||
| 18178 | 18178 | expr_ty a; | |
| 18179 | 18179 | expr_ty b; | |
| 18180 | 18180 | if ( | |
| 18181 | 18181 | (a = _PyPegen_name_token(p)) // NAME | |
| 18182 | 18182 | && | |
| 18183 | - (b = expression_without_invalid_rule(p)) // expression_without_invalid | ||
| 18183 | + (b = star_expressions_rule(p)) // star_expressions | ||
| 18184 | 18184 | ) | |
| 18185 | 18185 | { | |
| 18186 | - D(fprintf(stderr, "%*c+ invalid_legacy_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME expression_without_invalid")); | ||
| 18187 | - _res = _PyPegen_check_legacy_stmt ( p , a ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "Missing parentheses in call to '%U'." , a -> v . Name . id ) : NULL; | ||
| 18186 | + D(fprintf(stderr, "%*c+ invalid_legacy_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME star_expressions")); | ||
| 18187 | + _res = _PyPegen_check_legacy_stmt ( p , a ) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "Missing parentheses in call to '%U'. Did you mean %U(...)?" , a -> v . Name . id , a -> v . Name . id ) : NULL; | ||
| 18188 | 18188 | if (_res == NULL && PyErr_Occurred()) { | |
| 18189 | 18189 | p->error_indicator = 1; | |
| 18190 | 18190 | D(p->level--); | |
@@ -18194,7 +18194,7 @@ invalid_legacy_expression_rule(Parser *p) | |||
| 18194 | 18194 | } | |
| 18195 | 18195 | p->mark = _mark; | |
| 18196 | 18196 | D(fprintf(stderr, "%*c%s invalid_legacy_expression[%d-%d]: %s failed!\n", p->level, ' ', | |
| 18197 | - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME expression_without_invalid")); | ||
| 18197 | + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME star_expressions")); | ||
| 18198 | 18198 | } | |
| 18199 | 18199 | _res = NULL; | |
| 18200 | 18200 | done: | |
| Back | FazBrowse Home | New Git URL |
0 commit comments