summaryrefslogtreecommitdiff
path: root/lib9p/types.gen
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/types.gen')
-rwxr-xr-xlib9p/types.gen101
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))