From 21df02e499290e4041f7b1b75443bbef3980b6a4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 8 Feb 2023 13:17:47 +1000 Subject: [PATCH] protocol: add the "bitmask" enum type and check for it Plus check for duplicate values in enums --- proto/protocol.xml | 4 ++-- proto/scanner.py | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/proto/protocol.xml b/proto/protocol.xml index f37af85..bcedebd 100644 --- a/proto/protocol.xml +++ b/proto/protocol.xml @@ -311,7 +311,7 @@ - + A set of capabilities possible available on this seat. A client may bind to these capabilies and an EIS implementation may then create device based on the bound @@ -417,7 +417,7 @@ - + diff --git a/proto/scanner.py b/proto/scanner.py index 7a61a2f..8211dd8 100755 --- a/proto/scanner.py +++ b/proto/scanner.py @@ -183,14 +183,27 @@ class Enum: name: str = attr.ib() since: int = attr.ib() interface: "Interface" = attr.ib() + is_bitmask: bool = attr.ib(default=False) entries: list[Entry] = attr.ib(init=False, factory=list) @classmethod - def create(cls, name: str, interface: "Interface", since: int = 1) -> "Enum": - return cls(name=name, since=since, interface=interface) + def create( + cls, name: str, interface: "Interface", since: int = 1, is_bitmask: bool = False + ) -> "Enum": + return cls(name=name, since=since, interface=interface, is_bitmask=is_bitmask) def add_entry(self, entry: Entry) -> None: + for e in self.entries: + if e.value == entry.value: + raise ValueError(f"Duplicate enum value {entry.value}") + + if self.is_bitmask: + if e.value < 0: + raise ValueError("Bitmasks must not be less than zero") + if e.value.bit_count() > 1: + raise ValueError("Bitmasks must have exactly one bit set") + self.entries.append(entry) @property @@ -376,7 +389,20 @@ class Protocol(xml.sax.handler.ContentHandler): *self.location, f"Missing attribute {e} in element '{element}'" ) - enum = Enum.create(name=name, since=since, interface=self.current_interface) + enum_type = attrs.get("type", None) + if enum_type is not None and enum_type not in ["bitmask"]: + raise XmlError( + *self.location, + f"Invalid enum type {enum_type} in element '{element}'", + ) + is_bitmask = enum_type == "bitmask" + + enum = Enum.create( + name=name, + since=since, + interface=self.current_interface, + is_bitmask=is_bitmask, + ) self.current_interface.add_enum(enum) self.current_message = enum elif element == "arg": @@ -414,10 +440,13 @@ class Protocol(xml.sax.handler.ContentHandler): *self.location, f"Invalid element '{element}' must be inside " ) name = attrs["name"] - value = attrs["value"] + value = int(attrs["value"]) summary = attrs.get("summary", "") entry = Entry.create(name=name, value=value, summary=summary) - self.current_message.add_entry(entry) + try: + self.current_message.add_entry(entry) + except ValueError as e: + raise XmlError(*self.location, str(e)) def endElement(self, name): if name == "interface":