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 |