Skip to content

Commit

Permalink
Clean up modifier setting APIs (#10592)
Browse files Browse the repository at this point in the history
- Change `setComponentModifierValue` to be an alias of
  `setElementModifierValue` in order to avoid having to maintain both,
  since `setElementModifierValue` does everything
  `setComponentModifierValue` does and more.
- Fix `setElementModifierValue` so it handles components directly,
  instead of failing and falling back on the old
  `setComponentModifierValue` implementation.
- Add `setElementModifierValue` to ModelicaBuiltin so it can be
  documented.
  • Loading branch information
perost committed Apr 21, 2023
1 parent b22a39b commit a1ad0c7
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 387 deletions.
15 changes: 15 additions & 0 deletions OMCompiler/Compiler/FrontEnd/ModelicaBuiltin.mo
Expand Up @@ -3148,6 +3148,21 @@ annotation(
preferredView="text");
end getElementModifierNames;

function setComponentModifierValue = setElementModifierValue;

function setElementModifierValue
input TypeName className;
input TypeName elementName;
input ExpressionOrModification modifier;
output Boolean success;
external "builtin";
annotation(
Documentation(info="<html>
Sets a modifier on an element in a class definition.
</html>"),
preferredView="text");
end setElementModifierValue;

function getElementModifierValue
input TypeName className;
input TypeName modifier;
Expand Down
15 changes: 15 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFModelicaBuiltin.mo
Expand Up @@ -3401,6 +3401,21 @@ annotation(
preferredView="text");
end getElementModifierNames;

function setComponentModifierValue = setElementModifierValue;

function setElementModifierValue
input TypeName className;
input TypeName elementName;
input ExpressionOrModification modifier;
output Boolean success;
external "builtin";
annotation(
Documentation(info="<html>
Sets a modifier on an element in a class definition.
</html>"),
preferredView="text");
end setElementModifierValue;

function getElementModifierValue
input TypeName className;
input TypeName modifier;
Expand Down
11 changes: 11 additions & 0 deletions OMCompiler/Compiler/Script/CevalScriptBackend.mo
Expand Up @@ -1841,6 +1841,7 @@ algorithm
list<list<Values.Value>> valsLst;
SourceInfo info;
System.StatFileType statFileType;
Absyn.Modification mod;

case ("getAvailableIndexReductionMethods",_)
equation
Expand Down Expand Up @@ -2631,6 +2632,16 @@ algorithm
then
Values.STRING(str);

case ("setElementModifierValue",
{Values.CODE(Absyn.C_TYPENAME(classpath)),
Values.CODE(Absyn.C_TYPENAME(path)),
Values.CODE(Absyn.C_MODIFICATION(modification = mod))})
algorithm
(p, b) := InteractiveUtil.setElementModifier(classpath, path, mod, SymbolTable.getAbsyn());
SymbolTable.setAbsyn(p);
then
Values.BOOL(b);

case ("removeComponentModifiers",
Values.CODE(Absyn.C_TYPENAME(path))::
Values.STRING(str1)::
Expand Down
274 changes: 0 additions & 274 deletions OMCompiler/Compiler/Script/Interactive.mo
Expand Up @@ -940,30 +940,6 @@ algorithm
args := getApiFunctionArgs(inStatement);

outResult := match(fn_name)
case "setComponentModifierValue"
algorithm
{Absyn.CREF(componentRef = class_),
Absyn.CREF(componentRef = cr),
Absyn.CODE(code = Absyn.C_MODIFICATION(modification = mod))} := args;
(p, outResult) := setComponentModifier(class_, cr, mod, p);
SymbolTable.setAbsyn(p);
then
outResult;

case "setElementModifierValue"
algorithm
{Absyn.CREF(componentRef = class_),
Absyn.CREF(componentRef = cr),
Absyn.CODE(code = cn)} := args;
mod := match cn
case Absyn.C_MODIFICATION(modification = mod) then mod;
case Absyn.C_ELEMENT(element = el) then fail();
end match;
(p, outResult) := InteractiveUtil.setElementModifier(class_, cr, mod, p);
SymbolTable.setAbsyn(p);
then
outResult;

case "setParameterValue"
algorithm
{Absyn.CREF(componentRef = class_), Absyn.CREF(componentRef = crident), exp} := args;
Expand Down Expand Up @@ -5431,256 +5407,6 @@ algorithm
end try;
end removeComponentModifiers;

protected function setComponentModifier
"Sets a submodifier of a component."
input Absyn.ComponentRef inClass;
input Absyn.ComponentRef inComponentName;
input Absyn.Modification inMod;
input Absyn.Program inProgram;
output Absyn.Program outProgram;
output String outResult;
protected
Absyn.Path p_class;
Absyn.Within within_;
Absyn.Class cls;
algorithm
try
p_class := AbsynUtil.crefToPath(inClass);
within_ := InteractiveUtil.buildWithin(p_class);
cls := InteractiveUtil.getPathedClassInProgram(p_class, inProgram);
cls := setComponentSubmodifierInClass(cls, inComponentName, inMod);
outProgram := InteractiveUtil.updateProgram(Absyn.PROGRAM({cls}, within_), inProgram);
outResult := "Ok";
else
outProgram := inProgram;
outResult := "Error";
end try;
end setComponentModifier;

protected function setComponentSubmodifierInClass
" Sets a sub modifier on a component in a class.
inputs: (Absyn.Class,
Absyn.Ident, /* component name */
Absyn.ComponentRef, /* subvariable path */
Absyn.Modification)
outputs: Absyn.Class"
input Absyn.Class inClass;
input Absyn.ComponentRef inComponentName;
input Absyn.Modification inMod;
output Absyn.Class outClass = inClass;
algorithm
(outClass, true) := AbsynUtil.traverseClassComponents(inClass,
function setComponentSubmodifierInCompitems(inComponentName =
inComponentName, inMod = inMod), false);
end setComponentSubmodifierInClass;

public function setComponentSubmodifierInCompitems
"Helper function to setComponentSubmodifierInClass. Sets the modifier in a
ComponentItem."
input list<Absyn.ComponentItem> inComponents;
input Boolean inFound;
input Absyn.ComponentRef inComponentName;
input Absyn.Modification inMod;
output list<Absyn.ComponentItem> outComponents = {};
output Boolean outFound;
output Boolean outContinue;
protected
Absyn.ComponentItem item;
list<Absyn.ComponentItem> rest_items = inComponents;
Absyn.Component comp;
list<Absyn.ElementArg> args_old, args_new;
Absyn.EqMod eqmod_old, eqmod_new;
String comp_id;
algorithm
comp_id := AbsynUtil.crefFirstIdent(inComponentName);

// Try to find the component we're looking for.
while not listEmpty(rest_items) loop
item :: rest_items := rest_items;

if AbsynUtil.componentName(item) == comp_id then
// Found component, propagate the modifier to it.
_ := match item
case Absyn.COMPONENTITEM(component = comp as Absyn.COMPONENT())
algorithm
comp.modification := propagateMod(AbsynUtil.crefToPath(inComponentName),
inMod, comp.modification);
item.component := comp;
then
();
end match;

// Reassemble the item list and return.
outComponents := List.append_reverse(outComponents, item :: rest_items);
outFound := true;
outContinue := false;
return;
end if;
outComponents := item :: outComponents;
end while;

// Component not found, continue looking.
outComponents := inComponents;
outFound := false;
outContinue := true;
end setComponentSubmodifierInCompitems;

public function propagateMod
input Absyn.Path inComponentName;
input Absyn.Modification inNewMod;
input Option<Absyn.Modification> inOldMod;
output Option<Absyn.Modification> outMod;
protected
list<Absyn.ElementArg> new_args, old_args;
Absyn.EqMod new_eqmod, old_eqmod;
Absyn.Modification mod;
algorithm
if isSome(inOldMod) then
SOME(Absyn.CLASSMOD(elementArgLst = old_args, eqMod = old_eqmod)) := inOldMod;
else
old_args := {};
old_eqmod := Absyn.NOMOD();
end if;

if AbsynUtil.pathIsIdent(inComponentName) then
Absyn.CLASSMOD(elementArgLst = new_args, eqMod = new_eqmod) := inNewMod;

// If we have no eqmod but a list of submods, keep the old eqmod.
if valueEq(new_eqmod, Absyn.NOMOD()) and not listEmpty(new_args) then
new_eqmod := old_eqmod;
end if;

new_args := mergeElementArgs(old_args, new_args);
mod := Absyn.CLASSMOD(new_args, new_eqmod);
else
new_args := propagateMod2(inComponentName, old_args, inNewMod);
mod := Absyn.CLASSMOD(new_args, old_eqmod);
end if;

outMod := if AbsynUtil.isEmptyMod(mod) then NONE() else SOME(mod);
end propagateMod;

protected function mergeElementArgs
input list<Absyn.ElementArg> inOldArgs;
input list<Absyn.ElementArg> inNewArgs;
output list<Absyn.ElementArg> outArgs = inOldArgs;
protected
Boolean found;
algorithm
if listEmpty(inOldArgs) then
outArgs := inNewArgs;
elseif listEmpty(inNewArgs) then
outArgs := inOldArgs;
else
for narg in inNewArgs loop
(outArgs, found) := List.replaceOnTrue(narg, outArgs,
function AbsynUtil.elementArgEqualName(inArg2 = narg));

if not found then
outArgs := narg :: outArgs;
end if;
end for;
end if;
end mergeElementArgs;

protected function propagateMod2
input Absyn.Path inComponentName;
input list<Absyn.ElementArg> inSubMods;
input Absyn.Modification inNewMod;
output list<Absyn.ElementArg> outSubMods = {};
protected
Absyn.ElementArg submod;
list<Absyn.ElementArg> rest_submods = inSubMods;
Absyn.Modification new_mod;
Absyn.Path comp_name, comp_rest;
algorithm
// Search through the submods to see if one matches the component name.
while not listEmpty(rest_submods) loop
submod :: rest_submods := rest_submods;
comp_name := AbsynUtil.pathRest(inComponentName);
comp_rest := comp_name;

// Try to find the submod whose path matches the best. If the have a
// component name a.b.c, then first check a.b.c, then a.b, then a.
while true loop
if AbsynUtil.pathEqual(comp_name, AbsynUtil.elementArgName(submod)) then
// Found matching submod, propagate the modifier to it.
_ := match(submod)
case Absyn.MODIFICATION()
algorithm
if not AbsynUtil.pathIsIdent(comp_name) then
comp_name := AbsynUtil.pathPrefix(comp_name);
comp_rest := AbsynUtil.removePrefix(comp_name, comp_rest);
end if;

submod.modification := propagateMod(comp_rest, inNewMod, submod.modification);

if isSome(submod.modification) then
rest_submods := submod :: rest_submods;
end if;
then
();

case Absyn.REDECLARATION()
algorithm
rest_submods := List.append_reverse(inNewMod.elementArgLst, rest_submods);
then
();

else ();
end match;

outSubMods := List.append_reverse(outSubMods, rest_submods);
return;
end if;

if AbsynUtil.pathIsIdent(comp_name) then
// Nothing left of the path, break and continue with next submod.
break;
else
// Remove the last part of the component name and see if that matches
// instead.
comp_name := AbsynUtil.pathPrefix(comp_name);
end if;
end while;

outSubMods := submod :: outSubMods;
end while;

if not AbsynUtil.isEmptyMod(inNewMod) then
// No matching submod was found, create a new submod and insert it into the list.
submod := createNestedSubMod(AbsynUtil.pathRest(inComponentName), inNewMod);
outSubMods := listReverse(submod :: outSubMods);
else
outSubMods := inSubMods;
end if;
end propagateMod2;

protected function createNestedSubMod
input Absyn.Path inComponentName;
input Absyn.Modification inMod;
output Absyn.ElementArg outSubMod;
protected
Absyn.ElementArg e;
algorithm
if AbsynUtil.pathIsIdent(inComponentName) then
outSubMod := match inMod
case Absyn.CLASSMOD(elementArgLst = {e as Absyn.REDECLARATION()})
then
e;
else
Absyn.MODIFICATION(false, Absyn.NON_EACH(), inComponentName,
SOME(inMod), NONE(), AbsynUtil.dummyInfo);
end match;
else
outSubMod := createNestedSubMod(AbsynUtil.pathRest(inComponentName), inMod);
outSubMod := Absyn.MODIFICATION(false, Absyn.NON_EACH(),
AbsynUtil.pathFirstPath(inComponentName),
SOME(Absyn.CLASSMOD({outSubMod}, Absyn.NOMOD())), NONE(),
AbsynUtil.dummyInfo);
end if;
end createNestedSubMod;

public function getComponentModifierValue
input Absyn.ComponentRef classRef;
input Absyn.ComponentRef varRef;
Expand Down

0 comments on commit a1ad0c7

Please sign in to comment.