1 file changed
@@ -35,6 +35,7 @@ | |||
| 35 | 35 | import time | |
| 36 | 36 | import traceback | |
| 37 | 37 | from abc import abstractmethod | |
| 38 | + from dataclasses import dataclass | ||
| 38 | 39 | from itertools import takewhile | |
| 39 | 40 | from pathlib import Path | |
| 40 | 41 | from types import ModuleType, TracebackType | |
@@ -380,6 +381,17 @@ class SourceNotFound(Exception): | |||
| 380 | 381 | """Exception raised when the requested source could not be found.""" | |
| 381 | 382 | ||
| 382 | 383 | ||
| 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 | + | ||
| 383 | 395 | class Repl: | |
| 384 | 396 | """Implements the necessary guff for a Python-repl-alike interface | |
| 385 | 397 | ||
@@ -564,37 +576,37 @@ def get_object(self, name): | |||
| 564 | 576 | return obj | |
| 565 | 577 | ||
| 566 | 578 | @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]]]: | ||
| 568 | 582 | """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, "")] | ||
| 574 | 586 | try: | |
| 575 | 587 | for (token, value) in Python3Lexer().get_tokens(line): | |
| 576 | 588 | if token is Token.Punctuation: | |
| 577 | 589 | if value in "([{": | |
| 578 | - stack.append(["", "", 0, value]) | ||
| 590 | + stack.append(_FuncExpr("", "", 0, value)) | ||
| 579 | 591 | 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 | ||
| 584 | 596 | 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 | ||
| 595 | 607 | else: | |
| 596 | - stack[-1][1] = "" | ||
| 597 | - stack[-1][0] += value | ||
| 608 | + stack[-1].function_expr = "" | ||
| 609 | + stack[-1].full_expr += value | ||
| 598 | 610 | elif ( | |
| 599 | 611 | token is Token.Number | |
| 600 | 612 | or token in Token.Number.subtypes | |
@@ -603,25 +615,25 @@ def _funcname_and_argnum(cls, line): | |||
| 603 | 615 | or token is Token.Operator | |
| 604 | 616 | and value == "." | |
| 605 | 617 | ): | |
| 606 | - stack[-1][1] += value | ||
| 607 | - stack[-1][0] += value | ||
| 618 | + stack[-1].function_expr += value | ||
| 619 | + stack[-1].full_expr += value | ||
| 608 | 620 | 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 | ||
| 612 | 624 | 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 | ||
| 615 | 627 | elif token is Token.Keyword and value == "lambda": | |
| 616 | - stack.append([value, "", 0, value]) | ||
| 628 | + stack.append(_FuncExpr(value, "", 0, value)) | ||
| 617 | 629 | 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 "[{": | ||
| 621 | 633 | 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 | ||
| 625 | 637 | except IndexError: | |
| 626 | 638 | return None, None | |
| 627 | 639 | ||
0 commit comments