From 7944f6e75955f2f2a75a4c8e1892e1c52bb83ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 12 Oct 2024 13:54:34 +0200 Subject: [PATCH 01/23] Fix some attribute types in classes DiagramObjectGluePoint, VCompIEEEType2, WindContPType3IEC for cpp and modernpython MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 67813dd..155c6a3 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -8,6 +8,7 @@ import xmltodict from bs4 import BeautifulSoup +logging.basicConfig(level=logging.WARNING) logger = logging.getLogger(__name__) @@ -249,6 +250,7 @@ def subClasses(self): def setSubClasses(self, classes): self.subclasses = classes + @staticmethod def _simple_float_attribute(attr): if "dataType" in attr: return attr["label"] == "value" and attr["dataType"] == "#Float" @@ -856,7 +858,7 @@ def _get_attribute_type(attribute: dict, is_an_enum_class: bool) -> str: attribute_type = "primitive" elif is_an_enum_class: attribute_type = "enum" - elif attribute.get("multiplicity") in ("M:0..n", "M:1..n"): + elif attribute.get("multiplicity") in ("M:0..n", "M:1..n", "M:2..n"): attribute_type = "list" return attribute_type From 3b6e9d2260909e0fc3f65a328a07faec8559bc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 12 Oct 2024 14:19:50 +0200 Subject: [PATCH 02/23] Add class property "is_a_primitive_class" and attribute property "is_primitive_float_attribute" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 9 +++++++-- cimgen/languages/cpp/lang_pack.py | 6 +----- cimgen/languages/java/lang_pack.py | 6 +----- cimgen/languages/javascript/lang_pack.py | 2 ++ cimgen/languages/modernpython/lang_pack.py | 2 ++ cimgen/languages/python/lang_pack.py | 2 ++ 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 155c6a3..6d32e9b 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -211,6 +211,7 @@ def __init__(self, rdfsEntry): self.origin_list = [] self.super = rdfsEntry.subClassOf() self.subclasses = [] + self.stereotype = rdfsEntry.stereotype() def attributes(self): return self.attribute_list @@ -282,6 +283,9 @@ def is_a_float_class(self): return False return True + def is_a_primitive_class(self): + return self.stereotype == "Primitive" + def get_profile_name(descriptions): for list_elem in descriptions: @@ -382,8 +386,7 @@ def _add_class(classes_map, rdfs_entry): """ if rdfs_entry.label() in classes_map: logger.error("Class {} already exists".format(rdfs_entry.label())) - if rdfs_entry.label() != "String": - classes_map[rdfs_entry.label()] = CIMComponentDefinition(rdfs_entry) + classes_map[rdfs_entry.label()] = CIMComponentDefinition(rdfs_entry) def _add_profile_to_packages(profile_name, short_profile_name, profile_uri_list): @@ -481,6 +484,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): "enum_instances": elem_dict[class_name].enum_instances(), "is_an_enum_class": elem_dict[class_name].is_an_enum_class(), "is_a_float_class": elem_dict[class_name].is_a_float_class(), + "is_a_primitive_class": elem_dict[class_name].is_a_primitive_class(), "langPack": lang_pack, "sub_class_of": elem_dict[class_name].superClass(), "sub_classes": elem_dict[class_name].subClasses(), @@ -514,6 +518,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): attribute["is_enum_attribute"] = _get_bool_string(attribute_type == "enum") attribute["is_list_attribute"] = _get_bool_string(attribute_type == "list") attribute["is_primitive_attribute"] = _get_bool_string(attribute_type == "primitive") + attribute["is_primitive_float_attribute"] = _get_bool_string(elem_dict[attribute_class].is_a_float_class()) attribute["attribute_class"] = attribute_class class_details["attributes"].sort(key=lambda d: d["label"]) diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 09d73a9..1c548ad 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -63,11 +63,7 @@ def run_template(output_path, class_details): else: templates = template_files - if ( - class_details["class_name"] == "Integer" - or class_details["class_name"] == "Boolean" - or class_details["class_name"] == "Date" - ): + if class_details["class_name"] in ("String", "Integer", "Boolean", "Date"): # These classes are defined already # We have to implement operators for them return diff --git a/cimgen/languages/java/lang_pack.py b/cimgen/languages/java/lang_pack.py index fd671f0..fa47d30 100644 --- a/cimgen/languages/java/lang_pack.py +++ b/cimgen/languages/java/lang_pack.py @@ -57,11 +57,7 @@ def run_template(output_path, class_details): else: templates = template_files - if ( - class_details["class_name"] == "Integer" - or class_details["class_name"] == "Boolean" - or class_details["class_name"] == "Date" - ): + if class_details["class_name"] in ("String", "Integer", "Boolean", "Date"): # These classes are defined already # We have to implement operators for them return diff --git a/cimgen/languages/javascript/lang_pack.py b/cimgen/languages/javascript/lang_pack.py index f216816..a0e1596 100644 --- a/cimgen/languages/javascript/lang_pack.py +++ b/cimgen/languages/javascript/lang_pack.py @@ -102,6 +102,8 @@ def select_primitive_render_function(class_details): # This is the function that runs the template. def run_template(output_path, class_details): + if class_details["class_name"] == "String": + return for index, attribute in enumerate(class_details["attributes"]): if not attribute["is_used"]: diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index c4f9e83..1f321f0 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -82,6 +82,8 @@ def _get_type_and_default(text, renderer) -> tuple[str, str]: def run_template(output_path, class_details): + if class_details["class_name"] == "String": + return for template_info in template_files: resource_file = Path( os.path.join( diff --git a/cimgen/languages/python/lang_pack.py b/cimgen/languages/python/lang_pack.py index 08167e0..a5af5ab 100644 --- a/cimgen/languages/python/lang_pack.py +++ b/cimgen/languages/python/lang_pack.py @@ -74,6 +74,8 @@ def _set_default(text, render): def run_template(output_path, class_details): + if class_details["class_name"] == "String": + return for template_info in template_files: class_file = os.path.join(output_path, class_details["class_name"] + template_info["ext"]) _write_templated_file(class_file, class_details, template_info["filename"]) From bded89c6db19288406819eedcc005ca1bfbcb4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 12:48:33 +0200 Subject: [PATCH 03/23] Fix type and default of some attributes for modernpython (for enums and attribute types Date, DateTime, MonthDay, Status, StreetAddress, StreetDetail, TownDetail) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 20 +++--------- cimgen/languages/modernpython/lang_pack.py | 31 +++++++------------ .../templates/cimpy_class_template.mustache | 4 +-- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 6d32e9b..afa6495 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -512,8 +512,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): subsequent_indent=" " * 6, ) attribute_class = _get_attribute_class(attribute) - is_an_enum_class = attribute_class in elem_dict and elem_dict[attribute_class].is_an_enum_class() - attribute_type = _get_attribute_type(attribute, is_an_enum_class) + attribute_type = _get_attribute_type(attribute, elem_dict[attribute_class]) attribute["is_class_attribute"] = _get_bool_string(attribute_type == "class") attribute["is_enum_attribute"] = _get_bool_string(attribute_type == "enum") attribute["is_list_attribute"] = _get_bool_string(attribute_type == "list") @@ -842,26 +841,17 @@ def _get_attribute_class(attribute: dict) -> str: return _get_rid_of_hash(name) -def _get_attribute_type(attribute: dict, is_an_enum_class: bool) -> str: +def _get_attribute_type(attribute: dict, class_infos: CIMComponentDefinition) -> str: """Get the type of an attribute: "class", "enum", "list", or "primitive". :param attribute: Dictionary with information about an attribute of a class. - :param is_an_enum_class: Is this attribute an enumation? + :param class_infos: Information about the attribute class. :return: Type of the attribute. """ - so_far_not_primitive = _get_attribute_class(attribute) in ( - "Date", - "DateTime", - "MonthDay", - "Status", - "StreetAddress", - "StreetDetail", - "TownDetail", - ) attribute_type = "class" - if "dataType" in attribute and not so_far_not_primitive: + if class_infos.is_a_primitive_class() or class_infos.is_a_float_class(): attribute_type = "primitive" - elif is_an_enum_class: + elif class_infos.is_an_enum_class(): attribute_type = "enum" elif attribute.get("multiplicity") in ("M:0..n", "M:1..n", "M:2..n"): attribute_type = "list" diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 1f321f0..52f8eef 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -47,7 +47,7 @@ def get_class_location(class_name, class_map, version): # NOSONAR partials = {} -# called by chevron, text contains the label {{dataType}}, which is evaluated by the renderer (see class template) +# called by chevron, text contains the attribute infos, which are evaluated by the renderer (see class template) def _set_default(text, render): return _get_type_and_default(text, render)[1] @@ -56,29 +56,22 @@ def _set_type(text, render): return _get_type_and_default(text, render)[0] -def _get_type_and_default(text, renderer) -> tuple[str, str]: - result = renderer(text) - # the field {{dataType}} either contains the multiplicity of an attribute if it is a reference or otherwise the - # datatype of the attribute. If no datatype is set and there is also no multiplicity entry for an attribute, the - # default value is set to None. The multiplicity is set for all attributes, but the datatype is only set for basic - # data types. If the data type entry for an attribute is missing, the attribute contains a reference and therefore - # the default value is either None or [] depending on the multiplicity. See also write_python_files - # The default will be copied as-is, hence the possibility to have default or default_factory. - if result in ["M:1", "M:0..1", "M:1..1", ""]: +def _get_type_and_default(text, render) -> tuple[str, str]: + attribute_txt = render(text) + attribute_json = eval(attribute_txt) + if attribute_json["is_class_attribute"]: return ("Optional[str]", "default=None") - elif result in ["M:0..n", "M:1..n"] or "M:" in result: + elif attribute_json["is_list_attribute"]: return ("list", "default_factory=list") - - result = result.split("#")[1] - if result in ["integer", "Integer"]: + elif attribute_json["is_primitive_float_attribute"]: + return ("float", "default=0.0") + elif attribute_json["attribute_class"] == "Integer": return ("int", "default=0") - elif result in ["String", "DateTime", "Date"]: - return ("str", 'default=""') - elif result == "Boolean": + elif attribute_json["attribute_class"] == "Boolean": return ("bool", "default=False") else: - # everything else should be a float - return ("float", "default=0.0") + # everything else should be a string + return ("str", 'default=""') def run_template(output_path, class_details): diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index 08e125d..e6e9491 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -23,8 +23,8 @@ class {{class_name}}({{sub_class_of}}): """ {{#attributes}} - {{label}}: {{#setType}}{{dataType}}{{/setType}} = Field( - {{#setDefault}}{{dataType}}{{/setDefault}}, + {{label}}: {{#setType}}{{.}}{{/setType}} = Field( + {{#setDefault}}{{.}}{{/setDefault}}, json_schema_extra={ "in_profiles": [ {{#attr_origin}} From 037dc1c45b9d3218025a67ca5835d361a297ca7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 13:15:36 +0200 Subject: [PATCH 04/23] Fix handling of Decimal as float class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index afa6495..97bbd01 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -258,7 +258,7 @@ def _simple_float_attribute(attr): return False def is_a_float_class(self): - if self.about == "Float": + if self.about in ("Float", "Decimal"): return True simple_float = False for attr in self.attribute_list: From 08dfa2e720854cca4356fa2dfed0b70d99b18420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 13:33:41 +0200 Subject: [PATCH 05/23] Remove generation of unused classes for modernpython MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/modernpython/lang_pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 52f8eef..d25f903 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -75,7 +75,7 @@ def _get_type_and_default(text, render) -> tuple[str, str]: def run_template(output_path, class_details): - if class_details["class_name"] == "String": + if class_details["is_a_primitive_class"] or class_details["is_a_float_class"]: return for template_info in template_files: resource_file = Path( From 4ad48d7223f9bf3f0b015b3f1a9ea63b2cfc4bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 18:40:24 +0200 Subject: [PATCH 06/23] Improve setting of long profile names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 77 +++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 97bbd01..55b3b41 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -287,22 +287,6 @@ def is_a_primitive_class(self): return self.stereotype == "Primitive" -def get_profile_name(descriptions): - for list_elem in descriptions: - # only for CGMES-Standard - rdfsEntry = RDFSEntry(list_elem) - if rdfsEntry.stereotype() == "Entsoe": - return rdfsEntry.about() - - -def get_short_profile_name(descriptions): - for list_elem in descriptions: - # only for CGMES-Standard - rdfsEntry = RDFSEntry(list_elem) - if rdfsEntry.label() == "shortName": - return rdfsEntry.fixed() - - def wrap_and_clean(txt: str, width: int = 120, initial_indent="", subsequent_indent=" ") -> str: """ Used for comments: make them fit within character, including indentation. @@ -325,9 +309,9 @@ def wrap_and_clean(txt: str, width: int = 120, initial_indent="", subsequent_ind short_package_name = {} +long_profile_names = {} package_listed_by_short_name = {} cim_namespace = "" -profiles = {} def _rdfs_entry_types(rdfs_entry: RDFSEntry, version) -> list: @@ -389,23 +373,21 @@ def _add_class(classes_map, rdfs_entry): classes_map[rdfs_entry.label()] = CIMComponentDefinition(rdfs_entry) -def _add_profile_to_packages(profile_name, short_profile_name, profile_uri_list): +def _add_profile_to_packages(profile_name: str, short_profile_name: str, profile_uri_list: list[str]) -> None: """ - Add profile_uris + Add profile_uris and set long profile_name. """ - if profile_name not in profiles and profile_uri_list: - profiles[profile_name] = profile_uri_list - else: - profiles[profile_name].extend(profile_uri_list) - if short_profile_name not in package_listed_by_short_name and profile_uri_list: - package_listed_by_short_name[short_profile_name] = profile_uri_list - else: - package_listed_by_short_name[short_profile_name].extend(profile_uri_list) + uri_list = package_listed_by_short_name.setdefault(short_profile_name, []) + for uri in profile_uri_list: + if uri not in uri_list: + uri_list.append(uri) + long_profile_names[short_profile_name] = profile_name.removesuffix("Version").removesuffix("Profile") def _parse_rdf(input_dic, version): # NOSONAR classes_map = {} profile_name = "" + short_profile_name = "" profile_uri_list = [] attributes = [] enum_instances = [] @@ -429,22 +411,24 @@ def _parse_rdf(input_dic, version): # NOSONAR attributes.append(object_dic) if "rest_non_class_category" in rdfs_entry_types: enum_instances.append(object_dic) - if "profile_name_v2_4" in rdfs_entry_types: - profile_name = rdfsEntry.about() - if "profile_name_v3" in rdfs_entry_types: - profile_name = rdfsEntry.label() - if "short_profile_name_v2_4" in rdfs_entry_types and rdfsEntry.fixed(): - short_profile_name = rdfsEntry.fixed() - if "short_profile_name_v3" in rdfs_entry_types: - short_profile_name = rdfsEntry.keyword() + if not profile_name: + if "profile_name_v2_4" in rdfs_entry_types: + profile_name = rdfsEntry.about() + if "profile_name_v3" in rdfs_entry_types: + profile_name = rdfsEntry.label() + if not short_profile_name: + if "short_profile_name_v2_4" in rdfs_entry_types and rdfsEntry.fixed(): + short_profile_name = rdfsEntry.fixed() + if "short_profile_name_v3" in rdfs_entry_types: + short_profile_name = rdfsEntry.keyword() if "profile_iri_v2_4" in rdfs_entry_types and rdfsEntry.fixed(): profile_uri_list.append(rdfsEntry.fixed()) if "profile_iri_v3" in rdfs_entry_types: profile_uri_list.append(rdfsEntry.version_iri()) short_package_name[profile_name] = short_profile_name - package_listed_by_short_name[short_profile_name] = [] _add_profile_to_packages(profile_name, short_profile_name, profile_uri_list) + # Add attributes to corresponding class for attribute in attributes: clarse = attribute["domain"] @@ -746,32 +730,13 @@ def _get_profile_details(cgmes_profile_uris): profile_info = { "index": index, "short_name": profile, - "long_name": _extract_profile_long_name(cgmes_profile_uris[profile]), + "long_name": long_profile_names[profile], "uris": [{"uri": uri} for uri in cgmes_profile_uris[profile]], } profile_details.append(profile_info) return profile_details -def _extract_profile_long_name(profile_uris): - # Extract name from uri, e.g. "Topology" from "http://iec.ch/TC57/2013/61970-456/Topology/4" - # Examples of other possible uris: "http://entsoe.eu/CIM/Topology/4/1", "http://iec.ch/TC57/ns/CIM/Topology-EU/3.0" - # If more than one uri given, extract common part (e.g. "Equipment" from "EquipmentCore" and "EquipmentOperation") - long_name = "" - for uri in profile_uris: - match = re.search(r"/([^/-]*)(-[^/]*)?(/\d+)?/[\d.]+?$", uri) - if match: - name = match.group(1) - if long_name: - for idx in range(1, len(long_name)): - if idx >= len(name) or long_name[idx] != name[idx]: - long_name = long_name[:idx] - break - else: - long_name = name - return long_name - - def _get_sorted_profile_keys(profile_key_list): """Sort profiles alphabetically, but "EQ" to the first place. From ac487b34a008e7395da4438ad900c56b98c385c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 18:44:31 +0200 Subject: [PATCH 07/23] Refactor _merge_profiles and _merge_classes in cimgen.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 134 ++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 90 deletions(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 55b3b41..0855b82 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -216,7 +216,7 @@ def __init__(self, rdfsEntry): def attributes(self): return self.attribute_list - def addAttribute(self, attribute): + def add_attribute(self, attribute): self.attribute_list.append(attribute) def is_an_enum_class(self): @@ -229,10 +229,6 @@ def add_enum_instance(self, instance): instance["index"] = len(self.enum_instance_list) self.enum_instance_list.append(instance) - def addAttributes(self, attributes): - for attribute in attributes: - self.attribute_list.append(attribute) - def origins(self): return self.origin_list @@ -308,7 +304,6 @@ def wrap_and_clean(txt: str, width: int = 120, initial_indent="", subsequent_ind ) -short_package_name = {} long_profile_names = {} package_listed_by_short_name = {} cim_namespace = "" @@ -426,14 +421,13 @@ def _parse_rdf(input_dic, version): # NOSONAR if "profile_iri_v3" in rdfs_entry_types: profile_uri_list.append(rdfsEntry.version_iri()) - short_package_name[profile_name] = short_profile_name _add_profile_to_packages(profile_name, short_profile_name, profile_uri_list) # Add attributes to corresponding class for attribute in attributes: clarse = attribute["domain"] if clarse and classes_map[clarse]: - classes_map[clarse].addAttribute(attribute) + classes_map[clarse].add_attribute(attribute) else: logger.info("Class {} for attribute {} not found.".format(clarse, attribute)) @@ -461,7 +455,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): for class_name in elem_dict.keys(): class_details = { - "attributes": _find_multiple_attributes(elem_dict[class_name].attributes()), + "attributes": elem_dict[class_name].attributes(), "class_location": lang_pack.get_class_location(class_name, elem_dict, version), "class_name": class_name, "class_origin": elem_dict[class_name].origins(), @@ -541,20 +535,6 @@ def _write_files(class_details, output_path, version): class_details["langPack"].run_template(output_path, class_details) -# Find multiple entries for the same attribute -def _find_multiple_attributes(attributes_array): - merged_attributes = [] - for elem in attributes_array: - found = False - for i in range(len(merged_attributes)): - if elem["label"] == merged_attributes[i]["label"]: - found = True - break - if found is False: - merged_attributes.append(elem) - return merged_attributes - - # If multiple CGMES schema files for one profile are read, e.g. Equipment Core and Equipment Core Short Circuit # this function merges these into one profile, e.g. Equipment, after this function only one dictionary entry for each # profile exists. The profiles_array contains one entry for each CGMES schema file which was read. @@ -563,21 +543,21 @@ def _merge_profiles(profiles_array): # Iterate through array elements for elem_dict in profiles_array: # Iterate over profile names - for profile_key in elem_dict.keys(): - if profile_key in profiles_dict.keys(): - # Iterate over classes and check for multiple class definitions - for class_key in elem_dict[profile_key]: - if class_key in profiles_dict[profile_key].keys(): - # If class already exists in packageDict add attributes to attributes array - if len(elem_dict[profile_key][class_key].attributes()) > 0: - attributes_array = elem_dict[profile_key][class_key].attributes() - profiles_dict[profile_key][class_key].addAttributes(attributes_array) - # If class is not in packageDict, create entry - else: - profiles_dict[profile_key][class_key] = elem_dict[profile_key][class_key] - # If package name not in packageDict create entry - else: - profiles_dict[profile_key] = elem_dict[profile_key] + for profile_key, new_class_dict in elem_dict.items(): + class_dict = profiles_dict.setdefault(profile_key, {}) + # Iterate over classes and check for multiple class definitions + for class_key, new_class_infos in new_class_dict.items(): + if class_key in class_dict: + class_infos = class_dict[class_key] + for new_attr in new_class_infos.attributes(): + # Iterate over attributes and check for multiple attribute definitions + for attr in class_infos.attributes(): + if new_attr["label"] == attr["label"]: + break + else: + class_infos.add_attribute(new_attr) + else: + class_dict[class_key] = new_class_infos return profiles_dict @@ -586,63 +566,37 @@ def _merge_profiles(profiles_array): # the possibleProfileList used for the serialization. def _merge_classes(profiles_dict): class_dict = {} - # Iterate over profiles - for package_key in profiles_dict.keys(): - # get short name of the profile - short_name = "" - if package_key in short_package_name: - short_name = short_package_name[package_key] - else: - short_name = package_key - + for profile_key, new_class_dict in profiles_dict.items(): + origin = {"origin": profile_key} # iterate over classes in the current profile - for class_key in profiles_dict[package_key]: - # class already defined? - if class_key not in class_dict: - # store class and class origin - class_dict[class_key] = profiles_dict[package_key][class_key] - class_dict[class_key].addOrigin({"origin": short_name}) - for attr in class_dict[class_key].attributes(): - # store origin of the attributes - attr["attr_origin"] = [{"origin": short_name}] - else: + for class_key, new_class_infos in new_class_dict.items(): + if class_key in class_dict: + class_infos = class_dict[class_key] # some inheritance information is stored only in one of the packages. Therefore it has to be checked # if the subClassOf attribute is set. See for example TopologicalNode definitions in SV and TP. - if not class_dict[class_key].superClass(): - if profiles_dict[package_key][class_key].superClass(): - class_dict[class_key].super = profiles_dict[package_key][class_key].superClass() - - # check if profile is already stored in class origin list - multiple_origin = False - for origin in class_dict[class_key].origins(): - if short_name == origin["origin"]: - # origin already stored - multiple_origin = True - break - if not multiple_origin: - class_dict[class_key].addOrigin({"origin": short_name}) - - for attr in profiles_dict[package_key][class_key].attributes(): - # check if attribute is already in attributes list - multiple_attr = False - for attr_set in class_dict[class_key].attributes(): - if attr["label"] == attr_set["label"]: + if not class_infos.superClass(): + class_infos.super = new_class_infos.superClass() + if origin not in class_infos.origins(): + class_infos.addOrigin(origin) + for new_attr in new_class_infos.attributes(): + for attr in class_infos.attributes(): + if attr["label"] == new_attr["label"]: # attribute already in attributes list, check if origin is new - multiple_attr = True - for origin in attr_set["attr_origin"]: - multiple_attr_origin = False - if origin["origin"] == short_name: - multiple_attr_origin = True - break - if not multiple_attr_origin: - # new origin - attr_set["attr_origin"].append({"origin": short_name}) + origin_list = attr["attr_origin"] + if origin not in origin_list: + origin_list.append(origin) break - if not multiple_attr: + else: # new attribute - attr["attr_origin"] = [{"origin": short_name}] - class_dict[class_key].addAttribute(attr) + new_attr["attr_origin"] = [origin] + class_infos.add_attribute(new_attr) + else: + # store new class and origin + new_class_infos.addOrigin(origin) + for attr in new_class_infos.attributes(): + attr["attr_origin"] = [origin] + class_dict[class_key] = new_class_infos return class_dict @@ -710,7 +664,7 @@ def cim_generate(directory, output_path, version, lang_pack): superClass = class_dict_with_origins[superClassName] superClass.addSubClass(className) else: - print("No match for superClass in dict: :", superClassName) + logger.error("No match for superClass in dict: %s", superClassName) # recursively add the subclasses of subclasses addSubClassesOfSubClasses(class_dict_with_origins) @@ -777,7 +731,7 @@ def _get_recommended_class_profiles(elem_dict): profile_count_map = {} name = class_name while name: - for attribute in _find_multiple_attributes(elem_dict[name].attributes()): + for attribute in elem_dict[name].attributes(): profiles = [origin["origin"] for origin in attribute["attr_origin"]] ambiguous_profile = len(profiles) > 1 for profile in profiles: From 4ce0983962d17b31cc9c3ac9ed26ed791bdf6964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 13 Oct 2024 18:46:03 +0200 Subject: [PATCH 08/23] Fix attribute type of TieFlow in class Terminal for cpp and modernpython MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 0855b82..49e7795 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -772,7 +772,7 @@ def _get_attribute_type(attribute: dict, class_infos: CIMComponentDefinition) -> attribute_type = "primitive" elif class_infos.is_an_enum_class(): attribute_type = "enum" - elif attribute.get("multiplicity") in ("M:0..n", "M:1..n", "M:2..n"): + elif attribute.get("multiplicity") in ("M:0..n", "M:0..2", "M:1..n", "M:2..n"): attribute_type = "list" return attribute_type From 7c3a497178ee3cf9cd2a077f2dc096614c849f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 19 Oct 2024 12:12:42 +0200 Subject: [PATCH 09/23] Add generation of string classes for cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/lang_pack.py | 9 ++- .../cpp_string_header_template.mustache | 38 ++++++++++++ .../cpp_string_object_template.mustache | 62 +++++++++++++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 cimgen/languages/cpp/templates/cpp_string_header_template.mustache create mode 100644 cimgen/languages/cpp/templates/cpp_string_object_template.mustache diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 1c548ad..38e3d16 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -39,6 +39,10 @@ def setup(output_path: str, cgmes_profile_details: list, cim_namespace: str): # {"filename": "cpp_enum_header_template.mustache", "ext": ".hpp"}, {"filename": "cpp_enum_object_template.mustache", "ext": ".cpp"}, ] +string_template_files = [ + {"filename": "cpp_string_header_template.mustache", "ext": ".hpp"}, + {"filename": "cpp_string_object_template.mustache", "ext": ".cpp"}, +] def get_class_location(class_name, class_map, version): # NOSONAR @@ -60,10 +64,12 @@ def run_template(output_path, class_details): templates = float_template_files elif class_details["is_an_enum_class"]: templates = enum_template_files + elif class_details["is_a_primitive_class"]: + templates = string_template_files else: templates = template_files - if class_details["class_name"] in ("String", "Integer", "Boolean", "Date"): + if class_details["class_name"] in ("Integer", "Boolean"): # These classes are defined already # We have to implement operators for them return @@ -364,7 +370,6 @@ def set_default(dataType): "Factory", "Folders", "IEC61970", - "String", "Task", "UnknownType", ] diff --git a/cimgen/languages/cpp/templates/cpp_string_header_template.mustache b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache new file mode 100644 index 0000000..9a0de1a --- /dev/null +++ b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache @@ -0,0 +1,38 @@ +#ifndef {{class_name}}_H +#define {{class_name}}_H +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ + +#include +#include + +#include "BaseClass.hpp" + +namespace CIMPP +{ + class {{class_name}} : public BaseClass + { + public: + {{class_name}}(); + {{class_name}}(std::string value); + ~{{class_name}}() override; + {{class_name}}& operator=(std::string &rop); + operator std::string(); + + std::string value; + bool initialized = false; + + static const char debugName[]; + const char* debugString() const override; + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + static const BaseClassDefiner declare(); + + friend std::istream& operator>>(std::istream& lop, {{class_name}}& rop); + friend std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj); + }; +} +#endif diff --git a/cimgen/languages/cpp/templates/cpp_string_object_template.mustache b/cimgen/languages/cpp/templates/cpp_string_object_template.mustache new file mode 100644 index 0000000..865a271 --- /dev/null +++ b/cimgen/languages/cpp/templates/cpp_string_object_template.mustache @@ -0,0 +1,62 @@ +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ +#include "{{class_name}}.hpp" + +#include "CIMExceptions.hpp" + +using namespace CIMPP; + +{{class_name}}::{{class_name}}() {} +{{class_name}}::{{class_name}}(std::string value) : value(value), initialized(true) {} +{{class_name}}::~{{class_name}}() {} + +{{class_name}}& {{class_name}}::operator=(std::string &rop) +{ + value = rop; + initialized = true; + return *this; +} + +{{class_name}}::operator std::string() +{ + if (!initialized) + { + throw new ReadingUninitializedField(); + } + return value; +} + +const char {{class_name}}::debugName[] = "{{class_name}}"; +const char* {{class_name}}::debugString() const +{ + return {{class_name}}::debugName; +} + +void {{class_name}}::addConstructToMap(std::unordered_map& factory_map) {} +void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} +void {{class_name}}::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +const BaseClassDefiner {{class_name}}::declare() +{ + return BaseClassDefiner({{class_name}}::addConstructToMap, {{class_name}}::addPrimitiveAssignFnsToMap, {{class_name}}::addClassAssignFnsToMap, {{class_name}}::debugName); +} + +namespace CIMPP +{ + std::istream& operator>>(std::istream& lop, {{class_name}}& rop) + { + lop >> rop.value; + rop.initialized = true; + return lop; + } + + std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj) + { + if (obj.initialized) + { + os << obj.value; + } + return os; + } +} From 68f0df33cfb0d661e6b9de7d4c38625a95ab8d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 19 Oct 2024 13:41:20 +0200 Subject: [PATCH 10/23] Improve cpp templates: make debugstring() const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- .../languages/cpp/templates/cpp_float_header_template.mustache | 2 +- .../languages/cpp/templates/cpp_float_object_template.mustache | 3 ++- cimgen/languages/cpp/templates/cpp_header_template.mustache | 2 +- cimgen/languages/cpp/templates/cpp_object_template.mustache | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache index 7517148..002c198 100644 --- a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache @@ -28,7 +28,7 @@ namespace CIMPP bool initialized = false; static const char debugName[]; - virtual const char* debugString(); + const char* debugString() const override; static void addConstructToMap(std::unordered_map& factory_map); static void addPrimitiveAssignFnsToMap(std::unordered_map&); diff --git a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache index 1d7116a..721837e 100644 --- a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache @@ -16,7 +16,8 @@ void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} const char {{class_name}}::debugName[] = "{{class_name}}"; -const char* {{class_name}}::debugString() { +const char* {{class_name}}::debugString() const +{ return {{class_name}}::debugName; } diff --git a/cimgen/languages/cpp/templates/cpp_header_template.mustache b/cimgen/languages/cpp/templates/cpp_header_template.mustache index 6205a4c..fb42370 100644 --- a/cimgen/languages/cpp/templates/cpp_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_header_template.mustache @@ -23,7 +23,7 @@ namespace CIMPP { {{/attributes}} static const char debugName[]; - virtual const char* debugString(); + const char* debugString() const override; /* constructor initialising all attributes to null */ {{class_name}}(); diff --git a/cimgen/languages/cpp/templates/cpp_object_template.mustache b/cimgen/languages/cpp/templates/cpp_object_template.mustache index ae60165..1d36a74 100644 --- a/cimgen/languages/cpp/templates/cpp_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_object_template.mustache @@ -43,7 +43,7 @@ void {{class_name}}::addClassAssignFnsToMap(std::unordered_map Date: Sat, 19 Oct 2024 17:55:02 +0200 Subject: [PATCH 11/23] Add generated-via-cimgen comment to the header of all generated files for cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/lang_pack.py | 18 ++++++++++++++++-- .../cpp_enum_header_template.mustache | 3 +++ .../cpp_enum_object_template.mustache | 6 +++++- .../cpp_float_header_template.mustache | 3 +++ .../cpp_float_object_template.mustache | 4 ++++ .../cpp/templates/cpp_header_template.mustache | 3 +++ .../cpp/templates/cpp_object_template.mustache | 7 ++++++- 7 files changed, 40 insertions(+), 4 deletions(-) diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 38e3d16..ac96e51 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -411,6 +411,10 @@ def resolve_headers(path: str, version: str): # NOSONAR class_list_header = [ "#ifndef CIMCLASSLIST_H\n", "#define CIMCLASSLIST_H\n", + "/*\n", + "Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen\n", + "*/\n", + "\n", "using namespace CIMPP;\n", "#include \n", "static std::list CIMClassList = {\n", @@ -430,8 +434,18 @@ def resolve_headers(path: str, version: str): # NOSONAR class_blacklist, ) - iec61970_header = ["#ifndef IEC61970_H\n", "#define IEC61970_H\n"] - iec61970_footer = ['#include "UnknownType.hpp"\n', "#endif"] + iec61970_header = [ + "#ifndef IEC61970_H\n", + "#define IEC61970_H\n", + "/*\n", + "Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen\n", + "*/\n", + "\n", + ] + iec61970_footer = [ + '#include "UnknownType.hpp"\n', + "#endif", + ] _create_header_include_file( path, diff --git a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache index 888ac3c..75e30a0 100644 --- a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache @@ -1,5 +1,8 @@ #ifndef {{class_name}}_H #define {{class_name}}_H +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ namespace CIMPP { /* diff --git a/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache b/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache index 63eecae..14b9f71 100644 --- a/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache @@ -1,6 +1,10 @@ +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ +#include "{{class_name}}.hpp" + #include #include -#include "{{class_name}}.hpp" using namespace CIMPP; diff --git a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache index 002c198..a843219 100644 --- a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache @@ -1,5 +1,8 @@ #ifndef {{class_name}}_H #define {{class_name}}_H +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ #include #include diff --git a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache index 721837e..3f6f2f9 100644 --- a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache @@ -1,4 +1,8 @@ +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ #include "{{class_name}}.hpp" + #include "../src/CIMExceptions.hpp" using namespace CIMPP; diff --git a/cimgen/languages/cpp/templates/cpp_header_template.mustache b/cimgen/languages/cpp/templates/cpp_header_template.mustache index fb42370..b3af88e 100644 --- a/cimgen/languages/cpp/templates/cpp_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_header_template.mustache @@ -1,5 +1,8 @@ #ifndef {{class_name}}_H #define {{class_name}}_H +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ #include "{{sub_class_of}}.hpp" #include diff --git a/cimgen/languages/cpp/templates/cpp_object_template.mustache b/cimgen/languages/cpp/templates/cpp_object_template.mustache index 1d36a74..78e3283 100644 --- a/cimgen/languages/cpp/templates/cpp_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_object_template.mustache @@ -1,6 +1,11 @@ +/* +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +*/ +#include "{{class_name}}.hpp" + #include + #include "{{sub_class_of}}.hpp" -#include "{{class_name}}.hpp" {{#attributes}} #include "{{attribute_class}}.hpp" From 8e4855e693b7b3c249d0fb320357e1f9c7145e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 19 Oct 2024 18:27:49 +0200 Subject: [PATCH 12/23] Improve cpp templates (skip empty comments, improve indentations) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- .../cpp/templates/cpp_enum_header_template.mustache | 4 ++++ .../languages/cpp/templates/cpp_header_template.mustache | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache index 75e30a0..6de035a 100644 --- a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache @@ -5,15 +5,19 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim */ namespace CIMPP { +{{#class_comment}} /* {{{class_comment}}} */ +{{/class_comment}} enum class {{class_name}} { {{#enum_instances}} +{{#comment}} /** * {{comment}} */ +{{/comment}} {{label}}, {{/enum_instances}} }; diff --git a/cimgen/languages/cpp/templates/cpp_header_template.mustache b/cimgen/languages/cpp/templates/cpp_header_template.mustache index b3af88e..21fd927 100644 --- a/cimgen/languages/cpp/templates/cpp_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_header_template.mustache @@ -14,16 +14,18 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim namespace CIMPP { {{#langPack._create_attribute_class_declarations}}{{attributes}}{{/langPack._create_attribute_class_declarations}} +{{#class_comment}} /* {{{class_comment}}} */ +{{/class_comment}} class {{class_name}}: public {{sub_class_of}} { public: - {{#attributes}} - {{> attribute}} {{> label}}; /* {{comment}} Default: {{#langPack._set_default}}{{dataType}}{{/langPack._set_default}} */ - {{/attributes}} +{{#attributes}} + {{> attribute}} {{> label}}; /* {{comment}} Default: {{#langPack._set_default}}{{dataType}}{{/langPack._set_default}} */ +{{/attributes}} static const char debugName[]; const char* debugString() const override; From 04a1c995a9a2149714c6c4e71b3a87f69a8bd858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sat, 19 Oct 2024 20:07:29 +0200 Subject: [PATCH 13/23] Fix cpp create_assign functions for string attribute types (Date, DateTime, MonthDay) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/lang_pack.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index ac96e51..1893146 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -241,7 +241,11 @@ def create_assign(text, render): if label_without_keyword == "switch": label_without_keyword = "_switch" - if _class != "String": + if ( + attribute_json["is_enum_attribute"] + or attribute_json["is_primitive_float_attribute"] + or _class in ("Integer", "Boolean") + ): assign = ( """ bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { @@ -260,7 +264,7 @@ def create_assign(text, render): .replace("LABEL", attribute_json["label"]) .replace("LBL_WO_KEYWORD", label_without_keyword) ) - else: + else: # is_primitive_string_attribute assign = """ bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { if(CLASS* element = dynamic_cast(BaseClass_ptr1)) { From 24090494f1721ba26ef91c65d03f80bc88a81b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 20 Oct 2024 11:45:05 +0200 Subject: [PATCH 14/23] Fix cpp create_class_assign functions to prevent duplicate entries in attributes with attribute_type list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/lang_pack.py | 60 ++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 1893146..4df6542 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -174,8 +174,36 @@ def create_class_assign(text, render): if attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]: return "" if attribute_json["is_list_attribute"]: - assign = ( - """ + if "inverseRole" in attribute_json: + inverse = attribute_json["inverseRole"].split(".") + assign = ( + """ +bool assign_INVERSEC_INVERSEL(BaseClass*, BaseClass*); +bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) +{ + OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1); + ATTRIBUTE_CLASS* element2 = dynamic_cast(BaseClass_ptr2); + if (element != nullptr && element2 != nullptr) + { + if (std::find(element->LABEL.begin(), element->LABEL.end(), element2) == element->LABEL.end()) + { + element->LABEL.push_back(element2); + return assign_INVERSEC_INVERSEL(BaseClass_ptr2, BaseClass_ptr1); + } + return true; + } + return false; +}""".replace( # noqa: E101,W191 + "OBJECT_CLASS", attribute_json["domain"] + ) + .replace("ATTRIBUTE_CLASS", attribute_class) + .replace("LABEL", attribute_json["label"]) + .replace("INVERSEC", inverse[0]) + .replace("INVERSEL", inverse[1]) + ) + else: + assign = ( + """ bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { if(OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) { if(dynamic_cast(BaseClass_ptr2) != nullptr) { @@ -185,23 +213,29 @@ def create_class_assign(text, render): } return false; }""".replace( # noqa: E101,W191 - "OBJECT_CLASS", attribute_json["domain"] + "OBJECT_CLASS", attribute_json["domain"] + ) + .replace("ATTRIBUTE_CLASS", attribute_class) + .replace("LABEL", attribute_json["label"]) ) - .replace("ATTRIBUTE_CLASS", attribute_class) - .replace("LABEL", attribute_json["label"]) - ) - elif "inverseRole" in attribute_json and attribute_json["is_used"]: + elif "inverseRole" in attribute_json: inverse = attribute_json["inverseRole"].split(".") assign = ( """ bool assign_INVERSEC_INVERSEL(BaseClass*, BaseClass*); bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { - if(OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) { - element->LABEL = dynamic_cast(BaseClass_ptr2); - if(element->LABEL != nullptr) - return assign_INVERSEC_INVERSEL(BaseClass_ptr2, BaseClass_ptr1); - } - return false; + OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1); + ATTRIBUTE_CLASS* element2 = dynamic_cast(BaseClass_ptr2); + if (element != nullptr && element2 != nullptr) + { + if (element->LABEL != element2) + { + element->LABEL = element2; + return assign_INVERSEC_INVERSEL(BaseClass_ptr2, BaseClass_ptr1); + } + return true; + } + return false; }""".replace( # noqa: E101,W191 "OBJECT_CLASS", attribute_json["domain"] ) From ed8eb993fa0611e14be1c8c11871f8b4dc8af9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 20 Oct 2024 11:56:22 +0200 Subject: [PATCH 15/23] Add class comment to cpp templates for float and string classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- .../cpp/templates/cpp_float_header_template.mustache | 5 +++++ .../cpp/templates/cpp_string_header_template.mustache | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache index a843219..fa2f22c 100644 --- a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache @@ -11,6 +11,11 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim namespace CIMPP { +{{#class_comment}} + /* + {{{class_comment}}} + */ +{{/class_comment}} class {{class_name}} : public BaseClass { diff --git a/cimgen/languages/cpp/templates/cpp_string_header_template.mustache b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache index 9a0de1a..a8fb2c4 100644 --- a/cimgen/languages/cpp/templates/cpp_string_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache @@ -11,6 +11,11 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim namespace CIMPP { +{{#class_comment}} + /* + {{{class_comment}}} + */ +{{/class_comment}} class {{class_name}} : public BaseClass { public: From 1833e80437ea7461db808efd424fd55ed768c224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 27 Oct 2024 19:19:44 +0100 Subject: [PATCH 16/23] Simplify and unify cpp templates for enum, float and string classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- .../cpp_enum_header_template.mustache | 36 +++++-- .../cpp_enum_object_template.mustache | 56 ++++++++++- .../cpp_float_header_template.mustache | 37 ++++---- .../cpp_float_object_template.mustache | 94 ++++++++++--------- .../cpp_string_header_template.mustache | 24 ++--- .../cpp_string_object_template.mustache | 19 +--- 6 files changed, 157 insertions(+), 109 deletions(-) diff --git a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache index 6de035a..3076101 100644 --- a/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_enum_header_template.mustache @@ -4,23 +4,45 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen */ -namespace CIMPP { +#include +#include + +namespace CIMPP +{ {{#class_comment}} /* {{{class_comment}}} */ {{/class_comment}} - enum class {{class_name}} + class {{class_name}} { + public: + enum {{class_name}}_ENUM + { {{#enum_instances}} {{#comment}} - /** - * {{comment}} - */ + /** + * {{comment}} + */ {{/comment}} - {{label}}, + {{label}}, {{/enum_instances}} + }; + + {{class_name}}() : value(), initialized(false) {} + {{class_name}}({{class_name}}_ENUM value) : value(value), initialized(true) {} + + {{class_name}}& operator=({{class_name}}_ENUM rop); + operator {{class_name}}_ENUM() const; + + {{class_name}}_ENUM value; + bool initialized; + + static const char debugName[]; + const char* debugString() const; + + friend std::istream& operator>>(std::istream& lop, {{class_name}}& rop); + friend std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj); }; - std::istream& operator>>(std::istream& lop, CIMPP::{{class_name}}& rop); } #endif diff --git a/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache b/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache index 14b9f71..cb2998b 100644 --- a/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_enum_object_template.mustache @@ -3,14 +3,41 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim */ #include "{{class_name}}.hpp" -#include -#include +#include +#include + +#include "../src/CIMExceptions.hpp" using namespace CIMPP; -namespace CIMPP { - std::istream& operator>>(std::istream& lop, CIMPP::{{class_name}}& rop) +{{class_name}}& {{class_name}}::operator=({{class_name}}_ENUM rop) +{ + value = rop; + initialized = true; + return *this; +} + +{{class_name}}::operator {{class_name}}_ENUM() const +{ + if (!initialized) + { + throw new ReadingUninitializedField(); + } + return value; +} + +const char {{class_name}}::debugName[] = "{{class_name}}"; +const char* {{class_name}}::debugString() const +{ + return {{class_name}}::debugName; +} + +namespace CIMPP +{ + std::istream& operator>>(std::istream& lop, {{class_name}}& rop) { + rop.initialized = false; + std::string EnumSymbol; lop >> EnumSymbol; @@ -34,4 +61,25 @@ namespace CIMPP { lop.setstate(std::ios::failbit); return lop; } + + std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj) + { + if (obj.initialized) + { + std::string EnumSymbol; + +{{#enum_instances}} + if (obj.value == {{class_name}}::{{label}}) + { + EnumSymbol = "{{label}}"; + } +{{/enum_instances}} + + if (!EnumSymbol.empty()) + { + os << "{{class_name}}." << EnumSymbol; + } + } + return os; + } } diff --git a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache index fa2f22c..e558d70 100644 --- a/cimgen/languages/cpp/templates/cpp_float_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_header_template.mustache @@ -4,10 +4,8 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen */ -#include #include - -#include "BaseClass.hpp" +#include namespace CIMPP { @@ -16,31 +14,28 @@ namespace CIMPP {{{class_comment}}} */ {{/class_comment}} - class {{class_name}} : public BaseClass + class {{class_name}} { - public: - {{class_name}}(); - virtual ~{{class_name}}(); - {{class_name}}(long double value); - static const BaseClassDefiner declare(); - {{class_name}}& operator=(long double &rop); + {{class_name}}() : value(0.0), initialized(false) {} + {{class_name}}(long double value) : value(value), initialized(true) {} + + {{class_name}}& operator=(long double rop); + operator long double() const; + + long double value; + bool initialized; + + static const char debugName[]; + const char* debugString() const; + {{class_name}}& operator+=(const {{class_name}}& rhs); {{class_name}}& operator-=(const {{class_name}}& rhs); {{class_name}}& operator*=(const {{class_name}}& rhs); {{class_name}}& operator/=(const {{class_name}}& rhs); - friend std::istream& operator>>(std::istream& lop, {{class_name}}& rop); - operator long double(); - - long double value = 0.0; - bool initialized = false; - static const char debugName[]; - const char* debugString() const override; - - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); + friend std::istream& operator>>(std::istream& lop, {{class_name}}& rop); + friend std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj); }; } #endif diff --git a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache index 3f6f2f9..ca84b71 100644 --- a/cimgen/languages/cpp/templates/cpp_float_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_float_object_template.mustache @@ -3,21 +3,27 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim */ #include "{{class_name}}.hpp" +#include + #include "../src/CIMExceptions.hpp" using namespace CIMPP; -{{class_name}}::{{class_name}}() {} - -{{class_name}}::~{{class_name}}(){} - -{{class_name}}::{{class_name}}(long double value) : value(value), initialized(true) {} - -void {{class_name}}::addConstructToMap(std::unordered_map& factory_map) {} - -void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} +{{class_name}}& {{class_name}}::operator=(long double rop) +{ + value = rop; + initialized = true; + return *this; +} -void {{class_name}}::addClassAssignFnsToMap(std::unordered_map& assign_map) {} +{{class_name}}::operator long double() const +{ + if (!initialized) + { + throw new ReadingUninitializedField(); + } + return value; +} const char {{class_name}}::debugName[] = "{{class_name}}"; const char* {{class_name}}::debugString() const @@ -25,51 +31,47 @@ const char* {{class_name}}::debugString() const return {{class_name}}::debugName; } - -const BaseClassDefiner {{class_name}}::declare() { - return BaseClassDefiner({{class_name}}::addConstructToMap, {{class_name}}::addPrimitiveAssignFnsToMap, {{class_name}}::addClassAssignFnsToMap, {{class_name}}::debugName); +{{class_name}}& {{class_name}}::operator+=(const {{class_name}}& rhs) +{ + value += rhs.value; + return *this; } -namespace CIMPP { - {{class_name}}& {{class_name}}::operator=(long double &rop) { - value = rop; - initialized = true; - return *this; - } - - {{class_name}}& {{class_name}}::operator-=(const {{class_name}}& rhs) { - value -= rhs.value; - return *this; - } - - {{class_name}}& {{class_name}}::operator*=(const {{class_name}}& rhs) { - value *= rhs.value; - return *this; - } - - {{class_name}}& {{class_name}}::operator/=(const {{class_name}}& rhs) { - value /= rhs.value; - return *this; - } +{{class_name}}& {{class_name}}::operator-=(const {{class_name}}& rhs) +{ + value -= rhs.value; + return *this; +} - {{class_name}}& {{class_name}}::operator+=(const {{class_name}}& rhs) { - value += rhs.value; - return *this; - } +{{class_name}}& {{class_name}}::operator*=(const {{class_name}}& rhs) +{ + value *= rhs.value; + return *this; +} - {{class_name}}::operator long double() { - if(!initialized) - { - throw new ReadingUninitializedField(); - } - return value; - } +{{class_name}}& {{class_name}}::operator/=(const {{class_name}}& rhs) +{ + value /= rhs.value; + return *this; +} - std::istream& operator>>(std::istream& lop, {{class_name}}& rop) { +namespace CIMPP +{ + std::istream& operator>>(std::istream& lop, {{class_name}}& rop) + { std::string tmp; lop >> tmp; rop.value = stold(tmp); rop.initialized = true; return lop; } + + std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj) + { + if (obj.initialized) + { + os << obj.value; + } + return os; + } } diff --git a/cimgen/languages/cpp/templates/cpp_string_header_template.mustache b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache index a8fb2c4..acec4ba 100644 --- a/cimgen/languages/cpp/templates/cpp_string_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_string_header_template.mustache @@ -6,8 +6,7 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim #include #include - -#include "BaseClass.hpp" +#include namespace CIMPP { @@ -16,25 +15,20 @@ namespace CIMPP {{{class_comment}}} */ {{/class_comment}} - class {{class_name}} : public BaseClass + class {{class_name}} { public: - {{class_name}}(); - {{class_name}}(std::string value); - ~{{class_name}}() override; - {{class_name}}& operator=(std::string &rop); - operator std::string(); + {{class_name}}() : initialized(false) {} + {{class_name}}(const std::string& value) : value(value), initialized(true) {} + + {{class_name}}& operator=(const std::string &rop); + operator std::string() const; std::string value; - bool initialized = false; + bool initialized; static const char debugName[]; - const char* debugString() const override; - - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); - static const BaseClassDefiner declare(); + const char* debugString() const; friend std::istream& operator>>(std::istream& lop, {{class_name}}& rop); friend std::ostream& operator<<(std::ostream& os, const {{class_name}}& obj); diff --git a/cimgen/languages/cpp/templates/cpp_string_object_template.mustache b/cimgen/languages/cpp/templates/cpp_string_object_template.mustache index 865a271..0743449 100644 --- a/cimgen/languages/cpp/templates/cpp_string_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_string_object_template.mustache @@ -3,22 +3,18 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim */ #include "{{class_name}}.hpp" -#include "CIMExceptions.hpp" +#include "../src/CIMExceptions.hpp" using namespace CIMPP; -{{class_name}}::{{class_name}}() {} -{{class_name}}::{{class_name}}(std::string value) : value(value), initialized(true) {} -{{class_name}}::~{{class_name}}() {} - -{{class_name}}& {{class_name}}::operator=(std::string &rop) +{{class_name}}& {{class_name}}::operator=(const std::string& rop) { value = rop; initialized = true; return *this; } -{{class_name}}::operator std::string() +{{class_name}}::operator std::string() const { if (!initialized) { @@ -33,15 +29,6 @@ const char* {{class_name}}::debugString() const return {{class_name}}::debugName; } -void {{class_name}}::addConstructToMap(std::unordered_map& factory_map) {} -void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} -void {{class_name}}::addClassAssignFnsToMap(std::unordered_map& assign_map) {} - -const BaseClassDefiner {{class_name}}::declare() -{ - return BaseClassDefiner({{class_name}}::addConstructToMap, {{class_name}}::addPrimitiveAssignFnsToMap, {{class_name}}::addClassAssignFnsToMap, {{class_name}}::debugName); -} - namespace CIMPP { std::istream& operator>>(std::istream& lop, {{class_name}}& rop) From 450ff190600763273ef627c41f67b5e636f5a8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 27 Oct 2024 20:21:30 +0100 Subject: [PATCH 17/23] Unify formatting of the generated cpp classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/lang_pack.py | 99 +++++++++++-------- .../templates/cpp_header_template.mustache | 28 +++--- .../templates/cpp_object_template.mustache | 37 +++---- 3 files changed, 89 insertions(+), 75 deletions(-) diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 4df6542..2e02938 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -115,7 +115,7 @@ def insert_assign_fn(text, render): label = attribute_json["label"] class_name = attribute_json["domain"] return ( - 'assign_map.insert(std::make_pair(std::string("cim:' + ' assign_map.insert(std::make_pair(std::string("cim:' + class_name + "." + label @@ -135,7 +135,7 @@ def insert_class_assign_fn(text, render): label = attribute_json["label"] class_name = attribute_json["domain"] return ( - 'assign_map.insert(std::make_pair(std::string("cim:' + ' assign_map.insert(std::make_pair(std::string("cim:' + class_name + "." + label @@ -153,13 +153,13 @@ def create_nullptr_assigns(text, render): return "" else: attributes_json = eval(attributes_txt) - nullptr_init_string = ": " + nullptr_init_string = "" for attribute in attributes_json: if attribute["is_class_attribute"]: nullptr_init_string += "LABEL(nullptr), ".replace("LABEL", attribute["label"]) if len(nullptr_init_string) > 2: - return nullptr_init_string[:-2] + return " : " + nullptr_init_string[:-2] else: return "" @@ -204,10 +204,13 @@ def create_class_assign(text, render): else: assign = ( """ -bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { - if(OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) { - if(dynamic_cast(BaseClass_ptr2) != nullptr) { - element->LABEL.push_back(dynamic_cast(BaseClass_ptr2)); +bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) +{ + if (OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) + { + if (dynamic_cast(BaseClass_ptr2) != nullptr) + { + element->LABEL.push_back(dynamic_cast(BaseClass_ptr2)); return true; } } @@ -223,7 +226,8 @@ def create_class_assign(text, render): assign = ( """ bool assign_INVERSEC_INVERSEL(BaseClass*, BaseClass*); -bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { +bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) +{ OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1); ATTRIBUTE_CLASS* element2 = dynamic_cast(BaseClass_ptr2); if (element != nullptr && element2 != nullptr) @@ -247,13 +251,17 @@ def create_class_assign(text, render): else: assign = ( """ -bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { - if(OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) { - element->LABEL = dynamic_cast(BaseClass_ptr2); - if(element->LABEL != nullptr) - return true; - } - return false; +bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) +{ + if(OBJECT_CLASS* element = dynamic_cast(BaseClass_ptr1)) + { + element->LABEL = dynamic_cast(BaseClass_ptr2); + if (element->LABEL != nullptr) + { + return true; + } + } + return false; }""".replace( # noqa: E101,W191 "OBJECT_CLASS", attribute_json["domain"] ) @@ -282,16 +290,17 @@ def create_assign(text, render): ): assign = ( """ -bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { - if(CLASS* element = dynamic_cast(BaseClass_ptr1)) { - buffer >> element->LBL_WO_KEYWORD; - if(buffer.fail()) - return false; - else - return true; - } - else - return false; +bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) +{ + if (CLASS* element = dynamic_cast(BaseClass_ptr1)) + { + buffer >> element->LBL_WO_KEYWORD; + if (buffer.fail()) + return false; + else + return true; + } + return false; }""".replace( # noqa: E101,W191 "CLASS", attribute_json["domain"] ) @@ -300,10 +309,12 @@ def create_assign(text, render): ) else: # is_primitive_string_attribute assign = """ -bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { - if(CLASS* element = dynamic_cast(BaseClass_ptr1)) { +bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1) +{ + if (CLASS* element = dynamic_cast(BaseClass_ptr1)) + { element->LABEL = buffer.str(); - if(buffer.fail()) + if (buffer.fail()) return false; else return true; @@ -345,8 +356,8 @@ def _create_attribute_includes(text, render): for attribute in attributes: if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]: unique[attribute["attribute_class"]] = True - for clarse in unique: - include_string += '\n#include "' + clarse + '.hpp"' + for clarse in sorted(unique): + include_string += '#include "' + clarse + '.hpp"\n' return include_string @@ -361,8 +372,8 @@ def _create_attribute_class_declarations(text, render): for attribute in attributes: if attribute["is_class_attribute"] or attribute["is_list_attribute"]: unique[attribute["attribute_class"]] = True - for clarse in unique: - include_string += "\nclass " + clarse + ";" + for clarse in sorted(unique): + include_string += " class " + clarse + ";\n" return include_string @@ -415,15 +426,15 @@ def set_default(dataType): iec61970_blacklist = ["CIMClassList", "CIMNamespaces", "Folders", "Task", "IEC61970"] -def _is_enum_class(filepath): +def _is_primitive_or_enum_class(filepath): with open(filepath, encoding="utf-8") as f: try: for line in f: - if "enum class" in line: - return True + if "static const BaseClassDefiner declare();" in line: + return False except UnicodeDecodeError as error: print("Warning: UnicodeDecodeError parsing {0}: {1}".format(filepath, error)) - return False + return True def _create_header_include_file(directory, header_include_filename, header, footer, before, after, blacklist): @@ -434,7 +445,7 @@ def _create_header_include_file(directory, header_include_filename, header, foot filepath = os.path.join(directory, filename) basepath, ext = os.path.splitext(filepath) basename = os.path.basename(basepath) - if ext == ".hpp" and not _is_enum_class(filepath) and basename not in blacklist: + if ext == ".hpp" and not _is_primitive_or_enum_class(filepath) and basename not in blacklist: lines.append(before + basename + after) for line in lines: header.append(line) @@ -452,13 +463,15 @@ def resolve_headers(path: str, version: str): # NOSONAR "/*\n", "Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen\n", "*/\n", - "\n", - "using namespace CIMPP;\n", "#include \n", - "static std::list CIMClassList = {\n", + '#include "IEC61970.hpp"\n', + "using namespace CIMPP;\n", + "static std::list CIMClassList =\n", + "{\n", ] class_list_footer = [ - " UnknownType::declare() };\n", + " UnknownType::declare(),\n", + "};\n", "#endif // CIMCLASSLIST_H\n", ] @@ -467,7 +480,7 @@ def resolve_headers(path: str, version: str): # NOSONAR "CIMClassList.hpp", class_list_header, class_list_footer, - " ", + " ", "::declare(),\n", class_blacklist, ) diff --git a/cimgen/languages/cpp/templates/cpp_header_template.mustache b/cimgen/languages/cpp/templates/cpp_header_template.mustache index 21fd927..2d8322d 100644 --- a/cimgen/languages/cpp/templates/cpp_header_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_header_template.mustache @@ -4,25 +4,28 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen */ -#include "{{sub_class_of}}.hpp" #include -#include "Boolean.hpp" -#include "Float.hpp" +#include +#include +#include "{{sub_class_of}}.hpp" +#include "BaseClassDefiner.hpp" {{#langPack._create_attribute_includes}}{{attributes}}{{/langPack._create_attribute_includes}} - -namespace CIMPP { - +namespace CIMPP +{ {{#langPack._create_attribute_class_declarations}}{{attributes}}{{/langPack._create_attribute_class_declarations}} {{#class_comment}} /* {{{class_comment}}} */ {{/class_comment}} - class {{class_name}}: public {{sub_class_of}} + class {{class_name}} : public {{sub_class_of}} { - public: + /* constructor initialising all attributes to null */ + {{class_name}}(); + ~{{class_name}}() override; + {{#attributes}} {{> attribute}} {{> label}}; /* {{comment}} Default: {{#langPack._set_default}}{{dataType}}{{/langPack._set_default}} */ {{/attributes}} @@ -30,15 +33,10 @@ namespace CIMPP { static const char debugName[]; const char* debugString() const override; - /* constructor initialising all attributes to null */ - {{class_name}}(); - virtual ~{{class_name}}(); - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); + static void addPrimitiveAssignFnsToMap(std::unordered_map& assign_map); + static void addClassAssignFnsToMap(std::unordered_map& assign_map); static const BaseClassDefiner declare(); - }; BaseClass* {{class_name}}_factory(); diff --git a/cimgen/languages/cpp/templates/cpp_object_template.mustache b/cimgen/languages/cpp/templates/cpp_object_template.mustache index 78e3283..eec1a96 100644 --- a/cimgen/languages/cpp/templates/cpp_object_template.mustache +++ b/cimgen/languages/cpp/templates/cpp_object_template.mustache @@ -3,10 +3,9 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim */ #include "{{class_name}}.hpp" +#include #include -#include "{{sub_class_of}}.hpp" - {{#attributes}} #include "{{attribute_class}}.hpp" {{/attributes}} @@ -14,7 +13,6 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim using namespace CIMPP; {{class_name}}::{{class_name}}(){{#langPack.create_nullptr_assigns}} {{attributes}} {{/langPack.create_nullptr_assigns}} {}; - {{class_name}}::~{{class_name}}() {}; {{#attributes}} @@ -25,35 +23,40 @@ using namespace CIMPP; {{#langPack.create_class_assign}}{{.}}{{/langPack.create_class_assign}} {{/attributes}} -namespace CIMPP { - BaseClass* {{class_name}}_factory() { - return new {{class_name}}; - } +const char {{class_name}}::debugName[] = "{{class_name}}"; +const char* {{class_name}}::debugString() const +{ + return {{class_name}}::debugName; } -void {{class_name}}::addConstructToMap(std::unordered_map& factory_map) { +void {{class_name}}::addConstructToMap(std::unordered_map& factory_map) +{ factory_map.insert(std::make_pair(std::string("cim:{{class_name}}"), &{{class_name}}_factory)); } -void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) { +void {{class_name}}::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) +{ {{#attributes}} - {{> insert_assign}} +{{> insert_assign}} {{/attributes}} } -void {{class_name}}::addClassAssignFnsToMap(std::unordered_map& assign_map) { +void {{class_name}}::addClassAssignFnsToMap(std::unordered_map& assign_map) +{ {{#attributes}} - {{> insert_class_assign}} +{{> insert_class_assign}} {{/attributes}} } -const char {{class_name}}::debugName[] = "{{class_name}}"; -const char* {{class_name}}::debugString() const +const BaseClassDefiner {{class_name}}::declare() { - return {{class_name}}::debugName; + return BaseClassDefiner({{class_name}}::addConstructToMap, {{class_name}}::addPrimitiveAssignFnsToMap, {{class_name}}::addClassAssignFnsToMap, {{class_name}}::debugName); } -const BaseClassDefiner {{class_name}}::declare() +namespace CIMPP { - return BaseClassDefiner({{class_name}}::addConstructToMap, {{class_name}}::addPrimitiveAssignFnsToMap, {{class_name}}::addClassAssignFnsToMap, {{class_name}}::debugName); + BaseClass* {{class_name}}_factory() + { + return new {{class_name}}; + } } From 6e093343ca7f7d54d6d9ef193267318c6d2e88f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 27 Oct 2024 20:47:07 +0100 Subject: [PATCH 18/23] Add static cpp sources and parser classes (copied from libcimpp) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/src/Aliases.hpp | 106 +++++++ .../languages/cpp/src/AliasesAssignment.hpp | 2 + cimgen/languages/cpp/src/AliasesTask.hpp | 10 + .../languages/cpp/src/CIMContentHandler.cpp | 292 ++++++++++++++++++ .../languages/cpp/src/CIMContentHandler.hpp | 57 ++++ cimgen/languages/cpp/src/CIMExceptions.cpp | 56 ++++ cimgen/languages/cpp/src/CIMExceptions.hpp | 81 +++++ cimgen/languages/cpp/src/CIMFile.cpp | 54 ++++ cimgen/languages/cpp/src/CIMFile.hpp | 26 ++ cimgen/languages/cpp/src/CIMModel.cpp | 113 +++++++ cimgen/languages/cpp/src/CIMModel.hpp | 64 ++++ cimgen/languages/cpp/src/ModelDescription.cpp | 12 + cimgen/languages/cpp/src/ModelDescription.hpp | 26 ++ .../cpp/src/ModelDescriptionHandler.cpp | 160 ++++++++++ .../cpp/src/ModelDescriptionHandler.hpp | 41 +++ cimgen/languages/cpp/src/SAXErrorHandler.hpp | 44 +++ cimgen/languages/cpp/static/BaseClass.cpp | 22 ++ cimgen/languages/cpp/static/BaseClass.h | 1 + cimgen/languages/cpp/static/BaseClass.hpp | 22 ++ .../languages/cpp/static/BaseClassDefiner.cpp | 14 + .../languages/cpp/static/BaseClassDefiner.hpp | 24 ++ cimgen/languages/cpp/static/Boolean.cpp | 80 +++++ cimgen/languages/cpp/static/Boolean.hpp | 38 +++ cimgen/languages/cpp/static/CIMFactory.cpp | 44 +++ cimgen/languages/cpp/static/CIMFactory.hpp | 22 ++ cimgen/languages/cpp/static/Date.cpp | 20 ++ cimgen/languages/cpp/static/Date.hpp | 26 ++ cimgen/languages/cpp/static/Float.cpp | 67 ++++ cimgen/languages/cpp/static/Float.hpp | 42 +++ cimgen/languages/cpp/static/Folders.hpp | 1 + .../static/IEC61970/IEC61970CIMVersion.cpp | 15 + .../cpp/static/IEC61970/IEC61970CIMVersion.h | 31 ++ cimgen/languages/cpp/static/Integer.cpp | 72 +++++ cimgen/languages/cpp/static/Integer.hpp | 41 +++ cimgen/languages/cpp/static/String.hpp | 14 + cimgen/languages/cpp/static/Task.cpp | 57 ++++ cimgen/languages/cpp/static/Task.hpp | 22 ++ cimgen/languages/cpp/static/UnknownType.cpp | 136 ++++++++ cimgen/languages/cpp/static/UnknownType.hpp | 24 ++ cimgen/languages/cpp/static/assignments.cpp | 40 +++ cimgen/languages/cpp/static/assignments.hpp | 11 + 41 files changed, 2030 insertions(+) create mode 100644 cimgen/languages/cpp/src/Aliases.hpp create mode 100644 cimgen/languages/cpp/src/AliasesAssignment.hpp create mode 100644 cimgen/languages/cpp/src/AliasesTask.hpp create mode 100644 cimgen/languages/cpp/src/CIMContentHandler.cpp create mode 100644 cimgen/languages/cpp/src/CIMContentHandler.hpp create mode 100644 cimgen/languages/cpp/src/CIMExceptions.cpp create mode 100644 cimgen/languages/cpp/src/CIMExceptions.hpp create mode 100644 cimgen/languages/cpp/src/CIMFile.cpp create mode 100644 cimgen/languages/cpp/src/CIMFile.hpp create mode 100644 cimgen/languages/cpp/src/CIMModel.cpp create mode 100644 cimgen/languages/cpp/src/CIMModel.hpp create mode 100644 cimgen/languages/cpp/src/ModelDescription.cpp create mode 100644 cimgen/languages/cpp/src/ModelDescription.hpp create mode 100644 cimgen/languages/cpp/src/ModelDescriptionHandler.cpp create mode 100644 cimgen/languages/cpp/src/ModelDescriptionHandler.hpp create mode 100644 cimgen/languages/cpp/src/SAXErrorHandler.hpp create mode 100644 cimgen/languages/cpp/static/BaseClass.cpp create mode 100644 cimgen/languages/cpp/static/BaseClass.h create mode 100644 cimgen/languages/cpp/static/BaseClass.hpp create mode 100644 cimgen/languages/cpp/static/BaseClassDefiner.cpp create mode 100644 cimgen/languages/cpp/static/BaseClassDefiner.hpp create mode 100644 cimgen/languages/cpp/static/Boolean.cpp create mode 100644 cimgen/languages/cpp/static/Boolean.hpp create mode 100644 cimgen/languages/cpp/static/CIMFactory.cpp create mode 100644 cimgen/languages/cpp/static/CIMFactory.hpp create mode 100644 cimgen/languages/cpp/static/Date.cpp create mode 100644 cimgen/languages/cpp/static/Date.hpp create mode 100644 cimgen/languages/cpp/static/Float.cpp create mode 100644 cimgen/languages/cpp/static/Float.hpp create mode 100644 cimgen/languages/cpp/static/Folders.hpp create mode 100644 cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp create mode 100644 cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h create mode 100644 cimgen/languages/cpp/static/Integer.cpp create mode 100644 cimgen/languages/cpp/static/Integer.hpp create mode 100644 cimgen/languages/cpp/static/String.hpp create mode 100644 cimgen/languages/cpp/static/Task.cpp create mode 100644 cimgen/languages/cpp/static/Task.hpp create mode 100644 cimgen/languages/cpp/static/UnknownType.cpp create mode 100644 cimgen/languages/cpp/static/UnknownType.hpp create mode 100644 cimgen/languages/cpp/static/assignments.cpp create mode 100644 cimgen/languages/cpp/static/assignments.hpp diff --git a/cimgen/languages/cpp/src/Aliases.hpp b/cimgen/languages/cpp/src/Aliases.hpp new file mode 100644 index 0000000..08aaf74 --- /dev/null +++ b/cimgen/languages/cpp/src/Aliases.hpp @@ -0,0 +1,106 @@ +#ifndef ALIASES_HPP +#define ALIASES_HPP + +#include +#include +#include +#include +#include + +#include "IEC61970/IEC61970CIMVersion.h" + +static std::list search_paths = { + "./", + "${CIMPP_ALIASDIR}/", +#ifdef __linux__ + "/usr/share/cimpp/", + "/usr/local/share/cimpp/", + "/usr/share/cimpp/${CIM_VERSION}/", + "/usr/local/share/cimpp/${CIM_VERSION}/", + "${HOME}/.cimpp/" +#elif defined(_WIN32) + "${APPDATA}\\CIMpp\\", + "${APPDATA}\\CIMpp\\${CIM_VERSION}\\" +#endif +}; + +// Update the input string. +static std::string expand_env_variables(std::string str) +{ + static std::regex env("\\$\\{([^}]+)\\}"); + std::smatch match; + while (std::regex_search(str, match, env)) { +#if defined(__linux__) || defined(__APPLE__) + const char *s = getenv(match[1].str().c_str()); +#elif defined(_WIN32) + char *s; + size_t len; + _dupenv_s(&s, &len, match[1].str().c_str()); +#else + #error Unsupported platform +#endif + + const std::string var(s == NULL ? "" : s); + str.replace(match.position(0), match.length(0) , var); + } + + return str; +} + +static std::ifstream find_aliases(const std::string &filename) +{ + std::ifstream file; + std::string path; + std::string::size_type pos; + + // Set CIM_DIR variable if not set + std::string cim_dir = IEC61970::IEC61970CIMVersion::version; + + pos = cim_dir.find("IEC61970CIM"); + if (pos == 0) + cim_dir.erase(0, 11); +#ifdef __linux__ + setenv("CIM_VERSION", cim_dir.c_str(), 1); +#elif defined(_WIN32) + std::string cim_version = "CIM_VERSION=" + cim_dir; + _putenv(cim_version.c_str()); +#endif + + for (std::string &path : search_paths) { + std::string expanded_path = expand_env_variables(path); + + file.open(expanded_path + filename); + if (file.good()) + return file; + } + + return file; +} + +template +void load_aliases(std::unordered_map &map, const std::string &filename) +{ + std::ifstream file = find_aliases(filename); + + if(file.good() && file.is_open()) + { + std::string line; + std::regex expr("^([a-zA-Z0-9:.]*)[\t ,;]+([a-zA-Z0-9:.]*)$"); + std::smatch m; + typename std::unordered_map::iterator it; + + while (std::getline(file, line)) + { + if(std::regex_match(line, m, expr)) + { + it = map.find(m[1]); + if(it != map.end()) + { + map.insert(std::make_pair(m[2], it->second)); + } + } + } + } +} + +#endif // ALIASES_HPP diff --git a/cimgen/languages/cpp/src/AliasesAssignment.hpp b/cimgen/languages/cpp/src/AliasesAssignment.hpp new file mode 100644 index 0000000..77059f5 --- /dev/null +++ b/cimgen/languages/cpp/src/AliasesAssignment.hpp @@ -0,0 +1,2 @@ +dynamic_switch.insert(std::make_pair("cim:Terminal.sequenceNumber", &assign_ACDCTerminal_sequenceNumber)); +dynamic_switch.insert(std::make_pair("cim:Terminal.connected", &assign_ACDCTerminal_connected)); diff --git a/cimgen/languages/cpp/src/AliasesTask.hpp b/cimgen/languages/cpp/src/AliasesTask.hpp new file mode 100644 index 0000000..1666ad7 --- /dev/null +++ b/cimgen/languages/cpp/src/AliasesTask.hpp @@ -0,0 +1,10 @@ +map.insert(std::make_pair("cim:VoltageLevel.Substation", &assign_Substation_VoltageLevels)); +map.insert(std::make_pair("cim:SubGeographicalRegion.Region", &assign_GeographicalRegion_Regions)); +map.insert(std::make_pair("cim:Equipment.EquipmentContainer", &assign_EquipmentContainer_Equipments)); +map.insert(std::make_pair("cim:DiagramObject.IdentifiedObject", &assign_IdentifiedObject_DiagramObjects)); +map.insert(std::make_pair("cim:DiagramObjectPoint.DiagramObject", &assign_DiagramObject_DiagramObjectPoints)); +map.insert(std::make_pair("cim:Substation.Region", &assign_SubGeographicalRegion_Substations)); +map.insert(std::make_pair("cim:OperationalLimit.OperationalLimitSet", &assign_OperationalLimitSet_OperationalLimitValue)); +map.insert(std::make_pair("cim:ConformLoad.LoadGroup", &assign_ConformLoadGroup_EnergyConsumers)); +map.insert(std::make_pair("cim:LoadGroup.SubLoadArea", &assign_SubLoadArea_LoadGroups)); +map.insert(std::make_pair("cim:SubLoadArea.LoadArea", &assign_LoadArea_SubLoadAreas)); diff --git a/cimgen/languages/cpp/src/CIMContentHandler.cpp b/cimgen/languages/cpp/src/CIMContentHandler.cpp new file mode 100644 index 0000000..5aa026a --- /dev/null +++ b/cimgen/languages/cpp/src/CIMContentHandler.cpp @@ -0,0 +1,292 @@ +#include "CIMContentHandler.hpp" +#include +#include +#include + +#include + +#include "Folders.hpp" +#include "CIMFactory.hpp" +#include "assignments.hpp" +#include "CIMExceptions.hpp" + +#ifndef CGMES_BUILD +#include "CIMNamespaces.hpp" +#endif + +CIMContentHandler::CIMContentHandler() : Objects(nullptr), RDFMap(nullptr) +{ +} + +CIMContentHandler::~CIMContentHandler() +{ + checkStacksEmpty(); +} + +void CIMContentHandler::checkStacksEmpty() +{ + if (!objectStack.empty()) + { + throw CriticalError("CIMContentHandler: Critical Error: objectStack is not empty!"); + } + if (!tagStack.empty()) + { + std::cerr << "First 5 items on stack: " << std::endl; + int i = 10; + while (!tagStack.empty() && i--) { + std::string name = tagStack.top(); + std::cerr << "{" << name << "}" << std::endl; + tagStack.pop(); + } + throw CriticalError("CIMContentHandler: Critical Error: tagStack is not empty!"); + } +} + +void CIMContentHandler::setObjectsContainer(std::vector *Objects) +{ + this->Objects = Objects; +} + +void CIMContentHandler::setRDFMap(std::unordered_map *RDFMap) +{ + this->RDFMap = RDFMap; +} + +void CIMContentHandler::setDocumentLocator(const LocatorT &locator) +{} + +void CIMContentHandler::startDocument() +{ + if(Objects == nullptr) + { + throw NoObjectsContainer(this); + } + if(RDFMap == nullptr) + { + throw NoRdfMap(this); + } + +} + +void CIMContentHandler::endDocument() +{ +} + +void CIMContentHandler::startPrefixMapping(const std::string &prefix, const std::string &uri) +{} + +void CIMContentHandler::endPrefixMapping(const std::string &prefix) +{} + +void CIMContentHandler::startElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName, const AttributesT &atts) +{ + // Only process tags in cim namespace + if(qName.find("cim:") == std::string::npos) + { + bool isModelDescription = qName.find("md:") != std::string::npos || qName.find("DependentOn:") != std::string::npos || qName.find("createdBy") != std::string::npos; + bool isModel = qName.find("rdf:") != std::string::npos; + + if(!isModelDescription && !isModel) + { + std::cerr << "WARNING: "<< qName << " not in namespace \"cim\"" << std::endl; + } + return; + } + + // Remember last opened tag + tagStack.push(qName); + + // If there is no RDF ID (an XML attribute!) then we don't have a new CIM + // object or RDF relation therefore the XML element will contain a value + // assignment. + if(atts.getLength() == 0) + return; + // If name is a CIM class check if to create a new object + if(CIMFactory::IsCIMClass(qName)) + { + // Get rdf_id + std::string rdf_id = get_rdf_id(atts); + if(rdf_id.empty()) + { + throw NoRdfID(); + } + // check if object already exists + std::unordered_map::iterator it = RDFMap->find(rdf_id); + if(it != RDFMap->end()) // object exists -> push it on the stack + { + objectStack.push(it->second); + } + else // object does not exist -> create object + { + BaseClass* BaseClass_ptr = CIMFactory::CreateNew(qName); + + //Check if created Object is IdentifiedObject and place rdf_id into mRID + if(CIMPP::IdentifiedObject* idOb = dynamic_cast(BaseClass_ptr)) + { + (*idOb).mRID = rdf_id; + } + RDFMap->emplace(rdf_id, BaseClass_ptr); + objectStack.push(BaseClass_ptr); + Objects->push_back(BaseClass_ptr); + } + return; + } + // Create a task if the XML element is no CIM class and contains a RDF ID + std::string rdf_id = get_rdf_resource(atts); + if(!rdf_id.empty()) + { + taskQueue.push_back(Task(objectStack.top(), qName, rdf_id)); + return; + } + // Assign an enum symbol if the rdf id contains a enum symbol + std::string enumSymbol = get_rdf_enum(atts); + if(!enumSymbol.empty()) + { + if(!assign(objectStack.top(), qName, enumSymbol)) + std::cerr << "CIMContentHandler: Error: " << enumSymbol << " can not be assigned" << std::endl; + return; + } + + // Nobody knows what to do + std::cerr << "CIMContentHandler: Error: Nobody knows, the " << qName << " I've seen... *sing*" << std::endl; +} + +void CIMContentHandler::endElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName) +{ + // Only process tags in cim namespace + if(qName.find("cim:") == std::string::npos) + { + return; + } + + // Pop Stacks + if (tagStack.size() == 0) { + std::cerr << "WARNING: Nearly tried to pop empty tag stack for tag: " << qName << std::endl; + } + else { + tagStack.pop(); + } + if(CIMFactory::IsCIMClass(qName)) + { + if (objectStack.size() == 0) { + std::cerr << "WARNING: Nearly tried to pop empty object stack for tag: " << qName << std::endl; + } + else { + objectStack.pop(); + } + //std::cout << "Popped " << name << std::endl; + } +} + +void CIMContentHandler::characters(const std::string &characters) +{ + // Only process tags in "cim" namespace + if(tagStack.empty()) + { + return; + } + if(objectStack.empty()) + { + throw CriticalError("CIMContentHandler: Critical Error: objectStack empty"); + } + +#ifndef DEBUG + assign(objectStack.top(), tagStack.top(), characters); +#else + // Check if the characters only contain whitespace + if(is_only_whitespace(characters)) + { + return; + } + if(!assign(objectStack.top(), tagStack.top(), characters)) + std::cout << "CIMContentHandler: Note: Cannot assign '" << characters << "' to " << tagStack.top() << std::endl; +#endif +} + +void CIMContentHandler::ignorableWhitespace(const std::string &ch) +{} + +void CIMContentHandler::processingInstruction(const std::string &target, const std::string &data) +{} + +void CIMContentHandler::skippedEntity(const std::string &name) +{} + +std::string CIMContentHandler::get_rdf_id(const AttributesT &attributes) +{ + for(int i = 0; i < attributes.getLength(); i++) + { + if(attributes.getQName(i) == "rdf:ID") + return attributes.getValue(i); + if(attributes.getQName(i) == "rdf:about") + return attributes.getValue(i).substr(1); + } + return std::string(); +} + +std::string CIMContentHandler::get_rdf_resource(const AttributesT &attributes) +{ + for(int i = 0; i < attributes.getLength(); i++) + { + if(attributes.getQName(i) == "rdf:resource") + { + if(attributes.getValue(i).at(0) == '#') + { + return attributes.getValue(i).substr(1); + } + } + } + return std::string(); +} + +bool CIMContentHandler::is_only_whitespace(const std::string& characters) +{ + return std::regex_match(characters, std::regex("^[[:space:]]*$")); +} + +std::string CIMContentHandler::get_rdf_enum(const AttributesT &attributes) +{ + for(int i = 0; i < attributes.getLength(); i++) + { + if(attributes.getQName(i) == "rdf:resource") + { + std::regex expr("^http[s]*://[a-zA-Z0-9./_]*CIM-schema-cim[0-9]+#([a-zA-z0-9]*).([a-zA-z0-9]*)"); + std::smatch m; + std::string str = attributes.getValue(i); + if(std::regex_match(str, m, expr)) + { + return std::string(m[1]).append(".").append(m[2]); + } + std::cerr << "CIMContentHandler: Note: rdf:resource does not relate to an object in this file "<< str << std::endl; + } + } + std::cerr << "CIMContentHandler: Note: Attribute contain no rdf:resource" << std::endl; + return std::string(); +} + +bool CIMContentHandler::resolveRDFRelations() +{ + unsigned int unresolved; + unresolved = 0; + size_t taskSize = taskQueue.size(); + std::list::iterator it = taskQueue.begin(); + while(it != taskQueue.end()) + { + if(!it->resolve(RDFMap)) + { + std::cout << "CIMContentHandler: Note: Cannot resolve following RDF relationship: "; + it->print(); + unresolved++; + ++it; + } + else + { + taskQueue.erase(it++); + } + } + std::cout << "CIMContentHandler: Note: " << unresolved << " out of " << taskSize << " tasks remain unresolved!" << std::endl; + if(unresolved > 0) + return false; + else + return true; +} diff --git a/cimgen/languages/cpp/src/CIMContentHandler.hpp b/cimgen/languages/cpp/src/CIMContentHandler.hpp new file mode 100644 index 0000000..df23d00 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMContentHandler.hpp @@ -0,0 +1,57 @@ +#ifndef CIMCONTENTHANDLER_HPP +#define CIMCONTENTHANDLER_HPP + +#include +#include + +#include +#include +#include +#include + +#include "BaseClass.h" +#include "Task.hpp" +#include "Folders.hpp" + +class CIMContentHandler : public Arabica::SAX::ContentHandler +{ +public: + CIMContentHandler(); + ~CIMContentHandler(); + + std::vector *Objects; + std::unordered_map *RDFMap; + void setObjectsContainer(std::vector *Objects); + void setRDFMap(std::unordered_map *RDFMap); + + void checkStacksEmpty(); //Check if tagStack or ObjectStack is empty, throw CriticalError if true + + bool resolveRDFRelations(); // AKA work through task queue + +protected: + void setDocumentLocator(const LocatorT &locator) override; + void startDocument() override; + void endDocument() override; + void startPrefixMapping(const std::string &prefix, const std::string &uri) override; + void endPrefixMapping(const std::string &prefix) override; + void startElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName, const AttributesT &atts) override; + void endElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName) override; + void characters(const std::string &ch) override; + void ignorableWhitespace(const std::string &ch) override; + void processingInstruction(const std::string &target, const std::string &data) override; + void skippedEntity(const std::string &name) override; + + static std::string get_rdf_id(const AttributesT &properties); + static std::string get_rdf_resource(const AttributesT &properties); + static std::string get_rdf_enum(const AttributesT &properties); + static bool is_only_whitespace(const std::string &characters); + +private: + std::stack objectStack; + std::stack tagStack; + std::list taskQueue; +}; + + + +#endif // CIMCONTENTHANDLER_HPP diff --git a/cimgen/languages/cpp/src/CIMExceptions.cpp b/cimgen/languages/cpp/src/CIMExceptions.cpp new file mode 100644 index 0000000..2903b3d --- /dev/null +++ b/cimgen/languages/cpp/src/CIMExceptions.cpp @@ -0,0 +1,56 @@ +#include "CIMExceptions.hpp" + + +CIMException::CIMException() +{ +} + +CriticalError::CriticalError(const std::string& what) : runtime_error(what) +{ +} + +MissingDependencyFile::MissingDependencyFile(const CIMModel* model, const std::string id) + : Model(model), + rdfID(id) +{ + message = "CIMModel: Dependency is missing"; +} + +const char* CIMException::what() const noexcept +{ + return message.c_str(); +} + + + +MissingModelDescription::MissingModelDescription(const ModelDescriptionHandler* desc) + : DescriptionHandler(desc) +{ + message = "ModelDescriptionHandler: modelDescription not set"; +} + + +NoObjectsContainer::NoObjectsContainer(const CIMContentHandler* handler) + : ContentHandler(handler) +{ + message = "CIMContentHandler: Object container not set"; +} + + +NoRdfID::NoRdfID() +{ + message = "CIMContentHandler: Attributes contain no rdf:ID"; +} + + +NoRdfMap::NoRdfMap(const CIMContentHandler* handler) + : ContentHandler(handler) +{ + message = "CIMContentHandler: RDFMap not set"; +} + + +ReadingUninitializedField::ReadingUninitializedField() +{ + message = "Error: Uninitialized Field"; +} diff --git a/cimgen/languages/cpp/src/CIMExceptions.hpp b/cimgen/languages/cpp/src/CIMExceptions.hpp new file mode 100644 index 0000000..bd49150 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMExceptions.hpp @@ -0,0 +1,81 @@ +#ifndef CIMEXCEPTIONS_HPP +#define CIMEXCEPTIONS_HPP + +#include +#include + +class CIMException; +class CIMModel; +class ModelDescriptionHandler; +class CIMContentHandler; + +class CIMException : public std::exception +{ +public: + CIMException(); +protected: + std::string message; + virtual const char* what() const noexcept override; +}; + + +class CriticalError : public std::runtime_error +{ +public: + CriticalError(const std::string& what); +}; + + +class MissingDependencyFile : CIMException +{ +public: + MissingDependencyFile(const CIMModel* model, const std::string id); + + const CIMModel* Model; + const std::string rdfID; +}; + + + +class MissingModelDescription : CIMException +{ +public: + MissingModelDescription(const ModelDescriptionHandler* desc); + const ModelDescriptionHandler* DescriptionHandler; +}; + + + +class NoObjectsContainer : CIMException +{ +public: + NoObjectsContainer(const CIMContentHandler* handler); + const CIMContentHandler* ContentHandler; +}; + + + +class NoRdfID : CIMException +{ +public: + NoRdfID(); +}; + + + +class NoRdfMap : CIMException +{ +public: + NoRdfMap(const CIMContentHandler* handler); + const CIMContentHandler* ContentHandler; +}; + + + +class ReadingUninitializedField : CIMException +{ +public: + ReadingUninitializedField(); +}; + +#endif // CIMEXCEPTIONS_HPP diff --git a/cimgen/languages/cpp/src/CIMFile.cpp b/cimgen/languages/cpp/src/CIMFile.cpp new file mode 100644 index 0000000..9f78627 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMFile.cpp @@ -0,0 +1,54 @@ +#include "CIMFile.hpp" +#include "ModelDescription.hpp" + +#include "ModelDescriptionHandler.hpp" +#include "ModelDescription.hpp" +#include "SAX/InputSource.hpp" +#include "SAX/XMLReader.hpp" + +#include +#include + +CIMFile::CIMFile(std::string path) : path(path), modelDescription(nullptr) +{ +} + +std::string CIMFile::getpath() +{ + return path; +} + +ModelDescription* CIMFile::getModelDescription() +{ + if(modelDescription == nullptr) + { + if(!this->good()) + { + //TODO: file not good, say something + return nullptr; + } + modelDescription = new ModelDescription(); + ModelDescriptionHandler DescriptionHandler; + + DescriptionHandler.setModelDescription(modelDescription); + + Arabica::SAX::XMLReader Reader; + Reader.setContentHandler(DescriptionHandler); + + Arabica::SAX::InputSource source(path); + Reader.parse(source); + } + + return modelDescription; +} + +bool CIMFile::good() +{ + if(path.find(".xml") == std::string::npos) + { + return false; + } + + std::ifstream infile(path); + return infile.good(); +} diff --git a/cimgen/languages/cpp/src/CIMFile.hpp b/cimgen/languages/cpp/src/CIMFile.hpp new file mode 100644 index 0000000..2a54d85 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMFile.hpp @@ -0,0 +1,26 @@ +#ifndef CIMFILE_HPP +#define CIMFILE_HPP + +#include +#include "ModelDescription.hpp" + +/** \brief Class for encapsulating CIM XML files + */ +class CIMFile +{ +public: + CIMFile(std::string path); + + std::string getpath(); + + ModelDescription* getModelDescription(); + + bool good(); + +private: + std::string path; + + ModelDescription* modelDescription;// Additional meta data +}; + +#endif // CIMFILE_HPP diff --git a/cimgen/languages/cpp/src/CIMModel.cpp b/cimgen/languages/cpp/src/CIMModel.cpp new file mode 100644 index 0000000..8f92bc0 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMModel.cpp @@ -0,0 +1,113 @@ +#include "CIMModel.hpp" +#include "CIMContentHandler.hpp" +#include "SAXErrorHandler.hpp" +#include "ModelDescriptionHandler.hpp" +#include "ModelDescription.hpp" +#include "SAX/InputSource.hpp" +#include "SAX/XMLReader.hpp" +#include "CIMExceptions.hpp" + +#include +#include +#include +#include + +CIMModel::CIMModel() : DependencyCheck(true) +{ +} + +CIMModel::~CIMModel() +{ + // Clean up the mess + for(BaseClass* Object : Objects) + delete Object; +} + +bool CIMModel::addCIMFile(CIMFile file) +{ + if(!file.good()) + { + return false; + } + + Files.push_back(file); + + return true; +} + +bool CIMModel::addCIMFile(std::string path) +{ + CIMFile file(path); + + if(!file.good()) + { + return false; + } + + Files.push_back(file); + + return true; +} + +void CIMModel::parseFiles() +{ + // TODO: What happens when run twice?! + CIMContentHandler ContentHandler; + ContentHandler.setObjectsContainer(&Objects); + ContentHandler.setRDFMap(&RDFMap); + + SAXErrorHandler ErrorHandler; + + for(CIMFile& file : Files) //TODO: Suche evtl. mit eigener dependency-liste beschleunigen + { + Arabica::SAX::XMLReader Reader; + Reader.setContentHandler(ContentHandler); + Reader.setErrorHandler(ErrorHandler); + + if(DependencyCheck == true) + { + if(!(file.getModelDescription()->dependencyID).empty()) //TODO: Ueberpruefung besser Implementieren + { + bool depFound; + for(std::string& fileDepID : (file.getModelDescription()->dependencyID)) + { + depFound = 0; + for(CIMFile& fileDep : Files) + { + if(fileDep.getModelDescription()->rdfID == fileDepID) + { + depFound = 1; + break; + } + } + if(!depFound) + { + //throw MissingDependencyFile(this, fileDepID); + std::cerr << "WARNING: Dependency " << fileDepID << " is missing" << std::endl; + } + } + } + } + + + Arabica::SAX::InputSource source(file.getpath()); + Reader.parse(source); + } + + ContentHandler.resolveRDFRelations(); +} + +void CIMModel::setDependencyCheckOn() +{ + DependencyCheck = true; +} + +void CIMModel::setDependencyCheckOff() +{ + DependencyCheck = false; +} + +bool CIMModel::getDependencyCheck() +{ + return DependencyCheck; +} diff --git a/cimgen/languages/cpp/src/CIMModel.hpp b/cimgen/languages/cpp/src/CIMModel.hpp new file mode 100644 index 0000000..3ec13e2 --- /dev/null +++ b/cimgen/languages/cpp/src/CIMModel.hpp @@ -0,0 +1,64 @@ +#ifndef CIMModel_HPP +#define CIMModel_HPP + +#include +#include +#include +#include "CIMFile.hpp" +#include "BaseClass.h" + +/** \brief CIM model handler + * + * This model handler organizes the files of a CIM model. It also gives access + * to model description. + * + * The model owns the CIM objects it parses therefore it will free them when the + * model object is destroyed. + */ +class CIMModel +{ +public: + CIMModel(); + ~CIMModel(); + + /** \brief Add a file to the current model + * + * If the file belongs to another model or the file handle is invalid it will + * return false otherwise true. + */ + bool addCIMFile(CIMFile file); + + /** \brief Add a file to the current model + * + * If the file belongs to another model or the path is invalid it will + * return false otherwise true. + */ + bool addCIMFile(std::string path); + + /** \brief Parse CIM Files + * + * This function parses all the CIM files specified in this model + */ + void parseFiles(); + + /** Container to access all the CIM objects */ + std::vector Objects; + + /** \brief Set dependency check on */ + void setDependencyCheckOn(); + + /** \brief Set dependency check off */ + void setDependencyCheckOff(); + + /** \brief get dependency check status */ + bool getDependencyCheck(); + + // Model meta data + +private: + std::list Files; + std::unordered_map RDFMap; + bool DependencyCheck; +}; + +#endif // CIMModel_HPP diff --git a/cimgen/languages/cpp/src/ModelDescription.cpp b/cimgen/languages/cpp/src/ModelDescription.cpp new file mode 100644 index 0000000..cab8f01 --- /dev/null +++ b/cimgen/languages/cpp/src/ModelDescription.cpp @@ -0,0 +1,12 @@ +#include "ModelDescription.hpp" + + +ModelDescription::ModelDescription() +{ + +} + +ModelDescription::~ModelDescription() +{ + +} diff --git a/cimgen/languages/cpp/src/ModelDescription.hpp b/cimgen/languages/cpp/src/ModelDescription.hpp new file mode 100644 index 0000000..11f658d --- /dev/null +++ b/cimgen/languages/cpp/src/ModelDescription.hpp @@ -0,0 +1,26 @@ +#ifndef MODELDESCRIPTION_HPP +#define MODELDESCRIPTION_HPP + +#include +#include + +class ModelDescription +{ +public: + ModelDescription(); + ~ModelDescription(); + + std::string rdfID; + std::string created; + std::string scenarioTime; + std::string version; + std::string description; + std::string modelingAuthoritySet; + std::string profile; + + std::vector dependencyID;//TODO:Besserer Speicher fuer Dependencies? (tree) + + //TODO: Evtl. Suche nach ID im Vector implementieren +}; + +#endif // MODELDESCRIPTION_HPP diff --git a/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp b/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp new file mode 100644 index 0000000..42d78f8 --- /dev/null +++ b/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp @@ -0,0 +1,160 @@ +#include "ModelDescriptionHandler.hpp" +#include "IEC61970/IEC61970CIMVersion.h" + +#ifndef CGMES_BUILD +#include "IEC61970/Base/Domain/String.h" +#include "CIMNamespaces.hpp" +#else +#include "String.hpp" +#endif + +#include +#include +#include + +#include "CIMExceptions.hpp" + +using CIMPP::IEC61970CIMVersion; + +ModelDescriptionHandler::ModelDescriptionHandler() : modelDescription(nullptr) +{ +} + +void ModelDescriptionHandler::setDocumentLocator(const LocatorT &locator) +{} + +void ModelDescriptionHandler::startDocument() +{ + if(modelDescription == nullptr) + throw MissingModelDescription(this); +} + +void ModelDescriptionHandler::endDocument() +{} + +void ModelDescriptionHandler::startPrefixMapping(const std::string &prefix, const std::string &uri) +{ + if(prefix == "cim") + { + std::size_t pos = IEC61970CIMVersion::version.find("CIM"); + std::string versionParser = IEC61970CIMVersion::version.substr(pos+3,2); + + pos = uri.find("cim"); + std::string versionFile = uri.substr(pos+3,2); + + if(versionParser != versionFile) + { + std::cout << "CIM version(" << versionFile << ") in File does not match CIM version(" << versionParser << ") in Parser" << std::endl; + } + } +} + +void ModelDescriptionHandler::endPrefixMapping(const std::string &prefix) +{} + +void ModelDescriptionHandler::startElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName, const AttributesT &atts) +{ + //Only process tags in md namespace + if(qName.find("md:") == std::string::npos) + { + return; + } + + tagStack.push(qName); + + if(qName.find("DependentOn") != std::string::npos) + { + std::string rdfID = get_rdf_resource(atts); + + modelDescription->dependencyID.push_back(rdfID); + } + else if(qName.find("FullModel") != std::string::npos) + { + std::string rdfID = get_rdf_id(atts); + + modelDescription->rdfID = rdfID; + } +} + +void ModelDescriptionHandler::endElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName) +{ + //Only process tags in md namespace + if(qName.find("md:") == std::string::npos) + { + return; + } + + tagStack.pop(); +} + +void ModelDescriptionHandler::characters(const std::string &ch) //TODO:getter +{ + if(!tagStack.empty() && tagStack.top().find("md:") != std::string::npos) + { + std::string name = tagStack.top(); + if(name.find("created") != std::string::npos) + { + modelDescription->created = ch; + } + else if(name.find("scenarioTime") != std::string::npos) + { + modelDescription->scenarioTime = ch; + } + else if(name.find("version") != std::string::npos) + { + modelDescription->version = ch; + } + else if(name.find("description") != std::string::npos) + { + modelDescription->description = ch; + } + else if(name.find("modelingAuthoritySet") != std::string::npos) + { + modelDescription->modelingAuthoritySet = ch; + } + else if(name.find("profile") != std::string::npos) + { + modelDescription->profile = ch; + } + + } + +} + +void ModelDescriptionHandler::ignorableWhitespace(const std::string &ch) +{} + +void ModelDescriptionHandler::processingInstruction(const std::string &target, const std::string &data) +{} + +void ModelDescriptionHandler::skippedEntity(const std::string &name) +{} + +std::string ModelDescriptionHandler::get_rdf_id(const AttributesT &attributes) +{ + for(int i = 0; i < attributes.getLength(); i++) + { + if(attributes.getQName(i) == "rdf:ID") + return attributes.getValue(i); + if(attributes.getQName(i) == "rdf:about") + return attributes.getValue(i).substr(0); + } + return std::string(); +} + +std::string ModelDescriptionHandler::get_rdf_resource(const AttributesT &attributes) //TODO: Resource in get_rdf_id ? +{ + for(int i = 0; i < attributes.getLength(); i++) + { + if(attributes.getQName(i) == "rdf:resource") + { + return attributes.getValue(i).substr(0); + } + } + return std::string(); +} + +void ModelDescriptionHandler::setModelDescription(ModelDescription* mDesc) +{ + modelDescription = mDesc; +} diff --git a/cimgen/languages/cpp/src/ModelDescriptionHandler.hpp b/cimgen/languages/cpp/src/ModelDescriptionHandler.hpp new file mode 100644 index 0000000..3291fb4 --- /dev/null +++ b/cimgen/languages/cpp/src/ModelDescriptionHandler.hpp @@ -0,0 +1,41 @@ +#ifndef MODELDESCRIPTIONHANDLER_HPP +#define MODELDESCRIPTIONHANDLER_HPP + +#include +#include + +#include +#include + +#include "ModelDescription.hpp" + +class ModelDescriptionHandler : public Arabica::SAX::ContentHandler +{ +public: + ModelDescriptionHandler(); + + void setModelDescription(ModelDescription* mDesc); +protected: + void setDocumentLocator(const LocatorT &locator) override; + void startDocument() override; + void endDocument() override; + void startPrefixMapping(const std::string &prefix, const std::string &uri) override; + void endPrefixMapping(const std::string &prefix) override; + void startElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName, const AttributesT &atts) override; + void endElement(const std::string &namespaceURI, const std::string &localName, const std::string &qName) override; + void characters(const std::string &ch) override; + void ignorableWhitespace(const std::string &ch) override; + void processingInstruction(const std::string &target, const std::string &data) override; + void skippedEntity(const std::string &name) override; + + static std::string get_rdf_id(const AttributesT &properties); + static std::string get_rdf_resource(const AttributesT &properties); + +private: + ModelDescription* modelDescription; + + std::stack tagStack; + +}; + +#endif // MODELDESCRIPTIONHANDLER_HPP diff --git a/cimgen/languages/cpp/src/SAXErrorHandler.hpp b/cimgen/languages/cpp/src/SAXErrorHandler.hpp new file mode 100644 index 0000000..40766a5 --- /dev/null +++ b/cimgen/languages/cpp/src/SAXErrorHandler.hpp @@ -0,0 +1,44 @@ +#ifndef SAX_ERRORHANDLER_HPP +#define SAX_ERRORHANDLER_HPP + +#include +#include +#include +#include +#include + +class SAXErrorHandler : public Arabica::SAX::ErrorHandler +{ +private: + std::string saxParser; + +public: + SAXErrorHandler() + { +#ifdef ARABICA_USE_LIBXML2 + saxParser = "Libxml2"; +#elif defined(ARABICA_USE_MSXML) + saxParser = "MSXML"; +#else + saxParser = "SAX Parser"; +#endif + }; + + ~SAXErrorHandler(){}; + + void warning(const SAXParseExceptionT& exception){}; + + void error(const SAXParseExceptionT& exception) + { + std::cerr << saxParser << " encountered an Error:\n" << exception.what() << std::endl; + throw(exception); // SAXParseException is an std::runtime_error + }; + + void fatalError(const SAXParseExceptionT& exception) + { + std::cerr << saxParser << " encountered a Fatal Error:\n" << exception.what() << std::endl; + throw(exception); // SAXParseException is an std::runtime_error + }; +}; + +#endif //SAX_ERRORHANDLER_HPP diff --git a/cimgen/languages/cpp/static/BaseClass.cpp b/cimgen/languages/cpp/static/BaseClass.cpp new file mode 100644 index 0000000..20dc208 --- /dev/null +++ b/cimgen/languages/cpp/static/BaseClass.cpp @@ -0,0 +1,22 @@ + +#include "BaseClass.hpp" + +using namespace CIMPP; + +BaseClass::~BaseClass() {} + +void BaseClass::addConstructToMap(std::unordered_map& factory_map) {} + +void BaseClass::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} + +void BaseClass::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +const char BaseClass::debugName[] = "BaseClass"; +const char* BaseClass::debugString() +{ + return BaseClass::debugName; +} + +CIMPP::BaseClassDefiner BaseClass::declare() { + return BaseClassDefiner(BaseClass::addConstructToMap, BaseClass::addPrimitiveAssignFnsToMap, BaseClass::addClassAssignFnsToMap, BaseClass::debugName); +} diff --git a/cimgen/languages/cpp/static/BaseClass.h b/cimgen/languages/cpp/static/BaseClass.h new file mode 100644 index 0000000..d1ebb81 --- /dev/null +++ b/cimgen/languages/cpp/static/BaseClass.h @@ -0,0 +1 @@ +#include "BaseClass.hpp" diff --git a/cimgen/languages/cpp/static/BaseClass.hpp b/cimgen/languages/cpp/static/BaseClass.hpp new file mode 100644 index 0000000..a7cd612 --- /dev/null +++ b/cimgen/languages/cpp/static/BaseClass.hpp @@ -0,0 +1,22 @@ +#ifndef BASECLASS_HPP +#define BASECLASS_HPP + +#ifndef CGMES_BUILD +#define CGMES_BUILD +#endif + +#include +#include "BaseClassDefiner.hpp" + +class BaseClass { +public: + enum cgmesProfile {EQ = 0, SSH = 1, TP = 2, SV = 3, DY = 4, GL = 5, DI = 6}; + virtual ~BaseClass(); + static CIMPP::BaseClassDefiner declare(); + static void addConstructToMap(std::unordered_map&); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + const static char debugName[]; + virtual const char* debugString(); +}; +#endif // BASECLASS_HPP diff --git a/cimgen/languages/cpp/static/BaseClassDefiner.cpp b/cimgen/languages/cpp/static/BaseClassDefiner.cpp new file mode 100644 index 0000000..95bcb95 --- /dev/null +++ b/cimgen/languages/cpp/static/BaseClassDefiner.cpp @@ -0,0 +1,14 @@ + +#include "BaseClassDefiner.hpp" + +using namespace CIMPP; + +BaseClassDefiner::BaseClassDefiner(void(*addConstruct)(std::unordered_map&), + void(*addPrimitiveAssignFns)(std::unordered_map&), + void(*addClassAssignFns)(std::unordered_map&), + const char *debugStr) { + addConstructToMap = addConstruct; + addPrimitiveAssignFnsToMap = addPrimitiveAssignFns; + addClassAssignFnsToMap = addClassAssignFns; + debugString = debugStr; +} diff --git a/cimgen/languages/cpp/static/BaseClassDefiner.hpp b/cimgen/languages/cpp/static/BaseClassDefiner.hpp new file mode 100644 index 0000000..a873538 --- /dev/null +++ b/cimgen/languages/cpp/static/BaseClassDefiner.hpp @@ -0,0 +1,24 @@ +#ifndef BASECLASSDEFINER_HPP +#define BASECLASSDEFINER_HPP + +#include +#include + +class BaseClass; +typedef bool (*class_assign_function)(BaseClass*, BaseClass*); +typedef bool (*assign_function)(std::stringstream&, BaseClass*); +namespace CIMPP { + + class BaseClassDefiner { + public: + BaseClassDefiner(void(*addConstruct)(std::unordered_map&), + void(*addPrimitiveAssignFns)(std::unordered_map&), + void(*addClassAssignFns)(std::unordered_map&), + const char *debugStr); + void (*addConstructToMap)(std::unordered_map&); + void (*addPrimitiveAssignFnsToMap)(std::unordered_map&); + void (*addClassAssignFnsToMap)(std::unordered_map&); + const char* debugString; + }; +} +#endif // BASECLASSDEFINER diff --git a/cimgen/languages/cpp/static/Boolean.cpp b/cimgen/languages/cpp/static/Boolean.cpp new file mode 100644 index 0000000..35f7fa9 --- /dev/null +++ b/cimgen/languages/cpp/static/Boolean.cpp @@ -0,0 +1,80 @@ +#include "Boolean.hpp" +#include "CIMExceptions.hpp" + +using namespace CIMPP; + +Boolean::Boolean(){} + +Boolean::~Boolean(){} + +Boolean::Boolean(bool value) + : value(value), initialized(true) {} + +const BaseClassDefiner Boolean::declare() +{ + return BaseClassDefiner(Boolean::addConstructToMap, Boolean::addPrimitiveAssignFnsToMap, Boolean::addClassAssignFnsToMap, Boolean::debugName); +} + +Boolean& Boolean::operator=(bool &rop) +{ + value = rop; + initialized = true; + return *this; +} + +Boolean::operator bool() +{ + if(!initialized) + { + throw new ReadingUninitializedField(); + } + return value; +} + +void Boolean::addConstructToMap(std::unordered_map& factory_map) {} + +void Boolean::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} + +void Boolean::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +const char Boolean::debugName[] = "Boolean"; +const char* Boolean::debugString() +{ + return Boolean::debugName; +} + +namespace CIMPP { + std::istream& operator>>(std::istream& lop, Boolean& rop) + { + std::string tmp; + lop >> tmp; + if(tmp == "true" || tmp == "True" || tmp == "TRUE") + { + rop.value = true; + rop.initialized = true; + return lop; + } + if(tmp == "false" || tmp == "False" || tmp == "FALSE") + { + rop.value = false; + rop.initialized = true; + return lop; + } + else + { + lop.setstate(std::ios::failbit); + return lop; + } + } + + std::ostream& operator<<(std::ostream& os, Boolean& rop) + { + if (rop) { + os << "true"; + } + else { + os << "false"; + } + return os; + } +} diff --git a/cimgen/languages/cpp/static/Boolean.hpp b/cimgen/languages/cpp/static/Boolean.hpp new file mode 100644 index 0000000..34e30d1 --- /dev/null +++ b/cimgen/languages/cpp/static/Boolean.hpp @@ -0,0 +1,38 @@ +#ifndef BOOLEAN_H +#define BOOLEAN_H + +#include +#include +#include + +#include "BaseClass.hpp" + +namespace CIMPP { + /** + * A type with the value space "true" and "false". + */ + class Boolean + { + public: + Boolean(); + virtual ~Boolean(); + static const BaseClassDefiner declare(); + + Boolean(bool value); + Boolean& operator=(bool &rop); + friend std::istream& operator>>(std::istream& lop, Boolean& rop); + friend std::ostream& operator<<(std::ostream& os, Boolean& rop); + operator bool(); + + bool value = false; + bool initialized = false; + + static const char debugName[]; + virtual const char* debugString(); + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + }; +} +#endif diff --git a/cimgen/languages/cpp/static/CIMFactory.cpp b/cimgen/languages/cpp/static/CIMFactory.cpp new file mode 100644 index 0000000..a2ed2e7 --- /dev/null +++ b/cimgen/languages/cpp/static/CIMFactory.cpp @@ -0,0 +1,44 @@ +#include "CIMFactory.hpp" +#include "Folders.hpp" +#include "CIMClassList.hpp" +#include +#include + +using namespace CIMPP; + +static std::unordered_map initialize(); +std::unordered_map CIMFactory::factory_map = initialize(); + +BaseClass* CIMFactory::CreateNew(const std::string& name) { + std::unordered_map::iterator it = factory_map.find(name); + if(it != factory_map.end()) { + return (*it->second)(); + } + else { + std::cerr << "!! ** Could not find factory for " << name << " ** !!" << std::endl; + return nullptr; + } +} + +bool CIMFactory::IsCIMClass(const std::string& name) { + std::unordered_map::iterator it = factory_map.find(name); + if(it == factory_map.end()) { + return false; + } + else { + return true; + } +} + +CIMFactory::CIMFactory() {} + +CIMFactory::~CIMFactory() {} + +static std::unordered_map initialize() { + std::unordered_map map; + for (const BaseClassDefiner& CIMClass : CIMClassList) + { + CIMClass.addConstructToMap(map); + } + return map; +} diff --git a/cimgen/languages/cpp/static/CIMFactory.hpp b/cimgen/languages/cpp/static/CIMFactory.hpp new file mode 100644 index 0000000..9e3cbe4 --- /dev/null +++ b/cimgen/languages/cpp/static/CIMFactory.hpp @@ -0,0 +1,22 @@ +#ifndef CIMFACTORY_HPP +#define CIMFACTORY_HPP + +#include +#include +#include "BaseClass.hpp" + +namespace CIMPP { + + class CIMFactory + { + public: + CIMFactory(); + virtual ~CIMFactory(); + static BaseClass* CreateNew(const std::string& name); + static bool IsCIMClass(const std::string& name); + + private: + static std::unordered_map factory_map; + }; +} +#endif // CIMFACTORY_HPP diff --git a/cimgen/languages/cpp/static/Date.cpp b/cimgen/languages/cpp/static/Date.cpp new file mode 100644 index 0000000..79a800c --- /dev/null +++ b/cimgen/languages/cpp/static/Date.cpp @@ -0,0 +1,20 @@ + +#include "BaseClass.hpp" +#include "Date.hpp" +#include "String.hpp" + +using namespace CIMPP; + +Date::Date() {} + +Date::Date(String s) +{ + value=s; +} + +Date::~Date() {} + +BaseClass* Date_factory() +{ + return new Date; +} diff --git a/cimgen/languages/cpp/static/Date.hpp b/cimgen/languages/cpp/static/Date.hpp new file mode 100644 index 0000000..6027d6e --- /dev/null +++ b/cimgen/languages/cpp/static/Date.hpp @@ -0,0 +1,26 @@ +#ifndef Date_H +#define Date_H + +#include "BaseClass.hpp" +#include "String.hpp" + + +/* +Date as "yyyy-mm-dd", which conforms with ISO 8601. UTC time zone is specified as "yyyy-mm-ddZ". A local timezone relative UTC is specified as "yyyy-mm-dd(+/-)hh:mm". +*/ +namespace CIMPP { + + class Date: public BaseClass + { + public: + Date(); + Date(String); + virtual ~Date(); + + private: + String value; + }; + + BaseClass* Date_factory(); +} +#endif diff --git a/cimgen/languages/cpp/static/Float.cpp b/cimgen/languages/cpp/static/Float.cpp new file mode 100644 index 0000000..4daa766 --- /dev/null +++ b/cimgen/languages/cpp/static/Float.cpp @@ -0,0 +1,67 @@ +#include "Float.hpp" +#include "CIMExceptions.hpp" + +using namespace CIMPP; + +Float::Float(){} + +Float::~Float(){} + +Float::Float(long double value) : value(value), initialized(true) {} + +void Float::addConstructToMap(std::unordered_map& factory_map) {} + +void Float::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} + +void Float::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +const char Float::debugName[] = "Float"; +const char* Float::debugString() { + return Float::debugName; +} + +const BaseClassDefiner Float::declare() { + return BaseClassDefiner(Float::addConstructToMap, Float::addPrimitiveAssignFnsToMap, Float::addClassAssignFnsToMap, Float::debugName); +} + +Float& Float::operator=(long double &rop) { + value = rop; + initialized = true; + return *this; +} + +Float& Float::operator-=(const Float& rhs) { + value -= rhs.value; + return *this; +} + +Float& Float::operator*=(const Float& rhs) { + value *= rhs.value; + return *this; +} + +Float& Float::operator/=(const Float& rhs) { + value /= rhs.value; + return *this; +} + +Float& Float::operator+=(const Float& rhs) { + value += rhs.value; + return *this; +} + +Float::operator long double() { + if(!initialized) + { + throw new ReadingUninitializedField(); + } + return value; +} + +std::istream& operator>>(std::istream& lop, Float& rop) { + std::string tmp; + lop >> tmp; + rop.value = stold(tmp); + rop.initialized = true; + return lop; +} diff --git a/cimgen/languages/cpp/static/Float.hpp b/cimgen/languages/cpp/static/Float.hpp new file mode 100644 index 0000000..ab30f43 --- /dev/null +++ b/cimgen/languages/cpp/static/Float.hpp @@ -0,0 +1,42 @@ +#ifndef FLOAT_H +#define FLOAT_H + +#include +#include +#include + +#include "BaseClass.hpp" + +namespace CIMPP { + + /** + * A floating point number. The range is unspecified and not limited. + */ + class Float : public BaseClass + { + + public: + Float(); + virtual ~Float(); + Float(long double value); + static const BaseClassDefiner declare(); + Float& operator=(long double &rop); + Float& operator+=(const Float& rhs); + Float& operator-=(const Float& rhs); + Float& operator*=(const Float& rhs); + Float& operator/=(const Float& rhs); + friend std::istream& operator>>(std::istream& lop, Float& rop); + operator long double(); + + long double value = 0.0; + bool initialized = false; + + static const char debugName[]; + virtual const char* debugString(); + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + }; +} +#endif // FLOAT_H diff --git a/cimgen/languages/cpp/static/Folders.hpp b/cimgen/languages/cpp/static/Folders.hpp new file mode 100644 index 0000000..275606d --- /dev/null +++ b/cimgen/languages/cpp/static/Folders.hpp @@ -0,0 +1 @@ +#include "IEC61970.hpp" diff --git a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp new file mode 100644 index 0000000..c769c52 --- /dev/null +++ b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp @@ -0,0 +1,15 @@ +/////////////////////////////////////////////////////////// +// IEC61970CIMVersion.cpp +// Implementation of the Class IEC61970CIMVersion +/////////////////////////////////////////////////////////// + +#include "IEC61970CIMVersion.h" + +using namespace CIMPP; + +IEC61970CIMVersion::IEC61970CIMVersion(){} + +IEC61970CIMVersion::~IEC61970CIMVersion(){} + +const Date IEC61970CIMVersion::date = Date("2017-07-26"); +const String IEC61970CIMVersion::version = "IEC61970CIM17v23"; diff --git a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h new file mode 100644 index 0000000..61a9e29 --- /dev/null +++ b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////// +// IEC61970CIMVersion.h +// Implementation of the Class IEC61970CIMVersion +/////////////////////////////////////////////////////////// + +#ifndef IEC61970CIMVERSION_H +#define IEC61970CIMVERSION_H + +#include "BaseClass.hpp" +#include "Date.hpp" +#include "String.hpp" + +namespace CIMPP { + + class IEC61970CIMVersion : public BaseClass + { + public: + IEC61970CIMVersion(); + virtual ~IEC61970CIMVersion(); + /** + * Form is YYYY-MM-DD for example for January 5, 2009 it is 2009-01-05. + */ + static const Date date; + /** + * Form is IEC61970CIMXXvYY where XX is the major CIM package version and the YY + * is the minor version. For example IEC61970CIM13v18. + */ + static const String version; + }; +} +#endif // IEC61970CIMVERSION_H diff --git a/cimgen/languages/cpp/static/Integer.cpp b/cimgen/languages/cpp/static/Integer.cpp new file mode 100644 index 0000000..638dd41 --- /dev/null +++ b/cimgen/languages/cpp/static/Integer.cpp @@ -0,0 +1,72 @@ +#include "Integer.hpp" +#include "CIMExceptions.hpp" + +using namespace CIMPP; + +Integer::Integer(){} + +Integer::~Integer(){} + +Integer::Integer(long int value) + : value(value), initialized(true) {} + +const BaseClassDefiner Integer::declare() { + return BaseClassDefiner(Integer::addConstructToMap, Integer::addPrimitiveAssignFnsToMap, Integer::addClassAssignFnsToMap, Integer::debugName); +} + +const char Integer::debugName[] = "Integer"; +const char* Integer::debugString() { + return Integer::debugName; +} + +void Integer::addConstructToMap(std::unordered_map& factory_map) {} + +void Integer::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} + +void Integer::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +namespace CIMPP { + Integer& Integer::operator=(long int &rop){ + value = rop; + initialized = true; + return *this; + } + + Integer& Integer::operator-=(const Integer& rhs){ + value -= rhs.value; + return *this; + } + + Integer& Integer::operator*=(const Integer& rhs){ + value *= rhs.value; + return *this; + } + + Integer& Integer::operator/=(const Integer& rhs){ + value /= rhs.value; + return *this; + } + + Integer& Integer::operator+=(const Integer& rhs){ + value += rhs.value; + return *this; + } + + Integer::operator long int(){ + if(!initialized) + { + throw new ReadingUninitializedField(); + } + return value; + } + + std::istream& operator>>(std::istream& lop, Integer& rop) + { + std::string tmp; + lop >> tmp; + + rop.value = stol(tmp); + rop.initialized = true; + return lop; + } +} diff --git a/cimgen/languages/cpp/static/Integer.hpp b/cimgen/languages/cpp/static/Integer.hpp new file mode 100644 index 0000000..a39f6c8 --- /dev/null +++ b/cimgen/languages/cpp/static/Integer.hpp @@ -0,0 +1,41 @@ +#ifndef INTEGER_H +#define INTEGER_H + +#include +#include +#include + +#include "BaseClass.hpp" + +namespace CIMPP { + + /** + * An Integer number. The range is unspecified and not limited. + */ + class Integer + { + public: + Integer(); + Integer(long int value); + virtual ~Integer(); + static const BaseClassDefiner declare(); + Integer& operator=(long int &rop); + Integer& operator+=(const Integer& rhs); + Integer& operator-=(const Integer& rhs); + Integer& operator*=(const Integer& rhs); + Integer& operator/=(const Integer& rhs); + friend std::istream& operator>>(std::istream& lop, Integer& rop); + operator long int(); + + long int value = 0; + bool initialized = false; + + static const char debugName[]; + virtual const char* debugString(); + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + }; +} +#endif // INTEGER_H diff --git a/cimgen/languages/cpp/static/String.hpp b/cimgen/languages/cpp/static/String.hpp new file mode 100644 index 0000000..9ed6033 --- /dev/null +++ b/cimgen/languages/cpp/static/String.hpp @@ -0,0 +1,14 @@ +#ifndef STRING_H +#define STRING_H + +#include "BaseClass.hpp" +#include "string" + +/* +A string consisting of a sequence of characters. The character encoding is UTF-8. The string length is unspecified and unlimited. +*/ +namespace CIMPP { + + typedef std::string String; +} +#endif diff --git a/cimgen/languages/cpp/static/Task.cpp b/cimgen/languages/cpp/static/Task.cpp new file mode 100644 index 0000000..6fc4737 --- /dev/null +++ b/cimgen/languages/cpp/static/Task.cpp @@ -0,0 +1,57 @@ +#include + +#include "Folders.hpp" +#include "CIMClassList.hpp" +#include "Task.hpp" + +using namespace CIMPP; + +typedef bool (*task_function)(BaseClass*, BaseClass*); +static std::unordered_map initialize(); +std::unordered_map Task::dynamic_switch = initialize(); + +Task::Task() {} + +Task::Task(BaseClass* CIMObj, const std::string CIMAttrName, const std::string Value) + : _CIMObj(CIMObj), _CIMAttrName(CIMAttrName), _Value(Value) {} + +Task::~Task() {} + +void Task::print() +{ + if(IdentifiedObject* IdObj = dynamic_cast(_CIMObj)) + std::cout << _CIMAttrName << " '" << IdObj->name << "' = '" << _Value << "'" << std::endl; + else + std::cout << _CIMAttrName << " = '" << _Value << "'" << std::endl; + +} + +bool Task::resolve(std::unordered_map *RDFMap) +{ + std::unordered_map::iterator it_id = RDFMap->find(_Value); + if(it_id == RDFMap->end()) { + std::cerr << "Couldn't find " << _CIMAttrName << " with value: " << _Value << " in RDFMap." << std::endl; + return false; + } + + std::unordered_map::iterator it_func = dynamic_switch.find(_CIMAttrName); + if(it_func == dynamic_switch.end()) { + std::cerr << "Couldn't find " << _CIMAttrName << " in dynamic_switch map." << std::endl; + return false; + } + + if((*it_func->second)(_CIMObj, it_id->second)) + return true; + else + return (*it_func->second)(it_id->second, _CIMObj); +} + +static std::unordered_map initialize() +{ + std::unordered_map object_map; + for (const BaseClassDefiner& CIMClass : CIMClassList) { + CIMClass.addClassAssignFnsToMap(object_map); + } + + return object_map; +} diff --git a/cimgen/languages/cpp/static/Task.hpp b/cimgen/languages/cpp/static/Task.hpp new file mode 100644 index 0000000..2dd484a --- /dev/null +++ b/cimgen/languages/cpp/static/Task.hpp @@ -0,0 +1,22 @@ +#ifndef TASK_HPP +#define TASK_HPP + +#include +#include +#include "BaseClass.hpp" + +class Task +{ +public: + Task(); + Task(BaseClass* CIMObj, const std::string CIMAttrName, const std::string Value); + ~Task(); + bool resolve(std::unordered_map *RDFMap); + void print(); +private: + BaseClass* _CIMObj; + std::string _CIMAttrName; + std::string _Value; + static std::unordered_map dynamic_switch; +}; +#endif // TASK_HPP diff --git a/cimgen/languages/cpp/static/UnknownType.cpp b/cimgen/languages/cpp/static/UnknownType.cpp new file mode 100644 index 0000000..1518151 --- /dev/null +++ b/cimgen/languages/cpp/static/UnknownType.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "BaseClass.hpp" +#include "UnknownType.hpp" + +using namespace CIMPP; + +UnknownType::UnknownType() {}; + +UnknownType::~UnknownType() {}; + +bool seenAttribute(std::string name, std::string value) { + static std::list> seenAttributes; + bool found = false; + for(const std::pair & attribute : seenAttributes) { + if (name == attribute.first && value == attribute.second) { + found = true; + + } + } + if (!found) { + seenAttributes.push_back(std::pair(name, value)); + } + return found; +} + +bool assign_Unknown_Attribute(std::stringstream &buffer, std::string name) { + std::string attribute; + buffer >> attribute; + if(buffer.fail()) { + return false; + } + else if (!seenAttribute(name, attribute)) { + std::cout << "Warning: could not assign attribute with name: " << name << " and value: " << attribute << std::endl; + } + return true; +} + +bool assign_Name_name(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { + return assign_Unknown_Attribute(buffer, "cim:Name.name"); +} + +bool assign_NameType_name(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { + return assign_Unknown_Attribute(buffer, "cim:NameType.name"); +} + +bool assign_Name_IdentifiedObject(std::stringstream &buffer, BaseClass* BaseClass_ptr1) { + return assign_Unknown_Attribute(buffer, "cim:Name.IdentifiedObject"); +} + +bool assign_ACDCTerminal_connected(std::stringstream &buffer, BaseClass* BaseClass_ptr1); +bool assign_ACDCTerminal_sequenceNumber(std::stringstream &buffer, BaseClass* BaseClass_ptr1); + +bool assign_Unknown_Class(std::string type) { + std::cout << "Warning: could not assign class of unrecognised type " << type << "." << std::endl; + return true; +} + +bool assign_Class_NameType_name(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { + static bool seen = false; + if (seen){ + return true; + } + else { + seen = true; + return assign_Unknown_Class("cim:NameType.name"); + } +} + +bool assign_Class_Name_NameType(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { + static bool seen = false; + if (seen){ + return true; + } + else { + seen = true; + return assign_Unknown_Class("cim:Name.NameType"); + } +} + +bool assign_Class_Name_name(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { + static bool seen = false; + if (seen){ + return true; + } + else { + seen = true; + return assign_Unknown_Class("cim:Name.name"); + } +} + +bool assign_Class_Name_IdentifiedObject(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) { + static bool seen = false; + if (seen){ + return true; + } + else { + seen = true; + return assign_Unknown_Class("cim:Name.IdentifiedObject"); + } +} + +void UnknownType::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) { + assign_map.insert(std::make_pair(std::string("cim:Terminal.sequenceNumber"), &assign_ACDCTerminal_sequenceNumber)); + assign_map.insert(std::make_pair(std::string("cim:Terminal.connected"), &assign_ACDCTerminal_connected)); + assign_map.insert(std::make_pair(std::string("cim:Name.name"), &assign_Name_name)); + assign_map.insert(std::make_pair(std::string("cim:NameType.name"), &assign_NameType_name)); +} + +void UnknownType::addClassAssignFnsToMap(std::unordered_map& assign_map) { + assign_map.insert(std::make_pair(std::string("cim:Name.name"), &assign_Class_Name_name)); + assign_map.insert(std::make_pair(std::string("cim:Name.IdentifiedObject"), &assign_Class_Name_IdentifiedObject)); + assign_map.insert(std::make_pair(std::string("cim:NameType.name"), &assign_Class_NameType_name)); + assign_map.insert(std::make_pair(std::string("cim:Name.NameType"), &assign_Class_Name_NameType)); +} + +namespace CIMPP { + BaseClass* UnknownType_factory() { + return new UnknownType; + } +} + +void UnknownType::addConstructToMap(std::unordered_map& factory_map) { + factory_map.insert(std::make_pair(std::string("cim:NameType"), &UnknownType_factory)); + factory_map.insert(std::make_pair(std::string("cim:Name"), &UnknownType_factory)); +} + +const char UnknownType::debugName[] = "UnknownType"; + +const BaseClassDefiner UnknownType::declare() +{ + return BaseClassDefiner(addConstructToMap, addPrimitiveAssignFnsToMap, addClassAssignFnsToMap, debugName); +} diff --git a/cimgen/languages/cpp/static/UnknownType.hpp b/cimgen/languages/cpp/static/UnknownType.hpp new file mode 100644 index 0000000..6cc8acd --- /dev/null +++ b/cimgen/languages/cpp/static/UnknownType.hpp @@ -0,0 +1,24 @@ +#ifndef UnknownType_H +#define UnknownType_H +#include +#include +#include +#include "BaseClass.hpp" + + +namespace CIMPP { + + class UnknownType: public BaseClass + { +public: + static const char debugName[]; + UnknownType(); + virtual ~UnknownType(); + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map&); + static void addClassAssignFnsToMap(std::unordered_map&); + static const BaseClassDefiner declare(); + }; +} +#endif diff --git a/cimgen/languages/cpp/static/assignments.cpp b/cimgen/languages/cpp/static/assignments.cpp new file mode 100644 index 0000000..b437106 --- /dev/null +++ b/cimgen/languages/cpp/static/assignments.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "Folders.hpp" +#include "CIMClassList.hpp" +#include "assignments.hpp" +#include +#include "BaseClass.hpp" + +using namespace CIMPP; + +static std::unordered_map dynamic_switch_factory(); +static std::unordered_map dynamic_switch = dynamic_switch_factory(); + +bool assign(BaseClass* CIMObj, const std::string& CIMAttrName, const std::string& Value) +{ + std::unordered_map::iterator prim_it = dynamic_switch.find(CIMAttrName); + if(prim_it != dynamic_switch.end()) { + std::stringstream str; + str << Value; + return (*prim_it->second)(str, CIMObj); + } + +#ifdef DEBUG + std::cerr << "Couldn't assign attribute with value: " << Value << " to " << CIMAttrName << " in object of type " << CIMObj->debugString() << std::endl; +#endif + return false; +} + +std::unordered_map dynamic_switch_factory() +{ + std::unordered_map assign_map; + for (const BaseClassDefiner& CIMClass : CIMClassList) + { + CIMClass.addPrimitiveAssignFnsToMap(assign_map); + } + + return assign_map; +} diff --git a/cimgen/languages/cpp/static/assignments.hpp b/cimgen/languages/cpp/static/assignments.hpp new file mode 100644 index 0000000..1492ee2 --- /dev/null +++ b/cimgen/languages/cpp/static/assignments.hpp @@ -0,0 +1,11 @@ +#ifndef ASSIGN_HPP +#define ASSIGN_HPP + +#include +#include "BaseClass.hpp" + +using namespace CIMPP; + +bool assign(BaseClass* CIMObj, const std::string& CIMAttrName, const std::string& Value); + +#endif // ASSIGN_HPP From 75a69aeaef3b3f3daa9b03ef67c1522653a2ee9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 27 Oct 2024 20:58:44 +0100 Subject: [PATCH 19/23] Remove String, Date, Float from static directory (they are now generated) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/static/Date.cpp | 20 -------- cimgen/languages/cpp/static/Date.hpp | 26 ---------- cimgen/languages/cpp/static/Float.cpp | 67 -------------------------- cimgen/languages/cpp/static/Float.hpp | 42 ---------------- cimgen/languages/cpp/static/String.hpp | 14 ------ 5 files changed, 169 deletions(-) delete mode 100644 cimgen/languages/cpp/static/Date.cpp delete mode 100644 cimgen/languages/cpp/static/Date.hpp delete mode 100644 cimgen/languages/cpp/static/Float.cpp delete mode 100644 cimgen/languages/cpp/static/Float.hpp delete mode 100644 cimgen/languages/cpp/static/String.hpp diff --git a/cimgen/languages/cpp/static/Date.cpp b/cimgen/languages/cpp/static/Date.cpp deleted file mode 100644 index 79a800c..0000000 --- a/cimgen/languages/cpp/static/Date.cpp +++ /dev/null @@ -1,20 +0,0 @@ - -#include "BaseClass.hpp" -#include "Date.hpp" -#include "String.hpp" - -using namespace CIMPP; - -Date::Date() {} - -Date::Date(String s) -{ - value=s; -} - -Date::~Date() {} - -BaseClass* Date_factory() -{ - return new Date; -} diff --git a/cimgen/languages/cpp/static/Date.hpp b/cimgen/languages/cpp/static/Date.hpp deleted file mode 100644 index 6027d6e..0000000 --- a/cimgen/languages/cpp/static/Date.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef Date_H -#define Date_H - -#include "BaseClass.hpp" -#include "String.hpp" - - -/* -Date as "yyyy-mm-dd", which conforms with ISO 8601. UTC time zone is specified as "yyyy-mm-ddZ". A local timezone relative UTC is specified as "yyyy-mm-dd(+/-)hh:mm". -*/ -namespace CIMPP { - - class Date: public BaseClass - { - public: - Date(); - Date(String); - virtual ~Date(); - - private: - String value; - }; - - BaseClass* Date_factory(); -} -#endif diff --git a/cimgen/languages/cpp/static/Float.cpp b/cimgen/languages/cpp/static/Float.cpp deleted file mode 100644 index 4daa766..0000000 --- a/cimgen/languages/cpp/static/Float.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "Float.hpp" -#include "CIMExceptions.hpp" - -using namespace CIMPP; - -Float::Float(){} - -Float::~Float(){} - -Float::Float(long double value) : value(value), initialized(true) {} - -void Float::addConstructToMap(std::unordered_map& factory_map) {} - -void Float::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} - -void Float::addClassAssignFnsToMap(std::unordered_map& assign_map) {} - -const char Float::debugName[] = "Float"; -const char* Float::debugString() { - return Float::debugName; -} - -const BaseClassDefiner Float::declare() { - return BaseClassDefiner(Float::addConstructToMap, Float::addPrimitiveAssignFnsToMap, Float::addClassAssignFnsToMap, Float::debugName); -} - -Float& Float::operator=(long double &rop) { - value = rop; - initialized = true; - return *this; -} - -Float& Float::operator-=(const Float& rhs) { - value -= rhs.value; - return *this; -} - -Float& Float::operator*=(const Float& rhs) { - value *= rhs.value; - return *this; -} - -Float& Float::operator/=(const Float& rhs) { - value /= rhs.value; - return *this; -} - -Float& Float::operator+=(const Float& rhs) { - value += rhs.value; - return *this; -} - -Float::operator long double() { - if(!initialized) - { - throw new ReadingUninitializedField(); - } - return value; -} - -std::istream& operator>>(std::istream& lop, Float& rop) { - std::string tmp; - lop >> tmp; - rop.value = stold(tmp); - rop.initialized = true; - return lop; -} diff --git a/cimgen/languages/cpp/static/Float.hpp b/cimgen/languages/cpp/static/Float.hpp deleted file mode 100644 index ab30f43..0000000 --- a/cimgen/languages/cpp/static/Float.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef FLOAT_H -#define FLOAT_H - -#include -#include -#include - -#include "BaseClass.hpp" - -namespace CIMPP { - - /** - * A floating point number. The range is unspecified and not limited. - */ - class Float : public BaseClass - { - - public: - Float(); - virtual ~Float(); - Float(long double value); - static const BaseClassDefiner declare(); - Float& operator=(long double &rop); - Float& operator+=(const Float& rhs); - Float& operator-=(const Float& rhs); - Float& operator*=(const Float& rhs); - Float& operator/=(const Float& rhs); - friend std::istream& operator>>(std::istream& lop, Float& rop); - operator long double(); - - long double value = 0.0; - bool initialized = false; - - static const char debugName[]; - virtual const char* debugString(); - - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); - }; -} -#endif // FLOAT_H diff --git a/cimgen/languages/cpp/static/String.hpp b/cimgen/languages/cpp/static/String.hpp deleted file mode 100644 index 9ed6033..0000000 --- a/cimgen/languages/cpp/static/String.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef STRING_H -#define STRING_H - -#include "BaseClass.hpp" -#include "string" - -/* -A string consisting of a sequence of characters. The character encoding is UTF-8. The string length is unspecified and unlimited. -*/ -namespace CIMPP { - - typedef std::string String; -} -#endif From c60c319848e84e9e46ce3afc327652682e89d68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Sun, 27 Oct 2024 21:19:34 +0100 Subject: [PATCH 20/23] Update static cpp sources and parser classes to new generated String class; unify BaseClass, Integer, Boolean with generated classes; fix debugstring() in UnknownType MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/languages/cpp/src/Aliases.hpp | 106 ------------------ .../languages/cpp/src/AliasesAssignment.hpp | 2 - cimgen/languages/cpp/src/AliasesTask.hpp | 10 -- .../languages/cpp/src/CIMContentHandler.cpp | 11 +- .../cpp/src/ModelDescriptionHandler.cpp | 15 +-- cimgen/languages/cpp/static/BaseClass.cpp | 16 ++- cimgen/languages/cpp/static/BaseClass.hpp | 19 ++-- cimgen/languages/cpp/static/Boolean.cpp | 63 +++++------ cimgen/languages/cpp/static/Boolean.hpp | 31 ++--- .../static/IEC61970/IEC61970CIMVersion.cpp | 6 +- .../cpp/static/IEC61970/IEC61970CIMVersion.h | 28 ++--- cimgen/languages/cpp/static/Integer.cpp | 96 ++++++++-------- cimgen/languages/cpp/static/Integer.hpp | 43 ++++--- cimgen/languages/cpp/static/Task.cpp | 15 +-- cimgen/languages/cpp/static/UnknownType.cpp | 3 + cimgen/languages/cpp/static/UnknownType.hpp | 2 + 16 files changed, 159 insertions(+), 307 deletions(-) delete mode 100644 cimgen/languages/cpp/src/Aliases.hpp delete mode 100644 cimgen/languages/cpp/src/AliasesAssignment.hpp delete mode 100644 cimgen/languages/cpp/src/AliasesTask.hpp diff --git a/cimgen/languages/cpp/src/Aliases.hpp b/cimgen/languages/cpp/src/Aliases.hpp deleted file mode 100644 index 08aaf74..0000000 --- a/cimgen/languages/cpp/src/Aliases.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef ALIASES_HPP -#define ALIASES_HPP - -#include -#include -#include -#include -#include - -#include "IEC61970/IEC61970CIMVersion.h" - -static std::list search_paths = { - "./", - "${CIMPP_ALIASDIR}/", -#ifdef __linux__ - "/usr/share/cimpp/", - "/usr/local/share/cimpp/", - "/usr/share/cimpp/${CIM_VERSION}/", - "/usr/local/share/cimpp/${CIM_VERSION}/", - "${HOME}/.cimpp/" -#elif defined(_WIN32) - "${APPDATA}\\CIMpp\\", - "${APPDATA}\\CIMpp\\${CIM_VERSION}\\" -#endif -}; - -// Update the input string. -static std::string expand_env_variables(std::string str) -{ - static std::regex env("\\$\\{([^}]+)\\}"); - std::smatch match; - while (std::regex_search(str, match, env)) { -#if defined(__linux__) || defined(__APPLE__) - const char *s = getenv(match[1].str().c_str()); -#elif defined(_WIN32) - char *s; - size_t len; - _dupenv_s(&s, &len, match[1].str().c_str()); -#else - #error Unsupported platform -#endif - - const std::string var(s == NULL ? "" : s); - str.replace(match.position(0), match.length(0) , var); - } - - return str; -} - -static std::ifstream find_aliases(const std::string &filename) -{ - std::ifstream file; - std::string path; - std::string::size_type pos; - - // Set CIM_DIR variable if not set - std::string cim_dir = IEC61970::IEC61970CIMVersion::version; - - pos = cim_dir.find("IEC61970CIM"); - if (pos == 0) - cim_dir.erase(0, 11); -#ifdef __linux__ - setenv("CIM_VERSION", cim_dir.c_str(), 1); -#elif defined(_WIN32) - std::string cim_version = "CIM_VERSION=" + cim_dir; - _putenv(cim_version.c_str()); -#endif - - for (std::string &path : search_paths) { - std::string expanded_path = expand_env_variables(path); - - file.open(expanded_path + filename); - if (file.good()) - return file; - } - - return file; -} - -template -void load_aliases(std::unordered_map &map, const std::string &filename) -{ - std::ifstream file = find_aliases(filename); - - if(file.good() && file.is_open()) - { - std::string line; - std::regex expr("^([a-zA-Z0-9:.]*)[\t ,;]+([a-zA-Z0-9:.]*)$"); - std::smatch m; - typename std::unordered_map::iterator it; - - while (std::getline(file, line)) - { - if(std::regex_match(line, m, expr)) - { - it = map.find(m[1]); - if(it != map.end()) - { - map.insert(std::make_pair(m[2], it->second)); - } - } - } - } -} - -#endif // ALIASES_HPP diff --git a/cimgen/languages/cpp/src/AliasesAssignment.hpp b/cimgen/languages/cpp/src/AliasesAssignment.hpp deleted file mode 100644 index 77059f5..0000000 --- a/cimgen/languages/cpp/src/AliasesAssignment.hpp +++ /dev/null @@ -1,2 +0,0 @@ -dynamic_switch.insert(std::make_pair("cim:Terminal.sequenceNumber", &assign_ACDCTerminal_sequenceNumber)); -dynamic_switch.insert(std::make_pair("cim:Terminal.connected", &assign_ACDCTerminal_connected)); diff --git a/cimgen/languages/cpp/src/AliasesTask.hpp b/cimgen/languages/cpp/src/AliasesTask.hpp deleted file mode 100644 index 1666ad7..0000000 --- a/cimgen/languages/cpp/src/AliasesTask.hpp +++ /dev/null @@ -1,10 +0,0 @@ -map.insert(std::make_pair("cim:VoltageLevel.Substation", &assign_Substation_VoltageLevels)); -map.insert(std::make_pair("cim:SubGeographicalRegion.Region", &assign_GeographicalRegion_Regions)); -map.insert(std::make_pair("cim:Equipment.EquipmentContainer", &assign_EquipmentContainer_Equipments)); -map.insert(std::make_pair("cim:DiagramObject.IdentifiedObject", &assign_IdentifiedObject_DiagramObjects)); -map.insert(std::make_pair("cim:DiagramObjectPoint.DiagramObject", &assign_DiagramObject_DiagramObjectPoints)); -map.insert(std::make_pair("cim:Substation.Region", &assign_SubGeographicalRegion_Substations)); -map.insert(std::make_pair("cim:OperationalLimit.OperationalLimitSet", &assign_OperationalLimitSet_OperationalLimitValue)); -map.insert(std::make_pair("cim:ConformLoad.LoadGroup", &assign_ConformLoadGroup_EnergyConsumers)); -map.insert(std::make_pair("cim:LoadGroup.SubLoadArea", &assign_SubLoadArea_LoadGroups)); -map.insert(std::make_pair("cim:SubLoadArea.LoadArea", &assign_LoadArea_SubLoadAreas)); diff --git a/cimgen/languages/cpp/src/CIMContentHandler.cpp b/cimgen/languages/cpp/src/CIMContentHandler.cpp index 5aa026a..036b382 100644 --- a/cimgen/languages/cpp/src/CIMContentHandler.cpp +++ b/cimgen/languages/cpp/src/CIMContentHandler.cpp @@ -1,19 +1,12 @@ #include "CIMContentHandler.hpp" + #include -#include #include -#include - -#include "Folders.hpp" #include "CIMFactory.hpp" #include "assignments.hpp" #include "CIMExceptions.hpp" -#ifndef CGMES_BUILD -#include "CIMNamespaces.hpp" -#endif - CIMContentHandler::CIMContentHandler() : Objects(nullptr), RDFMap(nullptr) { } @@ -133,7 +126,7 @@ void CIMContentHandler::startElement(const std::string &namespaceURI, const std: } // Create a task if the XML element is no CIM class and contains a RDF ID std::string rdf_id = get_rdf_resource(atts); - if(!rdf_id.empty()) + if (!rdf_id.empty()) { taskQueue.push_back(Task(objectStack.top(), qName, rdf_id)); return; diff --git a/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp b/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp index 42d78f8..be0bdb1 100644 --- a/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp +++ b/cimgen/languages/cpp/src/ModelDescriptionHandler.cpp @@ -1,18 +1,10 @@ #include "ModelDescriptionHandler.hpp" -#include "IEC61970/IEC61970CIMVersion.h" - -#ifndef CGMES_BUILD -#include "IEC61970/Base/Domain/String.h" -#include "CIMNamespaces.hpp" -#else -#include "String.hpp" -#endif -#include #include #include #include "CIMExceptions.hpp" +#include "IEC61970/IEC61970CIMVersion.h" using CIMPP::IEC61970CIMVersion; @@ -36,8 +28,9 @@ void ModelDescriptionHandler::startPrefixMapping(const std::string &prefix, cons { if(prefix == "cim") { - std::size_t pos = IEC61970CIMVersion::version.find("CIM"); - std::string versionParser = IEC61970CIMVersion::version.substr(pos+3,2); + std::string version = IEC61970CIMVersion::version; + std::size_t pos = version.find("CIM"); + std::string versionParser = version.substr(pos+3, 2); pos = uri.find("cim"); std::string versionFile = uri.substr(pos+3,2); diff --git a/cimgen/languages/cpp/static/BaseClass.cpp b/cimgen/languages/cpp/static/BaseClass.cpp index 20dc208..ff3a94a 100644 --- a/cimgen/languages/cpp/static/BaseClass.cpp +++ b/cimgen/languages/cpp/static/BaseClass.cpp @@ -1,22 +1,20 @@ - #include "BaseClass.hpp" using namespace CIMPP; BaseClass::~BaseClass() {} -void BaseClass::addConstructToMap(std::unordered_map& factory_map) {} - -void BaseClass::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} - -void BaseClass::addClassAssignFnsToMap(std::unordered_map& assign_map) {} - const char BaseClass::debugName[] = "BaseClass"; -const char* BaseClass::debugString() +const char* BaseClass::debugString() const { return BaseClass::debugName; } -CIMPP::BaseClassDefiner BaseClass::declare() { +void BaseClass::addConstructToMap(std::unordered_map& factory_map) {} +void BaseClass::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} +void BaseClass::addClassAssignFnsToMap(std::unordered_map& assign_map) {} + +const BaseClassDefiner BaseClass::declare() +{ return BaseClassDefiner(BaseClass::addConstructToMap, BaseClass::addPrimitiveAssignFnsToMap, BaseClass::addClassAssignFnsToMap, BaseClass::debugName); } diff --git a/cimgen/languages/cpp/static/BaseClass.hpp b/cimgen/languages/cpp/static/BaseClass.hpp index a7cd612..7af998c 100644 --- a/cimgen/languages/cpp/static/BaseClass.hpp +++ b/cimgen/languages/cpp/static/BaseClass.hpp @@ -5,18 +5,23 @@ #define CGMES_BUILD #endif +#include #include + #include "BaseClassDefiner.hpp" -class BaseClass { +class BaseClass +{ public: enum cgmesProfile {EQ = 0, SSH = 1, TP = 2, SV = 3, DY = 4, GL = 5, DI = 6}; virtual ~BaseClass(); - static CIMPP::BaseClassDefiner declare(); - static void addConstructToMap(std::unordered_map&); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); - const static char debugName[]; - virtual const char* debugString(); + + static const char debugName[]; + virtual const char* debugString() const; + + static void addConstructToMap(std::unordered_map& factory_map); + static void addPrimitiveAssignFnsToMap(std::unordered_map& assign_map); + static void addClassAssignFnsToMap(std::unordered_map& assign_map); + static const CIMPP::BaseClassDefiner declare(); }; #endif // BASECLASS_HPP diff --git a/cimgen/languages/cpp/static/Boolean.cpp b/cimgen/languages/cpp/static/Boolean.cpp index 35f7fa9..1818ab8 100644 --- a/cimgen/languages/cpp/static/Boolean.cpp +++ b/cimgen/languages/cpp/static/Boolean.cpp @@ -1,21 +1,13 @@ #include "Boolean.hpp" -#include "CIMExceptions.hpp" -using namespace CIMPP; - -Boolean::Boolean(){} - -Boolean::~Boolean(){} +#include +#include -Boolean::Boolean(bool value) - : value(value), initialized(true) {} +#include "../src/CIMExceptions.hpp" -const BaseClassDefiner Boolean::declare() -{ - return BaseClassDefiner(Boolean::addConstructToMap, Boolean::addPrimitiveAssignFnsToMap, Boolean::addClassAssignFnsToMap, Boolean::debugName); -} +using namespace CIMPP; -Boolean& Boolean::operator=(bool &rop) +Boolean& Boolean::operator=(bool rop) { value = rop; initialized = true; @@ -24,56 +16,57 @@ Boolean& Boolean::operator=(bool &rop) Boolean::operator bool() { - if(!initialized) + if (!initialized) { throw new ReadingUninitializedField(); } return value; } -void Boolean::addConstructToMap(std::unordered_map& factory_map) {} - -void Boolean::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} - -void Boolean::addClassAssignFnsToMap(std::unordered_map& assign_map) {} - const char Boolean::debugName[] = "Boolean"; -const char* Boolean::debugString() +const char* Boolean::debugString() const { return Boolean::debugName; } -namespace CIMPP { +namespace CIMPP +{ std::istream& operator>>(std::istream& lop, Boolean& rop) { + rop.initialized = false; + std::string tmp; lop >> tmp; - if(tmp == "true" || tmp == "True" || tmp == "TRUE") + + if (tmp == "true" || tmp == "True" || tmp == "TRUE") { rop.value = true; rop.initialized = true; return lop; } - if(tmp == "false" || tmp == "False" || tmp == "FALSE") + if (tmp == "false" || tmp == "False" || tmp == "FALSE") { rop.value = false; rop.initialized = true; return lop; } - else - { - lop.setstate(std::ios::failbit); - return lop; - } + + lop.setstate(std::ios::failbit); + return lop; } - std::ostream& operator<<(std::ostream& os, Boolean& rop) + std::ostream& operator<<(std::ostream& os, const Boolean& obj) { - if (rop) { - os << "true"; - } - else { - os << "false"; + if (obj.initialized) + { + if (obj.value) + { + os << "true"; + } + else + { + os << "false"; + } } return os; } diff --git a/cimgen/languages/cpp/static/Boolean.hpp b/cimgen/languages/cpp/static/Boolean.hpp index 34e30d1..9dc8d09 100644 --- a/cimgen/languages/cpp/static/Boolean.hpp +++ b/cimgen/languages/cpp/static/Boolean.hpp @@ -1,38 +1,31 @@ #ifndef BOOLEAN_H #define BOOLEAN_H -#include -#include #include +#include -#include "BaseClass.hpp" - -namespace CIMPP { +namespace CIMPP +{ /** * A type with the value space "true" and "false". */ class Boolean { public: - Boolean(); - virtual ~Boolean(); - static const BaseClassDefiner declare(); + Boolean() : value(false), initialized(false) {} + Boolean(bool value) : value(value), initialized(true) {} - Boolean(bool value); - Boolean& operator=(bool &rop); - friend std::istream& operator>>(std::istream& lop, Boolean& rop); - friend std::ostream& operator<<(std::ostream& os, Boolean& rop); + Boolean& operator=(bool rop); operator bool(); - bool value = false; - bool initialized = false; + bool value; + bool initialized; static const char debugName[]; - virtual const char* debugString(); + const char* debugString() const; - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); + friend std::istream& operator>>(std::istream& lop, Boolean& rop); + friend std::ostream& operator<<(std::ostream& os, const Boolean& obj); }; } -#endif +#endif // BOOLEAN_H diff --git a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp index c769c52..8cda241 100644 --- a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp +++ b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.cpp @@ -7,9 +7,5 @@ using namespace CIMPP; -IEC61970CIMVersion::IEC61970CIMVersion(){} - -IEC61970CIMVersion::~IEC61970CIMVersion(){} - const Date IEC61970CIMVersion::date = Date("2017-07-26"); -const String IEC61970CIMVersion::version = "IEC61970CIM17v23"; +const String IEC61970CIMVersion::version = String("IEC61970CIM17v23"); diff --git a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h index 61a9e29..5860ce0 100644 --- a/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h +++ b/cimgen/languages/cpp/static/IEC61970/IEC61970CIMVersion.h @@ -1,31 +1,27 @@ +#ifndef IEC61970CIMVERSION_H +#define IEC61970CIMVERSION_H /////////////////////////////////////////////////////////// // IEC61970CIMVersion.h // Implementation of the Class IEC61970CIMVersion /////////////////////////////////////////////////////////// -#ifndef IEC61970CIMVERSION_H -#define IEC61970CIMVERSION_H - -#include "BaseClass.hpp" #include "Date.hpp" #include "String.hpp" namespace CIMPP { - class IEC61970CIMVersion : public BaseClass + class IEC61970CIMVersion { public: - IEC61970CIMVersion(); - virtual ~IEC61970CIMVersion(); - /** - * Form is YYYY-MM-DD for example for January 5, 2009 it is 2009-01-05. - */ - static const Date date; - /** - * Form is IEC61970CIMXXvYY where XX is the major CIM package version and the YY - * is the minor version. For example IEC61970CIM13v18. - */ - static const String version; + /** + * Form is YYYY-MM-DD for example for January 5, 2009 it is 2009-01-05. + */ + static const Date date; + /** + * Form is IEC61970CIMXXvYY where XX is the major CIM package version and the YY + * is the minor version. For example IEC61970CIM13v18. + */ + static const String version; }; } #endif // IEC61970CIMVERSION_H diff --git a/cimgen/languages/cpp/static/Integer.cpp b/cimgen/languages/cpp/static/Integer.cpp index 638dd41..2a1cda4 100644 --- a/cimgen/languages/cpp/static/Integer.cpp +++ b/cimgen/languages/cpp/static/Integer.cpp @@ -1,72 +1,74 @@ #include "Integer.hpp" -#include "CIMExceptions.hpp" -using namespace CIMPP; +#include -Integer::Integer(){} +#include "../src/CIMExceptions.hpp" -Integer::~Integer(){} +using namespace CIMPP; -Integer::Integer(long int value) - : value(value), initialized(true) {} +Integer& Integer::operator=(long int rop) +{ + value = rop; + initialized = true; + return *this; +} -const BaseClassDefiner Integer::declare() { - return BaseClassDefiner(Integer::addConstructToMap, Integer::addPrimitiveAssignFnsToMap, Integer::addClassAssignFnsToMap, Integer::debugName); +Integer::operator long int() +{ + if (!initialized) + { + throw new ReadingUninitializedField(); + } + return value; } const char Integer::debugName[] = "Integer"; -const char* Integer::debugString() { +const char* Integer::debugString() const +{ return Integer::debugName; } -void Integer::addConstructToMap(std::unordered_map& factory_map) {} - -void Integer::addPrimitiveAssignFnsToMap(std::unordered_map& assign_map) {} - -void Integer::addClassAssignFnsToMap(std::unordered_map& assign_map) {} - -namespace CIMPP { - Integer& Integer::operator=(long int &rop){ - value = rop; - initialized = true; - return *this; - } - - Integer& Integer::operator-=(const Integer& rhs){ - value -= rhs.value; - return *this; - } - - Integer& Integer::operator*=(const Integer& rhs){ - value *= rhs.value; - return *this; - } +Integer& Integer::operator+=(const Integer& rhs) +{ + value += rhs.value; + return *this; +} - Integer& Integer::operator/=(const Integer& rhs){ - value /= rhs.value; - return *this; - } +Integer& Integer::operator-=(const Integer& rhs) +{ + value -= rhs.value; + return *this; +} - Integer& Integer::operator+=(const Integer& rhs){ - value += rhs.value; - return *this; - } +Integer& Integer::operator*=(const Integer& rhs) +{ + value *= rhs.value; + return *this; +} - Integer::operator long int(){ - if(!initialized) - { - throw new ReadingUninitializedField(); - } - return value; - } +Integer& Integer::operator/=(const Integer& rhs) +{ + value /= rhs.value; + return *this; +} +namespace CIMPP +{ std::istream& operator>>(std::istream& lop, Integer& rop) { std::string tmp; lop >> tmp; - rop.value = stol(tmp); rop.initialized = true; return lop; } + + std::ostream& operator<<(std::ostream& os, const Integer& obj) + { + if (obj.initialized) + { + os << obj.value; + } + return os; + } } diff --git a/cimgen/languages/cpp/static/Integer.hpp b/cimgen/languages/cpp/static/Integer.hpp index a39f6c8..fab9a71 100644 --- a/cimgen/languages/cpp/static/Integer.hpp +++ b/cimgen/languages/cpp/static/Integer.hpp @@ -1,41 +1,36 @@ #ifndef INTEGER_H #define INTEGER_H -#include -#include #include +#include -#include "BaseClass.hpp" - -namespace CIMPP { - +namespace CIMPP +{ /** - * An Integer number. The range is unspecified and not limited. - */ + * An Integer number. The range is unspecified and not limited. + */ class Integer { public: - Integer(); - Integer(long int value); - virtual ~Integer(); - static const BaseClassDefiner declare(); - Integer& operator=(long int &rop); - Integer& operator+=(const Integer& rhs); - Integer& operator-=(const Integer& rhs); - Integer& operator*=(const Integer& rhs); - Integer& operator/=(const Integer& rhs); - friend std::istream& operator>>(std::istream& lop, Integer& rop); + Integer() : value(0), initialized(false) {} + Integer(long int value) : value(value), initialized(true) {} + + Integer& operator=(long int rop); operator long int(); - long int value = 0; - bool initialized = false; + long int value; + bool initialized; static const char debugName[]; - virtual const char* debugString(); + const char* debugString() const; - static void addConstructToMap(std::unordered_map& factory_map); - static void addPrimitiveAssignFnsToMap(std::unordered_map&); - static void addClassAssignFnsToMap(std::unordered_map&); + Integer& operator+=(const Integer& rhs); + Integer& operator-=(const Integer& rhs); + Integer& operator*=(const Integer& rhs); + Integer& operator/=(const Integer& rhs); + + friend std::istream& operator>>(std::istream& lop, Integer& rop); + friend std::ostream& operator<<(std::ostream& os, const Integer& obj); }; } #endif // INTEGER_H diff --git a/cimgen/languages/cpp/static/Task.cpp b/cimgen/languages/cpp/static/Task.cpp index 6fc4737..be10d25 100644 --- a/cimgen/languages/cpp/static/Task.cpp +++ b/cimgen/languages/cpp/static/Task.cpp @@ -1,8 +1,9 @@ +#include "Task.hpp" + #include -#include "Folders.hpp" +#include "IdentifiedObject.hpp" #include "CIMClassList.hpp" -#include "Task.hpp" using namespace CIMPP; @@ -30,15 +31,15 @@ bool Task::resolve(std::unordered_map *RDFMap) { std::unordered_map::iterator it_id = RDFMap->find(_Value); if(it_id == RDFMap->end()) { - std::cerr << "Couldn't find " << _CIMAttrName << " with value: " << _Value << " in RDFMap." << std::endl; + std::cerr << "Couldn't find " << _CIMAttrName << " with value: " << _Value << " in RDFMap." << std::endl; return false; } std::unordered_map::iterator it_func = dynamic_switch.find(_CIMAttrName); - if(it_func == dynamic_switch.end()) { - std::cerr << "Couldn't find " << _CIMAttrName << " in dynamic_switch map." << std::endl; - return false; - } + if (it_func == dynamic_switch.end()) { + std::cerr << "Couldn't find " << _CIMAttrName << " in dynamic_switch map." << std::endl; + return false; + } if((*it_func->second)(_CIMObj, it_id->second)) return true; diff --git a/cimgen/languages/cpp/static/UnknownType.cpp b/cimgen/languages/cpp/static/UnknownType.cpp index 1518151..fc55a92 100644 --- a/cimgen/languages/cpp/static/UnknownType.cpp +++ b/cimgen/languages/cpp/static/UnknownType.cpp @@ -129,6 +129,9 @@ void UnknownType::addConstructToMap(std::unordered_map Date: Mon, 28 Oct 2024 00:01:56 +0100 Subject: [PATCH 21/23] Fix unused import (pre-commit flake8: cimgen/cimgen.py:5:1: F401 're' imported but unused) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 49e7795..37c6336 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -2,7 +2,6 @@ import os import textwrap import warnings -import re from time import time import xmltodict From 997988e0a5a773c64dfddaedc2b6e7d9a83f983a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Tue, 12 Nov 2024 03:25:23 +0100 Subject: [PATCH 22/23] Add dependency to setuptools to fix ModuleNotFoundError for distutils in modernpython/lang_pack.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Günther --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3c4e017..1f2f8c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,8 @@ dependencies = [ "xmltodict >= 0.13.0, < 1", "chevron >= 0.14.0, < 1", "pydantic < 2", - "beautifulsoup4 >= 4.12.2, < 5" + "beautifulsoup4 >= 4.12.2, < 5", + "setuptools" ] requires-python = ">=3.11" From 0fc5750fbca5c7b62cbdb1b9902154123dfecd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Fri, 15 Nov 2024 02:32:41 +0100 Subject: [PATCH 23/23] Add "is_a_datatype_class" and "is_datatype_attribute" (stereotype == "CIMDatatype"), use these instead of "is_a_float_class" and "is_primitive_float_attribute" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are now 4 disjoint class types: - is_a_datatype_class (= float) - is_an_enum_class - is_a_primitive_class (Integer, Boolean, Float/Decimal = float, String/Date/DateTime/MonthDay = string) - all others are normal classes and 5 disjoint attribute types: - is_class_attribute - is_enum_attribute - is_datatype_attribute - is_list_attribute - is_primitive_attribute Signed-off-by: Thomas Günther --- cimgen/cimgen.py | 45 ++++--------------- cimgen/languages/cpp/lang_pack.py | 26 +++++++---- cimgen/languages/java/lang_pack.py | 14 +++--- cimgen/languages/javascript/lang_pack.py | 10 ++--- cimgen/languages/modernpython/lang_pack.py | 6 ++- .../templates/cimpy_class_template.mustache | 1 + .../utils/export_template.mustache | 6 +++ cimgen/languages/modernpython/utils/writer.py | 1 + 8 files changed, 51 insertions(+), 58 deletions(-) diff --git a/cimgen/cimgen.py b/cimgen/cimgen.py index 37c6336..dfea746 100644 --- a/cimgen/cimgen.py +++ b/cimgen/cimgen.py @@ -246,41 +246,12 @@ def subClasses(self): def setSubClasses(self, classes): self.subclasses = classes - @staticmethod - def _simple_float_attribute(attr): - if "dataType" in attr: - return attr["label"] == "value" and attr["dataType"] == "#Float" - return False - - def is_a_float_class(self): - if self.about in ("Float", "Decimal"): - return True - simple_float = False - for attr in self.attribute_list: - if CIMComponentDefinition._simple_float_attribute(attr): - simple_float = True - for attr in self.attribute_list: - if not CIMComponentDefinition._simple_float_attribute(attr): - simple_float = False - if simple_float: - return True - - candidate_array = {"value": False, "unit": False, "multiplier": False} - optional_attributes = ["denominatorUnit", "denominatorMultiplier"] - for attr in self.attribute_list: - key = attr["label"] - if key in candidate_array: - candidate_array[key] = True - elif key not in optional_attributes: - return False - for key in candidate_array: - if not candidate_array[key]: - return False - return True - def is_a_primitive_class(self): return self.stereotype == "Primitive" + def is_a_datatype_class(self): + return self.stereotype == "CIMDatatype" + def wrap_and_clean(txt: str, width: int = 120, initial_indent="", subsequent_indent=" ") -> str: """ @@ -460,8 +431,8 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): "class_origin": elem_dict[class_name].origins(), "enum_instances": elem_dict[class_name].enum_instances(), "is_an_enum_class": elem_dict[class_name].is_an_enum_class(), - "is_a_float_class": elem_dict[class_name].is_a_float_class(), "is_a_primitive_class": elem_dict[class_name].is_a_primitive_class(), + "is_a_datatype_class": elem_dict[class_name].is_a_datatype_class(), "langPack": lang_pack, "sub_class_of": elem_dict[class_name].superClass(), "sub_classes": elem_dict[class_name].subClasses(), @@ -494,7 +465,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version): attribute["is_enum_attribute"] = _get_bool_string(attribute_type == "enum") attribute["is_list_attribute"] = _get_bool_string(attribute_type == "list") attribute["is_primitive_attribute"] = _get_bool_string(attribute_type == "primitive") - attribute["is_primitive_float_attribute"] = _get_bool_string(elem_dict[attribute_class].is_a_float_class()) + attribute["is_datatype_attribute"] = _get_bool_string(attribute_type == "datatype") attribute["attribute_class"] = attribute_class class_details["attributes"].sort(key=lambda d: d["label"]) @@ -760,14 +731,16 @@ def _get_attribute_class(attribute: dict) -> str: def _get_attribute_type(attribute: dict, class_infos: CIMComponentDefinition) -> str: - """Get the type of an attribute: "class", "enum", "list", or "primitive". + """Get the type of an attribute: "class", "datatype", "enum", "list", or "primitive". :param attribute: Dictionary with information about an attribute of a class. :param class_infos: Information about the attribute class. :return: Type of the attribute. """ attribute_type = "class" - if class_infos.is_a_primitive_class() or class_infos.is_a_float_class(): + if class_infos.is_a_datatype_class(): + attribute_type = "datatype" + elif class_infos.is_a_primitive_class(): attribute_type = "primitive" elif class_infos.is_an_enum_class(): attribute_type = "enum" diff --git a/cimgen/languages/cpp/lang_pack.py b/cimgen/languages/cpp/lang_pack.py index 2e02938..f4bc29b 100644 --- a/cimgen/languages/cpp/lang_pack.py +++ b/cimgen/languages/cpp/lang_pack.py @@ -60,7 +60,7 @@ def get_class_location(class_name, class_map, version): # NOSONAR # This is the function that runs the template. def run_template(output_path, class_details): - if class_details["is_a_float_class"]: + if class_details["is_a_datatype_class"] or class_details["class_name"] in ("Float", "Decimal"): templates = float_template_files elif class_details["is_an_enum_class"]: templates = enum_template_files @@ -110,7 +110,7 @@ def label(text, render): def insert_assign_fn(text, render): attribute_txt = render(text) attribute_json = eval(attribute_txt) - if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]): + if not _attribute_is_primitive_or_datatype_or_enum(attribute_json): return "" label = attribute_json["label"] class_name = attribute_json["domain"] @@ -130,7 +130,7 @@ def insert_assign_fn(text, render): def insert_class_assign_fn(text, render): attribute_txt = render(text) attribute_json = eval(attribute_txt) - if attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute_json): return "" label = attribute_json["label"] class_name = attribute_json["domain"] @@ -171,7 +171,7 @@ def create_class_assign(text, render): attribute_json = eval(attribute_txt) assign = "" attribute_class = attribute_json["attribute_class"] - if attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute_json): return "" if attribute_json["is_list_attribute"]: if "inverseRole" in attribute_json: @@ -277,7 +277,7 @@ def create_assign(text, render): attribute_json = eval(attribute_txt) assign = "" _class = attribute_json["attribute_class"] - if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]): + if not _attribute_is_primitive_or_datatype_or_enum(attribute_json): return "" label_without_keyword = attribute_json["label"] if label_without_keyword == "switch": @@ -285,8 +285,8 @@ def create_assign(text, render): if ( attribute_json["is_enum_attribute"] - or attribute_json["is_primitive_float_attribute"] - or _class in ("Integer", "Boolean") + or attribute_json["is_datatype_attribute"] + or _class in ("Float", "Decimal", "Integer", "Boolean") ): assign = ( """ @@ -337,7 +337,7 @@ def attribute_decl(text, render): def _attribute_decl(attribute): _class = attribute["attribute_class"] - if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute): return "CIMPP::" + _class if attribute["is_list_attribute"]: return "std::list" @@ -354,7 +354,7 @@ def _create_attribute_includes(text, render): if jsonStringNoHtmlEsc is not None and jsonStringNoHtmlEsc != "": attributes = json.loads(jsonStringNoHtmlEsc) for attribute in attributes: - if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute): unique[attribute["attribute_class"]] = True for clarse in sorted(unique): include_string += '#include "' + clarse + '.hpp"\n' @@ -404,6 +404,14 @@ def set_default(dataType): return "nullptr" +def _attribute_is_primitive_or_datatype_or_enum(attribute: dict) -> bool: + return _attribute_is_primitive_or_datatype(attribute) or attribute["is_enum_attribute"] + + +def _attribute_is_primitive_or_datatype(attribute: dict) -> bool: + return attribute["is_primitive_attribute"] or attribute["is_datatype_attribute"] + + # The code below this line is used after the main cim_generate phase to generate # two include files. They are called CIMClassList.hpp and IEC61970.hpp, and # contain the list of the class files and the list of define functions that add diff --git a/cimgen/languages/java/lang_pack.py b/cimgen/languages/java/lang_pack.py index fa47d30..2e088a6 100644 --- a/cimgen/languages/java/lang_pack.py +++ b/cimgen/languages/java/lang_pack.py @@ -47,10 +47,10 @@ def run_template(output_path, class_details): class_details["primitives"] = [] for attr in class_details["attributes"]: - if attr["is_primitive_attribute"] or attr["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attr): class_details["primitives"].append(attr) - if class_details["is_a_float_class"]: + if class_details["is_a_datatype_class"] or class_details["class_name"] in ("Float", "Decimal"): templates = float_template_files elif class_details["is_an_enum_class"]: templates = enum_template_files @@ -103,7 +103,7 @@ def create_assign(text, render): attribute_json = eval(attribute_txt) assign = "" _class = attribute_json["attribute_class"] - if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]): + if not _attribute_is_primitive_or_datatype_or_enum(attribute_json): return "" label_without_keyword = attribute_json["label"] if label_without_keyword == "switch": @@ -140,7 +140,7 @@ def attribute_decl(text, render): def _attribute_decl(attribute): _class = attribute["attribute_class"] - if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute): return _class if attribute["is_list_attribute"]: return "List<" + _class + ">" @@ -157,7 +157,7 @@ def _create_attribute_includes(text, render): if jsonStringNoHtmlEsc is not None and jsonStringNoHtmlEsc != "": attributes = json.loads(jsonStringNoHtmlEsc) for attribute in attributes: - if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]: + if _attribute_is_primitive_or_datatype_or_enum(attribute): unique[attribute["attribute_class"]] = True for clarse in unique: if clarse != "String": @@ -206,6 +206,10 @@ def set_default(dataType): return "nullptr" +def _attribute_is_primitive_or_datatype_or_enum(attribute: dict) -> bool: + return attribute["is_primitive_attribute"] or attribute["is_datatype_attribute"] or attribute["is_enum_attribute"] + + # The code below this line is used after the main cim_generate phase to generate # two include files. They are called CIMClassList.hpp and IEC61970.hpp, and # contain the list of the class files and the list of define functions that add diff --git a/cimgen/languages/javascript/lang_pack.py b/cimgen/languages/javascript/lang_pack.py index a0e1596..6a00d23 100644 --- a/cimgen/languages/javascript/lang_pack.py +++ b/cimgen/languages/javascript/lang_pack.py @@ -76,7 +76,9 @@ def get_class_location(class_name, class_map, version): # NOSONAR def select_primitive_render_function(class_details): class_name = class_details["class_name"] render = "" - if class_details["is_a_float_class"]: + if class_details["is_a_datatype_class"]: + render = aggregateRenderer["renderFloat"] + elif class_name in ("Float", "Decimal"): render = aggregateRenderer["renderFloat"] elif class_name == "String": render = aggregateRenderer["renderString"] @@ -88,9 +90,6 @@ def select_primitive_render_function(class_details): elif class_name == "DateTime": # TODO: Implementation Required! render = aggregateRenderer["renderString"] - elif class_name == "Decimal": - # TODO: Implementation Required! - render = aggregateRenderer["renderString"] elif class_name == "Integer": # TODO: Implementation Required! render = aggregateRenderer["renderString"] @@ -158,8 +157,7 @@ def _create_cgmes_profile(output_path: str, profile_details: list, cim_namespace def _get_class_type(class_details): - class_name = class_details["class_name"] - if class_details["is_a_float_class"] or class_name in ("String", "Boolean", "Integer"): + if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]: return "primitive" if class_details["is_an_enum_class"]: return "enum" diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index d25f903..99685bf 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -63,7 +63,9 @@ def _get_type_and_default(text, render) -> tuple[str, str]: return ("Optional[str]", "default=None") elif attribute_json["is_list_attribute"]: return ("list", "default_factory=list") - elif attribute_json["is_primitive_float_attribute"]: + elif attribute_json["is_datatype_attribute"]: + return ("float", "default=0.0") + elif attribute_json["attribute_class"] in ("Float", "Decimal"): return ("float", "default=0.0") elif attribute_json["attribute_class"] == "Integer": return ("int", "default=0") @@ -75,7 +77,7 @@ def _get_type_and_default(text, render) -> tuple[str, str]: def run_template(output_path, class_details): - if class_details["is_a_primitive_class"] or class_details["is_a_float_class"]: + if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]: return for template_info in template_files: resource_file = Path( diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index e6e9491..58ba391 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -33,6 +33,7 @@ class {{class_name}}({{sub_class_of}}): ], "is_used": {{#is_used}}True{{/is_used}}{{^is_used}}False{{/is_used}}, "is_class_attribute": {{#is_class_attribute}}True{{/is_class_attribute}}{{^is_class_attribute}}False{{/is_class_attribute}}, + "is_datatype_attribute": {{#is_datatype_attribute}}True{{/is_datatype_attribute}}{{^is_datatype_attribute}}False{{/is_datatype_attribute}}, "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, diff --git a/cimgen/languages/modernpython/utils/export_template.mustache b/cimgen/languages/modernpython/utils/export_template.mustache index 4055d9e..410a266 100644 --- a/cimgen/languages/modernpython/utils/export_template.mustache +++ b/cimgen/languages/modernpython/utils/export_template.mustache @@ -13,6 +13,9 @@ {{#is_class_attribute}} {{/is_class_attribute}} + {{#is_datatype_attribute}} + {{value}} + {{/is_datatype_attribute}} {{#is_enum_attribute}} {{/is_enum_attribute}} @@ -31,6 +34,9 @@ {{#is_class_attribute}} {{/is_class_attribute}} + {{#is_datatype_attribute}} + {{value}} + {{/is_datatype_attribute}} {{#is_enum_attribute}} {{/is_enum_attribute}} diff --git a/cimgen/languages/modernpython/utils/writer.py b/cimgen/languages/modernpython/utils/writer.py index 89abb2e..729a3d1 100644 --- a/cimgen/languages/modernpython/utils/writer.py +++ b/cimgen/languages/modernpython/utils/writer.py @@ -190,6 +190,7 @@ def get_attribute_infos(obj: Base) -> dict[str, dict[str, object]]: "namespace": extra.get("namespace", obj.namespace), "value": getattr(obj, attr), "is_class_attribute": extra.get("is_class_attribute"), + "is_datatype_attribute": extra.get("is_datatype_attribute"), "is_enum_attribute": extra.get("is_enum_attribute"), "is_list_attribute": extra.get("is_list_attribute"), "is_primitive_attribute": extra.get("is_primitive_attribute"),