Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
parser.py183 linesDownload Raw Back to dotenv
1import codecs2import re3from typing import (4    IO,5    Iterator,6    Match,7    NamedTuple,8    Optional,9    Pattern,10    Sequence,11)12 13 14def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]:15    return re.compile(string, re.UNICODE | extra_flags)16 17 18_newline = make_regex(r"(\r\n|\n|\r)")19_multiline_whitespace = make_regex(r"\s*", extra_flags=re.MULTILINE)20_whitespace = make_regex(r"[^\S\r\n]*")21_export = make_regex(r"(?:export[^\S\r\n]+)?")22_single_quoted_key = make_regex(r"'([^']+)'")23_unquoted_key = make_regex(r"([^=\#\s]+)")24_equal_sign = make_regex(r"(=[^\S\r\n]*)")25_single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'")26_double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"')27_unquoted_value = make_regex(r"([^\r\n]*)")28_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?")29_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)")30_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?")31_double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]")32_single_quote_escapes = make_regex(r"\\[\\']")33 34 35class Original(NamedTuple):36    string: str37    line: int38 39 40class Binding(NamedTuple):41    key: Optional[str]42    value: Optional[str]43    original: Original44    error: bool45 46 47class Position:48    def __init__(self, chars: int, line: int) -> None:49        self.chars = chars50        self.line = line51 52    @classmethod53    def start(cls) -> "Position":54        return cls(chars=0, line=1)55 56    def set(self, other: "Position") -> None:57        self.chars = other.chars58        self.line = other.line59 60    def advance(self, string: str) -> None:61        self.chars += len(string)62        self.line += len(re.findall(_newline, string))63 64 65class Error(Exception):66    pass67 68 69class Reader:70    def __init__(self, stream: IO[str]) -> None:71        self.string = stream.read()72        self.position = Position.start()73        self.mark = Position.start()74 75    def has_next(self) -> bool:76        return self.position.chars < len(self.string)77 78    def set_mark(self) -> None:79        self.mark.set(self.position)80 81    def get_marked(self) -> Original:82        return Original(83            string=self.string[self.mark.chars : self.position.chars],84            line=self.mark.line,85        )86 87    def peek(self, count: int) -> str:88        return self.string[self.position.chars : self.position.chars + count]89 90    def read(self, count: int) -> str:91        result = self.string[self.position.chars : self.position.chars + count]92        if len(result) < count:93            raise Error("read: End of string")94        self.position.advance(result)95        return result96 97    def read_regex(self, regex: Pattern[str]) -> Sequence[str]:98        match = regex.match(self.string, self.position.chars)99        if match is None:100            raise Error("read_regex: Pattern not found")101        self.position.advance(self.string[match.start() : match.end()])102        return match.groups()103 104 105def decode_escapes(regex: Pattern[str], string: str) -> str:106    def decode_match(match: Match[str]) -> str:107        return codecs.decode(match.group(0), "unicode-escape")  # type: ignore108 109    return regex.sub(decode_match, string)110 111 112def parse_key(reader: Reader) -> Optional[str]:113    char = reader.peek(1)114    if char == "#":115        return None116    elif char == "'":117        (key,) = reader.read_regex(_single_quoted_key)118    else:119        (key,) = reader.read_regex(_unquoted_key)120    return key121 122 123def parse_unquoted_value(reader: Reader) -> str:124    (part,) = reader.read_regex(_unquoted_value)125    return re.sub(r"\s+#.*", "", part).rstrip()126 127 128def parse_value(reader: Reader) -> str:129    char = reader.peek(1)130    if char == "'":131        (value,) = reader.read_regex(_single_quoted_value)132        return decode_escapes(_single_quote_escapes, value)133    elif char == '"':134        (value,) = reader.read_regex(_double_quoted_value)135        return decode_escapes(_double_quote_escapes, value)136    elif char in ("", "\n", "\r"):137        return ""138    else:139        return parse_unquoted_value(reader)140 141 142def parse_binding(reader: Reader) -> Binding:143    reader.set_mark()144    try:145        reader.read_regex(_multiline_whitespace)146        if not reader.has_next():147            return Binding(148                key=None,149                value=None,150                original=reader.get_marked(),151                error=False,152            )153        reader.read_regex(_export)154        key = parse_key(reader)155        reader.read_regex(_whitespace)156        if reader.peek(1) == "=":157            reader.read_regex(_equal_sign)158            value: Optional[str] = parse_value(reader)159        else:160            value = None161        reader.read_regex(_comment)162        reader.read_regex(_end_of_line)163        return Binding(164            key=key,165            value=value,166            original=reader.get_marked(),167            error=False,168        )169    except Error:170        reader.read_regex(_rest_of_line)171        return Binding(172            key=None,173            value=None,174            original=reader.get_marked(),175            error=True,176        )177 178 179def parse_stream(stream: IO[str]) -> Iterator[Binding]:180    reader = Reader(stream)181    while reader.has_next():182        yield parse_binding(reader)183 
codekingpro/portable-devtools · Team Ai