gh-125588: Teach the python PEG generator the new f-string tokens (#1… · python/cpython@9dfef4e

GitHub

File tree

Lib/test/test_peg_generator

Misc/NEWS.d/next/Core_and_Builtins

Tools/peg_generator/pegen

Original file line numberDiff line numberDiff line change@@ -506,6 +506,14 @@ def test_python_expr(self) -> None:

506506val=eval(code)

507507self.assertEqual(val, 3.0)

508508509+deftest_f_string_in_action(self) ->None:

510+grammar="""

511+ start: n=NAME NEWLINE? $ { f"name -> {n.string}" }

512+ """

513+parser_class=make_parser(grammar)

514+node=parse_string("a", parser_class)

515+self.assertEqual(node.strip(), "name -> a")

516+509517deftest_nullable(self) ->None:

510518grammar_source="""

511519 start: sign NUMBER

Original file line numberDiff line numberDiff line change@@ -0,0 +1,2 @@

1+The Python PEG generator can now use f-strings in the grammar actions. Patch

2+by Pablo Galindo

Original file line numberDiff line numberDiff line change@@ -126,6 +126,9 @@ target_atom[str]:

126126 | NAME { name.string }

127127 | NUMBER { number.string }

128128 | STRING { string.string }

129+ | FSTRING_START { fstring_start.string }

130+ | FSTRING_MIDDLE { fstring_middle.string }

131+ | FSTRING_END { fstring_end.string }

129132 | "?" { "?" }

130133 | ":" { ":" }

131134 | !"}" !"]" OP { op.string }

Original file line numberDiff line numberDiff line change@@ -205,6 +205,36 @@ def string(self) -> Optional[tokenize.TokenInfo]:

205205returnself._tokenizer.getnext()

206206returnNone

207207208+@memoize

209+deffstring_start(self) ->Optional[tokenize.TokenInfo]:

210+FSTRING_START=getattr(token, "FSTRING_START")

211+ifnotFSTRING_START:

212+returnNone

213+tok=self._tokenizer.peek()

214+iftok.type==FSTRING_START:

215+returnself._tokenizer.getnext()

216+returnNone

217+218+@memoize

219+deffstring_middle(self) ->Optional[tokenize.TokenInfo]:

220+FSTRING_MIDDLE=getattr(token, "FSTRING_MIDDLE")

221+ifnotFSTRING_MIDDLE:

222+returnNone

223+tok=self._tokenizer.peek()

224+iftok.type==FSTRING_MIDDLE:

225+returnself._tokenizer.getnext()

226+returnNone

227+228+@memoize

229+deffstring_end(self) ->Optional[tokenize.TokenInfo]:

230+FSTRING_END=getattr(token, "FSTRING_END")

231+ifnotFSTRING_END:

232+returnNone

233+tok=self._tokenizer.peek()

234+iftok.type==FSTRING_END:

235+returnself._tokenizer.getnext()

236+returnNone

237+208238@memoize

209239defop(self) ->Optional[tokenize.TokenInfo]:

210240tok=self._tokenizer.peek()

Original file line numberDiff line numberDiff line change@@ -99,7 +99,8 @@ def visit_NameLeaf(self, node: NameLeaf) -> Tuple[Optional[str], str]:

9999name=node.value

100100ifname=="SOFT_KEYWORD":

101101return"soft_keyword", "self.soft_keyword()"

102-ifnamein ("NAME", "NUMBER", "STRING", "OP", "TYPE_COMMENT"):

102+ifnamein ("NAME", "NUMBER", "STRING", "OP", "TYPE_COMMENT",

103+"FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START"):

103104name=name.lower()

104105returnname, f"self.{name}()"

105106ifnamein ("NEWLINE", "DEDENT", "INDENT", "ENDMARKER"):