Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a parser for CSA XML data models #29888

Merged
merged 102 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
bd059c1
Move xml to say zapxml since that is the format
andreilitvin Oct 17, 2023
9ff4476
Start defining a data_model_xml parser (no functionality for now)
andreilitvin Oct 17, 2023
01c1045
Start adding some basic support for data model xml parsing
andreilitvin Oct 17, 2023
37ad950
make the DM parser executable
andreilitvin Oct 17, 2023
d8c9823
Start having the ability to parse clusters
andreilitvin Oct 17, 2023
2e4c2fc
More updates, we seem to have parsing for features
andreilitvin Oct 17, 2023
09a65c2
Hard-code global attributes
andreilitvin Oct 17, 2023
0a90b2c
Remove some comments
andreilitvin Oct 17, 2023
320e0bf
Add enumeration handling
andreilitvin Oct 17, 2023
c8308f1
Add bitmap handling
andreilitvin Oct 17, 2023
2be7262
Merge branch 'master' into csa_xml_parsing
andreilitvin Oct 17, 2023
f948f8f
Restyle
andreilitvin Oct 17, 2023
43791d5
Parse structs
andreilitvin Oct 17, 2023
af5d515
Re-organize parsing a bit
andreilitvin Oct 17, 2023
5e66b0d
Make a linter happy
andreilitvin Oct 17, 2023
e62228e
Another linter fix
andreilitvin Oct 17, 2023
cdb26aa
Handling of events
andreilitvin Oct 17, 2023
4df4178
More handling and logic on events
andreilitvin Oct 17, 2023
e462be5
Add support for access privilege parsing
andreilitvin Oct 17, 2023
64f2dc1
Merge branch 'master' into csa_xml_parsing
andy31415 Oct 18, 2023
22f70b6
XMLs have maybe invalid enum entries. Handle them gracefully
andy31415 Oct 18, 2023
db29dd5
More attribute handling updates
andy31415 Oct 18, 2023
9e91ac1
restyle
andy31415 Oct 18, 2023
a1b8a73
Support deprecate constraint
andy31415 Oct 18, 2023
4e05059
Support constraint decoding, apply on attributes for now
andy31415 Oct 18, 2023
2356c09
Restyle
andy31415 Oct 18, 2023
a29e22a
Restyle
andy31415 Oct 18, 2023
6858821
Field handling
andy31415 Oct 18, 2023
b3afea4
Field handling
andy31415 Oct 18, 2023
35bd355
Some bug fixing
andy31415 Oct 18, 2023
b758a70
Start adding command handling
andy31415 Oct 18, 2023
a8425f0
Restyle
andy31415 Oct 18, 2023
936513e
Name normalization and more parsing updates
andy31415 Oct 18, 2023
d0efaec
Name normalization and more parsing updates
andy31415 Oct 18, 2023
c369754
Better messaging and fix constraint types
andy31415 Oct 18, 2023
88428ec
Restyle
andy31415 Oct 18, 2023
aaa2b6c
Start creating a IDL codegen so we can self-test parsed output
andreilitvin Oct 19, 2023
672ecf3
Start with listing clusters
andreilitvin Oct 19, 2023
6cb81c3
Enum listing
andreilitvin Oct 19, 2023
41da54f
A lot more things supported
andreilitvin Oct 19, 2023
3d11d54
Attribute rendering
andreilitvin Oct 19, 2023
3e3e7ce
Support for string and octet string sizes
andreilitvin Oct 19, 2023
07d15e6
Timed command support
andreilitvin Oct 19, 2023
3a2133d
Restyle
andreilitvin Oct 19, 2023
cae7005
Add descriptions to clusters
andreilitvin Oct 19, 2023
c0ec338
Attempt to fix up alignment of things
andreilitvin Oct 19, 2023
41d5552
Alignment looks slightly better
andreilitvin Oct 19, 2023
f45f613
Better command separation
andreilitvin Oct 19, 2023
5576d68
Align comments
andreilitvin Oct 19, 2023
ce0f343
Align and output descriptions including clusters
andreilitvin Oct 19, 2023
84bcad2
More work regarding loop structures
andreilitvin Oct 19, 2023
d25a38a
Apply hex formatting to bitmaps. output now seems identical except on…
andreilitvin Oct 19, 2023
9c94d69
Identical output for now
andreilitvin Oct 19, 2023
7d6f882
Merge branch 'master' into idl_self_generator
andreilitvin Oct 19, 2023
66089f4
Support API maturity. Notice that doccomments are lost on maturity :(
andreilitvin Oct 19, 2023
1708396
Fix doxygen parsing for api maturity at the cluster level
andreilitvin Oct 19, 2023
09c5adb
Restyle
andreilitvin Oct 19, 2023
75e16b3
Support endpoints, although that is not 1:1 as hex encoding and order…
andreilitvin Oct 19, 2023
97532b8
Restyle
andreilitvin Oct 19, 2023
14c5920
Add todo note that default value does not string escaping
andreilitvin Oct 19, 2023
01d3b77
Default rendering and add to files
andreilitvin Oct 19, 2023
0b8e5a8
More updates on file dependencies
andreilitvin Oct 19, 2023
94b6ec1
Unit test IDL generator
andreilitvin Oct 19, 2023
792f1d0
Add the IDL unit test as a standard unit test
andreilitvin Oct 19, 2023
00f1efa
Update for python compatibility
andreilitvin Oct 19, 2023
c42c1da
Merge branch 'master' into idl_self_generator
andreilitvin Oct 19, 2023
7b4ed27
Fix unit testing of builds when GSDK root is defined
andreilitvin Oct 19, 2023
4948111
Added a readme file
andreilitvin Oct 19, 2023
5b33085
Restyle
andreilitvin Oct 19, 2023
0443766
Make xml parser use the idl codegen
andreilitvin Oct 19, 2023
640eeb2
Restyle
andreilitvin Oct 19, 2023
cbdf613
look to fix misspell warnings
andreilitvin Oct 19, 2023
b6de4df
Undo repo update
andreilitvin Oct 19, 2023
9a60d03
Fix linter errors
andreilitvin Oct 19, 2023
e49fb41
Merge branch 'idl_self_generator' into csa_xml_parsing
andreilitvin Oct 19, 2023
ea1cc13
Codegen as idl for data_model_xml_parser.py
andreilitvin Oct 19, 2023
5f581ed
Parsing closer to matter idl content
andreilitvin Oct 19, 2023
4fef788
more normalization and type processing
andreilitvin Oct 19, 2023
bfa9d91
More mandatory conformance logic
andreilitvin Oct 19, 2023
8785dd8
Fix mandatory conditionals
andreilitvin Oct 19, 2023
f2ff90d
Merge branch 'master' into csa_xml_parsing
andy31415 Oct 20, 2023
7af35ca
Make unit test pass
andy31415 Oct 20, 2023
b3908f1
Fix tests a bit more and make parsers better
andy31415 Oct 20, 2023
2b18ea6
Restyle
andy31415 Oct 20, 2023
b378f1f
Ignore min/max values while parsing xmls, even though raw data intern…
andy31415 Oct 20, 2023
4dd654c
Restyle
andy31415 Oct 20, 2023
aad8399
Fix space after click annotations
andy31415 Oct 20, 2023
12f1bd1
Compare support for human reviews
andy31415 Oct 20, 2023
a7b817c
Restyle
andy31415 Oct 20, 2023
71720e4
Merge branch 'master' into csa_xml_parsing
andy31415 Oct 20, 2023
6230566
Fix slash
andy31415 Oct 20, 2023
f1eb23d
Undo submodule change
andy31415 Oct 20, 2023
9ba5e67
fix xml to zapxml naming changes
andy31415 Oct 20, 2023
6e24285
Restyle
andy31415 Oct 20, 2023
ea95a79
Update dates from 2022 to 2023
andy31415 Oct 20, 2023
5bf9031
Add note about the complex test input
andy31415 Oct 20, 2023
1a1cd35
Remove unused imports
andy31415 Oct 20, 2023
9fe6a63
Restyle
andy31415 Oct 20, 2023
7e09032
Add some commends based on code review
andy31415 Oct 20, 2023
4bcbd43
Add heuristic for setting enum and bitmap sizes, to make output from …
andy31415 Oct 20, 2023
b2a2e67
Add support for timed and fabric scoped commands
andy31415 Oct 20, 2023
32f97ec
Add missing import
andy31415 Oct 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
#
run: |
./scripts/run_in_build_env.sh \
"./scripts/py_matter_idl/matter_idl/xml_parser.py \
"./scripts/py_matter_idl/matter_idl/zapxml_parser.py \
--no-print \
--log-level info \
src/app/zap-templates/zcl/data-model/chip/global-attributes.xml \
Expand Down
2 changes: 1 addition & 1 deletion scripts/py_matter_idl/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pw_python_package("matter_idl") {
"matter_idl/test_matter_idl_parser.py",
"matter_idl/test_generators.py",
"matter_idl/test_idl_generator.py",
"matter_idl/test_xml_parser.py",
"matter_idl/test_zapxml.py",
]

# TODO: at a future time consider enabling all (* or missing) here to get
Expand Down
11 changes: 9 additions & 2 deletions scripts/py_matter_idl/files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ matter_idl_generator_templates = [
matter_idl_generator_sources = [
"${chip_root}/scripts/py_matter_idl/matter_idl/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/backwards_compatibility.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/handlers/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/handlers/base.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/handlers/context.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/handlers/handlers.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/data_model_xml/handlers/parsing.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/generators/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/generators/cpp/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/generators/cpp/application/__init__.py",
Expand All @@ -38,16 +44,17 @@ matter_idl_generator_sources = [
"${chip_root}/scripts/py_matter_idl/matter_idl/matter_idl_parser.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/matter_idl_types.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_backwards_compatibility.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_data_model_xml.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_generators.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_matter_idl_parser.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_xml_parser.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/xml_parser.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/test_zapxml.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/handlers/__init__.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/handlers/base.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/handlers/context.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/handlers/handlers.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml/handlers/parsing.py",
"${chip_root}/scripts/py_matter_idl/matter_idl/zapxml_parser.py",
]

# All the files that the matter idl infrastructure will use
Expand Down
128 changes: 128 additions & 0 deletions scripts/py_matter_idl/matter_idl/data_model_xml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Copyright (c) 2022 Project CHIP Authors
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import typing
import xml.sax.handler
from dataclasses import dataclass
from typing import List, Optional, Union

from matter_idl.data_model_xml.handlers import Context, DataModelXmlHandler
from matter_idl.matter_idl_types import Idl


class ParseHandler(xml.sax.handler.ContentHandler):
"""A parser for data model XML data definitions.

Defers its processing to DataModelXmlHandler and keeps track of:
- an internal context for all handlers
- the parsed Idl structure that is incrementally built
- sets up parsing location within the context
- keeps track of ParsePath

Overall converts a python SAX handler into matter_idl.zapxml.handlers
"""

def __init__(self, include_meta_data=True):
super().__init__()
self._idl = Idl()
self._processing_stack = []
# Context persists across all
self._context = Context()
self._include_meta_data = include_meta_data
self._locator = None

def PrepareParsing(self, filename):
# This is a bit ugly: filename keeps changing during parse
# IDL meta is not prepared for this (as source is XML and .matter is
# single file)
if self._include_meta_data:
self._idl.parse_file_name = filename

self._context.file_name = filename

def Finish(self) -> Idl:
self._context.PostProcess(self._idl)
return self._idl

def startDocument(self):
if self._include_meta_data and self._locator:
self._context.locator = self._locator
self._processing_stack = [
DataModelXmlHandler(self._context, self._idl)]

def endDocument(self):
if len(self._processing_stack) != 1:
raise Exception("Unexpected nesting!")

def startElement(self, name: str, attrs):
logging.debug("ELEMENT START: %r / %r" % (name, attrs))
self._context.path.push(name)
self._processing_stack.append(
self._processing_stack[-1].GetNextProcessor(name, attrs))

def endElement(self, name: str):
logging.debug("ELEMENT END: %r" % name)

last = self._processing_stack.pop()
last.EndProcessing()

# important to pop AFTER processing end to allow processing
# end to access the current context
self._context.path.pop()

def characters(self, content):
self._processing_stack[-1].HandleContent(content)


@dataclass
class ParseSource:
"""Represents an input sopurce for ParseXmls.

Allows for named data sources to be parsed.
"""
source: Union[str, typing.IO] # filename or stream
# actual filename to use, None if the source is a filename already
name: Optional[str] = None

@ property
def source_file_name(self):
if self.name:
return self.name
return self.source # assume string


def ParseXmls(sources: List[ParseSource], include_meta_data=True) -> Idl:
"""Parse one or more XML inputs and return the resulting Idl data.

Params:
sources - what to parse
include_meta_data - if parsing location data should be included in the Idl
"""
handler = ParseHandler(include_meta_data=include_meta_data)

for source in sources:
logging.info('Parsing %s...' % source.source_file_name)
handler.PrepareParsing(source.source_file_name)

parser = xml.sax.make_parser()
parser.setContentHandler(handler)
try:
parser.parse(source.source)
except AssertionError as e:
logging.error("AssertionError %s at %r", e,
handler._context.GetCurrentLocationMeta())
raise

return handler.Finish()
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) 2023 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from matter_idl.matter_idl_types import Idl

from .base import BaseHandler
from .context import Context
from .handlers import ClusterHandler


class DataModelXmlHandler(BaseHandler):
"""Handles the top level (/) of a data model xml file
"""

def __init__(self, context: Context, idl: Idl):
super().__init__(context)
self._idl = idl

def GetNextProcessor(self, name, attrs):
if name.lower() == 'cluster':
return ClusterHandler(self.context, self._idl, attrs)
else:
return BaseHandler(self.context)
63 changes: 63 additions & 0 deletions scripts/py_matter_idl/matter_idl/data_model_xml/handlers/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright (c) 2023 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import enum

from .context import Context


class HandledDepth:
"""Defines how deep a XML element has been handled."""
NOT_HANDLED = enum.auto() # Unknown/parsed element
ENTIRE_TREE = enum.auto() # Entire tree can be ignored
SINGLE_TAG = enum.auto() # Single tag processed, but not sub-items


class BaseHandler:
"""A generic element handler.

XML processing is done in the form of depth-first processing:
- Tree is descended into using `GetNextProcessor`
- Processors are expected to extend `BaseHandler` and allow for:
- GetNextProcessor to recurse
- HandleContent in case the text content is relevant
- EndProcessing once the entire tree has been walked (when xml element ends)

BaseHandler keeps track if it has been handled or ot by its `_handled` setting and
init parameter. Non-handled elements will be tagged within the context, resulting
in logs. This is to detect if unknown/new tags appear in XML files.
"""

def __init__(self, context: Context, handled=HandledDepth.NOT_HANDLED):
self.context = context
self._handled = handled

def GetNextProcessor(self, name, attrs):
"""Get the next processor to use for the given name"""

if self._handled == HandledDepth.SINGLE_TAG:
handled = HandledDepth.NOT_HANDLED
else:
handled = self._handled

return BaseHandler(context=self.context, handled=handled)

def HandleContent(self, content):
"""Processes some content"""
pass

def EndProcessing(self):
"""Finalizes the processing of the current element"""
if self._handled == HandledDepth.NOT_HANDLED:
self.context.MarkTagNotHandled()
Loading
Loading