@@ -1539,103 +1539,9 @@ impl<'src> Parser<'src> {
15391539 flags = flags. with_unclosed ( true ) ;
15401540 }
15411541
1542- // test_ok pep701_f_string_py312
1543- // # parse_options: {"target-version": "3.12"}
1544- // f'Magic wand: { bag['wand'] }' # nested quotes
1545- // f"{'\n'.join(a)}" # escape sequence
1546- // f'''A complex trick: {
1547- // bag['bag'] # comment
1548- // }'''
1549- // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" # arbitrary nesting
1550- // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1551- // f"test {a \
1552- // } more" # line continuation
1553-
1554- // test_ok pep750_t_string_py314
1555- // # parse_options: {"target-version": "3.14"}
1556- // t'Magic wand: { bag['wand'] }' # nested quotes
1557- // t"{'\n'.join(a)}" # escape sequence
1558- // t'''A complex trick: {
1559- // bag['bag'] # comment
1560- // }'''
1561- // t"{t"{t"{t"{t"{t"{1+1}"}"}"}"}"}" # arbitrary nesting
1562- // t"{t'''{"nested"} inner'''} outer" # nested (triple) quotes
1563- // t"test {a \
1564- // } more" # line continuation
1565-
1566- // test_ok pep701_f_string_py311
1567- // # parse_options: {"target-version": "3.11"}
1568- // f"outer {'# not a comment'}"
1569- // f'outer {x:{"# not a comment"} }'
1570- // f"""{f'''{f'{"# not a comment"}'}'''}"""
1571- // f"""{f'''# before expression {f'# aro{f"#{1+1}#"}und #'}'''} # after expression"""
1572- // f"escape outside of \t {expr}\n"
1573- // f"test\"abcd"
1574- // f"{1:\x64}" # escapes are valid in the format spec
1575- // f"{1:\"d\"}" # this also means that escaped outer quotes are valid
1576-
1577- // test_err pep701_f_string_py311
1578- // # parse_options: {"target-version": "3.11"}
1579- // f'Magic wand: { bag['wand'] }' # nested quotes
1580- // f"{'\n'.join(a)}" # escape sequence
1581- // f'''A complex trick: {
1582- // bag['bag'] # comment
1583- // }'''
1584- // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" # arbitrary nesting
1585- // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1586- // f"test {a \
1587- // } more" # line continuation
1588- // f"""{f"""{x}"""}""" # mark the whole triple quote
1589- // f"{'\n'.join(['\t', '\v', '\r'])}" # multiple escape sequences, multiple errors
1590-
1591- // test_err nested_quote_in_format_spec_py312
1592- // # parse_options: {"target-version": "3.12"}
1593- // f"{1:""}" # this is a ParseError on all versions
1594-
1595- // test_ok non_nested_quote_in_format_spec_py311
1596- // # parse_options: {"target-version": "3.11"}
1597- // f"{1:''}" # but this is okay on all versions
1598- let range = self . node_range ( start) ;
1599-
1600- if !self . options . target_version . supports_pep_701 ( )
1601- && matches ! ( kind, InterpolatedStringKind :: FString )
1602- {
1603- let quote_bytes = flags. quote_str ( ) . as_bytes ( ) ;
1604- let quote_len = flags. quote_len ( ) ;
1605- for expr in elements. interpolations ( ) {
1606- // We need to check the whole expression range, including any leading or trailing
1607- // debug text, but exclude the format spec, where escapes and escaped, reused quotes
1608- // are allowed.
1609- let range = expr
1610- . format_spec
1611- . as_ref ( )
1612- . map ( |format_spec| TextRange :: new ( expr. start ( ) , format_spec. start ( ) ) )
1613- . unwrap_or ( expr. range ) ;
1614- for slash_position in memchr:: memchr_iter ( b'\\' , self . source [ range] . as_bytes ( ) ) {
1615- let slash_position = TextSize :: try_from ( slash_position) . unwrap ( ) ;
1616- self . add_unsupported_syntax_error (
1617- UnsupportedSyntaxErrorKind :: Pep701FString ( FStringKind :: Backslash ) ,
1618- TextRange :: at ( range. start ( ) + slash_position, '\\' . text_len ( ) ) ,
1619- ) ;
1620- }
1621-
1622- if let Some ( quote_position) =
1623- memchr:: memmem:: find ( self . source [ range] . as_bytes ( ) , quote_bytes)
1624- {
1625- let quote_position = TextSize :: try_from ( quote_position) . unwrap ( ) ;
1626- self . add_unsupported_syntax_error (
1627- UnsupportedSyntaxErrorKind :: Pep701FString ( FStringKind :: NestedQuote ) ,
1628- TextRange :: at ( range. start ( ) + quote_position, quote_len) ,
1629- ) ;
1630- }
1631- }
1632-
1633- self . check_fstring_comments ( range) ;
1634- }
1635-
16361542 InterpolatedStringData {
16371543 elements,
1638- range,
1544+ range : self . node_range ( start ) ,
16391545 flags,
16401546 }
16411547 }
@@ -1921,12 +1827,110 @@ impl<'src> Parser<'src> {
19211827 ) ;
19221828 }
19231829
1830+ // test_ok pep701_f_string_py312
1831+ // # parse_options: {"target-version": "3.12"}
1832+ // f'Magic wand: { bag['wand'] }' # nested quotes
1833+ // f"{'\n'.join(a)}" # escape sequence
1834+ // f'''A complex trick: {
1835+ // bag['bag'] # comment
1836+ // }'''
1837+ // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" # arbitrary nesting
1838+ // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1839+ // f"test {a \
1840+ // } more" # line continuation
1841+
1842+ // test_ok pep750_t_string_py314
1843+ // # parse_options: {"target-version": "3.14"}
1844+ // t'Magic wand: { bag['wand'] }' # nested quotes
1845+ // t"{'\n'.join(a)}" # escape sequence
1846+ // t'''A complex trick: {
1847+ // bag['bag'] # comment
1848+ // }'''
1849+ // t"{t"{t"{t"{t"{t"{1+1}"}"}"}"}"}" # arbitrary nesting
1850+ // t"{t'''{"nested"} inner'''} outer" # nested (triple) quotes
1851+ // t"test {a \
1852+ // } more" # line continuation
1853+
1854+ // test_ok pep701_f_string_py311
1855+ // # parse_options: {"target-version": "3.11"}
1856+ // f"outer {'# not a comment'}"
1857+ // f'outer {x:{"# not a comment"} }'
1858+ // f"""{f'''{f'{"# not a comment"}'}'''}"""
1859+ // f"""{f'''# before expression {f'# aro{f"#{1+1}#"}und #'}'''} # after expression"""
1860+ // f"escape outside of \t {expr}\n"
1861+ // f"test\"abcd"
1862+ // f"{1:\x64}" # escapes are valid in the format spec
1863+ // f"{1:\"d\"}" # this also means that escaped outer quotes are valid
1864+
1865+ // test_err pep701_f_string_py311
1866+ // # parse_options: {"target-version": "3.11"}
1867+ // f'Magic wand: { bag['wand'] }' # nested quotes
1868+ // f"{'\n'.join(a)}" # escape sequence
1869+ // f'''A complex trick: {
1870+ // bag['bag'] # comment
1871+ // }'''
1872+ // f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" # arbitrary nesting
1873+ // f"{f'''{"nested"} inner'''} outer" # nested (triple) quotes
1874+ // f"test {a \
1875+ // } more" # line continuation
1876+ // f"""{f"""{x}"""}""" # mark the whole triple quote
1877+ // f"{'\n'.join(['\t', '\v', '\r'])}" # multiple escape sequences, multiple errors
1878+
1879+ // test_err pep701_nested_interpolation_py311
1880+ // # parse_options: {"target-version": "3.11"}
1881+ // # nested interpolations also need to be checked
1882+ // f'{1: abcd "{'aa'}" }'
1883+ // f'{1: abcd "{"\n"}" }'
1884+
1885+ // test_err nested_quote_in_format_spec_py312
1886+ // # parse_options: {"target-version": "3.12"}
1887+ // f"{1:""}" # this is a ParseError on all versions
1888+
1889+ // test_ok non_nested_quote_in_format_spec_py311
1890+ // # parse_options: {"target-version": "3.11"}
1891+ // f"{1:''}" # but this is okay on all versions
1892+ let range = self . node_range ( start) ;
1893+
1894+ if !self . options . target_version . supports_pep_701 ( )
1895+ && matches ! ( string_kind, InterpolatedStringKind :: FString )
1896+ {
1897+ // We need to check the whole expression range, including any leading or trailing
1898+ // debug text, but exclude the format spec, where escapes and escaped, reused quotes
1899+ // are allowed.
1900+ let range = format_spec
1901+ . as_ref ( )
1902+ . map ( |format_spec| TextRange :: new ( range. start ( ) , format_spec. start ( ) ) )
1903+ . unwrap_or ( range) ;
1904+
1905+ let quote_bytes = flags. quote_str ( ) . as_bytes ( ) ;
1906+ let quote_len = flags. quote_len ( ) ;
1907+ for slash_position in memchr:: memchr_iter ( b'\\' , self . source [ range] . as_bytes ( ) ) {
1908+ let slash_position = TextSize :: try_from ( slash_position) . unwrap ( ) ;
1909+ self . add_unsupported_syntax_error (
1910+ UnsupportedSyntaxErrorKind :: Pep701FString ( FStringKind :: Backslash ) ,
1911+ TextRange :: at ( range. start ( ) + slash_position, '\\' . text_len ( ) ) ,
1912+ ) ;
1913+ }
1914+
1915+ if let Some ( quote_position) =
1916+ memchr:: memmem:: find ( self . source [ range] . as_bytes ( ) , quote_bytes)
1917+ {
1918+ let quote_position = TextSize :: try_from ( quote_position) . unwrap ( ) ;
1919+ self . add_unsupported_syntax_error (
1920+ UnsupportedSyntaxErrorKind :: Pep701FString ( FStringKind :: NestedQuote ) ,
1921+ TextRange :: at ( range. start ( ) + quote_position, quote_len) ,
1922+ ) ;
1923+ }
1924+
1925+ self . check_fstring_comments ( range) ;
1926+ }
1927+
19241928 ast:: InterpolatedElement {
19251929 expression : Box :: new ( value. expr ) ,
19261930 debug_text,
19271931 conversion,
19281932 format_spec,
1929- range : self . node_range ( start ) ,
1933+ range,
19301934 node_index : AtomicNodeIndex :: NONE ,
19311935 }
19321936 }
0 commit comments