Skip to content

Commit

Permalink
Fix enumeration connectors in instance API (#11733)
Browse files Browse the repository at this point in the history
- Dump the actual restriction of enumeration types rather than using
  `enumeration`, since `enumeration` is not a restriction but a type.
- Dump the full extends chain for an enumeration type, terminating in an
  extends of `enumeration` to indicate an enumeration type.
- Refactor the fetching of connector elements in OMEdit into a
  `getConnectorElement` method to avoid repetition.

Fixes #11726
  • Loading branch information
perost committed Dec 15, 2023
1 parent c26d25e commit 3a5196b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 74 deletions.
1 change: 1 addition & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFClass.mo
Expand Up @@ -655,6 +655,7 @@ constant Prefixes DEFAULT_PREFIXES = Prefixes.PREFIXES(
algorithm
isEnum := match cls
case PARTIAL_BUILTIN(ty = Type.ENUMERATION()) then true;
case INSTANCED_BUILTIN(ty = Type.ENUMERATION()) then true;
case EXPANDED_DERIVED() then isEnumeration(InstNode.getClass(cls.baseClass));
case TYPED_DERIVED() then isEnumeration(InstNode.getClass(cls.baseClass));
else false;
Expand Down
41 changes: 33 additions & 8 deletions OMCompiler/Compiler/Script/NFApi.mo
Expand Up @@ -842,10 +842,16 @@ uniontype InstanceTree
Boolean isExtends;
end CLASS;

record BUILTIN_BASE_CLASS
String name;
end BUILTIN_BASE_CLASS;

record EMPTY
end EMPTY;
end InstanceTree;

constant InstanceTree ENUM_BASE = InstanceTree.BUILTIN_BASE_CLASS("enumeration");

function getModelInstance
input Absyn.Path classPath;
input String modifier;
Expand Down Expand Up @@ -955,7 +961,7 @@ algorithm
cls_node := InstNode.resolveInner(node);
cls := InstNode.getClass(cls_node);

if not isDerived and Class.isOnlyBuiltin(cls) then
if not isDerived and Class.isOnlyBuiltin(cls) and not Class.isEnumeration(cls) then
tree := InstanceTree.EMPTY();
return;
end if;
Expand All @@ -976,7 +982,7 @@ algorithm
InstanceTree.CLASS(node, elems, isDerived);

case (_, ClassTree.FLAT_TREE())
then InstanceTree.CLASS(node, {}, isDerived);
then InstanceTree.CLASS(node, if InstNode.isEnumerationType(cls_node) then {ENUM_BASE} else {}, isDerived);

else
algorithm
Expand Down Expand Up @@ -1099,7 +1105,7 @@ algorithm

json := JSON.addPairNotNull("dims", dumpJSONClassDims(node, def), json);
json := JSON.addPair("restriction",
JSON.makeString(Restriction.toString(InstNode.restriction(node))), json);
JSON.makeString(SCodeDump.restrictionStringPP(SCodeUtil.getClassRestriction(def))), json);

json := JSON.addPairNotNull("prefixes", dumpJSONClassPrefixes(def, InstNode.parent(node)), json);

Expand Down Expand Up @@ -1232,6 +1238,7 @@ algorithm
case InstanceTree.CLASS(isExtends = true) then dumpJSONExtends(e, isDeleted);
case InstanceTree.CLASS() then dumpJSONReplaceableClass(e.node, scope);
case InstanceTree.COMPONENT() then dumpJSONComponent(e.node, e.binding, e.cls);
case InstanceTree.BUILTIN_BASE_CLASS() then dumpJSONBuiltinBaseClass(e.name);
else JSON.makeNull();
end match;

Expand All @@ -1246,6 +1253,7 @@ function dumpJSONExtends
output JSON json = JSON.makeNull();
protected
InstNode node;
Class cls;
SCode.Element cls_def, ext_def;
SCode.Mod mod;
algorithm
Expand All @@ -1257,13 +1265,22 @@ algorithm
json := dumpJSONSCodeMod(getExtendsModifier(ext_def, node), node, json);
json := dumpJSONCommentOpt(SCodeUtil.getElementComment(ext_def), node, json);

if Class.isOnlyBuiltin(InstNode.getClass(node)) then
cls := InstNode.getClass(node);
if Class.isOnlyBuiltin(cls) and not Class.isEnumeration(cls) then
json := JSON.addPair("baseClass", JSON.makeString(InstNode.name(node)), json);
else
json := JSON.addPair("baseClass", dumpJSONInstanceTree(ext, node, root = false, isDeleted = isDeleted), json);
end if;
end dumpJSONExtends;

function dumpJSONBuiltinBaseClass
input String name;
output JSON json = JSON.makeNull();
algorithm
json := JSON.addPair("$kind", JSON.makeString("extends"), json);
json := JSON.addPair("baseClass", JSON.makeString(name), json);
end dumpJSONBuiltinBaseClass;

function getExtendsModifier
input SCode.Element definition;
input InstNode node;
Expand Down Expand Up @@ -1377,7 +1394,7 @@ function dumpJSONComponentType
output JSON json;
algorithm
json := match (cls, Type.arrayElementType(ty))
case (_, Type.ENUMERATION()) then dumpJSONEnumType(node);
case (_, Type.ENUMERATION()) then dumpJSONEnumType(cls, node);
case (_, Type.UNKNOWN()) then dumpJSONSCodeElementType(InstNode.definition(node));
case (InstanceTree.CLASS(), _) then dumpJSONInstanceTree(cls, node, isDeleted = isDeleted);
else dumpJSONTypeName(ty);
Expand All @@ -1401,31 +1418,39 @@ algorithm
end dumpJSONSCodeElementType;

function dumpJSONEnumType
input InstanceTree tree;
input InstNode enumNode;
output JSON json;
protected
InstNode node = InstNode.resolveInner(InstNode.classScope(enumNode));
SCode.Element def;
array<InstNode> comps;
JSON json_elems, json_ext;
list<InstanceTree> elems;
algorithm
def := InstNode.definition(node);

json := JSON.makeNull();
json := JSON.addPair("name", dumpJSONNodePath(node), json);
json := JSON.addPairNotNull("dims", dumpJSONClassDims(node, def), json);
json := JSON.addPair("restriction", JSON.makeString("enumeration"), json);
json := JSON.addPair("restriction",
JSON.makeString(SCodeDump.restrictionStringPP(SCodeUtil.getClassRestriction(def))), json);
json := dumpJSONCommentOpt(SCodeUtil.getElementComment(def), node, json);

InstanceTree.CLASS(elements = elems) := tree;
json_elems := dumpJSONElements(elems, node, false);

comps := ClassTree.getComponents(Class.classTree(InstNode.getClass(node)));
json := JSON.addPair("elements", dumpJSONEnumTypeLiterals(comps, InstNode.parent(node)), json);
json_elems := dumpJSONEnumTypeLiterals(comps, InstNode.parent(node), json_elems);
json := JSON.addPair("elements", json_elems, json);

json := JSON.addPair("source", dumpJSONSourceInfo(InstNode.info(node)), json);
end dumpJSONEnumType;

function dumpJSONEnumTypeLiterals
input array<InstNode> literals;
input InstNode scope;
output JSON json = JSON.emptyArray();
input output JSON json = JSON.emptyArray();
algorithm
for i in 6:arrayLength(literals) loop
json := JSON.addElement(dumpJSONEnumTypeLiteral(literals[i], scope), json);
Expand Down
2 changes: 1 addition & 1 deletion OMEdit/OMEditLIB/Modeling/Model.cpp
Expand Up @@ -1184,7 +1184,7 @@ namespace ModelInstance

bool Model::isEnumeration() const
{
return (mRestriction.compare(QStringLiteral("enumeration")) == 0);
return getRootType() == QLatin1String("enumeration");
}

bool Model::isType() const
Expand Down
110 changes: 48 additions & 62 deletions OMEdit/OMEditLIB/Modeling/ModelWidgetContainer.cpp
Expand Up @@ -487,72 +487,24 @@ void GraphicsView::drawConnections(ModelInstance::Model *pModelInstance, bool in
// if connection is valid and has line annotation
if (pConnection->getStartConnector() && pConnection->getEndConnector() && pConnection->getAnnotation()->getLine()
&& !connectionExists(pConnection->getStartConnector()->getName(), pConnection->getEndConnector()->getName(), inherited)) {
// get start and end elements
QStringList startElementList = pConnection->getStartConnector()->getNameParts();
QStringList endElementList = pConnection->getEndConnector()->getNameParts();
// get start element
Element *pStartElement = 0;
if (startElementList.size() > 0) {
QString startElementName = startElementList.at(0);
if (startElementName.contains("[")) {
startElementName = startElementName.mid(0, startElementName.indexOf("["));
}
pStartElement = getElementObject(startElementName);
}
// get start connector
Element *pStartConnectorElement = 0;
Element *pEndConnectorElement = 0;
if (pStartElement) {
// if a element type is connector then we only get one item in startElementList
// check the startElementlist
// if conditional connector or condition is false or if type is missing then connect with the red cross box
if (startElementList.size() < 2 || pStartElement->isExpandableConnector() || !pStartElement->getModelComponent()->getCondition() || pStartElement->getModel()->isMissing()) {
pStartConnectorElement = pStartElement;
} else {
// look for port from the parent element
QString startElementName = startElementList.at(1);
if (startElementName.contains("[")) {
startElementName = startElementName.mid(0, startElementName.indexOf("["));
}
pStartConnectorElement = mpModelWidget->getConnectorElement(pStartElement, startElementName);
}
}
//// get start and end elements
auto pStartConnectorElement = getConnectorElement(pConnection->getStartConnector());
// show error message if start element is not found.
if (!pStartConnectorElement) {
MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, GUIMessages::getMessage(GUIMessages::UNABLE_FIND_COMPONENT_IN_CONNECTION_NEW)
.arg(pConnection->getStartConnector()->getName()).arg(pConnection->toString())
.arg(mpModelWidget->getLibraryTreeItem()->getNameStructure()), Helper::scriptingKind, Helper::errorLevel));
MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica,
GUIMessages::getMessage(GUIMessages::UNABLE_FIND_COMPONENT_IN_CONNECTION_NEW)
.arg(pConnection->getStartConnector()->getName()).arg(pConnection->toString())
.arg(mpModelWidget->getLibraryTreeItem()->getNameStructure()), Helper::scriptingKind, Helper::errorLevel));
continue;
}
// get end element
Element *pEndElement = 0;
if (endElementList.size() > 0) {
QString endElementName = endElementList.at(0);
if (endElementName.contains("[")) {
endElementName = endElementName.mid(0, endElementName.indexOf("["));
}
pEndElement = getElementObject(endElementName);
}
// get the end connector
if (pEndElement) {
// if a element type is connector then we only get one item in endElementList
// check the endElementList
// if conditional connector or condition is false or if type is missing then connect with the red cross box
if (endElementList.size() < 2 || pEndElement->isExpandableConnector() || !pEndElement->getModelComponent()->getCondition() || pEndElement->getModel()->isMissing()) {
pEndConnectorElement = pEndElement;
} else {
QString endElementName = endElementList.at(1);
if (endElementName.contains("[")) {
endElementName = endElementName.mid(0, endElementName.indexOf("["));
}
pEndConnectorElement = mpModelWidget->getConnectorElement(pEndElement, endElementName);
}
}

auto pEndConnectorElement = getConnectorElement(pConnection->getEndConnector());
// show error message if end element is not found.
if (!pEndConnectorElement) {
MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica, GUIMessages::getMessage(GUIMessages::UNABLE_FIND_COMPONENT_IN_CONNECTION_NEW)
.arg(pConnection->getEndConnector()->getName()).arg(pConnection->toString())
.arg(mpModelWidget->getLibraryTreeItem()->getNameStructure()), Helper::scriptingKind, Helper::errorLevel));
MessagesWidget::instance()->addGUIMessage(MessageItem(MessageItem::Modelica,
GUIMessages::getMessage(GUIMessages::UNABLE_FIND_COMPONENT_IN_CONNECTION_NEW)
.arg(pConnection->getEndConnector()->getName()).arg(pConnection->toString())
.arg(mpModelWidget->getLibraryTreeItem()->getNameStructure()), Helper::scriptingKind, Helper::errorLevel));
continue;
}

Expand Down Expand Up @@ -3131,8 +3083,42 @@ bool GraphicsView::updateElementConnectorSizingParameter(GraphicsView *pGraphics
return false;
}

/*!
* \brief GraphicsView::getConnectorName
/*! * \brief GraphicsView::getConnectorElement
* Returns the element associated with a Connector.
* \param pConnector
*/
Element* GraphicsView::getConnectorElement(ModelInstance::Connector *pConnector)
{
QStringList elementList = pConnector->getNameParts();
Element *element = nullptr;

// Get element.
if (elementList.size() > 0) {
QString elementName = elementList.front();
elementName = elementName.left(elementName.indexOf('['));
element = getElementObject(elementName);
}

// Get connector element.
Element *connectorElement = nullptr;
if (element) {
// If an element type is connector then we only get one item in elementList
// Check the elementList
// If conditional connector or condition is false or if type is missing then connect with the red cross box
if (elementList.size() < 2 || element->isExpandableConnector() || !element->getModelComponent()->getCondition() || element->getModel()->isMissing()) {
connectorElement = element;
} else {
// Look for port from the parent element
QString elementName = elementList.at(1);
elementName = elementName.left(elementName.indexOf('['));
connectorElement = mpModelWidget->getConnectorElement(element, elementName);
}
}

return connectorElement;
}

/*! * \brief GraphicsView::getConnectorName
* Returns the name of the connector element as a string.
* \param pConnector
*/
Expand Down
3 changes: 2 additions & 1 deletion OMEdit/OMEditLIB/Modeling/ModelWidgetContainer.h
Expand Up @@ -369,7 +369,8 @@ class GraphicsView : public QGraphicsView
Element* connectorElementAtPosition(QPoint position);
Element* stateElementAtPosition(QPoint position);
static bool updateElementConnectorSizingParameter(GraphicsView *pGraphicsView, QString className, Element *pElement);
QString getConnectorName(Element *connector);
Element* getConnectorElement(ModelInstance::Connector *pConnector);
QString getConnectorName(Element *pConnector);
bool handleDoubleClickOnComponent(QMouseEvent *event);
void uncheckAllShapeDrawingActions();
void setOriginAdjustAndInitialize(ShapeAnnotation* shapeAnnotation);
Expand Down
Expand Up @@ -29,13 +29,17 @@ getModelInstance(M, prettyPrint=true);
// \"name\": \"analogFil\",
// \"type\": {
// \"name\": \"AnalogFilter\",
// \"restriction\": \"enumeration\",
// \"restriction\": \"type\",
// \"comment\": \"Enumeration defining the method of filtering\",
// \"annotation\": {
// \"Evaluate\": true
// },
// \"elements\": [
// {
// \"$kind\": \"extends\",
// \"baseClass\": \"enumeration\"
// },
// {
// \"$kind\": \"component\",
// \"name\": \"CriticalDamping\",
// \"comment\": \"Filter with critical damping\"
Expand Down
22 changes: 21 additions & 1 deletion testsuite/openmodelica/instance-API/GetModelInstanceEnum2.mos
Expand Up @@ -26,9 +26,29 @@ getModelInstance(M, prettyPrint=true);
// \"name\": \"e\",
// \"type\": {
// \"name\": \"E2\",
// \"restriction\": \"enumeration\",
// \"restriction\": \"type\",
// \"elements\": [
// {
// \"$kind\": \"extends\",
// \"baseClass\": {
// \"name\": \"E1\",
// \"restriction\": \"type\",
// \"elements\": [
// {
// \"$kind\": \"extends\",
// \"baseClass\": \"enumeration\"
// }
// ],
// \"source\": {
// \"filename\": \"<interactive>\",
// \"lineStart\": 3,
// \"columnStart\": 5,
// \"lineEnd\": 3,
// \"columnEnd\": 47
// }
// }
// },
// {
// \"$kind\": \"component\",
// \"name\": \"a\",
// \"comment\": \"a\"
Expand Down

0 comments on commit 3a5196b

Please sign in to comment.