Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix class and attribute types #40

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7944f6e
Fix some attribute types in classes DiagramObjectGluePoint, VCompIEEE…
tom-hg57 Oct 12, 2024
3b6e9d2
Add class property "is_a_primitive_class" and attribute property "is_…
tom-hg57 Oct 12, 2024
bded89c
Fix type and default of some attributes for modernpython (for enums a…
tom-hg57 Oct 13, 2024
037dc1c
Fix handling of Decimal as float class
tom-hg57 Oct 13, 2024
08dfa2e
Remove generation of unused classes for modernpython
tom-hg57 Oct 13, 2024
4ad48d7
Improve setting of long profile names
tom-hg57 Oct 13, 2024
ac487b3
Refactor _merge_profiles and _merge_classes in cimgen.py
tom-hg57 Oct 13, 2024
4ce0983
Fix attribute type of TieFlow in class Terminal for cpp and modernpython
tom-hg57 Oct 13, 2024
7c3a497
Add generation of string classes for cpp
tom-hg57 Oct 19, 2024
68f0df3
Improve cpp templates: make debugstring() const
tom-hg57 Oct 19, 2024
c6aa544
Add generated-via-cimgen comment to the header of all generated files…
tom-hg57 Oct 19, 2024
8e4855e
Improve cpp templates (skip empty comments, improve indentations)
tom-hg57 Oct 19, 2024
04a1c99
Fix cpp create_assign functions for string attribute types (Date, Dat…
tom-hg57 Oct 19, 2024
2409049
Fix cpp create_class_assign functions to prevent duplicate entries in…
tom-hg57 Oct 20, 2024
ed8eb99
Add class comment to cpp templates for float and string classes
tom-hg57 Oct 20, 2024
1833e80
Simplify and unify cpp templates for enum, float and string classes
tom-hg57 Oct 27, 2024
450ff19
Unify formatting of the generated cpp classes
tom-hg57 Oct 27, 2024
6e09334
Add static cpp sources and parser classes (copied from libcimpp)
tom-hg57 Oct 27, 2024
75a69ae
Remove String, Date, Float from static directory (they are now genera…
tom-hg57 Oct 27, 2024
c60c319
Update static cpp sources and parser classes to new generated String …
tom-hg57 Oct 27, 2024
ab563b3
Fix unused import (pre-commit flake8: cimgen/cimgen.py:5:1: F401 're'…
tom-hg57 Oct 27, 2024
997988e
Add dependency to setuptools to fix ModuleNotFoundError for distutils…
tom-hg57 Nov 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 80 additions & 165 deletions cimgen/cimgen.py

Large diffs are not rendered by default.

196 changes: 131 additions & 65 deletions cimgen/languages/cpp/lang_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -60,14 +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"] == "Integer"
or class_details["class_name"] == "Boolean"
or class_details["class_name"] == "Date"
):
if class_details["class_name"] in ("Integer", "Boolean"):
# These classes are defined already
# We have to implement operators for them
return
Expand Down Expand Up @@ -113,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
Expand All @@ -133,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
Expand All @@ -151,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 ""

Expand All @@ -172,34 +174,72 @@ 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 = (
"""
bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2) {
if(OBJECT_CLASS* element = dynamic_cast<OBJECT_CLASS*>(BaseClass_ptr1)) {
if(dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2) != nullptr) {
element->LABEL.push_back(dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2));
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<OBJECT_CLASS*>(BaseClass_ptr1);
ATTRIBUTE_CLASS* element2 = dynamic_cast<ATTRIBUTE_CLASS*>(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<OBJECT_CLASS*>(BaseClass_ptr1))
{
if (dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2) != nullptr)
{
element->LABEL.push_back(dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2));
return true;
}
}
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<OBJECT_CLASS*>(BaseClass_ptr1)) {
element->LABEL = dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2);
if(element->LABEL != nullptr)
return assign_INVERSEC_INVERSEL(BaseClass_ptr2, BaseClass_ptr1);
}
return false;
bool assign_OBJECT_CLASS_LABEL(BaseClass* BaseClass_ptr1, BaseClass* BaseClass_ptr2)
{
OBJECT_CLASS* element = dynamic_cast<OBJECT_CLASS*>(BaseClass_ptr1);
ATTRIBUTE_CLASS* element2 = dynamic_cast<ATTRIBUTE_CLASS*>(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"]
)
Expand All @@ -211,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<OBJECT_CLASS*>(BaseClass_ptr1)) {
element->LABEL = dynamic_cast<ATTRIBUTE_CLASS*>(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<OBJECT_CLASS*>(BaseClass_ptr1))
{
element->LABEL = dynamic_cast<ATTRIBUTE_CLASS*>(BaseClass_ptr2);
if (element->LABEL != nullptr)
{
return true;
}
}
return false;
}""".replace( # noqa: E101,W191
"OBJECT_CLASS", attribute_json["domain"]
)
Expand All @@ -239,31 +283,38 @@ 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) {
if(CLASS* element = dynamic_cast<CLASS*>(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<CLASS*>(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"]
)
.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<CLASS*>(BaseClass_ptr1)) {
bool assign_CLASS_LABEL(std::stringstream &buffer, BaseClass* BaseClass_ptr1)
{
if (CLASS* element = dynamic_cast<CLASS*>(BaseClass_ptr1))
{
element->LABEL = buffer.str();
if(buffer.fail())
if (buffer.fail())
return false;
else
return true;
Expand Down Expand Up @@ -305,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


Expand All @@ -321,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


Expand Down Expand Up @@ -368,23 +419,22 @@ def set_default(dataType):
"Factory",
"Folders",
"IEC61970",
"String",
"Task",
"UnknownType",
]

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):
Expand All @@ -395,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)
Expand All @@ -410,12 +460,18 @@ def resolve_headers(path: str, version: str): # NOSONAR
class_list_header = [
"#ifndef CIMCLASSLIST_H\n",
"#define CIMCLASSLIST_H\n",
"using namespace CIMPP;\n",
"/*\n",
"Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen\n",
"*/\n",
"#include <list>\n",
"static std::list<BaseClassDefiner> CIMClassList = {\n",
'#include "IEC61970.hpp"\n',
"using namespace CIMPP;\n",
"static std::list<BaseClassDefiner> CIMClassList =\n",
"{\n",
]
class_list_footer = [
" UnknownType::declare() };\n",
" UnknownType::declare(),\n",
"};\n",
"#endif // CIMCLASSLIST_H\n",
]

Expand All @@ -424,13 +480,23 @@ def resolve_headers(path: str, version: str): # NOSONAR
"CIMClassList.hpp",
class_list_header,
class_list_footer,
" ",
" ",
"::declare(),\n",
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,
Expand Down
Loading