Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 27.3% 15 / 0 / 55
Functions: -% 0 / 1 / 1
Branches: 26.3% 10 / 0 / 38

OMCompiler/Compiler/FrontEnd/Parser.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 Parser
37 " file: Parser.mo
38 package: Parser
39 description: Interface to external code for parsing
40
41 $Id$
42
43 The parser module is used for both parsing of files and statements in
44 interactive mode."
45
46 import Absyn;
47 import GlobalScript;
48 import HashTableStringToProgram;
49
50 protected
51 import AbsynUtil;
52 import Config;
53 import ErrorExt;
54 import Flags;
55 import ParserExt;
56 import System;
57 import Testsuite;
58 import Util;
59 import List;
60
61 public
62
63 function parse "Parse a mo-file"
64 input String filename;
65 input String encoding;
66 input String libraryPath = "";
67 input Option<Integer> lveInstance = NONE();
68 input Integer acceptedGram = Config.acceptedGrammar();
69 input Integer languageStandardInt = Flags.getConfigEnum(Flags.LANGUAGE_STANDARD);
70 input Boolean strict = Flags.getConfigBool(Flags.STRICT);
71 output Absyn.Program outProgram;
72 protected
73 list<Absyn.Class> classes, classes1;
74 Absyn.Within w;
75 Absyn.Class cs;
76 String realpath;
77 algorithm
78 1265803 realpath := Util.replaceWindowsBackSlashWithPathDelimiter(System.realpath(filename));
79 1265803 outProgram := ParserExt.parse(realpath, Testsuite.friendly(realpath),
80 acceptedGram, encoding, languageStandardInt, strict, Testsuite.isRunning(), libraryPath, lveInstance);
81
82 // Check license features
83
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1265786 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1265786 times.
1265786 if (isSome(lveInstance)) then
84 ✗ Absyn.PROGRAM(classes, w) := outProgram;
85 classes1 := {};
86 ✗ for cs in classes loop
87 ✗ if checkLicenseAndFeatures(cs, lveInstance) then
88 classes1 := cs :: classes1;
89 end if;
90 end for;
91 ✗ outProgram := Absyn.PROGRAM(classes1, w);
92 end if;
93 end parse;
94
95 function parseexp "Parse a mos-file"
96 input String filename;
97 output GlobalScript.Statements outStatements;
98 algorithm
99 1683 outStatements := ParserExt.parseexp(System.realpath(filename), Testsuite.friendly(System.realpath(filename)), Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
100 end parseexp;
101
102 function parsestring "Parse a string as if it were a stored definition"
103 input String str;
104 input String infoFilename = "<interactive>";
105 input Integer grammar = Config.acceptedGrammar();
106 input Integer languageStd = Flags.getConfigEnum(Flags.LANGUAGE_STANDARD);
107 input Boolean strict = Flags.getConfigBool(Flags.STRICT);
108 output Absyn.Program outProgram;
109 algorithm
110 859 outProgram := ParserExt.parsestring(str, infoFilename, grammar, languageStd, strict, Testsuite.isRunning());
111 end parsestring;
112
113 function parsestringexp "Parse a string as if it was a sequence of statements"
114 input String str;
115 input String infoFilename = "<interactive>";
116 output GlobalScript.Statements outStatements;
117 algorithm
118 479 outStatements := ParserExt.parsestringexp(str,infoFilename,
119 Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
120 end parsestringexp;
121
122 function stringPath
123 input String str;
124 output Absyn.Path path;
125 algorithm
126 ✗ path := ParserExt.stringPath(str, "<internal>", Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
127 end stringPath;
128
129 function stringCref
130 input String str;
131 output Absyn.ComponentRef cref;
132 algorithm
133 4 cref := ParserExt.stringCref(str, "<internal>", Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
134 end stringCref;
135
136 function stringMod
137 input String str;
138 input String filename = "<internal>";
139 output Absyn.ElementArg mod;
140 algorithm
141 51 mod := ParserExt.stringMod(str, filename, Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
142 end stringMod;
143
144 function stringEq
145 input String str;
146 input String filename = "<internal>";
147 output Absyn.EquationItem eq;
148 algorithm
149 17 eq := ParserExt.stringEq(str, filename, Config.acceptedGrammar(), Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), Testsuite.isRunning());
150 end stringEq;
151
152 function parallelParseFiles
153 input list<String> filenames;
154 input String encoding;
155 input Integer numThreads = Config.noProc();
156 input String libraryPath = "";
157 input Option<Integer> lveInstance = NONE();
158 output HashTableStringToProgram.HashTable ht;
159 protected
160 list<ParserResult> partialResults;
161 algorithm
162 ✗ partialResults := parallelParseFilesWork(filenames, encoding, numThreads, libraryPath, lveInstance);
163 ✗ ht := HashTableStringToProgram.emptyHashTableSized(Util.nextPrime(listLength(partialResults)));
164 ✗ for res in partialResults loop
165 ht := match res
166 local
167 Absyn.Program p;
168 case PARSERRESULT(program=SOME(p))
169 ✗ then BaseHashTable.add((res.filename,p), ht);
170 end match;
171 end for;
172 end parallelParseFiles;
173
174 function parallelParseFilesToProgramList
175 input list<String> filenames;
176 input String encoding;
177 input Integer numThreads = Config.noProc();
178 output list<Absyn.Program> result = {};
179 algorithm
180
2/2
✓ Branch 1 taken 756 times.
✓ Branch 2 taken 4 times.
760 for r in parallelParseFilesWork(filenames, encoding, numThreads) loop
181 result := (match r
182 local
183 Absyn.Program p;
184 case PARSERRESULT(program=SOME(p)) then p;
185 end match) :: result;
186 end for;
187 4 result := MetaModelica.Dangerous.listReverseInPlace(result);
188 end parallelParseFilesToProgramList;
189
190 function startLibraryVendorExecutable
191 input String lvePath;
192 output Boolean success;
193 output Option<Integer> lveInstance "Stores a pointer. If it is declared as Integer, it is truncated to 32-bit.";
194 algorithm
195 ✗ (success, lveInstance) := ParserExt.startLibraryVendorExecutable(lvePath);
196 end startLibraryVendorExecutable;
197
198 function checkLVEToolLicense
199 input Option<Integer> lveInstance;
200 input String packageName;
201 output Boolean status;
202 algorithm
203 ✗ status := ParserExt.checkLVEToolLicense(lveInstance, packageName);
204 end checkLVEToolLicense;
205
206 function checkLVEToolFeature
207 input Option<Integer> lveInstance;
208 input String feature;
209 output Boolean status;
210 algorithm
211 ✗ status := ParserExt.checkLVEToolFeature(lveInstance, feature);
212 end checkLVEToolFeature;
213
214 function stopLibraryVendorExecutable
215 input Option<Integer> lveInstance "Stores a pointer. If it is declared as Integer, it is truncated to 32-bit.";
216 algorithm
217 ✗ ParserExt.stopLibraryVendorExecutable(lveInstance);
218 end stopLibraryVendorExecutable;
219
220 protected
221
222 uniontype ParserResult
223 record PARSERRESULT
224 String filename;
225 Option<Absyn.Program> program;
226 end PARSERRESULT;
227 end ParserResult;
228
229 function parallelParseFilesWork
230 input list<String> filenames;
231 input String encoding;
232 input Integer numThreads;
233 input String libraryPath = "";
234 input Option<Integer> lveInstance = NONE();
235 output list<ParserResult> partialResults;
236 protected
237 list<tuple<String,String,String,Option<Integer>>> workList = list((file,encoding,libraryPath,lveInstance) for file in filenames);
238 algorithm
239
1/12
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
4 if Testsuite.isRunning() or Config.noProc()==1 or numThreads == 1 or listLength(filenames)<2 or isSome(lveInstance) then
240
4/4
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 756 times.
✓ Branch 3 taken 4 times.
760 partialResults := list(loadFileThread(t) for t in workList);
241 else
242 // GCExt.disable(); // Seems to sometimes break building nightly omc
243 ✗ partialResults := System.launchParallelTasksThreaded(min(8, numThreads) /* Boehm GC does not scale to infinity */, workList, loadFileThread);
244 // GCExt.enable();
245 end if;
246 end parallelParseFilesWork;
247
248 function loadFileThread
249 input tuple<String,String,String,Option<Integer>> inFileEncoding;
250 output ParserResult result;
251 algorithm
252 result := matchcontinue inFileEncoding
253 local
254 String filename,encoding,libraryPath;
255 Option<Integer> lveInstance;
256 1512 case (filename,encoding,libraryPath,lveInstance) then PARSERRESULT(filename,SOME(Parser.parse(filename, encoding, libraryPath, lveInstance)));
257 ✗ case (filename,_,_,_) then PARSERRESULT(filename,NONE());
258 end matchcontinue;
259
1/2
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
756 if ErrorExt.getNumMessages() > 0 then
260 ✗ ErrorExt.moveMessagesToParentThread();
261 end if;
262 end loadFileThread;
263
264 public function checkLicenseAndFeatures
265 input Absyn.Class c1;
266 input Option<Integer> lveInstance = NONE();
267 output Boolean result;
268 protected
269 list<String> orFeatures;
270 list<String> andFeatures;
271 algorithm
272 // check license
273 //print("Parser.checkLVEToolLicense returned = " + boolString(Parser.checkLVEToolLicense(lveInstance, AbsynUtil.getClassName(c1))) + "\n");
274 //(libraryKey, licenseFile) := getLicenseAnnotation(c1);
275 //print("Library Key is : " + libraryKey + "\n");
276 //print("License File is : " + licenseFile + "\n");
277
278 // annotation(Protection(features={"LicenseOption1 LicenseOption2", "LicenseOption3"}));
279 // For above annotation. Requires license features ("LicenseOption1" and "LicenseOption2") or "LicenseOption3"
280 result := true;
281 ✗ orFeatures := getFeaturesAnnotation(c1);
282 ✗ for orFeature in orFeatures loop
283 ✗ andFeatures := Util.stringSplitAtChar(orFeature, " ");
284 result := true;
285 ✗ for andFeature in andFeatures loop
286 ✗ if not checkLVEToolFeature(lveInstance, andFeature) then
287 result := false;
288 break;
289 end if;
290 end for;
291 // If we one of the feature is there then do not look for other features.
292 // If the features vector has more than one element, then at least a license feature according to one of the elements must be present
293 ✗ if result then
294 break;
295 end if;
296 end for;
297 end checkLicenseAndFeatures;
298
299 protected function getLicenseAnnotation
300 "Returns the Protection(License=) annotation of a class.
301 This is annotated with the annotation:
302 annotation(Protection(License(libraryKey=\"15783-A39323-498222-444ckk4ll\", licenseFile=\"MyLibraryAuthorization_Tool.mo_lic\"))); in the class definition"
303 input Absyn.Class className;
304 output tuple<String, String> license;
305 protected
306 Option<tuple<String, String>> opt_license;
307 algorithm
308 ✗ opt_license := AbsynUtil.getNamedAnnotationInClass(className, Absyn.IDENT("Protection"), getLicenseAnnotationWork1);
309 ✗ license := Util.getOptionOrDefault(opt_license, ("", ""));
310 end getLicenseAnnotation;
311
312 protected function getLicenseAnnotationWork1
313 "Extractor function for getLicenseAnnotation"
314 input Option<Absyn.Modification> mod;
315 output tuple<String, String> license;
316 algorithm
317 license := match mod
318 local
319 list<Absyn.ElementArg> arglst;
320 String libraryKey, licenseFile;
321
322 case SOME(Absyn.CLASSMOD(elementArgLst = arglst))
323 algorithm
324 ✗ (libraryKey, licenseFile) := getLicenseAnnotationWork2(arglst);
325 ✗ then (libraryKey, licenseFile);
326 end match;
327 end getLicenseAnnotationWork1;
328
329 protected function getLicenseAnnotationWork2
330 "Extractor function for getLicenseAnnotation"
331 input list<Absyn.ElementArg> eltArgs;
332 output tuple<String, String> license;
333 algorithm
334 license := match eltArgs
335 local
336 Option<Absyn.Modification> mod;
337 list<Absyn.ElementArg> xs;
338 String libraryKey, licenseFile;
339
340 case {} then ("", "");
341
342 case Absyn.MODIFICATION(path = Absyn.IDENT(name="License"), modification = mod)::_
343 algorithm
344 ✗ (libraryKey, licenseFile) := getLicenseAnnotationTuple(mod);
345 ✗ then (libraryKey, licenseFile);
346
347 case _::xs
348 algorithm
349 ✗ (libraryKey, licenseFile) := getLicenseAnnotationWork2(xs);
350 ✗ then (libraryKey, licenseFile);
351
352 end match;
353 end getLicenseAnnotationWork2;
354
355 protected function getLicenseAnnotationTuple
356 "Extractor function for getLicenseAnnotation"
357 input Option<Absyn.Modification> mod;
358 output tuple<String, String> license;
359 algorithm
360 license := match mod
361 local
362 list<Absyn.ElementArg> arglst;
363 String libraryKey, licenseFile;
364
365 case SOME(Absyn.CLASSMOD(elementArgLst = arglst))
366 algorithm
367 ✗ libraryKey := getLicenseAnnotationLibraryKey(arglst);
368 ✗ licenseFile := getLicenseAnnotationLicenseFile(arglst);
369 ✗ then (libraryKey, licenseFile);
370 end match;
371 end getLicenseAnnotationTuple;
372
373 protected function getLicenseAnnotationLibraryKey
374 "Extractor function for getLicenseAnnotation"
375 input list<Absyn.ElementArg> eltArgs;
376 output String libraryKey;
377 algorithm
378 libraryKey := match eltArgs
379 local
380 list<Absyn.ElementArg> xs;
381 String s;
382
383 case {} then "";
384
385 case Absyn.MODIFICATION(path = Absyn.IDENT(name="libraryKey"), modification = SOME(Absyn.CLASSMOD(eqMod=Absyn.EQMOD(exp=Absyn.STRING(s)))))::_
386 then s;
387
388 case _::xs
389 algorithm
390 ✗ s := getLicenseAnnotationLibraryKey(xs);
391 then s;
392
393 end match;
394 end getLicenseAnnotationLibraryKey;
395
396 protected function getLicenseAnnotationLicenseFile
397 "Extractor function for getLicenseAnnotation"
398 input list<Absyn.ElementArg> eltArgs;
399 output String licenseFile;
400 algorithm
401 licenseFile := match eltArgs
402 local
403 list<Absyn.ElementArg> xs;
404 String s;
405
406 case {} then "";
407
408 case Absyn.MODIFICATION(path = Absyn.IDENT(name="licenseFile"), modification = SOME(Absyn.CLASSMOD(eqMod=Absyn.EQMOD(exp=Absyn.STRING(s)))))::_
409 then s;
410
411 case _::xs
412 algorithm
413 ✗ s := getLicenseAnnotationLicenseFile(xs);
414 then s;
415
416 end match;
417 end getLicenseAnnotationLicenseFile;
418
419 protected function getFeaturesAnnotation
420 "Returns the Protection(features=) annotation of a class.
421 This is annotated with the annotation:
422 annotation(Protection(features={\"LicenseOption1 LicenseOption2\", \"LicenseOption3\"})); in the class definition"
423 input Absyn.Class className;
424 output list<String> features;
425 protected
426 Option<list<String>> opt_featuresList;
427 algorithm
428 ✗ opt_featuresList := AbsynUtil.getNamedAnnotationInClass(className, Absyn.IDENT("Protection"), getFeaturesAnnotationList);
429 ✗ features := Util.getOptionOrDefault(opt_featuresList, {});
430 end getFeaturesAnnotation;
431
432 protected function getFeaturesAnnotationList
433 "Extractor function for getFeaturesAnnotation"
434 input Option<Absyn.Modification> mod;
435 output list<String> features;
436 algorithm
437 features := match mod
438 local
439 list<Absyn.ElementArg> arglst;
440
441 case SOME(Absyn.CLASSMOD(elementArgLst = arglst))
442 ✗ then getFeaturesAnnotationList2(arglst);
443
444 end match;
445 end getFeaturesAnnotationList;
446
447 protected function getFeaturesAnnotationList2
448 "Extractor function for getFeaturesAnnotation"
449 input list<Absyn.ElementArg> eltArgs;
450 output list<String> features;
451 algorithm
452 features := match eltArgs
453 local
454 list<Absyn.Exp> expList;
455 list<Absyn.ElementArg> xs;
456 list<String> featuresList;
457
458 case {} then {};
459
460 case Absyn.MODIFICATION(path = Absyn.IDENT(name="features"), modification = SOME(Absyn.CLASSMOD(eqMod=Absyn.EQMOD(exp=Absyn.ARRAY(expList)))))::_
461 algorithm
462 ✗ featuresList := List.map(expList, expToString);
463 then featuresList;
464
465 case _::xs
466 algorithm
467 ✗ featuresList := getFeaturesAnnotationList2(xs);
468 then featuresList;
469
470 end match;
471 end getFeaturesAnnotationList2;
472
473 protected function expToString
474 input Absyn.Exp inExp;
475 output String outExp;
476 algorithm
477 outExp := match inExp
478 local
479 String str;
480 case Absyn.STRING(str) then str;
481 case _ then "";
482 end match;
483 end expToString;
484
485 annotation(__OpenModelica_Interface="loader");
486 end Parser;
487