Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 71.7% 160 / 0 / 223
Functions: -% 0 / 1 / 1
Branches: 62.5% 75 / 0 / 120

OMCompiler/Compiler/Script/ProgramUtil.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 ProgramUtil
37 " file: ProgramUtil.mo
38 package: ProgramUtil
39 description: Absyn program-tree navigation and manipulation helpers, factored
40 out of InteractiveUtil so lower layers (backend/SimCode) can use
41 them without depending on the interactive/scripting layer."
42
43 import Absyn;
44
45 protected
46 import AbsynUtil;
47 import DoubleEnded;
48 import Dump;
49 import Error;
50 import FBuiltin;
51 import List;
52 import Print;
53 import Util;
54 import Testsuite;
55 import System;
56 import Settings;
57 import Autoconf;
58
59 public
60 public function buildWithin
61 " From a fully qualified model name, build a suitable within clause"
62 input Absyn.Path inPath;
63 output Absyn.Within outWithin;
64 algorithm
65 outWithin := match inPath
66 local Absyn.Path w_path,path;
67 case Absyn.IDENT() then Absyn.TOP();
68 case Absyn.FULLYQUALIFIED(path) // handle fully qual also!
69 140 then
70 buildWithin(path);
71 case path
72 algorithm
73 129 w_path := AbsynUtil.stripLast(path);
74 129 then
75 Absyn.WITHIN(w_path);
76 end match;
77 end buildWithin;
78 public function updateProgram
79 " This function takes an old program (second argument), i.e. the old
80 symboltable, and a new program (first argument), i.e. a new set of
81 classes and updates the old program with the definitions in the new one.
82 It also takes in the current symboltable and returns a new one with any
83 replaced functions cache cleared."
84 input Absyn.Program inNewProgram;
85 input Absyn.Program inOldProgram;
86 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
87 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
88 output Absyn.Program outProgram;
89 protected
90 list<Absyn.Class> cs;
91 Absyn.Within w;
92 algorithm
93 5153 Absyn.PROGRAM(classes=cs,within_=w) := inNewProgram;
94 5153 outProgram := updateProgram2(listReverse(cs),w,inOldProgram, mergeAST, allowFilenameChange);
95 end updateProgram;
96 public function updateProgram2
97 " This function takes an old program (second argument), i.e. the old
98 symboltable, and a new program (first argument), i.e. a new set of
99 classes and updates the old program with the definitions in the new one.
100 It also takes in the current symboltable and returns a new one with any
101 replaced functions cache cleared."
102 input list<Absyn.Class> inNewClasses;
103 input Absyn.Within w;
104 input Absyn.Program inOldProgram;
105 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
106 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
107 output Absyn.Program outProgram;
108 algorithm
109 outProgram := match (inNewClasses,w,inOldProgram)
110 local
111 Absyn.Program prg,newp,p2,newp_1;
112 Absyn.Class c1;
113 String name;
114 list<Absyn.Class> c2,c3;
115 Absyn.Within w2;
116
117 case ({},_,prg) then prg;
118
119 case ((c1 as Absyn.CLASS(name = name)) :: c2,Absyn.TOP(), (p2 as Absyn.PROGRAM(classes = c3,within_ = w2)))
120 algorithm
121
2/2
✓ Branch 1 taken 162 times.
✓ Branch 2 taken 6514 times.
6676 if classInProgram(name, p2) then
122 162 newp := replaceClassInProgram(c1, p2, mergeAST);
123 else
124 6514 newp := Absyn.PROGRAM((c1 :: c3),w2);
125 end if;
126 6676 then updateProgram2(c2,w,newp, mergeAST, allowFilenameChange);
127
128 case ((c1 :: c2),Absyn.WITHIN(),p2)
129 algorithm
130 34 newp := insertClassInProgram(c1, w, p2, mergeAST, allowFilenameChange);
131 34 newp_1 := updateProgram2(c2,w,newp, mergeAST, allowFilenameChange);
132 then newp_1;
133
134 end match;
135 end updateProgram2;
136 public function getClassnamesInParts
137 "Helper function to getClassnamesInClass."
138 input list<Absyn.ClassPart> inAbsynClassPartLst;
139 input Boolean inShowProtected;
140 input Boolean includeConstants;
141 output list<String> outStringLst;
142 algorithm
143 outStringLst:=
144 matchcontinue (inAbsynClassPartLst,inShowProtected,includeConstants)
145 local
146 list<String> l1,l2,res;
147 list<Absyn.ElementItem> elts;
148 list<Absyn.ClassPart> rest;
149 Boolean b,c;
150
151 case ({},_,_) then {};
152
153 case ((Absyn.PUBLIC(contents = elts) :: rest),b,c)
154 algorithm
155 12 l1 := getClassnamesInElts(elts,c);
156 12 l2 := getClassnamesInParts(rest,b,c);
157 12 res := listAppend(l1, l2);
158 then
159 res;
160
161 // adeas31 2012-01-25: Also check the protected sections.
162 case ((Absyn.PROTECTED(contents = elts) :: rest), true, c)
163 algorithm
164 ✗ l1 := getClassnamesInElts(elts,c);
165 ✗ l2 := getClassnamesInParts(rest,true,c);
166 ✗ res := listAppend(l1, l2);
167 then
168 res;
169
170 case ((_ :: rest),b,c)
171 algorithm
172 ✗ res := getClassnamesInParts(rest,b,c);
173 then
174 res;
175
176 end matchcontinue;
177 end getClassnamesInParts;
178 public function getClassnamesInElts
179 "Helper function to getClassnamesInParts."
180 input list<Absyn.ElementItem> inAbsynElementItemLst;
181 input Boolean includeConstants;
182 output list<String> outStringLst;
183 protected
184 DoubleEnded.MutableList<String> delst;
185 algorithm
186 12 delst := DoubleEnded.fromList({});
187
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 12 times.
50 for elt in inAbsynElementItemLst loop
188 () := match elt
189 local
190 String id;
191 list<Absyn.ComponentItem> lst;
192
193 case Absyn.ELEMENTITEM(element = Absyn.ELEMENT(specification = Absyn.CLASSDEF(class_ =
194 Absyn.CLASS(body = Absyn.CLASS_EXTENDS(baseClassName = id)))))
195 algorithm
196 ✗ DoubleEnded.push_back(delst, id);
197 then ();
198
199 case Absyn.ELEMENTITEM(element = Absyn.ELEMENT(specification = Absyn.CLASSDEF(class_ =
200 Absyn.CLASS(name = id))))
201 algorithm
202 32 DoubleEnded.push_back(delst, id);
203 then ();
204
205 case Absyn.ELEMENTITEM(element = Absyn.ELEMENT(specification = Absyn.COMPONENTS(attributes = Absyn.ATTR(variability = Absyn.CONST()),
206 components = lst))) guard includeConstants
207 algorithm
208 3 DoubleEnded.push_list_back(delst, getComponentItemsName(lst,false));
209 then ();
210
211 else ();
212 end match;
213 end for;
214 12 outStringLst := DoubleEnded.toListAndClear(delst);
215 end getClassnamesInElts;
216 public function getComponentItemsName
217 " separated list of all component names."
218 input list<Absyn.ComponentItem> inComponents;
219 input Boolean inQuoteNames "Adds quotes around the component names if true.";
220 output list<String> outStrings = {};
221 protected
222 String name;
223 algorithm
224
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 for comp in listReverse(inComponents) loop
225 () := match comp
226 case Absyn.COMPONENTITEM(component = Absyn.COMPONENT(name = name))
227 algorithm
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 outStrings := (if inQuoteNames then
229 stringAppendList({"\"", name, "\""}) else
230 stringAppendList({name})) :: outStrings;
231 then
232 ();
233
234 else ();
235 end match;
236 end for;
237 end getComponentItemsName;
238 public function replaceClassInProgram2
239 input Absyn.Class inClass;
240 input String inClassName;
241 output Boolean outReplace;
242 protected
243 String cls_name;
244 algorithm
245 512 Absyn.CLASS(name = cls_name) := inClass;
246
4/4
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 232 times.
✓ Branch 3 taken 115 times.
✓ Branch 4 taken 165 times.
512 outReplace := cls_name == inClassName;
247 end replaceClassInProgram2;
248 public function replaceClassInProgram
249 " This function takes a Class and a Program and replaces the class
250 definition at the top level in the program by the class definition of
251 the Class. It also updates the functionlist for the symboltable if needed."
252 input Absyn.Class inClass;
253 input Absyn.Program inProgram;
254 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
255 output Absyn.Program outProgram;
256 protected
257 String cls_name1;
258 list<Absyn.Class> clst, clsFilter;
259 Absyn.Within w;
260 Boolean replaced;
261 Absyn.Class cls;
262 algorithm
263 162 Absyn.CLASS(name = cls_name1) := inClass;
264 162 Absyn.PROGRAM(classes = clst, within_ = w) := inProgram;
265
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 159 times.
162 if mergeAST then
266 3 clsFilter := List.filterOnTrue(clst, function replaceClassInProgram2(inClassName = cls_name1));
267
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if listEmpty(clsFilter)
268 then
269 cls := inClass;
270 else
271 3 cls::_ := clsFilter;
272 3 cls := mergeClasses(inClass, cls);
273 end if;
274 else
275 cls := inClass;
276 end if;
277 162 (clst, replaced) := List.replaceOnTrue(cls, clst,
278 function replaceClassInProgram2(inClassName = cls_name1));
279
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 if not replaced then
281 ✗ clst := List.appendElt(inClass, clst);
282 end if;
283
284 162 outProgram := Absyn.PROGRAM(clst, w);
285 end replaceClassInProgram;
286 public function insertClassInProgram
287 " This function inserts the class into the Program at the scope given by
288 the within argument. If the class referenced by the within argument is
289 not defined, the function prints an error message and fails."
290 input Absyn.Class inClass;
291 input Absyn.Within inWithin;
292 input Absyn.Program inProgram;
293 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
294 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
295 output Absyn.Program outProgram;
296 algorithm
297 outProgram := matchcontinue (inClass,inWithin,inProgram)
298 local
299 Absyn.Class c2,c3,c1;
300 Absyn.Program pnew,p;
301 Absyn.Within w;
302 String n1,s1,s2,name;
303 list<Absyn.Path> paths;
304
305 case (c1,(w as Absyn.WITHIN(path = Absyn.QUALIFIED(name = n1))),p as Absyn.PROGRAM())
306 algorithm
307 7 c2 := getClassInProgram(n1, p);
308 7 c3 := insertClassInClass(c1, w, c2, mergeAST, allowFilenameChange);
309 7 pnew := updateProgram(Absyn.PROGRAM({c3},Absyn.TOP()), p, mergeAST, allowFilenameChange);
310 then
311 pnew;
312
313 case (c1,(w as Absyn.WITHIN(path = Absyn.IDENT(name = n1))),p as Absyn.PROGRAM())
314 algorithm
315 27 c2 := getClassInProgram(n1, p);
316 27 c3 := insertClassInClass(c1, w, c2, mergeAST, allowFilenameChange);
317 27 pnew := updateProgram(Absyn.PROGRAM({c3},Absyn.TOP()), p, mergeAST, allowFilenameChange);
318 then
319 pnew;
320
321 case (_,Absyn.WITHIN(path=Absyn.QUALIFIED(name="OpenModelica")),p) then p;
322
323 case ((Absyn.CLASS(name = name)),w,p)
324 algorithm
325 ✗ s1 := Dump.unparseWithin(w);
326 /* adeas31 2012-01-25: false indicates that the classnamesrecursive doesn't look into protected sections */
327 /* adeas31 2016-11-29: false indicates that the classnamesrecursive doesn't look for constants */
328 ✗ (_, paths) := getClassNamesRecursive(NONE(), p, false, false, {});
329 ✗ s2 := stringAppendList(List.map1r(list(AbsynUtil.pathString(p) for p in paths),stringAppend,"\n "));
330 ✗ Error.addMessage(Error.INSERT_CLASS, {name,s1,s2});
331 ✗ then
332 fail();
333
334 end matchcontinue;
335 end insertClassInProgram;
336 public function insertClassInClass "
337 This function takes a class to update (the first argument) and an inner
338 class (which is either replacing
339 an earlier class or is a new inner definition) and a within statement
340 pointing inside the class (including the class itself in the reference),
341 and updates the class with the inner class.
342 "
343 input Absyn.Class inClass1;
344 input Absyn.Within inWithin2;
345 input Absyn.Class inClass3;
346 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
347 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
348 output Absyn.Class outClass;
349 algorithm
350 outClass := match (inClass1,inWithin2,inClass3)
351 local
352 Absyn.Class cnew,c1,c2,cinner;
353 String name2;
354 Absyn.Path path;
355
356 case (c1,Absyn.WITHIN(path = Absyn.IDENT()),c2)
357 34 then replaceInnerClass(c1, c2, mergeAST, allowFilenameChange);
358
359 case (c1,Absyn.WITHIN(path = Absyn.QUALIFIED(path = path)),c2)
360 algorithm
361 7 name2 := AbsynUtil.pathFirstIdent(path);
362 7 cinner := getInnerClass(c2, name2);
363 7 cnew := insertClassInClass(c1, Absyn.WITHIN(path), cinner, mergeAST, allowFilenameChange);
364 7 then replaceInnerClass(cnew, c2, mergeAST, allowFilenameChange);
365
366 end match;
367 end insertClassInClass;
368 public function replaceInnerClass
369 "This function takes two class definitions. The first one is
370 inserted/replaced as a local class inside the second one."
371 input Absyn.Class inClass1;
372 input Absyn.Class inClass2;
373 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
374 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
375 output Absyn.Class outClass;
376 protected
377 String enclosingFileName;
378 algorithm
379 41 Absyn.CLASS(info = SOURCEINFO(fileName = enclosingFileName)) := inClass2;
380 outClass:=
381 matchcontinue (inClass1,inClass2)
382 local
383 list<Absyn.ElementItem> publst,publst2,prolst,prolst2;
384 list<Absyn.ClassPart> parts2,parts;
385 Absyn.Class c1;
386 String bcname;
387 Option<String> cmt;
388 list<Absyn.ElementArg> modif;
389 list<String> typeVars;
390 list<Absyn.NamedArg> classAttrs;
391 list<Absyn.Annotation> ann;
392
393 // a class with parts - we can find the element in the public list
394 case (c1,outClass as Absyn.CLASS(body = Absyn.PARTS(typeVars = typeVars, classAttrs = classAttrs, classParts = parts,ann=ann,comment = cmt)))
395 algorithm
396 41 publst := getPublicList(parts);
397
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 30 times.
41 (publst2, true) := replaceClassInElementitemlist(publst, c1, mergeAST, allowFilenameChange, enclosingFileName);
398 30 parts2 := replacePublicList(parts, publst2);
399 60 outClass.body := Absyn.PARTS(typeVars,classAttrs,parts2,ann,cmt);
400 then
401 outClass;
402
403 // a class with parts - we can find the element in the protected list
404 case (c1,outClass as Absyn.CLASS(
405 body = Absyn.PARTS(typeVars = typeVars, classAttrs = classAttrs, classParts = parts,ann=ann,comment = cmt)))
406 algorithm
407 11 prolst := getProtectedList(parts);
408
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 (prolst2, true) := replaceClassInElementitemlist(prolst, c1, mergeAST, allowFilenameChange, enclosingFileName);
409 ✗ parts2 := replaceProtectedList(parts, prolst2);
410 ✗ outClass.body := Absyn.PARTS(typeVars,classAttrs,parts2,ann,cmt);
411 then
412 outClass;
413
414 // a class with parts - we cannot find the element in the public or protected list, add it to the public list
415 case (c1,outClass as Absyn.CLASS(
416 body = Absyn.PARTS(typeVars = typeVars, classAttrs = classAttrs, classParts = parts,ann=ann,comment = cmt)))
417 algorithm
418 11 publst := getPublicList(parts);
419 11 publst := addClassInElementitemlist(publst, c1);
420 11 parts2 := replacePublicList(parts, publst);
421 22 outClass.body := Absyn.PARTS(typeVars,classAttrs,parts2,ann,cmt);
422 then
423 outClass;
424
425 // an extended class with parts: model extends M end M; - we can find the element in the public list
426 case (c1,outClass as Absyn.CLASS(body = Absyn.CLASS_EXTENDS(baseClassName = bcname,modifications = modif,parts = parts,ann=ann,comment = cmt)))
427 algorithm
428 ✗ publst := getPublicList(parts);
429 ✗ (publst2, true) := replaceClassInElementitemlist(publst, c1, mergeAST, allowFilenameChange, enclosingFileName);
430 ✗ parts2 := replacePublicList(parts, publst2);
431 ✗ outClass.body := Absyn.CLASS_EXTENDS(bcname,modif,cmt,parts2,ann);
432 then
433 outClass;
434
435 // an extended class with parts: model extends M end M; - we can find the element in the protected list
436 case (c1,outClass as Absyn.CLASS(body = Absyn.CLASS_EXTENDS(baseClassName = bcname,modifications = modif,parts = parts,ann=ann,comment = cmt)))
437 algorithm
438 ✗ prolst := getProtectedList(parts);
439 ✗ (prolst2, true) := replaceClassInElementitemlist(prolst, c1, mergeAST, allowFilenameChange, enclosingFileName);
440 ✗ parts2 := replaceProtectedList(parts, prolst2);
441 ✗ outClass.body := Absyn.CLASS_EXTENDS(bcname,modif,cmt,parts2,ann);
442 then
443 outClass;
444
445 // an extended class with parts: model extends M end M; - we cannot find the element in the public or protected list, add it to the public list
446 case (c1,outClass as Absyn.CLASS(body = Absyn.CLASS_EXTENDS(baseClassName = bcname,modifications = modif,parts = parts,ann=ann,comment = cmt)))
447 algorithm
448 ✗ publst := getPublicList(parts);
449 ✗ publst := addClassInElementitemlist(publst, c1);
450 ✗ parts2 := replacePublicList(parts, publst);
451 ✗ outClass.body := Absyn.CLASS_EXTENDS(bcname,modif,cmt,parts2,ann);
452 then
453 outClass;
454
455 else
456 algorithm
457 ✗ Print.printBuf("Failed in replaceInnerClass\n");
458 ✗ then
459 fail();
460 end matchcontinue;
461 end replaceInnerClass;
462 public function replaceClassInElementitemlist
463 "This function takes an Element list and a Class and returns a modified
464 element list where the class definition of the class is updated or added."
465 input list<Absyn.ElementItem> inAbsynElementItemLst;
466 input Absyn.Class inClass;
467 input Boolean mergeAST = false "when true, the new program should be merged with the old program";
468 input Boolean allowFilenameChange = false "when true, the class is allowed to move to the file it carries; only setSourceFile relocates a class";
469 input String enclosingFileName = "" "the file the enclosing class is stored in";
470 output list<Absyn.ElementItem> outAbsynElementItemLst;
471 output Boolean replaced "true signals a replacement, false nothing changed!";
472 algorithm
473 (outAbsynElementItemLst, replaced) := match (inAbsynElementItemLst,inClass)
474 local
475 list<Absyn.ElementItem> res,xs;
476 Absyn.ElementItem e1;
477 Absyn.Class c, c1, c2;
478 String name1,name,oldFileName;
479 Boolean a,e;
480 Option<Absyn.RedeclareKeywords> b;
481 SourceInfo info;
482 Option<Absyn.ConstrainClass> h;
483 Absyn.InnerOuter io;
484
485 case (((Absyn.ELEMENTITEM(element = Absyn.ELEMENT(finalPrefix = a,redeclareKeywords = b,innerOuter = io,specification = Absyn.CLASSDEF(replaceable_ = e,class_ = c1 as Absyn.CLASS(name = name1)),constrainClass = h))) :: xs),(c2 as Absyn.CLASS(name = name)))
486 guard stringEq(name1, name)
487 algorithm
488
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 26 times.
30 c := if mergeAST then mergeClasses(c2, c1) else c2;
489 // A class stored in the same file as the class enclosing it has to stay
490 // in that file. Letting the replacement bring its own file name along
491 // would make it invisible to listFile on the enclosing class, which
492 // dumps only the elements belonging to that class' file, and the class
493 // would silently disappear on the next listFile/loadString round trip.
494 // A class that already lives in a file of its own (a package stored with
495 // a folder structure) may be relocated, and setSourceFile relocates any
496 // class on purpose.
497 30 Absyn.CLASS(info = SOURCEINFO(fileName = oldFileName)) := c1;
498
5/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 6 times.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
30 if not allowFilenameChange and stringEq(oldFileName, enclosingFileName) then
499 22 c := AbsynUtil.setClassFilename(c, oldFileName);
500 end if;
501 30 Absyn.CLASS(info = info) := c;
502
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
90 then
503 (Absyn.ELEMENTITEM(Absyn.ELEMENT(a,b,io,Absyn.CLASSDEF(e,c),info /* The new CLASS might have update info */,h)) :: xs, true);
504
505 case ((e1 :: xs),c)
506 algorithm
507 15 (res, replaced) := replaceClassInElementitemlist(xs, c, mergeAST, allowFilenameChange, enclosingFileName);
508 15 then
509 (e1 :: res, replaced);
510
511 else ({}, false);
512
513 end match;
514 end replaceClassInElementitemlist;
515 public function addClassInElementitemlist
516 "This function takes an Element list and a Class and returns a modified
517 element list where the class definition of the class is updated or added."
518 input list<Absyn.ElementItem> inAbsynElementItemLst;
519 input Absyn.Class inClass;
520 output list<Absyn.ElementItem> outAbsynElementItemLst;
521 protected
522 Absyn.Info info;
523 algorithm
524 11 Absyn.CLASS(info=info) := inClass;
525 22 outAbsynElementItemLst := listAppend(inAbsynElementItemLst,
526 {Absyn.ELEMENTITEM(
527 Absyn.ELEMENT(false,NONE(),Absyn.NOT_INNER_OUTER(),Absyn.CLASSDEF(false,inClass),
528 info,NONE()))});
529 end addClassInElementitemlist;
530 public function getInnerClass
531 "This function takes a class name and a class and
532 returns the inner class definition having that name."
533 input Absyn.Class inClass;
534 input Absyn.Ident inIdent;
535 output Absyn.Class outClass;
536 algorithm
537 outClass:=
538 matchcontinue (inClass,inIdent)
539 local
540 list<Absyn.ElementItem> publst,prolst;
541 Absyn.Class c1;
542 list<Absyn.ClassPart> parts;
543 String name;
544
545 // class found in public
546 case (Absyn.CLASS(body = Absyn.PARTS(classParts = parts)),name)
547 algorithm
548 7 publst := getPublicList(parts);
549 7 c1 := getClassFromElementitemlist(publst, name);
550 then
551 c1;
552
553 // class found in protected
554 case (Absyn.CLASS(body = Absyn.PARTS(classParts = parts)),name)
555 algorithm
556 ✗ prolst := getProtectedList(parts);
557 ✗ c1 := getClassFromElementitemlist(prolst, name);
558 then
559 c1;
560
561 // class found in public
562 case (Absyn.CLASS(body = Absyn.CLASS_EXTENDS(parts = parts)),name)
563 algorithm
564 ✗ publst := getPublicList(parts);
565 ✗ c1 := getClassFromElementitemlist(publst, name);
566 then
567 c1;
568
569 // class found in protected
570 case (Absyn.CLASS(body = Absyn.CLASS_EXTENDS(parts = parts)),name)
571 algorithm
572 ✗ prolst := getProtectedList(parts);
573 ✗ c1 := getClassFromElementitemlist(prolst, name);
574 then
575 c1;
576
577 /* Does nothing
578 case (c as Absyn.CLASS(),name)
579 algorithm
580 handle = Print.saveAndClearBuf();
581 Print.printBuf("getInnerClass failed, c:");
582 Dump.dump(Absyn.PROGRAM({c},Absyn.TOP()));
583 Print.printBuf("name :");
584 Print.printBuf(name);
585 Print.clear(); // Print.getString();
586 Print.restoreBuf(handle);
587 then
588 fail();
589 */
590 end matchcontinue;
591 end getInnerClass;
592 public function replacePublicList
593 " This function replaces the ElementItem list in
594 the ClassPart list, and returns the updated list.
595 If no public list is available, one is created."
596 input list<Absyn.ClassPart> inAbsynClassPartLst;
597 input list<Absyn.ElementItem> inAbsynElementItemLst;
598 output list<Absyn.ClassPart> outAbsynClassPartLst;
599 algorithm
600 outAbsynClassPartLst := match (inAbsynClassPartLst,inAbsynElementItemLst)
601 local
602 list<Absyn.ClassPart> rest_1,rest,ys,xs;
603 Absyn.ClassPart x;
604 list<Absyn.ElementItem> newpublst,new,newpublist;
605
606 case (((Absyn.PUBLIC()) :: rest),newpublst)
607 algorithm
608 2585 rest_1 := deletePublicList(rest);
609 2585 then
610 (Absyn.PUBLIC(newpublst) :: rest_1);
611
612 case ((x :: xs),new)
613 algorithm
614 ✗ ys := replacePublicList(xs, new);
615 then
616 (x :: ys);
617
618 8 case ({},newpublist) then {Absyn.PUBLIC(newpublist)};
619
620 end match;
621 end replacePublicList;
622 public function replaceProtectedList "
623 This function replaces the `ElementItem\' list in the `ClassPart\' list,
624 and returns the updated list.
625 If no protected list is available, one is created.
626 "
627 input list<Absyn.ClassPart> inAbsynClassPartLst;
628 input list<Absyn.ElementItem> inAbsynElementItemLst;
629 output list<Absyn.ClassPart> outAbsynClassPartLst;
630 algorithm
631 outAbsynClassPartLst := match (inAbsynClassPartLst,inAbsynElementItemLst)
632 local
633 list<Absyn.ClassPart> rest_1,rest,ys,xs;
634 Absyn.ClassPart x;
635 list<Absyn.ElementItem> newprotlist,new;
636
637 case (((Absyn.PROTECTED()) :: rest),newprotlist)
638 algorithm
639 2 rest_1 := deleteProtectedList(rest);
640 2 then
641 (Absyn.PROTECTED(newprotlist) :: rest_1);
642
643 case ((x :: xs),new)
644 algorithm
645 4 ys := replaceProtectedList(xs, new);
646 then
647 (x :: ys);
648
649 2 case ({},newprotlist) then {Absyn.PROTECTED(newprotlist)};
650
651 end match;
652 end replaceProtectedList;
653 public function deletePublicList "
654 Deletes all PULIC classparts from the list.
655 "
656 input list<Absyn.ClassPart> inAbsynClassPartLst;
657 output list<Absyn.ClassPart> outAbsynClassPartLst;
658 algorithm
659 outAbsynClassPartLst:=
660 match inAbsynClassPartLst
661 local
662 list<Absyn.ClassPart> res,xs;
663 Absyn.ClassPart x;
664 case {} then {};
665 case Absyn.PUBLIC() :: xs
666 algorithm
667 52 res := deletePublicList(xs);
668 then
669 res;
670 case x :: xs
671 algorithm
672 2192 res := deletePublicList(xs);
673 then
674 (x :: res);
675 end match;
676 end deletePublicList;
677 public function deleteProtectedList "
678 Deletes all PROTECTED classparts from the list.
679 "
680 input list<Absyn.ClassPart> inAbsynClassPartLst;
681 output list<Absyn.ClassPart> outAbsynClassPartLst;
682 algorithm
683 outAbsynClassPartLst:=
684 match inAbsynClassPartLst
685 local
686 list<Absyn.ClassPart> res,xs;
687 Absyn.ClassPart x;
688 case {} then {};
689 case Absyn.PROTECTED() :: xs
690 algorithm
691 ✗ res := deleteProtectedList(xs);
692 then
693 res;
694 case x :: xs
695 algorithm
696 ✗ res := deleteProtectedList(xs);
697 then
698 (x :: res);
699 end match;
700 end deleteProtectedList;
701 public function getPublicList "
702 This function takes a ClassPart List and returns an appended list of
703 all public lists.
704 "
705 input list<Absyn.ClassPart> inAbsynClassPartLst;
706 output list<Absyn.ElementItem> outAbsynElementItemLst;
707 algorithm
708 outAbsynElementItemLst:=
709 match inAbsynClassPartLst
710 local
711 list<Absyn.ElementItem> res2,res,res1,ys;
712 list<Absyn.ClassPart> rest,xs;
713 case {} then {};
714 case Absyn.PUBLIC(contents = res1) :: rest
715 algorithm
716 5242 res2 := getPublicList(rest);
717 5242 res := listAppend(res1, res2);
718 then
719 res;
720 case _ :: xs
721 algorithm
722 4378 ys := getPublicList(xs);
723 then
724 ys;
725 end match;
726 end getPublicList;
727 public function getProtectedList "
728 This function takes a ClassPart List and returns an appended list of
729 all protected lists."
730 input list<Absyn.ClassPart> inAbsynClassPartLst;
731 output list<Absyn.ElementItem> outAbsynElementItemLst;
732 algorithm
733 outAbsynElementItemLst:=
734 match inAbsynClassPartLst
735 local
736 list<Absyn.ElementItem> res2,res,res1,ys;
737 list<Absyn.ClassPart> rest,xs;
738 case {} then {};
739 case Absyn.PROTECTED(contents = res1) :: rest
740 algorithm
741 12 res2 := getProtectedList(rest);
742 12 res := listAppend(res1, res2);
743 then
744 res;
745 case _ :: xs
746 algorithm
747 40 ys := getProtectedList(xs);
748 then
749 ys;
750 end match;
751 end getProtectedList;
752 public function getClassFromElementitemlist "
753 This function takes an ElementItem list and an Ident and returns the
754 class definition among the element list having that identifier.
755 "
756 input list<Absyn.ElementItem> inElements;
757 input Absyn.Ident inIdent;
758 output Absyn.Class outClass;
759 protected
760 Absyn.ElementItem elem;
761 algorithm
762 7 elem := List.getMemberOnTrue(inIdent, inElements, classElementItemIsNamed);
763
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
7 Absyn.ELEMENTITEM(element = Absyn.ELEMENT(specification =
764 Absyn.CLASSDEF(class_ = outClass))) := elem;
765 end getClassFromElementitemlist;
766 public function classInProgram
767 "This function takes a name and a Program and returns
768 true if the name exists as a top class in the program."
769 input String name;
770 input Absyn.Program p;
771 output Boolean b;
772 algorithm
773 b := match p
774 local
775 String str;
776 case Absyn.PROGRAM()
777 algorithm
778
2/2
✓ Branch 0 taken 102249 times.
✓ Branch 1 taken 6514 times.
108763 for cl in p.classes loop
779 102249 Absyn.CLASS(name=str) := cl;
780
4/4
✓ Branch 0 taken 7554 times.
✓ Branch 1 taken 94695 times.
✓ Branch 3 taken 162 times.
✓ Branch 4 taken 7392 times.
102249 if str == name then
781 b := true;
782 162 return;
783 end if;
784 end for;
785 then false;
786 end match;
787 end classInProgram;
788 public function getPathedClassInProgram
789 "This function takes a Path and a Program and retrieves the
790 class definition referenced by the Path from the Program.
791 If enclOnErr is true and such class doesn't exist return enclosing class."
792 input Absyn.Path inPath;
793 input Absyn.Program inProgram;
794 input Boolean enclOnErr = false;
795 input Boolean showError = false;
796 output Absyn.Class outClass;
797 algorithm
798 outClass := matchcontinue ()
799 36913 case () then getPathedClassInProgramWork(inPath, inProgram, enclOnErr);
800 2051 case () then getPathedClassInProgramWork(inPath, FBuiltin.getInitialFunctions(), enclOnErr);
801
802 else
803 algorithm
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2044 times.
2044 if showError then
805 ✗ Error.addMessage(Error.LOOKUP_ERROR,
806 {AbsynUtil.pathString(inPath), "<TOP>"});
807 end if;
808 2044 then
809 fail();
810
811 end matchcontinue;
812 end getPathedClassInProgram;
813 public function getPathedClassInProgramWork
814 "This function takes a Path and a Program and retrieves the class definition
815 referenced by the Path from the Program.
816 If enclOnErr is true and such class doesn't exist return enclosing class."
817 input Absyn.Path inPath;
818 input Absyn.Program inProgram;
819 input Boolean enclOnErr = false;
820 output Absyn.Class outClass;
821 algorithm
822 outClass := match inPath
823 local
824 Absyn.Class c;
825
826 case Absyn.IDENT()
827 14595 then getClassInProgram(inPath.name, inProgram);
828
829 case Absyn.QUALIFIED()
830 algorithm
831 24369 c := getClassInProgram(inPath.name, inProgram);
832 24333 then
833 getPathedClassInClass(inPath.path, c, enclOnErr);
834
835 case Absyn.FULLYQUALIFIED()
836 141 then
837 getPathedClassInProgramWork(inPath.path, inProgram, enclOnErr);
838
839 end match;
840 end getPathedClassInProgramWork;
841 public function getPathedClassInClass
842 "Retrieves the class definition referenced by the Path in the given class.
843 If such class doesn't exist return the class itself if enclOnError = true, otherwise fail."
844 input Absyn.Path inPath;
845 input Absyn.Class inClass;
846 input Boolean enclOnError;
847 output Absyn.Class outClass;
848 algorithm
849 outClass := matchcontinue inPath
850 local
851 Absyn.Class c;
852 String str;
853 Absyn.Path path;
854
855 case Absyn.IDENT(name = str)
856 24331 then
857 getClassInClass(str, inClass);
858
859 case Absyn.FULLYQUALIFIED(path)
860 ✗ then
861 getPathedClassInClass(path, inClass, enclOnError);
862
863 case Absyn.QUALIFIED(name = str, path = path)
864 algorithm
865 55544 c := getClassInClass(str, inClass);
866 55542 then
867 getPathedClassInClass(path, c, enclOnError);
868
869 case _ guard enclOnError then inClass;
870 end matchcontinue;
871 end getPathedClassInClass;
872 public function getClassInClass
873 "Looks up a named class in the given class. Fails if the class can't be found."
874 input String name;
875 input Absyn.Class inClass;
876 output Absyn.Class outClass;
877 algorithm
878
2/2
✓ Branch 1 taken 80879 times.
✓ Branch 2 taken 4 times.
80883 for part in AbsynUtil.getClassPartsInClass(inClass) loop
879
2/2
✓ Branch 1 taken 1052060 times.
✓ Branch 2 taken 1008 times.
1053068 for item in AbsynUtil.getElementItemsInClassPart(part) loop
880
2/2
✓ Branch 1 taken 79871 times.
✓ Branch 2 taken 972189 times.
1052060 if AbsynUtil.isElementItemClassNamed(name, item) then
881 79871 outClass := AbsynUtil.elementItemClass(item);
882 79871 return;
883 end if;
884 end for;
885 end for;
886
887 4 fail();
888 end getClassInClass;
889 public function getClassInProgram
890 "Looks up a function with the given name in a program, or fails if the class doesn't exist."
891 input String name;
892 input Absyn.Program program;
893 output Absyn.Class cls;
894 algorithm
895 47911 cls := List.find(program.classes, function AbsynUtil.isClassNamed(inName = name));
896 end getClassInProgram;
897 public function getClassnamesInClassList
898 input Absyn.Path inPath;
899 input Absyn.Program inProgram;
900 input Absyn.Class inClass;
901 input Boolean inShowProtected;
902 input Boolean includeConstants;
903 output list<String> outString;
904 algorithm
905 outString:=
906 match (inClass, inShowProtected, includeConstants)
907 local
908 list<String> strlist;
909 list<Absyn.ClassPart> parts;
910 Boolean b,c;
911
912 case (Absyn.CLASS(body = Absyn.PARTS(classParts = parts)), b, c)
913 algorithm
914 3 strlist := getClassnamesInParts(parts,b,c);
915 then
916 strlist;
917
918 case (Absyn.CLASS(body = Absyn.CLASS_EXTENDS(parts = parts)), b, c)
919 algorithm
920 ✗ strlist := getClassnamesInParts(parts,b,c);
921 then strlist;
922
923 case (Absyn.CLASS(body = Absyn.DERIVED(typeSpec=Absyn.TPATH())), _, _)
924 algorithm
925 //(cdef,newpath) = lookupClassdef(path, inmodel, p);
926 //res = getClassnamesInClassList(newpath, p, cdef);
927 then
928 {};//res;
929
930 case (Absyn.CLASS(body = Absyn.OVERLOAD()), _, _)
931 algorithm
932 then {};
933
934 case (Absyn.CLASS(body = Absyn.ENUMERATION()), _, _)
935 algorithm
936 then {};
937
938 case (Absyn.CLASS(body = Absyn.PDER()), _, _)
939 algorithm
940 then {};
941
942 end match;
943 end getClassnamesInClassList;
944 public function getClassNamesRecursive
945 "Returns a string with all the classes for a given path."
946 input Option<Absyn.Path> inPath;
947 input Absyn.Program inProgram;
948 input Boolean inShowProtected;
949 input Boolean includeConstants;
950 input list<Absyn.Path> inAcc;
951 output Option<Absyn.Path> opath;
952 output list<Absyn.Path> paths;
953 algorithm
954 (opath,paths) := matchcontinue (inPath,inProgram,inShowProtected,includeConstants,inAcc)
955 local
956 Absyn.Class cdef;
957 String s1;
958 list<String> strlst;
959 Absyn.Path pp;
960 Absyn.Program p;
961 list<Absyn.Class> classes;
962 list<Option<Absyn.Path>> result_path_lst;
963 list<Absyn.Path> acc;
964 Boolean b,c;
965
966 case (SOME(pp),p,b,c,acc)
967 algorithm
968 3 acc := pp::acc;
969 3 cdef := getPathedClassInProgram(pp, p);
970 3 strlst := getClassnamesInClassList(pp, p, cdef, b, c);
971 3 result_path_lst := List.map(List.map1(strlst, joinPaths, pp),Util.makeOption);
972
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 (_,acc) := List.map3Fold(result_path_lst, getClassNamesRecursive, p, b, c, acc);
973 3 then (inPath,acc);
974 case (NONE(),p as Absyn.PROGRAM(classes=classes),b,c,acc)
975 algorithm
976 ✗ strlst := List.map(classes, AbsynUtil.getClassName);
977 ✗ result_path_lst := List.mapMap(strlst, AbsynUtil.makeIdentPathFromString, Util.makeOption);
978 ✗ (_,acc) := List.map3Fold(result_path_lst, getClassNamesRecursive, p, b, c, acc);
979 ✗ then (inPath,acc);
980 case (SOME(pp),_,_,_,_)
981 algorithm
982 ✗ s1 := AbsynUtil.pathString(pp);
983 ✗ Error.addMessage(Error.LOOKUP_ERROR, {s1,"<TOP>"});
984 then (inPath,{});
985 end matchcontinue;
986 end getClassNamesRecursive;
987 public function mergeClasses
988 "@author adrpo
989 merge two classes cNew and cOld in the following way:
990 1. get all the inner class definitions from cOld that were loaded from a different file than itself
991 2. append all elements from step 1 to class cNew public list!"
992 input Absyn.Class cNew;
993 input Absyn.Class cOld;
994 output Absyn.Class c;
995 algorithm
996 c := matchcontinue(cNew, cOld)
997 local
998 list<Absyn.ClassPart> partsC1, partsC2;
999 list<Absyn.ElementItem> pubElementsC1, pubElementsC2;
1000 String file;
1001 list<String> typeVars1;
1002 list<Absyn.NamedArg> classAttrs1;
1003 list<Absyn.Annotation> ann1;
1004 Option<String> cmt1;
1005
1006
1007 // if cOld has no parts then just return cNew
1008 case (_, Absyn.CLASS(body = Absyn.PARTS(classParts = {}))) then cNew;
1009 case (_, Absyn.CLASS(body = Absyn.CLASS_EXTENDS(parts = {}))) then cNew;
1010
1011 // if cNew and cOld has parts, get the foreign elements (loaded from other file) from cOld
1012 // and append them to the public list of cNew
1013 case (c as Absyn.CLASS(body=Absyn.PARTS(typeVars1,classAttrs1,partsC1,ann1,cmt1)),
1014 Absyn.CLASS(body = Absyn.PARTS(classParts = partsC2), info = SOURCEINFO(fileName = file)))
1015 algorithm
1016 2524 pubElementsC2 := getPublicList(partsC2);
1017 2524 pubElementsC2 := excludeElementsFromFile(file, pubElementsC2);
1018 2524 pubElementsC1 := getPublicList(partsC1);
1019 2524 pubElementsC1 := mergeElements(pubElementsC1, pubElementsC2);
1020 2524 partsC1 := replacePublicList(partsC1, pubElementsC1);
1021 5048 c.body := Absyn.PARTS(typeVars1,classAttrs1,partsC1,ann1,cmt1);
1022 then c;
1023
1024 // TODO! FIXME! handle also CLASS_EXTENDS!
1025 // if the class cNew or cOld is not containing parts then don't bother, just replace the entire class!
1026 case (_, _) then cNew;
1027 end matchcontinue;
1028 end mergeClasses;
1029 public function mergeElement
1030 "@author adrpo
1031 merge the element given as second argument with the element from the first list with same name.
1032 if no such elements are in the first list, just append it at the end"
1033 input list<Absyn.ElementItem> inEls;
1034 input Absyn.ElementItem inEl;
1035 output list<Absyn.ElementItem> outEls;
1036 algorithm
1037 outEls := matchcontinue(inEls, inEl)
1038 local
1039 String n1,n2;
1040 list<Absyn.ElementItem> rest, filtered;
1041 Absyn.ElementItem e1,e2;
1042 Boolean r;
1043 Boolean f;
1044 Option<Absyn.RedeclareKeywords> redecl;
1045 Absyn.InnerOuter innout ;
1046 String name;
1047 Absyn.Info i;
1048 Option<Absyn.ConstrainClass> cc;
1049 Absyn.Class c1, c2;
1050 case ({}, _) then inEl::{};
1051 // not found put it at the end
1052 case (Absyn.ELEMENTITEM(Absyn.ELEMENT(f, redecl, innout, Absyn.CLASSDEF(r, c1 as Absyn.CLASS(name = n1)), i, cc)) :: rest,
1053 Absyn.ELEMENTITEM(Absyn.ELEMENT(specification = Absyn.CLASSDEF(_,c2 as Absyn.CLASS(name = n2)))))
1054 algorithm
1055
4/4
✓ Branch 0 taken 3847 times.
✓ Branch 1 taken 11773 times.
✓ Branch 3 taken 2555 times.
✓ Branch 4 taken 1292 times.
15620 true := stringEqual(n1, n2);
1056 // element found, merge it!
1057 2555 c1 := mergeClasses(c1, c2);
1058
2/4
✓ Branch 0 taken 2555 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2555 times.
✗ Branch 4 not taken.
7665 then
1059 Absyn.ELEMENTITEM(Absyn.ELEMENT(f, redecl, innout, Absyn.CLASSDEF(r, c1), i, cc)) :: rest;
1060 case (e1 :: rest, e2)
1061 algorithm
1062 // try the second from the first list
1063 15773 filtered := mergeElement(rest, e2);
1064 then
1065 e1::filtered;
1066 end matchcontinue;
1067 end mergeElement;
1068 public function mergeElements
1069 "@author adrpo see merge element"
1070 input list<Absyn.ElementItem> inEls1;
1071 input list<Absyn.ElementItem> inEls2;
1072 output list<Absyn.ElementItem> outEls;
1073 algorithm
1074 outEls := match(inEls1, inEls2)
1075 local
1076 list<Absyn.ElementItem> rest, merged;
1077 Absyn.ElementItem e2;
1078 case ({}, _) then inEls2;
1079 case (_, {}) then inEls1;
1080 case (_, e2::rest)
1081 algorithm
1082 2563 merged := mergeElement(inEls1, e2);
1083 2563 merged := mergeElements(merged, rest);
1084 then merged;
1085 end match;
1086 end mergeElements;
1087 public function excludeElementsFromFile
1088 "exclude all elements which are part of the given file"
1089 input String inFile;
1090 input list<Absyn.ElementItem> inEls;
1091 output list<Absyn.ElementItem> outEls;
1092 algorithm
1093 outEls := match (inFile,inEls)
1094 local
1095 Absyn.ElementItem e;
1096 list<Absyn.ElementItem> rest, filtered;
1097 String f,file;
1098 Boolean b = false;
1099
1100 case (_,{}) then {};
1101 // elements can come from different files
1102 case (file,(e as Absyn.ELEMENTITEM(Absyn.ELEMENT(info = SOURCEINFO(fileName = f))))::rest)
1103 algorithm
1104
4/4
✓ Branch 0 taken 19900 times.
✓ Branch 1 taken 2455 times.
✓ Branch 3 taken 109 times.
✓ Branch 4 taken 19791 times.
22355 b := stringEqual(file, f); // not from this file, use it, else discard!
1105 22355 filtered := excludeElementsFromFile(file, rest);
1106
2/2
✓ Branch 0 taken 2564 times.
✓ Branch 1 taken 19791 times.
22355 then if not b then e::filtered else filtered;
1107 // lexer comments can only be from this file, exclude
1108 case (file,(Absyn.LEXER_COMMENT(_))::rest)
1109 algorithm
1110 195 filtered := excludeElementsFromFile(file, rest);
1111 then filtered;
1112 end match;
1113 end excludeElementsFromFile;
1114 public function getClassnamesInClass
1115 " This function takes a `Class\' definition and a Path identifying the
1116 class.
1117 It returns a string containing comma separated package names found
1118 in the class definition.
1119 The list also contains proctected classes if inShowProtected is true."
1120 input Absyn.Path inPath;
1121 input Absyn.Program inProgram;
1122 input Absyn.Class inClass;
1123 input Boolean inShowProtected;
1124 input Boolean includeConstants;
1125 output list<Absyn.Path> paths;
1126 algorithm
1127 paths := match (inClass, inShowProtected, includeConstants)
1128 local
1129 list<String> strlist;
1130 list<Absyn.ClassPart> parts;
1131 Boolean b,c;
1132 /* a class with parts */
1133 case (Absyn.CLASS(body = Absyn.PARTS(classParts = parts)), b, c)
1134 algorithm
1135 9 strlist := ProgramUtil.getClassnamesInParts(parts,b,c);
1136 9 then List.map(strlist,AbsynUtil.makeIdentPathFromString);
1137 /* an extended class with parts: model extends M end M; */
1138 case (Absyn.CLASS(body = Absyn.CLASS_EXTENDS(parts = parts)), b, c)
1139 algorithm
1140 ✗ strlist := ProgramUtil.getClassnamesInParts(parts,b,c);
1141 ✗ then List.map(strlist,AbsynUtil.makeIdentPathFromString);
1142 /* a derived class */
1143 case (Absyn.CLASS(body = Absyn.DERIVED(typeSpec=Absyn.TPATH(_, _))), _, _)
1144 algorithm
1145 /* adrpo 2009-10-27: we sholdn't dive into derived classes!
1146 (cdef,newpath) = lookupClassdef(path, inmodel, p);
1147 res = getClassnamesInClass(newpath, p, cdef);
1148 */
1149 then {};
1150 end match;
1151 end getClassnamesInClass;
1152 public function classElementItemIsNamed
1153 input String inClassName;
1154 input Absyn.ElementItem inElement;
1155 output Boolean outIsNamed;
1156 algorithm
1157 outIsNamed := match inElement
1158 local
1159 String name;
1160
1161 case Absyn.ELEMENTITEM(element = Absyn.ELEMENT(specification =
1162 Absyn.CLASSDEF(class_ = (Absyn.CLASS(name = name)))))
1163
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
9 then inClassName == name;
1164
1165 else false;
1166 end match;
1167 end classElementItemIsNamed;
1168 public function joinPaths
1169 input String child;
1170 input Absyn.Path parent;
1171 output Absyn.Path outPath;
1172 algorithm
1173 outPath := match (child, parent)
1174 local
1175 Absyn.Path r, res;
1176 String c;
1177 case (c, r)
1178 algorithm
1179 6 res := AbsynUtil.joinPaths(r, Absyn.IDENT(c));
1180 then res;
1181 end match;
1182 end joinPaths;
1183 public function getDefaultComponentPrefixesModStr "Extractor function for defaultComponentPrefixes modifier"
1184 input Option<Absyn.Modification> mod;
1185 output String docStr;
1186 algorithm
1187 docStr := matchcontinue mod
1188 local Absyn.Exp e;
1189 case SOME(Absyn.CLASSMOD(eqMod = Absyn.EQMOD(exp=e))) algorithm
1190 4 docStr := Dump.printExpStr(e);
1191 then docStr;
1192 else "";
1193 end matchcontinue;
1194 end getDefaultComponentPrefixesModStr;
1195 public function getNamedAnnotationExp
1196 "This function takes a Path and a Program and returns a comma separated
1197 string of values for the Documentation annotation for the class named by the
1198 first argument."
1199 input Absyn.Path inPath;
1200 input Absyn.Program inProgram;
1201 input Absyn.Path id;
1202 input Option<T> default;
1203 input ModFunc f;
1204 partial function ModFunc
1205 input Option<Absyn.Modification> mod;
1206 output T docStr;
1207 end ModFunc;
1208 output T outString;
1209 replaceable type T subtypeof Any;
1210 algorithm
1211 outString := matchcontinue (inPath, inProgram, default)
1212 local
1213 Absyn.Class cdef;
1214 T str;
1215 Absyn.Path modelpath;
1216 Absyn.Program p;
1217
1218 case (modelpath, p, _)
1219 algorithm
1220 8177 cdef := getPathedClassInProgram(modelpath, p);
1221
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8161 times.
✓ Branch 3 taken 7317 times.
✓ Branch 4 taken 844 times.
8161 SOME(str) := AbsynUtil.getNamedAnnotationInClass(cdef,id,f);
1222 then
1223 str;
1224
1225 case (_, _, SOME(str)) then str;
1226 end matchcontinue;
1227 end getNamedAnnotationExp;
1228 public function getFileDir "author: x02lucpo
1229 returns the dir where class file (.mo) was saved or
1230 $OPENMODELICAHOME/work if the file was not saved yet"
1231 input Absyn.ComponentRef inComponentRef "class";
1232 input Absyn.Program inProgram;
1233 output String outString;
1234 algorithm
1235 outString:=
1236 matchcontinue (inComponentRef,inProgram)
1237 local
1238 Absyn.Path p_class;
1239 Absyn.Class cdef;
1240 String filename,pd,dir_1,omhome,omhome_1;
1241 String pd_1;
1242 list<String> filename_1,dir;
1243 Absyn.ComponentRef class_;
1244 Absyn.Program p;
1245 case (class_,p)
1246 algorithm
1247 1257 p_class := AbsynUtil.crefToPath(class_) "change to the saved files directory" ;
1248 1257 cdef := getPathedClassInProgram(p_class, p);
1249 1257 filename := AbsynUtil.classFilename(cdef);
1250 pd := Autoconf.pathDelimiter;
1251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1257 times.
1257 pd_1 :: _ := stringListStringChar(pd);
1252 1257 filename_1 := Util.stringSplitAtChar(filename, pd_1);
1253 1257 dir := List.stripLast(filename_1);
1254 1257 dir_1 := stringDelimitList(dir, pd);
1255 then
1256 dir_1;
1257 case (_,_)
1258 algorithm
1259 ✗ omhome := Settings.getInstallationDirectoryPath() "model not yet saved! change to $OPENMODELICAHOME/work" ;
1260 ✗ omhome_1 := System.trim(omhome, "\"");
1261 pd := Autoconf.pathDelimiter;
1262 ✗ dir_1 := stringAppendList({"\"",omhome_1,pd,"work","\""});
1263 then
1264 dir_1;
1265 else ""; /* this function should never fail */
1266 end matchcontinue;
1267 end getFileDir;
1268 public function getFullPathFromUri
1269 input Absyn.Program program;
1270 input String uri;
1271 input Boolean printError;
1272 output String path;
1273 protected
1274 String str1,str2,str3;
1275 algorithm
1276 1766 (str1,str2,str3) := System.uriToClassAndPath(uri);
1277 1766 path := getBasePathFromUri(str1,str2,program,Settings.getModelicaPath(Testsuite.isRunning()),printError) + str3;
1278 end getFullPathFromUri;
1279 public function getBasePathFromUri "Handle modelica:// URIs"
1280 input String scheme;
1281 input String iname;
1282 input Absyn.Program program;
1283 input String modelicaPath;
1284 input Boolean printError;
1285 output String basePath;
1286 algorithm
1287 basePath := matchcontinue (scheme, iname, modelicaPath, printError)
1288 local
1289 Boolean isDir;
1290 list<String> mps,names;
1291 String gd,mp,bp,str,name,fileName;
1292 case ("modelica://", name, _, _)
1293 algorithm
1294
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1766 times.
1766 name::names := System.strtok(name,".");
1295 1766 Absyn.CLASS(info=SOURCEINFO(fileName=fileName)) := getPathedClassInProgram(Absyn.IDENT(name),program);
1296 1712 mp := System.dirname(fileName);
1297 1712 bp := findModelicaPath2(mp,names,"",true);
1298 then bp;
1299 case ("modelica://", name, mp, _)
1300 algorithm
1301
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
54 name::names := System.strtok(name,".");
1302
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
108 failure(getPathedClassInProgram(Absyn.IDENT(name),program));
1303 gd := Autoconf.groupDelimiter;
1304 54 mps := System.strtok(mp, gd);
1305 54 (mp,name,isDir) := System.getLoadModelPath(name, {"default"}, mps);
1306 ✗ mp := if isDir then mp + name else mp;
1307 ✗ bp := findModelicaPath2(mp,names,"",true);
1308 then bp;
1309 case ("file://", _, _, _) then "";
1310 case ("modelica://", name, mp, true)
1311 algorithm
1312 ✗ name::_ := System.strtok(name,".");
1313 ✗ str := "Could not resolve modelica://" + name + " with OPENMODELICALIBRARY (MODELICAPATH in the language specification): " + mp;
1314 ✗ Error.addMessage(Error.COMPILER_ERROR,{str});
1315 ✗ then fail();
1316 end matchcontinue;
1317 end getBasePathFromUri;
1318 public function findModelicaPath "Handle modelica:// URIs"
1319 input list<String> imps;
1320 input list<String> names;
1321 input String version;
1322 output String basePath;
1323 algorithm
1324 basePath := matchcontinue imps
1325 local
1326 String mp;
1327 list<String> mps;
1328
1329 case mp::_
1330 ✗ then findModelicaPath2(mp,names,version,false);
1331 case _::mps
1332 ✗ then findModelicaPath(mps,names,version);
1333 end matchcontinue;
1334 end findModelicaPath;
1335 public function findModelicaPath2 "Handle modelica:// URIs"
1336 input String mp;
1337 input list<String> inames;
1338 input String version;
1339 input Boolean b;
1340 output String basePath;
1341 algorithm
1342 basePath := matchcontinue (inames, b)
1343 local
1344 list<String> names;
1345 String name,file;
1346
1347 case (name::names, _)
1348 algorithm
1349
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 false := stringEq(version,"");
1350 ✗ file := mp + "/" + name + " " + version;
1351 ✗ true := System.directoryExists(file);
1352 // print("Found file 1: " + file + "\n");
1353 ✗ then findModelicaPath2(file,names,"",true);
1354 case (name::_, _)
1355 algorithm
1356
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 false := stringEq(version,"");
1357 ✗ file := mp + "/" + name + " " + version + ".mo";
1358 ✗ true := System.regularFileExists(file);
1359 // print("Found file 2: " + file + "\n");
1360 then mp;
1361
1362 case (name::names, _)
1363 algorithm
1364 4 file := mp + "/" + name;
1365
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
4 true := System.directoryExists(file);
1366 // print("Found file 3: " + file + "\n");
1367 3 then findModelicaPath2(file,names,"",true);
1368 case (name::_, _)
1369 algorithm
1370 1 file := mp + "/" + name + ".mo";
1371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 true := System.regularFileExists(file);
1372 // print("Found file 4: " + file + "\n");
1373 then mp;
1374
1375 // This class is part of the current package.mo, or whatever...
1376 case (_, true)
1377 algorithm
1378 // print("Did not find file 5: " + mp + " - " + name + "\n");
1379 then mp;
1380 end matchcontinue;
1381 end findModelicaPath2;
1382 annotation(__OpenModelica_Interface="program_util");
1383 end ProgramUtil;
1384