Skip to content

Commit

Permalink
Add modifier argument to getModelInstance (#10412)
Browse files Browse the repository at this point in the history
- Add an argument to getModelInstance that makes it possible to supply a
  modifier to use when instantiating the model.
- Fix Static.elabCodeType to make it possible to use modifiers and
  expressions as default arguments in ModelicaBuiltin.

Fixes #10349
  • Loading branch information
perost committed Mar 17, 2023
1 parent 7f0681b commit 7ce7c53
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 13 deletions.
1 change: 1 addition & 0 deletions OMCompiler/Compiler/FrontEnd/ModelicaBuiltin.mo
Expand Up @@ -4405,6 +4405,7 @@ end convertPackageToLibrary;
function getModelInstance
"Dumps a model instance as a JSON string."
input TypeName className;
input String modifier = "";
input Boolean prettyPrint = false;
output String result;
external "builtin";
Expand Down
4 changes: 2 additions & 2 deletions OMCompiler/Compiler/FrontEnd/Static.mo
Expand Up @@ -2155,10 +2155,10 @@ algorithm
then DAE.T_COMPLEX(ClassInf.UNKNOWN(Absyn.IDENT("Element")),{},NONE(), false);
case Absyn.C_EXPRESSION()
then DAE.T_COMPLEX(ClassInf.UNKNOWN(Absyn.IDENT("Expression")),{},NONE(), false);
then DAE.T_CODE(DAE.C_EXPRESSION_OR_MODIFICATION());
case Absyn.C_MODIFICATION()
then DAE.T_COMPLEX(ClassInf.UNKNOWN(Absyn.IDENT("Modification")),{},NONE(), false);
then DAE.T_CODE(DAE.C_EXPRESSION_OR_MODIFICATION());
end match;
end elabCodeType;
Expand Down
6 changes: 4 additions & 2 deletions OMCompiler/Compiler/NFFrontEnd/NFInst.mo
Expand Up @@ -315,23 +315,25 @@ end lookupRootClass;
function instantiateRootClass
input output InstNode clsNode;
input InstContext.Type context;
input Modifier mod = Modifier.NOMOD();
algorithm
clsNode := instantiate(clsNode, context = context);
clsNode := instantiate(clsNode, mod, context = context);
checkPartialClass(clsNode, context);

insertGeneratedInners(clsNode, InstNode.topScope(clsNode), context);
end instantiateRootClass;

function instantiate
input output InstNode node;
input Modifier mod = Modifier.NOMOD();
input InstNode parent = InstNode.EMPTY_NODE();
input InstContext.Type context;
input Boolean instPartial = false "Whether to instantiate a partial class or not.";
algorithm
node := expand(node);

if instPartial or not InstNode.isPartial(node) or InstContext.inRelaxed(context) then
node := instClass(node, Modifier.NOMOD(), NFAttributes.DEFAULT_ATTR, true, 0, parent, context);
node := instClass(node, mod, NFAttributes.DEFAULT_ATTR, true, 0, parent, context);
end if;
end instantiate;

Expand Down
1 change: 1 addition & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFModelicaBuiltin.mo
Expand Up @@ -4658,6 +4658,7 @@ end convertPackageToLibrary;
function getModelInstance
"Dumps a model instance as a JSON string."
input TypeName className;
input String modifier = "";
input Boolean prettyPrint = false;
output String result;
external "builtin";
Expand Down
4 changes: 2 additions & 2 deletions OMCompiler/Compiler/Script/CevalScriptBackend.mo
Expand Up @@ -3085,8 +3085,8 @@ algorithm
case ("convertPackageToLibrary", {Values.CODE(Absyn.C_TYPENAME(classpath)), Values.CODE(Absyn.C_TYPENAME(path)), Values.STRING(str)})
then convertPackageToLibrary(classpath, path, str);
case ("getModelInstance", {Values.CODE(Absyn.C_TYPENAME(classpath)), Values.BOOL(b)})
then NFApi.getModelInstance(classpath, b);
case ("getModelInstance", {Values.CODE(Absyn.C_TYPENAME(classpath)), Values.STRING(str), Values.BOOL(b)})
then NFApi.getModelInstance(classpath, str, b);
case ("getModelInstanceIcon", {Values.CODE(Absyn.C_TYPENAME(classpath)), Values.BOOL(b)})
then NFApi.getModelInstanceIcon(classpath, b);
Expand Down
34 changes: 32 additions & 2 deletions OMCompiler/Compiler/Script/NFApi.mo
Expand Up @@ -35,6 +35,7 @@ import Absyn;
import AbsynUtil;
import SCode;
import DAE;
import NFModifier.Modifier;

protected

Expand All @@ -47,7 +48,6 @@ import Expression = NFExpression;
import NFClass.Class;
import NFInstNode.InstNode;
import NFInstNode.InstNodeType;
import NFModifier.Modifier;
import NFModifier.ModifierScope;
import Equation = NFEquation;
import NFType.Type;
Expand Down Expand Up @@ -82,6 +82,7 @@ import NFFlatten.FunctionTree;
import NFPrefixes.{Variability};
import NFSections.Sections;
import Package = NFPackage;
import Parser;
import Prefixes = NFPrefixes;
import Restriction = NFRestriction;
import Scalarize = NFScalarize;
Expand Down Expand Up @@ -850,6 +851,7 @@ end InstanceTree;

function getModelInstance
input Absyn.Path classPath;
input String modifier;
input Boolean prettyPrint;
output Values.Value res;
protected
Expand All @@ -859,14 +861,16 @@ protected
InstanceTree inst_tree;
InstSettings inst_settings;
String str;
Modifier mod;
algorithm
context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS);
context := InstContext.set(context, NFInstContext.INSTANCE_API);
inst_settings := InstSettings.SETTINGS(mergeExtendsSections = false);

(_, top) := mkTop(SymbolTable.getAbsyn(), AbsynUtil.pathString(classPath));
mod := parseModifier(modifier, top);
cls_node := Inst.lookupRootClass(classPath, top, context);
cls_node := Inst.instantiateRootClass(cls_node, context);
cls_node := Inst.instantiateRootClass(cls_node, context, mod);
inst_tree := buildInstanceTree(cls_node);
Inst.instExpressions(cls_node, context = context, settings = inst_settings);
Inst.updateImplicitVariability(cls_node, Flags.isSet(Flags.EVAL_PARAM));
Expand Down Expand Up @@ -899,6 +903,32 @@ algorithm
res := Values.STRING(JSON.toString(json, prettyPrint));
end getModelInstanceIcon;

function parseModifier
input String modifierValue;
input InstNode scope;
output Modifier outMod;
protected
Absyn.Modification amod;
SCode.Mod smod;
algorithm
try
// stringMod parses a single modifier ("x(start = 1) = 2"), but here we want
// to parse just a class modifier ("(x = 1, y = 2)"). So we add a dummy name
// to the string and then extract the modifier from the ElementArg.
Absyn.ElementArg.MODIFICATION(modification = SOME(amod)) :=
Parser.stringMod("dummy" + modifierValue);

// Then translate the Absyn mod to a Modifier, using the given scope (it
// doesn't matter much which scope it is, it just needs some scope or the
// instantiation will fail later).
smod := AbsynToSCode.translateMod(SOME(amod),
SCode.Final.NOT_FINAL(), SCode.Each.NOT_EACH(), AbsynUtil.dummyInfo);
outMod := Modifier.create(smod, "", NFModifier.ModifierScope.COMPONENT(""), scope);
else
outMod := Modifier.NOMOD();
end try;
end parseModifier;

function buildInstanceTree
input InstNode node;
input Boolean isDerived = false;
Expand Down
4 changes: 2 additions & 2 deletions OMEdit/OMEditLIB/OMC/OMCProxy.cpp
Expand Up @@ -3417,10 +3417,10 @@ QJsonObject OMCProxy::getModelInstance(const QString &className, bool prettyPrin
} else {
getErrorString();
}
modelInstanceJson = mpOMCInterface->getModelInstance(className, prettyPrint);
modelInstanceJson = mpOMCInterface->getModelInstance(className, QString(), prettyPrint);
}
} else {
modelInstanceJson = mpOMCInterface->getModelInstance(className, prettyPrint);
modelInstanceJson = mpOMCInterface->getModelInstance(className, QString(), prettyPrint);
}
printMessagesStringInternal();
if (!modelInstanceJson.isEmpty()) {
Expand Down
Expand Up @@ -15,7 +15,7 @@ loadString("
end M;
");

getModelInstance(M, true);
getModelInstance(M, prettyPrint = true);
getErrorString();

// Result:
Expand Down
Expand Up @@ -10,8 +10,8 @@ loadString("
type RealInput2 = RealInput(start = 1.0);
");

getModelInstance(RealInput, true); getErrorString();
getModelInstance(RealInput2, true); getErrorString();
getModelInstance(RealInput, prettyPrint = true); getErrorString();
getModelInstance(RealInput2, prettyPrint = true); getErrorString();

// Result:
// true
Expand Down
105 changes: 105 additions & 0 deletions testsuite/openmodelica/instance-API/GetModelInstanceMod4.mos
@@ -0,0 +1,105 @@
// name: GetModelInstanceMod4
// keywords:
// status: correct
// cflags: -d=newInst
//
//

loadString("
type MyReal = Real;

model A
Real x;
replaceable Real y;
end A;

model M
A a(x = 1, y = 2);
Real z;
end M;
");

getModelInstance(M, modifier = "(a(redeclare MyReal y = 4, x = 3), z = 5)", prettyPrint = true);
getErrorString();

// Result:
// true
// "{
// \"name\": \"M\",
// \"restriction\": \"model\",
// \"elements\": [
// {
// \"$kind\": \"component\",
// \"name\": \"a\",
// \"type\": {
// \"name\": \"A\",
// \"restriction\": \"model\",
// \"elements\": [
// {
// \"$kind\": \"component\",
// \"name\": \"x\",
// \"type\": \"Real\",
// \"value\": {
// \"binding\": 3
// }
// },
// {
// \"$kind\": \"component\",
// \"name\": \"y\",
// \"type\": {
// \"name\": \"MyReal\",
// \"restriction\": \"type\",
// \"elements\": [
// {
// \"$kind\": \"extends\",
// \"baseClass\": \"Real\"
// }
// ],
// \"source\": {
// \"filename\": \"<interactive>\",
// \"lineStart\": 2,
// \"columnStart\": 3,
// \"lineEnd\": 2,
// \"columnEnd\": 21
// }
// },
// \"value\": {
// \"binding\": 4
// },
// \"prefixes\": {
// \"replaceable\": true
// }
// }
// ],
// \"source\": {
// \"filename\": \"<interactive>\",
// \"lineStart\": 4,
// \"columnStart\": 3,
// \"lineEnd\": 7,
// \"columnEnd\": 8
// }
// },
// \"modifiers\": {
// \"x\": \"1\",
// \"y\": \"2\"
// }
// },
// {
// \"$kind\": \"component\",
// \"name\": \"z\",
// \"type\": \"Real\",
// \"value\": {
// \"binding\": 5
// }
// }
// ],
// \"source\": {
// \"filename\": \"<interactive>\",
// \"lineStart\": 9,
// \"columnStart\": 3,
// \"lineEnd\": 12,
// \"columnEnd\": 8
// }
// }"
// ""
// endResult
1 change: 1 addition & 0 deletions testsuite/openmodelica/instance-API/Makefile
Expand Up @@ -41,6 +41,7 @@ GetModelInstanceMissingClass2.mos \
GetModelInstanceMod1.mos \
GetModelInstanceMod2.mos \
GetModelInstanceMod3.mos \
GetModelInstanceMod4.mos \
GetModelInstanceReplaceable1.mos \
GetModelInstanceReplaceable2.mos \
GetModelInstanceReplaceable3.mos \
Expand Down

0 comments on commit 7ce7c53

Please sign in to comment.