summaryrefslogtreecommitdiff
path: root/lib9p/protogen
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/protogen')
-rw-r--r--lib9p/protogen/c.py2
-rw-r--r--lib9p/protogen/c9util.py25
-rw-r--r--lib9p/protogen/c_marshal.py12
-rw-r--r--lib9p/protogen/c_validate.py4
-rw-r--r--lib9p/protogen/h.py138
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