Skip to content
This repository has been archived by the owner on May 18, 2019. It is now read-only.

Commit

Permalink
[NF] inStream/actualStream improvements.
Browse files Browse the repository at this point in the history
- Fix infinite loop when inStream/actualStream is used in reductions,
  by expanding the reduction argument instead of treating it like an
  array constructor (since reductions does not expand to arrays).
- Added checking of the argument to inStream/actualStream to make sure
  it's a stream variable with parameter subscripts.

Belonging to [master]:
  - OpenModelica/OpenModelica#148
  - #3057
  • Loading branch information
perost authored and OpenModelica-Hudson committed Apr 18, 2019
1 parent e9f8330 commit 8e0f7c5
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 4 deletions.
59 changes: 59 additions & 0 deletions Compiler/NFFrontEnd/NFBuiltinCall.mo
Expand Up @@ -63,6 +63,7 @@ protected
import ExpandExp = NFExpandExp;
import Operator = NFOperator;
import NFComponent.Component;
import NFPrefixes.ConnectorType;

public
function needSpecialHandling
Expand Down Expand Up @@ -106,6 +107,7 @@ public

(callExp, ty, variability) := match ComponentRef.firstName(cref)
case "String" then typeStringCall(call, next_origin, info);
case "actualStream" then typeActualInStreamCall("actualStream", call, next_origin, info);
case "branch" then typeBranchCall(call, next_origin, info);
case "cardinality" then typeCardinalityCall(call, next_origin, info);
case "cat" then typeCatCall(call, next_origin, info);
Expand All @@ -116,6 +118,7 @@ public
case "fill" then typeFillCall(call, next_origin, info);
case "getInstanceName" then typeGetInstanceName(call);
case "initial" then typeDiscreteCall(call, next_origin, info);
case "inStream" then typeActualInStreamCall("inStream", call, next_origin, info);
case "isRoot" then typeIsRootCall(call, next_origin, info);
case "matrix" then typeMatrixCall(call, next_origin, info);
case "max" then typeMinMaxCall("max", call, next_origin, info);
Expand Down Expand Up @@ -1760,5 +1763,61 @@ protected
end match;
end typeSampleCall;

function typeActualInStreamCall
input String name;
input Call call;
input ExpOrigin.Type origin;
input SourceInfo info;
output Expression callExp;
output Type ty;
output Variability variability = Variability.DISCRETE;
protected
ComponentRef fn_ref, arg_ref;
list<Expression> args;
list<NamedArg> named_args;
Expression arg;
Variability var;
Function fn;
InstNode arg_node;
algorithm
Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call;
assertNoNamedParams(name, named_args, info);

if listLength(args) <> 1 then
Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST,
{Call.toString(call), ComponentRef.toString(fn_ref) + "(stream variable) => Real"}, info);
end if;

(arg, ty, var) := Typing.typeExp(listHead(args), origin, info);

// The argument of actualStream/inStream must be a component reference.
if not Expression.isCref(arg) then
Error.addSourceMessage(Error.ARGUMENT_MUST_BE_VARIABLE,
{"First", ComponentRef.toString(fn_ref), "<REMOVE ME>"}, info);
fail();
end if;

arg_ref := Expression.toCref(arg);
arg_node := ComponentRef.node(arg_ref);

// The argument of actualStream/inStream must be a stream variable.
if not InstNode.isComponent(arg_node) or
not ConnectorType.isStream(Component.connectorType(InstNode.component(arg_node))) then
Error.addSourceMessageAndFail(Error.NON_STREAM_OPERAND_IN_STREAM_OPERATOR,
{ComponentRef.toString(arg_ref), name}, info);
end if;

// The argument of actualStream/inStream must have subscripts that can be evaluated.
for sub in ComponentRef.subscriptsAllFlat(arg_ref) loop
if Subscript.variability(sub) > Variability.PARAMETER then
Error.addSourceMessageAndFail(Error.CONNECTOR_NON_PARAMETER_SUBSCRIPT,
{ComponentRef.toString(arg_ref), Subscript.toString(sub)}, info);
end if;
end for;

{fn} := Function.typeRefCache(fn_ref);
callExp := Expression.CALL(Call.makeTypedCall(fn, {arg}, var, ty));
end typeActualInStreamCall;

annotation(__OpenModelica_Interface="frontend");
end NFBuiltinCall;
53 changes: 49 additions & 4 deletions Compiler/NFFrontEnd/NFConnectEquations.mo
Expand Up @@ -66,6 +66,9 @@ import BuiltinCall = NFBuiltinCall;
import ComplexType = NFComplexType;
import ExpandExp = NFExpandExp;
import Prefixes = NFPrefixes;
import NFComponent.Component;
import Ceval = NFCeval;
import MetaModelica.Dangerous.listReverseInPlace;

constant Expression EQ_ASSERT_STR =
Expression.STRING("Connected constants/parameters must be equal");
Expand Down Expand Up @@ -142,11 +145,11 @@ algorithm
// constructors containing such calls needs to expanded to get rid of the iterators.
case Call.TYPED_REDUCTION()
guard Expression.contains(call.exp, isStreamCall)
then evaluateOperatorIteratorExp(exp, sets, setsArray, ctable);
then evaluateOperatorReductionExp(exp, sets, setsArray, ctable);

case Call.TYPED_ARRAY_CONSTRUCTOR()
guard Expression.contains(call.exp, isStreamCall)
then evaluateOperatorIteratorExp(exp, sets, setsArray, ctable);
then evaluateOperatorArrayConstructorExp(exp, sets, setsArray, ctable);

else Expression.mapShallow(exp,
function evaluateOperators(sets = sets, setsArray = setsArray, ctable = ctable));
Expand Down Expand Up @@ -611,7 +614,49 @@ algorithm
end match;
end isStreamCall;

function evaluateOperatorIteratorExp
function evaluateOperatorReductionExp
input Expression exp;
input ConnectionSets.Sets sets;
input array<list<Connector>> setsArray;
input CardinalityTable.Table ctable;
output Expression evalExp;
protected
Call call;
Function fn;
Type ty;
Expression arg, iter_exp;
list<tuple<InstNode, Expression>> iters = {};
InstNode iter_node;
algorithm
evalExp := match exp
case Expression.CALL(call = call as Call.TYPED_REDUCTION())
algorithm
ty := Expression.typeOf(call.exp);

for iter in call.iters loop
(iter_node, iter_exp) := iter;

if Component.variability(InstNode.component(iter_node)) > Variability.PARAMETER then
print("Iteration range in reduction containing connector operator calls must be a parameter expression.");
fail();
end if;

iter_exp := Ceval.evalExp(iter_exp);
ty := Type.liftArrayLeftList(ty, Type.arrayDims(Expression.typeOf(iter_exp)));
iters := (iter_node, iter_exp) :: iters;
end for;

iters := listReverseInPlace(iters);
arg := ExpandExp.expandArrayConstructor(call.exp, ty, iters);
then
Expression.CALL(Call.makeTypedCall(call.fn, {arg}, call.var, call.ty));

end match;

evalExp := evaluateOperators(evalExp, sets, setsArray, ctable);
end evaluateOperatorReductionExp;

function evaluateOperatorArrayConstructorExp
input Expression exp;
input ConnectionSets.Sets sets;
input array<list<Connector>> setsArray;
Expand All @@ -629,7 +674,7 @@ algorithm
end if;

evalExp := evaluateOperators(evalExp, sets, setsArray, ctable);
end evaluateOperatorIteratorExp;
end evaluateOperatorArrayConstructorExp;

function evaluateInStream
"Evaluates the inStream operator with the given cref as argument."
Expand Down
2 changes: 2 additions & 0 deletions Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -1380,6 +1380,7 @@ uniontype Function
special := match Absyn.pathFirstIdent(path)
// Can have variable number of arguments.
case "array" then true;
case "actualStream" then true;
case "branch" then true;
case "cardinality" then true;
case "cat" then true;
Expand All @@ -1395,6 +1396,7 @@ uniontype Function
case "getInstanceName" then true;
// Always discrete.
case "initial" then true;
case "inStream" then true;
case "isRoot" then true;
// Arguments can be scalar, vector, matrix, 3d array .... basically anything
// We need to make sure size(Arg,i) = 1 for 2 < i <= ndims(Arg).
Expand Down

0 comments on commit 8e0f7c5

Please sign in to comment.