← 返回首页
Refactor _funcname_and_argnum to avoid Exception-based control flow · bpython/bpython@e906df7 · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

Commit e906df7

Browse files
committed
Refactor _funcname_and_argnum to avoid Exception-based control flow
1 parent 0ada13d commit e906df7

1 file changed

Lines changed: 49 additions & 37 deletions

File tree

‎bpython/repl.py‎

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import time
3636
import traceback
3737
from abc import abstractmethod
38+
from dataclasses import dataclass
3839
from itertools import takewhile
3940
from pathlib import Path
4041
from types import ModuleType, TracebackType
@@ -380,6 +381,17 @@ class SourceNotFound(Exception):
380381
"""Exception raised when the requested source could not be found."""
381382

382383

384+
@dataclass
385+
class _FuncExpr:
386+
"""Stack element in Repl._funcname_and_argnum"""
387+
388+
full_expr: str
389+
function_expr: str
390+
arg_number: int
391+
opening: str
392+
keyword: Optional[str] = None
393+
394+
383395
class Repl:
384396
"""Implements the necessary guff for a Python-repl-alike interface
385397
@@ -564,37 +576,37 @@ def get_object(self, name):
564576
return obj
565577

566578
@classmethod
567-
def _funcname_and_argnum(cls, line):
579+
def _funcname_and_argnum(
580+
cls, line: str
581+
) -> Tuple[Optional[str], Optional[Union[str, int]]]:
568582
"""Parse out the current function name and arg from a line of code."""
569-
# each list in stack:
570-
# [full_expr, function_expr, arg_number, opening]
571-
# arg_number may be a string if we've encountered a keyword
572-
# argument so we're done counting
573-
stack = [["", "", 0, ""]]
583+
# each element in stack is a _FuncExpr instance
584+
# if keyword is not None, we've encountered a keyword and so we're done counting
585+
stack = [_FuncExpr("", "", 0, "")]
574586
try:
575587
for (token, value) in Python3Lexer().get_tokens(line):
576588
if token is Token.Punctuation:
577589
if value in "([{":
578-
stack.append(["", "", 0, value])
590+
stack.append(_FuncExpr("", "", 0, value))
579591
elif value in ")]}":
580-
full, _, _, start = stack.pop()
581-
expr = start + full + value
582-
stack[-1][1] += expr
583-
stack[-1][0] += expr
592+
element = stack.pop()
593+
expr = element.opening + element.full_expr + value
594+
stack[-1].function_expr += expr
595+
stack[-1].full_expr += expr
584596
elif value == ",":
585-
try:
586-
stack[-1][2] += 1
587-
except TypeError:
588-
stack[-1][2] = ""
589-
stack[-1][1] = ""
590-
stack[-1][0] += value
591-
elif value == ":" and stack[-1][3] == "lambda":
592-
expr = stack.pop()[0] + ":"
593-
stack[-1][1] += expr
594-
stack[-1][0] += expr
597+
if stack[-1].keyword is None:
598+
stack[-1].arg_number += 1
599+
else:
600+
stack[-1].keyword = ""
601+
stack[-1].function_expr = ""
602+
stack[-1].full_expr += value
603+
elif value == ":" and stack[-1].opening == "lambda":
604+
expr = stack.pop().full_expr + ":"
605+
stack[-1].function_expr += expr
606+
stack[-1].full_expr += expr
595607
else:
596-
stack[-1][1] = ""
597-
stack[-1][0] += value
608+
stack[-1].function_expr = ""
609+
stack[-1].full_expr += value
598610
elif (
599611
token is Token.Number
600612
or token in Token.Number.subtypes
@@ -603,25 +615,25 @@ def _funcname_and_argnum(cls, line):
603615
or token is Token.Operator
604616
and value == "."
605617
):
606-
stack[-1][1] += value
607-
stack[-1][0] += value
618+
stack[-1].function_expr += value
619+
stack[-1].full_expr += value
608620
elif token is Token.Operator and value == "=":
609-
stack[-1][2] = stack[-1][1]
610-
stack[-1][1] = ""
611-
stack[-1][0] += value
621+
stack[-1].keyword = stack[-1].function_expr
622+
stack[-1].function_expr = ""
623+
stack[-1].full_expr += value
612624
elif token is Token.Number or token in Token.Number.subtypes:
613-
stack[-1][1] = value
614-
stack[-1][0] += value
625+
stack[-1].function_expr = value
626+
stack[-1].full_expr += value
615627
elif token is Token.Keyword and value == "lambda":
616-
stack.append([value, "", 0, value])
628+
stack.append(_FuncExpr(value, "", 0, value))
617629
else:
618-
stack[-1][1] = ""
619-
stack[-1][0] += value
620-
while stack[-1][3] in "[{":
630+
stack[-1].function_expr = ""
631+
stack[-1].full_expr += value
632+
while stack[-1].opening in "[{":
621633
stack.pop()
622-
_, _, arg_number, _ = stack.pop()
623-
_, func, _, _ = stack.pop()
624-
return func, arg_number
634+
elem1 = stack.pop()
635+
elem2 = stack.pop()
636+
return elem2.function_expr, elem1.keyword or elem1.arg_number
625637
except IndexError:
626638
return None, None
627639

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.