From 92d5d23e928ca2168e0afd2638b13b92d01072f3 Mon Sep 17 00:00:00 2001 From: Sergey Kovalevich Date: Fri, 4 Oct 2024 21:36:01 +0300 Subject: [PATCH] update --- app/__main__.py | 4 +- app/generation/cpp/generator.py | 78 +-- app/generation/cpp/templates/common.tmpl | 201 ------ app/generation/cpp/templates/composite.tmpl | 4 +- app/generation/cpp/templates/document.tmpl | 2 +- app/generation/cpp/templates/enum.tmpl | 24 +- app/generation/cpp/templates/group.tmpl | 8 +- app/generation/cpp/templates/message.tmpl | 4 +- app/generation/cpp/templates/property.tmpl | 109 ++-- app/generation/cpp/templates/schema.tmpl | 2 +- app/generation/cpp/templates/set.tmpl | 2 +- app/generator.py | 248 ++++---- app/parser.py | 671 ++++++++++---------- app/schema.py | 148 ++--- app/xml.py | 10 +- 15 files changed, 635 insertions(+), 880 deletions(-) delete mode 100644 app/generation/cpp/templates/common.tmpl diff --git a/app/__main__.py b/app/__main__.py index c67c0b6..15f721a 100644 --- a/app/__main__.py +++ b/app/__main__.py @@ -17,11 +17,9 @@ def main() -> None: try: module = importlib.import_module(f'app.generation.{args.generator}') Generator = getattr(module, 'Generator') - - schema = Parser.fromFile(args.schema).getSchema() + schema = Parser.from_file(args.schema).get_schema() generator = Generator(args.destination) generator.generate(schema) - except Exception as e: sys.exit(f'error: {e}') diff --git a/app/generation/cpp/generator.py b/app/generation/cpp/generator.py index 3a6c838..556b998 100644 --- a/app/generation/cpp/generator.py +++ b/app/generation/cpp/generator.py @@ -17,78 +17,78 @@ def __init__(self, path: str) -> None: lstrip_blocks = True, keep_trailing_newline = True ) - self.addFilters() + self.add_filters() - def _generateImpl(self, schema: dict) -> None: - self.ensurePathExists() + def _generate_impl(self, schema: dict) -> None: + self.ensure_path_exists() - for encodedType in schema['types']: - documentName = self.makeDocumentName(encodedType['name']) - if encodedType['token'] == 'type': + for encoded_type in schema['types']: + document_name = self.make_document_name(encoded_type['name']) + if encoded_type['token'] == 'type': pass - elif encodedType['token'] == 'composite': - self.generateDocument(documentName, 'composite.tmpl', type = encodedType, schema = schema, - includes = self.generateIncludesForComposite(encodedType)) - elif encodedType['token'] == 'enum': - self.generateDocument(documentName, 'enum.tmpl', type = encodedType, schema = schema) - elif encodedType['token'] == 'set': - self.generateDocument(documentName, 'set.tmpl', type = encodedType, schema = schema) + elif encoded_type['token'] == 'composite': + self.generate_document(document_name, 'composite.tmpl', type=encoded_type, schema=schema, + includes=self.generate_includes_for_composite(encoded_type)) + elif encoded_type['token'] == 'enum': + self.generate_document(document_name, 'enum.tmpl', type=encoded_type, schema=schema) + elif encoded_type['token'] == 'set': + self.generate_document(document_name, 'set.tmpl', type=encoded_type, schema=schema) for message in schema['messages']: - documentName = self.makeDocumentName(message['name']) - self.generateDocument(documentName, 'message.tmpl', message = message, schema = schema, - includes = self.generateIncludesForMessage(message, schema)) + document_name = self.make_document_name(message['name']) + self.generate_document(document_name, 'message.tmpl', message=message, schema=schema, + includes=self.generate_includes_for_message(message, schema)) - self.generateDocument('schema.h', 'schema.tmpl', schema = schema, includes = self.generateIncludes(schema)) + self.generate_document('schema.h', 'schema.tmpl', schema=schema, includes=self.generate_includes(schema)) - def makeDocumentName(self, name: str) -> str: + def make_document_name(self, name: str) -> str: return self.env.filters['format_class_name'](name) + '.h' - def generateDocument(self, documentName: str, templateName: str, **kwargs) -> None: - template = self.env.get_template(templateName) - documentPath = f'{self.path}/{documentName}' - documentContent = template.render(**kwargs) - with open(documentPath, mode = 'w', encoding = 'utf8') as document: - document.write(documentContent) + def generate_document(self, document_name: str, template_name: str, **kwargs) -> None: + template = self.env.get_template(template_name) + document_path = f'{self.path}/{document_name}' + document_content = template.render(**kwargs) + with open(document_path, mode='w', encoding='utf8') as document: + document.write(document_content) - def generateIncludesForMessage(self, message: dict, schema: dict = None) -> list: + def generate_includes_for_message(self, message: dict, schema: dict = None) -> list: includes = set() for field in message['fields']: if field['token'] == 'field': if field['type']['token'] in ('composite', 'enum', 'set'): - includes.add(self.makeDocumentName(field['type']['name'])) + includes.add(self.make_document_name(field['type']['name'])) elif field['token'] == 'group': - includes.add(self.makeDocumentName(field['dimensionType']['name'])) + includes.add(self.make_document_name(field['dimension_type']['name'])) # this func could be used for iterate over group fields - includes = includes.union(self.generateIncludesForMessage(field)) + includes = includes.union(self.generate_includes_for_message(field)) elif field['token'] == 'data': - includes.add(self.makeDocumentName(field['type']['name'])) + includes.add(self.make_document_name(field['type']['name'])) if schema != None: - includes.add(self.makeDocumentName(schema['headerType']['name'])) + includes.add(self.make_document_name(schema['header_type']['name'])) return list(includes) - def generateIncludesForComposite(self, composite: dict) -> list: + def generate_includes_for_composite(self, composite: dict) -> list: includes = set() - for field in composite['containedTypes']: + for field in composite['contained_types']: if field['token'] in ('composite', 'enum', 'set'): - includes.add(self.makeDocumentName(field['type']['name'])) + includes.add(self.make_document_name(field['name'])) return list(includes) - def generateIncludes(self, schema: dict) -> list: + def generate_includes(self, schema: dict) -> list: includes = set() for message in schema['messages']: - includes.add(self.makeDocumentName(message['name'])) + includes.add(self.make_document_name(message['name'])) return list(includes) - def ensurePathExists(self) -> None: + def ensure_path_exists(self) -> None: if not os.path.exists(self.path): os.makedirs(self.path) - def addFilters(self) -> None: + def add_filters(self) -> None: self.env.filters['format_class_name'] = lambda value: value[0].upper() + value[1:] self.env.filters['format_method_name_get'] = lambda value: value[0].lower() + value[1:] self.env.filters['format_method_name_set'] = lambda value: value[0].lower() + value[1:] @@ -97,10 +97,10 @@ def addFilters(self) -> None: self.env.filters['format_method_name_length'] = lambda value: value[0].lower() + value[1:] + 'Length' self.env.filters['format_method_name_get_count'] = lambda value: value[0].lower() + value[1:] + 'Count' self.env.filters['format_constant_name'] = lambda value: 'k' + value[0].upper() + value[1:] - self.env.filters['replace_keyword'] = Generator.filterReplaceKeword + self.env.filters['replace_keyword'] = Generator.filter_replace_keyword @staticmethod - def filterReplaceKeword(value: str) -> str: + def filter_replace_keyword(value: str) -> str: return { 'int8': 'std::int8_t', 'int16': 'std::int16_t', diff --git a/app/generation/cpp/templates/common.tmpl b/app/generation/cpp/templates/common.tmpl deleted file mode 100644 index 515d7cc..0000000 --- a/app/generation/cpp/templates/common.tmpl +++ /dev/null @@ -1,201 +0,0 @@ -{% extends 'document.tmpl' %} - -{% block content %} -template -struct FixedString { - char storage[N + 1] = {}; - - constexpr FixedString(char const* str) noexcept { - for (std::size_t i = 0; i != N; ++i) { - storage[i] = str[i]; - } - } - - constexpr FixedString(std::string_view str) noexcept { - for (std::size_t i = 0; i != N; ++i) { - storage[i] = str[i]; - } - } - - [[nodiscard]] explicit constexpr operator std::string_view() const noexcept { - return std::string_view(storage, N); - } - - [[nodiscard]] constexpr char const* c_str() const noexcept { - return storage; - } - - [[nodiscard]] static constexpr std::size_t size() noexcept { - return N; - } - - constexpr auto operator<=>(FixedString const&) const = default; -}; - -template FixedString(char const (&)[N]) -> FixedString; - -template -struct TypeDescription; - -template -struct TypeDescription { - using value_type = T; - - static constexpr auto length = std::size_t(1); - - template - struct Constant { - using value_type = T; - static constexpr value_type value = Value; - constexpr operator value_type() const noexcept { return value; } - }; - - template - using Value = Constant; -}; - -template -struct TypeDescription { - static_assert(Length != 1, "impossible case, Luke"); - - using value_type = std::string_view; - using underlying_type = char; - - static constexpr auto length = Length; - static constexpr auto isVariableLength = (Length == 0); - - template - struct Constant { - static_assert(isVariableLength || Value.size() == Length, "string length size mismatch"); - - using value_type = std::string_view; - static constexpr value_type value = static_cast(Value); - constexpr operator value_type() const noexcept { return value; } - }; - - template - struct Value { - using value_type = char; - static constexpr value_type value = V; - constexpr operator value_type() const noexcept { return value; } - }; -}; - -template -struct TypeDescription : TypeDescription {}; - -enum class Presence { - REQUIRED, OPTIONAL, CONSTANT -}; - -template -struct ValueStorage { - [[nodiscard]] constexpr operator decltype(Value)() const noexcept { - return Value; - } -}; - -using PresenceRequired = ValueStorage; -using PresenceOptional = ValueStorage; -using PresenceConstant = ValueStorage; - -struct TrimString {}; -inline constexpr auto trim_string = TrimString(); - -template -struct FieldTraits { - using min_value_type = MinValue; - using max_value_type = MaxValue; - using null_value_type = NullValue; - using const_value_type = ConstValue; -}; - -template, class = void> -struct FieldDescription { - [[nodiscard]] static constexpr std::string_view name() noexcept { - return static_cast(Name); - } - - template - [[nodiscard]] static constexpr typename TypeDescription::value_type load([[maybe_unused]] Context const& context) noexcept - { - if constexpr (FieldPresence() == Presence::CONSTANT) { - return typename Traits::const_value_type(); - } else { - if constexpr (TypeDescription::length == 1) { - return *std::bit_cast(context.buffer + context.offset + Offset); - } else { - static_assert(TypeDescription::length > 1); - return typename TypeDescription::value_type(std::bit_cast(context.buffer + context.offset + Offset), TypeDescription::length); - } - } - } - - template - [[nodiscard]] static constexpr std::string_view load(TrimString, [[maybe_unused]] Context const& context) noexcept - { - static_assert(std::is_same_v); - static_assert(TypeDescription::length > 1); - - if constexpr (FieldPresence() == Presence::CONSTANT) { - return typename Traits::const_value_type(); - } else { - auto value = std::string_view(std::bit_cast(context.buffer + context.offset + Offset), TypeDescription::length); - if (auto const found = value.find('\0'); found != value.npos) { - return value.substr(0, found); - } else { - return value; - } - } - } - - template - static constexpr void store(Context& context, typename TypeDescription::value_type value) noexcept - { - static_assert(FieldPresence() != Presence::CONSTANT, "can't store anything for constant field"); - - if constexpr (TypeDescription::length == 1) { - *std::bit_cast(context.buffer + context.offset + Offset) = value; - } else { - static_assert(TypeDescription::length > 1); - // TODO: std::string_view case - std::copy_n(std::begin(value), TypeDescription::length, std::bit_cast(context.buffer + context.offset + Offset)); - } - } - - template - static constexpr void store(TrimString, Context& context, std::string_view value) noexcept - { - static_assert(std::is_same_v); - static_assert(TypeDescription::length > 1); - static_assert(FieldPresence() != Presence::CONSTANT, "can't store anything for constant field"); - - auto const size = std::min(std::size(value), TypeDescription::length); - std::copy_n(std::begin(value), size, std::bit_cast(context.buffer + context.offset + Offset)); - } - - template - [[nodiscard]] static constexpr bool present([[maybe_unused]] Context const& context) noexcept { - if constexpr (FieldPresence() == Presence::CONSTANT || FieldPresence() == Presence::REQUIRED) { - return true; - } else { - constexpr auto nullValue = static_cast(typename Traits::null_value_type()); - if constexpr (TypeDescription::length == 1) { - if constexpr (std::is_floating_point_v) { - if constexpr (std::isnan(nullValue)) { - return !std::isnan(load(context)); - } else { - return load(context) != nullValue; - } - } else { - return load(context) != nullValue; - } - } else { - return load(context).front() != nullValue; - } - } - } -}; - -{{ '' -}} -{% endblock %} diff --git a/app/generation/cpp/templates/composite.tmpl b/app/generation/cpp/templates/composite.tmpl index 12f2a1f..04ca767 100644 --- a/app/generation/cpp/templates/composite.tmpl +++ b/app/generation/cpp/templates/composite.tmpl @@ -42,7 +42,7 @@ public: } [[nodiscard]] static constexpr std::size_t encodedLength() noexcept { - return {{ type.encodedLength }}; + return {{ type.encoded_length }}; } [[nodiscard]] std::size_t offset() const noexcept { @@ -73,7 +73,7 @@ public: return {{ schema.version }}; } - {{ property.define(composite_class_name, type.containedTypes) | indent }} + {{ property.define(composite_class_name, type.contained_types) | indent }} {{- '' -}} }; diff --git a/app/generation/cpp/templates/document.tmpl b/app/generation/cpp/templates/document.tmpl index 972de6e..614c391 100644 --- a/app/generation/cpp/templates/document.tmpl +++ b/app/generation/cpp/templates/document.tmpl @@ -1,5 +1,5 @@ // Generated simple binary encoding message codec -// Message codec generator: https://github.com/TheBoysCoding/sbe-code-gen +// Message codec generator: https://github.com/ksergey/sbe-code-gen #pragma once diff --git a/app/generation/cpp/templates/enum.tmpl b/app/generation/cpp/templates/enum.tmpl index b5f2521..6179e91 100644 --- a/app/generation/cpp/templates/enum.tmpl +++ b/app/generation/cpp/templates/enum.tmpl @@ -3,7 +3,7 @@ {% block content %} {%- set enum_class_name = type.name | format_class_name -%} -{%- set underlying_type = type.encodingType | replace_keyword -%} +{%- set underlying_type = type.encoding_type | replace_keyword -%} class {{ enum_class_name }} final { private: @@ -11,14 +11,14 @@ private: public: enum enumerated : {{ underlying_type }} { -{% for validValue in type.validValues %} - {% if type.encodingType == 'char' %} - {{ validValue.name }} = '{{ validValue.value }}', +{% for valid_value in type.valid_values %} + {% if type.encoding_type == 'char' %} + {{ valid_value.name }} = '{{ valid_value.value }}', {% else %} - {{ validValue.name }} = {{ validValue.value }}, + {{ valid_value.name }} = {{ valid_value.value }}, {% endif %} {% endfor %} - NULL_VALUE = {{ type.nullValue | replace_keyword }} + NULL_VALUE = {{ type.null_value | replace_keyword }} }; constexpr {{ enum_class_name }}() noexcept @@ -39,9 +39,9 @@ public: [[nodiscard]] static constexpr char const* toString({{ enum_class_name }} value) noexcept { switch (value) { -{% for validValue in type.validValues %} - case {{ enum_class_name }}::{{ validValue.name }}: - return "{{ validValue.name }}"; +{% for valid_value in type.valid_values %} + case {{ enum_class_name }}::{{ valid_value.name }}: + return "{{ valid_value.name }}"; {% endfor %} default: break; @@ -51,9 +51,9 @@ public: [[nodiscard]] static constexpr {{ enum_class_name }} fromString(char const* value) noexcept { using namespace std::string_view_literals; -{% for validValue in type.validValues %} - if ("{{ validValue.name }}"sv == value) { - return {{ enum_class_name }}::{{ validValue.name }}; +{% for valid_value in type.valid_values %} + if ("{{ valid_value.name }}"sv == value) { + return {{ enum_class_name }}::{{ valid_value.name }}; } {% endfor %} return NULL_VALUE; diff --git a/app/generation/cpp/templates/group.tmpl b/app/generation/cpp/templates/group.tmpl index 300acda..829a80a 100644 --- a/app/generation/cpp/templates/group.tmpl +++ b/app/generation/cpp/templates/group.tmpl @@ -10,9 +10,9 @@ {% macro define_group(entry) %} {%- set group_class_name = entry.name | format_class_name -%} -{%- set dimensions_type_class_name = entry.dimensionType.name | format_class_name -%} +{%- set dimensions_type_class_name = entry.dimension_type.name | format_class_name -%} {%- set method_name = entry.name -%} -{%- set num_in_group_type = (entry.dimensionType.containedTypes | selectattr('name', 'equalto', 'numInGroup') | first) -%} +{%- set num_in_group_type = (entry.dimension_type.contained_types | selectattr('name', 'equalto', 'numInGroup') | first) -%} class {{ group_class_name }} final { private: @@ -45,7 +45,7 @@ public: {{ group_class_name }}(char* buffer, std::size_t count, std::size_t* pos, std::uint16_t actingVersion, std::size_t bufferLength) { - if (count > ({{ num_in_group_type.maxValue | replace_keyword }})) { + if (count > ({{ num_in_group_type.max_value | replace_keyword }})) { throw std::runtime_error("count outside of allowed range in group {{ entry.name }} [E110]"); } @@ -64,7 +64,7 @@ public: } [[nodiscard]] static constexpr std::size_t sbeBlockLength() noexcept { - return {{ entry.blockLength }}; + return {{ entry.block_length }}; } [[nodiscard]] std::size_t sbePosition() const noexcept { diff --git a/app/generation/cpp/templates/message.tmpl b/app/generation/cpp/templates/message.tmpl index fb9a0b1..ba072a5 100644 --- a/app/generation/cpp/templates/message.tmpl +++ b/app/generation/cpp/templates/message.tmpl @@ -6,7 +6,7 @@ {% block content %} {%- set message_class_name = message.name | format_class_name -%} -{%- set header_class_name = schema.headerType.name | format_class_name -%} +{%- set header_class_name = schema.header_type.name | format_class_name -%} class {{ message_class_name }} final { private: @@ -100,7 +100,7 @@ public: } [[nodiscard]] static constexpr std::size_t sbeBlockLength() noexcept { - return {{ message.blockLength }}; + return {{ message.block_length }}; } [[nodiscard]] static constexpr std::uint16_t sbeTemplateId() noexcept { diff --git a/app/generation/cpp/templates/property.tmpl b/app/generation/cpp/templates/property.tmpl index 9e8992c..a500b00 100644 --- a/app/generation/cpp/templates/property.tmpl +++ b/app/generation/cpp/templates/property.tmpl @@ -5,32 +5,38 @@ {% endmacro %} {% macro define_property(class_name, entry) %} +{%- if 'reference_name' in entry %} + {% set method_name = entry.reference_name -%} +{%- else %} + {% set method_name = entry.name -%} +{%- endif %} + {%- if entry.token == 'type' %} - {{- define_property_type(class_name, entry) -}} + {{- define_property_type(class_name, method_name, entry) -}} {%- elif entry.token == 'composite' %} - {{- define_property_composite(class_name, entry) -}} + {{- define_property_composite(class_name, methon_name, entry) -}} {%- elif entry.token == 'enum' %} - {{- define_property_enum(class_name, entry) -}} + {{- define_property_enum(class_name, method_name, entry) -}} {%- elif entry.token == 'set' %} - {{- define_property_set(class_name, entry) -}} + {{- define_property_set(class_name, method_name, entry) -}} {%- elif entry.token == 'field' %} {%- if entry.type.token == 'type' %} - {{- define_property_type(class_name, entry) -}} + {{- define_property_type(class_name, method_name, entry) -}} {%- elif entry.type.token == 'composite' %} - {{- define_property_composite(class_name, entry) -}} + {{- define_property_composite(class_name, method_name, entry) -}} {%- elif entry.type.token == 'enum' %} - {{- define_property_enum(class_name, entry) -}} + {{- define_property_enum(class_name, method_name, entry) -}} {%- elif entry.type.token == 'set' %} - {{- define_property_set(class_name, entry) -}} + {{- define_property_set(class_name, method_name, entry) -}} {%- endif %} {%- elif entry.token == 'group' %} - {{- define_property_group(class_name, entry) -}} + {{- define_property_group(class_name, method_name, entry) -}} {%- elif entry.token == 'data' %} - {{- define_property_data(class_name, entry) -}} + {{- define_property_data(class_name, method_name, entry) -}} {%- endif %} {% endmacro %} -{% macro define_property_type(class_name, entry) -%} +{% macro define_property_type(class_name, method_name, entry) -%} {%- if entry.token == 'field' %} {% set type = entry.type -%} {%- else %} @@ -38,28 +44,27 @@ {%- endif %} {%- if type.length == 1 %} - {{- define_property_type_single(class_name, entry) }} + {{- define_property_type_single(class_name, method_name, entry) }} {%- elif type.length > 1 %} - {{- define_property_type_array(class_name, entry) }} + {{- define_property_type_array(class_name, method_name, entry) }} {%- endif %} {%- endmacro %} -{% macro define_property_type_single(class_name, entry) %} +{% macro define_property_type_single(class_name, method_name, entry) %} {%- if entry.token == 'field' %} {% set type = entry.type -%} {%- else %} {% set type = entry -%} {%- endif %} -{%- set method_name = entry.name -%} -{%- set underlying_type = type.primitiveType | replace_keyword -%} +{%- set underlying_type = type.primitive_type | replace_keyword -%} {%- if entry.presence == 'constant' %} [[nodiscard]] static constexpr {{ underlying_type }} {{ method_name | format_method_name_get }}() noexcept { - {% if type.primitiveType == 'char' %} - return '{{ type.constValue }}'; + {% if type.primitive_type == 'char' %} + return '{{ type.const_value }}'; {% else %} - return {{ type.constValue }}; + return {{ type.const_value }}; {% endif %} } @@ -82,7 +87,7 @@ {%- if entry.presence == 'optional' %} {{ class_name }}& {{ method_name | format_method_name_reset }}() noexcept { - return {{ method_name | format_method_name_set }}({{ type.nullValue | replace_keyword }}); + return {{ method_name | format_method_name_set }}({{ type.null_value | replace_keyword }}); } {% endif %} @@ -95,27 +100,26 @@ {%- if entry.presence == 'optional' %} [[nodiscard]] bool {{ method_name | format_method_name_is_present }}() const noexcept { - {% if type.primitiveType == 'double' or type.primitiveType == 'float' %} - constexpr {{ underlying_type }} null = {{ type.nullValue | replace_keyword }}; + {% if type.primitive_type == 'double' or type.primitive_type == 'float' %} + constexpr {{ underlying_type }} null = {{ type.null_value | replace_keyword }}; constexpr {{ underlying_type }} value = {{ method_name | format_method_name_get() }}; return ((null != null && value != value) || (value != null)); {% else %} - return {{ type.nullValue | replace_keyword }} != {{ method_name | format_method_name_get }}(); + return {{ type.null_value | replace_keyword }} != {{ method_name | format_method_name_get }}(); {% endif %} } {% endif %} {% endmacro %} -{% macro define_property_type_array(class_name, entry) %} +{% macro define_property_type_array(class_name, method_name, entry) %} {%- if entry.token == 'field' %} {%- set type = entry.type -%} {%- else %} {%- set type = entry -%} {%- endif %} -{%- set method_name = entry.name -%} -{%- set underlying_type = type.primitiveType | replace_keyword -%} -{%- if type.primitiveType == 'char' %} +{%- set underlying_type = type.primitive_type | replace_keyword -%} +{%- if type.primitive_type == 'char' %} {% set value_type = 'std::string_view' -%} {%- else %} {% set value_type = 'std::span<' ~ underlying_type ~ ' const>' -%} @@ -123,8 +127,8 @@ {%- if entry.presence == 'constant' %} [[nodiscard]] static constexpr {{ value_type }} {{ method_name | format_method_name_get }}() noexcept { - {% if type.primitiveType == 'char' %} - return "{{ type.constValue }}"; + {% if type.primitive_type == 'char' %} + return "{{ type.const_value }}"; {% else %} assert(false, "not implemeted"); {% endif %} @@ -139,7 +143,7 @@ {% endif %} -{%- if entry.presence != 'constant' and type.primitiveType != 'char' %} +{%- if entry.presence != 'constant' and type.primitive_type != 'char' %} {{ class_name }}& {{ method_name | format_method_name_set }}({{ value_type }} value) noexcept { if (value.size() != {{ type.length }}) [[unlikely]] { # TODO @@ -151,12 +155,12 @@ {% endif %} -{%- if entry.presence != 'constant' and type.primitiveType == 'char' %} +{%- if entry.presence != 'constant' and type.primitive_type == 'char' %} {{ class_name }}& {{ method_name | format_method_name_set }}({{ value_type }} value) noexcept { std::size_t const lengthToCopy = std::min(value.size(), {{ type.length }}); std::memcpy(buffer_ + offset_ + {{ entry.offset }}, value.data(), lengthToCopy); for (std::size_t i = lengthToCopy; i < {{ type.length }}; ++i) { - *std::bit_cast<{{ underlying_type }}*>(buffer_ + offset_ + {{ entry.offset }} + i) = {{ type.nullValue | replace_keyword }}; + *std::bit_cast<{{ underlying_type }}*>(buffer_ + offset_ + {{ entry.offset }} + i) = {{ type.null_value | replace_keyword }}; } return *this; } @@ -178,12 +182,12 @@ {%- if entry.presence == 'optional' %} [[nodiscard]] bool {{ method_name | format_method_name_is_present }}() const noexcept { - return {{ type.nullValue | replace_keyword }} != {{ method_name | format_method_name_get }}().front(); + return {{ type.null_value | replace_keyword }} != {{ method_name | format_method_name_get }}().front(); } {% endif %} {% endmacro %} -{% macro define_property_composite(class_name, entry) %} +{% macro define_property_composite(class_name, method_name, entry) %} {%- if entry.token == 'field' %} {% set type = entry.type -%} @@ -191,8 +195,7 @@ {% set type = entry -%} {%- endif %} {%- set composite_class_name = type.name | format_class_name -%} -{%- set method_name = entry.name -%} -{%- set composite_first_entry_method_name = type.containedTypes[0].name -%} +{%- set composite_first_entry_method_name = type.contained_types[0].name -%} [[nodiscard]] {{ composite_class_name }} {{ method_name | format_method_name_get }}() { return {{ composite_class_name }}(buffer_, offset_ + {{ entry.offset }}, bufferLength_, actingVersion_); @@ -203,20 +206,19 @@ } {% endmacro %} -{% macro define_property_enum(class_name, entry) %} +{% macro define_property_enum(class_name, method_name, entry) %} {%- if entry.token == 'field' %} {%- set type = entry.type -%} {%- else %} {%- set type = entry -%} {%- endif %} -{%- if entry.valueRef != None %} - {%- set const_value = entry.valueRef -%} +{%- if entry.value_ref != None %} + {%- set const_value = entry.value_ref -%} {%- else %} {%- set const_value = type.const_value -%} {%- endif %} {%- set enum_class_name = type.name | format_class_name -%} -{%- set method_name = entry.name -%} -{%- set underlying_type = type.encodingType | replace_keyword -%} +{%- set underlying_type = type.encoding_type | replace_keyword -%} {%- if entry.presence == 'constant' %} [[nodiscard]] static constexpr {{ enum_class_name }} {{ method_name | format_method_name_get }}() noexcept { @@ -260,15 +262,14 @@ {% endif %} {% endmacro %} -{% macro define_property_set(class_name, entry) %} +{% macro define_property_set(class_name, method_name, entry) %} {%- if entry.token == 'field' %} {% set type = entry.type -%} {%- else %} {% set type = entry -%} {%- endif %} {%- set set_class_name = entry.name | format_class_name -%} -{%- set method_name = entry.name -%} -{%- set underlying_type = type.encodingType | replace_keyword -%} +{%- set underlying_type = type.encoding_type | replace_keyword -%} [[nodiscard]] {{ set_class_name }} {{ method_name | format_method_name_get }}() const { return {{ set_class_name }}(*std::bit_cast<{{ underlying_type }} const*>(buffer_ + offset_ + {{ entry.offset }})); @@ -284,11 +285,10 @@ } {% endmacro %} -{% macro define_property_group(class_name, entry) %} +{% macro define_property_group(class_name, method_name, entry) %} {%- set group_class_name = entry.name | format_class_name -%} -{%- set dimensions_type_class_name = entry.dimensionType.name | format_class_name -%} -{%- set method_name = entry.name -%} -{%- set num_in_group_type = (entry.dimensionType.containedTypes | selectattr('name', 'equalto', 'numInGroup') | first) -%} +{%- set dimensions_type_class_name = entry.dimension_type.name | format_class_name -%} +{%- set num_in_group_type = (entry.dimension_type.contained_types | selectattr('name', 'equalto', 'numInGroup') | first) -%} [[nodiscard]] {{ group_class_name }} {{ method_name | format_method_name_get }}() { return {{ group_class_name }}(buffer_, sbePositionPtr(), actingVersion_, bufferLength_); @@ -299,15 +299,14 @@ } {% endmacro %} -{% macro define_property_data(class_name, entry) %} +{% macro define_property_data(class_name, method_name, entry) %} {%- set type = entry.type -%} -{%- set length_type = (type.containedTypes | selectattr('name', 'equalto', 'length') | first) -%} -{%- set var_data_type = (type.containedTypes | selectattr('name', 'equalto', 'varData') | first) -%} -{%- set method_name = entry.name -%} -{%- set length_underlying_type = length_type.primitiveType | replace_keyword -%} -{%- set data_underlying_type = var_data_type.primitiveType | replace_keyword -%} +{%- set length_type = (type.contained_types | selectattr('name', 'equalto', 'length') | first) -%} +{%- set var_data_type = (type.contained_types | selectattr('name', 'equalto', 'varData') | first) -%} +{%- set length_underlying_type = length_type.primitive_type | replace_keyword -%} +{%- set data_underlying_type = var_data_type.primitive_type | replace_keyword -%} -{%- if var_data_type.primitiveType == 'char' or var_data_type.primitiveType == 'uint8' %} +{%- if var_data_type.primitive_type == 'char' or var_data_type.primitive_type == 'uint8' %} {%- set data_underlying_type = 'char' -%} {%- set value_type = 'std::string_view' -%} {%- else %} diff --git a/app/generation/cpp/templates/schema.tmpl b/app/generation/cpp/templates/schema.tmpl index d72a299..1199be8 100644 --- a/app/generation/cpp/templates/schema.tmpl +++ b/app/generation/cpp/templates/schema.tmpl @@ -1,5 +1,5 @@ // Generated simple binary encoding message codec -// Message codec generator: https://github.com/TheBoysCoding/sbe-code-gen +// Message codec generator: https://github.com/ksergey/sbe-code-gen #pragma once diff --git a/app/generation/cpp/templates/set.tmpl b/app/generation/cpp/templates/set.tmpl index 3165184..f5e271f 100644 --- a/app/generation/cpp/templates/set.tmpl +++ b/app/generation/cpp/templates/set.tmpl @@ -3,7 +3,7 @@ {% block content %} {%- set set_class_name = type.name | format_class_name -%} -{%- set underlying_type = type.encodingType | replace_keyword -%} +{%- set underlying_type = type.encoding_type | replace_keyword -%} class {{ set_class_name }} final { private: diff --git a/app/generator.py b/app/generator.py index ac21550..a1a99e2 100644 --- a/app/generator.py +++ b/app/generator.py @@ -8,191 +8,175 @@ from app.schema import * class GeneratorBase(ABC): - primitiveTypeByName = { - 'char': PrimitiveType('char', 1, "CHAR_NULL", "CHAR_MIN", "CHAR_MAX"), - 'int8': PrimitiveType('int8', 1, "INT8_NULL", "INT8_MIN", "INT8_MAX"), - 'int16': PrimitiveType('int16', 2, "INT16_NULL", "INT16_MIN", "INT16_MAX"), - 'int32': PrimitiveType('int32', 4, "INT32_NULL", "INT32_MIN", "INT32_MAX"), - 'int64': PrimitiveType('int64', 8, "INT64_NULL", "INT64_MIN", "INT64_MAX"), - 'uint8': PrimitiveType('uint8', 1, "UINT8_NULL", "UINT8_MIN", "UINT8_MAX"), - 'uint16': PrimitiveType('uint16', 2, "UINT16_NULL", "UINT16_MIN", "UINT16_MAX"), - 'uint32': PrimitiveType('uint32', 4, "UINT32_NULL", "UINT32_MIN", "UINT32_MAX"), - 'uint64': PrimitiveType('uint64', 8, "UINT64_NULL", "UINT64_MIN", "UINT64_MAX"), - 'float': PrimitiveType('float', 4, "FLOAT_NULL", "FLOAT_MIN", "FLOAT_MAX"), - 'double': PrimitiveType('double', 8, "DOUBLE_NULL", "DOUBLE_MIN", "DOUBLE_MAX") - } - @abstractmethod - def _generateImpl(self, schema: dict) -> None: + def _generate_impl(self, schema: dict) -> None: pass def generate(self, schema: Schema) -> None: ir = {} - if schema.package != None: ir['package'] = schema.package.split('.') else: ir['package'] = None - ir['id'] = schema.id ir['version'] = schema.version - ir['byteOrder'] = schema.byteOrder.value + ir['byte_order'] = schema.byte_order.value ir['description'] = schema.description - ir['headerType'] = GeneratorBase.makeEncodedTypeDefinition(schema.headerType) - + ir['header_type'] = GeneratorBase.make_encoded_type_definition(schema.header_type) ir['types'] = [] - for type in schema.types.values(): - ir['types'].append(GeneratorBase.makeEncodedTypeDefinition(type)) - + for encoded_type in schema.types.values(): + ir['types'].append(GeneratorBase.make_encoded_type_definition(encoded_type)) ir['messages'] = [] for message in schema.messages.values(): - ir['messages'].append(GeneratorBase.makeMessageDefinition(message)) - - self._generateImpl(ir) + ir['messages'].append(GeneratorBase.make_message_definition(message)) + self._generate_impl(ir) @staticmethod - def makeEncodedTypeDefinition(type: EncodedType) -> dict: - assert (isinstance(type, (Type, Composite, Enum, Set))), "unknown type" - if isinstance(type, Type): - return GeneratorBase.makeTypeDefinition(type) - if isinstance(type, Composite): - return GeneratorBase.makeCompositeDefinition(type) - if isinstance(type, Enum): - return GeneratorBase.makeEnumDefinition(type) - if isinstance(type, Set): - return GeneratorBase.makeSetDefinition(type) + def make_encoded_type_definition(encoded_type: EncodedType) -> dict: + assert isinstance(encoded_type, (Type, Composite, Enum, Set)) + if isinstance(encoded_type, Type): + return GeneratorBase.make_type_definition(encoded_type) + if isinstance(encoded_type, Composite): + return GeneratorBase.make_composite_definition(encoded_type) + if isinstance(encoded_type, Enum): + return GeneratorBase.make_enum_definition(encoded_type) + if isinstance(encoded_type, Set): + return GeneratorBase.make_set_definition(encoded_type) @staticmethod - def makeTypeDefinition(type: Type) -> dict: + def make_type_definition(type_type: Type) -> dict: return { 'token': 'type', - 'name': type.name, - 'description': type.description, - 'presence': type.presence.value, - 'nullValue': type.nullValue if type.nullValue != None else type.primitiveType.nullValue, - 'minValue': type.minValue if type.minValue != None else type.primitiveType.minValue, - 'maxValue': type.maxValue if type.maxValue != None else type.primitiveType.maxValue, - 'length': type.length, - 'offset': type.offset, - 'primitiveType': type.primitiveType.name, - 'semanticType': type.semanticType, - 'sinceVersion': type.sinceVersion, - 'deprecated': type.deprecated, - 'constValue': type.constValue, - 'characterEncoding': type.characterEncoding, - 'encodedLength': type.encodedLength() + 'name': type_type.name, + 'description': type_type.description, + 'presence': type_type.presence.value, + 'null_value': type_type.null_value if type_type.null_value != None else type_type.primitive_type.null_value, + 'min_value': type_type.min_value if type_type.min_value != None else type_type.primitive_type.min_value, + 'max_value': type_type.max_value if type_type.max_value != None else type_type.primitive_type.max_value, + 'length': type_type.length, + 'offset': type_type.offset, + 'primitive_type': type_type.primitive_type.name, + 'semantic_type': type_type.semantic_type, + 'since_version': type_type.since_version, + 'deprecated': type_type.deprecated, + 'const_value': type_type.const_value, + 'character_encoding': type_type.character_encoding, + 'encoded_length': type_type.encoded_length() } @staticmethod - def makeCompositeDefinition(type: Composite) -> dict: - containedTypes = [] - for containedType in type.containedTypes.values(): - assert (isinstance(containedType, (Type, Composite, Enum, Set, Ref))), "unknown type" + def make_composite_definition(composite_type: Composite) -> dict: + contained_types = [] + for contained_type in composite_type.contained_types.values(): + assert isinstance(contained_type, (Type, Composite, Enum, Set, Ref)) entry = None - if isinstance(containedType, Type): - entry = GeneratorBase.makeTypeDefinition(containedType) - elif isinstance(containedType, Composite): - entry = GeneratorBase.makeCompositeDefinition(containedType) - elif isinstance(containedType, Enum): - entry = GeneratorBase.makeEnumDefinition(containedType) - elif isinstance(containedType, Set): - entry = GeneratorBase.makeSetDefinition(containedType) - elif isinstance(containedType, Ref): - entry = GeneratorBase.makeEncodedTypeDefinition(containedType.type) - entry['name'] = containedType.name - entry['offset'] = containedType.offset - entry['description'] = containedType.description - entry['sinceVersion'] = containedType.sinceVersion - entry['deprecated'] = containedType.deprecated - containedTypes.append(entry) + if isinstance(contained_type, Type): + entry = GeneratorBase.make_type_definition(contained_type) + elif isinstance(contained_type, Composite): + entry = GeneratorBase.make_composite_definition(contained_type) + elif isinstance(contained_type, Enum): + entry = GeneratorBase.make_enum_definition(contained_type) + elif isinstance(contained_type, Set): + entry = GeneratorBase.make_set_definition(contained_type) + elif isinstance(contained_type, Ref): + entry = GeneratorBase.make_encoded_type_definition(contained_type.type) + entry['name'] = contained_type.type.name + entry['offset'] = contained_type.offset + entry['description'] = contained_type.description + entry['since_version'] = contained_type.since_version + entry['deprecated'] = contained_type.deprecated + entry['reference_name'] = contained_type.name + contained_types.append(entry) return { 'token': 'composite', - 'name': type.name, - 'offset': type.offset, - 'description': type.description, - 'semanticType': type.semanticType, - 'sinceVersion': type.sinceVersion, - 'deprecated': type.deprecated, - 'containedTypes': containedTypes, - 'encodedLength': type.encodedLength() + 'name': composite_type.name, + 'offset': composite_type.offset, + 'description': composite_type.description, + 'semantic_type': composite_type.semantic_type, + 'since_version': composite_type.since_version, + 'deprecated': composite_type.deprecated, + 'contained_types': contained_types, + 'encoded_length': composite_type.encoded_length() } @staticmethod - def makeEnumDefinition(type: Enum) -> dict: - validValues = [] - for validValue in type.validValueByName.values(): - validValues.append({ - 'name': validValue.name, - 'value': validValue.value, - 'description': validValue.description, - 'sinceVersion': validValue.sinceVersion, - 'deprecated': validValue.deprecated + def make_enum_definition(enum_type: Enum) -> dict: + valid_values = [] + for valid_value in enum_type.valid_value_by_name.values(): + valid_values.append({ + 'name': valid_value.name, + 'value': valid_value.value, + 'description': valid_value.description, + 'since_version': valid_value.since_version, + 'deprecated': valid_value.deprecated }) return { 'token': 'enum', - 'name': type.name, - 'description': type.description, - 'encodingType': type.encodingType.name, - 'sinceVersion': type.sinceVersion, - 'deprecated': type.deprecated, - 'offset': type.offset, - 'nullValue': type.nullValue if type.nullValue != None else type.encodingType.nullValue, - 'validValues': validValues, - 'encodedLength': type.encodedLength() + 'name': enum_type.name, + 'description': enum_type.description, + 'presence': enum_type.presence.value, + 'encoding_type': enum_type.encoding_type.name, + 'since_version': enum_type.since_version, + 'deprecated': enum_type.deprecated, + 'offset': enum_type.offset, + 'null_value': enum_type.null_value if enum_type.null_value != None else enum_type.encoding_type.null_value, + 'valid_values': valid_values, + 'encoded_length': enum_type.encoded_length() } @staticmethod - def makeSetDefinition(type: Set) -> dict: + def make_set_definition(set_type: Set) -> dict: choices = [] - for choice in type.choiceByName.values(): + for choice in set_type.choice_by_name.values(): choices.append({ 'name': choice.name, 'value': choice.value, 'description': choice.description, - 'sinceVersion': choice.sinceVersion, + 'since_version': choice.since_version, 'deprecated': choice.deprecated }) return { 'token': 'set', - 'name': type.name, - 'description': type.description, - 'encodingType': type.encodingType.name, - 'sinceVersion': type.sinceVersion, - 'deprecated': type.deprecated, - 'offset': type.offset, + 'name': set_type.name, + 'description': set_type.description, + 'presence': set_type.presence.value, + 'encoding_type': set_type.encoding_type.name, + 'since_version': set_type.since_version, + 'deprecated': set_type.deprecated, + 'offset': set_type.offset, 'choices': choices, - 'encodedLength': type.encodedLength() + 'encoded_length': set_type.encoded_length() } @staticmethod - def makeFieldDefinition(field: Field) -> dict: + def make_field_definition(field: Field) -> dict: return { 'token': 'field', 'name': field.name, 'id': field.id, 'description': field.description, - 'type': GeneratorBase.makeEncodedTypeDefinition(field.type), + 'type': GeneratorBase.make_encoded_type_definition(field.type), 'offset': field.offset, 'presence': field.presence.value, - 'valueRef': field.valueRef, - 'semanticType': field.semanticType, - 'sinceVersion': field.sinceVersion, + 'value_ref': field.value_ref, + 'semantic_type': field.semantic_type, + 'since_version': field.since_version, 'deprecated': field.deprecated } @staticmethod - def makeGroupDefinition(group: Group) -> dict: + def make_group_definition(group: Group) -> dict: fields = [] for field in group.fields.values(): - assert (isinstance(field, (Field, Group, Data))), "unknown group field" + assert isinstance(field, (Field, Group, Data)) entry = None if isinstance(field, Field): - entry = GeneratorBase.makeFieldDefinition(field) + entry = GeneratorBase.make_field_definition(field) elif isinstance(field, Group): - entry = GeneratorBase.makeGroupDefinition(field) + entry = GeneratorBase.make_group_definition(field) elif isinstance(field, Data): - entry = GeneratorBase.makeDataDefinition(field) + entry = GeneratorBase.make_data_definition(field) fields.append(entry) return { @@ -200,36 +184,36 @@ def makeGroupDefinition(group: Group) -> dict: 'name': group.name, 'id': group.id, 'description': group.description, - 'dimensionType': GeneratorBase.makeEncodedTypeDefinition(group.dimensionType), - 'blockLength': group.blockLength, + 'dimension_type': GeneratorBase.make_encoded_type_definition(group.dimension_type), + 'block_length': group.block_length, 'fields': fields } @staticmethod - def makeDataDefinition(data: Data) -> dict: + def make_data_definition(data: Data) -> dict: return { 'token': 'data', 'name': data.name, 'id': data.id, 'description': data.description, - 'type': GeneratorBase.makeEncodedTypeDefinition(data.type), - 'semanticType': data.semanticType, - 'sinceVersion': data.sinceVersion, + 'type': GeneratorBase.make_encoded_type_definition(data.type), + 'semantic_type': data.semantic_type, + 'since_version': data.since_version, 'deprecated': data.deprecated } @staticmethod - def makeMessageDefinition(message: Message) -> dict: + def make_message_definition(message: Message) -> dict: fields = [] for field in message.fields.values(): - assert (isinstance(field, (Field, Group, Data))), "unknown message field" + assert isinstance(field, (Field, Group, Data)) entry = None if isinstance(field, Field): - entry = GeneratorBase.makeFieldDefinition(field) + entry = GeneratorBase.make_field_definition(field) elif isinstance(field, Group): - entry = GeneratorBase.makeGroupDefinition(field) + entry = GeneratorBase.make_group_definition(field) elif isinstance(field, Data): - entry = GeneratorBase.makeDataDefinition(field) + entry = GeneratorBase.make_data_definition(field) fields.append(entry) return { @@ -237,9 +221,9 @@ def makeMessageDefinition(message: Message) -> dict: 'name': message.name, 'id': message.id, 'description': message.description, - 'blockLength': message.blockLength, - 'semanticType': message.semanticType, - 'sinceVersion': message.sinceVersion, + 'block_length': message.block_length, + 'semantic_type': message.semantic_type, + 'since_version': message.since_version, 'deprecated': message.deprecated, 'fields': fields } diff --git a/app/parser.py b/app/parser.py index 7ab36d5..d6780e8 100644 --- a/app/parser.py +++ b/app/parser.py @@ -16,7 +16,7 @@ def __setitem__(self, key, value): class Parser: ''' Primitive types ''' - PrimitiveTypeByName = UniqueKeysDict({ + PRIMITIVE_TYPE_BY_NAME = UniqueKeysDict({ 'char': PrimitiveType('char', 1, "CHAR_NULL", "CHAR_MIN", "CHAR_MAX"), 'int8': PrimitiveType('int8', 1, "INT8_NULL", "INT8_MIN", "INT8_MAX"), 'int16': PrimitiveType('int16', 2, "INT16_NULL", "INT16_MIN", "INT16_MAX"), @@ -31,472 +31,447 @@ class Parser: }) ''' Primitive type names suitable for encodingType of enum ''' - ValidPrimitiveTypeForEnum = [ 'char', 'uint8', 'uint16', 'uint32', 'uint64' ] + VALID_PRIMITIVE_TYPE_FOR_ENUM = [ 'char', 'uint8', 'uint16', 'uint32', 'uint64' ] ''' Primitive type names suitable for encodingType of set ''' - ValidPrimitiveTypeForSet = [ 'uint8', 'uint16', 'uint32', 'uint64' ] + VALID_PRIMITIVE_TYPE_FOR_SET = [ 'uint8', 'uint16', 'uint32', 'uint64' ] def __init__(self, root: ET.Element) -> None: self.root = root @staticmethod - def fromFile(path: str) -> Parser: - root = loadXMLFromFile(path) + def from_file(path: str) -> Parser: + root = load_xml_from_file(path) return Parser(root) @staticmethod - def getPrimitiveType(name: str) -> PrimitiveType: - if name in Parser.PrimitiveTypeByName: - return Parser.PrimitiveTypeByName[name] + def get_primitive_type(name: str) -> PrimitiveType: + if name in Parser.PRIMITIVE_TYPE_BY_NAME: + return Parser.PRIMITIVE_TYPE_BY_NAME[name] else: raise Exception(f'primitive type "{name}" not found') - def getSchema(self) -> Schema: - headerTypeStr = attr(self.root, 'headerType', 'messageHeader') - headerType = self.getEncodedTypeByName(headerTypeStr) - if not isinstance(headerType, Composite) or not headerType.isValidHeaderType(): - raise Exception(f'type "{headerType}" is not valid header type') + def get_schema(self) -> Schema: + header_type_str = attr(self.root, 'headerType', 'messageHeader') + header_type = self.get_encoded_type_by_name(header_type_str) + if not isinstance(header_type, Composite) or not header_type.is_valid_header_type(): + raise Exception(f'type "{header_type_str}" is not valid header type') return Schema( - package = attr(self.root, 'package', default=None), - id = attr(self.root, 'id', cast=int), - version = attr(self.root, 'version', 0, cast=int), - semanticType = attr(self.root, 'semanticType', None), - byteOrder = attr(self.root, 'byteOrder', 'littleEndian', cast=ByteOrder), - description = attr(self.root, 'description', None), - headerType = headerType, - types = self.getTypes(), - messages = self.getMessages() + package=attr(self.root, 'package', default=None), + id=attr(self.root, 'id', cast=int), + version=attr(self.root, 'version', 0, cast=int), + semantic_type=attr(self.root, 'semanticType', None), + byte_order=attr(self.root, 'byteOrder', 'littleEndian', cast=ByteOrder), + description=attr(self.root, 'description', None), + header_type=header_type, + types=self.get_types(), + messages=self.get_messages() ) - def getTypes(self) -> Dict[str, EncodedType]: + def get_types(self) -> Dict[str, EncodedType]: types = UniqueKeysDict() - # add generic types - for primitiveType in Parser.PrimitiveTypeByName.values(): - type = self.getPrimitiveTypeAsEncodedType(primitiveType) - types[type.name] = type - + for primitive_type in Parser.PRIMITIVE_TYPE_BY_NAME.values(): + encoded_type = Parser.get_primitive_type_as_encoded_type(primitive_type) + types[encoded_type.name] = encoded_type # load types from xml for node in self.root.findall('./types/*'): - type = self.getEncodedType(node) - types[type.name] = type - + encoded_type = self.parse_encoded_type_from_node(node) + types[encoded_type.name] = encoded_type return types - def getMessages(self) -> Dict[str, Message]: - messageByName = UniqueKeysDict() - messageByID = UniqueKeysDict() + def get_messages(self) -> Dict[str, Message]: + message_by_name = UniqueKeysDict() + message_by_id = UniqueKeysDict() for child in self.root.findall('./message'): - message = self.getMessage(child) - messageByName[message.name] = message - messageByID[message.id] = message - return messageByName + message = self.parse_message_from_node(child) + message_by_name[message.name] = message + message_by_id[message.id] = message + return message_by_name @staticmethod - def getPrimitiveTypeAsEncodedType(primitiveType: PrimitiveType) -> Type: + def get_primitive_type_as_encoded_type(primitive_type: PrimitiveType) -> Type: return Type( - name = primitiveType.name, - description = None, - presence = Presence.REQUIRED, - nullValue = None, - minValue = None, - maxValue = None, - length = 1, - offset = None, - primitiveType = primitiveType, - semanticType = None, - sinceVersion = 0, - deprecated = None, - constValue = None + name=primitive_type.name, + description=None, + presence=Presence.REQUIRED, + null_value=None, + min_value=None, + max_value=None, + length=1, + offset=None, + primitive_type=primitive_type, + semantic_type=None, + since_version=0, + deprecated=None, + const_value=None ) - def getType(self, node: ET.Element, offset: Optional[int] = None) -> Type: - nameStr = attr(node, 'name') + def parse_type_from_node(self, node: ET.Element, offset: Optional[int] = None) -> Type: + name_str = attr(node, 'name') presence = attr(node, 'presence', Presence.REQUIRED, cast=Presence) length = attr(node, 'length', 1, cast=int) - primitiveType = Parser.getPrimitiveType(attr(node, 'primitiveType')) - valueRef = attr(node, 'valueRef', None) - constValue = None - - ''' - For presence=constant - constValue = node.text on valueRef not set - constValue = valueRef on valueRef set - ''' - if valueRef != None: + primitive_type = Parser.get_primitive_type(attr(node, 'primitiveType')) + value_ref = attr(node, 'valueRef', None) + const_value = None + + # For presence=constant + # constValue = node.text on valueRef not set + # constValue = valueRef on valueRef set + if value_ref != None: if presence != Presence.CONSTANT: - raise Exception(f'presence must be constant when valueRef is set (type "{nameStr}")') - if not self.isValidValueRef(valueRef): - raise Exception(f'valueRef "{valueRef}" of type "{nameStr}" is not valid') + raise Exception(f'presence must be constant when valueRef is set (type "{name_str}")') + if not self.is_valid_value_ref(value_ref): + raise Exception(f'valueRef "{value_ref}" of type "{name_str}" is not valid') if presence == Presence.CONSTANT: - if valueRef == None: - constValue = node.text.strip() - if constValue == '': - raise Exception(f'node text is empty and valueRef is not set for constant type "{nameStr}"') - if primitiveType.name == 'char' and len(constValue) != length: - raise Exception(f'node text length is not equal to field length for constant type "{nameStr}"') + if value_ref == None: + const_value = node.text.strip() + if const_value == '': + raise Exception(f'node text is empty and value_ref is not set for constant type "{name_str}"') + if primitive_type.name == 'char' and len(const_value) != length: + raise Exception(f'node text length is not equal to field length for constant type "{name_str}"') else: - enumName, enumValueName = valueRef.split('.') - enumType = self.getEncodedTypeByName(enumName) - assert (isinstance(enumType, Enum)), "not an enum type" - constValue = enumType.validValueByName[enumValueName].value - - characterEncoding = None - if primitiveType.name == 'char': - characterEncoding = attr(node, 'characterEncoding', "US-ASCII") + enum_name, enum_value_name = value_ref.split('.') + enum_type = self.get_encoded_type_by_name(enum_name) + if not isinstance(enum_type, Enum): + raise Exception(f'"{name_str}" is not enum type') + const_value = enum_type.valid_value_by_name[enum_value_name].value + + character_encoding = None + if primitive_type.name == 'char': + character_encoding = attr(node, 'characterEncoding', "US-ASCII") else: - characterEncoding = attr(node, 'characterEncoding', None) - if characterEncoding != None: - characterEncoding.strip() + character_encoding = attr(node, 'characterEncoding', None) + if character_encoding != None: + character_encoding.strip() return Type( - name = nameStr, - description = attr(node, 'description', None), - presence = presence, - nullValue = attr(node, 'nullValue', None), - minValue = attr(node, 'minValue', None), - maxValue = attr(node, 'maxValue', None), - length = length, - offset = attr(node, 'offset', offset, cast=int), - primitiveType = primitiveType, - semanticType = attr(node, 'semanticType', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - valueRef = valueRef, - constValue = constValue, - characterEncoding = characterEncoding + name=name_str, + description=attr(node, 'description', None), + presence=presence, + null_value=attr(node, 'nullValue', None), + min_value=attr(node, 'minValue', None), + max_value=attr(node, 'maxValue', None), + length=length, + offset=attr(node, 'offset', offset, cast=int), + primitive_type=primitive_type, + semantic_type=attr(node, 'semanticType', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + value_ref=value_ref, + const_value=const_value, + character_encoding=character_encoding ) - def getComposite(self, node: ET.Element, offset: Optional[int] = None) -> Composite: - nameStr = attr(node, 'name') - + def parse_composite_from_node(self, node: ET.Element, offset: Optional[int] = None) -> Composite: + name_str = attr(node, 'name') # used for compute offset for each type inside composite - computedOffset = 0 + computed_offset = 0 + contained_types = UniqueKeysDict() - containedTypes = UniqueKeysDict() for child in node: - type = None + contained_type = None if child.tag == 'type': - type = self.getType(child, offset=computedOffset) + contained_type = self.parse_type_from_node(child, offset=computed_offset) elif child.tag == 'composite': - type = self.getComposite(child, offset=computedOffset) + contained_type = self.parse_composite_from_node(child, offset=computed_offset) elif child.tag == 'enum': - type = self.getEnum(child, offset=computedOffset) + contained_type = self.parse_enum_from_node(child, offset=computed_offset) elif child.tag == 'set': - type = self.getSet(child, offset=computedOffset) + contained_type = self.parse_set_from_node(child, offset=computed_offset) elif child.tag == 'ref': - type = self.getRef(child, offset=computedOffset) + contained_type = self.parse_ref_from_node(child, offset=computed_offset) else: - raise Exception(f'unknown composite type "{nameStr}" child node "{child.tag}"') + raise Exception(f'unknown composite type "{name_str}" child node "{child.tag}"') - if computedOffset > type.offset: - raise Exception(f'invalid type offset "{type.name}" inside composite type "{nameStr}"') + if computed_offset > contained_type.offset: + raise Exception(f'invalid offset of type "{contained_type.name}" inside composite type "{name_str}"') - computedOffset = type.offset + type.encodedLength(); - containedTypes[type.name] = type + computed_offset = contained_type.offset + contained_type.encoded_length(); + contained_types[contained_type.name] = contained_type return Composite( - name = nameStr, - offset = attr(node, 'offset', offset, cast=int), - description = attr(node, 'description', None), - semanticType = attr(node, 'semanticType', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - containedTypes = containedTypes + name=name_str, + offset=attr(node, 'offset', offset, cast=int), + description=attr(node, 'description', None), + semantic_type=attr(node, 'semanticType', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + contained_types=contained_types ) - def getValidValue(self, node: ET.Element) -> ValidValue: + def parse_valid_value_from_node(self, node: ET.Element) -> ValidValue: return ValidValue( - name = attr(node, 'name'), - description = attr(node, 'description', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - value = node.text.strip() + name=attr(node, 'name'), + description=attr(node, 'description', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + value=node.text.strip() ) - def getEnum(self, node: ET.Element, offset: Optional[int] = None) -> Enum: - nameStr = attr(node, 'name') + def parse_enum_from_node(self, node: ET.Element, offset: Optional[int] = None) -> Enum: + name_str = attr(node, 'name') + valid_value_by_name = UniqueKeysDict() - validValueByName = UniqueKeysDict() for child in node: if child.tag == 'validValue': - validValue = self.getValidValue(child) - validValueByName[validValue.name] = validValue + valid_value = self.parse_valid_value_from_node(child) + valid_value_by_name[valid_value.name] = valid_value else: - raise Exception(f'unexpected tag "{child.tag}" inside enum "{nameStr}" ') + raise Exception(f'unexpected tag "{child.tag}" inside enum "{name_str}"') return Enum( - name = nameStr, - description = attr(node, 'description', None), - encodingType = self.getEncodingTypeForEnum(attr(node, 'encodingType')), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - offset = attr(node, 'offset', offset, cast=int), - nullValue = attr(node, 'nullValue', None), - validValueByName = validValueByName + name=name_str, + description=attr(node, 'description', None), + presence=attr(node, 'presence', Presence.REQUIRED, cast=Presence), + encoding_type=self.get_encoding_type_for_enum(attr(node, 'encodingType')), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + offset=attr(node, 'offset', offset, cast=int), + null_value=attr(node, 'nullValue', None), + valid_value_by_name=valid_value_by_name ) - def getChoice(self, node: ET.Element) -> Choice: + def parse_choice_from_node(self, node: ET.Element) -> Choice: return Choice( - name = attr(node, 'name'), - description = attr(node, 'description', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - value = node.text.strip() + name=attr(node, 'name'), + description=attr(node, 'description', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + value=node.text.strip() ) - def getSet(self, node: ET.Element, offset: Optional[int] = None) -> Set: - nameStr = attr(node, 'name') + def parse_set_from_node(self, node: ET.Element, offset: Optional[int] = None) -> Set: + name_str = attr(node, 'name') + choice_by_name = UniqueKeysDict() - choiceByName = UniqueKeysDict() for child in node: - if child.tag == 'choice': - choice = self.getChoice(child) - choiceByName[choice.name] = choice - else: - raise Exception(f'unexpected tag "{child.tag}" inside set "{nameStr}" ') + if child.tag != 'choice': + raise Exception(f'unexpected tag "{child.tag}" inside set "{name_str}" ') + choice = self.parse_choice_from_node(child) + choice_by_name[choice.name] = choice return Set( - name=nameStr, - description = attr(node, 'description', None), - encodingType = self.getEncodingTypeForSet(attr(node, 'encodingType')), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - offset = attr(node, 'offset', offset, cast=int), - choiceByName = choiceByName + name=name_str, + description=attr(node, 'description', None), + presence=attr(node, 'presence', Presence.REQUIRED, cast=Presence), + encoding_type=self.get_encoding_type_for_set(attr(node, 'encodingType')), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + offset=attr(node, 'offset', offset, cast=int), + choice_by_name=choice_by_name ) - def getRef(self, node: ET.Element, offset: Optional[int] = None) -> Ref: + def parse_ref_from_node(self, node: ET.Element, offset: Optional[int] = None) -> Ref: return Ref( - name = attr(node, 'name'), - type = self.getEncodedTypeByName(attr(node, 'type')), - offset = attr(node, 'offset', offset, cast=int), - description = attr(node, 'description', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), + name=attr(node, 'name'), + type=self.get_encoded_type_by_name(attr(node, 'type')), + offset=attr(node, 'offset', offset, cast=int), + description=attr(node, 'description', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), ) - def getMessage(self, node: ET.Element) -> Message: - nameStr = attr(node, 'name') - - computedOffset = 0 - groupEncountered = False - dataEncountered = False + def parse_message_from_node(self, node: ET.Element) -> Message: + name_str = attr(node, 'name') + computed_offset = 0 + group_encountered = False + data_encountered = False + field_by_name = UniqueKeysDict() + field_by_id = UniqueKeysDict() - fieldByName = UniqueKeysDict() - fieldByID = UniqueKeysDict() for child in node: field = None if child.tag == 'field': - if groupEncountered or dataEncountered: - raise Exception(f'field node specified after group or data node in message "{nameStr}"') - field = self.getField(child, offset=computedOffset) - - if computedOffset > field.offset: - raise Exception(f'invalid field offset "{field.name}" inside message "{nameStr}"') - computedOffset = field.offset + field.encodedLength() - + if group_encountered or data_encountered: + raise Exception(f'"field" specified after "group" or "data" node in message "{name_str}"') + field = self.parse_field_from_node(child, offset=computed_offset) + if computed_offset > field.offset: + raise Exception(f'invalid field offset "{field.name}" inside message "{name_str}"') + computed_offset = field.offset + field.encoded_length() elif child.tag == 'group': - if dataEncountered: - raise Exception(f'group node specified after data node in message "{nameStr}"') - field = self.getGroup(child) - groupEncountered = True + if data_encountered: + raise Exception(f'"group" specified after "data" in message "{name_str}"') + field = self.parse_group_from_node(child) + group_encountered = True elif child.tag == 'data': - field = self.getData(child) - dataEncountered = True + field = self.parse_data_from_node(child) + data_encountered = True else: - raise Exception(f'unknown message "{nameStr}" child node "{child.tag}"') + raise Exception(f'unknown message "{name_str}" child node "{child.tag}"') + field_by_name[field.name] = field + field_by_id[field.id] = field - fieldByName[field.name] = field - fieldByID[field.id] = field - - blockLength = attr(node, 'blockLength', computedOffset, cast=int) - if blockLength < computedOffset: - raise Exception(f'invalid blockLength value for message "{nameStr}"') + block_length = attr(node, 'blockLength', computed_offset, cast=int) + if block_length < computed_offset: + raise Exception(f'invalid blockLength value for message "{name_str}"') return Message( - name = nameStr, - id = attr(node, 'id', cast=int), - description = attr(node, 'description', None), - blockLength = blockLength, - semanticType = attr(node, 'semanticType', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int), - fields = fieldByName + name=name_str, + id=attr(node, 'id', cast=int), + description=attr(node, 'description', None), + block_length=block_length, + semantic_type=attr(node, 'semanticType', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int), + fields=field_by_name ) - def getField(self, node: ET.Element, offset: int) -> Field: - nameStr = attr(node, 'name') - type = self.getEncodedTypeByName(attr(node, 'type')) - presence = attr(node, 'presence', type.presence if isinstance(type, Type) else Presence.REQUIRED, cast=Presence) - valueRef = attr(node, 'valueRef', None) - - if valueRef != None and not self.isValidValueRef(valueRef): - raise Exception(f'valueRef "{valueRef}" of type "{nameStr}" is not valid') + def parse_field_from_node(self, node: ET.Element, offset: int) -> Field: + name_str = attr(node, 'name') + encoded_type = self.get_encoded_type_by_name(attr(node, 'type')) + presence = attr(node, 'presence', encoded_type.presence if isinstance(encoded_type, Type) else Presence.REQUIRED, cast=Presence) + value_ref = attr(node, 'valueRef', None) + if value_ref != None and not self.is_valid_value_ref(value_ref): + raise Exception(f'valueRef "{value_ref}" of type "{name_str}" is not valid') if presence == Presence.CONSTANT: - if isinstance(type, Enum): - if valueRef == None: - raise Exception(f'valueRef not set for constant enum field "{nameStr}"') - if not self.isValidValueRef(valueRef): - raise Exception(f'valueRef "{valueRef}" for type "{nameStr}" is not valid') - elif isinstance(type, Type): - if type.constValue == None: - raise Exception(f'constValue not set of type for field "{nameStr}"') + if isinstance(encoded_type, Enum): + if value_ref == None: + raise Exception(f'valueRef not set for constant enum field "{name_str}"') + if not self.is_valid_value_ref(value_ref): + raise Exception(f'valueRef "{value_ref}" for type "{name_str}" is not valid') + elif isinstance(encoded_type, Type): + if encoded_type.const_value == None: + raise Exception(f'"constValue" not set of type for field "{name_str}"') else: - raise Exception(f'field "{fieldNode}" is constant but encoding type is not enum or type') - - if isinstance(type, Set): + raise Exception(f'field "{name_str}" is constant but encoding type is not "enum" or "type"') + if isinstance(encoded_type, Set): if presence != Presence.REQUIRED: - raise Exception(f'field "{nameStr}" of type "{type.name}" should be required') - - if isinstance(type, Composite): + raise Exception(f'field "{name_str}" of type "{encoded_type.name}" should be required') + if isinstance(encoded_type, Composite): if presence == Presence.CONSTANT: - raise Exception(f'field "{nameStr}" of type "{type.name}" should not be constant') + raise Exception(f'field "{name_str}" of type "{encoded_type.name}" should not be constant') return Field( - name = nameStr, - id = attr(node, 'id', cast=int), - description = attr(node, 'description', None), - type = type, - offset = attr(node, 'offset', offset, cast=int), - presence = presence, - valueRef = valueRef, - semanticType = attr(node, 'semanticType', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int) + name=name_str, + id=attr(node, 'id', cast=int), + description=attr(node, 'description', None), + type=encoded_type, + offset=attr(node, 'offset', offset, cast=int), + presence=presence, + value_ref=value_ref, + semantic_type=attr(node, 'semanticType', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int) ) - def getGroup(self, node: ET.Element) -> Group: - nameStr = attr(node, 'name') + def parse_group_from_node(self, node: ET.Element) -> Group: + name_str = attr(node, 'name') + computed_offset = 0 + group_encountered = False + data_encountered = False + field_by_name = UniqueKeysDict() + field_by_id = UniqueKeysDict() - computedOffset = 0 - groupEncountered = False - dataEncountered = False - - fieldByName = UniqueKeysDict() - fieldByID = UniqueKeysDict() for child in node: field = None if child.tag == 'field': - if groupEncountered or dataEncountered: - raise Exception(f'field node specified after group or data node in group "{nameStr}"') - field = self.getField(child, offset=computedOffset) - - if computedOffset > field.offset: - raise Exception(f'invalid field offset "{field.name}" inside group "{nameStr}"') - computedOffset = field.offset + field.encodedLength() - + if group_encountered or data_encountered: + raise Exception(f' specified after or in group "{name_str}"') + field = self.parse_field_from_node(child, offset=computed_offset) + if computed_offset > field.offset: + raise Exception(f'invalid field offset of "{field.name}" inside group "{name_str}"') + computed_offset = field.offset + field.encoded_length() elif child.tag == 'group': - if dataEncountered: - raise Exception(f'group node specified after data node in group "{nameStr}"') - field = self.getGroup(child) - groupEncountered = True + if data_encountered: + raise Exception(f' specified after in group "{name_str}"') + field = self.parse_group_from_node(child) + group_encountered = True elif child.tag == 'data': - field = self.getData(child) - dataEncountered = True + field = self.parse_data_from_node(child) + data_encountered = True else: - raise Exception(f'unknown group "{nameStr}" child node "{child.tag}"') - - fieldByName[field.name] = field - fieldByID[field.id] = field - - blockLength = attr(node, 'blockLength', computedOffset, cast=int) - if blockLength < computedOffset: - raise Exception(f'invalid blockLength value for group "{nameStr}"') - - dimensionTypeStr = attr(node, 'dimensionType', 'groupSizeEncoding') - dimensionType = self.getEncodedTypeByName(dimensionTypeStr) - if not isinstance(dimensionType, Composite) or not dimensionType.isValidDimensionType(): - raise Exception(f'type "{dimensionTypeStr}" is not valid dimension type') + raise Exception(f'unknown child node "{child.tag}" in group "{name_str}"') + field_by_name[field.name] = field + field_by_id[field.id] = field + + block_length = attr(node, 'blockLength', computed_offset, cast=int) + if block_length < computed_offset: + raise Exception(f'invalid blockLength value for group "{name_str}"') + dimension_type_str = attr(node, 'dimensionType', 'groupSizeEncoding') + dimension_type = self.get_encoded_type_by_name(dimension_type_str) + if not isinstance(dimension_type, Composite) or not dimension_type.is_valid_dimension_type(): + raise Exception(f'type "{dimension_type_str}" is not valid dimension type') return Group( - name = nameStr, - id = attr(node, 'id', cast=int), - description = attr(node, 'description', None), - dimensionType = dimensionType, - blockLength = blockLength, - fields = fieldByName + name=name_str, + id=attr(node, 'id', cast=int), + description=attr(node, 'description', None), + dimension_type=dimension_type, + block_length=block_length, + fields=field_by_name ) - def getData(self, node: ET.Element) -> Data: - typeStr = attr(node, 'type') - type = self.getEncodedTypeByName(typeStr) - if not isinstance(type, Composite) or not type.isValidVariableLength(): - raise Exception(f'type "{typeStr}" is not valid type for data') + def parse_data_from_node(self, node: ET.Element) -> Data: + type_str = attr(node, 'type') + encoded_type = self.get_encoded_type_by_name(type_str) + if not isinstance(encoded_type, Composite) or not encoded_type.is_valid_variable_length(): + raise Exception(f'type "{type_str}" is not valid type for ') return Data( - name = attr(node, 'name'), - id = attr(node, 'id', cast=int), - description = attr(node, 'description', None), - type = type, - semanticType = attr(node, 'semanticType', None), - sinceVersion = attr(node, 'sinceVersion', 0, cast=int), - deprecated = attr(node, 'deprecated', None, cast=int) + name=attr(node, 'name'), + id=attr(node, 'id', cast=int), + description=attr(node, 'description', None), + type=encoded_type, + semantic_type=attr(node, 'semanticType', None), + since_version=attr(node, 'sinceVersion', 0, cast=int), + deprecated=attr(node, 'deprecated', None, cast=int) ) - def getEncodingTypeForEnum(self, encodingTypeStr: str) -> PrimitiveType: - if encodingTypeStr in self.ValidPrimitiveTypeForEnum: - return self.getPrimitiveType(encodingTypeStr) - - encodingTypeNode = self.root.find(f'.//types/type[@name="{encodingTypeStr}"]') - if encodingTypeNode == None: - raise Exception(f'encodingType "{encodingTypeStr}" for enum not found') - - encodingType = self.getType(encodingTypeNode) - primitiveType = encodingType.primitiveType - if primitiveType.name not in self.ValidPrimitiveTypeForEnum: - raise Exception(f'type "{encodingTypeStr}" is not suitable for enum encodingType') - - return primitiveType - - def getEncodingTypeForSet(self, encodingTypeStr: str) -> PrimitiveType: - if encodingTypeStr in self.ValidPrimitiveTypeForSet: - return self.getPrimitiveType(encodingTypeStr) - - encodingTypeNode = self.root.find(f'.//types/type[@name="{encodingTypeStr}"]') - if encodingTypeNode == None: - raise Exception(f'encodingType "{encodingTypeStr}" for set not found') - - encodingType = self.getType(encodingTypeNode) - primitiveType = encodingType.primitiveType - if primitiveType.name not in self.ValidPrimitiveTypeForSet: - raise Exception(f'type "{encodingTypeStr}" is not suitable for set encodingType') - - return primitiveType - - def getEncodedType(self, node: ET.Element) -> EncodedType: + def get_encoding_type_for_enum(self, encoding_type_str: str) -> PrimitiveType: + if encoding_type_str in Parser.VALID_PRIMITIVE_TYPE_FOR_ENUM: + return Parser.get_primitive_type(encoding_type_str) + encoding_type_node = self.root.find(f'.//types/type[@name="{encoding_type_str}"]') + if encoding_type_node == None: + raise Exception(f'encodingType "{encoding_type_str}" for not found') + encoding_type = self.parse_type_from_node(encoding_type_node) + primitive_type = encoding_type.primitive_type + if primitive_type.name not in Parser.VALID_PRIMITIVE_TYPE_FOR_ENUM: + raise Exception(f'type "{encoding_type_str}" is not valid for encodingType') + return primitive_type + + def get_encoding_type_for_set(self, encoding_type_str: str) -> PrimitiveType: + if encoding_type_str in Parser.VALID_PRIMITIVE_TYPE_FOR_SET: + return Parser.get_primitive_type(encoding_type_str) + encoding_type_node = self.root.find(f'.//types/type[@name="{encoding_type_str}"]') + if encoding_type_node == None: + raise Exception(f'encodingType "{encoding_type_str}" for not found') + encoding_type = self.parse_type_from_node(encoding_type_node) + primitive_type = encoding_type.primitive_type + if primitive_type.name not in Parser.VALID_PRIMITIVE_TYPE_FOR_SET: + raise Exception(f'type "{encoding_type_str}" is not valid for encodingType') + return primitive_type + + def parse_encoded_type_from_node(self, node: ET.Element) -> EncodedType: if node.tag == 'type': - return self.getType(node) + return self.parse_type_from_node(node) elif node.tag == 'composite': - return self.getComposite(node) + return self.parse_composite_from_node(node) elif node.tag == 'enum': - return self.getEnum(node) + return self.parse_enum_from_node(node) elif node.tag == 'set': - return self.getSet(node) + return self.parse_set_from_node(node) else: - raise Exception(f'unknown node type definition (node: "{node.tag}")') - - def getEncodedTypeByName(self, name: str) -> EncodedType: - ''' first check type exist in xml ''' - typeNode = self.root.find(f'.//types/*[@name="{name}"]') - if typeNode != None: - return self.getEncodedType(typeNode) - - ''' now check type is primitive type ''' - if name in Parser.PrimitiveTypeByName: - return self.getPrimitiveTypeAsEncodedType(Parser.PrimitiveTypeByName[name]) - - raise Exception(f'type "{name}" not found') - - ''' Return True on valueRef is valid and False otherwise ''' - def isValidValueRef(self, valueRef: str) -> bool: - enumName, enumValueName = valueRef.split('.') - enumType = self.getEncodedTypeByName(enumName) - if not isinstance(enumType, Enum): + raise Exception(f'unknown node type definition (node: "{node.tag}", line: {node.sourceline})') + + def get_encoded_type_by_name(self, name: str) -> EncodedType: + # first check type exist in xml + node = self.root.find(f'.//types/*[@name="{name}"]') + if node != None: + return self.parse_encoded_type_from_node(node) + # check type is primitive type + if name in Parser.PRIMITIVE_TYPE_BY_NAME: + return Parser.get_primitive_type_as_encoded_type(Parser.PRIMITIVE_TYPE_BY_NAME[name]) + raise Exception(f'encoded type "{name}" not found') + + def is_valid_value_ref(self, value_ref: str) -> bool: + enum_name, enum_value_name = value_ref.split('.') + enum_type = self.get_encoded_type_by_name(enum_name) + if not isinstance(enum_type, Enum): return False - if enumValueName not in enumType.validValueByName: + if enum_value_name not in enum_type.valid_value_by_name: return False return True diff --git a/app/schema.py b/app/schema.py index 9537d64..406459b 100644 --- a/app/schema.py +++ b/app/schema.py @@ -20,114 +20,113 @@ class ByteOrder(enum.Enum): class PrimitiveType: name: str = field(default_factory=str) size: int = field(default_factory=int) - nullValue: str = field(default_factory=str) - minValue: str = field(default_factory=str) - maxValue: str = field(default_factory=str) + null_value: str = field(default_factory=str) + min_value: str = field(default_factory=str) + max_value: str = field(default_factory=str) @dataclass(frozen=True) class Type: name: str = field(default_factory=str) description: Optional[str] = field(default=None) presence: Presence = field(default=Presence.REQUIRED) - nullValue: Optional[str] = field(default=None) - minValue: Optional[str] = field(default=None) - maxValue: Optional[str] = field(default=None) + null_value: Optional[str] = field(default=None) + min_value: Optional[str] = field(default=None) + max_value: Optional[str] = field(default=None) length: int = field(default=1) offset: Optional[int] = field(default=None) - primitiveType: str = field(default_factory=str) - semanticType: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + primitive_type: str = field(default_factory=str) + semantic_type: Optional[str] = field(default=None) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) - valueRef: Optional[str] = field(default=None) - constValue: Optional[str] = field(default=None) - characterEncoding: Optional[str] = field(default=None) + value_ref: Optional[str] = field(default=None) + const_value: Optional[str] = field(default=None) + character_encoding: Optional[str] = field(default=None) - def encodedLength(self) -> int: + def encoded_length(self) -> int: if self.presence == Presence.CONSTANT: return 0 else: - return self.length * self.primitiveType.size + return self.length * self.primitive_type.size @dataclass(frozen=True) class Composite: name: str = field(default_factory=str) offset: Optional[int] = field(default=None) description: Optional[str] = field(default=None) - semanticType: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + semantic_type: Optional[str] = field(default=None) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) - containedTypes: Dict[str, Union[Type, Composite, Enum, Set, Ref]] = field(default_factory=dict) + contained_types: Dict[str, Union[Type, Composite, Enum, Set, Ref]] = field(default_factory=dict) - def encodedLength(self) -> int: + def encoded_length(self) -> int: length = 0 - for type in self.containedTypes.values(): - assert (type.offset != None), "offset inside composite type must be present" - if type.offset != None: - length = type.offset - length += type.encodedLength() + for contained_type in self.contained_types.values(): + assert (contained_type.offset != None), "offset inside composite type must be present" + if contained_type.offset != None: + length = contained_type.offset + length += contained_type.encoded_length() return length ''' Find contained type by name. Return EncodedType on success and None otherwise ''' - def findType(self, name: str) -> Optional[EncodedType]: - return self.containedTypes[name] if name in self.containedTypes else None + def find_type(self, name: str) -> Optional[EncodedType]: + return self.contained_types[name] if name in self.contained_types else None ''' Return True on composite is valid dimension type ''' - def isValidDimensionType(self) -> bool: - if not self.findType('blockLength'): + def is_valid_dimension_type(self) -> bool: + if not self.find_type('blockLength'): return False - if not self.findType('numInGroup'): + if not self.find_type('numInGroup'): return False return True ''' Return True on composite is valid header type ''' - def isValidHeaderType(self) -> bool: - if not self.findType('blockLength'): + def is_valid_header_type(self) -> bool: + if not self.find_type('blockLength'): return False - if not self.findType('templateId'): + if not self.find_type('templateId'): return False - if not self.findType('schemaId'): + if not self.find_type('schemaId'): return False - if not self.findType('version'): + if not self.find_type('version'): return False return True ''' Return True on composite is valid variable length type ''' - def isValidVariableLength(self) -> bool: - lengthType = self.findType('length') - if lengthType == None: + def is_valid_variable_length(self) -> bool: + length_type = self.find_type('length') + if length_type == None: return False - if lengthType.primitiveType.name not in ('uint8', 'uint16', 'uint32', 'uint64'): + if length_type.primitive_type.name not in ('uint8', 'uint16', 'uint32', 'uint64'): return False - - varDataType = self.findType('varData') - if varDataType == None: + var_data_type = self.find_type('varData') + if var_data_type == None: return False - if varDataType.length != 0: + if var_data_type.length != 0: return False - if varDataType.primitiveType.name not in ('char', 'uint8'): + if var_data_type.primitive_type.name not in ('char', 'uint8'): return False - return True @dataclass(frozen=True) class Enum: name: str = field(default_factory=str) description: Optional[str] = field(default=None) - encodingType: PrimitiveType = field(default_factory=PrimitiveType) - sinceVersion: int = field(default=0) + presence: Presence = field(default=Presence.REQUIRED) + encoding_type: PrimitiveType = field(default_factory=PrimitiveType) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) offset: Optional[int] = field(default=None) - nullValue: Optional[str] = field(default=None) - validValueByName: Dict[str, ValidValue] = field(default_factory=dict) + null_value: Optional[str] = field(default=None) + valid_value_by_name: Dict[str, ValidValue] = field(default_factory=dict) - def encodedLength(self) -> int: - return self.encodingType.size + def encoded_length(self) -> int: + return self.encoding_type.size @dataclass(frozen=True) class ValidValue: name: str = field(default_factory=str) description: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) value: str = field(default_factory=str) @@ -135,20 +134,21 @@ class ValidValue: class Set: name: str = field(default_factory=str) description: Optional[str] = field(default=None) - encodingType: PrimitiveType = field(default_factory=PrimitiveType) - sinceVersion: int = field(default=0) + presence: Presence = field(default=Presence.REQUIRED) + encoding_type: PrimitiveType = field(default_factory=PrimitiveType) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) offset: Optional[int] = field(default=None) - choiceByName: Dict[str, Choice] = field(default_factory=dict) + choice_by_name: Dict[str, Choice] = field(default_factory=dict) - def encodedLength(self) -> int: - return self.encodingType.size + def encoded_length(self) -> int: + return self.encoding_type.size @dataclass(frozen=True) class Choice: name: str = field(default_factory=str) description: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) value: str = field(default_factory=str) @@ -158,20 +158,20 @@ class Ref: type: EncodedType = field(default=None) offset: Optional[int] = field(default=None) description: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) - def encodedLength(self) -> int: - return self.type.encodedLength() + def encoded_length(self) -> int: + return self.type.encoded_length() @dataclass(frozen=True) class Message: name: str = field(default_factory=str) id: int = field(default_factory=int) description: Optional[str] = field(default=None) - blockLength: Optional[int] = field(default=None) - semanticType: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + block_length: Optional[int] = field(default=None) + semantic_type: Optional[str] = field(default=None) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) fields: Dict[str, EncodedType] = field(default_factory=dict) @@ -183,23 +183,23 @@ class Field: type: EncodedType = field(default=None) offset: Optional[int] = field(default=None) presence: Presence = field(default=Presence.REQUIRED) - valueRef: Optional[str] = field(default=None) - semanticType: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + value_ref: Optional[str] = field(default=None) + semantic_type: Optional[str] = field(default=None) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) - def encodedLength(self) -> int: + def encoded_length(self) -> int: if self.presence == Presence.CONSTANT: return 0 - return self.type.encodedLength() + return self.type.encoded_length() @dataclass(frozen=True) class Group: name: str = field(default_factory=str) id: int = field(default_factory=int) description: Optional[str] = field(default=None) - dimensionType: Composite = field(default_factory=Composite) - blockLength: Optional[int] = field(default=None) + dimension_type: Composite = field(default_factory=Composite) + block_length: Optional[int] = field(default=None) fields: Dict[str, Union[Field, Group, Data]] = field(default_factory=dict) @dataclass(frozen=True) @@ -208,8 +208,8 @@ class Data: id: int = field(default_factory=int) description: Optional[str] = field(default=None) type: Composite = field(default_factory=Composite) - semanticType: Optional[str] = field(default=None) - sinceVersion: int = field(default=0) + semantic_type: Optional[str] = field(default=None) + since_version: int = field(default=0) deprecated: Optional[int] = field(default=None) @dataclass(frozen=True) @@ -217,10 +217,10 @@ class Schema: package: Optional[str] = field(default=None) id: int = field(default_factory=int) version: int = field(default=0) - semanticType: Optional[str] = field(default=None) - byteOrder: ByteOrder = field(default=ByteOrder.LITTLE_ENDIAN) + semantic_type: Optional[str] = field(default=None) + byte_order: ByteOrder = field(default=ByteOrder.LITTLE_ENDIAN) description: Optional[str] = field(default=None) - headerType: Composite = field(default_factory=Composite) + header_type: Composite = field(default_factory=Composite) types: Dict[str, EncodedType] = field(default_factory=dict) messages: Dict[str, Message] = field(default_factory=dict) diff --git a/app/xml.py b/app/xml.py index 05b5b13..7dafdb3 100644 --- a/app/xml.py +++ b/app/xml.py @@ -6,17 +6,17 @@ from typing import ClassVar, Optional, Any class SentinelClass: - _instance: ClassVar[Optional[SentinelClass]] = None + instance_: ClassVar[Optional[SentinelClass]] = None @staticmethod def getInstance() -> SentinelClass: - if SentinelClass._instance is None: - SentinelClass._instance = SentinelClass() - return SentinelClass._instance + if SentinelClass.instance_ is None: + SentinelClass.instance_ = SentinelClass() + return SentinelClass.instance_ SENTINEL = SentinelClass.getInstance() -def loadXMLFromFile(path: str) -> ET.Element: +def load_xml_from_file(path: str) -> ET.Element: file = open(path, 'r', encoding='utf-8') it = ET.iterparse(file)