summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libobj/object.gen104
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])