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% 125 / 0 / 203
Functions: -% 0 / 1 / 1
Branches: 43.2% 70 / 0 / 162

OMCompiler/Compiler/FrontEnd/ClassLoader.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 ClassLoader
37 " file: ClassLoader.mo
38 package: ClassLoader
39 description: Loading of classes from $OPENMODELICALIBRARY.
40
41
42 This module loads classes from $OPENMODELICALIBRARY. It exports several functions:
43 loadClass function
44 loadModel function
45 loadFile function"
46
47 import Absyn;
48
49 protected
50 import AbsynUtil;
51 import Autoconf;
52 import BaseHashTable;
53 import Config;
54 import Debug;
55 import Error;
56 import Flags;
57 import HashTableStringToProgram;
58 import List;
59 import PackageManagement;
60 import Parser;
61 import System;
62 import Testsuite;
63 import Util;
64
65 type HashTable = HashTableStringToProgram.HashTable;
66
67 protected
68
69 uniontype PackageOrder
70 record CLASSPART
71 Absyn.ClassPart cp;
72 end CLASSPART;
73 record ELEMENT
74 Absyn.ElementItem element;
75 Boolean pub "public";
76 end ELEMENT;
77 record CLASSLOAD
78 String cl;
79 end CLASSLOAD;
80 end PackageOrder;
81
82 uniontype LoadFileStrategy
83 record STRATEGY_HASHTABLE
84 HashTable ht;
85 end STRATEGY_HASHTABLE;
86 record STRATEGY_ON_DEMAND
87 String encoding;
88 end STRATEGY_ON_DEMAND;
89 end LoadFileStrategy;
90
91 public function loadClass
92 "This function takes a \'Path\' and the $OPENMODELICALIBRARY as a string
93 and tries to load the class from the path.
94 If the classname is qualified, the complete package is loaded.
95 E.g. load_class(Modelica.SIunits.Voltage) -> whole Modelica package loaded."
96 input Absyn.Path inPath;
97 input list<String> priorityList;
98 input String modelicaPath;
99 input Option<String> encoding;
100 input Boolean requireExactVersion = false;
101 input Boolean encrypted = false;
102 output Absyn.Program outProgram;
103 algorithm
104 outProgram := matchcontinue (inPath, modelicaPath)
105 local
106 String gd,classname,mp,pack;
107 list<String> mps;
108 Absyn.Program p;
109 /* Simple names: Just load the file if it can be found in $OPENMODELICALIBRARY */
110 case (Absyn.IDENT(name = classname), mp)
111 algorithm
112 gd := Autoconf.groupDelimiter;
113 1857 mps := System.strtok(mp, gd);
114 1857 p := loadClassFromMps(classname, priorityList, mps, encoding, requireExactVersion, encrypted);
115 1463 checkOnLoadMessage(p);
116 then
117 p;
118 /* Qualified names: First check if it is defined in a file pack.mo */
119 case (Absyn.QUALIFIED(name = pack), mp)
120 algorithm
121 gd := Autoconf.groupDelimiter;
122 1 mps := System.strtok(mp, gd);
123 1 p := loadClassFromMps(pack, priorityList, mps, encoding, requireExactVersion, encrypted);
124 1 checkOnLoadMessage(p);
125 then
126 p;
127 /* failure */
128 else
129 algorithm
130
1/2
✓ Branch 1 taken 394 times.
✗ Branch 2 not taken.
394 true := Flags.isSet(Flags.FAILTRACE);
131 ✗ Debug.trace("ClassLoader.loadClass failed\n");
132 ✗ then
133 fail();
134 end matchcontinue;
135 end loadClass;
136
137 protected function loadClassFromMps
138 "Loads a class or classes from a set of paths in OPENMODELICALIBRARY"
139 input String id;
140 input list<String> prios;
141 input list<String> mps;
142 input Option<String> encoding;
143 input Boolean requireExactVersion = false;
144 input Boolean encrypted = false;
145 output Absyn.Program outProgram;
146 protected
147 String mp, name, version;
148 Boolean isDir;
149 Option<Absyn.Class> cl;
150 list<String> versionsThatProvideTheWanted, commands, versions;
151 algorithm
152
2/2
✓ Branch 0 taken 1857 times.
✓ Branch 1 taken 1 time.
1858 if not requireExactVersion then
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1857 times.
1857 if listEmpty(prios) then
154 ✗ versions := PackageManagement.versionsThatProvideTheWanted(id, "default", printError = false);
155 else
156 1857 versions := {};
157
158
2/2
✓ Branch 1 taken 1857 times.
✓ Branch 2 taken 1857 times.
5571 for v in listReverse(prios) loop
159 1857 versionsThatProvideTheWanted :=
160 PackageManagement.versionsThatProvideTheWanted(id, v, printError = false);
161
162
1/2
✓ Branch 0 taken 1857 times.
✗ Branch 1 not taken.
1857 if listEmpty(versionsThatProvideTheWanted) then
163 versions := v :: versions;
164 else
165 ✗ versions := listAppend(versionsThatProvideTheWanted, versions);
166 end if;
167 end for;
168 end if;
169 else
170 versions := prios;
171 end if;
172
173 try
174 1858 (mp,name,isDir) := System.getLoadModelPath(id,versions,mps,requireExactVersion);
175 else
176 version := match prios
177 case version::_ then version;
178 else "default";
179 end match;
180 394 versionsThatProvideTheWanted := PackageManagement.versionsThatProvideTheWanted(id, version, printError=false);
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394 times.
394 if not listEmpty(versionsThatProvideTheWanted) then
182 ✗ if version=="default" or version=="" then
183 ✗ commands := {" installPackage("+id+")"};
184 else
185 commands := {};
186
187 ✗ if listMember(version, versionsThatProvideTheWanted) then
188 ✗ commands := " installPackage("+id+", \""+version+"\", exactMatch=true)" :: commands;
189 end if;
190
191 ✗ commands := " installPackage("+id+", \""+version+"\", exactMatch=false)" :: commands;
192 end if;
193 ✗ if listHead(versionsThatProvideTheWanted) <> version then
194 ✗ commands := " installPackage("+id+", \""+listHead(versionsThatProvideTheWanted)+"\", exactMatch=true)" :: commands;
195 end if;
196 ✗ Error.addMessage(Error.NOTIFY_PKG_FOUND, {stringDelimitList(commands, "\n")});
197 end if;
198 394 fail();
199 end try;
200 // print("System.getLoadModelPath: " + id + " {" + stringDelimitList(prios,",") + "} " + stringDelimitList(mps,",") + " => " + mp + " " + name + " " + boolString(isDir));
201 1464 Config.setLanguageStandardFromMSL(name);
202 1464 cl := loadClassFromMp(id, mp, name, isDir, encoding, encrypted);
203
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1464 times.
✓ Branch 2 taken 1464 times.
✗ Branch 3 not taken.
1464 if (isSome(cl)) then
204 2928 outProgram := Absyn.PROGRAM({Util.getOption(cl)},Absyn.TOP());
205 else
206 outProgram := Absyn.PROGRAM({},Absyn.TOP());
207 end if;
208 end loadClassFromMps;
209
210 public function loadClassFromMp
211 input String id "the actual class name";
212 input String path;
213 input String name;
214 input Boolean isDir;
215 input Option<String> optEncoding;
216 input Boolean encrypted = false;
217 output Option<Absyn.Class> outClass;
218 algorithm
219 outClass := match isDir
220 local
221 String pd,encoding,encodingfile;
222 Option<Absyn.Class> cl;
223 list<String> filenames;
224 LoadFileStrategy strategy;
225 Boolean lveStarted = false;
226 Option<Integer> lveInstance;
227
228 case false
229 algorithm
230 pd := Autoconf.pathDelimiter;
231 /* Check for path/package.encoding; OpenModelica extension */
232 ✗ encodingfile := stringAppendList({path,pd,"package.encoding"});
233 ✗ encoding := System.trimChar(System.trimChar(if System.regularFileExists(encodingfile) then System.readFile(encodingfile) else Util.getOptionOrDefault(optEncoding,"UTF-8"),"\n")," ");
234 ✗ strategy := STRATEGY_ON_DEMAND(encoding);
235 ✗ cl := parsePackageFile(path + pd + name, strategy, false, Absyn.TOP(), id, encrypted);
236 then
237 cl;
238
239 case true
240 algorithm
241 /* Check for path/package.encoding; OpenModelica extension */
242 pd := Autoconf.pathDelimiter;
243 1511 encodingfile := stringAppendList({path,pd,name,pd,"package.encoding"});
244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1511 times.
1511 encoding := System.trimChar(System.trimChar(if System.regularFileExists(encodingfile) then System.readFile(encodingfile) else Util.getOptionOrDefault(optEncoding,"UTF-8"),"\n")," ");
245
246 1511 lveInstance := NONE();
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1511 times.
1511 if encrypted then
248 ✗ (lveStarted, lveInstance) := Parser.startLibraryVendorExecutable(path + pd + name);
249 ✗ if not lveStarted then
250 ✗ Error.addMessage(Error.INTERNAL_ERROR, {"Unable to start library vendor executable."});
251 ✗ fail();
252 end if;
253 end if;
254
255
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1511 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1511 times.
✗ Branch 7 not taken.
1511 if (Testsuite.isRunning() or Config.noProc()==1) and not encrypted then
256 1511 strategy := STRATEGY_ON_DEMAND(encoding);
257 else
258 ✗ filenames := getAllFilesFromDirectory(path + pd + name, encrypted);
259 // print("Files load in parallel:\n" + stringDelimitList(filenames, "\n") + "\n");
260 ✗ strategy := STRATEGY_HASHTABLE(Parser.parallelParseFiles(filenames, encoding, Config.noProc(), path + pd + name, lveInstance));
261 end if;
262 1511 cl := loadCompletePackageFromMp(id, name, path, strategy, Absyn.TOP(), Error.getNumErrorMessages(), encrypted);
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1511 times.
1511 if (encrypted and lveStarted) then
264 ✗ Parser.stopLibraryVendorExecutable(lveInstance);
265 end if;
266 then
267 cl;
268 end match;
269 end loadClassFromMp;
270
271 protected function getAllFilesFromDirectory
272 input String dir;
273 input Boolean encrypted;
274 input list<String> acc = {};
275 output list<String> files;
276 protected
277 list<String> subdirs;
278 String pd = Autoconf.pathDelimiter;
279 algorithm
280 ✗ if encrypted then
281 ✗ files := (dir + pd + "package.moc") :: listAppend(list(dir + pd + f for f in System.mocFiles(dir)), acc);
282 else
283 ✗ files := (dir + pd + "package.mo") :: listAppend(list(dir + pd + f for f in System.moFiles(dir)), acc);
284 end if;
285 ✗ subdirs := list(dir + pd + d for d in List.filter2OnTrue(System.subDirectories(dir), existPackage, dir, encrypted));
286 ✗ files := List.fold1(subdirs, getAllFilesFromDirectory, encrypted, files);
287 end getAllFilesFromDirectory;
288
289 protected function loadCompletePackageFromMp
290 "Loads a whole package from the ModelicaPaths defined in OPENMODELICALIBRARY"
291 input String id "actual class identifier";
292 input Absyn.Ident inIdent;
293 input String inString;
294 input LoadFileStrategy strategy;
295 input Absyn.Within inWithin;
296 input Integer numError;
297 input Boolean encrypted = false;
298 output Option<Absyn.Class> cl;
299 algorithm
300 cl := matchcontinue (inIdent, inString, inWithin)
301 local
302 String pd,mp_1,packagefile,orderfile,pack,mp;
303 Absyn.Within within_;
304 list<String> tv;
305 list<Absyn.NamedArg> ca;
306 list<Absyn.ClassPart> cp;
307 Option<String> cmt;
308 Option<Absyn.Class> opt_cl;
309 Absyn.Class class_;
310 Absyn.Path path;
311 Absyn.Within w2;
312 list<PackageOrder> reverseOrder;
313 list<Absyn.Annotation> ann;
314 case (pack, mp, within_)
315 algorithm
316 pd := Autoconf.pathDelimiter;
317 189608 mp_1 := stringAppendList({mp,pd,pack});
318
1/2
✓ Branch 0 taken 189608 times.
✗ Branch 1 not taken.
379216 packagefile := stringAppendList({mp_1,pd,if encrypted then "package.moc" else "package.mo"});
319 189608 orderfile := stringAppendList({mp_1,pd,"package.order"});
320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 189608 times.
189608 if not System.regularFileExists(packagefile) then
321 ✗ Error.addInternalError("Expected file " + packagefile + " to exist", sourceInfo());
322 ✗ fail();
323 end if;
324 // print("Look for " + packagefile + "\n");
325 189608 opt_cl := parsePackageFile(packagefile, strategy, true, within_, id, encrypted);
326 // print("Got " + packagefile + "\n");
327
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 189608 times.
✓ Branch 2 taken 189608 times.
✗ Branch 3 not taken.
189608 if (isSome(opt_cl)) then
328
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 189608 times.
189608 class_ as Absyn.CLASS(body=Absyn.PARTS(tv,ca,cp,ann,cmt)) := Util.getOption(opt_cl);
329 189608 reverseOrder := getPackageContentNames(class_, orderfile, mp_1, Error.getNumErrorMessages(), encrypted);
330 189608 path := AbsynUtil.joinWithinPath(within_,Absyn.IDENT(id));
331 189608 w2 := Absyn.WITHIN(path);
332
1/2
✓ Branch 0 taken 189608 times.
✗ Branch 1 not taken.
379216 cp := List.fold4(reverseOrder, loadCompletePackageFromMp2, mp_1, strategy, w2, encrypted, {});
333 379216 class_.body := Absyn.PARTS(tv,ca,cp,ann,cmt);
334 opt_cl := SOME(class_);
335 end if;
336 then opt_cl;
337 case (pack, mp, _)
338 algorithm
339 ✗ true := numError == Error.getNumErrorMessages();
340 ✗ Error.addInternalError("loadCompletePackageFromMp failed for unknown reason: mp=" + mp + " pack=" + pack, sourceInfo());
341 ✗ then fail();
342 end matchcontinue;
343 end loadCompletePackageFromMp;
344
345 protected function mergeBefore
346 input Absyn.ClassPart cp;
347 input list<Absyn.ClassPart> cps;
348 output list<Absyn.ClassPart> ocp;
349 algorithm
350 ocp := match (cp,cps)
351 local
352 list<Absyn.ElementItem> ei1,ei2,ei;
353 list<Absyn.ClassPart> rest;
354 case (Absyn.PUBLIC(ei1),Absyn.PUBLIC(ei2)::rest)
355 algorithm
356 1301200 ei := listAppend(ei1,ei2);
357 1301200 then Absyn.PUBLIC(ei)::rest;
358 case (Absyn.PROTECTED(ei1),Absyn.PROTECTED(ei2)::rest)
359 algorithm
360 1386 ei := listAppend(ei1,ei2);
361 1386 then Absyn.PROTECTED(ei)::rest;
362 else cp::cps;
363 end match;
364 end mergeBefore;
365
366 protected function loadCompletePackageFromMp2
367 "Loads a whole package from the ModelicaPaths defined in OPENMODELICALIBRARY"
368 input PackageOrder po "mo-file or directory";
369 input String mp;
370 input LoadFileStrategy strategy;
371 input Absyn.Within w1 "With the parent added";
372 input Boolean encrypted = false;
373 input list<Absyn.ClassPart> acc;
374 output list<Absyn.ClassPart> cps;
375 algorithm
376 cps := match po
377 local
378 Absyn.ElementItem ei;
379 String pd,file,id;
380 Absyn.ClassPart cp;
381 Option<Absyn.Class> cl;
382 Boolean bDirectoryAndFileExists;
383
384 case CLASSPART(cp)
385 algorithm
386 487 cps := mergeBefore(cp,acc);
387 then cps;
388
389 case ELEMENT(ei,true)
390 algorithm
391 238955 cps := mergeBefore(Absyn.PUBLIC({ei}),acc);
392 then cps;
393
394 case ELEMENT(ei,false)
395 algorithm
396 1847 cps := mergeBefore(Absyn.PROTECTED({ei}),acc);
397 then cps;
398
399 case CLASSLOAD(id)
400 algorithm
401 pd := Autoconf.pathDelimiter;
402
1/2
✓ Branch 2 taken 1251774 times.
✗ Branch 3 not taken.
2503548 file := mp + pd + id + (if encrypted then "/package.moc" else "/package.mo");
403
3/4
✓ Branch 3 taken 188097 times.
✓ Branch 4 taken 1063677 times.
✓ Branch 6 taken 188097 times.
✗ Branch 7 not taken.
1251774 bDirectoryAndFileExists := System.directoryExists(mp + pd + id) and System.regularFileExists(file);
404 if bDirectoryAndFileExists then
405 188097 cl := loadCompletePackageFromMp(id,id,mp,strategy,w1,Error.getNumErrorMessages(),encrypted);
406
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 188097 times.
✓ Branch 2 taken 188097 times.
✗ Branch 3 not taken.
188097 if (isSome(cl)) then
407 188097 ei := AbsynUtil.makeClassElement(Util.getOption(cl));
408 188097 cps := mergeBefore(Absyn.PUBLIC({ei}),acc);
409 else
410 cps := acc;
411 end if;
412 else
413
1/2
✓ Branch 2 taken 1063677 times.
✗ Branch 3 not taken.
2127354 file := mp + pd + id + (if encrypted then ".moc" else ".mo");
414
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1063677 times.
1063677 if not System.regularFileExists(file) then
415 ✗ Error.addInternalError("Expected file " + file + " to exist", sourceInfo());
416 ✗ fail();
417 end if;
418 1063677 cl := parsePackageFile(file, strategy, false, w1, id, encrypted);
419
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1063677 times.
✓ Branch 2 taken 1063677 times.
✗ Branch 3 not taken.
1063677 if (isSome(cl)) then
420 1063677 ei := AbsynUtil.makeClassElement(Util.getOption(cl));
421 1063677 cps := mergeBefore(Absyn.PUBLIC({ei}),acc);
422 else
423 cps := acc;
424 end if;
425 end if;
426 then cps;
427
428 end match;
429 end loadCompletePackageFromMp2;
430
431 public function parsePackageFile
432 "Parses a file containing a single class that matches the within"
433 input String name;
434 input LoadFileStrategy strategy;
435 input Boolean expectPackage;
436 input Absyn.Within w1 "Expected within of the package";
437 input String pack "Expected name of the package";
438 input Boolean encrypted = false;
439 output Option<Absyn.Class> cl;
440 protected
441 Absyn.Class class_;
442 list<Absyn.Class> cs;
443 Absyn.Within w2;
444 list<String> classNames;
445 SourceInfo info;
446 String str,s1,s2,cname;
447 Absyn.ClassDef body;
448 algorithm
449 1253285 Absyn.PROGRAM(cs,w2) := getProgramFromStrategy(name, strategy);
450 1253285 classNames := List.map(cs, AbsynUtil.getClassName);
451 1253285 str := stringDelimitList(classNames,", ");
452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1253285 times.
1253285 if not listLength(cs)==1 then
453 ✗ if encrypted then
454 cl := NONE();
455 ✗ return;
456 else
457 ✗ Error.addSourceMessage(Error.LIBRARY_ONE_PACKAGE_PER_FILE, {str}, SOURCEINFO(name,true,0,0,0,0,0.0));
458 ✗ fail();
459 end if;
460 end if;
461
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1253285 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1253285 times.
1253285 (class_ as Absyn.CLASS(name=cname,body=body,info=info))::{} := cs;
462 cl := SOME(class_);
463
2/4
✓ Branch 0 taken 1253285 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1253285 times.
1253285 if not stringEqual(cname,pack) then
464 ✗ if stringEqual(System.tolower(cname), System.tolower(pack)) then
465 ✗ Error.addSourceMessage(Error.LIBRARY_UNEXPECTED_NAME_CASE_SENSITIVE, {pack,cname}, info);
466 else
467 ✗ Error.addSourceMessage(Error.LIBRARY_UNEXPECTED_NAME, {pack,cname}, info);
468 ✗ fail();
469 end if;
470 end if;
471
3/4
✓ Branch 0 taken 189608 times.
✓ Branch 1 taken 1063677 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 189608 times.
1253285 if expectPackage and not AbsynUtil.isParts(body) then
472 ✗ Error.addSourceMessage(Error.LIBRARY_EXPECTED_PARTS, {pack}, info);
473 ✗ fail();
474 elseif not (AbsynUtil.withinEqual(w1,w2) or Config.languageStandardAtMost(Config.LanguageStandard._2_x)) then
475 ✗ s1 := AbsynUtil.withinString(w1);
476 ✗ s2 := AbsynUtil.withinString(w2);
477 ✗ if AbsynUtil.withinEqualCaseInsensitive(w1,w2) then
478 ✗ Error.addSourceMessage(Error.LIBRARY_WITHIN_WRONG_CASE, {s1,s2}, info);
479 else
480 ✗ Error.addSourceMessage(Error.LIBRARY_UNEXPECTED_WITHIN, {s1,s2}, info);
481 ✗ fail();
482 end if;
483 end if;
484 end parsePackageFile;
485
486 protected function getBothPackageAndFilename
487 input String str;
488 input String mp;
489 output String out;
490 algorithm
491 ✗ out := Testsuite.friendly(System.realpath(mp + "/" + str + ".mo")) + ", " + Testsuite.friendly(System.realpath(mp + "/" + str + "/package.mo"));
492 end getBothPackageAndFilename;
493
494 protected function getPackageContentNames
495 "Gets the names of packages to load before the package.mo, and the ones to load after"
496 input Absyn.Class cl;
497 input String filename;
498 input String mp;
499 input Integer numError;
500 input Boolean encrypted = false;
501 output list<PackageOrder> po "reverse";
502 algorithm
503 po := matchcontinue cl
504 local
505 String contents, duplicatesStr, differencesStr;
506 list<String> duplicates, namesToFind, mofiles, subdirs, differences, intersection;
507 list<Absyn.ClassPart> cp;
508 SourceInfo info;
509 list<PackageOrder> po1, po2;
510
511 case Absyn.CLASS(body=Absyn.PARTS(classParts=cp),info=info)
512 algorithm
513 try
514
2/2
✓ Branch 1 taken 487 times.
✓ Branch 2 taken 189121 times.
189608 true := System.regularFileExists(filename);
515 189121 contents := System.readFile(filename);
516 189121 namesToFind := System.strtok(contents, "\n");
517 189121 namesToFind := List.removeOnTrue("",stringEqual,List.map(namesToFind,System.trimWhitespace));
518 189121 duplicates := List.sortedDuplicates(List.sort(namesToFind,Util.strcmpBool),stringEq);
519 189121 duplicatesStr := stringDelimitList(duplicates, ", ");
520 189121 Error.assertionOrAddSourceMessage(listEmpty(duplicates),Error.PACKAGE_ORDER_DUPLICATES,{duplicatesStr},SOURCEINFO(filename,true,0,0,0,0,0.0));
521
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 189121 times.
189121 if encrypted then
523 // get all the .moc files in the directory!
524 ✗ mofiles := List.map(System.mocFiles(mp), Util.removeLast4Char);
525 else
526 // get all the .mo files in the directory!
527 189121 mofiles := List.map(System.moFiles(mp), Util.removeLast3Char);
528 end if;
529 // get all the subdirs
530 189121 subdirs := System.subDirectories(mp);
531
1/2
✓ Branch 0 taken 189121 times.
✗ Branch 1 not taken.
378242 subdirs := List.filter2OnTrue(subdirs, existPackage, mp, encrypted);
532 // build a list
533 189121 intersection := List.intersectionOnTrue(subdirs,mofiles,stringEq);
534 189121 differencesStr := stringDelimitList(List.map1(intersection, getBothPackageAndFilename, mp), ", ");
535 189121 Error.assertionOrAddSourceMessage(listEmpty(intersection),Error.PACKAGE_DUPLICATE_CHILDREN,{differencesStr},SOURCEINFO(filename,true,0,0,0,0,0.0));
536 189121 mofiles := listAppend(subdirs,mofiles);
537 // check if all are present in the package.order
538 189121 differences := List.setDifference(mofiles, namesToFind);
539 189121 po1 := getPackageContentNamesinParts(namesToFind,cp,{});
540 189121 (po1,differences) := List.map3Fold(po1,checkPackageOrderFilesExist,mp,info,encrypted,differences);
541
542 // issue a warning if not all are present
543 189121 differencesStr := stringDelimitList(differences, "\n\t");
544 189121 Error.assertionOrAddSourceMessage(listEmpty(differences),Error.PACKAGE_ORDER_FILE_NOT_COMPLETE,{differencesStr},SOURCEINFO(filename,true,0,0,0,0,0.0));
545
546 189121 po2 := List.map(differences, makeClassLoad);
547
548 189121 po := listAppend(po2, po1);
549 else // file not found
550 487 mofiles := List.map(System.moFiles(mp), Util.removeLast3Char) "Here .mo files in same directory as package.mo should be loaded as sub-packages";
551 487 subdirs := System.subDirectories(mp);
552
1/2
✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
974 subdirs := List.filter2OnTrue(subdirs, existPackage, mp, encrypted);
553 487 mofiles := List.sort(listAppend(subdirs,mofiles), Util.strcmpBool);
554 // Look for duplicates
555 487 intersection := List.sortedDuplicates(mofiles,stringEq);
556 487 differencesStr := stringDelimitList(List.map1(intersection, getBothPackageAndFilename, mp), ", ");
557 487 Error.assertionOrAddSourceMessage(listEmpty(intersection),Error.PACKAGE_DUPLICATE_CHILDREN,{differencesStr},info);
558
559 487 po := listAppend(List.map(cp, makeClassPart),List.map(mofiles, makeClassLoad));
560 end try;
561 then
562 po;
563
564 case Absyn.CLASS(info=info)
565 algorithm
566 ✗ true := numError == Error.getNumErrorMessages();
567 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR,{"getPackageContentNames failed for unknown reason"},info);
568 ✗ then fail();
569
570 end matchcontinue;
571 end getPackageContentNames;
572
573 protected function makeClassPart
574 input Absyn.ClassPart part;
575 output PackageOrder po;
576 algorithm
577 487 po := CLASSPART(part);
578 end makeClassPart;
579
580 protected function makeElement
581 input Absyn.ElementItem el;
582 input Boolean pub;
583 output PackageOrder po;
584 algorithm
585
2/2
✓ Branch 0 taken 1847 times.
✓ Branch 1 taken 38407 times.
42101 po := ELEMENT(el,pub);
586 end makeElement;
587
588 protected function makeClassLoad
589 input String str;
590 output PackageOrder po;
591 algorithm
592 1278053 po := CLASSLOAD(str);
593 end makeClassLoad;
594
595 protected function checkPackageOrderFilesExist
596 input output PackageOrder po;
597 input String mp;
598 input SourceInfo info;
599 input Boolean encrypted = false;
600 input output list<String> differences;
601 algorithm
602 () := match po
603 local
604 String pd,str,str2,str3,str4;
605 case CLASSLOAD(str)
606 algorithm
607 pd := Autoconf.pathDelimiter;
608
1/2
✓ Branch 0 taken 1251751 times.
✗ Branch 1 not taken.
2503502 str2 := str + (if encrypted then ".moc" else ".mo");
609
3/4
✓ Branch 5 taken 1063662 times.
✓ Branch 6 taken 188089 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1063662 times.
1251751 if not (System.directoryExists(mp + pd + str) or System.regularFileExists(mp + pd + str2)) then
610 try
611 ✗ str3 := List.find(System.moFiles(mp), function Util.stringEqCaseInsensitive(str2=System.tolower(str2)));
612 else
613 ✗ Error.addSourceMessage(Error.PACKAGE_ORDER_FILE_NOT_FOUND,{str},info);
614 ✗ fail();
615 end try;
616 ✗ Error.addSourceMessage(Error.PACKAGE_ORDER_CASE_SENSITIVE, {str, str2, str3}, info);
617 ✗ str4 := Util.removeLastNChar(str3,if encrypted then 4 else 3);
618 ✗ differences := List.removeOnTrue(str4, stringEq, differences);
619 ✗ po := CLASSLOAD(str4);
620 end if;
621 then ();
622 else ();
623 end match;
624 end checkPackageOrderFilesExist;
625
626 protected function existPackage
627 input String name;
628 input String mp;
629 input Boolean encrypted = false;
630 output Boolean b;
631 protected
632 String pd;
633 algorithm
634 pd := Autoconf.pathDelimiter;
635
1/2
✓ Branch 3 taken 188688 times.
✗ Branch 4 not taken.
377376 b := System.regularFileExists(mp + pd + name + pd + (if encrypted then "package.moc" else "package.mo"));
636 end existPackage;
637
638 protected function getPackageContentNamesinParts
639 input list<String> inNamesToSort;
640 input list<Absyn.ClassPart> cps;
641 input list<PackageOrder> acc;
642 output list<PackageOrder> outOrder "reverse";
643 algorithm
644 outOrder := match (inNamesToSort, cps)
645 local
646 list<Absyn.ClassPart> rcp;
647 list<Absyn.ElementItem> elts;
648 list<String> namesToSort;
649 Absyn.ClassPart cp;
650 case (namesToSort, {})
651 algorithm
652 189121 outOrder := listAppend(List.mapReverse(namesToSort,makeClassLoad),acc);
653 then outOrder;
654 case (namesToSort, Absyn.PUBLIC(elts)::rcp)
655 algorithm
656 189121 (outOrder,namesToSort) := getPackageContentNamesinElts(namesToSort,elts,acc,true);
657 189121 outOrder := getPackageContentNamesinParts(namesToSort,rcp,outOrder);
658 then outOrder;
659 case (namesToSort, Absyn.PROTECTED(elts)::rcp)
660 algorithm
661 461 (outOrder,namesToSort) := getPackageContentNamesinElts(namesToSort,elts,acc,false);
662 461 outOrder := getPackageContentNamesinParts(namesToSort,rcp,outOrder);
663 then outOrder;
664 case (namesToSort, cp::rcp)
665 algorithm
666 ✗ outOrder := getPackageContentNamesinParts(namesToSort,rcp,CLASSPART(cp)::acc);
667 then outOrder;
668 end match;
669 end getPackageContentNamesinParts;
670
671 protected function getPackageContentNamesinElts
672 input list<String> inNamesToSort;
673 input list<Absyn.ElementItem> inElts;
674 input list<PackageOrder> po;
675 input Boolean pub;
676 output list<PackageOrder> outOrder;
677 output list<String> outNames;
678 algorithm
679 (outOrder,outNames) := match (inNamesToSort, inElts)
680 local
681 String name1,name2;
682 list<String> namesToSort,names,compNames;
683 list<Absyn.ElementItem> elts;
684 Boolean b;
685 SourceInfo info;
686 list<Absyn.ComponentItem> comps;
687 Absyn.ElementItem ei;
688 PackageOrder orderElt,load;
689 case (namesToSort, {}) then (po,namesToSort);
690
691 case (name1::_, (ei as Absyn.ELEMENTITEM(Absyn.ELEMENT(specification=Absyn.COMPONENTS(components=comps),info=info)))::elts)
692 algorithm
693 14074 compNames := List.map(comps,AbsynUtil.componentName);
694 14074 (names,b) := matchCompNames(inNamesToSort,compNames,info);
695
2/2
✓ Branch 0 taken 13975 times.
✓ Branch 1 taken 99 times.
14074 orderElt := if b then makeElement(ei,pub) else makeClassLoad(name1);
696
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 13975 times.
248811 (outOrder,names) := getPackageContentNamesinElts(names,if b then elts else inElts,orderElt :: po,pub);
697 then (outOrder,names);
698
699 case (name1::namesToSort, (ei as Absyn.ELEMENTITEM(Absyn.ELEMENT(specification=Absyn.CLASSDEF(class_=Absyn.CLASS(name=name2,info=info)))))::elts)
700 algorithm
701 34090 load := makeClassLoad(name1);
702
4/4
✓ Branch 0 taken 27195 times.
✓ Branch 1 taken 6895 times.
✓ Branch 3 taken 916 times.
✓ Branch 4 taken 26279 times.
35006 b := name1 == name2;
703
3/4
✓ Branch 0 taken 26279 times.
✓ Branch 1 taken 7811 times.
✓ Branch 3 taken 26279 times.
✗ Branch 4 not taken.
60369 Error.assertionOrAddSourceMessage(if b then not listMember(load,po) else true, Error.PACKAGE_MO_NOT_IN_ORDER, {name2}, info);
704
2/2
✓ Branch 0 taken 26279 times.
✓ Branch 1 taken 7811 times.
34090 orderElt := if b then makeElement(ei,pub) else load;
705
2/2
✓ Branch 0 taken 7811 times.
✓ Branch 1 taken 26279 times.
41901 (outOrder,names) := getPackageContentNamesinElts(namesToSort,if b then elts else inElts,orderElt :: po, pub);
706 then (outOrder,names);
707
708 case ({}, (Absyn.ELEMENTITEM(Absyn.ELEMENT(specification=Absyn.CLASSDEF(class_=Absyn.CLASS(name=name2,info=info)))))::_)
709 algorithm
710 ✗ load := makeClassLoad(name2);
711 ✗ Error.assertionOrAddSourceMessage(not listMember(load,po), Error.PACKAGE_MO_NOT_IN_ORDER, {name2}, info);
712 ✗ Error.addSourceMessage(Error.FOUND_ELEMENT_NOT_IN_ORDER_FILE, {name2}, info);
713 ✗ (outOrder,names) := getPackageContentNamesinElts(name2 :: inNamesToSort, inElts, po, pub);
714 then (outOrder,names);
715
716 case ({}, Absyn.ELEMENTITEM(Absyn.ELEMENT(specification=Absyn.COMPONENTS(components=Absyn.COMPONENTITEM(component=Absyn.COMPONENT(name=name2))::_),info=info))::_)
717 algorithm
718 ✗ load := makeClassLoad(name2);
719 ✗ Error.assertionOrAddSourceMessage(not listMember(load,po), Error.PACKAGE_MO_NOT_IN_ORDER, {name2}, info);
720 ✗ Error.addSourceMessage(Error.FOUND_ELEMENT_NOT_IN_ORDER_FILE, {name2}, info);
721 ✗ (outOrder,names) := getPackageContentNamesinElts(name2 :: inNamesToSort, inElts, po, pub);
722 then (outOrder,names);
723
724 case (namesToSort, ei::elts)
725 algorithm
726
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200548 times.
401096 (outOrder,names) := getPackageContentNamesinElts(namesToSort,elts,ELEMENT(ei,pub) :: po, pub);
727 then (outOrder,names);
728 end match;
729 end getPackageContentNamesinElts;
730
731 protected function matchCompNames
732 input list<String> names;
733 input list<String> comps;
734 input SourceInfo info;
735 output list<String> outNames;
736 output Boolean matchedNames;
737 algorithm
738 (outNames,matchedNames) := match (names, comps)
739 local
740 Boolean b, b1;
741 String n1,n2;
742 list<String> rest1,rest2;
743
744 case (_, {}) then (names,true);
745
746 case (n1::rest1, n2::rest2)
747 algorithm
748
3/4
✓ Branch 0 taken 13975 times.
✓ Branch 1 taken 99 times.
✓ Branch 3 taken 13975 times.
✗ Branch 4 not taken.
14074 if (n1 == n2)
749 then
750 13975 (rest1,b) := matchCompNames(rest1,rest2,info);
751 13975 Error.assertionOrAddSourceMessage(b, Error.ORDER_FILE_COMPONENTS, {}, info);
752 13975 b1 := true;
753 else
754 b1 := false;
755 end if;
756 then (rest1,b1);
757
758 end match;
759 end matchCompNames;
760
761 protected function packageOrderName
762 input PackageOrder ord;
763 output String name;
764 algorithm
765 name := match ord
766 case CLASSLOAD(name) then name;
767 else "#";
768 end match;
769 end packageOrderName;
770
771 public function checkOnLoadMessage
772 "Checks annotation __OpenModelica_messageOnLoad for a message to display"
773 input Absyn.Program p1;
774 protected
775 list<Absyn.Class> classes;
776 algorithm
777 3422 Absyn.PROGRAM(classes=classes) := p1;
778 3422 List.map2(classes,AbsynUtil.getNamedAnnotationInClass,Absyn.IDENT("__OpenModelica_messageOnLoad"),checkOnLoadMessageWork);
779 end checkOnLoadMessage;
780
781 protected function checkOnLoadMessageWork
782 "Checks annotation __OpenModelica_messageOnLoad for a message to display"
783 input Option<Absyn.Modification> mod;
784 output Integer dummy;
785 algorithm
786 dummy := match mod
787 local
788 String str;
789 SourceInfo info;
790 case SOME(Absyn.CLASSMOD(eqMod=Absyn.EQMOD(info=info,exp=Absyn.STRING(str))))
791 algorithm
792 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION_SCRIPTING,{str},info);
793 then 1;
794 end match;
795 end checkOnLoadMessageWork;
796
797 function getProgramFromStrategy
798 input String filename;
799 input LoadFileStrategy strategy;
800 output Absyn.Program program;
801 protected
802 String f = filename;
803 algorithm
804 program := match strategy
805 case STRATEGY_HASHTABLE()
806 algorithm
807 ✗ if not BaseHashTable.hasKey(filename, strategy.ht) then
808 // it might NOT be in the hashtable because of case issues, check that!
809 try
810 ✗ f := List.getMemberOnTrue(filename, BaseHashTable.hashTableKeyList(strategy.ht), Util.stringEqCaseInsensitive);
811 // adrpo: not needed, a warning is given earlier about the case of the file vs the class
812 // Error.addSourceMessage(Error.COMPILER_WARNING, {"HashTable has entry for file:\n" + filename + "\nwith a different case:\n" + f + "\ncontinue ...\n"}, sourceInfo());
813 else
814 ✗ Error.addInternalError("HashTable missing file: " + filename + " - all entries include:\n" + stringDelimitList(BaseHashTable.hashTableKeyList(strategy.ht), "\n"), sourceInfo());
815 ✗ fail();
816 end try;
817 end if;
818 ✗ then BaseHashTable.get(f, strategy.ht);
819 1253285 case STRATEGY_ON_DEMAND() then Parser.parse(filename, strategy.encoding);
820 end match;
821 end getProgramFromStrategy;
822
823 annotation(__OpenModelica_Interface="loader");
824 end ClassLoader;
825