Source code for bTagScript.verb

from typing import Optional

__all__ = ("Verb",)


[docs]class 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. 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:: .. tagscript:: Normally {declaration(parameter):payload} """ __slots__ = ( "declaration", "parameter", "payload", "parsed_string", "dec_depth", "dec_start", "skip_next", "parsed_length", ) def __init__(self, verb_string: Optional[str] = None, *, limit: int = 2000) -> None: """ Constructor for the class """ self.declaration: Optional[str] = None self.parameter: Optional[str] = None self.payload: Optional[str] = None if verb_string is None: return self.__parse(verb_string, limit) self.dec_start: int = None 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.payload is not None: response += ":" + self.payload return response + "}" def __repr__(self) -> str: """ String represent """ 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: """ Parse the string into a verb Parameters ---------- verb_string: str The string to parse into a verb. limit: int The maximum number of characters to parse. Returns ------- 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_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: # if v == ":" and not dec_depth: self.set_payload() return elif parse_parameter(i, v): return # Used to have an else here self.set_payload() def _parse_parameter(self, i: int, v: str) -> bool: """ Parse the parameter in parentheses Parameters ---------- i: int ~ v: str ~ Returns ------- bool Whether the parameter was parsed """ if v == "(": self.open_parameter(i) elif v == ")" and self.dec_depth: return self.close_parameter(i) return False
[docs] def set_payload(self) -> None: """ Set the payload """ res = self.parsed_string.split(":", 1) if len(res) == 2: self.payload = res[1] self.declaration = res[0]
[docs] def open_parameter(self, i: int) -> None: """ Open the parameter """ self.dec_depth += 1 if not self.dec_start: self.dec_start = i self.declaration = self.parsed_string[:i]
[docs] def close_parameter(self, i: int) -> bool: """ Close the parameter """ 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