diff options
Diffstat (limited to 'lib9p/types.gen')
-rwxr-xr-x | lib9p/types.gen | 245 |
1 files changed, 146 insertions, 99 deletions
diff --git a/lib9p/types.gen b/lib9p/types.gen index a594e45..b41442a 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -35,10 +35,18 @@ class Atom(enum.Enum): class Bitfield: name: str bits: list[str] - aliases: dict[str, str] + names: dict[str, str] @property - def static_size(self) -> int | None: + def static_size(self) -> int: + if len(self.bits) <= 8: + return 1 + if len(self.bits) <= 16: + return 2 + if len(self.bits) <= 32: + return 4 + if len(self.bits) <= 64: + return 8 return int((len(self.bits) + 7) / 8) @@ -209,7 +217,7 @@ def parse_file( bf = Bitfield() bf.name = m.group("name") bf.bits = int(m.group("size")) * [""] - bf.aliases = {} + bf.names = {} env[bf.name] = bf prev = bf elif m := re.fullmatch(re_bitfieldspec_bit, line): @@ -232,10 +240,10 @@ def parse_file( raise ValueError(f"{bf.name}: bit {bit} is out-of-bounds") if bf.bits[bit]: raise ValueError(f"{bf.name}: bit {bit} already assigned") - if name in bf.aliases: + if name in bf.names: raise ValueError(f"{bf.name}: name {name} already assigned") bf.bits[bit] = name - bf.aliases[name] = "" + bf.names[name] = "" elif m := re.fullmatch(re_bitfieldspec_alias, line): if m.group("bitfield"): if m.group("bitfield") not in env: @@ -252,9 +260,9 @@ def parse_file( bf = prev name = m.group("name") val = m.group("val") - if name in bf.aliases: + if name in bf.names: raise ValueError(f"{bf.name}: name {name} already assigned") - bf.aliases[name] = val + bf.names[name] = val else: raise SyntaxError(f"invalid line {repr(line)}") if not version: @@ -348,10 +356,17 @@ enum {idprefix}version {{ for bf in just_bitfields(typs): ret += "\n" ret += f"typedef uint{bf.static_size*8}_t {c_typename(idprefix, bf)};\n" - vals = dict([ - *reversed([((k or f"_UNUSED_{v}"), f"1<<{v}") for (v, k) in enumerate(bf.bits)]), - *[(k, v) for (k, v) in bf.aliases.items() if v], - ]) + vals = dict( + [ + *reversed( + [ + ((k or f"_UNUSED_{v}"), f"1<<{v}") + for (v, k) in enumerate(bf.bits) + ] + ), + *[(k, v) for (k, v) in bf.names.items() if k not in bf.bits], + ] + ) namewidth = max(len(name) for name in vals) for name, val in vals.items(): ret += f"#define {idprefix.upper()}{bf.name.upper()}_{name.ljust(namewidth)} (({c_typename(idprefix, bf)})({val}))\n" @@ -505,17 +520,17 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, #define validate_4(ctx) _validate_size_net(ctx, 4) #define validate_8(ctx) _validate_size_net(ctx, 8) """ - for struct in just_structs_all(typs): - inline = " ALWAYS_INLINE" if struct.msgid is None else " FLATTEN" - argfn = used if struct.members else unused + for typ in typs: + inline = ( + " FLATTEN" + if (isinstance(typ, Struct) and typ.msgid is not None) + else " ALWAYS_INLINE" + ) + argfn = unused if (isinstance(typ, Struct) and not typ.members) else used ret += "\n" - ret += f"static{inline} bool validate_{struct.name}(struct _validate_ctx *{argfn('ctx')}) {{" - if len(struct.members) == 0: - ret += "\n\treturn false;\n" - ret += "}\n" - continue + ret += f"static{inline} bool validate_{typ.name}(struct _validate_ctx *{argfn('ctx')}) {{" - if struct.name == "d": # SPECIAL + if typ.name == "d": # SPECIAL # Optimize... maybe the compiler could figure out to do # this, but let's make it obvious. ret += "\n" @@ -526,7 +541,7 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, ret += "\treturn _validate_size_net(ctx, len) || _validate_size_host(ctx, len);\n" ret += "}\n" continue - if struct.name == "s": # SPECIAL + if typ.name == "s": # SPECIAL # Add an extra nul-byte on the host, and validate UTF-8 # (also, similar optimization to "d"). ret += "\n" @@ -542,27 +557,39 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, ret += "}\n" continue - prefix0 = "\treturn " - prefix1 = "\t || " - - struct_versions = struct.members[0].ver - - prefix = prefix0 - prev_size: int | None = None - for member in struct.members: - ret += f"\n{prefix}" - if member.ver != struct_versions: - ret += "( " + c_vercond(idprefix, member.ver) + " && " - if member.cnt is not None: - assert prev_size - ret += f"_validate_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), validate_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" - else: - ret += f"validate_{member.typ.name}(ctx)" - if member.ver != struct_versions: - ret += " )" - prefix = prefix1 - prev_size = member.static_size - ret += ";\n}\n" + match typ: + case Bitfield(): + ret += "\n" + # ret += "\t{c_typename(idprefix, typ)} mask = 0b" + (''.join('1' if b else '0' for b in reversed(typ.bits))) + ";\n" + ret += f"\treturn validate_{typ.static_size}(ctx);\n" + case Struct(): + if len(typ.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + + struct_versions = typ.members[0].ver + + prefix = prefix0 + prev_size: int | None = None + for member in typ.members: + ret += f"\n{prefix}" + if member.ver != struct_versions: + ret += "( " + c_vercond(idprefix, member.ver) + " && " + if member.cnt is not None: + assert prev_size + ret += f"_validate_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), validate_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" + else: + ret += f"validate_{member.typ.name}(ctx)" + if member.ver != struct_versions: + ret += " )" + prefix = prefix1 + prev_size = member.static_size + ret += ";\n" + ret += "}\n" # unmarshal_* ############################################################## ret += """ @@ -588,32 +615,42 @@ static ALWAYS_INLINE void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) ctx->net_offset += 8; } """ - for struct in just_structs_all(typs): - inline = " ALWAYS_INLINE" if struct.msgid is None else " FLATTEN" - argfn = used if struct.members else unused + for typ in typs: + inline = ( + " FLATTEN" + if (isinstance(typ, Struct) and typ.msgid is not None) + else " ALWAYS_INLINE" + ) + argfn = unused if (isinstance(typ, Struct) and not typ.members) else used ret += "\n" - ret += f"static{inline} void unmarshal_{struct.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *out) {{\n" - ret += "\tmemset(out, 0, sizeof(*out));\n" - - if struct.members: - struct_versions = struct.members[0].ver - for member in struct.members: - ret += "\t" - prefix = "\t" - if member.ver != struct_versions: - ret += "if ( " + c_vercond(idprefix, member.ver) + " ) " - prefix = "\t\t" - if member.cnt: - if member.ver != struct_versions: - ret += "{\n" - ret += f"{prefix}out->{member.name} = ctx->extra;\n" - ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n" - ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" - ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" - if member.ver != struct_versions: - ret += "\t}\n" - else: - ret += f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n" + ret += f"static{inline} void unmarshal_{typ.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, typ)} *out) {{\n" + match typ: + case Bitfield(): + ret += f"\tunmarshal_{typ.static_size}(ctx, (uint{typ.static_size*8}_t *)out);\n" + case Struct(): + ret += "\tmemset(out, 0, sizeof(*out));\n" + + if typ.members: + struct_versions = typ.members[0].ver + for member in typ.members: + ret += "\t" + prefix = "\t" + if member.ver != struct_versions: + ret += "if ( " + c_vercond(idprefix, member.ver) + " ) " + prefix = "\t\t" + if member.cnt: + if member.ver != struct_versions: + ret += "{\n" + ret += f"{prefix}out->{member.name} = ctx->extra;\n" + ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n" + ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" + ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" + if member.ver != struct_versions: + ret += "\t}\n" + else: + ret += ( + f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n" + ) ret += "}\n" # marshal_* ################################################################ @@ -660,39 +697,49 @@ static ALWAYS_INLINE bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { return false; } """ - for struct in just_structs_all(typs): - inline = " ALWAYS_INLINE" if struct.msgid is None else " FLATTEN" - argfn = used if struct.members else unused + for typ in typs: + inline = ( + " FLATTEN" + if (isinstance(typ, Struct) and typ.msgid is not None) + else " ALWAYS_INLINE" + ) + argfn = unused if (isinstance(typ, Struct) and not typ.members) else used ret += "\n" - ret += f"static{inline} bool marshal_{struct.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('val')}) {{" - if len(struct.members) == 0: - ret += "\n\treturn false;\n" - ret += "}\n" - continue - - prefix0 = "\treturn " - prefix1 = "\t || " - prefix2 = "\t " - - struct_versions = struct.members[0].ver - prefix = prefix0 - for member in struct.members: - ret += f"\n{prefix}" - if member.ver != struct_versions: - ret += "( " + c_vercond(idprefix, member.ver) + " && " - if member.cnt: - ret += "({" - ret += f"\n{prefix2}\tbool err = false;" - ret += f"\n{prefix2}\tfor (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)" - ret += f"\n{prefix2}\t\terr = marshal_{member.typ.name}(ctx, &val->{member.name}[i]);" - ret += f"\n{prefix2}\terr;" - ret += f"\n{prefix2}}})" - else: - ret += f"marshal_{member.typ.name}(ctx, &val->{member.name})" - if member.ver != struct_versions: - ret += " )" - prefix = prefix1 - ret += ";\n}\n" + ret += f"static{inline} bool marshal_{typ.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, typ)} *{argfn('val')}) {{" + match typ: + case Bitfield(): + ret += "\n" + ret += f"\treturn marshal_{typ.static_size}(ctx, (uint{typ.static_size*8}_t *)val);\n" + case Struct(): + if len(typ.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + prefix2 = "\t " + + struct_versions = typ.members[0].ver + prefix = prefix0 + for member in typ.members: + ret += f"\n{prefix}" + if member.ver != struct_versions: + ret += "( " + c_vercond(idprefix, member.ver) + " && " + if member.cnt: + ret += "({" + ret += f"\n{prefix2}\tbool err = false;" + ret += f"\n{prefix2}\tfor (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)" + ret += f"\n{prefix2}\t\terr = marshal_{member.typ.name}(ctx, &val->{member.name}[i]);" + ret += f"\n{prefix2}\terr;" + ret += f"\n{prefix2}}})" + else: + ret += f"marshal_{member.typ.name}(ctx, &val->{member.name})" + if member.ver != struct_versions: + ret += " )" + prefix = prefix1 + ret += ";\n" + ret += "}\n" # vtables ################################################################## ret += f""" |