mirror of
https://github.com/RGBCube/DML
synced 2025-07-27 23:57:44 +00:00
Initial Commit
This commit is contained in:
parent
66739939c2
commit
1e815a2dc0
9 changed files with 243 additions and 1 deletions
16
dml/__init__.py
Normal file
16
dml/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
Dotted Markup Language
|
||||
|
||||
Translate text to and from DML with ease.
|
||||
"""
|
||||
|
||||
__title__ = "DML"
|
||||
__author__ = "RGBCube"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright (c) 2022-present RGBCube"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
from .encoder import *
|
||||
from .errors import *
|
||||
from .fileutils import *
|
||||
from .run import *
|
61
dml/encoder.py
Normal file
61
dml/encoder.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
import typing as t
|
||||
|
||||
from .errors import DecodeError
|
||||
from .symbols import symbols as s
|
||||
|
||||
__all__ = ("encode", "decode")
|
||||
|
||||
|
||||
def encode(text: t.Union[t.Generator, t.List[str], str], *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
|
||||
"""Encodes text into Dotted Markup Language (DML)
|
||||
|
||||
Arguments:
|
||||
text (Union[Generator, List[str], str]): The text to encode.
|
||||
out (str): The filepath to write the encoded file to. If not specified, the encoded text will be returned as a generator.
|
||||
|
||||
Returns:
|
||||
Optional[Generator[str, None, None]]: The encoded text as a generator.
|
||||
"""
|
||||
|
||||
def inner() -> t.Generator[str, None, None]:
|
||||
for char_ in text:
|
||||
yield format(ord(char_), "b").replace("0", s["0"]).replace("1", s["1"]) + s["stop"]
|
||||
|
||||
if out:
|
||||
out = out + ".dml" if not out.endswith(".dml") else out
|
||||
with open(out, "w") as f:
|
||||
for char in inner():
|
||||
f.write(char)
|
||||
else:
|
||||
return inner()
|
||||
|
||||
|
||||
def decode(text: t.Union[t.Generator, t.List[str], str], *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
|
||||
"""Decodes text from Dotted Markup Language (DML)
|
||||
|
||||
Arguments:
|
||||
text (Union[Generator, List[str], str]): The text to decode.
|
||||
out (str): The filepath to write the decoded file to. If not specified, the decoded text will be returned as a generator.
|
||||
|
||||
Returns:
|
||||
Optional[Generator[str, None, None]]: The decoded text as a generator.
|
||||
|
||||
Raises:
|
||||
DecodeError: If the text is not valid DML.
|
||||
"""
|
||||
|
||||
def inner() -> t.Generator[str, None, None]:
|
||||
nonlocal text
|
||||
if isinstance(text, str):
|
||||
text = [e + s["stop"] for e in text.split(s["stop"]) if e]
|
||||
for char_ in text:
|
||||
if any(e not in s.values() for e in char_):
|
||||
raise DecodeError(f"Invalid character: '{char_}', expected {s['1']}, {s['0']} or {s['stop']}")
|
||||
yield chr(int(char_[:-1].replace(s['0'], "0").replace(s['1'], "1"), 2))
|
||||
|
||||
if out:
|
||||
with open(out, "w") as f:
|
||||
for char in inner():
|
||||
f.write(char)
|
||||
else:
|
||||
return inner()
|
11
dml/errors.py
Normal file
11
dml/errors.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
__all__ = ("DottedMarkupLanguageException", "DecodeError")
|
||||
|
||||
|
||||
class DottedMarkupLanguageException(Exception):
|
||||
"""Base class for all exceptions in this module."""
|
||||
pass
|
||||
|
||||
|
||||
class DecodeError(DottedMarkupLanguageException):
|
||||
"""Raised when there is an error decoding a string."""
|
||||
pass
|
67
dml/fileutils.py
Normal file
67
dml/fileutils.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
import typing as t
|
||||
|
||||
from .encoder import encode, decode
|
||||
from .errors import DecodeError
|
||||
from .symbols import symbols as s
|
||||
|
||||
__all__ = ("decode_file", "encode_file")
|
||||
|
||||
|
||||
def encode_file(fp: str, *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
|
||||
"""Encodes a file to DML.
|
||||
|
||||
Arguments:
|
||||
fp (str): The filepath to the file to encode.
|
||||
out (str): The filepath to write the encoded file to. If not specified, the encoded text will be returned as a generator.
|
||||
|
||||
Returns:
|
||||
Optional[Generator[str, None, None]]: The encoded text as a generator.
|
||||
"""
|
||||
|
||||
def read_file() -> t.Generator[str, None, None]:
|
||||
with open(fp) as f_:
|
||||
while char_ := f_.read(1):
|
||||
yield char_
|
||||
|
||||
if out:
|
||||
out = out + ".dml" if not out.endswith(".dml") else out
|
||||
with open(out, "w") as f:
|
||||
for char in encode(read_file()):
|
||||
f.write(char)
|
||||
else:
|
||||
return encode(read_file())
|
||||
|
||||
|
||||
def decode_file(fp: str, *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
|
||||
"""Decodes a file that has DML encoded in it.
|
||||
|
||||
Arguments:
|
||||
fp (str): The filepath to the file to decode.
|
||||
out (str): The filepath to write the decoded file to. If not specified, the decoded text will be returned as a generator.
|
||||
|
||||
Returns:
|
||||
Optional[Generator[str, None, None]]: The decoded text as a generator.
|
||||
|
||||
Raises:
|
||||
DecodeError: If the file is not valid DML.
|
||||
"""
|
||||
|
||||
def read_file() -> t.Generator[str, None, None]:
|
||||
buffer = ""
|
||||
with open(fp) as f_:
|
||||
while char_ := f_.read(1):
|
||||
if char_ not in s.values():
|
||||
raise DecodeError(f"Invalid character: '{char_}', expected {s['1']}, {s['0']} or {s['stop']}")
|
||||
elif char_ != s["stop"]:
|
||||
buffer += char_
|
||||
else:
|
||||
yield buffer + s["stop"]
|
||||
buffer = ""
|
||||
|
||||
if out:
|
||||
out = out + ".dml" if not out.endswith(".dml") else out
|
||||
with open(out, "w") as f:
|
||||
for char in decode(read_file()):
|
||||
f.write(char)
|
||||
else:
|
||||
return decode(read_file())
|
12
dml/run.py
Normal file
12
dml/run.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from .encoder import decode
|
||||
from .fileutils import decode_file
|
||||
|
||||
__all__ = ("run_file", "run")
|
||||
|
||||
|
||||
def run(dml: str) -> None:
|
||||
exec("".join(decode(dml)))
|
||||
|
||||
|
||||
def run_file(fp: str) -> None:
|
||||
exec("".join(decode_file(fp)))
|
5
dml/symbols.py
Normal file
5
dml/symbols.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
symbols = {
|
||||
"1": "\u0701", # Syriac Supralinear Full Stop
|
||||
"0": "\u0660", # Arabic-Indic Digit Zero
|
||||
"stop": "\u06F0", # Extended Arabic-Indic Digit Zero
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue