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"):