Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 67.2% 532 / 0 / 792
Functions: -% 0 / 1 / 1
Branches: 54.7% 337 / 0 / 616

OMCompiler/Compiler/NFFrontEnd/NFCall.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated uniontype NFCall
37
38 import Absyn;
39 import AbsynUtil;
40 import BaseModelica;
41 import DAE;
42 import Expression = NFExpression;
43 import NFCallAttributes;
44 import NFInstNode.InstNode;
45 import NFInstNode;
46 import NFPrefixes.{Variability, Purity};
47 import Type = NFType;
48 import Record = NFRecord;
49
50 protected
51 import Binding = NFBinding;
52 import BuiltinCall = NFBuiltinCall;
53 import Ceval = NFCeval;
54 import Component = NFComponent;
55 import ComponentRef = NFComponentRef;
56 import Dimension = NFDimension;
57 import ErrorExt;
58 import EvalFunction = NFEvalFunction;
59 import Inline = NFInline;
60 import Inst = NFInst;
61 import JSON;
62 import List;
63 import Lookup = NFLookup;
64 import MetaModelica.Dangerous.listReverseInPlace;
65 import Class = NFClass;
66 import NFFunction.Function;
67 import NFFunction.FunctionMatchKind;
68 import NFFunction.MatchedFunction;
69 import NFFunction.NamedArg;
70 import NFFunction.TypedArg;
71 import NFInstNode.CachedData;
72 import Operator = NFOperator;
73 import Prefixes = NFPrefixes;
74 import Restriction = NFRestriction;
75 import SCodeUtil;
76 import SimplifyExp = NFSimplifyExp;
77 import Structural = NFStructural;
78 import Subscript = NFSubscript;
79 import TypeCheck = NFTypeCheck;
80 import Typing = NFTyping;
81 import Util;
82 import InstContext = NFInstContext;
83 import ComplexType = NFComplexType;
84
85 import Call = NFCall;
86
87 protected
88 import NFCallParameterTree;
89 type ParameterTree = NFCallParameterTree.Tree;
90 public
91 record UNTYPED_CALL
92 ComponentRef ref;
93 list<Expression> arguments;
94 list<NamedArg> named_args;
95 NFInstNode.ScopeRef call_scope "Weakly: the scope owns the class this call
96 sits in.";
97 end UNTYPED_CALL;
98
99 record ARG_TYPED_CALL
100 ComponentRef ref;
101 list<TypedArg> positional_args;
102 list<TypedArg> named_args;
103 NFInstNode.ScopeRef call_scope "See UNTYPED_CALL.call_scope.";
104 end ARG_TYPED_CALL;
105
106 record TYPED_CALL
107 Function fn;
108 Type ty;
109 Variability var;
110 Purity purity;
111 list<Expression> arguments;
112 NFCallAttributes attributes;
113 end TYPED_CALL;
114
115 record UNTYPED_ARRAY_CONSTRUCTOR
116 Expression exp;
117 list<tuple<InstNode, Expression>> iters;
118 end UNTYPED_ARRAY_CONSTRUCTOR;
119
120 record TYPED_ARRAY_CONSTRUCTOR
121 Type ty;
122 Variability var;
123 Purity purity;
124 Expression exp;
125 list<tuple<InstNode, Expression>> iters;
126 end TYPED_ARRAY_CONSTRUCTOR;
127
128 record UNTYPED_REDUCTION
129 ComponentRef ref;
130 Expression exp;
131 list<tuple<InstNode, Expression>> iters;
132 end UNTYPED_REDUCTION;
133
134 record TYPED_REDUCTION
135 Function fn;
136 Type ty;
137 Variability var;
138 Purity purity;
139 Expression exp;
140 list<tuple<InstNode, Expression>> iters;
141 Option<Expression> defaultExp;
142 tuple<Option<Expression>, String, String> foldExp;
143 end TYPED_REDUCTION;
144
145 function instantiate
146 input Absyn.ComponentRef functionName;
147 input Absyn.FunctionArgs functionArgs;
148 input InstNode scope;
149 input InstContext.Type context;
150 input SourceInfo info;
151 output Expression callExp;
152 algorithm
153 callExp := match functionArgs
154 110173 case Absyn.FUNCTIONARGS() then instNormalCall(functionName, functionArgs, scope, context, info);
155 1775 case Absyn.FOR_ITER_FARG() then instIteratorCall(functionName, functionArgs, scope, context, info);
156 else
157 algorithm
158 ✗ Error.terminate(getInstanceName() + " got unknown call type", sourceInfo());
159 ✗ then
160 fail();
161 end match;
162 end instantiate;
163
164 function typeCall
165 input Expression callExp;
166 input InstContext.Type context;
167 input SourceInfo info;
168 input Boolean retype = false;
169 output Expression outExp;
170 output Type ty;
171 output Variability var;
172 output Purity pur;
173 protected
174 NFCall call, ty_call;
175 ComponentRef cref;
176 algorithm
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103726 times.
103726 Expression.CALL(call = call) := callExp;
178
179 outExp := match call
180 // 1. typing all the untyped calls
181 case UNTYPED_CALL(ref = cref)
182 algorithm
183
2/2
✓ Branch 1 taken 30062 times.
✓ Branch 2 taken 71573 times.
101635 if BuiltinCall.needSpecialHandling(call) then
184 30062 (outExp, ty, var, pur) := BuiltinCall.typeSpecial(call, context, info);
185 else
186 71573 checkNotPartial(cref, context, info);
187 71573 ty_call := typeMatchNormalCall(call, context, info);
188 71560 (outExp, ty, var, pur) := typeCallExp(ty_call);
189 end if;
190 then
191 outExp;
192
193 case UNTYPED_ARRAY_CONSTRUCTOR()
194 algorithm
195 1354 (ty_call, ty, var, pur) := typeArrayConstructor(call, context, info);
196 1354 then
197 Expression.CALL(ty_call);
198
199 case UNTYPED_REDUCTION()
200 algorithm
201 300 checkNotPartial(call.ref, context, info);
202 300 (ty_call, ty, var, pur) := typeReduction(call, context, info);
203 298 then
204 Expression.CALL(ty_call);
205
206 // 2. retyping already typed calls
207 case TYPED_CALL() guard(retype and not BuiltinCall.needSpecialHandling(call))
208 algorithm
209 165 ty_call := retypeCall(call, context, info);
210 165 (outExp, ty, var, pur) := typeCallExp(ty_call);
211 then
212 outExp;
213
214 // 3. not retyping already typed calls
215 case TYPED_CALL()
216 algorithm
217 262 ty := call.ty;
218 262 var := call.var;
219 262 pur := call.purity;
220 then
221 callExp;
222
223 case TYPED_ARRAY_CONSTRUCTOR()
224 algorithm
225 10 ty := call.ty;
226 10 var := call.var;
227 10 pur := call.purity;
228 then
229 callExp;
230
231 case TYPED_REDUCTION()
232 algorithm
233 ✗ ty := call.ty;
234 ✗ var := call.var;
235 ✗ pur := call.purity;
236 then
237 callExp;
238
239 else
240 algorithm
241 ✗ Error.terminate(getInstanceName() + ": " + Expression.toString(callExp), sourceInfo());
242 ✗ then fail();
243 end match;
244 end typeCall;
245
246 function checkNotPartial
247 input ComponentRef fnRef;
248 input InstContext.Type context;
249 input SourceInfo info;
250 algorithm
251
3/4
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 71872 times.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
71873 if InstNode.isPartial(ComponentRef.node(fnRef)) and not InstContext.inRelaxed(context) then
252 ✗ Error.addSourceMessage(Error.PARTIAL_FUNCTION_CALL,
253 {ComponentRef.toString(fnRef)}, info);
254 ✗ fail();
255 end if;
256 end checkNotPartial;
257
258 function typeCallExp
259 input Call ty_call;
260 output Expression outExp;
261 output Type ty;
262 output Variability var;
263 output Purity pur;
264 algorithm
265 71725 ty := typeOf(ty_call);
266 71725 var := variability(ty_call);
267 71725 pur := purity(ty_call);
268
2/2
✓ Branch 1 taken 832 times.
✓ Branch 2 taken 70893 times.
71725 if isRecordConstructor(ty_call) then
269 832 outExp := toRecordExpression(ty_call, ty);
270 else
271
2/2
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 70770 times.
70893 if Function.hasUnboxArgs(typedFunction(ty_call)) then
272 123 outExp := Expression.CALL(unboxArgs(ty_call));
273 else
274 70770 outExp := Expression.CALL(ty_call);
275 end if;
276 70893 outExp := Inline.inlineCallExp(outExp);
277
278 // The parameters of a partial function are boxed, so calling a functional
279 // input argument gives a boxed value. Unbox it here so the rest of the
280 // expression sees the actual type, otherwise the boxed type leaks into
281 // e.g. array constructors and reductions and gives invalid code.
282
4/6
✓ Branch 1 taken 70824 times.
✓ Branch 2 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 69 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 69 times.
70893 if Type.isBoxed(ty) and isUnboxableType(Type.unbox(ty)) and
283 Function.isFunctionPointer(typedFunction(ty_call)) then
284 69 ty := Type.unbox(ty);
285 69 outExp := Expression.UNBOX(outExp, ty);
286 end if;
287 end if;
288 end typeCallExp;
289
290 function isUnboxableType
291 "Returns true for the types that the code generator knows how to unbox."
292 input Type ty;
293 output Boolean unboxable = Type.isScalarBuiltin(ty) or Type.isRecord(ty);
294 end isUnboxableType;
295
296 function typeNormalCall
297 input output NFCall call;
298 input InstContext.Type context;
299 input SourceInfo info;
300 algorithm
301 call := match call
302 local
303 InstContext.Type fn_context;
304
305 case UNTYPED_CALL()
306 algorithm
307 // Strip any contexts that don't apply inside the function itself.
308
2/2
✓ Branch 1 taken 14290 times.
✓ Branch 2 taken 64466 times.
78756 if InstContext.inRelaxed(context) then
309 14290 fn_context := InstContext.set(NFInstContext.FUNCTION, NFInstContext.RELAXED);
310 else
311 fn_context := NFInstContext.FUNCTION;
312 end if;
313
314 78756 Function.typeRefCache(call.ref, fn_context);
315 78748 then
316 typeArgs(call, context, info);
317
318 else
319 algorithm
320 ✗ Error.terminate(getInstanceName() + " got invalid function call expression", sourceInfo());
321 ✗ then
322 fail();
323 end match;
324 end typeNormalCall;
325
326 function makeTypedCall
327 input Function fn;
328 input list<Expression> args;
329 input Variability variability;
330 input Purity purity;
331 input Type returnType = fn.returnType;
332 output NFCall call;
333 protected
334 NFCallAttributes ca;
335 algorithm
336
8/8
✓ Branch 2 taken 196976 times.
✓ Branch 3 taken 69 times.
✓ Branch 5 taken 195945 times.
✓ Branch 6 taken 1100 times.
✓ Branch 8 taken 61646 times.
✓ Branch 9 taken 135399 times.
✓ Branch 11 taken 195898 times.
✓ Branch 12 taken 1147 times.
847510 ca := NFCallAttributes.CALL_ATTR(
337 Type.isTuple(returnType),
338 Function.isBuiltin(fn),
339 Function.isImpure(fn),
340 Function.isFunctionPointer(fn),
341 Function.inlineBuiltin(fn),
342 DAE.NO_TAIL()
343 );
344
345 197045 call := TYPED_CALL(fn, returnType, variability, purity, args, ca);
346 end makeTypedCall;
347
348 function unboxArgs
349 input output NFCall call;
350 protected
351 Call c;
352 algorithm
353 () := match call
354 case TYPED_CALL()
355 algorithm
356
4/4
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 363 times.
✓ Branch 2 taken 151 times.
✓ Branch 3 taken 363 times.
877 call.arguments := list(Expression.unbox(arg) for arg in call.arguments);
357 then
358 ();
359
360 case TYPED_ARRAY_CONSTRUCTOR(exp = Expression.CALL(call = c))
361 algorithm
362 ✗ call.exp := Expression.CALL(unboxArgs(c));
363 then
364 ();
365
366 else ();
367 end match;
368 end unboxArgs;
369
370 function typeMatchNormalCall
371 input output NFCall call;
372 input InstContext.Type context;
373 input SourceInfo info;
374 input Boolean vectorize = true;
375 protected
376 NFCall argtycall;
377 algorithm
378 74338 argtycall := typeNormalCall(call, context, info);
379 74329 call := matchTypedNormalCall(argtycall, context, info, vectorize);
380 end typeMatchNormalCall;
381
382 function matchTypedNormalCall
383 input output NFCall call;
384 input InstContext.Type context;
385 input SourceInfo info;
386 input Boolean vectorize = true;
387 protected
388 Function func;
389 list<Expression> args;
390 list<TypedArg> typed_args;
391 MatchedFunction matchedFunc;
392 NFInstNode.ScopeRef scope;
393 Variability var, arg_var;
394 Purity pur, arg_pur;
395 Type ty;
396 Expression arg_exp;
397 algorithm
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78603 times.
78603 ARG_TYPED_CALL(call_scope = scope) := call;
399 78603 matchedFunc := checkMatchingFunctions(call, context, info, vectorize);
400
401 78598 func := matchedFunc.func;
402 78598 typed_args := matchedFunc.args;
403
404 args := {};
405 var := Variability.CONSTANT;
406
2/2
✓ Branch 1 taken 77719 times.
✓ Branch 2 taken 879 times.
78598 pur := if Function.isImpure(func) then Purity.IMPURE else Purity.PURE;
407
408
2/2
✓ Branch 0 taken 153449 times.
✓ Branch 1 taken 78598 times.
232047 for a in typed_args loop
409 153449 TypedArg.TYPED_ARG(value = arg_exp, var = arg_var, purity = arg_pur) := a;
410 args := arg_exp :: args;
411 153449 var := Prefixes.variabilityMax(var, arg_var);
412 153449 pur := Prefixes.purityMin(pur, arg_pur);
413 end for;
414 78598 args := listReverseInPlace(args);
415
416 78598 ty := Function.returnType(func);
417 78598 ty := resolvePolymorphicReturnType(func, typed_args, ty);
418
419
4/4
✓ Branch 0 taken 4460 times.
✓ Branch 1 taken 74138 times.
✓ Branch 3 taken 4326 times.
✓ Branch 4 taken 134 times.
78598 if var == Variability.PARAMETER and Function.isExternal(func) then
420 // Mark external functions with parameter expressions as non-structural,
421 // to avoid them being marked as structural unnecessarily.
422 var := Variability.NON_STRUCTURAL_PARAMETER;
423 elseif Type.isDiscrete(ty) and var == Variability.CONTINUOUS then
424 // Functions that return a discrete type, e.g. Integer, should probably be
425 // treated as implicitly discrete if the arguments are continuous.
426 var := Variability.IMPLICITLY_DISCRETE;
427 end if;
428
429 78598 ty := evaluateCallType(ty, func, args);
430 78598 call := makeTypedCall(func, args, var, pur, ty);
431
432 // If the matching was a vectorized one then create a map call
433 // using the vectorization dim. This means going through each argument
434 // and subscripting it with an iterator for each dim and creating a map call.
435
2/2
✓ Branch 1 taken 1515 times.
✓ Branch 2 taken 77083 times.
78598 if MatchedFunction.isVectorized(matchedFunc) then
436 1515 call := vectorizeCall(call, matchedFunc.mk, scope, info);
437 end if;
438
439
2/2
✓ Branch 1 taken 78018 times.
✓ Branch 2 taken 580 times.
78598 if Function.isExternal(func) then
440 580 updateExternalRecordArgs(args);
441 580 updateExternalRecordArgsInType(ty);
442 end if;
443 end matchTypedNormalCall;
444
445 function retypeCall
446 input Call call;
447 input InstContext.Type context;
448 input SourceInfo info;
449 output Call ty_call;
450 protected
451 InstContext.Type next_context;
452 Type ty, arg_ty;
453 Variability arg_var;
454 Purity arg_pur;
455 list<TypedArg> typed_args = {};
456 list<Expression> args = {};
457 algorithm
458 ty_call := match call
459 case TYPED_CALL() algorithm
460 165 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
461
2/2
✓ Branch 1 taken 319 times.
✓ Branch 2 taken 165 times.
484 for arg in listReverse(call.arguments) loop
462 319 (arg, arg_ty, arg_var, arg_pur) := Typing.typeExp(arg, next_context, info, true);
463 319 typed_args := TypedArg.TYPED_ARG(NONE(), arg, arg_ty, arg_var, arg_pur) :: typed_args;
464 args := arg :: args;
465 end for;
466
467 165 ty := Function.returnType(call.fn);
468 165 ty := resolvePolymorphicReturnType(call.fn, typed_args, ty);
469
470 165 ty := evaluateCallType(ty, call.fn, args);
471 165 ty_call := makeTypedCall(call.fn, args, call.var, call.purity, ty);
472 then ty_call;
473
474 else
475 algorithm
476 ✗ Error.terminate(getInstanceName() + " got invalid function call expression", sourceInfo());
477 ✗ then
478 fail();
479 end match;
480 end retypeCall;
481
482 function typeOf
483 input NFCall call;
484 output Type ty;
485 algorithm
486 ty := match call
487 876474 case TYPED_CALL() then call.ty;
488 11639 case TYPED_ARRAY_CONSTRUCTOR() then call.ty;
489 511 case TYPED_REDUCTION() then call.ty;
490 else Type.UNKNOWN();
491 end match;
492 end typeOf;
493
494 function setType
495 input output NFCall call;
496 input Type ty;
497 algorithm
498 call := match call
499 324893 case TYPED_CALL() algorithm call.ty := ty; then call;
500 8187 case TYPED_ARRAY_CONSTRUCTOR() algorithm call.ty := ty; then call;
501 62 case TYPED_REDUCTION() algorithm call.ty := ty; then call;
502 end match;
503 end setType;
504
505 function variability
506 input NFCall call;
507 output Variability var = Variability.CONTINUOUS;
508 algorithm
509 var := match call
510 local
511 Boolean var_set;
512
513 case UNTYPED_CALL()
514 algorithm
515 var_set := true;
516
517 ✗ if ComponentRef.isSimple(call.ref) then
518 var := match ComponentRef.firstName(call.ref)
519 case "change" then Variability.DISCRETE;
520 case "edge" then Variability.DISCRETE;
521 case "pre" then Variability.DISCRETE;
522 case "ndims" then Variability.PARAMETER;
523 case "cardinality" then Variability.PARAMETER;
524 else algorithm var_set := false; then Variability.CONTINUOUS;
525 end match;
526 else
527 var_set := false;
528 end if;
529
530 if not var_set then
531 ✗ var := Expression.variabilityList(call.arguments);
532
533 ✗ for narg in call.named_args loop
534 ✗ var := Prefixes.variabilityMax(var, Expression.variability(Util.tuple22(narg)));
535 end for;
536 end if;
537 then
538 var;
539
540 1 case UNTYPED_ARRAY_CONSTRUCTOR() then Expression.variability(call.exp);
541 ✗ case UNTYPED_REDUCTION() then Expression.variability(call.exp);
542 93665 case TYPED_CALL() then call.var;
543 1569 case TYPED_ARRAY_CONSTRUCTOR() then call.var;
544 ✗ case TYPED_REDUCTION() then call.var;
545 else algorithm
546 ✗ Error.terminate(getInstanceName() + " got untyped call", sourceInfo());
547 ✗ then fail();
548 end match;
549 end variability;
550
551 function purity
552 input Call call;
553 output Purity purity;
554 algorithm
555 purity := match call
556 77132 case TYPED_CALL() then call.purity;
557 1515 case TYPED_ARRAY_CONSTRUCTOR() then call.purity;
558 ✗ case TYPED_REDUCTION() then call.purity;
559 else Purity.PURE;
560 end match;
561 end purity;
562
563 function compare
564 input NFCall call1;
565 input NFCall call2;
566 output Integer comp;
567 algorithm
568 2194 comp := AbsynUtil.pathCompare(functionName(call1), functionName(call2));
569
570
2/2
✓ Branch 0 taken 1947 times.
✓ Branch 1 taken 247 times.
2194 if comp == 0 then
571 1947 comp := Expression.compareList(arguments(call1), arguments(call2));
572 end if;
573
574
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1672 times.
2194 if comp == 0 then
575 1672 comp := List.compare(iterators(call1), iterators(call2), compareIterator);
576 end if;
577 end compare;
578
579 function compareIterator
580 input tuple<InstNode, Expression> iter1;
581 input tuple<InstNode, Expression> iter2;
582 output Integer comp;
583 protected
584 InstNode n1, n2;
585 Expression e1, e2;
586 algorithm
587 54 (n1, e1) := iter1;
588 54 (n2, e2) := iter2;
589 54 comp := stringCompare(InstNode.name(n1), InstNode.name(n2));
590
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if comp == 0 then
592 54 comp := Expression.compare(e1, e2);
593 end if;
594 end compareIterator;
595
596 function isExternal
597 input NFCall call;
598 output Boolean isExternal;
599 algorithm
600 isExternal := match call
601 1496 case UNTYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref)));
602 ✗ case ARG_TYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref)));
603 216552 case TYPED_CALL() then Function.isExternal(call.fn);
604 else false;
605 end match;
606 end isExternal;
607
608 function isImpure
609 input NFCall call;
610 output Boolean isImpure;
611 algorithm
612 isImpure := match call
613 1496 case UNTYPED_CALL() then Function.isImpure(listHead(Function.getRefCache(call.ref)));
614 773 case TYPED_CALL(purity = Purity.IMPURE) then Function.isImpure(call.fn);
615 else false;
616 end match;
617 end isImpure;
618
619 function isRecordConstructor
620 input NFCall call;
621 output Boolean isConstructor;
622 algorithm
623 isConstructor := match call
624 case UNTYPED_CALL()
625 ✗ then SCodeUtil.isRecord(InstNode.definition(ComponentRef.node(call.ref)));
626 case TYPED_CALL() guard(not InstNode.isEmpty(InstNode.fromHandle(call.fn.node)))
627 70210 then SCodeUtil.isRecord(InstNode.definition(InstNode.fromHandle(call.fn.node)));
628 else false;
629 end match;
630 end isRecordConstructor;
631
632 function isExternalObjectConstructor
633 input NFCall call;
634 output Boolean isConstructor;
635 algorithm
636 isConstructor := match call
637 // Only constructors may return external objects...
638 case TYPED_CALL()
639 30 then Type.isExternalObject(call.ty);
640 else false;
641 end match;
642 end isExternalObjectConstructor;
643
644 function isLiteral
645 input Call call;
646 output Boolean literal;
647 protected
648 function is_literal_iter
649 input tuple<InstNode, Expression> iter;
650 output Boolean literal = Expression.isLiteral(Util.tuple22(iter));
651 end is_literal_iter;
652 algorithm
653 literal := match call
654 ✗ case TYPED_CALL() then List.all(call.arguments, Expression.isLiteral);
655
656 case TYPED_REDUCTION()
657 ✗ then Expression.isLiteral(call.exp) and List.all(call.iters, is_literal_iter);
658
659 case TYPED_ARRAY_CONSTRUCTOR()
660 ✗ then Expression.isLiteral(call.exp) and List.all(call.iters, is_literal_iter);
661
662 else false;
663 end match;
664 end isLiteral;
665
666 function isKnownSizeFill
667 input Call call;
668 output Boolean res;
669 protected
670 function is_literal_iter
671 input tuple<InstNode, Expression> iter;
672 output Boolean literal = Expression.isLiteral(Util.tuple22(iter));
673 end is_literal_iter;
674 algorithm
675 res := match call
676
4/4
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 27 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 22 times.
55 case TYPED_CALL() then isNamed(call, "fill") and List.all(listRest(call.arguments), Expression.isLiteral);
677 447 case TYPED_ARRAY_CONSTRUCTOR() then List.all(call.iters, is_literal_iter);
678 else false;
679 end match;
680 end isKnownSizeFill;
681
682 function isReduction
683 "returns true if the call is a typed reduction or if the call is a typed
684 call of a function that represents an array reduction"
685 input Call call;
686 output Boolean b;
687 algorithm
688 b := match call
689 case TYPED_REDUCTION() then true;
690 case TYPED_CALL() then match AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn))
691 case "min" then true;
692 case "max" then true;
693 case "sum" then true;
694 case "product" then true;
695 else false;
696 end match;
697 else false;
698 end match;
699 end isReduction;
700
701 function isPositive
702 "True if the return value of the function is known to be > 0, otherwise false."
703 input Call call;
704 output Boolean positive;
705 algorithm
706 positive := match call
707 case TYPED_CALL()
708 then match functionNameFirst(call)
709 ✗ case "abs" then Expression.isNonZero(listHead(call.arguments));
710 2 case "max" then List.any(call.arguments, Expression.isPositive);
711 ✗ case "min" then List.all(call.arguments, Expression.isPositive);
712 else false;
713 end match;
714
715 else false;
716 end match;
717 end isPositive;
718
719 function isNegative
720 "True if the return value of the function is known to be < 0, otherwise false."
721 input Call call;
722 output Boolean negative;
723 algorithm
724 negative := match call
725 case TYPED_CALL()
726 then match functionNameFirst(call)
727 case "abs" then false;
728 ✗ case "min" then List.any(call.arguments, Expression.isNegative);
729 ✗ case "max" then List.all(call.arguments, Expression.isNegative);
730 else false;
731 end match;
732
733 else false;
734 end match;
735 end isNegative;
736
737 function isNonPositive
738 "True if the return value of the function is known to be <= 0, otherwise false."
739 input Call call;
740 output Boolean nonPositive;
741 algorithm
742 nonPositive := match call
743 case TYPED_CALL()
744 then match functionNameFirst(call)
745 ✗ case "abs" then Expression.isZero(listHead(call.arguments));
746 ✗ case "max" then List.all(call.arguments, Expression.isNonPositive);
747 ✗ case "min" then List.any(call.arguments, Expression.isNonPositive);
748 else false;
749 end match;
750
751 else false;
752 end match;
753 end isNonPositive;
754
755 function isNonNegative
756 "True if the return value of the function is known to be >= 0, otherwise false."
757 input Call call;
758 output Boolean nonNegative;
759 algorithm
760 nonNegative := match call
761 case TYPED_CALL()
762 then match functionNameFirst(call)
763 case "abs" then true;
764 ✗ case "max" then List.any(call.arguments, Expression.isNonNegative);
765 ✗ case "min" then List.all(call.arguments, Expression.isNonNegative);
766 else false;
767 end match;
768
769 else false;
770 end match;
771 end isNonNegative;
772
773 function inlineType
774 input NFCall call;
775 output DAE.InlineType inlineTy;
776 algorithm
777 inlineTy := match call
778 case TYPED_CALL(attributes = NFCallAttributes.CALL_ATTR(inlineType = inlineTy))
779 then inlineTy;
780 else DAE.InlineType.NO_INLINE();
781 end match;
782 end inlineType;
783
784 function typedFunction
785 input NFCall call;
786 output Function fn;
787 algorithm
788 fn := match call
789 147806 case TYPED_CALL() then call.fn;
790 2711 case TYPED_ARRAY_CONSTRUCTOR() then NFBuiltinFuncs.ARRAY_FUNC;
791 36 case TYPED_REDUCTION() then call.fn;
792 else
793 algorithm
794 ✗ Error.terminate(getInstanceName() + " got untyped function", sourceInfo());
795 ✗ then
796 fail();
797 end match;
798 end typedFunction;
799
800 function functionName
801 input NFCall call;
802 output Absyn.Path name;
803 algorithm
804 name := match call
805 ✗ case UNTYPED_CALL() then ComponentRef.toPath(call.ref);
806 ✗ case ARG_TYPED_CALL() then ComponentRef.toPath(call.ref);
807 49152 case TYPED_CALL() then Function.nameConsiderBuiltin(call.fn);
808 case UNTYPED_ARRAY_CONSTRUCTOR() then Absyn.IDENT("array");
809 case TYPED_ARRAY_CONSTRUCTOR() then Absyn.IDENT("array");
810 ✗ case UNTYPED_REDUCTION() then ComponentRef.toPath(call.ref);
811 80 case TYPED_REDUCTION() then Function.nameConsiderBuiltin(call.fn);
812 end match;
813 end functionName;
814
815 function functionNameLast
816 input Call call;
817 output String ident = AbsynUtil.pathLastIdent(functionName(call));
818 end functionNameLast;
819
820 function functionNameFirst
821 input Call call;
822 output String ident = AbsynUtil.pathFirstIdent(functionName(call));
823 end functionNameFirst;
824
825 function isNamed
826 input Call call;
827 input String name;
828 output Boolean res;
829 protected
830 Absyn.Path path;
831 algorithm
832 32860 path := functionName(call);
833
834 res := match path
835
4/4
✓ Branch 0 taken 19495 times.
✓ Branch 1 taken 7522 times.
✓ Branch 3 taken 3163 times.
✓ Branch 4 taken 16332 times.
27017 case Absyn.IDENT() then path.name == name;
836 else false;
837 end match;
838 end isNamed;
839
840 function arguments
841 input NFCall call;
842 output list<Expression> arguments;
843 algorithm
844 arguments := match call
845 ✗ case UNTYPED_CALL() then call.arguments;
846 14087 case TYPED_CALL() then call.arguments;
847 ✗ case UNTYPED_ARRAY_CONSTRUCTOR() then {call.exp};
848 127 case TYPED_ARRAY_CONSTRUCTOR() then {call.exp};
849 ✗ case UNTYPED_REDUCTION() then {call.exp};
850 31 case TYPED_REDUCTION() then {call.exp};
851 end match;
852 end arguments;
853
854 function setArguments
855 input output NFCall call;
856 input list<Expression> arguments;
857 algorithm
858 call := match call
859 ✗ case UNTYPED_CALL() algorithm call.arguments := arguments; then call;
860 203 case TYPED_CALL() algorithm call.arguments := arguments; then call;
861 end match;
862 end setArguments;
863
864 function iterators
865 input Call call;
866 output list<tuple<InstNode, Expression>> iters;
867 algorithm
868 iters := match call
869 ✗ case UNTYPED_ARRAY_CONSTRUCTOR() then call.iters;
870 699 case TYPED_ARRAY_CONSTRUCTOR() then call.iters;
871 ✗ case UNTYPED_REDUCTION() then call.iters;
872 89 case TYPED_REDUCTION() then call.iters;
873 else {};
874 end match;
875 end iterators;
876
877 function toRecordExpression
878 input NFCall call;
879 input Type ty;
880 output Expression exp;
881 algorithm
882 exp := match call
883 case TYPED_CALL()
884 832 then EvalFunction.evaluateRecordConstructor(call.fn, ty, call.arguments, evaluate = false);
885
886 else
887 algorithm
888 ✗ Error.terminate(getInstanceName() + " got unknown call", sourceInfo());
889 ✗ then
890 fail();
891
892 end match;
893 end toRecordExpression;
894
895 function toString
896 input NFCall call;
897 output String str;
898 protected
899 String name, arg_str,c;
900 list<InstNode> iters;
901 algorithm
902 str := match call
903 case UNTYPED_CALL()
904 algorithm
905 62 name := ComponentRef.toString(call.ref);
906
4/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 209 times.
✓ Branch 3 taken 62 times.
271 arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", ");
907 62 then
908 name + "(" + arg_str + ")";
909
910 case ARG_TYPED_CALL()
911 algorithm
912 ✗ name := ComponentRef.toString(call.ref);
913 ✗ arg_str :=
914 stringDelimitList(list(Expression.toString(arg.value) for arg in call.positional_args), ", ");
915 ✗ for arg in call.named_args loop
916 ✗ c := if arg_str == "" then "" else ", ";
917 ✗ arg_str := arg_str + c + Util.getOption(arg.name) + " = " + Expression.toString(arg.value);
918 end for;
919 ✗ then
920 name + "(" + arg_str + ")";
921
922 case UNTYPED_ARRAY_CONSTRUCTOR()
923 algorithm
924 ✗ name := AbsynUtil.pathString(Function.nameConsiderBuiltin(NFBuiltinFuncs.ARRAY_FUNC));
925 ✗ arg_str := Expression.toString(call.exp);
926 ✗ c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " +
927 Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", ");
928 ✗ then
929 "{" + arg_str + " for " + c + "}";
930
931 case UNTYPED_REDUCTION()
932 algorithm
933 ✗ name := ComponentRef.toString(call.ref);
934 ✗ arg_str := Expression.toString(call.exp);
935 ✗ c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " +
936 Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", ");
937 ✗ then
938 name + "(" + arg_str + " for " + c + ")";
939
940 case TYPED_CALL()
941 algorithm
942 8273 name := AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn));
943
4/4
✓ Branch 0 taken 15883 times.
✓ Branch 1 taken 8273 times.
✓ Branch 2 taken 15883 times.
✓ Branch 3 taken 8273 times.
24156 arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", ");
944 8273 then
945 name + "(" + arg_str + ")";
946
947 case TYPED_ARRAY_CONSTRUCTOR()
948 algorithm
949 80 name := AbsynUtil.pathString(Function.nameConsiderBuiltin(NFBuiltinFuncs.ARRAY_FUNC));
950 80 arg_str := Expression.toString(call.exp);
951
4/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 80 times.
164 c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " +
952 Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", ");
953 80 then
954 "{" + arg_str + " for " + c + "}";
955
956 case TYPED_REDUCTION()
957 algorithm
958 37 name := AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn));
959 37 arg_str := Expression.toString(call.exp);
960
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 37 times.
74 c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " +
961 Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", ");
962 37 then
963 name + "(" + arg_str + " for " + c + ")";
964
965 end match;
966 end toString;
967
968 function toFlatString
969 input NFCall call;
970 input BaseModelica.OutputFormat format;
971 output String str;
972 protected
973 String name, arg_str,c;
974 list<InstNode> iters;
975 algorithm
976 str := match call
977 case TYPED_CALL()
978 algorithm
979 105 name := AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn));
980 105 arg_str := toFlatStringArgs(call.arguments, name, format);
981
3/4
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
240 then
982 if Function.isBuiltin(call.fn) then
983 stringAppendList({name, "(", arg_str, ")"})
984 elseif isExternalObjectConstructor(call) then
985 stringAppendList({Type.toFlatString(call.ty, format), "(", arg_str, ")"})
986 else
987 stringAppendList({Util.makeQuotedIdentifier(name), "(", arg_str, ")"});
988
989 case TYPED_ARRAY_CONSTRUCTOR()
990 algorithm
991
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if isVectorized(call) then
992 // Vectorized calls contains iterators with illegal Modelica names
993 // (to avoid name conflicts), to make the flat output legal such
994 // calls are reverted to their original form here.
995 ✗ str := Expression.toFlatString(devectorizeCall(call), format);
996 else
997 1 name := AbsynUtil.pathString(Function.nameConsiderBuiltin(NFBuiltinFuncs.ARRAY_FUNC));
998 1 arg_str := Expression.toFlatString(call.exp, format);
999
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 c := stringDelimitList(list(Util.makeQuotedIdentifier(InstNode.name(Util.tuple21(iter))) + " in " +
1000 Expression.toFlatString(Util.tuple22(iter), format) for iter in call.iters), ", ");
1001 1 str := stringAppendList({"{", arg_str, " for ", c, "}"});
1002 end if;
1003 then
1004 str;
1005
1006 case TYPED_REDUCTION()
1007 algorithm
1008 ✗ name := AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn));
1009 ✗ arg_str := Expression.toFlatString(call.exp, format);
1010 ✗ c := stringDelimitList(list(Util.makeQuotedIdentifier(InstNode.name(Util.tuple21(iter))) + " in " +
1011 Expression.toFlatString(Util.tuple22(iter), format) for iter in call.iters), ", ");
1012 ✗ then
1013 if Function.isBuiltin(call.fn) then
1014 stringAppendList({name, "(", arg_str, " for ", c, ")"})
1015 else
1016 stringAppendList({Util.makeQuotedIdentifier(name), "(", arg_str, " for ", c, ")"});
1017
1018 end match;
1019 end toFlatString;
1020
1021 function toFlatStringArgs
1022 input list<Expression> args;
1023 input String fnName;
1024 input BaseModelica.OutputFormat format;
1025 output String argsString;
1026 protected
1027 Expression arg1, arg2;
1028 list<Expression> rest_args;
1029 algorithm
1030 argsString := match fnName
1031 case "String"
1032 then match args
1033 case {arg1, arg2}
1034 2 then Expression.toFlatString(arg1, format) + ", format = " + Expression.toFlatString(arg2, format);
1035
1036 else
1037 algorithm
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 arg1 :: rest_args := args;
1039 10 argsString := Expression.toFlatString(arg1, format);
1040
1041
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
10 if listLength(rest_args) == 3 then
1042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 arg1 :: rest_args := rest_args;
1043
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
4 if not Expression.isIntegerValue(arg1, 6) then
1044 1 argsString := argsString + ", significantDigits = " + Expression.toFlatString(arg1, format);
1045 end if;
1046 end if;
1047
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 arg1 :: rest_args := rest_args;
1049
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 if not Expression.isZero(arg1) then
1050 5 argsString := argsString + ", minimumLength = " + Expression.toFlatString(arg1, format);
1051 end if;
1052
1053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 arg1 :: rest_args := rest_args;
1054
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 7 times.
10 if not Expression.isTrue(arg1) then
1055 3 argsString := argsString + ", leftJustified = " + Expression.toFlatString(arg1, format);
1056 end if;
1057 then
1058 argsString;
1059 end match;
1060
1061
4/4
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 93 times.
258 else stringDelimitList(list(Expression.toFlatString(arg, format) for arg in args), ", ");
1062 end match;
1063 end toFlatStringArgs;
1064
1065 function typedString
1066 "Like toString, but prefixes each argument with its type as a comment."
1067 input NFCall call;
1068 output String str;
1069 protected
1070 String name, arg_str,c;
1071 algorithm
1072 str := match call
1073 case ARG_TYPED_CALL()
1074 algorithm
1075 2 name := ComponentRef.toString(call.ref);
1076
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 arg_str := stringDelimitList(list("/*" + Type.toString(arg.ty) + "*/ " +
1077 Expression.toString(arg.value) for arg in call.positional_args), ", ");
1078
1079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for arg in call.named_args loop
1080 ✗ c := if arg_str == "" then "" else ", ";
1081 ✗ arg_str := arg_str + c + Util.getOption(arg.name) + " = /*" +
1082 Type.toString(arg.ty) + "*/ " + Expression.toString(arg.value);
1083 end for;
1084 2 then
1085 name + "(" + arg_str + ")";
1086
1087 case TYPED_CALL()
1088 algorithm
1089 ✗ name := AbsynUtil.pathString(Function.name(call.fn));
1090 ✗ arg_str := stringDelimitList(list(Expression.toStringTyped(arg) for arg in call.arguments), ", ");
1091 ✗ then
1092 name + "(" + arg_str + ")";
1093
1094 ✗ else toString(call);
1095 end match;
1096 end typedString;
1097
1098 function toJSON
1099 input Call call;
1100 output JSON json = JSON.emptyListObject();
1101
1102 function iterators_json
1103 input list<tuple<InstNode, Expression>> iters;
1104 output JSON json = JSON.emptyArray(listLength(iters));
1105 protected
1106 JSON j;
1107 algorithm
1108
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for i in iters loop
1109 1 j := JSON.emptyListObject();
1110 1 j := JSON.addPair("name", JSON.makeString(InstNode.name(Util.tuple21(i))), j);
1111 1 j := JSON.addPair("range", Expression.toJSON(Util.tuple22(i)), j);
1112 1 json := JSON.addElement(j, json);
1113 end for;
1114 end iterators_json;
1115 protected
1116 Absyn.Path path;
1117 algorithm
1118 () := match call
1119 case TYPED_CALL()
1120 algorithm
1121 4 path := Function.nameConsiderBuiltin(call.fn);
1122 4 json := JSON.addPair("$kind", JSON.makeString("call"), json);
1123 4 json := JSON.addPair("name", JSON.makeString(AbsynUtil.pathString(path)), json);
1124
1125
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
4 if isNamed(call, "String") then
1126 1 json := toJSONStringArgs(call.arguments, json);
1127 else
1128
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
9 json := JSON.addPair("arguments", JSON.makeArray(
1129 list(Expression.toJSON(a) for a in call.arguments)), json);
1130 end if;
1131 then
1132 ();
1133
1134 case TYPED_ARRAY_CONSTRUCTOR()
1135 algorithm
1136 1 json := JSON.addPair("$kind", JSON.makeString("iterator_call"), json);
1137 1 json := JSON.addPair("name", JSON.makeString("$array"), json);
1138 1 json := JSON.addPair("exp", Expression.toJSON(call.exp), json);
1139 1 json := JSON.addPair("iterators", iterators_json(call.iters), json);
1140 then
1141 ();
1142
1143 case TYPED_REDUCTION()
1144 algorithm
1145 ✗ path := Function.nameConsiderBuiltin(call.fn);
1146 ✗ json := JSON.addPair("$kind", JSON.makeString("iterator_call"), json);
1147 ✗ json := JSON.addPair("name", JSON.makeString(AbsynUtil.pathString(path)), json);
1148 ✗ json := JSON.addPair("exp", Expression.toJSON(call.exp), json);
1149 ✗ json := JSON.addPair("iterators", iterators_json(call.iters), json);
1150 then
1151 ();
1152
1153 else
1154 algorithm
1155 ✗ json := JSON.addPair("$kind", JSON.makeString("call"), json);
1156 then
1157 ();
1158
1159 end match;
1160 end toJSON;
1161
1162 function toJSONStringArgs
1163 input list<Expression> args;
1164 input output JSON json;
1165 protected
1166 Integer arg_count;
1167 Expression value, arg;
1168 list<Expression> rest_args;
1169 list<JSON> json_args;
1170
1171 function make_arg
1172 input String name;
1173 input Expression value;
1174 output JSON json = JSON.emptyListObject();
1175 algorithm
1176 1 json := JSON.addPair("$kind", JSON.makeString("named_arg"), json);
1177 1 json := JSON.addPair(name, Expression.toJSON(value), json);
1178 end make_arg;
1179 algorithm
1180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 value :: rest_args := args;
1181 1 arg_count := listLength(rest_args);
1182 1 json_args := {Expression.toJSON(value)};
1183
1184
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if arg_count == 1 then
1185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 arg :: _ := rest_args;
1186 1 json_args := make_arg("format", arg) :: json_args;
1187 else
1188 ✗ if arg_count == 3 then
1189 ✗ arg :: rest_args := rest_args;
1190 ✗ if not Expression.isIntegerValue(arg, 6) then
1191 ✗ json_args := make_arg("significantDigits", arg) :: json_args;
1192 end if;
1193 end if;
1194
1195 ✗ arg :: rest_args := rest_args;
1196 ✗ if not Expression.isZero(arg) then
1197 ✗ json_args := make_arg("minimumLength", arg) :: json_args;
1198 end if;
1199
1200 ✗ arg :: rest_args := rest_args;
1201 ✗ if not Expression.isTrue(arg) then
1202 ✗ json_args := make_arg("leftJustified", arg) :: json_args;
1203 end if;
1204 end if;
1205
1206 1 json := JSON.addPair("arguments", JSON.makeList(listReverseInPlace(json_args)), json);
1207 end toJSONStringArgs;
1208
1209 function toAbsyn
1210 input Call call;
1211 output Absyn.Exp absynCall;
1212 algorithm
1213 absynCall := match call
1214 local
1215 list<Absyn.Exp> pargs;
1216 list<Absyn.NamedArg> nargs;
1217
1218 case UNTYPED_CALL()
1219 algorithm
1220 ✗ pargs := list(Expression.toAbsyn(arg) for arg in call.arguments);
1221 ✗ nargs := list(Absyn.NamedArg.NAMEDARG(Util.tuple21(arg),
1222 Expression.toAbsyn(Util.tuple22(arg))) for arg in call.named_args);
1223 ✗ then
1224 AbsynUtil.makeCall(ComponentRef.toAbsyn(call.ref), pargs, nargs);
1225
1226 case ARG_TYPED_CALL()
1227 algorithm
1228 ✗ pargs := list(Expression.toAbsyn(arg.value) for arg in call.positional_args);
1229 ✗ nargs := list(Absyn.NamedArg.NAMEDARG(Util.getOption(arg.name),
1230 Expression.toAbsyn(arg.value)) for arg in call.named_args);
1231 ✗ then
1232 AbsynUtil.makeCall(ComponentRef.toAbsyn(call.ref), pargs, nargs);
1233
1234 case TYPED_CALL()
1235 algorithm
1236 ✗ pargs := list(Expression.toAbsyn(arg) for arg in call.arguments);
1237 ✗ then
1238 AbsynUtil.makeCall(AbsynUtil.pathToCref(Function.name(call.fn)), pargs);
1239
1240 case UNTYPED_ARRAY_CONSTRUCTOR()
1241 ✗ then Absyn.Exp.CALL(Absyn.ComponentRef.CREF_IDENT("array", {}), toAbsynIterators(call.exp, call.iters), {});
1242
1243 case TYPED_ARRAY_CONSTRUCTOR()
1244 ✗ then Absyn.Exp.CALL(Absyn.ComponentRef.CREF_IDENT("array", {}), toAbsynIterators(call.exp, call.iters), {});
1245
1246 case UNTYPED_REDUCTION()
1247 ✗ then Absyn.Exp.CALL(ComponentRef.toAbsyn(call.ref), toAbsynIterators(call.exp, call.iters), {});
1248
1249 case TYPED_REDUCTION()
1250 ✗ then Absyn.Exp.CALL(AbsynUtil.pathToCref(Function.name(call.fn)), toAbsynIterators(call.exp, call.iters), {});
1251
1252 else
1253 algorithm
1254 ✗ Error.terminate(getInstanceName() + " got unknown call", sourceInfo());
1255 ✗ then
1256 fail();
1257 end match;
1258 end toAbsyn;
1259
1260 function toAbsynIterators
1261 input Expression iterExp;
1262 input list<tuple<InstNode, Expression>> iters;
1263 output Absyn.FunctionArgs args;
1264 algorithm
1265 ✗ args := Absyn.FunctionArgs.FOR_ITER_FARG(
1266 Expression.toAbsyn(iterExp),
1267 Absyn.ReductionIterType.COMBINE(),
1268 list(Absyn.ForIterator.ITERATOR(
1269 InstNode.name(Util.tuple21(i)),
1270 NONE(),
1271 SOME(Expression.toAbsyn(Util.tuple22(i)))
1272 ) for i in iters));
1273 end toAbsynIterators;
1274
1275 function toDAE
1276 input NFCall call;
1277 output DAE.Exp daeCall;
1278 algorithm
1279 // The code generation can't handle reductions/array constructors with
1280 // multiple iterators so we need to convert them to nested calls with one
1281 // iterator each. But the frontend can handle multiple iterators more
1282 // efficiently so we do it only just before passing them to the backend.
1283 73055 daeCall := toDAE_work(expandReduction(call));
1284 end toDAE;
1285
1286 function toDAE_work
1287 input NFCall call;
1288 output DAE.Exp daeCall;
1289 algorithm
1290 daeCall := match call
1291 local
1292 String fold_id, res_id;
1293 Option<Expression> fold_exp;
1294
1295 case TYPED_CALL()
1296
4/4
✓ Branch 0 taken 126258 times.
✓ Branch 1 taken 72457 times.
✓ Branch 2 taken 126258 times.
✓ Branch 3 taken 72457 times.
198715 then DAE.CALL(
1297 Function.nameConsiderBuiltin(call.fn),
1298 list(Expression.toDAE(e) for e in call.arguments),
1299 NFCallAttributes.toDAE(call.attributes, call.ty));
1300
1301 case TYPED_ARRAY_CONSTRUCTOR()
1302 algorithm
1303 548 fold_id := Util.getTempVariableIndex();
1304 548 res_id := Util.getTempVariableIndex();
1305
4/4
✓ Branch 5 taken 548 times.
✓ Branch 6 taken 548 times.
✓ Branch 7 taken 548 times.
✓ Branch 8 taken 548 times.
1096 then
1306 DAE.REDUCTION(
1307 DAE.REDUCTIONINFO(
1308 Function.name(NFBuiltinFuncs.ARRAY_FUNC),
1309 Absyn.COMBINE(),
1310 Type.toDAE(call.ty),
1311 NONE(),
1312 fold_id,
1313 res_id,
1314 NONE()),
1315 Expression.toDAE(call.exp),
1316 list(iteratorToDAE(iter) for iter in call.iters));
1317
1318 case TYPED_REDUCTION()
1319 algorithm
1320 50 (fold_exp, fold_id, res_id) := call.foldExp;
1321
4/4
✓ Branch 7 taken 50 times.
✓ Branch 8 taken 50 times.
✓ Branch 9 taken 50 times.
✓ Branch 10 taken 50 times.
100 then
1322 DAE.REDUCTION(
1323 DAE.REDUCTIONINFO(
1324 Function.name(call.fn),
1325 Absyn.COMBINE(),
1326 Type.toDAE(call.ty),
1327 Util.applyOption(call.defaultExp, Expression.toDAEValue),
1328 fold_id,
1329 res_id,
1330 Util.applyOption(fold_exp, function Expression.toDAE(allowEmpty = false))),
1331 Expression.toDAE(call.exp),
1332 list(iteratorToDAE(iter) for iter in call.iters));
1333
1334 else
1335 algorithm
1336 ✗ Error.terminate(getInstanceName() + " got untyped call", sourceInfo());
1337 ✗ then
1338 fail();
1339 end match;
1340 end toDAE_work;
1341
1342 function expandReduction
1343 "Turns reductions/array constructors with multiple iterators into nested
1344 reductions/array constructors."
1345 input Call call;
1346 output Call outCall;
1347 algorithm
1348 outCall := match call
1349 local
1350 list<tuple<InstNode, Expression>> iters;
1351 tuple<InstNode, Expression> iter;
1352 Type ty;
1353
1354 case TYPED_ARRAY_CONSTRUCTOR(iters = iters)
1355 guard listLength(iters) > 1
1356 algorithm
1357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 iter :: iters := iters;
1358 6 ty := Type.liftArrayLeftList(Expression.typeOf(call.exp),
1359 Type.arrayDims(Expression.typeOf(Util.tuple22(iter))));
1360 6 outCall := TYPED_ARRAY_CONSTRUCTOR(ty, call.var, call.purity, call.exp, {iter});
1361
1362
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 for i in iters loop
1363 7 ty := Type.liftArrayLeftList(ty, Type.arrayDims(Expression.typeOf(Util.tuple22(i))));
1364 14 outCall := TYPED_ARRAY_CONSTRUCTOR(ty, call.var, call.purity, Expression.CALL(outCall), {i});
1365 end for;
1366 then
1367 outCall;
1368
1369 case TYPED_REDUCTION(iters = iters)
1370 guard listLength(iters) > 1
1371 algorithm
1372 ✗ iter :: iters := iters;
1373 ✗ outCall := makeTypedReduction(call.fn, call.ty, call.var, call.purity,
1374 call.exp, {iter}, Absyn.dummyInfo);
1375
1376 ✗ for i in iters loop
1377 ✗ outCall := makeTypedReduction(call.fn, call.ty, call.var, call.purity,
1378 Expression.CALL(outCall), {i}, Absyn.dummyInfo);
1379 end for;
1380 then
1381 outCall;
1382
1383 else call;
1384 end match;
1385 end expandReduction;
1386
1387 function isVectorizeable
1388 input NFCall call;
1389 output Boolean isVect;
1390 algorithm
1391 isVect := match call
1392 local
1393 String name;
1394
1395 case TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = name)))
1396 then match name
1397 case "der" then false;
1398 case "pre" then false;
1399 case "previous" then false;
1400 else true;
1401 end match;
1402
1403 else true;
1404 end match;
1405 end isVectorizeable;
1406
1407 function retype
1408 input output NFCall call;
1409 algorithm
1410 () := match call
1411 local
1412 Type ty;
1413 list<Dimension> dims;
1414
1415 case TYPED_ARRAY_CONSTRUCTOR()
1416 algorithm
1417 dims := {};
1418
1419
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 19 times.
38 for i in listReverse(call.iters) loop
1420 19 dims := listAppend(Type.arrayDims(Expression.typeOf(Util.tuple22(i))), dims);
1421 end for;
1422
1423 19 call.ty := Type.liftArrayLeftList(Type.arrayElementType(call.ty), dims);
1424 then
1425 ();
1426
1427 else ();
1428 end match;
1429 end retype;
1430
1431 function typeCast
1432 input output Expression callExp;
1433 input Type ty;
1434 protected
1435 NFCall call;
1436 Type cast_ty;
1437 algorithm
1438
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11492 times.
11492 Expression.CALL(call = call) := callExp;
1439
1440 callExp := match call
1441 case TYPED_CALL() guard Function.isBuiltin(call.fn)
1442 algorithm
1443 11415 cast_ty := Type.setArrayElementType(call.ty, ty);
1444 then
1445 match AbsynUtil.pathFirstIdent(Function.name(call.fn))
1446 // For 'fill' we can type cast the first argument rather than the
1447 // whole array that 'fill' constructs.
1448 case "fill"
1449 algorithm
1450 19204 call.arguments := Expression.typeCast(listHead(call.arguments), ty) ::
1451 listRest(call.arguments);
1452 9602 call.ty := cast_ty;
1453 9602 then
1454 Expression.CALL(call);
1455
1456 // For diagonal we can type cast the argument rather than the
1457 // matrix that diagonal constructs.
1458 case "diagonal"
1459 algorithm
1460 4 call.arguments := {Expression.typeCast(listHead(call.arguments), ty)};
1461 2 call.ty := cast_ty;
1462 2 then
1463 Expression.CALL(call);
1464
1465 // For DynamicSelect we type cast both of the arguments.
1466 case "DynamicSelect"
1467 algorithm
1468
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 4 times.
16 call.arguments := list(Expression.typeCast(arg, ty) for arg in call.arguments);
1469 4 then
1470 Expression.CALL(call);
1471
1472 1807 else Expression.CAST(cast_ty, callExp);
1473 end match;
1474
1475 77 else Expression.typeCastGeneric(callExp, ty);
1476 end match;
1477 end typeCast;
1478
1479 function containsExp
1480 input Call call;
1481 input ContainsPred func;
1482 output Boolean res;
1483
1484 partial function ContainsPred
1485 input Expression exp;
1486 output Boolean res;
1487 end ContainsPred;
1488 algorithm
1489 res := match call
1490 local
1491 Expression e;
1492
1493 case UNTYPED_CALL()
1494 algorithm
1495 ✗ res := Expression.listContains(call.arguments, func);
1496
1497 ✗ if not res then
1498 ✗ for arg in call.named_args loop
1499 ✗ (_, e) := arg;
1500
1501 ✗ if Expression.contains(e, func) then
1502 res := true;
1503 break;
1504 end if;
1505 end for;
1506 end if;
1507 then
1508 res;
1509
1510 case ARG_TYPED_CALL()
1511 algorithm
1512 ✗ for arg in call.positional_args loop
1513 ✗ if Expression.contains(arg.value, func) then
1514 res := true;
1515 ✗ return;
1516 end if;
1517 end for;
1518
1519 ✗ for arg in call.named_args loop
1520 ✗ if Expression.contains(arg.value, func) then
1521 res := true;
1522 ✗ return;
1523 end if;
1524 end for;
1525 then
1526 false;
1527
1528 61071 case TYPED_CALL() then Expression.listContains(call.arguments, func);
1529 case UNTYPED_ARRAY_CONSTRUCTOR()
1530 ✗ then Expression.contains(call.exp, func) or itersContainExp(call.iters, func);
1531 case TYPED_ARRAY_CONSTRUCTOR()
1532
3/4
✓ Branch 1 taken 283 times.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 283 times.
290 then Expression.contains(call.exp, func) or itersContainExp(call.iters, func);
1533 case UNTYPED_REDUCTION()
1534 ✗ then Expression.contains(call.exp, func) or itersContainExp(call.iters, func);
1535 case TYPED_REDUCTION()
1536
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
13 then Expression.contains(call.exp, func) or itersContainExp(call.iters, func);
1537 end match;
1538 end containsExp;
1539
1540 function itersContainExp
1541 "An iterator range is a subexpression too: `sum(x[k] for k in i:n)` uses `i`."
1542 input list<tuple<InstNode, Expression>> iters;
1543 input ContainsPred func;
1544 output Boolean res = false;
1545
1546 partial function ContainsPred
1547 input Expression exp;
1548 output Boolean res;
1549 end ContainsPred;
1550 algorithm
1551
2/2
✓ Branch 0 taken 296 times.
✓ Branch 1 taken 296 times.
592 for iter in iters loop
1552
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 296 times.
296 if Expression.contains(Util.tuple22(iter), func) then
1553 res := true;
1554 ✗ return;
1555 end if;
1556 end for;
1557 end itersContainExp;
1558
1559 function containsExpShallow
1560 input Call call;
1561 input ContainsPred func;
1562 output Boolean res;
1563
1564 partial function ContainsPred
1565 input Expression exp;
1566 output Boolean res;
1567 end ContainsPred;
1568 algorithm
1569 res := match call
1570 local
1571 Expression e;
1572
1573 case UNTYPED_CALL()
1574 algorithm
1575 1496 res := List.any(call.arguments, func);
1576
1577
2/2
✓ Branch 0 taken 1343 times.
✓ Branch 1 taken 153 times.
1496 if not res then
1578
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1343 times.
1345 for arg in call.named_args loop
1579 2 (_, e) := arg;
1580
1581
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 if func(e) then
1582 res := true;
1583 break;
1584 end if;
1585 end for;
1586 end if;
1587 then
1588 res;
1589
1590 case ARG_TYPED_CALL()
1591 algorithm
1592 ✗ for arg in call.positional_args loop
1593 ✗ if func(arg.value) then
1594 res := true;
1595 ✗ return;
1596 end if;
1597 end for;
1598
1599 ✗ for arg in call.named_args loop
1600 ✗ if func(arg.value) then
1601 res := true;
1602 ✗ return;
1603 end if;
1604 end for;
1605 then
1606 false;
1607
1608 131502 case TYPED_CALL() then List.any(call.arguments, func);
1609
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 case UNTYPED_ARRAY_CONSTRUCTOR() then func(call.exp);
1610
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 621 times.
624 case TYPED_ARRAY_CONSTRUCTOR() then func(call.exp);
1611 ✗ case UNTYPED_REDUCTION() then func(call.exp);
1612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 case TYPED_REDUCTION() then func(call.exp);
1613 end match;
1614 end containsExpShallow;
1615
1616 function applyExp
1617 input Call call;
1618 input ApplyFunc func;
1619
1620 partial function ApplyFunc
1621 input Expression exp;
1622 end ApplyFunc;
1623 algorithm
1624 () := match call
1625 local
1626 Expression e;
1627
1628 case UNTYPED_CALL()
1629 algorithm
1630 16299 Expression.applyList(call.arguments, func);
1631
1632
2/2
✓ Branch 0 taken 801 times.
✓ Branch 1 taken 16299 times.
17100 for arg in call.named_args loop
1633 801 (_, e) := arg;
1634 801 Expression.apply(e, func);
1635 end for;
1636 then
1637 ();
1638
1639 case ARG_TYPED_CALL()
1640 algorithm
1641 ✗ for arg in call.positional_args loop
1642 ✗ Expression.apply(arg.value, func);
1643 end for;
1644
1645 ✗ for arg in call.named_args loop
1646 ✗ Expression.apply(arg.value, func);
1647 end for;
1648 then
1649 ();
1650
1651 case TYPED_CALL()
1652 algorithm
1653 197790 Expression.applyList(call.arguments, func);
1654 then
1655 ();
1656
1657 case UNTYPED_ARRAY_CONSTRUCTOR()
1658 algorithm
1659 896 Expression.apply(call.exp, func);
1660
1661
2/2
✓ Branch 0 taken 896 times.
✓ Branch 1 taken 896 times.
1792 for i in call.iters loop
1662 896 Expression.apply(Util.tuple22(i), func);
1663 end for;
1664 then
1665 ();
1666
1667 case TYPED_ARRAY_CONSTRUCTOR()
1668 algorithm
1669 3842 Expression.apply(call.exp, func);
1670
1671
2/2
✓ Branch 0 taken 3952 times.
✓ Branch 1 taken 3842 times.
7794 for i in call.iters loop
1672 3952 Expression.apply(Util.tuple22(i), func);
1673 end for;
1674 then
1675 ();
1676
1677 case UNTYPED_REDUCTION()
1678 algorithm
1679 28 Expression.apply(call.exp, func);
1680
1681
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 28 times.
57 for i in call.iters loop
1682 29 Expression.apply(Util.tuple22(i), func);
1683 end for;
1684 then
1685 ();
1686
1687 case TYPED_REDUCTION()
1688 algorithm
1689 71 Expression.apply(call.exp, func);
1690
1691
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 71 times.
143 for i in call.iters loop
1692 72 Expression.apply(Util.tuple22(i), func);
1693 end for;
1694
1695 71 Expression.applyOpt(call.defaultExp, func);
1696 71 Expression.applyOpt(Util.tuple31(call.foldExp), func);
1697 then
1698 ();
1699 end match;
1700 end applyExp;
1701
1702 function applyExpShallow
1703 input Call call;
1704 input ApplyFunc func;
1705
1706 partial function ApplyFunc
1707 input Expression exp;
1708 end ApplyFunc;
1709 algorithm
1710 () := match call
1711 local
1712 Expression e;
1713
1714 case UNTYPED_CALL()
1715 algorithm
1716 1797 Expression.applyListShallow(call.arguments, func);
1717
1718
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1797 times.
1801 for arg in call.named_args loop
1719 4 (_, e) := arg;
1720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 func(e);
1721 end for;
1722 then
1723 ();
1724
1725 case ARG_TYPED_CALL()
1726 algorithm
1727 ✗ for arg in call.positional_args loop
1728 ✗ func(arg.value);
1729 end for;
1730
1731 ✗ for arg in call.named_args loop
1732 ✗ func(arg.value);
1733 end for;
1734 then
1735 ();
1736
1737 case TYPED_CALL()
1738 algorithm
1739 152 Expression.applyListShallow(call.arguments, func);
1740 then
1741 ();
1742
1743 case UNTYPED_ARRAY_CONSTRUCTOR()
1744 algorithm
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 func(call.exp);
1746
1747
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for i in call.iters loop
1748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 func(Util.tuple22(i));
1749 end for;
1750 then
1751 ();
1752
1753 case TYPED_ARRAY_CONSTRUCTOR()
1754 algorithm
1755 ✗ func(call.exp);
1756
1757 ✗ for i in call.iters loop
1758 ✗ func(Util.tuple22(i));
1759 end for;
1760 then
1761 ();
1762
1763 case UNTYPED_REDUCTION()
1764 algorithm
1765 ✗ func(call.exp);
1766
1767 ✗ for i in call.iters loop
1768 ✗ func(Util.tuple22(i));
1769 end for;
1770 then
1771 ();
1772
1773 case TYPED_REDUCTION()
1774 algorithm
1775 ✗ func(call.exp);
1776
1777 ✗ for i in call.iters loop
1778 ✗ func(Util.tuple22(i));
1779 end for;
1780
1781 ✗ Expression.applyShallowOpt(call.defaultExp, func);
1782 ✗ Expression.applyShallowOpt(Util.tuple31(call.foldExp), func);
1783 then
1784 ();
1785 end match;
1786 end applyExpShallow;
1787
1788 function foldExp<ArgT>
1789 input Call call;
1790 input FoldFunc func;
1791 input output ArgT foldArg;
1792
1793 partial function FoldFunc
1794 input Expression exp;
1795 input output ArgT arg;
1796 end FoldFunc;
1797 algorithm
1798 () := match call
1799 local
1800 Expression e;
1801
1802 case UNTYPED_CALL()
1803 algorithm
1804 2 foldArg := Expression.foldList(call.arguments, func, foldArg);
1805
1806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for arg in call.named_args loop
1807 ✗ (_, e) := arg;
1808 ✗ foldArg := Expression.fold(e, func, foldArg);
1809 end for;
1810 then
1811 ();
1812
1813 case ARG_TYPED_CALL()
1814 algorithm
1815 ✗ for arg in call.positional_args loop
1816 ✗ foldArg := Expression.fold(arg.value, func, foldArg);
1817 end for;
1818
1819 ✗ for arg in call.named_args loop
1820 ✗ foldArg := Expression.fold(arg.value, func, foldArg);
1821 end for;
1822 then
1823 ();
1824
1825 case TYPED_CALL()
1826 algorithm
1827 148509 foldArg := Expression.foldList(call.arguments, func, foldArg);
1828 then
1829 ();
1830
1831 case UNTYPED_ARRAY_CONSTRUCTOR()
1832 algorithm
1833 2 foldArg := Expression.fold(call.exp, func, foldArg);
1834
1835
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for i in call.iters loop
1836 2 foldArg := Expression.fold(Util.tuple22(i), func, foldArg);
1837 end for;
1838 then
1839 ();
1840
1841 case TYPED_ARRAY_CONSTRUCTOR()
1842 algorithm
1843 2150 foldArg := Expression.fold(call.exp, func, foldArg);
1844
1845
2/2
✓ Branch 0 taken 2170 times.
✓ Branch 1 taken 2150 times.
4320 for i in call.iters loop
1846 2170 foldArg := Expression.fold(Util.tuple22(i), func, foldArg);
1847 end for;
1848 then
1849 ();
1850
1851 case UNTYPED_REDUCTION()
1852 algorithm
1853 ✗ foldArg := Expression.fold(call.exp, func, foldArg);
1854
1855 ✗ for i in call.iters loop
1856 ✗ foldArg := Expression.fold(Util.tuple22(i), func, foldArg);
1857 end for;
1858 then
1859 ();
1860
1861 case TYPED_REDUCTION()
1862 algorithm
1863 91 foldArg := Expression.fold(call.exp, func, foldArg);
1864
1865
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 91 times.
182 for i in call.iters loop
1866 91 foldArg := Expression.fold(Util.tuple22(i), func, foldArg);
1867 end for;
1868
1869 91 foldArg := Expression.foldOpt(call.defaultExp, func, foldArg);
1870 91 foldArg := Expression.foldOpt(Util.tuple31(call.foldExp), func, foldArg);
1871 then
1872 ();
1873 end match;
1874 end foldExp;
1875
1876 function mapExp
1877 input Call call;
1878 input MapFunc func;
1879 output Call outCall;
1880
1881 partial function MapFunc
1882 input output Expression e;
1883 end MapFunc;
1884 algorithm
1885 outCall := match call
1886 local
1887 list<Expression> args;
1888 list<NamedArg> nargs;
1889 list<TypedArg> targs, tnargs;
1890 String s;
1891 Expression e;
1892 list<tuple<InstNode, Expression>> iters;
1893 Option<Expression> default_exp;
1894 tuple<Option<Expression>, String, String> fold_exp;
1895
1896 case UNTYPED_CALL()
1897 algorithm
1898
4/4
✓ Branch 0 taken 373 times.
✓ Branch 1 taken 544 times.
✓ Branch 2 taken 373 times.
✓ Branch 3 taken 544 times.
917 args := list(Expression.map(arg, func) for arg in call.arguments);
1899 nargs := {};
1900
1901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 544 times.
544 for arg in call.named_args loop
1902 ✗ (s, e) := arg;
1903 ✗ e := Expression.map(e, func);
1904 ✗ nargs := (s, e) :: nargs;
1905 end for;
1906 544 then
1907 UNTYPED_CALL(call.ref, args, listReverse(nargs), call.call_scope);
1908
1909 case ARG_TYPED_CALL()
1910 algorithm
1911 targs := {};
1912 tnargs := {};
1913
1914 ✗ for arg in call.positional_args loop
1915 ✗ arg.value := Expression.map(arg.value, func);
1916 targs := arg :: targs;
1917 end for;
1918
1919 ✗ for arg in call.named_args loop
1920 ✗ arg.value := Expression.map(arg.value, func);
1921 tnargs := arg :: tnargs;
1922 end for;
1923 ✗ then
1924 ARG_TYPED_CALL(call.ref, listReverse(targs), listReverse(tnargs), call.call_scope);
1925
1926 case TYPED_CALL()
1927 algorithm
1928
4/4
✓ Branch 0 taken 1301551 times.
✓ Branch 1 taken 710361 times.
✓ Branch 2 taken 1301551 times.
✓ Branch 3 taken 710361 times.
2011912 args := list(Expression.map(arg, func) for arg in call.arguments);
1929 710361 then
1930 TYPED_CALL(call.fn, call.ty, call.var, call.purity, args, call.attributes);
1931
1932 case UNTYPED_ARRAY_CONSTRUCTOR()
1933 algorithm
1934 1 e := Expression.map(call.exp, func);
1935 1 iters := mapIteratorsExp(call.iters, func);
1936 1 then
1937 UNTYPED_ARRAY_CONSTRUCTOR(e, iters);
1938
1939 case TYPED_ARRAY_CONSTRUCTOR()
1940 algorithm
1941 9159 e := Expression.map(call.exp, func);
1942 9159 iters := mapIteratorsExp(call.iters, func);
1943 9159 then
1944 TYPED_ARRAY_CONSTRUCTOR(call.ty, call.var, call.purity, e, iters);
1945
1946 case UNTYPED_REDUCTION()
1947 algorithm
1948 ✗ e := Expression.map(call.exp, func);
1949 ✗ iters := mapIteratorsExp(call.iters, func);
1950 ✗ then
1951 UNTYPED_REDUCTION(call.ref, e, iters);
1952
1953 case TYPED_REDUCTION()
1954 algorithm
1955 438 e := Expression.map(call.exp, func);
1956 438 iters := mapIteratorsExp(call.iters, func);
1957 438 default_exp := Util.applyOption(call.defaultExp, function Expression.map(func = func));
1958 438 fold_exp := Util.applyTuple31(call.foldExp, function Expression.mapOpt(func = func));
1959 438 then
1960 TYPED_REDUCTION(call.fn, call.ty, call.var, call.purity, e, iters, default_exp, fold_exp);
1961
1962 end match;
1963 end mapExp;
1964
1965 function mapIteratorsExp
1966 input list<tuple<InstNode, Expression>> iters;
1967 input MapFunc func;
1968 output list<tuple<InstNode, Expression>> outIters = {};
1969
1970 partial function MapFunc
1971 input output Expression e;
1972 end MapFunc;
1973 protected
1974 InstNode node;
1975 Expression exp, new_exp;
1976 algorithm
1977
2/2
✓ Branch 0 taken 9971 times.
✓ Branch 1 taken 9598 times.
19569 for i in iters loop
1978 9971 (node, exp) := i;
1979 9971 new_exp := Expression.map(exp, func);
1980
2/2
✓ Branch 0 taken 3101 times.
✓ Branch 1 taken 6870 times.
9971 outIters := (if referenceEq(new_exp, exp) then i else (node, new_exp)) :: outIters;
1981 end for;
1982
1983 9598 outIters := listReverseInPlace(outIters);
1984 end mapIteratorsExp;
1985
1986 function mapExpShallow
1987 input Call call;
1988 input MapFunc func;
1989 output Call outCall;
1990
1991 partial function MapFunc
1992 input output Expression e;
1993 end MapFunc;
1994 algorithm
1995 outCall := match call
1996 local
1997 list<Expression> args;
1998 list<NamedArg> nargs;
1999 list<TypedArg> targs, tnargs;
2000 String s;
2001 Expression e;
2002 list<tuple<InstNode, Expression>> iters;
2003 Option<Expression> default_exp;
2004 tuple<Option<Expression>, String, String> fold_exp;
2005
2006 case UNTYPED_CALL()
2007 algorithm
2008
5/6
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 104 times.
✓ Branch 3 taken 88 times.
✓ Branch 4 taken 104 times.
✗ Branch 5 not taken.
192 args := list(func(arg) for arg in call.arguments);
2009 nargs := {};
2010
2011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 for arg in call.named_args loop
2012 ✗ (s, e) := arg;
2013 ✗ e := func(e);
2014 ✗ nargs := (s, e) :: nargs;
2015 end for;
2016 88 then
2017 UNTYPED_CALL(call.ref, args, listReverse(nargs), call.call_scope);
2018
2019 case ARG_TYPED_CALL()
2020 algorithm
2021 targs := {};
2022 tnargs := {};
2023
2024 ✗ for arg in call.positional_args loop
2025 ✗ arg.value := func(arg.value);
2026 targs := arg :: targs;
2027 end for;
2028
2029 ✗ for arg in call.named_args loop
2030 ✗ arg.value := func(arg.value);
2031 tnargs := arg :: tnargs;
2032 end for;
2033 ✗ then
2034 ARG_TYPED_CALL(call.ref, listReverse(targs), listReverse(tnargs), call.call_scope);
2035
2036 case TYPED_CALL()
2037 algorithm
2038
6/6
✓ Branch 0 taken 605910 times.
✓ Branch 1 taken 312544 times.
✓ Branch 2 taken 605910 times.
✓ Branch 3 taken 312544 times.
✓ Branch 4 taken 601439 times.
✓ Branch 5 taken 4471 times.
918454 args := list(func(arg) for arg in call.arguments);
2039 312544 then
2040 TYPED_CALL(call.fn, call.ty, call.var, call.purity, args, call.attributes);
2041
2042 case UNTYPED_ARRAY_CONSTRUCTOR()
2043 algorithm
2044 ✗ e := func(call.exp);
2045 ✗ iters := mapIteratorsExpShallow(call.iters, func);
2046 ✗ then
2047 UNTYPED_ARRAY_CONSTRUCTOR(e, iters);
2048
2049 case TYPED_ARRAY_CONSTRUCTOR()
2050 algorithm
2051
2/2
✓ Branch 0 taken 4854 times.
✓ Branch 1 taken 7 times.
4861 e := func(call.exp);
2052 4861 iters := mapIteratorsExpShallow(call.iters, func);
2053 4861 then
2054 TYPED_ARRAY_CONSTRUCTOR(call.ty, call.var, call.purity, e, iters);
2055
2056 case UNTYPED_REDUCTION()
2057 algorithm
2058 ✗ e := func(call.exp);
2059 ✗ iters := mapIteratorsExpShallow(call.iters, func);
2060 ✗ then
2061 UNTYPED_REDUCTION(call.ref, e, iters);
2062
2063 case TYPED_REDUCTION()
2064 algorithm
2065
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 3 times.
118 e := func(call.exp);
2066 118 iters := mapIteratorsExpShallow(call.iters, func);
2067 118 default_exp := Expression.mapShallowOpt(call.defaultExp, func);
2068 118 fold_exp := Util.applyTuple31(call.foldExp, function Expression.mapShallowOpt(func = func));
2069 118 then
2070 TYPED_REDUCTION(call.fn, call.ty, call.var, call.purity, e, iters, default_exp, fold_exp);
2071
2072 end match;
2073 end mapExpShallow;
2074
2075 function mapIteratorsExpShallow
2076 input list<tuple<InstNode, Expression>> iters;
2077 input MapFunc func;
2078 output list<tuple<InstNode, Expression>> outIters = {};
2079
2080 partial function MapFunc
2081 input output Expression e;
2082 end MapFunc;
2083 protected
2084 InstNode node;
2085 Expression exp, new_exp;
2086 algorithm
2087
2/2
✓ Branch 0 taken 5592 times.
✓ Branch 1 taken 5565 times.
11157 for i in iters loop
2088 5592 (node, exp) := i;
2089
2/2
✓ Branch 0 taken 4995 times.
✓ Branch 1 taken 597 times.
5592 new_exp := func(exp);
2090
2/2
✓ Branch 0 taken 2911 times.
✓ Branch 1 taken 2681 times.
5592 outIters := (if referenceEq(new_exp, exp) then i else (node, new_exp)) :: outIters;
2091 end for;
2092
2093 5565 outIters := listReverseInPlace(outIters);
2094 end mapIteratorsExpShallow;
2095
2096 function mapFoldExp<ArgT>
2097 input Call call;
2098 input MapFunc func;
2099 output Call outCall;
2100 input output ArgT foldArg;
2101
2102 partial function MapFunc
2103 input output Expression e;
2104 input output ArgT arg;
2105 end MapFunc;
2106 algorithm
2107 outCall := match call
2108 local
2109 list<Expression> args;
2110 list<NamedArg> nargs;
2111 list<TypedArg> targs, tnargs;
2112 String s;
2113 Expression e;
2114 list<tuple<InstNode, Expression>> iters;
2115 Option<Expression> default_exp;
2116 tuple<Option<Expression>, String, String> fold_exp;
2117 Option<Expression> oe;
2118
2119 case UNTYPED_CALL()
2120 algorithm
2121 ✗ (args, foldArg) := List.map1Fold(call.arguments, Expression.mapFold, func, foldArg);
2122 nargs := {};
2123
2124 ✗ for arg in call.named_args loop
2125 ✗ (s, e) := arg;
2126 ✗ (e, foldArg) := Expression.mapFold(e, func, foldArg);
2127 ✗ nargs := (s, e) :: nargs;
2128 end for;
2129 ✗ then
2130 UNTYPED_CALL(call.ref, args, listReverse(nargs), call.call_scope);
2131
2132 case ARG_TYPED_CALL()
2133 algorithm
2134 targs := {};
2135 tnargs := {};
2136
2137 ✗ for arg in call.positional_args loop
2138 ✗ (e, foldArg) := Expression.mapFold(arg.value, func, foldArg);
2139 ✗ arg.value := e;
2140 targs := arg :: targs;
2141 end for;
2142
2143 ✗ for arg in call.named_args loop
2144 ✗ (e, foldArg) := Expression.mapFold(arg.value, func, foldArg);
2145 ✗ arg.value := e;
2146 targs := arg :: targs;
2147 end for;
2148 ✗ then
2149 ARG_TYPED_CALL(call.ref, listReverse(targs), listReverse(tnargs), call.call_scope);
2150
2151 case TYPED_CALL()
2152 algorithm
2153 27 (args, foldArg) := List.map1Fold(call.arguments, Expression.mapFold, func, foldArg);
2154 27 then
2155 TYPED_CALL(call.fn, call.ty, call.var, call.purity, args, call.attributes);
2156
2157 case UNTYPED_ARRAY_CONSTRUCTOR()
2158 algorithm
2159 ✗ (e, foldArg) := Expression.mapFold(call.exp, func, foldArg);
2160 ✗ (iters, foldArg) := mapFoldIteratorsExp(call.iters, func, foldArg);
2161 ✗ then
2162 UNTYPED_ARRAY_CONSTRUCTOR(e, iters);
2163
2164 case TYPED_ARRAY_CONSTRUCTOR()
2165 algorithm
2166 1 (e, foldArg) := Expression.mapFold(call.exp, func, foldArg);
2167 1 (iters, foldArg) := mapFoldIteratorsExp(call.iters, func, foldArg);
2168 1 then
2169 TYPED_ARRAY_CONSTRUCTOR(call.ty, call.var, call.purity, e, iters);
2170
2171 case UNTYPED_REDUCTION()
2172 algorithm
2173 ✗ (e, foldArg) := Expression.mapFold(call.exp, func, foldArg);
2174 ✗ (iters, foldArg) := mapFoldIteratorsExp(call.iters, func, foldArg);
2175 ✗ then
2176 UNTYPED_REDUCTION(call.ref, e, iters);
2177
2178 case TYPED_REDUCTION()
2179 algorithm
2180 ✗ (e, foldArg) := Expression.mapFold(call.exp, func, foldArg);
2181 ✗ (iters, foldArg) := mapFoldIteratorsExp(call.iters, func, foldArg);
2182 ✗ (default_exp, foldArg) := Expression.mapFoldOpt(call.defaultExp, func, foldArg);
2183 ✗ oe := Util.tuple31(call.foldExp);
2184
2185 ✗ if isSome(oe) then
2186 ✗ (oe, foldArg) := Expression.mapFoldOpt(oe, func, foldArg);
2187 ✗ fold_exp := Util.applyTuple31(call.foldExp, function Util.replace(arg = oe));
2188 else
2189 ✗ fold_exp := call.foldExp;
2190 end if;
2191 ✗ then
2192 TYPED_REDUCTION(call.fn, call.ty, call.var, call.purity, e, iters, default_exp, fold_exp);
2193 end match;
2194 end mapFoldExp;
2195
2196 function mapFoldIteratorsExp<ArgT>
2197 input list<tuple<InstNode, Expression>> iters;
2198 input MapFunc func;
2199 output list<tuple<InstNode, Expression>> outIters = {};
2200 input output ArgT arg;
2201
2202 partial function MapFunc
2203 input output Expression e;
2204 input output ArgT arg;
2205 end MapFunc;
2206 protected
2207 InstNode node;
2208 Expression exp, new_exp;
2209 algorithm
2210
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for i in iters loop
2211 1 (node, exp) := i;
2212 1 (new_exp, arg) := Expression.mapFold(exp, func, arg);
2213
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 outIters := (if referenceEq(new_exp, exp) then i else (node, new_exp)) :: outIters;
2214 end for;
2215
2216 1 outIters := listReverseInPlace(outIters);
2217 end mapFoldIteratorsExp;
2218
2219 function mapFoldExpShallow<ArgT>
2220 input Call call;
2221 input MapFunc func;
2222 output Call outCall;
2223 input output ArgT foldArg;
2224
2225 partial function MapFunc
2226 input output Expression e;
2227 input output ArgT arg;
2228 end MapFunc;
2229 algorithm
2230 outCall := match call
2231 local
2232 list<Expression> args;
2233 list<NamedArg> nargs;
2234 list<TypedArg> targs, tnargs;
2235 String s;
2236 Expression e;
2237 list<tuple<InstNode, Expression>> iters;
2238 Option<Expression> default_exp;
2239 tuple<Option<Expression>, String, String> fold_exp;
2240 Option<Expression> oe;
2241
2242 case UNTYPED_CALL()
2243 algorithm
2244 ✗ (args, foldArg) := List.mapFold(call.arguments, func, foldArg);
2245 nargs := {};
2246
2247 ✗ for arg in call.named_args loop
2248 ✗ (s, e) := arg;
2249 ✗ (e, foldArg) := func(e, foldArg);
2250 ✗ nargs := (s, e) :: nargs;
2251 end for;
2252 ✗ then
2253 UNTYPED_CALL(call.ref, args, listReverse(nargs), call.call_scope);
2254
2255 case ARG_TYPED_CALL()
2256 algorithm
2257 targs := {};
2258 tnargs := {};
2259
2260 ✗ for arg in call.positional_args loop
2261 ✗ (e, foldArg) := func(arg.value, foldArg);
2262 ✗ arg.value := e;
2263 targs := arg :: targs;
2264 end for;
2265
2266 ✗ for arg in call.named_args loop
2267 ✗ (e, foldArg) := func(arg.value, foldArg);
2268 ✗ arg.value := e;
2269 targs := arg :: targs;
2270 end for;
2271 ✗ then
2272 ARG_TYPED_CALL(call.ref, listReverse(targs), listReverse(tnargs), call.call_scope);
2273
2274 case TYPED_CALL()
2275 algorithm
2276 165291 (args, foldArg) := List.mapFold(call.arguments, func, foldArg);
2277 165291 then
2278 TYPED_CALL(call.fn, call.ty, call.var, call.purity, args, call.attributes);
2279
2280 case UNTYPED_ARRAY_CONSTRUCTOR()
2281 algorithm
2282 ✗ (e, foldArg) := func(call.exp, foldArg);
2283 ✗ iters := mapFoldIteratorsExpShallow(call.iters, func, foldArg);
2284 ✗ then
2285 UNTYPED_ARRAY_CONSTRUCTOR(e, iters);
2286
2287 case TYPED_ARRAY_CONSTRUCTOR()
2288 algorithm
2289
1/2
✓ Branch 0 taken 1738 times.
✗ Branch 1 not taken.
1738 (e, foldArg) := func(call.exp, foldArg);
2290 1738 iters := mapFoldIteratorsExpShallow(call.iters, func, foldArg);
2291 1738 then
2292 TYPED_ARRAY_CONSTRUCTOR(call.ty, call.var, call.purity, e, iters);
2293
2294 case UNTYPED_REDUCTION()
2295 algorithm
2296 ✗ (e, foldArg) := func(call.exp, foldArg);
2297 ✗ iters := mapFoldIteratorsExpShallow(call.iters, func, foldArg);
2298 ✗ then
2299 UNTYPED_REDUCTION(call.ref, e, iters);
2300
2301 case TYPED_REDUCTION()
2302 algorithm
2303
1/2
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
277 (e, foldArg) := func(call.exp, foldArg);
2304 277 iters := mapFoldIteratorsExpShallow(call.iters, func, foldArg);
2305 277 (default_exp, foldArg) := Expression.mapFoldOptShallow(call.defaultExp, func, foldArg);
2306 277 oe := Util.tuple31(call.foldExp);
2307
2308
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 277 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 277 times.
277 if isSome(oe) then
2309 277 (oe, foldArg) := Expression.mapFoldOptShallow(oe, func, foldArg);
2310 277 fold_exp := Util.applyTuple31(call.foldExp, function Util.replace(arg = oe));
2311 else
2312 ✗ fold_exp := call.foldExp;
2313 end if;
2314 277 then
2315 TYPED_REDUCTION(call.fn, call.ty, call.var, call.purity, e, iters, default_exp, fold_exp);
2316
2317 end match;
2318 end mapFoldExpShallow;
2319
2320 function mapFoldIteratorsExpShallow<ArgT>
2321 input list<tuple<InstNode, Expression>> iters;
2322 input MapFunc func;
2323 output list<tuple<InstNode, Expression>> outIters = {};
2324 input output ArgT arg;
2325
2326 partial function MapFunc
2327 input output Expression e;
2328 input output ArgT arg;
2329 end MapFunc;
2330 protected
2331 InstNode node;
2332 Expression exp, new_exp;
2333 algorithm
2334
2/2
✓ Branch 0 taken 2025 times.
✓ Branch 1 taken 2015 times.
4040 for i in iters loop
2335 2025 (node, exp) := i;
2336
1/2
✓ Branch 0 taken 2025 times.
✗ Branch 1 not taken.
2025 (new_exp, arg) := func(exp, arg);
2337
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 1904 times.
2025 outIters := (if referenceEq(new_exp, exp) then i else (node, new_exp)) :: outIters;
2338 end for;
2339
2340 2015 outIters := listReverseInPlace(outIters);
2341 end mapFoldIteratorsExpShallow;
2342
2343 function updateExternalRecordArgs
2344 input list<Expression> args;
2345 algorithm
2346
2/2
✓ Branch 0 taken 1786 times.
✓ Branch 1 taken 733 times.
2519 for arg in args loop
2347 1786 updateExternalRecordArgsInType(Expression.typeOf(arg));
2348 end for;
2349 end updateExternalRecordArgs;
2350
2351 function updateExternalRecordArgsInType
2352 input Type ty;
2353 protected
2354 InstNode node;
2355 Class cls;
2356 Restriction res;
2357 algorithm
2358
2/2
✓ Branch 1 taken 5027 times.
✓ Branch 2 taken 13 times.
5040 if Type.isRecord(ty) then
2359 13 node := Type.complexNode(ty);
2360 13 cls := InstNode.getClass(node);
2361 13 res := Restriction.setExternalRecord(Class.restriction(cls));
2362 13 cls := Class.setRestriction(res, cls);
2363 13 InstNode.updateClass(cls, node);
2364 end if;
2365 end updateExternalRecordArgsInType;
2366
2367 function toArrayConstructor
2368 "tries to make an array constructor from any call"
2369 input Call iCall;
2370 input Pointer<Integer> index_ptr;
2371 output Call oCall;
2372 algorithm
2373 oCall := match iCall
2374 local
2375 InstNode iter_name;
2376 Expression start, body, iter_range;
2377 Option<Expression> step;
2378 list<Expression> rest;
2379 list<tuple<InstNode, Expression>> iterators = {};
2380 Call body_call;
2381 Integer index;
2382
2383 case TYPED_CALL() then match AbsynUtil.pathString(Function.nameConsiderBuiltin(iCall.fn))
2384 case "fill" algorithm
2385 1730 index := Pointer.access(index_ptr);
2386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1730 times.
1730 body :: rest := iCall.arguments;
2387 start := Expression.INTEGER(1);
2388 step := NONE();
2389
2/2
✓ Branch 1 taken 1770 times.
✓ Branch 2 taken 1730 times.
3500 for stop in listReverse(rest) loop
2390 1770 iter_name := InstNode.newIndexedIterator(index, "f");
2391 1770 iter_range := Expression.makeRange(start, step, stop);
2392 1770 iterators := (iter_name, iter_range) :: iterators;
2393 1770 index := index + 1;
2394 end for;
2395
2396 // if there are nested calls, combine them
2397 (body, iterators) := match body
2398 case Expression.CALL(call = body_call as TYPED_ARRAY_CONSTRUCTOR()) algorithm
2399 54 then (body_call.exp, listAppend(iterators, body_call.iters));
2400 else (body, iterators);
2401 end match;
2402
2403 1730 Pointer.update(index_ptr, index);
2404 1730 then TYPED_ARRAY_CONSTRUCTOR(iCall.ty, iCall.var, iCall.purity, body, listReverse(iterators));
2405 else iCall;
2406 end match;
2407 else iCall;
2408 end match;
2409 end toArrayConstructor;
2410
2411 function isConnectionsOperator
2412 input Call call;
2413 output Boolean isOp;
2414 algorithm
2415 isOp := match call
2416 case TYPED_CALL()
2417
6/6
✓ Branch 1 taken 697 times.
✓ Branch 2 taken 99 times.
✓ Branch 5 taken 313 times.
✓ Branch 6 taken 384 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 308 times.
796 then Function.isBuiltin(call.fn) and AbsynUtil.pathFirstIdent(Function.name(call.fn)) == "Connections";
2418 else false;
2419 end match;
2420 end isConnectionsOperator;
2421
2422 function isStreamOperator
2423 input Call call;
2424 output Boolean isOp;
2425 protected
2426 String name;
2427 algorithm
2428 isOp := match call
2429 case TYPED_CALL()
2430 guard Function.isBuiltin(call.fn)
2431 algorithm
2432 389 name := functionNameFirst(call);
2433
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 389 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
✓ Branch 6 taken 350 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 33 times.
389 then
2434 name == "actualStream" or name == "inStream";
2435
2436 else false;
2437 end match;
2438 end isStreamOperator;
2439
2440 function isCardinality
2441 input Call call;
2442 output Boolean isCardinality;
2443 algorithm
2444 isCardinality := match call
2445 case TYPED_CALL() guard Function.isBuiltin(call.fn)
2446
3/4
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 378 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
383 then functionNameFirst(call) == "cardinality";
2447 else false;
2448 end match;
2449 end isCardinality;
2450
2451 protected
2452 function instNormalCall
2453 input Absyn.ComponentRef functionName;
2454 input Absyn.FunctionArgs functionArgs;
2455 input InstNode scope;
2456 input InstContext.Type context;
2457 input SourceInfo info;
2458 output Expression callExp;
2459 protected
2460 ComponentRef fn_ref;
2461 list<Expression> args;
2462 list<NamedArg> named_args;
2463 String name;
2464 algorithm
2465
2466 110173 name := AbsynUtil.crefFirstIdent(functionName);
2467
2468 // try to inst the parameters
2469 try
2470 110173 (args, named_args) := instArgs(functionArgs, scope, context, info);
2471 else
2472 // didn't work, is this DynamicSelect dynamic part?! #5631
2473
3/8
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2 if InstContext.inAnnotation(context) and not InstContext.inInstanceAPI(context) and
2474 stringEq(name, "DynamicSelect") then
2475 // return just the first part of DynamicSelect
2476 callExp := match functionArgs
2477 ✗ case Absyn.FUNCTIONARGS() then
2478 Inst.instExp(listHead(functionArgs.args), scope, context, info);
2479 end match;
2480 ✗ return;
2481 else
2482 2 fail();
2483 end if;
2484 end try;
2485
2486 callExp := match name
2487 // size creates Expression.SIZE instead of Expression.CALL.
2488 2642 case "size" then BuiltinCall.makeSizeExp(args, named_args, info);
2489 // array() call with no iterators creates Expression.ARRAY instead of Expression.CALL.
2490 // If it had iterators then it will not reach here. The args would have been parsed to
2491 // Absyn.FOR_ITER_FARG and that is handled in instIteratorCall.
2492 149 case "array" then BuiltinCall.makeArrayExp(args, named_args, info);
2493
2494 else
2495 algorithm
2496 107380 fn_ref := Function.instFunction(functionName, scope, context, info);
2497 107369 then
2498 Expression.CALL(UNTYPED_CALL(fn_ref, args, named_args, InstNode.scopeRef(scope)));
2499
2500 end match;
2501 end instNormalCall;
2502
2503 function instArgs
2504 input Absyn.FunctionArgs args;
2505 input InstNode scope;
2506 input InstContext.Type context;
2507 input SourceInfo info;
2508 output list<Expression> posArgs;
2509 output list<NamedArg> namedArgs;
2510 algorithm
2511 (posArgs, namedArgs) := match args
2512 case Absyn.FUNCTIONARGS()
2513 algorithm
2514
4/4
✓ Branch 0 taken 175550 times.
✓ Branch 1 taken 110172 times.
✓ Branch 2 taken 175550 times.
✓ Branch 3 taken 110172 times.
285722 posArgs := list(Inst.instExp(a, scope, context, info) for a in args.args);
2515
5/6
✓ Branch 0 taken 6119 times.
✓ Branch 1 taken 110171 times.
✓ Branch 2 taken 6119 times.
✓ Branch 3 taken 110171 times.
✓ Branch 5 taken 110171 times.
✗ Branch 6 not taken.
116290 namedArgs := list(instNamedArg(a, scope, context, info) for a in args.argNames);
2516 then
2517 (posArgs, namedArgs);
2518
2519 else
2520 algorithm
2521 ✗ Error.terminate(getInstanceName() + " got unknown function args", sourceInfo());
2522 ✗ then
2523 fail();
2524 end match;
2525 end instArgs;
2526
2527 function instNamedArg
2528 input Absyn.NamedArg absynArg;
2529 input InstNode scope;
2530 input InstContext.Type context;
2531 input SourceInfo info;
2532 output NamedArg arg;
2533 protected
2534 String name;
2535 Absyn.Exp exp;
2536 algorithm
2537 6119 Absyn.NAMEDARG(argName = name, argValue = exp) := absynArg;
2538 6119 arg := (name, Inst.instExp(exp, scope, context, info));
2539 end instNamedArg;
2540
2541 function instIteratorCall
2542 input Absyn.ComponentRef functionName;
2543 input Absyn.FunctionArgs functionArgs;
2544 input InstNode scope;
2545 input InstContext.Type context;
2546 input SourceInfo info;
2547 output Expression callExp;
2548 protected
2549 Absyn.ComponentRef fn_name;
2550 ComponentRef fn_ref;
2551 Expression exp;
2552 list<tuple<InstNode, Expression>> iters;
2553 algorithm
2554 // The parser turns {exp for i in ...} into $array(exp for i in ...), but we
2555 // change it to just array here so we can handle array constructors uniformly.
2556 fn_name := match functionName
2557 case Absyn.CREF_IDENT("$array") then Absyn.CREF_IDENT("array", {});
2558 else functionName;
2559 end match;
2560
2561 1775 (exp, iters) := instIteratorCallArgs(functionArgs, scope, context, info);
2562
2563
3/4
✓ Branch 1 taken 1471 times.
✓ Branch 2 taken 304 times.
✓ Branch 5 taken 1471 times.
✗ Branch 6 not taken.
1775 if AbsynUtil.crefFirstIdent(fn_name) == "array" then
2564 1471 callExp := Expression.CALL(UNTYPED_ARRAY_CONSTRUCTOR(exp, iters));
2565 else
2566 304 fn_ref := Function.instFunction(fn_name, scope, context, info);
2567 304 callExp := Expression.CALL(UNTYPED_REDUCTION(fn_ref, exp, iters));
2568 end if;
2569 end instIteratorCall;
2570
2571 function instIteratorCallArgs
2572 input Absyn.FunctionArgs args;
2573 input InstNode scope;
2574 input InstContext.Type context;
2575 input SourceInfo info;
2576 output Expression exp;
2577 output list<tuple<InstNode, Expression>> iters;
2578 algorithm
2579 () := match args
2580 local
2581 InstNode for_scope;
2582
2583 case Absyn.FOR_ITER_FARG()
2584 algorithm
2585 1775 (for_scope, iters) := instIterators(args.iterators, scope, context, info);
2586 1775 exp := Inst.instExp(args.exp, for_scope, context, info);
2587 then
2588 ();
2589 end match;
2590 end instIteratorCallArgs;
2591
2592 function instIterators
2593 input list<Absyn.ForIterator> inIters;
2594 input InstNode scope;
2595 input InstContext.Type context;
2596 input SourceInfo info;
2597 output InstNode outScope = scope;
2598 output list<tuple<InstNode, Expression>> outIters = {};
2599 protected
2600 Expression range;
2601 InstNode iter, range_node;
2602 Type ty;
2603 algorithm
2604
2/2
✓ Branch 1 taken 1776 times.
✓ Branch 2 taken 1775 times.
3551 for i in listReverse(inIters) loop
2605
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1776 times.
✓ Branch 2 taken 1775 times.
✓ Branch 3 taken 1 time.
1776 if isSome(i.range) then
2606 1775 range := Inst.instExp(Util.getOption(i.range), outScope, context, info);
2607 else
2608 // Use an empty expression to indicate that the range is missing and
2609 // needs to be deduced during typing.
2610 range := Expression.EMPTY(Type.UNKNOWN());
2611 end if;
2612
2613 // If the range is a cref, use it as the iterator type to allow lookup in
2614 // the iterator.
2615 ty := match range
2616 case Expression.CREF(cref = ComponentRef.CREF())
2617 guard InstNode.isComponent(ComponentRef.node(range.cref))
2618 1 then Type.COMPLEX(InstNode.identityCell(Component.classInstance(
2619 InstNode.component(ComponentRef.node(range.cref)))), ComplexType.CLASS());
2620 else Type.UNKNOWN();
2621 end match;
2622
2623 1776 (outScope, iter) := Inst.addIteratorToScope(i.name, outScope, info, ty);
2624 1776 outIters := (iter, range) :: outIters;
2625 end for;
2626 end instIterators;
2627
2628 function typeArrayConstructor
2629 input output NFCall call;
2630 input InstContext.Type context;
2631 input SourceInfo info;
2632 output Type ty;
2633 output Variability variability;
2634 output Purity purity;
2635 protected
2636 Expression arg, range;
2637 Type iter_ty;
2638 Variability iter_var, exp_var;
2639 Purity iter_pur, exp_pur;
2640 InstNode iter;
2641 list<Dimension> dims = {};
2642 list<tuple<InstNode, Expression>> iters = {};
2643 InstContext.Type next_context;
2644 Boolean is_structural, has_iterator;
2645 algorithm
2646 (call, ty, variability, purity) := match call
2647 case UNTYPED_ARRAY_CONSTRUCTOR()
2648 algorithm
2649 variability := Variability.CONSTANT;
2650 purity := Purity.PURE;
2651 // The size of the expression must be known unless we're in a function.
2652 1354 is_structural := not InstContext.inFunction(context);
2653 1354 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2654
2655
2/2
✓ Branch 1 taken 1354 times.
✓ Branch 2 taken 1354 times.
2708 for i in listReverse(call.iters) loop
2656 1354 (iter, range) := i;
2657
2658
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1352 times.
1354 if Expression.isEmpty(range) then
2659 2 range := Typing.deduceIterationRangeExp(Expression.CALL(call), iter, info);
2660 end if;
2661
2662 1354 (range, iter_ty, iter_var, iter_pur) := Typing.typeIterator(iter, range, next_context, is_structural);
2663
2664 // Don't try to evaluate the range if it contains an iterator.
2665
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1352 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
1354 has_iterator := iter_pur == Purity.IMPURE and Expression.contains(range, Expression.isIterator);
2666
2667
2/2
✓ Branch 0 taken 1278 times.
✓ Branch 1 taken 76 times.
1354 if is_structural and not has_iterator then
2668
2/2
✓ Branch 1 taken 352 times.
✓ Branch 2 taken 926 times.
1278 if InstContext.inRelaxed(context) then
2669 352 range := Ceval.tryEvalExp(range);
2670 else
2671 926 range := Ceval.evalExp(range, Ceval.EvalTarget.new(info, NFInstContext.ITERATION_RANGE));
2672 end if;
2673 1278 iter_ty := Expression.typeOf(range);
2674 end if;
2675
2676 1354 dims := List.append_reverse(Type.arrayDims(iter_ty), dims);
2677 1354 variability := Prefixes.variabilityMax(variability, iter_var);
2678 1354 purity := Prefixes.purityMin(purity, iter_pur);
2679 1354 iters := (iter, range) :: iters;
2680 end for;
2681
2682 1354 dims := listReverseInPlace(dims);
2683
2684 // InstContext.FOR is used here as a marker that this expression may contain iterators.
2685 1354 next_context := InstContext.set(next_context, NFInstContext.FOR);
2686 1354 (arg, ty, exp_var, exp_pur) := Typing.typeExp(call.exp, next_context, info);
2687 1354 variability := Prefixes.variabilityMax(variability, exp_var);
2688 1354 purity := Prefixes.purityMin(purity, exp_pur);
2689 1354 ty := Type.liftArrayLeftList(ty, dims);
2690
1/2
✓ Branch 1 taken 1354 times.
✗ Branch 2 not taken.
1354 then
2691 (TYPED_ARRAY_CONSTRUCTOR(ty, variability, purity, arg, iters), ty, variability, purity);
2692
2693 else
2694 algorithm
2695 ✗ Error.terminate(getInstanceName() + " got invalid function call expression", sourceInfo());
2696 ✗ then
2697 fail();
2698 end match;
2699 end typeArrayConstructor;
2700
2701 function typeReduction
2702 input output NFCall call;
2703 input InstContext.Type context;
2704 input SourceInfo info;
2705 output Type ty;
2706 output Variability variability;
2707 output Purity purity;
2708 protected
2709 Expression range, arg;
2710 InstNode iter;
2711 Variability iter_var, exp_var;
2712 Purity iter_pur, exp_pur;
2713 list<tuple<InstNode, Expression>> iters = {};
2714 InstContext.Type next_context;
2715 Function fn;
2716 algorithm
2717 (call, ty, variability, purity) := match call
2718 case UNTYPED_REDUCTION()
2719 algorithm
2720 variability := Variability.CONSTANT;
2721 purity := Purity.PURE;
2722 300 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2723
2724
2/2
✓ Branch 1 taken 301 times.
✓ Branch 2 taken 300 times.
601 for i in listReverse(call.iters) loop
2725 301 (iter, range) := i;
2726
2727
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 301 times.
301 if Expression.isEmpty(range) then
2728 ✗ range := Typing.deduceIterationRangeExp(Expression.CALL(call), iter, info);
2729 end if;
2730
2731 301 (range, _, iter_var, iter_pur) := Typing.typeIterator(iter, range, context, structural = false);
2732 301 variability := Variability.variabilityMax(variability, iter_var);
2733 301 purity := Variability.purityMin(purity, iter_pur);
2734 301 iters := (iter, range) :: iters;
2735 end for;
2736
2737 // InstContext.FOR is used here as a marker that this expression may contain iterators.
2738 300 next_context := InstContext.set(next_context, NFInstContext.FOR);
2739 300 (arg, ty, exp_var, exp_pur) := Typing.typeExp(call.exp, next_context, info);
2740 300 variability := Variability.variabilityMax(variability, exp_var);
2741 300 purity := Variability.purityMin(purity, exp_pur);
2742
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 300 times.
300 {fn} := Function.typeRefCache(call.ref);
2743 300 TypeCheck.checkReductionType(ty, Function.name(fn), call.exp, info);
2744
1/2
✓ Branch 1 taken 298 times.
✗ Branch 2 not taken.
298 then
2745 (makeTypedReduction(fn, ty, variability, purity, arg, iters, info), ty, variability, purity);
2746
2747 else
2748 algorithm
2749 ✗ Error.terminate(getInstanceName() + " got invalid reduction call", sourceInfo());
2750 ✗ then
2751 fail();
2752 end match;
2753 end typeReduction;
2754
2755 public
2756 function makeTypedReduction
2757 input Function fn;
2758 input Type ty;
2759 input Variability var;
2760 input Purity purity;
2761 input Expression arg;
2762 input list<tuple<InstNode, Expression>> iters;
2763 input SourceInfo info;
2764 output Call call;
2765 protected
2766 String fold_id, res_id;
2767 Option<Expression> default_exp, fold_exp;
2768 tuple<Option<Expression>, String, String> fold_tuple;
2769 algorithm
2770 308 fold_id := Util.getTempVariableIndex();
2771 308 res_id := Util.getTempVariableIndex();
2772 308 default_exp := reductionDefaultValue(fn, ty);
2773 308 fold_exp := reductionFoldExpression(fn, ty, var, purity, fold_id, res_id, info);
2774 308 fold_tuple := (fold_exp, fold_id, res_id);
2775
2776 308 call := TYPED_REDUCTION(fn, ty, var, purity, arg, iters, default_exp, fold_tuple);
2777 end makeTypedReduction;
2778
2779 protected
2780 function reductionDefaultValue
2781 input Function fn;
2782 input Type ty;
2783 output Option<Expression> defaultValue;
2784 algorithm
2785
2/2
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 1 time.
308 if Type.isArray(ty) then
2786 defaultValue := NONE();
2787 else
2788 defaultValue := match AbsynUtil.pathFirstIdent(Function.name(fn))
2789 283 case "sum" then SOME(Expression.makeZero(ty));
2790 4 case "product" then SOME(Expression.makeOne(ty));
2791 9 case "min" then SOME(Expression.makeMaxValue(ty));
2792 11 case "max" then SOME(Expression.makeMinValue(ty));
2793 else
2794 algorithm
2795 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR,
2796 {getInstanceName() + " got unknown reduction name " + AbsynUtil.pathFirstIdent(Function.name(fn))},
2797 sourceInfo());
2798 ✗ then
2799 fail();
2800 end match;
2801 end if;
2802 end reductionDefaultValue;
2803
2804 function reductionFoldExpression
2805 input Function reductionFn;
2806 input Type reductionType;
2807 input Variability reductionVar;
2808 input Purity reductionPurity;
2809 input String foldId;
2810 input String resultId;
2811 input SourceInfo info;
2812 output Option<Expression> foldExp;
2813 protected
2814 InstNode op_node;
2815 Function fn;
2816 algorithm
2817
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 307 times.
308 if Type.isComplex(reductionType) then
2818 foldExp := match AbsynUtil.pathFirstIdent(Function.name(reductionFn))
2819 case "sum"
2820 algorithm
2821 1 op_node := Type.complexNode(reductionType);
2822 1 op_node := Class.lookupElement("'+'", InstNode.getClass(op_node));
2823 1 Function.instFunctionNode(op_node, NFInstContext.NO_CONTEXT, info);
2824
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 {fn} := Function.typeNodeCache(op_node);
2825 3 then
2826 SOME(Expression.CALL(makeTypedCall(fn,
2827 {reductionFoldIterator(resultId, reductionType),
2828 reductionFoldIterator(foldId, reductionType)}, reductionVar, reductionPurity)));
2829
2830 else NONE();
2831 end match;
2832 else
2833 foldExp := match AbsynUtil.pathFirstIdent(Function.name(reductionFn))
2834 case "sum"
2835 283 then SOME(Expression.BINARY(
2836 reductionFoldIterator(resultId, reductionType),
2837 Operator.makeAdd(reductionType),
2838 reductionFoldIterator(foldId, reductionType)));
2839
2840 case "product"
2841 4 then SOME(Expression.BINARY(
2842 reductionFoldIterator(resultId, reductionType),
2843 Operator.makeMul(reductionType),
2844 reductionFoldIterator(foldId, reductionType)));
2845
2846 case "$array" then NONE();
2847 case "array" then NONE();
2848 case "list" then NONE();
2849 case "listReverse" then NONE();
2850
2851 60 else
2852 SOME(Expression.CALL(makeTypedCall(reductionFn,
2853 {reductionFoldIterator(foldId, reductionType),
2854 reductionFoldIterator(resultId, reductionType)},
2855 reductionVar, reductionPurity, reductionType)));
2856
2857 end match;
2858 end if;
2859 end reductionFoldExpression;
2860
2861 function reductionFoldIterator
2862 input String name;
2863 input Type ty;
2864 output Expression iterExp;
2865 algorithm
2866 616 iterExp := Expression.CREF(ty, ComponentRef.makeIterator(InstNode.NAME_NODE(name), ty));
2867 end reductionFoldIterator;
2868
2869 function typeArgs
2870 input output NFCall call;
2871 input InstContext.Type context;
2872 input SourceInfo info;
2873 algorithm
2874 call := match call
2875 local
2876 Expression arg;
2877 Type arg_ty;
2878 Variability arg_var;
2879 Purity arg_pur;
2880 list<TypedArg> typed_args, typed_nargs;
2881 String name;
2882 InstContext.Type next_context;
2883
2884 case UNTYPED_CALL()
2885 algorithm
2886 typed_args := {};
2887 78748 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2888
2889
2/2
✓ Branch 0 taken 130926 times.
✓ Branch 1 taken 78747 times.
209673 for arg in call.arguments loop
2890 130926 (arg, arg_ty, arg_var, arg_pur) := Typing.typeExp(arg, next_context, info);
2891 130925 typed_args := TypedArg.TYPED_ARG(NONE(), arg, arg_ty, arg_var, arg_pur) :: typed_args;
2892 end for;
2893
2894 78747 typed_args := listReverse(typed_args);
2895
2896 typed_nargs := {};
2897
2/2
✓ Branch 0 taken 5321 times.
✓ Branch 1 taken 78747 times.
84068 for narg in call.named_args loop
2898 5321 (name, arg) := narg;
2899 5321 (arg, arg_ty, arg_var, arg_pur) := Typing.typeExp(arg, next_context, info);
2900 5321 typed_nargs := TypedArg.TYPED_ARG(SOME(name), arg, arg_ty, arg_var, arg_pur) :: typed_nargs;
2901 end for;
2902
2903 78747 typed_nargs := listReverse(typed_nargs);
2904 78747 then
2905 ARG_TYPED_CALL(call.ref, typed_args, typed_nargs, call.call_scope);
2906 end match;
2907 end typeArgs;
2908
2909 function checkMatchingFunctions
2910 input NFCall call;
2911 input InstContext.Type context;
2912 input SourceInfo info;
2913 input Boolean vectorize = true;
2914 output MatchedFunction matchedFunc;
2915 protected
2916 list<MatchedFunction> matchedFunctions, exactMatches;
2917 Function func;
2918 list<Function> allfuncs;
2919 InstNode fn_node;
2920 Integer numerr = Error.getNumErrorMessages();
2921 algorithm
2922 78603 ErrorExt.setCheckpoint("NFCall:checkMatchingFunctions");
2923
2924 matchedFunctions := match call
2925 case ARG_TYPED_CALL(ref = ComponentRef.CREF())
2926 algorithm
2927 78603 fn_node := ComponentRef.node(call.ref);
2928 78603 allfuncs := Function.getCachedFuncs(fn_node);
2929
2930
2/2
✓ Branch 1 taken 8391 times.
✓ Branch 2 taken 70212 times.
78603 if listLength(allfuncs) > 1 then
2931
6/6
✓ Branch 1 taken 1050 times.
✓ Branch 2 taken 28731 times.
✓ Branch 3 taken 29781 times.
✓ Branch 4 taken 8391 times.
✓ Branch 5 taken 28731 times.
✓ Branch 6 taken 8391 times.
38172 allfuncs := list(fn for fn guard not Function.isDefaultRecordConstructor(fn) in allfuncs);
2932 end if;
2933 78603 then
2934 Function.matchFunctions(allfuncs, call.positional_args, call.named_args, context, info, vectorize,
2935 callPrefix = ComponentRef.stripClassScope(ComponentRef.rest(call.ref)));
2936 end match;
2937
2938
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 78598 times.
78603 if listEmpty(matchedFunctions) then
2939 // Don't show error messages for overloaded functions, it leaks
2940 // implementation details and usually doesn't provide any more info than
2941 // what the "no match found" error gives anyway.
2942
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
5 if listLength(allfuncs) > 1 then
2943 2 ErrorExt.rollBack("NFCall:checkMatchingFunctions");
2944 6 Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST,
2945 {typedString(call), Function.candidateFuncListString(allfuncs)}, info);
2946
2947 // Only show the error message for no matching functions if no other error
2948 // was shown.
2949 // functions that for some reason failed to match without giving any error.
2950 elseif numerr == Error.getNumErrorMessages() then
2951 ✗ ErrorExt.rollBack("NFCall:checkMatchingFunctions");
2952 ✗ Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST,
2953 {typedString(call), Function.candidateFuncListString(allfuncs)}, info);
2954 else
2955 3 ErrorExt.delCheckpoint("NFCall:checkMatchingFunctions");
2956 end if;
2957
2958 5 fail();
2959 end if;
2960
2961 // If we have at least one matching function then we discard all error messages
2962 // about matching. We have one matching func if we reach here.
2963 78598 ErrorExt.rollBack("NFCall:checkMatchingFunctions");
2964
2965
2/2
✓ Branch 1 taken 519 times.
✓ Branch 2 taken 78079 times.
78598 if listLength(matchedFunctions) > 1 then
2966 519 exactMatches := MatchedFunction.getExactMatches(matchedFunctions);
2967
2968
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 518 times.
519 if listEmpty(exactMatches) then
2969 1 exactMatches := MatchedFunction.getExactVectorizedMatches(matchedFunctions);
2970 end if;
2971
2972
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 519 times.
519 if listLength(exactMatches) > 1 then
2973 ✗ Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_FUNCTIONS_NFINST,
2974 {typedString(call), Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info);
2975 ✗ fail();
2976 end if;
2977
2978 519 matchedFunc := listHead(exactMatches);
2979 else
2980 78079 matchedFunc := listHead(matchedFunctions);
2981 end if;
2982
2983 // Overwrite the actual function name with the overload name for builtin functions.
2984
2/2
✓ Branch 1 taken 59733 times.
✓ Branch 2 taken 18865 times.
78598 if Function.isBuiltin(matchedFunc.func) then
2985 18865 func := matchedFunc.func;
2986 18865 func.path := Function.nameConsiderBuiltin(func);
2987 18865 matchedFunc.func := func;
2988 end if;
2989 end checkMatchingFunctions;
2990
2991 function iteratorToDAE
2992 input tuple<InstNode, Expression> iter;
2993 output DAE.ReductionIterator diter;
2994 protected
2995 InstNode iter_node;
2996 Expression iter_range;
2997 algorithm
2998 598 (iter_node, iter_range) := iter;
2999 598 diter := DAE.REDUCTIONITER(InstNode.name(iter_node), Expression.toDAE(iter_range), NONE(),
3000 Type.toDAE(InstNode.getType(iter_node)));
3001 end iteratorToDAE;
3002
3003 function vectorizeCall
3004 input NFCall base_call;
3005 input FunctionMatchKind mk;
3006 input NFInstNode.ScopeRef scope;
3007 input SourceInfo info;
3008 output NFCall vectorized_call;
3009 protected
3010 Type ty, vect_ty;
3011 Expression exp;
3012 list<tuple<InstNode, Expression>> iters;
3013 InstNode iter;
3014 Integer i;
3015 list<Expression> call_args;
3016 Subscript sub;
3017 algorithm
3018 vectorized_call := match (base_call, mk)
3019 case (TYPED_CALL(arguments = call_args), FunctionMatchKind.VECTORIZED())
3020 algorithm
3021 iters := {};
3022 i := 1;
3023
3024
2/2
✓ Branch 0 taken 1523 times.
✓ Branch 1 taken 1515 times.
3038 for dim in mk.vectDims loop
3025 1523 Error.assertion(Dimension.isKnown(dim, allowExp = true), getInstanceName() +
3026 " got unknown dimension for vectorized call", info);
3027
3028 // Create the range on which we will iterate to vectorize.
3029 1523 ty := Type.ARRAY(Type.INTEGER(), {dim});
3030 1523 exp := Expression.RANGE(ty, Expression.INTEGER(1), NONE(), Dimension.sizeExp(dim));
3031
3032 // Create the iterator.
3033 1523 iter := InstNode.newUniqueIterator(info);
3034 1523 iters := (iter, exp) :: iters;
3035
3036 // Now that iterator is ready apply it, as a subscript, to each argument that is supposed to be vectorized
3037 // Make a cref expression from the iterator
3038 1523 exp := Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER()));
3039 1523 sub := Subscript.INDEX(exp);
3040
3041 1523 call_args := List.mapIndices(call_args, mk.vectorizedArgs,
3042 function Expression.applySubscript(subscript = sub, restSubscripts = {}, applyToScope = false));
3043
3044 i := i + 1;
3045 end for;
3046
3047 1515 vect_ty := Type.liftArrayLeftList(base_call.ty, mk.vectDims);
3048 1515 base_call.arguments := call_args;
3049 1515 then
3050 TYPED_ARRAY_CONSTRUCTOR(vect_ty, base_call.var, base_call.purity, Expression.CALL(base_call), iters);
3051
3052 else
3053 algorithm
3054 ✗ Error.addInternalError(getInstanceName() + " got unknown call", info);
3055 ✗ then
3056 fail();
3057
3058 end match;
3059 end vectorizeCall;
3060
3061 function isVectorized
3062 input NFCall call;
3063 output Boolean vectorized;
3064 algorithm
3065 vectorized := match call
3066 // A call is considered to be vectorized if the first iterator has a name
3067 // beginning with $.
3068 case TYPED_ARRAY_CONSTRUCTOR(exp = Expression.CALL())
3069 ✗ then stringGet(InstNode.name(Util.tuple21(listHead(call.iters))), 1) == 36; /* $ */
3070 else false;
3071 end match;
3072 end isVectorized;
3073
3074 function devectorizeCall
3075 "Transforms a vectorized call into a non-vectorized one. This function is
3076 used as a helper to output valid flat Modelica, and should probably not
3077 be used where e.g. correct types are required."
3078 input NFCall call;
3079 output Expression result;
3080 protected
3081 Expression exp, iter_exp;
3082 list<tuple<InstNode, Expression>> iters;
3083 InstNode iter_node;
3084 algorithm
3085 ✗ TYPED_ARRAY_CONSTRUCTOR(exp = exp, iters = iters) := call;
3086
3087 ✗ for i in iters loop
3088 ✗ (iter_node, iter_exp) := i;
3089 ✗ exp := Expression.replaceIterator(exp, iter_node, iter_exp);
3090 end for;
3091
3092 ✗ result := SimplifyExp.simplify(exp);
3093 end devectorizeCall;
3094
3095 function evaluateCallType
3096 "Replaces references to inputs in a call's return type with the call's
3097 arguments, in order to determine e.g. the sizes of output arrays."
3098 input output Type ty;
3099 input Function fn;
3100 input list<Expression> args;
3101 input Integer outputIndex = 1;
3102 input output ParameterTree ptree = ParameterTree.EMPTY();
3103 protected
3104 list<Dimension> dims;
3105 list<Type> tys;
3106 Binding binding;
3107 Expression binding_exp;
3108 Type t;
3109 Integer output_index;
3110 algorithm
3111 ty := match ty
3112 case Type.ARRAY()
3113 algorithm
3114 17373 (dims, ptree) := List.mapFold(ty.dimensions, function evaluateCallTypeDim(fn = fn, args = args), ptree);
3115 17373 ty.dimensions := dims;
3116 then
3117 ty;
3118
3119 case Type.TUPLE()
3120 algorithm
3121 tys := {};
3122 output_index := 1;
3123
3124
2/2
✓ Branch 0 taken 2557 times.
✓ Branch 1 taken 1131 times.
3688 for t in ty.types loop
3125 2557 (t, ptree) := evaluateCallType(t, fn, args, output_index, ptree);
3126 tys := t :: tys;
3127 2557 output_index := output_index + 1;
3128 end for;
3129
3130 1131 ty.types := listReverseInPlace(tys);
3131 then
3132 ty;
3133
3134 // A normal record output
3135 case Type.COMPLEX()
3136 guard Type.isRecord(ty) and not Function.isNonDefaultRecordConstructor(fn)
3137 algorithm
3138 10333 binding := Component.getBinding(InstNode.component(InstNode.fromHandle(listGet(fn.outputs, outputIndex))));
3139
3140
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 10332 times.
10333 if Binding.isBound(binding) then
3141 // If the output has a binding, replace inputs in it and update the type of the output.
3142 1 binding_exp := Binding.getExp(binding);
3143 1 ptree := buildParameterTree(fn, args, ptree);
3144 1 binding_exp := Expression.map(binding_exp, function evaluateCallTypeDimExp(ptree = ptree));
3145 1 t := Expression.typeOf(binding_exp);
3146 else
3147 t := ty;
3148 end if;
3149 then
3150 t;
3151
3152 else ty;
3153 end match;
3154 end evaluateCallType;
3155
3156 function evaluateCallTypeDim
3157 input output Dimension dim;
3158 input Function fn;
3159 input list<Expression> args;
3160 input output ParameterTree ptree;
3161 algorithm
3162 dim := match dim
3163 local
3164 Expression exp;
3165 Dimension new_dim;
3166
3167 case Dimension.EXP()
3168 algorithm
3169 2749 ptree := buildParameterTree(fn, args, ptree);
3170 2749 exp := Expression.map(dim.exp, function evaluateCallTypeDimExp(ptree = ptree));
3171 // size(x, i) of a resizable dimension is its expression (e.g. N), the
3172 // dimension of the output stays resizable instead of being evaluated
3173 2749 exp := Expression.map(exp, resizableSizeExp);
3174
3175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2749 times.
2749 if Expression.contains(exp, Expression.isResizableCref) then
3176 ✗ new_dim := Dimension.fromExp(SimplifyExp.simplify(exp), Variability.NON_STRUCTURAL_PARAMETER);
3177 else
3178 2749 ErrorExt.setCheckpoint(getInstanceName());
3179 try
3180 2749 Structural.markExp(exp);
3181 2749 exp := Ceval.evalExp(exp);
3182 else
3183 end try;
3184 2749 ErrorExt.rollBack(getInstanceName());
3185 2749 new_dim := Dimension.fromExp(exp, Variability.CONSTANT);
3186 end if;
3187 then
3188 new_dim;
3189
3190 else dim;
3191 end match;
3192 end evaluateCallTypeDim;
3193
3194 function resizableSizeExp
3195 "size(x, i) -> the expression of dimension i of x if it is resizable"
3196 input Expression exp;
3197 output Expression outExp = exp;
3198 protected
3199 Integer i;
3200 Dimension d;
3201 algorithm
3202 () := match exp
3203 case Expression.SIZE(dimIndex = SOME(Expression.INTEGER(i))) algorithm
3204 try
3205 2057 d := Type.nthDimension(Expression.typeOf(exp.exp), i);
3206
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2057 times.
2057 if Dimension.isResizable(d) then
3207 ✗ outExp := Dimension.sizeExp(d);
3208 end if;
3209 else
3210 end try;
3211 then ();
3212 else ();
3213 end match;
3214 end resizableSizeExp;
3215
3216 function buildParameterTree
3217 input Function fn;
3218 input list<Expression> args;
3219 input output ParameterTree ptree;
3220 protected
3221 Expression arg;
3222 list<Expression> rest_args = args;
3223 algorithm
3224
2/2
✓ Branch 1 taken 810 times.
✓ Branch 2 taken 1940 times.
2750 if not ParameterTree.isEmpty(ptree) then
3225 810 return;
3226 end if;
3227
3228
2/2
✓ Branch 0 taken 3207 times.
✓ Branch 1 taken 1940 times.
5147 for i in fn.inputs loop
3229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3207 times.
3207 arg :: rest_args := rest_args;
3230 3207 ptree := ParameterTree.add(ptree, InstNode.name(i), arg);
3231 end for;
3232
3233 // TODO: Add local variable bindings.
3234 end buildParameterTree;
3235
3236 function evaluateCallTypeDimExp
3237 input Expression exp;
3238 input ParameterTree ptree;
3239 output Expression outExp;
3240 protected
3241 list<ComponentRef> cref_parts;
3242 ComponentRef cref;
3243 Option<Expression> oexp;
3244 algorithm
3245 outExp := match exp
3246 case Expression.CREF(cref = ComponentRef.CREF())
3247 algorithm
3248
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2854 times.
2854 cref :: cref_parts := ComponentRef.toListReverse(exp.cref);
3249 2854 oexp := ParameterTree.getOpt(ptree, ComponentRef.nodeName(cref));
3250
3251
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2854 times.
✓ Branch 2 taken 2853 times.
✓ Branch 3 taken 1 time.
2854 if isSome(oexp) then
3252 2853 SOME(outExp) := oexp;
3253 2853 outExp := Expression.applySubscripts(ComponentRef.getSubscripts(cref), outExp);
3254
3255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2853 times.
2856 for cr in cref_parts loop
3256 3 outExp := Expression.recordElement(ComponentRef.nodeName(cr), outExp);
3257 3 outExp := Expression.applySubscripts(ComponentRef.getSubscripts(cr), outExp);
3258 end for;
3259 else
3260 outExp := exp;
3261 end if;
3262 then
3263 outExp;
3264
3265 else exp;
3266 end match;
3267 end evaluateCallTypeDimExp;
3268
3269 function resolvePolymorphicReturnType
3270 "Resolves a polymorphic type to the actual type based on the inputs of a function."
3271 input Function fn;
3272 input list<TypedArg> args;
3273 input Type ty;
3274 output Type outType;
3275 protected
3276 String name;
3277 Type input_ty;
3278 TypedArg arg;
3279 list<TypedArg> rest_args = args;
3280 algorithm
3281 outType := match ty
3282 case Type.POLYMORPHIC(name = name)
3283 algorithm
3284 // Go through the inputs until we find one with the same polymorphic
3285 // type as the one we're looking for.
3286
2/2
✓ Branch 0 taken 3601 times.
✓ Branch 1 taken 1706 times.
5307 for i in fn.inputs loop
3287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3601 times.
3601 arg :: rest_args := rest_args;
3288 3601 input_ty := InstNode.getType(i);
3289
3290
2/2
✓ Branch 2 taken 1895 times.
✓ Branch 3 taken 1706 times.
3601 if Type.isPolymorphicNamed(Type.arrayElementType(input_ty), name) then
3291 // Replace the type with the corresponding argument type, but
3292 // remove as many dimensions from it as the input has.
3293 // For example: T[:] and Real[2, 3] gives T = Real[3]
3294 1895 outType := Type.unliftArrayN(Type.dimensionCount(input_ty), arg.ty);
3295 1895 return;
3296 end if;
3297 end for;
3298
3299 // If no input with the same type could be found and the result type
3300 // is __Scalar, try to find some input with the type __Array and
3301 // assume they have the same element type.
3302
2/4
✓ Branch 0 taken 1706 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1706 times.
✗ Branch 4 not taken.
1706 if name == "__Scalar" then
3303 1706 outType := resolvePolymorphicReturnType(fn, args, Type.POLYMORPHIC("__Array"));
3304 1706 outType := Type.arrayElementType(outType);
3305 1706 return;
3306 end if;
3307 ✗ then
3308 fail();
3309
3310 case Type.ARRAY(elementType = Type.POLYMORPHIC())
3311 algorithm
3312 // For an array of polymorphic types, only resolve the polymorphic
3313 // type itself and keep the dimensions.
3314 109 ty.elementType := resolvePolymorphicReturnType(fn, args, ty.elementType);
3315 then
3316 ty;
3317
3318 else ty;
3319 end match;
3320 end resolvePolymorphicReturnType;
3321
3322 annotation(__OpenModelica_Interface="nf_frontend");
3323 end NFCall;
3324