Skip to content

Commit 860caea

Browse files
committed
First pass at update to grammar and action_helpers.c
Squashed commit of the following: commit 0941a3088578c1a8002e58ea6e11527bedf0e81e Author: Dave <[email protected]> Date: Thu Jul 10 01:49:24 2025 +0000 Maybe cleaner? commit e5a69c851a0f43a4e84325051a37de20282dd810 Author: Dave <[email protected]> Date: Wed Jul 9 23:17:58 2025 +0000 In progress: update grammar
1 parent 091a2a9 commit 860caea

File tree

5 files changed

+1312
-1141
lines changed

5 files changed

+1312
-1141
lines changed

Grammar/python.gram

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,10 @@ tstring[expr_ty] (memo):
987987
_PyPegen_template_str(p, a, (asdl_expr_seq*)b, c)) }
988988

989989
string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) }
990-
strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string|tstring)+ { _PyPegen_concatenate_strings(p, a, EXTRA) }
990+
strings[expr_ty] (memo):
991+
| invalid_string_tstring_concat
992+
| a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) }
993+
| a[asdl_expr_seq*]=tstring+ { _PyPegen_concatenate_tstrings(p, a, EXTRA) }
991994

992995
list[expr_ty]:
993996
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
@@ -1553,6 +1556,12 @@ invalid_tstring_conversion_character:
15531556
| '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("t-string: missing conversion character") }
15541557
| '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("t-string: invalid conversion character") }
15551558

1559+
invalid_string_tstring_concat:
1560+
| (fstring|string)+ a=tstring+ {
1561+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(PyPegen_first_item(a, expr_ty), "cannot mix t-strings with strings or f-strings") }
1562+
| tstring+ a=(fstring|string)+ {
1563+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(PyPegen_first_item(a, expr_ty), "cannot mix t-strings with strings or f-strings") }
1564+
15561565
invalid_arithmetic:
15571566
| sum ('+'|'-'|'*'|'/'|'%'|'//'|'@') a='not' b=inversion { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "'not' after an operator must be parenthesized") }
15581567
invalid_factor:

Lib/test/test_tstring.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,30 +240,22 @@ def test_literal_concatenation(self):
240240
self.assertTStringEqual(t, ("Hello, ", ""), [(name, "name")])
241241
self.assertEqual(fstring(t), "Hello, Python")
242242

243-
# Test disallowed mix of t-string and string
243+
# Test disallowed mix of t-string and string/f-string (incl. bytes)
244244
what = 't'
245-
expected_msg = 'cannot mix str and Template literals'
245+
expected_msg = 'cannot mix t-strings with strings or f-strings'
246246
for case in (
247247
"t'{what}-string literal' 'str literal'",
248248
"t'{what}-string literal' u'unicode literal'",
249249
"t'{what}-string literal' f'f-string literal'",
250250
"t'{what}-string literal' r'raw string literal'",
251251
"t'{what}-string literal' rf'raw f-string literal'",
252+
"t'{what}-string literal' b'bytes literal'",
253+
"t'{what}-string literal' br'raw bytes literal'",
252254
"'str literal' t'{what}-string literal'",
253255
"u'unicode literal' t'{what}-string literal'",
254256
"f'f-string literal' t'{what}-string literal'",
255257
"r'raw string literal' t'{what}-string literal'",
256258
"rf'raw f-string literal' t'{what}-string literal'",
257-
):
258-
with self.subTest(case):
259-
with self.assertRaisesRegex(SyntaxError, expected_msg):
260-
eval(case)
261-
262-
# Test disallowed mix of t-string and bytes
263-
expected_msg = 'cannot mix bytes and nonbytes literals'
264-
for case in (
265-
"t'{what}-string literal' b'bytes literal'",
266-
"t'{what}-string literal' br'raw bytes literal'",
267259
"b'bytes literal' t'{what}-string literal'",
268260
"br'raw bytes literal' t'{what}-string literal'",
269261
):

Parser/action_helpers.c

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,8 +1834,8 @@ _build_concatenated_joined_str(Parser *p, asdl_expr_seq *strings,
18341834
return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, p->arena);
18351835
}
18361836

1837-
static expr_ty
1838-
_build_concatenated_template_str(Parser *p, asdl_expr_seq *strings,
1837+
expr_ty
1838+
_PyPegen_concatenate_tstrings(Parser *p, asdl_expr_seq *strings,
18391839
int lineno, int col_offset, int end_lineno,
18401840
int end_col_offset, PyArena *arena)
18411841
{
@@ -1853,7 +1853,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings,
18531853
Py_ssize_t len = asdl_seq_LEN(strings);
18541854
assert(len > 0);
18551855

1856-
int t_string_found = 0;
18571856
int f_string_found = 0;
18581857
int unicode_string_found = 0;
18591858
int bytes_found = 0;
@@ -1872,29 +1871,20 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings,
18721871
case JoinedStr_kind:
18731872
f_string_found = 1;
18741873
break;
1875-
case TemplateStr_kind:
1876-
t_string_found = 1;
1877-
break;
18781874
default:
18791875
f_string_found = 1;
18801876
break;
18811877
}
18821878
}
18831879

18841880
// Cannot mix unicode and bytes
1885-
if ((unicode_string_found || f_string_found || t_string_found) && bytes_found) {
1881+
if ((unicode_string_found || f_string_found) && bytes_found) {
18861882
RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals");
18871883
return NULL;
18881884
}
18891885

1890-
// Cannot mix strings/f-strings and t-strings
1891-
if ((unicode_string_found || f_string_found) && t_string_found) {
1892-
RAISE_SYNTAX_ERROR("cannot mix str and Template literals");
1893-
return NULL;
1894-
}
1895-
18961886
// If it's only bytes or only unicode string, do a simple concat
1897-
if (!f_string_found && !t_string_found) {
1887+
if (!f_string_found) {
18981888
if (len == 1) {
18991889
return asdl_seq_GET(strings, 0);
19001890
}
@@ -1908,11 +1898,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings,
19081898
}
19091899
}
19101900

1911-
if (t_string_found) {
1912-
return _build_concatenated_template_str(p, strings, lineno,
1913-
col_offset, end_lineno, end_col_offset, arena);
1914-
}
1915-
19161901
return _build_concatenated_joined_str(p, strings, lineno,
19171902
col_offset, end_lineno, end_col_offset, arena);
19181903
}

0 commit comments

Comments
 (0)