Skip to content

Commit

Permalink
Use enum.Flag for qualities in IDL parsing - clearer than using a set (
Browse files Browse the repository at this point in the history
…#23020)

* Use enum.Flag for qualities in IDL parsing - clearer than using a set

* Update the syntax of union a bit: accept None and use or syntax to specify default value
  • Loading branch information
andy31415 authored and pull[bot] committed Sep 29, 2023
1 parent bfa9460 commit 2814432
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 87 deletions.
4 changes: 2 additions & 2 deletions scripts/idl/generators/java/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def FieldToGlobalName(field: Field, context: TypeLookupContext) -> Union[str, No
if field.is_list:
return None # lists are always specific per cluster

if FieldQuality.NULLABLE in field.qualities:
if FieldQuality.NULLABLE & field.qualities:
return None

if FieldQuality.OPTIONAL in field.qualities:
if FieldQuality.OPTIONAL & field.qualities:
return None

actual = ParseDataType(field.data_type, context)
Expand Down
26 changes: 15 additions & 11 deletions scripts/idl/matter_idl_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import enum
import functools
import logging

from lark import Lark
Expand All @@ -16,6 +17,12 @@
from matter_idl_types import *


def UnionOfAllFlags(flags_list):
if not flags_list:
return None
return functools.reduce(lambda a, b: a | b, flags_list)


class AddServerClusterToEndpointTransform:
"""Provides an 'apply' method that can be run on endpoints
to add a server cluster to the given endpoint.
Expand Down Expand Up @@ -164,13 +171,13 @@ def attr_nosubscribe(self, _):
return AttributeQuality.NOSUBSCRIBE

def attribute_qualities(self, qualities):
return qualities
return UnionOfAllFlags(qualities) or AttributeQuality.NONE

def struct_fabric_scoped(self, _):
return StructQuality.FABRIC_SCOPED

def struct_qualities(self, qualities):
return qualities
return UnionOfAllFlags(qualities) or StructQuality.NONE

def critical_priority(self, _):
return EventPriority.CRITICAL
Expand All @@ -185,7 +192,7 @@ def event_fabric_sensitive(self, _):
return EventQuality.FABRIC_SENSITIVE

def event_qualities(selt, qualities):
return set(qualities)
return UnionOfAllFlags(qualities) or EventQuality.NONE

def timed_command(self, _):
return CommandQuality.TIMED_INVOKE
Expand All @@ -194,14 +201,13 @@ def fabric_scoped_command(self, _):
return CommandQuality.FABRIC_SCOPED

def command_qualities(self, attrs):
# List because attrs is a tuple
return set(list(attrs))
return UnionOfAllFlags(attrs) or CommandQuality.NONE

def struct_field(self, args):
# Last argument is the named_member, the rest
# are qualities
field = args[-1]
field.qualities = set(args[:-1])
field.qualities = UnionOfAllFlags(args[:-1]) or FieldQuality.NONE
return field

def server_cluster(self, _):
Expand Down Expand Up @@ -317,22 +323,20 @@ def ESCAPED_STRING(self, s):

@v_args(inline=True)
def attribute(self, qualities, definition_tuple):

qualities = set(qualities)
(definition, acl) = definition_tuple

# until we support write only (and need a bit of a reshuffle)
# if the 'attr_readonly == READABLE' is not in the list, we make things
# read/write
if AttributeQuality.READABLE not in qualities:
qualities.add(AttributeQuality.READABLE)
qualities.add(AttributeQuality.WRITABLE)
qualities |= AttributeQuality.READABLE
qualities |= AttributeQuality.WRITABLE

return Attribute(definition=definition, qualities=qualities, **acl)

@v_args(inline=True)
def struct(self, qualities, id, *fields):
return Struct(name=id, qualities=set(qualities), fields=list(fields))
return Struct(name=id, qualities=qualities, fields=list(fields))

@v_args(inline=True)
def request_struct(self, value):
Expand Down
39 changes: 22 additions & 17 deletions scripts/idl/matter_idl_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,26 @@ def __init__(self, meta: Meta = None, line: int = None, column: int = None):
self.column = column


class StructQuality(enum.Enum):
class StructQuality(enum.Flag):
NONE = 0
FABRIC_SCOPED = enum.auto()


class FieldQuality(enum.Enum):
class FieldQuality(enum.Flag):
NONE = 0
OPTIONAL = enum.auto()
NULLABLE = enum.auto()
FABRIC_SENSITIVE = enum.auto()


class CommandQuality(enum.Enum):
class CommandQuality(enum.Flag):
NONE = 0
TIMED_INVOKE = enum.auto()
FABRIC_SCOPED = enum.auto()


class AttributeQuality(enum.Enum):
class AttributeQuality(enum.Flag):
NONE = 0
READABLE = enum.auto()
WRITABLE = enum.auto()
NOSUBSCRIBE = enum.auto()
Expand All @@ -54,7 +58,8 @@ class EventPriority(enum.Enum):
CRITICAL = enum.auto()


class EventQuality(enum.Enum):
class EventQuality(enum.Flag):
NONE = 0
FABRIC_SENSITIVE = enum.auto()


Expand Down Expand Up @@ -99,36 +104,36 @@ class Field:
code: int
name: str
is_list: bool = False
qualities: Set[FieldQuality] = field(default_factory=set)
qualities: FieldQuality = FieldQuality.NONE

@property
def is_optional(self):
return FieldQuality.OPTIONAL in self.qualities
return FieldQuality.OPTIONAL & self.qualities

@property
def is_nullable(self):
return FieldQuality.NULLABLE in self.qualities
return FieldQuality.NULLABLE & self.qualities


@dataclass
class Attribute:
definition: Field
qualities: Set[AttributeQuality] = field(default_factory=set)
qualities: AttributeQuality = AttributeQuality.NONE
readacl: AccessPrivilege = AccessPrivilege.VIEW
writeacl: AccessPrivilege = AccessPrivilege.OPERATE
default: Optional[Union[str, int]] = None

@property
def is_readable(self):
return AttributeQuality.READABLE in self.qualities
return AttributeQuality.READABLE & self.qualities

@property
def is_writable(self):
return AttributeQuality.WRITABLE in self.qualities
return AttributeQuality.WRITABLE & self.qualities

@property
def is_subscribable(self):
return AttributeQuality.NOSUBSCRIBE not in self.qualities
return not (AttributeQuality.NOSUBSCRIBE & self.qualities)


@dataclass
Expand All @@ -137,7 +142,7 @@ class Struct:
fields: List[Field]
tag: Optional[StructTag] = None
code: Optional[int] = None # for responses only
qualities: Set[StructQuality] = field(default_factory=set)
qualities: StructQuality = StructQuality.NONE


@dataclass
Expand All @@ -147,11 +152,11 @@ class Event:
code: int
fields: List[Field]
readacl: AccessPrivilege = AccessPrivilege.VIEW
qualities: Set[EventQuality] = field(default_factory=set)
qualities: EventQuality = EventQuality.NONE

@property
def is_fabric_sensitive(self):
return EventQuality.FABRIC_SENSITIVE in self.qualities
return EventQuality.FABRIC_SENSITIVE & self.qualities


@dataclass
Expand Down Expand Up @@ -180,12 +185,12 @@ class Command:
code: int
input_param: Optional[str]
output_param: str
qualities: Set[CommandQuality] = field(default_factory=set)
qualities: CommandQuality = CommandQuality.NONE
invokeacl: AccessPrivilege = AccessPrivilege.OPERATE

@property
def is_timed_invoke(self):
return CommandQuality.TIMED_INVOKE in self.qualities
return CommandQuality.TIMED_INVOKE & self.qualities


@dataclass
Expand Down
57 changes: 28 additions & 29 deletions scripts/idl/test_matter_idl_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,11 @@ def test_global_struct(self):
fields=[
Field(
data_type=DataType(name="CHAR_STRING"), code=1, name="astring", ),
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist", is_list=True, qualities=set(
[FieldQuality.OPTIONAL])),
Field(data_type=DataType(name="int"), code=0x123, name="valueThatIsNullable", qualities=set(
[FieldQuality.NULLABLE])),
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist",
is_list=True, qualities=FieldQuality.OPTIONAL),
Field(data_type=DataType(name="int"), code=0x123, name="valueThatIsNullable", qualities=FieldQuality.NULLABLE),
Field(data_type=DataType(name="char_string", max_length=123),
code=222, name="sized_string", qualities=set()),
code=222, name="sized_string"),
])]
)
self.assertEqual(actual, expected)
Expand All @@ -100,14 +99,14 @@ def test_fabric_scoped_struct(self):

expected = Idl(structs=[
Struct(name='FabricStruct',
qualities={StructQuality.FABRIC_SCOPED},
qualities=StructQuality.FABRIC_SCOPED,
fields=[
Field(
data_type=DataType(name="CHAR_STRING"), code=1, name="astring", ),
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist", is_list=True, qualities=set(
[FieldQuality.OPTIONAL])),
Field(data_type=DataType(name="int"), code=0x123, name="nullablesensitive", qualities=set(
[FieldQuality.NULLABLE, FieldQuality.FABRIC_SENSITIVE])),
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist",
is_list=True, qualities=FieldQuality.OPTIONAL),
Field(data_type=DataType(name="int"), code=0x123, name="nullablesensitive",
qualities=FieldQuality.NULLABLE | FieldQuality.FABRIC_SENSITIVE),
])]
)
self.assertEqual(actual, expected)
Expand All @@ -127,14 +126,14 @@ def test_cluster_attribute(self):
name="MyCluster",
code=0x321,
attributes=[
Attribute(qualities=set([AttributeQuality.READABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE, definition=Field(
data_type=DataType(name="int8u"), code=1, name="roAttr")),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int32u"), code=123, name="rwAttr", is_list=True)),
Attribute(qualities=set([AttributeQuality.NOSUBSCRIBE, AttributeQuality.READABLE]), definition=Field(
Attribute(qualities=AttributeQuality.NOSUBSCRIBE | AttributeQuality.READABLE, definition=Field(
data_type=DataType(name="int8s"), code=0xAA, name="nosub", is_list=True)),
Attribute(qualities=set([AttributeQuality.READABLE]), definition=Field(
data_type=DataType(name="int8s"), code=0xAB, name="isNullable", qualities=set([FieldQuality.NULLABLE]))),
Attribute(qualities=AttributeQuality.READABLE, definition=Field(
data_type=DataType(name="int8s"), code=0xAB, name="isNullable", qualities=FieldQuality.NULLABLE)),
]
)])
self.assertEqual(actual, expected)
Expand All @@ -152,9 +151,9 @@ def test_sized_attribute(self):
name="MyCluster",
code=1,
attributes=[
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="char_string", max_length=11), code=1, name="attr1")),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="octet_string", max_length=33), code=2, name="attr2", is_list=True)),
]
)])
Expand All @@ -176,25 +175,25 @@ def test_attribute_access(self):
name="MyCluster",
code=1,
attributes=[
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int8s"), code=1, name="attr1"),
readacl=AccessPrivilege.VIEW,
writeacl=AccessPrivilege.OPERATE
),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int8s"), code=2, name="attr2"),
readacl=AccessPrivilege.VIEW,
writeacl=AccessPrivilege.OPERATE
),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int8s"), code=3, name="attr3"),
readacl=AccessPrivilege.MANAGE
),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int8s"), code=4, name="attr4"),
writeacl=AccessPrivilege.ADMINISTER
),
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
data_type=DataType(name="int8s"), code=5, name="attr5"),
readacl=AccessPrivilege.OPERATE,
writeacl=AccessPrivilege.MANAGE
Expand Down Expand Up @@ -234,13 +233,13 @@ def test_cluster_commands(self):
input_param="InParam", output_param="OutParam"),
Command(name="TimedCommand", code=0xab,
input_param="InParam", output_param="DefaultSuccess",
qualities=set([CommandQuality.TIMED_INVOKE])),
qualities=CommandQuality.TIMED_INVOKE),
Command(name="FabricScopedCommand", code=0xac,
input_param="InParam", output_param="DefaultSuccess",
qualities=set([CommandQuality.FABRIC_SCOPED])),
qualities=CommandQuality.FABRIC_SCOPED),
Command(name="FabricScopedTimedCommand", code=0xad,
input_param="InParam", output_param="DefaultSuccess",
qualities=set([CommandQuality.TIMED_INVOKE, CommandQuality.FABRIC_SCOPED])),
qualities=CommandQuality.TIMED_INVOKE | CommandQuality.FABRIC_SCOPED),
],
)])
self.assertEqual(actual, expected)
Expand Down Expand Up @@ -272,7 +271,7 @@ def test_cluster_command_access(self):
Command(name="TimedCommand", code=2,
input_param="InParam", output_param="OutParam",
invokeacl=AccessPrivilege.MANAGE,
qualities=set([CommandQuality.TIMED_INVOKE])),
qualities=CommandQuality.TIMED_INVOKE),
Command(name="OutOnly", code=3,
input_param=None, output_param="OutParam",
invokeacl=AccessPrivilege.ADMINISTER,
Expand Down Expand Up @@ -387,11 +386,11 @@ def test_fabric_sensitive_event(self):
code=0x123,
events=[
Event(priority=EventPriority.INFO, readacl=AccessPrivilege.VIEW,
name="Hello", code=1, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
name="Hello", code=1, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
Event(priority=EventPriority.DEBUG, readacl=AccessPrivilege.MANAGE,
name="GoodBye", code=2, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
name="GoodBye", code=2, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
Event(priority=EventPriority.DEBUG, readacl=AccessPrivilege.ADMINISTER,
name="AdminEvent", code=3, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
name="AdminEvent", code=3, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
])])
self.assertEqual(actual, expected)

Expand Down
Loading

0 comments on commit 2814432

Please sign in to comment.