Skip to content

Commit

Permalink
pythongh-125588: Teach the python PEG generator the new f-string tokens
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Galindo <[email protected]>
  • Loading branch information
pablogsal committed Oct 16, 2024
1 parent 760872e commit 3363178
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Lib/test/test_peg_generator/test_pegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,14 @@ def test_python_expr(self) -> None:
val = eval(code)
self.assertEqual(val, 3.0)

def test_f_string_in_action(self) -> None:
grammar = """
start: n=NAME NEWLINE? $ { f"name -> {n.string}" }
"""
parser_class = make_parser(grammar)
node = parse_string("a", parser_class)
self.assertEqual(node.strip(), "name -> a")

def test_nullable(self) -> None:
grammar_source = """
start: sign NUMBER
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The Python PEG generator can now use f-strings in the grammar actions. Patch
by Pablo Galindo
17 changes: 16 additions & 1 deletion Tools/peg_generator/pegen/grammar_parser.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Tools/peg_generator/pegen/metagrammar.gram
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ target_atom[str]:
| NAME { name.string }
| NUMBER { number.string }
| STRING { string.string }
| FSTRING_START { fstring_start.string }
| FSTRING_MIDDLE { fstring_middle.string }
| FSTRING_END { fstring_end.string }
| "?" { "?" }
| ":" { ":" }
| !"}" !"]" OP { op.string }
30 changes: 30 additions & 0 deletions Tools/peg_generator/pegen/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,36 @@ def string(self) -> Optional[tokenize.TokenInfo]:
return self._tokenizer.getnext()
return None

@memoize
def fstring_start(self) -> Optional[tokenize.TokenInfo]:
FSTRING_START = getattr(token, "FSTRING_START")
if not FSTRING_START:
return None
tok = self._tokenizer.peek()
if tok.type == FSTRING_START:
return self._tokenizer.getnext()
return None

@memoize
def fstring_middle(self) -> Optional[tokenize.TokenInfo]:
FSTRING_MIDDLE = getattr(token, "FSTRING_MIDDLE")
if not FSTRING_MIDDLE:
return None
tok = self._tokenizer.peek()
if tok.type == FSTRING_MIDDLE:
return self._tokenizer.getnext()
return None

@memoize
def fstring_end(self) -> Optional[tokenize.TokenInfo]:
FSTRING_END = getattr(token, "FSTRING_END")
if not FSTRING_END:
return None
tok = self._tokenizer.peek()
if tok.type == FSTRING_END:
return self._tokenizer.getnext()
return None

@memoize
def op(self) -> Optional[tokenize.TokenInfo]:
tok = self._tokenizer.peek()
Expand Down
3 changes: 2 additions & 1 deletion Tools/peg_generator/pegen/python_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ def visit_NameLeaf(self, node: NameLeaf) -> Tuple[Optional[str], str]:
name = node.value
if name == "SOFT_KEYWORD":
return "soft_keyword", "self.soft_keyword()"
if name in ("NAME", "NUMBER", "STRING", "OP", "TYPE_COMMENT"):
if name in ("NAME", "NUMBER", "STRING", "OP", "TYPE_COMMENT",
"FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START"):
name = name.lower()
return name, f"self.{name}()"
if name in ("NEWLINE", "DEDENT", "INDENT", "ENDMARKER"):
Expand Down

0 comments on commit 3363178

Please sign in to comment.