diff options
Diffstat (limited to 'lib9p/types.gen')
-rwxr-xr-x | lib9p/types.gen | 101 |
1 files changed, 71 insertions, 30 deletions
diff --git a/lib9p/types.gen b/lib9p/types.gen index 141b591..5eee551 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -73,8 +73,7 @@ re_memberspec = ( def parse_members( - ver: str, - env: dict[str, Atom | Struct], existing: list[Member], specs: str + ver: str, env: dict[str, Atom | Struct], existing: list[Member], specs: str ) -> list[Member]: ret = existing for spec in specs.split(): @@ -105,14 +104,16 @@ def parse_members( re_version = r'version\s+"(?P<version>[^"]+)"' -re_import = r'from\s+(?P<file>\S+)\s+import\s+(?P<syms>\S+(?:\s*,\s*\S+)*)\s*' +re_import = r"from\s+(?P<file>\S+)\s+import\s+(?P<syms>\S+(?:\s*,\s*\S+)*)\s*" re_structspec = ( r'(?:(?P<msgid>[0-9]+)/)?(?P<name>\S+)\s*(?P<op>\+?=)\s*"(?P<members>[^"]*)"' ) re_structspec_cont = r'"(?P<members>[^"]*)"' -def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struct]]]) -> tuple[str, list[Struct]]: +def parse_file( + filename: str, get_include: Callable[[str], tuple[str, list[Struct]]] +) -> tuple[str, list[Struct]]: version: str | None = None env: dict[str, Atom | Struct] = { "1": Atom.u8, @@ -137,7 +138,7 @@ def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struc for symname in m.group("syms").split(sep=","): symname = symname.strip() for struct in other_structs: - if struct.name == symname or symname == '*': + if struct.name == symname or symname == "*": if struct.msgid: struct.msgver.add(version) for member in struct.members: @@ -156,7 +157,9 @@ def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struc struct.msgid = int(m.group("msgid")) struct.msgver.add(version) struct.name = m.group("name") - struct.members = parse_members(version, env, [], m.group("members")) + struct.members = parse_members( + version, env, [], m.group("members") + ) env[struct.name] = struct prev = struct case "+=": @@ -168,15 +171,17 @@ def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struc f"Type {repr(m.group('name'))} is not a struct" ) struct = _struct - struct.members = parse_members(version, - env, struct.members, m.group("members") + struct.members = parse_members( + version, env, struct.members, m.group("members") ) prev = struct elif m := re.fullmatch(re_structspec_cont, line): if not prev: raise SyntaxError("continuation line must come after a struct line") - assert(version) - prev.members = parse_members(version, env, prev.members, m.group("members")) + assert version + prev.members = parse_members( + version, env, prev.members, m.group("members") + ) else: raise SyntaxError(f"invalid line {repr(line)}") if not version: @@ -184,6 +189,7 @@ def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struc structs = [x for x in env.values() if isinstance(x, Struct)] return version, structs + # Generate C ################################################################### @@ -198,14 +204,17 @@ def c_typename(idprefix: str, typ: Atom | Struct) -> str: case _: raise ValueError(f"not a type: {typ.__class__.__name__}") -def c_vercomment(versions: set[str]) -> str|None: + +def c_vercomment(versions: set[str]) -> str | None: if "9P2000" in versions: return None - return "/* "+(", ".join(sorted(versions)))+" */" + return "/* " + (", ".join(sorted(versions))) + " */" + def c_ver(idprefix: str, ver: str) -> str: return f"{idprefix.upper()}VER_{ver.replace('.', '_')}" + def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str: guard = "_LIB9P__TYPES_H_" ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ @@ -225,7 +234,7 @@ enum {idprefix}version {{ verwidth = max(len(v) for v in versions) for ver in sorted(versions): ret += f"\t{c_ver(idprefix, ver)}," - ret += (" "*(verwidth-len(ver))) + ' /* "' + ver + '" */\n' + ret += (" " * (verwidth - len(ver))) + ' /* "' + ver + '" */\n' ret += f"\t{idprefix.upper()}VER_NUM,\n" ret += "};\n" @@ -236,7 +245,9 @@ enum {idprefix}version {{ if struct.msgid is not None: continue - all_the_same = len(struct.members) == 0 or all(m.ver == struct.members[0].ver for m in struct.members) + all_the_same = len(struct.members) == 0 or all( + m.ver == struct.members[0].ver for m in struct.members + ) typewidth = max(len(c_typename(idprefix, m.typ)) for m in struct.members) if not all_the_same: namewidth = max(len(m.name) for m in struct.members) @@ -246,7 +257,7 @@ enum {idprefix}version {{ for member in struct.members: ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" if (not all_the_same) and (comment := c_vercomment(member.ver)): - ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += (" " * (namewidth - len(member.name))) + " " + comment ret += "\n" ret += "};\n" @@ -260,7 +271,7 @@ enum {idprefix}version {{ if msg.msgid is None: continue ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid}," - if (comment := c_vercomment(msg.msgver)): + if comment := c_vercomment(msg.msgver): ret += " " + comment ret += "\n" ret += "};\n" @@ -270,7 +281,9 @@ enum {idprefix}version {{ for msg in structs: if msg.msgid is None: continue - ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" + ret += ( + f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" + ) ret += ")\n" for msg in structs: @@ -286,7 +299,9 @@ enum {idprefix}version {{ continue ret += "\n" - all_the_same = len(msg.members) == 0 or all(m.ver == msg.members[0].ver for m in msg.members) + all_the_same = len(msg.members) == 0 or all( + m.ver == msg.members[0].ver for m in msg.members + ) typewidth = max(len(c_typename(idprefix, m.typ)) for m in msg.members) if not all_the_same: namewidth = max(len(m.name) for m in msg.members) @@ -294,11 +309,10 @@ enum {idprefix}version {{ for member in msg.members: ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" if (not all_the_same) and (comment := c_vercomment(member.ver)): - ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += (" " * (namewidth - len(member.name))) + " " + comment ret += "\n" ret += "};\n" - ret += "\n" ret += f"#endif /* {guard} */\n" return ret @@ -358,7 +372,7 @@ static inline bool _checksize_list(struct _checksize_ctx *ctx, #define checksize_8(ctx) _checksize_net(ctx, 8) """ for struct in structs: - inline = ' inline' if struct.msgid is None else '' + inline = " inline" if struct.msgid is None else "" argfn = used if struct.members else unused ret += "\n" ret += f"static{inline} bool checksize_{struct.name}(struct _checksize_ctx *{argfn('ctx')}) {{" @@ -403,7 +417,16 @@ static inline bool _checksize_list(struct _checksize_ctx *ctx, for member in struct.members: ret += f"\n{prefix}" if member.ver != struct_versions: - ret += "( ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) && " + ret += ( + "( ( " + + ( + " || ".join( + f"(ctx->ctx->version=={c_ver(idprefix, v)})" + for v in sorted(member.ver) + ) + ) + + " ) && " + ) if member.cnt is not None: assert prev_size ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" @@ -440,7 +463,7 @@ static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { } """ for struct in structs: - inline = ' inline' if struct.msgid is None else '' + inline = " inline" if struct.msgid is None else "" argfn = used if struct.members else unused ret += "\n" ret += f"static{inline} void unmarshal_{struct.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n" @@ -452,7 +475,16 @@ static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { ret += "\t" prefix = "\t" if member.ver != struct_versions: - ret += "if ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) " + ret += ( + "if ( " + + ( + " || ".join( + f"(ctx->ctx->version=={c_ver(idprefix, v)})" + for v in sorted(member.ver) + ) + ) + + " ) " + ) prefix = "\t\t" if member.cnt: if member.ver != struct_versions: @@ -512,7 +544,7 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { } """ for struct in structs: - inline = ' inline' if struct.msgid is None else '' + inline = " inline" if struct.msgid is None else "" argfn = used if struct.members else unused ret += "\n" ret += f"static{inline} bool marshal_{struct.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('val')}) {{" @@ -549,6 +581,7 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { ret += f"\t\t\tr.marshal = (_marshal_fn_t)marshal_{msg.name},\n" ret += "\t\t}" return ret + ret += f""" /* vtables ********************************************************************/ @@ -573,18 +606,24 @@ struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{ ################################################################################ + class Parser: cache: dict[str, tuple[str, list[Struct]]] = {} def parse_file(self, filename: str) -> tuple[str, list[Struct]]: + filename = os.path.normpath(filename) if filename not in self.cache: - self.cache[filename] = parse_file(filename, self.parse_file) + + def get_include(other_filename: str) -> tuple[str, list[Struct]]: + return self.parse_file(os.path.join(filename, "..", other_filename)) + + self.cache[filename] = parse_file(filename, get_include) return self.cache[filename] - + def all(self) -> tuple[set[str], list[Struct]]: ret_versions: set[str] = set() ret_structs: dict[str, Struct] = {} - for (version, structs) in self.cache.values(): + for version, structs in self.cache.values(): if version in ret_versions: raise ValueError(f"duplicate protocol version {repr(version)}") ret_versions.add(version) @@ -596,6 +635,7 @@ class Parser: ret_structs[struct.name] = struct return ret_versions, list(ret_structs.values()) + if __name__ == "__main__": import sys @@ -605,7 +645,8 @@ if __name__ == "__main__": for txtname in sys.argv[1:]: parser.parse_file(txtname) versions, structs = parser.all() - with open("include/lib9p/_types.h", "w") as fh: + outdir = os.path.normpath(os.path.join(sys.argv[0], "..")) + with open(os.path.join(outdir, "include/lib9p/_types.h"), "w") as fh: fh.write(gen_h("lib9p_", versions, structs)) - with open("types.c", "w") as fh: + with open(os.path.join(outdir, "types.c"), "w") as fh: fh.write(gen_c("lib9p_", versions, structs)) |