Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.1% 1064 / 0 / 1221
Functions: 100.0% 1 / 0 / 1
Branches: 77.8% 630 / 0 / 810

OMCompiler/Compiler/NFFrontEnd/NFInst.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 NFInst
37 " file: NFInst.mo
38 package: NFInst
39 description: Instantiation
40
41 New instantiation, enable with -d=newInst.
42 "
43
44 import Absyn;
45 import AbsynUtil;
46 import SCode;
47 import DAE;
48
49 import Builtin = NFBuiltin;
50 import Binding = NFBinding;
51 import Component = NFComponent;
52 import NFComponent.ComponentState;
53 import ComponentRef = NFComponentRef;
54 import ConnectBreakTree = NFConnectBreakTree;
55 import Dimension = NFDimension;
56 import Expression = NFExpression;
57 import Class = NFClass;
58 import NFInstNode.InstNode;
59 import NFInstNode;
60 import MutableWeak;
61 import NFInstNode.InstNodeType;
62 import NFModifier.Modifier;
63 import NFModifier.ModifierScope;
64 import Operator = NFOperator;
65 import Equation = NFEquation;
66 import Statement = NFStatement;
67 import Type = NFType;
68 import Subscript = NFSubscript;
69 import Connector = NFConnector;
70 import Connection = NFConnection;
71 import Algorithm = NFAlgorithm;
72 import InstContext = NFInstContext;
73 import Attributes = NFAttributes;
74
75 protected
76 import Config;
77 import Array;
78 import Error;
79 import ErrorExt;
80 import FlagsUtil;
81 import Global;
82 import Flatten = NFFlatten;
83 import Connections = NFConnections;
84 import InstUtil = NFInstUtil;
85 import List;
86 import Lookup = NFLookup;
87 import MetaModelica.Dangerous;
88 import Typing = NFTyping;
89 import ExecStat.{execStat,execStatReset};
90 import SCodeDump;
91 import SCodeUtil;
92 import System;
93 import Call = NFCall;
94 import Absyn.Path;
95 import NFClassTree.ClassTree;
96 import NFSections.Sections;
97 import NFInstNode.CachedData;
98 import NFInstNode.NodeTree;
99 import UnitCheck = NFUnitCheck;
100 import Unit = NFUnit;
101 import NFPrefixes.*;
102 import Prefixes = NFPrefixes;
103 import NFFlatten.FunctionTree;
104 import ConvertDAE = NFConvertDAE;
105 import Scalarize = NFScalarize;
106 import Restriction = NFRestriction;
107 import ComplexType = NFComplexType;
108 import Package = NFPackage;
109 import NFFunction.Function;
110 import FlatModel = NFFlatModel;
111 import ElementSource;
112 import SimplifyModel = NFSimplifyModel;
113 import StateMachineFlatten = NFStateMachineFlatten;
114 import Record = NFRecord;
115 import Variable = NFVariable;
116 import OperatorOverloading = NFOperatorOverloading;
117 import EvalConstants = NFEvalConstants;
118 import VerifyModel = NFVerifyModel;
119 import Structural = NFStructural;
120 import UnorderedMap;
121 import CheckModel = NFCheckModel;
122 import EvalFunction = NFEvalFunction;
123 import MetaModelica.Dangerous.listReverseInPlace;
124
125 public
126
127 uniontype InstSettings
128 record SETTINGS
129 Boolean mergeExtendsSections "Merge sections from extends clauses if true";
130 Boolean resizableArrays "Consider all arrays resizable if true";
131 end SETTINGS;
132
133 function create
134 output InstSettings settings = SETTINGS(
135 mergeExtendsSections = true,
136 resizableArrays = Flags.getConfigBool(Flags.RESIZABLE_ARRAYS)
137 );
138 end create;
139 end InstSettings;
140
141 constant InstSettings DEFAULT_SETTINGS = InstSettings.SETTINGS(
142 mergeExtendsSections = true,
143 resizableArrays = false
144 );
145
146
2/2
✓ Branch 2 taken 28399 times.
✓ Branch 3 taken 28 times.
85253 function Inst_makeTopNode
147 input SCode.Program program;
148 input SCode.Program annotationProgram;
149 output InstNode topNode;
150 external "C" topNode=Inst_makeTopNode(program, annotationProgram);
151 end Inst_makeTopNode;
152
153 function instClassInProgram
154 "Instantiates a class given by its fully qualified path, with the result being
155 a DAE."
156 input Absyn.Path classPath;
157 input SCode.Program program;
158 input SCode.Program annotationProgram;
159 input Boolean relaxedFrontend = false;
160 input Boolean dumpFlat = false;
161 output FlatModel flatModel;
162 output FunctionTree functions;
163 output String flatString "The flat model as a string if dumpFlat = true.";
164 algorithm
165 1637 System.reportProgress(-1, 3) "PHASE_INSTANTIATE";
166
167 try
168 1637 (flatModel, functions, flatString) :=
169 instClassInProgram2(classPath, program, annotationProgram, relaxedFrontend, dumpFlat);
170 else
171 207 System.reportProgress(-1, 0) "PHASE_IDLE";
172 207 fail();
173 end try;
174
175 1430 System.reportProgress(-1, 0) "PHASE_IDLE";
176 end instClassInProgram;
177
178 function instClassInProgram2
179 input Absyn.Path classPath;
180 input SCode.Program program;
181 input SCode.Program annotationProgram;
182 input Boolean relaxedFrontend;
183 input Boolean dumpFlat;
184 output FlatModel flatModel;
185 output FunctionTree functions;
186 output String flatString;
187 protected
188 InstNode top, cls, inst_cls;
189 InstContext.Type context;
190 SCode.Program prog = program;
191 InstSettings settings;
192 algorithm
193 1637 resetGlobalFlags();
194
5/6
✓ Branch 0 taken 1635 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 1567 times.
✓ Branch 4 taken 68 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1567 times.
1637 context := if relaxedFrontend or Flags.getConfigBool(Flags.CHECK_MODEL) or Flags.isSet(Flags.NF_API) then
195 NFInstContext.RELAXED else NFInstContext.NO_CONTEXT;
196
197 // Create a top scope from the given top-level classes.
198 1637 top := makeTopNode(prog, annotationProgram);
199
200 // Look up the class to instantiate.
201 1637 cls := lookupRootClass(classPath, top, context);
202
203 // If the class is a function (allowed with checkModel), do the usual function
204 // handling to check that it's ok and return a dummy model since it won't be
205 // used anyway.
206
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1636 times.
1636 if SCodeUtil.isFunction(InstNode.definition(cls)) then
207 ✗ (flatModel, functions, flatString) := instantiateRootFunction(cls, context);
208 ✗ return;
209 end if;
210
211 // Instantiate the class.
212 1636 inst_cls := instantiateRootClass(cls, context);
213 1579 execStat("NFInst.instantiate(" + AbsynUtil.pathString(classPath) + ")");
214
215 // create the settings from flags
216 1579 settings := InstSettings.create();
217
218 // Instantiate expressions (i.e. anything that can contains crefs, like
219 // bindings, dimensions, etc). This is done as a separate step after
220 // instantiation to make sure that lookup is able to find the correct nodes.
221 1579 Error.checkCancel();
222 1579 instExpressions(inst_cls, context = context, settings = settings);
223 1545 execStat("NFInst.instExpressions");
224
225 // Mark structural parameters.
226 1545 updateImplicitVariability(inst_cls, Flags.isSet(Flags.EVAL_PARAM), context);
227 1545 execStat("NFInst.updateImplicitVariability");
228
229 // Type the class.
230 1545 Error.checkCancel();
231 1545 Typing.typeClass(inst_cls, context);
232
233 // Flatten the model and evaluate constants in it.
234 1454 Error.checkCancel();
235 1454 flatModel := Flatten.flatten(inst_cls, classPath);
236 1444 flatModel := EvalConstants.evaluate(flatModel, context);
237
238 1437 InstUtil.dumpFlatModelDebug("eval", flatModel);
239
240 // Do unit checking
241 1437 flatModel := UnitCheck.checkUnits(flatModel);
242
243 // Apply simplifications to the model.
244
1/2
✓ Branch 1 taken 1437 times.
✗ Branch 2 not taken.
1437 if not Flags.getConfigBool(Flags.NO_SIMPLIFY) then
245 1437 flatModel := SimplifyModel.simplify(flatModel);
246 1435 InstUtil.dumpFlatModelDebug("simplify", flatModel);
247 end if;
248
249 // Flatten state machines to data-flow equations (MLS §17).
250 1435 flatModel := StateMachineFlatten.flatten(flatModel);
251 1435 InstUtil.dumpFlatModelDebug("stateMachineFlatten", flatModel);
252
253 // Collect package constants that couldn't be substituted with their values
254 // (e.g. because they where used with non-constant subscripts), and add them
255 // to the model.
256 1435 flatModel := Package.collectConstants(flatModel);
257
258 // Collect a tree of all functions that are still used in the flat model.
259 1435 functions := Flatten.collectFunctions(flatModel);
260
261 // Dump the flat model to a string if dumpFlat = true and --baseModelicaOptions=scalarize is not set.
262
2/2
✓ Branch 1 taken 1430 times.
✓ Branch 2 taken 5 times.
1435 if not Flags.isConfigFlagSet(Flags.BASE_MODELICA_OPTIONS, "scalarize") then
263
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1403 times.
1430 flatString := if dumpFlat then InstUtil.dumpFlatModel(flatModel, functions) else "";
264 end if;
265
266 1435 InstUtil.printStructuralParameters(flatModel);
267
268 // Scalarize array components in the flat model.
269
2/2
✓ Branch 1 taken 1216 times.
✓ Branch 2 taken 219 times.
1435 if Flags.isSet(Flags.NF_SCALARIZE) then
270 1216 flatModel := Scalarize.scalarize(flatModel);
271 else
272 // Remove empty arrays from variables
273 219 flatModel.variables := List.filterOnFalse(flatModel.variables, Variable.isEmptyArray);
274
4/4
✓ Branch 0 taken 6556 times.
✓ Branch 1 taken 219 times.
✓ Branch 2 taken 6556 times.
✓ Branch 3 taken 219 times.
6994 flatModel.variables := list(Flatten.fillVectorizedVariableBinding(v) for v in flatModel.variables);
275 end if;
276
277 1435 flatModel := InstUtil.replaceEmptyArrays(flatModel);
278 1435 InstUtil.dumpFlatModelDebug("scalarize", flatModel, functions);
279
280 // Dump the flat model to a string if dumpFlat = true and --baseModelicaOptions=scalarize is set.
281
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1430 times.
1435 if Flags.isConfigFlagSet(Flags.BASE_MODELICA_OPTIONS, "scalarize") then
282
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 flatString := if dumpFlat then InstUtil.dumpFlatModel(flatModel, functions) else "";
283 end if;
284
285
2/2
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 1232 times.
1435 if Flags.getConfigBool(Flags.NEW_BACKEND) then
286 // Combine the binaries to multaries. For now only on new backend
287 // since the old frontend and backend do not support it
288 203 flatModel := SimplifyModel.combineBinaries(flatModel);
289 203 execStat("combineBinaries");
290 // try to replace calls with array constructors for the new backend
291
4/4
✓ Branch 6 taken 6432 times.
✓ Branch 7 taken 203 times.
✓ Branch 8 taken 6432 times.
✓ Branch 9 taken 203 times.
6635 flatModel.equations := Equation.mapExpList(flatModel.equations, function Expression.wrapCall(fun = function Call.toArrayConstructor(index_ptr = Pointer.create(1))));
292 flatModel.variables := list(Variable.mapExp(var, function Expression.wrapCall(fun = function Call.toArrayConstructor(index_ptr = Pointer.create(1)))) for var in flatModel.variables);
293 203 execStat("replaceArrayConstructors");
294 end if;
295
296 1435 VerifyModel.verify(flatModel, InstNode.isPartial(inst_cls));
297
298 1430 (flatModel, functions) := InstUtil.expandSlicedCrefs(flatModel, functions);
299
300 1430 flatModel := InstUtil.combineSubscripts(flatModel);
301
302 // propagate hide result attribute
303 // ticket #4346
304
4/4
✓ Branch 0 taken 378211 times.
✓ Branch 1 taken 1430 times.
✓ Branch 2 taken 378211 times.
✓ Branch 3 taken 1430 times.
381071 flatModel.variables := list(Variable.propagateAnnotation("HideResult", false, true, var) for var in flatModel.variables);
305
306 1430 flatModel := FlatModel.removeNonTopLevelDirections(flatModel);
307
308
4/8
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1429 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1429 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1430 if Flags.getConfigString(Flags.OBFUSCATE) == "protected" or
309 Flags.getConfigString(Flags.OBFUSCATE) == "encrypted" then
310 1 flatModel := FlatModel.obfuscate(flatModel);
311 end if;
312
313 //(var_count, eq_count) := CheckModel.checkModel(flatModel);
314 //print(AbsynUtil.pathString(classPath) + " has " + String(var_count) + " variable(s) and " + String(eq_count) + " equation(s).\n");
315
316 1430 clearCaches();
317 end instClassInProgram2;
318
319 function instClassForConnection
320 "Instantiates a class given by its fully qualified path, with the result being
321 a list of all connections."
322 input Absyn.Path classPath;
323 input SCode.Program program;
324 input SCode.Program annotationProgram;
325 output list<list<String>> connList = {};
326 protected
327 Connections conns;
328 InstNode top, cls, inst_cls;
329 InstContext.Type context;
330 algorithm
331 2 resetGlobalFlags();
332
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 context := if Flags.getConfigBool(Flags.CHECK_MODEL) or Flags.isSet(Flags.NF_API) then
333 NFInstContext.RELAXED else NFInstContext.NO_CONTEXT;
334
335 // Create a top scope from the given top-level classes.
336 2 top := makeTopNode(program, annotationProgram);
337
338 // Look up the class to instantiate.
339 2 cls := lookupRootClass(classPath, top, context);
340
341 // Instantiate the class.
342 2 inst_cls := instantiateRootClass(cls, context);
343
344 // Instantiate expressions (i.e. anything that can contains crefs, like
345 // bindings, dimensions, etc). This is done as a separate step after
346 // instantiation to make sure that lookup is able to find the correct nodes.
347 2 instExpressions(inst_cls, context = context, settings = DEFAULT_SETTINGS);
348
349 // Type the class.
350 2 Typing.typeClass(inst_cls, context);
351
352 // Flatten the model and get connections
353 2 conns := Flatten.flattenConnection(inst_cls, classPath);
354 2 connList := Connections.toStringList(conns);
355
356 2 clearCaches();
357 end instClassForConnection;
358
359 function resetGlobalFlags
360 "Resets the global flags that the frontend uses."
361 algorithm
362
2/2
✓ Branch 1 taken 366 times.
✓ Branch 2 taken 3378 times.
3744 if Flags.getConfigBool(Flags.NEW_BACKEND) then
363
1/2
✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
366 if not Flags.isSet(Flags.FORCE_SCALARIZE) then
364 366 FlagsUtil.set(Flags.NF_SCALARIZE, false);
365 end if;
366 366 FlagsUtil.set(Flags.VECTORIZE_BINDINGS, true);
367 end if;
368
369 // gather here all the flags to disable expansion
370 // and scalarization if -d=-nfScalarize is on
371
2/2
✓ Branch 1 taken 385 times.
✓ Branch 2 taken 3359 times.
3744 if not Flags.isSet(Flags.NF_SCALARIZE) then
372 // make sure we don't expand anything
373 385 FlagsUtil.set(Flags.NF_EXPAND_OPERATIONS, false);
374 385 FlagsUtil.set(Flags.NF_EXPAND_FUNC_ARGS, false);
375 end if;
376
377 3744 System.setUsesCardinality(false);
378 3744 System.setHasOverconstrainedConnectors(false);
379 3744 System.setHasStreamConnectors(false);
380 end resetGlobalFlags;
381
382 function clearCaches
383 "Clears global caches used by the instantiation."
384 algorithm
385 6111 EvalFunction.clearLibraryCache();
386 end clearCaches;
387
388 function lookupRootClass
389 "Looks up the class to instantiate and marks it as a root node."
390 input Absyn.Path path;
391 input InstNode topScope;
392 input InstContext.Type context;
393 output InstNode clsNode;
394 protected
395 InstContext.Type next_context;
396 String last;
397 ComplexType cty;
398 NFInstNode.ScopeRef structor_ref;
399 algorithm
400 6066 next_context := InstContext.set(context, NFInstContext.RELAXED);
401
402 6066 ErrorExt.setCheckpoint(getInstanceName());
403 try
404 6066 clsNode := Lookup.lookupClassName(path, topScope, next_context, Absyn.dummyInfo, checkAccessViolations = false);
405 6065 ErrorExt.delCheckpoint(getInstanceName());
406 else
407 // Allow lookup of structor functions in ExternalObject:s (to allow e.g.
408 // checkModel on them). These are stored in the ComplexType of the node
409 // instead of in the class tree like normal elements.
410 try
411 1 last := AbsynUtil.pathLastIdent(path);
412
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1 true := last == "constructor" or last == "destructor";
413 ✗ clsNode := Lookup.lookupName(AbsynUtil.stripLast(path), topScope, next_context, checkAccessViolations = false);
414 ✗ Type.COMPLEX(complexTy = cty) := InstNode.getType(clsNode);
415
416 ✗ if last == "constructor" then
417 ✗ ComplexType.EXTERNAL_OBJECT(constructor = structor_ref) := cty;
418 else
419 ✗ ComplexType.EXTERNAL_OBJECT(destructor = structor_ref) := cty;
420 end if;
421 ✗ clsNode := InstNode.borrow(structor_ref);
422 ✗ ErrorExt.rollBack(getInstanceName());
423 else
424 1 ErrorExt.delCheckpoint(getInstanceName());
425 1 fail();
426 end try;
427 end try;
428
429 6065 clsNode := InstUtil.mergeScalars(clsNode, path, isRootClass = true);
430 6065 checkInstanceRestriction(clsNode, path, context);
431 6064 clsNode := InstNode.makeRootClass(clsNode);
432 end lookupRootClass;
433
434 function instantiateRootClass
435 input output InstNode clsNode;
436 input InstContext.Type context;
437 input Modifier mod = Modifier.NOMOD();
438 algorithm
439 1686 clsNode := instantiate(clsNode, mod, context = context);
440 1634 checkPartialClass(clsNode, context);
441
442 1633 insertGeneratedInners(clsNode, InstNode.topScope(clsNode), context);
443 end instantiateRootClass;
444
445 function instantiateRootFunction
446 input InstNode funcNode;
447 input InstContext.Type context;
448 output FlatModel flatModel;
449 output FunctionTree functions;
450 output String flatString = "";
451 algorithm
452 ✗ Function.instFunctionNode(funcNode, context, InstNode.info(funcNode));
453 ✗ functions := FunctionTree.new();
454
455 ✗ for fn in Function.typeNodeCache(funcNode, context) loop
456 ✗ functions := Flatten.flattenFunction(fn, functions);
457 end for;
458
459 ✗ flatModel := FlatModel.FLAT_MODEL(Absyn.Path.IDENT(InstNode.name(funcNode)), {}, {}, {}, {}, {},
460 ElementSource.createElementSource(InstNode.info(funcNode)));
461 end instantiateRootFunction;
462
463 function instantiate
464 input output InstNode node;
465 input Modifier mod = Modifier.NOMOD();
466 input InstNode parent = InstNode.EMPTY_NODE();
467 input InstContext.Type context;
468 input Boolean instPartial = false "Whether to instantiate a partial class or not.";
469 algorithm
470 47820 node := expand(node, context);
471
472
8/8
✓ Branch 0 taken 23777 times.
✓ Branch 1 taken 24035 times.
✓ Branch 3 taken 59 times.
✓ Branch 4 taken 23718 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 56 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 1 time.
47812 if instPartial or not InstNode.isPartial(node) or
473 InstContext.inRelaxed(context) or InstContext.inRedeclared(context) then
474 47810 node := instClass(node, mod, NFAttributes.DEFAULT_ATTR, true, 0, 0, parent, context);
475 end if;
476 end instantiate;
477
478 function expand
479 input output InstNode node;
480 input InstContext.Type context;
481 algorithm
482 1112307 node := partialInstClass(node);
483 1112304 node := expandClass(node, context);
484 end expand;
485
486 function makeTopNode
487 "Creates an instance node from the given list of top-level classes."
488 input list<SCode.Element> topClasses;
489 input list<SCode.Element> annotationClasses;
490 output InstNode topNode;
491 protected
492 list<SCode.Element> top_classes;
493 SCode.Element cls_elem, ann_package;
494 Class cls;
495 ClassTree elems;
496 InstNodeType node_ty;
497 InstNode ann_node;
498 UnorderedMap<String, InstNode> generated_inners;
499 MutableWeak.Roots roots;
500 algorithm
501 //topNode := Inst_makeTopNode(topClasses, annotationClasses);
502
503 top_classes := topClasses;
504
505
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 3711 times.
3744 if Flags.getConfigBool(Flags.BASE_MODELICA) then
506 top_classes := NFBuiltinFuncs.BASE_MODELICA_POSITIVE_MAX_SIMPLE :: top_classes;
507 end if;
508
509 // Create a fake SCode.Element for the top scope, so we don't have to make the
510 // definition in InstNode an Option only because of this node.
511 3744 cls_elem := SCode.CLASS("<top>", SCode.defaultPrefixes, SCode.NOT_ENCAPSULATED(),
512 SCode.NOT_PARTIAL(), SCode.R_PACKAGE(),
513 SCode.PARTS(top_classes, {}, {}, {}, {}, {}, {}, NONE()),
514 SCode.COMMENT(NONE(), NONE()), Absyn.dummyInfo);
515
516 // Make an InstNode for the top scope, to use as the parent of the top level elements.
517 3744 generated_inners := UnorderedMap.new<InstNode>(stringHashDjb2, stringEq);
518 // The tree about to be built owns its identity cells; see TOP_SCOPE.roots.
519 3744 roots := MutableWeak.newRoots();
520 3744 node_ty := InstNodeType.TOP_SCOPE(InstNode.EMPTY_NODE(), generated_inners, roots);
521 3744 topNode := InstNode.newClass(cls_elem, InstNode.EMPTY_NODE(), node_ty);
522
523 // Create a node for the builtin annotation classes. These should only be
524 // accessible in annotations, so they're stored in a separate scope stored in
525 // the node type for the top scope.
526 3744 ann_package := SCode.CLASS("<annotations>", SCode.defaultPrefixes, SCode.ENCAPSULATED(),
527 SCode.NOT_PARTIAL(), SCode.R_PACKAGE(),
528 SCode.PARTS(annotationClasses, {}, {}, {}, {}, {}, {}, NONE()),
529 SCode.COMMENT(NONE(), NONE()), Absyn.dummyInfo);
530
531 3744 ann_node := InstNode.newClass(ann_package, topNode, InstNodeType.IMPLICIT_SCOPE());
532 3744 expand(ann_node, NFInstContext.NO_CONTEXT);
533 // Mark annotations as builtin.
534 3744 cls := InstNode.getClass(ann_node);
535 3744 elems := Class.classTree(cls);
536 3744 ClassTree.mapClasses(elems, markBuiltinTypeNodes);
537 3744 cls := Class.setClassTree(elems, cls);
538 3744 ann_node := InstNode.updateClass(cls, ann_node);
539
540 // Recreate the node type for the top scope to include the annotation node.
541 // Note that this means that the annotation node will refer to a top scope
542 // without an annotation node, which avoid loops during lookup.
543 3744 node_ty := InstNodeType.TOP_SCOPE(ann_node, generated_inners, roots);
544 3744 topNode := InstNode.setNodeType(node_ty, topNode);
545
546 // Create a new class from the elements, and update the inst node with it.
547 3744 cls := Class.fromSCode(top_classes, false, topNode, NFClass.DEFAULT_PREFIXES);
548
549 // Set the correct InstNodeType for classes with builtin annotation. This
550 // could also be done when creating InstNodes, but only top-level classes
551 // should have this annotation anyway.
552 3744 elems := Class.classTree(cls);
553 3744 ClassTree.mapClasses(elems, markBuiltinTypeNodesByAnnotation);
554
555 // ModelicaBuiltin has a dummy declaration of Clock to make sure no one can
556 // declare another Clock class in the top scope, here we replace it with the
557 // actual Clock node (which can't be defined in regular Modelica).
558 14976 ClassTree.replaceClass(NFBuiltin.CLOCK_NODE, elems);
559
560 3744 cls := Class.setClassTree(elems, cls);
561 3744 topNode := InstNode.updateClass(cls, topNode);
562
563 // Root the top scope: everything below it refers to its enclosing scope
564 // weakly, so nothing else keeps it alive.
565 3744 setGlobalRoot(Global.nfTopScope, {topNode});
566 3744 setGlobalRoot(Global.nbCreatedVars, {});
567 end makeTopNode;
568
569 function markBuiltinTypeNodes
570 input output InstNode node;
571 algorithm
572 172168 node := InstNode.setNodeType(InstNodeType.BUILTIN_CLASS(), node);
573 end markBuiltinTypeNodes;
574
575 function markBuiltinTypeNodesByAnnotation
576 input output InstNode node;
577 algorithm
578
2/2
✓ Branch 2 taken 51336 times.
✓ Branch 3 taken 325730 times.
377066 if SCodeUtil.hasBooleanNamedAnnotationInClass(InstNode.definition(node), "__OpenModelica_builtin") then
579 325730 node := InstNode.setNodeType(InstNodeType.BUILTIN_CLASS(), node);
580 end if;
581 end markBuiltinTypeNodesByAnnotation;
582
583 function partialInstClass
584 input output InstNode node;
585 protected
586 Class c;
587 algorithm
588 () := match InstNode.getClass(node)
589 case Class.NOT_INSTANTIATED()
590 algorithm
591 94424 c := partialInstClass2(InstNode.definition(node), node);
592 94421 node := InstNode.updateClass(c, node);
593 94421 c := Class.initImports(c, node);
594 94421 node := InstNode.updateClass(c, node);
595 then
596 ();
597
598 else ();
599 end match;
600 end partialInstClass;
601
602 function partialInstClass2
603 input SCode.Element definition;
604 input InstNode scope;
605 output Class cls;
606 protected
607 SCode.ClassDef cdef, ce_cdef;
608 Type ty;
609 Class.Prefixes prefs;
610 algorithm
611 94424 Error.assertion(SCodeUtil.elementIsClass(definition), getInstanceName() + " got non-class element", sourceInfo());
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94424 times.
94424 SCode.CLASS(classDef = cdef) := definition;
613 94424 prefs := instClassPrefixes(definition);
614
615 cls := match cdef
616 // A long class definition, add its elements to a new scope.
617 case SCode.PARTS()
618 72355 then Class.fromSCode(cdef.elementLst, false, scope, prefs);
619
620 // A class extends, add its elements to a new scope.
621 case SCode.CLASS_EXTENDS(composition = ce_cdef as SCode.PARTS())
622 algorithm
623 // Give a warning if the class extends is not declared as a redeclare.
624 // This was not clarified until Modelica 3.4, so for now we just treat
625 // all class extends like redeclares and give a warning about it.
626
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3506 times.
3507 if not SCodeUtil.isElementRedeclare(definition) then
627 2 Error.addSourceMessage(Error.CLASS_EXTENDS_MISSING_REDECLARE,
628 {SCodeUtil.elementName(definition)}, SCodeUtil.elementInfo(definition));
629 end if;
630 3507 then
631 Class.fromSCode(ce_cdef.elementLst, true, scope, prefs);
632
633 // An enumeration definition, add the literals to a new scope.
634 case SCode.ENUMERATION()
635 algorithm
636 1179 ty := makeEnumerationType(cdef.enumLst, scope);
637 1179 then
638 Class.fromEnumeration(cdef.enumLst, ty, prefs, scope);
639
640 17383 else Class.PARTIAL_CLASS(NFClassTree.EMPTY, Modifier.NOMOD(), Modifier.NOMOD(), prefs);
641 end match;
642 end partialInstClass2;
643
644 function instClassPrefixes
645 input SCode.Element cls;
646 output Class.Prefixes prefixes;
647 protected
648 SCode.Prefixes prefs;
649 algorithm
650 prefixes := match cls
651 case SCode.CLASS(
652 encapsulatedPrefix = SCode.Encapsulated.NOT_ENCAPSULATED(),
653 partialPrefix = SCode.Partial.NOT_PARTIAL(),
654 prefixes = SCode.Prefixes.PREFIXES(
655 finalPrefix = SCode.Final.NOT_FINAL(),
656 innerOuter = Absyn.InnerOuter.NOT_INNER_OUTER(),
657 replaceablePrefix = SCode.NOT_REPLACEABLE()))
658 then NFClass.DEFAULT_PREFIXES;
659
660 case SCode.CLASS(prefixes = prefs)
661 24550 then Class.Prefixes.PREFIXES(
662 cls.encapsulatedPrefix,
663 cls.partialPrefix,
664 prefs.finalPrefix,
665 prefs.innerOuter,
666 prefs.replaceablePrefix);
667
668 end match;
669 end instClassPrefixes;
670
671 function makeEnumerationType
672 input list<SCode.Enum> literals;
673 input InstNode scope;
674 output Type ty;
675 protected
676 list<String> lits;
677 Absyn.Path path;
678 algorithm
679 1179 path := InstNode.scopePath(scope);
680
4/4
✓ Branch 0 taken 4470 times.
✓ Branch 1 taken 1179 times.
✓ Branch 2 taken 4470 times.
✓ Branch 3 taken 1179 times.
5649 lits := list(e.literal for e in literals);
681 1179 ty := Type.ENUMERATION(path, lits);
682 end makeEnumerationType;
683
684 function expandClass
685 input output InstNode node;
686 input InstContext.Type context;
687 algorithm
688 node := match InstNode.getClass(node)
689 86143 case Class.PARTIAL_CLASS() then expandClass2(node, context);
690 else node;
691 end match;
692 end expandClass;
693
694 function expandClass2
695 input output InstNode node;
696 input InstContext.Type context;
697 protected
698 SCode.Element def = InstNode.definition(node);
699 SCode.ClassDef cdef;
700 SourceInfo info;
701 Option<InstUtil.MergeNameMap> name_map = NONE();
702 algorithm
703
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 86143 times.
✓ Branch 3 taken 70173 times.
✓ Branch 4 taken 1238 times.
✓ Branch 5 taken 14730 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
86143 SCode.CLASS(classDef = cdef, info = info) := def;
704
705 node := match cdef
706 case SCode.PARTS()
707 algorithm
708 70173 (node, name_map) := expandClassParts(def, node, context, info);
709
710
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70151 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 70151 times.
70151 if isSome(name_map) then
711 ✗ InstUtil.mergeScalarsComponentBindings(node, Util.getOption(name_map));
712 end if;
713 then
714 node;
715
716 case SCode.CLASS_EXTENDS()
717 algorithm
718 1238 (node, name_map) := expandClassParts(def, node, context, info);
719
720
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1211 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1211 times.
1211 if isSome(name_map) then
721 ✗ InstUtil.mergeScalarsComponentBindings(node, Util.getOption(name_map));
722 end if;
723 then
724 node;
725
726 // A short class definition, e.g. class A = B.
727 case SCode.DERIVED()
728 then match cdef.typeSpec
729 1502 case Absyn.TypeSpec.TCOMPLEX() then expandClassDerivedComplex(def, cdef, node, info);
730 13228 else expandClassDerived(def, cdef, node, context, info);
731 end match;
732
733 // Overloaded functions are normally handled separately in Function, but we might
734 // get here through e.g. the interactive API. In that case just ignore them.
735 case SCode.OVERLOAD() then node;
736
737 // A partial derivative of a function, function df = der(f, x).
738 // Treat it as a short class definition here,
739 case SCode.PDER()
740 2 then expandClassDerived(def,
741 SCode.ClassDef.DERIVED(Absyn.TypeSpec.TPATH(cdef.functionPath, NONE()),
742 SCode.NOMOD(), SCode.defaultVarAttr),
743 node, context, info);
744
745 else
746 algorithm
747 ✗ Error.terminate(getInstanceName() + " got unknown class:\n" + SCodeDump.unparseElementStr(def), sourceInfo());
748 ✗ then
749 fail();
750
751 end match;
752 end expandClass2;
753
754 function expandClassParts
755 input SCode.Element def;
756 input output InstNode node;
757 input InstContext.Type context;
758 input SourceInfo info;
759 output Option<InstUtil.MergeNameMap> nameMap;
760 protected
761 Class cls;
762 ClassTree cls_tree;
763 Modifier mod, cc_mod;
764 InstNode builtin_ext;
765 Class.Prefixes prefs;
766 Restriction res;
767 InstUtil.MergeNameMap name_map;
768 algorithm
769 71411 cls := InstNode.getClass(node);
770 // Change the class to an empty expanded class, to avoid instantiation loops.
771 71411 cls := Class.initExpandedClass(cls);
772 71411 node := InstNode.updateClass(cls, node);
773
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71411 times.
71411 Class.EXPANDED_CLASS(elements = cls_tree, modifier = mod, ccMod = cc_mod, prefixes = prefs) := cls;
775
776
2/2
✓ Branch 1 taken 42295 times.
✓ Branch 2 taken 29116 times.
71411 if ClassTree.extendsCount(cls_tree) > 0 then
777 42295 name_map := InstUtil.makeMergeNameMap();
778 42295 builtin_ext := ClassTree.mapFoldExtends(cls_tree, function expandExtends(context = context, nameMap = name_map), InstNode.EMPTY_NODE());
779
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42279 times.
42279 nameMap := if UnorderedMap.isEmpty(name_map) then NONE() else SOME(name_map);
780 else
781 builtin_ext := InstNode.EMPTY_NODE();
782 nameMap := NONE();
783 end if;
784
785
4/4
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 71294 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 61 times.
71395 if InstNode.name(builtin_ext) == "ExternalObject" then
786 40 node := expandExternalObject(cls_tree, node);
787 else
788
2/2
✓ Branch 1 taken 438 times.
✓ Branch 2 taken 70917 times.
71355 if not InstNode.isEmpty(builtin_ext) then
789 438 checkBuiltinTypeExtends(builtin_ext, cls_tree, node);
790 end if;
791
792 71353 cls_tree := ClassTree.expand(cls_tree);
793 71323 res := Restriction.fromSCode(SCodeUtil.getClassRestriction(def));
794 71323 cls := Class.EXPANDED_CLASS(cls_tree, mod, cc_mod, prefs, res);
795 71323 node := InstNode.updateClass(cls, node);
796 end if;
797 end expandClassParts;
798
799 function expandExtends
800 input output InstNode ext;
801 input output InstNode builtinExt = InstNode.EMPTY_NODE();
802 input InstContext.Type context;
803 input InstUtil.MergeNameMap nameMap;
804 protected
805 SCode.Element def;
806 Absyn.Path base_path;
807 list<InstNode> base_nodes;
808 InstNode scope, base_node;
809 SCode.Mod smod;
810 SourceInfo info;
811 algorithm
812
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 43752 times.
43778 if InstNode.isEmpty(ext) then
813 26 return;
814 end if;
815
816 43752 def := InstNode.definition(ext);
817
818 () := match def
819 case SCode.Element.EXTENDS(base_path, _, smod, _, info)
820 algorithm
821 // Look up the base class and expand it.
822 42540 scope := InstNode.parent(ext);
823
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42536 times.
42540 base_nodes as (base_node :: _) := Lookup.lookupBaseClassName(base_path, scope, context, info);
824 42536 checkExtendsLoop(base_node, scope, base_path, info);
825 42530 checkReplaceableBaseClass(base_nodes, base_path, info);
826
827
4/4
✓ Branch 1 taken 14119 times.
✓ Branch 2 taken 28405 times.
✓ Branch 4 taken 13546 times.
✓ Branch 5 taken 573 times.
42524 if InstNode.isRootClass(scope) and SCodeUtil.isEmptyMod(smod) then
828 13546 base_node := InstUtil.mergeScalars(base_node, base_path, false, nameMap);
829 end if;
830
831 42524 base_node := expand(base_node, context);
832
833 42524 ext := InstNode.setNodeType(
834 InstNodeType.BASE_CLASS(InstNode.identityCell(scope), def, InstNode.nodeType(base_node)), base_node);
835
836 // If the extended class is a builtin class, like Real or any type derived
837 // from Real, then return it so we can handle it properly in expandClass.
838 // We don't care if builtinExt is already SOME, since that's not legal and
839 // will be caught by expandBuiltinExtends.
840
4/4
✓ Branch 1 taken 42196 times.
✓ Branch 2 taken 328 times.
✓ Branch 5 taken 150 times.
✓ Branch 6 taken 42046 times.
42524 if InstNode.isBuiltin(base_node) or Class.isBuiltin(InstNode.getClass(base_node)) then
841 builtinExt := ext;
842 end if;
843 then
844 ();
845
846 else ();
847 end match;
848 end expandExtends;
849
850 function checkExtendsLoop
851 "Gives an error if a base node is in the process of being expanded itself,
852 since that means we have an extends loop in the model."
853 input InstNode node;
854 input InstNode scope;
855 input Absyn.Path path;
856 input SourceInfo info;
857 protected
858 InstNode parent;
859 algorithm
860 () := match InstNode.getClass(node)
861 // expand begins by changing the class to an EXPANDED_CLASS, but keeps the
862 // class tree. So finding a PARTIAL_TREE here means the class is in the
863 // process of being expanded.
864 case Class.EXPANDED_CLASS(elements = ClassTree.PARTIAL_TREE())
865 algorithm
866 4 Error.addSourceMessage(Error.EXTENDS_LOOP,
867 {AbsynUtil.pathString(path)}, info);
868 2 then
869 fail();
870
871 else
872 algorithm
873 parent := scope;
874
875
2/2
✓ Branch 1 taken 185964 times.
✓ Branch 2 taken 42530 times.
228494 while not InstNode.isTopScope(parent) loop
876
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 185960 times.
185964 if InstNode.refEqual(parent, node) then
877 8 Error.addSourceMessage(Error.EXTENDS_LOOP,
878 {AbsynUtil.pathString(path)}, info);
879 4 fail();
880 end if;
881
882 185960 parent := InstNode.parentScope(parent);
883 end while;
884 then
885 ();
886
887 end match;
888 end checkExtendsLoop;
889
890 function checkReplaceableBaseClass
891 "Checks that all parts of a name used as a base class are transitively
892 non-replaceable."
893 input list<InstNode> baseClasses;
894 input Absyn.Path basePath;
895 input SourceInfo info;
896 protected
897 Integer i = 0;
898 String name;
899 list<InstNode> rest;
900 algorithm
901
2/2
✓ Branch 0 taken 128850 times.
✓ Branch 1 taken 42524 times.
171374 for base in baseClasses loop
902 128850 i := i + 1;
903
904
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 128844 times.
128850 if SCodeUtil.isElementReplaceable(InstNode.definition(base)) then
905 // The path might contain several classes with the same name, so mark the
906 // class in the path string to make it clear which one we mean.
907
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 if listLength(baseClasses) > 1 then
908 rest := baseClasses;
909 name := "";
910
911
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
6 for j in 1:i-1 loop
912 2 name := "." + InstNode.name(listHead(rest)) + name;
913 2 rest := listRest(rest);
914 end for;
915
916 4 name := "<" + InstNode.name(listHead(rest)) + ">" + name;
917 4 rest := listRest(rest);
918
919
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for n in rest loop
920 4 name := InstNode.name(n) + "." + name;
921 end for;
922 else
923 2 name := AbsynUtil.pathString(basePath);
924 end if;
925
926 18 Error.addMultiSourceMessage(Error.REPLACEABLE_BASE_CLASS,
927 {InstNode.name(base), name}, {InstNode.info(base), info});
928 6 fail();
929 end if;
930 end for;
931 end checkReplaceableBaseClass;
932
933 function expandExternalObject
934 input ClassTree clsTree;
935 input output InstNode node;
936 protected
937 ComplexType eo_ty;
938 Class c;
939 algorithm
940 // Construct the ComplexType for the external object.
941 40 eo_ty := makeExternalObjectType(clsTree, node);
942 // Construct the Class for the external object. We use an empty class
943 // tree here, since the constructor and destructor is embedded in the
944 // ComplexType instead. Using an empty class tree makes sure it's not
945 // possible to call the constructor or destructor explicitly.
946 39 c := Class.PARTIAL_BUILTIN(Type.COMPLEX(InstNode.identityCell(node), eo_ty), NFClassTree.EMPTY_FLAT,
947 Modifier.NOMOD(), NFClass.DEFAULT_PREFIXES, Restriction.EXTERNAL_OBJECT());
948 39 node := InstNode.updateClass(c, node);
949 end expandExternalObject;
950
951 function checkBuiltinTypeExtends
952 input InstNode builtinExtends;
953 input ClassTree tree;
954 input InstNode node;
955 algorithm
956 // A class extending from a builtin type may not have other components or baseclasses.
957
3/4
✓ Branch 1 taken 436 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 436 times.
438 if ClassTree.componentCount(tree) > 0 or ClassTree.extendsCount(tree) > 1 then
958 // ***TODO***: Find the invalid element and use its info to make the error
959 // message more accurate.
960 4 Error.addSourceMessage(Error.BUILTIN_EXTENDS_INVALID_ELEMENTS,
961 {InstNode.name(builtinExtends)}, InstNode.info(node));
962 2 fail();
963 end if;
964 end checkBuiltinTypeExtends;
965
966 function makeExternalObjectType
967 "Constructs a ComplexType for an external object, and also checks that the
968 external object declaration is valid."
969 input ClassTree tree;
970 input InstNode node;
971 output ComplexType ty;
972 protected
973 Absyn.Path base_path;
974 InstNode constructor = InstNode.EMPTY_NODE(), destructor = InstNode.EMPTY_NODE();
975 algorithm
976 ty := match tree
977 case ClassTree.PARTIAL_TREE()
978 algorithm
979 // An external object may not contain components.
980
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 40 times.
120 for comp in tree.components loop
981
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 if InstNode.isComponent(comp) then
982 ✗ Error.addSourceMessage(Error.EXTERNAL_OBJECT_INVALID_ELEMENT,
983 {InstNode.name(node), InstNode.name(comp)}, InstNode.info(comp));
984 ✗ fail();
985 end if;
986 end for;
987
988 // An external object may not contain extends other than the ExternalObject one.
989
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
80 if arrayLength(tree.exts) > 1 then
990 ✗ for ext in tree.exts loop
991 ✗ if InstNode.name(ext) <> "ExternalObject" and
992 ClassTree.recursiveElementCount(Class.classTree(InstNode.getClass(ext))) <> 0 then
993 ✗ InstNode.CLASS_NODE(nodeType = InstNodeType.BASE_CLASS(definition =
994 SCode.EXTENDS(baseClassPath = base_path))) := ext;
995 ✗ Error.addSourceMessage(Error.EXTERNAL_OBJECT_INVALID_ELEMENT,
996 {InstNode.name(node), "extends " + AbsynUtil.pathString(base_path)}, InstNode.info(ext));
997 ✗ fail();
998 end if;
999 end for;
1000 end if;
1001
1002 // An external object must have exactly two non-replaceable functions
1003 // called constructor and destructor.
1004
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✓ Branch 3 taken 79 times.
✓ Branch 4 taken 39 times.
158 for cls in tree.classes loop
1005 () := match InstNode.name(cls)
1006 case "constructor" guard SCodeUtil.isFunction(InstNode.definition(cls))
1007 algorithm
1008 39 checkElementNotReplaceable(cls);
1009 constructor := cls;
1010 then
1011 ();
1012
1013 case "destructor" guard SCodeUtil.isFunction(InstNode.definition(cls))
1014 algorithm
1015 39 checkElementNotReplaceable(cls);
1016 destructor := cls;
1017 then
1018 ();
1019
1020 else
1021 algorithm
1022 // Found some other element => error.
1023 3 Error.addSourceMessage(Error.EXTERNAL_OBJECT_INVALID_ELEMENT,
1024 {InstNode.name(node), InstNode.name(cls)}, InstNode.info(cls));
1025 1 then
1026 fail();
1027
1028 end match;
1029 end for;
1030
1031
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if InstNode.isEmpty(constructor) then
1032 // The constructor is missing.
1033 ✗ Error.addSourceMessage(Error.EXTERNAL_OBJECT_MISSING_STRUCTOR,
1034 {InstNode.name(node), "constructor"}, InstNode.info(node));
1035 ✗ fail();
1036 end if;
1037
1038
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if InstNode.isEmpty(destructor) then
1039 // The destructor is missing.
1040 ✗ Error.addSourceMessage(Error.EXTERNAL_OBJECT_MISSING_STRUCTOR,
1041 {InstNode.name(node), "destructor"}, InstNode.info(node));
1042 ✗ fail();
1043 end if;
1044 39 then
1045 ComplexType.EXTERNAL_OBJECT(InstNode.scopeRef(constructor), InstNode.scopeRef(destructor));
1046
1047 end match;
1048 end makeExternalObjectType;
1049
1050 function checkElementNotReplaceable
1051 input InstNode node;
1052 algorithm
1053
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
78 if SCodeUtil.isElementReplaceable(InstNode.definition(node)) then
1054 ✗ Error.addSourceMessage(Error.ELEMENT_REPLACEABLE_NOT_ALLOWED,
1055 {InstNode.name(node)}, InstNode.info(node));
1056 ✗ fail();
1057 end if;
1058 end checkElementNotReplaceable;
1059
1060 function expandClassDerived
1061 input SCode.Element element;
1062 input SCode.ClassDef definition;
1063 input output InstNode node;
1064 input InstContext.Type context;
1065 input SourceInfo info;
1066 protected
1067 Absyn.TypeSpec ty;
1068 InstNode ext_node;
1069 Class cls;
1070 Class.Prefixes prefs;
1071 SCode.Attributes sattrs;
1072 Attributes attrs;
1073 list<Dimension> dims;
1074 Modifier mod, cc_mod;
1075 Restriction res;
1076 algorithm
1077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13230 times.
13230 SCode.DERIVED(typeSpec = ty, attributes = sattrs) := definition;
1078
1079 // Look up the class that's being derived from and expand it.
1080
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 13230 times.
13230 ext_node :: _ := Lookup.lookupBaseClassName(AbsynUtil.typeSpecPath(ty), InstNode.parent(node), context, info);
1081
1082 // Check that the class isn't extending itself, i.e. class A = A.
1083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13230 times.
13230 if referenceEq(ext_node, node) then
1084 ✗ Error.addSourceMessage(Error.RECURSIVE_SHORT_CLASS_DEFINITION,
1085 {InstNode.name(node), Dump.unparseTypeSpec(ty)}, info);
1086 ✗ fail();
1087 end if;
1088
1089 13230 ext_node := expand(ext_node, context);
1090 13230 ext_node := InstNode.clone(ext_node);
1091
1092 // Fetch the needed information from the class definition and construct a EXPANDED_DERIVED.
1093 13230 cls := InstNode.getClass(node);
1094 13230 prefs := Class.getPrefixes(cls);
1095
1096 // A short class definition deriving from a partial class is itself partial.
1097
3/4
✓ Branch 1 taken 13230 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 13192 times.
13230 if not Class.Prefixes.isPartial(prefs) and InstNode.isPartial(ext_node) then
1098 38 prefs.partialPrefix := SCode.Partial.PARTIAL();
1099 end if;
1100
1101 13230 attrs := Attributes.fromDerivedSCode(sattrs);
1102
4/4
✓ Branch 1 taken 475 times.
✓ Branch 2 taken 13230 times.
✓ Branch 3 taken 475 times.
✓ Branch 4 taken 13230 times.
13705 dims := list(Dimension.RAW_DIM(d, InstNode.scopeRef(InstNode.parent(node))) for d in AbsynUtil.typeSpecDimensions(ty));
1103 13230 mod := Class.getModifier(cls);
1104 13230 cc_mod := Class.getCCModifier(cls);
1105
1106 13230 res := Restriction.fromSCode(SCodeUtil.getClassRestriction(element));
1107 13230 cls := Class.EXPANDED_DERIVED(ext_node, mod, cc_mod, listArray(dims), prefs, attrs, res);
1108 13230 node := InstNode.updateClass(cls, node);
1109 end expandClassDerived;
1110
1111 function expandClassDerivedComplex
1112 input SCode.Element element;
1113 input SCode.ClassDef definition;
1114 input output InstNode node;
1115 input SourceInfo info;
1116 protected
1117 Absyn.Path ty_path;
1118 Class.Prefixes prefs;
1119 Type ty;
1120 Restriction res;
1121 Class cls;
1122 algorithm
1123
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1502 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1502 times.
1502 SCode.DERIVED(typeSpec = Absyn.TypeSpec.TCOMPLEX(path = ty_path)) := definition;
1124
1125 ty := match ty_path
1126 1502 case Absyn.IDENT("polymorphic") then Type.POLYMORPHIC(InstNode.name(node));
1127 else
1128 algorithm
1129 ✗ Error.addSourceMessage(Error.LOOKUP_BASECLASS_ERROR,
1130 {AbsynUtil.pathString(ty_path), InstNode.scopeName(node)}, info);
1131 ✗ then
1132 fail();
1133 end match;
1134
1135 1502 cls := InstNode.getClass(node);
1136 1502 prefs := Class.getPrefixes(cls);
1137 1502 res := Restriction.fromSCode(SCodeUtil.getClassRestriction(element));
1138 1502 cls := Class.PARTIAL_BUILTIN(ty, NFClassTree.EMPTY, Modifier.NOMOD(), prefs, res);
1139 1502 node := InstNode.updateClass(cls, node);
1140 end expandClassDerivedComplex;
1141
1142 function instClass
1143 input output InstNode node;
1144 input Modifier modifier;
1145 input output Attributes attributes = NFAttributes.DEFAULT_ATTR;
1146 input Boolean useBinding;
1147 input Integer instLevel;
1148 input Integer typeConfidence "confidence of the class's own modifiers, see classConfidence";
1149 input InstNode parent = InstNode.EMPTY_NODE();
1150 input InstContext.Type context;
1151 protected
1152 Class cls;
1153 Modifier outer_mod;
1154 algorithm
1155 1698376 Error.checkCancel();
1156 1698376 cls := InstNode.getClass(node);
1157 1698376 outer_mod := Class.getModifier(cls);
1158
1159 // Give an error for modifiers such as (A = B), i.e. attempting to replace a
1160 // class without using redeclare.
1161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1698376 times.
1698376 if Modifier.hasBinding(outer_mod) then
1162 ✗ Error.addSourceMessage(Error.MISSING_REDECLARE_IN_CLASS_MOD,
1163 {InstNode.name(node)}, Binding.getInfo(Modifier.binding(outer_mod)));
1164 ✗ fail();
1165 end if;
1166
1167 1698376 (attributes, node) := instClassDef(cls, modifier, attributes, useBinding, node, parent, instLevel, typeConfidence, context);
1168 end instClass;
1169
1170 function instClassDef
1171 input Class cls;
1172 input Modifier outerMod;
1173 input output Attributes attributes;
1174 input Boolean useBinding;
1175 input output InstNode node;
1176 input InstNode parent;
1177 input Integer instLevel;
1178 input Integer typeConfidence;
1179 input InstContext.Type context;
1180 protected
1181 InstNode par, base_node;
1182 Class inst_cls;
1183 ClassTree cls_tree;
1184 Modifier mod, outer_mod;
1185 Restriction res;
1186 Type ty;
1187 Attributes attrs;
1188 algorithm
1189 () := match cls
1190 case Class.EXPANDED_CLASS(restriction = res)
1191 algorithm
1192 // Skip instantiating the class tree if the class is a base class,
1193 // it has (hopefully) already been instantiated in that case.
1194
2/2
✓ Branch 1 taken 28623 times.
✓ Branch 2 taken 138684 times.
167307 if InstNode.isBaseClass(node) then
1195 28623 par := parent;
1196 else
1197 138684 (node, par) := ClassTree.instantiate(node, parent);
1198 end if;
1199
1200 167300 updateComponentType(parent, node);
1201 167300 attributes := Attributes.updateClassConnectorType(res, attributes);
1202
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 167300 times.
167300 inst_cls as Class.EXPANDED_CLASS(elements = cls_tree) := InstNode.getClass(node);
1203
1204 // Fetch modification on the class definition (for class extends).
1205 167300 mod := instElementModifier(InstNode.definition(node), node, par, typeConfidence);
1206 167300 mod := Modifier.propagate(mod, node, par);
1207 167300 mod := Modifier.merge(mod, cls.ccMod);
1208 // Merge with any outer modifications.
1209 167300 outer_mod := Modifier.propagate(cls.modifier, node, par);
1210 167300 mod := Modifier.merge(outer_mod, mod);
1211 167300 mod := markTypeModifier(mod, res, typeConfidence);
1212 167300 mod := Modifier.merge(outerMod, mod);
1213
1214 // Apply the modifiers of extends nodes.
1215 167300 ClassTree.mapExtends(cls_tree,
1216 function modifyExtends(scope = par, context = context, instLevel = instLevel));
1217
1218 // Propagate the visibility of extends to their elements.
1219 167296 ClassTree.mapExtends(cls_tree,
1220 function applyExtendsVisibility(visibility = ExtendsVisibility.PUBLIC));
1221
1222 // Apply the modifiers of this scope.
1223 167296 applyModifier(mod, cls_tree, node, context);
1224
1225 // Apply element redeclares.
1226 167287 ClassTree.mapRedeclareChains(cls_tree,
1227 function redeclareElements(instLevel = instLevel, context = context));
1228
1229 // Redeclare classes with redeclare modifiers. Redeclared components could
1230 // also be handled here, but since each component is only instantiated once
1231 // it's more efficient to apply the redeclare when instantiating them instead.
1232 167284 redeclareClasses(cls_tree, par, context, instLevel);
1233
1234 // Instantiate the extends nodes.
1235
2/2
✓ Branch 0 taken 35261 times.
✓ Branch 1 taken 132022 times.
202544 ClassTree.mapExtends(cls_tree,
1236 function instExtends(attributes = attributes, useBinding = useBinding,
1237 instLevel = instLevel, context = context));
1238
1239 // Instantiate local components.
1240 167279 ClassTree.applyLocalComponents(cls_tree,
1241 function instComponent(attributes = attributes, innerMod = Modifier.NOMOD(),
1242 useBinding = useBinding, instLevel = instLevel + 1, context = context,
1243 originalAttr = NONE(), propagatedSubs = {}));
1244
1245 // Remove duplicate elements.
1246 167039 cls_tree := ClassTree.replaceDuplicates(cls_tree);
1247 167039 ClassTree.checkDuplicates(cls_tree);
1248 167039 InstNode.updateClass(Class.setClassTree(cls_tree, inst_cls), node);
1249 167039 Restriction.checkClass(node, res, context);
1250 then
1251 ();
1252
1253 case Class.EXPANDED_DERIVED()
1254 algorithm
1255 693489 (node, par) := ClassTree.instantiate(node, parent);
1256 693489 node := InstNode.setNodeType(InstNodeType.DERIVED_CLASS(InstNode.nodeType(node)), node);
1257
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 693489 times.
693489 Class.EXPANDED_DERIVED(baseClass = base_node) := InstNode.getClass(node);
1258
1259 // Merge outer modifiers and attributes.
1260 693489 mod := instElementModifier(InstNode.definition(node), node, InstNode.rootParent(node), typeConfidence);
1261 693489 mod := Modifier.propagate(mod, node, par);
1262 693489 mod := Modifier.merge(mod, cls.ccMod);
1263 693489 outer_mod := Modifier.propagate(cls.modifier, node, par);
1264 693489 mod := Modifier.merge(outer_mod, mod);
1265 693489 mod := markTypeModifier(mod, cls.restriction, typeConfidence);
1266 693489 mod := Modifier.merge(outerMod, mod);
1267 693489 attrs := Attributes.updateClassConnectorType(cls.restriction, cls.attributes);
1268 693489 attributes := Attributes.mergeDerivedAttributes(attrs, attributes, parent);
1269
1270 // Instantiate the base class and update the nodes.
1271 693488 (base_node, attributes) := instClass(base_node, mod, attributes, useBinding, instLevel, typeConfidence, par, context);
1272 693488 cls.baseClass := base_node;
1273 693488 cls.attributes := attributes;
1274 693488 cls.dims := arrayCopy(cls.dims);
1275
1276 // Update the parent's type with the new class instance.
1277 693488 node := InstNode.updateClass(cls, node);
1278 693488 updateComponentType(parent, node);
1279 then
1280 ();
1281
1282 case Class.PARTIAL_BUILTIN(restriction = Restriction.EXTERNAL_OBJECT())
1283 algorithm
1284 349 inst_cls := Class.INSTANCED_BUILTIN(cls.ty, cls.elements, cls.restriction);
1285
1286 // External objects have nothing to modify, but call applyModifier
1287 // so we get an error message if there is a modifier anyway.
1288 349 applyModifier(outerMod, cls.elements, node, context);
1289 348 node := InstNode.replaceClass(inst_cls, node);
1290 348 updateComponentType(parent, node);
1291 348 instExternalObjectStructors(cls.ty, parent, context);
1292 then
1293 ();
1294
1295 case Class.PARTIAL_BUILTIN(ty = ty, restriction = res)
1296 algorithm
1297 836915 (node, par) := ClassTree.instantiate(node, parent);
1298 836915 updateComponentType(parent, node);
1299 836915 cls_tree := Class.classTree(InstNode.getClass(node));
1300
1301 836915 mod := instElementModifier(InstNode.definition(node), node, InstNode.parent(node), typeConfidence);
1302 836915 mod := Modifier.merge(cls.modifier, mod);
1303 836915 mod := markTypeModifier(mod, Restriction.TYPE(), typeConfidence);
1304 836915 mod := Modifier.merge(outerMod, mod);
1305 836915 applyModifier(mod, cls_tree, node, context);
1306
1307 836915 inst_cls := Class.INSTANCED_BUILTIN(ty, cls_tree, res);
1308 836915 node := InstNode.updateClass(inst_cls, node);
1309 then
1310 ();
1311
1312 // If a class has an instance of a encapsulating class, then the encapsulating
1313 // class will have been fully instantiated to allow lookup in it. This is a
1314 // rather uncommon case hopefully, so in that case just reinstantiate the class.
1315 case Class.INSTANCED_CLASS()
1316 algorithm
1317 316 node := InstNode.replaceClass(Class.NOT_INSTANTIATED(), node);
1318 316 node := InstNode.reidentify(node);
1319 316 node := InstNode.setNodeType(InstNodeType.NORMAL_CLASS(), node);
1320 316 node := expand(node, context);
1321 316 node := instClass(node, outerMod, attributes, useBinding, instLevel, typeConfidence, parent, context);
1322 316 updateComponentType(parent, node);
1323 then
1324 ();
1325
1326 else
1327 algorithm
1328 ✗ Error.terminate(getInstanceName() + " got unknown class.", sourceInfo());
1329 then
1330 ();
1331
1332 end match;
1333 end instClassDef;
1334
1335 function updateComponentType
1336 "Sets the class instance of a component node."
1337 input output InstNode component;
1338 input InstNode cls;
1339 algorithm
1340
2/2
✓ Branch 1 taken 49462 times.
✓ Branch 2 taken 1648905 times.
1698367 if InstNode.isComponent(component) then
1341 1648905 component := InstNode.componentApply(component, Component.setClassInstance, cls);
1342 end if;
1343 end updateComponentType;
1344
1345 function instExternalObjectStructors
1346 "Instantiates the constructor and destructor for an ExternalObject class."
1347 input Type ty;
1348 input InstNode parent;
1349 input InstContext.Type context;
1350 protected
1351 InstNode constructor, destructor, par;
1352 NFInstNode.ScopeRef con_ref, de_ref;
1353 SourceInfo info;
1354 algorithm
1355 // The constructor and destructor have function parameters that are instances
1356 // of the external object class, and we instantiate the structors when we
1357 // instantiate such instances. To break that loop we check that we're not
1358 // inside the external object class before instantiating the structors.
1359 348 par := InstNode.parent(InstNode.parent(parent));
1360
1361
4/4
✓ Branch 1 taken 327 times.
✓ Branch 2 taken 21 times.
✓ Branch 5 taken 70 times.
✓ Branch 6 taken 257 times.
348 if not (InstNode.isClass(par) and Class.isExternalObject(InstNode.getClass(par))) then
1362
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 278 times.
278 Type.COMPLEX(complexTy = ComplexType.EXTERNAL_OBJECT(con_ref, de_ref)) := ty;
1363 278 constructor := InstNode.borrow(con_ref);
1364 278 destructor := InstNode.borrow(de_ref);
1365 278 info := InstNode.info(parent);
1366 278 Function.instFunctionNode(constructor, context, info);
1367 278 Function.instFunctionNode(destructor, context, info);
1368 end if;
1369 end instExternalObjectStructors;
1370
1371 function instPackage
1372 "This function instantiates a package given a package node. If the package has
1373 already been instantiated, then the cached instance from the node is
1374 returned. Otherwise the node is instantiated, the instance is added to the
1375 node's cache, and the instantiated node is returned."
1376 input output InstNode node;
1377 input InstContext.Type context;
1378 protected
1379 CachedData cache;
1380 InstNode inst;
1381 import NFInstNode.PackageCacheState;
1382 PackageCacheState state;
1383 Option<InstNode> alias;
1384 algorithm
1385 1083977 cache := InstNode.getPackageCache(node);
1386
1387 // Check which state the cached package is in, if any.
1388 (inst, state) := match cache
1389
2/2
✓ Branch 1 taken 1047317 times.
✓ Branch 2 taken 16357 times.
1063674 case CachedData.PACKAGE() then (InstNode.fromHandle(cache.instance), cache.state);
1390 else (node, PackageCacheState.NOT_INITIALIZED);
1391 end match;
1392
1393 // If the package is already fully instantiated then we don't need to do anything.
1394
2/2
✓ Branch 0 taken 1047317 times.
✓ Branch 1 taken 16357 times.
1063674 if state == PackageCacheState.INSTANTIATED then
1395 node := inst;
1396 1047317 return;
1397 end if;
1398
1399 // If we're currently trying to instantiate this package then return it
1400 // unchanged to avoid an instantiation loop.
1401
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 36651 times.
36660 if state == PackageCacheState.PROCESSING then
1402 node := inst;
1403 9 return;
1404 end if;
1405
1406
2/2
✓ Branch 0 taken 20303 times.
✓ Branch 1 taken 16348 times.
36651 if state == PackageCacheState.NOT_INITIALIZED then
1407 20303 alias := packageAlias(node, context);
1408
1409
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20303 times.
✓ Branch 2 taken 1033 times.
✓ Branch 3 taken 19270 times.
20303 if isSome(alias) then
1410 1033 SOME(inst) := alias;
1411 1033 InstNode.setPackageCache(node, inst, PackageCacheState.INSTANTIATED);
1412 node := inst;
1413 1033 return;
1414 end if;
1415 end if;
1416
1417 // Otherwise we need to at least partially instantiate the package.
1418
2/2
✓ Branch 0 taken 19270 times.
✓ Branch 1 taken 16348 times.
35618 if state < PackageCacheState.PARTIALLY_INSTANTIATED then
1419 19270 InstNode.setPackageCache(node, node, PackageCacheState.PROCESSING);
1420 19270 inst := instantiate(node, context = context);
1421 19261 InstNode.setPackageCache(node, inst, PackageCacheState.PARTIALLY_INSTANTIATED);
1422 end if;
1423
1424 // If the package isn't partial we also instantiate expressions in it,
1425 // except when doing lookup for API functions that only care about looking up classes.
1426
7/8
✓ Branch 0 taken 35609 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 16841 times.
✓ Branch 4 taken 18768 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 16831 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 3 times.
35609 if state < PackageCacheState.INSTANTIATED and not InstContext.inFastLookup(context) and
1427 (not InstNode.isPartial(inst) or InstContext.inRelaxed(context)) then
1428 16838 InstNode.setPackageCache(node, inst, PackageCacheState.INSTANTIATED);
1429 16838 instExpressions(inst, context = context, settings = DEFAULT_SETTINGS);
1430 end if;
1431
1432 node := inst;
1433 end instPackage;
1434
1435 function packageAlias
1436 "Returns the instance of the aliased package if the given node is a plain
1437 alias for another package, i.e. 'package P = A.B' without modifications of
1438 its own, which includes the common 'redeclare package Medium = A.B'. Such an
1439 alias contains exactly what A.B contains, so A.B's shared instance can be
1440 used instead of instantiating a copy of it per alias."
1441 input InstNode node;
1442 input InstContext.Type context;
1443 output Option<InstNode> aliasInst;
1444 protected
1445 Class cls;
1446 Absyn.Path path;
1447 InstNode base;
1448 algorithm
1449 aliasInst := match (InstNode.definition(node), InstNode.getClass(node))
1450 case (SCode.CLASS(restriction = SCode.Restriction.R_PACKAGE(),
1451 partialPrefix = SCode.Partial.NOT_PARTIAL(),
1452 classDef = SCode.ClassDef.DERIVED(
1453 typeSpec = Absyn.TypeSpec.TPATH(path = path, arrayDim = NONE()),
1454 modifications = SCode.Mod.NOMOD())),
1455 cls as Class.PARTIAL_CLASS())
1456 guard Modifier.isEmpty(cls.modifier) and Modifier.isEmpty(cls.ccMod)
1457 algorithm
1458
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1033 times.
1033 base :: _ := Lookup.lookupBaseClassName(path, InstNode.parent(node), context, InstNode.info(node));
1459
2/4
✓ Branch 1 taken 1033 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1033 times.
✗ Branch 4 not taken.
1033 then
1460 if isAliasablePackage(base) and not referenceEq(base, node) then
1461 SOME(instPackage(base, context)) else NONE();
1462
1463 else NONE();
1464 end match;
1465 end packageAlias;
1466
1467 function isAliasablePackage
1468 input InstNode node;
1469 output Boolean aliasable;
1470 algorithm
1471 aliasable := match node
1472 case InstNode.CLASS_NODE(definition = SCode.CLASS(
1473 restriction = SCode.Restriction.R_PACKAGE(),
1474 partialPrefix = SCode.Partial.NOT_PARTIAL()))
1475 then true;
1476 else false;
1477 end match;
1478 end isAliasablePackage;
1479
1480 function modifyExtends
1481 input output InstNode extendsNode;
1482 input InstNode scope;
1483 input InstContext.Type context;
1484 input Integer instLevel;
1485 protected
1486 SCode.Element elem;
1487 Modifier ext_mod;
1488 InstNode ext_node;
1489 SourceInfo info;
1490 Class cls;
1491 ClassTree cls_tree;
1492 algorithm
1493 157259 cls := InstNode.getClass(extendsNode);
1494 157259 cls_tree := Class.classTree(cls);
1495
1496 // Create a modifier from the extends.
1497
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 157259 times.
157259 InstNodeType.BASE_CLASS(definition = elem) := InstNode.nodeType(extendsNode);
1498 157259 ext_mod := Modifier.fromElement(elem, scope, instLevel);
1499 157258 ext_mod := Modifier.merge(InstNode.getModifier(extendsNode), ext_mod);
1500
1501
2/2
✓ Branch 1 taken 130334 times.
✓ Branch 2 taken 26924 times.
157258 if not Class.isBuiltin(cls) then
1502 130334 ClassTree.mapExtends(cls_tree,
1503 function modifyExtends(scope = extendsNode, context = context, instLevel = instLevel));
1504
1505 () := match elem
1506 case SCode.EXTENDS()
1507 algorithm
1508 // TODO: Lookup the base class and merge its modifier.
1509
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 126994 times.
126994 ext_node :: _ := Lookup.lookupBaseClassName(elem.baseClassPath, scope, context, elem.info);
1510
1511 // Finding a different element than before expanding extends
1512 // (probably an inherited element) is an error.
1513
3/4
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 126993 times.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
126994 if not referenceEq(InstNode.definition(extendsNode), InstNode.definition(ext_node)) and
1514 not Flags.isSet(Flags.MERGE_COMPONENTS) then
1515 4 Error.addMultiSourceMessage(Error.FOUND_OTHER_BASECLASS,
1516 {AbsynUtil.pathString(elem.baseClassPath)},
1517 {InstNode.info(extendsNode), InstNode.info(ext_node)});
1518 1 fail();
1519 end if;
1520 then
1521 ();
1522
1523 // Class extends?
1524 case SCode.CLASS()
1525 then ();
1526 end match;
1527 end if;
1528
1529 157255 applyModifier(ext_mod, cls_tree, extendsNode, context);
1530 end modifyExtends;
1531
1532 type ExtendsVisibility = enumeration(PUBLIC, DERIVED_PROTECTED, PROTECTED);
1533
1534 function applyExtendsVisibility
1535 input output InstNode node;
1536 input ExtendsVisibility visibility;
1537 protected
1538 Class cls;
1539 ClassTree cls_tree;
1540 ExtendsVisibility vis = visibility;
1541 algorithm
1542 159441 cls := InstNode.getClass(node);
1543
1544 () := match cls
1545 case Class.EXPANDED_CLASS(elements = cls_tree as ClassTree.INSTANTIATED_TREE())
1546 algorithm
1547
6/6
✓ Branch 0 taken 130327 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 130325 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 130325 times.
130328 if vis == ExtendsVisibility.PUBLIC and InstNode.isProtectedBaseClass(node) or
1548 vis == ExtendsVisibility.DERIVED_PROTECTED then
1549 vis := ExtendsVisibility.PROTECTED;
1550 end if;
1551
1552 // Protect components and classes if the extends is protected, except
1553 // if they've already been protected by an extends higher up.
1554
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 130325 times.
130328 if vis == ExtendsVisibility.PROTECTED and visibility <> ExtendsVisibility.PROTECTED then
1555
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 3 times.
7 for c in cls_tree.classes loop
1556 1 Mutable.update(c, InstNode.protectClass(Mutable.access(c)));
1557 end for;
1558
1559
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
8 for c in cls_tree.components loop
1560 2 Mutable.update(c, InstNode.protectComponent(Mutable.access(c)));
1561 end for;
1562 end if;
1563
1564 130328 ClassTree.mapExtends(cls_tree, function applyExtendsVisibility(visibility = vis));
1565 then
1566 ();
1567
1568 case Class.EXPANDED_DERIVED()
1569 algorithm
1570
3/4
✓ Branch 0 taken 2189 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2188 times.
2189 if vis == ExtendsVisibility.PUBLIC and InstNode.isProtectedBaseClass(node) then
1571 vis := ExtendsVisibility.DERIVED_PROTECTED;
1572 end if;
1573
1574 2189 cls.baseClass := applyExtendsVisibility(cls.baseClass, vis);
1575 2189 node := InstNode.updateClass(cls, node);
1576 then
1577 ();
1578
1579 else ();
1580 end match;
1581 end applyExtendsVisibility;
1582
1583 function instExtends
1584 input output InstNode node;
1585 input Attributes attributes;
1586 input Boolean useBinding;
1587 input Integer instLevel;
1588 input InstContext.Type context;
1589 protected
1590 Class cls, inst_cls;
1591 ClassTree cls_tree;
1592 algorithm
1593 159431 cls := InstNode.getClass(node);
1594
1595 () := match cls
1596 case Class.EXPANDED_CLASS(elements = cls_tree as ClassTree.INSTANTIATED_TREE())
1597 algorithm
1598
2/2
✓ Branch 0 taken 9237 times.
✓ Branch 1 taken 121081 times.
139555 ClassTree.mapExtends(cls_tree,
1599 function instExtends(attributes = attributes, useBinding = useBinding,
1600 instLevel = instLevel, context = context));
1601
1602 130318 ClassTree.applyLocalComponents(cls_tree,
1603 function instComponent(attributes = attributes, innerMod = Modifier.NOMOD(),
1604 useBinding = useBinding, instLevel = instLevel, context = context,
1605 originalAttr = NONE(), propagatedSubs = {}));
1606 then
1607 ();
1608
1609 case Class.EXPANDED_DERIVED()
1610 algorithm
1611 2189 cls.baseClass := instExtends(cls.baseClass, attributes, useBinding, instLevel, context);
1612 2189 node := InstNode.updateClass(cls, node);
1613 then
1614 ();
1615
1616 case Class.PARTIAL_BUILTIN()
1617 algorithm
1618 26924 inst_cls := Class.INSTANCED_BUILTIN(cls.ty, cls.elements, cls.restriction);
1619 26924 node := InstNode.updateClass(inst_cls, node);
1620 then
1621 ();
1622
1623 else ();
1624 end match;
1625 end instExtends;
1626
1627 function applyModifier
1628 "Applies a modifier in the given scope, by splitting the modifier and merging
1629 each part with the relevant element in the scope."
1630 input Modifier modifier;
1631 input output ClassTree cls;
1632 input InstNode parent;
1633 input InstContext.Type context;
1634 protected
1635 list<Modifier> mods;
1636 list<Mutable<InstNode>> node_ptrs;
1637 InstNode node;
1638 Boolean found;
1639 algorithm
1640 // Split the modifier into a list of submodifiers.
1641 1161815 mods := Modifier.toList(modifier);
1642
1643
2/2
✓ Branch 0 taken 613166 times.
✓ Branch 1 taken 548649 times.
1161815 if listEmpty(mods) then
1644 613166 return;
1645 end if;
1646
1647 () := match cls
1648 case ClassTree.FLAT_TREE()
1649 algorithm
1650
2/2
✓ Branch 0 taken 1360336 times.
✓ Branch 1 taken 482607 times.
1842943 for mod in mods loop
1651 try
1652 1360336 node := ClassTree.lookupElement(Modifier.name(mod), cls);
1653 1360335 InstNode.componentApply(node, Component.mergeModifier, mod);
1654 else
1655 3 Error.addSourceMessage(Error.MISSING_MODIFIED_ELEMENT,
1656 {Modifier.name(mod), InstNode.name(parent)}, Modifier.info(mod));
1657
1658
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if not InstContext.inInstanceAPI(context) then
1659 1 fail();
1660 end if;
1661 end try;
1662 end for;
1663 then
1664 ();
1665
1666 else
1667 algorithm
1668
2/2
✓ Branch 0 taken 435562 times.
✓ Branch 1 taken 66030 times.
501592 for mod in mods loop
1669 // Look up the node(s) to modify. Might be several in case of duplicate inherited elements.
1670 try
1671 435562 node_ptrs := ClassTree.lookupElementsPtr(Modifier.name(mod), cls);
1672 else
1673 node_ptrs := {};
1674 end try;
1675
1676 found := false;
1677
1678 // Apply the modifier to each found node.
1679
2/2
✓ Branch 0 taken 463825 times.
✓ Branch 1 taken 435557 times.
899382 for node_ptr in node_ptrs loop
1680 463825 node := Mutable.access(node_ptr);
1681
1682
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 463823 times.
463825 if InstNode.isEmpty(node) then
1683 // Component removed by 'break'.
1684 2 continue;
1685 end if;
1686
1687 found := true;
1688 463823 node := InstNode.resolveOuter(node);
1689
1690
6/6
✓ Branch 1 taken 301 times.
✓ Branch 2 taken 463522 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 297 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 1 time.
463823 if InstNode.isProtected(node) and not (InstNode.isExtends(parent) or InstNode.isBaseClass(parent)) then
1691 15 Error.addMultiSourceMessage(Error.NF_MODIFY_PROTECTED,
1692 {InstNode.name(node), Modifier.toString(mod)}, {Modifier.info(mod), InstNode.info(node)});
1693
1694
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if InstContext.inInstanceAPI(context) then
1695 ✗ continue;
1696 else
1697 3 fail();
1698 end if;
1699 end if;
1700
1701
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 463819 times.
463820 if InstNode.isOnlyOuter(node) then
1702 3 Error.addSourceMessage(Error.OUTER_ELEMENT_MOD,
1703 {Modifier.toString(mod, printName = false), Modifier.name(mod)},
1704 Modifier.info(mod));
1705
1706
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if InstContext.inInstanceAPI(context) then
1707 ✗ continue;
1708 else
1709 1 fail();
1710 end if;
1711 end if;
1712
1713
2/2
✓ Branch 1 taken 462029 times.
✓ Branch 2 taken 1790 times.
463819 if InstNode.isComponent(node) then
1714 462029 InstNode.componentApply(node, Component.mergeModifier, mod);
1715 else
1716 1790 partialInstClass(node);
1717 1790 node := InstNode.replaceClass(Class.mergeModifier(mod, InstNode.getClass(node)), node);
1718 1790 node := InstNode.clearPackageCache(node);
1719 1790 Mutable.update(node_ptr, node);
1720 end if;
1721 end for;
1722
1723
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 435551 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
435557 if not found and not InstContext.inInstanceAPI(context) then
1724 18 Error.addSourceMessage(Error.MISSING_MODIFIED_ELEMENT,
1725 {Modifier.name(mod), InstNode.name(parent)}, Modifier.info(mod));
1726 6 fail();
1727 end if;
1728 end for;
1729 then
1730 ();
1731
1732 end match;
1733 end applyModifier;
1734
1735 function redeclareClasses
1736 input output ClassTree tree;
1737 input InstNode parent;
1738 input InstContext.Type context;
1739 input Integer instLevel;
1740 protected
1741 InstNode cls_node, redecl_node;
1742 Class cls;
1743 Modifier mod, cc_mod;
1744 algorithm
1745 () := match tree
1746 case ClassTree.INSTANTIATED_TREE()
1747 algorithm
1748
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 167284 times.
✓ Branch 3 taken 520248 times.
✓ Branch 4 taken 167283 times.
854815 for cls_ptr in tree.classes loop
1749 520248 cls_node := Mutable.access(cls_ptr);
1750 520248 cls := InstNode.getClass(InstNode.resolveOuter(cls_node));
1751 520248 mod := Class.getModifier(cls);
1752
1753
2/2
✓ Branch 1 taken 1520 times.
✓ Branch 2 taken 518728 times.
520248 if Modifier.isRedeclare(mod) then
1754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
1520 Modifier.REDECLARE(element = redecl_node, outerMod = mod, constrainingMod = cc_mod) := mod;
1755 1520 cc_mod := getConstrainingMod(InstNode.definition(cls_node), parent, cc_mod, instLevel);
1756 1520 cls_node := redeclareClass(redecl_node, cls_node, mod, cc_mod, instLevel, context);
1757 1519 Mutable.update(cls_ptr, cls_node);
1758 end if;
1759 end for;
1760 then
1761 ();
1762
1763 else ();
1764 end match;
1765 end redeclareClasses;
1766
1767 function redeclareElements
1768 input list<Mutable<InstNode>> chain;
1769 input Integer instLevel;
1770 input InstContext.Type context;
1771 protected
1772 InstNode node;
1773 Mutable<InstNode> node_ptr;
1774 algorithm
1775 4244 node := Mutable.access(listHead(chain));
1776 4244 node_ptr := listHead(chain);
1777
1778
2/2
✓ Branch 1 taken 4240 times.
✓ Branch 2 taken 4 times.
4244 if InstNode.isClass(node) then
1779
2/2
✓ Branch 1 taken 4920 times.
✓ Branch 2 taken 4239 times.
9159 for cls_ptr in listRest(chain) loop
1780 4920 node_ptr := redeclareClassElement(cls_ptr, node_ptr, instLevel, context);
1781 end for;
1782 4239 node := Mutable.access(node_ptr);
1783 else
1784
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 for comp_ptr in listRest(chain) loop
1785 4 node_ptr := redeclareComponentElement(comp_ptr, node_ptr, instLevel, context);
1786 end for;
1787 3 node := Mutable.access(node_ptr);
1788 end if;
1789
1790
2/2
✓ Branch 0 taken 9164 times.
✓ Branch 1 taken 4242 times.
13406 for cls_ptr in chain loop
1791 9164 Mutable.update(cls_ptr, node);
1792 end for;
1793 end redeclareElements;
1794
1795 function redeclareClassElement
1796 input Mutable<InstNode> redeclareCls;
1797 input Mutable<InstNode> replaceableCls;
1798 input Integer instLevel;
1799 input InstContext.Type context;
1800 output Mutable<InstNode> outCls;
1801 protected
1802 InstNode rdcl_node, repl_node;
1803 algorithm
1804 4920 rdcl_node := Mutable.access(redeclareCls);
1805 4920 repl_node := Mutable.access(replaceableCls);
1806 4920 rdcl_node := redeclareClass(rdcl_node, repl_node, Modifier.NOMOD(), Modifier.NOMOD(), instLevel, context);
1807 4919 outCls := Mutable.create(rdcl_node);
1808 end redeclareClassElement;
1809
1810 function redeclareComponentElement
1811 input Mutable<InstNode> redeclareComp;
1812 input Mutable<InstNode> replaceableComp;
1813 input Integer instLevel;
1814 input InstContext.Type context;
1815 output Mutable<InstNode> outComp;
1816 protected
1817 InstNode rdcl_node, repl_node;
1818 algorithm
1819 4 rdcl_node := Mutable.access(redeclareComp);
1820 4 repl_node := Mutable.access(replaceableComp);
1821 4 instComponent(repl_node, NFAttributes.DEFAULT_ATTR, Modifier.NOMOD(), true, instLevel, context);
1822 4 redeclareComponent(rdcl_node, repl_node, Modifier.NOMOD(), Modifier.NOMOD(), {}, NFAttributes.DEFAULT_ATTR, rdcl_node, instLevel, context);
1823 3 outComp := Mutable.create(rdcl_node);
1824 end redeclareComponentElement;
1825
1826 function redeclareClass
1827 input InstNode redeclareNode;
1828 input InstNode originalNode;
1829 input Modifier outerMod;
1830 input Modifier constrainingMod;
1831 input Integer instLevel;
1832 input InstContext.Type context;
1833 output InstNode redeclaredNode;
1834 protected
1835 InstNode orig_node;
1836 Class orig_cls, rdcl_cls, new_cls;
1837 Class.Prefixes prefs;
1838 InstNodeType node_ty;
1839 Modifier mod;
1840 Option<InstNode> orig_opt;
1841 ClassTree cls_tree;
1842 algorithm
1843 // Check that the redeclare element is actually a class.
1844
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 6439 times.
6440 if not InstNode.isClass(redeclareNode) then
1845 6 Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
1846 {InstNode.typeName(originalNode), InstNode.name(originalNode), InstNode.typeName(redeclareNode)},
1847 {InstNode.info(redeclareNode), InstNode.info(originalNode)});
1848 1 fail();
1849 end if;
1850
1851 6439 partialInstClass(originalNode);
1852 6439 orig_cls := InstNode.getClass(originalNode);
1853 6439 partialInstClass(redeclareNode);
1854 6439 rdcl_cls := InstNode.getClass(redeclareNode);
1855
1856 6439 mod := Class.getModifier(rdcl_cls);
1857 //mod := Modifier.merge(mod, constrainingMod);
1858 6439 mod := Modifier.merge(outerMod, mod);
1859
1860 6439 prefs := Attributes.mergeRedeclaredClassPrefixes(Class.getPrefixes(orig_cls),
1861 Class.getPrefixes(rdcl_cls), redeclareNode);
1862
1863
2/2
✓ Branch 2 taken 3482 times.
✓ Branch 3 taken 2957 times.
6439 if SCodeUtil.isClassExtends(InstNode.definition(redeclareNode)) then
1864 3482 orig_node := expand(originalNode, context);
1865 3482 orig_cls := InstNode.getClass(orig_node);
1866
1867 new_cls := match rdcl_cls
1868 // Class extends of a builtin type. Not very useful, but technically allowed
1869 // if the redeclaring class is empty.
1870 case Class.PARTIAL_CLASS() guard Class.isBuiltin(orig_cls)
1871 algorithm
1872
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 if not SCodeUtil.isEmptyClassDef(SCodeUtil.getClassDef(InstNode.definition(redeclareNode))) then
1873 // Class extends of a builtin type is only allowed if the extending class is empty,
1874 // otherwise it violates the rules of extending a builtin type.
1875 ✗ Error.addSourceMessage(Error.BUILTIN_EXTENDS_INVALID_ELEMENTS,
1876 {InstNode.name(redeclareNode)}, InstNode.info(redeclareNode));
1877 ✗ fail();
1878 end if;
1879 1 then
1880 Class.setPrefixes(prefs, orig_cls);
1881
1882 // Class extends of a normal class.
1883 case Class.PARTIAL_CLASS()
1884 algorithm
1885 3480 node_ty := InstNodeType.BASE_CLASS(InstNode.identityCell(InstNode.parent(orig_node)),
1886 InstNode.definition(orig_node), InstNode.nodeType(orig_node));
1887 3480 orig_node := InstNode.setNodeType(node_ty, orig_node);
1888 3480 cls_tree := ClassTree.setClassExtends(orig_node, rdcl_cls.elements);
1889 3480 then
1890 Class.PARTIAL_CLASS(cls_tree, mod, constrainingMod, prefs);
1891
1892 else
1893 algorithm
1894 1 Error.terminate(getInstanceName() + " got unknown classes", sourceInfo());
1895 ✗ then
1896 fail();
1897 end match;
1898 else
1899 new_cls := match (orig_cls, rdcl_cls)
1900 case (Class.PARTIAL_BUILTIN(), _)
1901 5 then redeclareEnum(rdcl_cls, orig_cls, prefs, mod, redeclareNode, originalNode, context);
1902
1903 case (_, Class.PARTIAL_CLASS())
1904 2952 then Class.PARTIAL_CLASS(rdcl_cls.elements, mod, constrainingMod, prefs);
1905
1906 else
1907 algorithm
1908 ✗ Error.terminate(getInstanceName() + " got unknown classes", sourceInfo());
1909 ✗ then
1910 fail();
1911 end match;
1912 end if;
1913
1914
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6435 times.
6438 orig_opt := if InstContext.inInstanceAPI(context) then SOME(originalNode) else NONE();
1915
1916 6438 redeclaredNode := InstNode.replaceClass(new_cls, redeclareNode);
1917 6438 node_ty := InstNodeType.REDECLARED_CLASS(InstNode.scopeRef(InstNode.parent(originalNode)), InstNode.nodeType(originalNode), orig_opt, instLevel);
1918 6438 redeclaredNode := InstNode.setNodeType(node_ty, redeclaredNode);
1919 end redeclareClass;
1920
1921 function redeclareEnum
1922 input Class redeclareClass;
1923 input Class originalClass;
1924 input Class.Prefixes prefixes;
1925 input Modifier outerMod;
1926 input InstNode redeclareNode;
1927 input InstNode originalNode;
1928 input InstContext.Type context;
1929 output Class redeclaredClass = redeclareClass;
1930 algorithm
1931 // Expand the redeclare node so we can check whether it's an enumeration or not.
1932 5 expand(redeclareNode, context);
1933 5 redeclaredClass := InstNode.getClass(redeclareNode);
1934
1935 redeclaredClass := match (redeclaredClass, originalClass)
1936 local
1937 list<String> lits1, lits2;
1938
1939 // Redeclare enumeration(:).
1940 case (_, Class.PARTIAL_BUILTIN(ty = Type.ENUMERATION(literals = {})))
1941 guard InstNode.isEnumerationType(redeclareNode)
1942 algorithm
1943 4 redeclaredClass := Class.setPrefixes(prefixes, redeclaredClass);
1944 4 redeclaredClass := Class.mergeModifier(outerMod, redeclaredClass);
1945 then
1946 redeclaredClass;
1947
1948 // Redeclare normal enumeration.
1949 case (Class.PARTIAL_BUILTIN(ty = Type.ENUMERATION(literals = lits1)),
1950 Class.PARTIAL_BUILTIN(ty = Type.ENUMERATION(literals = lits2)))
1951 algorithm
1952
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 if not (listEmpty(lits2) or List.isEqualOnTrue(lits1, lits2, stringEq)) then
1953 ✗ Error.addMultiSourceMessage(Error.REDECLARE_ENUM_NON_SUBTYPE,
1954 {InstNode.name(originalNode)}, {InstNode.info(redeclareNode), InstNode.info(originalNode)});
1955 ✗ fail();
1956 end if;
1957
1958 1 redeclaredClass.prefixes := prefixes;
1959 1 redeclaredClass.modifier := Modifier.merge(outerMod, redeclaredClass.modifier);
1960 then
1961 redeclaredClass;
1962
1963 else
1964 algorithm
1965 ✗ Error.addMultiSourceMessage(Error.REDECLARE_CLASS_NON_SUBTYPE,
1966 {Restriction.toString(Class.restriction(originalClass)), InstNode.name(originalNode)},
1967 {InstNode.info(redeclareNode), InstNode.info(originalNode)});
1968 ✗ then
1969 fail();
1970
1971 end match;
1972 end redeclareEnum;
1973
1974 function instComponent
1975 input InstNode node "The component node to instantiate";
1976 input Attributes attributes "Attributes to be propagated to the component.";
1977 input Modifier innerMod;
1978 input Boolean useBinding "Ignore the component's binding if false.";
1979 input Integer instLevel;
1980 input InstContext.Type context;
1981 input Option<Attributes> originalAttr = NONE();
1982 input list<Subscript> propagatedSubs = {};
1983 protected
1984 Component comp;
1985 SCode.Element def;
1986 InstNode comp_node, rdcl_node;
1987 Modifier outer_mod, inner_mod, cc_mod = innerMod;
1988 InstNode parent;
1989 InstContext.Type next_context;
1990 list<Subscript> propagated_subs;
1991 algorithm
1992
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 958439 times.
958445 if InstNode.isEmpty(node) then
1993 6 return;
1994 end if;
1995
1996 958439 checkOuterComponentMod(node, context);
1997
1998
2/2
✓ Branch 1 taken 1789 times.
✓ Branch 2 taken 956650 times.
958439 if InstNode.isOnlyOuter(node) then
1999 1789 return;
2000 end if;
2001
2002 956650 comp_node := InstNode.resolveOuter(node);
2003 956650 comp := InstNode.component(comp_node);
2004 956650 parent := InstNode.parent(comp_node);
2005
2006 // Skip already instantiated components.
2007
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 956643 times.
956650 if not Component.isDefinition(comp) then
2008 // An already instantiated component might be due to an instantiation loop, check it.
2009 7 checkRecursiveDefinition(Component.classInstance(comp), comp_node, limitReached = false);
2010 6 return;
2011 end if;
2012
2013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 956643 times.
956643 Component.COMPONENT_DEF(definition = def, modifier = outer_mod) := comp;
2014
2015
2/2
✓ Branch 1 taken 5557 times.
✓ Branch 2 taken 951086 times.
956643 if Modifier.isRedeclare(outer_mod) then
2016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5557 times.
5557 Modifier.REDECLARE(element = rdcl_node, innerMod = inner_mod,
2017 outerMod = outer_mod, constrainingMod = cc_mod, propagatedSubs = propagated_subs) := outer_mod;
2018
2019 5557 next_context := InstContext.set(context, NFInstContext.REDECLARED);
2020 5557 instComponentDef(def, Modifier.NOMOD(), inner_mod, NFAttributes.DEFAULT_ATTR,
2021 useBinding, comp_node, parent, instLevel, originalAttr, {}, next_context);
2022
2023 5557 cc_mod := getConstrainingMod(def, parent, cc_mod, instLevel);
2024 5557 cc_mod := Modifier.merge(cc_mod, innerMod);
2025
2026 5557 outer_mod := Modifier.merge(InstNode.getModifier(rdcl_node), outer_mod);
2027 5557 InstNode.setModifier(outer_mod, rdcl_node);
2028 5557 redeclareComponent(rdcl_node, node, Modifier.NOMOD(), cc_mod, propagated_subs, attributes, node, instLevel, context);
2029 else
2030 951086 instComponentDef(def, outer_mod, innerMod, attributes, useBinding, comp_node, parent, instLevel, originalAttr, propagatedSubs, context);
2031 end if;
2032 end instComponent;
2033
2034 function instComponentDef
2035 input SCode.Element component;
2036 input Modifier outerMod;
2037 input Modifier innerMod;
2038 input Attributes attributes;
2039 input Boolean useBinding;
2040 input InstNode node;
2041 input InstNode parent;
2042 input Integer instLevel;
2043 input Option<Attributes> originalAttr = NONE();
2044 input list<Subscript> propagatedSubs = {};
2045 input InstContext.Type context;
2046 algorithm
2047 () := match component
2048 local
2049 SourceInfo info;
2050 Modifier mod;
2051 list<Dimension> dims;
2052 Binding binding, condition;
2053 Attributes attr, ty_attr;
2054 Component inst_comp;
2055 InstNode ty_node;
2056 Class ty;
2057 SCode.Element elementDefinition;
2058 Restriction parent_res, res;
2059 SCode.Comment cmt;
2060
2061 case SCode.COMPONENT(info = info)
2062 algorithm
2063 956643 mod := instElementModifier(component, node, parent, instLevel);
2064
2065
2/2
✓ Branch 0 taken 5342 times.
✓ Branch 1 taken 951300 times.
956642 if not listEmpty(propagatedSubs) then
2066 5342 mod := Modifier.propagateSubs(mod, propagatedSubs);
2067 end if;
2068
2069 956642 mod := Modifier.merge(mod, innerMod);
2070 956642 mod := Modifier.merge(outerMod, mod);
2071
2072
4/4
✓ Branch 0 taken 248765 times.
✓ Branch 1 taken 956641 times.
✓ Branch 2 taken 248765 times.
✓ Branch 3 taken 956641 times.
1205406 dims := list(Dimension.RAW_DIM(d, InstNode.scopeRef(parent)) for d in component.attributes.arrayDims);
2073
2/2
✓ Branch 0 taken 889590 times.
✓ Branch 1 taken 67051 times.
956641 binding := if useBinding then Modifier.binding(mod) else NFBinding.EMPTY_BINDING;
2074 956641 condition := Binding.fromAbsyn(component.condition, false, parent, instLevel, info);
2075
2076 // Instantiate the component's attributes, and merge them with the
2077 // attributes of the component's parent (e.g. constant SomeComplexClass c).
2078 956641 parent_res := Class.restriction(InstNode.getClass(parent));
2079 956641 attr := Attributes.fromSCode(component.attributes, component.prefixes);
2080 956641 attr := Attributes.checkDeclaredComponentAttributes(attr, parent_res, node);
2081 956641 attr := Attributes.mergeComponentAttributes(attributes, attr, node, parent_res);
2082
2083
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 956640 times.
✓ Branch 2 taken 5561 times.
✓ Branch 3 taken 951079 times.
956640 if isSome(originalAttr) then
2084 5561 attr := Attributes.mergeRedeclaredComponentAttributes(Util.getOption(originalAttr), attr, node);
2085 end if;
2086
2087
4/4
✓ Branch 0 taken 897771 times.
✓ Branch 1 taken 58868 times.
✓ Branch 3 taken 11911 times.
✓ Branch 4 taken 885860 times.
956639 if not attr.isFinal and Modifier.isFinal(mod) then
2088 11911 attr.isFinal := true;
2089 end if;
2090
2091 // Create the untyped component and update the node with it. We need the
2092 // untyped component in instClass to make sure everything is scoped
2093 // correctly during lookup, but the class node the component should have
2094 // is created by instClass. To break the circle we leave the class node
2095 // empty here, and let instClass set it for us instead.
2096 956639 inst_comp := Component.COMPONENT(InstNode.EMPTY_NODE(), Type.UNKNOWN(),
2097 binding, condition, attr, component.comment,
2098 ComponentState.PartiallyInstantiated, info);
2099 956639 InstNode.updateComponent(inst_comp, node);
2100
2101 // Instantiate the type of the component.
2102 956639 mod := Modifier.propagate(mod, node, node);
2103
4/4
✓ Branch 0 taken 889588 times.
✓ Branch 1 taken 67051 times.
✓ Branch 3 taken 555575 times.
✓ Branch 4 taken 334013 times.
1512214 (ty_node, ty_attr) := instTypeSpec(component.typeSpec, mod, attr,
2104 useBinding and not Binding.isBound(binding), parent, node, info, instLevel, context);
2105
2106 956403 InstNode.componentApply(node, Component.setType, Type.UNTYPED(ty_node, listArray(dims)));
2107
2108
2/2
✓ Branch 1 taken 956400 times.
✓ Branch 2 taken 3 times.
956403 if not InstNode.isEmpty(ty_node) then
2109 956400 ty := InstNode.getClass(ty_node);
2110 956400 res := Class.restriction(ty);
2111
2112 /* fix issue https://github.com/OpenModelica/OpenModelica/issues/12533
2113 * check if restriction is TYPE and has named annotation absoluteValue=false, if so set absoluteValue=false in the component's annotation too.
2114 * (e.g) type TemperatureDifference = Real (final quantity="ThermodynamicTemperature", final unit="K") annotation(absoluteValue=false);
2115 */
2116 956400 elementDefinition := InstNode.definition(ty_node);
2117
4/4
✓ Branch 1 taken 852744 times.
✓ Branch 2 taken 103656 times.
✓ Branch 5 taken 66 times.
✓ Branch 6 taken 852678 times.
956400 if (Restriction.isType(res) and SCodeUtil.optCommentHasBooleanNamedAnnotationFalse(SCodeUtil.getElementComment(elementDefinition), "absoluteValue")) then
2118 66 cmt := Component.comment(InstNode.component(node));
2119 66 cmt := SCodeUtil.setAnnotationInComment("absoluteValue", Absyn.Exp.BOOL(false), cmt, replace = false);
2120 66 InstNode.componentApply(node, Component.setComment, cmt);
2121 end if;
2122
2123
2/2
✓ Branch 1 taken 947117 times.
✓ Branch 2 taken 9283 times.
956400 if not InstContext.inRedeclared(context) then
2124 947117 checkPartialComponent(node, attr, ty_node, Class.isPartial(ty), res, context, info);
2125 end if;
2126
2127 956399 checkBindingRestriction(res, binding, node, info);
2128
2129 // Update some of the attributes now that we now the type of the component.
2130 956397 ty_attr := Attributes.updateVariability(ty_attr, ty, ty_node, node, context);
2131 956397 ty_attr := Attributes.updateComponentConnectorType(ty_attr, res, context, node);
2132
2133
2/2
✓ Branch 0 taken 101790 times.
✓ Branch 1 taken 854607 times.
956397 if not referenceEq(attr, ty_attr) then
2134 101790 InstNode.componentApply(node, Component.setAttributes, ty_attr);
2135 end if;
2136
2137
10/10
✓ Branch 0 taken 889346 times.
✓ Branch 1 taken 67051 times.
✓ Branch 3 taken 333776 times.
✓ Branch 4 taken 555570 times.
✓ Branch 6 taken 152165 times.
✓ Branch 7 taken 181611 times.
✓ Branch 8 taken 26574 times.
✓ Branch 9 taken 125591 times.
✓ Branch 11 taken 1536 times.
✓ Branch 12 taken 25038 times.
956397 if useBinding and Binding.isUnbound(binding) and not InstContext.inFunction(context) and
2138 ty_attr.variability <= Variability.PARAMETER and Restriction.isType(res) then
2139 1536 updateParameterBinding(node, context);
2140 end if;
2141
2142 end if;
2143 then
2144 ();
2145 end match;
2146 end instComponentDef;
2147
2148 function instElementModifier
2149 input SCode.Element element;
2150 input InstNode component;
2151 input InstNode parent;
2152 input Integer instLevel;
2153 output Modifier mod;
2154 protected
2155 Modifier cc_mod;
2156 algorithm
2157 2654347 mod := Modifier.fromElement(element, parent, instLevel);
2158
2159
2/2
✓ Branch 1 taken 7081 times.
✓ Branch 2 taken 2647265 times.
2654346 if InstNode.isRedeclared(component) then
2160 7081 mod := propagateRedeclaredMod(mod, component);
2161 else
2162 2647265 cc_mod := instConstrainingMod(element, parent, instLevel);
2163 2647265 mod := Modifier.merge(mod, cc_mod);
2164 end if;
2165 end instElementModifier;
2166
2167 function instConstrainingMod
2168 input SCode.Element element;
2169 input InstNode parent;
2170 input Integer instLevel;
2171 output Modifier ccMod;
2172 algorithm
2173 ccMod := match element
2174 local
2175 SCode.Mod smod;
2176
2177 case SCode.Element.CLASS(prefixes = SCode.Prefixes.PREFIXES(replaceablePrefix =
2178 SCode.Replaceable.REPLACEABLE(cc = SOME(SCode.ConstrainClass.CONSTRAINCLASS(modifier = smod)))))
2179 196 then Modifier.create(smod, element.name, ModifierScope.CLASS(element.name), parent, instLevel);
2180
2181 case SCode.Element.COMPONENT(prefixes = SCode.Prefixes.PREFIXES(replaceablePrefix =
2182 SCode.Replaceable.REPLACEABLE(cc = SOME(SCode.ConstrainClass.CONSTRAINCLASS(modifier = smod)))))
2183 10 then Modifier.create(smod, element.name, ModifierScope.COMPONENT(element.name), parent, instLevel);
2184
2185 else Modifier.NOMOD();
2186 end match;
2187 end instConstrainingMod;
2188
2189 function getConstrainingMod
2190 input SCode.Element element;
2191 input InstNode parent;
2192 input Modifier outerMod;
2193 input Integer instLevel;
2194 output Modifier ccMod;
2195 protected
2196 String name;
2197 SCode.Mod cc_smod;
2198 algorithm
2199 7077 cc_smod := SCodeUtil.getConstrainingMod(element);
2200
2201
2/2
✓ Branch 1 taken 208 times.
✓ Branch 2 taken 6869 times.
7077 if not SCodeUtil.isEmptyMod(cc_smod) then
2202 208 name := SCodeUtil.elementName(element);
2203 208 ccMod := Modifier.create(cc_smod, name, ModifierScope.fromElement(element), parent, instLevel);
2204 208 ccMod := Modifier.merge(outerMod, ccMod);
2205 else
2206 ccMod := outerMod;
2207 end if;
2208 end getConstrainingMod;
2209
2210 function propagateRedeclaredMod
2211 input Modifier mod;
2212 input InstNode component;
2213 output Modifier outMod;
2214 protected
2215 InstNode parent;
2216 NFInstNode.ScopeRef rdcl_scope;
2217 algorithm
2218 outMod := match component
2219 case InstNode.COMPONENT_NODE(nodeType = InstNodeType.REDECLARED_COMP(parent = rdcl_scope))
2220 algorithm
2221 5585 parent := InstNode.getDerivedNode(InstNode.fromCell(rdcl_scope));
2222 5585 outMod := propagateRedeclaredMod(mod, parent);
2223 5585 then
2224 Modifier.propagateBinding(outMod, parent, parent);
2225
2226 else mod;
2227 end match;
2228 end propagateRedeclaredMod;
2229
2230 function checkPartialComponent
2231 input InstNode compNode;
2232 input Attributes compAttr;
2233 input InstNode clsNode;
2234 input Boolean isPartial;
2235 input Restriction res;
2236 input InstContext.Type context;
2237 input SourceInfo info;
2238 algorithm
2239
2/2
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 947076 times.
947117 if Restriction.isFunction(res) then
2240
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
41 if not isPartial and not InstContext.inRelaxed(context) then
2241 // The type of a function pointer must be a partial function.
2242 ✗ Error.addSourceMessage(Error.META_FUNCTION_TYPE_NO_PARTIAL_PREFIX,
2243 {AbsynUtil.pathString(InstNode.scopePath(clsNode))}, info);
2244 ✗ fail();
2245 end if;
2246 elseif isPartial and compAttr.innerOuter <> InnerOuter.OUTER and not InstContext.inRelaxed(context) then
2247 // The type of a component may not be a partial class.
2248 4 Error.addMultiSourceMessage(Error.PARTIAL_COMPONENT_TYPE,
2249 {AbsynUtil.pathString(InstNode.scopePath(compNode)), InstNode.name(clsNode)},
2250 {InstNode.info(clsNode), info});
2251 1 fail();
2252 end if;
2253 end checkPartialComponent;
2254
2255 function checkBindingRestriction
2256 input Restriction restriction;
2257 input Binding binding;
2258 input InstNode component;
2259 input SourceInfo info;
2260 algorithm
2261
2/2
✓ Branch 1 taken 555572 times.
✓ Branch 2 taken 400827 times.
956399 if Binding.isBound(binding) then
2262 () := match restriction
2263 case Restriction.CLOCK() then ();
2264 case Restriction.CONNECTOR() then ();
2265 case Restriction.ENUMERATION() then ();
2266 case Restriction.EXTERNAL_OBJECT() then ();
2267 case Restriction.RECORD() then ();
2268 case Restriction.TYPE() then ();
2269 else
2270 algorithm
2271 6 Error.addSourceMessage(Error.INVALID_SPECIALIZATION_FOR_BINDING_EQUATION,
2272 {InstNode.name(component), Restriction.toString(restriction)}, info);
2273 2 then
2274 fail();
2275 end match;
2276 end if;
2277 end checkBindingRestriction;
2278
2279 function redeclareComponent
2280 input InstNode redeclareNode;
2281 input InstNode originalNode;
2282 input Modifier outerMod;
2283 input Modifier constrainingMod;
2284 input list<Subscript> propagatedSubs;
2285 input Attributes outerAttr;
2286 input InstNode redeclaredNode;
2287 input Integer instLevel;
2288 input InstContext.Type context;
2289 protected
2290 Component orig_comp, rdcl_comp, new_comp;
2291 Binding binding, condition;
2292 Attributes attr;
2293 Type orig_ty, rdcl_ty;
2294 SCode.Comment cmt;
2295 InstNode orig_node, rdcl_node;
2296 InstNodeType rdcl_type;
2297 algorithm
2298 // Check that the redeclare element actually is a component.
2299
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5561 times.
5561 if not InstNode.isComponent(redeclareNode) then
2300 ✗ Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
2301 {InstNode.typeName(originalNode), InstNode.name(originalNode), InstNode.typeName(redeclareNode)},
2302 {InstNode.info(redeclareNode), InstNode.info(originalNode)});
2303 ✗ fail();
2304 end if;
2305
2306 5561 orig_node := InstNode.resolveInner(originalNode);
2307 5561 orig_comp := InstNode.component(orig_node);
2308 5561 rdcl_type := InstNodeType.REDECLARED_COMP(InstNode.scopeRef(InstNode.parent(orig_node)));
2309 5561 rdcl_node := InstNode.setNodeType(rdcl_type, redeclareNode);
2310 5561 rdcl_node := InstNode.copyInstancePtr(orig_node, rdcl_node);
2311 5561 rdcl_node := InstNode.updateComponent(InstNode.component(redeclareNode), rdcl_node);
2312 11122 instComponent(rdcl_node, outerAttr, constrainingMod, true, instLevel, context,
2313 SOME(Component.getAttributes(orig_comp)), propagatedSubs);
2314 5560 rdcl_comp := InstNode.component(rdcl_node);
2315
2316 new_comp := match (orig_comp, rdcl_comp)
2317 case (Component.COMPONENT(ty = orig_ty as Type.UNTYPED()), Component.COMPONENT(ty = rdcl_ty as Type.UNTYPED()))
2318 algorithm
2319
4/6
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5557 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
5560 if not InstNode.isReplaceable(orig_node) and
2320 not InstContext.inInstanceAPI(context) and
2321 not Type.isEqual(Type.arrayElementType(orig_ty), Type.arrayElementType(rdcl_ty)) then
2322 ✗ Error.addMultiSourceMessage(Error.REDECLARE_NON_REPLACEABLE,
2323 {InstNode.name(orig_node)}, {InstNode.info(orig_node), InstNode.info(rdcl_node)});
2324 ✗ fail();
2325 end if;
2326
2327 // Take the binding from the outer modifier, the redeclare, or the
2328 // original component, in that order of priority.
2329 5560 binding := Modifier.binding(outerMod);
2330
1/2
✓ Branch 1 taken 5560 times.
✗ Branch 2 not taken.
5560 if Binding.isUnbound(binding) then
2331
2/2
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 5451 times.
5560 binding := if Binding.isBound(rdcl_comp.binding) then rdcl_comp.binding else orig_comp.binding;
2332 end if;
2333
2334 // A redeclare is not allowed to have a condition expression.
2335
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5559 times.
5560 if Binding.isBound(rdcl_comp.condition) then
2336 2 Error.addSourceMessage(Error.REDECLARE_CONDITION,
2337 {InstNode.name(redeclareNode)}, InstNode.info(redeclareNode));
2338 1 fail();
2339 end if;
2340
2341 5559 condition := orig_comp.condition;
2342 5559 attr := rdcl_comp.attributes;
2343
2344 // Use the dimensions of the redeclare if any, otherwise take them from the original.
2345
2/2
✓ Branch 1 taken 5557 times.
✓ Branch 2 taken 2 times.
5559 if Type.dimensionCount(rdcl_ty) == 0 then
2346 5557 rdcl_ty := Type.UNTYPED(rdcl_ty.typeNode, orig_ty.dimensions);
2347 end if;
2348
2349 // TODO: Use comment of redeclare if available?
2350 5559 cmt := orig_comp.comment;
2351 5559 then
2352 Component.COMPONENT(rdcl_comp.classInst, rdcl_ty, binding, condition,
2353 attr, cmt, ComponentState.PartiallyInstantiated, rdcl_comp.info);
2354
2355 else
2356 algorithm
2357 ✗ Error.terminate(getInstanceName() + " got unknown components", sourceInfo());
2358 ✗ then
2359 fail();
2360
2361 end match;
2362
2363 5559 InstNode.updateComponent(new_comp, InstNode.resolveInner(redeclaredNode));
2364 end redeclareComponent;
2365
2366 function checkOuterComponentMod
2367 "Prints an error message and fails if it gets an outer component with a modifier."
2368 input InstNode node;
2369 input InstContext.Type context;
2370 protected
2371 InstNode outer_node;
2372 SCode.Element elem;
2373 SCode.Mod smod;
2374 algorithm
2375 958439 outer_node := InstNode.resolveOuter(node);
2376 958439 elem := InstNode.definition(outer_node);
2377
2378
2/2
✓ Branch 3 taken 1789 times.
✓ Branch 4 taken 956650 times.
958439 if AbsynUtil.isOnlyOuter(SCodeUtil.prefixesInnerOuter(SCodeUtil.elementPrefixes(elem))) then
2379 1789 smod := SCodeUtil.componentMod(elem);
2380
2381
1/2
✓ Branch 1 taken 1789 times.
✗ Branch 2 not taken.
1789 if not SCodeUtil.isEmptyMod(smod) then
2382 ✗ Error.addSourceMessage(Error.OUTER_ELEMENT_MOD,
2383 {SCodeDump.printModStr(smod), InstNode.name(outer_node)}, InstNode.info(outer_node));
2384
2385 ✗ if not InstContext.inInstanceAPI(context) then
2386 ✗ fail();
2387 end if;
2388 end if;
2389 end if;
2390 end checkOuterComponentMod;
2391
2392 function classConfidence
2393 "Returns the confidence of the start attributes a component gets from its
2394 type (MLS 8.6.2 with the type rule from ModelicaSpecification#3933): the
2395 instance level of the innermost redeclare the type is looked up through, or
2396 the component's own level if the type is not redeclared."
2397 input InstNode clsNode;
2398 input InstNode scope "The scope the type was looked up from.";
2399 input Integer instLevel;
2400 input list<InstNode> prefixes = {} "The classes the type was looked up through.";
2401 output Integer confidence = instLevel;
2402 protected
2403 InstNode node = scope;
2404 list<InstNode> enclosing = {};
2405 InstNodeType ty;
2406 algorithm
2407 // Only a redeclared class lowers the confidence.
2408
4/4
✓ Branch 1 taken 954652 times.
✓ Branch 2 taken 1969 times.
✓ Branch 4 taken 4692 times.
✓ Branch 5 taken 949960 times.
956621 if not (hasRedeclaredScope(clsNode) or List.any(prefixes, isRedeclaredClass)) then
2409 949960 return;
2410 end if;
2411
2412 // Redeclares of the scopes enclosing the component did not determine its type.
2413
3/4
✓ Branch 1 taken 61820 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55159 times.
✓ Branch 5 taken 6661 times.
61820 while not (InstNode.isEmpty(node) or InstNode.isTopScope(node)) loop
2414 enclosing := node :: enclosing;
2415 55159 node := instanceScope(node);
2416 end while;
2417
2418 node := clsNode;
2419
5/6
✓ Branch 1 taken 50868 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 704 times.
✓ Branch 5 taken 50164 times.
✓ Branch 7 taken 5957 times.
✓ Branch 8 taken 44207 times.
50868 while not (InstNode.isEmpty(node) or InstNode.isTopScope(node) or
2420 List.exist1(enclosing, InstNode.refEqual, node)) loop
2421 () := match node
2422 case InstNode.CLASS_NODE(nodeType = ty as InstNodeType.REDECLARED_CLASS())
2423 algorithm
2424 1910 confidence := min(confidence, ty.confidence);
2425 then
2426 ();
2427
2428 else ();
2429 end match;
2430
2431 44207 node := instanceScope(node);
2432 end while;
2433
2434 // A package alias that shares the instance of the package it names is not in
2435 // the instance scope chain of what is looked up through it, so the redeclares
2436 // on the lookup path have to be considered too.
2437
2/2
✓ Branch 0 taken 5503 times.
✓ Branch 1 taken 6661 times.
12164 for p in prefixes loop
2438
2/2
✓ Branch 1 taken 5483 times.
✓ Branch 2 taken 20 times.
5503 if not List.exist1(enclosing, InstNode.refEqual, p) then
2439 () := match p
2440 case InstNode.CLASS_NODE(nodeType = ty as InstNodeType.REDECLARED_CLASS())
2441 algorithm
2442 5403 confidence := min(confidence, ty.confidence);
2443 then
2444 ();
2445
2446 else ();
2447 end match;
2448 end if;
2449 end for;
2450 end classConfidence;
2451
2452 function isRedeclaredClass
2453 input InstNode node;
2454 output Boolean res;
2455 algorithm
2456 res := match node
2457 case InstNode.CLASS_NODE(nodeType = InstNodeType.REDECLARED_CLASS()) then true;
2458 else false;
2459 end match;
2460 end isRedeclaredClass;
2461
2462 function hasRedeclaredScope
2463 "Whether a redeclared class is on the instance scope chain of a node."
2464 input InstNode node;
2465 output Boolean res = false;
2466 protected
2467 InstNode scope = node;
2468 algorithm
2469
4/4
✓ Branch 1 taken 3408993 times.
✓ Branch 2 taken 398377 times.
✓ Branch 4 taken 556275 times.
✓ Branch 5 taken 2852718 times.
3807370 while not (InstNode.isEmpty(scope) or InstNode.isTopScope(scope)) loop
2470
2/2
✓ Branch 1 taken 1969 times.
✓ Branch 2 taken 2850749 times.
2852718 if isRedeclaredClass(scope) then
2471 res := true;
2472 1969 return;
2473 end if;
2474
2475 2850749 scope := instanceScope(scope);
2476 end while;
2477 end hasRedeclaredScope;
2478
2479 function instanceScope
2480 "Returns the scope a node was instantiated in, for a redeclared class the
2481 scope of the class it replaced. The scope is borrowed: it is only for
2482 inspecting and comparing."
2483 input InstNode node;
2484 output InstNode scope;
2485 algorithm
2486 scope := match node
2487 local NFInstNode.ScopeRef ext_scope;
2488 case InstNode.CLASS_NODE(nodeType = InstNodeType.BASE_CLASS(parent = ext_scope))
2489 128308 then InstNode.borrow(ext_scope);
2490 case InstNode.CLASS_NODE(nodeType = InstNodeType.REDECLARED_CLASS(parent = ext_scope))
2491 1992 then InstNode.borrow(ext_scope);
2492 2819815 else InstNode.borrowParent(node);
2493 end match;
2494 end instanceScope;
2495
2496 function markTypeModifier
2497 "Marks the modifiers a type applies to its attributes as coming from the type,
2498 with the type's confidence. Modifiers on other classes modify components and
2499 are left alone."
2500 input output Modifier mod;
2501 input Restriction res;
2502 input Integer confidence;
2503 algorithm
2504 mod := match res
2505 1544290 case Restriction.TYPE() then Modifier.setSource(mod, NFBinding.Source.TYPE, confidence);
2506 ✗ case Restriction.ENUMERATION() then Modifier.setSource(mod, NFBinding.Source.TYPE, confidence);
2507 else mod;
2508 end match;
2509 end markTypeModifier;
2510
2511 function instTypeSpec
2512 input Absyn.TypeSpec typeSpec;
2513 input Modifier modifier;
2514 input Attributes attributes;
2515 input Boolean useBinding;
2516 input InstNode scope;
2517 input InstNode parent;
2518 input SourceInfo info;
2519 input Integer instLevel;
2520 input InstContext.Type context;
2521 output InstNode node;
2522 output Attributes outAttributes;
2523 protected
2524 list<InstNode> prefixes;
2525 algorithm
2526 node := matchcontinue typeSpec
2527 case Absyn.TPATH()
2528 algorithm
2529 956639 (node, prefixes) := Lookup.lookupClassName(typeSpec.path, scope, context, info);
2530
2531
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 956627 times.
956629 if instLevel >= 100 then
2532 2 checkRecursiveDefinition(node, parent, limitReached = true);
2533 end if;
2534
2535 956627 node := expand(node, context);
2536 956621 (node, outAttributes) := instClass(node, modifier, attributes, useBinding, instLevel,
2537 classConfidence(node, scope, instLevel, prefixes), parent, context);
2538 then
2539 node;
2540
2541 case Absyn.TPATH()
2542 guard InstContext.inInstanceAPI(context)
2543 algorithm
2544 3 outAttributes := attributes;
2545 then
2546 InstNode.EMPTY_NODE();
2547
2548 case Absyn.TCOMPLEX()
2549 algorithm
2550 ✗ print("NFInst.instTypeSpec: TCOMPLEX not implemented.\n");
2551 ✗ then
2552 fail();
2553
2554 end matchcontinue;
2555 end instTypeSpec;
2556
2557 function checkRecursiveDefinition
2558 "Prints an error if a component causes a loop in the instance tree, for
2559 example because it has the same type as one of its parents. If the depth
2560 limit of the instance tree is reached, indicated by limitReached = true, then
2561 some error is always given. Otherwise an error is only given if an actual
2562 issue can be detected."
2563 input InstNode componentType;
2564 input InstNode component;
2565 input Boolean limitReached;
2566 protected
2567 InstNode parent = InstNode.parent(component);
2568 InstNode parent_type;
2569 algorithm
2570 // Functions can contain instances of a parent, e.g. in equalityConstraint
2571 // functions, so skip this check for functions.
2572
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 if not Class.isFunction(InstNode.getClass(parent)) then
2573 // Check whether any parent of the component has the same type as the component.
2574
2/2
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 7 times.
125 while not InstNode.isEmpty(parent) loop
2575 118 parent_type := InstNode.classScope(parent);
2576
2577 // Check equality by comparing the definitions, because comparing the
2578 // nodes or instances in the nodes is unreliable due to instantiation
2579 // creating new nodes.
2580
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 116 times.
118 if referenceEq(InstNode.definition(componentType), InstNode.definition(parent_type)) then
2581 6 Error.addSourceMessage(Error.RECURSIVE_DEFINITION,
2582 {InstNode.name(component), InstNode.name(InstNode.classScope(InstNode.parent(component)))},
2583 InstNode.info(component));
2584 // Remove the class node from the component to avoid infinite loops when
2585 // using the instance API.
2586 2 InstNode.componentApply(component, Component.setClassInstance, InstNode.EMPTY_NODE());
2587 2 fail();
2588 end if;
2589
2590 116 parent := InstNode.parent(parent);
2591 end while;
2592 end if;
2593
2594
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
7 if limitReached then
2595 // If we couldn't determine the exact cause of the recursion, print a generic error.
2596 2 Error.addSourceMessage(Error.INST_RECURSION_LIMIT_REACHED,
2597 {AbsynUtil.pathString(InstNode.scopePath(component))}, InstNode.info(component));
2598 1 InstNode.componentApply(component, Component.setClassInstance, InstNode.EMPTY_NODE());
2599 1 fail();
2600 end if;
2601 end checkRecursiveDefinition;
2602
2603 function updateParameterBinding
2604 "Tries to update the binding of a fixed parameter without binding by using the
2605 parameter's start attribute."
2606 input InstNode node;
2607 input InstContext.Type context;
2608 protected
2609 Component comp;
2610 Binding binding;
2611 algorithm
2612
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1532 times.
1536 if InstContext.inRedeclared(context) then
2613 // Don't update the binding if the parameter is being redeclared.
2614 4 return;
2615 end if;
2616
2617 1532 comp := InstNode.component(node);
2618
2619
4/4
✓ Branch 1 taken 878 times.
✓ Branch 2 taken 654 times.
✓ Branch 4 taken 797 times.
✓ Branch 5 taken 81 times.
1532 if not Component.isFixed(comp) or InstNode.hasBinding(node) then
2620 // If the parameter is not fixed or belongs to a record with a binding, do nothing.
2621 1451 return;
2622 end if;
2623
2624 81 binding := Component.getTypeAttributeBinding(comp, "start");
2625
2626
4/4
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 32 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 25 times.
81 if Binding.isBound(binding) and not Binding.hasTypeOrigin(binding) then
2627
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 11 times.
25 if not InstContext.inRelaxed(context) then
2628 42 Error.addSourceMessage(Error.UNBOUND_PARAMETER_WITH_START_VALUE_WARNING,
2629 {AbsynUtil.pathString(InstNode.scopePath((node))), Binding.toString(binding)}, InstNode.info(node));
2630 end if;
2631
2632 25 binding := Binding.unpropagate(binding, node);
2633
2634
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if Binding.isEach(binding) then
2635 ✗ binding := Binding.expandEach(binding, node);
2636 end if;
2637
2638 25 comp := Component.setBinding(binding, comp);
2639 25 InstNode.updateComponent(comp, node);
2640 end if;
2641 end updateParameterBinding;
2642
2643 function instDimension
2644 input output Dimension dimension;
2645 input InstContext.Type context;
2646 input InstSettings settings;
2647 input SourceInfo info;
2648 algorithm
2649 dimension := match dimension
2650 local
2651 Absyn.Subscript dim;
2652 Expression exp;
2653
2654 case Dimension.RAW_DIM(dim = dim)
2655 then
2656 matchcontinue dim
2657 case Absyn.NOSUB() then Dimension.UNKNOWN();
2658 case Absyn.SUBSCRIPT()
2659 algorithm
2660 223840 exp := instExp(dim.subscript, InstNode.fromCell(dimension.scope), context, info);
2661
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 223798 times.
223839 if settings.resizableArrays then
2662 41 exp := Expression.map(exp, instResizable);
2663 end if;
2664 223839 then
2665 Dimension.UNTYPED(exp, false);
2666
2667 case _
2668 guard InstContext.inRelaxed(context)
2669 then Dimension.UNKNOWN();
2670
2671 end matchcontinue;
2672
2673 else dimension;
2674 end match;
2675 end instDimension;
2676
2677 function instResizable
2678 "only updates component pointers"
2679 input output Expression exp;
2680 algorithm
2681 () := match exp
2682 local
2683 InstNode node;
2684 Component comp;
2685 Attributes attr;
2686
2687 case Expression.CREF(cref = ComponentRef.CREF())
2688 guard InstNode.isComponent(ComponentRef.node(exp.cref)) and
2689 Component.variability(InstNode.component(ComponentRef.node(exp.cref))) == Variability.PARAMETER
2690 algorithm
2691 16 node := ComponentRef.node(exp.cref);
2692 16 comp := InstNode.component(node);
2693 () :=match comp
2694 case Component.COMPONENT(attributes = attr) algorithm
2695 16 attr.variability := Variability.NON_STRUCTURAL_PARAMETER;
2696 16 attr.isResizable := true;
2697 16 comp.attributes := attr;
2698 16 InstNode.updateComponent(comp, node);
2699 then ();
2700 else ();
2701 end match;
2702 then ();
2703 else ();
2704 end match;
2705 end instResizable;
2706
2707 function instExpressions
2708 input InstNode node;
2709 input InstNode scope = node;
2710 input output Sections sections = Sections.EMPTY();
2711 input ConnectBreakTree.Tree connectBreaks = ConnectBreakTree.new();
2712 input InstContext.Type context;
2713 input InstSettings settings;
2714 protected
2715 Class cls = InstNode.getClass(node), inst_cls;
2716 array<InstNode> local_comps, exts;
2717 ClassTree cls_tree;
2718 array<Dimension> dims;
2719 SourceInfo info;
2720 Type ty;
2721 InstContext.Type next_context;
2722 ConnectBreakTree.Tree connect_breaks;
2723 list<Mutable<ConnectBreakTree.Entry>> local_connect_breaks;
2724 algorithm
2725 () := match cls
2726 // Long class declaration of a type.
2727 case Class.EXPANDED_CLASS(elements = cls_tree, restriction = Restriction.TYPE())
2728 algorithm
2729 // Instantiate expressions in the extends nodes.
2730 18039 exts := ClassTree.getExtends(cls_tree);
2731
2/2
✓ Branch 1 taken 17685 times.
✓ Branch 2 taken 18039 times.
35724 for ext in exts loop
2732 17685 instExpressions(ext, ext, sections, connectBreaks, context, settings);
2733 end for;
2734
2735 // A type must extend a basic type.
2736
2/2
✓ Branch 0 taken 17685 times.
✓ Branch 1 taken 354 times.
18039 if arrayLength(exts) == 1 then
2737 17685 ty := Type.COMPLEX(InstNode.identityCell(node), ComplexType.EXTENDS_TYPE(InstNode.identityCell(exts[1])));
2738 elseif SCodeUtil.hasBooleanNamedAnnotationInClass(InstNode.definition(node), "__OpenModelica_builtinType") then
2739 353 ty := Type.COMPLEX(InstNode.identityCell(node), ComplexType.CLASS());
2740 else
2741 2 Error.addSourceMessage(Error.MISSING_TYPE_BASETYPE,
2742 {InstNode.name(node)}, InstNode.info(node));
2743 1 fail();
2744 end if;
2745
2746 18038 cls_tree := ClassTree.flatten(cls_tree);
2747 18038 inst_cls := Class.INSTANCED_CLASS(ty, cls_tree, Sections.EMPTY(), cls.prefixes, cls.restriction);
2748 18038 InstNode.updateClass(inst_cls, node);
2749 then
2750 ();
2751
2752 case Class.EXPANDED_CLASS(elements = cls_tree)
2753 algorithm
2754 254193 (connect_breaks, local_connect_breaks) := ConnectBreakTree.appendBreaksInNode(node, connectBreaks);
2755
2756 // Instantiate expressions in the extends nodes.
2757
2/2
✓ Branch 0 taken 254101 times.
✓ Branch 1 taken 92 times.
254193 if settings.mergeExtendsSections then
2758
2/2
✓ Branch 2 taken 122122 times.
✓ Branch 3 taken 254099 times.
630322 for ext in ClassTree.getExtends(cls_tree) loop
2759 122122 sections := instExpressions(ext, ext, sections, connect_breaks, context, settings);
2760 end for;
2761 else
2762
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 92 times.
193 for ext in ClassTree.getExtends(cls_tree) loop
2763 9 instExpressions(ext, ext, sections, connect_breaks, context, settings);
2764 end for;
2765 end if;
2766
2767 // Instantiate expressions in the local components.
2768 254191 ClassTree.applyLocalComponents(cls_tree,
2769 function instComponentExpressions(context = context, settings = settings));
2770
2771 // Flatten the class tree so we don't need to deal with extends anymore.
2772 254170 cls.elements := ClassTree.flatten(cls_tree);
2773 254170 InstNode.updateClass(cls, node);
2774
2775 // Instantiate local equation/algorithm sections.
2776
2/2
✓ Branch 1 taken 215744 times.
✓ Branch 2 taken 38426 times.
254170 next_context := if Restriction.isFunction(cls.restriction) then
2777 NFInstContext.FUNCTION else NFInstContext.CLASS;
2778 254170 next_context := InstContext.set(context, next_context);
2779 254170 sections := instSections(node, scope, connect_breaks, next_context, sections);
2780 254154 ConnectBreakTree.checkUnmatchedBreaks(local_connect_breaks);
2781
2782 254152 ty := makeComplexType(cls.restriction, node, cls);
2783 254152 inst_cls := Class.INSTANCED_CLASS(ty, cls.elements, sections, cls.prefixes, cls.restriction);
2784 254152 InstNode.updateClass(inst_cls, node);
2785
2786 254152 instComplexType(ty, context);
2787 then
2788 ();
2789
2790 case Class.EXPANDED_DERIVED(dims = dims)
2791 algorithm
2792 652654 sections := instExpressions(cls.baseClass, scope, sections, connectBreaks, context, settings);
2793
2794 652654 info := InstNode.info(node);
2795
2796
2/2
✓ Branch 0 taken 7552 times.
✓ Branch 1 taken 645102 times.
661215 for i in 1:arrayLength(dims) loop
2797 8561 dims[i] := instDimension(dims[i], context, settings, info);
2798 end for;
2799
2800
2/2
✓ Branch 1 taken 4593 times.
✓ Branch 2 taken 648061 times.
652654 if Restriction.isRecord(cls.restriction) then
2801 4593 instRecordConstructor(node, context);
2802 end if;
2803 then
2804 ();
2805
2806 case Class.INSTANCED_BUILTIN(elements = ClassTree.FLAT_TREE(components = local_comps))
2807 algorithm
2808
2/2
✓ Branch 1 taken 8198240 times.
✓ Branch 2 taken 808617 times.
9006857 for comp in local_comps loop
2809 8198240 instComponentExpressions(comp, context, settings);
2810 end for;
2811 then
2812 ();
2813
2814 case Class.INSTANCED_BUILTIN() then ();
2815 case Class.INSTANCED_CLASS() then ();
2816
2817 else
2818 algorithm
2819 ✗ Error.terminate(getInstanceName() + " got invalid class", sourceInfo());
2820 ✗ then
2821 fail();
2822
2823 end match;
2824 end instExpressions;
2825
2826 function makeComplexType
2827 input Restriction restriction;
2828 input InstNode node;
2829 input Class cls;
2830 output Type ty;
2831 protected
2832 ComplexType cty;
2833 algorithm
2834 cty := match restriction
2835 case Restriction.RECORD()
2836 127938 then makeRecordComplexType(InstNode.classScope(InstNode.getDerivedNode(node)), cls);
2837 else ComplexType.CLASS();
2838 end match;
2839
2840 254152 ty := Type.COMPLEX(InstNode.identityCell(node), cty);
2841 end makeComplexType;
2842
2843 function makeRecordComplexType
2844 input InstNode node;
2845 input Class cls;
2846 output ComplexType ty;
2847 protected
2848 InstNode cls_node;
2849 UnorderedMap<String, Integer> indexMap = UnorderedMap.new<Integer>(stringHashDjb2, stringEq);
2850 algorithm
2851
2/2
✓ Branch 2 taken 3333 times.
✓ Branch 3 taken 124605 times.
127938 cls_node := if SCodeUtil.isOperatorRecord(InstNode.definition(node))
2852 then InstNode.classScope(node) else InstNode.classScope(InstNode.getDerivedNode(node));
2853 127938 ty := ComplexType.RECORD(InstNode.identityCell(cls_node), listArray({}), indexMap);
2854 end makeRecordComplexType;
2855
2856 function instComplexType
2857 input Type ty;
2858 input InstContext.Type context;
2859 algorithm
2860 () := match ty
2861 local
2862 InstNode node;
2863 NFInstNode.ScopeRef cell;
2864
2865 case Type.COMPLEX(complexTy = ComplexType.RECORD(cell))
2866 // Make sure it's really a record, and not e.g. a record inherited by a model.
2867 // TODO: This check should really be InstNode.isRecord(node), but that
2868 // causes issues with e.g. ComplexInput/ComplexOutput.
2869 guard not InstNode.isModel(InstNode.borrow(cell))
2870 algorithm
2871 127935 instRecordConstructor(InstNode.borrow(cell), context);
2872 then
2873 ();
2874
2875 else ();
2876 end match;
2877 end instComplexType;
2878
2879 function instRecordConstructor
2880 input InstNode node;
2881 input InstContext.Type context;
2882 protected
2883 CachedData cache;
2884 algorithm
2885 132528 cache := InstNode.getFuncCache(node);
2886
2887 () := match cache
2888 case CachedData.FUNCTION() then ();
2889 else
2890 algorithm
2891 2660 InstNode.cacheInitFunc(node);
2892
2893
2/2
✓ Branch 2 taken 236 times.
✓ Branch 3 taken 2424 times.
2660 if SCodeUtil.isOperatorRecord(InstNode.definition(node)) then
2894 236 OperatorOverloading.instConstructor(InstNode.fullPath(node), node, context, InstNode.info(node));
2895 else
2896 2424 Record.instDefaultConstructor(InstNode.fullPath(node), node, context, InstNode.info(node));
2897 end if;
2898 then
2899 ();
2900
2901 end match;
2902 end instRecordConstructor;
2903
2904 function instBuiltinAttribute
2905 input output Modifier attribute;
2906 input InstNode node;
2907 input InstContext.Type context;
2908 algorithm
2909 () := match attribute
2910 local
2911 Binding binding;
2912
2913 case Modifier.MODIFIER(binding = binding)
2914 algorithm
2915 1316599 attribute.binding := instBinding(binding, context);
2916 then
2917 ();
2918
2919 // Redeclaration of builtin attributes is not allowed.
2920 case Modifier.REDECLARE()
2921 algorithm
2922 2 Error.addSourceMessage(Error.INVALID_REDECLARE_IN_BASIC_TYPE,
2923 {Modifier.name(attribute)}, Modifier.info(attribute));
2924 1 then
2925 fail();
2926
2927 else ();
2928 end match;
2929 end instBuiltinAttribute;
2930
2931 function instComponentExpressions
2932 input InstNode component;
2933 input InstContext.Type context;
2934 input InstSettings settings;
2935 protected
2936 InstNode node;
2937 Component c;
2938 array<Dimension> dims;
2939 algorithm
2940
4/4
✓ Branch 1 taken 9128215 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 1638 times.
✓ Branch 5 taken 9126577 times.
9128221 if InstNode.isEmpty(component) or InstNode.isOnlyOuter(component) then
2941 1644 return;
2942 end if;
2943
2944 9126577 node := InstNode.resolveOuter(component);
2945 9126577 c := InstNode.component(node);
2946
2947 () := match c
2948 case Component.COMPONENT(ty = Type.UNTYPED(dimensions = dims))
2949 guard c.state == ComponentState.PartiallyInstantiated
2950 algorithm
2951 // This is to avoid instantiating the same component multiple times,
2952 // which can otherwise happen with duplicate components at this stage.
2953 897816 c.state := ComponentState.FullyInstantiated;
2954 897816 InstNode.updateComponent(c, node);
2955
2956
2/2
✓ Branch 1 taken 897813 times.
✓ Branch 2 taken 3 times.
897816 if not InstNode.isEmpty(c.classInst) then
2957 897813 c.binding := convertUnitfulLiterals(node, c);
2958 end if;
2959
2960 897816 c.binding := instBinding(c.binding, context);
2961 897799 c.condition := instBinding(c.condition, context);
2962
2963
2/2
✓ Branch 1 taken 897796 times.
✓ Branch 2 taken 3 times.
897799 if not InstNode.isEmpty(c.classInst) then
2964 897796 instExpressions(c.classInst, node, context = context, settings = settings);
2965 end if;
2966
2967
2/2
✓ Branch 0 taken 206404 times.
✓ Branch 1 taken 691391 times.
1119890 for i in 1:arrayLength(dims) loop
2968 222095 dims[i] := instDimension(dims[i], context, settings, c.info);
2969 end for;
2970
2971 897795 InstNode.updateComponent(c, node);
2972 then
2973 ();
2974
2975 case Component.COMPONENT() then ();
2976 case Component.ENUM_LITERAL() then ();
2977 case Component.TYPE_ATTRIBUTE(modifier = Modifier.NOMOD()) then ();
2978
2979 case Component.TYPE_ATTRIBUTE()
2980 algorithm
2981 1316600 c.modifier := instBuiltinAttribute(c.modifier, component, context);
2982 1316599 InstNode.updateComponent(c, node);
2983 then
2984 ();
2985
2986 else
2987 algorithm
2988 ✗ if not InstContext.inRelaxed(context) then
2989 ✗ Error.terminate(getInstanceName() + " got invalid component", sourceInfo());
2990 ✗ fail();
2991 end if;
2992 then
2993 ();
2994
2995 end match;
2996 end instComponentExpressions;
2997
2998 function convertUnitfulLiterals
2999 "Converts a (negated) unitful literal that is the whole binding equation or
3000 start/min/max/nominal modifier of a component to the component's unit.
3001 Returns the component's binding and updates the modifiers in place."
3002 input InstNode node;
3003 input Component component;
3004 output Binding binding = Component.getBinding(component);
3005 protected
3006 Option<Class> ocls;
3007 Class cls;
3008 Boolean convert_binding;
3009 list<InstNode> attrs = {};
3010 InstNode attr_node;
3011 Component attr;
3012 String unit, name;
3013 Option<Boolean> abs_value;
3014 algorithm
3015 897813 ocls := realTypeClass(Component.classInstance(component));
3016
3017
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 897813 times.
✓ Branch 2 taken 195491 times.
✓ Branch 3 taken 702322 times.
897813 if isNone(ocls) then
3018 195491 return;
3019 end if;
3020
3021 702322 SOME(cls) := ocls;
3022
3023 702322 convert_binding := isUnitfulBinding(binding);
3024
3025
2/2
✓ Branch 0 taken 2809288 times.
✓ Branch 1 taken 702322 times.
3511610 for attr_name in {"start", "min", "max", "nominal"} loop
3026 2809288 attr_node := ClassTree.lookupElement(attr_name, Class.classTree(cls));
3027
3028
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 2809288 times.
2809288 if isUnitfulBinding(Component.getBinding(InstNode.component(attr_node))) then
3029 attrs := attr_node :: attrs;
3030 end if;
3031 end for;
3032
3033
2/4
✓ Branch 0 taken 702322 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 702322 times.
✗ Branch 3 not taken.
702322 if not convert_binding and listEmpty(attrs) then
3034 702322 return;
3035 end if;
3036
3037 unit := match Class.lookupAttributeBinding("unit", cls)
3038 case Binding.RAW_BINDING(bindingExp = Absyn.Exp.STRING(value = unit))
3039 ✗ then System.unescapedString(unit);
3040 case Binding.UNTYPED_BINDING(bindingExp = Expression.STRING(value = unit)) then unit;
3041 case Binding.TYPED_BINDING(bindingExp = Expression.STRING(value = unit)) then unit;
3042 else "";
3043 end match;
3044
3045 ✗ if stringEmpty(unit) then
3046 ✗ return;
3047 end if;
3048
3049 ✗ name := InstNode.name(node);
3050 ✗ abs_value := SCodeUtil.lookupBooleanAnnotationMod(
3051 SCodeUtil.lookupElementAnnotation(InstNode.definition(node), "absoluteValue"));
3052
3053 ✗ if isNone(abs_value) then
3054 ✗ abs_value := typeAbsoluteValue(Component.classInstance(component));
3055 end if;
3056
3057 ✗ if convert_binding then
3058 ✗ binding := convertUnitfulBinding(binding, unit, abs_value, name);
3059 end if;
3060
3061 ✗ for attr_node in attrs loop
3062 ✗ attr := InstNode.component(attr_node);
3063 ✗ attr := Component.setBinding(
3064 convertUnitfulBinding(Component.getBinding(attr), unit, abs_value, name), attr);
3065 ✗ InstNode.updateComponent(attr, attr_node);
3066 end for;
3067 end convertUnitfulLiterals;
3068
3069 function realTypeClass
3070 "Returns the builtin Real class a type is derived from, the only type with a unit."
3071 input InstNode node;
3072 output Option<Class> outCls;
3073 protected
3074 Class cls = InstNode.getClass(node);
3075 algorithm
3076 outCls := match cls
3077 649037 case Class.EXPANDED_DERIVED() then realTypeClass(cls.baseClass);
3078 case Class.INSTANCED_BUILTIN(ty = Type.REAL()) then SOME(cls);
3079 else NONE();
3080 end match;
3081 end realTypeClass;
3082
3083 function typeAbsoluteValue
3084 "Returns the absoluteValue annotation of a type, which is inherited by the
3085 types derived from it."
3086 input InstNode node;
3087 output Option<Boolean> absValue;
3088 protected
3089 Class cls;
3090 algorithm
3091 ✗ absValue := SCodeUtil.lookupBooleanAnnotationMod(
3092 SCodeUtil.lookupElementAnnotation(InstNode.definition(node), "absoluteValue"));
3093
3094 ✗ if isNone(absValue) then
3095 ✗ cls := InstNode.getClass(node);
3096
3097 absValue := match cls
3098 ✗ case Class.EXPANDED_DERIVED() then typeAbsoluteValue(cls.baseClass);
3099 else NONE();
3100 end match;
3101 end if;
3102 end typeAbsoluteValue;
3103
3104 function isUnitfulBinding
3105 input Binding binding;
3106 output Boolean res;
3107 algorithm
3108 res := match binding
3109 case Binding.RAW_BINDING(bindingExp = Absyn.Exp.UNITFUL_LITERAL()) then true;
3110 case Binding.RAW_BINDING(bindingExp = Absyn.Exp.UNARY(op = Absyn.Operator.UMINUS(),
3111 exp = Absyn.Exp.UNITFUL_LITERAL())) then true;
3112 else false;
3113 end match;
3114 end isUnitfulBinding;
3115
3116 function convertUnitfulBinding
3117 input output Binding binding;
3118 input String unit;
3119 input Option<Boolean> absValue;
3120 input String name;
3121 algorithm
3122 () := match binding
3123 case Binding.RAW_BINDING()
3124 algorithm
3125 ✗ binding.bindingExp := convertUnitfulLiteral(binding.bindingExp, unit, absValue, name, binding.info);
3126 then
3127 ();
3128
3129 else ();
3130 end match;
3131 end convertUnitfulBinding;
3132
3133 function convertUnitfulLiteral
3134 "Converts e.g. -5'cm' to -0.05 for unit m. A literal that can't be converted
3135 is returned as the bare number after a warning."
3136 input Absyn.Exp exp;
3137 input String unit;
3138 input Option<Boolean> absValue;
3139 input String name;
3140 input SourceInfo info;
3141 output Absyn.Exp outExp;
3142 protected
3143 Absyn.Exp value_exp;
3144 String lit_unit;
3145 Boolean negated;
3146 Real value, from_factor, from_offset, to_factor, to_offset;
3147 Unit.StringToUnitTable known_units;
3148 Unit.Unit from, to;
3149 algorithm
3150 (value_exp, lit_unit, negated) := match exp
3151 case Absyn.Exp.UNITFUL_LITERAL(value = value_exp, unit = lit_unit) then (value_exp, lit_unit, false);
3152 case Absyn.Exp.UNARY(exp = Absyn.Exp.UNITFUL_LITERAL(value = value_exp, unit = lit_unit))
3153 then (value_exp, lit_unit, true);
3154 end match;
3155
3156 ✗ outExp := if negated then Absyn.Exp.UNARY(Absyn.Operator.UMINUS(), value_exp) else value_exp;
3157
3158 ✗ if lit_unit == unit then
3159 ✗ return;
3160 end if;
3161
3162 ✗ known_units := Unit.getKnownUnits();
3163 ✗ ErrorExt.setCheckpoint(getInstanceName());
3164 try
3165 ✗ from := Unit.parseUnitString(lit_unit, known_units);
3166 ✗ to := Unit.parseUnitString(unit, known_units);
3167 ✗ (from_factor, from_offset, to_factor, to_offset) := unitConversion(from, to);
3168 else
3169 ✗ ErrorExt.rollBack(getInstanceName());
3170 ✗ Error.addSourceMessage(Error.UNITFUL_LITERAL_UNIT_CONFLICT, {Dump.printExpStr(exp), unit, name}, info);
3171 ✗ return;
3172 end try;
3173 ✗ ErrorExt.rollBack(getInstanceName());
3174
3175 value := match value_exp
3176 ✗ case Absyn.Exp.INTEGER() then intReal(value_exp.value);
3177 ✗ case Absyn.Exp.REAL() then stringReal(value_exp.value);
3178 end match;
3179
3180 ✗ if negated then
3181 ✗ value := -value;
3182 end if;
3183
3184 ✗ if from_offset <> to_offset then
3185 ✗ if isNone(absValue) then
3186 ✗ Error.addSourceMessage(Error.UNITFUL_LITERAL_ABSOLUTE_VALUE, {Dump.printExpStr(exp), unit, name}, info);
3187 ✗ return;
3188 elseif Util.getOption(absValue) then
3189 ✗ value := (value * from_factor + from_offset - to_offset) / to_factor;
3190 else
3191 ✗ value := scaleUnitValue(value, from_factor, to_factor);
3192 end if;
3193 else
3194 ✗ value := scaleUnitValue(value, from_factor, to_factor);
3195 end if;
3196
3197 // 15 digits drop the noise of the conversion, e.g. -20'degC' = 253.14999999999998'K'.
3198 ✗ outExp := Absyn.Exp.REAL(System.sprintff("%.15g", abs(value)));
3199
3200 ✗ if value < 0 then
3201 ✗ outExp := Absyn.Exp.UNARY(Absyn.Operator.UMINUS(), outExp);
3202 end if;
3203 end convertUnitfulLiteral;
3204
3205 function unitConversion
3206 "Returns the factors and offsets of two units, failing if their dimensions differ."
3207 input Unit.Unit from;
3208 input Unit.Unit to;
3209 output Real fromFactor;
3210 output Real fromOffset;
3211 output Real toFactor;
3212 output Real toOffset;
3213 algorithm
3214 (fromFactor, fromOffset, toFactor, toOffset) := match (from, to)
3215 case (Unit.UNIT(), Unit.UNIT())
3216 guard from.s == to.s and from.m == to.m and from.g == to.g and from.A == to.A and
3217 from.K == to.K and from.mol == to.mol and from.cd == to.cd
3218 ✗ then (from.factor, from.offset, to.factor, to.offset);
3219 end match;
3220 end unitConversion;
3221
3222 function scaleUnitValue
3223 "Divides by the larger factor ratio to avoid e.g. 3 * 0.01 = 0.030000000000000002."
3224 input Real value;
3225 input Real fromFactor;
3226 input Real toFactor;
3227 output Real outValue = if fromFactor >= toFactor then value * (fromFactor / toFactor)
3228 else value / (toFactor / fromFactor);
3229 end scaleUnitValue;
3230
3231 function instBinding
3232 input output Binding binding;
3233 input InstContext.Type context;
3234 algorithm
3235
2/2
✓ Branch 1 taken 1401 times.
✓ Branch 2 taken 3112216 times.
3113617 if InstContext.inInstanceAPI(context) then
3236 1401 ErrorExt.setCheckpoint(getInstanceName());
3237 try
3238 1401 binding := instBinding(binding, InstContext.unset(context, NFInstContext.INSTANCE_API));
3239 else
3240 ✗ binding := Binding.INVALID_BINDING(binding, ErrorExt.getCheckpointMessages());
3241 end try;
3242 1401 ErrorExt.delCheckpoint(getInstanceName());
3243 else
3244 binding := match binding
3245 local
3246 Expression bind_exp;
3247
3248 // Binding is removed by a break, change it to an unbound binding.
3249 case Binding.RAW_BINDING(bindingExp = Absyn.Exp.BREAK()) then Binding.UNBOUND();
3250
3251 case Binding.RAW_BINDING()
3252 algorithm
3253 1838172 bind_exp := instExp(binding.bindingExp, InstNode.fromCell(binding.scope), context, binding.info);
3254
3255
2/2
✓ Branch 0 taken 1682637 times.
✓ Branch 1 taken 155518 times.
1838155 if not listEmpty(binding.subs) then
3256 1682637 bind_exp := Expression.SUBSCRIPTED_EXP(bind_exp, binding.subs, Type.UNKNOWN(), true);
3257 end if;
3258 1838155 then
3259 Binding.UNTYPED_BINDING(bind_exp, false, binding.scope, binding.eachType, binding.source, binding.confidence, binding.info);
3260
3261 else binding;
3262 end match;
3263 end if;
3264 end instBinding;
3265
3266 function instExpOpt
3267 input Option<Absyn.Exp> absynExp;
3268 input InstNode scope;
3269 input InstContext.Type context;
3270 input SourceInfo info;
3271 output Option<Expression> exp;
3272 algorithm
3273 exp := match absynExp
3274 local
3275 Absyn.Exp aexp;
3276
3277 case NONE() then NONE();
3278 2450 case SOME(aexp) then SOME(instExp(aexp, scope, context, info));
3279
3280 end match;
3281 end instExpOpt;
3282
3283 function instExp
3284 input Absyn.Exp absynExp;
3285 input InstNode scope;
3286 input InstContext.Type context;
3287 input SourceInfo info;
3288 output Expression exp;
3289 algorithm
3290 exp := match absynExp
3291 local
3292 Expression e1, e2, e3;
3293 Option<Expression> oe;
3294 Operator op;
3295 list<Expression> expl;
3296 list<list<Expression>> expll;
3297 Absyn.Exp absynExp1;
3298 array<Expression> arr;
3299 String name;
3300
3301 837082 case Absyn.Exp.INTEGER() then Expression.INTEGER(absynExp.value);
3302 1110463 case Absyn.Exp.REAL() then Expression.REAL(stringReal(absynExp.value));
3303 980005 case Absyn.Exp.STRING() then Expression.STRING(System.unescapedString(absynExp.value));
3304 31080 case Absyn.Exp.BOOL() then Expression.BOOLEAN(absynExp.value);
3305
3306 case Absyn.Exp.CREF()
3307 1149914 then instCref(absynExp.componentRef, scope, context, info);
3308
3309 case Absyn.Exp.ARRAY()
3310 algorithm
3311 156261 arr := Array.mapList(absynExp.arrayExp,
3312 function instExp(scope = scope, context = context, info = info));
3313 156259 then
3314 Expression.makeArrayCheckLiteral(Type.UNKNOWN(), arr);
3315
3316 case Absyn.Exp.MATRIX()
3317 algorithm
3318
8/8
✓ Branch 0 taken 16735 times.
✓ Branch 1 taken 1906 times.
✓ Branch 2 taken 16735 times.
✓ Branch 3 taken 1906 times.
✓ Branch 4 taken 28097 times.
✓ Branch 5 taken 16735 times.
✓ Branch 6 taken 28097 times.
✓ Branch 7 taken 16735 times.
46738 expll := list(list(instExp(e, scope, context, info) for e in el) for el in absynExp.matrix);
3319 1906 then
3320 Expression.MATRIX(expll);
3321
3322 case Absyn.Exp.RANGE()
3323 algorithm
3324 10459 e1 := instExp(absynExp.start, scope, context, info);
3325 10459 oe := instExpOpt(absynExp.step, scope, context, info);
3326 10459 e3 := instExp(absynExp.stop, scope, context, info);
3327 10459 then
3328 Expression.RANGE(Type.UNKNOWN(), e1, oe, e3);
3329
3330 148529 case Absyn.Exp.TUPLE(expressions={absynExp1}) then instExp(absynExp1, scope, context, info);
3331
3332 case Absyn.Exp.TUPLE()
3333 algorithm
3334
4/4
✓ Branch 0 taken 2555 times.
✓ Branch 1 taken 1062 times.
✓ Branch 2 taken 2555 times.
✓ Branch 3 taken 1062 times.
3617 expl := list(instExp(e, scope, context, info) for e in absynExp.expressions);
3335 1062 then
3336 Expression.TUPLE(Type.UNKNOWN(), expl);
3337
3338 case Absyn.Exp.BINARY()
3339 algorithm
3340 656519 e1 := instExp(absynExp.exp1, scope, context, info);
3341 656519 e2 := instExp(absynExp.exp2, scope, context, info);
3342 656519 op := Operator.fromAbsyn(absynExp.op);
3343 656519 then
3344 Expression.BINARY(e1, op, e2);
3345
3346 case Absyn.Exp.UNARY()
3347 algorithm
3348 397349 e1 := instExp(absynExp.exp, scope, context, info);
3349 397349 op := Operator.fromAbsyn(absynExp.op);
3350 397349 then
3351 Expression.makeUnary(op, e1);
3352
3353 case Absyn.Exp.LBINARY()
3354 algorithm
3355 10392 e1 := instExp(absynExp.exp1, scope, context, info);
3356 10392 e2 := instExp(absynExp.exp2, scope, context, info);
3357 10392 op := Operator.fromAbsyn(absynExp.op);
3358 10392 then
3359 Expression.LBINARY(e1, op, e2);
3360
3361 case Absyn.Exp.LUNARY()
3362 algorithm
3363 3867 e1 := instExp(absynExp.exp, scope, context, info);
3364 3867 op := Operator.fromAbsyn(absynExp.op);
3365 3867 then
3366 Expression.LUNARY(op, e1);
3367
3368 case Absyn.Exp.RELATION()
3369 algorithm
3370 32931 e1 := instExp(absynExp.exp1, scope, context, info);
3371 32930 e2 := instExp(absynExp.exp2, scope, context, info);
3372 32930 op := Operator.fromAbsyn(absynExp.op);
3373 32930 then
3374 Expression.RELATION(e1, op, e2, -1);
3375
3376 case Absyn.Exp.IFEXP()
3377 algorithm
3378 14945 e3 := instExp(absynExp.elseBranch, scope, context, info);
3379
3380
2/2
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 14945 times.
15119 for branch in listReverse(absynExp.elseIfBranch) loop
3381 174 e1 := instExp(Util.tuple21(branch), scope, context, info);
3382 174 e2 := instExp(Util.tuple22(branch), scope, context, info);
3383 174 e3 := Expression.IF(Type.UNKNOWN(), e1, e2, e3);
3384 end for;
3385
3386 14945 e1 := instExp(absynExp.ifExp, scope, context, info);
3387 14945 e2 := instExp(absynExp.trueBranch, scope, context, info);
3388 14945 then
3389 Expression.IF(Type.UNKNOWN(), e1, e2, e3);
3390
3391 case Absyn.Exp.CALL()
3392 111948 then Call.instantiate(absynExp.function_, absynExp.functionArgs, scope, context, info);
3393
3394 case Absyn.Exp.PARTEVALFUNCTION()
3395 54 then instPartEvalFunction(absynExp.function_, absynExp.functionArgs, scope, context, info);
3396
3397 case Absyn.Exp.END() then Expression.END();
3398 257 case Absyn.Exp.EXPRESSIONCOMMENT() then instExp(absynExp.exp, scope, context, info);
3399
3400 case Absyn.Exp.SUBSCRIPTED_EXP()
3401
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 then Expression.SUBSCRIPTED_EXP(
3402 instExp(absynExp.exp, scope, context, info),
3403 list(instSubscript(Subscript.RAW_SUBSCRIPT(s), scope, context, info) for s in absynExp.subscripts),
3404 Type.UNKNOWN(),
3405 false
3406 );
3407
3408 case Absyn.Exp.DOT(index = Absyn.Exp.CREF(Absyn.ComponentRef.CREF_IDENT(name = name, subscripts = {})))
3409 ✗ then Expression.RECORD_ELEMENT(instExp(absynExp.exp, scope, context, info), 0, name, Type.UNKNOWN());
3410
3411 ✗ case Absyn.Exp.UNITFUL_LITERAL() then instExp(absynExp.value, scope, context, info);
3412
3413 else
3414 algorithm
3415 ✗ Error.terminate(getInstanceName() + " got unknown expression: " + Dump.printExpStr(absynExp), sourceInfo());
3416 ✗ then
3417 fail();
3418
3419 end match;
3420 end instExp;
3421
3422 function instCref
3423 input Absyn.ComponentRef absynCref;
3424 input InstNode scope;
3425 input InstContext.Type context;
3426 input SourceInfo info;
3427 output Expression crefExp;
3428 protected
3429 ComponentRef cref;
3430 InstNode found_scope;
3431 algorithm
3432 (cref, found_scope) := match absynCref
3433 5 case Absyn.ComponentRef.WILD() then (ComponentRef.WILD(), scope);
3434 ✗ case Absyn.ComponentRef.ALLWILD() then (ComponentRef.WILD(), scope);
3435 1149963 else Lookup.lookupComponent(absynCref, scope, context, info);
3436 end match;
3437
3438 1149958 cref := instCrefSubscripts(cref, scope, context, info);
3439
3440 crefExp := match cref
3441 case ComponentRef.CREF()
3442 then
3443 match ComponentRef.node(cref)
3444 case InstNode.COMPONENT_NODE()
3445 1149654 then instCrefComponent(cref, ComponentRef.node(cref), found_scope, info);
3446 case InstNode.CLASS_NODE()
3447
2/2
✓ Branch 3 taken 57 times.
✓ Branch 4 taken 242 times.
299 then if Class.isFunction(InstNode.getClass(ComponentRef.node(cref))) then
3448 instCrefFunction(cref, found_scope, context, info)
3449 else
3450 instCrefTypename(cref, ComponentRef.node(cref), info);
3451 else
3452 algorithm
3453 ✗ Error.terminate(getInstanceName() + " got invalid instance node", sourceInfo());
3454 ✗ then
3455 fail();
3456 end match;
3457
3458 5 else Expression.CREF(Type.UNKNOWN(), cref);
3459 end match;
3460 end instCref;
3461
3462 function instCrefComponent
3463 input ComponentRef cref;
3464 input InstNode node;
3465 input InstNode scope;
3466 input SourceInfo info;
3467 output Expression crefExp;
3468 protected
3469 Component comp;
3470 algorithm
3471 1149654 comp := InstNode.component(node);
3472
3473 crefExp := match comp
3474 case _ guard ComponentRef.isIterator(cref)
3475 algorithm
3476 17393 checkUnsubscriptableCref(cref, info);
3477 17392 then
3478 Expression.CREF(Type.UNKNOWN(), cref);
3479
3480 case Component.ENUM_LITERAL()
3481 algorithm
3482 27094 checkUnsubscriptableCref(cref, info);
3483 27094 then
3484 comp.literal;
3485
3486 case Component.TYPE_ATTRIBUTE()
3487 algorithm
3488 ✗ Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR,
3489 {InstNode.name(node), InstNode.name(InstNode.parent(node))}, info);
3490 ✗ then
3491 fail();
3492
3493 1105167 else Expression.CREF(Type.UNKNOWN(), ComponentRef.appendScope(scope, cref));
3494 end match;
3495 end instCrefComponent;
3496
3497 function instCrefFunction
3498 input ComponentRef cref;
3499 input InstNode scope;
3500 input InstContext.Type context;
3501 input SourceInfo info;
3502 output Expression crefExp;
3503 protected
3504 ComponentRef fn_ref;
3505 algorithm
3506 57 fn_ref := ComponentRef.appendScope(scope, cref, includeRoot = true);
3507 57 fn_ref := Function.instFunctionRef(fn_ref, context, info);
3508 57 crefExp := Expression.CREF(Type.UNKNOWN(), fn_ref);
3509 end instCrefFunction;
3510
3511 function instCrefTypename
3512 input ComponentRef cref;
3513 input InstNode node;
3514 input SourceInfo info;
3515 output Expression crefExp;
3516 protected
3517 Type ty;
3518 algorithm
3519 242 checkUnsubscriptableCref(cref, info);
3520 242 ty := InstNode.getType(node);
3521
3522 ty := match ty
3523 2 case Type.BOOLEAN() then Type.ARRAY(ty, {Dimension.BOOLEAN()});
3524 480 case Type.ENUMERATION() then Type.ARRAY(ty, {Dimension.ENUM(ty)});
3525 else
3526 algorithm
3527 ✗ Error.terminate(getInstanceName() + " got unknown class node " +
3528 InstNode.name(node), sourceInfo());
3529 ✗ then
3530 fail();
3531 end match;
3532
3533 242 crefExp := Expression.TYPENAME(ty);
3534 end instCrefTypename;
3535
3536 function checkUnsubscriptableCref
3537 input ComponentRef cref;
3538 input SourceInfo info;
3539 algorithm
3540
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 44728 times.
44729 if ComponentRef.hasSubscripts(cref) then
3541 3 Error.addSourceMessage(Error.WRONG_NUMBER_OF_SUBSCRIPTS,
3542 {ComponentRef.toString(cref), String(listLength(ComponentRef.getSubscripts(cref))), "0"}, info);
3543 1 fail();
3544 end if;
3545 end checkUnsubscriptableCref;
3546
3547 function instCrefSubscripts
3548 input output ComponentRef cref;
3549 input InstNode scope;
3550 input InstContext.Type context;
3551 input SourceInfo info;
3552 algorithm
3553 () := match cref
3554 local
3555 ComponentRef rest_cr;
3556
3557 case ComponentRef.CREF()
3558 algorithm
3559
2/2
✓ Branch 0 taken 257486 times.
✓ Branch 1 taken 1300965 times.
1558451 if not listEmpty(cref.subscripts) then
3560
4/4
✓ Branch 0 taken 307936 times.
✓ Branch 1 taken 257486 times.
✓ Branch 2 taken 307936 times.
✓ Branch 3 taken 257486 times.
822908 cref.subscripts := list(instSubscript(s, scope, context, info) for s in cref.subscripts);
3561 end if;
3562
3563 1558451 rest_cr := instCrefSubscripts(cref.restCref, scope, context, info);
3564
2/2
✓ Branch 0 taken 4520 times.
✓ Branch 1 taken 1553931 times.
1558451 if not referenceEq(rest_cr, cref.restCref) then
3565 4520 cref.restCref := rest_cr;
3566 end if;
3567 then
3568 ();
3569
3570 else ();
3571 end match;
3572 end instCrefSubscripts;
3573
3574 function instSubscript
3575 input Subscript subscript;
3576 input InstNode scope;
3577 input InstContext.Type context;
3578 input SourceInfo info;
3579 output Subscript outSubscript;
3580 protected
3581 Expression exp;
3582 Absyn.Subscript absynSub;
3583 algorithm
3584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 307940 times.
307940 Subscript.RAW_SUBSCRIPT(subscript = absynSub) := subscript;
3585
3586 outSubscript := match absynSub
3587 case Absyn.Subscript.NOSUB() then Subscript.WHOLE();
3588 case Absyn.Subscript.SUBSCRIPT()
3589 algorithm
3590 268030 exp := instExp(absynSub.subscript, scope, context, info);
3591 268030 then
3592 Subscript.fromExp(exp);
3593 end match;
3594 end instSubscript;
3595
3596 function instPartEvalFunction
3597 input Absyn.ComponentRef func;
3598 input Absyn.FunctionArgs funcArgs;
3599 input InstNode scope;
3600 input InstContext.Type context;
3601 input SourceInfo info;
3602 output Expression outExp;
3603 protected
3604 ComponentRef fn_ref;
3605 list<Absyn.NamedArg> nargs;
3606 list<Expression> args;
3607 list<String> arg_names;
3608 algorithm
3609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 Absyn.FunctionArgs.FUNCTIONARGS(argNames = nargs) := funcArgs;
3610 54 outExp := instCref(func, scope, context, info);
3611
3612
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 43 times.
54 if not listEmpty(nargs) then
3613 43 fn_ref := Expression.toCref(outExp);
3614
4/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 43 times.
170 args := list(instExp(arg.argValue, scope, context, info) for arg in nargs);
3615
4/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 43 times.
170 arg_names := list(arg.argName for arg in nargs);
3616 43 outExp := Expression.PARTIAL_FUNCTION_APPLICATION(fn_ref, args, arg_names, Type.UNKNOWN());
3617 end if;
3618 end instPartEvalFunction;
3619
3620 function instSections
3621 input InstNode node;
3622 input InstNode scope;
3623 input ConnectBreakTree.Tree connectBreaks;
3624 input InstContext.Type context;
3625 input output Sections sections;
3626 protected
3627 SCode.Element el = InstNode.definition(node);
3628 SCode.ClassDef def;
3629 algorithm
3630 sections := match el
3631 case SCode.CLASS(classDef = SCode.PARTS())
3632 250920 then instSections2(el.classDef, scope, connectBreaks, context, sections);
3633
3634 case SCode.CLASS(classDef = SCode.CLASS_EXTENDS(composition = def as SCode.PARTS()))
3635 3250 then instSections2(def, scope, connectBreaks, context, sections);
3636
3637 else sections;
3638 end match;
3639 end instSections;
3640
3641 function instSections2
3642 input SCode.ClassDef parts;
3643 input InstNode scope;
3644 input ConnectBreakTree.Tree connectBreaks;
3645 input InstContext.Type context;
3646 input output Sections sections;
3647 algorithm
3648 sections := match (parts, sections)
3649 local
3650 list<Equation> eq, ieq;
3651 list<Algorithm> alg, ialg;
3652 SCode.ExternalDecl ext_decl;
3653 InstContext.Type icontext;
3654
3655 // allow non standard Modelica on a flag
3656 case(SCode.PARTS(externalDecl = SOME(ext_decl)), Sections.EXTERNAL())
3657 guard Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdMultipleExternalDeclarations")
3658 ✗ then
3659 instExternalDecl(ext_decl, scope, context);
3660
3661 case (_, Sections.EXTERNAL())
3662 guard SCodeUtil.classDefHasSections(parts, checkExternal = true)
3663 algorithm
3664 // Class with inherited external section that also contains other sections.
3665 3 Error.addMultiSourceMessage(Error.MULTIPLE_SECTIONS_IN_FUNCTION,
3666 {InstNode.name(scope)}, {sections.info, InstNode.info(scope)});
3667 1 then
3668 fail();
3669
3670 case (SCode.PARTS(externalDecl = SOME(ext_decl)), _)
3671 algorithm
3672
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 6851 times.
6852 if SCodeUtil.classDefHasSections(parts, checkExternal = false) then
3673 // Class with external section that also contains other sections.
3674 2 Error.addSourceMessage(Error.MULTIPLE_SECTIONS_IN_FUNCTION,
3675 {InstNode.name(scope)}, InstNode.info(scope));
3676 1 fail();
3677 end if;
3678 6851 then
3679 instExternalDecl(ext_decl, scope, context);
3680
3681 case (SCode.PARTS(), _)
3682 algorithm
3683 247317 icontext := InstContext.set(context, NFInstContext.INITIAL);
3684
3685 247317 eq := instEquations(parts.normalEquationLst, scope, connectBreaks, context);
3686 247311 ieq := instEquations(parts.initialEquationLst, scope, connectBreaks, icontext);
3687 247311 alg := instAlgorithmSections(parts.normalAlgorithmLst, scope, context);
3688 247303 ialg := instAlgorithmSections(parts.initialAlgorithmLst, scope, icontext);
3689 247303 then
3690 Sections.join(Sections.new(eq, ieq, alg, ialg), sections);
3691
3692 end match;
3693 end instSections2;
3694
3695 function instExternalDecl
3696 input SCode.ExternalDecl extDecl;
3697 input InstNode scope;
3698 input InstContext.Type context;
3699 output Sections sections;
3700 algorithm
3701 sections := match extDecl
3702 local
3703 String name;
3704 String lang;
3705 list<Expression> args;
3706 ComponentRef ret_cref;
3707 SourceInfo info;
3708
3709 case SCode.EXTERNALDECL()
3710 algorithm
3711 6851 info := InstNode.info(scope);
3712 6851 name := Util.getOptionOrDefault(extDecl.funcName, InstNode.name(scope));
3713 6851 lang := Util.getOptionOrDefault(extDecl.lang, "C");
3714 6851 checkExternalDeclLanguage(lang, info);
3715
4/4
✓ Branch 0 taken 2552 times.
✓ Branch 1 taken 6851 times.
✓ Branch 2 taken 2552 times.
✓ Branch 3 taken 6851 times.
9403 args := list(instExp(arg, scope, context, info) for arg in extDecl.args);
3716
3717
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6851 times.
✓ Branch 2 taken 1421 times.
✓ Branch 3 taken 5430 times.
6851 if isSome(extDecl.output_) then
3718 1421 ret_cref := Lookup.lookupLocalComponent(Util.getOption(extDecl.output_), scope, context, info);
3719 else
3720 ret_cref := ComponentRef.EMPTY();
3721 end if;
3722
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6851 times.
✓ Branch 2 taken 5313 times.
✓ Branch 3 taken 1538 times.
12164 then
3723 Sections.EXTERNAL(name, args, ret_cref, lang, extDecl.annotation_, isSome(extDecl.funcName), info);
3724
3725 end match;
3726 end instExternalDecl;
3727
3728 function checkExternalDeclLanguage
3729 "Checks that the language declared for an external function is valid."
3730 input String language;
3731 input SourceInfo info;
3732 algorithm
3733 () := match language
3734 // The specification also allows for C89, C99, and C11, but our code
3735 // generation only seems to support C.
3736 case "C" then ();
3737 case "FORTRAN 77" then ();
3738 // Not in the specification, but used by libraries and allowed by other tools.
3739 case "Fortran 77" then ();
3740 case "builtin" then ();
3741 else
3742 algorithm
3743 ✗ Error.addSourceMessage(Error.INVALID_EXTERNAL_LANGUAGE,
3744 {language}, info);
3745 ✗ then
3746 fail();
3747 end match;
3748 end checkExternalDeclLanguage;
3749
3750 function instEquations
3751 input list<SCode.Equation> scodeEql;
3752 input InstNode scope;
3753 input ConnectBreakTree.Tree connectBreaks;
3754 input InstContext.Type context;
3755 output list<Equation> instEql = {};
3756 algorithm
3757
2/2
✓ Branch 1 taken 510007 times.
✓ Branch 2 taken 411 times.
510418 if InstContext.inInstanceAPI(context) then
3758
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 411 times.
416 for eq in filterInstanceAPIEquations(scodeEql) loop
3759 try
3760 5 instEql := instEquation(eq, scope, connectBreaks, context, instEql);
3761 else
3762 end try;
3763 end for;
3764 else
3765
2/2
✓ Branch 0 taken 87123 times.
✓ Branch 1 taken 510000 times.
597123 for eq in scodeEql loop
3766 87123 instEql := instEquation(eq, scope, connectBreaks, context, instEql);
3767 end for;
3768 end if;
3769
3770 510411 instEql := listReverseInPlace(instEql);
3771 end instEquations;
3772
3773 function filterInstanceAPIEquations
3774 input list<SCode.Equation> eql;
3775 output list<SCode.Equation> outEql = {};
3776 protected
3777 String name;
3778 algorithm
3779
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 413 times.
419 for eq in eql loop
3780 outEql := match eq
3781 case SCode.Equation.EQ_CONNECT() then eq :: outEql;
3782
3783 case SCode.Equation.EQ_NORETCALL(exp = Absyn.Exp.CALL(function_ = Absyn.ComponentRef.CREF_IDENT(name = name)))
3784 guard name == "transition" or name == "initialState"
3785 then eq :: outEql;
3786
3787 case SCode.Equation.EQ_FOR()
3788 algorithm
3789 ✗ eq.eEquationLst := filterInstanceAPIEquations(eq.eEquationLst);
3790 ✗ then
3791 if listEmpty(eq.eEquationLst) then outEql else eq :: outEql;
3792
3793 case SCode.Equation.EQ_IF()
3794 algorithm
3795
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 eq.thenBranch := list(filterInstanceAPIEquations(eql) for eql in eq.thenBranch);
3796 1 eq.elseBranch := filterInstanceAPIEquations(eq.elseBranch);
3797
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 then
3798 if List.all(eq.thenBranch, listEmpty) and listEmpty(eq.elseBranch) then outEql else eq :: outEql;
3799
3800 else outEql;
3801 end match;
3802 end for;
3803
3804 413 outEql := listReverseInPlace(outEql);
3805 end filterInstanceAPIEquations;
3806
3807 function instEquation
3808 input SCode.Equation scodeEq;
3809 input InstNode scope;
3810 input ConnectBreakTree.Tree connectBreaks;
3811 input InstContext.Type context;
3812 input output list<Equation> equations;
3813 algorithm
3814 equations := match scodeEq
3815 local
3816 Expression exp1, exp2, exp3;
3817 Option<Expression> oexp;
3818 list<Expression> expl;
3819 list<Equation> eql;
3820 list<Equation.Branch> branches;
3821 SourceInfo info;
3822 InstNode for_scope, iter;
3823 ComponentRef lhs_cr, rhs_cr;
3824 InstContext.Type next_context;
3825
3826 case SCode.Equation.EQ_EQUALS(info = info)
3827 algorithm
3828 59288 exp1 := instExp(scodeEq.expLeft, scope, context, info);
3829 59287 exp2 := instExp(scodeEq.expRight, scope, context, info);
3830 59286 then
3831 Equation.makeEquality(exp1, exp2, Type.UNKNOWN(), makeSource(scodeEq.comment, info), scope) :: equations;
3832
3833 case SCode.Equation.EQ_CONNECT(info = info)
3834 algorithm
3835
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13400 times.
13400 if InstContext.inInitial(context) then
3836 ✗ Error.addSourceMessage(Error.CONNECT_IN_INITIAL_EQUATION, {}, info);
3837 ✗ fail();
3838 elseif InstContext.inWhen(context) then
3839 ✗ Error.addSourceMessage(Error.CONNECT_IN_WHEN,
3840 {Dump.printComponentRefStr(scodeEq.crefLeft),
3841 Dump.printComponentRefStr(scodeEq.crefRight)}, info);
3842 ✗ fail();
3843 end if;
3844
3845
2/2
✓ Branch 1 taken 13397 times.
✓ Branch 2 taken 3 times.
13400 if not ConnectBreakTree.isConnectBroken(scodeEq.crefLeft, scodeEq.crefRight, scope, connectBreaks) then
3846 13397 next_context := InstContext.set(context, NFInstContext.CONNECT);
3847 13397 lhs_cr := instConnectorCref(scodeEq.crefLeft, scope, next_context, info);
3848 13395 rhs_cr := instConnectorCref(scodeEq.crefRight, scope, next_context, info);
3849
3850 // Add the connection, unless either connector has been disabled with a 'break' modifier.
3851
3/4
✓ Branch 2 taken 13394 times.
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 13394 times.
✗ Branch 7 not taken.
13395 if not (InstNode.isEmpty(ComponentRef.node(lhs_cr)) or InstNode.isEmpty(ComponentRef.node(rhs_cr))) then
3852 13394 exp1 := Expression.CREF(Type.UNKNOWN(), lhs_cr);
3853 13394 exp2 := Expression.CREF(Type.UNKNOWN(), rhs_cr);
3854 13394 equations := Equation.CONNECT(exp1, exp2, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3855 end if;
3856 end if;
3857 then
3858 equations;
3859
3860 case SCode.Equation.EQ_FOR(info = info)
3861 algorithm
3862 1678 oexp := instExpOpt(scodeEq.range, scope, context, info);
3863 1678 checkIteratorShadowing(scodeEq.index, scope, scodeEq.info);
3864 1678 (for_scope, iter) := addIteratorToScope(scodeEq.index, scope, scodeEq.info);
3865 1678 next_context := InstContext.set(context, NFInstContext.FOR);
3866 1678 eql := instEquations(scodeEq.eEquationLst, for_scope, connectBreaks, next_context);
3867 1677 then
3868 Equation.FOR(iter, oexp, eql, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3869
3870 case SCode.Equation.EQ_IF(info = info)
3871 algorithm
3872 // Instantiate the conditions.
3873
4/4
✓ Branch 0 taken 9560 times.
✓ Branch 1 taken 7227 times.
✓ Branch 2 taken 9560 times.
✓ Branch 3 taken 7227 times.
16787 expl := list(instExp(c, scope, context, info) for c in scodeEq.condition);
3874
3875 // Instantiate each branch and pair it up with a condition.
3876 7227 next_context := InstContext.set(context, NFInstContext.IF);
3877 branches := {};
3878
2/2
✓ Branch 0 taken 9559 times.
✓ Branch 1 taken 7227 times.
16786 for branch in scodeEq.thenBranch loop
3879 9559 eql := instEquations(branch, scope, connectBreaks, next_context);
3880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9559 times.
9559 exp1 :: expl := expl;
3881 9559 branches := Equation.makeBranch(exp1, eql) :: branches;
3882 end for;
3883
3884 // Instantiate the else-branch, if there is one, and make it a branch
3885 // with condition true (so we only need a simple list of branches).
3886
2/2
✓ Branch 0 taken 4152 times.
✓ Branch 1 taken 3075 times.
7227 if not listEmpty(scodeEq.elseBranch) then
3887 4152 eql := instEquations(scodeEq.elseBranch, scope, connectBreaks, next_context);
3888 4152 branches := Equation.makeBranch(Expression.BOOLEAN(true), eql) :: branches;
3889 end if;
3890 7227 then
3891 Equation.IF(listReverse(branches), InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3892
3893 case SCode.Equation.EQ_WHEN(info = info)
3894 algorithm
3895
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 361 times.
361 if InstContext.inWhen(context) then
3896 ✗ Error.addSourceMessageAndFail(Error.NESTED_WHEN, {}, info);
3897 elseif InstContext.inInitial(context) then
3898 ✗ Error.addSourceMessageAndFail(Error.INITIAL_WHEN, {}, info);
3899 end if;
3900
3901 361 next_context := InstContext.set(context, NFInstContext.WHEN);
3902 361 exp1 := instExp(scodeEq.condition, scope, context, info);
3903 361 eql := instEquations(scodeEq.eEquationLst, scope, connectBreaks, next_context);
3904 361 branches := {Equation.makeBranch(exp1, eql)};
3905
3906
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 361 times.
401 for branch in scodeEq.elseBranches loop
3907 40 exp1 := instExp(Util.tuple21(branch), scope, context, info);
3908 40 eql := instEquations(Util.tuple22(branch), scope, connectBreaks, next_context);
3909 40 branches := Equation.makeBranch(exp1, eql) :: branches;
3910 end for;
3911 361 then
3912 Equation.WHEN(listReverse(branches), InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3913
3914 case SCode.Equation.EQ_ASSERT(info = info)
3915 algorithm
3916 3767 exp1 := instExp(scodeEq.condition, scope, context, info);
3917 3767 exp2 := instExp(scodeEq.message, scope, context, info);
3918 3767 exp3 := instExp(scodeEq.level, scope, context, info);
3919 3767 then
3920 Equation.ASSERT(exp1, exp2, exp3, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3921
3922 case SCode.Equation.EQ_TERMINATE(info = info)
3923 algorithm
3924 9 exp1 := instExp(scodeEq.message, scope, context, info);
3925 9 then
3926 Equation.TERMINATE(exp1, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3927
3928 case SCode.Equation.EQ_REINIT(info = info)
3929 algorithm
3930
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 43 times.
44 if not InstContext.inWhen(context) then
3931 1 Error.addSourceMessage(Error.REINIT_NOT_IN_WHEN, {}, info);
3932 1 fail();
3933 end if;
3934
3935 43 exp1 := instExp(scodeEq.cref, scope, context, info);
3936 43 exp2 := instExp(scodeEq.expReinit, scope, context, info);
3937 43 then
3938 Equation.REINIT(exp1, exp2, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3939
3940 case SCode.Equation.EQ_NORETCALL(info = info)
3941 algorithm
3942 1353 exp1 := instExp(scodeEq.exp, scope, context, info);
3943 1353 then
3944 Equation.NORETCALL(exp1, InstNode.identityCell(scope), makeSource(scodeEq.comment, info)) :: equations;
3945
3946 else
3947 algorithm
3948 ✗ Error.terminate(getInstanceName() + " got unknown equation", sourceInfo());
3949 ✗ then
3950 fail();
3951
3952 end match;
3953 end instEquation;
3954
3955 function instConnectorCref
3956 input Absyn.ComponentRef absynCref;
3957 input InstNode scope;
3958 input InstContext.Type context;
3959 input SourceInfo info;
3960 output ComponentRef cref;
3961 protected
3962 InstNode found_scope;
3963 algorithm
3964 26792 (cref, found_scope) := Lookup.lookupConnector(absynCref, scope, context, info);
3965 26790 cref := instCrefSubscripts(cref, scope, context, info);
3966 26790 cref := ComponentRef.appendScope(found_scope, cref);
3967 end instConnectorCref;
3968
3969 function makeSource
3970 input SCode.Comment comment;
3971 input SourceInfo info;
3972 output DAE.ElementSource source;
3973 algorithm
3974 210022 source := DAE.ElementSource.SOURCE(info, {}, DAE.NOCOMPPRE(), {}, {}, {}, {comment});
3975 end makeSource;
3976
3977 function instAlgorithmSections
3978 input list<SCode.AlgorithmSection> algorithmSections;
3979 input InstNode scope;
3980 input InstContext.Type context;
3981 output list<Algorithm> algs;
3982 algorithm
3983
2/2
✓ Branch 1 taken 494204 times.
✓ Branch 2 taken 410 times.
494614 if InstContext.inInstanceAPI(context) then
3984 algs := {};
3985 else
3986
4/4
✓ Branch 0 taken 16990 times.
✓ Branch 1 taken 494196 times.
✓ Branch 2 taken 16990 times.
✓ Branch 3 taken 494196 times.
511186 algs := list(instAlgorithmSection(alg, scope, context) for alg in algorithmSections);
3987 end if;
3988 end instAlgorithmSections;
3989
3990 function instAlgorithmSection
3991 input SCode.AlgorithmSection algorithmSection;
3992 input InstNode scope;
3993 input InstContext.Type context;
3994 output Algorithm alg;
3995 protected
3996 list<Statement> statements;
3997 algorithm
3998 // collect inputs and outputs later when types are computed properly
3999 16990 statements := instStatements(algorithmSection.statements, scope, context);
4000 16982 alg := Algorithm.ALGORITHM(statements, {}, {}, NONE(), InstNode.identityCell(scope), DAE.emptyElementSource);
4001 end instAlgorithmSection;
4002
4003 function instStatements
4004 input list<SCode.Statement> scodeStmtl;
4005 input InstNode scope;
4006 input InstContext.Type context;
4007 output list<Statement> statements;
4008 algorithm
4009
4/4
✓ Branch 0 taken 122916 times.
✓ Branch 1 taken 31245 times.
✓ Branch 2 taken 122916 times.
✓ Branch 3 taken 31245 times.
154161 statements := list(instStatement(stmt, scope, context) for stmt in scodeStmtl);
4010 end instStatements;
4011
4012 function instStatement
4013 input SCode.Statement scodeStmt;
4014 input InstNode scope;
4015 input InstContext.Type context;
4016 output Statement statement;
4017 algorithm
4018 statement := match scodeStmt
4019 local
4020 Expression exp1, exp2, exp3;
4021 Option<Expression> oexp;
4022 list<Statement> stmtl;
4023 list<tuple<Expression, list<Statement>>> branches;
4024 SourceInfo info;
4025 InstNode for_scope, iter;
4026 InstContext.Type next_context;
4027
4028 case SCode.Statement.ALG_ASSIGN(info = info)
4029 algorithm
4030 112712 exp1 := instExp(scodeStmt.assignComponent, scope, context, info);
4031 112712 checkAssignmentRestriction(exp1, info);
4032 112710 exp2 := instExp(scodeStmt.value, scope, context, info);
4033 112709 then
4034 Statement.ASSIGNMENT(exp1, exp2, Type.UNKNOWN(), makeSource(scodeStmt.comment, info));
4035
4036 case SCode.Statement.ALG_FOR(info = info)
4037 algorithm
4038 715 oexp := instExpOpt(scodeStmt.range, scope, context, info);
4039 715 (for_scope, iter) := addIteratorToScope(scodeStmt.index, scope, info);
4040 715 next_context := InstContext.set(context, NFInstContext.FOR);
4041 715 stmtl := instStatements(scodeStmt.forBody, for_scope, next_context);
4042 713 then
4043 Statement.FOR(iter, oexp, stmtl, Statement.ForType.NORMAL(), makeSource(scodeStmt.comment, info), {});
4044
4045 case SCode.Statement.ALG_PARFOR(info = info)
4046 algorithm
4047 ✗ oexp := instExpOpt(scodeStmt.range, scope, context, info);
4048 ✗ (for_scope, iter) := addIteratorToScope(scodeStmt.index, scope, info);
4049 ✗ next_context := InstContext.set(context, NFInstContext.FOR);
4050 ✗ stmtl := instStatements(scodeStmt.parforBody, for_scope, next_context);
4051 ✗ then
4052 Statement.FOR(iter, oexp, stmtl, Statement.ForType.PARALLEL({}), makeSource(scodeStmt.comment, info), {});
4053
4054 case SCode.Statement.ALG_IF(info = info)
4055 algorithm
4056 branches := {};
4057 6152 next_context := InstContext.set(context, NFInstContext.FOR);
4058
4059
2/2
✓ Branch 2 taken 8573 times.
✓ Branch 3 taken 6152 times.
14725 for branch in (scodeStmt.boolExpr, scodeStmt.trueBranch) :: scodeStmt.elseIfBranch loop
4060 8573 exp1 := instExp(Util.tuple21(branch), scope, context, info);
4061 8573 stmtl := instStatements(Util.tuple22(branch), scope, next_context);
4062 8573 branches := (exp1, stmtl) :: branches;
4063 end for;
4064
4065
2/2
✓ Branch 0 taken 4531 times.
✓ Branch 1 taken 1621 times.
6152 if not listEmpty(scodeStmt.elseBranch) then
4066 4531 stmtl := instStatements(scodeStmt.elseBranch, scope, next_context);
4067 4531 branches := (Expression.BOOLEAN(true), stmtl) :: branches;
4068 end if;
4069 6152 then
4070 Statement.IF(listReverse(branches), makeSource(scodeStmt.comment, info));
4071
4072 case SCode.Statement.ALG_WHEN_A(info = info)
4073 algorithm
4074
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 88 times.
91 if not InstContext.inValidWhenScope(context) then
4075
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 if InstContext.inWhen(context) then
4076 1 Error.addSourceMessageAndFail(Error.NESTED_WHEN, {}, info);
4077 elseif InstContext.inInitial(context) then
4078 ✗ Error.addSourceMessageAndFail(Error.INITIAL_WHEN, {}, info);
4079 else
4080 2 Error.addSourceMessageAndFail(Error.INVALID_WHEN_STATEMENT_CONTEXT, {}, info);
4081 end if;
4082 end if;
4083
4084 branches := {};
4085
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 87 times.
211 for branch in scodeStmt.branches loop
4086 124 exp1 := instExp(Util.tuple21(branch), scope, context, info);
4087 124 next_context := InstContext.set(context, NFInstContext.WHEN);
4088 124 stmtl := instStatements(Util.tuple22(branch), scope, next_context);
4089 123 branches := (exp1, stmtl) :: branches;
4090 end for;
4091 87 then
4092 Statement.WHEN(listReverse(branches), makeSource(scodeStmt.comment, info));
4093
4094 case SCode.Statement.ALG_ASSERT(info = info)
4095 algorithm
4096 2766 exp1 := instExp(scodeStmt.condition, scope, context, info);
4097 2766 exp2 := instExp(scodeStmt.message, scope, context, info);
4098 2766 exp3 := instExp(scodeStmt.level, scope, context, info);
4099 2766 then
4100 Statement.ASSERT(exp1, exp2, exp3, makeSource(scodeStmt.comment, info));
4101
4102 case SCode.Statement.ALG_TERMINATE(info = info)
4103 algorithm
4104 2 exp1 := instExp(scodeStmt.message, scope, context, info);
4105 2 then
4106 Statement.TERMINATE(exp1, makeSource(scodeStmt.comment, info));
4107
4108 case SCode.Statement.ALG_REINIT(info = info)
4109 algorithm
4110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if not Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "reinitInAlgorithms") then
4111 ✗ Error.addSourceMessage(Error.REINIT_IN_ALGORITHM, {}, info);
4112 ✗ fail();
4113 end if;
4114
4115
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if not InstContext.inWhen(context) then
4116 ✗ Error.addSourceMessage(Error.REINIT_NOT_IN_WHEN, {}, info);
4117 ✗ fail();
4118 end if;
4119
4120 4 exp1 := instExp(scodeStmt.cref, scope, context, info);
4121 4 exp2 := instExp(scodeStmt.newValue, scope, context, info);
4122 4 then
4123 Statement.REINIT(exp1, exp2, makeSource(scodeStmt.comment, info));
4124
4125 case SCode.Statement.ALG_NORETCALL(info = info)
4126 algorithm
4127 135 exp1 := instExp(scodeStmt.exp, scope, context, info);
4128 135 then
4129 Statement.NORETCALL(exp1, makeSource(scodeStmt.comment, info));
4130
4131 case SCode.Statement.ALG_WHILE(info = info)
4132 algorithm
4133 323 exp1 := instExp(scodeStmt.boolExpr, scope, context, info);
4134 323 next_context := InstContext.set(context, NFInstContext.WHILE);
4135 323 stmtl := instStatements(scodeStmt.whileBody, scope, next_context);
4136 323 then
4137 Statement.WHILE(exp1, stmtl, makeSource(scodeStmt.comment, info));
4138
4139 case SCode.Statement.ALG_RETURN()
4140 algorithm
4141
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 9 times.
10 if not InstContext.inFunction(context) then
4142 1 Error.addSourceMessage(Error.RETURN_OUTSIDE_FUNCTION, {}, scodeStmt.info);
4143 1 fail();
4144 end if;
4145 9 then
4146 Statement.RETURN(makeSource(scodeStmt.comment, scodeStmt.info));
4147
4148 case SCode.Statement.ALG_BREAK()
4149 algorithm
4150
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5 times.
6 if not InstContext.inLoop(context) then
4151 1 Error.addSourceMessage(Error.BREAK_OUTSIDE_LOOP, {}, scodeStmt.info);
4152 1 fail();
4153 end if;
4154 5 then
4155 Statement.BREAK(makeSource(scodeStmt.comment, scodeStmt.info));
4156
4157 case SCode.Statement.ALG_FAILURE()
4158 algorithm
4159 ✗ stmtl := instStatements(scodeStmt.stmts, scope, context);
4160 ✗ then
4161 Statement.FAILURE(stmtl, makeSource(scodeStmt.comment, scodeStmt.info));
4162
4163 else
4164 algorithm
4165 ✗ Error.terminate(getInstanceName() + " got unknown statement", sourceInfo());
4166 ✗ then
4167 fail();
4168
4169 end match;
4170 end instStatement;
4171
4172 function checkAssignmentRestriction
4173 input Expression lhs;
4174 input SourceInfo info;
4175 protected
4176 InstNode node;
4177 Restriction res;
4178 algorithm
4179 () := match lhs
4180 case Expression.CREF()
4181 guard ComponentRef.isIterator(lhs.cref)
4182 algorithm
4183 // Give an error if assigning to an iterator.
4184 2 Error.addSourceMessage(Error.ASSIGN_ITERATOR_ERROR,
4185 {ComponentRef.toString(lhs.cref)}, info);
4186 1 then
4187 fail();
4188
4189 case Expression.CREF()
4190 guard ComponentRef.isCref(lhs.cref)
4191 algorithm
4192 113740 node := ComponentRef.node(lhs.cref);
4193 113740 res := Class.restriction(InstNode.getClass(node));
4194
4195 () := match res
4196 case Restriction.CLOCK() then ();
4197 case Restriction.CONNECTOR() then ();
4198 case Restriction.ENUMERATION() then ();
4199 case Restriction.RECORD() then ();
4200 case Restriction.TYPE() then ();
4201 else
4202 algorithm
4203 3 Error.addSourceMessage(Error.INVALID_SPECIALIZATION_IN_ASSIGNMENT,
4204 {InstNode.name(node), Restriction.toString(res)}, info);
4205 1 then
4206 fail();
4207 end match;
4208 then
4209 ();
4210
4211 case Expression.TUPLE()
4212 algorithm
4213
2/2
✓ Branch 0 taken 1844 times.
✓ Branch 1 taken 813 times.
2657 for e in lhs.elements loop
4214 1844 checkAssignmentRestriction(e, info);
4215 end for;
4216 then
4217 ();
4218
4219 else ();
4220 end match;
4221 end checkAssignmentRestriction;
4222
4223 function addIteratorToScope
4224 input String name;
4225 input output InstNode scope;
4226 input SourceInfo info;
4227 input Type iter_type = Type.UNKNOWN();
4228 output InstNode iterator;
4229 protected
4230 Component iter_comp;
4231 algorithm
4232 4169 scope := InstNode.openImplicitScope(scope);
4233 4169 iter_comp := Component.ITERATOR(iter_type, Variability.CONTINUOUS, info);
4234 4169 iterator := InstNode.fromComponent(name, iter_comp, scope);
4235 4169 scope := InstNode.addIterator(iterator, scope);
4236 end addIteratorToScope;
4237
4238 function checkIteratorShadowing
4239 "Gives a warning if the given iterator name is already used in an outer
4240 implicit scope."
4241 input String name;
4242 input InstNode scope;
4243 input SourceInfo info;
4244 algorithm
4245 () := match scope
4246 case InstNode.IMPLICIT_SCOPE()
4247 algorithm
4248
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 29 times.
61 for iter in scope.locals loop
4249
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 32 times.
32 if InstNode.name(iter) == name then
4250 ✗ Error.addMultiSourceMessage(Error.SHADOWED_ITERATOR,
4251 {name}, {InstNode.info(iter), info});
4252 ✗ return;
4253 end if;
4254 end for;
4255 then
4256 ();
4257
4258 else ();
4259 end match;
4260 end checkIteratorShadowing;
4261
4262 function insertGeneratedInners
4263 "Inner elements can be generated automatically during instantiation if they're
4264 missing, and are stored in the cache of the top scope since that's easily
4265 accessible during lookup. This function copies any such inner elements into
4266 the class we're instantiating, so that they are typed and flattened properly."
4267 input InstNode node;
4268 input InstNode topScope;
4269 input InstContext.Type context;
4270 protected
4271 UnorderedMap<String, InstNode> generated_inners;
4272 list<Mutable<InstNode>> inner_comps;
4273 InstNode n;
4274 String name, str;
4275 Class cls;
4276 ClassTree cls_tree;
4277 InstNode base_node;
4278 algorithm
4279
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1647 times.
1647 InstNodeType.TOP_SCOPE(generatedInners = generated_inners) := InstNode.nodeType(topScope);
4280
4281 // No inners => nothing more to do.
4282
2/2
✓ Branch 1 taken 1633 times.
✓ Branch 2 taken 14 times.
1647 if UnorderedMap.isEmpty(generated_inners) then
4283 1633 return;
4284 end if;
4285
4286 14 inner_comps := {};
4287
4288
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 10 times.
38 for n in UnorderedMap.valueArray(generated_inners) loop
4289 14 name := InstNode.name(n);
4290 14 checkTopLevelOuter(name, n, node, context);
4291
4292 // Always print a warning that an inner element was automatically generated.
4293
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 time.
10 if not InstContext.inInstanceAPI(context) then
4294 18 Error.addSourceMessage(Error.MISSING_INNER_ADDED,
4295 {InstNode.typeName(n), name}, InstNode.info(n));
4296 end if;
4297
4298 // Only components needs to be added to the class, since classes are
4299 // not part of the flat class.
4300
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 time.
10 if InstNode.isComponent(n) then
4301 // The component might have been instantiated during lookup, otherwise do
4302 // it here (instComponent will skip already instantiated components).
4303 9 instComponent(n, NFAttributes.DEFAULT_ATTR, Modifier.NOMOD(), true, 0, NFInstContext.CLASS);
4304
4305 // If the component's class has a missingInnerMessage annotation, use it
4306 // to give a diagnostic message.
4307
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
9 if not InstContext.inInstanceAPI(context) then
4308 try
4309
4/6
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
8 SOME(Absyn.STRING(str)) := SCodeUtil.lookupElementAnnotationBinding(
4310 InstNode.definition(InstNode.classScope(n)), "missingInnerMessage");
4311 14 Error.addSourceMessage(Error.MISSING_INNER_MESSAGE, {System.unescapedString(str)}, InstNode.info(n));
4312 else
4313 end try;
4314 end if;
4315
4316 // Add the instantiated component to the list.
4317 9 inner_comps := Mutable.create(n) :: inner_comps;
4318 end if;
4319 end for;
4320
4321 // If we found any components, add them to the component list of the class tree.
4322
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9 times.
10 if not listEmpty(inner_comps) then
4323 9 base_node := Class.lastBaseClass(node);
4324 9 cls := InstNode.getClass(base_node);
4325 9 cls_tree := ClassTree.appendComponentsToInstTree(inner_comps, Class.classTree(cls));
4326 9 InstNode.updateClass(Class.setClassTree(cls_tree, cls), base_node);
4327 end if;
4328 end insertGeneratedInners;
4329
4330 function checkTopLevelOuter
4331 input String name;
4332 input InstNode outerNode;
4333 input InstNode scope;
4334 input InstContext.Type context;
4335 protected
4336 InstNode node;
4337 Boolean is_error;
4338 algorithm
4339
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 13 times.
14 if InstContext.inInstanceAPI(context) then
4340 1 return;
4341 end if;
4342
4343 try
4344 13 node := Lookup.lookupSimpleName(name, scope, context);
4345
4346
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 time.
11 if InstNode.isInner(node) then
4347
4/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
10 is_error := not (InstContext.inRelaxed(context) or Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdTopLevelOuter"));
4348
4349 if is_error then
4350 3 Error.addSourceMessageAsError(Error.TOP_LEVEL_OUTER, {name}, InstNode.info(node));
4351 else
4352 7 Error.addSourceMessage(Error.TOP_LEVEL_OUTER, {name}, InstNode.info(node));
4353 end if;
4354 else
4355 3 Error.addMultiSourceMessage(Error.MISSING_INNER_NAME_CONFLICT,
4356 {name}, {InstNode.info(node), InstNode.info(outerNode)});
4357 is_error := true;
4358 end if;
4359 else
4360 is_error := false;
4361 end try;
4362
4363
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if is_error then
4364 4 fail();
4365 end if;
4366 end checkTopLevelOuter;
4367
4368 function updateImplicitVariability
4369 input InstNode node;
4370 input Boolean parentEval;
4371 input InstContext.Type context;
4372 protected
4373 Class cls = InstNode.getClass(node);
4374 ClassTree cls_tree;
4375 algorithm
4376 () := match cls
4377 case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE())
4378 algorithm
4379
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 57812 times.
✓ Branch 3 taken 414600 times.
✓ Branch 4 taken 57812 times.
530224 for c in cls_tree.components loop
4380 414600 updateImplicitVariabilityComp(c, parentEval, context);
4381 end for;
4382
4383 57812 Sections.apply(cls.sections,
4384 function updateImplicitVariabilityEq(inWhen = false),
4385 updateImplicitVariabilityAlg);
4386 then
4387 ();
4388
4389 case Class.EXPANDED_DERIVED()
4390 algorithm
4391
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 245901 times.
✓ Branch 3 taken 4790 times.
✓ Branch 4 taken 245901 times.
496592 for dim in cls.dims loop
4392 4790 Structural.markDimension(dim);
4393 end for;
4394
4395 245901 updateImplicitVariability(cls.baseClass, parentEval, context);
4396 then
4397 ();
4398
4399 case Class.INSTANCED_BUILTIN(elements = cls_tree as ClassTree.FLAT_TREE())
4400 algorithm
4401
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 226704 times.
✓ Branch 3 taken 2324720 times.
✓ Branch 4 taken 226704 times.
2778128 for c in cls_tree.components loop
4402 2324720 updateImplicitVariabilityComp(c, parentEval, context);
4403 end for;
4404 then
4405 ();
4406
4407 else ();
4408 end match;
4409 end updateImplicitVariability;
4410
4411 function isForcedStructural
4412 "Whether translateModel asked to evaluate the parameter, see Global.structuralParameters."
4413 input InstNode node;
4414 output Boolean res;
4415 protected
4416 list<String> names = getGlobalRoot(Global.structuralParameters);
4417 algorithm
4418
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 99475 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 time.
99478 res := not listEmpty(names) and listMember(AbsynUtil.pathString(InstNode.scopePath(node)), names);
4419 end isForcedStructural;
4420
4421 function updateImplicitVariabilityComp
4422 input InstNode component;
4423 input Boolean parentEval;
4424 input InstContext.Type context;
4425 protected
4426 InstNode node;
4427 Component c;
4428 algorithm
4429
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2739315 times.
2739320 if InstNode.isEmpty(component) then
4430 5 return;
4431 end if;
4432
4433 2739315 node := InstNode.resolveOuter(component);
4434 2739315 c := InstNode.component(node);
4435
4436 () := match c
4437 local
4438 Binding binding, condition;
4439 Option<Boolean> opt_eval;
4440 Boolean eval;
4441
4442 case Component.COMPONENT(binding = binding, condition = condition)
4443 algorithm
4444 282774 opt_eval := Component.getEvaluateAnnotation(c);
4445 282774 eval := Util.getOptionOrDefault(opt_eval, false);
4446
4447
7/8
✗ Branch 0 not taken.
✓ Branch 1 taken 282774 times.
✓ Branch 2 taken 11631 times.
✓ Branch 3 taken 271143 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 11623 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 1 time.
282774 if isSome(opt_eval) and not eval and c.attributes.variability == Variability.PARAMETER then
4448 // If the component is a parameter with Evaluate=false,
4449 // mark it as non-structural to try to avoid it being evaluated.
4450 7 InstNode.updateComponent(Component.setVariability(Variability.NON_STRUCTURAL_PARAMETER, c), node);
4451 else
4452 // Otherwise check if we should mark it as structural.
4453
8/8
✓ Branch 0 taken 271144 times.
✓ Branch 1 taken 11623 times.
✓ Branch 2 taken 99478 times.
✓ Branch 3 taken 171666 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 99477 times.
✓ Branch 8 taken 23604 times.
✓ Branch 9 taken 259163 times.
282768 if Structural.isStructuralComponent(c, c.attributes, binding, node,
4454 eval or (c.attributes.variability == Variability.PARAMETER and isForcedStructural(node)), parentEval, context) then
4455 23604 Structural.markComponent(c, node);
4456 end if;
4457 end if;
4458
4459 // Parameters used in array dimensions are structural.
4460
2/2
✓ Branch 1 taken 61554 times.
✓ Branch 2 taken 282774 times.
344328 for dim in Type.arrayDims(c.ty) loop
4461 61554 Structural.markDimension(dim);
4462 end for;
4463
4464 // Parameters that determine the size of a component binding are structural.
4465
2/2
✓ Branch 1 taken 108661 times.
✓ Branch 2 taken 174113 times.
282774 if Binding.isBound(binding) then
4466 108661 Structural.markExpSize(Binding.getUntypedExp(binding));
4467 end if;
4468
4469 // Parameters used in a component condition are structural.
4470
2/2
✓ Branch 1 taken 5742 times.
✓ Branch 2 taken 277032 times.
282774 if Binding.isBound(condition) then
4471 5742 Structural.markExp(Binding.getUntypedExp(condition));
4472 end if;
4473
4474
2/2
✓ Branch 1 taken 282771 times.
✓ Branch 2 taken 3 times.
282774 if not InstNode.isEmpty(c.classInst) then
4475 282771 updateImplicitVariability(c.classInst, eval or parentEval, context);
4476 end if;
4477 then
4478 ();
4479
4480 case Component.TYPE_ATTRIBUTE()
4481 guard listMember(InstNode.name(component), {"fixed", "stateSelect"})
4482 algorithm
4483 453959 binding := Modifier.binding(c.modifier);
4484
4485
2/2
✓ Branch 1 taken 5923 times.
✓ Branch 2 taken 448036 times.
453959 if Binding.isBound(binding) then
4486 5923 Structural.markExp(Binding.getUntypedExp(binding));
4487 end if;
4488 then
4489 ();
4490
4491 else ();
4492 end match;
4493 end updateImplicitVariabilityComp;
4494
4495 function updateImplicitVariabilityEql
4496 input list<Equation> eql;
4497 input Boolean inWhen = false;
4498 algorithm
4499
2/2
✓ Branch 0 taken 27639 times.
✓ Branch 1 taken 15786 times.
43425 for eq in eql loop
4500 27639 updateImplicitVariabilityEq(eq, inWhen);
4501 end for;
4502 end updateImplicitVariabilityEql;
4503
4504 function updateImplicitVariabilityEq
4505 input Equation eq;
4506 input Boolean inWhen = false;
4507 algorithm
4508 () := match eq
4509 local
4510
4511 case Equation.EQUALITY()
4512 algorithm
4513
2/2
✓ Branch 0 taken 523 times.
✓ Branch 1 taken 58762 times.
59285 if inWhen then
4514 523 markImplicitWhenExp(eq.lhs);
4515 end if;
4516 then
4517 ();
4518
4519 case Equation.CONNECT()
4520 algorithm
4521 13386 Structural.markSubscriptsInExp(eq.lhs);
4522 13386 Structural.markSubscriptsInExp(eq.rhs);
4523 then
4524 ();
4525
4526 case Equation.FOR()
4527 algorithm
4528 1675 updateImplicitVariabilityEql(eq.body, inWhen);
4529 then
4530 ();
4531
4532 case Equation.IF()
4533 algorithm
4534
2/2
✓ Branch 0 taken 13710 times.
✓ Branch 1 taken 7226 times.
20936 for branch in eq.branches loop
4535 () := match branch
4536 case Equation.Branch.BRANCH()
4537 algorithm
4538 13710 updateImplicitVariabilityEql(branch.body, inWhen);
4539 then
4540 ();
4541 end match;
4542 end for;
4543 then
4544 ();
4545
4546 case Equation.WHEN()
4547 algorithm
4548
2/2
✓ Branch 0 taken 401 times.
✓ Branch 1 taken 361 times.
762 for branch in eq.branches loop
4549 () := match branch
4550 case Equation.Branch.BRANCH()
4551 algorithm
4552 401 updateImplicitVariabilityEql(branch.body, inWhen = true);
4553 then
4554 ();
4555 end match;
4556 end for;
4557 then
4558 ();
4559
4560 else ();
4561 end match;
4562 end updateImplicitVariabilityEq;
4563
4564 function updateImplicitVariabilityAlg
4565 input Algorithm alg;
4566 algorithm
4567 201 updateImplicitVariabilityStmts(alg.statements);
4568 end updateImplicitVariabilityAlg;
4569
4570 function updateImplicitVariabilityStmts
4571 input list<Statement> stmtl;
4572 input Boolean inWhen = false;
4573 algorithm
4574
2/2
✓ Branch 0 taken 651 times.
✓ Branch 1 taken 342 times.
993 for s in stmtl loop
4575 651 updateImplicitVariabilityStmt(s, inWhen);
4576 end for;
4577 end updateImplicitVariabilityStmts;
4578
4579 function updateImplicitVariabilityStmt
4580 input Statement stmt;
4581 input Boolean inWhen;
4582 algorithm
4583 () := match stmt
4584 case Statement.ASSIGNMENT()
4585 algorithm
4586
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 191 times.
370 if inWhen then
4587 179 markImplicitWhenExp(stmt.lhs);
4588 end if;
4589 then
4590 ();
4591
4592 case Statement.FOR()
4593 algorithm
4594 // 'when' is not allowed in 'for', so we only need to keep going if
4595 // we're already in a 'when'.
4596
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 74 times.
78 if inWhen then
4597 4 updateImplicitVariabilityStmts(stmt.body, true);
4598 end if;
4599 then
4600 ();
4601
4602 case Statement.IF()
4603 algorithm
4604 // 'when' is not allowed in 'if', so we only need to keep going if
4605 // we're already in a 'when.
4606
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 43 times.
63 if inWhen then
4607
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for branch in stmt.branches loop
4608 20 updateImplicitVariabilityStmts(Util.tuple22(branch), true);
4609 end for;
4610 end if;
4611 then
4612 ();
4613
4614 case Statement.WHEN()
4615 algorithm
4616
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 83 times.
200 for branch in stmt.branches loop
4617 117 updateImplicitVariabilityStmts(Util.tuple22(branch), true);
4618 end for;
4619 then
4620 ();
4621
4622 case Statement.WHILE()
4623 algorithm
4624 // 'when' is not allowed in 'while', so we only need to keep going if
4625 // we're already in a 'when.
4626 ✗ if inWhen then
4627 ✗ updateImplicitVariabilityStmts(stmt.body, true);
4628 end if;
4629 then
4630 ();
4631
4632 else ();
4633 end match;
4634 end updateImplicitVariabilityStmt;
4635
4636 function markImplicitWhenExp
4637 input Expression exp;
4638 algorithm
4639 702 Expression.apply(exp, markImplicitWhenExp_traverser);
4640 end markImplicitWhenExp;
4641
4642 function markImplicitWhenExp_traverser
4643 input Expression exp;
4644 algorithm
4645 () := match exp
4646 local
4647 InstNode node;
4648 Component comp;
4649
4650 case Expression.CREF(cref = ComponentRef.CREF())
4651 algorithm
4652 756 node := ComponentRef.node(exp.cref);
4653
4654
1/2
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
756 if InstNode.isComponent(node) then
4655 756 comp := InstNode.component(node);
4656
4657
2/2
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 588 times.
756 if Component.variability(comp) == Variability.CONTINUOUS then
4658 168 comp := Component.setVariability(Variability.IMPLICITLY_DISCRETE, comp);
4659 168 InstNode.updateComponent(comp, node);
4660 end if;
4661 end if;
4662 then
4663 ();
4664
4665 else ();
4666 end match;
4667 end markImplicitWhenExp_traverser;
4668
4669 function checkPartialClass
4670 input InstNode node;
4671 input InstContext.Type context;
4672 algorithm
4673
4/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1631 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 time.
1634 if InstNode.isPartial(node) and not InstContext.inRelaxed(context) then
4674 2 Error.addSourceMessage(Error.INST_PARTIAL_CLASS,
4675 {InstNode.name(node)}, InstNode.info(node));
4676 1 fail();
4677 end if;
4678 end checkPartialClass;
4679
4680 function checkInstanceRestriction
4681 input InstNode node;
4682 input Absyn.Path path;
4683 input InstContext.Type context;
4684 protected
4685 SCode.Element elem;
4686 algorithm
4687
2/2
✓ Branch 1 taken 4498 times.
✓ Branch 2 taken 1567 times.
6065 if InstContext.inRelaxed(context) then
4688 4498 return;
4689 end if;
4690
4691 1567 elem := InstNode.definition(node);
4692
4693
3/4
✓ Branch 1 taken 1566 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1566 times.
1567 if SCodeUtil.isFunction(elem) or SCodeUtil.isPackage(elem) then
4694 3 Error.addSourceMessage(Error.INST_INVALID_RESTRICTION,
4695 {AbsynUtil.pathString(path),
4696 SCodeDump.restrString(SCodeUtil.getClassRestriction(elem))},
4697 InstNode.info(node));
4698 1 fail();
4699 end if;
4700 end checkInstanceRestriction;
4701
4702 annotation(__OpenModelica_Interface="nf_frontend");
4703 end NFInst;
4704