Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 75.7% 134 / 0 / 177
Functions: -% 0 / 1 / 1
Branches: 51.4% 72 / 0 / 140

OMCompiler/Compiler/Script/SymbolTable.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 uniontype SymbolTable
37 " file: SymbolTable.mo
38 package: SymbolTable
39 description: Thread-local, mutable symbol table. Set this at the start
40 of any interactive call or in Main.
41 "
42
43 import Absyn;
44 import FCore;
45 import InteractiveTypes;
46 import SCode;
47 import Values;
48 import Vector;
49
50 protected
51 import AvlTreeStringString;
52 import CevalFunction;
53 import DAE;
54 import Error;
55 import FGraph;
56 import Global;
57 import Inst;
58 import Lookup;
59 import List;
60 import AbsynToSCode;
61 import BackendInterface;
62 import Config;
63 import MetaUtil;
64 import System;
65 import SCodeUtil;
66 import UnorderedMap;
67 import Util;
68 protected import ComponentReferenceBasics;
69
70 public
71
72 record SYMBOLTABLE
73 Absyn.Program ast "ast ; The ast" ;
74 Option<SCode.Program> explodedAst "the explodedAst is invalidated every time the program is updated";
75 list<InteractiveTypes.Variable> vars "List of variables with values" ;
76 Vector<Absyn.Program> cachedAsts;
77 Integer cacheIndex;
78 tuple<Boolean,Boolean,Boolean,Boolean> connectorFlags
79 "has inner/outer, expandable, overconstrained and stream connectors; a side
80 effect of translating explodedAst that the old frontend reads later. Stored
81 here so getSCode can re-assert it on a cache hit, since an intervening
82 translation or NFInst.resetGlobalFlags may have cleared the global flags.";
83 Option<tuple<Absyn.Program, SCode.Program, tuple<Boolean,Boolean,Boolean,Boolean>>> scodeBase
84 "the last translated program, its SCode and connector flags, set while
85 explodedAst is invalid; getSCode only translates the top-level classes
86 that changed since then";
87 end SYMBOLTABLE;
88
89 constant Integer AST_CACHE_MAX_SIZE = 1000;
90
91 function reset
92 type Program = Absyn.Program;
93 algorithm
94 2683 setGlobalRoot(Global.symbolTable, SYMBOLTABLE(
95 ast=Absyn.PROGRAM({},Absyn.TOP()),
96 explodedAst=NONE(),
97 vars={},
98 cachedAsts=Vector.new<Program>(),
99 cacheIndex=0,
100 connectorFlags=(false,false,false,false),
101 scodeBase=NONE()
102 ));
103 2683 updateUriMapping({});
104 end reset;
105
106 function currentConnectorFlags
107 "Reads the global connector flags set as a side effect of translating SCode."
108 output tuple<Boolean,Boolean,Boolean,Boolean> flags;
109 algorithm
110
7/8
✓ Branch 1 taken 3911 times.
✓ Branch 2 taken 854 times.
✓ Branch 4 taken 4765 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3954 times.
✓ Branch 8 taken 811 times.
✓ Branch 10 taken 3883 times.
✓ Branch 11 taken 882 times.
21278 flags := (System.getHasInnerOuterDefinitions(), System.getHasExpandableConnectors(),
111 System.getHasOverconstrainedConnectors(), System.getHasStreamConnectors());
112 end currentConnectorFlags;
113
114 function applyConnectorFlags
115 "Restores the global connector flags to match the cached SCode."
116 input tuple<Boolean,Boolean,Boolean,Boolean> flags;
117 protected
118 Boolean io, ec, oc, sc;
119 algorithm
120 33479 (io, ec, oc, sc) := flags;
121 33479 System.setHasInnerOuterDefinitions(io);
122 33479 System.setHasExpandableConnectors(ec);
123 33479 System.setHasOverconstrainedConnectors(oc);
124 33479 System.setHasStreamConnectors(sc);
125 end applyConnectorFlags;
126
127 function update
128 input SymbolTable table;
129 algorithm
130 19951 setGlobalRoot(Global.symbolTable, table);
131 end update;
132
133 function get
134 output SymbolTable table;
135 algorithm
136 112204 table := getGlobalRoot(Global.symbolTable);
137 end get;
138
139 function getAbsyn
140 output Absyn.Program ast;
141 protected
142 SymbolTable table;
143 algorithm
144 30924 table := get();
145 30924 ast := table.ast;
146 end getAbsyn;
147
148 function setAbsyn
149 input Absyn.Program ast;
150 protected
151 SymbolTable table;
152 algorithm
153 2952 table := get();
154
2/2
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 2557 times.
2952 if referenceEq(table.ast, ast) then
155 395 return;
156 end if;
157
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2557 times.
✓ Branch 2 taken 1292 times.
✓ Branch 3 taken 1265 times.
2557 if isSome(table.explodedAst) then
158 2584 table.scodeBase := SOME((table.ast, Util.getOption(table.explodedAst), table.connectorFlags));
159 table.explodedAst := NONE();
160 end if;
161 2557 table.ast := ast;
162 2557 updateUriMapping(ast.classes);
163 2557 update(table);
164 end setAbsyn;
165
166 function setAbsynElement
167 "Sets the Absyn program in the symbol table like setAbsyn, but also updates
168 the SCode if it's cached. This can be used to avoid invalidating the whole
169 SCode program when only updating a single element in the Absyn."
170 input Absyn.Program ast;
171 input Absyn.Element element;
172 input Absyn.Path path;
173 protected
174 SymbolTable table;
175 SCode.Element scode_elem;
176 list<SCode.Element> scode_elems, scode_prog;
177
178 function update_element
179 input SCode.Element oldElement;
180 input output SCode.Element newElement;
181 algorithm
182 ✗ if SCodeUtil.isElementProtected(oldElement) then
183 ✗ newElement := SCodeUtil.makeElementProtected(newElement);
184 end if;
185 end update_element;
186 algorithm
187 ✗ table := get();
188
189 ✗ if referenceEq(table.ast, ast) then
190 ✗ return;
191 end if;
192
193 ✗ table.ast := ast;
194 ✗ updateUriMapping(ast.classes);
195
196 ✗ if isSome(table.explodedAst) then
197 // Restore the flags for the rest of the program so translateElement only
198 // adds to them, then record the updated set.
199 ✗ applyConnectorFlags(table.connectorFlags);
200 // Assume the element is public here since we don't know the actual
201 // visibility, and then update it later in update_element if it's not.
202 ✗ scode_elems := AbsynToSCode.translateElement(element, SCode.Visibility.PUBLIC());
203
204 ✗ if listLength(scode_elems) > 1 then
205 // translateElement can return multiple elements when multiple components
206 // are declared in the same declaration, pick the one matching the path.
207 ✗ SOME(scode_elem) := List.findOption(scode_elems,
208 function SCodeUtil.isElementNamed(name = AbsynUtil.pathLastIdent(path)));
209 else
210 ✗ scode_elem := listHead(scode_elems);
211 end if;
212
213 ✗ SOME(scode_prog) := table.explodedAst;
214 ✗ (scode_prog, true) := SCodeUtil.transformPathedElementInProgram(path,
215 function update_element(newElement = scode_elem), scode_prog);
216 ✗ table.explodedAst := SOME(scode_prog);
217 table.connectorFlags := currentConnectorFlags();
218 end if;
219
220 ✗ update(table);
221 end setAbsynElement;
222
223 function setAbsynClass
224 "Sets the Absyn program in the symbol table like setAbsyn, but also updates
225 the SCode if it's cached. This can be used to avoid invalidating the whole
226 SCode program when only updating a single class in the Absyn."
227 input Absyn.Program ast;
228 input Absyn.Class cls;
229 input Absyn.Path path;
230 protected
231 SymbolTable table;
232 SCode.Element scode_elem;
233 list<SCode.Element> scode_prog;
234
235 function update_element
236 input SCode.Element oldElement;
237 input output SCode.Element newElement;
238 algorithm
239 // An SCode.Element created from an Absyn.Class will only have default prefixes set,
240 // so copy those from the old element to make sure they're not lost.
241 42 newElement := SCodeUtil.setElementPrefixes(SCodeUtil.elementPrefixes(oldElement), newElement);
242 end update_element;
243 algorithm
244 42 table := get();
245
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if referenceEq(table.ast, ast) then
247 ✗ return;
248 end if;
249
250 42 table.ast := ast;
251 42 updateUriMapping(ast.classes);
252
253
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 if isSome(table.explodedAst) then
254 42 applyConnectorFlags(table.connectorFlags);
255 42 scode_elem := AbsynToSCode.translateClass(cls);
256
257
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 SOME(scode_prog) := table.explodedAst;
258
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
42 (scode_prog, true) := SCodeUtil.transformPathedElementInProgram(path,
259 function update_element(newElement = scode_elem), scode_prog);
260 42 table.explodedAst := SOME(scode_prog);
261 table.connectorFlags := currentConnectorFlags();
262 end if;
263
264 42 update(table);
265 end setAbsynClass;
266
267 function setAbsynLoaded
268 "Sets the Absyn program like setAbsyn, but for loadString: when the SCode is
269 cached and the loaded classes are top-level, it refreshes only those classes
270 in the SCode instead of dropping the whole cache. This keeps a loadString of
271 one class from re-exploding the entire loaded library. Falls back to full
272 invalidation if the merge changed the program in any other way (e.g. a
273 `uses` clause pulled in extra libraries)."
274 input Absyn.Program ast "the full program after merging";
275 input Absyn.Program loaded "the just-parsed classes, with their within";
276 protected
277 SymbolTable table;
278 list<SCode.Element> sp, newElems = {};
279 SCode.Element se;
280 Boolean found, topLevel;
281 Absyn.Program metaLoaded;
282
283 function update_element
284 input SCode.Element oldElement;
285 input output SCode.Element newElement;
286 algorithm
287 9 newElement := SCodeUtil.setElementPrefixes(SCodeUtil.elementPrefixes(oldElement), newElement);
288 end update_element;
289 algorithm
290 768 table := get();
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 768 times.
768 if referenceEq(table.ast, ast) then
292 ✗ return;
293 end if;
294 768 table.ast := ast;
295 768 updateUriMapping(ast.classes);
296
297 topLevel := match loaded.within_ case Absyn.TOP() then true; else false; end match;
298
299
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 759 times.
✓ Branch 2 taken 759 times.
✗ Branch 3 not taken.
759 if topLevel and isSome(table.explodedAst) then
300 759 SOME(sp) := table.explodedAst;
301 759 applyConnectorFlags(table.connectorFlags);
302 // translateClass does not run MetaUtil.createMetaClassesInProgram, which lifts
303 // uniontype records into top-level metarecords (a no-op outside MetaModelica).
304 // Apply it to the loaded classes so the incremental SCode matches what a full
305 // translateAbsyn2SCode would produce.
306 759 metaLoaded := MetaUtil.createMetaClassesInProgram(loaded);
307
2/2
✓ Branch 0 taken 932 times.
✓ Branch 1 taken 759 times.
1691 for cls in metaLoaded.classes loop
308 932 se := AbsynToSCode.translateClass(cls);
309 932 (sp, found) := SCodeUtil.transformPathedElementInProgram(Absyn.IDENT(cls.name),
310 function update_element(newElement = se), sp);
311
2/2
✓ Branch 0 taken 923 times.
✓ Branch 1 taken 9 times.
932 if not found then
312 newElems := se :: newElems;
313 end if;
314 end for;
315 759 newElems := listReverse(newElems);
316 759 table.connectorFlags := currentConnectorFlags();
317 // Only trust the incremental SCode if it accounts for exactly the program's
318 // top-level classes after meta expansion; otherwise the merge did more than
319 // we tracked (e.g. a `uses` clause pulled in extra libraries).
320 759 metaLoaded := MetaUtil.createMetaClassesInProgram(table.ast);
321
2/2
✓ Branch 3 taken 758 times.
✓ Branch 4 taken 1 time.
1517 table.explodedAst := if listLength(sp) + listLength(newElems) == listLength(metaLoaded.classes)
322 then SOME(listAppend(sp, newElems)) else NONE();
323 elseif isSome(table.explodedAst) then
324 9 table.explodedAst := NONE();
325 end if;
326
327 768 update(table);
328 end setAbsynLoaded;
329
330 function setAbsynDeleted
331 "Sets the Absyn program like setAbsyn after a class was deleted, but when the
332 SCode is cached and a top-level class was removed, drops just that class from
333 the SCode instead of invalidating the whole cache."
334 input Absyn.Program ast;
335 input Absyn.Path path;
336 protected
337 SymbolTable table;
338 list<SCode.Element> sp;
339 String name;
340 Boolean topLevel;
341 algorithm
342 4 table := get();
343 4 table.ast := ast;
344 4 updateUriMapping(ast.classes);
345
346 (topLevel, name) := match path case Absyn.IDENT(name) then (true, name); else (false, ""); end match;
347
348
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if isSome(table.explodedAst) then
349
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if topLevel then
350 3 SOME(sp) := table.explodedAst;
351
4/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
9 table.explodedAst := SOME(list(e for e guard not SCodeUtil.isElementNamed(name, e) in sp));
352 else
353 1 table.explodedAst := NONE();
354 end if;
355 end if;
356
357 4 update(table);
358 end setAbsynDeleted;
359
360 function getSCode
361 output SCode.Program ast;
362 protected
363 SymbolTable table;
364 Option<SCode.Program> updated;
365 Absyn.Program base_ast;
366 SCode.Program base_scode;
367 tuple<Boolean,Boolean,Boolean,Boolean> base_flags;
368 algorithm
369 35399 table := get();
370
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 35399 times.
✓ Branch 2 taken 3964 times.
✓ Branch 3 taken 31435 times.
35399 if isNone(table.explodedAst) then
371 updated := match table.scodeBase
372 case SOME((base_ast, base_scode, base_flags))
373 1289 then updateSCode(table.ast, base_ast, base_scode, base_flags);
374 else NONE();
375 end match;
376 ast := match updated
377 case SOME(ast) then ast;
378 2721 else AbsynToSCode.translateAbsyn2SCode(table.ast);
379 end match;
380 3964 table.explodedAst := SOME(ast);
381 table.scodeBase := NONE();
382 table.connectorFlags := currentConnectorFlags();
383 3964 update(table);
384 else
385 31435 SOME(ast) := table.explodedAst;
386 31435 applyConnectorFlags(table.connectorFlags);
387 end if;
388 end getSCode;
389
390 protected function updateSCode
391 "Translates the top-level classes of ast that are not in baseAst and reuses
392 the SCode of the others, or returns NONE() if the classes cannot be
393 matched by name."
394 input Absyn.Program ast;
395 input Absyn.Program baseAst;
396 input SCode.Program baseSCode;
397 input tuple<Boolean,Boolean,Boolean,Boolean> baseFlags;
398 output Option<SCode.Program> outSCode = NONE();
399 protected
400 UnorderedMap<String, Absyn.Class> base_classes;
401 UnorderedMap<String, SCode.Element> base_elements;
402 list<SCode.Element> elements = {};
403 Option<SCode.Element> elem;
404 algorithm
405 // MetaUtil.createMetaClassesInProgram adds top-level classes.
406
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 1243 times.
1289 if Config.acceptMetaModelicaGrammar() then
407 46 return;
408 end if;
409
410 1243 base_classes := UnorderedMap.new<Absyn.Class>(stringHashDjb2, stringEq);
411
2/2
✓ Branch 0 taken 1290 times.
✓ Branch 1 taken 1243 times.
2533 for cls in baseAst.classes loop
412
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1290 times.
1290 if not referenceEq(UnorderedMap.tryAdd(cls.name, cls, base_classes), cls) then
413 ✗ return;
414 end if;
415 end for;
416
417 1243 base_elements := UnorderedMap.new<SCode.Element>(stringHashDjb2, stringEq);
418
2/2
✓ Branch 0 taken 1290 times.
✓ Branch 1 taken 1243 times.
2533 for e in baseSCode loop
419 1290 UnorderedMap.tryAdd(SCodeUtil.elementName(e), e, base_elements);
420 end for;
421
422 1243 BackendInterface.initInstHashTable();
423 1243 applyConnectorFlags(baseFlags);
424
2/2
✓ Branch 1 taken 3661 times.
✓ Branch 2 taken 1243 times.
4904 for cls in ast.classes loop
425 elem := match UnorderedMap.get(cls.name, base_classes)
426 local
427 Absyn.Class base_cls;
428 1159 case SOME(base_cls) guard referenceEq(base_cls, cls) then UnorderedMap.get(cls.name, base_elements);
429 else NONE();
430 end match;
431 elements := (match elem
432 local
433 SCode.Element e;
434 case SOME(e) then e;
435 2502 else AbsynToSCode.translateClass(cls);
436 end match) :: elements;
437 end for;
438
439 1243 outSCode := SOME(listReverse(elements));
440 end updateSCode;
441
442 public function setSCode
443 input Option<SCode.Program> ast;
444 protected
445 SymbolTable table;
446 algorithm
447 ✗ table := get();
448 ✗ if referenceEq(table.explodedAst, ast) then
449 ✗ return;
450 end if;
451 ✗ table.explodedAst := ast;
452 table.scodeBase := NONE();
453 ✗ update(table);
454 end setSCode;
455
456 function clearSCode
457 protected
458 SymbolTable table;
459 algorithm
460 ✗ table := get();
461 ✗ if isSome(table.explodedAst) or isSome(table.scodeBase) then
462 ✗ table.explodedAst := NONE();
463 table.scodeBase := NONE();
464 ✗ update(table);
465 end if;
466 end clearSCode;
467
468 function clearProgram
469 protected
470 SymbolTable table;
471 algorithm
472 1 table := get();
473 1 reset();
474 1 setVars(table.vars);
475 end clearProgram;
476
477 public function getVars
478 "Adds a list of variables to the interactive symboltable."
479 output list<InteractiveTypes.Variable> vars;
480 protected
481 SymbolTable table;
482 algorithm
483 1549 table := get();
484 1549 vars := table.vars;
485 end getVars;
486
487 public function setVars
488 "Adds a list of variables to the interactive symboltable."
489 input list<InteractiveTypes.Variable> vars;
490 protected
491 SymbolTable table;
492 algorithm
493 1 table := get();
494 1 table.vars := vars;
495 1 update(table);
496 end setVars;
497
498 function addVars
499 "Adds a list of variables to the interactive symboltable."
500 input list<DAE.ComponentRef> inCref;
501 input list<Values.Value> inValues;
502 input FCore.Graph inEnv;
503 protected
504 list<DAE.ComponentRef> crefs;
505 list<Values.Value> vals;
506 Values.Value v;
507 DAE.ComponentRef cr;
508 algorithm
509 crefs := inCref;
510 vals := inValues;
511
2/2
✓ Branch 0 taken 1214 times.
✓ Branch 1 taken 468 times.
1682 while not listEmpty(crefs) loop
512 1214 cr::crefs := crefs;
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1214 times.
1214 v::vals := vals;
514 1214 addVar(cr, v, inEnv);
515 end while;
516 end addVars;
517
518 public function addVar
519 "Adds a variable to the interactive symboltable."
520 input DAE.ComponentRef inCref;
521 input Values.Value inValue;
522 input FCore.Graph inEnv;
523 protected
524 list<InteractiveTypes.Variable> vars;
525 SymbolTable table;
526 algorithm
527 10398 table := get();
528 10398 vars := addVarToVarList(inCref, inValue, inEnv, table.vars);
529 10397 table.vars := addVarToVarList(inCref, inValue, inEnv, vars);
530 10397 update(table);
531 end addVar;
532
533 public function appendVar
534 "Appends a variable to the interactive symbol table.
535 Compared to addVarToSymboltable, this function does
536 not search for the identifier, it adds the variable
537 to the beginning of the list.
538 Used in for example iterators in for statements."
539 input Absyn.Ident inIdent;
540 input Values.Value inValue;
541 input DAE.Type inType;
542 protected
543 SymbolTable table;
544 algorithm
545 1109 table := get();
546 2218 table.vars := InteractiveTypes.IVAR(inIdent, inValue, inType) :: table.vars;
547 1109 update(table);
548 end appendVar;
549
550 public function deleteVarFirstEntry
551 input Absyn.Ident inIdent;
552 protected
553 SymbolTable table;
554 algorithm
555 1109 table := get();
556 1109 table.vars := List.deleteMemberOnTrue(inIdent, table.vars, isVarNamed);
557 1109 update(table);
558 end deleteVarFirstEntry;
559
560 function storeAST
561 output Integer id;
562 protected
563 SymbolTable table;
564 algorithm
565 ✗ table := get();
566 ✗ id := table.cacheIndex + 1;
567
568 // Handle integer wraparound.
569 ✗ if id < 0 then
570 id := 1;
571 end if;
572
573 // Update the index in the symbol table.
574 ✗ table.cacheIndex := id;
575 ✗ update(table);
576
577 ✗ if Vector.size(table.cachedAsts) >= AST_CACHE_MAX_SIZE then
578 // Wrap around if the cache is full.
579 ✗ Vector.update(table.cachedAsts, intMod(id-1, AST_CACHE_MAX_SIZE)+1, getAbsyn());
580 else
581 // Otherwise just push a new value onto the vector.
582 ✗ Vector.push(table.cachedAsts, getAbsyn());
583 end if;
584 end storeAST;
585
586 function restoreAST
587 input Integer id;
588 output Boolean success;
589 protected
590 SymbolTable table;
591 algorithm
592 ✗ table := get();
593 // Make sure the id is in the current index range.
594 ✗ success := id <= table.cacheIndex and id > table.cacheIndex - AST_CACHE_MAX_SIZE and id > 0;
595
596 if success then
597 ✗ setAbsyn(Vector.get(table.cachedAsts, intMod(id-1, AST_CACHE_MAX_SIZE)+1));
598 end if;
599 end restoreAST;
600
601 protected
602
603 function isVarNamed
604 input Absyn.Ident id;
605 input InteractiveTypes.Variable v;
606 output Boolean b;
607 algorithm
608
4/4
✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1109 times.
1120 b := v.varIdent == id;
609 end isVarNamed;
610
611 function addVarToVarList
612 "Assigns a value to a variable with a specific identifier."
613 input DAE.ComponentRef inCref;
614 input Values.Value inValue;
615 input FCore.Graph inEnv;
616 input list<InteractiveTypes.Variable> inVariables;
617 output list<InteractiveTypes.Variable> outVariables;
618 protected
619 Boolean found;
620 algorithm
621 20795 (outVariables, found) :=
622 List.findMap(inVariables, function addVarToVarList2(inCref = inCref, inValue = inValue, inEnv = inEnv));
623 20795 outVariables := addVarToVarList4(found, inCref, inValue, outVariables);
624 end addVarToVarList;
625
626 protected function addVarToVarList2
627 input InteractiveTypes.Variable inOldVariable;
628 input DAE.ComponentRef inCref;
629 input Values.Value inValue;
630 input FCore.Graph inEnv;
631 output InteractiveTypes.Variable outVariable;
632 output Boolean outFound;
633 protected
634 Absyn.Ident id1, id2;
635 algorithm
636 166918 InteractiveTypes.IVAR(varIdent = id1) := inOldVariable;
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166918 times.
166918 DAE.CREF_IDENT(ident = id2) := inCref;
638
4/4
✓ Branch 0 taken 23592 times.
✓ Branch 1 taken 143326 times.
✓ Branch 3 taken 9468 times.
✓ Branch 4 taken 14124 times.
166918 outFound := stringEq(id1, id2);
639 166918 outVariable := addVarToVarList3(outFound, inOldVariable, inCref, inValue, inEnv);
640 end addVarToVarList2;
641
642 protected function addVarToVarList3
643 input Boolean inFound;
644 input InteractiveTypes.Variable inOldVariable;
645 input DAE.ComponentRef inCref;
646 input Values.Value inValue;
647 input FCore.Graph inEnv;
648 output InteractiveTypes.Variable outVariable;
649 algorithm
650 outVariable := match(inFound, inOldVariable, inCref)
651 local
652 Absyn.Ident id;
653 Values.Value val;
654 DAE.Type ty;
655 list<DAE.Subscript> subs;
656
657 // InteractiveTypes.Variable is not a match, keep the old one.
658 case (false, _, _) then inOldVariable;
659
660 // Assigning whole variable => return new variable.
661 14114 case (true, _, DAE.CREF_IDENT(id, ty, {})) then InteractiveTypes.IVAR(id, inValue, ty);
662
663 // Assigning array slice => update the old variable's value.
664 case (true, InteractiveTypes.IVAR(id, val, ty), DAE.CREF_IDENT(subscriptLst = subs))
665 algorithm
666 10 (_, val) := CevalFunction.assignVector(inValue, val, subs, FCore.emptyCache(), inEnv);
667 10 then
668 InteractiveTypes.IVAR(id, val, ty);
669
670 end match;
671 end addVarToVarList3;
672
673 protected function addVarToVarList4
674 input Boolean inFound;
675 input DAE.ComponentRef inCref;
676 input Values.Value inValue;
677 input list<InteractiveTypes.Variable> inVariables;
678 output list<InteractiveTypes.Variable> outVariables;
679 algorithm
680 outVariables := match(inFound, inCref)
681 local
682 Absyn.Ident id;
683 DAE.Type ty;
684
685 // InteractiveTypes.Variable was already updated in addVarToVar, do nothing.
686 case (true, _) then inVariables;
687
688 // InteractiveTypes.Variable is new, add it to the list of variables.
689 case (false, DAE.CREF_IDENT(id, ty, {}))
690 6670 then InteractiveTypes.IVAR(id, inValue, ty) :: inVariables;
691
692 // Assigning to an array slice is only allowed for variables that have
693 // already been defined, i.e. that have a size. Print an error otherwise.
694 case (false, DAE.CREF_IDENT(ident = id, subscriptLst = _ :: _))
695 algorithm
696 1 Error.addMessage(Error.SLICE_ASSIGN_NON_ARRAY, {id});
697 1 then
698 fail();
699
700 end match;
701 end addVarToVarList4;
702
703 public function buildEnv
704 "Builds an environment from a symboltable by adding all interactive
705 variables and their bindings to the environment."
706 output FCore.Graph env;
707 protected
708 SymbolTable table;
709 algorithm
710 27948 table := get();
711 27948 (_,env) := Inst.makeEnvFromProgram(getSCode());
712 // Reverse the variable list to make sure iterators overwrite other
713 // variables (iterators are appended to the front of the list).
714 27948 env := addVarsToEnv(listReverse(table.vars), env);
715 end buildEnv;
716
717 protected function addVarsToEnv
718 "Helper function to buildEnvFromSymboltable."
719 input list<InteractiveTypes.Variable> inVariableLst;
720 input FCore.Graph inEnv;
721 output FCore.Graph outEnv;
722 algorithm
723 27948 outEnv := List.fold(inVariableLst, addVarToEnv, inEnv);
724 end addVarsToEnv;
725
726 protected function addVarToEnv
727 input InteractiveTypes.Variable inVariable;
728 input FCore.Graph inEnv;
729 output FCore.Graph outEnv;
730 algorithm
731 outEnv := matchcontinue(inVariable, inEnv)
732 local
733 FCore.Graph env, empty_env;
734 String id;
735 Values.Value v;
736 DAE.Type tp;
737 DAE.ComponentRef cref;
738
739 case (InteractiveTypes.IVAR(varIdent = id, value = v, type_ = tp), env)
740 algorithm
741 358976 cref := ComponentReferenceBasics.makeCrefIdent(id, DAE.T_UNKNOWN_DEFAULT, {});
742 358976 empty_env := FGraph.empty();
743 358976 Lookup.lookupVar(FCore.emptyCache(), env, cref);
744 ✗ env := FGraph.updateComp(
745 env,
746 DAE.TYPES_VAR(
747 id,
748 DAE.dummyAttrVar,
749 tp,
750 DAE.VALBOUND(v, DAE.BINDING_FROM_DEFAULT_VALUE()),
751 false,
752 NONE()),
753 FCore.VAR_TYPED(),
754 empty_env);
755 then
756 env;
757
758 case (InteractiveTypes.IVAR(varIdent = id, value = v, type_ = tp), env)
759 algorithm
760 358976 empty_env := FGraph.empty();
761 358976 env := FGraph.mkComponentNode(
762 env,
763 DAE.TYPES_VAR(id,DAE.dummyAttrVar,tp,DAE.VALBOUND(v,DAE.BINDING_FROM_DEFAULT_VALUE()),false,NONE()),
764 SCode.COMPONENT(
765 id,
766 SCode.defaultPrefixes,
767 SCode.ATTR({}, SCode.POTENTIAL(), SCode.NON_PARALLEL(), SCode.VAR(), Absyn.BIDIR(), Absyn.NONFIELD()),
768 Absyn.TPATH(Absyn.IDENT(""), NONE()), SCode.NOMOD(),
769 SCode.noComment, NONE(), Absyn.dummyInfo),
770 DAE.NOMOD(),
771 FCore.VAR_UNTYPED(),
772 empty_env);
773 then
774 env;
775
776 end matchcontinue;
777 end addVarToEnv;
778
779 protected function updateUriMapping
780 input list<Absyn.Class> classes;
781 protected
782 AvlTreeStringString.Tree tree;
783 String name, fileName, dir;
784 Boolean b;
785 array<String> namesAndDirs;
786 list<SourceInfo> infos;
787 algorithm
788 tree := AvlTreeStringString.EMPTY();
789
2/2
✓ Branch 0 taken 9445 times.
✓ Branch 1 taken 6054 times.
15499 for cl in classes loop
790 () := match cl
791 case Absyn.CLASS(info=SOURCEINFO(fileName="<interactive>")) then ();
792 case Absyn.CLASS(name=name,info=SOURCEINFO(fileName=fileName))
793 algorithm
794 8411 dir := System.dirname(fileName);
795 8411 fileName := System.basename(fileName);
796
10/12
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 8190 times.
✓ Branch 3 taken 221 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 180 times.
✓ Branch 6 taken 8231 times.
✓ Branch 8 taken 180 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 115 times.
✓ Branch 11 taken 8296 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 109 times.
8411 b := stringEq(fileName,"ModelicaBuiltin.mo") or stringEq(fileName,"MetaModelicaBuiltin.mo") or stringEq(dir,".");
797 if not b then
798
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8302 times.
8302 if AvlTreeStringString.hasKey(tree, name) then
799 ✗ infos := list(cl.info for cl in classes);
800 ✗ Error.addMultiSourceMessage(Error.DOUBLE_DECLARATION_OF_ELEMENTS, {name}, infos);
801 end if;
802 8302 tree := AvlTreeStringString.add(tree, name, dir);
803 end if;
804 then ();
805 else ();
806 end match;
807 end for;
808 6054 namesAndDirs := listArray(List.thread(AvlTreeStringString.listValues(tree), AvlTreeStringString.listKeys(tree)));
809 6054 System.updateUriMapping(namesAndDirs);
810 end updateUriMapping;
811
812 annotation(__OpenModelica_Interface="backend");
813 end SymbolTable;
814