diff options
Diffstat (limited to 'lib9p/protogen')
-rw-r--r-- | lib9p/protogen/c.py | 2 | ||||
-rw-r--r-- | lib9p/protogen/c9util.py | 25 | ||||
-rw-r--r-- | lib9p/protogen/c_marshal.py | 12 | ||||
-rw-r--r-- | lib9p/protogen/c_validate.py | 4 | ||||
-rw-r--r-- | lib9p/protogen/h.py | 138 |
5 files changed, 133 insertions, 48 deletions
diff --git a/lib9p/protogen/c.py b/lib9p/protogen/c.py index 5e67939..cc1daea 100644 --- a/lib9p/protogen/c.py +++ b/lib9p/protogen/c.py @@ -118,7 +118,7 @@ const char *const {c9util.ident('_table_ver_name')}[{c9util.ver_enum('NUM')}] = + "".join( ( "1" - if bit.cat in (idl.BitCat.USED, idl.BitCat.SUBFIELD) + if (bit.cat == "USED" or isinstance(bit.cat, idl.BitNum)) and ver in bit.in_versions else "0" ) diff --git a/lib9p/protogen/c9util.py b/lib9p/protogen/c9util.py index e7ad999..85fd47b 100644 --- a/lib9p/protogen/c9util.py +++ b/lib9p/protogen/c9util.py @@ -3,6 +3,7 @@ # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later +import re import typing import idl @@ -90,20 +91,30 @@ def typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str: raise ValueError(f"not a type: {typ.__class__.__name__}") -def idl_expr(expr: idl.Expr, lookup_sym: typing.Callable[[str], str]) -> str: +def idl_expr( + expr: idl.Expr, lookup_sym: typing.Callable[[str], str], bitwidth: int = 0 +) -> str: ret: list[str] = [] for tok in expr.tokens: match tok: case idl.ExprOp(): ret.append(tok.op) case idl.ExprLit(): - ret.append(str(tok.val)) - case idl.ExprSym(symname="s32_max"): - ret.append("INT32_MAX") - case idl.ExprSym(symname="s64_max"): - ret.append("INT64_MAX") + if bitwidth: + ret.append(f"{tok.val:#0{bitwidth}b}") + else: + ret.append(str(tok.val)) case idl.ExprSym(): - ret.append(lookup_sym(tok.symname)) + if m := re.fullmatch(r"^u(8|16|32|64)_max$", tok.symname): + ret.append(f"UINT{m.group(1)}_MAX") + elif m := re.fullmatch(r"^s(8|16|32|64)_max$", tok.symname): + ret.append(f"INT{m.group(1)}_MAX") + else: + ret.append(lookup_sym(tok.symname)) + case idl.ExprOff(): + ret.append(lookup_sym("&" + tok.membname)) + case idl.ExprNum(): + ret.append(Ident(add_prefix(f"{tok.numname}_".upper(), tok.valname))) case _: assert False return " ".join(ret) diff --git a/lib9p/protogen/c_marshal.py b/lib9p/protogen/c_marshal.py index a358cf2..4dab864 100644 --- a/lib9p/protogen/c_marshal.py +++ b/lib9p/protogen/c_marshal.py @@ -278,11 +278,13 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str: if not member.val: continue for tok in member.val.tokens: - if not isinstance(tok, idl.ExprSym): - continue - if tok.symname == "end" or tok.symname.startswith("&"): - if tok.symname not in offsets: - offsets.append(tok.symname) + match tok: + case idl.ExprSym(symname="end"): + if tok.symname not in offsets: + offsets.append(tok.symname) + case idl.ExprOff(): + if f"&{tok.membname}" not in offsets: + offsets.append(f"&{tok.membname}") for name in offsets: name_prefix = f"offsetof{''.join('_'+m.membname for m in path.elems)}_" if name == "end": diff --git a/lib9p/protogen/c_validate.py b/lib9p/protogen/c_validate.py index 7d0c69e..535a750 100644 --- a/lib9p/protogen/c_validate.py +++ b/lib9p/protogen/c_validate.py @@ -24,11 +24,11 @@ def should_save_offset(parent: idl.Struct, child: idl.StructMember) -> bool: for sibling in parent.members: if sibling.val: for tok in sibling.val.tokens: - if isinstance(tok, idl.ExprSym) and tok.symname == f"&{child.membname}": + if isinstance(tok, idl.ExprOff) and tok.membname == child.membname: return True if sibling.max: for tok in sibling.max.tokens: - if isinstance(tok, idl.ExprSym) and tok.symname == f"&{child.membname}": + if isinstance(tok, idl.ExprOff) and tok.membname == child.membname: return True return False diff --git a/lib9p/protogen/h.py b/lib9p/protogen/h.py index b0d38bf..13c3f89 100644 --- a/lib9p/protogen/h.py +++ b/lib9p/protogen/h.py @@ -362,42 +362,49 @@ enum {c9util.ident('version')} {{ def gen_number(typ: idl.Number) -> str: ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n" + def lookup_sym(sym: str) -> str: + assert False + def cname(base: str) -> str: prefix = f"{typ.typname}_".upper() return c9util.Ident(c9util.add_prefix(prefix, base)) namewidth = max(len(cname(name)) for name in typ.vals) for name, val in typ.vals.items(): - ret += f"#define {cname(name):<{namewidth}} (({c9util.typename(typ)})UINT{typ.static_size*8}_C({val}))\n" + c_name = cname(name) + c_val = c9util.idl_expr(val, lookup_sym) + ret += f"#define {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val}))\n" return ret def gen_bitfield(typ: idl.Bitfield) -> str: ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n" - def bitname(val: idl.Bit | idl.BitAlias) -> str: - s = val.bitname - match val: - case idl.Bit(cat=idl.BitCat.RESERVED): - s = "_RESERVED_" + s - case idl.Bit(cat=idl.BitCat.SUBFIELD): - assert isinstance(typ, idl.Bitfield) - n = sum( - 1 - for b in typ.bits[: val.num] - if b.cat == idl.BitCat.SUBFIELD and b.bitname == val.bitname - ) - s = f"_{s}_{n}" - case idl.Bit(cat=idl.BitCat.UNUSED): - return "" - return c9util.Ident(c9util.add_prefix(typ.typname.upper() + "_", s)) - - namewidth = max(len(bitname(val)) for val in [*typ.bits, *typ.names.values()]) + def lookup_sym(sym: str) -> str: + assert False - ret += "\n" + # There are 4 parts here: bits, aliases, masks, and numbers. + + # 1. bits + + def bitname(bit: idl.Bit) -> str: + prefix = f"{typ.typname}_".upper() + base = bit.bitname + match bit: + case idl.Bit(cat="RESERVED"): + base = "_RESERVED_" + base + case idl.Bit(cat=idl.BitNum()): + base += "_*" + case idl.Bit(cat="UNUSED"): + base = f"_UNUSED_{bit.num}" + return c9util.Ident(c9util.add_prefix(prefix, base)) + + namewidth = max(len(bitname(bit)) for bit in typ.bits) + + ret += "/* bits */\n" for bit in reversed(typ.bits): vers = bit.in_versions - if bit.cat == idl.BitCat.UNUSED: + if bit.cat == "UNUSED": vers = typ.in_versions ret += cutil.ifdef_push(2, c9util.ver_ifdef(vers)) @@ -405,26 +412,32 @@ def gen_bitfield(typ: idl.Bitfield) -> str: # the same length. end = "" match bit.cat: - case idl.BitCat.USED | idl.BitCat.RESERVED | idl.BitCat.SUBFIELD: + case "USED" | "RESERVED" | "UNUSED": if cutil.ifdef_leaf_is_noop(): beg = "#define " else: beg = "# define" - case idl.BitCat.UNUSED: - beg = "/* unused" + case idl.BitNum(): + beg = "/* number" end = " */" c_name = bitname(bit) - c_val = f"1<<{bit.num}" + c_val = f"UINT{typ.static_size*8}_C(1)<<{bit.num}" ret += ( f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" ) - if aliases := [ - alias for alias in typ.names.values() if isinstance(alias, idl.BitAlias) - ]: - ret += "\n" + ret += cutil.ifdef_pop(1) + + # 2. aliases + if typ.aliases: - for alias in aliases: + def aliasname(alias: idl.BitAlias) -> str: + prefix = f"{typ.typname}_".upper() + base = alias.bitname + return c9util.Ident(c9util.add_prefix(prefix, base)) + + ret += "/* aliases */\n" + for alias in typ.aliases.values(): ret += cutil.ifdef_push(2, c9util.ver_ifdef(alias.in_versions)) end = "" @@ -433,10 +446,69 @@ def gen_bitfield(typ: idl.Bitfield) -> str: else: beg = "# define" - c_name = bitname(alias) - c_val = alias.val + c_name = aliasname(alias) + c_val = c9util.idl_expr(alias.val, lookup_sym) ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" - ret += cutil.ifdef_pop(1) + + ret += cutil.ifdef_pop(1) + + # 3. masks + if typ.masks: + + def maskname(mask: idl.BitAlias) -> str: + prefix = f"{typ.typname}_".upper() + base = mask.bitname + return c9util.Ident(c9util.add_prefix(prefix, base) + "_MASK") + + ret += "/* masks */\n" + for mask in typ.masks.values(): + ret += cutil.ifdef_push(2, c9util.ver_ifdef(mask.in_versions)) + + end = "" + if cutil.ifdef_leaf_is_noop(): + beg = "#define " + else: + beg = "# define" + + c_name = maskname(mask) + c_val = c9util.idl_expr(mask.val, lookup_sym, bitwidth=typ.static_size * 8) + ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" + + ret += cutil.ifdef_pop(1) + + # 4. numbers + def numname(num: idl.BitNum, base: str) -> str: + prefix = f"{typ.typname}_{num.numname}_".upper() + return c9util.Ident(c9util.add_prefix(prefix, base)) + + for num in typ.nums.values(): + namewidth = max( + len(numname(num, base)) + for base in [ + *[alias.bitname for alias in num.vals.values()], + "MASK", + ] + ) + ret += f"/* number: {num.numname} */\n" + for alias in num.vals.values(): + ret += cutil.ifdef_push(2, c9util.ver_ifdef(alias.in_versions)) + + end = "" + if cutil.ifdef_leaf_is_noop(): + beg = "#define " + else: + beg = "# define" + + c_name = numname(num, alias.bitname) + c_val = c9util.idl_expr(alias.val, lookup_sym) + ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" + ret += cutil.ifdef_pop(1) + c_name = numname(num, "MASK") + c_val = f"{num.mask:#0{typ.static_size*8}b}" + ret += ( + f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" + ) + return ret |