Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 61.6% 905 / 0 / 1470
Functions: -% 0 / 1 / 1
Branches: 58.4% 436 / 0 / 746

OMCompiler/Compiler/FrontEnd/InstUtil.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 package InstUtil
37 " file: InstUtil.mo
38 package: InstUtil
39 description: Instantiation utilities
40
41
42 This package supports Inst*.mo
43 "
44
45 import Absyn;
46 import AbsynUtil;
47 import ClassInf;
48 import DAE;
49 import FCore;
50 import InnerOuter;
51 import InstTypes;
52 import Mod;
53 import SCode;
54 import UnitAbsyn;
55 import Values;
56 import HashTable;
57 import HashTable5;
58
59 protected
60 import AvlSetCR;
61 import ClassInfUtil;
62 import DoubleEnded;
63 import List;
64 import BaseHashTable;
65 import Expression;
66 import Error;
67 import Util;
68 import ComponentReference;
69 protected import ComponentReferenceBasics;
70 import Patternm;
71 import DAEUtil;
72 import DAEDump;
73 import Types;
74 import Debug;
75 import PrefixUtil;
76 import ElementSource;
77 import Flags;
78 import FGraph;
79 import FNode;
80 import SCodeDump;
81 import SCodeUtil;
82 import Lookup;
83 import ValuesDump;
84 import ValuesUtil;
85 import Static;
86 import Ceval;
87 import Dump;
88 import Config;
89 import Inst;
90 import InstBasics;
91 import InstFunction;
92 import System;
93 import ErrorExt;
94 import InstExtends;
95 import Graph;
96 import UnitAbsynBuilder;
97 import UnitChecker;
98 import NFSCodeFlatten;
99 import HashSet;
100 import BaseHashSet;
101 import MetaModelica.Dangerous.listReverseInPlace;
102 import ExpressionBasics;
103
104 protected type Ident = DAE.Ident "an identifier";
105 protected type InstanceHierarchy = InnerOuter.InstHierarchy "an instance hierarchy";
106 protected type InstDims = list<list<DAE.Dimension>>;
107
108 public function newIdent
109 "This function creates a new, unique identifer.
110 The same name is never returned twice."
111 output DAE.ComponentRef outComponentRef;
112 protected
113 Integer i;
114 String is,s;
115 algorithm
116 ✗ i := tick();
117 ✗ is := intString(i);
118 ✗ s := stringAppend("__TMP__", is);
119 ✗ outComponentRef := ComponentReferenceBasics.makeCrefIdent(s,DAE.T_UNKNOWN_DEFAULT,{});
120 end newIdent;
121
122 protected function isNotFunction
123 "This function returns true if the Class is not a function."
124 input SCode.Element cls;
125 output Boolean res;
126 algorithm
127 ✗ res := SCodeUtil.isFunction(cls);
128 ✗ res := boolNot(res);
129 end isNotFunction;
130
131 public function scodeFlatten
132 input SCode.Program inProgram;
133 input Absyn.Path inPath;
134 output SCode.Program outProgram;
135 algorithm
136 outProgram := matchcontinue inPath
137
138 case _
139 algorithm
140
1/2
✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
1104 false := Flags.isSet(Flags.DO_SCODE_DEP);
141 then
142 inProgram;
143
144 case Absyn.IDENT("")
145 algorithm
146 ✗ outProgram := scodeFlattenProgram(inProgram);
147 then
148 outProgram;
149
150 else
151 algorithm
152 1104 (outProgram, _) := NFSCodeFlatten.flattenClassInProgram(inPath, inProgram);
153 then
154 outProgram;
155
156 end matchcontinue;
157 end scodeFlatten;
158
159 protected function scodeFlattenProgram
160 input SCode.Program inProgram;
161 output SCode.Program outProgram;
162 algorithm
163 outProgram := matchcontinue inProgram
164
165 case _
166 algorithm
167 ✗ ErrorExt.setCheckpoint("scodeFlattenProgram");
168 ✗ outProgram := NFSCodeFlatten.flattenCompleteProgram(inProgram);
169 ✗ ErrorExt.delCheckpoint("scodeFlattenProgram");
170 then
171 outProgram;
172
173 else
174 algorithm
175 ✗ ErrorExt.rollBack("scodeFlattenProgram");
176 then
177 inProgram;
178 end matchcontinue;
179 end scodeFlattenProgram;
180
181 public function reEvaluateInitialIfEqns "
182 Author BZ
183 This is a backpatch to fix the case of 'connection.isRoot' in initial if equations.
184 After the class is instantiated a second sweep is done to check the initial if equations conditions.
185 If all conditions are constant, we return only the 'correct' branch equations."
186 input FCore.Cache cache;
187 input FCore.Graph env;
188 input DAE.DAElist dae;
189 input Boolean isTopCall;
190 output DAE.DAElist odae;
191 algorithm
192 odae := match(dae, isTopCall)
193 local
194 list<DAE.Element> elems;
195 case(DAE.DAE(elementLst = elems), true)
196 algorithm
197 1000 elems := listReverse(List.fold2r(elems,reEvaluateInitialIfEqns2,cache,env,{}));
198 1000 then
199 DAE.DAE(elems);
200 case(_, false) then dae;
201 end match;
202 end reEvaluateInitialIfEqns;
203
204 protected function reEvaluateInitialIfEqns2 ""
205 input list<DAE.Element> acc;
206 input DAE.Element elem;
207 input FCore.Cache inCache;
208 input FCore.Graph env;
209 output list<DAE.Element> oelems;
210 algorithm
211 oelems := matchcontinue (elem, inCache)
212 local
213 list<DAE.Exp> conds;
214 list<Values.Value> valList;
215 list<list<DAE.Element>> tbs;
216 list<DAE.Element> fb,selectedBranch;
217 list<Boolean> blist;
218 FCore.Cache cache;
219
220 case (DAE.INITIAL_IF_EQUATION(condition1 = conds, equations2=tbs, equations3=fb), cache)
221 algorithm
222 //print(" (Initial if)To ceval: " + stringDelimitList(List.map(conds,ExpressionBasics.printExpStr),", ") + "\n");
223 6 (_,valList) := Ceval.cevalList(cache,env, conds, true, Absyn.NO_MSG(),0);
224 //print(" Ceval res: ("+stringDelimitList(List.map(valList,ValuesDump.printValStr),",")+")\n");
225
226 2 blist := List.map(valList,ValuesUtil.valueBool);
227 2 selectedBranch := List.findBoolList(blist, tbs, fb);
228 2 selectedBranch := makeDAEElementInitial(selectedBranch);
229 2 then listAppend(selectedBranch,acc);
230 else elem::acc;
231 end matchcontinue;
232 end reEvaluateInitialIfEqns2;
233
234 protected function makeDAEElementInitial "
235 Author BZ
236 Helper function for reEvaluateInitialIfEqns, makes the contenst of an initial if equation initial."
237 input list<DAE.Element> inElems;
238 output list<DAE.Element> outElems;
239 algorithm
240 outElems := match inElems
241 local
242 DAE.Element elem;
243 DAE.ComponentRef cr;
244 DAE.Exp e1,e2;
245 DAE.ElementSource s;
246 list<DAE.Exp> expl;
247 list<list<DAE.Element>> tbs ;
248 list<DAE.Element> fb;
249 DAE.Algorithm al;
250 DAE.Dimensions dims;
251 list<DAE.Element> elems;
252
253 case {} then {};
254
255 case DAE.DEFINE(cr,e1,s)::elems
256 algorithm
257 ✗ outElems := makeDAEElementInitial(elems);
258 ✗ then
259 DAE.INITIALDEFINE(cr,e1,s)::outElems;
260
261 case DAE.ARRAY_EQUATION(dims,e1,e2,s)::elems
262 algorithm
263 ✗ outElems := makeDAEElementInitial(elems);
264 ✗ then
265 DAE.INITIAL_ARRAY_EQUATION(dims,e1,e2,s)::outElems;
266
267 case DAE.EQUATION(e1,e2,s)::elems
268 algorithm
269 ✗ outElems := makeDAEElementInitial(elems);
270 ✗ then
271 DAE.INITIALEQUATION(e1,e2,s)::outElems;
272
273 case DAE.IF_EQUATION(expl,tbs,fb,s)::elems
274 algorithm
275 ✗ outElems := makeDAEElementInitial(elems);
276 ✗ then
277 DAE.INITIAL_IF_EQUATION(expl,tbs,fb,s)::outElems;
278
279 case DAE.ALGORITHM(al,s)::elems
280 algorithm
281 ✗ outElems := makeDAEElementInitial(elems);
282 ✗ then
283 DAE.INITIALALGORITHM(al,s)::outElems;
284
285 case DAE.COMPLEX_EQUATION(e1,e2,s)::elems
286 algorithm
287 ✗ outElems := makeDAEElementInitial(elems);
288 ✗ then
289 DAE.INITIAL_COMPLEX_EQUATION(e1,e2,s)::outElems;
290
291 case elem::elems // safe "last case" since we can not fail in cases above.
292 algorithm
293 1 outElems := makeDAEElementInitial(elems);
294 then
295 elem::outElems;
296 end match;
297 end makeDAEElementInitial;
298
299 public function lookupTopLevelClass
300 "Looks up a top level class with the given name."
301 input String inName;
302 input SCode.Program inProgram;
303 input Boolean inPrintError;
304 output SCode.Element outClass;
305 algorithm
306 outClass := matchcontinue inPrintError
307 local
308 SCode.Element cls;
309
310 case _
311 algorithm
312 861 cls := List.getMemberOnTrue(inName, inProgram, SCodeUtil.isClassNamed);
313 then
314 cls;
315
316 case true
317 algorithm
318 ✗ Error.addMessage(Error.LOAD_MODEL_ERROR, {inName});
319 ✗ then
320 fail();
321
322 end matchcontinue;
323 end lookupTopLevelClass;
324
325 public function fixInstClassType
326 "Fixes the type of a class if it is uniontype or function reference.
327 These are MetaModelica extensions."
328 input DAE.Type ty;
329 input Boolean isPartialFn;
330 output DAE.Type outType;
331 algorithm
332 outType := matchcontinue (ty,isPartialFn)
333 local
334 String name;
335 Absyn.Path path1, path2;
336 case (DAE.T_COMPLEX(complexClassType = ClassInf.State.TYPE(path=path1)),_)
337 algorithm
338 26321 name := AbsynUtil.pathLastIdent(path1);
339 26321 path2 := AbsynUtil.stripLast(path1);
340
3/4
✓ Branch 1 taken 26261 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26261 times.
26321 "$Code" := AbsynUtil.pathLastIdent(path2);
341 26261 path2 := AbsynUtil.stripLast(path2);
342
2/4
✓ Branch 1 taken 26261 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26261 times.
26261 "OpenModelica" := AbsynUtil.pathLastIdent(path2);
343 26261 then Util.assoc(name,{
344 ("Expression", DAE.T_CODE(DAE.C_EXPRESSION())),
345 ("ExpressionOrModification", DAE.T_CODE(DAE.C_EXPRESSION_OR_MODIFICATION())),
346 ("TypeName", DAE.T_CODE(DAE.C_TYPENAME())),
347 ("VariableName", DAE.T_CODE(DAE.C_VARIABLENAME())),
348 ("VariableNames", DAE.T_CODE(DAE.C_VARIABLENAMES()))
349 });
350 case (_,false) then ty;
351 486 case (_,true) then Types.makeFunctionPolymorphicReference(ty);
352 end matchcontinue;
353 end fixInstClassType;
354
355 public function updateEnumerationEnvironment
356 input FCore.Cache inCache;
357 input FCore.Graph inEnv;
358 input DAE.Type inType;
359 input SCode.Element inClass;
360 input ClassInf.State inCi_State;
361 output FCore.Cache outCache;
362 output FCore.Graph outEnv;
363 algorithm
364 (outCache,outEnv) := matchcontinue(inCache, inEnv, inType, inCi_State)
365 local
366 FCore.Cache cache;
367 FCore.Graph env,env_1;
368 list<String> names;
369 list<DAE.Var> vars;
370 Absyn.Path p,pname;
371
372 case (cache, env, DAE.T_ENUMERATION(names = names, literalVarLst = vars, path=p), ClassInf.ENUMERATION(pname))
373 algorithm
374 4390 (cache,env_1) := updateEnumerationEnvironment1(cache,env,AbsynUtil.pathString(pname),names,vars,p);
375 then
376 (cache,env_1);
377
378 ✗ case (cache, env, _, _) then (cache,env);
379
380 end matchcontinue;
381 end updateEnumerationEnvironment;
382
383 protected function updateEnumerationEnvironment1
384 "update enumeration value in environment"
385 input FCore.Cache inCache;
386 input FCore.Graph inEnv;
387 input Absyn.Ident inName;
388 input list<String> inNames;
389 input list<DAE.Var> inVars;
390 input Absyn.Path inPath;
391 output FCore.Cache outCache;
392 output FCore.Graph outEnv;
393 algorithm
394 (outCache,outEnv) := match(inCache, inEnv, inNames, inVars, inPath)
395 local
396 FCore.Cache cache;
397 FCore.Graph env,env_1,env_2,compenv;
398 String name,nn;
399 list<String> names;
400 list<DAE.Var> vars;
401 DAE.Var var;
402 DAE.Type ty;
403 Absyn.Path p;
404
405 case (cache, env, nn::names, (DAE.TYPES_VAR(ty = ty))::vars, p)
406 algorithm
407 // get Var
408 24053 (cache,var, _,_,_,compenv) :=
409 Lookup.lookupIdentLocal(cache, env, nn);
410 // print("updateEnumerationEnvironment1 -> component: " + name + " ty: " + TypesDump.printTypeStr(ty) + "\n");
411 // change type
412 24053 var.ty := ty;
413 // update
414 24053 env_1 := FGraph.updateComp(env, var, FCore.VAR_DAE(), compenv);
415 // next
416 24053 (cache,env_2) := updateEnumerationEnvironment1(cache,env_1,var.name,names,vars,p);
417 then
418 (cache,env_2);
419 case (cache, env, {}, _, _) then (cache,env);
420 end match;
421 end updateEnumerationEnvironment1;
422
423 public function updateDeducedUnits "updates the deduced units in each DAE.VAR"
424 input Boolean callScope;
425 input UnitAbsyn.InstStore store;
426 input DAE.DAElist dae;
427 output DAE.DAElist outDae;
428 algorithm
429 outDae := match (callScope,store,dae)
430 local
431 HashTable.HashTable ht;
432 array<Option<UnitAbsyn.Unit>> vec;
433 list<DAE.Element> elts;
434
435 /* Only traverse on top scope */
436 case (true,UnitAbsyn.INSTSTORE(UnitAbsyn.STORE(vec,_),ht,_),DAE.DAE(elts))
437 algorithm
438 ✗ elts := List.map2(elts,updateDeducedUnits2,vec,ht);
439 ✗ then DAE.DAE(elts);
440
441 else dae;
442 end match;
443 end updateDeducedUnits;
444
445 protected function updateDeducedUnits2 "updates the deduced units in each DAE.VAR"
446 input DAE.Element elt;
447 input array<Option<UnitAbsyn.Unit>> vec;
448 input HashTable.HashTable ht;
449 output DAE.Element oelt;
450 algorithm
451 oelt := matchcontinue elt
452 local
453 Integer indx;
454 String unitStr;
455 UnitAbsyn.Unit unit;
456 Option<DAE.VariableAttributes> varOpt;
457 DAE.ComponentRef cr;
458
459 /* Only traverse on top scope */
460 case DAE.VAR(componentRef=cr,variableAttributesOption=varOpt as SOME(DAE.VAR_ATTR_REAL(unit = NONE())))
461 algorithm
462 ✗ indx := BaseHashTable.get(cr,ht);
463 ✗ SOME(unit) := vec[indx];
464 ✗ unitStr := UnitAbsynBuilder.unit2str(unit);
465 ✗ varOpt := DAEUtil.setUnitAttr(varOpt,DAE.SCONST(unitStr));
466 ✗ then DAEUtil.setVariableAttributes(elt,varOpt);
467
468 else elt;
469 end matchcontinue;
470 end updateDeducedUnits2;
471
472 public function reportUnitConsistency "reports CONSISTENT or INCOMPLETE error message depending on content of store"
473 input Boolean topScope;
474 input UnitAbsyn.InstStore store;
475 algorithm
476 () := matchcontinue(topScope,store)
477 local
478 Boolean complete; UnitAbsyn.Store st;
479
480 case(_,_)
481 algorithm
482 // phi: very old unit checking
483 /*
484 false = Flags.getConfigBool(Flags.UNIT_CHECKING);
485 */
486 then
487 ();
488
489 case(true,UnitAbsyn.INSTSTORE(st,_,SOME(UnitAbsyn.CONSISTENT())))
490 algorithm
491 ✗ (complete,_) := UnitChecker.isComplete(st);
492 ✗ Error.addMessage(if complete then Error.CONSISTENT_UNITS else Error.INCOMPLETE_UNITS,{});
493 then
494 ();
495
496 else ();
497
498 end matchcontinue;
499 end reportUnitConsistency;
500
501 protected function extractConnectorPrefix
502 "Author: BZ, 2009-09
503 Extract the part before the conector ex: a.b.c.connector_d.e would return a.b.c"
504 input DAE.ComponentRef connectorRef;
505 output DAE.ComponentRef prefixCon;
506 algorithm
507 prefixCon := matchcontinue connectorRef
508 local
509 DAE.ComponentRef child;
510 String name;
511 list<DAE.Subscript> subs;
512 DAE.Type ty;
513
514 // If the bottom var is a connector, then it is not an outside connector. (spec 0.1.2)
515 case DAE.CREF_IDENT(_,_,_)
516 algorithm
517 // print(name + " is not a outside connector \n");
518 then
519 fail();
520
521 case DAE.CREF_QUAL(name,(ty as DAE.T_COMPLEX(complexClassType=ClassInf.CONNECTOR(_,_))),subs,_)
522 ✗ then ComponentReferenceBasics.makeCrefIdent(name,ty,subs);
523
524 case DAE.CREF_QUAL(name,ty,subs,child)
525 algorithm
526 ✗ child := extractConnectorPrefix(child);
527 ✗ then
528 ComponentReferenceBasics.makeCrefQual(name,ty,subs,child);
529
530 end matchcontinue;
531 end extractConnectorPrefix;
532
533 protected function updateCrefTypesWithConnectorPrefix "
534 Author: BZ, 2009-09
535 Helper function for updateTypesInUnconnectedConnectors2"
536 input DAE.ComponentRef cr1,cr2;
537 output DAE.ComponentRef outCref;
538 algorithm outCref := matchcontinue(cr1,cr2)
539 local
540 String name,name2;
541 DAE.ComponentRef child,child2;
542 DAE.Type ty;
543 list<DAE.Subscript> subs;
544 case (DAE.CREF_IDENT(name,ty,subs),DAE.CREF_QUAL(name2,_,_,child2))
545 algorithm
546 ✗ true := stringEq(name,name2);
547 ✗ then
548 ComponentReferenceBasics.makeCrefQual(name,ty,subs,child2);
549
550 case (DAE.CREF_QUAL(name,ty,subs,child),DAE.CREF_QUAL(name2,_,_,child2))
551 algorithm
552 ✗ true := stringEq(name,name2);
553 ✗ outCref := updateCrefTypesWithConnectorPrefix(child,child2);
554 ✗ then
555 ComponentReferenceBasics.makeCrefQual(name,ty,subs,outCref);
556 else
557 algorithm
558 ✗ print(" ***** FAILURE with " + ComponentReferenceBasics.printComponentRefStr(cr1) + " _and_ " + ComponentReferenceBasics.printComponentRefStr(cr2) + "\n");
559 ✗ then fail();
560 end matchcontinue;
561 end updateCrefTypesWithConnectorPrefix;
562
563 protected function checkClassEqual
564 input SCode.Element c1;
565 input SCode.Element c2;
566 output Boolean areEqual;
567 algorithm
568 areEqual := matchcontinue(c1, c2)
569 local
570 SCode.Restriction r;
571 list<SCode.AlgorithmSection> normalAlgorithmLst1,normalAlgorithmLst2;
572 list<SCode.AlgorithmSection> initialAlgorithmLst1,initialAlgorithmLst2;
573 SCode.ClassDef cd1, cd2;
574
575 // when -g=MetaModelica, check class equality!
576 case (_,_) guard Config.acceptMetaModelicaGrammar() and not valueEq(c1, c2)
577 then false;
578
579 // check the types for equality!
580 case (SCode.CLASS(restriction = SCode.R_TYPE()),_) guard not valueEq(c1, c2)
581 then
582 false;
583
584 // anything else but functions, do not check equality
585 case (SCode.CLASS(restriction = r),_)
586 algorithm
587 ✗ false := SCodeUtil.isFunctionRestriction(r);
588 then
589 true;
590
591 // check the class equality only for functions, made of parts
592 case (SCode.CLASS(classDef=SCode.PARTS(normalAlgorithmLst=normalAlgorithmLst1, initialAlgorithmLst=initialAlgorithmLst1)),
593 SCode.CLASS(classDef=SCode.PARTS(normalAlgorithmLst=normalAlgorithmLst2, initialAlgorithmLst=initialAlgorithmLst2)))
594 algorithm
595 // only check if algorithm list lengths are the same!
596 ✗ true := intEq(listLength(normalAlgorithmLst1), listLength(normalAlgorithmLst2));
597 ✗ true := intEq(listLength(initialAlgorithmLst1), listLength(initialAlgorithmLst2));
598 then
599 true;
600 // check the class equality only for functions, made of derived
601 case (SCode.CLASS(classDef=cd1 as SCode.DERIVED()),
602 SCode.CLASS(classDef=cd2 as SCode.DERIVED()))
603 // only check class definitions are the same!
604 ✗ then valueEq(cd1, cd2);
605 // anything else, false!
606 else false;
607 end matchcontinue;
608 end checkClassEqual;
609
610 public function prefixEqualUnlessBasicType
611 "Checks if two prefixes are equal, unless the class is a
612 basic type, i.e. all reals, integers, enumerations with
613 the same name, etc. are equal."
614 input DAE.Prefix pre1;
615 input DAE.Prefix pre2;
616 input SCode.Element cls;
617 algorithm
618 () := matchcontinue cls
619 local
620 String idn;
621 // adrpo: TODO! FIXME!, I think here we should have pre1 = DAE.CLASSPRE(variability1) == pre2 = DAE.CLASSPRE(variability2)
622
623 // don't care about prefix for:
624 // - enumerations
625 // - types as they cannot have components
626 // - predefined types as they cannot have components
627 case SCode.CLASS(restriction = SCode.R_ENUMERATION()) then ();
628 // case (_, _, SCode.CLASS(restriction = SCode.R_TYPE())) then ();
629 case SCode.CLASS(restriction = SCode.R_PREDEFINED_ENUMERATION()) then ();
630 case SCode.CLASS(restriction = SCode.R_PREDEFINED_INTEGER()) then ();
631 case SCode.CLASS(restriction = SCode.R_PREDEFINED_REAL()) then ();
632 case SCode.CLASS(restriction = SCode.R_PREDEFINED_STRING()) then ();
633 case SCode.CLASS(restriction = SCode.R_PREDEFINED_BOOLEAN()) then ();
634 // BTH
635 case SCode.CLASS(restriction = SCode.R_PREDEFINED_CLOCK()) then ();
636 // don't care about prefix for:
637 // - Real, String, Integer, Boolean
638 case SCode.CLASS(name = idn) guard idn=="Real" or idn== "Integer" or idn=="String" or idn=="Boolean" then ();
639 // BTH
640 case SCode.CLASS(name = "Clock")
641 algorithm
642 ✗ true := Config.synchronousFeaturesAllowed();
643 then ();
644
645 // anything else, check for equality!
646 else
647 algorithm
648
2/2
✓ Branch 1 taken 95028 times.
✓ Branch 2 taken 1308494 times.
1403522 true := valueEq(pre1, pre2);
649 then ();
650 end matchcontinue;
651 end prefixEqualUnlessBasicType;
652
653 public function isBuiltInClass "
654 Author: BZ, this function identifies built in classes."
655 input String className;
656 output Boolean b;
657 algorithm
658 b := match className
659 case "Real" then true;
660 case "Integer" then true;
661 case "String" then true;
662 case "Boolean" then true;
663 // BTH
664 ✗ case "Clock" then Config.synchronousFeaturesAllowed();
665 else false;
666 end match;
667 end isBuiltInClass;
668
669 protected function equalityConstraintOutputDimension
670 input list<SCode.Element> inElements;
671 output Integer outDimension;
672 algorithm
673 outDimension := match inElements
674 local
675 list<SCode.Element> tail;
676 Integer dim;
677 case {} algorithm
678 then 0;
679 case SCode.COMPONENT(attributes = SCode.ATTR(
680 direction = Absyn.OUTPUT(),
681 arrayDims = {Absyn.SUBSCRIPT(Absyn.INTEGER(dim))}
682 )) :: _ algorithm
683 then dim;
684 case _ :: tail algorithm
685 8268 dim := equalityConstraintOutputDimension(tail);
686 then dim;
687 end match;
688 end equalityConstraintOutputDimension;
689
690 public function equalityConstraint
691 " Tests if the given elements contain equalityConstraint function and returns
692 corresponding DAE.EqualityConstraint."
693 input FCore.Graph inEnv;
694 input list<SCode.Element> inCdefelts;
695 input SourceInfo info;
696 output DAE.EqualityConstraint outResult=NONE();
697 protected
698 list<SCode.Element> els;
699 Absyn.Path path;
700 Integer dimension;
701 DAE.InlineType inlineType;
702 algorithm
703 try
704
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 168356 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 168350 times.
168356 SOME(path) := FGraph.getScopePath(inEnv);
705 168350 path := AbsynUtil.joinPaths(path, Absyn.IDENT("equalityConstraint"));
706 168350 path := AbsynUtil.makeFullyQualified(path);
707 else
708 6 return;
709 end try;
710
2/2
✓ Branch 0 taken 964810 times.
✓ Branch 1 taken 165594 times.
1130404 for el in inCdefelts loop
711 try
712
8/10
✓ Branch 0 taken 387274 times.
✓ Branch 1 taken 577536 times.
✓ Branch 2 taken 5444 times.
✓ Branch 3 taken 572092 times.
✓ Branch 4 taken 2688 times.
✓ Branch 5 taken 2756 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2756 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2756 times.
964810 SCode.CLASS(name = "equalityConstraint", restriction = SCode.R_FUNCTION(), classDef = SCode.PARTS(elementLst = els)) := el;
713 2756 dimension := equalityConstraintOutputDimension(els);
714 2756 inlineType := classIsInlineFunc(el);
715 2756 outResult := SOME((path, dimension, inlineType));
716 2756 return;
717 else
718 end try;
719 end for;
720 end equalityConstraint;
721
722 public function handleUnitChecking
723 "@author: adrpo
724 do this unit checking ONLY if we have the flag!"
725 input FCore.Cache cache;
726 input FCore.Graph env;
727 input UnitAbsyn.InstStore inStore;
728 input DAE.Prefix pre;
729 input DAE.DAElist compDAE;
730 input list<DAE.DAElist> daes;
731 input String className "for debugging";
732 output FCore.Cache outCache;
733 output FCore.Graph outEnv;
734 output UnitAbsyn.InstStore outStore;
735 algorithm
736 (outCache,outEnv,outStore) := match inStore
737 local
738 DAE.DAElist daetemp;
739 UnitAbsyn.UnitTerms ut;
740 UnitAbsyn.InstStore store;
741
742 // do nothing if we don't have to do unit checking
743 case store
744 // phi: very old unit checking
745 /*
746 guard
747 not Flags.getConfigBool(Flags.UNIT_CHECKING)
748 */
749 then
750 (cache,env,store);
751
752 case store
753 algorithm
754 // Perform unit checking/dimensional analysis
755 //(daetemp,_) = ConnectUtil.equations(csets,pre,false,ConnectionGraph.EMPTY); // ToDO. calculation of connect eqns done twice. remove in future.
756 // equations from components (dae1) not considered, they are checked in resp recursive call
757 // but bindings on scalar variables must be considered, therefore passing dae1 separately
758 //daetemp = DAEUtil.joinDaeLst(daetemp::daes);
759 ✗ daetemp := DAEUtil.joinDaeLst(daes);
760 ✗ (store,ut):= UnitAbsynBuilder.instBuildUnitTerms(env,daetemp,compDAE,store);
761
762 //print("built store for "+className+"\n");
763 //UnitAbsynBuilder.printInstStore(store);
764 //print("terms for "+className+"\n");
765 //UnitAbsynBuilder.printTerms(ut);
766
767 ✗ UnitAbsynBuilder.registerUnitWeights(cache,env,compDAE);
768
769 // perform the check
770 ✗ store := UnitChecker.check(ut,store);
771
772 //print("store for "+className+"\n");
773 //UnitAbsynBuilder.printInstStore(store);
774 //print("dae1="+DAEDump.dumpDebugDAE(DAE.DAE(dae1))+"\n");
775 then
776 (cache,env,store);
777 end match;
778 end handleUnitChecking;
779
780 protected function checkExtendsRestrictionMatch
781 "see Modelica Specfification 3.1, 7.1.3 Restrictions on the Kind of Base Class"
782 input SCode.Restriction r1;
783 input SCode.Restriction r2;
784 algorithm
785 () := match(r1, r2)
786 // package can be extendended by package
787 case (SCode.R_PACKAGE(), SCode.R_PACKAGE()) then ();
788 // normal function -> normal function
789 case (SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_)), SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_))) then ();
790 // external function -> normal function
791 case (SCode.R_FUNCTION(SCode.FR_EXTERNAL_FUNCTION(_)), SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_))) then ();
792 // operator function -> normal function
793 case (SCode.R_FUNCTION(SCode.FR_OPERATOR_FUNCTION()), SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_))) then ();
794 // operator function -> operator function
795 case (SCode.R_FUNCTION(SCode.FR_OPERATOR_FUNCTION()), SCode.R_FUNCTION(SCode.FR_OPERATOR_FUNCTION())) then ();
796 // type -> type
797 case (SCode.R_TYPE(), SCode.R_TYPE()) then ();
798 // record -> record
799 case (SCode.R_RECORD(_), SCode.R_RECORD(_)) then ();
800 // connector -> type
801 case (SCode.R_CONNECTOR(_), SCode.R_TYPE()) then ();
802 // connector -> record
803 case (SCode.R_CONNECTOR(_), SCode.R_RECORD(_)) then ();
804 // connector -> connector
805 case (SCode.R_CONNECTOR(_), SCode.R_CONNECTOR(_)) then ();
806 // block -> record
807 case (SCode.R_BLOCK(), SCode.R_RECORD(false)) then ();
808 // block -> block
809 case (SCode.R_BLOCK(), SCode.R_BLOCK()) then ();
810 // model -> record
811 case (SCode.R_MODEL(), SCode.R_RECORD(false)) then ();
812 // model -> block
813 case (SCode.R_MODEL(), SCode.R_BLOCK()) then ();
814 // model -> model
815 case (SCode.R_MODEL(), SCode.R_MODEL()) then ();
816
817 // class??? same restrictions as model?
818 // model -> class
819 case (SCode.R_MODEL(), SCode.R_CLASS()) then ();
820 // class -> model
821 case (SCode.R_CLASS(), SCode.R_MODEL()) then ();
822 // class -> record
823 case (SCode.R_CLASS(), SCode.R_RECORD(_)) then ();
824 // class -> block
825 case (SCode.R_CLASS(), SCode.R_BLOCK()) then ();
826 // class -> class
827 case (SCode.R_CLASS(), SCode.R_CLASS()) then ();
828 // operator -> operator
829 case (SCode.R_OPERATOR(), SCode.R_OPERATOR()) then ();
830 end match;
831 end checkExtendsRestrictionMatch;
832
833 protected function checkExtendsForTypeRestiction
834 "@author: adrpo
835 This function will check extends for Modelica 3.1 restrictions"
836 input FCore.Cache inCache;
837 input FCore.Graph inEnv;
838 input InnerOuter.InstHierarchy inIH;
839 input SCode.Restriction inRestriction;
840 input list<SCode.Element> inSCodeElementLst;
841 algorithm
842 () := matchcontinue(inRestriction, inSCodeElementLst)
843 local
844 Absyn.Path p;
845 SCode.Restriction r1, r2, r;
846 String id;
847
848 // check the basics ....
849 // type or connector can be extended by a type
850 case (r, {SCode.EXTENDS(baseClassPath=Absyn.IDENT(id))})
851 algorithm
852 ✗ true := listMember(r, {SCode.R_TYPE(), SCode.R_CONNECTOR(false), SCode.R_CONNECTOR(true)});
853 ✗ true := listMember(id, {"Real", "Integer", "Boolean", "String"});
854 then ();
855
856 //BTH same as above but extended with Clock type if Flags.SYNCHRONOUS_FEATURES == true
857 case (r, {SCode.EXTENDS(baseClassPath=Absyn.IDENT(id))})
858 algorithm
859 ✗ true := Config.synchronousFeaturesAllowed();
860 ✗ true := listMember(r, {SCode.R_TYPE(), SCode.R_CONNECTOR(false), SCode.R_CONNECTOR(true)});
861 ✗ true := listMember(id, {"Real", "Integer", "Boolean", "String", "Clock"});
862 then ();
863
864 // we haven't found the class, do nothing
865 case (_, {SCode.EXTENDS(baseClassPath=p)})
866 algorithm
867 ✗ failure(Lookup.lookupClass(inCache, inEnv, p));
868 then ();
869
870 // we found te class, check the restriction
871 case (r1, {SCode.EXTENDS(baseClassPath=p)})
872 algorithm
873 ✗ (_,SCode.CLASS(restriction=r2),_) := Lookup.lookupClass(inCache,inEnv,p);
874 ✗ checkExtendsRestrictionMatch(r1, r2);
875 then ();
876
877 // make some waves that this is not correct
878 case (r1, {SCode.EXTENDS(baseClassPath=p)})
879 algorithm
880 ✗ (_,SCode.CLASS(restriction=r2),_) := Lookup.lookupClass(inCache, inEnv, p);
881 ✗ print("Error!: " + SCodeDump.restrString(r1) + " " + FGraph.printGraphPathStr(inEnv) +
882 " cannot be extended by " + SCodeDump.restrString(r2) + " " + AbsynUtil.pathString(p) + " due to derived/base class restrictions.\n");
883 ✗ then fail();
884 end matchcontinue;
885 end checkExtendsForTypeRestiction;
886
887 public function checkDerivedRestriction
888 input SCode.Restriction parentRestriction;
889 input SCode.Restriction childRestriction;
890 input SCode.Ident childName;
891 output Boolean b;
892 protected
893 Boolean b1, b2, b3, b4;
894 list<String> strLst;
895 list<SCode.Restriction> rstLst;
896 algorithm
897 // BTH add Clock type to both lists if Flags.SYNCHRONOUS_FEATURES == true
898
2/2
✓ Branch 1 taken 2897 times.
✓ Branch 2 taken 204882 times.
207779 strLst := if Config.synchronousFeaturesAllowed()
899 then {"Real", "Integer", "String", "Boolean", "Clock"}
900 else {"Real", "Integer", "String", "Boolean"};
901 207779 b1 := listMember(childName, strLst);
902
903
2/2
✓ Branch 1 taken 2897 times.
✓ Branch 2 taken 204882 times.
207779 rstLst := if Config.synchronousFeaturesAllowed()
904 then {SCode.R_TYPE(), SCode.R_PREDEFINED_INTEGER(), SCode.R_PREDEFINED_REAL(), SCode.R_PREDEFINED_STRING(), SCode.R_PREDEFINED_BOOLEAN(), SCode.R_PREDEFINED_CLOCK()}
905 else {SCode.R_TYPE(), SCode.R_PREDEFINED_INTEGER(), SCode.R_PREDEFINED_REAL(), SCode.R_PREDEFINED_STRING(), SCode.R_PREDEFINED_BOOLEAN()};
906 207779 b2 := listMember(childRestriction, rstLst);
907
908 207779 b3 := valueEq(parentRestriction, SCode.R_TYPE());
909
910 //b2 := listMember(childRestriction, {SCode.R_TYPE(), SCode.R_ENUMERATION(), SCode.R_PREDEFINED_INTEGER(), SCode.R_PREDEFINED_REAL(), SCode.R_PREDEFINED_STRING(), SCode.R_PREDEFINED_BOOLEAN(), SCode.R_PREDEFINED_ENUMERATION()});
911 //b3 := boolOr(valueEq(parentRestriction, SCode.R_TYPE()), valueEq(parentRestriction, SCode.R_ENUMERATION()));
912
913
2/2
✓ Branch 1 taken 204829 times.
✓ Branch 2 taken 2950 times.
207779 b4 := valueEq(parentRestriction, SCode.R_CONNECTOR(false)) or valueEq(parentRestriction, SCode.R_CONNECTOR(true));
914 // basically if child or parent is a type or basic type or parent is a connector and child is a type
915
4/4
✓ Branch 0 taken 83752 times.
✓ Branch 1 taken 124027 times.
✓ Branch 2 taken 2724 times.
✓ Branch 3 taken 81028 times.
207779 b := boolOr(b1, boolOr(b2, boolOr(b3, boolAnd(boolOr(b1,b2), b4))));
916 end checkDerivedRestriction;
917
918 public function matchModificationToComponents "
919 Author: BZ, 2009-05
920 This function is called from instClassDef, recursivly remove modifers on each component.
921 What ever is left in modifier is printed as a warning. That means that we have modifiers on a component that does not exist."
922 input list<SCode.Element> inElems;
923 input DAE.Mod inmod;
924 input String callingScope;
925 algorithm
926 () := match(inElems, inmod)
927 local
928 String cn,s1,s2;
929 list<SCode.Element> elems;
930 DAE.Mod mod;
931
932 case(_, DAE.NOMOD()) then ();
933 case(_, DAE.MOD(subModLst={})) then ();
934
935 case({}, _)
936 algorithm
937 17 s1 := Mod.prettyPrintMod(inmod,0);
938 17 s2 := s1 + " not found in <" + callingScope + ">";
939 // Line below can be used for testing test-suite for dangling modifiers when getErrorString() is not called.
940 //print(" *** ERROR Unused modifer...: " + s2 + "\n");
941 17 Error.addMessage(Error.UNUSED_MODIFIER,{s2});
942 17 then
943 fail();
944
945 case((SCode.COMPONENT(name=cn))::elems, mod)
946 algorithm
947 78689 mod := Mod.removeMod(mod,cn);
948 78689 matchModificationToComponents(elems,mod,callingScope);
949 then
950 ();
951
952 case((SCode.EXTENDS())::elems, _)
953 ✗ algorithm matchModificationToComponents(elems,inmod,callingScope); then ();
954 //TODO: only remove modifiers on replaceable classes, make special case for redeclaration of local classes
955
956 case((SCode.CLASS(name=cn,prefixes=SCode.PREFIXES()))::elems, mod)
957 algorithm
958 381 mod := Mod.removeMod(mod,cn);
959 381 matchModificationToComponents(elems,mod,callingScope);
960 then ();
961
962 case((SCode.IMPORT())::elems, _)
963 algorithm
964 ✗ matchModificationToComponents(elems,inmod,callingScope);
965 then ();
966
967 case((SCode.CLASS(prefixes=SCode.PREFIXES(replaceablePrefix=SCode.NOT_REPLACEABLE())))::elems, _)
968 algorithm
969 ✗ matchModificationToComponents(elems,inmod,callingScope);
970 then ();
971 end match;
972 end matchModificationToComponents;
973
974 protected function elementNameMember
975 "Returns true if the given element is in the list"
976 input tuple<SCode.Element, DAE.Mod> inElement;
977 input list<SCode.Element> els;
978 output Boolean isNamed;
979 algorithm
980 ✗ isNamed := listMember(Util.tuple21(inElement), els);
981 end elementNameMember;
982
983 public function extractConstantPlusDepsTpl "
984 Author: adrpo, see extractConstantPlusDeps for comments"
985 input list<tuple<SCode.Element, DAE.Mod>> inComps;
986 input Option<DAE.ComponentRef> ocr;
987 input list<SCode.Element> allComps;
988 input String className;
989 input list<SCode.Equation> ieql;
990 input list<SCode.Equation> iieql;
991 input list<SCode.AlgorithmSection> ialgs;
992 input list<SCode.AlgorithmSection> iialgs;
993 output list<tuple<SCode.Element, DAE.Mod>> oel;
994 output list<SCode.Equation> oeql;
995 output list<SCode.Equation> oieql;
996 output list<SCode.AlgorithmSection> oalgs;
997 output list<SCode.AlgorithmSection> oialgs;
998 algorithm
999 (oel, oeql, oieql, oalgs, oialgs)
1000 := matchcontinue(inComps, ocr)
1001 local
1002 DAE.ComponentRef cr;
1003 list<SCode.Element> lst;
1004
1005 // handle empty!
1006 case({}, _) then ({}, ieql, iieql, ialgs, iialgs);
1007
1008 // handle none
1009 case (_, NONE()) then (inComps, ieql, iieql, ialgs, iialgs);
1010
1011 // handle some
1012 case(_, SOME(_))
1013 algorithm
1014 ✗ lst := List.map(inComps, Util.tuple21);
1015 ✗ lst := extractConstantPlusDeps2(lst, ocr, allComps, className, {});
1016 ✗ false := listEmpty(lst);
1017 ✗ lst := listReverse(lst);
1018 ✗ oel := List.filter1OnTrue(inComps, elementNameMember, lst);
1019 then
1020 (oel, {}, {}, {}, {});
1021
1022 case(_, SOME(cr))
1023 algorithm
1024 ✗ true := Flags.isSet(Flags.FAILTRACE);
1025 ✗ Debug.trace("- InstUtil.extractConstantPlusDeps failure to find " + ComponentReferenceBasics.printComponentRefStr(cr) + ", returning \n");
1026 ✗ Debug.trace("- InstUtil.extractConstantPlusDeps elements to instantiate:" + intString(listLength(inComps)) + "\n");
1027 ✗ then fail(); // TODO: This used to return the input only if failtrace was set; should it always succeed?
1028 end matchcontinue;
1029 end extractConstantPlusDepsTpl;
1030
1031 public function extractConstantPlusDeps "
1032 Author: BZ, 2009-04
1033 This function filters the list of elements to instantiate depending on optional(DAE.ComponentRef), the
1034 optional argument is set in Lookup.lookupVarInPackages.
1035 If it is set, we are only looking for one variable in current scope hence we are not interested in
1036 instantiating more then nescessary.
1037
1038 The actuall action of this function is to compare components to the DAE.ComponentRef name
1039 if it is found return that component and any dependant components(modifiers), this is done by calling the function recursivly.
1040
1041 If the component specified in argument 2 is not found, we return all extend and import statements.
1042 TODO: search import and extends statements for specified variable.
1043 this includes to check class definitions to so that we do not need to instantiate local class definitions while looking for a constant."
1044 input list<SCode.Element> inComps;
1045 input Option<DAE.ComponentRef> ocr;
1046 input list<SCode.Element> allComps;
1047 input String className;
1048 output list<SCode.Element> outComps;
1049 algorithm
1050 outComps := matchcontinue ocr
1051 local
1052 DAE.ComponentRef cr;
1053
1054 // handle empty!
1055 // case({}, _, allComps, className) then {};
1056
1057 // handle none
1058 case NONE() then inComps;
1059
1060 // handle StateSelect as we will NEVER find it!
1061 // case(inComps, SOME(DAE.CREF_QUAL(ident="StateSelect")), allComps, className) then inComps;
1062
1063 // handle some
1064 case SOME(_)
1065 algorithm
1066 ✗ outComps := extractConstantPlusDeps2(inComps, ocr, allComps, className,{});
1067 ✗ false := listEmpty(outComps);
1068 ✗ outComps := listReverse(outComps);
1069 then
1070 outComps;
1071
1072 case SOME(cr)
1073 algorithm
1074 ✗ true := Flags.isSet(Flags.FAILTRACE);
1075 ✗ Debug.trace("- InstUtil.extractConstantPlusDeps failure to find " + ComponentReferenceBasics.printComponentRefStr(cr) + ", returning \n");
1076 ✗ Debug.trace("- InstUtil.extractConstantPlusDeps elements to instantiate:" + intString(listLength(inComps)) + "\n");
1077 ✗ then fail(); // TODO: This used to return the input only if failtrace was set; should it always succeed?
1078 end matchcontinue;
1079 end extractConstantPlusDeps;
1080
1081 protected function extractConstantPlusDeps2 "
1082 Author: BZ, 2009-04
1083 Helper function for extractConstantPlusDeps"
1084 input list<SCode.Element> inComps;
1085 input Option<DAE.ComponentRef> ocr;
1086 input list<SCode.Element> inAllComps;
1087 input String className;
1088 input list<String> inExisting;
1089 output list<SCode.Element> outComps;
1090 algorithm
1091 outComps := matchcontinue(inComps, ocr, inAllComps, inExisting)
1092 local
1093 SCode.Element compMod;
1094 list<SCode.Element> recDeps;
1095 SCode.Element selem;
1096 String name,name2;
1097 SCode.Mod scmod;
1098 list<Absyn.ComponentRef> crefs;
1099 list<SCode.Element> comps;
1100 list<SCode.Element> allComps;
1101 list<String> existing;
1102
1103 case({}, SOME(_), _, _)
1104 algorithm
1105 //print(" failure to find: " + ComponentReferenceBasics.printComponentRefStr(cr) + " in scope: " + className + "\n");
1106 then {};
1107 case({}, _, _, _) then fail();
1108 case (_, NONE(), _, _) then inComps;
1109 /*
1110 case( (selem as SCode.CLASS(name=name2))::comps,SOME(DAE.CREF_IDENT(ident=name)),allComps,className,existing)
1111 algorithm
1112 true = stringEq(name,name2);
1113 outComps = extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1114 then
1115 selem::outComps;
1116 */
1117 case(((selem as SCode.CLASS(name=name2)))::comps, SOME(DAE.CREF_IDENT()), allComps, existing)
1118 algorithm
1119 //false = stringEq(name,name2);
1120 allComps := selem::allComps;
1121 existing := name2::existing;
1122 ✗ outComps := extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1123 then //extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1124 selem::outComps;
1125
1126 case((selem as SCode.COMPONENT(name=name2,modifications=scmod))::comps, SOME(DAE.CREF_IDENT(ident=name)), allComps, existing)
1127 algorithm
1128 ✗ true := stringEq(name,name2);
1129 ✗ crefs := getCrefFromMod(scmod);
1130 ✗ allComps := listAppend(comps,allComps);
1131 existing := name2::existing;
1132 ✗ recDeps := extractConstantPlusDeps3(crefs,allComps,className,existing);
1133 then
1134 selem::recDeps;
1135
1136 case(( (selem as SCode.COMPONENT(name=name2)))::comps, SOME(DAE.CREF_IDENT(ident=name)), allComps, existing)
1137 algorithm
1138 ✗ false := stringEq(name,name2);
1139 allComps := selem::allComps;
1140 ✗ then extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1141
1142 case((compMod as SCode.EXTENDS())::comps, (SOME(DAE.CREF_IDENT())), allComps, existing)
1143 algorithm
1144 allComps := compMod::allComps;
1145 ✗ recDeps := extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1146 then
1147 compMod::recDeps;
1148 case((compMod as SCode.IMPORT())::comps, (SOME(DAE.CREF_IDENT())), allComps, existing)
1149 algorithm
1150 allComps := compMod::allComps;
1151 ✗ recDeps := extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1152 then
1153 compMod::recDeps;
1154
1155 case((compMod as SCode.DEFINEUNIT())::comps, (SOME(DAE.CREF_IDENT())), allComps, existing)
1156 algorithm
1157 allComps := compMod::allComps;
1158 ✗ recDeps := extractConstantPlusDeps2(comps,ocr,allComps,className,existing);
1159 then
1160 compMod::recDeps;
1161 else
1162 algorithm
1163 //debug_print("all", (inComps, ocr, allComps, className, existing));
1164 ✗ print(" failure in get_Constant_PlusDeps \n");
1165 ✗ then fail();
1166 end matchcontinue;
1167 end extractConstantPlusDeps2;
1168
1169 protected function extractConstantPlusDeps3 "
1170 Author: BZ, 2009-04
1171 Helper function for extractConstantPlusDeps"
1172 input list<Absyn.ComponentRef> inAcrefs;
1173 input list<SCode.Element> remainingComps;
1174 input String className;
1175 input list<String> inExisting;
1176 output list<SCode.Element> outComps;
1177 algorithm outComps := matchcontinue(inAcrefs, inExisting)
1178 local
1179 String s1;
1180 Absyn.ComponentRef acr;
1181 list<SCode.Element> localComps;
1182 list<String> names;
1183 DAE.ComponentRef cref_;
1184 list<Absyn.ComponentRef> acrefs;
1185 list<String> existing;
1186
1187 case({}, _) then {};
1188
1189 case (Absyn.CREF_FULLYQUALIFIED(acr) :: acrefs, existing)
1190 ✗ then extractConstantPlusDeps3(acr :: acrefs, remainingComps, className, existing);
1191
1192 case(Absyn.CREF_QUAL(s1,_,(acr as Absyn.CREF_IDENT(_,_)))::acrefs, existing)
1193 guard
1194 stringEq(className,s1) // in same scope look up.
1195 ✗ then
1196 extractConstantPlusDeps3(acr::acrefs,remainingComps,className,existing);
1197 case((Absyn.CREF_QUAL(_,_,_))::acrefs, existing)
1198 algorithm
1199 // false = stringEq(className,s1);
1200 ✗ outComps := extractConstantPlusDeps3(acrefs,remainingComps,className,existing);
1201 then
1202 outComps;
1203 case(Absyn.CREF_IDENT(s1,_)::acrefs, existing) // modifer dep already added
1204 guard
1205 List.isMemberOnTrue(s1,existing,stringEq)
1206 ✗ then
1207 extractConstantPlusDeps3(acrefs,remainingComps,className,existing);
1208 case(Absyn.CREF_IDENT(s1,_)::acrefs, existing)
1209 algorithm
1210 ✗ cref_ := ComponentReferenceBasics.makeCrefIdent(s1,DAE.T_UNKNOWN_DEFAULT,{});
1211 ✗ localComps := extractConstantPlusDeps2(remainingComps,SOME(cref_),{},className,existing);
1212 ✗ names := SCodeUtil.componentNamesFromElts(localComps);
1213 ✗ existing := listAppend(names,existing);
1214 ✗ outComps := extractConstantPlusDeps3(acrefs,remainingComps,className,existing);
1215 ✗ outComps := listAppend(localComps,outComps);
1216 then
1217 outComps;
1218 end matchcontinue;
1219 end extractConstantPlusDeps3;
1220
1221 public function removeSelfReference
1222 "@author adrpo
1223 Removes self reference from a path if it exists.
1224 Examples:
1225 removeSelfReference('Icons', 'Icons.BaseLibrary') => 'BaseLibrary'
1226 removeSelfReference('Icons', 'BlaBla.BaseLibrary') => 'BlaBla.BaseLibrary'"
1227 input String className;
1228 input Absyn.Path path;
1229 output Absyn.Path outPath;
1230 algorithm
1231
3/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
7 outPath := if stringEq(className, AbsynUtil.pathFirstIdent(path)) then
1232 AbsynUtil.removePrefix(Absyn.IDENT(className), path)
1233 else
1234 path;
1235 end removeSelfReference;
1236
1237 public function printExtcomps
1238 "prints the tuple of elements and modifiers to stdout"
1239 input list<tuple<SCode.Element, DAE.Mod>> inElements;
1240 algorithm
1241 () := match inElements
1242 local
1243 String s;
1244 SCode.Element el;
1245 DAE.Mod mod;
1246 list<tuple<SCode.Element, DAE.Mod>> els;
1247 case {} then ();
1248 case (el,mod) :: els
1249 algorithm
1250 ✗ s := SCodeDump.unparseElementStr(el,SCodeDump.defaultOptions);
1251 ✗ print(s);
1252 ✗ print(", ");
1253 ✗ print(Mod.printModStr(mod));
1254 ✗ print("\n");
1255 ✗ printExtcomps(els);
1256 then
1257 ();
1258 end match;
1259 end printExtcomps;
1260
1261 public function constantEls
1262 "Returns only elements that are constants or have annotation(Evaluate = true)!
1263 author: PA & adrpo
1264 Used buy partialInstClassdef to instantiate constants in packages."
1265 input list<SCode.Element> elements;
1266 output list<SCode.Element> outElements;
1267 protected
1268 SCode.Attributes attr;
1269 algorithm
1270
2/2
✓ Branch 2 taken 7474640 times.
✓ Branch 3 taken 42445 times.
7522982 outElements := list(el for el guard match el case SCode.COMPONENT(attributes=attr) then SCodeUtil.isConstant(SCodeUtil.attrVariability(attr)); else false; end match in elements);
1271 end constantEls;
1272
1273 public function constantAndParameterEls
1274 "Returns only elements that are constants.
1275 author: @adrpo
1276 Used by partialInstClassdef to instantiate constants and parameters in packages."
1277 input list<SCode.Element> elements;
1278 output list<SCode.Element> outElements;
1279 protected
1280 SCode.Attributes attr;
1281 algorithm
1282
2/2
✓ Branch 2 taken 360275 times.
✓ Branch 3 taken 74998 times.
647386 outElements := list(el for el guard match el case SCode.COMPONENT(attributes=attr) then SCodeUtil.isParameterOrConst(SCodeUtil.attrVariability(attr)); else false; end match in elements);
1283 end constantAndParameterEls;
1284
1285 protected function removeBindings
1286 "remove bindings for all elements if we do partial instantiation"
1287 input list<SCode.Element> elements;
1288 output list<SCode.Element> outElements;
1289 algorithm
1290 outElements := match elements
1291 local
1292 SCode.Element el;
1293 list<SCode.Element> els,els1;
1294 SCode.Ident name "the component name";
1295 SCode.Prefixes prefixes "the common class or component prefixes";
1296 SCode.Attributes attributes "the component attributes";
1297 Absyn.TypeSpec typeSpec "the type specification";
1298 SCode.Comment comment "this if for extraction of comments and annotations from Absyn";
1299 Option<Absyn.Exp> condition "the conditional declaration of a component";
1300 SourceInfo info "this is for line and column numbers, also file name.";
1301
1302 case {} then {};
1303
1304 case (SCode.COMPONENT(name, prefixes, attributes, typeSpec, _, comment, condition, info))::els
1305 algorithm
1306 ✗ els1 := removeBindings(els);
1307 ✗ then (SCode.COMPONENT(name, prefixes, attributes, typeSpec, SCode.NOMOD(), comment, condition, info)::els1);
1308
1309 case el::els
1310 algorithm
1311 ✗ els1 := removeBindings(els);
1312 then el::els1;
1313 end match;
1314 end removeBindings;
1315
1316 protected function removeExtBindings
1317 "remove bindings for all elements if we do partial instantiation"
1318 input list<tuple<SCode.Element, DAE.Mod>> elements;
1319 output list<tuple<SCode.Element, DAE.Mod>> outElements;
1320 algorithm
1321 outElements := match elements
1322 local
1323 tuple<SCode.Element, DAE.Mod> el;
1324 list<tuple<SCode.Element, DAE.Mod>> els,els1;
1325 SCode.Ident name "the component name";
1326 SCode.Prefixes prefixes "the common class or component prefixes";
1327 SCode.Attributes attributes "the component attributes";
1328 Absyn.TypeSpec typeSpec "the type specification";
1329 SCode.Comment comment "this if for extraction of comments and annotations from Absyn";
1330 Option<Absyn.Exp> condition "the conditional declaration of a component";
1331 SourceInfo info "this is for line and column numbers, also file name.";
1332
1333 case {} then {};
1334
1335 case (SCode.COMPONENT(name, prefixes, attributes, typeSpec, _, comment, condition, info),_)::els
1336 algorithm
1337 ✗ els1 := removeExtBindings(els);
1338 ✗ then ((SCode.COMPONENT(name, prefixes, attributes, typeSpec, SCode.NOMOD(), comment, condition, info),DAE.NOMOD())::els1);
1339
1340 case el::els
1341 algorithm
1342 ✗ els1 := removeExtBindings(els);
1343 then el::els1;
1344 end match;
1345 end removeExtBindings;
1346
1347 public function getModsForDep "
1348 Author: BZ, 2009-08
1349 Extract modifer for dependent variables(dep)."
1350 input Absyn.ComponentRef inDepCref;
1351 input list<tuple<SCode.Element, DAE.Mod>> inElems;
1352 output DAE.Mod omods;
1353 algorithm
1354 omods := matchcontinue(inDepCref,inElems)
1355 local
1356 String name1,name2;
1357 DAE.Mod cmod;
1358 Absyn.ComponentRef dep;
1359 list<tuple<SCode.Element, DAE.Mod>> elems;
1360
1361 case(_,{}) then DAE.NOMOD();
1362 case(dep,((SCode.COMPONENT(),DAE.NOMOD()))::elems)
1363 ✗ then getModsForDep(dep,elems);
1364 case(dep,((SCode.COMPONENT(name=name1),cmod))::_)
1365 algorithm
1366 ✗ name2 := Dump.printComponentRefStr(dep);
1367 ✗ true := stringEq(name2,name1);
1368 ✗ cmod := DAE.MOD(SCode.NOT_FINAL(),SCode.NOT_EACH(),{DAE.NAMEMOD(name2,cmod)},NONE(), Absyn.dummyInfo);
1369 then
1370 cmod;
1371 case(dep,_::elems)
1372 algorithm
1373 ✗ cmod := getModsForDep(dep,elems);
1374 then
1375 cmod;
1376 end matchcontinue;
1377 end getModsForDep;
1378
1379 protected function getOptionArraydim
1380 "Return the Arraydim of an optional arradim.
1381 Empty list returned if no arraydim present."
1382 input Option<Absyn.ArrayDim> inAbsynArrayDimOption;
1383 output Absyn.ArrayDim outArrayDim;
1384 algorithm
1385 outArrayDim := match inAbsynArrayDimOption
1386 local list<Absyn.Subscript> dim;
1387 case SOME(dim) then dim;
1388 else {};
1389 end match;
1390 end getOptionArraydim;
1391
1392 public function addNomod
1393 "This function takes an SCode.Element list and tranforms it into a
1394 (SCode.Element Mod) list by inserting DAE.NOMOD() for each element.
1395 Used to transform elements into a uniform list combined from inherited
1396 elements and ordinary elements."
1397 input list<SCode.Element> inElements;
1398 output list<tuple<SCode.Element, DAE.Mod>> outElements;
1399 algorithm
1400
4/4
✓ Branch 0 taken 1219498 times.
✓ Branch 1 taken 408578 times.
✓ Branch 2 taken 1219498 times.
✓ Branch 3 taken 408578 times.
1628076 outElements := list((x,DAE.NOMOD()) for x in inElements);
1401 end addNomod;
1402
1403 public function sortElementList
1404 "Sorts constants and parameters by dependencies, so that they are instantiated
1405 before they are used.
1406 For MetaModelica we just check for cycles. We do not do reordering"
1407 input output list<Element> inElements;
1408 input FCore.Graph inEnv;
1409 input Boolean isFunctionScope;
1410 type Element = tuple<SCode.Element, DAE.Mod>;
1411 protected
1412 list<Element> outE;
1413 list<tuple<Element, list<Element>>> cycles;
1414 list<tuple<Element, list<Element>>> g;
1415 algorithm
1416 // sort the elements according to the dependencies
1417
2/2
✓ Branch 0 taken 183592 times.
✓ Branch 1 taken 95400 times.
462584 g := Graph.buildGraph(inElements, getElementDependencies, (inElements,isFunctionScope));
1418 278992 (outE, cycles) := Graph.topologicalSort(g, isElementEqual);
1419
2/2
✓ Branch 1 taken 173069 times.
✓ Branch 2 taken 105923 times.
278992 if not Config.acceptMetaModelicaGrammar() then
1420 // append the elements in the cycles as they might not actually be cycles, but they depend on elements not in the list (i.e. package constants, etc)!
1421 173069 inElements := listAppend(outE, List.map(cycles, Util.tuple21));
1422 end if;
1423 278992 checkCyclicalComponents(cycles, inEnv);
1424 end sortElementList;
1425
1426 protected function printGraph
1427 input FGraph.Graph env;
1428 input list<tuple<Element, list<Element>>> g;
1429 input list<Element> order;
1430 input list<tuple<Element, list<Element>>> cycles;
1431 type Element = tuple<SCode.Element, DAE.Mod>;
1432 algorithm
1433 () := match g
1434 // nothing for empty graph
1435 case {} then ();
1436 // show me something!
1437 case _
1438 algorithm
1439 ✗ print("Graph for env: " + FGraph.printGraphPathStr(env) + "\n" + Graph.printGraph(g, elementName) + "\n");
1440 ✗ print("Element order:\n\t" + stringDelimitList(List.map(order, elementName), "\n\t") + "\n");
1441 ✗ print("Cycles:\n" + Graph.printGraph(cycles, elementName) + "\n");
1442 then ();
1443 end match;
1444 end printGraph;
1445
1446 protected function getDepsFromExps
1447 input list<Absyn.Exp> inExps;
1448 input list<tuple<SCode.Element, DAE.Mod>> inAllElements;
1449 input list<tuple<SCode.Element, DAE.Mod>> inDependencies;
1450 input Boolean isFunction;
1451 output list<tuple<SCode.Element, DAE.Mod>> outDependencies;
1452 algorithm
1453 outDependencies := match(inExps, inDependencies)
1454 local
1455 list<Absyn.Exp> rest;
1456 Absyn.Exp e;
1457 list<tuple<SCode.Element, DAE.Mod>> deps;
1458
1459 // handle the empty case
1460 case ({}, _) then inDependencies;
1461 // handle the normal case
1462 case (e::rest, deps)
1463 algorithm
1464 //(_, (_, _, (els, deps))) = AbsynUtil.traverseExpBidir(e, (getElementDependenciesTraverserEnter, getElementDependenciesTraverserExit, (inAllElements, deps)));
1465 //deps = getDepsFromExps(rest, els, deps);
1466
2/2
✓ Branch 0 taken 229736 times.
✓ Branch 1 taken 4415 times.
463887 (_, (_, _, deps, _)) := AbsynUtil.traverseExpBidir(e, getElementDependenciesTraverserEnter, getElementDependenciesTraverserExit, (inAllElements, {}, deps, isFunction));
1467 234151 deps := getDepsFromExps(rest, inAllElements, deps, isFunction);
1468 then
1469 deps;
1470 end match;
1471 end getDepsFromExps;
1472
1473 protected function removeCurrentElementFromArrayDimDeps
1474 "@author: adrpo
1475 removes the name from deps (Real A[size(A,1)] dependency)"
1476 input String name;
1477 input list<tuple<SCode.Element, DAE.Mod>> inDependencies;
1478 output list<tuple<SCode.Element, DAE.Mod>> outDependencies;
1479 algorithm
1480
8/8
✓ Branch 2 taken 8901 times.
✓ Branch 3 taken 46442 times.
✓ Branch 7 taken 4008 times.
✓ Branch 8 taken 4893 times.
✓ Branch 9 taken 55343 times.
✓ Branch 10 taken 938784 times.
✓ Branch 11 taken 51335 times.
✓ Branch 12 taken 938784 times.
994127 outDependencies := list(dep for dep guard not stringEq(name, SCodeUtil.elementName(Util.tuple21(dep))) in inDependencies);
1481 end removeCurrentElementFromArrayDimDeps;
1482
1483 public function getExpsFromConstrainClass
1484 input SCode.Replaceable inRP;
1485 output list<Absyn.Exp> outBindingExp "the bind exp if any";
1486 output list<Absyn.Exp> outSubsExps "the expressions from subs";
1487 algorithm
1488 (outBindingExp, outSubsExps) := match inRP
1489 local
1490 list<Absyn.Exp> l1, l2;
1491 SCode.Mod m;
1492
1493 327356 case SCode.NOT_REPLACEABLE() then ({}, {});
1494
1495 // no cc
1496 918 case SCode.REPLACEABLE(NONE()) then ({}, {});
1497
1498 // yeha, we have a ccccc :)
1499 case SCode.REPLACEABLE(SOME(SCode.CONSTRAINCLASS(modifier = m)))
1500 algorithm
1501 60 (l1, l2) := getExpsFromMod(m);
1502 then
1503 (l1, l2);
1504
1505 end match;
1506 end getExpsFromConstrainClass;
1507
1508 protected function getExpsFromSubMods
1509 input list<SCode.SubMod> inSubMods "the component sub modifiers";
1510 output list<Absyn.Exp> outSubsExps "the expressions from subs";
1511 algorithm
1512 outSubsExps := match inSubMods
1513 local
1514 SCode.Mod mod;
1515 list<SCode.SubMod> rest;
1516 list<Absyn.Exp> e, exps, sm;
1517
1518
1519 // handle empty
1520 case {} then {};
1521
1522 // handle namemod
1523 case SCode.NAMEMOD(mod = mod)::rest
1524 algorithm
1525 158490 (e, sm) := getExpsFromMod(mod);
1526 158490 exps := getExpsFromSubMods(rest);
1527 158490 exps := listAppend(e, listAppend(sm, exps));
1528 then
1529 exps;
1530
1531 end match;
1532 end getExpsFromSubMods;
1533
1534 public function getCrefFromMod
1535 input SCode.Mod inMod "the component modifier";
1536 output list<Absyn.ComponentRef> outCrefs;
1537 algorithm
1538 outCrefs := matchcontinue inMod
1539 local
1540 list<Absyn.Exp> l1, l2;
1541
1542 case _
1543 algorithm
1544 570598 (l1, l2) := getExpsFromMod(inMod);
1545 570598 outCrefs := List.flatten(List.map2(listAppend(l1, l2), AbsynUtil.getCrefFromExp, true, true));
1546 then
1547 outCrefs;
1548
1549 else
1550 algorithm
1551 ✗ print(getInstanceName() + ": could not retrieve crefs from SCode.Mod: " + SCodeDump.printModStr(inMod,SCodeDump.defaultOptions) + "\n");
1552 ✗ then
1553 fail();
1554
1555 end matchcontinue;
1556 end getCrefFromMod;
1557
1558 public function getExpsFromMod
1559 input SCode.Mod inMod "the component modifier";
1560 output list<Absyn.Exp> outBindingExp "the bind exp if any";
1561 output list<Absyn.Exp> outSubsExps "the expressions from subs";
1562 algorithm
1563 (outBindingExp, outSubsExps) := match inMod
1564 local
1565 list<Absyn.Exp> se, l1, l2, l3, l4;
1566 Absyn.Exp e;
1567 list<SCode.SubMod> subs;
1568 Option<Absyn.ArrayDim> ado;
1569 SCode.Mod m;
1570 Absyn.ArrayDim ad;
1571 SCode.Replaceable rp;
1572
1573 // no mods!
1574 904642 case SCode.NOMOD() then ({}, {});
1575 // the special kind of crappy mods
1576 4 case SCode.MOD(subModLst = {}, binding = NONE()) then ({}, {});
1577
1578 // mods with binding
1579 case SCode.MOD(subModLst = subs, binding = SOME(e))
1580 algorithm
1581 412720 se := getExpsFromSubMods(subs);
1582 412720 then
1583 ({e}, se);
1584
1585 // mods without binding
1586 case SCode.MOD(subModLst = subs, binding = NONE())
1587 algorithm
1588 54142 se := getExpsFromSubMods(subs);
1589 54142 then
1590 ({}, se);
1591
1592 // redeclare short class, investigate cc mods and own mods/array dims
1593 case SCode.REDECL(element = SCode.CLASS(prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1594 classDef = SCode.DERIVED(Absyn.TPATH(_, ado), m, _)))
1595 algorithm
1596 372 (l1, l2) := getExpsFromConstrainClass(rp);
1597 372 (_, se) := AbsynUtil.getExpsFromArrayDimOpt(ado);
1598 372 (l3, l4) := getExpsFromMod(m);
1599 372 l1 := listAppend(se, listAppend(l1, l3));
1600 372 l4 := listAppend(l2, l4);
1601 372 then
1602 (l1, l4);
1603
1604 // redeclare long class extends class, investigate cc and mods
1605 case SCode.REDECL(element = SCode.CLASS(prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1606 classDef = SCode.CLASS_EXTENDS(modifications = m)))
1607 algorithm
1608 ✗ (l1, l2) := getExpsFromConstrainClass(rp);
1609 ✗ (l3, l4) := getExpsFromMod(m);
1610 ✗ l3 := listAppend(l1, l3);
1611 ✗ l4 := listAppend(l2, l4);
1612 ✗ then
1613 (l3, l4);
1614
1615 // redeclare long class, investigate cc
1616 case SCode.REDECL(element = SCode.CLASS(prefixes = SCode.PREFIXES(replaceablePrefix = rp)))
1617 algorithm
1618 4454 (l1, l2) := getExpsFromConstrainClass(rp);
1619 then
1620 (l1, l2);
1621
1622 // redeclare component, investigate cc mods and own mods/array dims
1623 case SCode.REDECL(element = SCode.COMPONENT(prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1624 modifications = m, attributes = SCode.ATTR(arrayDims = ad)))
1625 algorithm
1626 101 (l1, l2) := getExpsFromConstrainClass(rp);
1627 101 (_, se) := AbsynUtil.getExpsFromArrayDim(ad);
1628 101 (l3, l4) := getExpsFromMod(m);
1629 101 l1 := listAppend(se, listAppend(l1, l3));
1630 101 l4 := listAppend(l2, l4);
1631 101 then
1632 (l1, l4);
1633
1634 end match;
1635 end getExpsFromMod;
1636
1637 public function getCrefFromDim
1638 "author: PA
1639 Similar to getCrefFromMod, but investigates
1640 array dimensionalitites instead."
1641 input Absyn.ArrayDim inArrayDim;
1642 output list<Absyn.ComponentRef> outAbsynComponentRefLst;
1643 algorithm
1644 outAbsynComponentRefLst := matchcontinue inArrayDim
1645 local
1646 list<Absyn.ComponentRef> l1,l2,res;
1647 Absyn.Exp exp;
1648 list<Absyn.Subscript> rest;
1649 case Absyn.SUBSCRIPT(subscript = exp) :: rest
1650 algorithm
1651 59299 l1 := getCrefFromDim(rest);
1652 59299 l2 := AbsynUtil.getCrefFromExp(exp,true,true);
1653 59299 res := List.union(l1, l2);
1654 then
1655 res;
1656 case Absyn.NOSUB() :: rest
1657 algorithm
1658 6567 res := getCrefFromDim(rest);
1659 then
1660 res;
1661 case {} then {};
1662 else
1663 algorithm
1664 ✗ true := Flags.isSet(Flags.FAILTRACE);
1665 ✗ Debug.trace("- InstUtil.getCrefFromDim failed\n");
1666 ✗ then
1667 fail();
1668 end matchcontinue;
1669 end getCrefFromDim;
1670
1671 public function getElementDependencies
1672 "Returns the dependencies given an element."
1673 input tuple<SCode.Element, DAE.Mod> inElement;
1674 input tuple<list<tuple<SCode.Element, DAE.Mod>>, Boolean> inAllElementsAndIsFunctionScope;
1675 output list<tuple<SCode.Element, DAE.Mod>> outDependencies;
1676 algorithm
1677 outDependencies := matchcontinue(inElement, inAllElementsAndIsFunctionScope)
1678 local
1679 SCode.Variability var;
1680 Option<Absyn.Exp> cExpOpt;
1681 list<tuple<SCode.Element, DAE.Mod>> deps;
1682 DAE.Mod daeMod;
1683 Absyn.ArrayDim ad;
1684 list<Absyn.Exp> exps, sexps, bexps;
1685 SCode.Mod mod;
1686 String name;
1687 Absyn.Direction direction;
1688 list<tuple<SCode.Element, DAE.Mod>> inAllElements;
1689 SCode.Replaceable rp;
1690 Option<SCode.ExternalDecl> externalDecl;
1691 Boolean isFunction;
1692
1693 // For constants and parameters we check the component conditional, array dimensions, modifiers and binding
1694 case ((SCode.COMPONENT(name = name, condition = cExpOpt,
1695 prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1696 attributes = SCode.ATTR(arrayDims = ad, variability = var),
1697 modifications = mod), daeMod), (inAllElements, isFunction))
1698 algorithm
1699
2/2
✓ Branch 1 taken 705368 times.
✓ Branch 2 taken 70533 times.
775901 true := SCodeUtil.isParameterOrConst(var);
1700 70533 (_, exps) := AbsynUtil.getExpsFromArrayDim(ad);
1701 70533 (bexps, sexps) := getExpsFromMod(mod);
1702 70533 exps := listAppend(bexps, listAppend(sexps, exps));
1703 70533 (bexps, sexps) := getExpsFromConstrainClass(rp);
1704 70533 exps := listAppend(bexps, listAppend(sexps, exps));
1705 70533 (bexps, sexps) := getExpsFromMod(Mod.unelabMod(daeMod));
1706 70533 exps := listAppend(bexps, listAppend(sexps, exps));
1707 70533 deps := getDepsFromExps(exps, inAllElements, {}, isFunction);
1708 // remove the current element from the deps as it is usally Real A[size(A,1)]; or self reference FlowModel fm(... blah = fcall(fm.x));
1709 70533 deps := removeCurrentElementFromArrayDimDeps(name, deps);
1710 70533 deps := getDepsFromExps(List.fromOption(cExpOpt), inAllElements, deps, isFunction);
1711 70533 deps := List.union(deps,{});
1712 // print(name + " deps " + stringDelimitList(list(SCodeUtil.elementName(Util.tuple21(e)) for e in deps),",") + "\n");
1713 then
1714 deps;
1715
1716 // For input and output variables in function scope return no dependencies so they stay in order!
1717 case ((SCode.COMPONENT(attributes = SCode.ATTR(direction = direction)), _), (_, true))
1718 algorithm
1719
2/2
✓ Branch 1 taken 12907 times.
✓ Branch 2 taken 463444 times.
476351 true := AbsynUtil.isInputOrOutput(direction);
1720 then
1721 {};
1722
1723 // For other variables we check the condition, since they might be conditional on a constant or parameter.
1724 case ((SCode.COMPONENT(name = name, condition = cExpOpt,
1725 prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1726 attributes = SCode.ATTR(arrayDims = ad),
1727 modifications = mod), daeMod), (inAllElements, isFunction))
1728 algorithm
1729 241924 (_, exps) := AbsynUtil.getExpsFromArrayDim(ad);
1730 241924 (bexps, sexps) := getExpsFromMod(mod);
1731 241924 exps := listAppend(sexps, exps);
1732 // DO *NOT* ignore the bindings in function scope. We do not want to keep the order!
1733 241924 exps := listAppend(bexps, exps);
1734 // exps = if_(hasUnknownDims, listAppend(bexps, exps), exps);
1735 241924 (bexps, sexps) := getExpsFromConstrainClass(rp);
1736 241924 exps := listAppend(bexps, listAppend(sexps, exps));
1737 241924 (bexps, sexps) := getExpsFromMod(Mod.unelabMod(daeMod));
1738 241924 exps := listAppend(sexps, exps);
1739 // DO *NOT* ignore the bindings in function scope so we keep the order!
1740 241924 exps := listAppend(bexps, exps);
1741 // exps = if_(hasUnknownDims, listAppend(bexps, exps), exps);
1742 241924 deps := getDepsFromExps(exps, inAllElements, {}, isFunction);
1743 // remove the current element from the deps as it is usally Real A[size(A,1)];
1744 241924 deps := removeCurrentElementFromArrayDimDeps(name, deps);
1745 241924 deps := getDepsFromExps(List.fromOption(cExpOpt), inAllElements, deps, isFunction);
1746 241924 deps := List.union(deps,{});
1747 // print(name + " deps " + stringDelimitList(list(SCodeUtil.elementName(Util.tuple21(e)) for e in deps),",") + "\n");
1748 then
1749 deps;
1750
1751 // We might actually get packages here, check the modifiers and the array dimensions
1752 case ((SCode.CLASS(name = name,
1753 prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1754 classDef = SCode.DERIVED(modifications = mod, attributes = SCode.ATTR(arrayDims = ad))),
1755 daeMod), (inAllElements, isFunction))
1756 algorithm
1757 10950 (_, exps) := AbsynUtil.getExpsFromArrayDim(ad);
1758 10950 (_, sexps) := getExpsFromMod(mod);
1759 10950 exps := listAppend(sexps, exps);
1760 10950 (bexps, sexps) := getExpsFromConstrainClass(rp);
1761 10950 exps := listAppend(bexps, listAppend(sexps, exps));
1762 10950 (_, sexps) := getExpsFromMod(Mod.unelabMod(daeMod));
1763 10950 exps := listAppend(sexps, exps);
1764 10950 deps := getDepsFromExps(exps, inAllElements, {}, isFunction);
1765 10950 deps := removeCurrentElementFromArrayDimDeps(name, deps);
1766 10950 deps := List.union(deps,{});
1767 then
1768 deps;
1769
1770 // We might have functions here and their input/output elements can have bindings from the list
1771 // see reference_X in PartialMedium
1772 // see ExternalMedia.Media.ExternalTwoPhaseMedium.FluidConstants
1773 // which depends on function calls which depend on package constants inside external decl
1774 case ((SCode.CLASS(name = name,
1775 prefixes = SCode.PREFIXES(),
1776 classDef = SCode.PARTS(externalDecl = externalDecl)),
1777 _), (inAllElements, isFunction))
1778 algorithm
1779 615377 exps := getExpsFromExternalDecl(externalDecl);
1780 /*
1781 exps = getExpsFromDefaults(els, exps);
1782 (bexps, sexps) = getExpsFromConstrainClass(rp);
1783 exps = listAppend(bexps, listAppend(sexps, exps));
1784 (bexps, sexps) = getExpsFromMod(Mod.unelabMod(daeMod));
1785 exps = listAppend(bexps, listAppend(sexps, exps));
1786 */
1787 615377 deps := getDepsFromExps(exps, inAllElements, {}, isFunction);
1788 615377 deps := removeCurrentElementFromArrayDimDeps(name, deps);
1789 615377 deps := List.union(deps,{});
1790 then
1791 deps;
1792
1793 else {};
1794 end matchcontinue;
1795 end getElementDependencies;
1796
1797 protected function getExpsFromExternalDecl
1798 "get dependencies from external declarations"
1799 input Option<SCode.ExternalDecl> inExternalDecl;
1800 output list<Absyn.Exp> outExps;
1801 algorithm
1802 outExps := match inExternalDecl
1803 local list<Absyn.Exp> exps;
1804 case NONE() then {};
1805 case SOME(SCode.EXTERNALDECL(args = exps))
1806 then
1807 exps;
1808 end match;
1809 end getExpsFromExternalDecl;
1810
1811 protected function getExpsFromDefaults
1812 input SCode.Program inEls;
1813 input list<Absyn.Exp> inAcc;
1814 output list<Absyn.Exp> outExps;
1815 algorithm
1816 outExps := matchcontinue inEls
1817 local
1818 SCode.Program rest;
1819 list<Absyn.Exp> exps, sexps, bexps;
1820 SCode.Mod m;
1821 SCode.Replaceable rp;
1822
1823 case {} then inAcc;
1824
1825 case SCode.COMPONENT(
1826 prefixes = SCode.PREFIXES(replaceablePrefix = rp),
1827 modifications = m)::rest
1828 algorithm
1829 exps := inAcc;
1830 ✗ (bexps, sexps) := getExpsFromConstrainClass(rp);
1831 ✗ exps := listAppend(bexps, listAppend(sexps, exps));
1832 ✗ (bexps, sexps) := getExpsFromMod(m);
1833 ✗ exps := listAppend(bexps, listAppend(sexps, exps));
1834 ✗ exps := getExpsFromDefaults(rest, exps);
1835 then
1836 exps;
1837
1838 case _::rest
1839 algorithm
1840 ✗ exps := getExpsFromDefaults(rest, inAcc);
1841 then
1842 exps;
1843 end matchcontinue;
1844 end getExpsFromDefaults;
1845
1846 protected function getElementDependenciesTraverserEnter
1847 "Traverse function used by getElementDependencies to collect all dependencies
1848 for an element. The first ElementList in the input argument is a list of all
1849 elements, and the second is a list of accumulated dependencies."
1850 input Absyn.Exp inExp;
1851 input tuple<ElementList, list<ElementList>, ElementList, Boolean> inTuple;
1852 output Absyn.Exp outExp;
1853 output tuple<ElementList, list<ElementList>, ElementList, Boolean> outTuple;
1854 type ElementList = list<tuple<SCode.Element, DAE.Mod>>;
1855 algorithm
1856 (outExp,outTuple) := matchcontinue (inExp,inTuple)
1857 local
1858 Absyn.Exp exp;
1859 String id;
1860 ElementList all_el, accum_el;
1861 list<ElementList> stack;
1862 tuple<SCode.Element, DAE.Mod> e;
1863 Absyn.ComponentRef cref;
1864 Boolean b;
1865
1866 case (exp as Absyn.CREF(componentRef = cref), (all_el, stack, accum_el, b))
1867 algorithm
1868 83750 id := AbsynUtil.crefFirstIdent(cref);
1869 83750 e := List.find1(all_el, isElementNamed, id);
1870
2/2
✓ Branch 0 taken 61571 times.
✓ Branch 1 taken 2118 times.
125260 then
1871 (exp, (all_el, stack, e :: accum_el, b));
1872
1873 case (exp as Absyn.CALL(function_ = cref), (all_el, stack, accum_el, b))
1874 algorithm
1875 32259 id := AbsynUtil.crefFirstIdent(cref);
1876 32259 e := List.find1(all_el, isElementNamed, id);
1877
1/2
✓ Branch 0 taken 2481 times.
✗ Branch 1 not taken.
4962 then
1878 (exp, (all_el, stack, e :: accum_el, b));
1879
1880 // The condition expression is always used
1881 case (exp as Absyn.IFEXP(), (all_el, stack, accum_el, false))
1882 3470 then (exp,(all_el,accum_el::stack,{},false));
1883
1884 else (inExp,inTuple);
1885 end matchcontinue;
1886 end getElementDependenciesTraverserEnter;
1887
1888 protected function getElementDependenciesTraverserExit
1889 "Dummy traversal function used by getElementDependencies."
1890 input Absyn.Exp inExp;
1891 input tuple<ElementList, list<ElementList>, ElementList, Boolean> inTuple;
1892 output Absyn.Exp outExp;
1893 output tuple<ElementList, list<ElementList>, ElementList, Boolean> outTuple;
1894 type ElementList = list<tuple<SCode.Element, DAE.Mod>>;
1895 algorithm
1896 (outExp,outTuple) := matchcontinue (inExp,inTuple)
1897 local
1898 ElementList all_el, stack_el, deps;
1899 list<ElementList> rest_stack;
1900 Absyn.Exp exp,ifExp;
1901
1902 // If a binding contains an if-equation we don't really have any idea which
1903 // branch will be used, which causes some problems with Fluid. So we just
1904 // reset everything up to this point and pray that we didn't miss anything
1905 // important.
1906 case (exp as Absyn.IFEXP(ifExp = ifExp), (all_el, stack_el::rest_stack, _, false))
1907 algorithm
1908 3470 (_, (_, _, deps, _)) := AbsynUtil.traverseExpBidir(ifExp, getElementDependenciesTraverserEnter, getElementDependenciesTraverserExit, (all_el, {}, {}, false));
1909 3470 then
1910 (exp, (all_el, rest_stack, listAppend(deps, stack_el), false));
1911
1912 else (inExp,inTuple);
1913 end matchcontinue;
1914 end getElementDependenciesTraverserExit;
1915
1916 protected function isElementNamed
1917 "Returns true if the given element has the same name as the given string,
1918 otherwise false."
1919 input tuple<SCode.Element, DAE.Mod> inElement;
1920 input String inName;
1921 output Boolean isNamed;
1922 algorithm
1923 isNamed := match inElement
1924 local
1925 String name;
1926
1927
4/4
✓ Branch 0 taken 462677 times.
✓ Branch 1 taken 9814222 times.
✓ Branch 3 taken 399889 times.
✓ Branch 4 taken 62788 times.
10276899 case (SCode.COMPONENT(name = name), _) then name == inName;
1928
4/4
✓ Branch 0 taken 32906 times.
✓ Branch 1 taken 1091724 times.
✓ Branch 3 taken 29524 times.
✓ Branch 4 taken 3382 times.
1124630 case (SCode.CLASS(name = name), _) then name == inName;
1929 else false;
1930 end match;
1931 end isElementNamed;
1932
1933 protected function isElementEqual
1934 "Checks that two elements are equal, i.e. has the same name."
1935 input tuple<SCode.Element, DAE.Mod> inElement1;
1936 input tuple<SCode.Element, DAE.Mod> inElement2;
1937 output Boolean isEqual;
1938 algorithm
1939 isEqual := match(inElement1, inElement2)
1940 local
1941 String id1, id2;
1942
1943 case ((SCode.COMPONENT(name = id1), _),
1944 (SCode.COMPONENT(name = id2), _))
1945
4/4
✓ Branch 0 taken 80063 times.
✓ Branch 1 taken 466410 times.
✓ Branch 3 taken 37355 times.
✓ Branch 4 taken 42708 times.
546473 then stringEqual(id1, id2);
1946
1947 // we can also have packages!
1948 case ((SCode.CLASS(name = id1), _),
1949 (SCode.CLASS(name = id2), _))
1950
4/4
✓ Branch 0 taken 9261 times.
✓ Branch 1 taken 85436 times.
✓ Branch 3 taken 6270 times.
✓ Branch 4 taken 2991 times.
94697 then stringEqual(id1, id2);
1951
1952
3/4
✓ Branch 2 taken 12951 times.
✓ Branch 3 taken 432670 times.
✓ Branch 7 taken 12951 times.
✗ Branch 8 not taken.
445621 else stringEq(elementName(inElement1), elementName(inElement2));
1953
1954 end match;
1955 end isElementEqual;
1956
1957 protected function checkCyclicalComponents
1958 "Checks the return value from Graph.topologicalSort. If the list of cycles is
1959 not empty, print an error message and fail, since it's not allowed for
1960 constants or parameters to have cyclic dependencies."
1961 input list<tuple<Element, list<Element>>> inCycles;
1962 input FCore.Graph inEnv;
1963 type Element = tuple<SCode.Element, DAE.Mod>;
1964 algorithm
1965 () := matchcontinue inCycles
1966 local
1967 list<list<Element>> cycles;
1968 list<list<String>> names;
1969 list<String> cycles_strs;
1970 String cycles_str, scope_str;
1971 list<tuple<Element, list<Element>>> graph;
1972
1973 case {} then ();
1974
1975 case _
1976 algorithm
1977 144 graph := Graph.filterGraph(inCycles, isElementParamOrConst);
1978
2/2
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 2 times.
144 {} := Graph.findCycles(graph, isElementEqual);
1979 then
1980 ();
1981
1982 else
1983 algorithm
1984 142 cycles := Graph.findCycles(inCycles, isElementEqual);
1985 142 names := List.mapList(cycles, elementName);
1986 142 cycles_strs := List.map1(names, stringDelimitList, ",");
1987 142 cycles_str := stringDelimitList(cycles_strs, "}, {");
1988 142 cycles_str := "{" + cycles_str + "}";
1989 142 scope_str := FGraph.printGraphPathStr(inEnv);
1990 142 Error.addMessage(Error.CIRCULAR_COMPONENTS, {scope_str, cycles_str});
1991
1992
1/2
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
142 if not Flags.isSet(Flags.IGNORE_CYCLES) then
1993 142 fail();
1994 end if;
1995 then
1996 ();
1997 end matchcontinue;
1998 end checkCyclicalComponents;
1999
2000 protected function isElementParamOrConst
2001 input tuple<SCode.Element, DAE.Mod> inElement;
2002 output Boolean outIsParamOrConst;
2003 algorithm
2004 outIsParamOrConst := match inElement
2005 local
2006 SCode.Variability var;
2007
2008 case (SCode.COMPONENT(attributes = SCode.ATTR(variability = var)), _)
2009 574 then SCodeUtil.isParameterOrConst(var);
2010
2011 else false;
2012 end match;
2013 end isElementParamOrConst;
2014
2015 protected function elementName
2016 "Returns the name of the given element."
2017 input tuple<SCode.Element, DAE.Mod> inElement;
2018 output String outName;
2019 protected
2020 SCode.Element elem;
2021 algorithm
2022 outName := matchcontinue inElement
2023 local
2024 String str;
2025
2026 case _
2027 algorithm
2028 917428 (elem, _) := inElement;
2029 917428 outName := SCodeUtil.elementName(elem);
2030 then
2031 outName;
2032
2033 case _
2034 algorithm
2035 2839 str := SCodeDump.shortElementStr(Util.tuple21(inElement));
2036 then
2037 str;
2038 end matchcontinue;
2039 end elementName;
2040
2041 public function classdefElts2
2042 "author: PA
2043 This function filters out the class definitions (ElementMod) list."
2044 input list<tuple<SCode.Element, DAE.Mod>> inElements;
2045 input SCode.Partial partialPrefix;
2046 output list<SCode.Element> outClassDefs;
2047 output list<tuple<SCode.Element, DAE.Mod>> outConstEls;
2048 algorithm
2049 (outClassDefs, outConstEls) := matchcontinue (inElements, partialPrefix)
2050 local
2051 list<SCode.Element> cdefs;
2052 SCode.Element cdef;
2053 tuple<SCode.Element, DAE.Mod> el;
2054 list<tuple<SCode.Element, DAE.Mod>> xs, els;
2055 SCode.Attributes attr;
2056 42445 case ({},_) then ({},{});
2057 case ((cdef as SCode.CLASS(restriction = SCode.R_PACKAGE()),_) :: xs,SCode.PARTIAL())
2058 algorithm
2059 ✗ (cdefs,els) := classdefElts2(xs,partialPrefix);
2060 ✗ then
2061 (cdef::cdefs,els);
2062 case (((cdef as SCode.CLASS(),_)) :: xs,SCode.NOT_PARTIAL())
2063 algorithm
2064 19276 (cdefs,els) := classdefElts2(xs,partialPrefix);
2065 19276 then
2066 (cdef::cdefs,els);
2067 case((el as (SCode.COMPONENT(attributes=attr),_))::xs,SCode.NOT_PARTIAL())
2068 algorithm
2069
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4009 times.
4009 SCode.CONST() := SCodeUtil.attrVariability(attr);
2070 4009 (cdefs,els) := classdefElts2(xs,partialPrefix);
2071 4009 then (cdefs,el::els);
2072 case ((_ :: xs),_)
2073 algorithm
2074 ✗ (cdefs,els) := classdefElts2(xs,partialPrefix);
2075 then
2076 (cdefs,els);
2077 end matchcontinue;
2078 end classdefElts2;
2079
2080 public function classdefAndImpElts
2081 "author: PA
2082 This function filters out the class definitions
2083 and import statements of an Element list."
2084 input list<SCode.Element> elts;
2085 output list<SCode.Element> cdefElts;
2086 output list<SCode.Element> restElts;
2087 algorithm
2088 (cdefElts,restElts) := match elts
2089 local
2090 list<SCode.Element> xs;
2091 SCode.Element cdef,imp,e;
2092
2093 case {} then ({},{});
2094
2095 case (cdef as SCode.CLASS()) :: xs
2096 algorithm
2097 ✗ (_,restElts) := classdefAndImpElts(xs);
2098 ✗ then
2099 (cdef :: restElts,restElts);
2100
2101 case (imp as SCode.IMPORT()) :: xs
2102 algorithm
2103 ✗ (cdefElts,restElts) := classdefAndImpElts(xs);
2104 ✗ then
2105 (imp :: cdefElts,restElts);
2106
2107 case e :: xs
2108 algorithm
2109 ✗ (cdefElts,restElts) := classdefAndImpElts(xs);
2110 ✗ then
2111 (cdefElts,e::restElts);
2112 end match;
2113 end classdefAndImpElts;
2114
2115 /*
2116 protected function extendsElts
2117 "author: PA
2118 This function filters out the extends Element in an Element list"
2119 input list<SCode.Element> inSCodeElementLst;
2120 output list<SCode.Element> outSCodeElementLst;
2121 algorithm
2122 outSCodeElementLst := match (inSCodeElementLst)
2123 local
2124 list<SCode.Element> res,xs;
2125 SCode.Element cdef;
2126 case ({}) then {};
2127 case (((cdef as SCode.EXTENDS(baseClassPath = _)) :: xs))
2128 algorithm
2129 res = extendsElts(xs);
2130 then
2131 (cdef :: res);
2132 case ((_ :: xs))
2133 algorithm
2134 res = extendsElts(xs);
2135 then
2136 res;
2137 end match;
2138 end extendsElts;
2139 */
2140
2141 public function componentElts
2142 "author: PA
2143 This function filters out the component Element in an Element list"
2144 input list<SCode.Element> inSCodeElementLst;
2145 output list<SCode.Element> outSCodeElementLst;
2146 algorithm
2147 outSCodeElementLst := match inSCodeElementLst
2148 local
2149 list<SCode.Element> res,xs;
2150 SCode.Element cdef;
2151 case {} then {};
2152 case (cdef as SCode.COMPONENT()) :: xs
2153 algorithm
2154 ✗ res := componentElts(xs);
2155 then
2156 (cdef :: res);
2157 case _ :: xs
2158 algorithm
2159 ✗ res := componentElts(xs);
2160 then
2161 res;
2162 end match;
2163 end componentElts;
2164
2165 public function addClassdefsToEnv
2166 "This function adds class definitions and import statements to the environment."
2167 input FCore.Cache inCache;
2168 input FCore.Graph inEnv;
2169 input InnerOuter.InstHierarchy inIH;
2170 input DAE.Prefix inPrefix;
2171 input list<SCode.Element> inClasses;
2172 input Boolean inImpl;
2173 input Option<DAE.Mod> inRedeclareMod;
2174 input Boolean checkDuplicates = false;
2175 output FCore.Cache outCache = inCache;
2176 output FCore.Graph outEnv = inEnv;
2177 output InnerOuter.InstHierarchy outIH = inIH;
2178 algorithm
2179
2/2
✓ Branch 0 taken 8141529 times.
✓ Branch 1 taken 576539 times.
8718068 for c in inClasses loop
2180 8141529 (outCache, outEnv, outIH) :=
2181 addClassdefToEnv(outCache, outEnv, outIH, inPrefix, c, inImpl, inRedeclareMod, checkDuplicates);
2182 end for;
2183 end addClassdefsToEnv;
2184
2185 protected function addClassdefToEnv
2186 "author: PA
2187 Helper relation to addClassdefsToEnv"
2188 input FCore.Cache inCache;
2189 input FCore.Graph inEnv;
2190 input InnerOuter.InstHierarchy inIH;
2191 input DAE.Prefix inPrefix;
2192 input SCode.Element inSCodeElement;
2193 input Boolean inBoolean;
2194 input Option<DAE.Mod> redeclareMod;
2195 input Boolean checkDuplicates = false;
2196 output FCore.Cache outCache;
2197 output FCore.Graph outEnv;
2198 output InnerOuter.InstHierarchy outIH;
2199 algorithm
2200 (outCache,outEnv,outIH) := matchcontinue (inCache,inEnv,inIH,inPrefix,inSCodeElement,redeclareMod)
2201 local
2202 FCore.Cache cache;
2203 FCore.Graph env,env_1;
2204 SCode.Element cl2, imp;
2205 SCode.Element sel1,elt;
2206 InstanceHierarchy ih;
2207 DAE.Prefix pre;
2208 DAE.Mod m;
2209
2210 // we do have a redeclaration of class.
2211 case (cache,env,ih,pre,( (sel1 as SCode.CLASS())),SOME(m))
2212 algorithm
2213 8064891 m := Mod.lookupCompModification(m, sel1.name);
2214
2/2
✓ Branch 1 taken 8061052 times.
✓ Branch 2 taken 3839 times.
8064891 false := valueEq(m, DAE.NOMOD());
2215 3839 env_1 := FGraph.mkClassNode(env, sel1, pre, m);
2216 // call to redeclareType which calls updateComponents in env wich updates the class frame
2217 3839 (cache,env_1,ih,cl2) := addClassdefsToEnv3(cache, env_1, ih, pre, redeclareMod, sel1);
2218 3839 ih := InnerOuter.addClassIfInner(cl2, pre, env_1, ih);
2219 then
2220 (cache,env_1,ih);
2221
2222 // otherwise, extend frame with in class.
2223 case (cache,env,ih,pre,(sel1 as SCode.CLASS()),_)
2224 algorithm
2225 // Debug.traceln("Extend frame " + FGraph.printGraphPathStr(env) + " with " + SCodeUtil.className(cl));
2226 8061052 env_1 := FGraph.mkClassNode(env, sel1, pre, DAE.NOMOD(), checkDuplicates);
2227 8061052 ih := InnerOuter.addClassIfInner(sel1, pre, env_1, ih);
2228 then
2229 (cache,env_1,ih);
2230
2231 // adrpo: we should have no imports after SCodeFlatten!
2232 // unfortunately we do because of the way we evaluate
2233 // programs for interactive evaluation
2234 case (cache,env,ih,_,(imp as SCode.IMPORT()),_)
2235 algorithm
2236 76638 env_1 := FGraph.mkImportNode(env, imp);
2237 then
2238 (cache,env_1,ih);
2239
2240 case(cache,env,ih,_,((elt as SCode.DEFINEUNIT())),_)
2241 algorithm
2242 ✗ env_1 := FGraph.mkDefunitNode(env,elt);
2243 then (cache,env_1,ih);
2244
2245 else
2246 algorithm
2247 ✗ true := Flags.isSet(Flags.FAILTRACE);
2248 ✗ Debug.trace("- InstUtil.addClassdefToEnv2 failed\n");
2249 ✗ then
2250 fail();
2251 end matchcontinue;
2252 end addClassdefToEnv;
2253
2254 protected function checkCompEnvPathVsCompTypePath
2255 "fails if the comp env path is NOT a prefix of comp type path"
2256 input Option<Absyn.Path> inCompEnvPath;
2257 input Absyn.Path inCompTypePath;
2258 algorithm
2259 () := match(inCompEnvPath, inCompTypePath)
2260
2261 local Absyn.Path ep, tp;
2262
2263 // if the type path is just an ident, we have a problem!
2264 case (_, Absyn.IDENT(_)) then ();
2265
2266 // if env path where the component C resides A.B.P.Z
2267 // has as prefix the component C type path C say A.B.P.C
2268 // it means that when we search for component A.B.P.Z.C
2269 // we might find the type: A.B.P.C instead.
2270 case (SOME(ep), tp)
2271 algorithm
2272 57 tp := AbsynUtil.stripLast(tp);
2273
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 true := AbsynUtil.pathPrefixOf(tp, ep);
2274 then
2275 ();
2276
2277 end match;
2278 end checkCompEnvPathVsCompTypePath;
2279
2280 public function addComponentsToEnv
2281 "author: PA
2282 Since Modelica has removed the declare before use limitation, all
2283 components are intially added untyped to the environment, i.e. the
2284 SCode.Element is added. This is performed by this function. Later,
2285 during the second pass of the instantiation of components, the components
2286 are updated in the environment. This is done by the function
2287 update_components_in_env. This function is also responsible for
2288 changing parameters into structural parameters if they are affecting
2289 the number of variables or equations. This is needed because Modelica has
2290 no language construct for structural parameters, i.e. they must be
2291 detected by the compiler.
2292
2293 Structural parameters are identified by investigating array dimension
2294 sizes of components and by investigating if-equations. If an if-equation
2295 has a boolean expression controlled by parameter(s), these are structural
2296 parameters."
2297 input output FCore.Cache cache;
2298 input output FCore.Graph env;
2299 input output InnerOuter.InstHierarchy ih;
2300 input DAE.Mod mod;
2301 input DAE.Prefix prefix;
2302 input ClassInf.State state;
2303 input list<tuple<SCode.Element, DAE.Mod>> components;
2304 input Boolean impl;
2305 protected
2306 SCode.Element comp, comp2;
2307 DAE.Mod cmod, local_mod, comp_mod, mod2;
2308 Absyn.Path ty_path;
2309 SCode.Prefixes prefs;
2310 SCode.Attributes attr;
2311 DAE.Attributes dattr;
2312 Boolean error = false;
2313 String err_msg;
2314 algorithm
2315
2/2
✓ Branch 0 taken 1313804 times.
✓ Branch 1 taken 226092 times.
1539896 for compmod in components loop
2316 1313804 (comp, cmod) := compmod;
2317
2318 error := matchcontinue comp
2319 case SCode.COMPONENT(typeSpec = Absyn.TPATH(path = ty_path))
2320 guard(comp.name == AbsynUtil.pathLastIdent(ty_path))
2321 algorithm
2322 // name is equal with the last ident from type path.
2323 // this is only a problem if the environment in which the component
2324 // resides has as prefix the type path (without the last ident)
2325 // as this would mean that we might find the type instead of the
2326 // component when we do lookup
2327 57 checkCompEnvPathVsCompTypePath(FGraph.getScopePath(env), ty_path);
2328 ✗ err_msg := comp.name + " in env: " + FGraph.printGraphPathStr(env);
2329 ✗ Error.addSourceMessage(Error.COMPONENT_NAME_SAME_AS_TYPE_NAME,
2330 {err_msg, AbsynUtil.pathString(ty_path)}, comp.info);
2331 then
2332 true;
2333
2334 case SCode.COMPONENT(prefixes = prefs as SCode.PREFIXES(),
2335 attributes = attr as SCode.ATTR())
2336 algorithm
2337 683692 ty_path := AbsynUtil.typeSpecPath(comp.typeSpec);
2338 683692 local_mod := Mod.lookupModificationP(mod, ty_path);
2339
2340
2/2
✓ Branch 2 taken 3276 times.
✓ Branch 3 taken 680416 times.
683692 if SCodeUtil.finalBool(SCodeUtil.prefixesFinal(prefs)) then
2341 3276 comp.modifications := traverseModAddFinal(comp.modifications);
2342 end if;
2343
2344 683692 (cache, env, ih, comp2, mod2) := Inst.redeclareType(cache, env, ih,
2345 local_mod, comp, prefix, state, impl, cmod);
2346
2347 683692 comp_mod := Mod.lookupCompModification(mod, comp.name);
2348 683692 cmod := Mod.merge(comp_mod, cmod);
2349
2350 683692 dattr := DAEUtil.translateSCodeAttrToDAEAttr(attr, prefs);
2351 683692 env := FGraph.mkComponentNode(env,
2352 DAE.TYPES_VAR(comp.name, dattr, DAE.T_UNKNOWN_DEFAULT, DAE.UNBOUND(), false, NONE()),
2353 comp, cmod, FCore.VAR_UNTYPED(), FGraph.empty());
2354 then
2355 false;
2356
2357 // Something went wrong.
2358 case SCode.COMPONENT() then true;
2359
2360 // Skip non-components.
2361 else false;
2362 end matchcontinue;
2363
2364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1313804 times.
1313804 if error then
2365 ✗ fail();
2366 end if;
2367 end for;
2368 end addComponentsToEnv;
2369
2370 protected function getCrefsFromCompdims
2371 "author: PA
2372 This function collects all variables from the dimensionalities of
2373 component elements. These variables are candidates for structural
2374 parameters."
2375 input list<tuple<SCode.Element, DAE.Mod>> inComponents;
2376 output list<Absyn.ComponentRef> outCrefs;
2377 algorithm
2378 outCrefs := matchcontinue inComponents
2379 local
2380 list<Absyn.ComponentRef> crefs1,crefs2,crefs;
2381 list<Absyn.Subscript> arraydim;
2382 list<tuple<SCode.Element, DAE.Mod>> xs;
2383 case {} then {};
2384 case (SCode.COMPONENT(attributes = SCode.ATTR(arrayDims = arraydim)),_) :: xs
2385 algorithm
2386 ✗ crefs1 := getCrefFromDim(arraydim);
2387 ✗ crefs2 := getCrefsFromCompdims(xs);
2388 ✗ crefs := listAppend(crefs1, crefs2);
2389 then
2390 crefs;
2391 case _ :: xs
2392 algorithm
2393 ✗ crefs := getCrefsFromCompdims(xs);
2394 then
2395 crefs;
2396 end matchcontinue;
2397 end getCrefsFromCompdims;
2398
2399 protected function memberCrefs
2400 "author: PA
2401 This function checks if a componentreferece is a member of
2402 a list of component references, disregarding subscripts."
2403 input Absyn.ComponentRef inComponentRef;
2404 input list<Absyn.ComponentRef> inComponentRefs;
2405 output Boolean outIsMember;
2406 algorithm
2407 ✗ outIsMember := List.isMemberOnTrue(inComponentRef, inComponentRefs,
2408 AbsynUtil.crefEqualNoSubs);
2409 end memberCrefs;
2410
2411 public function chainRedeclares "
2412 if we have an outer modification: redeclare X = Y
2413 and a component modification redeclare X = Z
2414 update the component modification to redeclare X = Y"
2415 input DAE.Mod inModOuter "the outer mod which should overwrite the inner mod";
2416 input SCode.Mod inModInner "the inner mod";
2417 output SCode.Mod outMod;
2418 protected
2419 Boolean b;
2420 algorithm
2421 outMod := match inModInner
2422 /*
2423 case(_, _)
2424 algorithm
2425 outMod = chainRedeclare_dispatch(inModOuter,inModInner);
2426 false = SCodeUtil.modEqual(inModInner, outMod);
2427 print("Chain:\nO:" + Mod.printModStr(inModOuter) + "\nI:" + SCodeDump.printModStr(inModInner, SCodeDump.defaultOptions) + "\nR:" + SCodeDump.printModStr(outMod, SCodeDump.defaultOptions) + "\n");
2428 then
2429 outMod;
2430 */
2431 case _
2432 algorithm
2433 774509 (outMod,b) := chainRedeclare_dispatch(inModOuter,inModInner);
2434
2/2
✓ Branch 0 taken 773794 times.
✓ Branch 1 taken 715 times.
774509 then if b then outMod else inModInner;
2435 end match;
2436 end chainRedeclares;
2437
2438 public function chainRedeclare_dispatch "
2439 if we have an outer modification: redeclare X = Y
2440 and a component modification redeclare X = Z
2441 update the component modification to redeclare X = Y"
2442 input DAE.Mod inModOuter "the outer mod which should overwrite the inner mod";
2443 input SCode.Mod inModInner "the inner mod";
2444 output SCode.Mod outMod;
2445 output Boolean change;
2446 algorithm
2447 (outMod,change) := matchcontinue inModInner
2448 local
2449 SCode.Final f;
2450 SCode.Each e;
2451 SCode.Element cls;
2452 String name, nInner, nDerivedInner;
2453 list<SCode.SubMod> rest, subs;
2454 Option<Absyn.Exp> b;
2455 SCode.Mod m,m2;
2456 SCode.SubMod sm;
2457 SourceInfo info;
2458 Option<String> cmt;
2459
2460 // outer B(redeclare X = Y), inner B(redeclare Y = Z) -> B(redeclare X = Z)
2461 case SCode.REDECL(f, e, SCode.CLASS(name = nInner, classDef = SCode.DERIVED(typeSpec = Absyn.TPATH(path = Absyn.IDENT(nDerivedInner)))))
2462 algorithm
2463 // lookup the class mod in the outer
2464
2/2
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 112 times.
156 DAE.REDECL(element = cls) := Mod.lookupCompModification(inModOuter, nDerivedInner);
2465 112 cls := SCodeUtil.setClassName(nInner, cls);
2466 112 then (SCode.REDECL(f, e, cls),true);
2467
2468 // outer B(redeclare X = Y), inner B(redeclare X = Z) -> B(redeclare X = Z)
2469 case SCode.REDECL(f, e, SCode.CLASS(name = nInner, classDef = SCode.DERIVED(typeSpec = Absyn.TPATH(path = Absyn.IDENT(_)))))
2470 algorithm
2471 // lookup the class mod in the outer
2472
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 1 time.
44 DAE.REDECL(element = cls) := Mod.lookupCompModification(inModOuter, nInner);
2473 1 then (SCode.REDECL(f, e, cls),true);
2474
2475 // a mod with a name mod
2476 case SCode.MOD(f, e, SCode.NAMEMOD(name, m as SCode.REDECL())::rest, b, cmt, info)
2477 algorithm
2478 // lookup the class mod in the outer
2479 4000 m2 := chainRedeclare_dispatch(inModOuter, m);
2480
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4000 times.
4000 (SCode.MOD(subModLst = subs),_) := chainRedeclare_dispatch(inModOuter, SCode.MOD(f, e, rest, b, cmt, info));
2481 8000 then (SCode.MOD(f, e, SCode.NAMEMOD(name, m2)::subs, b, cmt, info), true);
2482
2483 // something else, move along!
2484 case SCode.MOD(f, e, sm::rest, b, cmt, info)
2485 algorithm
2486
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 477834 times.
477834 (SCode.MOD(subModLst = subs), change) := chainRedeclare_dispatch(inModOuter, SCode.MOD(f, e, rest, b, cmt, info));
2487 477834 then (SCode.MOD(f, e, sm::subs, b, cmt, info), change);
2488
2489 else (inModInner, false);
2490
2491 end matchcontinue;
2492 end chainRedeclare_dispatch;
2493
2494 protected function addRecordConstructorsToTheCache
2495 "@author: adrpo
2496 add the record constructor to the cache if we have
2497 it as the type of an input component to a function"
2498 input FCore.Cache inCache;
2499 input FCore.Graph inEnv;
2500 input InnerOuter.InstHierarchy inIH;
2501 input DAE.Mod inMod;
2502 input DAE.Prefix inPrefix;
2503 input ClassInf.State inState;
2504 input Absyn.Direction inDirection;
2505 input SCode.Element inClass;
2506 input list<list<DAE.Dimension>> inInstDims;
2507 output FCore.Cache outCache;
2508 output FCore.Graph outEnv;
2509 output InnerOuter.InstHierarchy outIH;
2510 algorithm
2511 (outCache, outEnv, outIH) := matchcontinue(inState, inClass)
2512 local
2513 FCore.Cache cache;
2514 FCore.Graph env;
2515 InstanceHierarchy ih;
2516 String name;
2517 Absyn.Path path;
2518
2519 // add it to the cache if we have a input record component
2520 case (ClassInf.FUNCTION(path = path), SCode.CLASS(name = name, restriction = SCode.R_RECORD(_)))
2521 algorithm
2522 ✗ print("Depreciated record constructor used: Inst.addRecordConstructorsToTheCache");
2523
2524 // false = Config.acceptMetaModelicaGrammar();
2525 ✗ true := AbsynUtil.isInputOrOutput(inDirection);
2526 // TODO, add the env path to the check!
2527 ✗ false := stringEq(AbsynUtil.pathLastIdent(path), name);
2528 // print("InstFunction.implicitFunctionInstantiation: " + name + " in f:" + AbsynUtil.pathString(path) + " in s:" + FGraph.printGraphPathStr(inEnv) + " m: " + Mod.printModStr(inMod) + "\n");
2529 ✗ (cache, env, ih) := InstFunction.implicitFunctionInstantiation(inCache, inEnv, inIH, inMod, inPrefix, inClass, inInstDims);
2530 then
2531 (cache, env, ih);
2532
2533 // do nothing otherwise!
2534 else
2535 ✗ then
2536 (inCache, inEnv, inIH);
2537
2538 end matchcontinue;
2539 end addRecordConstructorsToTheCache;
2540
2541 public function checkMultiplyDeclared
2542 "Check if variable is multiply declared and
2543 that all declarations are identical if so."
2544 input FCore.Cache cache;
2545 input FCore.Graph env;
2546 input DAE.Mod mod;
2547 input DAE.Prefix prefix;
2548 input ClassInf.State ciState;
2549 input tuple<SCode.Element, DAE.Mod> compTuple;
2550 input list<list<DAE.Dimension>> instDims;
2551 input Boolean impl;
2552 output Boolean alreadyDeclared;
2553 algorithm
2554 alreadyDeclared := matchcontinue compTuple
2555 local
2556 String n,n2;
2557 SCode.Element oldElt;
2558 DAE.Mod oldMod;
2559 tuple<SCode.Element,DAE.Mod> newComp;
2560 FCore.Status instStatus;
2561 SCode.Element oldClass,newClass;
2562
2563 556056 case _ algorithm /*print(" dupe check setting ");*/ ErrorExt.setCheckpoint("checkMultiplyDeclared"); then fail();
2564
2565
2566 // If a component definition is replaceable, skip check
2567 case (SCode.COMPONENT(prefixes = SCode.PREFIXES(replaceablePrefix=SCode.REPLACEABLE(_))),_)
2568 algorithm
2569 105 ErrorExt.rollBack("checkMultiplyDeclared");
2570 then false;
2571
2572 // If a comopnent definition is redeclaration, skip check
2573 case (SCode.COMPONENT(),DAE.REDECL(_,_,_))
2574 algorithm
2575 ✗ ErrorExt.rollBack("checkMultiplyDeclared");
2576 then false;
2577
2578 // If a variable is declared multiple times, the first is used.
2579 // If the two variables are not identical, an error is given.
2580 case newComp as (SCode.COMPONENT(name = n),_)
2581 algorithm
2582 555951 (_,_,oldElt,oldMod,instStatus,_) := Lookup.lookupIdentLocal(cache, env, n);
2583 463523 checkMultipleElementsIdentical(cache,env,(oldElt,oldMod),newComp);
2584 463519 alreadyDeclared := instStatusToBool(instStatus);
2585 463519 ErrorExt.delCheckpoint("checkMultiplyDeclared");
2586 then alreadyDeclared;
2587
2588 // If not multiply declared, return.
2589 case (SCode.COMPONENT(name = n),_)
2590 algorithm
2591
2/2
✓ Branch 0 taken 92432 times.
✓ Branch 1 taken 92428 times.
184860 failure(Lookup.lookupIdentLocal(cache, env, n));
2592 92428 ErrorExt.rollBack("checkMultiplyDeclared");
2593 then false;
2594
2595
2596 // If a class definition is replaceable, skip check
2597 case (SCode.CLASS(prefixes = SCode.PREFIXES(replaceablePrefix=SCode.REPLACEABLE(_))),_)
2598 algorithm
2599 ✗ ErrorExt.rollBack("checkMultiplyDeclared");
2600 then false;
2601
2602 // If a class definition is redeclaration, skip check
2603 case (SCode.CLASS(),DAE.REDECL(_,_,_))
2604 algorithm
2605 ✗ ErrorExt.rollBack("checkMultiplyDeclared");
2606 then false;
2607
2608 // If a class definition is a product of InstExtends.instClassExtendsList2, skip check
2609 case (SCode.CLASS(name=n,classDef=SCode.PARTS(elementLst=SCode.EXTENDS(baseClassPath=Absyn.IDENT(n2))::_ )),_)
2610 algorithm
2611 ✗ n := "$parent" + "." + n;
2612 ✗ 0 := System.stringFind(n, n2);
2613 ✗ ErrorExt.rollBack("checkMultiplyDeclared");
2614 then false;
2615
2616 // If a class is defined multiple times, the first is used.
2617 // If the two class definitions are not equivalent, an error is given.
2618 case (newClass as SCode.CLASS(name=n),_)
2619 algorithm
2620 ✗ (oldClass,_) := Lookup.lookupClassLocal(env, n);
2621 ✗ checkMultipleClassesEquivalent(oldClass,newClass);
2622 ✗ ErrorExt.delCheckpoint("checkMultiplyDeclared");
2623 then true;
2624
2625 // If a class not multiply defined, return.
2626 case (SCode.CLASS(name=n),_)
2627 algorithm
2628 ✗ failure(Lookup.lookupClassLocal(env, n));
2629 ✗ ErrorExt.rollBack("checkMultiplyDeclared");
2630 then false;
2631
2632 // failure
2633 else
2634 algorithm
2635 4 ErrorExt.delCheckpoint("checkMultiplyDeclared");
2636
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if Flags.isSet(Flags.FAILTRACE) then
2637 ✗ Debug.trace("-Inst.checkMultiplyDeclared failed\n");
2638 end if;
2639 4 then fail();
2640 end matchcontinue;
2641 end checkMultiplyDeclared;
2642
2643 protected function instStatusToBool
2644 "Translates InstStatus to a boolean indicating if component is allready declared."
2645 input FCore.Status instStatus;
2646 output Boolean alreadyDeclared;
2647 algorithm
2648 alreadyDeclared := match instStatus
2649 case FCore.VAR_DAE() then true;
2650 case FCore.VAR_UNTYPED() then false;
2651 case FCore.VAR_TYPED() then false;
2652 end match;
2653 end instStatusToBool;
2654
2655 protected function checkMultipleElementsIdentical
2656 "Checks that the old declaration is identical
2657 to the new one. If not, give error message"
2658 input FCore.Cache inCache;
2659 input FCore.Graph inEnv;
2660 input tuple<SCode.Element,DAE.Mod> oldComponent;
2661 input tuple<SCode.Element,DAE.Mod> newComponent;
2662 algorithm
2663 () := matchcontinue(inCache,inEnv,oldComponent,newComponent)
2664 local
2665 SCode.Element oldElt,newElt;
2666 String s1,s2,s;
2667 SCode.Mod smod1, smod2;
2668 FCore.Graph env, env1, env2;
2669 FCore.Cache cache;
2670 SCode.Element c1, c2;
2671 Absyn.Path tpath1, tpath2;
2672 SourceInfo old_info, new_info;
2673 SCode.Prefixes prefixes1, prefixes2;
2674 SCode.Attributes attr1,attr2;
2675 String n1, n2;
2676 Option<Absyn.ArrayDim> ad1, ad2;
2677 Option<Absyn.Exp> cond1, cond2;
2678
2679 // try equality first!
2680 case(_,_,(oldElt,_),(newElt,_))
2681 algorithm
2682 // NOTE: Should be type identical instead? see spec.
2683 // p.23, check of flattening. "Check that duplicate elements are identical".
2684
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 463519 times.
463523 true := SCodeUtil.elementEqual(oldElt,newElt);
2685 then
2686 ();
2687
2688 // adrpo: see if they are not syntactically equivalent, but semantically equivalent!
2689 // see Modelica Spec. 3.1, page 66.
2690 // COMPONENT
2691 case (cache,env,(SCode.COMPONENT(n1, prefixes1, attr1, Absyn.TPATH(tpath1, ad1), smod1, _, cond1, _),_),
2692 (SCode.COMPONENT(n2, prefixes2, attr2, Absyn.TPATH(tpath2, ad2), smod2, _, cond2, _),_))
2693 algorithm
2694 // see if the most stuff is the same!
2695
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 true := stringEq(n1, n2);
2696
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 true := SCodeUtil.prefixesEqual(prefixes1, prefixes2);
2697
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
4 true := SCodeUtil.attributesEqual(attr1, attr2);
2698
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 true := SCodeUtil.modEqual(smod1, smod2);
2699
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 true := valueEq(ad1, ad2);
2700
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 true := valueEq(cond1, cond2);
2701 // if we lookup tpath1 and tpath2 and reach the same class, we're fine!
2702 3 (_, c1, env1) := Lookup.lookupClass(cache, env, tpath1);
2703 3 (_, c2, env2) := Lookup.lookupClass(cache, env, tpath2);
2704 // the class has the same environment
2705
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
3 true := stringEq(FGraph.printGraphPathStr(env1), FGraph.printGraphPathStr(env2));
2706 // the classes are the same!
2707
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 true := SCodeUtil.elementEqual(c1, c2);
2708 /*
2709 // add a warning and let it continue!
2710 s1 = SCodeDump.unparseElementStr(oldElt);
2711 s2 = SCodeDump.unparseElementStr(newElt);
2712 Error.addMultiSourceMessage(Error.DUPLICATE_ELEMENTS_NOT_SYNTACTICALLY_IDENTICAL, {s1, s2}, {old_info, new_info});
2713 */
2714 then
2715 ();
2716
2717 // adrpo: handle bug: https://trac.modelica.org/Modelica/ticket/627
2718 // TODO! FIXME! REMOVE! remove when the bug is fixed!
2719 case (cache,env,(oldElt as SCode.COMPONENT(n1, prefixes1, attr1, Absyn.TPATH(tpath1, ad1), smod1, _, cond1, old_info),_),
2720 (newElt as SCode.COMPONENT(n2, prefixes2, attr2, Absyn.TPATH(tpath2, ad2), smod2, _, cond2, new_info),_))
2721 algorithm
2722 // see if the most stuff is the same!
2723
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 true := stringEq(n1, n2);
2724
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 true := stringEq(n1, "m_flow");
2725 ✗ true := SCodeUtil.prefixesEqual(prefixes1, prefixes2);
2726 ✗ true := SCodeUtil.attributesEqual(attr1, attr2);
2727 ✗ false := SCodeUtil.modEqual(smod1, smod2);
2728 ✗ true := valueEq(ad1, ad2);
2729 ✗ true := valueEq(cond1, cond2);
2730 // if we lookup tpath1 and tpath2 and reach the same class, we're fine!
2731 ✗ (_, c1, env1) := Lookup.lookupClass(cache, env, tpath1);
2732 ✗ (_, c2, env2) := Lookup.lookupClass(cache, env, tpath2);
2733 // the class has the same environment
2734 ✗ true := stringEq(FGraph.printGraphPathStr(env1), FGraph.printGraphPathStr(env2));
2735 // the classes are the same!
2736 ✗ true := SCodeUtil.elementEqual(c1, c2);
2737 // add a warning and let it continue!
2738 ✗ s1 := SCodeDump.unparseElementStr(oldElt,SCodeDump.defaultOptions);
2739 ✗ s2 := SCodeDump.unparseElementStr(newElt,SCodeDump.defaultOptions);
2740 ✗ s := "Inherited elements are not identical: bug: https://trac.modelica.org/Modelica/ticket/627\n\tfirst: " +
2741 s1 + "\n\tsecond: " + s2 + "\nContinue ....";
2742 ✗ Error.addMultiSourceMessage(Error.COMPILER_WARNING, {s}, {old_info, new_info});
2743 then ();
2744
2745 // fail baby and add a source message!
2746 case (_, _, (oldElt as SCode.COMPONENT(info = old_info),_),
2747 (newElt as SCode.COMPONENT(info = new_info),_))
2748 algorithm
2749 4 s1 := SCodeDump.unparseElementStr(oldElt,SCodeDump.defaultOptions);
2750 4 s2 := SCodeDump.unparseElementStr(newElt,SCodeDump.defaultOptions);
2751 4 Error.addMultiSourceMessage(Error.DUPLICATE_ELEMENTS_NOT_IDENTICAL,
2752 {s1, s2}, {old_info, new_info});
2753 4 then
2754 fail();
2755
2756 end matchcontinue;
2757 end checkMultipleElementsIdentical;
2758
2759 protected function checkMultipleClassesEquivalent
2760 "Checks that the old class definition is equivalent
2761 to the new one. If not, give error message"
2762 input SCode.Element oldClass;
2763 input SCode.Element newClass;
2764 algorithm
2765 () := matchcontinue(oldClass,newClass)
2766 local
2767 SCode.Element oldCl,newCl;
2768 String s1,s2;
2769 list<String> sl1,sl2;
2770 list<SCode.Enum> enumLst;
2771 list<SCode.Element> elementLst;
2772 SourceInfo info1, info2;
2773
2774 // Special cases for checking enumerations which can be represented differently
2775 case(SCode.CLASS(classDef=SCode.ENUMERATION(enumLst=enumLst)), SCode.CLASS(restriction=SCode.R_ENUMERATION(),classDef=SCode.PARTS(elementLst=elementLst)))
2776 algorithm
2777 ✗ sl1:=List.map(enumLst,SCodeUtil.enumName);
2778 ✗ sl2:=List.map(elementLst,SCodeUtil.elementName);
2779 ✗ true := List.isEqualOnTrue(sl1,sl2,stringEq);
2780 then
2781 ();
2782
2783 case(SCode.CLASS(restriction=SCode.R_ENUMERATION(),classDef=SCode.PARTS(elementLst=elementLst)), SCode.CLASS(classDef=SCode.ENUMERATION(enumLst=enumLst)))
2784 algorithm
2785 ✗ sl1:=List.map(enumLst,SCodeUtil.enumName);
2786 ✗ sl2:=List.map(elementLst,SCodeUtil.elementName);
2787 ✗ true := List.isEqualOnTrue(sl1,sl2,stringEq);
2788 then
2789 ();
2790
2791 // try equality first!
2792 case(oldCl,newCl)
2793 algorithm
2794 ✗ true := SCodeUtil.elementEqual(oldCl,newCl);
2795 then ();
2796
2797 case (oldCl,newCl)
2798 algorithm
2799 ✗ s1 := SCodeDump.unparseElementStr(oldCl,SCodeDump.defaultOptions);
2800 ✗ s2 := SCodeDump.unparseElementStr(newCl,SCodeDump.defaultOptions);
2801 ✗ info1 := SCodeUtil.elementInfo(oldCl);
2802 ✗ info2 := SCodeUtil.elementInfo(newCl);
2803 ✗ Error.addMultiSourceMessage(Error.DUPLICATE_CLASSES_NOT_EQUIVALENT,
2804 {s1, s2}, {info1, info2});
2805 //print(" *** error message added *** \n");
2806 ✗ then fail();
2807 end matchcontinue;
2808 end checkMultipleClassesEquivalent;
2809
2810 public function removeOptCrefFromCrefs
2811 input list<Absyn.ComponentRef> inCrefs;
2812 input Option<Absyn.ComponentRef> inCref;
2813 output list<Absyn.ComponentRef> outCrefs;
2814 algorithm
2815 outCrefs := match inCref
2816 local
2817 Absyn.ComponentRef cref;
2818
2819 29 case SOME(cref) then removeCrefFromCrefs(inCrefs, cref);
2820 else inCrefs;
2821 end match;
2822 end removeOptCrefFromCrefs;
2823
2824 public function removeCrefFromCrefs
2825 "Removes a variable from a variable list"
2826 input list<Absyn.ComponentRef> inAbsynComponentRefLst;
2827 input Absyn.ComponentRef inComponentRef;
2828 output list<Absyn.ComponentRef> outAbsynComponentRefLst;
2829 algorithm
2830 outAbsynComponentRefLst := match (inAbsynComponentRefLst,inComponentRef)
2831 local
2832 String n1,n2;
2833 list<Absyn.ComponentRef> rest_1,rest;
2834 Absyn.ComponentRef cr1,cr2;
2835 case ({},_) then {};
2836 case ((Absyn.CREF_IDENT(name = n1,subscripts = {}) :: rest),cr2 as Absyn.CREF_IDENT(name = n2,subscripts = {}))
2837 guard stringEq(n1, n2)
2838 algorithm
2839 204 rest_1 := removeCrefFromCrefs(rest, cr2);
2840 then
2841 rest_1;
2842 case ((Absyn.CREF_QUAL(name = n1) :: rest),cr2 as Absyn.CREF_IDENT(name = n2)) // If modifier like on comp like: T t(x=t.y) => t.y must be removed
2843 guard stringEq(n1, n2)
2844 algorithm
2845 4974 rest_1 := removeCrefFromCrefs(rest, cr2);
2846 then
2847 rest_1;
2848 case ((cr1 :: rest),cr2)
2849 algorithm
2850 88664 rest_1 := removeCrefFromCrefs(rest, cr2);
2851 then
2852 (cr1 :: rest_1);
2853 end match;
2854 end removeCrefFromCrefs;
2855
2856 public function keepConstrainingTypeModifersOnly
2857 "Author: BZ, 2009-07
2858 A function for filtering out the modifications on the constraining type class."
2859 input DAE.Mod inMod;
2860 input list<SCode.Element> elems;
2861 output DAE.Mod filteredMod;
2862 algorithm
2863 filteredMod := match(inMod,elems)
2864 local
2865 SCode.Final f;
2866 SCode.Each e;
2867 Option<DAE.EqMod> oe;
2868 list<DAE.SubMod> subs;
2869 list<String> compNames;
2870 SourceInfo info;
2871
2872 case (_,{}) then inMod;
2873 case(DAE.NOMOD(),_ ) then DAE.NOMOD();
2874 case(DAE.REDECL(_,_,_),_) then inMod;
2875 case(DAE.MOD(f,e,subs,oe,info),_)
2876 algorithm
2877 4 compNames := List.map(elems,SCodeUtil.elementName);
2878 4 subs := keepConstrainingTypeModifersOnly2(subs,compNames);
2879 4 then
2880 DAE.MOD(f,e,subs,oe,info);
2881 end match;
2882 end keepConstrainingTypeModifersOnly;
2883
2884 protected function keepConstrainingTypeModifersOnly2 "
2885 Author BZ
2886 Helper function for keepConstrainingTypeModifersOnly"
2887 input list<DAE.SubMod> isubs;
2888 input list<String> elems;
2889 output list<DAE.SubMod> osubs;
2890 algorithm
2891 osubs := match(isubs,elems)
2892 local
2893 DAE.SubMod sub;
2894 String n;
2895 list<DAE.SubMod> subs;
2896
2897 case({},_) then {};
2898 case(subs,{}) then subs;
2899 case((sub as DAE.NAMEMOD(ident=n))::subs,_)
2900 guard
2901 List.isMemberOnTrue(n,elems,stringEq)
2902 ✗ then
2903 sub::keepConstrainingTypeModifersOnly2(subs,elems);
2904 4 case(_::subs,_) then keepConstrainingTypeModifersOnly2(subs,elems);
2905
2906 end match;
2907 end keepConstrainingTypeModifersOnly2;
2908
2909 public function extractConstrainingComps
2910 "Author: BZ, 2009-07
2911 This function examines a optional Absyn.ConstrainClass argument.
2912 If there is a constraining class, lookup the class and return its elements."
2913 input Option<SCode.ConstrainClass> cc;
2914 input FCore.Graph env;
2915 input DAE.Prefix pre;
2916 output list<SCode.Element> elems;
2917 algorithm
2918 elems := matchcontinue cc
2919 local
2920 Absyn.Path path;
2921 String name;
2922 list<SCode.Element> selems,extendselts,compelts,extcompelts,classextendselts,classes;
2923 list<tuple<SCode.Element, DAE.Mod>> extcomps;
2924 SCode.Mod mod;
2925 SCode.Comment cmt;
2926
2927 case NONE() then {};
2928 case SOME(SCode.CONSTRAINCLASS(constrainingClass = path))
2929 algorithm
2930
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
6 (_,SCode.CLASS(name = name, classDef = SCode.PARTS(elementLst=selems)), _) := Lookup.lookupClass(FCore.emptyCache(),env,path);
2931 6 (classes,classextendselts,extendselts,compelts) := splitElts(selems);
2932 6 (_,_,_,_,extcomps,_,_,_,_) := InstExtends.instExtendsAndClassExtendsList(FCore.emptyCache(), env, InnerOuter.emptyInstHierarchy, DAE.NOMOD(), pre, extendselts, classextendselts, selems, ClassInf.UNKNOWN(Absyn.IDENT("")), name, true, false);
2933 6 extcompelts := List.map(extcomps,Util.tuple21);
2934 6 compelts := listAppend(classes,listAppend(compelts,extcompelts));
2935 then
2936 compelts;
2937 case SOME(SCode.CONSTRAINCLASS(path, mod, cmt))
2938 algorithm
2939 ✗ (_,SCode.CLASS(classDef = SCode.DERIVED(typeSpec = Absyn.TPATH(path = path))),_) := Lookup.lookupClass(FCore.emptyCache(),env,path);
2940 ✗ compelts := extractConstrainingComps(SOME(SCode.CONSTRAINCLASS(path, mod, cmt)),env,pre);
2941 then
2942 compelts;
2943 end matchcontinue;
2944 end extractConstrainingComps;
2945
2946 public function moveBindings
2947 "This function takes two DAElists, the first with equations generated by
2948 InstBinding.instModEquation and the second the variables that bindings
2949 belonged to. The function moves the equations back as bindings for the
2950 variables, used for fixing record bindings."
2951 input DAE.DAElist inEquations;
2952 input DAE.DAElist inVariables;
2953 output DAE.DAElist outVariables;
2954 protected
2955 list<DAE.Element> eqs, vars;
2956 algorithm
2957
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1257 times.
1257 if Config.getGraphicsExpMode() then
2958 outVariables := inVariables;
2959 ✗ return;
2960 end if;
2961 1257 DAE.DAE(elementLst = eqs) := inEquations;
2962 1257 DAE.DAE(elementLst = vars) := inVariables;
2963 1257 Error.assertion(intEq(listLength(eqs), listLength(vars)),
2964 "- InstUtil.moveBindings: Mismatched number of equations and variables.", Absyn.dummyInfo);
2965 1257 vars := List.threadMap(eqs, vars, moveBindings2);
2966 1257 outVariables := DAE.DAE(vars);
2967 end moveBindings;
2968
2969 protected function moveBindings2
2970 input DAE.Element inEquation;
2971 input DAE.Element inVariable;
2972 output DAE.Element outVariable;
2973 algorithm
2974 outVariable := matchcontinue inVariable
2975 local
2976 DAE.ComponentRef cref;
2977 DAE.VarKind kind;
2978 DAE.VarDirection dir;
2979 DAE.VarParallelism prl;
2980 DAE.VarVisibility vis;
2981 DAE.Type ty;
2982 DAE.InstDims dims;
2983 DAE.ConnectorType ct;
2984 DAE.ElementSource src;
2985 Option<DAE.VariableAttributes> attr;
2986 Option<SCode.Comment> cmt;
2987 Absyn.InnerOuter io;
2988 Boolean e;
2989 DAE.Exp bind_exp;
2990
2991 case DAE.VAR(cref, kind, dir, prl, vis, ty, _, dims, ct, src, attr, cmt, io, e)
2992 algorithm
2993 14046 bind_exp := moveBindings3(inEquation);
2994
1/2
✓ Branch 0 taken 14046 times.
✗ Branch 1 not taken.
28092 then
2995 DAE.VAR(cref, kind, dir, prl, vis, ty, SOME(bind_exp), dims, ct, src, attr, cmt, io, e);
2996
2997 case DAE.VAR(componentRef = cref)
2998 algorithm
2999 ✗ true := Flags.isSet(Flags.FAILTRACE);
3000 ✗ Debug.traceln("- InstUtil.moveBindings failed on " +
3001 ComponentReferenceBasics.printComponentRefStr(cref));
3002 ✗ then
3003 fail();
3004
3005 end matchcontinue;
3006 end moveBindings2;
3007
3008 protected function moveBindings3
3009 input DAE.Element inEquation;
3010 output DAE.Exp outBinding;
3011 algorithm
3012 outBinding := match inEquation
3013 local
3014 DAE.Exp bind_exp;
3015
3016 case DAE.EQUATION(scalar = bind_exp) then bind_exp;
3017 case DAE.DEFINE(exp = bind_exp) then bind_exp;
3018
3019 end match;
3020 end moveBindings3;
3021
3022 public function checkModificationOnOuter
3023 input FCore.Cache inCache;
3024 input FCore.Graph inEnv;
3025 input InnerOuter.InstHierarchy inIH;
3026 input DAE.Prefix inPrefix;
3027 input String inName;
3028 input DAE.ComponentRef inCref;
3029 input DAE.Mod inMod;
3030 input SCode.Variability inVariability;
3031 input Absyn.InnerOuter inInnerOuter;
3032 input Boolean inImpl;
3033 input SourceInfo inInfo;
3034 algorithm
3035 () := matchcontinue(inIH, inMod, inVariability, inInnerOuter)
3036 local
3037 HashSet.HashSet sm;
3038 DAE.ComponentRef cref;
3039
3040 case (_, _, SCode.CONST(), _)
3041 then ();
3042
3043 case (_, _, SCode.PARAM(), _)
3044 then ();
3045
3046 case (InnerOuter.TOP_INSTANCE(sm=sm)::_, DAE.MOD(), _, Absyn.OUTER())
3047 algorithm
3048 // BTH: we check if the outer variable is in an instance that is
3049 // part of a Modelica state machine. In that case we have added
3050 // an equation modification, binding the inner variable to
3051 // the outer variable (instead of replacing the outer variable
3052 // by the inner variable). See InstVar.instVar(..).
3053 // Hence, such a modification should not throw an error.
3054 ✗ cref := PrefixUtil.prefixToCref(inPrefix);
3055 ✗ true := BaseHashSet.has(cref, sm);
3056 then ();
3057
3058 else
3059 algorithm
3060 // adrpo: we cannot check this here as:
3061 // we might have modifications on inner that we copy here
3062 // Dymola doesn't report modifications on outer as error!
3063 // instead we check here if the modification is not the same
3064 // as the one on inner
3065
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 385939 times.
385939 false := InnerOuter.modificationOnOuter(inCache, inEnv, inIH, inPrefix,
3066 inName, inCref, inMod, inInnerOuter, inImpl, inInfo);
3067 then
3068 ();
3069 end matchcontinue;
3070 end checkModificationOnOuter;
3071
3072 public function checkFunctionVar
3073 "Checks that a function variable is valid."
3074 input String inName;
3075 input SCode.Attributes inAttributes;
3076 input SCode.Prefixes inPrefixes;
3077 input SourceInfo inInfo;
3078 algorithm
3079 () := match(inAttributes, inPrefixes)
3080 // Public non-formal parameters are not allowed, but since they're used in
3081 // the MSL we just issue a warning for now.
3082 case (SCode.ATTR(direction = Absyn.BIDIR()), SCode.PREFIXES(visibility = SCode.PUBLIC()))
3083 algorithm
3084 4 Error.addSourceMessage(Error.NON_FORMAL_PUBLIC_FUNCTION_VAR,
3085 {inName}, inInfo);
3086 then
3087 ();
3088
3089 // Protected non-formal parameters are ok.
3090 case (SCode.ATTR(direction = Absyn.BIDIR()), SCode.PREFIXES(visibility = SCode.PROTECTED()))
3091 then ();
3092
3093 // Protected formal parameters are not allowed.
3094 case (SCode.ATTR(), SCode.PREFIXES(visibility = SCode.PROTECTED()))
3095 algorithm
3096 ✗ Error.addSourceMessage(Error.PROTECTED_FORMAL_FUNCTION_VAR,
3097 {inName}, inInfo);
3098 ✗ then
3099 fail();
3100
3101 // Everything else, i.e. public formal parameters, are ok.
3102 else ();
3103 end match;
3104 end checkFunctionVar;
3105
3106 public function checkFunctionVarType
3107 input DAE.Type inType;
3108 input ClassInf.State inState;
3109 input String inVarName;
3110 input SourceInfo inInfo;
3111 algorithm
3112
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 277532 times.
277542 if not Types.isValidFunctionVarType(inType) then
3113 20 Error.addSourceMessage(Error.INVALID_FUNCTION_VAR_TYPE,
3114 {TypesDump.getTypeName(inType), inVarName}, inInfo);
3115 10 fail();
3116 end if;
3117 end checkFunctionVarType;
3118
3119 public function liftNonBasicTypes
3120 "Helper functin to instVar2. All array variables should be
3121 given array types, by lifting the type given a dimensionality.
3122 An exception are types extending builtin types, since they already
3123 have array types. This relation performs the lifting for alltypes
3124 except types extending basic types."
3125 input DAE.Type tp;
3126 input DAE.Dimension dimt;
3127 output DAE.Type outTp;
3128 algorithm
3129 outTp:= match tp
3130 local DAE.Type ty;
3131 case DAE.T_SUBTYPE_BASIC(complexType = ty) guard not listEmpty(TypesDump.getDimensions(ty))
3132 then
3133 tp;
3134 72235 else Types.liftArray(tp, dimt);
3135 end match;
3136 end liftNonBasicTypes;
3137
3138 public function checkHigherVariability
3139 "If the binding expression has higher variability that the component, generates an error.
3140 Helper to makeVariableBinding. Author -- alleb"
3141 input DAE.Const compConst;
3142 input DAE.Const bindConst;
3143 input DAE.Prefix pre;
3144 input String name;
3145 input DAE.Exp binding;
3146 input SourceInfo info;
3147 algorithm
3148 () := matchcontinue(compConst, bindConst, name, binding)
3149 local
3150 DAE.Const c,c1;
3151 Ident n;
3152 String sc,sc1,se,sn;
3153 DAE.Exp e;
3154 case (c, c1, _, _) guard valueEq(c,c1)
3155 then ();
3156
3157 // When doing checkModel we might have parameters with variable bindings,
3158 // for example when the binding depends on the dimensions on an array with
3159 // unknown dimensions.
3160 case (DAE.C_PARAM(), DAE.C_UNKNOWN(), _, _)
3161 algorithm
3162 ✗ true := Flags.getConfigBool(Flags.CHECK_MODEL);
3163 then ();
3164
3165 // Since c1 is generated by Types.matchProp, it can not be lower that c, so no need to check that it is higher
3166 case (c, c1, n, e)
3167 algorithm
3168 2 sn := PrefixUtil.printPrefixStr2(pre)+n;
3169 2 sc := DAEUtil.constStr(c);
3170 2 sc1 := DAEUtil.constStr(c1);
3171 2 se := ExpressionBasics.printExpStr(e);
3172 2 Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING,{sn,sc,se,sc1}, info);
3173 2 then
3174 fail();
3175 end matchcontinue;
3176 end checkHigherVariability;
3177
3178 public function makeArrayType
3179 "Creates an array type from the element type
3180 given as argument and a list of dimensional sizes."
3181 input DAE.Dimensions inDimensionLst;
3182 input DAE.Type inType;
3183 output DAE.Type outType;
3184 algorithm
3185
3186 /*
3187 if Types.isArray(inType) then
3188 Error.addInternalError(getInstanceName() + ": input Type is already an array. This should not happen.", sourceInfo());
3189 fail();
3190 end if;
3191
3192 outType := if listEmpty(inDimensionLst) then inType else DAE.T_ARRAY(inType, inDimensionLst);
3193 */
3194
3195 outType := matchcontinue (inDimensionLst,inType)
3196 local
3197 DAE.Type ty,ty_1;
3198 DAE.Dimensions xs;
3199 DAE.Type tty;
3200 DAE.Dimension dim;
3201
3202 case ({},ty) then ty;
3203
3204 case (dim :: xs, tty)
3205 algorithm
3206 15053 ty_1 := makeArrayType(xs, tty);
3207 15053 then
3208 DAE.T_ARRAY(ty_1, {dim});
3209
3210 else
3211 algorithm
3212 ✗ true := Flags.isSet(Flags.FAILTRACE);
3213 ✗ Debug.trace("- InstUtil.makeArrayType failed\n");
3214 ✗ then
3215 fail();
3216 end matchcontinue;
3217 end makeArrayType;
3218
3219 public function getUsertypeDimensions
3220 "Retrieves the dimensions of a usertype and the innermost class type to instantiate,
3221 and also any modifications from the base classes of the usertype.
3222 The builtin types have no dimension, whereas a user defined type might
3223 have dimensions. For instance, type Point = Real[3];
3224 has one dimension of size 3 and the class to instantiate is Real"
3225 input FCore.Cache inCache;
3226 input FCore.Graph inEnv;
3227 input InnerOuter.InstHierarchy inIH;
3228 input DAE.Prefix inPrefix;
3229 input SCode.Element inClass;
3230 input list<list<DAE.Dimension>> inInstDims;
3231 input Boolean inBoolean;
3232 output FCore.Cache outCache;
3233 output DAE.Dimensions outDimensionLst;
3234 output SCode.Element classToInstantiate;
3235 output DAE.Mod outMods "modifications from base classes";
3236 algorithm
3237 (outCache,outDimensionLst,classToInstantiate,outMods) := matchcontinue (inCache,inEnv,inIH,inPrefix,inClass,inInstDims,inBoolean)
3238 local
3239 SCode.Element cl;
3240 FCore.Graph cenv,env;
3241 Absyn.ComponentRef owncref;
3242 list<Absyn.Subscript> ad_1;
3243 DAE.Mod mod_1,type_mods;
3244 Option<DAE.EqMod> eq;
3245 DAE.Dimensions dim1,dim2,res;
3246 DAE.Prefix pre;
3247 String id;
3248 Absyn.Path cn;
3249 Option<list<Absyn.Subscript>> ad;
3250 SCode.Mod mod;
3251 InstDims dims;
3252 Boolean impl;
3253 FCore.Cache cache;
3254 InstanceHierarchy ih;
3255 SourceInfo info;
3256 list<SCode.Element> els;
3257 SCode.Path path;
3258
3259 419278 case (cache, _, _, _, cl as SCode.CLASS(name = id), _, _) guard id=="Real" or id=="Integer" or id=="String" or id=="Boolean" then (cache,{},cl,DAE.NOMOD());
3260 // BTH
3261 case (cache, _, _, _, cl as SCode.CLASS(name = "Clock"), _, _)
3262 algorithm
3263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 162 times.
162 true := Config.synchronousFeaturesAllowed();
3264 162 then (cache,{},cl,DAE.NOMOD());
3265
3266 case (cache, _, _, _, cl as SCode.CLASS(restriction = SCode.R_RECORD(_),
3267 classDef = SCode.PARTS()), _, _) then (cache,{},cl,DAE.NOMOD());
3268
3269 //------------------------
3270 // MetaModelica extension
3271 case (cache, env, _, pre, cl as SCode.CLASS(name = id, info=info,
3272 classDef = SCode.DERIVED(typeSpec = Absyn.TCOMPLEX(path = Absyn.IDENT(), arrayDim = ad))),
3273 dims,impl)
3274 algorithm
3275
2/2
✓ Branch 1 taken 566 times.
✓ Branch 2 taken 31047 times.
31613 true:=Config.acceptMetaModelicaGrammar();
3276 31047 owncref := Absyn.CREF_IDENT(id,{});
3277 31047 ad_1 := getOptionArraydim(ad);
3278 // Absyn.IDENT("Integer") used as a dummie
3279 31047 (cache,dim1) := elabArraydim(cache,env, owncref, Absyn.IDENT("Integer"), ad_1,NONE(),impl,true,false,pre,info,dims);
3280 31047 then
3281 (cache,dim1,cl,DAE.NOMOD());
3282
3283 // Partial function definitions with no output - stefan
3284 case (cache, _, _, _,
3285 cl as SCode.CLASS(restriction = SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_)),
3286 partialPrefix = SCode.PARTIAL()), _, _)
3287 then
3288 (cache,{},cl,DAE.NOMOD());
3289
3290 case (_, _, _, _,
3291 SCode.CLASS(name = id,info=info,restriction = SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(_)),
3292 partialPrefix = SCode.NOT_PARTIAL()),_,_)
3293 algorithm
3294 ✗ Error.addSourceMessage(Error.META_FUNCTION_TYPE_NO_PARTIAL_PREFIX, {id}, info);
3295 ✗ then fail();
3296
3297 // MetaModelica Uniontype. Added 2009-05-11 sjoelund
3298 case (cache, _, _, _,
3299 cl as SCode.CLASS(restriction = SCode.R_UNIONTYPE()), _, _)
3300 then (cache,{},cl,DAE.NOMOD());
3301 /*----------------------*/
3302
3303 // Derived classes with restriction type, e.g. type Point = Real[3];
3304 case (cache, env, ih, pre,
3305 SCode.CLASS(name = id,restriction = SCode.R_TYPE(),info=info,
3306 classDef = SCode.DERIVED(typeSpec = Absyn.TPATH(path = cn, arrayDim = ad),modifications = mod)),
3307 dims, impl)
3308 algorithm
3309 197407 (cache,cl,cenv) := Lookup.lookupClass(cache, env, cn, SOME(info));
3310 197407 owncref := Absyn.CREF_IDENT(id,{});
3311 197407 ad_1 := getOptionArraydim(ad);
3312 197407 env := addEnumerationLiteralsToEnv(env, cl);
3313
3314 197407 (cache,mod_1) := Mod.elabMod(cache, env, ih, pre, mod, impl, Mod.DERIVED(cn), info);
3315 197407 eq := Mod.modEquation(mod_1);
3316 197407 (cache,dim1,cl,type_mods) := getUsertypeDimensions(cache, cenv, ih, pre, cl, dims, impl);
3317 197407 (cache,dim2) := elabArraydim(cache, env, owncref, cn, ad_1, eq, impl, true, false, pre, info, dims);
3318 197407 type_mods := Mod.addEachIfNeeded(type_mods, dim2);
3319 // do not add each to mod_1, it should have it already!
3320 // mod_1 = Mod.addEachIfNeeded(mod_1, dim2);
3321 197407 type_mods := Mod.merge(mod_1, type_mods);
3322 197407 res := listAppend(dim2, dim1);
3323 197407 then
3324 (cache,res,cl,type_mods);
3325
3326 // extended classes type Y = Real[3]; class X extends Y;
3327 case (cache, env, ih, pre,
3328 SCode.CLASS(
3329 classDef = SCode.PARTS(elementLst=els,
3330 normalEquationLst = {},
3331 initialEquationLst = {},
3332 normalAlgorithmLst = {},
3333 initialAlgorithmLst = {})),
3334 _, impl)
3335 algorithm
3336
7/8
✓ Branch 1 taken 58142 times.
✓ Branch 2 taken 12918 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12918 times.
✓ Branch 5 taken 440 times.
✓ Branch 6 taken 12478 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 12382 times.
71060 (_,_,{SCode.EXTENDS(path, _, mod,_, info)},{}) := splitElts(els); // ONLY ONE extends!
3337 12382 (cache,mod_1) := Mod.elabModForBasicType(cache, env, ih, pre, mod, impl, Mod.EXTENDS(path), info);
3338 12373 (cache,cl,_) := Lookup.lookupClass(cache, env, path);
3339 12373 (cache,res,cl,type_mods) := getUsertypeDimensions(cache,env,ih,pre,cl,{},impl);
3340 // type_mods = Mod.addEachIfNeeded(type_mods, res);
3341 12373 type_mods := Mod.merge(mod_1, type_mods);
3342 12373 then
3343 (cache,res,cl,type_mods);
3344
3345 case (cache, _, _, _, cl as SCode.CLASS(), _, _)
3346 then (cache,{},cl,DAE.NOMOD());
3347
3348 case (_, _, _, _, SCode.CLASS(), _, _)
3349 algorithm
3350 ✗ true := Flags.isSet(Flags.FAILTRACE);
3351 ✗ id := SCodeDump.unparseElementStr(inClass,SCodeDump.defaultOptions);
3352 ✗ Debug.traceln("InstUtil.getUsertypeDimensions failed: " + id);
3353 ✗ then
3354 fail();
3355
3356 end matchcontinue;
3357 end getUsertypeDimensions;
3358
3359 protected function addEnumerationLiteralsToEnv
3360 "If the input SCode.Element is an enumeration, this function adds all of it's
3361 enumeration literals to the environment. This is used in getUsertypeDimensions
3362 so that the modifiers on an enumeration can be elaborated when the literals
3363 are used, for example like this:
3364 type enum1 = enumeration(val1, val2);
3365 type enum2 = enum1(start = val1); // val1 needs to be in the environment here."
3366 input FCore.Graph inEnv;
3367 input SCode.Element inClass;
3368 output FCore.Graph outEnv;
3369 algorithm
3370 outEnv := matchcontinue inClass
3371 local
3372 list<SCode.Element> enums;
3373 FCore.Graph env;
3374 case SCode.CLASS(restriction = SCode.R_ENUMERATION(), classDef = SCode.PARTS(elementLst = enums))
3375 algorithm
3376 1 env := List.fold(enums, addEnumerationLiteralToEnv, inEnv);
3377 then env;
3378 else inEnv; // Not an enumeration, no need to do anything.
3379 end matchcontinue;
3380 end addEnumerationLiteralsToEnv;
3381
3382 protected function addEnumerationLiteralToEnv
3383 input SCode.Element inEnum;
3384 input FCore.Graph inEnv;
3385 output FCore.Graph outEnv;
3386 algorithm
3387 outEnv := matchcontinue inEnum
3388 local
3389 SCode.Ident lit;
3390 FCore.Graph env;
3391
3392 case SCode.COMPONENT(name = lit)
3393 algorithm
3394 2 env := FGraph.mkComponentNode(inEnv,
3395 DAE.TYPES_VAR(lit, DAE.dummyAttrVar, DAE.T_UNKNOWN_DEFAULT, DAE.UNBOUND(), false, NONE()),
3396 inEnum, DAE.NOMOD(), FCore.VAR_UNTYPED(), FGraph.empty());
3397 then env;
3398
3399 else
3400 algorithm
3401 ✗ print("InstUtil.addEnumerationLiteralToEnv: Unknown enumeration type!\n");
3402 ✗ then fail();
3403 end matchcontinue;
3404 end addEnumerationLiteralToEnv;
3405
3406 public function updateClassInfState
3407 input FCore.Cache inCache;
3408 input FCore.Graph inNewEnv;
3409 input FCore.Graph inOldEnv;
3410 input ClassInf.State inCIState;
3411 output ClassInf.State outCIState;
3412 algorithm
3413 outCIState := matchcontinue inCIState
3414 local
3415 ClassInf.State ci_state;
3416 FCore.Graph rest;
3417 Absyn.Ident id;
3418 SCode.Element cls;
3419
3420 // top env, return the same ci_state
3421 case ci_state
3422 algorithm
3423
2/2
✓ Branch 1 taken 28582 times.
✓ Branch 2 taken 60 times.
28642 true := FGraph.isTopScope(inNewEnv);
3424 then
3425 ci_state;
3426
3427 // same environment, return the same ci_state
3428 case ci_state
3429 algorithm
3430
2/4
✓ Branch 2 taken 28582 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 28582 times.
✗ Branch 8 not taken.
28582 true := stringEq(FGraph.getGraphNameStr(inNewEnv),
3431 FGraph.getGraphNameStr(inOldEnv));
3432 then
3433 ci_state;
3434
3435 // not the same environment, try to
3436 // make a ci state from the new env
3437 case _
3438 algorithm
3439 // not top scope
3440 ✗ false := FGraph.isTopScope(inNewEnv);
3441 ✗ id := FNode.refName(FGraph.lastScopeRef(inNewEnv));
3442 ✗ (rest, _) := FGraph.stripLastScopeRef(inNewEnv);
3443 ✗ (_, cls, _) := Lookup.lookupClassIdent(inCache, rest, id);
3444 ✗ ci_state := ClassInfUtil.start(SCodeUtil.getClassRestriction(cls), FGraph.getGraphName(inNewEnv));
3445 then
3446 ci_state;
3447
3448 else inCIState;
3449
3450 end matchcontinue;
3451 end updateClassInfState;
3452
3453 public function evalEnumAndBoolDim
3454 "function: instDAE.Dimension
3455 instantiates one dimension expression, See also instDimExpLst."
3456 input DAE.Dimension inDimension;
3457 output DAE.Dimension outDimension;
3458 algorithm
3459 outDimension := match inDimension
3460 local
3461
3462 // case (DAE.DIM_ENUM(size = i)) then DAE.DIM_INTEGER(i);
3463 case DAE.DIM_BOOLEAN() then DAE.DIM_INTEGER(2);
3464 else inDimension;
3465 end match;
3466 end evalEnumAndBoolDim;
3467
3468 /*TODO: mahge: Remove me*/
3469 public function instDimExpNonSplit
3470 "the vesrion of instDimExp for the case of non-expanded arrays"
3471 input DAE.Dimension inDimension;
3472 input Boolean inBoolean;
3473 output DAE.Subscript outSubscript;
3474 algorithm
3475 outSubscript := match inDimension
3476 local
3477 DAE.Exp e;
3478 Integer i;
3479
3480 case DAE.DIM_UNKNOWN() then DAE.WHOLEDIM();
3481 ✗ case DAE.DIM_INTEGER(integer = i) then DAE.WHOLE_NONEXP(DAE.ICONST(i));
3482 ✗ case DAE.DIM_ENUM(size = i) then DAE.WHOLE_NONEXP(DAE.ICONST(i));
3483 case DAE.DIM_BOOLEAN() then DAE.WHOLE_NONEXP(DAE.ICONST(2));
3484 //case (DAE.DIM_EXP(exp = e as DAE.RANGE(exp = _)), _) then DAE.INDEX(e);
3485 ✗ case DAE.DIM_EXP(exp = e) then DAE.WHOLE_NONEXP(e);
3486 end match;
3487 end instDimExpNonSplit;
3488
3489 public function instWholeDimFromMod
3490 "Tries to determine the size of a WHOLEDIM dimension by looking at a variables
3491 modifier."
3492 input DAE.Dimension dimensionExp;
3493 input DAE.Mod modifier;
3494 input String inVarName;
3495 input SourceInfo inInfo;
3496 output DAE.Dimension outDimension;
3497 algorithm
3498 outDimension := matchcontinue(dimensionExp, modifier)
3499 local
3500 DAE.Dimension d;
3501 DAE.Exp exp;
3502 String exp_str;
3503
3504 case (DAE.DIM_UNKNOWN(), DAE.MOD(binding =
3505 SOME(DAE.TYPED(modifierAsExp = exp))))
3506 algorithm
3507
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 d :: _ := Expression.expDimensions(exp);
3508 then d;
3509
3510 // TODO: We should print an error if we fail to deduce the dimensions from
3511 // the modifier, but we do not yet handle some cases (such as
3512 // Modelica.Blocks.Sources.KinematicPTP), so just print a warning for now.
3513 case (DAE.DIM_UNKNOWN(), DAE.MOD(binding =
3514 SOME(DAE.TYPED(modifierAsExp = exp))))
3515 algorithm
3516 ✗ exp_str := ExpressionBasics.printExpStr(exp);
3517 ✗ Error.addSourceMessage(Error.FAILURE_TO_DEDUCE_DIMS_FROM_MOD,
3518 {inVarName, exp_str}, inInfo);
3519 ✗ then
3520 fail();
3521
3522 case (DAE.DIM_UNKNOWN(), _)
3523 algorithm
3524 ✗ true := Flags.isSet(Flags.FAILTRACE);
3525 ✗ Debug.trace("- InstUtil.instWholeDimFromMod failed\n");
3526 ✗ then
3527 fail();
3528 end matchcontinue;
3529 end instWholeDimFromMod;
3530
3531 public function propagateAttributes
3532 "Propagates attributes (flow, stream, discrete, parameter, constant, input,
3533 output) to elements in a structured component."
3534 input DAE.DAElist inDae;
3535 input SCode.Attributes inAttributes;
3536 input SCode.Prefixes inPrefixes;
3537 input SourceInfo inInfo;
3538 output DAE.DAElist outDae;
3539 protected
3540 list<DAE.Element> elts;
3541 algorithm
3542 526566 DAE.DAE(elementLst = elts) := inDae;
3543 526566 elts := List.map3(elts, propagateAllAttributes, inAttributes, inPrefixes, inInfo);
3544 526566 outDae := DAE.DAE(elts);
3545 end propagateAttributes;
3546
3547 protected function propagateAllAttributes
3548 "Helper function to propagateAttributes. Propagates all attributes if needed."
3549 input DAE.Element inElement;
3550 input SCode.Attributes inAttributes;
3551 input SCode.Prefixes inPrefixes;
3552 input SourceInfo inInfo;
3553 output DAE.Element outElement;
3554 algorithm
3555 outElement := match(inElement, inAttributes, inPrefixes)
3556 local
3557 DAE.ComponentRef cr;
3558 DAE.VarKind vk;
3559 DAE.VarDirection vdir;
3560 DAE.VarParallelism vprl;
3561 DAE.VarVisibility vvis;
3562 DAE.Type ty;
3563 Option<DAE.Exp> binding;
3564 DAE.InstDims dims;
3565 SCode.ConnectorType ct1;
3566 DAE.ConnectorType ct2;
3567 DAE.ElementSource source;
3568 Option<DAE.VariableAttributes> var_attrs;
3569 Option<SCode.Comment> cmt;
3570 Absyn.InnerOuter io1, io2;
3571 Boolean e;
3572 SCode.Parallelism sprl;
3573 SCode.Variability var;
3574 Absyn.Direction dir;
3575 SCode.Final fp;
3576 SCode.Ident ident;
3577 list<DAE.Element> el;
3578 SCode.Visibility vis;
3579
3580 // Just return the element if nothing needs to be changed.
3581 case (_, SCode.ATTR(
3582 connectorType = SCode.POTENTIAL(),
3583 parallelism = SCode.NON_PARALLEL(),
3584 variability = SCode.VAR(),
3585 direction = Absyn.BIDIR()), SCode.PREFIXES(
3586 visibility = SCode.PUBLIC(),
3587 finalPrefix = SCode.NOT_FINAL(),
3588 innerOuter = Absyn.NOT_INNER_OUTER()))
3589 then inElement;
3590
3591 // Normal variable.
3592 case (DAE.VAR(
3593 componentRef = cr,
3594 kind = vk,
3595 direction = vdir,
3596 parallelism = vprl,
3597 protection = vvis,
3598 ty = ty,
3599 binding = binding,
3600 dims = dims,
3601 connectorType = ct2,
3602 source = source,
3603 variableAttributesOption = var_attrs,
3604 comment = cmt,
3605 innerOuter = io2,
3606 encrypted = e), SCode.ATTR(
3607 connectorType = ct1,
3608 parallelism = sprl,
3609 variability = var,
3610 direction = dir), SCode.PREFIXES(
3611 visibility = vis,
3612 finalPrefix = fp,
3613 innerOuter = io1))
3614 algorithm
3615 199533 vdir := propagateDirection(vdir, dir, cr, inInfo);
3616 199533 vk := propagateVariability(vk, var);
3617 199533 vprl := propagateParallelism(vprl,sprl,cr,inInfo);
3618 199533 vvis := propagateVisibility(vvis, vis);
3619 199533 var_attrs := propagateFinal(var_attrs, fp);
3620 199533 io2 := propagateInnerOuter(io2, io1);
3621 199533 ct2 := propagateConnectorType(ct2, ct1, cr, inInfo);
3622
1/2
✓ Branch 0 taken 199533 times.
✗ Branch 1 not taken.
399066 then
3623 DAE.VAR(cr, vk, vdir, vprl, vvis, ty, binding, dims, ct2, source, var_attrs, cmt, io2, e);
3624
3625 // Structured component.
3626 case (DAE.COMP(ident = ident, dAElist = el, source = source, comment = cmt), _, _)
3627 algorithm
3628 ✗ el := List.map3(el, propagateAllAttributes, inAttributes, inPrefixes, inInfo);
3629 ✗ then
3630 DAE.COMP(ident, el, source, cmt);
3631
3632 // Everything else.
3633 else inElement;
3634
3635 end match;
3636 end propagateAllAttributes;
3637
3638 protected function propagateDirection
3639 "Helper function to propagateAttributes. Propagates the input/output
3640 attribute to variables of a structured component."
3641 input DAE.VarDirection inVarDirection;
3642 input Absyn.Direction inDirection;
3643 input DAE.ComponentRef inCref;
3644 input SourceInfo inInfo;
3645 output DAE.VarDirection outVarDirection;
3646 algorithm
3647 outVarDirection := match(inVarDirection, inDirection)
3648 local
3649 String s1, s2, s3;
3650
3651 // Component that is bidirectional does not change direction on subcomponents.
3652 case (_, Absyn.BIDIR()) then inVarDirection;
3653
3654 // Bidirectional variables are changed to input or output if component has
3655 // such prefix.
3656 5 case (DAE.BIDIR(), _) then absynDirToDaeDir(inDirection);
3657
3658 // Error when component declared as input or output if the variable already
3659 // has such a prefix.
3660 else
3661 algorithm
3662 ✗ s1 := Dump.directionSymbol(inDirection);
3663 ✗ s2 := ComponentReferenceBasics.printComponentRefStr(inCref);
3664 ✗ s3 := DAEDump.dumpDirectionStr(inVarDirection);
3665 ✗ Error.addSourceMessage(Error.COMPONENT_INPUT_OUTPUT_MISMATCH,
3666 {s1, s2, s3}, inInfo);
3667 ✗ then
3668 fail();
3669 end match;
3670 end propagateDirection;
3671
3672 protected function propagateParallelism
3673 "Helper function to propagateAttributes. Propagates the input/output
3674 attribute to variables of a structured component."
3675 input DAE.VarParallelism inVarParallelism;
3676 input SCode.Parallelism inParallelism;
3677 input DAE.ComponentRef inCref;
3678 input SourceInfo inInfo;
3679 output DAE.VarParallelism outVarParallelism;
3680 algorithm
3681 outVarParallelism := matchcontinue(inVarParallelism, inParallelism)
3682 local
3683 String s1, s2, s3, s4;
3684 DAE.VarParallelism daeprl1,daeprl2;
3685
3686 // Component that is non parallel does not change Parallelism on subcomponents.
3687 case (_, SCode.NON_PARALLEL()) then inVarParallelism;
3688
3689 // non_parallel variables are changed to parlocal or parglobal
3690 // depending on the component
3691 ✗ case (DAE.NON_PARALLEL(), _) then DAEUtil.scodePrlToDaePrl(inParallelism);
3692
3693 // if the two parallelisms are equal then it is OK
3694 case(daeprl1, _)
3695 algorithm
3696 ✗ daeprl2 := DAEUtil.scodePrlToDaePrl(inParallelism);
3697 ✗ true := DAEUtil.daeParallelismEqual(daeprl1,daeprl2);
3698 then
3699 daeprl1;
3700
3701 // Reaches here If the component is declared as parlocal or parglobal
3702 // and the subcomponent is declared as parglobal or parlocal, respectively.
3703 // Print a warning and override the subcomponent's parallelism.
3704 else
3705 algorithm
3706 ✗ daeprl2 := DAEUtil.scodePrlToDaePrl(inParallelism);
3707
3708 ✗ s1 := DAEDump.dumpVarParallelismStr(daeprl2);
3709 ✗ s2 := ComponentReferenceBasics.printComponentRefStr(inCref);
3710 ✗ s3 := DAEDump.dumpVarParallelismStr(inVarParallelism);
3711
3712 ✗ s4 := "\n" +
3713 "- Component declared as '" + s1 +
3714 "' when having the variable '" + s2 +
3715 "' declared as '" + s3 + "' : Subcomponent parallelism modified to." +
3716 s1
3717 ;
3718 ✗ Error.addSourceMessage(Error.PARMODELICA_WARNING,
3719 {s4}, inInfo);
3720 then
3721 daeprl2;
3722 end matchcontinue;
3723 end propagateParallelism;
3724
3725 protected function propagateVisibility
3726 "Helper function to propagateAttributes. Propagates the visibility (public or
3727 protected) attribute to variables of a structured component."
3728 input DAE.VarVisibility inVarVisibility;
3729 input SCode.Visibility inVisibility;
3730 output DAE.VarVisibility outVarVisibility;
3731 algorithm
3732 outVarVisibility := match inVisibility
3733 case SCode.PROTECTED() then DAE.PROTECTED();
3734 else inVarVisibility;
3735 end match;
3736 end propagateVisibility;
3737
3738 protected function propagateVariability
3739 "Helper function to propagateAttributes. Propagates the variability (parameter
3740 or constant) attribute to variables of a structured component."
3741 input DAE.VarKind inVarKind;
3742 input SCode.Variability inVariability;
3743 output DAE.VarKind outVarKind;
3744 algorithm
3745 outVarKind := match(inVarKind, inVariability)
3746 // Component that is VAR does not change variability of subcomponents.
3747 case (_, SCode.VAR()) then inVarKind;
3748 // Most restrictive variability is preserved.
3749 case (DAE.DISCRETE(), _) then inVarKind;
3750 case (_, SCode.DISCRETE()) then DAE.DISCRETE();
3751 case (DAE.CONST(), _) then inVarKind;
3752 case (_, SCode.CONST()) then DAE.CONST();
3753 case (DAE.PARAM(), _) then inVarKind;
3754 case (_, SCode.PARAM()) then DAE.PARAM();
3755 else inVarKind;
3756 end match;
3757 end propagateVariability;
3758
3759 protected function propagateFinal
3760 "Helper function to propagateAttributes. Propagates the final attribute to
3761 variables of a structured component."
3762 input Option<DAE.VariableAttributes> inVarAttributes;
3763 input SCode.Final inFinal;
3764 output Option<DAE.VariableAttributes> outVarAttributes;
3765 algorithm
3766 outVarAttributes := match inFinal
3767 case SCode.FINAL()
3768 3939 then DAEUtil.setFinalAttr(inVarAttributes, SCodeUtil.finalBool(inFinal));
3769 else inVarAttributes;
3770 end match;
3771 end propagateFinal;
3772
3773 protected function propagateInnerOuter
3774 "Helper function to propagateAttributes. Propagates the inner/outer attribute
3775 to variables of a structured component."
3776 input Absyn.InnerOuter inVarInnerOuter;
3777 input Absyn.InnerOuter inInnerOuter;
3778 output Absyn.InnerOuter outVarInnerOuter;
3779 algorithm
3780 outVarInnerOuter := match(inVarInnerOuter, inInnerOuter)
3781 // Component that is unspecified does not change inner/outer on subcomponents.
3782 case (_, Absyn.NOT_INNER_OUTER()) then inVarInnerOuter;
3783 // Unspecified variables are changed to the same inner/outer prefix as the
3784 // component.
3785 case (Absyn.NOT_INNER_OUTER(), _) then inInnerOuter;
3786 // If variable already have inner/outer, keep it.
3787 else inVarInnerOuter;
3788 end match;
3789 end propagateInnerOuter;
3790
3791 protected function propagateConnectorType
3792 "Helper function to propagateAttributes. Propagates the flow/stream attribute
3793 to variables of a structured component."
3794 input DAE.ConnectorType inVarConnectorType;
3795 input SCode.ConnectorType inConnectorType;
3796 input DAE.ComponentRef inCref;
3797 input SourceInfo inInfo;
3798 output DAE.ConnectorType outVarConnectorType;
3799 algorithm
3800 outVarConnectorType :=
3801 match(inVarConnectorType, inConnectorType)
3802 local
3803 String s1, s2, s3;
3804
3805 case (_, SCode.POTENTIAL()) then inVarConnectorType;
3806 case (DAE.POTENTIAL(), SCode.FLOW()) then DAE.FLOW();
3807 case (DAE.NON_CONNECTOR(), SCode.FLOW()) then DAE.FLOW();
3808 case (DAE.POTENTIAL(), SCode.STREAM()) then DAE.STREAM(NONE());
3809 case (DAE.NON_CONNECTOR(), SCode.STREAM()) then DAE.STREAM(NONE());
3810
3811 // Error if the component tries to overwrite the prefix of a subcomponent.
3812 else
3813 algorithm
3814 ✗ s1 := SCodeDump.connectorTypeStr(inConnectorType);
3815 ✗ s2 := ComponentReferenceBasics.printComponentRefStr(inCref);
3816 ✗ s3 := DAEDump.dumpConnectorType(inVarConnectorType);
3817 ✗ Error.addSourceMessage(Error.INVALID_TYPE_PREFIX,
3818 {s1, "variable", s2, s3}, inInfo);
3819 ✗ then
3820 fail();
3821
3822 end match;
3823 end propagateConnectorType;
3824
3825 protected function absynDirToDaeDir
3826 "Translates Absyn.Direction to DAE.VarDirection.
3827 Needed so that input, output is transferred to DAE."
3828 input Absyn.Direction inDirection;
3829 output DAE.VarDirection outVarDirection;
3830 algorithm
3831 outVarDirection := match inDirection
3832 case Absyn.INPUT() then DAE.INPUT();
3833 case Absyn.OUTPUT() then DAE.OUTPUT();
3834 case Absyn.BIDIR() then DAE.BIDIR();
3835 end match;
3836 end absynDirToDaeDir;
3837
3838 protected function attrIsParam
3839 "Returns true if attributes contain PARAM"
3840 input SCode.Attributes inAttributes;
3841 output Boolean outBoolean;
3842 algorithm
3843 outBoolean := match inAttributes
3844 case SCode.ATTR(variability = SCode.PARAM()) then true;
3845 else false;
3846 end match;
3847 end attrIsParam;
3848
3849 public function elabComponentArraydimFromEnv
3850 "author: PA
3851 Lookup uninstantiated component in env, elaborate its modifiers to
3852 find arraydimensions and return as DAE.Dimension list.
3853 Used when components have submodifiers (on e.g. attributes) using
3854 size to find dimensions of component."
3855 input FCore.Cache inCache;
3856 input FCore.Graph inEnv;
3857 input DAE.ComponentRef inComponentRef;
3858 input SourceInfo info;
3859 output FCore.Cache outCache;
3860 output DAE.Dimensions outDimensionLst;
3861 algorithm
3862 (outCache,outDimensionLst) := matchcontinue (inCache, inEnv, inComponentRef)
3863 local
3864 String id;
3865 list<Absyn.Subscript> ad;
3866 SCode.Mod m,m_1;
3867 DAE.Mod cmod,cmod_1,m_2,mod_2;
3868 DAE.EqMod eq;
3869 DAE.Dimensions dims;
3870 FCore.Graph env;
3871 DAE.ComponentRef cref;
3872 FCore.Cache cache;
3873 list<DAE.Subscript> subs;
3874
3875 case (cache, env, DAE.CREF_IDENT(ident = id))
3876 algorithm
3877
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
85 (cache,_,SCode.COMPONENT(modifications = m),cmod,_,_)
3878 := Lookup.lookupIdent(cache, env, id);
3879 44 cmod_1 := Mod.stripSubmod(cmod);
3880 44 m_1 := SCodeUtil.stripSubmod(m);
3881 44 (cache,m_2) := Mod.elabMod(cache, env, InnerOuter.emptyInstHierarchy, DAE.NOPRE(), m_1, false, Mod.COMPONENT(id), info);
3882 44 mod_2 := Mod.merge(cmod_1, m_2);
3883
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 4 times.
44 SOME(eq) := Mod.modEquation(mod_2);
3884 4 (cache,dims) := elabComponentArraydimFromEnv2(cache,eq, env);
3885 then
3886 (cache,dims);
3887
3888 case (cache, env, DAE.CREF_IDENT(ident = id))
3889 algorithm
3890
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
41 (cache,_,SCode.COMPONENT(attributes = SCode.ATTR(arrayDims = ad)),_,_,_)
3891 := Lookup.lookupIdent(cache,env, id);
3892 40 (cache, subs) := Static.elabSubscripts(cache, env, ad, true, DAE.NOPRE(), info);
3893 40 dims := Expression.subscriptDimensions(subs);
3894 40 then
3895 (cache,dims);
3896
3897 case (_, _, cref)
3898 algorithm
3899
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 true := Flags.isSet(Flags.FAILTRACE);
3900 ✗ Debug.traceln("- InstUtil.elabComponentArraydimFromEnv failed: " +
3901 ComponentReferenceBasics.printComponentRefStr(cref));
3902 ✗ then
3903 fail();
3904
3905 end matchcontinue;
3906 end elabComponentArraydimFromEnv;
3907
3908 protected function elabComponentArraydimFromEnv2
3909 "author: PA
3910 Helper function to elabComponentArraydimFromEnv.
3911 This function is similar to elabArraydim, but it will only
3912 investigate binding (DAE.EqMod) and not the component declaration."
3913 input FCore.Cache inCache;
3914 input DAE.EqMod inEqMod;
3915 input FCore.Graph inEnv;
3916 output FCore.Cache outCache;
3917 output DAE.Dimensions outDimensionLst;
3918 algorithm
3919 (outCache,outDimensionLst) := match (inCache, inEqMod)
3920 local
3921 list<Integer> lst;
3922 DAE.Dimensions lst_1;
3923 DAE.Type t;
3924 FCore.Cache cache;
3925
3926 case (cache, DAE.TYPED(properties = DAE.PROP(type_ = t)))
3927 algorithm
3928 4 lst := Types.getDimensionSizes(t);
3929 4 lst_1 := List.map(lst, Expression.intDimension);
3930 then
3931 (cache,lst_1);
3932
3933 end match;
3934 end elabComponentArraydimFromEnv2;
3935
3936 public function elabArraydimOpt
3937 "Same functionality as elabArraydim, but takes an optional arraydim.
3938 In case of NONE(), empty DAE.Dimension list is returned."
3939 input FCore.Cache inCache;
3940 input FCore.Graph inEnv;
3941 input Absyn.ComponentRef inComponentRef;
3942 input Absyn.Path path "Class of declaration";
3943 input Option<Absyn.ArrayDim> inAbsynArrayDimOption;
3944 input Option<DAE.EqMod> inTypesEqModOption;
3945 input Boolean inBoolean;
3946 input Boolean performVectorization;
3947 input DAE.Prefix inPrefix;
3948 input SourceInfo info;
3949 input list<list<DAE.Dimension>> inInstDims;
3950 output FCore.Cache outCache;
3951 output DAE.Dimensions outDimensionLst;
3952 algorithm
3953 (outCache,outDimensionLst) :=
3954 match (inCache, inEnv, inComponentRef, inAbsynArrayDimOption, inTypesEqModOption, inBoolean, performVectorization, inPrefix, inInstDims)
3955 local
3956 DAE.Dimensions res;
3957 FCore.Graph env;
3958 Absyn.ComponentRef owncref;
3959 list<Absyn.Subscript> ad;
3960 Option<DAE.EqMod> eq;
3961 Boolean impl;
3962 FCore.Cache cache;
3963 Boolean doVect;
3964 DAE.Prefix pre;
3965 InstDims inst_dims;
3966 case (cache, env, owncref, SOME(ad), eq, impl, doVect, pre, inst_dims)
3967 algorithm
3968 2 (cache,res) := elabArraydim(cache,env, owncref, path,ad, eq, impl, doVect, false,pre,info,inst_dims);
3969 then
3970 (cache,res);
3971 205487 case (cache, _, _, NONE(), _, _, _, _, _) then (cache,{});
3972 end match;
3973 end elabArraydimOpt;
3974
3975 public function elabArraydim
3976 "This functions examines both an `Absyn.ArrayDim\' and an `DAE.EqMod
3977 option\' argument to find out the dimensions af a component. If
3978 no equation modifications is given, only the declared dimension is
3979 used.
3980
3981 When the size of a dimension in the type is undefined, the
3982 corresponding size in the type of the modification is used.
3983
3984 All this is accomplished by examining the two arguments separately
3985 and then using `complete_arraydime\' or `compatible_arraydim\' to
3986 check that that the dimension sizes are compatible and complete."
3987 input FCore.Cache inCache;
3988 input FCore.Graph inEnv;
3989 input Absyn.ComponentRef inComponentRef;
3990 input Absyn.Path path "Class of declaration";
3991 input Absyn.ArrayDim inArrayDim;
3992 input Option<DAE.EqMod> inTypesEqModOption;
3993 input Boolean inBoolean;
3994 input Boolean performVectorization;
3995 input Boolean isFunctionInput;
3996 input DAE.Prefix inPrefix;
3997 input SourceInfo inInfo;
3998 input list<list<DAE.Dimension>> inInstDims;
3999 output FCore.Cache outCache;
4000 output DAE.Dimensions outDimensionLst;
4001 algorithm
4002 (outCache,outDimensionLst) :=
4003 matchcontinue
4004 (inCache, inEnv, inComponentRef, inArrayDim, inTypesEqModOption, inBoolean, performVectorization, isFunctionInput, inPrefix, inInfo, inInstDims)
4005 local
4006 DAE.Dimensions dim,dim1,dim2;
4007 DAE.Dimensions dim3;
4008 FCore.Graph env;
4009 Absyn.ComponentRef cref;
4010 list<Absyn.Subscript> ad;
4011 Boolean impl;
4012 DAE.Exp e,e_1;
4013 DAE.Type t;
4014 String e_str,t_str,dim_str;
4015 FCore.Cache cache;
4016 Boolean doVect;
4017 DAE.Properties prop;
4018 DAE.Prefix pre;
4019 Absyn.Exp aexp;
4020 Option<DAE.EqMod> eq;
4021 InstDims inst_dims;
4022 SourceInfo info, info2;
4023
4024 // The size of function input arguments should not be set here, since they
4025 // may vary depending on the inputs. So we ignore any modifications on input
4026 // variables here.
4027 case (cache, env, cref, ad, _, _, doVect, true, pre, info, _)
4028 algorithm
4029 167950 (cache, dim) := Static.elabArrayDims(cache, env, cref, ad, true, doVect, pre, info);
4030 then
4031 (cache, dim);
4032
4033 590517 case (cache, _, _, {}, _, _, _, _, _, _, _) then (cache, {});
4034
4035 case (cache, env, cref, ad, NONE(), impl, doVect, _, pre, info, _) /* impl */
4036 algorithm
4037 20268 (cache,dim) := Static.elabArrayDims(cache,env, cref, ad, impl,doVect,pre,info);
4038 then
4039 (cache,dim);
4040
4041 case (cache, env, cref, ad, SOME(DAE.TYPED(e,_,prop,_)), impl, doVect, _, pre, info, inst_dims) /* Untyped expressions must be elaborated. */
4042 algorithm
4043 36934 t := Types.getPropType(prop);
4044 36934 (cache,dim1) := Static.elabArrayDims(cache,env, cref, ad, impl,doVect,pre,info);
4045 36934 dim2 := elabArraydimType(t, ad, e, path, pre, cref, info,inst_dims);
4046 //Debug.traceln("TYPED: " + ExpressionBasics.printExpStr(e) + " s: " + FGraph.printGraphPathStr(env));
4047 36932 dim3 := List.threadMap(dim1, dim2, compatibleArraydim);
4048 36931 then
4049 (cache,dim3);
4050
4051 case (cache, env, cref, ad, SOME(DAE.UNTYPED(aexp)), impl, doVect, _, pre, info, inst_dims)
4052 algorithm
4053 ✗ (cache,e_1,prop) := Static.elabExp(cache,env, aexp, impl,doVect,pre,info);
4054 ✗ (cache, e_1, prop) := Ceval.cevalIfConstant(cache, env, e_1, prop, impl, info);
4055 ✗ t := Types.getPropType(prop);
4056 ✗ (cache,dim1) := Static.elabArrayDims(cache,env, cref, ad, impl, doVect ,pre, info);
4057 ✗ dim2 := elabArraydimType(t, ad, e_1, path, pre, cref, info,inst_dims);
4058 //Debug.traceln("UNTYPED");
4059 ✗ dim3 := List.threadMap(dim1, dim2, compatibleArraydim);
4060 ✗ then
4061 (cache,dim3);
4062
4063 case (cache, env, cref, ad, SOME(DAE.TYPED(e,_,DAE.PROP(t,_),_,info2)), impl, doVect, _, pre, info, inst_dims)
4064 algorithm
4065 // adrpo: do not display error when running checkModel
4066 // TODO! FIXME! check if this doesn't actually get rid of useful error messages
4067
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 false := Flags.getConfigBool(Flags.CHECK_MODEL);
4068 3 (_,dim1) := Static.elabArrayDims(cache, env, cref, ad, impl, doVect,pre,info);
4069 3 dim2 := elabArraydimType(t, ad, e, path, pre, cref, info,inst_dims);
4070
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 failure(List.threadMap(dim1, dim2, compatibleArraydim));
4071 1 e_str := ExpressionBasics.printExpStr(e);
4072 1 t_str := TypesDump.unparseType(t);
4073 1 dim_str := ExpressionBasics.dimensionsString(dim1);
4074 1 Error.addMultiSourceMessage(Error.ARRAY_DIMENSION_MISMATCH, {e_str,t_str,dim_str}, info2::info::{});
4075 1 then
4076 fail();
4077
4078 // print some failures
4079 case (_, _, cref, ad, eq, _, _, _, _, _, _)
4080 algorithm
4081 // only display when the failtrace flag is on
4082
1/2
✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
104 true := Flags.isSet(Flags.FAILTRACE);
4083 ✗ Debug.trace("- InstUtil.elabArraydim failed on: \n\tcref:");
4084 ✗ Debug.trace(AbsynUtil.pathString(path) + " " + Dump.printComponentRefStr(cref));
4085 ✗ Debug.traceln(Dump.printArraydimStr(ad) + " = " + TypesDump.unparseOptionEqMod(eq));
4086 ✗ then
4087 fail();
4088 end matchcontinue;
4089 end elabArraydim;
4090
4091 protected function compatibleArraydim
4092 "Given two, possibly incomplete, array dimension size specifications, this
4093 function checks whether they are compatible. Being compatible means that they
4094 have the same number of dimensions, and for every dimension at least one of
4095 the lists specifies it's size. If both lists specify a dimension size, they
4096 have to specify the same size."
4097 input DAE.Dimension inDimension1;
4098 input DAE.Dimension inDimension2;
4099 output DAE.Dimension outDimension;
4100 algorithm
4101 outDimension := match(inDimension1, inDimension2)
4102 local
4103 case (DAE.DIM_UNKNOWN(), DAE.DIM_UNKNOWN()) then DAE.DIM_UNKNOWN();
4104 case (_, DAE.DIM_UNKNOWN()) then inDimension1;
4105 case (DAE.DIM_UNKNOWN(), _) then inDimension2;
4106 case (_, DAE.DIM_EXP()) then inDimension1;
4107 case (DAE.DIM_EXP(), _) then inDimension2;
4108 case (_, _)
4109 algorithm
4110
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36141 times.
36143 true := intEq(Expression.dimensionSize(inDimension1),
4111 Expression.dimensionSize(inDimension2));
4112 then
4113 inDimension1;
4114
4115 else
4116 algorithm
4117 ✗ true := Flags.isSet(Flags.FAILTRACE);
4118 ✗ Debug.trace("- InstUtil.compatibleArraydim failed\n");
4119 ✗ then
4120 fail();
4121 end match;
4122 end compatibleArraydim;
4123
4124 protected function elabArraydimType
4125 "Find out the dimension sizes of a type. The second argument is used to know
4126 how many dimensions should be extracted from the type."
4127 input DAE.Type inType;
4128 input Absyn.ArrayDim inArrayDim;
4129 input DAE.Exp inExp "User for error messages.";
4130 input Absyn.Path inPath "Class of declaration, used for error messages.";
4131 input DAE.Prefix inPrefix;
4132 input Absyn.ComponentRef inCref;
4133 input SourceInfo inInfo;
4134 input list<list<DAE.Dimension>> inInstDims;
4135 output DAE.Dimensions outDimensions;
4136 protected
4137 list<DAE.Dimension> flat_id;
4138 String ad_str, ty_str, exp_str, name_str;
4139 algorithm
4140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36937 times.
36937 flat_id := if Config.splitArrays() then {} else List.flatten(inInstDims);
4141
4142 try
4143
2/2
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 36933 times.
36937 true := Types.numberOfDimensions(inType) >= listLength(inArrayDim) + listLength(flat_id);
4144 36933 outDimensions := elabArraydimType2(inType, inArrayDim, flat_id);
4145 else
4146 4 ad_str := AbsynUtil.pathString(inPath) + Dump.printArraydimStr(inArrayDim);
4147 4 ty_str := TypesDump.unparseTypeNoAttr(inType);
4148 4 exp_str := ExpressionBasics.printExpStr(inExp);
4149 4 name_str := PrefixUtil.printPrefixStrIgnoreNoPre(inPrefix) +
4150 Dump.printComponentRefStr(inCref);
4151 4 Error.addSourceMessageAndFail(Error.MODIFIER_DECLARATION_TYPE_MISMATCH_ERROR,
4152 {name_str, ad_str, exp_str, ty_str}, inInfo);
4153 end try;
4154 end elabArraydimType;
4155
4156 protected function elabArraydimType2
4157 "Help function to elabArraydimType."
4158 input DAE.Type inType;
4159 input Absyn.ArrayDim inArrayDim;
4160 input list<DAE.Dimension> inDims;
4161 output list<DAE.Dimension> outDimensions;
4162 protected
4163 algorithm
4164 /*
4165 // I am not sure what excatly this is supposed to do. Anyway it seems to expect the
4166 // nested array representations we used to have before T_ARRAY(d, T_ARRAY(...)). We
4167 // have moved to flat arrays a while back. This was overlooked. I have tried to simulate what
4168 // I can understand from the cases commented below.
4169 // I am not sure if any of it is really needed though.
4170
4171 outDimensions := {};
4172 tyDims := TypesDump.getDimensions(inType);
4173
4174 try
4175 for fl_dim in inDims loop
4176 tydim::tyDims := tyDims;
4177 compatibleArraydim(tydim, fl_dim);
4178 end for;
4179
4180 for ab_dim in inArrayDim loop
4181 tydim::tyDims := tyDims;
4182 outDimensions := tydim::outDimensions;
4183 end for;
4184 else
4185 if Flags.isSet(Flags.FAILTRACE) then
4186 Debug.trace("Undefined! The type detected: ");
4187 Debug.traceln(TypesDump.printTypeStr(inType));
4188 end if;
4189
4190 fail();
4191 end try;
4192 */
4193
4194 outDimensions := matchcontinue (inType, inArrayDim, inDims)
4195 local
4196 DAE.Dimension d;
4197 DAE.Dimension dim;
4198 list<DAE.Dimension> rest_dims;
4199 DAE.Type t;
4200
4201 case (DAE.T_ARRAY(dims = {d}, ty = t), _, dim :: rest_dims)
4202 algorithm
4203 ✗ compatibleArraydim(d, dim);
4204 ✗ then
4205 elabArraydimType2(t, inArrayDim, rest_dims);
4206
4207 case (DAE.T_ARRAY(dims = {d}, ty = t), _, {})
4208 38124 then d :: elabArraydimType2(t, listRest(inArrayDim), {});
4209
4210 case (_, {}, {}) then {};
4211
4212 case (_, (_ :: _), _) // PR, for debugging
4213 algorithm
4214 ✗ true := Flags.isSet(Flags.FAILTRACE);
4215 ✗ Debug.trace("Undefined! The type detected: ");
4216 ✗ Debug.traceln(TypesDump.printTypeStr(inType));
4217 ✗ then
4218 fail();
4219 end matchcontinue;
4220
4221 end elabArraydimType2;
4222
4223 public function addFunctionsToDAE
4224 "@author: adrpo
4225 we might need to intantiate partial functions, but we should NOT add them to the DAE!"
4226 input FCore.Cache inCache;
4227 input list<DAE.Function> funcs "fully qualified function name";
4228 input SCode.Partial inPartialPrefix;
4229 output FCore.Cache outCache;
4230 algorithm
4231 outCache := match inCache
4232 local
4233 FCore.Cache cache;
4234
4235 /*/ if not meta-modelica and we have a partial function, DO NOT ADD IT TO THE DAE!
4236 case (cache, funcs, pPrefix as SCode.PARTIAL())
4237 algorithm
4238 false = Config.acceptMetaModelicaGrammar();
4239 true = System.getPartialInstantiation();
4240 // if all the functions are complete, add them, otherwise, NO
4241 fLst = List.select(funcs, DAEUtil.isNotCompleteFunction);
4242 fLst = if_(listEmpty(fLst), funcs, {});
4243 cache = FCore.addDaeFunction(cache, fLst);
4244 then
4245 cache;*/
4246
4247 // otherwise add it to the DAE!
4248 case cache
4249 algorithm
4250 13700 cache := FCore.addDaeFunction(cache, funcs);
4251 then
4252 cache;
4253
4254 end match;
4255 end addFunctionsToDAE;
4256
4257 public function addNameToDerivativeMapping
4258 input list<DAE.Function> inElts;
4259 input Absyn.Path path;
4260 output list<DAE.Function> outElts;
4261 algorithm
4262
4/4
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 283 times.
✓ Branch 2 taken 283 times.
✓ Branch 3 taken 283 times.
566 outElts := list(
4263 match fn
4264 case DAE.FUNCTION()
4265 algorithm
4266 283 fn.functions := addNameToDerivativeMappingFunctionDefs(fn.functions, path);
4267 then
4268 fn;
4269
4270 else fn;
4271 end match
4272 for fn in inElts);
4273 end addNameToDerivativeMapping;
4274
4275 protected function addNameToDerivativeMappingFunctionDefs " help function to addNameToDerivativeMapping"
4276 input list<DAE.FunctionDefinition> inFuncs;
4277 input Absyn.Path path;
4278 output list<DAE.FunctionDefinition> outFuncs;
4279 algorithm
4280
4/4
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 283 times.
✓ Branch 2 taken 288 times.
✓ Branch 3 taken 283 times.
571 outFuncs := list(
4281 match fn
4282 case DAE.FUNCTION_DER_MAPPER()
4283 algorithm
4284 10 fn.lowerOrderDerivatives := path :: fn.lowerOrderDerivatives;
4285 then
4286 fn;
4287
4288 else fn;
4289 end match
4290 for fn in inFuncs);
4291 end addNameToDerivativeMappingFunctionDefs;
4292
4293 public function getDeriveAnnotation "
4294 Authot BZ
4295 helper function for InstFunction.implicitFunctionInstantiation, returns derivative of function, if any."
4296 input SCode.ClassDef cd;
4297 input SCode.Comment cmt;
4298 input Absyn.Path baseFunc;
4299 input FCore.Cache inCache;
4300 input FCore.Graph inEnv;
4301 input InnerOuter.InstHierarchy inIH;
4302 input DAE.Prefix inPrefix;
4303 input SourceInfo info;
4304 output list<DAE.FunctionDefinition> element;
4305 algorithm
4306 element := matchcontinue(cd, cmt)
4307 local
4308 list<SCode.Element> elemDecl;
4309 SCode.Annotation ann;
4310
4311 case(SCode.PARTS(elementLst = elemDecl, externalDecl=SOME(SCode.EXTERNALDECL(annotation_=SOME(ann)))), _)
4312 1819 then getDeriveAnnotation2(ann,elemDecl,baseFunc,inCache,inEnv,inIH,inPrefix,info);
4313
4314 case(SCode.PARTS(elementLst = elemDecl), SCode.COMMENT(annotation_=SOME(ann)))
4315 51757 then getDeriveAnnotation2(ann,elemDecl,baseFunc,inCache,inEnv,inIH,inPrefix,info);
4316
4317 else {};
4318
4319 end matchcontinue;
4320 end getDeriveAnnotation;
4321
4322 protected function getDeriveAnnotation2 "
4323 helper function for getDeriveAnnotation"
4324 input SCode.Annotation ann;
4325 input list<SCode.Element> elemDecl;
4326 input Absyn.Path baseFunc;
4327 input FCore.Cache inCache;
4328 input FCore.Graph inEnv;
4329 input InnerOuter.InstHierarchy inIH;
4330 input DAE.Prefix inPrefix;
4331 input SourceInfo info;
4332 output list<DAE.FunctionDefinition> element;
4333 algorithm
4334 element := match ann
4335 local
4336 list<SCode.SubMod> smlst;
4337
4338 case SCode.ANNOTATION(SCode.MOD(subModLst = smlst))
4339 53576 then getDeriveAnnotation3(smlst,elemDecl,baseFunc,inCache,inEnv,inIH,inPrefix,info);
4340
4341 end match;
4342 end getDeriveAnnotation2;
4343
4344 protected function getDeriveAnnotation3 "
4345 Author: bjozac
4346 helper function to getDeriveAnnotation2"
4347 input list<SCode.SubMod> inSubs;
4348 input list<SCode.Element> elemDecl;
4349 input Absyn.Path baseFunc;
4350 input FCore.Cache inCache;
4351 input FCore.Graph inEnv;
4352 input InnerOuter.InstHierarchy inIH;
4353 input DAE.Prefix inPrefix;
4354 input SourceInfo info;
4355 output list<DAE.FunctionDefinition> element;
4356 algorithm
4357 element := matchcontinue inSubs
4358 local
4359 Absyn.ComponentRef acr;
4360 Absyn.Path deriveFunc;
4361 Option<Absyn.Path> defaultDerivative;
4362 list<SCode.SubMod> subs2;
4363 Integer order;
4364 list<tuple<Integer,DAE.derivativeCond>> conditionRefs;
4365 DAE.FunctionDefinition mapper;
4366 list<SCode.SubMod> subs;
4367
4368 case {} then fail();
4369
4370 case SCode.NAMEMOD("derivative",(SCode.MOD(subModLst = subs2,binding=SOME(Absyn.CREF(acr))))) :: subs
4371 algorithm
4372 960 deriveFunc := AbsynUtil.crefToPath(acr);
4373 960 (_,deriveFunc) := Inst.makeFullyQualified(inCache,inEnv,deriveFunc);
4374 960 order := getDerivativeOrder(subs2);
4375
4376 960 ErrorExt.setCheckpoint("getDeriveAnnotation3") "don't report errors on modifers in functions";
4377 960 conditionRefs := getDeriveCondition(subs2,elemDecl,inCache,inEnv,inIH,inPrefix,info);
4378 960 ErrorExt.rollBack("getDeriveAnnotation3");
4379
4380 960 conditionRefs := List.sort(conditionRefs,DAEUtil.derivativeOrder);
4381 960 defaultDerivative := getDerivativeSubModsOptDefault(subs,inCache,inEnv,inPrefix);
4382
4383
4384 /*print("\n adding conditions on derivative count: " + intString(listLength(conditionRefs)) + "\n");
4385 dbgString = AbsynUtil.optPathString(defaultDerivative);
4386 dbgString = if_(stringEq(dbgString,""),"", "**** Default Derivative: " + dbgString + "\n");
4387 print("**** Function derived: " + AbsynUtil.pathString(baseFunc) + " \n");
4388 print("**** Deriving function: " + AbsynUtil.pathString(deriveFunc) + "\n");
4389 print("**** Conditions: " + stringDelimitList(DAEDump.dumpDerivativeCond(conditionRefs),", ") + "\n");
4390 print("**** Order: " + intString(order) + "\n");
4391 print(dbgString);*/
4392
4393
4394 960 mapper := DAE.FUNCTION_DER_MAPPER(baseFunc,deriveFunc,order,conditionRefs,defaultDerivative,{});
4395 then
4396 {mapper};
4397
4398 case _ :: subs
4399 88001 then getDeriveAnnotation3(subs,elemDecl,baseFunc,inCache,inEnv,inIH,inPrefix,info);
4400 end matchcontinue;
4401 end getDeriveAnnotation3;
4402
4403 protected function getDeriveCondition "
4404 helper function for getDeriveAnnotation
4405 Extracts conditions for derivative."
4406 input list<SCode.SubMod> inSubs;
4407 input list<SCode.Element> elemDecl;
4408 input FCore.Cache inCache;
4409 input FCore.Graph inEnv;
4410 input InnerOuter.InstHierarchy inIH;
4411 input DAE.Prefix inPrefix;
4412 input SourceInfo info;
4413 output list<tuple<Integer,DAE.derivativeCond>> outconds;
4414 algorithm
4415 outconds := matchcontinue inSubs
4416 local
4417 SCode.Mod m;
4418 DAE.SubMod sub;
4419 String name;
4420 DAE.derivativeCond cond;
4421 Absyn.ComponentRef acr;
4422 Integer varPos;
4423 list<SCode.SubMod> subs;
4424 FCore.Cache cache;
4425
4426 case {} then {};
4427
4428 case SCode.NAMEMOD("noDerivative",(SCode.MOD(binding = SOME(Absyn.CREF(acr)))))::subs
4429 algorithm
4430 295 name := Dump.printComponentRefStr(acr);
4431 295 outconds := getDeriveCondition(subs,elemDecl,inCache,inEnv,inIH,inPrefix,info);
4432 295 varPos := setFunctionInputIndex(elemDecl,name,1);
4433 295 then
4434 (varPos,DAE.NO_DERIVATIVE(DAE.ICONST(99)))::outconds;
4435
4436 case SCode.NAMEMOD("zeroDerivative",(SCode.MOD(binding = SOME(Absyn.CREF(acr)))))::subs
4437 algorithm
4438 14 name := Dump.printComponentRefStr(acr);
4439 14 outconds := getDeriveCondition(subs,elemDecl,inCache,inEnv,inIH,inPrefix,info);
4440 14 varPos := setFunctionInputIndex(elemDecl,name,1);
4441 14 then
4442 (varPos,DAE.ZERO_DERIVATIVE())::outconds;
4443
4444 case SCode.NAMEMOD("noDerivative",(m as SCode.MOD()))::subs
4445 algorithm
4446
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
2 (cache,DAE.MOD(subModLst={sub})) := Mod.elabMod(inCache, inEnv, inIH, inPrefix, m, false, Mod.COMPONENT("noDerivative"), info);
4447 2 (name,cond) := extractNameAndExp(sub);
4448 2 outconds := getDeriveCondition(subs,elemDecl,cache,inEnv,inIH,inPrefix,info);
4449 2 varPos := setFunctionInputIndex(elemDecl,name,1);
4450 2 then
4451 (varPos,cond)::outconds;
4452
4453 case _::subs
4454 5 then getDeriveCondition(subs,elemDecl,inCache,inEnv,inIH,inPrefix,info);
4455 end matchcontinue;
4456 end getDeriveCondition;
4457
4458 protected function setFunctionInputIndex "
4459 Author BZ"
4460 input list<SCode.Element> inElemDecl;
4461 input String str;
4462 input Integer currPos;
4463 output Integer index;
4464 algorithm
4465 index := matchcontinue inElemDecl
4466 local
4467 String str2;
4468 list<SCode.Element> elemDecl;
4469
4470 case {}
4471 algorithm
4472 ✗ print(" failure in setFunctionInputIndex, didn't find any index for: " + str + "\n");
4473 ✗ then fail();
4474
4475 /* found matching input*/
4476 case SCode.COMPONENT(name=str2,attributes =SCode.ATTR(direction=Absyn.INPUT()))::_
4477 algorithm
4478
4/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 264 times.
✓ Branch 3 taken 311 times.
✓ Branch 4 taken 22 times.
597 true := stringEq(str2, str);
4479 then
4480 currPos;
4481
4482 /* Non-matching input, increase inputarg pos*/
4483 case SCode.COMPONENT(attributes =SCode.ATTR(direction=Absyn.INPUT()))::elemDecl
4484 286 then setFunctionInputIndex(elemDecl,str,currPos+1);
4485
4486 /* Other element, do not increaese inputarg pos*/
4487 262 case _::elemDecl then setFunctionInputIndex(elemDecl,str,currPos);
4488 end matchcontinue;
4489 end setFunctionInputIndex;
4490
4491 protected function extractNameAndExp "
4492 Author BZ
4493 could be used by getDeriveCondition, depending on interpretation of spec compared to constructed libraries.
4494 helper function for getDeriveAnnotation"
4495 input DAE.SubMod m;
4496 output String inputVar;
4497 output DAE.derivativeCond cond;
4498 algorithm
4499 (inputVar,cond) := match m
4500 local
4501 DAE.Exp e;
4502 case DAE.NAMEMOD(ident = inputVar,mod = DAE.MOD(binding = SOME(DAE.TYPED(modifierAsExp=e))))
4503 2 then (inputVar,DAE.NO_DERIVATIVE(e));
4504 case DAE.NAMEMOD(ident = inputVar,mod = DAE.MOD(binding = NONE()))
4505 then (inputVar,DAE.NO_DERIVATIVE(DAE.ICONST(1)));
4506 case DAE.NAMEMOD(ident = inputVar,mod = DAE.MOD(binding = NONE())) // zeroderivative
4507 then (inputVar,DAE.ZERO_DERIVATIVE());
4508
4509 else ("",DAE.ZERO_DERIVATIVE());
4510 end match;
4511 end extractNameAndExp;
4512
4513 protected function getDerivativeSubModsOptDefault "
4514 helper function for getDeriveAnnotation"
4515 input list<SCode.SubMod> inSubs;
4516 input FCore.Cache inCache;
4517 input FCore.Graph inEnv;
4518 input DAE.Prefix inPrefix;
4519 output Option<Absyn.Path> defaultDerivative;
4520 algorithm defaultDerivative := matchcontinue inSubs
4521 local
4522 Absyn.ComponentRef acr;
4523 Absyn.Path p;
4524 list<SCode.SubMod> subs;
4525
4526 case {} then NONE();
4527 case SCode.NAMEMOD("derivative",(SCode.MOD(binding =SOME(Absyn.CREF(acr)))))::_
4528 algorithm
4529 ✗ p := AbsynUtil.crefToPath(acr);
4530 ✗ (_,p) := Inst.makeFullyQualified(inCache,inEnv, p);
4531 ✗ then
4532 SOME(p);
4533 824 case _::subs then getDerivativeSubModsOptDefault(subs,inCache,inEnv,inPrefix);
4534 end matchcontinue;
4535 end getDerivativeSubModsOptDefault;
4536
4537 protected function getDerivativeOrder "
4538 helper function for getDeriveAnnotation
4539 Get current derive order"
4540 input list<SCode.SubMod> inSubs;
4541 output Integer order;
4542 algorithm order := match inSubs
4543 local
4544 list<SCode.SubMod> subs;
4545 case {} then 1;
4546 case SCode.NAMEMOD("order",(SCode.MOD(binding= SOME((Absyn.INTEGER(order))))))::_
4547 then order;
4548 311 case _::subs then getDerivativeOrder(subs);
4549 end match;
4550 end getDerivativeOrder;
4551
4552 public function setFullyQualifiedTypename
4553 "This function sets the FQ path given as argument in types that have optional path set.
4554 (The optional path points to the class the type is built from)"
4555 input DAE.Type inType;
4556 input Absyn.Path path;
4557 output DAE.Type resType;
4558 algorithm
4559 resType := match inType
4560 local
4561
4562 case resType as DAE.T_FUNCTION()
4563 algorithm
4564 68841 resType.path := path;
4565 then resType;
4566
4567 else inType;
4568 end match;
4569 end setFullyQualifiedTypename;
4570
4571 public function classIsInlineFunc
4572 input SCode.Element elt;
4573 output DAE.InlineType outInlineType;
4574 algorithm
4575 outInlineType := match elt
4576 2756 case SCode.CLASS() then InstBasics.commentIsInlineFunc(elt.cmt);
4577 else DAE.DEFAULT_INLINE();
4578 end match;
4579 end classIsInlineFunc;
4580
4581 public function stripFuncOutputsMod "strips the assignment modification of the component declared as output"
4582 input SCode.Element elem;
4583 output SCode.Element stripped_elem;
4584 protected
4585 SCode.Mod mod;
4586 algorithm
4587 stripped_elem := match elem
4588 case SCode.COMPONENT(attributes = SCode.ATTR(direction = Absyn.OUTPUT()),
4589 modifications = mod as SCode.MOD(binding = SOME(_)))
4590 algorithm
4591 ✗ mod.binding := NONE();
4592 ✗ elem.modifications := mod;
4593 then
4594 elem;
4595
4596 else elem;
4597 end match;
4598 end stripFuncOutputsMod;
4599
4600 public function checkExternalFunction "
4601 * All in-/outputs are referenced
4602 * There must be no algorithm section (checked earlier)
4603 "
4604 input list<DAE.Element> els;
4605 input DAE.ExternalDecl decl;
4606 input String name;
4607 algorithm
4608
3/4
✓ Branch 0 taken 44918 times.
✓ Branch 1 taken 1735 times.
✓ Branch 3 taken 44918 times.
✗ Branch 4 not taken.
46653 if decl.language == "builtin" then
4609 44918 return;
4610 end if;
4611 1735 List.map2_0(els,checkExternalFunctionOutputAssigned,decl,name);
4612 1735 checkFunctionInputUsed(els,SOME(decl),name);
4613 end checkExternalFunction;
4614
4615 public function checkFunctionInputUsed
4616 input list<DAE.Element> elts;
4617 input Option<DAE.ExternalDecl> decl;
4618 input String name;
4619 protected
4620 list<DAE.Element> invars,vars,algs;
4621 algorithm
4622 1735 (vars,_,_,_,algs,_,_,_,_) := DAEUtil.splitElements(elts);
4623 1735 invars := List.filterOnTrue(vars,DAEUtil.isInputVar);
4624 1735 invars := List.select(invars,checkInputUsedAnnotation);
4625 1735 invars := checkExternalDeclInputUsed(invars,decl);
4626 1735 invars := List.select1(invars,checkVarBindingsInputUsed,vars);
4627 1735 (_,(_,invars)) := DAEUtil.traverseDAEElementList(algs,Expression.traverseSubexpressionsHelper,(checkExpInputUsed,invars));
4628 1735 List.map1_0(invars,warnUnusedFunctionVar,name);
4629 end checkFunctionInputUsed;
4630
4631 public function checkInputUsedAnnotation "
4632 True if __OpenModelica_UnusedVariable does not exist in the element.
4633 "
4634 input DAE.Element inElement;
4635 output Boolean result;
4636 algorithm
4637 result := match inElement
4638 local
4639 Option<SCode.Comment> cmt;
4640 case DAE.VAR(comment = cmt)
4641 algorithm
4642 3329 result := SCodeUtil.optCommentHasBooleanNamedAnnotation(cmt, "__OpenModelica_UnusedVariable");
4643 3329 then not result;
4644 else true;
4645 end match;
4646 end checkInputUsedAnnotation;
4647
4648 protected function warnUnusedFunctionVar
4649 input DAE.Element v;
4650 input String name;
4651 protected
4652 DAE.ComponentRef cr;
4653 DAE.ElementSource source;
4654 String str;
4655 algorithm
4656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 DAE.VAR(componentRef=cr,source=source) := v;
4657 2 str := ComponentReferenceBasics.printComponentRefStr(cr);
4658 2 Error.addSourceMessage(Error.FUNCTION_UNUSED_INPUT,{str,name},ElementSource.getElementSourceFileInfo(source));
4659 end warnUnusedFunctionVar;
4660
4661 protected function checkExternalDeclInputUsed
4662 input list<DAE.Element> inames;
4663 input Option<DAE.ExternalDecl> decl;
4664 output list<DAE.Element> onames;
4665 algorithm
4666 onames := match (inames,decl)
4667 local
4668 list<DAE.ExtArg> args;
4669 DAE.ExtArg arg;
4670 list<DAE.Element> names;
4671 case (names,NONE()) then names;
4672 case ({},_) then {};
4673 case (names,SOME(DAE.EXTERNALDECL(returnArg=arg,args=args)))
4674 algorithm
4675 1578 names := List.select1(names,checkExternalDeclArgs,arg::args);
4676 then names;
4677 end match;
4678 end checkExternalDeclInputUsed;
4679
4680 protected function checkExpInputUsed
4681 input DAE.Exp inExp;
4682 input list<DAE.Element> inEls;
4683 output DAE.Exp exp;
4684 output list<DAE.Element> els;
4685 algorithm
4686 (exp,els) := matchcontinue (inExp,inEls)
4687 local
4688 DAE.ComponentRef cr;
4689 Absyn.Path path;
4690 case (exp as DAE.CREF(componentRef=cr),els)
4691 algorithm
4692 ✗ els := List.select1(els,checkExpInputUsed3,cr);
4693 then (exp,els);
4694 case (exp as DAE.CALL(path=path),els)
4695 algorithm
4696 ✗ true := Config.acceptMetaModelicaGrammar();
4697 ✗ cr := ComponentReference.pathToCref(path);
4698 ✗ els := List.select1(els,checkExpInputUsed3,cr);
4699 then (exp,els);
4700 else (inExp,inEls);
4701 end matchcontinue;
4702 end checkExpInputUsed;
4703
4704 protected function checkExpInputUsed3
4705 input DAE.Element el;
4706 input DAE.ComponentRef cr2;
4707 output Boolean noteq;
4708 protected
4709 DAE.ComponentRef cr1;
4710 algorithm
4711 ✗ DAE.VAR(componentRef=cr1) := el;
4712 ✗ noteq := not ComponentReferenceBasics.crefEqualNoStringCompare(cr1,cr2);
4713 end checkExpInputUsed3;
4714
4715 protected function checkVarBindingsInputUsed
4716 input DAE.Element v;
4717 input list<DAE.Element> els;
4718 output Boolean notfound;
4719 algorithm
4720 65 notfound := not List.isMemberOnTrue(v,els,checkVarBindingInputUsed);
4721 end checkVarBindingsInputUsed;
4722
4723 protected function checkVarBindingInputUsed
4724 input DAE.Element v;
4725 input DAE.Element el;
4726 output Boolean found;
4727 algorithm
4728 found := match (v,el)
4729 local
4730 DAE.Exp exp;
4731 DAE.ComponentRef cr;
4732 case (DAE.VAR(),DAE.VAR(direction=DAE.INPUT())) then false;
4733 71 case (DAE.VAR(componentRef=cr),DAE.VAR(binding=SOME(exp))) then Expression.expHasCref(exp,cr);
4734 else false;
4735 end match;
4736 end checkVarBindingInputUsed;
4737
4738 protected function checkExternalDeclArgs
4739 input DAE.Element v;
4740 input list<DAE.ExtArg> args;
4741 output Boolean notfound;
4742 algorithm
4743 3325 notfound := not List.isMemberOnTrue(v,args,extArgCrefEq);
4744 end checkExternalDeclArgs;
4745
4746 protected function checkExternalFunctionOutputAssigned
4747 "All outputs must either have a default binding or be used in the external function
4748 declaration as there is no way to make assignments in external functions."
4749 input DAE.Element v;
4750 input DAE.ExternalDecl decl;
4751 input String name;
4752 algorithm
4753 () := match (v, decl)
4754 local
4755 DAE.ExtArg arg;
4756 list<DAE.ExtArg> args;
4757 Option<DAE.Exp> binding;
4758 String str;
4759 DAE.ComponentRef cr;
4760 DAE.ElementSource source;
4761 case (DAE.VAR(direction=DAE.OUTPUT(),componentRef=cr,binding=binding,source=source), DAE.EXTERNALDECL(returnArg=arg,args=args))
4762 algorithm
4763 // Some weird functions pass the same output twice so we cannot check for exactly 1 occurance
4764 // Interfacing with LAPACK routines is fun, fun, fun :)
4765
4/6
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1096 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 86 times.
1182 if not (List.isMemberOnTrue(v,arg::args,extArgCrefEq) or isSome(binding)) then
4766 ✗ str := ComponentReferenceBasics.printComponentRefStr(cr);
4767 ✗ Error.addSourceMessage(Error.EXTERNAL_NOT_SINGLE_RESULT,{str,name},ElementSource.getElementSourceFileInfo(source));
4768 ✗ fail();
4769 end if;
4770 then ();
4771 else ();
4772 end match;
4773 end checkExternalFunctionOutputAssigned;
4774
4775 protected function extArgCrefEq
4776 "See if an external argument matches a cref"
4777 input DAE.Element v;
4778 input DAE.ExtArg arg;
4779 output Boolean b;
4780 algorithm
4781 b := match (v,arg)
4782 local
4783 DAE.ComponentRef cr1,cr2;
4784 DAE.Exp exp;
4785
4786 case (DAE.VAR(componentRef=cr1), DAE.EXTARG(componentRef=cr2))
4787 algorithm
4788 // If the external argument refers to a record member, i.e. a qualified
4789 // cref, consider the whole record to be used.
4790 10881 cr2 := ComponentReferenceBasics.crefFirstCref(cr2);
4791 10881 then
4792 ComponentReferenceBasics.crefEqualNoStringCompare(cr1,cr2);
4793
4794 case (DAE.VAR(direction=DAE.OUTPUT()), _) then false;
4795
4796 case (DAE.VAR(componentRef=cr1), DAE.EXTARGSIZE(componentRef=cr2))
4797 algorithm
4798 574 cr2 := ComponentReferenceBasics.crefFirstCref(cr2);
4799 574 then
4800 ComponentReferenceBasics.crefEqualNoStringCompare(cr1,cr2);
4801
4802 case (DAE.VAR(componentRef=cr1), DAE.EXTARGEXP(exp=exp))
4803 468 then Expression.expHasCref(exp,cr1);
4804
4805 else false;
4806 end match;
4807 end extArgCrefEq;
4808
4809 public function isExtExplicitCall
4810 "If the external function id is present, then a function call must
4811 exist, i.e. explicit call was written in the external clause."
4812 input SCode.ExternalDecl inExternalDecl;
4813 output Boolean isExplicit;
4814 algorithm
4815 isExplicit := match inExternalDecl
4816 case SCode.EXTERNALDECL(funcName = SOME(_)) then true;
4817 else false;
4818 end match;
4819 end isExtExplicitCall;
4820
4821 protected function isInoutVar
4822 "Succeds for Elements that are input or output components"
4823 input SCode.Element inElement;
4824 output Boolean b;
4825 algorithm
4826 ✗ b := isOutputVar(inElement) or isInputVar(inElement);
4827 end isInoutVar;
4828
4829 protected function isOutputVar
4830 "Succeds for element that is output component"
4831 input SCode.Element inElement;
4832 output Boolean b;
4833 algorithm
4834 b := match inElement
4835 case SCode.COMPONENT(attributes = SCode.ATTR(direction = Absyn.OUTPUT())) then true;
4836 else false;
4837 end match;
4838 end isOutputVar;
4839
4840 protected function isInputVar
4841 "Succeds for element that is input component"
4842 input SCode.Element inElement;
4843 output Boolean b;
4844 algorithm
4845 b := match inElement
4846 case SCode.COMPONENT(attributes = SCode.ATTR(direction = Absyn.INPUT())) then true;
4847 else false;
4848 end match;
4849 end isInputVar;
4850
4851 public function instExtGetFname
4852 "Returns the function name of the externally defined function."
4853 input SCode.ExternalDecl inExternalDecl;
4854 input String inIdent;
4855 output String outIdent;
4856 algorithm
4857 outIdent := match (inExternalDecl,inIdent)
4858 local String id,fid;
4859 case (SCode.EXTERNALDECL(funcName = SOME(id)),_) then id;
4860 case (SCode.EXTERNALDECL(funcName = NONE()),fid) then fid;
4861 end match;
4862 end instExtGetFname;
4863
4864 public function instExtGetAnnotation
4865 "author: PA
4866 Return the annotation associated with an external function declaration.
4867 If no annotation is found, check the classpart annotations."
4868 input SCode.ExternalDecl inExternalDecl;
4869 output Option<SCode.Annotation> outAnnotation;
4870 algorithm
4871 outAnnotation := match inExternalDecl
4872 local Option<SCode.Annotation> ann;
4873 case SCode.EXTERNALDECL(annotation_ = ann) then ann;
4874 end match;
4875 end instExtGetAnnotation;
4876
4877 public function instExtGetLang
4878 "Return the implementation language of the external function declaration.
4879 Defaults to \"C\" if no language specified."
4880 input SCode.ExternalDecl inExternalDecl;
4881 output String outString;
4882 algorithm
4883 outString := match inExternalDecl
4884 local String lang;
4885 case SCode.EXTERNALDECL(lang = SOME(lang)) then lang;
4886 case SCode.EXTERNALDECL(lang = NONE()) then "C";
4887 end match;
4888 end instExtGetLang;
4889
4890 protected function elabExpListExt
4891 "Special elabExp for explicit external calls.
4892 This special function calls elabExpExt which handles size builtin
4893 calls specially, and uses the ordinary Static.elab_exp for other
4894 expressions."
4895 input FCore.Cache inCache;
4896 input FCore.Graph inEnv;
4897 input list<Absyn.Exp> inAbsynExpLst;
4898 input Boolean inBoolean;
4899 input DAE.Prefix inPrefix;
4900 input SourceInfo info;
4901 output FCore.Cache outCache;
4902 output list<DAE.Exp> outExpExpLst;
4903 output list<DAE.Properties> outTypesPropertiesLst;
4904 algorithm
4905 (outCache,outExpExpLst,outTypesPropertiesLst):=
4906 match (inCache, inEnv, inAbsynExpLst, inBoolean, inPrefix)
4907 local
4908 Boolean impl;
4909 DAE.Exp exp;
4910 DAE.Properties p;
4911 list<DAE.Exp> exps;
4912 list<DAE.Properties> props;
4913 FCore.Graph env;
4914 Absyn.Exp e;
4915 list<Absyn.Exp> rest;
4916 FCore.Cache cache;
4917 DAE.Prefix pre;
4918 case (cache, _, {}, _, _) then (cache,{},{});
4919 case (cache, env, (e :: rest), impl, pre)
4920 algorithm
4921 25127 (cache,exp,p) := elabExpExt(cache,env, e, impl,pre,info);
4922 25127 (cache,exps,props) := elabExpListExt(cache,env, rest, impl,pre,info);
4923 25127 then
4924 (cache,(exp :: exps),(p :: props));
4925 end match;
4926 end elabExpListExt;
4927
4928 protected function elabExpExt
4929 "author: LS
4930 special elabExp for explicit external calls.
4931 This special function calls elabExpExt which handles size builtin calls
4932 specially, and uses the ordinary Static.elab_exp for other expressions."
4933 input FCore.Cache inCache;
4934 input FCore.Graph inEnv;
4935 input Absyn.Exp inExp;
4936 input Boolean inBoolean;
4937 input DAE.Prefix inPrefix;
4938 input SourceInfo info;
4939 output FCore.Cache outCache;
4940 output DAE.Exp outExp;
4941 output DAE.Properties outProperties;
4942 algorithm
4943 (outCache,outExp,outProperties):=
4944 matchcontinue (inCache, inEnv, inExp, inBoolean, inPrefix)
4945 local
4946 DAE.Exp dimp,arraycrefe,exp,e;
4947 DAE.Properties arraycrprop,prop;
4948 FCore.Graph env;
4949 Absyn.Exp arraycr,dim;
4950 list<Absyn.Exp> args;
4951 Boolean impl;
4952 FCore.Cache cache;
4953 Absyn.Exp absynExp;
4954 DAE.Prefix pre;
4955
4956 // special case for size
4957 case (cache, env, (Absyn.CALL(function_ = Absyn.CREF_IDENT(name = "size"),
4958 functionArgs = Absyn.FUNCTIONARGS(args = {arraycr,dim}))), impl, pre)
4959 algorithm
4960
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
184 (cache,dimp,prop as DAE.PROP(_,_)) := Static.elabExp(cache, env, dim, impl,false,pre,info);
4961 184 (cache, dimp, prop) := Ceval.cevalIfConstant(cache, env, dimp, prop, impl, info);
4962 184 (cache,arraycrefe,arraycrprop) := Static.elabExp(cache, env, arraycr, impl,false,pre,info);
4963 184 (cache,arraycrefe,arraycrprop) := Ceval.cevalIfConstant(cache, env, arraycrefe, arraycrprop, impl, info);
4964 184 exp := DAE.SIZE(arraycrefe,SOME(dimp));
4965 184 then
4966 (cache,exp,DAE.PROP(DAE.T_INTEGER_DEFAULT,DAE.C_VAR()));
4967 // For all other expressions, use normal elaboration
4968 case (cache, env, absynExp, impl, pre)
4969 algorithm
4970 24943 (cache,e,prop) := Static.elabExp(cache, env, absynExp, impl,false,pre,info);
4971 24943 (cache, e, prop) := Ceval.cevalIfConstant(cache, env, e, prop, impl, info);
4972 then
4973 (cache,e,prop);
4974 else
4975 algorithm
4976 ✗ true := Flags.isSet(Flags.FAILTRACE);
4977 ✗ Debug.traceln("-Inst.elabExpExt failed");
4978 ✗ then
4979 fail();
4980 end matchcontinue;
4981 end elabExpExt;
4982
4983 public function instExtGetFargs
4984 "author: LS
4985 instantiates function arguments, i.e. actual parameters, in external declaration."
4986 input FCore.Cache inCache;
4987 input FCore.Graph inEnv;
4988 input SCode.ExternalDecl inExternalDecl;
4989 input Boolean inBoolean;
4990 input DAE.Prefix inPrefix;
4991 input SourceInfo info;
4992 output FCore.Cache outCache;
4993 output list<DAE.ExtArg> outDAEExtArgLst;
4994 algorithm
4995 (outCache,outDAEExtArgLst) :=
4996 matchcontinue (inCache, inEnv, inExternalDecl, inBoolean, inPrefix)
4997 local
4998 list<DAE.Exp> exps;
4999 list<DAE.Properties> props;
5000 list<DAE.ExtArg> extargs;
5001 FCore.Graph env;
5002 Option<String> lang;
5003 list<Absyn.Exp> absexps;
5004 Boolean impl;
5005 FCore.Cache cache;
5006 DAE.Prefix pre;
5007 case (cache, env, SCode.EXTERNALDECL(lang = lang,args = absexps), impl, pre)
5008 algorithm
5009 17984 (cache,exps,props) := elabExpListExt(cache,env, absexps, impl, pre, info);
5010 17984 (cache,extargs) := instExtGetFargs2(cache, env, absexps, exps, props, lang, info);
5011 then
5012 (cache,extargs);
5013 else
5014 algorithm
5015 ✗ true := Flags.isSet(Flags.FAILTRACE);
5016 ✗ Debug.traceln("- InstUtil.instExtGetFargs failed");
5017 ✗ then
5018 fail();
5019 end matchcontinue;
5020 end instExtGetFargs;
5021
5022 protected function instExtGetFargs2
5023 "author: LS
5024 Helper function to instExtGetFargs"
5025 input FCore.Cache inCache;
5026 input FCore.Graph inEnv;
5027 input list<Absyn.Exp> absynExps;
5028 input list<DAE.Exp> inExpExpLst;
5029 input list<DAE.Properties> inTypesPropertiesLst;
5030 input Option<String> lang;
5031 input SourceInfo info;
5032 output FCore.Cache outCache;
5033 output list<DAE.ExtArg> outDAEExtArgLst;
5034 algorithm
5035 (outCache,outDAEExtArgLst) := match (inCache, inEnv, absynExps, inExpExpLst, inTypesPropertiesLst)
5036 local
5037 list<DAE.ExtArg> extargs;
5038 DAE.ExtArg extarg;
5039 FCore.Graph env;
5040 DAE.Exp e;
5041 list<DAE.Exp> exps;
5042 DAE.Properties p;
5043 list<DAE.Properties> props;
5044 FCore.Cache cache;
5045 Absyn.Exp ae;
5046 list<Absyn.Exp> aes;
5047 case (cache, _, _, {}, _) then (cache,{});
5048 case (cache, env, ae :: aes, e :: exps, p :: props)
5049 algorithm
5050
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 25127 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25127 times.
25127 (cache,SOME(extarg)) := instExtGetFargsSingle(cache, env, ae, e, p, lang, info);
5051 25127 (cache,extargs) := instExtGetFargs2(cache, env, aes, exps, props, lang, info);
5052 25127 then
5053 (cache,extarg :: extargs);
5054 end match;
5055 end instExtGetFargs2;
5056
5057 protected function instExtGetFargsSingle
5058 "author: LS
5059 Helper function to instExtGetFargs2, does the work for one argument."
5060 input FCore.Cache inCache;
5061 input FCore.Graph inEnv;
5062 input Absyn.Exp absynExp;
5063 input DAE.Exp inExp;
5064 input DAE.Properties inProperties;
5065 input Option<String> lang;
5066 input SourceInfo info;
5067 output FCore.Cache outCache;
5068 output Option<DAE.ExtArg> outExtArg;
5069 algorithm
5070 (outCache,outExtArg) := matchcontinue (inCache, inEnv, absynExp, inExp, inProperties, lang)
5071 local
5072 DAE.Attributes attr, fattr;
5073 DAE.Type ty,varty;
5074 FCore.Graph env;
5075 DAE.ComponentRef cref, fcr;
5076 String crefstr,scope;
5077 DAE.Exp dim,exp;
5078 FCore.Cache cache;
5079 String str;
5080
5081 case (_, _, _, DAE.CREF(componentRef = cref as DAE.CREF_QUAL()), DAE.PROP(constFlag = DAE.C_VAR()), _)
5082 algorithm
5083 12 (cache,_, ty,_, _, _, _, _, _) := Lookup.lookupVarLocal(inCache, inEnv, cref);
5084 // For qualified crefs, copy input/output from the first part of the
5085 // cref. This is done so that the correct code can be generated when
5086 // using qualified crefs in external function definitions.
5087 12 fcr := ComponentReferenceBasics.crefFirstCref(cref);
5088 12 (cache, fattr, _, _, _, _, _, _, _) := Lookup.lookupVarLocal(cache, inEnv, fcr);
5089 12 then
5090 (cache, SOME(DAE.EXTARG(cref, DAEUtil.getAttrDirection(fattr), ty)));
5091
5092 case (_, _, _, DAE.CREF(componentRef = cref as DAE.CREF_IDENT()), DAE.PROP(constFlag = DAE.C_VAR()), _)
5093 algorithm
5094 39316 (cache, attr, ty,_, _, _, _, _, _) := Lookup.lookupVarLocal(inCache, inEnv, cref);
5095 39316 then
5096 (cache,SOME(DAE.EXTARG(cref, DAEUtil.getAttrDirection(attr), ty)));
5097
5098 case (cache, env, _, DAE.CREF(componentRef = cref), DAE.PROP(), _)
5099 algorithm
5100
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 failure(Lookup.lookupVarLocal(cache,env,cref));
5101 ✗ crefstr := ComponentReferenceBasics.printComponentRefStr(cref);
5102 ✗ scope := FGraph.printGraphPathStr(env);
5103 ✗ Error.addMessage(Error.LOOKUP_VARIABLE_ERROR, {crefstr,scope});
5104 ✗ then
5105 (cache, NONE());
5106
5107 case (cache, env, _, DAE.SIZE(exp = DAE.CREF(componentRef = cref),sz = SOME(dim)), DAE.PROP(), _)
5108 algorithm
5109 184 (cache,_,varty,_,_,_,_,_,_) := Lookup.lookupVarLocal(cache,env, cref);
5110 184 then
5111 (cache,SOME(DAE.EXTARGSIZE(cref,varty,dim)));
5112
5113 // adrpo: these can be non-local if they are constants or parameters!
5114 case (cache, env, _, _, DAE.PROP(type_ = ty,constFlag = DAE.C_CONST()), _)
5115 algorithm
5116 468 (cache, exp) := Ceval.cevalIfConstant(cache, env, inExp, inProperties, false, info);
5117
2/2
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 12 times.
468 true := Expression.isScalarConst(exp);
5118 12 then
5119 (cache,SOME(DAE.EXTARGEXP(exp, ty)));
5120
5121 case (cache, _, _, _, DAE.PROP(type_ = ty), SOME("builtin"))
5122 230 then (cache,SOME(DAE.EXTARGEXP(inExp, ty)));
5123
5124 case (cache, _, _, DAE.CALL(attr = DAE.CALL_ATTR(builtin = true)), DAE.PROP(type_ = ty), _)
5125 732 then (cache,SOME(DAE.EXTARGEXP(inExp, ty)));
5126
5127 case (cache, _, Absyn.CREF(_), _, DAE.PROP(type_ = ty), _)
5128 ✗ then (cache,SOME(DAE.EXTARGEXP(inExp, ty)));
5129
5130 case (cache, _, _, exp, DAE.PROP(), _)
5131 algorithm
5132 ✗ str := ExpressionBasics.printExpStr(exp);
5133 ✗ Error.addSourceMessage(Error.EXTERNAL_ARG_WRONG_EXP,{str},info);
5134 ✗ then
5135 (cache, NONE());
5136
5137 end matchcontinue;
5138 end instExtGetFargsSingle;
5139
5140 public function instExtGetRettype
5141 "author: LS
5142 Instantiates the return type of an external declaration."
5143 input FCore.Cache inCache;
5144 input FCore.Graph inEnv;
5145 input SCode.ExternalDecl inExternalDecl;
5146 input Boolean inBoolean;
5147 input DAE.Prefix inPrefix;
5148 input SourceInfo info;
5149 output FCore.Cache outCache;
5150 output DAE.ExtArg outExtArg;
5151 algorithm
5152 (outCache,outExtArg) := matchcontinue (inCache, inEnv, inExternalDecl, inBoolean, inPrefix)
5153 local
5154 DAE.Exp exp;
5155 DAE.Properties prop;
5156 DAE.ExtArg extarg;
5157 FCore.Graph env;
5158 Option<String> lang;
5159 Absyn.ComponentRef cref;
5160 Boolean impl;
5161 FCore.Cache cache;
5162 DAE.Prefix pre;
5163
5164 case (cache, _, SCode.EXTERNALDECL(output_ = NONE()), _, _) then (cache,DAE.NOEXTARG()); /* impl */
5165
5166 case (cache, env, SCode.EXTERNALDECL(lang = lang,output_ = SOME(cref)), impl, pre)
5167 algorithm
5168
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 15359 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15359 times.
15359 (cache,SOME((exp,prop,_))) := Static.elabCref(cache,env,cref,impl,false /* Do NOT vectorize arrays; we require a CREF */,pre,info);
5169
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 15359 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15359 times.
15359 (cache,SOME(extarg)) := instExtGetFargsSingle(cache,env,Absyn.CREF(cref),exp,prop,lang,info);
5170 15359 assertExtArgOutputIsCrefVariable(lang,extarg,Types.getPropType(prop),Types.propAllConst(prop),info);
5171 then
5172 (cache,extarg);
5173
5174 else
5175 algorithm
5176
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 true := Flags.isSet(Flags.FAILTRACE);
5177 ✗ Debug.traceln("- InstUtil.instExtRettype failed");
5178 ✗ then
5179 fail();
5180 end matchcontinue;
5181 end instExtGetRettype;
5182
5183 protected function assertExtArgOutputIsCrefVariable
5184 input Option<String> lang;
5185 input DAE.ExtArg arg;
5186 input DAE.Type ty;
5187 input DAE.Const c;
5188 input SourceInfo info;
5189 algorithm
5190 () := match (lang, arg, ty, c)
5191 local
5192 String str;
5193 case (SOME("builtin"), _, _, _) then ();
5194 case (_, _, DAE.T_ARRAY(), _)
5195 algorithm
5196 14 str := TypesDump.unparseType(ty);
5197 14 Error.addSourceMessage(Error.EXTERNAL_FUNCTION_RESULT_ARRAY_TYPE,{str},info);
5198 14 then fail();
5199 case (_, DAE.EXTARG(), _, DAE.C_VAR()) then ();
5200 case (_, _, _, DAE.C_VAR())
5201 algorithm
5202 ✗ str := DAEDump.dumpExtArgStr(arg);
5203 ✗ Error.addSourceMessage(Error.EXTERNAL_FUNCTION_RESULT_NOT_CREF,{str},info);
5204 ✗ then fail();
5205 else
5206 algorithm
5207 ✗ Error.addSourceMessage(Error.EXTERNAL_FUNCTION_RESULT_NOT_VAR,{},info);
5208 ✗ then fail();
5209 end match;
5210 end assertExtArgOutputIsCrefVariable;
5211
5212 public function makeDaeProt
5213 "Creates a DAE.VarVisibility from a SCode.Visibility"
5214 input SCode.Visibility visibility;
5215 output DAE.VarVisibility res;
5216 algorithm
5217 res := match visibility
5218 case SCode.PROTECTED() then DAE.PROTECTED();
5219 case SCode.PUBLIC() then DAE.PUBLIC();
5220 end match;
5221 end makeDaeProt;
5222
5223 public function makeDaeVariability
5224 input SCode.Variability inVariability;
5225 output DAE.VarKind outVariability;
5226 algorithm
5227 outVariability := match inVariability
5228 case SCode.VAR() then DAE.VARIABLE();
5229 case SCode.PARAM() then DAE.PARAM();
5230 case SCode.CONST() then DAE.CONST();
5231 case SCode.DISCRETE() then DAE.DISCRETE();
5232 end match;
5233 end makeDaeVariability;
5234
5235 public function makeDaeDirection
5236 input Absyn.Direction inDirection;
5237 output DAE.VarDirection outDirection;
5238 algorithm
5239 outDirection := match inDirection
5240 case Absyn.INPUT() then DAE.INPUT();
5241 case Absyn.OUTPUT() then DAE.OUTPUT();
5242 case Absyn.BIDIR() then DAE.BIDIR();
5243 end match;
5244 end makeDaeDirection;
5245
5246 public function mktype
5247 "From a class typename, its inference state, and a list of subcomponents,
5248 this function returns DAE.Type. If the class inference state
5249 indicates that the type should be a built-in type, one of the
5250 built-in type constructors is used. Otherwise, a T_COMPLEX is
5251 built."
5252 input Absyn.Path inPath;
5253 input ClassInf.State inState;
5254 input list<DAE.Var> inTypesVarLst;
5255 input Option<DAE.Type> inTypesTypeOption;
5256 input DAE.EqualityConstraint inEqualityConstraint;
5257 input SCode.Element inClass;
5258 input SCode.Comment inheritedComment;
5259 output DAE.Type outType;
5260 algorithm
5261 outType := matchcontinue (inPath,inState,inTypesVarLst,inTypesTypeOption,inEqualityConstraint,inClass)
5262 local
5263 Absyn.Path p;
5264 list<DAE.Var> v,vl,l;
5265 DAE.Type bc2,functype,enumtype;
5266 ClassInf.State st;
5267 DAE.Type bc;
5268 SCode.Element cl;
5269 DAE.Type arrayType;
5270 DAE.Type resType;
5271 ClassInf.State classState;
5272 DAE.EqualityConstraint equalityConstraint;
5273 DAE.FunctionAttributes funcattr;
5274 String pstr;
5275 SourceInfo info;
5276
5277 case (_,ClassInf.TYPE_INTEGER(),v,_,_,_)
5278 46048 then DAE.T_INTEGER(v);
5279
5280 case (_,ClassInf.TYPE_REAL(),v,_,_,_)
5281 445209 then DAE.T_REAL(v);
5282
5283 case (_,ClassInf.TYPE_STRING(),v,_,_,_)
5284 76781 then DAE.T_STRING(v);
5285
5286 case (_,ClassInf.TYPE_BOOL(),v,_,_,_)
5287 67771 then DAE.T_BOOL(v);
5288
5289 // BTH
5290 case (_,ClassInf.TYPE_CLOCK(),v,_,_,_)
5291 166 then DAE.T_CLOCK(v);
5292
5293 case (p,ClassInf.TYPE_ENUM(),_,_,_,_)
5294 24056 then DAE.T_ENUMERATION(NONE(), p, {}, {}, {});
5295
5296 // Insert function type construction here after checking input/output arguments? see Types.mo T_FUNCTION
5297 case (p,(ClassInf.FUNCTION()),vl,_,_,cl)
5298 algorithm
5299 69216 funcattr := getFunctionAttributes(cl, vl, inheritedComment);
5300 69216 functype := Types.makeFunctionType(p, vl, funcattr);
5301 then
5302 functype;
5303
5304 case (_, ClassInf.ENUMERATION(path = p), _, SOME(enumtype), _, _)
5305 algorithm
5306 7599 enumtype := Types.makeEnumerationType(p, enumtype);
5307 then
5308 enumtype;
5309
5310 // Array of type extending from base type, adrpo: WITH NO EQUALITY CONSTRAINT, otherwise we loose it!
5311 case (_, ClassInf.TYPE(), _, SOME(DAE.T_ARRAY(ty = arrayType)), NONE(), _)
5312 algorithm
5313 204 classState := arrayTTypeToClassInfState(arrayType);
5314 204 resType := mktype(inPath, classState, inTypesVarLst, inTypesTypeOption, inEqualityConstraint, inClass, inheritedComment);
5315 then
5316 resType;
5317
5318 // Array of type extending from base type, adrpo: WITH EQUALITY CONSTRAINT, build a T_SUBTYPE_BASIC
5319 case (_, ClassInf.TYPE(), _, SOME(DAE.T_ARRAY(ty = arrayType)), SOME(_), _)
5320 algorithm
5321 ✗ classState := arrayTTypeToClassInfState(arrayType);
5322 ✗ resType := mktype(inPath, classState, inTypesVarLst, inTypesTypeOption, inEqualityConstraint, inClass, inheritedComment);
5323 ✗ resType := DAE.T_SUBTYPE_BASIC(inState,{},resType,inEqualityConstraint);
5324 then
5325 resType;
5326
5327 /* MetaModelica extension */
5328 case (_,ClassInf.META_TUPLE(_),_,SOME(bc2),_,_) then bc2;
5329 case (_,ClassInf.META_OPTION(_),_,SOME(bc2),_,_) then bc2;
5330 case (_,ClassInf.META_LIST(_),_,SOME(bc2),_,_) then bc2;
5331 case (_,ClassInf.META_POLYMORPHIC(_),_,SOME(bc2),_,_) then bc2;
5332 case (_,ClassInf.META_ARRAY(_),_,SOME(bc2),_,_) then bc2;
5333 case (_,ClassInf.META_UNIONTYPE(_),_,SOME(bc2),_,_) then bc2;
5334 case (p,ClassInf.META_UNIONTYPE(_),_,_,_,_)
5335 algorithm
5336 ✗ pstr := AbsynUtil.pathString(p);
5337 ✗ info := SCodeUtil.elementInfo(inClass);
5338 ✗ Error.addSourceMessage(Error.META_UNIONTYPE_ALIAS_MODS, {pstr}, info);
5339 ✗ then fail();
5340 /*------------------------*/
5341
5342 // not extending
5343 case (_,st,l,NONE(),equalityConstraint,_)
5344 algorithm
5345
2/4
✓ Branch 0 taken 54482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54482 times.
✗ Branch 3 not taken.
54482 failure(ClassInf.META_UNIONTYPE(_) := st);
5346 54482 then DAE.T_COMPLEX(st,l,equalityConstraint, true);
5347
5348 // extending
5349 case (_,st,l,SOME(bc),equalityConstraint,_)
5350 algorithm
5351
2/4
✓ Branch 0 taken 5412 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5412 times.
✗ Branch 3 not taken.
5412 failure(ClassInf.META_UNIONTYPE(_) := st);
5352 5412 then DAE.T_SUBTYPE_BASIC(st,l,bc,equalityConstraint);
5353 end matchcontinue;
5354 end mktype;
5355
5356 protected function arrayTTypeToClassInfState
5357 input DAE.Type arrayType;
5358 output ClassInf.State classInfState;
5359 algorithm
5360 classInfState := match arrayType
5361 local
5362 DAE.Type t;
5363 ClassInf.State cs;
5364
5365 case DAE.T_INTEGER() then ClassInf.TYPE_INTEGER(Absyn.IDENT(""));
5366 case DAE.T_REAL() then ClassInf.TYPE_REAL(Absyn.IDENT(""));
5367 case DAE.T_STRING() then ClassInf.TYPE_STRING(Absyn.IDENT(""));
5368 case DAE.T_BOOL() then ClassInf.TYPE_BOOL(Absyn.IDENT(""));
5369 // BTH FIXME Dont understand for what this function is good to. Just adding clock anyway
5370 case DAE.T_CLOCK() then ClassInf.TYPE_CLOCK(Absyn.IDENT(""));
5371 case DAE.T_ARRAY(ty = t)
5372 algorithm
5373 ✗ cs := arrayTTypeToClassInfState(t);
5374 then cs;
5375 end match;
5376 end arrayTTypeToClassInfState;
5377
5378 public function mktypeWithArrays
5379 "author: PA
5380 This function is similar to mktype with the exception
5381 that it will create array types based on the last argument,
5382 which indicates wheter the class extends from a basictype.
5383 It is used only in the inst_class_basictype function."
5384 input Absyn.Path inPath;
5385 input ClassInf.State inState;
5386 input list<DAE.Var> inTypesVarLst;
5387 input Option<DAE.Type> inTypesTypeOption;
5388 input SCode.Element inClass;
5389 input SCode.Comment inheritedComment;
5390 output DAE.Type outType;
5391 algorithm
5392 outType := matchcontinue (inPath,inState,inTypesVarLst,inTypesTypeOption,inClass)
5393 local
5394 Absyn.Path p;
5395 ClassInf.State ci,st;
5396 list<DAE.Var> v,vl,l;
5397 DAE.Type tp,functype,enumtype;
5398 SCode.Element cl;
5399 DAE.Type bc;
5400 DAE.FunctionAttributes funcattr;
5401
5402 case (_,ci,_,SOME(tp),_)
5403 algorithm
5404
2/2
✓ Branch 1 taken 3839 times.
✓ Branch 2 taken 245 times.
4084 true := Types.isArray(tp);
5405
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 245 times.
490 failure(ClassInfUtil.isConnector(ci));
5406 245 then
5407 tp;
5408
5409 case (p,ClassInf.TYPE_INTEGER(),v,_,_)
5410 algorithm
5411 5 getOptPath(p);
5412 5 then DAE.T_INTEGER(v);
5413
5414 case (_,ClassInf.TYPE_REAL(),v,_,_)
5415 2580 then DAE.T_REAL(v);
5416
5417 case (_,ClassInf.TYPE_STRING(),v,_,_)
5418 1249 then DAE.T_STRING(v);
5419
5420 case (_,ClassInf.TYPE_BOOL(),v,_,_)
5421 ✗ then DAE.T_BOOL(v);
5422
5423 // BTH
5424 case (_,ClassInf.TYPE_CLOCK(),v,_,_)
5425 ✗ then DAE.T_CLOCK(v);
5426
5427 case (p,ClassInf.TYPE_ENUM(),_,_,_)
5428 ✗ then DAE.T_ENUMERATION(NONE(), p,{},{},{});
5429
5430 // Insert function type construction here after checking input/output arguments? see Types.mo T_FUNCTION
5431 case (p,(ClassInf.FUNCTION()),vl,_,cl)
5432 algorithm
5433 ✗ funcattr := getFunctionAttributes(cl,vl,inheritedComment);
5434 ✗ functype := Types.makeFunctionType(p, vl, funcattr);
5435 then
5436 functype;
5437
5438 case (p, ClassInf.ENUMERATION(), _, SOME(enumtype), _)
5439 algorithm
5440 ✗ enumtype := Types.makeEnumerationType(p, enumtype);
5441 then
5442 enumtype;
5443
5444 // not extending basic type!
5445 case (_,st,l,NONE(),_)
5446 125 then DAE.T_COMPLEX(st,l,NONE(), true); // adrpo: TODO! check equalityConstraint!
5447
5448 case (_,st,l,SOME(bc),_)
5449 5 then DAE.T_SUBTYPE_BASIC(st,l,bc,NONE());
5450
5451 else
5452 algorithm
5453 ✗ print("InstUtil.mktypeWithArrays failed\n");
5454 ✗ then fail();
5455
5456 end matchcontinue;
5457 end mktypeWithArrays;
5458
5459 protected function getOptPath
5460 "Helper function to mktype
5461 Transforms a Path into a Path option."
5462 input Absyn.Path inPath;
5463 output Option<Absyn.Path> outAbsynPathOption;
5464 algorithm
5465 outAbsynPathOption := match inPath
5466 local Absyn.Path p;
5467 case Absyn.IDENT(name = "") then NONE();
5468 case p then SOME(p);
5469 end match;
5470 end getOptPath;
5471
5472 protected function checkProt
5473 "This function is used to check that a
5474 protected element is not modified."
5475 input SCode.Visibility inVisibility;
5476 input DAE.Mod inMod;
5477 input DAE.ComponentRef inComponentRef;
5478 input SourceInfo info;
5479 algorithm
5480 () := match (inVisibility, inMod, inComponentRef)
5481 local
5482 DAE.ComponentRef cref;
5483 String str1, str2;
5484 case (SCode.PUBLIC(), _, _) then ();
5485 case (_, DAE.NOMOD(), _) then ();
5486 case (_, DAE.MOD(_, _, {}, NONE()), _) then ();
5487 case (SCode.PROTECTED(), _, cref)
5488 algorithm
5489 ✗ str1 := ComponentReferenceBasics.printComponentRefStr(cref);
5490 ✗ str2 := Mod.prettyPrintMod(inMod, 0);
5491 ✗ Error.addSourceMessage(Error.MODIFY_PROTECTED, {str1, str2}, info);
5492 then
5493 ();
5494 end match;
5495 end checkProt;
5496
5497 public function getStateSelectFromExpOption
5498 "author: LP
5499 Retrieves the stateSelect value, as defined in DAE, from an Expression option."
5500 input Option<DAE.Exp> inExpExpOption;
5501 output Option<DAE.StateSelect> outDAEStateSelectOption;
5502 algorithm
5503 outDAEStateSelectOption:=
5504 match inExpExpOption
5505 case SOME(DAE.ENUM_LITERAL(name = Absyn.QUALIFIED(name = "StateSelect", path = Absyn.IDENT("never")))) then SOME(DAE.NEVER());
5506 case SOME(DAE.ENUM_LITERAL(name = Absyn.QUALIFIED(name = "StateSelect", path = Absyn.IDENT("avoid")))) then SOME(DAE.AVOID());
5507 case SOME(DAE.ENUM_LITERAL(name = Absyn.QUALIFIED(name = "StateSelect", path = Absyn.IDENT("default")))) then SOME(DAE.DEFAULT());
5508 case SOME(DAE.ENUM_LITERAL(name = Absyn.QUALIFIED(name = "StateSelect", path = Absyn.IDENT("prefer")))) then SOME(DAE.PREFER());
5509 case SOME(DAE.ENUM_LITERAL(name = Absyn.QUALIFIED(name = "StateSelect", path = Absyn.IDENT("always")))) then SOME(DAE.ALWAYS());
5510 else NONE();
5511 end match;
5512 end getStateSelectFromExpOption;
5513
5514 public function isSubModNamed
5515 "Returns true if the given submod is a namemod with the same name as the given
5516 name, otherwise false."
5517 input String inName;
5518 input DAE.SubMod inSubMod;
5519 output Boolean isNamed;
5520 algorithm
5521 isNamed := match inSubMod
5522 local
5523 String submod_name;
5524
5525 case DAE.NAMEMOD(ident = submod_name)
5526
4/4
✓ Branch 0 taken 25587 times.
✓ Branch 1 taken 573 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 25565 times.
26160 then stringEqual(inName, submod_name);
5527
5528 else false;
5529 end match;
5530 end isSubModNamed;
5531
5532 public function liftRecordBinding
5533 "If the type is an array type this function creates an array of the given
5534 record, otherwise it just returns the input arguments."
5535 input DAE.Type inType;
5536 input DAE.Exp inExp;
5537 input Values.Value inValue;
5538 output DAE.Exp outExp;
5539 output Values.Value outValue;
5540 algorithm
5541 (outExp, outValue) := matchcontinue inType
5542 local
5543 DAE.Dimension dim;
5544 DAE.Type ty;
5545 DAE.Exp exp;
5546 Values.Value val;
5547 DAE.Type ety;
5548 Integer int_dim;
5549 list<DAE.Exp> expl;
5550 list<Values.Value> vals;
5551
5552 case DAE.T_ARRAY(dims = {dim}, ty = ty)
5553 algorithm
5554 20 int_dim := Expression.dimensionSize(dim);
5555 20 (exp, val) := liftRecordBinding(ty, inExp, inValue);
5556 20 ety := Types.simplifyType(inType);
5557 20 expl := List.fill(exp, int_dim);
5558 20 vals := List.fill(val, int_dim);
5559 20 exp := DAE.ARRAY(ety, true, expl);
5560 20 val := Values.ARRAY(vals, {int_dim});
5561 then
5562 (exp, val);
5563
5564 else
5565 algorithm
5566
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4051 times.
4051 false := Types.isArray(inType);
5567 then
5568 (inExp, inValue);
5569 end matchcontinue;
5570 end liftRecordBinding;
5571
5572 public function isTopCall
5573 "author: PA
5574 The topmost instantiation call is treated specially with for instance unconnected connectors.
5575 This function returns true if the CallingScope indicates the top call."
5576 input InstTypes.CallingScope inCallingScope;
5577 output Boolean outBoolean;
5578 algorithm
5579 outBoolean:=
5580 match inCallingScope
5581 case InstTypes.TOP_CALL() then true;
5582 else false;
5583 end match;
5584 end isTopCall;
5585
5586 public function extractCurrentName
5587 " Extracts SCode.Element name."
5588 input SCode.Element sele;
5589 output String ostring;
5590 output SourceInfo oinfo;
5591 algorithm
5592 (ostring ,oinfo) := match sele
5593 local
5594 Absyn.Path path;
5595 String name,ret;
5596 Absyn.Import imp;
5597 SourceInfo info;
5598
5599 case SCode.CLASS(name = name, info = info) then (name, info);
5600 case SCode.COMPONENT(name = name, info=info) then (name, info);
5601 case SCode.EXTENDS(baseClassPath=path, info = info)
5602 algorithm
5603 ✗ ret := AbsynUtil.pathString(path);
5604 then
5605 (ret, info);
5606 case SCode.IMPORT(imp = imp, info = info)
5607 algorithm
5608 ✗ name := AbsynUtil.printImportString(imp);
5609 then
5610 (name, info);
5611 end match;
5612 end extractCurrentName;
5613
5614 public function reorderConnectEquationsExpandable
5615 "@author: adrpo
5616 Reorder the connect equations to have non-expandable connect first:
5617 connect(non_expandable, non_expandable);
5618 connect(non_expandable, expandable);
5619 connect(expandable, non_expandable);
5620 connect(expandable, expandable);"
5621 input output FCore.Cache cache;
5622 input FCore.Graph env;
5623 input list<SCode.Equation> inEquations;
5624 output list<SCode.Equation> outEquations;
5625 protected
5626 DoubleEnded.MutableList<SCode.Equation> delst;
5627 list<SCode.Equation> expandableEqs;
5628 Absyn.ComponentRef crefLeft, crefRight;
5629 DAE.Type ty1,ty2;
5630 algorithm
5631
4/4
✓ Branch 0 taken 3764 times.
✓ Branch 1 taken 156201 times.
✓ Branch 3 taken 1032 times.
✓ Branch 4 taken 2732 times.
159965 if if listEmpty(inEquations) then true else (not System.getHasExpandableConnectors()) then
5632 outEquations := inEquations;
5633 157233 return;
5634 end if;
5635 2732 ErrorExt.setCheckpoint("expandableConnectorsOrder");
5636 2732 delst := DoubleEnded.fromList({});
5637
2/2
✓ Branch 0 taken 15409 times.
✓ Branch 1 taken 2732 times.
18141 expandableEqs := list(
5638 eq
5639 for eq
5640 guard matchcontinue eq
5641 case SCode.EQ_CONNECT(crefLeft=crefLeft, crefRight=crefRight)
5642 algorithm
5643 3748 (_, ty1, _) := Lookup.lookupConnectorVar(env, ComponentReference.toExpCref(crefLeft));
5644 // type of left var is an expandable connector!
5645
2/2
✓ Branch 1 taken 3587 times.
✓ Branch 2 taken 161 times.
3748 true := Types.isExpandableConnector(ty1);
5646 161 (_, ty2, _) := Lookup.lookupConnectorVar(env, ComponentReference.toExpCref(crefRight));
5647 // type of right left var is an expandable connector!
5648
2/2
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 55 times.
161 true := Types.isExpandableConnector(ty2);
5649 then true;
5650 15354 else algorithm DoubleEnded.push_back(delst, eq); then false;
5651 end matchcontinue in inEquations
5652 );
5653
5654
2/2
✓ Branch 0 taken 2712 times.
✓ Branch 1 taken 20 times.
2732 if listEmpty(expandableEqs) then
5655 2712 ErrorExt.delCheckpoint("expandableConnectorsOrder");
5656 outEquations := inEquations; // Just to preserve referenceEq; does not really matter
5657 2712 return;
5658 end if;
5659 20 ErrorExt.rollBack("expandableConnectorsOrder");
5660
5661 // Reorder the connect equations to have non-expandable connect first:
5662 // connect(non_expandable, non_expandable);
5663 // connect(non_expandable, expandable);
5664 // connect(expandable, non_expandable);
5665 // connect(expandable, expandable);
5666
5667 // put expandable at the begining
5668 20 DoubleEnded.push_list_front(delst, expandableEqs);
5669 // put expandable at the end
5670 20 DoubleEnded.push_list_back(delst, expandableEqs);
5671 // duplicate expandable to get the union
5672 () := match expandableEqs
5673 16 case _::_::_ algorithm DoubleEnded.push_list_back(delst, expandableEqs); then (); // > length 1
5674 else ();
5675 end match;
5676
5677 20 outEquations := DoubleEnded.toListAndClear(delst);
5678 end reorderConnectEquationsExpandable;
5679
5680 public function sortInnerFirstTplLstElementMod
5681 "@author: adrpo
5682 This function will move all the *inner*
5683 elements first in the given list of elements"
5684 input list<tuple<SCode.Element, DAE.Mod>> inTplLstElementMod;
5685 output list<tuple<SCode.Element, DAE.Mod>> outTplLstElementMod;
5686 protected
5687 list<tuple<SCode.Element, DAE.Mod>> innerElts, innerouterElts, otherElts, innerModelicaServices, innerModelica, innerOthers;
5688 algorithm
5689 // no sorting if we don't have any inner/outer in the model
5690
2/2
✓ Branch 1 taken 182928 times.
✓ Branch 2 taken 95922 times.
278850 if not System.getHasInnerOuterDefinitions() then
5691 outTplLstElementMod := inTplLstElementMod;
5692 182928 return;
5693 end if;
5694
5695 // split into inner, inner outer and other elements
5696 95922 (innerElts, innerouterElts, otherElts) := splitInnerAndOtherTplLstElementMod(inTplLstElementMod);
5697 // sort the inners to put Modelica types first!
5698 95922 (innerModelicaServices, innerModelica, innerOthers) := splitInners(innerElts, {}, {}, {});
5699
5700 // put the inner elements first
5701 // put the innerouter elements second
5702 95922 outTplLstElementMod := listAppend(innerModelicaServices, listAppend(innerModelica, listAppend(innerOthers, listAppend(innerouterElts, otherElts))));
5703 end sortInnerFirstTplLstElementMod;
5704
5705 protected function splitInners
5706 "@author: adrpo
5707 This function will sort inner into 3 lists:
5708 *inner* ModelicaServices.*
5709 *inner* Modelica.*
5710 *inner* Other.*"
5711 input list<tuple<SCode.Element, DAE.Mod>> inTplLstElementMod;
5712 input list<tuple<SCode.Element, DAE.Mod>> inAcc1;
5713 input list<tuple<SCode.Element, DAE.Mod>> inAcc2;
5714 input list<tuple<SCode.Element, DAE.Mod>> inAcc3;
5715 output list<tuple<SCode.Element, DAE.Mod>> outModelicaServices;
5716 output list<tuple<SCode.Element, DAE.Mod>> outModelica;
5717 output list<tuple<SCode.Element, DAE.Mod>> outOthers;
5718 algorithm
5719 (outModelicaServices, outModelica, outOthers) :=
5720 matchcontinue inTplLstElementMod
5721 local
5722 list<tuple<SCode.Element, DAE.Mod>> rest, acc1, acc2, acc3;
5723 SCode.Element e;
5724 tuple<SCode.Element, DAE.Mod> em;
5725 Absyn.Path p;
5726
5727 case {}
5728 95922 then (listReverse(inAcc1), listReverse(inAcc2), listReverse(inAcc3));
5729
5730 case em::rest
5731 algorithm
5732 40 e := Util.tuple21(em);
5733
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 Absyn.TPATH(p, _) := SCodeUtil.getComponentTypeSpec(e);
5734
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
40 true := stringEq("ModelicaServices", AbsynUtil.pathFirstIdent(p));
5735 ✗ (acc1, acc2, acc3) := splitInners(rest, em::inAcc1, inAcc2, inAcc3);
5736 then
5737 (acc1, acc2, acc3);
5738
5739 case em::rest
5740 algorithm
5741 40 e := Util.tuple21(em);
5742
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 Absyn.TPATH(p, _) := SCodeUtil.getComponentTypeSpec(e);
5743
3/4
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
40 true := stringEq("Modelica", AbsynUtil.pathFirstIdent(p));
5744 25 (acc1, acc2, acc3) := splitInners(rest, inAcc1, em::inAcc2, inAcc3);
5745 then
5746 (acc1, acc2, acc3);
5747
5748 case (em as _)::rest
5749 algorithm
5750 15 (acc1, acc2, acc3) := splitInners(rest, inAcc1, inAcc2, em::inAcc3);
5751 then
5752 (acc1, acc2, acc3);
5753 end matchcontinue;
5754 end splitInners;
5755
5756 public function splitInnerAndOtherTplLstElementMod
5757 "@author: adrpo
5758 Split the elements into inner, inner outer and others"
5759 input list<tuple<SCode.Element, DAE.Mod>> inTplLstElementMod;
5760 output list<tuple<SCode.Element, DAE.Mod>> outInnerTplLstElementMod = {};
5761 output list<tuple<SCode.Element, DAE.Mod>> outInnerOuterTplLstElementMod = {};
5762 output list<tuple<SCode.Element, DAE.Mod>> outOtherTplLstElementMod = {};
5763 protected
5764 SCode.Element comp;
5765 Absyn.InnerOuter io;
5766 algorithm
5767
2/2
✓ Branch 1 taken 424540 times.
✓ Branch 2 taken 95922 times.
520462 for e in listReverse(inTplLstElementMod) loop
5768 424540 (comp, _) := e;
5769
5770 () := match comp
5771 case SCode.COMPONENT(prefixes = SCode.PREFIXES(innerOuter = io))
5772 guard AbsynUtil.isInner(io)
5773 algorithm
5774
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 40 times.
44 if AbsynUtil.isOuter(io) then
5775 // inner outer components.
5776 outInnerOuterTplLstElementMod := e :: outInnerOuterTplLstElementMod;
5777 else
5778 // inner components.
5779 outInnerTplLstElementMod := e :: outInnerTplLstElementMod;
5780 end if;
5781 then
5782 ();
5783
5784 else
5785 algorithm
5786 // any other components.
5787 outOtherTplLstElementMod := e :: outOtherTplLstElementMod;
5788 then
5789 ();
5790 end match;
5791 end for;
5792 end splitInnerAndOtherTplLstElementMod;
5793
5794 public function splitEltsOrderInnerOuter "
5795 This function splits the Element list into four lists
5796 1. Class definitions , imports and defineunits
5797 2. Class-extends class definitions
5798 3. Extends elements
5799 4. Components which are ordered by inner/outer, inner first"
5800 input list<SCode.Element> elts;
5801 output list<SCode.Element> cdefImpElts;
5802 output list<SCode.Element> classextendsElts;
5803 output list<SCode.Element> extElts;
5804 output list<SCode.Element> compElts;
5805 algorithm
5806 (cdefImpElts,classextendsElts,extElts,compElts) := match elts
5807 local
5808 list<SCode.Element> innerComps,otherComps,comps;
5809
5810 case _
5811 algorithm
5812 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(elts);
5813 // put inner elements first in the list of
5814 // elements so they are instantiated first!
5815 ✗ comps := listAppend(innerComps, otherComps);
5816 ✗ then
5817 (cdefImpElts,classextendsElts,extElts,comps);
5818 end match;
5819 end splitEltsOrderInnerOuter;
5820
5821 public function splitElts "
5822 This function splits the Element list into four lists
5823 1. Class definitions , imports and defineunits
5824 2. Class-extends class definitions
5825 3. Extends elements
5826 4. Components"
5827 input list<SCode.Element> elts;
5828 output list<SCode.Element> cdefImpElts={};
5829 output list<SCode.Element> classextendsElts={};
5830 output list<SCode.Element> extElts={};
5831 output list<SCode.Element> compElts={};
5832 algorithm
5833
6/8
✓ Branch 0 taken 8522026 times.
✓ Branch 1 taken 76636 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50347 times.
✓ Branch 4 taken 632497 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9281506 times.
✓ Branch 7 taken 372964 times.
9654470 for elt in elts loop
5834 () := match elt
5835 case SCode.CLASS()
5836 algorithm
5837 if match elt.classDef case SCode.CLASS_EXTENDS() then true; else false; end match then
5838 // class definitions with class extends
5839 classextendsElts := elt :: classextendsElts;
5840 else
5841 // class definitions without class extends
5842 cdefImpElts := elt :: cdefImpElts;
5843 end if;
5844 then ();
5845
5846 // imports
5847 case SCode.IMPORT()
5848 algorithm
5849 cdefImpElts := elt :: cdefImpElts;
5850 then ();
5851
5852 // units
5853 case SCode.DEFINEUNIT()
5854 algorithm
5855 cdefImpElts := elt :: cdefImpElts;
5856 then ();
5857
5858 // extends elements
5859 case SCode.EXTENDS()
5860 algorithm
5861 extElts := elt :: extElts;
5862 then ();
5863
5864 // components
5865 case SCode.COMPONENT()
5866 algorithm
5867 compElts := elt :: compElts;
5868 then ();
5869 end match;
5870 end for;
5871 372964 cdefImpElts := listReverseInPlace(cdefImpElts);
5872 372964 classextendsElts := listReverseInPlace(classextendsElts);
5873 372964 extElts := listReverseInPlace(extElts);
5874 372964 compElts := listReverseInPlace(compElts);
5875 end splitElts;
5876
5877 public function splitEltsNoComponents "
5878 This function splits the Element list into these categories:
5879 1. Imports
5880 2. Define units and class definitions
5881 3. Class-extends class definitions
5882 4. Filtered class extends and imports"
5883 input list<SCode.Element> elts;
5884 output list<SCode.Element> impElts;
5885 output list<SCode.Element> defElts;
5886 output list<SCode.Element> classextendsElts;
5887 output list<SCode.Element> filtered;
5888 algorithm
5889 (impElts,defElts,classextendsElts,filtered) := match elts
5890 local
5891 list<SCode.Element> xs;
5892 SCode.Element elt;
5893
5894 // empty case
5895 case {} then ({},{},{},{});
5896
5897 // class definitions with class extends
5898 case (elt as SCode.CLASS(classDef = SCode.CLASS_EXTENDS()))::xs
5899 algorithm
5900 9877 (impElts,defElts,classextendsElts,filtered) := splitEltsNoComponents(xs);
5901 9877 then
5902 (impElts,defElts,elt::classextendsElts,filtered);
5903
5904 // class definitions without class extends
5905 case (elt as SCode.CLASS()) :: xs
5906 algorithm
5907 61826 (impElts,defElts,classextendsElts,filtered) := splitEltsNoComponents(xs);
5908 61826 then
5909 (impElts,elt::defElts,classextendsElts,elt::filtered);
5910
5911 // imports
5912 case (elt as SCode.IMPORT()) :: xs
5913 algorithm
5914 2 (impElts,defElts,classextendsElts,filtered) := splitEltsNoComponents(xs);
5915 2 then
5916 (elt::impElts,defElts,classextendsElts,filtered);
5917
5918 // units
5919 case (elt as SCode.DEFINEUNIT()) :: xs
5920 algorithm
5921 ✗ (impElts,defElts,classextendsElts,filtered) := splitEltsNoComponents(xs);
5922 ✗ then
5923 (impElts,elt::defElts,classextendsElts,elt::filtered);
5924
5925 // extends and components elements
5926 case elt::xs
5927 algorithm
5928 141321 (impElts,defElts,classextendsElts,filtered) := splitEltsNoComponents(xs);
5929 141321 then
5930 (impElts,defElts,classextendsElts,elt::filtered);
5931
5932 end match;
5933 end splitEltsNoComponents;
5934
5935 public function splitEltsInnerAndOther "
5936 @author: adrpo
5937 Splits elements into these categories:
5938 1. Class definitions, imports and defineunits
5939 2. Class-extends class definitions
5940 3. Extends elements
5941 4. Inner Components
5942 5. Any Other Components"
5943 input list<SCode.Element> elts;
5944 output list<SCode.Element> cdefImpElts;
5945 output list<SCode.Element> classextendsElts;
5946 output list<SCode.Element> extElts;
5947 output list<SCode.Element> innerCompElts;
5948 output list<SCode.Element> otherCompElts;
5949 algorithm
5950 (cdefImpElts,classextendsElts,extElts,innerCompElts,otherCompElts) := match elts
5951 local
5952 list<SCode.Element> xs,innerComps,otherComps;
5953 SCode.Element cdef,imp,ext,comp;
5954 Absyn.InnerOuter io;
5955
5956 // empty case
5957 case {} then ({},{},{},{},{});
5958
5959 // class definitions with class extends
5960 case (cdef as SCode.CLASS(classDef = SCode.CLASS_EXTENDS()))::xs
5961 algorithm
5962 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5963 ✗ then
5964 (cdefImpElts,cdef :: classextendsElts,extElts,innerComps,otherComps);
5965
5966 // class definitions without class extends
5967 case (cdef as SCode.CLASS()) :: xs
5968 algorithm
5969 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5970 ✗ then
5971 (cdef :: cdefImpElts,classextendsElts,extElts,innerComps,otherComps);
5972
5973 // imports
5974 case (imp as SCode.IMPORT()) :: xs
5975 algorithm
5976 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5977 ✗ then
5978 (imp :: cdefImpElts,classextendsElts,extElts,innerComps,otherComps);
5979
5980 // units
5981 case (imp as SCode.DEFINEUNIT()) :: xs
5982 algorithm
5983 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5984 ✗ then
5985 (imp :: cdefImpElts,classextendsElts,extElts,innerComps,otherComps);
5986
5987 // extends elements
5988 case (ext as SCode.EXTENDS())::xs
5989 algorithm
5990 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5991 ✗ then
5992 (cdefImpElts,classextendsElts,ext::extElts,innerComps,otherComps);
5993
5994 // inner components
5995 case (comp as SCode.COMPONENT(prefixes = SCode.PREFIXES(innerOuter = io))) :: xs
5996 algorithm
5997 ✗ true := AbsynUtil.isInner(io);
5998 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
5999 ✗ then
6000 (cdefImpElts,classextendsElts,extElts,comp::innerComps,otherComps);
6001
6002 // any other components
6003 case (comp as SCode.COMPONENT() ):: xs
6004 algorithm
6005 ✗ (cdefImpElts,classextendsElts,extElts,innerComps,otherComps) := splitEltsInnerAndOther(xs);
6006 ✗ then
6007 (cdefImpElts,classextendsElts,extElts,innerComps,comp::otherComps);
6008 end match;
6009 end splitEltsInnerAndOther;
6010
6011 protected function orderComponents
6012 "@author: adrpo
6013 this functions puts the component in front of the list if
6014 is inner or innerouter and at the end of the list otherwise"
6015 input SCode.Element inComp;
6016 input list<SCode.Element> inCompElts;
6017 output list<SCode.Element> outCompElts;
6018 algorithm
6019 outCompElts := match inComp
6020 local
6021 list<SCode.Element> compElts;
6022
6023 // input/output come first!
6024 case SCode.COMPONENT(attributes = SCode.ATTR(direction = Absyn.INPUT()))
6025 then inComp::inCompElts;
6026 case SCode.COMPONENT(attributes = SCode.ATTR(direction = Absyn.OUTPUT()))
6027 then inComp::inCompElts;
6028 // put inner/outer in front.
6029 case SCode.COMPONENT(prefixes = SCode.PREFIXES(innerOuter = Absyn.INNER()))
6030 then inComp::inCompElts;
6031 case SCode.COMPONENT(prefixes = SCode.PREFIXES(innerOuter = Absyn.INNER_OUTER()))
6032 then inComp::inCompElts;
6033 // put constants in front
6034 case SCode.COMPONENT(attributes = SCode.ATTR(variability = SCode.CONST()))
6035 then inComp::inCompElts;
6036 // put parameters in front
6037 case SCode.COMPONENT(attributes = SCode.ATTR(variability = SCode.PARAM()))
6038 then inComp::inCompElts;
6039 // all other append to the end.
6040 case SCode.COMPONENT()
6041 algorithm
6042 ✗ compElts := listAppend(inCompElts, {inComp});
6043 then compElts;
6044 end match;
6045 end orderComponents;
6046
6047 protected function splitClassExtendsElts
6048 "This function splits the Element list into two lists
6049 1. Class-extends class definitions
6050 2. Any other element"
6051 input list<SCode.Element> elts;
6052 output list<SCode.Element> classextendsElts;
6053 output list<SCode.Element> outElts;
6054 algorithm
6055 (classextendsElts,outElts) := match elts
6056 local
6057 list<SCode.Element> res,xs;
6058 SCode.Element cdef;
6059 case {} then ({},{});
6060
6061 case (cdef as SCode.CLASS(classDef = SCode.CLASS_EXTENDS()))::xs
6062 algorithm
6063 ✗ (classextendsElts,res) := splitClassExtendsElts(xs);
6064 ✗ then
6065 (cdef :: classextendsElts, res);
6066
6067 case cdef::xs
6068 algorithm
6069 ✗ (classextendsElts,res) := splitClassExtendsElts(xs);
6070 ✗ then
6071 (classextendsElts, cdef :: res);
6072
6073 end match;
6074 end splitClassExtendsElts;
6075
6076 protected function addClassdefsToEnv3
6077 "function: addClassdefsToEnv3 "
6078 input FCore.Cache inCache;
6079 input FCore.Graph env;
6080 input InnerOuter.InstHierarchy inIH;
6081 input DAE.Prefix inPrefix;
6082 input Option<DAE.Mod> inMod;
6083 input SCode.Element sele;
6084 output FCore.Cache outCache;
6085 output FCore.Graph oenv;
6086 output InnerOuter.InstHierarchy outIH;
6087 output SCode.Element osele;
6088 algorithm
6089 (outCache,oenv,outIH,osele) := match(inCache, inIH, inPrefix, inMod, sele)
6090 local
6091 DAE.Mod mo2;
6092 SCode.Element sele2;
6093 FCore.Cache cache;
6094 FCore.Graph env2;
6095 String str;
6096 InstanceHierarchy ih;
6097 list<DAE.SubMod> lsm;
6098 DAE.Prefix pre;
6099
6100 ✗ case(_, _, _, NONE(), _) then fail();
6101
6102 case(cache, ih, pre, SOME(DAE.MOD(subModLst = lsm)), SCode.CLASS(name=str))
6103 algorithm
6104 // fprintln(Flags.INST_TRACE, "Mods in addClassdefsToEnv3: " + Mod.printModStr(mo) + " class name: " + str);
6105 3839 (mo2,_) := extractCorrectClassMod2(lsm,str,{});
6106 // fprintln(Flags.INST_TRACE, "Mods in addClassdefsToEnv3 after extractCorrectClassMod2: " + Mod.printModStr(mo2) + " class name: " + str);
6107 // TODO: classinf below should be FQ
6108
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 3839 times.
✓ Branch 5 taken 3839 times.
✗ Branch 6 not taken.
3839 (cache, env2, ih, sele2 as SCode.CLASS() , _) :=
6109 Inst.redeclareType(cache, env, ih, mo2, sele, pre, ClassInf.MODEL(Absyn.IDENT(str)), true, DAE.NOMOD());
6110 then
6111 (cache,env2,ih,sele2);
6112
6113 end match;
6114 end addClassdefsToEnv3;
6115
6116 protected function extractCorrectClassMod2
6117 " This function extracts a modifier on a specific component.
6118 Referenced by the name."
6119 input list<DAE.SubMod> smod;
6120 input String name;
6121 input list<DAE.SubMod> premod;
6122 output DAE.Mod omod;
6123 output list<DAE.SubMod> restmods;
6124 algorithm (omod,restmods) := match smod
6125 local
6126 DAE.Mod mod;
6127 DAE.SubMod sub;
6128 String id;
6129 list<DAE.SubMod> rest,rest2;
6130
6131 case {} then (DAE.NOMOD(),premod);
6132
6133 case DAE.NAMEMOD(id, mod) :: rest
6134 guard
6135 stringEq(id, name)
6136 algorithm
6137 3839 rest2 := listAppend(premod,rest);
6138 then
6139 (mod, rest2);
6140
6141 case sub::rest
6142 algorithm
6143 51501 (mod,rest2) := extractCorrectClassMod2(rest,name,premod);
6144 51501 then
6145 (mod, sub::rest2);
6146 end match;
6147 end extractCorrectClassMod2;
6148
6149 public function traverseModAddFinal
6150 "Helper function for traverseModAddFinal"
6151 input output SCode.Mod mod;
6152 algorithm
6153 mod := matchcontinue mod
6154 local
6155 SCode.Element element1,element2;
6156 SCode.Each each_;
6157 list<SCode.SubMod> subs1,subs2;
6158 Option<Absyn.Exp> eq;
6159 SourceInfo info;
6160 SCode.Final f;
6161 Option<String> cmt;
6162
6163 112 case SCode.NOMOD() then mod;
6164
6165 case SCode.REDECL(eachPrefix = each_, element = element1)
6166 algorithm
6167 ✗ element2 := traverseModAddFinal3(element1);
6168 ✗ then if referenceEq(element1,element2) then mod else SCode.REDECL(SCode.FINAL(),each_,element2);
6169
6170 case SCode.MOD(f,each_,subs1,eq,cmt,info)
6171 algorithm
6172 7774 subs2 := List.mapCheckReferenceEq(subs1, traverseModAddFinal4);
6173
3/4
✓ Branch 1 taken 498 times.
✓ Branch 2 taken 7276 times.
✓ Branch 3 taken 498 times.
✗ Branch 4 not taken.
7774 then
6174 if valueEq(SCode.FINAL(),f) and referenceEq(subs1, subs2) then mod else SCode.MOD(SCode.FINAL(),each_,subs2,eq,cmt,info);
6175
6176 else
6177 algorithm
6178 ✗ Error.addInternalError(getInstanceName(), sourceInfo());
6179 ✗ then fail();
6180
6181 end matchcontinue;
6182 end traverseModAddFinal;
6183
6184 protected function traverseModAddFinal3
6185 "Helper function for traverseModAddFinal2"
6186 input SCode.Element inElement;
6187 output SCode.Element outElement;
6188 algorithm
6189 outElement := matchcontinue inElement
6190 local
6191 SCode.Attributes attr;
6192 Absyn.TypeSpec tySpec;
6193 SCode.Mod mod, oldmod;
6194 Ident name;
6195 SCode.Visibility vis;
6196 SCode.Prefixes prefixes;
6197 SCode.Comment cmt;
6198 Option<Absyn.Exp> cond;
6199 Absyn.Path p;
6200 Option<SCode.Annotation> ann;
6201 SourceInfo info;
6202
6203 case SCode.COMPONENT(name,prefixes,attr,tySpec,oldmod,cmt,cond,info)
6204 algorithm
6205 ✗ mod := traverseModAddFinal(oldmod);
6206 ✗ then
6207 if referenceEq(oldmod,mod) then inElement else SCode.COMPONENT(name,prefixes,attr,tySpec,mod,cmt,cond,info);
6208
6209 case SCode.IMPORT() then inElement;
6210 case SCode.CLASS() then inElement;
6211
6212 case SCode.EXTENDS(p,vis,oldmod,ann,info)
6213 algorithm
6214 ✗ mod := traverseModAddFinal(oldmod);
6215 ✗ then if referenceEq(oldmod,mod) then inElement else SCode.EXTENDS(p,vis,mod,ann,info);
6216
6217 else
6218 algorithm
6219 ✗ print(" we failed with traverseModAddFinal3\n");
6220 ✗ then
6221 fail();
6222
6223 end matchcontinue;
6224 end traverseModAddFinal3;
6225
6226 protected function traverseModAddFinal4
6227 "Helper function for traverseModAddFinal2"
6228 input output SCode.SubMod sub;
6229 protected
6230 SCode.Mod mod;
6231 algorithm
6232 1334 mod := traverseModAddFinal(sub.mod);
6233
2/2
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 836 times.
1334 if not referenceEq(sub.mod, mod) then
6234 836 sub.mod := mod;
6235 end if;
6236 end traverseModAddFinal4;
6237
6238 public function traverseModAddDims
6239 "The function used to modify modifications for non-expanded arrays"
6240 input FCore.Cache inCache;
6241 input FCore.Graph inEnv;
6242 input DAE.Prefix inPrefix;
6243 input SCode.Mod inMod;
6244 input list<list<DAE.Dimension>> inInstDims;
6245 output SCode.Mod outMod;
6246 algorithm
6247 outMod := matchcontinue(inCache,inEnv,inPrefix,inMod,inInstDims)
6248 local
6249 FCore.Cache cache;
6250 FCore.Graph env;
6251 DAE.Prefix pre;
6252 SCode.Mod mod, mod2;
6253 InstDims inst_dims;
6254 list<list<DAE.Exp>> exps;
6255 list<list<Absyn.Exp>> aexps;
6256
6257 case (_,_,_,mod,_) //If arrays are expanded, no action is needed
6258 algorithm
6259
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 530010 times.
530010 true := Config.splitArrays();
6260 then
6261 mod;
6262 case (_,_,_,_,{}) then inMod;
6263 case (cache,env,pre,mod,inst_dims)
6264 algorithm
6265 ✗ exps := List.map(inst_dims,Expression.dimensionsToExps);
6266 ✗ aexps := List.mapList(exps, Expression.unelabExp);
6267 ✗ mod2 := traverseModAddDims4(cache,env,pre,mod, aexps, true);
6268
6269 then
6270 mod2;
6271 end matchcontinue;
6272 end traverseModAddDims;
6273
6274 protected function traverseModAddDims4
6275 "Helper function for traverseModAddDims"
6276 input FCore.Cache inCache;
6277 input FCore.Graph inEnv;
6278 input DAE.Prefix inPrefix;
6279 input SCode.Mod inMod;
6280 input list<list<Absyn.Exp>> inExps;
6281 input Boolean inIsTop;
6282 output SCode.Mod outMod;
6283 algorithm
6284 outMod := match(inCache,inEnv,inPrefix,inMod,inExps)
6285 local
6286 FCore.Cache cache;
6287 FCore.Graph env;
6288 DAE.Prefix pre;
6289 list<SCode.SubMod> submods2;
6290 Option<Absyn.Exp> binding;
6291 list<list<Absyn.Exp>> exps;
6292
6293 case (_,_,_,SCode.NOMOD(),_) then inMod;
6294 case (_,_,_,SCode.REDECL(),_) then inMod; // Though redeclarations may need some processing as well
6295 case (cache,env,pre,SCode.MOD(eachPrefix = SCode.NOT_EACH()),exps)
6296 algorithm
6297 ✗ submods2 := traverseModAddDims5(cache,env,pre,inMod.subModLst,exps);
6298 ✗ binding := insertSubsInBinding(inMod.binding, exps);
6299 ✗ then
6300 SCode.MOD(inMod.finalPrefix, SCode.NOT_EACH(),submods2, binding, inMod.comment, inMod.info);
6301 end match;
6302 end traverseModAddDims4;
6303
6304 protected function traverseModAddDims5
6305 "Helper function for traverseModAddDims2"
6306 input FCore.Cache inCache;
6307 input FCore.Graph inEnv;
6308 input DAE.Prefix inPrefix;
6309 input list<SCode.SubMod> inMods;
6310 input list<list<Absyn.Exp>> inExps;
6311 output list<SCode.SubMod> outMods;
6312 algorithm
6313 outMods := match(inCache, inEnv, inPrefix, inMods)
6314 local
6315 FCore.Cache cache;
6316 FCore.Graph env;
6317 DAE.Prefix pre;
6318 SCode.Mod mod,mod2;
6319 list<SCode.SubMod> smods,smods2;
6320 Ident n;
6321 case (_, _, _, {}) then {};
6322 case (cache, env, pre, SCode.NAMEMOD(n,mod)::smods)
6323 algorithm
6324 ✗ mod2 := traverseModAddDims4(cache,env,pre,mod,inExps,false);
6325 ✗ smods2 := traverseModAddDims5(cache,env,pre,smods,inExps);
6326 ✗ then
6327 SCode.NAMEMOD(n,mod2)::smods2;
6328 end match;
6329 end traverseModAddDims5;
6330
6331 protected function insertSubsInBinding
6332 input Option<Absyn.Exp> inOpt;
6333 input list<list<Absyn.Exp>> inExps;
6334 output Option<Absyn.Exp> outOpt;
6335 algorithm
6336 outOpt := match(inOpt,inExps)
6337 local
6338 list<list<Absyn.Exp>> exps;
6339 Absyn.Exp e,e2;
6340 list<list<Absyn.Subscript>> subs;
6341 list<list<Absyn.Ident>> vars;
6342
6343 case (NONE(),_) then NONE();
6344 case (SOME(e), exps)
6345 algorithm
6346 ✗ vars := generateUnusedNamesLstCall(e,exps);
6347 ✗ subs := List.mapList(vars,stringSub);
6348 ✗ (e2,_) := AbsynUtil.traverseExp(e,AbsynUtil.crefInsertSubscriptLstLst, subs);
6349 ✗ e2 := wrapIntoForLst(e2,vars,exps);
6350 then
6351 SOME(e2);
6352 end match;
6353 end insertSubsInBinding;
6354
6355 protected function generateUnusedNames
6356 "Generates a list of variable names which are not used in any of expressions.
6357 The number of variables is the same as the length of input list.
6358 TODO: Write the REAL function!"
6359 input Absyn.Exp inExp;
6360 input list<Absyn.Exp> inList;
6361 output list<String> outNames;
6362 algorithm
6363 ✗ (outNames,_) := generateUnusedNames2(inList,1);
6364 end generateUnusedNames;
6365
6366 protected function generateUnusedNames2
6367 input list<Absyn.Exp> inList;
6368 input Integer inInt;
6369 output list<String> outNames;
6370 output Integer outInt;
6371 algorithm
6372 (outNames,outInt) := match(inList,inInt)
6373 local
6374 Integer i,i1,i2;
6375 String s;
6376 list<String> names;
6377 list<Absyn.Exp> exps;
6378 case ({},i) then ({},i);
6379 case (_::exps,i)
6380 algorithm
6381 ✗ s := intString(i);
6382 ✗ s := "i" + s;
6383 ✗ i1 := i + 1;
6384 ✗ (names,i2) := generateUnusedNames2(exps,i1);
6385 ✗ then
6386 (s::names,i2);
6387 end match;
6388 end generateUnusedNames2;
6389
6390 protected function generateUnusedNamesLst
6391 input list<list<Absyn.Exp>> inList;
6392 input Integer inInt;
6393 output list<list<String>> outNames;
6394 output Integer outInt;
6395 algorithm
6396 (outNames,outInt) := match(inList,inInt)
6397 local
6398 Integer i,i1,i2;
6399 list<list<String>> names;
6400 list<String> ns;
6401 list<list<Absyn.Exp>> exps;
6402 list<Absyn.Exp> e0;
6403 case ({},i) then ({},i);
6404 case (e0::exps,i)
6405 algorithm
6406 ✗ (ns,i1) := generateUnusedNames2(e0,i);
6407 ✗ (names,i2) := generateUnusedNamesLst(exps,i1);
6408 ✗ then
6409 (ns::names,i2);
6410 end match;
6411 end generateUnusedNamesLst;
6412
6413 protected function generateUnusedNamesLstCall
6414 "Generates a list of lists of variable names which are not used in any of expressions.
6415 The structure of lsis of lists is the same as of input list of lists.
6416 TODO: Write the REAL function!"
6417 input Absyn.Exp inExp;
6418 input list<list<Absyn.Exp>> inList;
6419 output list<list<String>> outNames;
6420 algorithm
6421 ✗ (outNames,_) := generateUnusedNamesLst(inList,1);
6422 end generateUnusedNamesLstCall;
6423
6424 protected function stringsSubs
6425 input list<String> inNames;
6426 output list<Absyn.Subscript> outSubs;
6427 algorithm
6428 outSubs := match inNames
6429 local
6430 String n;
6431 list<String> names;
6432 list<Absyn.Subscript> subs;
6433 case {} then {};
6434 case n::names
6435 algorithm
6436 ✗ subs := stringsSubs(names);
6437 ✗ then
6438 Absyn.SUBSCRIPT(Absyn.CREF(Absyn.CREF_IDENT(n,{})))::subs;
6439 end match;
6440 end stringsSubs;
6441
6442 protected function stringSub
6443 input String inName;
6444 output Absyn.Subscript outSub;
6445 algorithm
6446 outSub := match inName
6447 local
6448 String n;
6449 case n
6450 ✗ then
6451 Absyn.SUBSCRIPT(Absyn.CREF(Absyn.CREF_IDENT(n,{})));
6452 end match;
6453 end stringSub;
6454
6455 protected function wrapIntoFor
6456 input Absyn.Exp inExp;
6457 input list<String> inNames;
6458 input list<Absyn.Exp> inRanges;
6459 output Absyn.Exp outExp;
6460 algorithm
6461 outExp := match(inExp,inNames,inRanges)
6462 local
6463 Absyn.Exp e,e2,r;
6464 String n;
6465 list<String> names;
6466 list<Absyn.Exp> ranges;
6467 case (e,{},{}) then e;
6468 case (e,n::names,r::ranges)
6469 algorithm
6470 ✗ e2 := wrapIntoFor(e, names, ranges);
6471 ✗ then Absyn.CALL(Absyn.CREF_IDENT("array",{}), Absyn.FOR_ITER_FARG(e2, Absyn.COMBINE() ,{Absyn.ITERATOR(n,NONE(),SOME(Absyn.RANGE(Absyn.INTEGER(1),NONE(),r)))}),{});
6472 end match;
6473 end wrapIntoFor;
6474
6475 protected function wrapIntoForLst
6476 input Absyn.Exp inExp;
6477 input list<list<String>> inNames;
6478 input list<list<Absyn.Exp>> inRanges;
6479 output Absyn.Exp outExp;
6480 algorithm
6481 outExp := match(inExp,inNames,inRanges)
6482 local
6483 Absyn.Exp e,e2,e3;
6484 list<String> n;
6485 list<list<String>> names;
6486 list<Absyn.Exp> r;
6487 list<list<Absyn.Exp>> ranges;
6488 case (e,{},{}) then e;
6489 case (e,n::names,r::ranges)
6490 algorithm
6491 ✗ e2 := wrapIntoForLst(e, names, ranges);
6492 ✗ e3 := wrapIntoFor(e2, n, r);
6493 then
6494 e3;
6495 end match;
6496 end wrapIntoForLst;
6497
6498 public function componentHasCondition
6499 input tuple<SCode.Element, DAE.Mod> component;
6500 output Boolean hasCondition;
6501 algorithm
6502 hasCondition := match component
6503 case (SCode.COMPONENT(condition = SOME(_)), _) then true;
6504 else false;
6505 end match;
6506 end componentHasCondition;
6507
6508 public function instElementCondExp
6509 input FCore.Cache inCache;
6510 input FCore.Graph inEnv;
6511 input SCode.Element component;
6512 input DAE.Prefix prefix;
6513 input SourceInfo info;
6514 output Option<Boolean> outCondValue;
6515 output FCore.Cache outCache;
6516 algorithm
6517 (outCondValue, outCache) := matchcontinue component
6518 local
6519 Absyn.Exp cond_exp;
6520 Boolean cond_val;
6521 FCore.Cache cache;
6522
6523 case SCode.COMPONENT(condition = SOME(cond_exp))
6524 algorithm
6525 1745 (cond_val, cache) := instConditionalDeclaration(inCache, inEnv, cond_exp, prefix, info);
6526
2/2
✓ Branch 0 taken 972 times.
✓ Branch 1 taken 773 times.
3490 then
6527 (SOME(cond_val), cache);
6528
6529 case SCode.COMPONENT(condition = SOME(_)) then (NONE(), inCache);
6530 else (SOME(true), inCache);
6531 end matchcontinue;
6532 end instElementCondExp;
6533
6534 protected function instConditionalDeclaration
6535 input FCore.Cache inCache;
6536 input FCore.Graph inEnv;
6537 input Absyn.Exp inCondition;
6538 input DAE.Prefix inPrefix;
6539 input SourceInfo inInfo;
6540 output Boolean outIsConditional;
6541 output FCore.Cache outCache;
6542 protected
6543 DAE.Exp e;
6544 DAE.Type t;
6545 DAE.Const c;
6546 Boolean b;
6547 Values.Value val;
6548 algorithm
6549 // Elaborate the conditional expression.
6550
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1745 times.
1745 (outCache, e, DAE.PROP(type_ = t, constFlag = c)) :=
6551 Static.elabExp(inCache, inEnv, inCondition, false, false, inPrefix, inInfo);
6552
6553 // The expression must be of boolean type.
6554
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1745 times.
1745 if not Types.isBoolean(t) then
6555 ✗ Error.addSourceMessageAndFail(Error.IF_CONDITION_TYPE_ERROR,
6556 {Dump.printExpStr(inCondition), TypesDump.unparseTypeNoAttr(t)}, inInfo);
6557 end if;
6558
6559 // The expression must be a parameter expression that can be evaluated at compile-time.
6560
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1745 times.
1745 if not Types.isParameterOrConstant(c) then
6561 ✗ Error.addSourceMessageAndFail(Error.COMPONENT_CONDITION_VARIABILITY,
6562 {Dump.printExpStr(inCondition)}, inInfo);
6563 end if;
6564
6565 // If it is a boolean parameter expression, try to evaluate it.
6566 1745 (outCache, val) := Ceval.ceval(outCache, inEnv, e, false, Absyn.MSG(inInfo), 0);
6567
6568 outIsConditional := match val
6569 case Values.BOOL(b) then b;
6570 case Values.EMPTY() // Print an error if the expression has no value.
6571 algorithm
6572 ✗ if not Config.getGraphicsExpMode() then
6573 ✗ Error.addSourceMessage(Error.CONDITIONAL_EXP_WITHOUT_VALUE,
6574 {Dump.printExpStr(inCondition)}, inInfo);
6575 ✗ fail();
6576 end if;
6577 then true; // Randomly pick a default for graphics mode...
6578 else
6579 algorithm
6580 ✗ Error.addInternalError("InstUtil.instConditionalDeclaration got unexpected value " + ValuesDump.valString(val), sourceInfo());
6581 ✗ then
6582 fail();
6583 end match;
6584 end instConditionalDeclaration;
6585
6586 public function propagateClassPrefix
6587 "Propagate ClassPrefix, i.e. variability to a component.
6588 This is needed to make sure that e.g. a parameter does
6589 not generate an equation but a binding."
6590 input SCode.Attributes attr;
6591 input DAE.Prefix pre;
6592 output SCode.Attributes outAttr;
6593 algorithm
6594 outAttr := match(attr,pre)
6595 local
6596 Absyn.ArrayDim ad;
6597 SCode.ConnectorType ct;
6598 Absyn.Direction dir;
6599 SCode.Parallelism prl;
6600 SCode.Variability vt;
6601 Absyn.IsField isf;
6602
6603 // if classprefix is variable, keep component variability
6604 case (_,DAE.PREFIX(_,DAE.CLASSPRE(SCode.VAR()))) then attr;
6605 // if variability is constant, do not override it!
6606 case(SCode.ATTR(variability = SCode.CONST()),_) then attr;
6607 // if classprefix is parameter or constant, override component variability
6608 case(SCode.ATTR(ad,ct,prl,_,dir,isf),DAE.PREFIX(_,DAE.CLASSPRE(vt)))
6609 ✗ then SCode.ATTR(ad,ct,prl,vt,dir,isf);
6610 // anything else
6611 else attr;
6612 end match;
6613 end propagateClassPrefix;
6614
6615 public function checkUseConstValue
6616 "help function to instBinding.
6617 If first arg is true, it returns the constant expression found in Value option.
6618 This is used to ensure that e.g. stateSelect attribute gets a constant value
6619 and not a parameter expression."
6620 input Boolean useConstValue;
6621 input DAE.Exp ie;
6622 input Option<Values.Value> v;
6623 output DAE.Exp outE;
6624 algorithm
6625 outE := matchcontinue(useConstValue,ie,v)
6626 local
6627 Values.Value val;
6628 DAE.Exp e;
6629
6630 case(false,e,_) then e;
6631 case(true,_,SOME(val)) algorithm
6632 6390 e := ValuesUtil.valueExp(val);
6633 then e;
6634 case(_,e,_) then e;
6635 end matchcontinue;
6636 end checkUseConstValue;
6637
6638 public function propagateAbSCDirection
6639 input SCode.Variability inVariability;
6640 input SCode.Attributes inAttributes;
6641 input Option<SCode.Attributes> inClassAttributes;
6642 input SourceInfo inInfo;
6643 output SCode.Attributes outAttributes;
6644 algorithm
6645 outAttributes := match inVariability
6646 local
6647 Absyn.Direction dir;
6648
6649 case SCode.CONST() then inAttributes;
6650 case SCode.PARAM() then inAttributes;
6651 else
6652 algorithm
6653 385939 SCode.ATTR(direction = dir) := inAttributes;
6654 385939 dir := propagateAbSCDirection2(dir, inClassAttributes, inInfo);
6655 385939 then
6656 SCodeUtil.setAttributesDirection(inAttributes, dir);
6657 end match;
6658 end propagateAbSCDirection;
6659
6660 public function propagateAbSCDirection2 "
6661 Author BZ 2008-05
6662 This function merged derived SCode.Attributes with the current input SCode.Attributes."
6663 input Absyn.Direction v1;
6664 input Option<SCode.Attributes> optDerAttr;
6665 input SourceInfo inInfo;
6666 output Absyn.Direction v3;
6667 algorithm
6668 v3 := match(v1, optDerAttr)
6669 local
6670 Absyn.Direction v2;
6671
6672 case (_, NONE()) then v1;
6673 case(Absyn.BIDIR(), SOME(SCode.ATTR(direction=v2))) then v2;
6674 case (_, SOME(SCode.ATTR(direction=Absyn.BIDIR()))) then v1;
6675 case(_, SOME(SCode.ATTR(direction=v2))) guard valueEq(v1, v2)
6676 then v1;
6677
6678 else
6679 algorithm
6680 ✗ print(" failure in propagateAbSCDirection2, Absyn.DIRECTION mismatch");
6681 ✗ Error.addSourceMessage(Error.COMPONENT_INPUT_OUTPUT_MISMATCH, {"",""}, inInfo);
6682 ✗ then
6683 fail();
6684
6685 end match;
6686 end propagateAbSCDirection2;
6687
6688 public function makeCrefBaseType
6689 input DAE.Type inBaseType;
6690 input list<list<DAE.Dimension>>inDimensions;
6691 output DAE.Type outType;
6692 algorithm
6693 526574 outType := Types.simplifyType(makeCrefBaseType2(inBaseType, inDimensions));
6694 end makeCrefBaseType;
6695
6696 protected function makeCrefBaseType2
6697 input DAE.Type inBaseType;
6698 input list<list<DAE.Dimension>>inDimensions;
6699 output DAE.Type outType;
6700 algorithm
6701 outType := matchcontinue(inBaseType, inDimensions)
6702 local
6703 DAE.Type ty;
6704 DAE.Dimensions dims;
6705
6706 // Types extending basic type has dimensions already added
6707 // adrpo: not true, see PowerSystems library for example
6708 // type ReferenceAngle extends .Modelica.SIunits.Angle; some equalityConstraint function end ReferenceAngle;
6709 // used like: ReferenceAngle[x] theta in a connector
6710 case (DAE.T_SUBTYPE_BASIC(complexType = ty), _)
6711 algorithm
6712 // check if it has any dimensions
6713
2/2
✓ Branch 1 taken 5346 times.
✓ Branch 2 taken 38 times.
5384 false := listEmpty(TypesDump.getDimensions(ty));
6714 then
6715 ty;
6716
6717 case (_, {}) then inBaseType;
6718
6719 else
6720 algorithm
6721 477796 dims := List.last(inDimensions);
6722 477796 ty := Expression.liftArrayLeftList(inBaseType, dims);
6723 then
6724 ty;
6725
6726 end matchcontinue;
6727 end makeCrefBaseType2;
6728
6729 public function getCrefFromCompDim
6730 "Author: BZ, 2009-07
6731 Get Absyn.ComponentRefs from dimension in SCode.COMPONENT"
6732 input SCode.Element inEle;
6733 output list<Absyn.ComponentRef> cref;
6734 algorithm
6735 cref := matchcontinue inEle
6736 local
6737 list<Absyn.Subscript> ads;
6738
6739 case SCode.COMPONENT(attributes = SCode.ATTR(arrayDims = ads))
6740 6814 then
6741 AbsynUtil.getCrefsFromSubs(ads,true,true);
6742
6743 else {};
6744
6745 end matchcontinue;
6746 end getCrefFromCompDim;
6747
6748 public function getCrefFromCond "
6749 author: PA
6750 Return all variables in a conditional component clause.
6751 Done to instantiate components referenced in other components, See also getCrefFromMod and
6752 updateComponentsInEnv."
6753 input Option<Absyn.Exp> cond;
6754 output list<Absyn.ComponentRef> crefs;
6755 algorithm
6756 crefs := match cond
6757 local Absyn.Exp e;
6758 case NONE() then {};
6759 774 case SOME(e) then AbsynUtil.getCrefFromExp(e,true,true);
6760 end match;
6761 end getCrefFromCond;
6762
6763 protected function checkVariabilityOfUpdatedComponent "
6764 For components that already have been visited by updateComponentsInEnv, they must be instantiated without
6765 modifiers to prevent infinite recursion. However, parameters and constants may not have recursive definitions.
6766 So we print errors for those instead."
6767 input SCode.Variability variability;
6768 input Absyn.ComponentRef cref;
6769 algorithm
6770 () := match variability
6771 local
6772 case SCode.VAR() then ();
6773 case SCode.DISCRETE() then ();
6774 else
6775 algorithm
6776 /* Doesn't work anyway right away
6777 crefStr = Dump.printComponentRefStr(cref);
6778 varStr = SCodeDump.variabilityString(variability);
6779 Error.addMessage(Error.CIRCULAR_PARAM,{crefStr,varStr});*/
6780 then fail();
6781 end match;
6782 end checkVariabilityOfUpdatedComponent;
6783
6784 public function propagateBinding "
6785 This function modifies equations into bindings for parameters"
6786 input DAE.DAElist inVarsDae;
6787 input DAE.DAElist inEquationsDae "Note: functions from here are not considered";
6788 output DAE.DAElist outVarsDae;
6789 protected
6790 list<DAE.Element> vars, vars1, equations, equations1;
6791 DAE.Element v1;
6792 Integer i;
6793 list<Integer> is;
6794 DAE.Exp e;
6795 DAE.ComponentRef cr;
6796 Absyn.Path path;
6797 algorithm
6798 37130 DAE.DAE(vars) := inVarsDae;
6799 37130 DAE.DAE(equations) := inEquationsDae;
6800
4/4
✓ Branch 0 taken 367 times.
✓ Branch 1 taken 36763 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 351 times.
37130 if listEmpty(vars) or listEmpty(equations) then
6801 outVarsDae := inVarsDae;
6802 36779 return;
6803 end if;
6804 vars1 := {};
6805 is := {};
6806
2/2
✓ Branch 0 taken 4065 times.
✓ Branch 1 taken 351 times.
4416 for v in vars loop
6807 v1 := matchcontinue v
6808 case v1 as DAE.VAR()
6809 algorithm
6810 4048 (e,i) := findCorrespondingBinding(v1.componentRef, equations);
6811 24 v1.binding := SOME(e);
6812 24 is := i::is;
6813 then v1;
6814 4041 else v;
6815 end matchcontinue;
6816 vars1 := v1::vars1;
6817 end for;
6818 351 vars1 := listReverse(vars1);
6819 351 equations1 := List.deletePositions(equations, is);
6820
4/4
✓ Branch 0 taken 373 times.
✓ Branch 1 taken 351 times.
✓ Branch 2 taken 373 times.
✓ Branch 3 taken 351 times.
724 equations1 := list(DAEUtil.moveElementToInitialSection(eq) for eq in equations);
6821 351 i := 1;
6822
2/2
✓ Branch 0 taken 373 times.
✓ Branch 1 taken 351 times.
724 for eq in equations1 loop
6823 () := match eq
6824 case DAE.INITIALEQUATION(exp1=DAE.CREF(ty=DAE.T_COMPLEX()), exp2=DAE.CALL(path=path))
6825 guard AbsynUtil.pathLastIdent(path)=="constructor"
6826 algorithm
6827 // Don't duplicate constructor calls
6828 17 is := i::is;
6829 then ();
6830 case DAE.INITIAL_COMPLEX_EQUATION(lhs=DAE.CREF(componentRef=cr))
6831 algorithm
6832
4/4
✓ Branch 0 taken 4024 times.
✓ Branch 1 taken 332 times.
✓ Branch 2 taken 4024 times.
✓ Branch 3 taken 332 times.
4356 vars1 := list(match v
6833 case DAE.VAR(binding=SOME(_)) guard ComponentReferenceBasics.crefPrefixOf(cr, v.componentRef)
6834 algorithm
6835 4024 is := i::is;
6836 4024 then v;
6837 // Moving parameter bindings into initial equation section means we need to force fixed=false...
6838 case DAE.VAR(binding=NONE()) guard ComponentReferenceBasics.crefPrefixOf(cr, v.componentRef)
6839 algorithm
6840 ✗ v.variableAttributesOption := DAEUtil.setFixedAttr(v.variableAttributesOption, SOME(DAE.BCONST(false)));
6841 ✗ Error.addSourceMessage(Error.MOVING_PARAMETER_BINDING_TO_INITIAL_EQ_SECTION, {ComponentReferenceBasics.printComponentRefStr(v.componentRef)}, eq.source.info);
6842 then v;
6843 ✗ else v;
6844 end match for v in vars1);
6845 then ();
6846 else /* algorithm print(anyString(eq)); */ then ();
6847 end match;
6848 373 i := i+1;
6849 end for;
6850 351 equations1 := List.deletePositions(equations1, is);
6851 351 outVarsDae := DAE.DAE(listAppend(equations1, vars1));
6852 end propagateBinding;
6853
6854 protected function findCorrespondingBinding "
6855 Helper function for propagateBinding"
6856 input DAE.ComponentRef inCref;
6857 input list<DAE.Element> inEquations;
6858 output DAE.Exp outExp;
6859 input output Integer i=1;
6860 algorithm
6861 outExp :=match (inCref, inEquations)
6862 local
6863 DAE.ComponentRef cref,cref2,cref3;
6864 DAE.Exp e;
6865 list<DAE.Element> equations;
6866
6867 case (cref, DAE.DEFINE(componentRef=cref2, exp=e)::_)
6868 guard ComponentReferenceBasics.crefEqual(cref,cref2)
6869 then e;
6870
6871 case (cref, DAE.EQUATION(exp=DAE.CREF(cref2,_),scalar=e)::_)
6872 guard ComponentReferenceBasics.crefEqual(cref,cref2)
6873 then e;
6874
6875 case (cref, DAE.EQUEQUATION(cr1=cref2,cr2=cref3)::_)
6876 guard ComponentReferenceBasics.crefEqual(cref,cref2)
6877 ✗ then Expression.crefExp(cref3);
6878
6879 case (cref, DAE.COMPLEX_EQUATION(lhs=DAE.CREF(cref2,_),rhs=e)::_)
6880 guard ComponentReferenceBasics.crefEqual(cref,cref2)
6881 then e;
6882
6883 case (cref, _::equations)
6884 algorithm
6885 4156 (outExp,i) := findCorrespondingBinding(cref,equations,i+1);
6886 then outExp;
6887
6888 end match;
6889 end findCorrespondingBinding;
6890
6891 public function isPartial
6892 input SCode.Partial partialPrefix;
6893 input DAE.Mod mods;
6894 output SCode.Partial outPartial;
6895 algorithm
6896 outPartial := match (partialPrefix,mods)
6897 case (SCode.PARTIAL(),DAE.NOMOD()) then SCode.PARTIAL();
6898 else SCode.NOT_PARTIAL();
6899 end match;
6900 end isPartial;
6901
6902 public function isFunctionInput
6903 input ClassInf.State classState;
6904 input Absyn.Direction direction;
6905 output Boolean functionInput;
6906 algorithm
6907 functionInput := match(classState, direction)
6908 case (ClassInf.FUNCTION(), Absyn.INPUT()) then true;
6909 else false;
6910 end match;
6911 end isFunctionInput;
6912
6913 public function extractComment
6914 "This function extracts the comment section from a list of elements."
6915 input list<DAE.Element> elts;
6916 output SCode.Comment cmt=SCode.COMMENT(NONE(),NONE());
6917 algorithm
6918
2/2
✓ Branch 0 taken 1275794 times.
✓ Branch 1 taken 854901 times.
2130695 for elt in elts loop
6919 () := match elt
6920 case DAE.COMMENT(cmt=cmt)
6921 algorithm
6922 116934 return;
6923 then fail();
6924 else ();
6925 end match;
6926 end for;
6927 end extractComment;
6928
6929 protected function mergeClassComments
6930 "This function merges two comments together. The rule is that the string
6931 comment is taken from the first comment, and the annotations from both
6932 comments are merged."
6933 input SCode.Comment comment1;
6934 input SCode.Comment comment2;
6935 output SCode.Comment outComment;
6936 algorithm
6937 outComment := match(comment1, comment2)
6938 local
6939 Option<SCode.Annotation> ann1,ann2,ann;
6940 Option<String> str1,str2,str;
6941 list<SCode.SubMod> mods1,mods2,mods;
6942 SourceInfo info;
6943 case (SCode.COMMENT(SOME(SCode.ANNOTATION(SCode.MOD(subModLst=mods1,info=info))),str1),SCode.COMMENT(SOME(SCode.ANNOTATION(SCode.MOD(subModLst=mods2))),str2))
6944 algorithm
6945 ✗ str := if isSome(str1) then str1 else str2;
6946 ✗ mods := listAppend(mods1,mods2);
6947 ✗ then SCode.COMMENT(SOME(SCode.ANNOTATION(SCode.MOD(SCode.NOT_FINAL(),SCode.NOT_EACH(),mods,NONE(),NONE(),info))),str);
6948 case (SCode.COMMENT(ann1,str1),SCode.COMMENT(ann2,str2))
6949 algorithm
6950 ✗ str := if isSome(str1) then str1 else str2;
6951 ✗ ann := if isSome(ann1) then ann1 else ann2;
6952 ✗ then SCode.COMMENT(ann,str);
6953 end match;
6954 end mergeClassComments;
6955
6956 public function makeNonExpSubscript
6957 input DAE.Subscript inSubscript;
6958 output DAE.Subscript outSubscript;
6959 algorithm
6960 outSubscript := match inSubscript
6961 local
6962 DAE.Exp e;
6963 DAE.Subscript subscript;
6964 case DAE.INDEX(e)
6965 ✗ then DAE.WHOLE_NONEXP(e);
6966 case subscript as DAE.WHOLE_NONEXP(_)
6967 then subscript;
6968 end match;
6969 end makeNonExpSubscript;
6970
6971 protected function getFunctionAttributes
6972 "Looks at the annotations of an SCode.Element to create the function attributes,
6973 i.e. Inline and Purity"
6974 input SCode.Element cl;
6975 input list<DAE.Var> vl;
6976 input SCode.Comment inheritedComment;
6977 output DAE.FunctionAttributes attr;
6978 protected
6979 SCode.Restriction restriction;
6980 SCode.FunctionRestriction fres;
6981 Boolean isOpenModelicaPure, isImpure, hasOutVars, unboxArgs;
6982 DAE.NoReturn noReturn;
6983 DAE.FunctionBuiltin isBuiltin;
6984 DAE.InlineType inlineType;
6985 String name;
6986 list<DAE.Var> inVars,outVars;
6987 Absyn.FunctionPurity purity;
6988 DAE.Purity daePurity;
6989 algorithm
6990 69216 restriction := SCodeUtil.getClassRestriction(cl);
6991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69216 times.
69216 SCode.Restriction.R_FUNCTION(functionRestriction = fres) := restriction;
6992 69216 daePurity := InstBasics.getFunctionRestrictionPurity(SCodeUtil.getFunctionRestrictionPurity(fres), inheritedComment, newFrontend = false);
6993
2/2
✓ Branch 1 taken 69213 times.
✓ Branch 2 taken 3 times.
69216 noReturn := if SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment, "__OpenModelica_NoReturn") then DAE.NoReturn.NORETURN else DAE.NoReturn.RETURNS;
6994
6995 attr := matchcontinue fres
6996 case SCode.FR_EXTERNAL_FUNCTION(purity)
6997 algorithm
6998 46705 isImpure := AbsynUtil.isImpure(purity);
6999 46705 inVars := List.select(vl,Types.isInputVar);
7000 46705 outVars := List.select(vl,Types.isOutputVar);
7001 46705 name := SCodeUtil.isBuiltinFunction(cl,List.map(inVars,TypesDump.getVarName),List.map(outVars,TypesDump.getVarName));
7002 44985 inlineType := InstBasics.commentIsInlineFunc(inheritedComment);
7003 44985 unboxArgs := SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment, "__OpenModelica_UnboxArguments");
7004
2/2
✓ Branch 0 taken 44752 times.
✓ Branch 1 taken 233 times.
89970 then (DAE.FUNCTION_ATTRIBUTES(inlineType,false,daePurity,false,DAE.FUNCTION_BUILTIN(SOME(name), unboxArgs),DAE.FP_NON_PARALLEL(),noReturn));
7005
7006 //parallel functions: There are some builtin functions.
7007 case SCode.FR_PARALLEL_FUNCTION()
7008 algorithm
7009 ✗ inVars := List.select(vl,Types.isInputVar);
7010 ✗ outVars := List.select(vl,Types.isOutputVar);
7011 ✗ name := SCodeUtil.isBuiltinFunction(cl,List.map(inVars,TypesDump.getVarName),List.map(outVars,TypesDump.getVarName));
7012 ✗ inlineType := InstBasics.commentIsInlineFunc(inheritedComment);
7013 ✗ isOpenModelicaPure := not SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment,"__OpenModelica_Impure");
7014 ✗ unboxArgs := SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment, "__OpenModelica_UnboxArguments");
7015 ✗ then (DAE.FUNCTION_ATTRIBUTES(inlineType,false,daePurity,false,DAE.FUNCTION_BUILTIN(SOME(name), unboxArgs),DAE.FP_PARALLEL_FUNCTION(),noReturn));
7016
7017 //parallel functions: non-builtin
7018 case SCode.FR_PARALLEL_FUNCTION()
7019 algorithm
7020 ✗ inlineType := InstBasics.commentIsInlineFunc(inheritedComment);
7021 ✗ isBuiltin := if SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment,"__OpenModelica_BuiltinPtr") then DAE.FUNCTION_BUILTIN_PTR() else DAE.FUNCTION_NOT_BUILTIN();
7022 ✗ isOpenModelicaPure := not SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment,"__OpenModelica_Impure");
7023 ✗ then DAE.FUNCTION_ATTRIBUTES(inlineType,false,daePurity,false,isBuiltin,DAE.FP_PARALLEL_FUNCTION(),noReturn);
7024
7025 //kernel functions: never builtin and never inlined.
7026 case SCode.FR_KERNEL_FUNCTION()
7027 ✗ then DAE.FUNCTION_ATTRIBUTES(DAE.NO_INLINE(),false,daePurity, false, DAE.FUNCTION_NOT_BUILTIN(),DAE.FP_KERNEL_FUNCTION(),noReturn);
7028
7029 else
7030 algorithm
7031 24231 inlineType := InstBasics.commentIsInlineFunc(inheritedComment);
7032 24231 hasOutVars := List.any(vl,Types.isOutputVar);
7033
2/2
✓ Branch 1 taken 23712 times.
✓ Branch 2 taken 519 times.
24231 isBuiltin := if SCodeUtil.commentHasBooleanNamedAnnotation(inheritedComment,"__OpenModelica_BuiltinPtr") then DAE.FUNCTION_BUILTIN_PTR() else DAE.FUNCTION_NOT_BUILTIN();
7034
7035 // In Modelica 3.2 and before, external functions with side-effects are not marked.
7036
7/8
✓ Branch 0 taken 23691 times.
✓ Branch 1 taken 540 times.
✓ Branch 3 taken 1203 times.
✓ Branch 4 taken 22488 times.
✓ Branch 5 taken 490 times.
✓ Branch 6 taken 713 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 490 times.
24231 if daePurity == DAE.Purity.UNDEFINED and SCodeUtil.isExternalFunctionRestriction(fres) and
7037 not (hasOutVars or Config.languageStandardAtLeast(Config.LanguageStandard._3_3)) then
7038 daePurity := DAE.Purity.IMPURE;
7039 end if;
7040 24231 then
7041 DAE.FUNCTION_ATTRIBUTES(inlineType,false,daePurity,false,isBuiltin,DAE.FP_NON_PARALLEL(),noReturn);
7042 end matchcontinue;
7043 end getFunctionAttributes;
7044
7045 public function checkFunctionElement
7046 "Verifies that an element of a function is correct, i.e.
7047 public input/output, protected variable/parameter/constant or algorithm section"
7048 input DAE.Element elt;
7049 input Boolean isExternal;
7050 input SourceInfo info;
7051 algorithm
7052 () := match (elt, isExternal)
7053 local
7054 String str;
7055
7056 // Variables have already been checked in checkFunctionVar.
7057 case (DAE.VAR(), _) then ();
7058
7059 case (DAE.ALGORITHM(algorithm_= DAE.ALGORITHM_STMTS({DAE.STMT_ASSIGN(
7060 exp = DAE.METARECORDCALL())})), _)
7061 algorithm
7062 // We need to know the inlineType to make a good notification
7063 // Error.addSourceMessage(true,Error.COMPILER_NOTIFICATION, {"metarecordcall"}, info);
7064 then ();
7065
7066 case (DAE.ALGORITHM(), false) then ();
7067
7068 case (DAE.COMMENT(), _) then ();
7069
7070 else
7071 algorithm
7072 ✗ str := DAEDump.dumpElementsStr({elt});
7073 ✗ Error.addSourceMessage(Error.FUNCTION_ELEMENT_WRONG_KIND,{str},info);
7074 ✗ then fail();
7075 end match;
7076 end checkFunctionElement;
7077
7078 public function printElementAndModList
7079 input list<tuple<SCode.Element, DAE.Mod>> inLstElAndMod;
7080 output String outStr;
7081 algorithm
7082 outStr := match inLstElAndMod
7083 local
7084 SCode.Element e;
7085 DAE.Mod m;
7086 list<tuple<SCode.Element, DAE.Mod>> rest;
7087 String s1, s2, s3, s;
7088
7089 case {} then "";
7090
7091 case (e,m)::rest
7092 algorithm
7093 ✗ s1 := SCodeDump.unparseElementStr(e,SCodeDump.defaultOptions);
7094 ✗ s2 := Mod.printModStr(m);
7095 ✗ s3 := printElementAndModList(rest);
7096 ✗ s := "Element:\n" + s1 + "\nModifier: " + s2 + "\n" + s3;
7097 then
7098 s;
7099
7100 end match;
7101 end printElementAndModList;
7102
7103 protected function splitClassDefsAndComponents
7104 input list<tuple<SCode.Element, DAE.Mod>> inLstElAndMod;
7105 output list<tuple<SCode.Element, DAE.Mod>> outClassDefs;
7106 output list<tuple<SCode.Element, DAE.Mod>> outComponentDefs;
7107 algorithm
7108 (outClassDefs, outComponentDefs) := match inLstElAndMod
7109 local
7110 SCode.Element e;
7111 DAE.Mod m;
7112 list<tuple<SCode.Element, DAE.Mod>> rest, clsdefs, compdefs;
7113
7114 case {} then ({},{});
7115
7116 // components
7117 case (e as SCode.COMPONENT(),m)::rest
7118 algorithm
7119 ✗ (clsdefs, compdefs) := splitClassDefsAndComponents(rest);
7120 ✗ then
7121 (clsdefs, (e,m)::compdefs);
7122
7123 // classes and others
7124 case (e,m)::rest
7125 algorithm
7126 ✗ (clsdefs, compdefs) := splitClassDefsAndComponents(rest);
7127 ✗ then
7128 ((e,m)::clsdefs, compdefs);
7129
7130 end match;
7131 end splitClassDefsAndComponents;
7132
7133 public function selectModifiers
7134 "this function selects the correct modifiers for class/binding
7135 i.e.
7136 fromMerging: redeclare constant Boolean standardOrderComponents = tru
7137 fromRedeclareType: = true
7138 take binding to be the second and the other one you make NOMOD
7139 as it doesn't belong in the Boolean class.
7140 Weird Modelica.Media stuff"
7141 input DAE.Mod fromMerging;
7142 input DAE.Mod fromRedeclareType;
7143 input Absyn.Path typePath;
7144 output DAE.Mod bindingMod;
7145 output DAE.Mod classMod;
7146 algorithm
7147 // if the thing we got from merging is a redeclare
7148 // for a component of a basic type, skip it!
7149
2/2
✓ Branch 1 taken 529932 times.
✓ Branch 2 taken 5 times.
529937 bindingMod := if redeclareBasicType(fromMerging) then fromRedeclareType else fromMerging;
7150 classMod := fromRedeclareType;
7151 end selectModifiers;
7152
7153 public function redeclareBasicType
7154 input DAE.Mod mod;
7155 output Boolean isRedeclareOfBasicType;
7156 algorithm
7157 isRedeclareOfBasicType := matchcontinue mod
7158 local
7159 String name;
7160 Absyn.Path path;
7161 // you cannot redeclare a basic type, only the properties and the binding, i.e.
7162 // redeclare constant Boolean standardOrderComponents = true
7163 case DAE.REDECL(element = SCode.COMPONENT(typeSpec=Absyn.TPATH(path=path))) algorithm
7164
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 75 times.
87 true := Config.synchronousFeaturesAllowed();
7165
7166 75 name := AbsynUtil.pathFirstIdent(path);
7167 // BTH
7168
2/2
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 6 times.
75 true := listMember(name, {"Real", "Integer", "Boolean", "String", "Clock"});
7169 then true;
7170
7171 case DAE.REDECL(element = SCode.COMPONENT(typeSpec=Absyn.TPATH(path=path))) algorithm
7172
2/2
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 12 times.
81 false := Config.synchronousFeaturesAllowed();
7173
7174 12 name := AbsynUtil.pathFirstIdent(path);
7175 // BTH
7176
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 true := listMember(name, {"Real", "Integer", "Boolean", "String"});
7177 then true;
7178
7179 else false;
7180 end matchcontinue;
7181 end redeclareBasicType;
7182
7183 public function optimizeFunctionCheckForLocals
7184 "* Does tail recursion optimization"
7185 input Absyn.Path path;
7186 input list<DAE.Element> inElts;
7187 input Option<DAE.Element> oalg;
7188 input list<DAE.Element> acc;
7189 input list<String> invars;
7190 input list<String> outvars;
7191 output list<DAE.Element> outElts;
7192 algorithm
7193 outElts := match (inElts, oalg)
7194 local
7195 list<DAE.Statement> stmts;
7196 DAE.Element elt,elt1,elt2;
7197 DAE.ElementSource source;
7198 String str,name;
7199 list<DAE.Element> elts;
7200 // No algorithm section; allowed
7201 15068 case ({}, NONE()) then listReverse(acc);
7202 case ({}, SOME(DAE.ALGORITHM(DAE.ALGORITHM_STMTS(stmts),source)))
7203 algorithm
7204 // Adding tail recursion optimization
7205 6991 stmts := optimizeLastStatementTail(path,stmts,listReverse(invars),listReverse(outvars),{});
7206 13982 then listReverse(DAE.ALGORITHM(DAE.ALGORITHM_STMTS(stmts),source)::acc);
7207 // Remove empty sections
7208 case ((DAE.ALGORITHM(algorithm_=DAE.ALGORITHM_STMTS({})))::elts, _)
7209 10 then optimizeFunctionCheckForLocals(path,elts,oalg,acc,invars,outvars);
7210 case ((elt1 as DAE.ALGORITHM(source=source))::elts, SOME(elt2))
7211 algorithm
7212 ✗ str := AbsynUtil.pathString(path);
7213 ✗ if not Config.acceptMetaModelicaGrammar() then
7214 ✗ Error.addSourceMessage(Error.FUNCTION_MULTIPLE_ALGORITHM,{str},ElementSource.getElementSourceFileInfo(source));
7215 end if;
7216 ✗ then optimizeFunctionCheckForLocals(path,elts,SOME(elt1),elt2::acc,invars,outvars);
7217 case ((elt as DAE.ALGORITHM())::elts, NONE())
7218 6991 then optimizeFunctionCheckForLocals(path,elts,SOME(elt),acc,invars,outvars);
7219 case ((elt as DAE.VAR(componentRef=DAE.CREF_IDENT(ident=name),direction=DAE.OUTPUT()))::elts, _)
7220 23219 then optimizeFunctionCheckForLocals(path,elts,oalg,elt::acc,invars,name::outvars);
7221 case ((elt as DAE.VAR(componentRef=DAE.CREF_IDENT(ident=name),direction=DAE.INPUT()))::elts, _)
7222 46062 then optimizeFunctionCheckForLocals(path,elts,oalg,elt::acc,name::invars,outvars);
7223 22901 case (elt::elts, _) then optimizeFunctionCheckForLocals(path,elts,oalg,elt::acc,invars,outvars);
7224 end match;
7225 end optimizeFunctionCheckForLocals;
7226
7227 protected function optimizeLastStatementTail
7228 input Absyn.Path path;
7229 input list<DAE.Statement> inStmts;
7230 input list<String> invars;
7231 input list<String> outvars;
7232 input list<DAE.Statement> acc;
7233 output list<DAE.Statement> ostmts;
7234 algorithm
7235 ostmts := match inStmts
7236 local
7237 DAE.Statement stmt;
7238 list<DAE.Statement> stmts;
7239
7240 case {stmt}
7241 algorithm
7242 8704 stmt := optimizeStatementTail(path,stmt,invars,outvars);
7243 8704 then listReverse(stmt::acc);
7244 18664 case stmt::stmts then optimizeLastStatementTail(path,stmts,invars,outvars,stmt::acc);
7245 end match;
7246 end optimizeLastStatementTail;
7247
7248 protected function optimizeStatementTail
7249 input Absyn.Path path;
7250 input DAE.Statement inStmt;
7251 input list<String> invars;
7252 input list<String> outvars;
7253 output DAE.Statement ostmt;
7254 algorithm
7255 ostmt := matchcontinue (inStmt, outvars)
7256 local
7257 DAE.Type tp;
7258 DAE.Exp lhs,rhs,cond;
7259 list<DAE.Exp> lhsLst;
7260 String name;
7261 list<String> lhsNames;
7262 list<DAE.Statement> stmts;
7263 DAE.ElementSource source;
7264 DAE.Statement stmt;
7265 DAE.Else else_;
7266
7267 case (DAE.STMT_ASSIGN(tp,lhs,rhs,source), _)
7268 algorithm
7269 6122 name := Expression.simpleCrefName(lhs);
7270 5555 rhs := optimizeStatementTail2(path,rhs,{name},invars,outvars,source);
7271
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 85 times.
86 stmt := if Expression.isTailCall(rhs) then DAE.STMT_NORETCALL(rhs,source) else DAE.STMT_ASSIGN(tp,lhs,rhs,source);
7272 then stmt;
7273 case (DAE.STMT_TUPLE_ASSIGN(tp,lhsLst,rhs,source), _)
7274 algorithm
7275 90 lhsNames := List.map(lhsLst,Expression.simpleCrefName);
7276 89 rhs := optimizeStatementTail2(path,rhs,lhsNames,invars,outvars,source);
7277
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 stmt := if Expression.isTailCall(rhs) then DAE.STMT_NORETCALL(rhs,source) else DAE.STMT_TUPLE_ASSIGN(tp,lhsLst,rhs,source);
7278 then stmt;
7279 case (DAE.STMT_IF(cond,stmts,else_,source), _)
7280 algorithm
7281 755 stmts := optimizeLastStatementTail(path,stmts,invars,outvars,{});
7282 755 else_ := optimizeElseTail(path,else_,invars,outvars);
7283 755 then DAE.STMT_IF(cond,stmts,else_,source);
7284 case (DAE.STMT_NORETCALL(rhs,source), {})
7285 algorithm
7286 91 rhs := optimizeStatementTail2(path,rhs,{},invars,{},source);
7287 7 stmt := DAE.STMT_NORETCALL(rhs,source);
7288 then stmt;
7289 else inStmt;
7290 end matchcontinue;
7291 end optimizeStatementTail;
7292
7293 protected function optimizeElseTail
7294 input Absyn.Path path;
7295 input DAE.Else inElse;
7296 input list<String> invars;
7297 input list<String> outvars;
7298 output DAE.Else outElse;
7299 algorithm
7300 outElse := matchcontinue inElse
7301 local
7302 DAE.Exp cond;
7303 list<DAE.Statement> stmts;
7304 DAE.Else else_;
7305
7306 case DAE.ELSEIF(cond,stmts,else_)
7307 algorithm
7308 320 stmts := optimizeLastStatementTail(path,stmts,invars,outvars,{});
7309 320 else_ := optimizeElseTail(path,else_,invars,outvars);
7310 320 then DAE.ELSEIF(cond,stmts,else_);
7311
7312 case DAE.ELSE(stmts)
7313 algorithm
7314 638 stmts := optimizeLastStatementTail(path,stmts,invars,outvars,{});
7315 638 then DAE.ELSE(stmts);
7316
7317 else inElse;
7318 end matchcontinue;
7319 end optimizeElseTail;
7320
7321 protected function optimizeStatementTail2
7322 input Absyn.Path path;
7323 input DAE.Exp rhs;
7324 input list<String> lhsVars;
7325 input list<String> invars;
7326 input list<String> outvars;
7327 input DAE.ElementSource source;
7328 output DAE.Exp orhs;
7329 algorithm
7330
2/2
✓ Branch 1 taken 209 times.
✓ Branch 2 taken 5526 times.
5735 true:=valueEq(lhsVars,outvars);
7331
2/2
✓ Branch 1 taken 5417 times.
✓ Branch 2 taken 109 times.
5526 (orhs,true) := optimizeStatementTail3(path,rhs,invars,lhsVars,source);
7332 end optimizeStatementTail2;
7333
7334 protected function optimizeStatementTail3
7335 input Absyn.Path path;
7336 input DAE.Exp rhs;
7337 input list<String> vars, lhsVars;
7338 input DAE.ElementSource source;
7339 output DAE.Exp orhs;
7340 output Boolean isTailRecursive;
7341 algorithm
7342 (orhs,isTailRecursive) := matchcontinue (path, rhs)
7343 local
7344 Absyn.Path path1,path2;
7345 String str;
7346 Boolean b1,b2;
7347 DAE.Type et;
7348 list<DAE.Exp> inputs;
7349 DAE.Exp e1,e2,e3;
7350 list<DAE.Element> localDecls;
7351 DAE.MatchType matchType;
7352 list<DAE.MatchCase> cases;
7353 list<list<String>> aliases;
7354 DAE.CallAttributes attr;
7355 DAE.Exp call;
7356
7357 case (path1, call as DAE.CALL(path=path2,attr=attr as DAE.CALL_ATTR(tailCall=DAE.NO_TAIL())))
7358 algorithm
7359
2/2
✓ Branch 1 taken 3512 times.
✓ Branch 2 taken 224 times.
3736 true := AbsynUtil.pathEqual(path1,path2);
7360 224 str := "Tail recursion of: " + ExpressionBasics.printExpStr(rhs) + " with input vars: " + stringDelimitList(vars,",");
7361
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 223 times.
224 if Flags.isSet(Flags.TAIL) then
7362 1 Error.addSourceMessage(Error.COMPILER_NOTIFICATION,{str},ElementSource.getElementSourceFileInfo(source));
7363 end if;
7364 448 attr.tailCall := DAE.TAIL(vars,lhsVars);
7365 224 call.attr := attr;
7366 then (call,true);
7367 case (_, DAE.IFEXP(e1,e2,e3))
7368 algorithm
7369 260 (e2,b1) := optimizeStatementTail3(path,e2,vars,lhsVars,source);
7370 260 (e3,b2) := optimizeStatementTail3(path,e3,vars,lhsVars,source);
7371
4/4
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 208 times.
✓ Branch 3 taken 14 times.
260 true := b1 or b2;
7372 52 then (DAE.IFEXP(e1,e2,e3),true);
7373 case (_, DAE.MATCHEXPRESSION(matchType as DAE.MATCH(_) /*TODO:matchcontinue*/,inputs,aliases,localDecls,cases,et))
7374 algorithm
7375 848 cases := optimizeStatementTailMatchCases(path,cases,false,{},vars,lhsVars,source);
7376 106 then (DAE.MATCHEXPRESSION(matchType,inputs,aliases,localDecls,cases,et),true);
7377 else (rhs,false);
7378 end matchcontinue;
7379 end optimizeStatementTail3;
7380
7381 protected function optimizeStatementTailMatchCases
7382 input Absyn.Path path;
7383 input list<DAE.MatchCase> inCases;
7384 input Boolean changed;
7385 input list<DAE.MatchCase> inAcc;
7386 input list<String> vars, lhsVars;
7387 input DAE.ElementSource source;
7388 output list<DAE.MatchCase> ocases;
7389 algorithm
7390 ocases := matchcontinue (inCases, changed, inAcc)
7391 local
7392 list<DAE.Pattern> patterns;
7393 list<DAE.Element> localDecls;
7394 list<DAE.Statement> body;
7395 Option<DAE.Exp> patternGuard;
7396 SourceInfo resultInfo,info;
7397 Integer jump;
7398 DAE.MatchCase case_;
7399 DAE.Exp exp;
7400 list<DAE.MatchCase> cases,acc;
7401 DAE.ElementSource sourceStmt;
7402
7403 106 case ({}, true, acc) then listReverse(acc);
7404 case (DAE.CASE(patterns,patternGuard,localDecls,body,SOME(exp),resultInfo,jump,info)::cases, _, acc)
7405 algorithm
7406
2/2
✓ Branch 1 taken 3532 times.
✓ Branch 2 taken 215 times.
3747 (exp,true) := optimizeStatementTail3(path,exp,vars,lhsVars,source);
7407 215 case_ := DAE.CASE(patterns,patternGuard,localDecls,body,SOME(exp),resultInfo,jump,info);
7408 215 then optimizeStatementTailMatchCases(path,cases,true,case_::acc,vars,lhsVars,source);
7409 case (DAE.CASE(patterns,patternGuard,localDecls,body,SOME(DAE.TUPLE({})),resultInfo,jump,info)::cases, _, acc)
7410 algorithm
7411
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 51 times.
122 DAE.STMT_NORETCALL(exp,sourceStmt) := List.last(body);
7412
2/2
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 6 times.
51 (exp,true) := optimizeStatementTail3(path,exp,vars,lhsVars,source);
7413 6 body := List.set(body,listLength(body),DAE.STMT_NORETCALL(exp,sourceStmt));
7414 6 case_ := DAE.CASE(patterns,patternGuard,localDecls,body,SOME(DAE.TUPLE({})),resultInfo,jump,info);
7415 6 then optimizeStatementTailMatchCases(path,cases,true,case_::acc,vars,lhsVars,source);
7416 case (case_::cases, _, acc)
7417 3585 then optimizeStatementTailMatchCases(path,cases,changed,case_::acc,vars,lhsVars,source);
7418 end matchcontinue;
7419 end optimizeStatementTailMatchCases;
7420
7421 public function pushStructuralParameters
7422 "Cannot be part of Env due to RML issues"
7423 input FCore.Cache cache;
7424 output FCore.Cache ocache;
7425 algorithm
7426 ocache := match cache
7427 local
7428 Option<FCore.Graph> ie;
7429 Mutable<AvlTreePathFunction.Tree> f;
7430 AvlSetCR.Tree ht;
7431 list<list<DAE.ComponentRef>> crs;
7432 Absyn.Path p;
7433 278992 case FCore.CACHE(ie,f,(ht,crs),p) then FCore.CACHE(ie,f,(ht,{}::crs),p);
7434 else cache;
7435 end match;
7436 end pushStructuralParameters;
7437
7438 public function popStructuralParameters
7439 "Cannot be part of Env due to RML issues"
7440 input FCore.Cache cache;
7441 input DAE.Prefix pre;
7442 output FCore.Cache ocache;
7443 algorithm
7444 ocache := match cache
7445 local
7446 Option<FCore.Graph> ie;
7447 Mutable<AvlTreePathFunction.Tree> f;
7448 AvlSetCR.Tree ht;
7449 list<DAE.ComponentRef> crs;
7450 list<list<DAE.ComponentRef>> crss;
7451 Absyn.Path p;
7452 case FCore.CACHE(ie,f,(ht,crs::crss),p)
7453 algorithm
7454 261378 ht := prefixAndAddCrefsToHt(cache,ht,pre,crs);
7455 261378 then FCore.CACHE(ie,f,(ht,crss),p);
7456 case FCore.CACHE(_,_,(_,{}),_) then cache;
7457 case FCore.NO_CACHE() then cache;
7458 end match;
7459 end popStructuralParameters;
7460
7461 protected function prefixAndAddCrefsToHt
7462 "Cannot be part of Env due to RML issues"
7463 input FCore.Cache cache;
7464 input output AvlSetCR.Tree set;
7465 input DAE.Prefix pre;
7466 input list<DAE.ComponentRef> icrs;
7467 algorithm
7468
2/2
✓ Branch 0 taken 9365 times.
✓ Branch 1 taken 261378 times.
270743 for cr in icrs loop
7469 9365 (_,cr) := PrefixUtil.prefixCref(cache, FGraph.empty(), InnerOuter.emptyInstHierarchy, pre, cr);
7470 9365 set := AvlSetCR.add(set,cr);
7471 end for;
7472 end prefixAndAddCrefsToHt;
7473
7474 protected function numStructuralParameterScopes
7475 input FCore.Cache cache;
7476 output Integer i;
7477 protected
7478 list<list<DAE.ComponentRef>> lst;
7479 algorithm
7480 ✗ FCore.CACHE(evaluatedParams=(_,lst)) := cache;
7481 ✗ i := listLength(lst);
7482 end numStructuralParameterScopes;
7483
7484 public function functionAlwaysFails
7485 "True if every execution of the function body reaches a guaranteed failure
7486 (fail(), assert(false), terminate()) before any normal return. Such functions
7487 are marked no-return so that calls to them can be treated as terminating."
7488 input list<DAE.Element> elts;
7489 output Boolean alwaysFails;
7490 protected
7491 list<list<DAE.Statement>> sections = {};
7492 algorithm
7493
2/2
✓ Branch 0 taken 99183 times.
✓ Branch 1 taken 22059 times.
121242 for e in elts loop
7494 _ := match e
7495 local list<DAE.Statement> ss;
7496 case DAE.ALGORITHM(algorithm_=DAE.ALGORITHM_STMTS(ss))
7497 algorithm sections := ss :: sections; then ();
7498 else ();
7499 end match;
7500 end for;
7501 22059 alwaysFails := stmtsAlwaysFail(List.flatten(listReverse(sections)));
7502 end functionAlwaysFails;
7503
7504 protected function stmtsAlwaysFail
7505 "Scan a statement sequence: it always fails if a guaranteed-fail statement is
7506 reached while every preceding statement merely falls through."
7507 input list<DAE.Statement> stmts;
7508 output Boolean alwaysFails = false;
7509 algorithm
7510
2/2
✓ Branch 0 taken 22182 times.
✓ Branch 1 taken 22478 times.
44660 for s in stmts loop
7511
2/2
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 22107 times.
22182 if statementGuaranteesFail(s) then
7512 alwaysFails := true;
7513 75 return;
7514 elseif not statementIsTransparent(s) then
7515 // a statement that may complete some other way (return, loop, try, ...);
7516 // we cannot prove the function always fails
7517 1583 return;
7518 end if;
7519 end for;
7520 end stmtsAlwaysFail;
7521
7522 protected function statementGuaranteesFail
7523 "True if executing this single statement always leads to a failure."
7524 input DAE.Statement s;
7525 output Boolean b;
7526 algorithm
7527 b := match s
7528 local list<DAE.Statement> ss; DAE.Else el; Boolean b1,b2;
7529 case DAE.STMT_NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("fail"),expLst={})) then true;
7530 case DAE.STMT_ASSERT(cond=DAE.BCONST(false)) then true;
7531 case DAE.STMT_TERMINATE() then true;
7532 case DAE.STMT_IF(statementLst=ss, else_=el)
7533 algorithm
7534 900 b1 := stmtsAlwaysFail(ss);
7535 900 b2 := elseGuaranteesFail(el);
7536 900 then b1 and b2;
7537 else false;
7538 end match;
7539 end statementGuaranteesFail;
7540
7541 protected function elseGuaranteesFail
7542 input DAE.Else inElse;
7543 output Boolean b;
7544 algorithm
7545 b := match inElse
7546 local list<DAE.Statement> ss; DAE.Else el; Boolean b1,b2;
7547 case DAE.NOELSE() then false;
7548 801 case DAE.ELSE(statementLst=ss) then stmtsAlwaysFail(ss);
7549 case DAE.ELSEIF(statementLst=ss, else_=el)
7550 algorithm
7551 376 b1 := stmtsAlwaysFail(ss);
7552 376 b2 := elseGuaranteesFail(el);
7553 376 then b1 and b2;
7554 end match;
7555 end elseGuaranteesFail;
7556
7557 protected function statementIsTransparent
7558 "True if the statement always completes normally and falls through, so the
7559 scan for a guaranteed failure may continue past it. Treating a maybe-failing
7560 assign/call as transparent is sound: reaching a later guaranteed failure
7561 means the function fails either way."
7562 input DAE.Statement s;
7563 output Boolean b;
7564 algorithm
7565 b := match s
7566 case DAE.STMT_ASSIGN() then true;
7567 case DAE.STMT_TUPLE_ASSIGN() then true;
7568 case DAE.STMT_ASSIGN_ARR() then true;
7569 case DAE.STMT_ARRAY_INIT() then true;
7570 case DAE.STMT_NORETCALL() then true;
7571 else false;
7572 end match;
7573 end statementIsTransparent;
7574
7575 public function checkFunctionDefUse
7576 "Finds any variable that might be used without first being defined"
7577 input list<DAE.Element> elts;
7578 input SourceInfo info;
7579 algorithm
7580 () := matchcontinue info
7581 local
7582 case _
7583 algorithm
7584 22059 checkFunctionDefUse2(elts,NONE(),{},{},info);
7585 then ();
7586 else
7587 algorithm
7588 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR, {"InstUtil.checkFunctionDefUse failed"}, info);
7589 then ();
7590 end matchcontinue;
7591 end checkFunctionDefUse;
7592
7593 protected function checkFunctionDefUse2
7594 "Finds any variable that might be used without first being defined"
7595 input list<DAE.Element> elts;
7596 input Option<list<DAE.Statement>> alg "NONE() in first iteration";
7597 input list<String> inUnbound "{} in first iteration";
7598 input list<String> inOutputs "List of variables that are also used, when returning";
7599 input SourceInfo inInfo;
7600 output list<String> outUnbound;
7601 algorithm
7602 outUnbound := match (elts, alg, inUnbound, inOutputs)
7603 local
7604 list<DAE.Element> rest;
7605 list<DAE.Statement> stmts,prevStmts;
7606 list<String> unbound,maybeUnbound,outputs,names,outNames;
7607 String name;
7608 DAE.InstDims dims;
7609 DAE.VarDirection dir;
7610 list<DAE.Var> vars;
7611 case ({}, NONE(), _, _)
7612 // This would run also for partial function inst... So let's skip it
7613 // equation
7614 // unbound = List.fold1(outputs, checkOutputDefUse, inInfo, unbound);
7615 then inUnbound;
7616 case ({}, SOME(stmts), unbound, outputs)
7617 algorithm
7618 6991 (_,_,unbound,maybeUnbound) := List.fold1(stmts, checkFunctionDefUseStmt, false, (false,false,unbound,{}));
7619 6991 unbound := List.fold1(outputs, checkOutputDefUse, inInfo, unbound);
7620 // Outputs that are only assigned on some control flow paths cannot be
7621 // proven to be initialized; the specification recommends a warning when
7622 // the static check is not possible. Only enabled on request to avoid
7623 // flooding existing code with warnings.
7624
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6991 times.
6991 if Flags.isSet(Flags.CHECK_DEF_USE) then
7625 ✗ for name in outputs loop
7626 ✗ if listMember(name, maybeUnbound) then
7627 ✗ Error.addSourceMessage(Error.UNASSIGNED_FUNCTION_OUTPUT_UNPROVEN, {name}, inInfo);
7628 end if;
7629 end for;
7630 end if;
7631 then unbound;
7632 case (DAE.VAR(direction=DAE.INPUT())::rest, _, unbound, _)
7633 algorithm
7634 46062 unbound := checkFunctionDefUse2(rest,alg,unbound,inOutputs,inInfo);
7635 then unbound;
7636 case (DAE.VAR(direction=dir,componentRef=DAE.CREF_IDENT(ident=name),ty=DAE.T_COMPLEX(complexClassType=ClassInf.RECORD(_),varLst=vars),dims=dims,binding=NONE())::rest, _, unbound, _)
7637 algorithm
7638 1976 vars := List.filterOnTrue(vars, Types.varIsVariable);
7639 // TODO: We filter out parameters at the moment. I'm unsure if this is correct. Might be that this is an automatic error...
7640 1976 names := List.map1r(List.map(vars, TypesDump.getVarName), stringAppend, name + ".");
7641 // print("for record: " + stringDelimitList(names,",") + "\n");
7642 // Arrays with unknown bounds (size(cr,1), etc) are treated as initialized because they may have 0 dimensions checked for in the code
7643
2/2
✓ Branch 1 taken 663 times.
✓ Branch 2 taken 1313 times.
1976 outNames := if DAEUtil.varDirectionEqual(dir,DAE.OUTPUT()) then names else {};
7644
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1971 times.
1976 names := if Expression.dimensionsKnownAndNonZero(dims) then names else {};
7645 1976 unbound := listAppend(names,unbound);
7646 1976 outputs := listAppend(outNames,inOutputs);
7647 1976 unbound := checkFunctionDefUse2(rest,alg,unbound,outputs,inInfo);
7648 then unbound;
7649 case (DAE.VAR(direction=dir,componentRef=DAE.CREF_IDENT(ident=name),dims=dims,binding=NONE())::rest, _, unbound, _)
7650 algorithm
7651 // Arrays with unknown bounds (size(cr,1), etc) are treated as initialized because they may have 0 dimensions checked for in the code
7652 30068 unbound := List.consOnTrue(Expression.dimensionsKnownAndNonZero(dims),name,unbound);
7653 30068 outputs := List.consOnTrue(DAEUtil.varDirectionEqual(dir,DAE.OUTPUT()),name,inOutputs);
7654 30068 unbound := checkFunctionDefUse2(rest,alg,unbound,outputs,inInfo);
7655 then unbound;
7656 case (DAE.ALGORITHM(algorithm_=DAE.ALGORITHM_STMTS(stmts))::rest, NONE(), unbound, _)
7657 algorithm
7658 6991 unbound := checkFunctionDefUse2(rest,SOME(stmts),unbound,inOutputs,inInfo);
7659 then unbound;
7660 // Several algorithm sections run in sequence; analyse them as one body.
7661 case (DAE.ALGORITHM(algorithm_=DAE.ALGORITHM_STMTS(stmts))::rest, SOME(prevStmts), unbound, _)
7662 algorithm
7663 ✗ unbound := checkFunctionDefUse2(rest,SOME(listAppend(prevStmts,stmts)),unbound,inOutputs,inInfo);
7664 then unbound;
7665 case (_::rest, _, unbound, _)
7666 algorithm
7667 18630 unbound := checkFunctionDefUse2(rest,alg,unbound,inOutputs,inInfo);
7668 then unbound;
7669 end match;
7670 end checkFunctionDefUse2;
7671
7672 protected function checkOutputDefUse
7673 input String name;
7674 input SourceInfo info;
7675 input list<String> inUnbound;
7676 output list<String> outUnbound;
7677 protected
7678 Boolean b;
7679 algorithm
7680 11323 b := listMember(name,inUnbound);
7681 11323 Error.assertionOrAddSourceMessage(not b, Error.WARNING_DEF_USE, {name}, info);
7682 11323 outUnbound := List.filter1OnTrue(inUnbound,Util.stringNotEqual,name);
7683 end checkOutputDefUse;
7684
7685 protected function checkFunctionDefUseStmt
7686 "Find any variable that might be used in the statement without prior definition. Any defined variables are removed from undefined.
7687 The fourth element of the state tuple tracks variables that are assigned on
7688 some but not all control flow paths: uses of those cannot be proven to be
7689 defined (reported separately, only for MetaModelica)."
7690 input DAE.Statement inStmt;
7691 input Boolean inLoop;
7692 input tuple<Boolean,Boolean,list<String>,list<String>> inUnbound "Return or Break ; Returned for sure ; Unbound ; Possibly unbound";
7693 output tuple<Boolean,Boolean,list<String>,list<String>> outUnbound "";
7694 algorithm
7695 outUnbound := match (inStmt, inUnbound)
7696 local
7697 DAE.ElementSource source;
7698 String str,iter;
7699 DAE.Exp exp,lhs,rhs,exp1,exp2;
7700 list<DAE.Exp> lhss;
7701 list<String> unbound,maybe,maybeBody,unboundBefore,lhsNames,guaranteed;
7702 Boolean b,b1,b2;
7703 DAE.Else else_;
7704 list<DAE.Statement> stmts;
7705 SourceInfo info;
7706
7707 case (_, (true,_,_,_)) then inUnbound;
7708 case (_, (false,true,_,_))
7709 algorithm
7710 ✗ info := ElementSource.getElementSourceFileInfo(ElementSource.getStatementSource(inStmt));
7711 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR,
7712 {"InstUtil.checkFunctionDefUseStmt failed"}, info);
7713 ✗ then fail();
7714 case (DAE.STMT_ASSIGN(exp1=lhs,exp=rhs,source=source), (_,_,unbound,maybe))
7715 algorithm
7716 30799 info := ElementSource.getElementSourceFileInfo(source);
7717 30799 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(rhs,findUnboundVariableUse,(unbound,maybe,info));
7718 // Traverse subs too! arr[x] := ..., x unbound
7719 30799 (unbound,maybe) := traverseCrefSubs(lhs,info,unbound,maybe);
7720 30799 unbound := crefFiltering(lhs,unbound);
7721 30799 maybe := crefFiltering(lhs,maybe);
7722 30799 then ((false,false,unbound,maybe));
7723 case (DAE.STMT_TUPLE_ASSIGN(expExpLst=lhss,exp=rhs,source=source), (_,_,unbound,maybe))
7724 algorithm
7725 678 info := ElementSource.getElementSourceFileInfo(source);
7726 678 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(rhs,findUnboundVariableUse,(unbound,maybe,info));
7727 // Traverse subs too! arr[x] := ..., x unbound
7728
2/2
✓ Branch 0 taken 1518 times.
✓ Branch 1 taken 678 times.
2196 for l in lhss loop
7729 1518 (unbound,maybe) := traverseCrefSubs(l,info,unbound,maybe);
7730 end for;
7731 678 unbound := List.fold(lhss,crefFiltering,unbound);
7732 678 maybe := List.fold(lhss,crefFiltering,maybe);
7733 678 then ((false,false,unbound,maybe));
7734 case (DAE.STMT_ASSIGN_ARR(lhs=lhs,exp=rhs,source=source), (_,_,unbound,maybe))
7735 algorithm
7736 1483 info := ElementSource.getElementSourceFileInfo(source);
7737 1483 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(rhs,findUnboundVariableUse,(unbound,maybe,info));
7738 // Traverse subs too! arr[x] := ..., x unbound
7739 1483 (unbound,maybe) := traverseCrefSubs(lhs,info,unbound,maybe);
7740 1483 unbound := crefFiltering(lhs,unbound);
7741 1483 maybe := crefFiltering(lhs,maybe);
7742 1483 then ((false,false,unbound,maybe));
7743 case (DAE.STMT_IF(exp,stmts,else_,source), (_,_,unbound,maybe))
7744 algorithm
7745 1552 info := ElementSource.getElementSourceFileInfo(source);
7746 1552 (b1,b2,unbound,maybe) := checkFunctionDefUseElse(DAE.ELSEIF(exp,stmts,else_),unbound,maybe,inLoop,info);
7747
4/4
✓ Branch 0 taken 1550 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1550 times.
✓ Branch 3 taken 2 times.
4652 then ((b1,b2,unbound,maybe));
7748 case (DAE.STMT_FOR(iter=iter,range=exp,statementLst=stmts,source=source), (_,_,unbound,maybe))
7749 algorithm
7750 406 info := ElementSource.getElementSourceFileInfo(source);
7751 406 unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,iter);
7752 406 maybe := List.filter1OnTrue(maybe,Util.stringNotEqual,iter);
7753 406 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7754 unboundBefore := unbound;
7755 406 (_,b,unbound,maybeBody) := List.fold1(stmts, checkFunctionDefUseStmt, true, (false,false,unbound,maybe));
7756 // the loop body may run zero times, so anything assigned in it cannot
7757 // be proven to be assigned afterwards
7758 406 maybe := List.unionOnTrue(maybe, maybeBody, stringEq);
7759 406 maybe := List.unionOnTrue(maybe, List.setDifferenceOnTrue(unboundBefore, unbound, stringEq), stringEq);
7760
1/2
✓ Branch 0 taken 406 times.
✗ Branch 1 not taken.
812 then ((b,b,unbound,maybe));
7761 case (DAE.STMT_PARFOR(iter=iter,range=exp,statementLst=stmts,source=source), (_,_,unbound,maybe))
7762 algorithm
7763 ✗ info := ElementSource.getElementSourceFileInfo(source);
7764 ✗ unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,iter);
7765 ✗ maybe := List.filter1OnTrue(maybe,Util.stringNotEqual,iter);
7766 ✗ (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7767 unboundBefore := unbound;
7768 ✗ (_,b,unbound,maybeBody) := List.fold1(stmts, checkFunctionDefUseStmt, true, (false,false,unbound,maybe));
7769 ✗ maybe := List.unionOnTrue(maybe, maybeBody, stringEq);
7770 ✗ maybe := List.unionOnTrue(maybe, List.setDifferenceOnTrue(unboundBefore, unbound, stringEq), stringEq);
7771 ✗ then ((b,b,unbound,maybe));
7772 case (DAE.STMT_WHILE(exp=DAE.BCONST(true),statementLst=stmts), (_,_,unbound,maybe))
7773 algorithm
7774 ✗ guaranteed := whileTrueBreakAssigned(stmts, unbound);
7775 unboundBefore := unbound;
7776 ✗ (_,_,unbound,maybeBody) := List.fold1(stmts, checkFunctionDefUseStmt, true, (false,false,unbound,maybe));
7777 ✗ maybe := List.unionOnTrue(maybe, maybeBody, stringEq);
7778 ✗ maybe := List.unionOnTrue(maybe, List.setDifferenceOnTrue(unboundBefore, unbound, stringEq), stringEq);
7779 ✗ maybe := List.setDifferenceOnTrue(maybe, guaranteed, stringEq);
7780 ✗ then ((false,false,unbound,maybe));
7781 case (DAE.STMT_WHILE(exp=exp,statementLst=stmts,source=source), (_,_,unbound,maybe))
7782 algorithm
7783 116 info := ElementSource.getElementSourceFileInfo(source);
7784 116 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7785 unboundBefore := unbound;
7786 116 (_,b,unbound,maybeBody) := List.fold1(stmts, checkFunctionDefUseStmt, true, (false,false,unbound,maybe));
7787 // the loop body may run zero times, so anything assigned in it cannot
7788 // be proven to be assigned afterwards
7789 116 maybe := List.unionOnTrue(maybe, maybeBody, stringEq);
7790 116 maybe := List.unionOnTrue(maybe, List.setDifferenceOnTrue(unboundBefore, unbound, stringEq), stringEq);
7791
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
232 then ((b,b,unbound,maybe));
7792 case (DAE.STMT_ASSERT(cond=DAE.BCONST(false)), _) // TODO: Re-write these earlier from assert(false,msg) to terminate(msg)
7793 then ((true,true,{},{}));
7794 case (DAE.STMT_ASSERT(cond=exp1,msg=exp2,source=source), (_,_,unbound,maybe))
7795 algorithm
7796 437 info := ElementSource.getElementSourceFileInfo(source);
7797 437 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp1,findUnboundVariableUse,(unbound,maybe,info));
7798 437 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp2,findUnboundVariableUse,(unbound,maybe,info));
7799 437 then ((false,false,unbound,maybe));
7800 case (DAE.STMT_TERMINATE(msg=exp,source=source), (_,_,unbound,maybe))
7801 algorithm
7802 ✗ info := ElementSource.getElementSourceFileInfo(source);
7803 ✗ (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7804 ✗ then ((true,true,unbound,maybe));
7805 case (DAE.STMT_NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("fail"),expLst={})), _)
7806 then ((true,true,{},{}));
7807 // a call to a function that never returns normally terminates this path
7808 case (DAE.STMT_NORETCALL(exp=DAE.CALL(attr=DAE.CALL_ATTR(noReturn=DAE.NoReturn.NORETURN))), _)
7809 then ((true,true,{},{}));
7810 case (DAE.STMT_NORETCALL(exp=exp as DAE.CALL(attr=DAE.CALL_ATTR(tailCall=DAE.TAIL(outVars=lhsNames))),source=source), (_,_,unbound,maybe))
7811 algorithm
7812 // a tail call assigns its TAIL output variables
7813 8 info := ElementSource.getElementSourceFileInfo(source);
7814 8 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7815 8 unbound := List.setDifferenceOnTrue(unbound,lhsNames,stringEq);
7816 8 maybe := List.setDifferenceOnTrue(maybe,lhsNames,stringEq);
7817 8 then ((false,false,unbound,maybe));
7818 case (DAE.STMT_NORETCALL(exp=exp,source=source), (_,_,unbound,maybe))
7819 algorithm
7820 740 info := ElementSource.getElementSourceFileInfo(source);
7821 740 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
7822 740 then ((false,false,unbound,maybe));
7823 13 case (DAE.STMT_BREAK(), (_,_,unbound,maybe)) then ((true,false,unbound,maybe));
7824 82 case (DAE.STMT_RETURN(), (_,_,unbound,maybe)) then ((true,true,unbound,maybe));
7825 1 case (DAE.STMT_CONTINUE(), (_,_,unbound,maybe)) then ((false,false,unbound,maybe));
7826 case (DAE.STMT_ARRAY_INIT(), _) then inUnbound;
7827 case (DAE.STMT_FAILURE(body=stmts), (_,_,unbound,maybe))
7828 algorithm
7829 unboundBefore := unbound;
7830
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 4 times.
6 (_,b,unbound,maybeBody) := List.fold1(stmts, checkFunctionDefUseStmt, inLoop, (false,false,unbound,maybe));
7831 // the failure body is expected to fail partway through, so anything
7832 // assigned in it cannot be proven to be assigned afterwards
7833 5 maybe := List.unionOnTrue(maybe, maybeBody, stringEq);
7834 5 maybe := List.unionOnTrue(maybe, List.setDifferenceOnTrue(unboundBefore, unbound, stringEq), stringEq);
7835
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
10 then ((b,b,unbound,maybe));
7836
7837 // STMT_WHEN not in functions
7838 // STMT_REINIT not in functions
7839 else
7840 algorithm
7841 ✗ str := DAEDump.ppStatementStr(inStmt);
7842 ✗ str := "InstUtil.checkFunctionDefUseStmt failed: " + str;
7843 ✗ info := ElementSource.getElementSourceFileInfo(ElementSource.getStatementSource(inStmt));
7844 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR, {str}, info);
7845 ✗ then fail();
7846 end match;
7847 end checkFunctionDefUseStmt;
7848
7849 protected function whileTrueBreakAssigned
7850 "Variables definitely assigned on every control-flow path that leaves a
7851 'while true' loop via break; those are defined after the loop. Nested loops
7852 and failure blocks are conservatively credited with nothing assigned."
7853 input list<DAE.Statement> stmts;
7854 input list<String> entryUnbound;
7855 output list<String> assigned;
7856 protected
7857 Option<list<String>> atBreak;
7858 algorithm
7859 ✗ (_, _, atBreak) := walkBreakAssigned(stmts, entryUnbound);
7860 assigned := match atBreak
7861 local list<String> u;
7862 // u holds the variables possibly still unbound at some break
7863 ✗ case SOME(u) then List.setDifferenceOnTrue(entryUnbound, u, stringEq);
7864 // no break: the loop never falls through, so code after it is unreachable
7865 else entryUnbound;
7866 end match;
7867 end whileTrueBreakAssigned;
7868
7869 protected function walkBreakAssigned
7870 "Walk a statement sequence tracking which of the entry variables are still
7871 unbound. Returns the fall-through unbound set, whether the sequence always
7872 exits (break/return), and the union of the unbound sets seen at each break."
7873 input list<DAE.Statement> stmts;
7874 input list<String> inUnbound;
7875 output list<String> outUnbound = inUnbound;
7876 output Boolean exits = false;
7877 output Option<list<String>> atBreak = NONE();
7878 protected
7879 list<String> ub, ue;
7880 Boolean xt, xe;
7881 Option<list<String>> bt, be, ifBreak;
7882 algorithm
7883 ✗ for s in stmts loop
7884 _ := match s
7885 local
7886 DAE.Exp lhs;
7887 list<DAE.Exp> lhss;
7888 list<DAE.Statement> ss;
7889 DAE.Else el;
7890 case DAE.STMT_ASSIGN(exp1=lhs)
7891 ✗ algorithm outUnbound := crefFiltering(lhs, outUnbound); then ();
7892 case DAE.STMT_ASSIGN_ARR(lhs=lhs)
7893 ✗ algorithm outUnbound := crefFiltering(lhs, outUnbound); then ();
7894 case DAE.STMT_TUPLE_ASSIGN(expExpLst=lhss)
7895 ✗ algorithm outUnbound := List.fold(lhss, crefFiltering, outUnbound); then ();
7896 case DAE.STMT_BREAK()
7897 algorithm
7898 ✗ atBreak := mergeBreakUnbound(atBreak, SOME(outUnbound));
7899 ✗ exits := true;
7900 then ();
7901 ✗ case DAE.STMT_RETURN() algorithm exits := true; then ();
7902 ✗ case DAE.STMT_TERMINATE() algorithm exits := true; then ();
7903 case DAE.STMT_NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("fail"),expLst={}))
7904 ✗ algorithm exits := true; then ();
7905 case DAE.STMT_IF(statementLst=ss, else_=el)
7906 algorithm
7907 ✗ (ub, xt, bt) := walkBreakAssigned(ss, outUnbound);
7908 ✗ (ue, xe, be) := walkBreakAssignedElse(el, outUnbound);
7909 ✗ (outUnbound, exits, ifBreak) := mergeBranches(outUnbound, ub, xt, bt, ue, xe, be);
7910 ✗ atBreak := mergeBreakUnbound(atBreak, ifBreak);
7911 then ();
7912 else ();
7913 end match;
7914 ✗ if exits then break; end if;
7915 end for;
7916 end walkBreakAssigned;
7917
7918 protected function walkBreakAssignedElse
7919 input DAE.Else inElse;
7920 input list<String> inUnbound;
7921 output list<String> outUnbound;
7922 output Boolean exits;
7923 output Option<list<String>> atBreak;
7924 protected
7925 list<String> ub, ue;
7926 Boolean xt, xe;
7927 Option<list<String>> bt, be;
7928 algorithm
7929 (outUnbound, exits, atBreak) := match inElse
7930 local
7931 list<DAE.Statement> ss;
7932 DAE.Else el;
7933 ✗ case DAE.NOELSE() then (inUnbound, false, NONE());
7934 ✗ case DAE.ELSE(statementLst=ss) then walkBreakAssigned(ss, inUnbound);
7935 case DAE.ELSEIF(statementLst=ss, else_=el)
7936 algorithm
7937 ✗ (ub, xt, bt) := walkBreakAssigned(ss, inUnbound);
7938 ✗ (ue, xe, be) := walkBreakAssignedElse(el, inUnbound);
7939 ✗ then mergeBranches(inUnbound, ub, xt, bt, ue, xe, be);
7940 end match;
7941 end walkBreakAssignedElse;
7942
7943 protected function mergeBranches
7944 "Combine the then- and else-branch results of an if into the state after the
7945 if. A variable is assigned afterwards only if assigned in both fall-through
7946 branches; the if exits only if both branches exit."
7947 input list<String> entryUnbound;
7948 input list<String> thenUnbound;
7949 input Boolean thenExits;
7950 input Option<list<String>> thenBreak;
7951 input list<String> elseUnbound;
7952 input Boolean elseExits;
7953 input Option<list<String>> elseBreak;
7954 output list<String> outUnbound;
7955 output Boolean exits;
7956 output Option<list<String>> atBreak;
7957 algorithm
7958 ✗ atBreak := mergeBreakUnbound(thenBreak, elseBreak);
7959 ✗ if thenExits and elseExits then
7960 exits := true;
7961 outUnbound := entryUnbound;
7962 elseif thenExits then
7963 exits := false;
7964 outUnbound := elseUnbound;
7965 elseif elseExits then
7966 exits := false;
7967 outUnbound := thenUnbound;
7968 else
7969 exits := false;
7970 ✗ outUnbound := List.unionOnTrue(thenUnbound, elseUnbound, stringEq);
7971 end if;
7972 end mergeBranches;
7973
7974 protected function mergeBreakUnbound
7975 "A variable is possibly unbound at a break if it is so on either path."
7976 input Option<list<String>> a;
7977 input Option<list<String>> b;
7978 output Option<list<String>> res;
7979 algorithm
7980 res := match (a, b)
7981 local list<String> la, lb;
7982 case (NONE(), _) then b;
7983 case (_, NONE()) then a;
7984 ✗ case (SOME(la), SOME(lb)) then SOME(List.unionOnTrue(la, lb, stringEq));
7985 end match;
7986 end mergeBreakUnbound;
7987
7988 protected function checkFunctionDefUseElse
7989 input DAE.Else inElse;
7990 input list<String> inUnbound;
7991 input list<String> inMaybeUnbound;
7992 input Boolean inLoop;
7993 input SourceInfo info;
7994 output tuple<Boolean,Boolean,list<String>,list<String>> outUnbound;
7995 algorithm
7996 outUnbound := match (inElse, inUnbound, inLoop)
7997 local
7998 DAE.Exp exp;
7999 list<DAE.Statement> stmts;
8000 DAE.Else else_;
8001 list<String> unbound,unboundBranch,maybe,maybeBranch,assignedThen,assignedElse,proven,entryUnbound;
8002 Boolean b1,b2,b3,b4;
8003 474 case (DAE.NOELSE(), _, _) then ((false,false,inUnbound,inMaybeUnbound));
8004 case (DAE.ELSEIF(exp,stmts,else_), unbound, _)
8005 algorithm
8006 maybe := inMaybeUnbound;
8007 1989 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(exp,findUnboundVariableUse,(unbound,maybe,info));
8008 entryUnbound := unbound;
8009 1989 (b1,b2,unboundBranch,maybeBranch) := checkFunctionDefUseElse(else_,unbound,maybe,inLoop,info);
8010
2/2
✓ Branch 1 taken 1661 times.
✓ Branch 2 taken 328 times.
3650 (b3,b4,unbound,maybe) := List.fold1(stmts, checkFunctionDefUseStmt, inLoop, (false,false,unbound,maybe));
8011 // Pessimistic bookkeeping: anything that is assigned in only some of
8012 // the branches (ignoring branches that surely return or fail) cannot
8013 // be proven to be assigned after the if-statement.
8014
2/2
✓ Branch 0 taken 1895 times.
✓ Branch 1 taken 94 times.
1989 assignedThen := if b4 then {} else List.setDifferenceOnTrue(entryUnbound, unbound, stringEq);
8015
2/2
✓ Branch 0 taken 1906 times.
✓ Branch 1 taken 83 times.
1989 assignedElse := if b2 then {} else List.setDifferenceOnTrue(entryUnbound, unboundBranch, stringEq);
8016
2/2
✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 81 times.
1989 if b2 and not b4 then
8017 proven := assignedThen; // only the then-branch continues
8018 elseif b4 and not b2 then
8019 proven := assignedElse; // only the else-branch continues
8020 else
8021 1816 proven := List.intersectionOnTrue(assignedThen, assignedElse, stringEq);
8022 end if;
8023
4/4
✓ Branch 0 taken 1895 times.
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 1906 times.
✓ Branch 3 taken 83 times.
5790 maybe := List.unionOnTrue(if b4 then {} else maybe, if b2 then {} else maybeBranch, stringEq);
8024 1989 maybe := List.unionOnTrue(maybe,
8025 List.setDifferenceOnTrue(List.unionOnTrue(assignedThen, assignedElse, stringEq), proven, stringEq), stringEq);
8026 // Optimistic merge for the hard warnings: a variable assigned in any
8027 // branch is treated as assigned afterwards to avoid false positives.
8028 1989 unbound := List.intersectionOnTrue(unboundBranch, unbound, stringEq);
8029 /* Merge the state of the two branches. Either they can break/return or not */
8030 1989 b1 := b1 and b3;
8031 1989 b2 := b2 and b4;
8032
4/4
✓ Branch 0 taken 1987 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1987 times.
✓ Branch 3 taken 2 times.
5963 then ((b1,b2,unbound,maybe));
8033 case (DAE.ELSE(stmts), unbound, _)
8034 algorithm
8035
2/2
✓ Branch 1 taken 946 times.
✓ Branch 2 taken 132 times.
2024 (b1,b2,unbound,maybe) := List.fold1(stmts, checkFunctionDefUseStmt, inLoop, (false,false,unbound,inMaybeUnbound));
8036
4/4
✓ Branch 0 taken 995 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 991 times.
✓ Branch 3 taken 87 times.
3064 then ((b1,b2,unbound,maybe));
8037 end match;
8038 end checkFunctionDefUseElse;
8039
8040 protected function crefFiltering
8041 "If the expression is a cref, remove it from the unbound variables"
8042 input DAE.Exp inExp;
8043 input list<String> inUnbound;
8044 output list<String> outUnbound;
8045 algorithm
8046 outUnbound := match (inExp,inUnbound)
8047 local
8048 list<String> unbound;
8049 DAE.ComponentRef cr;
8050 DAE.Exp exp;
8051 DAE.Pattern pattern;
8052 String id1,id2;
8053 case (DAE.CREF(componentRef=DAE.WILD()),_) then inUnbound;
8054 // Assignment to part of a record
8055 case (DAE.CREF(componentRef=DAE.CREF_QUAL(ident=id1,componentRef=DAE.CREF_IDENT(ident=id2))),unbound)
8056 algorithm
8057 9242 unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,id1 + "." + id2);
8058 then unbound;
8059 // Assignment to the whole record - filter out everything it is prefix of
8060 case (DAE.CREF(componentRef=DAE.CREF_IDENT(ident=id1),ty=DAE.T_COMPLEX(complexClassType=ClassInf.RECORD(_))),unbound)
8061 algorithm
8062 1836 id1 := id1 + ".";
8063 1836 unbound := List.filter2OnTrue(unbound,Util.notStrncmp,id1,stringLength(id1));
8064 then unbound;
8065 case (DAE.CREF(componentRef=cr),unbound)
8066 algorithm
8067 55132 unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,ComponentReferenceBasics.crefFirstIdent(cr));
8068 then unbound;
8069 14 case (DAE.ASUB(exp=exp),unbound) then crefFiltering(exp,unbound);
8070 case (DAE.PATTERN(pattern=pattern),unbound)
8071 algorithm
8072 1324 (_,unbound) := Patternm.traversePattern(pattern,patternFiltering,unbound);
8073 1324 then unbound;
8074 else inUnbound;
8075 end match;
8076 end crefFiltering;
8077
8078 protected function patternFiltering
8079 input DAE.Pattern inPat;
8080 input list<String> inLst;
8081 output DAE.Pattern outPat=inPat;
8082 output list<String> unbound=inLst;
8083 algorithm
8084 unbound := match inPat
8085 case DAE.PAT_AS()
8086 16140 then List.filter1OnTrue(unbound,Util.stringNotEqual,inPat.id);
8087 case DAE.PAT_AS_FUNC_PTR()
8088 22 then List.filter1OnTrue(unbound,Util.stringNotEqual,inPat.id);
8089 else unbound;
8090 end match;
8091 end patternFiltering;
8092
8093 protected function traverseCrefSubs
8094 input DAE.Exp exp;
8095 input SourceInfo info;
8096 input list<String> inUnbound;
8097 input list<String> inMaybeUnbound;
8098 output list<String> outUnbound;
8099 output list<String> outMaybeUnbound;
8100 algorithm
8101 (outUnbound,outMaybeUnbound) := match (exp, inUnbound)
8102 local
8103 list<String> unbound,maybe;
8104 DAE.ComponentRef cr;
8105 case (DAE.CREF(componentRef=cr), unbound)
8106 algorithm
8107 33102 (_,(unbound,maybe,_)) := Expression.traverseExpTopDownCrefHelper(cr,findUnboundVariableUse,(unbound,inMaybeUnbound,info));
8108 then (unbound,maybe);
8109 else (inUnbound,inMaybeUnbound);
8110 end match;
8111 end traverseCrefSubs;
8112
8113 protected function findUnboundVariableUse "Check if the expression is used before it is defined"
8114 input DAE.Exp inExp;
8115 input tuple<list<String>,list<String>,SourceInfo> inTpl;
8116 output DAE.Exp outExp;
8117 output Boolean cont;
8118 output tuple<list<String>,list<String>,SourceInfo> outTpl;
8119 algorithm
8120 (outExp,cont,outTpl) := match (inExp,inTpl)
8121 local
8122 DAE.Exp exp;
8123 list<String> unbound,maybe,unboundLocal,assigned,assignedUnion,proven,maybeMerged,caseUnbound,caseMaybe;
8124 SourceInfo info;
8125 String str,name;
8126 DAE.ComponentRef cr;
8127 Boolean b,caseReturns,provenInit;
8128 tuple<list<String>,list<String>,SourceInfo> arg;
8129 list<DAE.Exp> inputs;
8130 list<DAE.Element> localDecls;
8131 list<DAE.MatchCase> cases;
8132 list<tuple<list<String>,list<String>,Boolean>> caseResults;
8133 DAE.Exp redExpr,iterExp;
8134 DAE.ReductionIterators iterators;
8135 Option<DAE.Exp> guardExp;
8136 list<String> iterUnbound,iterMaybe;
8137 case (exp as DAE.SIZE(),arg) then (exp,false,arg);
8138 case (exp as DAE.CALL(path=Absyn.IDENT("isPresent"), attr = DAE.CALL_ATTR(builtin = true)),arg)
8139 then (exp,false,arg);
8140 case (DAE.CREF(componentRef = DAE.WILD()), (_, _, info))
8141 algorithm
8142 // _ shouldn't be allowed to be used like a variable, but until that's
8143 // enforced just give an error message here instead of just failing.
8144 1 Error.addSourceMessage(Error.WARNING_DEF_USE, {"_"}, info);
8145 then (inExp, true, inTpl);
8146 case (exp as DAE.CREF(componentRef=cr),(unbound,maybe,info))
8147 algorithm
8148 181741 str := ComponentReferenceBasics.crefFirstIdent(cr);
8149
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 181698 times.
181741 if listMember(str,unbound) then
8150 43 Error.addSourceMessage(Error.WARNING_DEF_USE, {str}, info);
8151 43 unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,str);
8152 elseif listMember(str,maybe) then
8153 // assigned on some but not all control flow paths leading here
8154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
35 if Flags.isSet(Flags.CHECK_DEF_USE) then
8155 ✗ Error.addSourceMessage(Error.WARNING_DEF_USE_UNPROVEN, {str}, info);
8156 end if;
8157 35 maybe := List.filter1OnTrue(maybe,Util.stringNotEqual,str);
8158 end if;
8159 181741 then (exp,true,(unbound,maybe,info));
8160 case (exp as DAE.CALL(path=Absyn.IDENT(name)),(unbound,maybe,info))
8161 algorithm
8162
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5038 times.
5038 if listMember(name,unbound) then
8163 ✗ Error.addSourceMessage(Error.WARNING_DEF_USE, {name}, info);
8164 ✗ unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,name);
8165 elseif listMember(name,maybe) then
8166 ✗ if Flags.isSet(Flags.CHECK_DEF_USE) then
8167 ✗ Error.addSourceMessage(Error.WARNING_DEF_USE_UNPROVEN, {name}, info);
8168 end if;
8169 ✗ maybe := List.filter1OnTrue(maybe,Util.stringNotEqual,name);
8170 end if;
8171 5038 then (exp,true,(unbound,maybe,info));
8172 case (exp as DAE.MATCHEXPRESSION(inputs=inputs,localDecls=localDecls,cases=cases),(unbound,maybe,info))
8173 algorithm
8174 1169 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(DAE.LIST(inputs),findUnboundVariableUse,(unbound,maybe,info));
8175 1169 unboundLocal := checkFunctionDefUse2(localDecls,NONE(),unbound,{},info);
8176
4/4
✓ Branch 0 taken 5163 times.
✓ Branch 1 taken 1169 times.
✓ Branch 2 taken 5163 times.
✓ Branch 3 taken 1169 times.
6332 caseResults := list(findUnboundVariableUseInCase(c,unboundLocal,maybe) for c in cases);
8177 // Find variables assigned in a case, like: _ = match () case () equation o = 1.5; then ();
8178
4/4
✓ Branch 0 taken 5163 times.
✓ Branch 1 taken 1169 times.
✓ Branch 2 taken 5163 times.
✓ Branch 3 taken 1169 times.
6332 unbound := List.fold1r(list(Util.tuple31(t) for t in caseResults), List.intersectionOnTrue, stringEq, unbound);
8179 // Pessimistic bookkeeping: only variables that are assigned in every
8180 // case that can reach the code after the match-expression are proven
8181 // to be assigned; the rest cannot be proven to be initialized.
8182 provenInit := true;
8183 proven := {};
8184 assignedUnion := {};
8185 maybeMerged := {};
8186
2/2
✓ Branch 0 taken 5163 times.
✓ Branch 1 taken 1169 times.
6332 for t in caseResults loop
8187 5163 (caseUnbound,caseMaybe,caseReturns) := t;
8188
2/2
✓ Branch 0 taken 5062 times.
✓ Branch 1 taken 101 times.
5163 if not caseReturns then
8189 5062 assigned := List.setDifferenceOnTrue(unboundLocal, caseUnbound, stringEq);
8190
2/2
✓ Branch 0 taken 3893 times.
✓ Branch 1 taken 1169 times.
5062 proven := if provenInit then assigned else List.intersectionOnTrue(proven, assigned, stringEq);
8191 provenInit := false;
8192 5062 assignedUnion := List.unionOnTrue(assignedUnion, assigned, stringEq);
8193 5062 maybeMerged := List.unionOnTrue(maybeMerged, caseMaybe, stringEq);
8194 end if;
8195 end for;
8196
1/2
✓ Branch 0 taken 1169 times.
✗ Branch 1 not taken.
1169 if not provenInit then
8197 1169 maybe := List.unionOnTrue(maybeMerged,
8198 List.setDifferenceOnTrue(assignedUnion, proven, stringEq), stringEq);
8199 end if;
8200 1169 then (exp,false,(unbound,maybe,info));
8201 case (exp as DAE.REDUCTION(expr=redExpr,iterators=iterators),(unbound,maybe,info))
8202 algorithm
8203 // The iterator ranges are evaluated in the enclosing scope.
8204
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 180 times.
368 for it in iterators loop
8205 188 DAE.REDUCTIONITER(exp=iterExp) := it;
8206 188 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(iterExp,findUnboundVariableUse,(unbound,maybe,info));
8207 end for;
8208 // The iterator variables are bound within the reduction guard/body, so
8209 // they shadow any enclosing variable of the same name. Remember whether
8210 // each name was (maybe) unbound outside so the enclosing state can be
8211 // restored afterwards, and remove them while traversing the body.
8212 iterUnbound := {};
8213 iterMaybe := {};
8214
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 180 times.
368 for it in iterators loop
8215 188 DAE.REDUCTIONITER(id=name) := it;
8216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
188 if listMember(name,unbound) then
8217 iterUnbound := name :: iterUnbound;
8218 ✗ unbound := List.filter1OnTrue(unbound,Util.stringNotEqual,name);
8219 end if;
8220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
188 if listMember(name,maybe) then
8221 iterMaybe := name :: iterMaybe;
8222 ✗ maybe := List.filter1OnTrue(maybe,Util.stringNotEqual,name);
8223 end if;
8224 end for;
8225
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 180 times.
368 for it in iterators loop
8226 188 DAE.REDUCTIONITER(guardExp=guardExp) := it;
8227 188 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(DAE.META_OPTION(guardExp),findUnboundVariableUse,(unbound,maybe,info));
8228 end for;
8229 180 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(redExpr,findUnboundVariableUse,(unbound,maybe,info));
8230 // Restore the enclosing scope's status for the iterator names.
8231 180 unbound := listAppend(iterUnbound,unbound);
8232 180 maybe := listAppend(iterMaybe,maybe);
8233 180 then (exp,false,(unbound,maybe,info));
8234 case (exp,arg) then (exp,true,arg);
8235 end match;
8236 end findUnboundVariableUse;
8237
8238 protected function findUnboundVariableUseInCase "Check if the expression is used before it is defined"
8239 input DAE.MatchCase case_;
8240 input list<String> inUnbound;
8241 input list<String> inMaybeUnbound;
8242 output tuple<list<String>,list<String>,Boolean> outResult "Unbound ; Possibly unbound ; Surely returns or fails";
8243 algorithm
8244 outResult := match (case_,inUnbound)
8245 local
8246 SourceInfo info,resultInfo;
8247 Option<DAE.Exp> patternGuard,result;
8248 list<DAE.Pattern> patterns;
8249 list<DAE.Statement> body;
8250 list<String> unbound,maybe;
8251 Boolean returned;
8252 case (DAE.CASE(patterns=patterns,patternGuard=patternGuard,body=body,result=result,info=info,resultInfo=resultInfo),unbound)
8253 algorithm
8254 5163 maybe := inMaybeUnbound;
8255 5163 (_,unbound) := Patternm.traversePatternList(patterns,patternFiltering,unbound);
8256 5163 (_,maybe) := Patternm.traversePatternList(patterns,patternFiltering,maybe);
8257 5163 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(DAE.META_OPTION(patternGuard),findUnboundVariableUse,(unbound,maybe,info));
8258 5163 (_,returned,unbound,maybe) := List.fold1(body, checkFunctionDefUseStmt, true, (false,false,unbound,maybe));
8259 5163 (_,(unbound,maybe,_)) := Expression.traverseExpTopDown(DAE.META_OPTION(result),findUnboundVariableUse,(unbound,maybe,resultInfo));
8260 // a case without a result expression is 'then fail()': it never
8261 // continues past the match-expression
8262
5/8
✓ Branch 0 taken 5149 times.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5149 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 5062 times.
✓ Branch 7 taken 87 times.
5163 returned := returned or not isSome(result);
8263 5163 then ((unbound,maybe,returned));
8264 end match;
8265 end findUnboundVariableUseInCase;
8266
8267 public function checkParallelismWRTEnv
8268 input FCore.Graph inEnv;
8269 input String inName;
8270 input SCode.Attributes inAttr;
8271 input SourceInfo inInfo;
8272 output Boolean isValid;
8273 algorithm
8274 isValid := matchcontinue inAttr
8275 local
8276 String errorString,scopeName;
8277 Absyn.Direction dir;
8278 SCode.Parallelism prl;
8279 Boolean isparglobal;
8280 Boolean hasnodir;
8281 FCore.Ref r;
8282
8283 case SCode.ATTR(parallelism = prl, direction = dir)
8284 algorithm
8285 ✗ r := FGraph.lastScopeRef(inEnv);
8286 ✗ false := FNode.isRefTop(r);
8287 ✗ scopeName := FNode.refName(r);
8288 ✗ true := FGraph.checkScopeType({r}, SOME(FCore.PARALLEL_SCOPE()));
8289 ✗ isparglobal := SCodeUtil.parallelismEqual(prl, SCode.PARGLOBAL());
8290 ✗ hasnodir := not AbsynUtil.isInputOrOutput(dir);
8291 ✗ true := isparglobal and hasnodir;
8292
8293 ✗ errorString := "\n" +
8294 "- local parglobal component '" + inName +
8295 "' is declared in parallel/parkernel function '" + scopeName + "'. \n" +
8296 "- parglobal variables can be declared only in normal functions. \n";
8297
8298 ✗ Error.addSourceMessage(Error.PARMODELICA_ERROR,
8299 {errorString}, inInfo);
8300 then false;
8301
8302 else true;
8303
8304 end matchcontinue;
8305 end checkParallelismWRTEnv;
8306
8307 public function instDimsHasZeroDims
8308 input list<list<DAE.Dimension>> inInstDims;
8309 output Boolean outHasZeroDims;
8310 algorithm
8311 outHasZeroDims := matchcontinue inInstDims
8312 local
8313 list<DAE.Dimension> dims;
8314 InstDims rest_dims;
8315
8316 case dims :: _
8317 algorithm
8318
2/2
✓ Branch 1 taken 96440 times.
✓ Branch 2 taken 1 time.
96441 true := List.any(dims, Expression.dimensionIsZero);
8319 then
8320 true;
8321
8322 96440 case _ :: rest_dims then instDimsHasZeroDims(rest_dims);
8323
8324 else false;
8325 end matchcontinue;
8326 end instDimsHasZeroDims;
8327
8328 public function noModForUpdatedComponents "help function for updateComponentInEnv,
8329 For components that already have been visited by updateComponentsInEnv, they must be instantiated without
8330 modifiers to prevent infinite recursion"
8331 input SCode.Variability variability;
8332 input HashTable5.HashTable updatedComps;
8333 input Absyn.ComponentRef cref;
8334 input DAE.Mod mods;
8335 input DAE.Mod cmod;
8336 input SCode.Mod m;
8337 output DAE.Mod outMods;
8338 output DAE.Mod outCmod;
8339 output SCode.Mod outM;
8340 algorithm
8341 (outMods,outCmod,outM) := matchcontinue m
8342 case _
8343 guard BaseHashTable.hasKey(cref,updatedComps)
8344 algorithm
8345 2 checkVariabilityOfUpdatedComponent(variability,cref);
8346 then (DAE.NOMOD(),DAE.NOMOD(),SCode.NOMOD());
8347
8348 else (mods,cmod,m);
8349 end matchcontinue;
8350 end noModForUpdatedComponents;
8351
8352 public function propagateModFinal
8353 "Takes a component's modifier and final attribute, and return FINAL if either
8354 of them is final, otherwise NOT_FINAL."
8355 input DAE.Mod inMod;
8356 input SCode.Final inFinal;
8357 output SCode.Final outFinal;
8358 algorithm
8359 outFinal := match(inMod, inFinal)
8360 local
8361 SCode.Final fp;
8362
8363 // If the component is already final, keep it.
8364 case (_, SCode.FINAL()) then inFinal;
8365 // If we got a modifier, use its final prefix instead.
8366 case (DAE.MOD(finalPrefix = fp), _) then fp;
8367 // Otherwise, do nothing.
8368 else inFinal;
8369
8370 end match;
8371 end propagateModFinal;
8372
8373 //------------------------------
8374 //------ PDE extension: ------
8375 //------------------------------
8376 public type DomainFieldOpt = Option<tuple<Absyn.ComponentRef,DAE.ComponentRef>>;
8377 public type DomainFieldsLst = list<tuple<DAE.ComponentRef,list<Absyn.ComponentRef>>>;
8378
8379 public function addGhostCells
8380 //add ghost cells to fields that are differentiated in pder
8381 input list<tuple<SCode.Element, DAE.Mod>> inCompelts;
8382 input list<SCode.Equation> inEqs;
8383 output list<tuple<SCode.Element, DAE.Mod>> outCompelts;
8384 protected list<Absyn.Ident> fieldNamesP;
8385 protected list<tuple<SCode.Element, DAE.Mod>> ghostCompelts;
8386 algorithm
8387 34 fieldNamesP := List.fold(inEqs, fieldsInPderEq, {});
8388 34 ghostCompelts := List.fold1(inCompelts,addGhostCells2,fieldNamesP,{});
8389 34 outCompelts := listAppend(inCompelts,ghostCompelts);
8390 end addGhostCells;
8391
8392 function fieldsInPderEq
8393 //adds field variable names that are differentiated using pder
8394 //in given equation to given list if it isn't already there
8395 input SCode.Equation eq;
8396 input list<Absyn.Ident> inFieldNames;
8397 output list<Absyn.Ident> outFieldNames;
8398 algorithm
8399 outFieldNames := match eq
8400 local
8401 list<Absyn.Ident> fieldNames1;
8402 Absyn.Exp lhs_exp, rhs_exp;
8403 case SCode.EQ_PDE(expLeft = lhs_exp, expRight = rhs_exp)
8404 /*,domain = domainCr as Absyn.CREF_IDENT(), comment = comment, info = info))*/
8405 algorithm
8406 3 (_,fieldNames1) := AbsynUtil.traverseExpTopDown(lhs_exp, fieldInPderExp, inFieldNames);
8407 3 (_,fieldNames1) := AbsynUtil.traverseExpTopDown(rhs_exp, fieldInPderExp, fieldNames1);
8408 3 then
8409 listAppend(inFieldNames,fieldNames1);
8410 else
8411 inFieldNames;
8412 end match;
8413 end fieldsInPderEq;
8414
8415 function fieldInPderExp
8416 //if given expression is pder call, than adds the differentiated field name
8417 //to given list of names if it is not already there
8418 input Absyn.Exp inExp;
8419 input list<Absyn.Ident> inFieldNames;
8420 output Absyn.Exp outExp;
8421 output list<Absyn.Ident> outFieldNames;
8422 algorithm
8423 outFieldNames := match inExp
8424 local
8425 Absyn.Ident newFieldName;
8426 case Absyn.CALL(function_=Absyn.CREF_IDENT(name="pder"),functionArgs=Absyn.FUNCTIONARGS(args={Absyn.CREF(Absyn.CREF_IDENT(name=newFieldName)),_}))
8427 1 then
8428 List.unionElt(newFieldName,inFieldNames);
8429 case Absyn.CALL(function_=Absyn.CREF_IDENT(name="pder"),functionArgs=Absyn.FUNCTIONARGS(args={Absyn.CREF(Absyn.CREF_IDENT(name=newFieldName)),_,_}))
8430 1 then
8431 List.unionElt(newFieldName,inFieldNames);
8432 else
8433 inFieldNames;
8434 end match;
8435 outExp := inExp;
8436 end fieldInPderExp;
8437
8438 function addGhostCells2
8439 //if name of given variable is in the given array
8440 //adds ghost cells for it
8441 input tuple<SCode.Element, DAE.Mod> inCompelt;
8442 input list<Absyn.Ident> fieldNamesP;
8443 input list<tuple<SCode.Element, DAE.Mod>> inGhosts;
8444 output list<tuple<SCode.Element, DAE.Mod>> outGhosts;
8445 algorithm
8446 outGhosts := matchcontinue inCompelt
8447 local
8448 SCode.Ident name;
8449 SCode.Prefixes prefixes;
8450 Absyn.TypeSpec typeSpec;
8451 SCode.Comment comment;
8452 Option<Absyn.Exp> condition;
8453 SourceInfo info;
8454 SCode.Mod mod;
8455
8456 Absyn.ArrayDim arrayDims;
8457 SCode.ConnectorType connectorType;
8458 SCode.Parallelism parallelism;
8459 SCode.Variability variability;
8460 Absyn.Direction direction;
8461
8462 DAE.Mod daeMod;
8463
8464 tuple<SCode.Element, DAE.Mod> ghostL, ghostR;
8465
8466 case (SCode.COMPONENT(name, prefixes,
8467 SCode.ATTR(arrayDims,connectorType,parallelism,
8468 variability, direction, Absyn.FIELD()
8469 ), typeSpec,
8470 mod as SCode.MOD()/*modifications*/,
8471 comment, condition, info),daeMod) guard listMember(name, fieldNamesP)
8472 algorithm
8473 //remove domain from the subModLst:
8474 1 mod.subModLst := List.filterOnFalse(mod.subModLst,isSubModDomainOrStart);
8475
8476 1 ghostL := (SCode.COMPONENT(stringAppend(name,"$ghostL"), prefixes,
8477 SCode.ATTR(arrayDims,connectorType,parallelism,
8478 variability, direction, Absyn.NONFIELD()), typeSpec, mod,
8479 comment, condition, info),daeMod);
8480 1 ghostR := (SCode.COMPONENT(stringAppend(name,"$ghostR"), prefixes,
8481 SCode.ATTR(arrayDims,connectorType,parallelism,
8482 variability, direction, Absyn.NONFIELD()), typeSpec, mod,
8483 comment, condition, info),daeMod);
8484 then
8485 ghostL::ghostR::inGhosts;
8486 else
8487 inGhosts;
8488 end matchcontinue;
8489 end addGhostCells2;
8490
8491 function isSubModDomainOrStart
8492 input SCode.SubMod subMod;
8493 output Boolean isNotDomain;
8494 algorithm
8495 isNotDomain := match subMod
8496 local String idn;
8497 case SCode.NAMEMOD(ident=idn) guard idn=="domain" or idn=="start" then true;
8498 else false;
8499 end match;
8500 end isSubModDomainOrStart;
8501
8502
8503 public function elabField
8504 //For field variables: finds the "domain" modifier,
8505 //finds domain.N - length of discretized field array
8506 //and removes "domain" from the modifiers list.
8507 input FCore.Cache inCache;
8508 input FCore.Graph inEnv;
8509 input String name;
8510 input SCode.Attributes attr;
8511 input DAE.Dimensions inDims;
8512 input DAE.Mod inMod;
8513 input SourceInfo inInfo;
8514 output DAE.Dimensions outDims;
8515 output DAE.Mod outMod;
8516 output DomainFieldOpt outFieldDomOpt;
8517
8518 algorithm
8519 (outDims, outMod, outFieldDomOpt) := match(attr, inMod)
8520 local
8521 DAE.Dimension dim_f;
8522 SCode.Final finalPrefix;
8523 SCode.Each eachPrefix;
8524 list<DAE.SubMod> subModLst;
8525 Option<DAE.EqMod> binding;
8526 SourceInfo info;
8527 Integer N = -1;
8528 DAE.ComponentRef dcr;
8529 DAE.SubMod domainSubMod;
8530 case(SCode.ATTR(isField=Absyn.NONFIELD()),_)
8531 //TODO: check that the domain attribute (modifier) is not present.
8532 then
8533 (inDims,inMod,NONE());
8534 case(SCode.ATTR(isField=Absyn.FIELD()),DAE.MOD(finalPrefix = finalPrefix, eachPrefix = eachPrefix, subModLst = subModLst, binding = binding, info = info))
8535 algorithm
8536 //find the domain modifier:
8537 1 (domainSubMod, subModLst) := List.findAndRemove(subModLst, findDomainSubMod);
8538 1 dcr := getQualDcr(domainSubMod, inInfo);
8539 //get N from the domain and remove domain from the subModLst:
8540 1 (N, dcr) := getNDcr(dcr);
8541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (N == -1) then Error.addSourceMessageAndFail(Error.PDEModelica_ERROR,
8542 {"Domain of the field variable '" + name + "' not found."}, inInfo);
8543 end if;
8544 1 subModLst := listReverse(subModLst);
8545 1 subModLst := List.map(subModLst,addEach);
8546 1 outMod := DAE.MOD(finalPrefix, eachPrefix, subModLst, binding, info);
8547 1 dim_f := DAE.DIM_INTEGER(N);
8548 1 then
8549 (dim_f::inDims, outMod, SOME((Absyn.CREF_IDENT(name, {}),dcr)));
8550 case(_,DAE.NOMOD())
8551 algorithm
8552 ✗ Error.addSourceMessageAndFail(Error.PDEModelica_ERROR,
8553 {"Field variable '" + name + "' has no domain modifier."}, inInfo);
8554 then
8555 (inDims,inMod,NONE());
8556 end match;
8557 end elabField;
8558
8559 protected function findDomainSubMod
8560 input DAE.SubMod subMod;
8561 output Boolean isDomain;
8562 algorithm
8563 isDomain := match subMod
8564 case DAE.NAMEMOD(ident="domain") then true;
8565 else false;
8566 end match;
8567 end findDomainSubMod;
8568
8569 protected function getQualDcr
8570 input DAE.SubMod domainSubMod;
8571 input SourceInfo inInfo;
8572 output DAE.ComponentRef dcr;
8573 algorithm
8574 dcr := match domainSubMod
8575 local
8576 DAE.ComponentRef cr;
8577 case DAE.NAMEMOD(ident="domain", mod=DAE.MOD(binding=SOME(
8578 DAE.TYPED(
8579 modifierAsExp=DAE.CREF(
8580 componentRef = cr,
8581 ty=DAE.T_COMPLEX(
8582 complexClassType=ClassInf.RECORD(
8583 path=Absyn.FULLYQUALIFIED(
8584 path=Absyn.IDENT(name="DomainLineSegment1D")
8585 )
8586 )
8587 )
8588 )
8589 )
8590 )))
8591 then cr;
8592 case _
8593 algorithm
8594 ✗ Error.addSourceMessageAndFail(Error.PDEModelica_ERROR,
8595 {"The domain type is wrong.\n"}, inInfo);
8596 ✗ then
8597 fail();
8598 end match;
8599 end getQualDcr;
8600
8601 protected function getNDcr
8602 input DAE.ComponentRef dcr;
8603 output Integer outN;
8604 output DAE.ComponentRef outCrOpt;
8605 algorithm
8606 (outN,outCrOpt) := match dcr
8607 local
8608 DAE.ComponentRef cr1;
8609 list<DAE.Var> varLst;
8610 Integer N;
8611 case DAE.CREF_QUAL(componentRef = cr1)
8612 1 then getNDcr(cr1);
8613 case DAE.CREF_IDENT(identType = DAE.T_COMPLEX(varLst = varLst))
8614 algorithm
8615
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
1 SOME(N) := List.findSome(varLst,findN);
8616 then (N,dcr);
8617 end match;
8618 end getNDcr;
8619
8620
8621 protected function findN
8622 "a map function to find N in domain class modifiers"
8623 input DAE.Var inVar;
8624 output Option<Integer> optN;
8625 algorithm
8626 optN := match inVar
8627 local
8628 Integer N;
8629 case DAE.TYPES_VAR(name="N",binding=DAE.EQBOUND(evaluatedExp=SOME(Values.INTEGER(N))))
8630 then SOME(N);
8631 else NONE();
8632 end match;
8633 end findN;
8634
8635 protected function addEach
8636 "map function that adds each prefix to given modifier"
8637 input DAE.SubMod inSubMod;
8638 output DAE.SubMod outSubMod;
8639 protected DAE.Ident ident;
8640 protected SCode.Final finalPrefix;
8641 protected list<DAE.SubMod> subModLst;
8642 protected Option<DAE.EqMod> binding;
8643 protected SourceInfo info;
8644
8645 /* equation
8646 DAE.NAMEMOD(ident, DAE.MOD(finalPrefix, _, subModLst, eqModOption)) = inSubMod;
8647 outSubMod = DAE.NAMEMOD(ident, DAE.MOD(finalPrefix, SCode.EACH(), subModLst, eqModOption));*/
8648 algorithm
8649 outSubMod := match inSubMod
8650 case DAE.NAMEMOD(ident, DAE.MOD(finalPrefix, _, subModLst, binding, info))
8651 ✗ then DAE.NAMEMOD(ident, DAE.MOD(finalPrefix, SCode.EACH(), subModLst, binding, info));
8652 end match;
8653 end addEach;
8654
8655 //----end elabField and sub funs
8656
8657 public function optAppendField
8658 input DomainFieldsLst inDomFieldsLst;
8659 input DomainFieldOpt fieldDomOpt;
8660 output DomainFieldsLst outDomFieldsLst;
8661 algorithm
8662 outDomFieldsLst := match fieldDomOpt
8663 local
8664 Absyn.ComponentRef fieldCr;
8665 DAE.ComponentRef domainCr;
8666 Boolean found;
8667 case NONE()
8668 then inDomFieldsLst;
8669 case SOME((fieldCr,domainCr))
8670 algorithm
8671 1 (outDomFieldsLst, found) := List.map2Fold(inDomFieldsLst,optAppendFieldMapFun,domainCr,fieldCr,false);
8672
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if not found then
8673 1 outDomFieldsLst := (domainCr,{fieldCr})::inDomFieldsLst;
8674 end if;
8675 then
8676 outDomFieldsLst;
8677 end match;
8678 end optAppendField;
8679
8680 protected function optAppendFieldMapFun
8681 input tuple<DAE.ComponentRef,List<Absyn.ComponentRef>> inDomainFields;
8682 input DAE.ComponentRef domainCrToAdd;
8683 input Absyn.ComponentRef fieldCrToAdd;
8684 input Boolean inFound;
8685 output tuple<DAE.ComponentRef,List<Absyn.ComponentRef>> outDomainFields;
8686 output Boolean outFound;
8687 algorithm
8688 (outDomainFields, outFound) := matchcontinue (inDomainFields,inFound)
8689 local
8690 DAE.ComponentRef domainCr;
8691 List<Absyn.ComponentRef> fieldCrLst;
8692 case ((domainCr,fieldCrLst),false)
8693 algorithm
8694 ✗ true := ComponentReferenceBasics.crefEqual(domainCr,domainCrToAdd);
8695 ✗ then
8696 ((domainCr,fieldCrToAdd::fieldCrLst),true);
8697 else
8698 (inDomainFields,inFound);
8699 end matchcontinue;
8700 end optAppendFieldMapFun;
8701
8702 //----end optAppendField and sub funs
8703
8704 public function discretizePDE
8705 //main discretization function, converts PDE into set of ODEs
8706 input SCode.Equation inEQ;
8707 input DomainFieldsLst inDomFieldLst;
8708 // input list<tuple<String,Integer>> domainNLst;
8709 input List<SCode.Equation> inDiscretizedEQs;
8710 output List<SCode.Equation> outDiscretizedEQs;
8711 protected List<SCode.Equation> newDiscretizedEQs;
8712 algorithm
8713 newDiscretizedEQs := match inEQ
8714 local
8715 Absyn.Exp lhs_exp, rhs_exp;
8716 Absyn.ComponentRef domainCr, domainCr1;
8717 SCode.Comment comment;
8718 SourceInfo info;
8719 Integer N;
8720 List<Absyn.ComponentRef> fieldLst;
8721 Absyn.Ident name;
8722 list<Absyn.Subscript> subscripts;
8723
8724 //PDE with domain specified, allow for field variables:
8725 case SCode.EQ_PDE(expLeft = lhs_exp, expRight = rhs_exp,
8726 domain = domainCr as Absyn.CREF_IDENT(), comment = comment, info = info)
8727 algorithm
8728 2 (N,fieldLst) := getDomNFields(inDomFieldLst,domainCr,info);
8729 2 then creatFieldEqs(lhs_exp, rhs_exp, domainCr, N, fieldLst, comment, info);
8730
8731 //same as previous but with ".interior"
8732 case SCode.EQ_PDE(expLeft = lhs_exp, expRight = rhs_exp,
8733 domain = domainCr as Absyn.CREF_QUAL(name, subscripts, Absyn.CREF_IDENT(name="interior")),
8734 comment = comment, info = info)
8735 algorithm
8736 ✗ domainCr1 := Absyn.CREF_IDENT(name, subscripts);
8737 ✗ (N,fieldLst) := getDomNFields(inDomFieldLst,domainCr1,info);
8738 ✗ then creatFieldEqs(lhs_exp, rhs_exp, domainCr, N, fieldLst, comment, info);
8739
8740 //left boundary condition or extrapolation
8741 case SCode.EQ_PDE(expLeft = lhs_exp, expRight = rhs_exp,
8742 domain = Absyn.CREF_QUAL(name, subscripts, Absyn.CREF_IDENT(name="left")),
8743 comment = comment, info = info)
8744 algorithm
8745 1 domainCr1 := Absyn.CREF_IDENT(name, subscripts);
8746 1 (N,fieldLst) := getDomNFields(inDomFieldLst,domainCr1,info);
8747 1 (lhs_exp, _) := AbsynUtil.traverseExp(lhs_exp, extrapFieldTraverseFun, 1);
8748 1 (rhs_exp, _) := AbsynUtil.traverseExp(rhs_exp, extrapFieldTraverseFun, 1);
8749 1 then
8750 {newEQFun(1, lhs_exp, rhs_exp, domainCr1, N, true, fieldLst, comment, info)};
8751
8752 //right boundary condition or extrapolation
8753 case SCode.EQ_PDE(expLeft = lhs_exp, expRight = rhs_exp,
8754 domain = Absyn.CREF_QUAL(name, subscripts, Absyn.CREF_IDENT(name="right")),
8755 comment = comment, info = info)
8756 algorithm
8757 1 domainCr1 := Absyn.CREF_IDENT(name, subscripts);
8758 1 (N,fieldLst) := getDomNFields(inDomFieldLst,domainCr1,info);
8759 1 (lhs_exp, _) := AbsynUtil.traverseExp(lhs_exp, extrapFieldTraverseFun, N);
8760 1 (rhs_exp, _) := AbsynUtil.traverseExp(rhs_exp, extrapFieldTraverseFun, N);
8761 1 then
8762 {newEQFun(N, lhs_exp, rhs_exp, domainCr1, N, true, fieldLst, comment, info)};
8763 //Unhandled pde
8764 case SCode.EQ_PDE()
8765 algorithm
8766 ✗ print("Unhandled type of EQ_PDE in discretizePDE\n");
8767 ✗ fail();
8768 then {};
8769 //Other than EQ_PDE:
8770 else {inEQ};
8771 end match;
8772
8773 4 outDiscretizedEQs := listAppend(inDiscretizedEQs, newDiscretizedEQs);
8774 end discretizePDE;
8775
8776 protected function extrapFieldTraverseFun
8777 input Absyn.Exp inExp;
8778 input Integer inN "If N = 1 then left extrapolation, right extrapolation otherwise";
8779 output Absyn.Exp outExp;
8780 output Integer outN = inN;
8781 algorithm
8782 outExp := match inExp
8783 local
8784 Absyn.Ident name;
8785 list<Absyn.Subscript> subscripts;
8786 Integer i;
8787 case Absyn.CALL(
8788 function_ = Absyn.CREF_IDENT(name="extrapolateField", subscripts={}),
8789 functionArgs = Absyn.FUNCTIONARGS(args = {Absyn.CREF(Absyn.CREF_IDENT(name,subscripts))})
8790 )
8791 algorithm
8792
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if inN == 1 then
8793 i := 1;
8794 else
8795 i := -1;
8796 end if;
8797 3 then
8798 //TODO: add check wheter the field in extrapolateField arg is in given domain.
8799 Absyn.BINARY(
8800 Absyn.BINARY(
8801 Absyn.INTEGER(2),
8802 Absyn.MUL(),
8803 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(inN))::subscripts))
8804 ),
8805 Absyn.SUB(),
8806 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(inN+i))::subscripts))
8807 );
8808 else
8809 inExp;
8810 end match;
8811
8812
8813 end extrapFieldTraverseFun;
8814
8815
8816 protected function getDomNFields
8817 input DomainFieldsLst inDomFieldLst;
8818 input Absyn.ComponentRef inDomainCr;
8819 input SourceInfo info;
8820 output Integer outN = 0;
8821 output List<Absyn.ComponentRef> outFieldLst = {};
8822 algorithm
8823 try
8824
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
4 SOME((outN,outFieldLst)) := List.findSome(inDomFieldLst, function domNFieldsFindFun(inDomainCr = inDomainCr));
8825 else
8826 ✗ Error.addSourceMessageAndFail(Error.COMPILER_ERROR,{"There are no fields defined within the domain of this equation."}, info);
8827 end try;
8828 end getDomNFields;
8829
8830 protected function domNFieldsFindFun
8831 input tuple<DAE.ComponentRef,List<Absyn.ComponentRef>> inDomFields;
8832 input Absyn.ComponentRef inDomainCr;
8833 output Option<tuple<Integer,List<Absyn.ComponentRef>>> outOptNFields;
8834 algorithm
8835 outOptNFields := matchcontinue inDomFields
8836 local
8837 DAE.ComponentRef domainCr;
8838 List<Absyn.ComponentRef> fieldCrLst;
8839 list<DAE.Var> varLst;
8840 Integer N;
8841 case (domainCr, fieldCrLst)
8842 algorithm
8843
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 true := absynDAECrefEqualName(inDomainCr,domainCr);
8844
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 DAE.CREF_IDENT(identType = DAE.T_COMPLEX(varLst = varLst)) := domainCr;
8845
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 SOME(N) := List.findSome(varLst,findN);
8846 4 then
8847 SOME((N,fieldCrLst));
8848 else
8849 NONE();
8850 end matchcontinue;
8851 end domNFieldsFindFun;
8852
8853 protected function absynDAECrefEqualName
8854 input Absyn.ComponentRef domainCr1;
8855 input DAE.ComponentRef domainCr2;
8856 output Boolean equal;
8857 protected String name1, name2;
8858 algorithm
8859 //TODO: implement
8860 equal := match (domainCr1, domainCr2)
8861 case (Absyn.CREF_IDENT(name = name1), DAE.CREF_IDENT(ident = name2))
8862 guard
8863 stringEqual(name1,name2)
8864 then
8865 true;
8866 else
8867 false;
8868 end match;
8869 end absynDAECrefEqualName;
8870
8871
8872 protected function extrapolateFieldEq
8873 //extrapolateFieldEq(false,lhs_exp, rhs_exp, domainCr1, comment, info, fieldLst)
8874 input Boolean isRight; //otherwise is left
8875 input Absyn.ComponentRef fieldCr;
8876 input Absyn.ComponentRef domainCr;
8877 input Integer N;
8878 input SCode.Comment comment;
8879 input SourceInfo info;
8880 input List<Absyn.ComponentRef> fieldLst;
8881 output SCode.Equation outEQ;
8882 protected Absyn.Ident name;
8883 protected list<Absyn.Subscript> subscripts;
8884 protected Integer i1 = 1, i2 = 2, i3 = 3;
8885 algorithm
8886 ✗ if List.isMemberOnTrue(fieldCr,fieldLst,AbsynUtil.crefEqual) then
8887 (name, subscripts) := match fieldCr
8888 case Absyn.CREF_IDENT(name = name, subscripts = subscripts)
8889 then
8890 (name, subscripts);
8891 end match;
8892 //left eq: u_1 = 2*u_2 - u_3
8893 //right eq: u_N = 2*u_{N-1} - u_{N-2}
8894 ✗ if isRight then
8895 i1 := N;
8896 ✗ i2 := N - 1;
8897 ✗ i3 := N - 2;
8898 end if;
8899 ✗ outEQ := SCode.EQ_EQUALS(Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i1))::subscripts)),Absyn.BINARY(
8900 Absyn.BINARY(
8901 Absyn.INTEGER(2),
8902 Absyn.MUL(),
8903 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i2))::subscripts))
8904 ),
8905 Absyn.SUB(),
8906 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i3))::subscripts))
8907 ), comment, info);
8908 else
8909 ✗ fail();
8910 end if;
8911 end extrapolateFieldEq;
8912
8913 protected function creatFieldEqs "creates list of equations for fields. If the equation contains pder it spans 2:N-1, otherwise 1:N"
8914 input Absyn.Exp lhs_exp;
8915 input Absyn.Exp rhs_exp;
8916 input Absyn.ComponentRef domainCr;
8917 input Integer N;
8918 input List<Absyn.ComponentRef> fieldLst;
8919 input SCode.Comment comment;
8920 input SourceInfo info;
8921 output List<SCode.Equation> outDiscretizedEQs;
8922 protected Boolean bl, br;
8923 algorithm
8924 2 (_,bl) := AbsynUtil.traverseExp(lhs_exp, hasPderTraverseFun, false);
8925 2 (_,br) := AbsynUtil.traverseExp(rhs_exp, hasPderTraverseFun, false);
8926 //outDiscretizedEQs := match (AbsynUtil.traverseExp(lhs_exp, hasPderTraverseFun, false),Absyn.traverseExp(rhs_exp, hasPderTraverseFun, false))
8927 outDiscretizedEQs := match (bl, br)
8928 //case ((_,false),(_,false)) //no pder()
8929 case (false,false) //no pder()
8930
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 then //TODO: both branches are the same now, when using ghost cells, simplify!
8931 list(newEQFun(i, lhs_exp, rhs_exp, domainCr, N, false, fieldLst, comment, info) for i in 1:N);
8932
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 else //contains some pder()
8933 list(newEQFun(i, lhs_exp, rhs_exp, domainCr, N, false, fieldLst, comment, info) for i in 1:N);
8934 end match;
8935 end creatFieldEqs;
8936
8937
8938 protected function hasPderTraverseFun
8939 input Absyn.Exp inExp;
8940 input Boolean inHasPder;
8941 output Absyn.Exp outExp = inExp;
8942 output Boolean outHasPder;
8943 algorithm
8944 outHasPder := match (inExp,inHasPder)
8945 case (_,true)
8946 then true;
8947 case (Absyn.CALL(function_ = Absyn.CREF_IDENT(name="pder")),_)
8948 then true;
8949 else false;
8950 end match;
8951 end hasPderTraverseFun;
8952
8953 protected function newEQFun
8954 input Integer i;
8955 input Absyn.Exp inLhs_exp;
8956 input Absyn.Exp inRhs_exp;
8957 input Absyn.ComponentRef domainCr;
8958 input Integer N;
8959 input Boolean isBC; //-1 left ghost cell, 0 no ghost cell, 1 right ghost cell
8960 input list<Absyn.ComponentRef> fieldLst;
8961 input SCode.Comment comment;
8962 input SourceInfo info;
8963 output SCode.Equation outEQ;
8964 protected Absyn.Exp outLhs_exp, outRhs_exp;
8965 algorithm
8966
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
22 (outLhs_exp, _) := AbsynUtil.traverseExpTopDown(inLhs_exp,discretizeTraverseFun,(i,fieldLst,domainCr,info,false,N,isBC));
8967 12 (outRhs_exp, _) := AbsynUtil.traverseExpTopDown(inRhs_exp,discretizeTraverseFun,(i,fieldLst,domainCr,info,false,N,isBC));
8968 12 outEQ := SCode.EQ_EQUALS(outLhs_exp, outRhs_exp, comment, info);
8969 end newEQFun;
8970
8971 protected function discretizeTraverseFun
8972 input Absyn.Exp inExp;
8973 input tuple<Integer, list<Absyn.ComponentRef>, Absyn.ComponentRef, SourceInfo,Boolean,Integer,Boolean> inTup;
8974 output Absyn.Exp outExp;
8975 output tuple<Integer, list<Absyn.ComponentRef>, Absyn.ComponentRef, SourceInfo,Boolean,Integer,Boolean> outTup;
8976 protected Integer i,N;
8977 // protected String eqDomainName;
8978 protected list<Absyn.ComponentRef> fieldLst;
8979 protected SourceInfo info;
8980 protected Boolean skip, failVar,isBC;
8981 protected Absyn.ComponentRef domainCr;
8982 protected Absyn.Ident domName;
8983 algorithm
8984 196 failVar := false;
8985 196 (i, fieldLst, domainCr, info, skip, N, isBC) := inTup;
8986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 Absyn.CREF_IDENT(name = domName) := domainCr;
8987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 if skip then
8988 outExp := inExp;
8989 outTup := inTup;
8990 ✗ return;
8991 end if;
8992 outExp := matchcontinue inExp
8993 local
8994 Absyn.Ident name;
8995 list<Absyn.Subscript> subscripts;
8996 Absyn.ComponentRef fieldCr;
8997 Absyn.Exp exp, leftVar, actualVar, rightVar;
8998 case Absyn.CREF(Absyn.CREF_QUAL(name = domName, subscripts = {}, componentRef=Absyn.CREF_IDENT(name="x",subscripts={})))
8999 //coordinate x
9000 10 then
9001 Absyn.CREF(Absyn.CREF_QUAL(name = domName, subscripts = {}, componentRef=Absyn.CREF_IDENT(name="x",subscripts = {Absyn.SUBSCRIPT(Absyn.INTEGER(i))})));
9002 case Absyn.CREF(fieldCr as Absyn.CREF_IDENT(name, subscripts))
9003 //field
9004 algorithm
9005
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 12 times.
44 true := List.isMemberOnTrue(fieldCr,fieldLst,AbsynUtil.crefEqual);
9006
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 11 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 10 times.
22 exp := (if isBC and i == 1 then
9007 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostL"), subscripts)) //left BC
9008 elseif isBC and i == N then
9009 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostR"), subscripts)) //right BC
9010 else
9011 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i))::subscripts)) //no BC
9012 );
9013 then
9014 exp;
9015 case Absyn.CALL(Absyn.CREF_IDENT("pder",{}),Absyn.FUNCTIONARGS({Absyn.CREF(fieldCr as Absyn.CREF_IDENT(name, subscripts)),Absyn.CREF(Absyn.CREF_IDENT(name="x"))},_),{})
9016 //pder - first derivative
9017 algorithm
9018
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if not List.isMemberOnTrue(fieldCr,fieldLst,AbsynUtil.crefEqual) then
9019 ✗ failVar := true;
9020 ✗ Error.addSourceMessageAndFail(Error.COMPILER_ERROR,{"Field variable '" + name + "' has different domain than the equation or is not a field." }, info);
9021 end if;
9022 //skip = true
9023
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
9 leftVar := (if i == 1 then
9024 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostL"), subscripts))
9025 else
9026 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i-1))::subscripts))
9027 );
9028
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
9 rightVar := (if i == N then
9029 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostR"), subscripts))
9030 else
9031 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i+1))::subscripts))
9032 );
9033 5 then
9034 Absyn.BINARY(
9035 Absyn.BINARY(rightVar, Absyn.SUB(), leftVar),
9036 Absyn.DIV(),
9037 Absyn.BINARY(
9038 Absyn.INTEGER(2),
9039 Absyn.MUL(),
9040 Absyn.CREF(Absyn.CREF_QUAL(domName,{},Absyn.CREF_IDENT("dx",{})))
9041 )
9042 );
9043 case Absyn.CALL(Absyn.CREF_IDENT("pder",{}),Absyn.FUNCTIONARGS({Absyn.CREF(fieldCr as Absyn.CREF_IDENT(name, subscripts)),Absyn.CREF(Absyn.CREF_IDENT(name="x")),Absyn.CREF(Absyn.CREF_IDENT(name="x"))},_),{})
9044 //pder - second derivative
9045 algorithm
9046
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if not List.isMemberOnTrue(fieldCr,fieldLst,AbsynUtil.crefEqual) then
9047 ✗ failVar := true;
9048 ✗ Error.addSourceMessageAndFail(Error.COMPILER_ERROR,{"Field variable '" + name + "' has different domain than the equation or is not a field." }, info);
9049 end if;
9050 //skip = true
9051
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
9 leftVar := (if i == 1 then
9052 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostL"), subscripts))
9053 else
9054 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i-1))::subscripts))
9055 );
9056 10 actualVar := Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i))::subscripts));
9057
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
9 rightVar := (if i == N then
9058 Absyn.CREF(Absyn.CREF_IDENT(stringAppend(name,"$ghostR"), subscripts))
9059 else
9060 Absyn.CREF(Absyn.CREF_IDENT(name, Absyn.SUBSCRIPT(Absyn.INTEGER(i+1))::subscripts))
9061 );
9062 5 then
9063 Absyn.BINARY(
9064 Absyn.BINARY(
9065 Absyn.BINARY(
9066 leftVar, Absyn.SUB(), Absyn.BINARY(
9067 Absyn.INTEGER(2),Absyn.MUL(),actualVar
9068 )
9069 ), Absyn.ADD(),rightVar
9070 ), Absyn.DIV(), Absyn.BINARY(
9071 Absyn.CREF(Absyn.CREF_QUAL(domName,{},Absyn.CREF_IDENT("dx",{}))),Absyn.POW(),Absyn.INTEGER(2)
9072 )
9073 );
9074
9075
9076
9077 case Absyn.CALL(function_ = Absyn.CREF_IDENT("pder",{}), functionArgs = Absyn.FUNCTIONARGS({Absyn.CREF(_),_},_))
9078 //pder with differentiating wrt wrong variable
9079 algorithm
9080 ✗ Error.addSourceMessageAndFail(Error.COMPILER_ERROR,{"You are differentiating with respect to variable that is not a coordinate."}, info);
9081 then
9082 inExp;
9083 case Absyn.CALL(function_ = Absyn.CREF_IDENT("pder",{}), functionArgs = Absyn.FUNCTIONARGS({_,_},_))
9084 algorithm
9085 ✗ Error.addSourceMessageAndFail(Error.COMPILER_ERROR,{"Unsupported partial derivative."}, info);
9086 then
9087 inExp;
9088 else
9089 inExp;
9090 end matchcontinue;
9091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 if failVar then
9092 ✗ fail();
9093 end if;
9094
3/4
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
578 outTup := (i, fieldLst, domainCr, info, skip, N, isBC);
9095 end discretizeTraverseFun;
9096
9097 protected function findDomF<T>
9098 input tuple<String,T> inTup;
9099 input String name;
9100 output Boolean found;
9101 algorithm
9102 found := match inTup
9103 local String nameLoc;
9104 case (nameLoc,_)
9105 guard
9106 stringEqual(nameLoc,name)
9107 then true;
9108 else false;
9109 end match;
9110 end findDomF;
9111 /*
9112 public function findDomains
9113 input SCode.Element el;
9114 input list<tuple<String,Integer>> domainLstIn;
9115 output list<tuple<String,Integer>> domainLstOut;
9116 algorithm
9117 //TODO: rewrite to use instantiated domain elements
9118 domainLstOut := match el
9119 local
9120 String name;
9121 list<SCode.SubMod> subModLst;
9122 Integer N;
9123 case SCode.COMPONENT(typeSpec=Absyn.TPATH(path=Absyn.IDENT(name="DomainLineSegment1D")), name = name,
9124 modifications = SCode.MOD(subModLst = subModLst))
9125 then
9126 (name,findDomains1(subModLst))::domainLstIn;
9127 else
9128 domainLstIn;
9129 end match;
9130 end findDomains;
9131
9132
9133 protected function findDomains1
9134 input list<SCode.SubMod> subModLst;
9135 output Integer N;
9136 algorithm
9137 try
9138 N := match List.find(subModLst,findDomains2)
9139 local
9140 Integer n;
9141 case SCode.NAMEMOD("N",SCode.MOD(binding = SOME(Absyn.INTEGER(n))))
9142 then
9143 n;
9144 end match;
9145 else
9146 print("\nError: Variable N not found in the domain.\n");
9147 fail();
9148 end try;
9149 end findDomains1;
9150
9151 protected function findDomains2
9152 input SCode.SubMod subMod;
9153 output Boolean found;
9154 algorithm
9155 found := match subMod
9156 case SCode.NAMEMOD(ident = "N")
9157 then
9158 true;
9159 else
9160 false;
9161 end match;
9162 end findDomains2;
9163 */
9164 annotation(__OpenModelica_Interface="frontend");
9165 end InstUtil;
9166