Source code for TagScriptEngine.verb

from __future__ import annotations

from typing import Optional, Protocol, Tuple

__all__: Tuple[str, ...] = ("Verb",)


class _Verb(Protocol):
    def __init__(
        self, verb_string: Optional[str] = None, *, limit: int = 2000, dot_parameter: bool = False
    ) -> None: ...

    def __parse(self, verb_string: str, limit: int) -> None: ...

    def _parse_paranthesis_parameter(self, i: int, v: str) -> bool: ...

    def _parse_dot_parameter(self, i: int, v: str) -> bool: ...

    def set_payload(self) -> None: ...

    def open_parameter(self, i: int) -> None: ...

    def close_parameter(self, i: int) -> bool: ...


[docs] class Verb(_Verb): """ Represents the passed TagScript block. Parameters ---------- verb_string: Optional[str] The string to parse into a verb. limit: int The maximum number of characters to parse. dot_parameter: bool Whether the parameter should be followed after a "." or use the default of parantheses. Attributes ---------- declaration: Optional[str] The text used to declare the block. parameter: Optional[str] The text passed to the block parameter in the parentheses. payload: Optional[str] The text passed to the block payload after the colon. Example ------- Below is a visual representation of a block and its attributes:: {declaration(parameter):payload} # dot_parameter = True {declaration.parameter:payload} """ __slots__: Tuple[str, ...] = ( "declaration", "parameter", "payload", "parsed_string", "dec_depth", "dec_start", "skip_next", "parsed_length", "dot_parameter", ) def __init__( self, verb_string: Optional[str] = None, *, limit: int = 2000, dot_parameter: bool = False ) -> None: self.declaration: Optional[str] = None self.parameter: Optional[str] = None self.payload: Optional[str] = None self.dot_parameter = dot_parameter if verb_string is None: return self.__parse(verb_string, limit) def __str__(self) -> str: """This makes Verb compatible with str(x)""" response = "{" if self.declaration is not None: response += self.declaration if self.parameter is not None: response += f".{self.parameter}" if self.dot_parameter else f"({self.parameter})" if self.payload is not None: response += ":" + self.payload return response + "}" def __repr__(self) -> str: attrs = ("declaration", "parameter", "payload") inner = " ".join(f"{attr}={getattr(self, attr)!r}" for attr in attrs) return f"<Verb {inner}>" def __parse(self, verb_string: str, limit: int) -> None: self.parsed_string = verb_string[1:-1][:limit] self.parsed_length = len(self.parsed_string) self.dec_depth = 0 self.dec_start = 0 self.skip_next = False parse_parameter = ( self._parse_dot_parameter if self.dot_parameter else self._parse_paranthesis_parameter ) for i, v in enumerate(self.parsed_string): if self.skip_next: self.skip_next = False continue elif v == "\\": self.skip_next = True continue if v == ":" and not self.dec_depth: self.set_payload() return elif parse_parameter(i, v): return else: self.set_payload() def _parse_paranthesis_parameter(self, i: int, v: str) -> bool: if v == "(": self.open_parameter(i) elif v == ")" and self.dec_depth: return self.close_parameter(i) return False def _parse_dot_parameter(self, i: int, v: str) -> bool: if v == ".": self.open_parameter(i) elif (v == ":" or i == self.parsed_length - 1) and self.dec_depth: return self.close_parameter(i + 1) return False def set_payload(self) -> None: res = self.parsed_string.split(":", 1) if len(res) == 2: self.payload = res[1] self.declaration = res[0] def open_parameter(self, i: int) -> None: self.dec_depth += 1 if not self.dec_start: self.dec_start = i self.declaration = self.parsed_string[:i] def close_parameter(self, i: int) -> bool: self.dec_depth -= 1 if self.dec_depth == 0: self.parameter = self.parsed_string[self.dec_start + 1 : i] try: if self.parsed_string[i + 1] == ":": self.payload = self.parsed_string[i + 2 :] except IndexError: pass return True return False