diff options
-rw-r--r-- | libobj/object.gen | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/libobj/object.gen b/libobj/object.gen new file mode 100644 index 0000000..121e4e1 --- /dev/null +++ b/libobj/object.gen @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +import subprocess +import re +import os + +class Function: + iface_name: str + ret: str + name: str + args: list[str] + +class Implementation: + iface_name: str + typ: str + name: str + +class Interface: + name: str + + nested: list[str] + funcs: dict[str, Function] + impls: list[Implementor] + + def __init__(self, name: str) -> None: + self.name = name + self.nested = [] + self.funcs = {} + self.impls = [] + +def gather(c_filenames: list[str]) -> dict[str, Interface]: + ifaces: dict[str, Interface] = {} + impls: list[Implementor] = [] + + re_extract = re.compile(r'__XX_LO_(?P<macro>INTERFACE|FUNC|IMPLEMENT)_XX__\((?P<args>[^)]*)\)') + cp = subprocess.run(["cpp", "-D_LO_EXTRACT", "--", *c_filenames], + check=True, capture_output=True, encoding="utf-8") + for m in re_extract.finditer(cp.stdout): + macro_args = [a.strip() for a in m.group("args").split(",")] + match m.group("macro"): + case "INTERFACE": + assert len(macro_args) == 1 + iface_name = macro_args[0] + if iface_name in ifaces: + continue + ifaces[iface_name] = Interface(iface_name) + case "FUNC": + assert len(macro_args) >= 3 + func = Function() + func.iface_name = macro_args[0] + func.ret = macro_args[1] + func.name = macro_args[2] + func.args = macro_args[3:] + ifaces[func.iface_name].funcs[func.name] = func + case "IMPLEMENT": + assert len(macro_args) == 3 + impl = Implementation() + impl.iface_name = macro_args[0] + impl.typ = macro_args[1] + impl.name = macro_args[2] + ifaces[impl.iface_name].impls.append(impl) + +def c_macro(full: str) -> str: + full = full.rstrip() + assert "\n" in full + lines = [l.rstrip() for l in full.split("\n")] + width = max(len(l.expandtabs(tabsize=8)) for l in lines[:-1]) + lines = [tab_ljust(l, width) for l in lines] + return " \\\n".join(lines).rstrip() + "\n" + +def main(c_filenames: list[str]) -> None: + ifaces = gather(c_filenames) + ret = "" + ret += "static_assert(_LO_PHASE == 1);\n" + ret += "#undef _LO_PHASE\n" + ret += "#define _LO_PHASE 2\n" + + def define_func_wrappers(root: Interface, iface: Interface) -> None: + nonlocal ifaces + nonlocal ret + for child_name in iface.nested: + define_func_wrappers(root, ifaces[child_name]) + for func in iface.funcs: + macro = f"#define {root.name}_{func.name}(SELF, ...) _Generic((SELF),\n" + for impl in root.impls: + macro += f"\t{impl.typ} *: {impl.name}_{func.name}((SELF) __VA_OPT__(,) __VA_ARGS),\n" + macro += f"\tlo_interface {root.name}: (SELF).vtable->{func.name}((SELF).self, __VA_OPT__(,) __VA_ARGS__))\n" + ret += c_macro(macro) + + for iface in ifaces.values(): + macro = f"#define LO_BOX_{iface.name}(VAL) _Generic((VAL)\n" + for impl in iface.impls: + pass # TODO + for wrapper in iface.values(): + if iface.name not in wrapper.nested: + continue + pass # TODO + macro += ")" + ret += c_macro(macro) + + define_func_wrappers(iface, iface) + +if __name__ == '__main__': + main(os.args[:1]) |