Пример #1
0
    def extract_args_and_kwargs(
        self,
        context: InterpretingTask,
        options: TokenSeq,
    ) -> tuple[list, dict]:
        """
        Returns a pair of positional argument list and keyword argument dict.
        """
        section_flipped = False  # kwargs found
        args = []
        kwargs = {}

        for keyword_name, value_token in self.tokenize_args(context, options):
            if keyword_name is not None:
                section_flipped = True
                if keyword_name in kwargs:
                    raise PaxterRenderError(
                        f"duplicated keyword {keyword_name} at %(pos)s",
                        pos=CharLoc(context.src_text, options.start_pos),
                    )
                kwargs[keyword_name] = context.transform_token(value_token)
            elif section_flipped:
                raise PaxterRenderError(
                    "found positional argument after keyword argument at %(pos)s",
                    pos=CharLoc(context.src_text, options.start_pos),
                )
            else:
                args.append(context.transform_token(value_token))

        return args, kwargs
Пример #2
0
    def tokenize_args(
        context: InterpretingTask,
        options: TokenSeq,
    ) -> tuple[Optional[str], Token]:
        """
        Generates a sequence of arguments, each of which
        is a tuple pair of (argument name, argument value token).
        The first component may be None which indicates positional arguments.
        """
        remains: list[Token] = list(options.children)

        while remains:
            # Checks whether the second token is an '=' operator
            # indicating the existence of keyword argument
            keyword_name = None
            if len(remains) >= 2:
                first_token, second_token = remains[0], remains[1]
                if second_token == Operator.without_pos(symbols='='):
                    # Then the first token must be an identifier
                    if not isinstance(first_token, Identifier):
                        raise PaxterRenderError(
                            "expected an identifier before the '=' sign at %(pos)s",
                            pos=CharLoc(context.src_text,
                                        first_token.start_pos),
                        )
                    keyword_name = first_token.name
                    remains = remains[2:]

            # Expects the next value token to exist
            if not remains:
                raise PaxterRenderError(
                    "expected a value after the '=' sign at %(pos)s",
                    pos=CharLoc(context.src_text, options.end_pos),
                )
            value_token = remains[0]
            remains = remains[1:]

            # Yields the next argument
            yield keyword_name, value_token

            # If tokens are still remaining, the next one has to be a ',' operator
            if remains:
                end_token = remains[0]
                if end_token != Operator.without_pos(symbols=','):
                    raise PaxterRenderError(
                        "expected a comma token after the value token at %(pos)s",
                        pos=CharLoc(context.src_text, end_token.start_pos),
                    )
                remains = remains[1:]
Пример #3
0
 def transform_operator(self, token: Operator):
     """
     Transforms a given parsed operator.
     """
     raise PaxterRenderError(
         "operator not expected at %(pos)",
         pos=CharLoc(self.src_text, token.start_pos),
     )
Пример #4
0
 def transform_identifier(self, token: Identifier):
     """
     Transforms a given parsed identifier.
     """
     raise PaxterRenderError(
         "identifier not expected at %(pos)",
         pos=CharLoc(self.src_text, token.start_pos),
     )
Пример #5
0
 def transform_token_list(self, seq: TokenSeq):
     """
     Transforms a given parsed token list.
     """
     raise PaxterRenderError(
         "token list not expected at %(pos)s",
         pos=CharLoc(self.src_text, seq.start_pos),
     )
Пример #6
0
    def transform_command(self, token: Command) -> Any:
        """
        Transforms a given parsed command.
        """
        # Try to interp the phrase section
        # using the interp function from _phrase_eval_
        try:
            phrase_eval = self.env['_phrase_eval_']
        except KeyError as exc:
            raise PaxterRenderError(
                "expected '_phrase_eval_' to be defined at %(pos)s",
                pos=CharLoc(self.src_text, token.start_pos),
            ) from exc
        try:
            phrase_value = phrase_eval(token.phrase, self.env)
        except PaxterRenderError:
            raise
        except Exception as exc:
            raise PaxterRenderError(
                "paxter command phrase evaluation error at %(pos)s: "
                f"{token.phrase!r}",
                pos=CharLoc(self.src_text, token.start_pos),
            ) from exc

        # Bail out if options section and main arg section are empty
        if token.options is None and token.main_arg is None:
            return phrase_value

        # Wrap the function if not yet wrapped
        if not isinstance(phrase_value, BaseApply):
            phrase_value = NormalApply(phrase_value)

        # Make the call to the wrapped function
        try:
            return phrase_value.call(self, token)
        except PaxterRenderError:
            raise
        except Exception as exc:
            raise PaxterRenderError(
                "paxter apply evaluation error at %(pos)s",
                pos=CharLoc(self.src_text, token.start_pos),
            ) from exc
Пример #7
0
 def transform_fragment(self, fragment: Fragment) -> Any:
     """
     Transforms a given parsed fragment.
     """
     if isinstance(fragment, Text):
         return self.transform_text(fragment)
     if isinstance(fragment, Command):
         return self.transform_command(fragment)
     raise PaxterRenderError(
         "unrecognized fragment at %(pos)s",
         pos=CharLoc(self.src_text, fragment.start_pos),
     )
Пример #8
0
 def transform_token(self, token: Token) -> Any:
     """
     Transforms a given parsed token.
     """
     if isinstance(token, Fragment):
         return self.transform_fragment(token)
     if isinstance(token, TokenSeq):
         return self.transform_token_list(token)
     if isinstance(token, Identifier):
         return self.transform_identifier(token)
     if isinstance(token, Operator):
         return self.transform_operator(token)
     if isinstance(token, Number):
         return self.transform_number(token)
     if isinstance(token, FragmentSeq):
         return self.transform_fragment_list(token)
     raise PaxterRenderError(
         "unrecognized token at %(pos)s",
         pos=CharLoc(self.src_text, token.start_pos),
     )
Пример #9
0
 def raise_error(message):
     raise PaxterRenderError(
         f"{message} in if statement at %(pos)s",
         pos=CharLoc(context.src_text, node.options.start_pos),
     )