2 Commits
+104 -172
View File
@@ -1,12 +1,11 @@
"thanks chatgpt" "thanks chatgpt"
import os
import textwrap
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections.abc import Iterable from collections.abc import Iterable
from functools import wraps
from pathlib import Path from pathlib import Path
from pprint import pprint from typing import Callable
from typing import Callable, TypedDict, overload
root = Path(__file__).parent.parent root = Path(__file__).parent.parent
static = root / "static" static = root / "static"
@@ -20,13 +19,7 @@ assert 'name = "wakey"' in (root / "Cargo.toml").read_text(encoding="utf-8"), (
def sanitize(name: str) -> str: def sanitize(name: str) -> str:
# Valid Rust identifiers: letters, digits, underscores; no starting digit # Valid Rust identifiers: letters, digits, underscores; no starting digit
out = [] s = "".join(c if c.isalnum() else "_" for c in name)
for c in name:
if c.isalnum() or c == "_":
out.append(c)
else:
out.append("_")
s = "".join(out)
if s and s[0].isdigit(): if s and s[0].isdigit():
s = "_" + s s = "_" + s
return s return s
@@ -34,70 +27,73 @@ def sanitize(name: str) -> str:
def indent(text: str, n: int) -> str: def indent(text: str, n: int) -> str:
pad = " " * n pad = " " * n
return "\n".join(pad + line if line.strip() else line for line in text.splitlines()) return textwrap.indent(text, pad)
class RsAsset(ABC): class RsAsset(ABC):
path: Path path: Path
@abstractmethod
def plain(self) -> str: ...
@abstractmethod
def macroed(self) -> str: ...
class RsAssetWithName(ABC):
class RsAssetFile(RsAsset): name: str
def __init__(self, path: Path, name: str | None = None):
self.path = path
if name is None:
self.name = sanitize(self.path.name).upper()
else:
self.name = name
def _apply_template(self, template):
return template.format(
const_name=self.name,
relative_path=self.path.relative_to(src, walk_up=True).as_posix(),
)
plain_template = 'pub const {const_name}: &str = include_str!("{relative_path}");'
macroed_template = 'file {const_name} "{relative_path}"'
def plain(self):
return self._apply_template(self.plain_template)
def macroed(self):
return self._apply_template(self.macroed_template)
class RsAssetModule(RsAsset):
def __init__(self, path: Path, name: str | None = None):
self.path = path
if name is None:
self.name = sanitize(self.path.name).lower()
else:
self.name = name
plain_template = "pub mod {sanitized_name} {{\n{indented_body}\n}}"
macroed_template = "folder {sanitized_name} {{\n{indented_body}\n}}"
def plain(self):
return self._apply_template(self.plain_template, lambda it: it.plain())
def macroed(self):
return self._apply_template(self.macroed_template, lambda it: it.macroed())
def _apply_template(self, template: str, renderer: Callable[[RsAsset], str]):
body = self._process_body(self.path, renderer)
return template.format(
sanitized_name=self.name,
indented_body=indent(body, 4),
)
@staticmethod @staticmethod
def _process_body(path: Path, renderer: Callable[[RsAsset], str]): @abstractmethod
def name_gen(path: Path) -> str:
"helper"
class RsAssetFile(RsAsset, RsAssetWithName):
__match_args__ = ("path", "name")
def __init__(self, path: Path, name: str | None = None):
self.path = path
if name is None:
self.name: str = RsAssetFile.name_gen(path)
else:
self.name = name
def path_relative_to(self, path: Path):
"helper"
return self.path.relative_to(path, walk_up=True).as_posix()
@staticmethod
def plain_template(const_name: str, relative_path: str):
return f'pub const {const_name}: &str = include_str!("{relative_path}");'
@staticmethod
def macroed_template(const_name: str, relative_path: str):
return f'file {const_name} "{relative_path}"'
@staticmethod
def name_gen(path: Path) -> str:
return sanitize(path.name).upper()
class RsAssetModule(RsAsset, RsAssetWithName):
__match_args__ = ("path", "name")
def __init__(self, path: Path, name: str | None = None):
self.path = path
if name is None:
self.name: str = RsAssetModule.name_gen(path)
else:
self.name = name
@staticmethod
def plain_template(sanitized_name: str, body: str):
"braindead"
indented_body = indent(body, 4)
return f"pub mod {sanitized_name} {{\n{indented_body}\n}}"
@staticmethod
def macroed_template(sanitized_name: str, body: str):
indented_body = indent(body, 4)
return f"folder {sanitized_name} {{\n{indented_body}\n}}"
@staticmethod
def process_body(path: Path, renderer: Callable[[RsAsset], str]):
"here just cuz. Path has to be a folder... so idk"
body = RsAssetModule.iterate_assets(path) body = RsAssetModule.iterate_assets(path)
return "\n".join(map(renderer, body)) return "\n".join(map(renderer, body))
@@ -111,21 +107,27 @@ class RsAssetModule(RsAsset):
subs.append(RsAssetModule(f)) subs.append(RsAssetModule(f))
yield from subs yield from subs
@staticmethod
def name_gen(path: Path) -> str:
return sanitize(path.name).lower()
# i meant plain # i meant plain
def render_pain(ass: RsAsset) -> str: def render_pain(ass: RsAsset) -> str:
""" """
fym i have to deal with all RsAsset subclasses fym i have to deal with all RsAsset subclasses.
whats the point then. unless there is a `Intermediate Representation` whats the point then. ts like a matrix of ahh.
""" """
match ass: match ass:
case RsAssetRoot() as r: case RsAssetRoot(path):
return r.plain() body = RsAssetModule.process_body(path, render_pain)
case RsAssetModule() as folder: return RsAssetRoot.plain_template(body)
return folder.plain() case RsAssetModule(path, name):
case RsAssetFile() as file: body = RsAssetModule.process_body(path, render_pain)
return file.plain() return RsAssetModule.plain_template(name, body)
case RsAssetFile(path, name) as file:
return RsAssetFile.plain_template(name, file.path_relative_to(src))
case _: case _:
raise TypeError("who are you?") raise TypeError("who are you?")
@@ -135,61 +137,21 @@ def render_macro(ass: RsAsset) -> str:
ts is ridiculous ts is ridiculous
""" """
match ass: match ass:
case RsAssetRoot() as r: case RsAssetRoot(path):
return r.macroed() body = RsAssetModule.process_body(path, render_macro)
case RsAssetModule() as folder: return RsAssetRoot.macroed_template(body)
return folder.macroed() case RsAssetModule(path, name):
case RsAssetFile() as file: body = RsAssetModule.process_body(path, render_macro)
return file.macroed() return RsAssetModule.macroed_template(name, body)
case RsAssetFile(path, name) as file:
return RsAssetFile.macroed_template(name, file.path_relative_to(src))
case _: case _:
raise TypeError("who are you?") raise TypeError("who are you?")
class RsAssetModule2(TypedDict): # region shit ass
name: str # im deleting this code because its so ass
path: Path # endregion
children: "list[RsAssetModule2 | RsAssetFile2]"
class RsAssetFile2(TypedDict):
name: str
path: Path
@overload
def dictionary(im: "RsAssetRoot") -> RsAssetModule2: ...
@overload
def dictionary(im: RsAssetModule) -> RsAssetModule2: ...
@overload
def dictionary(im: RsAssetFile) -> RsAssetFile2: ...
@overload
def dictionary(im: RsAssetFile | RsAssetModule) -> RsAssetFile2 | RsAssetModule2: ...
def dictionary(im: RsAsset) -> RsAssetModule2 | RsAssetFile2:
match im:
case RsAssetRoot() as r:
return RsAssetModule2(
name="ROOT",
path=r.path,
children=list(map(dictionary, RsAssetModule.iterate_assets(r.path))),
)
case RsAssetModule() as folder:
return RsAssetModule2(
name=sanitize(folder.path.name).lower(),
path=folder.path,
children=list(
map(dictionary, RsAssetModule.iterate_assets(folder.path))
),
)
case RsAssetFile() as file:
return RsAssetFile2(
name=sanitize(file.path.name).upper(),
path=file.path,
)
case _:
raise TypeError("who are you?")
lda_macro = """ lda_macro = """
macro_rules! hehe { macro_rules! hehe {
@@ -212,67 +174,37 @@ macro_rules! hehe {
header = "// generated with ./scripts/map_static.py" header = "// generated with ./scripts/map_static.py"
def announce_yourself(*pa, **pkw):
def wpr[**P, R](f: Callable[P, R]) -> Callable[P, R]:
@wraps(f)
def wpd(*a: P.args, **k: P.kwargs) -> R:
print(*pa, **pkw)
return f(*a, **k)
return wpd
return wpr
class RsAssetRoot(RsAsset): class RsAssetRoot(RsAsset):
plain_template = """{header} __match_args__ = ("path",)
@staticmethod
def plain_template(body: str):
return f"""{header}
{body} {body}
""" """
macroed_template = """{header}
@staticmethod
def macroed_template(body: str):
indented_body = indent(body, 4)
return f"""{header}
{lda_macro} {lda_macro}
hehe! {{ hehe! {{
{indented_body} {indented_body}
}} }}
""" """
def __init__(self, asset_root: Path) -> None: def __init__(self, path: Path) -> None:
self.path = asset_root os.scandir(path) # is you a dir?
self._w = RsAssetModule(asset_root) self.path = path
def plain(self) -> str:
body = RsAssetModule._process_body(self.path, lambda it: it.plain())
return self.plain_template.format(
header=header,
body=body,
)
def macroed(self) -> str:
body = RsAssetModule._process_body(self.path, lambda it: it.macroed())
return self.macroed_template.format(
header=header,
lda_macro=lda_macro,
indented_body=indent(body, 4),
)
asset_root = RsAssetRoot(static) asset_root = RsAssetRoot(static)
pprint(dictionary(asset_root)) # print(render_pain(asset_root))
# print(render_macro(asset_root))
def render_ir(node: RsAssetModule2 | RsAssetFile2) -> str:
"gemini 3 pro"
if "children" in node:
body = "\n".join(map(render_ir, node["children"])) # type: ignore[typeddict-item]
if node["name"] == "ROOT":
return f"{header}\n\n{body}\n"
return f"pub mod {node['name']} {{\n{indent(body, 4)}\n}}"
rel = node["path"].relative_to(src, walk_up=True).as_posix()
return f'pub const {node["name"]}: &str = include_str!("{rel}");'
# rs_code = render_pain(asset_root)
rs_code = render_macro(asset_root) rs_code = render_macro(asset_root)
# generate # generate