Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 52.8% 243 / 0 / 460
Functions: -% 0 / 1 / 1
Branches: 53.7% 181 / 0 / 337

OMCompiler/Compiler/Script/Conversion.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 Conversion
37 protected
38 import Absyn;
39 import AbsynUtil;
40 import Dump;
41 import Error;
42 import Flags;
43 import GlobalScript;
44 import GlobalScriptDump;
45 import List;
46 import Parser;
47 import System;
48 import UnorderedMap;
49 import UnorderedSet;
50 import Util;
51 import MetaModelica.Dangerous.*;
52
53 uniontype ConversionRule
54 record CLASS "convertClass"
55 array<String> oldPath;
56 Absyn.Path newPath;
57 end CLASS;
58
59 record CLASS_IF "convertClassIf (not yet implemented)"
60
61 end CLASS_IF;
62
63 record ELEMENT "convertElement"
64 array<String> oldPath;
65 String oldName;
66 String newName;
67 end ELEMENT;
68
69 record MODIFIERS "convertModifiers"
70 list<Absyn.ElementArg> oldMods;
71 list<Absyn.ElementArg> newMods;
72 SourceInfo info;
73 end MODIFIERS;
74
75 record MESSAGE "convertMessage"
76 String message;
77 end MESSAGE;
78 end ConversionRule;
79
80 uniontype ConversionRules
81 "Structure used to store conversion rules. Each node corresponds to one
82 element, and each node has a map of child nodes and a list of rules. So
83 e.g. convertClass('A.B', 'A.C') becomes
84 A(nodes = {B(nodes = {}, rules = {convertClass(A.C)})}, rules = {})"
85 record CONVERSION_RULES
86 UnorderedMap<String, ConversionRules> nodes;
87 list<ConversionRule> rules;
88 end CONVERSION_RULES;
89
90 function newNode
91 output ConversionRules node;
92 algorithm
93 41 node := CONVERSION_RULES(UnorderedMap.new<ConversionRules>(stringHashDjb2, stringEq), {});
94 end newNode;
95 end ConversionRules;
96
97 type RuleList = list<ConversionRule>;
98 type RuleTable = UnorderedMap<String, RuleList>;
99 type TypeTable = UnorderedMap<String, Absyn.Path>;
100
101 // Used to specify which arguments to the conversion functions can be vectorized.
102 type ArgType = enumeration(SCALAR, ARRAY);
103 constant list<ArgType> CONVERT_CLASS_TYPE = {ArgType.SCALAR, ArgType.SCALAR};
104 constant list<ArgType> CONVERT_CLASS_IF_TYPE = {ArgType.SCALAR, ArgType.SCALAR, ArgType.SCALAR, ArgType.SCALAR};
105 constant list<ArgType> CONVERT_ELEMENT_TYPE = {ArgType.SCALAR, ArgType.SCALAR, ArgType.SCALAR};
106 constant list<ArgType> CONVERT_MODIFIER_TYPE = {ArgType.SCALAR, ArgType.ARRAY, ArgType.ARRAY, ArgType.SCALAR};
107 constant list<ArgType> CONVERT_MESSAGE_TYPE = {ArgType.SCALAR, ArgType.SCALAR, ArgType.SCALAR};
108
109 uniontype ImportData
110 "Struct for storing import data."
111 record IMPORT_DATA
112 Absyn.Path originalPath "The import before conversion";
113 Absyn.Path convertedPath "The import after conversion";
114 String importName "The import name after conversion (same as before for
115 named imports, possibly different for qualified imports)";
116 Boolean shadowed "Shadowed by another element or not";
117 end IMPORT_DATA;
118 end ImportData;
119
120 type ImportTree = ImportTreeImpl.Tree;
121
122 encapsulated package ImportTreeImpl
123 "Lookup tree for imports used to fully qualify imported names (like SI.Time
124 -> Modelica.SIunits.Time), in order to be able to find conversion rules for
125 such names (see applyImportsToPath and stripImportPath)."
126
127 import BaseAvlTree;
128 import Absyn.Path;
129 import Conversion.ImportData;
130
131 extends BaseAvlTree;
132 redeclare type Key = String;
133 redeclare type Value = ImportData;
134
135 redeclare function extends keyStr
136 algorithm
137 outString := inKey;
138 end keyStr;
139
140 redeclare function extends valueStr
141 algorithm
142 outString := "";
143 end valueStr;
144
145 redeclare function extends keyCompare
146 algorithm
147 42 outResult := stringCompare(inKey1, inKey2);
148 end keyCompare;
149
150 redeclare function addConflictDefault = addConflictReplace;
151 end ImportTreeImpl;
152
153 uniontype Env
154 record ENV
155 TypeTable components;
156 ImportTree imports;
157 end ENV;
158 end Env;
159
160 public
161 function convertPackage
162 "Converts a package using the given conversion script file."
163 input output Absyn.Class cls;
164 input String scriptFile;
165 protected
166 ConversionRules rules;
167 list<GlobalScript.Statement> stmts;
168 algorithm
169 10 stmts := loadScript(scriptFile);
170 10 rules := ConversionRules.newNode();
171 10 rules := parseRules(stmts, rules);
172
173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if Flags.isSet(Flags.DUMP_CONVERSION_RULES) then
174 ✗ dumpRules(rules);
175 end if;
176
177 9 cls := convertClass(cls, rules, newEnv(), {});
178 end convertPackage;
179
180 protected
181 function loadScript
182 "Loads and parses a script file into a list of statements."
183 input String scriptFile;
184 output list<GlobalScript.Statement> stmts;
185 protected
186 String script;
187 algorithm
188 10 script := System.readFile(scriptFile);
189 // It's not required to end conversion statements with a semicolon, so to be
190 // able to use the normal parser we add semicolons where necessary before parsing.
191 10 script := System.stringReplace(script, ")\n", ");\n");
192 10 GlobalScript.Statements.ISTMTS(interactiveStmtLst = stmts) :=
193 Parser.parsestringexp(script, infoFilename = scriptFile);
194 end loadScript;
195
196 function parseRules
197 "Converts a list of statements into conversion rules and inserts them into
198 the conversion rules structure."
199 input list<GlobalScript.Statement> stmts;
200 input output ConversionRules rules;
201 algorithm
202
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 9 times.
26 for stmt in stmts loop
203 17 rules := parseRule(stmt, rules);
204 end for;
205 end parseRules;
206
207 function parseRule
208 "Converts a statement into a conversion rule and insert it into the
209 conversion rules structure."
210 input GlobalScript.Statement stmt;
211 input output ConversionRules rules;
212 protected
213 partial function ParseFn
214 input list<Absyn.Exp> args;
215 input SourceInfo info;
216 input output ConversionRules rules;
217 end ParseFn;
218
219 String fn_name;
220 list<Absyn.Exp> args;
221 ParseFn parse_fn;
222 list<ArgType> fn_type;
223 algorithm
224 () := match stmt
225 case GlobalScript.Statement.IEXP(exp = Absyn.Exp.CALL(
226 function_ = Absyn.ComponentRef.CREF_IDENT(name = fn_name),
227 functionArgs = Absyn.FunctionArgs.FUNCTIONARGS(args = args, argNames = {})))
228 algorithm
229 (parse_fn, fn_type) := match fn_name
230 case "convertClass" then (parseConvertClass, CONVERT_CLASS_TYPE);
231 case "convertClassIf" then (parseConvertClassIf, CONVERT_CLASS_IF_TYPE);
232 case "convertElement" then (parseConvertElement, CONVERT_ELEMENT_TYPE);
233 case "convertModifiers" then (parseConvertModifiers, CONVERT_MODIFIER_TYPE);
234 case "convertMessage" then (parseConvertMessage, CONVERT_MESSAGE_TYPE);
235 else
236 algorithm
237 ✗ printConversionRuleError(stmt);
238 then
239 fail();
240 end match;
241
242
4/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 17 times.
55 args := list(expandArg(a) for a in args);
243
244
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 16 times.
34 for a in vectorizeArgs(args, fn_type, stmt) loop
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 rules := parse_fn(a, stmt.info, rules);
246 end for;
247 then
248 ();
249
250 else
251 algorithm
252 ✗ printConversionRuleError(stmt);
253 then
254 fail();
255
256 end match;
257 end parseRule;
258
259 function expandArg
260 "Converts fill(0, _) into {}."
261 input Absyn.Exp exp;
262 output Absyn.Exp outExp;
263 algorithm
264 outExp := match exp
265 case Absyn.Exp.CALL(function_ = Absyn.ComponentRef.CREF_IDENT(name = "fill"),
266 functionArgs = Absyn.FunctionArgs.FUNCTIONARGS(args =
267 {_, Absyn.Exp.INTEGER(value = 0)}))
268 then Absyn.Exp.ARRAY({});
269
270 else exp;
271 end match;
272 end expandArg;
273
274 function vectorizeArgs
275 "Vectorizes a list of function arguments using the vectorization rules."
276 input list<Absyn.Exp> args;
277 input list<ArgType> fnType;
278 input GlobalScript.Statement stmt;
279 output list<list<Absyn.Exp>> vargs;
280 protected
281 Integer vdim = -1, dim;
282 list<ArgType> fn_ty = fnType;
283 ArgType arg_ty;
284 list<Boolean> is_varg = {};
285 list<Absyn.Exp> expl;
286 algorithm
287
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if listLength(args) > listLength(fnType) then
288 ✗ printConversionRuleError(stmt);
289 end if;
290
291 // Get the dimension to vectorize along, if any.
292
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 16 times.
54 for arg in args loop
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 arg_ty :: fn_ty := fn_ty;
294
295 (vdim, is_varg) := match (arg, arg_ty)
296 // Got array, expected scalar => vectorize.
297 case (Absyn.Exp.ARRAY(), ArgType.SCALAR)
298 algorithm
299 3 dim := listLength(arg.arrayExp);
300
301
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if vdim >= 0 and dim <> vdim then
302 1 printConversionRuleError(stmt);
303 end if;
304 then
305 (dim, true :: is_varg);
306
307 // Got array, expected array => do nothing.
308 case (Absyn.Exp.ARRAY(), ArgType.ARRAY)
309 then (vdim, false :: is_varg);
310
311 // Got scalar, expected array => error.
312 case (_, ArgType.ARRAY)
313 algorithm
314 ✗ printConversionRuleError(stmt);
315 then
316 fail();
317
318 // Got scalar, expected scalar => do nothing.
319 else (vdim, false :: is_varg);
320 end match;
321 end for;
322
323
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if vdim == 0 then
324 // Empty array arguments => ignore call
325 vargs := {};
326 elseif vdim == -1 then
327 // No array arguments => scalar call
328 vargs := {args};
329 else
330 // Array arguments => vectorize call
331 vargs := {};
332
333
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
3 for arg in listReverse(args) loop
334
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if listHead(is_varg) then
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 Absyn.Exp.ARRAY(arrayExp = expl) := arg;
336 vargs := expl :: vargs;
337 else
338 1 vargs := List.fill(arg, vdim) :: vargs;
339 end if;
340
341 2 is_varg := listRest(is_varg);
342 end for;
343
344 1 vargs := List.transposeList(vargs);
345 end if;
346 end vectorizeArgs;
347
348 function statementInfo
349 "Returns the SourceInfo contained in a statement."
350 input GlobalScript.Statement stmt;
351 output SourceInfo info;
352 algorithm
353 info := match stmt
354 1 case GlobalScript.Statement.IEXP() then stmt.info;
355 else Absyn.dummyInfo;
356 end match;
357 end statementInfo;
358
359 function printConversionRuleError
360 "Prints a generic error for invalid conversion rules and fails."
361 input GlobalScript.Statement stmt;
362 algorithm
363 2 Error.addSourceMessage(Error.INVALID_CONVERSION_RULE,
364 {GlobalScriptDump.printIstmtStr(stmt)}, statementInfo(stmt));
365 1 fail();
366 end printConversionRuleError;
367
368 function parseConvertClass
369 "Converts a convertClass statement into a conversion rule and inserts it
370 into the conversion rules structure."
371 input list<Absyn.Exp> args;
372 input SourceInfo info;
373 input output ConversionRules rules;
374 algorithm
375 () := match args
376 local
377 String old_cls, new_cls;
378
379 case {Absyn.Exp.STRING(value = old_cls), Absyn.Exp.STRING(value = new_cls)}
380 algorithm
381 14 parseConvertClassStr(old_cls, new_cls, rules);
382 then
383 ();
384
385 else
386 algorithm
387 ✗ Error.addSourceMessage(Error.INVALID_CONVERSION_RULE,
388 {List.toStringCustom(args, Dump.printExpStr, "convertClass", "(", ", ", ")", true)}, info);
389 ✗ then
390 fail();
391
392 end match;
393 end parseConvertClass;
394
395 function parseConvertClassStr
396 input String oldName;
397 input String newName;
398 input output ConversionRules rules;
399 protected
400 list<String> old_path;
401 ConversionRule rule;
402 algorithm
403 14 old_path := parsePathList(oldName);
404 14 rule := ConversionRule.CLASS(listArray(old_path), parsePath(newName));
405 14 rules := addRule(old_path, rule, rules);
406 end parseConvertClassStr;
407
408 function parseConvertClassIf
409 "Converts a conertClassIf statement into a conversion rule and inserts it
410 into the conversion rules structure."
411 input list<Absyn.Exp> args;
412 input SourceInfo info;
413 input output ConversionRules rules;
414 algorithm
415 ✗ Error.terminate(getInstanceName() + ": not implemented", info);
416 end parseConvertClassIf;
417
418 function parseConvertElement
419 "Converts a convertElement statement into a conversion rule and inserts it
420 into the conversion rules structure."
421 input list<Absyn.Exp> args;
422 input SourceInfo info;
423 input output ConversionRules rules;
424 algorithm
425 () := match args
426 local
427 String cls_name, old_name, new_name;
428 list<String> old_path;
429 ConversionRule rule;
430
431 case {Absyn.Exp.STRING(value = cls_name),
432 Absyn.Exp.STRING(value = old_name),
433 Absyn.Exp.STRING(value = new_name)}
434 algorithm
435 1 old_path := parsePathList(cls_name);
436 1 rule := ConversionRule.ELEMENT(listArray(old_path), old_name, new_name);
437 1 rules := addRule(old_path, rule, rules);
438 then
439 ();
440
441 else
442 algorithm
443 ✗ Error.addSourceMessage(Error.INVALID_CONVERSION_RULE,
444 {List.toStringCustom(args, Dump.printExpStr, "convertElement", "(", ", ", ")", true)}, info);
445 ✗ then
446 fail();
447
448 end match;
449 end parseConvertElement;
450
451 function parseConvertModifiers
452 "Converts a convertModifiers statement into a conversion rule and inserts it
453 into the conversion rules structure."
454 input list<Absyn.Exp> args;
455 input SourceInfo info;
456 input output ConversionRules rules;
457 algorithm
458 rules := matchcontinue args
459 local
460 String cls_name;
461 list<Absyn.Exp> old_mods, new_mods;
462 Boolean simplify;
463
464 case {Absyn.Exp.STRING(value = cls_name),
465 Absyn.Exp.ARRAY(arrayExp = old_mods),
466 Absyn.Exp.ARRAY(arrayExp = new_mods)}
467 1 then parseConvertModifiers2(cls_name, old_mods, new_mods, false, info, rules);
468
469 case {Absyn.Exp.STRING(value = cls_name),
470 Absyn.Exp.ARRAY(arrayExp = old_mods),
471 Absyn.Exp.ARRAY(arrayExp = new_mods),
472 Absyn.Exp.BOOL(value = simplify)}
473 1 then parseConvertModifiers2(cls_name, old_mods, new_mods, simplify, info, rules);
474
475 else
476 algorithm
477 ✗ Error.addSourceMessage(Error.INVALID_CONVERSION_RULE,
478 {List.toStringCustom(args, Dump.printExpStr, "convertModifiers", "(", ", ", ")", true)}, info);
479 ✗ then
480 fail();
481
482 end matchcontinue;
483 end parseConvertModifiers;
484
485 function parseConvertModifiers2
486 input String className;
487 input list<Absyn.Exp> oldMods;
488 input list<Absyn.Exp> newMods;
489 input Boolean simplify;
490 input SourceInfo info;
491 input output ConversionRules rules;
492 protected
493 list<String> cls_path;
494 list<Absyn.ElementArg> old_mods, new_mods;
495 algorithm
496 2 cls_path := parsePathList(className);
497
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
3 old_mods := list(parseModifier(m, info) for m in oldMods);
498
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 new_mods := list(parseModifier(m, info) for m in newMods);
499 2 rules := addRule(cls_path, ConversionRule.MODIFIERS(old_mods, new_mods, info), rules);
500 end parseConvertModifiers2;
501
502 function parseModifier
503 "Parses a string expression into an Absyn modifier. Fails if the given
504 expressions isn't a string or not a syntactically valid modifier."
505 input Absyn.Exp mod;
506 input SourceInfo info;
507 output Absyn.ElementArg outMod;
508 protected
509 String str;
510 algorithm
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 Absyn.Exp.STRING(value = str) := mod;
512 3 outMod := Parser.stringMod(quotePlaceholders(str, info));
513 end parseModifier;
514
515 function quotePlaceholders
516 "Quotes placeholder names in conversion modifiers, i.e. %name% => '%name%',
517 so they can be parsed by the normal Modelica parser."
518 input output String str;
519 input SourceInfo info;
520 protected
521 list<String> strl, res = {};
522 Boolean in_ident = false;
523 algorithm
524 3 strl := System.strtokIncludingDelimiters(str, "%");
525
526
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if listLength(strl) <= 1 then
527 3 return;
528 end if;
529
530 ✗ for s in strl loop
531 ✗ if s == "%" then
532 ✗ s := if in_ident then "%'" else "'%";
533 ✗ in_ident := not in_ident;
534 end if;
535
536 res := s :: res;
537 end for;
538
539 ✗ if in_ident then
540 ✗ Error.addSourceMessage(Error.CONVERSION_MISMATCHED_PLACEHOLDER, {str}, info);
541 ✗ fail();
542 end if;
543
544 ✗ str := stringAppendList(listReverseInPlace(res));
545 end quotePlaceholders;
546
547 function parseConvertMessage
548 "Converts a convertMessage statement into a conversion rule and inserts it
549 into the conversion rules structure."
550 input list<Absyn.Exp> args;
551 input SourceInfo info;
552 input output ConversionRules rules;
553 algorithm
554 () := match args
555 local
556 String cls_name, msg;
557 ConversionRule rule;
558
559 case {Absyn.Exp.STRING(value = cls_name), Absyn.Exp.STRING(value = msg)}
560 algorithm
561 ✗ rule := ConversionRule.MESSAGE(msg);
562 ✗ rules := addRule(parsePathList(cls_name), rule, rules);
563 then
564 ();
565
566 else
567 algorithm
568 ✗ Error.addSourceMessage(Error.INVALID_CONVERSION_RULE,
569 {List.toStringCustom(args, Dump.printExpStr, "convertMessage", "(", ", ", ")", true)}, info);
570 ✗ then
571 fail();
572
573 end match;
574 end parseConvertMessage;
575
576 function parsePath
577 "Converts a string into an Absyn path."
578 input String str;
579 output Absyn.Path path = AbsynUtil.stringPath(str);
580 end parsePath;
581
582 function parsePathList
583 "Splits a string into a list of strings using . as delimiter."
584 input String str;
585 output list<String> path = Util.stringSplitAtChar(str, ".");
586 end parsePathList;
587
588 function addRule
589 "Inserts a rule into the conversion rules structure using the given path."
590 input list<String> path;
591 input ConversionRule rule;
592 input output ConversionRules rules;
593 algorithm
594 17 updateNode(SOME(rules), path, rule);
595 end addRule;
596
597 function updateNode
598 "Adds the given rule to an existing node in the conversion rules structure,
599 or to a new node if there's no existing node."
600 input Option<ConversionRules> onode;
601 input list<String> path;
602 input ConversionRule rule;
603 output ConversionRules node;
604 algorithm
605
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 33 times.
64 if isSome(onode) then
606 33 SOME(node) := onode;
607 else
608 31 node := ConversionRules.newNode();
609 end if;
610
611
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 47 times.
64 if listEmpty(path) then
612 34 node.rules := rule :: node.rules;
613 else
614 47 UnorderedMap.addUpdate(listHead(path),
615 function updateNode(path = listRest(path), rule = rule), node.nodes);
616 end if;
617 end updateNode;
618
619 function lookupRuleNode
620 "Looks up a node in the conversion rules structure."
621 input Absyn.Path path;
622 input ConversionRules rules;
623 output Option<ConversionRules> outNode = NONE();
624 protected
625 ConversionRules node = rules;
626 algorithm
627
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 for name in AbsynUtil.pathToStringList(path) loop
628 4 outNode := UnorderedMap.get(name, node.nodes);
629
630
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 3 times.
4 if isNone(outNode) then
631 1 return;
632 end if;
633
634 3 SOME(node) := outNode;
635 end for;
636 end lookupRuleNode;
637
638 function lookupRules
639 "Returns the rules for each identifier in a path with the rules for the last
640 identifier that could be found first. If an identifier can't be found the
641 lookup stops and returns the rules found so far, with an empty list added
642 to the beginning of the list to indicate that the lookup stopped early."
643 input Absyn.Path path;
644 input ConversionRules rules;
645 output list<list<ConversionRule>> outRules = {};
646 protected
647 Option<ConversionRules> onode;
648 ConversionRules node = rules;
649 algorithm
650
2/2
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 13 times.
78 for name in AbsynUtil.pathToStringList(path) loop
651 65 onode := UnorderedMap.get(name, node.nodes);
652
653
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 52 times.
65 if isNone(onode) then
654 outRules := {} :: outRules;
655 13 return;
656 end if;
657
658 52 SOME(node) := onode;
659
660
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if not listEmpty(node.rules) then
661 outRules := node.rules :: outRules;
662 end if;
663 end for;
664 end lookupRules;
665
666 function lookupTypeRules
667 "Looks up the conversion rules associated with the given type name."
668 input Absyn.Path typePath;
669 input ConversionRules rules;
670 input Env env;
671 output Option<ConversionRule> typeRule = NONE();
672 output RuleTable localRules = newRuleTable();
673 output list<ConversionRule> modifierRules = {};
674 protected
675 list<list<ConversionRule>> found_rules;
676 algorithm
677 18 found_rules := lookupRules(typePath, rules);
678
679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if listEmpty(found_rules) then
680 ✗ return;
681 end if;
682
683 // The rules at the head of the list applies to the referenced type.
684 18 modifierRules := sortLocalRules(listHead(found_rules), localRules);
685
686 // Also try to find a convertClass rule, which might be for a prefix of the
687 // type name. The rule for the longest prefix is used.
688
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 18 times.
47 for rl in found_rules loop
689
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 29 times.
46 for r in rl loop
690 () := match r
691 case ConversionRule.CLASS()
692 algorithm
693
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 5 times.
14 if isNone(typeRule) then
694 typeRule := SOME(r);
695 end if;
696 then
697 ();
698
699 else ();
700 end match;
701 end for;
702 end for;
703 end lookupTypeRules;
704
705 function newRuleTable
706 output RuleTable table;
707 algorithm
708 34 table := UnorderedMap.new<RuleList>(stringHashDjb2, stringEq);
709 end newRuleTable;
710
711 function newTypeTable
712 output TypeTable table;
713 algorithm
714 9 table := UnorderedMap.new<Absyn.Path>(stringHashDjb2, stringEq);
715 end newTypeTable;
716
717 function newEnv
718 output Env env = ENV(newTypeTable(), ImportTree.new());
719 end newEnv;
720
721 function sortLocalRules
722 "Sorts a list of local rules, inserting element rules into the given table
723 and returning a list of modifier rules."
724 input list<ConversionRule> rules;
725 input RuleTable localRules;
726 output list<ConversionRule> modifierRules = {};
727 algorithm
728
5/5
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 18 times.
24 for rule in rules loop
729 () := match rule
730 case ConversionRule.ELEMENT()
731 algorithm
732 1 UnorderedMap.addUpdate(rule.oldName,
733 function mergeRuleList(newRule = rule), localRules);
734 then
735 ();
736
737 case ConversionRule.MODIFIERS()
738 algorithm
739 modifierRules := rule :: modifierRules;
740 then
741 ();
742
743 else ();
744 end match;
745 end for;
746 end sortLocalRules;
747
748 function mergeRuleList
749 "Merges a rule into an existing list of rules, or creates a new list with
750 the rule if there's no existing list."
751 input Option<list<ConversionRule>> oldRules;
752 input ConversionRule newRule;
753 output list<ConversionRule> outRules;
754 algorithm
755
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if isNone(oldRules) then
756 outRules := {newRule};
757 else
758 ✗ SOME(outRules) := oldRules;
759 outRules := newRule :: outRules;
760 end if;
761 end mergeRuleList;
762
763 function lookupClassExtendsRules
764 "Looks up the conversion rules for a class extends name."
765 input String name;
766 input list<ConversionRules> extendsRules;
767 output RuleTable localRules = newRuleTable();
768 output list<ConversionRule> modificationRules = {};
769 protected
770 Option<ConversionRules> onode;
771 ConversionRules node;
772 algorithm
773 ✗ for ext in extendsRules loop
774 ✗ onode := UnorderedMap.get(name, ext.nodes);
775
776 ✗ if isSome(onode) then
777 ✗ SOME(node) := onode;
778 ✗ modificationRules := sortLocalRules(node.rules, localRules);
779 ✗ return;
780 end if;
781 end for;
782 end lookupClassExtendsRules;
783
784 function dumpRules
785 "Dumps a ConversionRules structure in a needlessly elaborate manner for debugging."
786 input ConversionRules rules;
787 input String indent = "";
788 protected
789 array<String> keys;
790 array<ConversionRules> values;
791 ConversionRule rule;
792 list<ConversionRule> rest_rules = rules.rules;
793 algorithm
794 ✗ keys := UnorderedMap.keyArray(rules.nodes);
795 ✗ values := UnorderedMap.valueArray(rules.nodes);
796
797 ✗ while not listEmpty(rest_rules) loop
798 ✗ rule :: rest_rules := rest_rules;
799
800 ✗ if listEmpty(rest_rules) and arrayEmpty(keys) then
801 ✗ dumpRule(rule, indent + "└─");
802 else
803 ✗ dumpRule(rule, indent + "├─");
804 end if;
805 end while;
806
807 ✗ for i in 1:arrayLength(keys) loop
808 ✗ if i == arrayLength(keys) then
809 ✗ print(indent + "└─");
810 ✗ print(keys[i]);
811 ✗ print("\n");
812 ✗ dumpRules(values[i], indent + " ");
813 else
814 ✗ print(indent + "├─");
815 ✗ print(keys[i]);
816 ✗ print("\n");
817 ✗ dumpRules(values[i], indent + "│ ");
818 end if;
819 end for;
820 end dumpRules;
821
822 function dumpRule
823 "Dumps a single conversion rule."
824 input ConversionRule rule;
825 input String indent;
826 algorithm
827 ✗ print(indent);
828
829 () := match rule
830 case ConversionRule.CLASS()
831 algorithm
832 ✗ print("convertClass: ");
833 ✗ print(AbsynUtil.pathString(rule.newPath));
834 then
835 ();
836
837 case ConversionRule.CLASS_IF()
838 algorithm
839 ✗ print("convertClassIf: ");
840 then
841 ();
842
843 case ConversionRule.ELEMENT()
844 algorithm
845 ✗ print("convertElement: ");
846 ✗ print(rule.oldName);
847 ✗ print(" => ");
848 ✗ print(rule.newName);
849 then
850 ();
851
852 case ConversionRule.MODIFIERS()
853 algorithm
854 ✗ print("convertModifiers: ");
855 ✗ print(List.toString(rule.oldMods, Dump.unparseElementArgStr, List.Style.FLAT_CURLY));
856 ✗ print(" => ");
857 ✗ print(List.toString(rule.newMods, Dump.unparseElementArgStr, List.Style.FLAT_CURLY));
858 then
859 ();
860
861 case ConversionRule.MESSAGE()
862 algorithm
863 ✗ print("convertMessage: \"");
864 ✗ print(rule.message);
865 ✗ print("\"");
866 then
867 ();
868
869 end match;
870
871 ✗ print("\n");
872 end dumpRule;
873
874 function convertProgram
875 "Converts an Absyn.Program."
876 input output Absyn.Program program;
877 input ConversionRules rules;
878 input Env env;
879 algorithm
880 ✗ program.classes := list(convertClass(c, rules, env, {}) for c in program.classes);
881 end convertProgram;
882
883 function convertClass
884 "Converts an Absyn.Class."
885 input output Absyn.Class cls;
886 input ConversionRules rules;
887 input Env env;
888 input list<ConversionRules> extendsRules;
889 algorithm
890 16 cls.body := convertClassDef(cls.body, rules, env, extendsRules, cls.info);
891 end convertClass;
892
893 function convertClassDef
894 "Converts an Absyn.ClassDef."
895 input output Absyn.ClassDef cdef;
896 input ConversionRules rules;
897 input Env env;
898 input list<ConversionRules> extendsRules;
899 input SourceInfo info;
900 algorithm
901 () := match cdef
902 local
903 RuleTable local_rules;
904 list<ConversionRule> mod_rules;
905 Absyn.TypeSpec ty;
906
907 case Absyn.ClassDef.PARTS()
908 algorithm
909 16 cdef.classParts := convertClassParts(cdef.classParts, newRuleTable(), rules, env, info);
910 then
911 ();
912
913 case Absyn.ClassDef.DERIVED()
914 algorithm
915 ✗ (ty, local_rules, mod_rules) := convertTypeSpec(cdef.typeSpec, rules, env, info);
916 ✗ cdef.typeSpec := ty;
917 ✗ cdef.arguments := convertModification2(mod_rules, cdef.arguments);
918 ✗ cdef.arguments := convertElementArgs(cdef.arguments, local_rules, rules, env);
919 then
920 ();
921
922 case Absyn.ClassDef.CLASS_EXTENDS()
923 algorithm
924 ✗ (local_rules, mod_rules) := lookupClassExtendsRules(cdef.baseClassName, extendsRules);
925 ✗ cdef.modifications := convertModification2(mod_rules, cdef.modifications);
926 ✗ cdef.modifications := convertElementArgs(cdef.modifications, local_rules, rules, env);
927 ✗ cdef.parts := convertClassParts(cdef.parts, local_rules, rules, env, info);
928 then
929 ();
930
931 else ();
932 end match;
933 end convertClassDef;
934
935 function convertClassParts
936 "Converts a list of Absyn.ClassParts."
937 input output list<Absyn.ClassPart> parts;
938 input RuleTable localRules;
939 input ConversionRules rules;
940 input Env env;
941 input SourceInfo info;
942 protected
943 list<ConversionRules> extends_rules;
944 Env cls_env;
945 algorithm
946 16 cls_env := addImportNamesToEnv(getImportsInParts(parts), rules, env);
947 16 addComponentTypesToEnv(parts, env.components);
948 16 cls_env.imports := shadowImportsInParts(parts, cls_env.imports);
949 16 extends_rules := getExtendsRules(parts, rules, cls_env);
950
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 16 times.
33 parts := list(convertClassPart(p, localRules, rules, cls_env, extends_rules, info) for p in parts);
951 end convertClassParts;
952
953 function convertClassPart
954 "Converts an Absyn.ClassPart."
955 input output Absyn.ClassPart part;
956 input RuleTable localRules;
957 input ConversionRules rules;
958 input Env env;
959 input list<ConversionRules> extendsRules;
960 input SourceInfo info;
961 algorithm
962 () := match part
963 case Absyn.ClassPart.PUBLIC()
964 algorithm
965 16 part.contents := convertElementItems(part.contents, rules, env, extendsRules);
966 then
967 ();
968
969 case Absyn.ClassPart.PROTECTED()
970 algorithm
971 ✗ part.contents := convertElementItems(part.contents, rules, env, extendsRules);
972 then
973 ();
974
975 case Absyn.ClassPart.EQUATIONS()
976 algorithm
977 1 part.contents := convertEquationItems(part.contents, localRules, rules, env);
978 then
979 ();
980
981 case Absyn.ClassPart.INITIALEQUATIONS()
982 algorithm
983 ✗ part.contents := convertEquationItems(part.contents, localRules, rules, env);
984 then
985 ();
986
987 case Absyn.ClassPart.ALGORITHMS()
988 algorithm
989 ✗ part.contents := convertAlgorithmItems(part.contents, localRules, rules, env);
990 then
991 ();
992
993 case Absyn.ClassPart.INITIALALGORITHMS()
994 algorithm
995 ✗ part.contents := convertAlgorithmItems(part.contents, localRules, rules, env);
996 then
997 ();
998
999 case Absyn.ClassPart.EXTERNAL()
1000 algorithm
1001 ✗ part.externalDecl := convertExternalDecl(part.externalDecl, localRules, rules, env, info);
1002 then
1003 ();
1004
1005 else ();
1006 end match;
1007 end convertClassPart;
1008
1009 function convertElementArgs
1010 "Converts a list of Absyn.ElementArgs."
1011 input output list<Absyn.ElementArg> args;
1012 input RuleTable localRules;
1013 input ConversionRules rules;
1014 input Env env;
1015 algorithm
1016
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
9 args := list(convertElementArg(a, localRules, rules, env) for a in args);
1017 end convertElementArgs;
1018
1019 function convertElementArg
1020 "Converts an Absyn.ElementArg."
1021 input output Absyn.ElementArg arg;
1022 input RuleTable localRules;
1023 input ConversionRules rules;
1024 input Env env;
1025 algorithm
1026 () := match arg
1027 local
1028 list<ConversionRule> mod_rules;
1029
1030 case Absyn.ElementArg.MODIFICATION()
1031 algorithm
1032 3 mod_rules := UnorderedMap.getOrDefault(AbsynUtil.pathString(arg.path), localRules, {});
1033
1034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 for rule in mod_rules loop
1035 () := match rule
1036 case ConversionRule.ELEMENT()
1037 algorithm
1038 ✗ arg.path := Absyn.IDENT(rule.newName);
1039 then
1040 ();
1041
1042 else ();
1043 end match;
1044 end for;
1045
1046 3 arg.modification := convertModificationExps(arg.modification, localRules, rules, env, arg.info);
1047 then
1048 ();
1049
1050 case Absyn.ElementArg.REDECLARATION()
1051 algorithm
1052 ✗ arg.elementSpec := convertElementSpec(arg.elementSpec, rules, env, {}, arg.info);
1053 ✗ arg.constrainClass := convertOption(arg.constrainClass, convertConstrainClass, rules, env, arg.info);
1054 then
1055 ();
1056
1057 case Absyn.ElementArg.ELEMENTARGCOMMENT()
1058 then ();
1059
1060 end match;
1061 end convertElementArg;
1062
1063 function convertModificationExps
1064 "Converts the expressions in an Absyn.Modification (but not the modifier
1065 names, which is handled by convertModification)."
1066 input output Option<Absyn.Modification> mod;
1067 input RuleTable localRules;
1068 input ConversionRules rules;
1069 input Env env;
1070 input SourceInfo info;
1071 algorithm
1072 20 mod := convertOption(mod, function convertModificationExps2(localRules = localRules), rules, env, info);
1073 end convertModificationExps;
1074
1075 function convertModificationExps2
1076 input output Absyn.Modification mod;
1077 input RuleTable localRules;
1078 input ConversionRules rules;
1079 input Env env;
1080 input SourceInfo info;
1081 algorithm
1082 5 mod.elementArgLst := convertElementArgs(mod.elementArgLst, localRules, rules, env);
1083 mod.eqMod := convertEqMod(mod.eqMod, localRules, rules, env);
1084 end convertModificationExps2;
1085
1086 function convertEqMod
1087 "Converts the expressions in an Absyn.EqMod."
1088 input output Absyn.EqMod mod;
1089 input RuleTable localRules;
1090 input ConversionRules rules;
1091 input Env env;
1092 algorithm
1093 () := match mod
1094 case Absyn.EqMod.EQMOD()
1095 algorithm
1096 3 mod.exp := convertExp(mod.exp, localRules, rules, env, mod.info);
1097 then
1098 ();
1099
1100 else ();
1101 end match;
1102 end convertEqMod;
1103
1104 function convertModification
1105 "Converts an Absyn.Modification using convertModifiers rules."
1106 input output Option<Absyn.Modification> mod;
1107 input list<ConversionRule> modifierRules;
1108 protected
1109 list<Absyn.ElementArg> elem_args;
1110 Absyn.EqMod eq_mod;
1111 algorithm
1112
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if isSome(mod) then
1113 2 SOME(Absyn.Modification.CLASSMOD(elem_args, eq_mod)) := mod;
1114 else
1115 elem_args := {};
1116 eq_mod := Absyn.EqMod.NOMOD();
1117 end if;
1118
1119 2 elem_args := convertModification2(modifierRules, elem_args);
1120
1121 mod := match (elem_args, eq_mod)
1122 case ({}, Absyn.EqMod.NOMOD()) then NONE();
1123 2 else SOME(Absyn.Modification.CLASSMOD(elem_args, eq_mod));
1124 end match;
1125 end convertModification;
1126
1127 function convertModification2
1128 input list<ConversionRule> modifierRules;
1129 input output list<Absyn.ElementArg> elemArgs;
1130 algorithm
1131
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 for rule in modifierRules loop
1132 2 elemArgs := convertModifier(rule, elemArgs);
1133 end for;
1134 end convertModification2;
1135
1136 function convertModifier
1137 "Applies a single convertModifiers rule to a list of Absyn.ElementArgs."
1138 input ConversionRule rule;
1139 input output list<Absyn.ElementArg> elemArgs;
1140 protected
1141 list<Absyn.ElementArg> old_mods, new_mods, matching_mods, rest_mods;
1142 UnorderedMap<String, Option<Absyn.Exp>> placeholders;
1143 SourceInfo info;
1144 algorithm
1145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ConversionRule.MODIFIERS(oldMods = old_mods, newMods = new_mods, info = info) := rule;
1146
1147
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if listEmpty(old_mods) then
1148 // If the list of old modifiers is empty, just add the new modifiers.
1149 1 elemArgs := mergeModifiers(elemArgs, new_mods);
1150 else
1151 // Otherwise, filter out the referenced old modifiers from the list of
1152 // modifiers on the element.
1153 1 (matching_mods, rest_mods) :=
1154 List.splitOnTrue(elemArgs, function isModifierInList(mods = old_mods));
1155
1156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if not listEmpty(matching_mods) then
1157 // If any old modifiers matched, replace them with the new modifiers.
1158 1 placeholders := makePlaceholderTable(listAppend(old_mods, matching_mods));
1159
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 new_mods := list(replacePlaceholders(m, placeholders, info) for m in new_mods);
1160 1 elemArgs := mergeModifiers(rest_mods, new_mods);
1161 end if;
1162 end if;
1163 end convertModifier;
1164
1165 function isModifierInList
1166 "Returns whether a modifier with the same name exists in the given list."
1167 input Absyn.ElementArg mod;
1168 input list<Absyn.ElementArg> mods;
1169 output Boolean res = List.any(mods, function isEqualNameMod(mod2 = mod));
1170 end isModifierInList;
1171
1172 function isEqualNameMod
1173 "Returns whether the two modifiers have the same name or not."
1174 input Absyn.ElementArg mod1;
1175 input Absyn.ElementArg mod2;
1176 output Boolean res;
1177 algorithm
1178 res := match (mod1, mod2)
1179 case (Absyn.ElementArg.MODIFICATION(), Absyn.ElementArg.MODIFICATION())
1180 4 then AbsynUtil.pathEqual(mod1.path, mod2.path);
1181
1182 else false;
1183 end match;
1184 end isEqualNameMod;
1185
1186 function makePlaceholderTable
1187 "Creates a table with placeholders and the values they should be replaced with."
1188 input list<Absyn.ElementArg> args;
1189 output UnorderedMap<String, Option<Absyn.Exp>> placeholders;
1190 protected
1191 type OptExp = Option<Absyn.Exp>;
1192 algorithm
1193 1 placeholders := UnorderedMap.new<OptExp>(stringHashDjb2, stringEq);
1194
1195
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for arg in args loop
1196 2 UnorderedMap.add(AbsynUtil.pathString(AbsynUtil.elementArgName(arg)),
1197 getElementArgBinding(arg), placeholders);
1198 end for;
1199 end makePlaceholderTable;
1200
1201 function getElementArgBinding
1202 "Returns the binding of a modifier, or NONE() if the modifier has not binding."
1203 input Absyn.ElementArg arg;
1204 output Option<Absyn.Exp> exp;
1205 protected
1206 Absyn.Exp e;
1207 algorithm
1208 exp := match arg
1209 case Absyn.ElementArg.MODIFICATION(modification =
1210 SOME(Absyn.Modification.CLASSMOD(eqMod = Absyn.EqMod.EQMOD(exp = e))))
1211 then SOME(e);
1212
1213 else NONE();
1214 end match;
1215 end getElementArgBinding;
1216
1217 function replacePlaceholders
1218 "Replaces placeholders with their respective values in a modifier."
1219 input output Absyn.ElementArg arg;
1220 input UnorderedMap<String, Option<Absyn.Exp>> placeholders;
1221 input SourceInfo info;
1222 protected
1223 Absyn.Modification mod;
1224 list<Absyn.ElementArg> args;
1225 Absyn.EqMod eq_mod;
1226 algorithm
1227 () := match arg
1228 case Absyn.ElementArg.MODIFICATION(modification = SOME(mod))
1229 algorithm
1230 ✗ Absyn.Modification.CLASSMOD(args, eq_mod) := mod;
1231 ✗ args := list(replacePlaceholders(a, placeholders, info) for a in args);
1232 ✗ eq_mod := replacePlaceholdersEqMod(eq_mod, placeholders, {arg.info, info});
1233 ✗ arg.modification := SOME(Absyn.Modification.CLASSMOD(args, eq_mod));
1234 then
1235 ();
1236
1237 else ();
1238 end match;
1239 end replacePlaceholders;
1240
1241 function replacePlaceholdersEqMod
1242 "Replaces placeholders with their respective values in an Absyn.EqMod."
1243 input output Absyn.EqMod eqMod;
1244 input UnorderedMap<String, Option<Absyn.Exp>> placeholders;
1245 input list<SourceInfo> info;
1246 algorithm
1247 () := match eqMod
1248 case Absyn.EqMod.EQMOD()
1249 algorithm
1250 ✗ eqMod.exp := AbsynUtil.traverseExp(eqMod.exp,
1251 function replacePlaceholdersExp(info = info), placeholders);
1252 then
1253 ();
1254
1255 else ();
1256 end match;
1257 end replacePlaceholdersEqMod;
1258
1259 function replacePlaceholdersExp
1260 "Replaces placeholders with their respective values in an Absyn.Exp."
1261 input Absyn.Exp exp;
1262 input UnorderedMap<String, Option<Absyn.Exp>> placeholders;
1263 input list<SourceInfo> info;
1264 output Absyn.Exp outExp;
1265 output UnorderedMap<String, Option<Absyn.Exp>> outPlaceholders = placeholders;
1266 protected
1267 String name;
1268 Integer len;
1269 Option<Absyn.Exp> new_exp;
1270 algorithm
1271 outExp := match exp
1272 case Absyn.Exp.CREF(componentRef =
1273 Absyn.ComponentRef.CREF_IDENT(name = name, subscripts = {}))
1274 algorithm
1275 ✗ len := stringLength(name);
1276
1277 // Placeholders have the form '%name%'
1278 ✗ if len > 4 and stringGet(name, 1) == 39 and stringGet(name, 2) == 37 and
1279 stringGet(name, len - 1) == 37 and stringGet(name, len) == 39 then
1280 ✗ name := substring(name, 3, len - 2);
1281 ✗ new_exp := UnorderedMap.getOrDefault(name, placeholders, NONE());
1282
1283 ✗ if isNone(new_exp) then
1284 ✗ Error.addMultiSourceMessage(Error.CONVERSION_MISSING_PLACEHOLDER_VALUE,
1285 {"%" + name + "%"}, info);
1286 end if;
1287
1288 ✗ SOME(outExp) := new_exp;
1289 else
1290 outExp := exp;
1291 end if;
1292 then
1293 outExp;
1294
1295 else exp;
1296 end match;
1297 end replacePlaceholdersExp;
1298
1299 function mergeModifiers
1300 "Merges two lists of modifiers, with the outer modifiers having precedence."
1301 input list<Absyn.ElementArg> outerMods;
1302 input list<Absyn.ElementArg> innerMods;
1303 output list<Absyn.ElementArg> mods = outerMods;
1304 algorithm
1305
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 for m in listReverse(innerMods) loop
1306
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if not isModifierInList(m, outerMods) then
1307 mods := m :: mods;
1308 end if;
1309 end for;
1310 end mergeModifiers;
1311
1312 function convertTypeSpec
1313 "Converts an Absyn.TypeSpec."
1314 input output Absyn.TypeSpec ty;
1315 input ConversionRules rules;
1316 input Env env;
1317 input SourceInfo info;
1318 output RuleTable localRules;
1319 output list<ConversionRule> modifierRules;
1320 protected
1321 Option<ConversionRule> ty_rule;
1322 Absyn.Path ty_path;
1323 Option<tuple<Absyn.Path, String>> import_path;
1324 algorithm
1325 // Apply imports before looking the path up, convertTypePath then strips it if necessary.
1326 17 (ty_path, import_path) := applyImportsToPath(AbsynUtil.typeSpecPath(ty), env.imports);
1327 17 (ty_rule, localRules, modifierRules) := lookupTypeRules(ty_path, rules, env);
1328
1329 () := match ty
1330 case Absyn.TypeSpec.TPATH()
1331 algorithm
1332
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 9 times.
17 if isSome(ty_rule) then
1333 8 ty.path := convertTypePath(ty_path, Util.getOption(ty_rule), import_path, info);
1334 end if;
1335
1336 34 ty.arrayDim := convertOption(ty.arrayDim,
1337 function convertSubscripts(localRules = localRules), rules, env, info);
1338 then
1339 ();
1340
1341 case Absyn.TypeSpec.TCOMPLEX()
1342 algorithm
1343 ✗ if isSome(ty_rule) then
1344 ✗ ty.path := convertTypePath(ty_path, Util.getOption(ty_rule), import_path, info);
1345 end if;
1346
1347 ✗ ty.typeSpecs := list(convertTypeSpec(t, rules, env, info) for t in ty.typeSpecs);
1348 ✗ ty.arrayDim := convertOption(ty.arrayDim,
1349 function convertSubscripts(localRules = localRules), rules, env, info);
1350 then
1351 ();
1352
1353 else ();
1354 end match;
1355 end convertTypeSpec;
1356
1357 function convertTypePath
1358 "Converts an Absyn.Path representing a type."
1359 input output Absyn.Path path;
1360 input ConversionRule rule;
1361 input Option<tuple<Absyn.Path, String>> importPath;
1362 input SourceInfo info;
1363 algorithm
1364 () := match rule
1365 case ConversionRule.CLASS()
1366 algorithm
1367
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 5 times.
16 if AbsynUtil.pathPartCount(path) == arrayLength(rule.oldPath) then
1368 // convertClass(A.B.C, X.Y.Z) on A.B.C => X.Y.Z
1369 3 path := rule.newPath;
1370 else
1371 // convertClass(A.B.C, X.Y.Z) on A.B.C.D... => X.Y.Z.D...
1372 5 path := Util.foldcallN(arrayLength(rule.oldPath), AbsynUtil.pathRest, path);
1373 5 path := AbsynUtil.joinPaths(rule.newPath, path);
1374 end if;
1375 then
1376 ();
1377
1378 case ConversionRule.MESSAGE()
1379 algorithm
1380 ✗ Error.addSourceMessage(Error.CONVERSION_MESSAGE, {rule.message}, info);
1381 then
1382 ();
1383
1384 else ();
1385 end match;
1386
1387 8 path := stripImportPath(path, importPath);
1388 end convertTypePath;
1389
1390 function convertElementItems
1391 "Converts a list of Absyn.ElementItems."
1392 input output list<Absyn.ElementItem> elements;
1393 input ConversionRules rules;
1394 input Env env;
1395 input list<ConversionRules> extendsRules;
1396 algorithm
1397
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 16 times.
44 elements := list(convertElementItem(e, rules, env, extendsRules) for e in elements);
1398
1399 // After converting elements we might end up with duplicate imports, for example:
1400 // import SI = Modelica.SIunits;
1401 // import Modelica.SIunits;
1402 // becomes after conversion:
1403 // import Modelica.Units.SI; // After simplification of SI = Modelica.Units.SI
1404 // import Modelica.Units.SI;
1405 // To avoid issues we filter out such duplicate imports here.
1406 16 elements := filterDuplicateImports(elements);
1407 end convertElementItems;
1408
1409 function convertElementItem
1410 "Converts an Absyn.ElementItem."
1411 input output Absyn.ElementItem element;
1412 input ConversionRules rules;
1413 input Env env;
1414 input list<ConversionRules> extendsRules;
1415 algorithm
1416 () := match element
1417 case Absyn.ElementItem.ELEMENTITEM()
1418 algorithm
1419 28 element.element := convertElement(element.element, rules, env, extendsRules);
1420 then
1421 ();
1422
1423 else ();
1424 end match;
1425 end convertElementItem;
1426
1427 function convertElement
1428 "Converts an Absyn.Element."
1429 input output Absyn.Element element;
1430 input ConversionRules rules;
1431 input Env env;
1432 input list<ConversionRules> extendsRules;
1433 algorithm
1434 () := match element
1435 local
1436 RuleTable local_rules;
1437
1438 case Absyn.Element.ELEMENT()
1439 algorithm
1440 28 element.specification := convertElementSpec(element.specification,
1441 rules, env, extendsRules, element.info);
1442 28 element.constrainClass := convertOption(element.constrainClass,
1443 convertConstrainClass, rules, env, element.info);
1444 then
1445 ();
1446
1447 case Absyn.Element.DEFINEUNIT()
1448 algorithm
1449 ✗ local_rules := newRuleTable();
1450 ✗ element.args := list(convertNamedArg(a, local_rules, rules, env, element.info) for a in element.args);
1451 then
1452 ();
1453
1454 else ();
1455 end match;
1456 end convertElement;
1457
1458 function convertConstrainClass
1459 "Converts an Absyn.ConstrainClass."
1460 input output Absyn.ConstrainClass cc;
1461 input ConversionRules rules;
1462 input Env env;
1463 input SourceInfo info;
1464 algorithm
1465 ✗ cc.elementSpec := convertElementSpec(cc.elementSpec, rules, env, {}, info);
1466 end convertConstrainClass;
1467
1468 function convertElementSpec
1469 "Converts an Absyn.ElementSpec."
1470 input output Absyn.ElementSpec spec;
1471 input ConversionRules rules;
1472 input Env env;
1473 input list<ConversionRules> extendsRules;
1474 input SourceInfo info;
1475 algorithm
1476 () := match spec
1477 local
1478 RuleTable local_rules;
1479 list<ConversionRule> mod_rules;
1480 Absyn.Path ty_path;
1481 Option<tuple<Absyn.Path, String>> import_path;
1482 Absyn.TypeSpec ty;
1483
1484 case Absyn.ElementSpec.CLASSDEF()
1485 algorithm
1486 7 spec.class_ := convertClass(spec.class_, rules, env, extendsRules);
1487 then
1488 ();
1489
1490 case Absyn.ElementSpec.EXTENDS()
1491 algorithm
1492 1 (ty_path, import_path) := applyImportsToPath(spec.path, env.imports);
1493 1 (_, local_rules, mod_rules) := lookupTypeRules(ty_path, rules, env);
1494 1 ty_path := convertPath(ty_path, rules, env.imports, info);
1495 1 spec.path := stripImportPath(ty_path, import_path);
1496 1 spec.elementArg := convertModification2(mod_rules, spec.elementArg);
1497 1 spec.elementArg := convertElementArgs(spec.elementArg, local_rules, rules, env);
1498 then
1499 ();
1500
1501 case Absyn.ElementSpec.IMPORT()
1502 algorithm
1503 3 spec.import_ := convertImport(spec.import_, rules, info);
1504 then
1505 ();
1506
1507 case Absyn.ElementSpec.COMPONENTS()
1508 algorithm
1509 17 (ty, local_rules, mod_rules) := convertTypeSpec(spec.typeSpec, rules, env, info);
1510 17 spec.typeSpec := ty;
1511
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 17 times.
51 spec.components := list(convertComponentItem(c, local_rules, mod_rules, rules, env, info) for c in spec.components);
1512 then
1513 ();
1514
1515 else ();
1516 end match;
1517 end convertElementSpec;
1518
1519 function convertImport
1520 "Converts an Absyn.Import."
1521 input output Absyn.Import imp;
1522 input ConversionRules rules;
1523 input SourceInfo info;
1524 algorithm
1525 () := match imp
1526 case Absyn.Import.NAMED_IMPORT()
1527 algorithm
1528 3 imp.path := convertPath(imp.path, rules, ImportTree.new(), info);
1529 then
1530 ();
1531
1532 case Absyn.Import.QUAL_IMPORT()
1533 algorithm
1534 ✗ imp.path := convertPath(imp.path, rules, ImportTree.new(), info);
1535 then
1536 ();
1537
1538 case Absyn.Import.UNQUAL_IMPORT()
1539 algorithm
1540 ✗ imp.path := convertPath(imp.path, rules, ImportTree.new(), info);
1541 then
1542 ();
1543
1544 case Absyn.Import.GROUP_IMPORT()
1545 algorithm
1546 ✗ imp.prefix := convertPath(imp.prefix, rules, ImportTree.new(), info);
1547 then
1548 ();
1549
1550 else ();
1551 end match;
1552
1553 3 imp := simplifyImport(imp);
1554 end convertImport;
1555
1556 function simplifyImport
1557 "Simplifies imports like `import C = A.B.C;` to `import A.B.C`"
1558 input output Absyn.Import imp;
1559 algorithm
1560 imp := match imp
1561 case Absyn.Import.NAMED_IMPORT()
1562 guard imp.name == AbsynUtil.pathLastIdent(imp.path)
1563 3 then Absyn.Import.QUAL_IMPORT(imp.path);
1564
1565 else imp;
1566 end match;
1567 end simplifyImport;
1568
1569 function filterDuplicateImports
1570 "Filters out duplicate imports in a list of elements."
1571 input list<Absyn.ElementItem> elements;
1572 output list<Absyn.ElementItem> outElements;
1573 protected
1574 UnorderedSet<Absyn.Path> imports;
1575 algorithm
1576 16 imports := UnorderedSet.new(AbsynUtil.pathHash, AbsynUtil.pathEqual, 1);
1577
5/6
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 16 times.
44 outElements := list(e for e guard not importExists(e, imports) in elements);
1578 end filterDuplicateImports;
1579
1580 function importExists
1581 input Absyn.ElementItem element;
1582 input UnorderedSet<Absyn.Path> imports;
1583 output Boolean exists;
1584 protected
1585 Absyn.Path path;
1586 algorithm
1587 exists := match element
1588 case Absyn.ElementItem.ELEMENTITEM(element = Absyn.Element.ELEMENT(
1589 specification = Absyn.ElementSpec.IMPORT(import_ = Absyn.Import.QUAL_IMPORT(path = path))))
1590 algorithm
1591 3 exists := UnorderedSet.contains(path, imports);
1592
1593
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if not exists then
1594 3 UnorderedSet.add(path, imports);
1595 end if;
1596 then
1597 exists;
1598
1599 else false;
1600 end match;
1601 end importExists;
1602
1603 function convertComponentItem
1604 "Converts an Absyn.ComponentItem."
1605 input output Absyn.ComponentItem comp;
1606 input RuleTable localRules;
1607 input list<ConversionRule> modifierRules;
1608 input ConversionRules rules;
1609 input Env env;
1610 input SourceInfo info;
1611 algorithm
1612 17 comp.component := convertComponent(comp.component, localRules, modifierRules, rules, env, info);
1613 comp.condition := convertOptExp(comp.condition, localRules, rules, env, info);
1614 end convertComponentItem;
1615
1616 function convertComponent
1617 "Converts an Absyn.Component."
1618 input output Absyn.Component comp;
1619 input RuleTable localRules;
1620 input list<ConversionRule> modifierRules;
1621 input ConversionRules rules;
1622 input Env env;
1623 input SourceInfo info;
1624 algorithm
1625 17 comp.arrayDim := convertSubscripts(comp.arrayDim, localRules, rules, env, info);
1626
1627
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
17 if not listEmpty(modifierRules) then
1628 2 comp.modification := convertModification(comp.modification, modifierRules);
1629 end if;
1630
1631 17 comp.modification := convertModificationExps(comp.modification, localRules, rules, env, info);
1632 end convertComponent;
1633
1634 function convertEquationItems
1635 "Converts a list of Absyn.EquationItems."
1636 input output list<Absyn.EquationItem> eqs;
1637 input RuleTable localRules;
1638 input ConversionRules rules;
1639 input Env env;
1640 algorithm
1641
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 eqs := list(convertEquationItem(eq, localRules, rules, env) for eq in eqs);
1642 end convertEquationItems;
1643
1644 function convertEquationItem
1645 "Converts an Absyn.EquationItem."
1646 input output Absyn.EquationItem eq;
1647 input RuleTable localRules;
1648 input ConversionRules rules;
1649 input Env env;
1650 algorithm
1651 () := match eq
1652 case Absyn.EquationItem.EQUATIONITEM()
1653 algorithm
1654 1 eq.equation_ := convertEquation(eq.equation_, localRules, rules, env, eq.info);
1655 then
1656 ();
1657
1658 else ();
1659 end match;
1660 end convertEquationItem;
1661
1662 function convertEquation
1663 "Converts an Absyn.Equation."
1664 input output Absyn.Equation eq;
1665 input RuleTable localRules;
1666 input ConversionRules rules;
1667 input Env env;
1668 input SourceInfo info;
1669 algorithm
1670 () := match eq
1671 case Absyn.Equation.EQ_IF()
1672 algorithm
1673 ✗ eq.ifExp := convertExp(eq.ifExp, localRules, rules, env, info);
1674 ✗ eq.equationTrueItems := convertEquationItems(eq.equationTrueItems, localRules, rules, env);
1675 ✗ eq.elseIfBranches := convertBranches(eq.elseIfBranches,
1676 function convertExp(info = info), convertEquationItems, localRules, rules, env);
1677 ✗ eq.equationElseItems := convertEquationItems(eq.equationElseItems, localRules, rules, env);
1678 then
1679 ();
1680
1681 case Absyn.Equation.EQ_EQUALS()
1682 algorithm
1683 1 eq.leftSide := convertExp(eq.leftSide, localRules, rules, env, info);
1684 1 eq.rightSide := convertExp(eq.rightSide, localRules, rules, env, info);
1685 then
1686 ();
1687
1688 case Absyn.Equation.EQ_PDE()
1689 algorithm
1690 ✗ eq.leftSide := convertExp(eq.leftSide, localRules, rules, env, info);
1691 ✗ eq.rightSide := convertExp(eq.rightSide, localRules, rules, env, info);
1692 then
1693 ();
1694
1695 case Absyn.Equation.EQ_CONNECT()
1696 algorithm
1697 ✗ eq.connector1 := convertCref(eq.connector1, localRules, rules, env, info);
1698 ✗ eq.connector2 := convertCref(eq.connector2, localRules, rules, env, info);
1699 then
1700 ();
1701
1702 case Absyn.Equation.EQ_FOR()
1703 algorithm
1704 ✗ eq.iterators := convertForIterators(eq.iterators, localRules, rules, env, info);
1705 ✗ eq.forEquations := convertEquationItems(eq.forEquations, localRules, rules, env);
1706 then
1707 ();
1708
1709 case Absyn.Equation.EQ_WHEN_E()
1710 algorithm
1711 ✗ eq.whenExp := convertExp(eq.whenExp, localRules, rules, env, info);
1712 ✗ eq.whenEquations := convertEquationItems(eq.whenEquations, localRules, rules, env);
1713 ✗ eq.elseWhenEquations := convertBranches(eq.elseWhenEquations,
1714 function convertExp(info = info), convertEquationItems, localRules, rules, env);
1715 then
1716 ();
1717
1718 case Absyn.Equation.EQ_NORETCALL()
1719 algorithm
1720 ✗ eq.functionName := convertCref(eq.functionName, localRules, rules, env, info);
1721 ✗ eq.functionArgs := convertFunctionArgs(eq.functionArgs, localRules, rules, env, info);
1722 then
1723 ();
1724
1725 case Absyn.Equation.EQ_FAILURE()
1726 algorithm
1727 ✗ eq.equ := convertEquationItem(eq.equ, localRules, rules, env);
1728 then
1729 ();
1730
1731 else ();
1732 end match;
1733 end convertEquation;
1734
1735 function convertAlgorithmItems
1736 "Converts a list of Absyn.AlgorithmItems."
1737 input output list<Absyn.AlgorithmItem> algs;
1738 input RuleTable localRules;
1739 input ConversionRules rules;
1740 input Env env;
1741 algorithm
1742 ✗ algs := list(convertAlgorithmItem(alg, localRules, rules, env) for alg in algs);
1743 end convertAlgorithmItems;
1744
1745 function convertAlgorithmItem
1746 "Converts an Absyn.AlgorithmItem."
1747 input output Absyn.AlgorithmItem alg;
1748 input RuleTable localRules;
1749 input ConversionRules rules;
1750 input Env env;
1751 algorithm
1752 () := match alg
1753 case Absyn.AlgorithmItem.ALGORITHMITEM()
1754 algorithm
1755 ✗ alg.algorithm_ := convertAlgorithm(alg.algorithm_, localRules, rules, env, alg.info);
1756 then
1757 ();
1758
1759 else ();
1760 end match;
1761 end convertAlgorithmItem;
1762
1763 function convertAlgorithm
1764 "Converts an Absyn.Algorithm."
1765 input output Absyn.Algorithm alg;
1766 input RuleTable localRules;
1767 input ConversionRules rules;
1768 input Env env;
1769 input SourceInfo info;
1770 algorithm
1771 () := match alg
1772 case Absyn.Algorithm.ALG_ASSIGN()
1773 algorithm
1774 ✗ alg.assignComponent := convertExp(alg.assignComponent, localRules, rules, env, info);
1775 ✗ alg.value := convertExp(alg.value, localRules, rules, env, info);
1776 then
1777 ();
1778
1779 case Absyn.Algorithm.ALG_IF()
1780 algorithm
1781 ✗ alg.ifExp := convertExp(alg.ifExp, localRules, rules, env, info);
1782 ✗ alg.trueBranch := convertAlgorithmItems(alg.trueBranch, localRules, rules, env);
1783 ✗ alg.elseIfAlgorithmBranch := convertBranches(alg.elseIfAlgorithmBranch,
1784 function convertExp(info = info), convertAlgorithmItems, localRules, rules, env);
1785 ✗ alg.elseBranch := convertAlgorithmItems(alg.elseBranch, localRules, rules, env);
1786 then
1787 ();
1788
1789 case Absyn.Algorithm.ALG_FOR()
1790 algorithm
1791 ✗ alg.iterators := convertForIterators(alg.iterators, localRules, rules, env, info);
1792 ✗ alg.forBody := convertAlgorithmItems(alg.forBody, localRules, rules, env);
1793 then
1794 ();
1795
1796 case Absyn.Algorithm.ALG_PARFOR()
1797 algorithm
1798 ✗ alg.iterators := convertForIterators(alg.iterators, localRules, rules, env, info);
1799 ✗ alg.parforBody := convertAlgorithmItems(alg.parforBody, localRules, rules, env);
1800 then
1801 ();
1802
1803 case Absyn.Algorithm.ALG_WHILE()
1804 algorithm
1805 ✗ alg.boolExpr := convertExp(alg.boolExpr, localRules, rules, env, info);
1806 ✗ alg.whileBody := convertAlgorithmItems(alg.whileBody, localRules, rules, env);
1807 then
1808 ();
1809
1810 case Absyn.Algorithm.ALG_WHEN_A()
1811 algorithm
1812 ✗ alg.boolExpr := convertExp(alg.boolExpr, localRules, rules, env, info);
1813 ✗ alg.whenBody := convertAlgorithmItems(alg.whenBody, localRules, rules, env);
1814 ✗ alg.elseWhenAlgorithmBranch := convertBranches(alg.elseWhenAlgorithmBranch,
1815 function convertExp(info = info), convertAlgorithmItems, localRules, rules, env);
1816 then
1817 ();
1818
1819 case Absyn.Algorithm.ALG_NORETCALL()
1820 algorithm
1821 ✗ alg.functionCall := convertCref(alg.functionCall, localRules, rules, env, info);
1822 ✗ alg.functionArgs := convertFunctionArgs(alg.functionArgs, localRules, rules, env, info);
1823 then
1824 ();
1825
1826 case Absyn.Algorithm.ALG_FAILURE()
1827 algorithm
1828 ✗ alg.equ := convertAlgorithmItems(alg.equ, localRules, rules, env);
1829 then
1830 ();
1831
1832 case Absyn.Algorithm.ALG_TRY()
1833 algorithm
1834 ✗ alg.body := convertAlgorithmItems(alg.body, localRules, rules, env);
1835 ✗ alg.elseBody := convertAlgorithmItems(alg.elseBody, localRules, rules, env);
1836 then
1837 ();
1838
1839 else ();
1840 end match;
1841 end convertAlgorithm;
1842
1843 function convertBranches<CondT, BodyT>
1844 "Generic function for converting if/when branches."
1845 input output list<tuple<CondT, BodyT>> branches;
1846 input CondFunc condFunc;
1847 input BodyFunc bodyFunc;
1848 input RuleTable localRules;
1849 input ConversionRules rules;
1850 input Env env;
1851
1852 partial function CondFunc
1853 input output CondT cond;
1854 input RuleTable localRules;
1855 input ConversionRules rules;
1856 input Env env;
1857 end CondFunc;
1858
1859 partial function BodyFunc
1860 input output BodyT body;
1861 input RuleTable localRules;
1862 input ConversionRules rules;
1863 input Env env;
1864 end BodyFunc;
1865 algorithm
1866 ✗ branches := list(
1867 (condFunc(Util.tuple21(b), localRules, rules, env),
1868 bodyFunc(Util.tuple22(b), localRules, rules, env))
1869 for b in branches
1870 );
1871 end convertBranches;
1872
1873 function convertForIterators
1874 "Converts an Absyn.ForIterators."
1875 input output Absyn.ForIterators iters;
1876 input RuleTable localRules;
1877 input ConversionRules rules;
1878 input Env env;
1879 input SourceInfo info;
1880 algorithm
1881 ✗ iters := list(convertForIterator(i, localRules, rules, env, info) for i in iters);
1882 end convertForIterators;
1883
1884 function convertForIterator
1885 "Converts an Absyn.ForIterator."
1886 input output Absyn.ForIterator iter;
1887 input RuleTable localRules;
1888 input ConversionRules rules;
1889 input Env env;
1890 input SourceInfo info;
1891 algorithm
1892 ✗ iter.guardExp := convertOptExp(iter.guardExp, localRules, rules, env, info);
1893 iter.range := convertOptExp(iter.range, localRules, rules, env, info);
1894 end convertForIterator;
1895
1896 function convertExternalDecl
1897 "Converts an Absyn.ExternalDecl."
1898 input output Absyn.ExternalDecl extDecl;
1899 input RuleTable localRules;
1900 input ConversionRules rules;
1901 input Env env;
1902 input SourceInfo info;
1903 algorithm
1904 ✗ extDecl.args := convertExps(extDecl.args, localRules, rules, env, info);
1905 end convertExternalDecl;
1906
1907 function convertExps
1908 "Converts a list of Absyn.Exps."
1909 input output list<Absyn.Exp> exps;
1910 input RuleTable localRules;
1911 input ConversionRules rules;
1912 input Env env;
1913 input SourceInfo info;
1914 algorithm
1915 ✗ exps := list(convertExp(e, localRules, rules, env, info) for e in exps);
1916 end convertExps;
1917
1918 function convertOptExp
1919 "Converts an optional Absyn.Exp."
1920 input output Option<Absyn.Exp> exp;
1921 input RuleTable localRules;
1922 input ConversionRules rules;
1923 input Env env;
1924 input SourceInfo info;
1925 algorithm
1926 exp := match exp
1927 local
1928 Absyn.Exp e;
1929
1930 ✗ case SOME(e) then SOME(convertExp(e, localRules, rules, env, info));
1931 else NONE();
1932 end match;
1933 end convertOptExp;
1934
1935 function convertExp
1936 "Converts an Absyn.Exp."
1937 input output Absyn.Exp exp;
1938 input RuleTable localRules;
1939 input ConversionRules rules;
1940 input Env env;
1941 input SourceInfo info;
1942 algorithm
1943 () := match exp
1944 case Absyn.Exp.CREF()
1945 algorithm
1946 1 exp.componentRef := convertCref(exp.componentRef, localRules, rules, env, info);
1947 then
1948 ();
1949
1950 case Absyn.Exp.BINARY()
1951 algorithm
1952 ✗ exp.exp1 := convertExp(exp.exp1, localRules, rules, env, info);
1953 ✗ exp.exp2 := convertExp(exp.exp2, localRules, rules, env, info);
1954 then
1955 ();
1956
1957 case Absyn.Exp.UNARY()
1958 algorithm
1959 ✗ exp.exp := convertExp(exp.exp, localRules, rules, env, info);
1960 then
1961 ();
1962
1963 case Absyn.Exp.LBINARY()
1964 algorithm
1965 ✗ exp.exp1 := convertExp(exp.exp1, localRules, rules, env, info);
1966 ✗ exp.exp2 := convertExp(exp.exp2, localRules, rules, env, info);
1967 then
1968 ();
1969
1970 case Absyn.Exp.LUNARY()
1971 algorithm
1972 ✗ exp.exp := convertExp(exp.exp, localRules, rules, env, info);
1973 then
1974 ();
1975
1976 case Absyn.Exp.RELATION()
1977 algorithm
1978 ✗ exp.exp1 := convertExp(exp.exp1, localRules, rules, env, info);
1979 ✗ exp.exp2 := convertExp(exp.exp2, localRules, rules, env, info);
1980 then
1981 ();
1982
1983 case Absyn.Exp.IFEXP()
1984 algorithm
1985 ✗ exp.ifExp := convertExp(exp.ifExp, localRules, rules, env, info);
1986 ✗ exp.trueBranch := convertExp(exp.trueBranch, localRules, rules, env, info);
1987 ✗ exp.elseBranch := convertExp(exp.elseBranch, localRules, rules, env, info);
1988 ✗ exp.elseIfBranch := convertBranches(exp.elseIfBranch,
1989 function convertExp(info = info), function convertExp(info = info), localRules, rules, env);
1990 then
1991 ();
1992
1993 case Absyn.Exp.CALL()
1994 algorithm
1995 ✗ exp.function_ := convertCref(exp.function_, localRules, rules, env, info);
1996 ✗ exp.functionArgs := convertFunctionArgs(exp.functionArgs, localRules, rules, env, info);
1997 then
1998 ();
1999
2000 case Absyn.Exp.PARTEVALFUNCTION()
2001 algorithm
2002 ✗ exp.function_ := convertCref(exp.function_, localRules, rules, env, info);
2003 ✗ exp.functionArgs := convertFunctionArgs(exp.functionArgs, localRules, rules, env, info);
2004 then
2005 ();
2006
2007 case Absyn.Exp.ARRAY()
2008 algorithm
2009 ✗ exp.arrayExp := convertExps(exp.arrayExp, localRules, rules, env, info);
2010 then
2011 ();
2012
2013 case Absyn.Exp.MATRIX()
2014 algorithm
2015 ✗ exp.matrix := list(convertExps(e, localRules, rules, env, info) for e in exp.matrix);
2016 then
2017 ();
2018
2019 case Absyn.Exp.RANGE()
2020 algorithm
2021 ✗ exp.start := convertExp(exp.start, localRules, rules, env, info);
2022 ✗ exp.step := convertOptExp(exp.step, localRules, rules, env, info);
2023 ✗ exp.stop := convertExp(exp.stop, localRules, rules, env, info);
2024 then
2025 ();
2026
2027 case Absyn.Exp.TUPLE()
2028 algorithm
2029 ✗ exp.expressions := convertExps(exp.expressions, localRules, rules, env, info);
2030 then
2031 ();
2032
2033 case Absyn.Exp.EXPRESSIONCOMMENT()
2034 algorithm
2035 ✗ exp.exp := convertExp(exp.exp, localRules, rules, env, info);
2036 then
2037 ();
2038
2039 case Absyn.Exp.SUBSCRIPTED_EXP()
2040 algorithm
2041 ✗ exp.exp := convertExp(exp.exp, localRules, rules, env, info);
2042 ✗ exp.subscripts := convertSubscripts(exp.subscripts, localRules, rules, env, info);
2043 then
2044 ();
2045
2046 else ();
2047 end match;
2048 end convertExp;
2049
2050 function convertCref
2051 "Converts an Absyn.ComponentRef."
2052 input output Absyn.ComponentRef cref;
2053 input RuleTable localRules;
2054 input ConversionRules rules;
2055 input Env env;
2056 input SourceInfo info;
2057 algorithm
2058 cref := match cref
2059 case Absyn.ComponentRef.WILD() then cref;
2060 case Absyn.ComponentRef.ALLWILD() then cref;
2061 case Absyn.ComponentRef.CREF_FULLYQUALIFIED()
2062 ✗ then Absyn.ComponentRef.CREF_FULLYQUALIFIED(
2063 convertCref2(cref.componentRef, localRules, rules, env, info));
2064 1 else convertCref2(cref, localRules, rules, env, info);
2065 end match;
2066 end convertCref;
2067
2068 function convertCref2
2069 "Converts an Absyn.ComponentRef."
2070 input output Absyn.ComponentRef cref;
2071 input RuleTable localRules;
2072 input ConversionRules rules;
2073 input Env env;
2074 input SourceInfo info;
2075 protected
2076 Absyn.Path path;
2077 list<ConversionRule> cref_rules;
2078 ConversionRule rule;
2079 Boolean has_subs, converted;
2080 algorithm
2081 1 has_subs := AbsynUtil.crefHasSubscripts(cref);
2082
2083 // Convert subscripts if the cref has any.
2084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if has_subs then
2085 ✗ cref := convertCrefSubscripts(cref, localRules, rules, env, info);
2086 end if;
2087
2088 // Try to find rules for the cref that applies to the scope the cref is used in.
2089 1 cref_rules := UnorderedMap.getOrDefault(AbsynUtil.crefFirstIdent(cref), localRules, {});
2090
2091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if not listEmpty(cref_rules) then
2092 // Apply local rules if found.
2093 ✗ rule := listHead(cref_rules);
2094
2095 cref := match rule
2096 case ConversionRule.ELEMENT()
2097 ✗ then AbsynUtil.crefSetFirstIdent(cref, rule.newName);
2098 else cref;
2099 end match;
2100
2101 ✗ converted := true;
2102 else
2103 // Otherwise, try to convert the cref based on its type.
2104 1 (cref, converted) := convertCrefFromType(cref, rules, env);
2105 end if;
2106
2107 // If no rules could be found and the cref has no subscripts, try to convert
2108 // it as a path instead in case it's an imported name.
2109
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if not converted and not has_subs then
2110 ✗ path := AbsynUtil.crefToPath(cref);
2111 ✗ path := convertPath(path, rules, env.imports, info);
2112 ✗ cref := AbsynUtil.pathToCref(path);
2113 end if;
2114 end convertCref2;
2115
2116 function convertCrefFromType
2117 "Converts an Absyn.ComponentRef based on its type. For a cref such as a.b
2118 this means looking up the type of a and then applying any rules for that
2119 type that applies to b. So with e.g. the rule:
2120
2121 convertElement('SomeType', 'b', 'c')
2122
2123 and a model like this:
2124
2125 model M
2126 SomeType a;
2127 algorithm
2128 a.b = 0;
2129 end M;
2130
2131 we convert the cref and get:
2132
2133 model M
2134 SomeType a;
2135 algorithm
2136 a.c = 0;
2137 end M;
2138 "
2139 input output Absyn.ComponentRef cref;
2140 input ConversionRules rules;
2141 input Env env;
2142 output Boolean converted = false;
2143 protected
2144 String id;
2145 Absyn.ComponentRef first_cref, rest_cref;
2146 Option<Absyn.Path> opt_ty;
2147 list<ConversionRule> cref_rules;
2148 algorithm
2149 // Only qualified crefs can be converted.
2150
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if not AbsynUtil.crefIsQual(cref) then
2151 ✗ return;
2152 end if;
2153
2154 // Look up the type of the first identifier.
2155 1 id := AbsynUtil.crefFirstIdent(cref);
2156 1 opt_ty := UnorderedMap.get(id, env.components);
2157
2158 // Look up the rules for the first identifier, if any.
2159
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if isSome(opt_ty) then
2160 1 cref_rules := listHead(lookupRules(Util.getOption(opt_ty), rules));
2161 else
2162 cref_rules := {};
2163 end if;
2164
2165 // No rules => nothing to do.
2166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if listEmpty(cref_rules) then
2167 ✗ return;
2168 end if;
2169
2170 // Split the cref into the first part and the rest of the cref.
2171 1 first_cref := AbsynUtil.crefFirstCref(cref);
2172 1 rest_cref := AbsynUtil.crefStripFirst(cref);
2173 1 id := AbsynUtil.crefFirstIdent(rest_cref);
2174
2175 // Try to find a convertElement rule for the second identifier in the cref.
2176
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 for rule in cref_rules loop
2177 () := match rule
2178 case ConversionRule.ELEMENT()
2179 guard rule.oldName == id
2180 algorithm
2181 // Matching rule found, replace the second identifier with the one
2182 // given by the rule and assemble the cref again.
2183 1 rest_cref := AbsynUtil.crefSetFirstIdent(rest_cref, rule.newName);
2184 1 cref := AbsynUtil.joinCrefs(first_cref, rest_cref);
2185 converted := true;
2186 1 return;
2187 then
2188 ();
2189
2190 else ();
2191 end match;
2192 end for;
2193 end convertCrefFromType;
2194
2195 function convertCrefSubscripts
2196 "Converts an Absyn.ComponentRef."
2197 input output Absyn.ComponentRef cref;
2198 input RuleTable localRules;
2199 input ConversionRules rules;
2200 input Env env;
2201 input SourceInfo info;
2202 algorithm
2203 () := match cref
2204 case Absyn.ComponentRef.CREF_QUAL()
2205 algorithm
2206 ✗ cref.subscripts := convertSubscripts(cref.subscripts, localRules, rules, env, info);
2207 ✗ cref.componentRef := convertCrefSubscripts(cref.componentRef, localRules, rules, env, info);
2208 then
2209 ();
2210
2211 case Absyn.ComponentRef.CREF_IDENT()
2212 algorithm
2213 ✗ cref.subscripts := convertSubscripts(cref.subscripts, localRules, rules, env, info);
2214 then
2215 ();
2216
2217 else ();
2218 end match;
2219 end convertCrefSubscripts;
2220
2221 function convertSubscripts
2222 "Converts a list of Absyn.Subscripts."
2223 input output list<Absyn.Subscript> subs;
2224 input RuleTable localRules;
2225 input ConversionRules rules;
2226 input Env env;
2227 input SourceInfo info;
2228 algorithm
2229
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 subs := list(convertSubscript(s, localRules, rules, env, info) for s in subs);
2230 end convertSubscripts;
2231
2232 function convertSubscript
2233 "Converts an Absyn.Subscript."
2234 input output Absyn.Subscript sub;
2235 input RuleTable localRules;
2236 input ConversionRules rules;
2237 input Env env;
2238 input SourceInfo info;
2239 algorithm
2240 () := match sub
2241 case Absyn.Subscript.SUBSCRIPT()
2242 algorithm
2243 ✗ sub.subscript := convertExp(sub.subscript, localRules, rules, env, info);
2244 then
2245 ();
2246
2247 else ();
2248 end match;
2249 end convertSubscript;
2250
2251 function convertPath
2252 "Converts an Absyn.Path."
2253 input output Absyn.Path path;
2254 input ConversionRules rules;
2255 input ImportTree imports;
2256 input SourceInfo info;
2257 protected
2258 Option<tuple<Absyn.Path, String>> import_path;
2259 algorithm
2260 7 (path, import_path) := applyImportsToPath(path, imports);
2261 7 path := applyRulesPath(path, lookupRules(path, rules), info);
2262 7 path := stripImportPath(path, import_path);
2263 end convertPath;
2264
2265 function applyRulesPath
2266 input output Absyn.Path path;
2267 input list<list<ConversionRule>> rules;
2268 input SourceInfo info;
2269 protected
2270 Integer path_len = AbsynUtil.pathPartCount(path);
2271 Boolean found;
2272 algorithm
2273
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 for rl in rules loop
2274
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 for rule in rl loop
2275 found := match rule
2276 case ConversionRule.CLASS()
2277 algorithm
2278
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 time.
14 if path_len == arrayLength(rule.oldPath) then
2279 // convertClass(A.B.C, X.Y.Z) on A.B.C => X.Y.Z
2280 6 path := rule.newPath;
2281 else
2282 // convertClass(A.B.C, X.Y.Z) on A.B.C.D... => X.Y.Z.D...
2283 1 path := Util.foldcallN(arrayLength(rule.oldPath), AbsynUtil.pathRest, path);
2284 1 path := AbsynUtil.joinPaths(rule.newPath, path);
2285 end if;
2286 then
2287 true;
2288
2289 case ConversionRule.ELEMENT()
2290 guard path_len > arrayLength(rule.oldPath) and
2291 AbsynUtil.pathNthIdent(path, arrayLength(rule.oldPath) + 1) == rule.oldName
2292 algorithm
2293 ✗ if path_len == arrayLength(rule.oldPath) - 1 then
2294 // convertElement(A.B.C, X, Y) on A.B.C.X => A.B.C.Y
2295 ✗ path := AbsynUtil.pathSetLastIdent(path, rule.newName);
2296 else
2297 // convertElement(A.B.C, X, Y) on A.B.C.X.E... => A.B.C.Y.E...
2298 ✗ path := AbsynUtil.pathSetNthIdent(path, rule.newName,
2299 arrayLength(rule.oldPath) + 1);
2300 end if;
2301 then
2302 true;
2303
2304 case ConversionRule.MESSAGE()
2305 algorithm
2306 ✗ Error.addSourceMessage(Error.CONVERSION_MESSAGE, {rule.message}, info);
2307 then
2308 true;
2309
2310 else false;
2311 end match;
2312
2313 if found then
2314 7 return;
2315 end if;
2316 end for;
2317 end for;
2318 end applyRulesPath;
2319
2320 function convertFunctionArgs
2321 "Converts an Absyn.FunctionArgs."
2322 input output Absyn.FunctionArgs args;
2323 input RuleTable localRules;
2324 input ConversionRules rules;
2325 input Env env;
2326 input SourceInfo info;
2327 algorithm
2328 () := match args
2329 case Absyn.FunctionArgs.FUNCTIONARGS()
2330 algorithm
2331 ✗ args.args := convertExps(args.args, localRules, rules, env, info);
2332 ✗ args.argNames := list(convertNamedArg(a, localRules, rules, env, info) for a in args.argNames);
2333 then
2334 ();
2335
2336 case Absyn.FunctionArgs.FOR_ITER_FARG()
2337 algorithm
2338 ✗ args.exp := convertExp(args.exp, localRules, rules, env, info);
2339 ✗ args.iterators := convertForIterators(args.iterators, localRules, rules, env, info);
2340 then
2341 ();
2342
2343 end match;
2344 end convertFunctionArgs;
2345
2346 function convertNamedArg
2347 "Converts an Absyn.NamedArg."
2348 input output Absyn.NamedArg arg;
2349 input RuleTable localRules;
2350 input ConversionRules rules;
2351 input Env env;
2352 input SourceInfo info;
2353 algorithm
2354 ✗ arg.argValue := convertExp(arg.argValue, localRules, rules, env, info);
2355 end convertNamedArg;
2356
2357 function convertOption<T>
2358 "Converts an optional value using the given conversion function."
2359 input output Option<T> opt;
2360 input OptFunc optFunc;
2361 input ConversionRules rules;
2362 input Env env;
2363 input SourceInfo info;
2364
2365 partial function OptFunc
2366 input output T e;
2367 input ConversionRules rules;
2368 input Env env;
2369 input SourceInfo info;
2370 end OptFunc;
2371 protected
2372 T e;
2373 algorithm
2374 opt := match opt
2375
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 case SOME(e) then SOME(optFunc(e, rules, env, info));
2376 else opt;
2377 end match;
2378 end convertOption;
2379
2380 function getExtendsRules
2381 "Returns the rules for any extends clauses in the given list of class parts."
2382 input list<Absyn.ClassPart> parts;
2383 input ConversionRules rules;
2384 input Env env;
2385 output list<ConversionRules> extendsRules = {};
2386 protected
2387 Option<ConversionRules> onode;
2388 algorithm
2389
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 16 times.
17 for ext in getExtendsPathsInParts(parts) loop
2390 1 onode := lookupRuleNode(ext, rules);
2391
2392
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if isSome(onode) then
2393 ✗ extendsRules := Util.getOption(onode) :: extendsRules;
2394 end if;
2395 end for;
2396 end getExtendsRules;
2397
2398 function getExtendsPathsInParts
2399 "Returns a list of extends clauses in the given list of class parts."
2400 input list<Absyn.ClassPart> parts;
2401 output list<Absyn.Path> extendsPaths = {};
2402 algorithm
2403
4/5
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 16 times.
33 for part in parts loop
2404 () := match part
2405 case Absyn.ClassPart.PUBLIC()
2406 algorithm
2407
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 for e in part.contents loop
2408 28 extendsPaths := getExtendsPathsInElementItem(e, extendsPaths);
2409 end for;
2410 then
2411 ();
2412
2413 case Absyn.ClassPart.PROTECTED()
2414 algorithm
2415 ✗ for e in part.contents loop
2416 ✗ extendsPaths := getExtendsPathsInElementItem(e, extendsPaths);
2417 end for;
2418 then
2419 ();
2420
2421 else ();
2422 end match;
2423 end for;
2424 end getExtendsPathsInParts;
2425
2426 function getExtendsPathsInElementItem
2427 "Appends the path of the element to the given list if the element is an extends clause."
2428 input Absyn.ElementItem element;
2429 input output list<Absyn.Path> extendsPaths;
2430 algorithm
2431 () := match element
2432 local
2433 Absyn.Path ext_path;
2434
2435 case Absyn.ElementItem.ELEMENTITEM(element =
2436 Absyn.Element.ELEMENT(specification = Absyn.ElementSpec.EXTENDS(path = ext_path)))
2437 algorithm
2438 extendsPaths := ext_path :: extendsPaths;
2439 then
2440 ();
2441
2442 else ();
2443 end match;
2444 end getExtendsPathsInElementItem;
2445
2446 function getImportsInParts
2447 "Returns a list of imports in the given list of class parts."
2448 input list<Absyn.ClassPart> parts;
2449 output list<Absyn.ElementSpec> imports = {};
2450 algorithm
2451
4/5
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 16 times.
33 for part in parts loop
2452 () := match part
2453 case Absyn.ClassPart.PUBLIC()
2454 algorithm
2455
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 for e in part.contents loop
2456 28 imports := getImportsInElementItem(e, imports);
2457 end for;
2458 then
2459 ();
2460
2461 case Absyn.ClassPart.PROTECTED()
2462 algorithm
2463 ✗ for e in part.contents loop
2464 ✗ imports := getImportsInElementItem(e, imports);
2465 end for;
2466 then
2467 ();
2468
2469 else ();
2470 end match;
2471 end for;
2472 end getImportsInParts;
2473
2474 function getImportsInElementItem
2475 "Appends the element spec to the given list if the element is an import clause."
2476 input Absyn.ElementItem element;
2477 input output list<Absyn.ElementSpec> imports;
2478 algorithm
2479 () := match element
2480 local
2481 Absyn.ElementSpec imp;
2482
2483 case Absyn.ElementItem.ELEMENTITEM(element =
2484 Absyn.Element.ELEMENT(specification = imp as Absyn.ElementSpec.IMPORT()))
2485 algorithm
2486 imports := imp :: imports;
2487 then
2488 ();
2489
2490 else ();
2491 end match;
2492 end getImportsInElementItem;
2493
2494 function addImportNamesToEnv
2495 "Adds any imports found in the given elements to the import lookup tree."
2496 input list<Absyn.ElementSpec> elements;
2497 input ConversionRules rules;
2498 input output Env env;
2499 protected
2500 Absyn.Import imp;
2501 SourceInfo info;
2502 ImportTree imps;
2503 algorithm
2504
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 if listEmpty(elements) then
2505 13 return;
2506 end if;
2507
2508 3 imps := env.imports;
2509
2510
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for e in elements loop
2511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 Absyn.IMPORT(import_ = imp, info = info) := e;
2512 3 imps := addImportName(imp, rules, info, imps);
2513 end for;
2514
2515 3 env.imports := imps;
2516 end addImportNamesToEnv;
2517
2518 function addImportName
2519 "Adds an import to the import lookup tree."
2520 input Absyn.Import imp;
2521 input ConversionRules rules;
2522 input SourceInfo info;
2523 input output ImportTree imports;
2524 protected
2525 String name, imp_name;
2526 Absyn.Path old_path, new_path;
2527 algorithm
2528 () := match imp
2529 case Absyn.Import.NAMED_IMPORT(name = name, path = old_path)
2530 algorithm
2531 3 new_path := convertPath(old_path, rules, ImportTree.new(), info);
2532 3 imports := ImportTree.add(imports, name, ImportData.IMPORT_DATA(old_path, new_path, name, false));
2533 then
2534 ();
2535
2536 case Absyn.Import.QUAL_IMPORT(path = old_path)
2537 algorithm
2538 ✗ new_path := convertPath(old_path, rules, ImportTree.new(), info);
2539 ✗ name := AbsynUtil.pathLastIdent(old_path);
2540 ✗ imp_name := AbsynUtil.pathLastIdent(new_path);
2541 ✗ imports := ImportTree.add(imports, name, ImportData.IMPORT_DATA(old_path, new_path, imp_name, false));
2542 then
2543 ();
2544
2545 case Absyn.Import.GROUP_IMPORT(prefix = old_path)
2546 algorithm
2547 ✗ for group in imp.groups loop
2548 ✗ imports := addGroupImportName(old_path, group, rules, info, imports);
2549 end for;
2550 then
2551 ();
2552
2553 else ();
2554 end match;
2555 end addImportName;
2556
2557 function addGroupImportName
2558 input Absyn.Path prefix;
2559 input Absyn.GroupImport imp;
2560 input ConversionRules rules;
2561 input SourceInfo info;
2562 input output ImportTree imports;
2563 protected
2564 String rename, name, imp_name;
2565 Absyn.Path old_path, new_path;
2566 algorithm
2567 (rename, name) := match imp
2568 case Absyn.GroupImport.GROUP_IMPORT_NAME(name = name) then (name, name);
2569 case Absyn.GroupImport.GROUP_IMPORT_RENAME(rename = rename, name = name) then (rename, name);
2570 end match;
2571
2572 ✗ old_path := AbsynUtil.suffixPath(prefix, name);
2573 ✗ new_path := convertPath(old_path, rules, ImportTree.new(), info);
2574
2575 imp_name := match imp
2576 ✗ case Absyn.GroupImport.GROUP_IMPORT_NAME() then AbsynUtil.pathLastIdent(new_path);
2577 case Absyn.GroupImport.GROUP_IMPORT_RENAME() then rename;
2578 end match;
2579
2580 ✗ imports := ImportTree.add(imports, rename, ImportData.IMPORT_DATA(old_path, new_path, imp_name, false));
2581 end addGroupImportName;
2582
2583 function shadowImportsInParts
2584 "Checks if any of the element names in the given parts shadows an import,
2585 and if so marks the import as shadowed in the lookup tree."
2586 input list<Absyn.ClassPart> parts;
2587 input output ImportTree imports;
2588 algorithm
2589
4/5
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 16 times.
33 for part in parts loop
2590 () := match part
2591 case Absyn.ClassPart.PUBLIC()
2592 algorithm
2593
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 for e in part.contents loop
2594 28 imports := shadowImportsInElementItem(e, imports);
2595 end for;
2596 then
2597 ();
2598
2599 case Absyn.ClassPart.PROTECTED()
2600 algorithm
2601 ✗ for e in part.contents loop
2602 ✗ imports := shadowImportsInElementItem(e, imports);
2603 end for;
2604 then
2605 ();
2606
2607 else ();
2608 end match;
2609 end for;
2610 end shadowImportsInParts;
2611
2612 function shadowImportsInElementItem
2613 input Absyn.ElementItem element;
2614 input output ImportTree imports;
2615 algorithm
2616 () := match element
2617 local
2618 Absyn.ElementSpec spec;
2619
2620 case Absyn.ElementItem.ELEMENTITEM(element = Absyn.Element.ELEMENT(specification = spec))
2621 algorithm
2622 28 imports := shadowImportsInElementSpec(spec, imports);
2623 then
2624 ();
2625
2626 else ();
2627 end match;
2628 end shadowImportsInElementItem;
2629
2630 function shadowImportsInElementSpec
2631 input Absyn.ElementSpec spec;
2632 input output ImportTree imports;
2633 algorithm
2634 () := match spec
2635 local
2636 String name;
2637
2638 case Absyn.ElementSpec.CLASSDEF(class_ = Absyn.Class.CLASS(name = name))
2639 algorithm
2640 7 imports := shadowImport(name, imports);
2641 then
2642 ();
2643
2644 case Absyn.ElementSpec.COMPONENTS()
2645 algorithm
2646
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 for c in spec.components loop
2647 17 imports := shadowImport(AbsynUtil.componentName(c), imports);
2648 end for;
2649 then
2650 ();
2651
2652 else ();
2653 end match;
2654 end shadowImportsInElementSpec;
2655
2656 function shadowImport
2657 "Checks if a name already exists in the import lookup tree, and if so sets
2658 the shadowed attribute of the import to true."
2659 input String name;
2660 input output ImportTree imports;
2661 protected
2662 ImportData imp_data;
2663 algorithm
2664 // Shadowed imports should be extremely rare compared to the number of
2665 // elements in a package, so first just check if it exists even if it means
2666 // having to look it up again if it does.
2667
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 2 times.
24 if not ImportTree.hasKey(imports, name) then
2668 22 return;
2669 end if;
2670
2671 2 imp_data := ImportTree.get(imports, name);
2672 2 imp_data.shadowed := true;
2673 2 imports := ImportTree.update(imports, name, imp_data);
2674 end shadowImport;
2675
2676 function applyImportsToPath
2677 "Fully qualifies the given path if an import that matches the path's first
2678 identifier exists."
2679 input output Absyn.Path path;
2680 input ImportTree imports;
2681 output Option<tuple<Absyn.Path, String>> importPath;
2682 protected
2683 Option<ImportData> imp_data_opt;
2684 ImportData imp_data;
2685 algorithm
2686 imp_data_opt := match path
2687 19 case Absyn.Path.QUALIFIED() then ImportTree.getOpt(imports, path.name);
2688 6 case Absyn.Path.IDENT() then ImportTree.getOpt(imports, path.name);
2689 else NONE(); // Fully qualified names are not imported.
2690 end match;
2691
2692
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 20 times.
25 if isSome(imp_data_opt) then
2693 5 SOME(imp_data) := imp_data_opt;
2694
2695
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if not imp_data.shadowed then
2696 3 importPath := SOME((imp_data.convertedPath, imp_data.importName));
2697 3 path := AbsynUtil.pathReplaceFirst(path, imp_data.originalPath);
2698 else
2699 importPath := NONE();
2700 end if;
2701 else
2702 importPath := NONE();
2703 end if;
2704 end applyImportsToPath;
2705
2706 function stripImportPath
2707 "Tries to remove the import path from a given path if that path was
2708 imported. This is not always possible though, in which case the path is
2709 left as it is. For example:
2710
2711 conversion rules:
2712 Modelica.SIunits -> Modelica.Units.SI
2713 Modelica.SIunits.Conversions.NonSIunits -> Modelica.Units.NonSI
2714
2715 model before conversion:
2716 import SI = Modelica.SIunits;
2717 SI.Time t;
2718 SI.Conversions.NonSIunits.Angle_deg angle;
2719
2720 model after applying imports:
2721 import SI = Modelica.SIunits;
2722 Modelica.SIunits.Time t;
2723 Modelica.SIunits.Conversions.NonSIunits.Angle_deg angle;
2724
2725 model after conversion:
2726 import SI = Modelica.Units.SI;
2727 Modelica.Units.SI.Time t;
2728 Modelica.Units.NonSI.Angle_deg angle;
2729
2730 The import can't be converted in such a way that both of the components'
2731 types can use it, so only the one that matches fully is removed:
2732 import SI = Modelica.Units.SI;
2733 SI.Time t;
2734 Modelica.Units.NonSI.Angle_deg angle;
2735 "
2736 input output Absyn.Path path;
2737 input Option<tuple<Absyn.Path, String>> importPath;
2738 protected
2739 Absyn.Path import_path;
2740 String import_name;
2741 Integer imp_len, path_len;
2742 algorithm
2743
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 3 times.
16 if isNone(importPath) then
2744 // The path was not imported, do nothing.
2745 13 return;
2746 end if;
2747
2748 3 SOME((import_path, import_name)) := importPath;
2749
2750 // Replace the prefix of the path with the import name if the prefix
2751 // is the same as the import path.
2752
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
3 if AbsynUtil.pathPrefixOf(import_path, path) then
2753 1 imp_len := AbsynUtil.pathPartCount(import_path);
2754 1 path_len := AbsynUtil.pathPartCount(path);
2755
2756
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if imp_len == path_len then
2757 ✗ path := Absyn.Path.IDENT(import_name);
2758 else
2759 1 path := Util.foldcallN(AbsynUtil.pathPartCount(import_path), AbsynUtil.pathRest, path);
2760 1 path := AbsynUtil.prefixPath(import_name, path);
2761 end if;
2762 end if;
2763 end stripImportPath;
2764
2765 function addComponentTypesToEnv
2766 "Adds all components in the given list of class parts to the type table in
2767 the environment."
2768 input list<Absyn.ClassPart> parts;
2769 input TypeTable components;
2770 algorithm
2771 16 UnorderedMap.clear(components);
2772
2773
4/5
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 16 times.
33 for part in parts loop
2774 () := match part
2775 case Absyn.ClassPart.PUBLIC()
2776 algorithm
2777
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 for e in part.contents loop
2778 28 addComponentTypesToEnv2(e, components);
2779 end for;
2780 then
2781 ();
2782
2783 case Absyn.ClassPart.PROTECTED()
2784 algorithm
2785 ✗ for e in part.contents loop
2786 ✗ addComponentTypesToEnv2(e, components);
2787 end for;
2788 then
2789 ();
2790
2791 else ();
2792 end match;
2793 end for;
2794 end addComponentTypesToEnv;
2795
2796 function addComponentTypesToEnv2
2797 "Adds all components in the given element item to the type table in the
2798 environment."
2799 input Absyn.ElementItem element;
2800 input TypeTable components;
2801 algorithm
2802 () := match element
2803 local
2804 Absyn.ElementSpec comps;
2805 Absyn.Path ty_path;
2806
2807 case Absyn.ElementItem.ELEMENTITEM(element =
2808 Absyn.Element.ELEMENT(specification = comps as Absyn.ElementSpec.COMPONENTS()))
2809 algorithm
2810 17 ty_path := AbsynUtil.typeSpecPath(comps.typeSpec);
2811
2812
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 for c in comps.components loop
2813 17 UnorderedMap.add(AbsynUtil.componentName(c), ty_path, components);
2814 end for;
2815 then
2816 ();
2817
2818 else ();
2819 end match;
2820 end addComponentTypesToEnv2;
2821
2822 annotation(__OpenModelica_Interface="backend_tools");
2823 end Conversion;
2824