OMCompiler/Compiler/FrontEnd/NFEnvExtends.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 NFEnvExtends | ||
| 37 | " file: NFEnvExtends.mo | ||
| 38 | package: NFEnvExtends | ||
| 39 | description: Utility functions for extends in the environment. | ||
| 40 | |||
| 41 | |||
| 42 | This package contains functions for handling extends in the environment. | ||
| 43 | Extends are added to the environment while the environment is built, and we | ||
| 44 | can't do any lookup at that time since we don't have a complete environment. | ||
| 45 | |||
| 46 | There are several important things done by this package: | ||
| 47 | |||
| 48 | QUALIFYING EXTENDS: | ||
| 49 | All base class names in the environment are fully qualified by the qualify | ||
| 50 | function. This is to avoid potential exponential complexity during lookup with | ||
| 51 | regards to the nesting depth of classes. One such case is the pattern used in | ||
| 52 | the MSL, where every class extends from a a class in Modelica.Icons: | ||
| 53 | |||
| 54 | package Modelica | ||
| 55 | package Icons end Icons; | ||
| 56 | |||
| 57 | package A | ||
| 58 | extends Modelica.Icons.foo; | ||
| 59 | package B | ||
| 60 | extends Modelica.Icons.bar; | ||
| 61 | package C | ||
| 62 | ... | ||
| 63 | end C; | ||
| 64 | end B; | ||
| 65 | end A; | ||
| 66 | end Modelica; | ||
| 67 | |||
| 68 | To look a name up in C that references a name in the top scope we need to | ||
| 69 | first look up in C. When the name is not found there we look in B, which | ||
| 70 | extends Modelica.Icons.bar. We then need to look for Modelica in B, and then | ||
| 71 | Modelica in A, which extends Modelica.Icons.foo. We then need to follow that | ||
| 72 | extends, and look for Modelica in A, etc. This means that we need to look up | ||
| 73 | 2^n extends to find a relative name in the top scope. By fully qualifying the | ||
| 74 | base class names we avoid these problems. | ||
| 75 | |||
| 76 | To avoid qualifying an extends multiple times we store them in an array which | ||
| 77 | is updated during the qualifying phase. Each extends is given a unique index | ||
| 78 | for this purpose when it's added to the environment by | ||
| 79 | NFSCodeEnv.extendEnvWithExtends, which is used to index the array. | ||
| 80 | |||
| 81 | When errors are found in this phase, such as missing base classes, we want to | ||
| 82 | only report errors for models which are actually used. We therefore delay the | ||
| 83 | error messages until the extends are used. This is done by returning special | ||
| 84 | error paths instead of the fully qualified paths, see checkExtendsPart for | ||
| 85 | details. When e.g. NFSCodeLookup.lookupBaseClassName encounters such a path it | ||
| 86 | uses printExtendsError to print the appropriate error. | ||
| 87 | |||
| 88 | INSERT ELEMENT REDECLARES INTO EXTENDS: | ||
| 89 | The update function goes through all the scopes and insert element redeclares | ||
| 90 | into the appropriate extends with addElementRedeclarationsToEnv from | ||
| 91 | NFSCodeFlattenRedeclare. See the comment in SCodeFlattenRedeclare for more | ||
| 92 | information about this. | ||
| 93 | |||
| 94 | UPDATE CLASS EXTENDS: | ||
| 95 | Class extends are handled by initially adding them to the environment with | ||
| 96 | NFSCodeEnv.extendEnvWithClassExtends. This function add the given class as a | ||
| 97 | normal class to the environment, and sets the class extends information field | ||
| 98 | in the class's environment. This information is later used when the extends | ||
| 99 | are updated with the update function, and updateClassExtends is called. | ||
| 100 | updateClassExtends looks the base class up and makes sure it is replaceable, | ||
| 101 | and adds an extends clause to the extending class and the environment. The | ||
| 102 | base class will be prefixed with $ce so that the lookup knows that it should | ||
| 103 | look among the inherited elements of the scope above when looking for a class | ||
| 104 | extends base class. | ||
| 105 | |||
| 106 | However, since it's possible to redeclare the base class of a class extends | ||
| 107 | it's possible that the base class is replaced with a class that extends from | ||
| 108 | it. If the base class were to be replaced with this class it would mean that | ||
| 109 | the class extends from itself, causing a loop. To avoid this an alias for the | ||
| 110 | base class is added instead, and the base class itself is added with the | ||
| 111 | BASE_CLASS_SUFFIX defined in NFSCodeEnv. The alias can then be safely redeclared | ||
| 112 | while preserving the base class for the class extends to extend from. It's | ||
| 113 | somewhat difficault to only add aliases for classes that are used by class | ||
| 114 | extends though, so an alias is currently added for all replaceable classes in | ||
| 115 | NFSCodeEnv.extendEnvWithClassDef for simplicity's sake. The function | ||
| 116 | NFSCodeLookup.resolveAlias is then used to resolve any alias items to the real | ||
| 117 | items whenever an item is looked up in the environment. | ||
| 118 | |||
| 119 | So a class extends on the form 'class extends X' is thus translated to | ||
| 120 | 'class X extends $ce.X$base', and then mostly handled like a normal class | ||
| 121 | since the lookup knows how to handle the base class. Some care is needed in | ||
| 122 | the dependency analysis to make sure that nothing important is removed, see | ||
| 123 | the comment in SCodeDependency.analyseClassExtends. | ||
| 124 | " | ||
| 125 | |||
| 126 | public import Absyn; | ||
| 127 | public import AbsynUtil; | ||
| 128 | public import SCode; | ||
| 129 | public import NFSCodeEnv; | ||
| 130 | |||
| 131 | protected import Debug; | ||
| 132 | protected import Error; | ||
| 133 | protected import Flags; | ||
| 134 | protected import List; | ||
| 135 | protected import NFSCodeCheck; | ||
| 136 | protected import SCodeDump; | ||
| 137 | import SCodeUtil; | ||
| 138 | protected import NFSCodeFlattenRedeclare; | ||
| 139 | protected import NFSCodeLookup; | ||
| 140 | protected import System; | ||
| 141 | protected import Util; | ||
| 142 | |||
| 143 | public type Env = NFSCodeEnv.Env; | ||
| 144 | |||
| 145 | protected type ClassType = NFSCodeEnv.ClassType; | ||
| 146 | protected type Extends = NFSCodeEnv.Extends; | ||
| 147 | protected type Frame = NFSCodeEnv.Frame; | ||
| 148 | protected type FrameType = NFSCodeEnv.FrameType; | ||
| 149 | protected type Import = Absyn.Import; | ||
| 150 | protected type Item = NFSCodeEnv.Item; | ||
| 151 | |||
| 152 | protected type ExtendsTableArray = array<ExtendsWrapper>; | ||
| 153 | |||
| 154 | import NFSCodeEnv.EnvTree; | ||
| 155 | |||
| 156 | public constant String BASECLASS_NOT_FOUND_ERROR = "$1"; | ||
| 157 | public constant String BASECLASS_INHERITED_ERROR = "$2"; | ||
| 158 | public constant String BASECLASS_REPLACEABLE_ERROR = "$3"; | ||
| 159 | public constant String BASECLASS_IS_VAR_ERROR = "$4"; | ||
| 160 | public constant String BASECLASS_UNKNOWN_ERROR = "$5"; | ||
| 161 | |||
| 162 | protected uniontype ExtendsWrapper | ||
| 163 | record UNQUALIFIED_EXTENDS | ||
| 164 | Extends ext; | ||
| 165 | end UNQUALIFIED_EXTENDS; | ||
| 166 | |||
| 167 | record QUALIFIED_EXTENDS | ||
| 168 | Extends ext; | ||
| 169 | end QUALIFIED_EXTENDS; | ||
| 170 | |||
| 171 | record NO_EXTENDS end NO_EXTENDS; | ||
| 172 | end ExtendsWrapper; | ||
| 173 | |||
| 174 | public function update | ||
| 175 | "While building the environment some extends information is stored that needs | ||
| 176 | to be updated once the environment is complete, since we can't reliably look | ||
| 177 | things up in an incomplete environment. This includes fully qualifying the | ||
| 178 | names of the extended classes, updating the class extends base classes and | ||
| 179 | inserting element redeclares into the proper extends." | ||
| 180 | input Env inEnv; | ||
| 181 | output Env outEnv; | ||
| 182 | protected | ||
| 183 | Env env; | ||
| 184 | algorithm | ||
| 185 | //System.startTimer(); | ||
| 186 | 1103 | env := qualify(inEnv); | |
| 187 | 1103 | outEnv := update2(env); | |
| 188 | //System.stopTimer(); | ||
| 189 | //print("Updating extends took " + realString(System.getTimerIntervalTime()) + " seconds.\n"); | ||
| 190 | end update; | ||
| 191 | |||
| 192 | public function qualify | ||
| 193 | "Fully qualified all base class names using in extends clauses. This is done | ||
| 194 | to avoid some cases where the lookup might exhibit exponential complexity | ||
| 195 | with regards to the nesting depth of classes. One such case is the pattern | ||
| 196 | used in the MSL, where every class extends from a class in Modelica.Icons: | ||
| 197 | |||
| 198 | package Modelica | ||
| 199 | package Icons end Icons; | ||
| 200 | |||
| 201 | package A | ||
| 202 | extends Modelica.Icons.foo; | ||
| 203 | package B | ||
| 204 | extends Modelica.Icons.bar; | ||
| 205 | package C | ||
| 206 | ... | ||
| 207 | end C; | ||
| 208 | end B; | ||
| 209 | end A; | ||
| 210 | |||
| 211 | To look a name up in C that references a name in the top scope we need to | ||
| 212 | first look in C. When the name is not found there we look in B, which extends | ||
| 213 | Modelica.Icons.bar. We then need to look for Modelica in B, and then Modelica | ||
| 214 | in A, which extends Modelica.Icons.foo. We then need to follow that extends, | ||
| 215 | and look for Modelica in A, etc. This means that we need to look up 2^n | ||
| 216 | extends to find a relative name at the top scope. By fully qualifying the | ||
| 217 | base class names we avoid these problems." | ||
| 218 | input Env inEnv; | ||
| 219 | output Env outEnv; | ||
| 220 | algorithm | ||
| 221 | outEnv := matchcontinue inEnv | ||
| 222 | local | ||
| 223 | Integer ext_count; | ||
| 224 | ExtendsTableArray ext_table; | ||
| 225 | |||
| 226 | case _ | ||
| 227 | algorithm | ||
| 228 | 1103 | ext_count := System.tmpTickIndex(NFSCodeEnv.extendsTickIndex); | |
| 229 | 1103 | ext_table := createExtendsTable(ext_count); | |
| 230 | 1103 | then | |
| 231 | qualify2(inEnv, NFSCodeEnv.USERDEFINED(), ext_table); | ||
| 232 | |||
| 233 | else | ||
| 234 | algorithm | ||
| 235 | ✗ | true := Flags.isSet(Flags.FAILTRACE); | |
| 236 | ✗ | Debug.traceln("- NFEnvExtends.qualify failed."); | |
| 237 | ✗ | then | |
| 238 | fail(); | ||
| 239 | |||
| 240 | end matchcontinue; | ||
| 241 | end qualify; | ||
| 242 | |||
| 243 | protected function qualify2 | ||
| 244 | input Env inEnv; | ||
| 245 | input ClassType inClassType; | ||
| 246 | input ExtendsTableArray inExtendsTable; | ||
| 247 | output Env outEnv; | ||
| 248 | protected | ||
| 249 | Env env; | ||
| 250 | EnvTree.Tree tree; | ||
| 251 | algorithm | ||
| 252 | // Qualify the extends in this scope. | ||
| 253 | 1458066 | env := qualifyLocalScope(inEnv, inClassType, inExtendsTable); | |
| 254 | |||
| 255 | // Recurse down the tree. | ||
| 256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1458066 times.
|
1458066 | NFSCodeEnv.FRAME(clsAndVars = tree) :: _ := env; |
| 257 | 1458066 | tree := EnvTree.map(tree, | |
| 258 | function qualify3(inEnv = env, inExtendsTable = inExtendsTable)); | ||
| 259 | 1458066 | outEnv := NFSCodeEnv.setEnvClsAndVars(tree, env); | |
| 260 | end qualify2; | ||
| 261 | |||
| 262 | protected function qualify3 | ||
| 263 | input String name; | ||
| 264 | input output Item item; | ||
| 265 | input Env inEnv; | ||
| 266 | input ExtendsTableArray inExtendsTable; | ||
| 267 | algorithm | ||
| 268 | item := match item | ||
| 269 | local | ||
| 270 | SCode.Element cls; | ||
| 271 | Frame cls_env; | ||
| 272 | ClassType cls_ty; | ||
| 273 | Env env; | ||
| 274 | |||
| 275 | case NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty) | ||
| 276 | algorithm | ||
| 277 | 1456963 | env := NFSCodeEnv.enterFrame(cls_env, inEnv); | |
| 278 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1456963 times.
|
1456963 | cls_env :: _ := qualify2(env, cls_ty, inExtendsTable); |
| 279 | 1456963 | then | |
| 280 | NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty); | ||
| 281 | |||
| 282 | else item; | ||
| 283 | end match; | ||
| 284 | end qualify3; | ||
| 285 | |||
| 286 | protected function qualifyLocalScope | ||
| 287 | input Env inEnv; | ||
| 288 | input ClassType inClassType; | ||
| 289 | input ExtendsTableArray inExtendsTable; | ||
| 290 | output Env outEnv; | ||
| 291 | protected | ||
| 292 | list<Extends> exts; | ||
| 293 | list<SCode.Element> re; | ||
| 294 | Option<SCode.Element> cei; | ||
| 295 | algorithm | ||
| 296 | 1458066 | NFSCodeEnv.EXTENDS_TABLE(exts, re, cei) := NFSCodeEnv.getEnvExtendsTable(inEnv); | |
| 297 | 1458066 | exts := qualifyExtendsList(exts, inClassType, inEnv, inExtendsTable); | |
| 298 | 1458066 | outEnv := NFSCodeEnv.setEnvExtendsTable(NFSCodeEnv.EXTENDS_TABLE(exts, re, cei), inEnv); | |
| 299 | end qualifyLocalScope; | ||
| 300 | |||
| 301 | protected function qualifyExtendsList | ||
| 302 | input list<Extends> inExtends; | ||
| 303 | input ClassType inClassType; | ||
| 304 | input Env inEnv; | ||
| 305 | input ExtendsTableArray inExtendsTable; | ||
| 306 | output list<Extends> outExtends; | ||
| 307 | algorithm | ||
| 308 | outExtends := match(inExtends, inClassType) | ||
| 309 | local | ||
| 310 | Extends ext; | ||
| 311 | list<Extends> extl; | ||
| 312 | |||
| 313 | // Skip the first extends in a class extends, since it's added by the | ||
| 314 | // compiler itself and shouldn't be qualified. | ||
| 315 | case (ext :: extl, NFSCodeEnv.CLASS_EXTENDS()) | ||
| 316 | algorithm | ||
| 317 | 3749 | extl := List.map2Reverse(extl, qualifyExtends, inEnv, inExtendsTable); | |
| 318 | then | ||
| 319 | ext :: extl; | ||
| 320 | |||
| 321 | // Otherwise, qualify all the extends. | ||
| 322 | else | ||
| 323 | algorithm | ||
| 324 | 1454317 | extl := List.map2Reverse(inExtends, qualifyExtends, inEnv, inExtendsTable); | |
| 325 | then | ||
| 326 | extl; | ||
| 327 | |||
| 328 | end match; | ||
| 329 | end qualifyExtendsList; | ||
| 330 | |||
| 331 | protected function qualifyExtends | ||
| 332 | input Extends inExtends; | ||
| 333 | input Env inEnv; | ||
| 334 | input ExtendsTableArray inExtendsTable; | ||
| 335 | output Extends outExtends; | ||
| 336 | algorithm | ||
| 337 | outExtends := matchcontinue inExtends | ||
| 338 | local | ||
| 339 | Absyn.Ident id; | ||
| 340 | Extends ext; | ||
| 341 | Absyn.Path bc; | ||
| 342 | |||
| 343 | // Check if the base class is a built in type such as Real, then we don't | ||
| 344 | // need to do anything. | ||
| 345 | case NFSCodeEnv.EXTENDS(baseClass = Absyn.IDENT(name = id)) | ||
| 346 | algorithm | ||
| 347 | 97981 | NFSCodeLookup.lookupBuiltinType(id); | |
| 348 | then | ||
| 349 | inExtends; | ||
| 350 | |||
| 351 | case _ | ||
| 352 | algorithm | ||
| 353 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 592151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 592151 times.
|
592151 | SOME(ext) := qualifyExtends2(inExtends, inEnv, inExtendsTable); |
| 354 | then | ||
| 355 | ext; | ||
| 356 | |||
| 357 | case NFSCodeEnv.EXTENDS(baseClass = bc) | ||
| 358 | algorithm | ||
| 359 | ✗ | true := Flags.isSet(Flags.FAILTRACE); | |
| 360 | ✗ | Debug.traceln("- NFEnvExtends.qualifyExtends failed on " + | |
| 361 | AbsynUtil.pathString(bc) + "\n"); | ||
| 362 | ✗ | then | |
| 363 | fail(); | ||
| 364 | |||
| 365 | end matchcontinue; | ||
| 366 | end qualifyExtends; | ||
| 367 | |||
| 368 | protected function qualifyExtends2 | ||
| 369 | input Extends inExtends; | ||
| 370 | input Env inEnv; | ||
| 371 | input ExtendsTableArray inExtendsTable; | ||
| 372 | output Option<Extends> outExtends; | ||
| 373 | algorithm | ||
| 374 | outExtends := matchcontinue inExtends | ||
| 375 | local | ||
| 376 | Absyn.Path bc; | ||
| 377 | list<NFSCodeEnv.Redeclaration> rl; | ||
| 378 | Integer index; | ||
| 379 | SourceInfo info; | ||
| 380 | Extends ext; | ||
| 381 | Env env; | ||
| 382 | |||
| 383 | case NFSCodeEnv.EXTENDS(index = index) | ||
| 384 | 3561751 | then lookupQualifiedExtends(index, inExtendsTable); | |
| 385 | |||
| 386 | case NFSCodeEnv.EXTENDS(bc, rl, index, info) | ||
| 387 | algorithm | ||
| 388 | 592472 | addUnqualifiedToTable(inExtends, index, inExtendsTable); | |
| 389 | 592472 | env := NFSCodeEnv.removeExtendFromLocalScope(bc, inEnv); | |
| 390 | 592472 | bc := qualifyExtends3(bc, env, inExtendsTable, true, bc, info, NONE()); | |
| 391 | /*********************************************************************/ | ||
| 392 | // TODO: Convert this check to the delayed error system. | ||
| 393 | /*********************************************************************/ | ||
| 394 | 592472 | List.map2_0(rl, NFSCodeCheck.checkRedeclareModifier, bc, inEnv); | |
| 395 | 592472 | ext := NFSCodeEnv.EXTENDS(bc, rl, index, info); | |
| 396 | 592472 | updateQualifiedInTable(ext, index, inExtendsTable); | |
| 397 | then | ||
| 398 | SOME(ext); | ||
| 399 | |||
| 400 | end matchcontinue; | ||
| 401 | end qualifyExtends2; | ||
| 402 | |||
| 403 | protected function qualifyExtends3 | ||
| 404 | input Absyn.Path inBaseClass; | ||
| 405 | input Env inEnv; | ||
| 406 | input ExtendsTableArray inExtendsTable; | ||
| 407 | input Boolean inIsFirst; | ||
| 408 | input Absyn.Path inFullPath; | ||
| 409 | input SourceInfo inInfo; | ||
| 410 | input Option<Absyn.Path> inErrorPath; | ||
| 411 | output Absyn.Path outBaseClass; | ||
| 412 | algorithm | ||
| 413 | outBaseClass := match(inBaseClass, inErrorPath) | ||
| 414 | local | ||
| 415 | String name; | ||
| 416 | Absyn.Path bc, rest_path; | ||
| 417 | Env env; | ||
| 418 | Option<Absyn.Path> ep, opath; | ||
| 419 | |||
| 420 | case (_, SOME(bc)) then bc; | ||
| 421 | |||
| 422 | case (Absyn.IDENT(name = name), _) | ||
| 423 | algorithm | ||
| 424 | 592461 | (opath, env, ep) := qualifyExtendsPart(name, inEnv, inExtendsTable, inIsFirst, | |
| 425 | inFullPath, inInfo); | ||
| 426 | 592461 | then | |
| 427 | makeExtendsPath(opath, NONE(), env, ep, inIsFirst); | ||
| 428 | |||
| 429 | case (Absyn.QUALIFIED(name = name, path = rest_path), _) | ||
| 430 | algorithm | ||
| 431 | 1276072 | (opath, env, ep) := qualifyExtendsPart(name, inEnv, inExtendsTable, inIsFirst, | |
| 432 | inFullPath, inInfo); | ||
| 433 | 1276072 | rest_path := qualifyExtends3(rest_path, env, inExtendsTable, false, inFullPath, inInfo, ep); | |
| 434 | 1276072 | then | |
| 435 | makeExtendsPath(opath, SOME(rest_path), env, ep, inIsFirst); | ||
| 436 | |||
| 437 | case (Absyn.FULLYQUALIFIED(path = rest_path), _) | ||
| 438 | algorithm | ||
| 439 | 132 | env := NFSCodeEnv.getEnvTopScope(inEnv); | |
| 440 | 132 | then | |
| 441 | qualifyExtends3(rest_path, env, inExtendsTable, inIsFirst, rest_path, | ||
| 442 | inInfo, NONE()); | ||
| 443 | |||
| 444 | end match; | ||
| 445 | end qualifyExtends3; | ||
| 446 | |||
| 447 | protected function makeExtendsPath | ||
| 448 | input Option<Absyn.Path> inFirstPath; | ||
| 449 | input Option<Absyn.Path> inRestPath; | ||
| 450 | input Env inEnv; | ||
| 451 | input Option<Absyn.Path> inErrorPath; | ||
| 452 | input Boolean inIsFirst; | ||
| 453 | output Absyn.Path outPath; | ||
| 454 | algorithm | ||
| 455 | outPath := match(inFirstPath, inRestPath, inErrorPath, inIsFirst) | ||
| 456 | local | ||
| 457 | Absyn.Path path; | ||
| 458 | |||
| 459 | // If an error has occured, return the error path. | ||
| 460 | case (_, _, SOME(path), _) then path; | ||
| 461 | case (_, SOME(path as Absyn.QUALIFIED(name = "$E")), _, _) then path; | ||
| 462 | |||
| 463 | // If the rest of the path is fully qualified it overwrites everything before. | ||
| 464 | case (_, SOME(path as Absyn.FULLYQUALIFIED()), _, _) then path; | ||
| 465 | |||
| 466 | // If inFirstPath is the very first part of the path, use the environment to | ||
| 467 | // get the whole path. | ||
| 468 | case (_, _, _, true) | ||
| 469 | algorithm | ||
| 470 | 592133 | path := NFSCodeEnv.getEnvPath(inEnv); | |
| 471 | 592133 | path := AbsynUtil.joinPathsOptSuffix(path, inRestPath); | |
| 472 | 592133 | path := AbsynUtil.makeFullyQualified(path); | |
| 473 | then | ||
| 474 | path; | ||
| 475 | |||
| 476 | // Otherwise, just join them. | ||
| 477 | 1276038 | case (SOME(path), _, _, _) then AbsynUtil.joinPathsOptSuffix(path, inRestPath); | |
| 478 | |||
| 479 | end match; | ||
| 480 | end makeExtendsPath; | ||
| 481 | |||
| 482 | protected function qualifyExtendsPart | ||
| 483 | input String inName; | ||
| 484 | input Env inEnv; | ||
| 485 | input ExtendsTableArray inExtendsTable; | ||
| 486 | input Boolean inIsFirst; | ||
| 487 | input Absyn.Path inFullPath; | ||
| 488 | input SourceInfo inInfo; | ||
| 489 | output Option<Absyn.Path> outPath; | ||
| 490 | output Env outEnv; | ||
| 491 | output Option<Absyn.Path> outErrorPath; | ||
| 492 | protected | ||
| 493 | Option<Item> oitem; | ||
| 494 | Option<Env> oenv; | ||
| 495 | Boolean fe; | ||
| 496 | algorithm | ||
| 497 | 1868533 | (oitem, outPath, oenv, fe) := lookupSimpleName(inName, inEnv, inExtendsTable); | |
| 498 | 1868533 | (outEnv, outErrorPath) := qualifyExtendsPart2(Absyn.IDENT(inName), oitem, | |
| 499 | oenv, inEnv, inIsFirst, fe, inFullPath); | ||
| 500 | end qualifyExtendsPart; | ||
| 501 | |||
| 502 | protected function qualifyExtendsPart2 | ||
| 503 | input Absyn.Path inPartName; | ||
| 504 | input Option<Item> inItem; | ||
| 505 | input Option<Env> inFoundEnv; | ||
| 506 | input Env inOriginEnv; | ||
| 507 | input Boolean inIsFirst; | ||
| 508 | input Boolean inFromExtends; | ||
| 509 | input Absyn.Path inFullPath; | ||
| 510 | output Env outEnv; | ||
| 511 | output Option<Absyn.Path> outErrorPath; | ||
| 512 | algorithm | ||
| 513 | (outEnv, outErrorPath) := match(inItem, inFoundEnv) | ||
| 514 | local | ||
| 515 | Item item; | ||
| 516 | Env env; | ||
| 517 | Option<Absyn.Path> ep; | ||
| 518 | |||
| 519 | case (SOME(item), SOME(env)) | ||
| 520 | algorithm | ||
| 521 | 1868196 | ep := checkExtendsPart(inIsFirst, inFromExtends, inPartName, item, | |
| 522 | inFullPath, env, inOriginEnv); | ||
| 523 | 1868196 | env := NFSCodeEnv.mergeItemEnv(item, env); | |
| 524 | then | ||
| 525 | (env, ep); | ||
| 526 | |||
| 527 | 337 | else (NFSCodeEnv.emptyEnv, | |
| 528 | makeExtendsError(inFullPath, inPartName, BASECLASS_NOT_FOUND_ERROR)); | ||
| 529 | end match; | ||
| 530 | end qualifyExtendsPart2; | ||
| 531 | |||
| 532 | protected function makeExtendsError | ||
| 533 | input Absyn.Path inBaseClass; | ||
| 534 | input Absyn.Path inPart; | ||
| 535 | input String inError; | ||
| 536 | output Option<Absyn.Path> outError; | ||
| 537 | algorithm | ||
| 538 | outError := match inError | ||
| 539 | local | ||
| 540 | Absyn.Path path; | ||
| 541 | |||
| 542 | case _ | ||
| 543 | algorithm | ||
| 544 | 339 | path := AbsynUtil.joinPaths(inPart, Absyn.QUALIFIED("$bc", inBaseClass)); | |
| 545 | 339 | path := Absyn.QUALIFIED("$E", Absyn.QUALIFIED(inError, path)); | |
| 546 | then | ||
| 547 | SOME(path); | ||
| 548 | |||
| 549 | end match; | ||
| 550 | end makeExtendsError; | ||
| 551 | |||
| 552 | protected function checkExtendsPart | ||
| 553 | "This function checks that part of a base class name is correct. If it is not | ||
| 554 | correct it returns an error path on the form $E.$N.part_path.$bc.base_class. | ||
| 555 | $N, where N is an integer, defined the actual error as defined by the error | ||
| 556 | constants at the beginning of this file. part_path is the path of the part | ||
| 557 | which the error occured in, and base_class is the path of the base class as | ||
| 558 | declared in the code. This is used by printExtendsError to print an | ||
| 559 | appropriate error when needed." | ||
| 560 | input Boolean inIsFirst; | ||
| 561 | input Boolean inFromExtends; | ||
| 562 | input Absyn.Path inPartName; | ||
| 563 | input Item inItem; | ||
| 564 | input Absyn.Path inBaseClass; | ||
| 565 | input Env inFoundEnv; | ||
| 566 | input Env inOriginEnv; | ||
| 567 | output Option<Absyn.Path> outErrorPath; | ||
| 568 | algorithm | ||
| 569 | outErrorPath := matchcontinue(inIsFirst, inFromExtends, inItem) | ||
| 570 | local | ||
| 571 | Absyn.Path part; | ||
| 572 | |||
| 573 | // The first part of the base class name may not be inherited. | ||
| 574 | case (true, true, _) | ||
| 575 | 1 | then makeExtendsError(inBaseClass, inPartName, BASECLASS_INHERITED_ERROR); | |
| 576 | |||
| 577 | // Not inherited class, ok! | ||
| 578 | case (_, _, NFSCodeEnv.CLASS()) | ||
| 579 | then NONE(); | ||
| 580 | |||
| 581 | // The base class part is actually not a class but a component, which is not | ||
| 582 | // allowed either. | ||
| 583 | case (_, _, NFSCodeEnv.VAR()) | ||
| 584 | algorithm | ||
| 585 | 1 | part := NFSCodeEnv.mergePathWithEnvPath(inPartName, inFoundEnv); | |
| 586 | 1 | then | |
| 587 | makeExtendsError(inBaseClass, part, BASECLASS_IS_VAR_ERROR); | ||
| 588 | |||
| 589 | // We shouldn't get here. | ||
| 590 | ✗ | else makeExtendsError(inBaseClass, inPartName, BASECLASS_UNKNOWN_ERROR); | |
| 591 | end matchcontinue; | ||
| 592 | end checkExtendsPart; | ||
| 593 | |||
| 594 | protected function splitExtendsErrorPath | ||
| 595 | input Absyn.Path inPath; | ||
| 596 | output Absyn.Path outBaseClass; | ||
| 597 | output Absyn.Path outPartPath; | ||
| 598 | algorithm | ||
| 599 | (outBaseClass, outPartPath) := match inPath | ||
| 600 | local | ||
| 601 | String part_str; | ||
| 602 | Absyn.Path part, bc; | ||
| 603 | |||
| 604 | case Absyn.QUALIFIED(part_str, Absyn.QUALIFIED("$bc", bc)) | ||
| 605 | 2 | then (bc, Absyn.IDENT(part_str)); | |
| 606 | |||
| 607 | case Absyn.QUALIFIED(part_str, part) | ||
| 608 | algorithm | ||
| 609 | 1 | (bc, part) := splitExtendsErrorPath(part); | |
| 610 | 1 | then | |
| 611 | (bc, Absyn.QUALIFIED(part_str, part)); | ||
| 612 | |||
| 613 | end match; | ||
| 614 | end splitExtendsErrorPath; | ||
| 615 | |||
| 616 | public function printExtendsError | ||
| 617 | input Absyn.Path inErrorPath; | ||
| 618 | input Env inEnv; | ||
| 619 | input SourceInfo inInfo; | ||
| 620 | algorithm | ||
| 621 | () := matchcontinue inErrorPath | ||
| 622 | local | ||
| 623 | String err_str; | ||
| 624 | Absyn.Path bc, part; | ||
| 625 | Env env; | ||
| 626 | |||
| 627 | case Absyn.QUALIFIED(name = "$E", | ||
| 628 | path = Absyn.QUALIFIED(name = err_str, path = bc)) | ||
| 629 | algorithm | ||
| 630 | 2 | (bc, part) := splitExtendsErrorPath(bc); | |
| 631 | 2 | env := NFSCodeEnv.removeExtendFromLocalScope(inErrorPath, inEnv); | |
| 632 | 2 | printExtendsError2(err_str, bc, part, env, inInfo); | |
| 633 | then | ||
| 634 | (); | ||
| 635 | |||
| 636 | else | ||
| 637 | algorithm | ||
| 638 | ✗ | true := Flags.isSet(Flags.FAILTRACE); | |
| 639 | ✗ | Debug.traceln("- NFEnvExtends.printExtendsError failed to print error " + | |
| 640 | AbsynUtil.pathString(inErrorPath)); | ||
| 641 | ✗ | then | |
| 642 | fail(); | ||
| 643 | |||
| 644 | end matchcontinue; | ||
| 645 | end printExtendsError; | ||
| 646 | |||
| 647 | public function printExtendsError2 | ||
| 648 | input String inError; | ||
| 649 | input Absyn.Path inBaseClass; | ||
| 650 | input Absyn.Path inPartPath; | ||
| 651 | input Env inEnv; | ||
| 652 | input SourceInfo inInfo; | ||
| 653 | algorithm | ||
| 654 | () := matchcontinue inPartPath | ||
| 655 | local | ||
| 656 | String bc_str, env_str, part; | ||
| 657 | list<Extends> exts; | ||
| 658 | SourceInfo info; | ||
| 659 | |||
| 660 | case _ | ||
| 661 | algorithm | ||
| 662 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
2 | true := stringEq(inError, BASECLASS_NOT_FOUND_ERROR); |
| 663 | |||
| 664 | ✗ | bc_str := AbsynUtil.pathString(inBaseClass); | |
| 665 | ✗ | env_str := NFSCodeEnv.getEnvName(inEnv); | |
| 666 | ✗ | Error.addSourceMessage(Error.LOOKUP_BASECLASS_ERROR, | |
| 667 | {bc_str, env_str}, inInfo); | ||
| 668 | then | ||
| 669 | (); | ||
| 670 | |||
| 671 | case Absyn.IDENT(part) | ||
| 672 | algorithm | ||
| 673 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
|
1 | true := stringEq(inError, BASECLASS_INHERITED_ERROR); |
| 674 | |||
| 675 | 1 | bc_str := AbsynUtil.pathString(inBaseClass); | |
| 676 | 1 | Error.addSourceMessage(Error.INHERITED_EXTENDS, {bc_str}, inInfo); | |
| 677 | 1 | exts := NFSCodeEnv.getEnvExtendsFromTable(inEnv); | |
| 678 | 1 | printInheritedExtendsError(part, exts, inEnv); | |
| 679 | then | ||
| 680 | (); | ||
| 681 | |||
| 682 | case _ | ||
| 683 | algorithm | ||
| 684 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
|
1 | true := stringEq(inError, BASECLASS_REPLACEABLE_ERROR); |
| 685 | |||
| 686 | ✗ | (NFSCodeEnv.CLASS(cls = SCode.CLASS(name = part, info = info)), _, _) := | |
| 687 | NFSCodeLookup.lookupFullyQualified(inPartPath, inEnv); | ||
| 688 | ✗ | bc_str := AbsynUtil.pathString(inBaseClass); | |
| 689 | ✗ | Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, inInfo); | |
| 690 | ✗ | Error.addSourceMessage(Error.REPLACEABLE_BASE_CLASS, {part, bc_str}, info); | |
| 691 | then | ||
| 692 | (); | ||
| 693 | |||
| 694 | case _ | ||
| 695 | algorithm | ||
| 696 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
|
1 | true := stringEq(inError, BASECLASS_IS_VAR_ERROR); |
| 697 | |||
| 698 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
|
1 | (NFSCodeEnv.VAR(var = SCode.COMPONENT(name = part, info = info)), _, _) := |
| 699 | NFSCodeLookup.lookupFullyQualified(inPartPath, inEnv); | ||
| 700 | 1 | bc_str := AbsynUtil.pathString(inBaseClass); | |
| 701 | 1 | Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, info); | |
| 702 | 1 | Error.addSourceMessage(Error.EXTEND_THROUGH_COMPONENT, | |
| 703 | {part, bc_str}, inInfo); | ||
| 704 | then | ||
| 705 | (); | ||
| 706 | |||
| 707 | end matchcontinue; | ||
| 708 | end printExtendsError2; | ||
| 709 | |||
| 710 | protected function printInheritedExtendsError | ||
| 711 | input String inName; | ||
| 712 | input list<Extends> inExtends; | ||
| 713 | input Env inEnv; | ||
| 714 | algorithm | ||
| 715 | () := matchcontinue inExtends | ||
| 716 | local | ||
| 717 | list<Extends> rest_ext; | ||
| 718 | Extends ext; | ||
| 719 | Item item; | ||
| 720 | SourceInfo info1, info2; | ||
| 721 | Absyn.Path bc; | ||
| 722 | String bc_str; | ||
| 723 | |||
| 724 | case (ext as NFSCodeEnv.EXTENDS(baseClass = bc, info = info2)) :: rest_ext | ||
| 725 | algorithm | ||
| 726 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
2 | (SOME(item), _, _) := NFSCodeLookup.lookupInBaseClasses3(inName, ext, |
| 727 | inEnv, inEnv, NFSCodeLookup.IGNORE_REDECLARES(), {}); | ||
| 728 | 2 | info1 := NFSCodeEnv.getItemInfo(item); | |
| 729 | 2 | NFSCodeEnv.EXTENDS(baseClass = bc, info = info2) := ext; | |
| 730 | 2 | bc := AbsynUtil.makeNotFullyQualified(bc); | |
| 731 | 2 | bc_str := AbsynUtil.pathString(bc); | |
| 732 | 2 | Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, info1); | |
| 733 | 2 | Error.addSourceMessage(Error.EXTENDS_INHERITED_FROM_LOCAL_EXTENDS, | |
| 734 | {inName, bc_str}, info2); | ||
| 735 | 2 | printInheritedExtendsError(inName, rest_ext, inEnv); | |
| 736 | then | ||
| 737 | (); | ||
| 738 | |||
| 739 | case _ :: rest_ext | ||
| 740 | algorithm | ||
| 741 | ✗ | printInheritedExtendsError(inName, rest_ext, inEnv); | |
| 742 | then | ||
| 743 | (); | ||
| 744 | |||
| 745 | case {} then (); | ||
| 746 | |||
| 747 | end matchcontinue; | ||
| 748 | end printInheritedExtendsError; | ||
| 749 | |||
| 750 | protected function lookupSimpleName | ||
| 751 | input String inName; | ||
| 752 | input Env inEnv; | ||
| 753 | input ExtendsTableArray inExtendsTable; | ||
| 754 | output Option<Item> outItem; | ||
| 755 | output Option<Absyn.Path> outPath; | ||
| 756 | output Option<Env> outEnv; | ||
| 757 | output Boolean outFromExtends; | ||
| 758 | algorithm | ||
| 759 | (outItem, outPath, outEnv, outFromExtends) := | ||
| 760 | matchcontinue inEnv | ||
| 761 | local | ||
| 762 | FrameType frame_type; | ||
| 763 | Env env; | ||
| 764 | Option<Item> opt_item; | ||
| 765 | Option<Env> opt_env; | ||
| 766 | Option<Absyn.Path> opt_path; | ||
| 767 | Boolean fe; | ||
| 768 | |||
| 769 | case _ | ||
| 770 | algorithm | ||
| 771 | 4542586 | (opt_item, opt_path, opt_env, fe) := lookupInLocalScope(inName, inEnv, inExtendsTable); | |
| 772 | then | ||
| 773 | (opt_item, opt_path, opt_env, fe); | ||
| 774 | |||
| 775 | case NFSCodeEnv.FRAME(frameType = frame_type) :: env | ||
| 776 | algorithm | ||
| 777 | 2674053 | NFSCodeLookup.frameNotEncapsulated(frame_type); | |
| 778 | 2674053 | (opt_item, opt_path, opt_env, _) := lookupSimpleName(inName, env, inExtendsTable); | |
| 779 | 2674053 | then | |
| 780 | (opt_item, opt_path, opt_env, false); | ||
| 781 | |||
| 782 | 337 | else (NONE(), NONE(), NONE(), false); | |
| 783 | |||
| 784 | end matchcontinue; | ||
| 785 | end lookupSimpleName; | ||
| 786 | |||
| 787 | protected function lookupInLocalScope | ||
| 788 | input String inName; | ||
| 789 | input Env inEnv; | ||
| 790 | input ExtendsTableArray inExtendsTable; | ||
| 791 | output Option<Item> outItem; | ||
| 792 | output Option<Absyn.Path> outPath; | ||
| 793 | output Option<Env> outEnv; | ||
| 794 | output Boolean outFromExtends; | ||
| 795 | algorithm | ||
| 796 | (outItem, outPath, outEnv, outFromExtends) := | ||
| 797 | matchcontinue inEnv | ||
| 798 | local | ||
| 799 | Item item; | ||
| 800 | Env env; | ||
| 801 | Option<Item> oitem; | ||
| 802 | Option<Absyn.Path> opath; | ||
| 803 | Option<Env> oenv; | ||
| 804 | list<Extends> bcl; | ||
| 805 | list<Import> imps; | ||
| 806 | |||
| 807 | case _ | ||
| 808 | algorithm | ||
| 809 | 16809654 | (item, env) := NFSCodeLookup.lookupInClass(inName, inEnv); | |
| 810 | 22290118 | then | |
| 811 | (SOME(item), SOME(Absyn.IDENT(inName)), SOME(env), false); | ||
| 812 | |||
| 813 | case NFSCodeEnv.FRAME(extendsTable = NFSCodeEnv.EXTENDS_TABLE( | ||
| 814 | baseClasses = bcl as _ :: _)) :: _ | ||
| 815 | algorithm | ||
| 816 | 2915524 | (oitem, oenv) := lookupInBaseClasses(inName, bcl, inEnv, inExtendsTable); | |
| 817 | 6 | then | |
| 818 | (oitem, SOME(Absyn.IDENT(inName)), oenv, true); | ||
| 819 | |||
| 820 | case NFSCodeEnv.FRAME(importTable = | ||
| 821 | NFSCodeEnv.IMPORT_TABLE(hidden = false, qualifiedImports = imps)) :: _ | ||
| 822 | algorithm | ||
| 823 | 2695304 | (oitem, opath, oenv) := | |
| 824 | lookupInQualifiedImports(inName, imps, inEnv, inExtendsTable); | ||
| 825 | 18982 | then | |
| 826 | (oitem, opath, oenv, false); | ||
| 827 | |||
| 828 | case NFSCodeEnv.FRAME(importTable = | ||
| 829 | NFSCodeEnv.IMPORT_TABLE(hidden = false, unqualifiedImports = imps)) :: _ | ||
| 830 | algorithm | ||
| 831 | 2676322 | (oitem, opath, oenv) := | |
| 832 | lookupInUnqualifiedImports(inName, imps, inEnv, inExtendsTable); | ||
| 833 | 1 | then | |
| 834 | (oitem, opath, oenv, false); | ||
| 835 | |||
| 836 | end matchcontinue; | ||
| 837 | end lookupInLocalScope; | ||
| 838 | |||
| 839 | protected function lookupInBaseClasses | ||
| 840 | input String inName; | ||
| 841 | input list<Extends> inExtends; | ||
| 842 | input Env inEnv; | ||
| 843 | input ExtendsTableArray inExtendsTable; | ||
| 844 | output Option<Item> outItem; | ||
| 845 | output Option<Env> outEnv; | ||
| 846 | algorithm | ||
| 847 | (outItem, outEnv) := | ||
| 848 | matchcontinue inExtends | ||
| 849 | local | ||
| 850 | Extends ext; | ||
| 851 | list<Extends> rest_ext; | ||
| 852 | Option<Extends> opt_ext; | ||
| 853 | Option<Item> opt_item; | ||
| 854 | Option<Env> opt_env; | ||
| 855 | Env env; | ||
| 856 | |||
| 857 | case ext :: _ | ||
| 858 | algorithm | ||
| 859 | // Unhide the imports, otherwise we might not be able to find the base | ||
| 860 | // classes. | ||
| 861 | 2969600 | env := NFSCodeEnv.setImportTableHidden(inEnv, false); | |
| 862 | 2969600 | opt_ext := qualifyExtends2(ext, env, inExtendsTable); | |
| 863 | 2969600 | (opt_item, opt_env) := | |
| 864 | lookupInBaseClasses2(inName, opt_ext, env, inExtendsTable); | ||
| 865 | then | ||
| 866 | (opt_item, opt_env); | ||
| 867 | |||
| 868 | case _ :: rest_ext | ||
| 869 | algorithm | ||
| 870 | 2969597 | (opt_item, opt_env) := | |
| 871 | lookupInBaseClasses(inName, rest_ext, inEnv, inExtendsTable); | ||
| 872 | then | ||
| 873 | (opt_item, opt_env); | ||
| 874 | |||
| 875 | end matchcontinue; | ||
| 876 | end lookupInBaseClasses; | ||
| 877 | |||
| 878 | protected function lookupInBaseClasses2 | ||
| 879 | input String inName; | ||
| 880 | input Option<Extends> inExtends; | ||
| 881 | input Env inEnv; | ||
| 882 | input ExtendsTableArray inExtendsTable; | ||
| 883 | output Option<Item> outItem; | ||
| 884 | output Option<Env> outEnv; | ||
| 885 | algorithm | ||
| 886 | (outItem, outEnv) := match inExtends | ||
| 887 | local | ||
| 888 | Absyn.Path bc; | ||
| 889 | Item item; | ||
| 890 | Env env; | ||
| 891 | Option<Item> opt_item; | ||
| 892 | Option<Env> opt_env; | ||
| 893 | |||
| 894 | case SOME(NFSCodeEnv.EXTENDS(baseClass = Absyn.FULLYQUALIFIED(bc))) | ||
| 895 | algorithm | ||
| 896 | 2968954 | (item, env) := lookupFullyQualified(bc, inEnv, inExtendsTable); | |
| 897 | 2968954 | env := NFSCodeEnv.mergeItemEnv(item, env); | |
| 898 | // Hide the imports to make sure we don't find any elements through | ||
| 899 | // them, since imports are not inherited. | ||
| 900 | 2968954 | env := NFSCodeEnv.setImportTableHidden(env, true); | |
| 901 | 2968954 | (opt_item, _, opt_env, _) := lookupInLocalScope(inName, env, inExtendsTable); | |
| 902 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | then |
| 903 | (opt_item, opt_env); | ||
| 904 | |||
| 905 | end match; | ||
| 906 | end lookupInBaseClasses2; | ||
| 907 | |||
| 908 | protected function lookupInQualifiedImports | ||
| 909 | input String inName; | ||
| 910 | input list<Import> inImports; | ||
| 911 | input Env inEnv; | ||
| 912 | input ExtendsTableArray inExtendsTable; | ||
| 913 | output Option<Item> outItem; | ||
| 914 | output Option<Absyn.Path> outPath; | ||
| 915 | output Option<Env> outEnv; | ||
| 916 | algorithm | ||
| 917 | (outItem, outPath, outEnv) := matchcontinue inImports | ||
| 918 | local | ||
| 919 | Absyn.Ident name; | ||
| 920 | Absyn.Path path; | ||
| 921 | Item item; | ||
| 922 | list<Import> rest_imps; | ||
| 923 | Option<Item> opt_item; | ||
| 924 | Option<Absyn.Path> opt_path; | ||
| 925 | Option<Env> opt_env; | ||
| 926 | Env env; | ||
| 927 | |||
| 928 | case Absyn.NAMED_IMPORT(name = name) :: rest_imps | ||
| 929 | algorithm | ||
| 930 |
4/4✓ Branch 0 taken 28291 times.
✓ Branch 1 taken 964412 times.
✓ Branch 3 taken 18982 times.
✓ Branch 4 taken 9309 times.
|
992703 | false := stringEqual(inName, name); |
| 931 | 973721 | (opt_item, opt_path, opt_env) := | |
| 932 | lookupInQualifiedImports(inName, rest_imps, inEnv, inExtendsTable); | ||
| 933 | then | ||
| 934 | (opt_item, opt_path, opt_env); | ||
| 935 | |||
| 936 | case Absyn.NAMED_IMPORT(name = name, path = path) :: _ | ||
| 937 | algorithm | ||
| 938 |
4/4✓ Branch 0 taken 24225 times.
✓ Branch 1 taken 960328 times.
✓ Branch 3 taken 5243 times.
✓ Branch 4 taken 18982 times.
|
984553 | true := stringEqual(inName, name); |
| 939 | 18982 | (item, env) := lookupFullyQualified(path, inEnv, inExtendsTable); | |
| 940 | 18982 | path := NFSCodeEnv.prefixIdentWithEnv(inName, env); | |
| 941 | 18982 | path := AbsynUtil.makeFullyQualified(path); | |
| 942 | 18982 | then | |
| 943 | (SOME(item), SOME(path), SOME(env)); | ||
| 944 | |||
| 945 | case Absyn.NAMED_IMPORT(name = name) :: _ | ||
| 946 | algorithm | ||
| 947 |
3/4✓ Branch 0 taken 5243 times.
✓ Branch 1 taken 960328 times.
✓ Branch 3 taken 5243 times.
✗ Branch 4 not taken.
|
965571 | true := stringEqual(inName, name); |
| 948 | ✗ | then | |
| 949 | (NONE(), NONE(), NONE()); | ||
| 950 | |||
| 951 | end matchcontinue; | ||
| 952 | end lookupInQualifiedImports; | ||
| 953 | |||
| 954 | protected function lookupInUnqualifiedImports | ||
| 955 | input Absyn.Ident inName; | ||
| 956 | input list<Import> inImports; | ||
| 957 | input Env inEnv; | ||
| 958 | input ExtendsTableArray inExtendsTable; | ||
| 959 | output Option<Item> outItem; | ||
| 960 | output Option<Absyn.Path> outPath; | ||
| 961 | output Option<Env> outEnv; | ||
| 962 | algorithm | ||
| 963 | (outItem, outPath, outEnv) := matchcontinue inImports | ||
| 964 | local | ||
| 965 | Item item; | ||
| 966 | Absyn.Path path; | ||
| 967 | list<Import> rest_imps; | ||
| 968 | Env env; | ||
| 969 | Option<Item> opt_item; | ||
| 970 | Option<Absyn.Path> opt_path; | ||
| 971 | Option<Env> opt_env; | ||
| 972 | |||
| 973 | case Absyn.UNQUAL_IMPORT(path = path) :: _ | ||
| 974 | algorithm | ||
| 975 | 2269 | (item, env) := lookupFullyQualified(path, inEnv, inExtendsTable); | |
| 976 | 2269 | env := NFSCodeEnv.mergeItemEnv(item, env); | |
| 977 | 2269 | (item, env) := lookupFullyQualified2(Absyn.IDENT(inName), env, inExtendsTable); | |
| 978 | 1 | path := NFSCodeEnv.prefixIdentWithEnv(inName, env); | |
| 979 | 1 | path := AbsynUtil.makeFullyQualified(path); | |
| 980 | 1 | then | |
| 981 | (SOME(item), SOME(path), SOME(env)); | ||
| 982 | |||
| 983 | case _ :: rest_imps | ||
| 984 | algorithm | ||
| 985 | 2268 | (opt_item, opt_path, opt_env) := | |
| 986 | lookupInUnqualifiedImports(inName, rest_imps, inEnv, inExtendsTable); | ||
| 987 | then | ||
| 988 | (opt_item, opt_path, opt_env); | ||
| 989 | |||
| 990 | end matchcontinue; | ||
| 991 | end lookupInUnqualifiedImports; | ||
| 992 | |||
| 993 | protected function lookupFullyQualified | ||
| 994 | input Absyn.Path inName; | ||
| 995 | input Env inEnv; | ||
| 996 | input ExtendsTableArray inExtendsTable; | ||
| 997 | output Item outItem; | ||
| 998 | output Env outEnv; | ||
| 999 | protected | ||
| 1000 | Env env; | ||
| 1001 | algorithm | ||
| 1002 | 2990205 | env := NFSCodeEnv.getEnvTopScope(inEnv); | |
| 1003 | 2990205 | (outItem, outEnv) := lookupFullyQualified2(inName, env, inExtendsTable); | |
| 1004 | end lookupFullyQualified; | ||
| 1005 | |||
| 1006 | protected function lookupFullyQualified2 | ||
| 1007 | input Absyn.Path inName; | ||
| 1008 | input Env inEnv; | ||
| 1009 | input ExtendsTableArray inExtendsTable; | ||
| 1010 | output Item outItem; | ||
| 1011 | output Env outEnv; | ||
| 1012 | algorithm | ||
| 1013 | (outItem, outEnv) := match inName | ||
| 1014 | local | ||
| 1015 | String name; | ||
| 1016 | Absyn.Path rest_path; | ||
| 1017 | Item item; | ||
| 1018 | Env env; | ||
| 1019 | |||
| 1020 | case Absyn.IDENT(name = name) | ||
| 1021 | algorithm | ||
| 1022 |
5/10✗ Branch 1 not taken.
✓ Branch 2 taken 2990206 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2990206 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2990206 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2990206 times.
✓ Branch 9 taken 2990206 times.
✗ Branch 10 not taken.
|
2992474 | (SOME(item), _, SOME(env), _) := |
| 1023 | lookupInLocalScope(name, inEnv, inExtendsTable); | ||
| 1024 | then | ||
| 1025 | (item, env); | ||
| 1026 | |||
| 1027 | case Absyn.QUALIFIED(name = name, path = rest_path) | ||
| 1028 | algorithm | ||
| 1029 |
4/8✗ Branch 1 not taken.
✓ Branch 2 taken 6305640 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6305640 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6305640 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6305640 times.
|
6305640 | (SOME(item), _, SOME(env), _) := |
| 1030 | lookupInLocalScope(name, inEnv, inExtendsTable); | ||
| 1031 | 6305640 | env := NFSCodeEnv.mergeItemEnv(item, env); | |
| 1032 | 6305640 | (item, env) := lookupFullyQualified2(rest_path, env, inExtendsTable); | |
| 1033 | then | ||
| 1034 | (item, env); | ||
| 1035 | |||
| 1036 | end match; | ||
| 1037 | end lookupFullyQualified2; | ||
| 1038 | |||
| 1039 | protected function createExtendsTable | ||
| 1040 | input Integer inSize; | ||
| 1041 | output ExtendsTableArray outTable; | ||
| 1042 | algorithm | ||
| 1043 | 1103 | outTable := arrayCreate(inSize, NO_EXTENDS()); | |
| 1044 | end createExtendsTable; | ||
| 1045 | |||
| 1046 | protected function lookupQualifiedExtends | ||
| 1047 | input Integer inIndex; | ||
| 1048 | input ExtendsTableArray inExtendsTable; | ||
| 1049 | output Option<Extends> outExtends; | ||
| 1050 | protected | ||
| 1051 | ExtendsWrapper ext; | ||
| 1052 | algorithm | ||
| 1053 | 3561751 | ext := arrayGet(inExtendsTable, inIndex); | |
| 1054 | 3561751 | outExtends := lookupQualifiedExtends2(ext, inExtendsTable); | |
| 1055 | end lookupQualifiedExtends; | ||
| 1056 | |||
| 1057 | protected function lookupQualifiedExtends2 | ||
| 1058 | input ExtendsWrapper inExtends; | ||
| 1059 | input ExtendsTableArray inExtendsTable; | ||
| 1060 | output Option<Extends> outExtends; | ||
| 1061 | algorithm | ||
| 1062 | outExtends := match inExtends | ||
| 1063 | local | ||
| 1064 | Extends ext; | ||
| 1065 | |||
| 1066 | case QUALIFIED_EXTENDS(ext = ext) then SOME(ext); | ||
| 1067 | |||
| 1068 | case UNQUALIFIED_EXTENDS(ext = NFSCodeEnv.EXTENDS()) | ||
| 1069 | then NONE(); | ||
| 1070 | |||
| 1071 | end match; | ||
| 1072 | end lookupQualifiedExtends2; | ||
| 1073 | |||
| 1074 | protected function addUnqualifiedToTable | ||
| 1075 | input Extends inExtends; | ||
| 1076 | input Integer inIndex; | ||
| 1077 | input ExtendsTableArray inExtendsTable; | ||
| 1078 | algorithm | ||
| 1079 | 592472 | arrayUpdate(inExtendsTable, inIndex, UNQUALIFIED_EXTENDS(inExtends)); | |
| 1080 | end addUnqualifiedToTable; | ||
| 1081 | |||
| 1082 | protected function updateQualifiedInTable | ||
| 1083 | input Extends inExtends; | ||
| 1084 | input Integer inIndex; | ||
| 1085 | input ExtendsTableArray inExtendsTable; | ||
| 1086 | algorithm | ||
| 1087 | 592472 | arrayUpdate(inExtendsTable, inIndex, QUALIFIED_EXTENDS(inExtends)); | |
| 1088 | end updateQualifiedInTable; | ||
| 1089 | |||
| 1090 | protected function update2 | ||
| 1091 | input Env inEnv; | ||
| 1092 | output Env outEnv; | ||
| 1093 | protected | ||
| 1094 | Env env, rest_env; | ||
| 1095 | Option<String> name; | ||
| 1096 | FrameType ty; | ||
| 1097 | EnvTree.Tree tree; | ||
| 1098 | list<Extends> bcl; | ||
| 1099 | list<SCode.Element> re; | ||
| 1100 | NFSCodeEnv.ImportTable imps; | ||
| 1101 | Option<Mutable<Boolean>> iu; | ||
| 1102 | algorithm | ||
| 1103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1456771 times.
|
1456771 | NFSCodeEnv.FRAME(name, ty, tree, |
| 1104 | NFSCodeEnv.EXTENDS_TABLE(bcl, re, _), imps, iu) :: rest_env := inEnv; | ||
| 1105 | 1456771 | tree := EnvTree.map(tree, function update3(inEnv = inEnv)); | |
| 1106 | 1456769 | env := NFSCodeEnv.FRAME(name, ty, tree, | |
| 1107 | NFSCodeEnv.EXTENDS_TABLE(bcl, {}, NONE()), imps, iu) :: rest_env; | ||
| 1108 | 1456769 | outEnv := NFSCodeFlattenRedeclare.addElementRedeclarationsToEnv(re, env); | |
| 1109 | end update2; | ||
| 1110 | |||
| 1111 | protected function update3 | ||
| 1112 | input String name; | ||
| 1113 | input output Item item; | ||
| 1114 | input Env inEnv; | ||
| 1115 | algorithm | ||
| 1116 | () := match item | ||
| 1117 | local | ||
| 1118 | Env env; | ||
| 1119 | SCode.Element cls; | ||
| 1120 | ClassType cls_ty; | ||
| 1121 | Frame cls_env; | ||
| 1122 | |||
| 1123 | case NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty) | ||
| 1124 | algorithm | ||
| 1125 | // Enter the class' frame and update the class extends in it. | ||
| 1126 | 1455668 | env := NFSCodeEnv.enterFrame(cls_env, inEnv); | |
| 1127 | 1455668 | (cls, env) := updateClassExtends(cls, env, cls_ty); | |
| 1128 | // Call update2 on the class' environment to update the extends. | ||
| 1129 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1455666 times.
|
1455668 | cls_env :: _ := update2(env); |
| 1130 | // Rebuild the class item with the updated information. | ||
| 1131 | 1455666 | item := NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty); | |
| 1132 | then | ||
| 1133 | (); | ||
| 1134 | |||
| 1135 | else (); | ||
| 1136 | end match; | ||
| 1137 | end update3; | ||
| 1138 | |||
| 1139 | protected function updateClassExtends | ||
| 1140 | input SCode.Element inClass; | ||
| 1141 | input Env inEnv; | ||
| 1142 | input ClassType inClassType; | ||
| 1143 | output SCode.Element outClass; | ||
| 1144 | output Env outEnv; | ||
| 1145 | algorithm | ||
| 1146 | (outClass, outEnv) := match(inEnv, inClassType) | ||
| 1147 | local | ||
| 1148 | String name; | ||
| 1149 | Env env; | ||
| 1150 | SCode.Mod mods; | ||
| 1151 | SourceInfo info; | ||
| 1152 | SCode.Element cls, ext; | ||
| 1153 | |||
| 1154 | case (NFSCodeEnv.FRAME(name = SOME(name), | ||
| 1155 | extendsTable = NFSCodeEnv.EXTENDS_TABLE(classExtendsInfo = SOME(ext))) :: _, NFSCodeEnv.CLASS_EXTENDS()) | ||
| 1156 | algorithm | ||
| 1157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38783 times.
|
38783 | SCode.EXTENDS(modifications = mods, info = info) := ext; |
| 1158 | 38783 | (cls, env) := updateClassExtends2(inClass, name, mods, info, inEnv); | |
| 1159 | then | ||
| 1160 | (cls, env); | ||
| 1161 | |||
| 1162 | 1416885 | else (inClass, inEnv); | |
| 1163 | end match; | ||
| 1164 | end updateClassExtends; | ||
| 1165 | |||
| 1166 | protected function updateClassExtends2 | ||
| 1167 | input SCode.Element inClass; | ||
| 1168 | input String inName; | ||
| 1169 | input SCode.Mod inMods; | ||
| 1170 | input SourceInfo inInfo; | ||
| 1171 | input Env inEnv; | ||
| 1172 | output SCode.Element outClass; | ||
| 1173 | output Env outEnv; | ||
| 1174 | algorithm | ||
| 1175 | (outClass, outEnv) := matchcontinue inEnv | ||
| 1176 | local | ||
| 1177 | SCode.Element ext; | ||
| 1178 | Frame cls_frame; | ||
| 1179 | Env env; | ||
| 1180 | SCode.Element cls; | ||
| 1181 | Absyn.Path path; | ||
| 1182 | |||
| 1183 | case cls_frame :: env | ||
| 1184 | algorithm | ||
| 1185 | 38783 | (path,_) := lookupClassExtendsBaseClass(inName, env, inInfo); | |
| 1186 | 38782 | ext := SCode.EXTENDS(path, SCode.PUBLIC(), inMods, NONE(), inInfo); | |
| 1187 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 38782 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38782 times.
|
38782 | {cls_frame} := NFSCodeEnv.extendEnvWithExtends(ext, {cls_frame}); |
| 1188 | 38782 | cls := SCodeUtil.addElementToClass(ext, inClass); | |
| 1189 | then | ||
| 1190 | (cls, cls_frame :: env); | ||
| 1191 | |||
| 1192 | else (inClass, inEnv); | ||
| 1193 | end matchcontinue; | ||
| 1194 | end updateClassExtends2; | ||
| 1195 | |||
| 1196 | protected function lookupClassExtendsBaseClass | ||
| 1197 | "This function takes the name of a base class and looks up that name suffixed | ||
| 1198 | with the base class suffix defined in NFSCodeEnv. I.e. it looks up the real base | ||
| 1199 | class of a class extends, and not the alias introduced when adding replaceable | ||
| 1200 | classes to the environment in NFSCodeEnv.extendEnvWithClassDef. It returns the | ||
| 1201 | path and the item for that base class." | ||
| 1202 | input String inName; | ||
| 1203 | input Env inEnv; | ||
| 1204 | input SourceInfo inInfo; | ||
| 1205 | output Absyn.Path outPath; | ||
| 1206 | output Item outItem; | ||
| 1207 | algorithm | ||
| 1208 | (outPath, outItem) := matchcontinue inInfo | ||
| 1209 | local | ||
| 1210 | Absyn.Path path; | ||
| 1211 | Item item; | ||
| 1212 | String basename; | ||
| 1213 | |||
| 1214 | // Add the base class suffix to the name and try to look it up. | ||
| 1215 | case _ | ||
| 1216 | algorithm | ||
| 1217 | 38783 | basename := inName + NFSCodeEnv.BASE_CLASS_SUFFIX; | |
| 1218 | 38783 | (item, _) := NFSCodeLookup.lookupInheritedName(basename, inEnv); | |
| 1219 | // Use a special $ce qualified so that we can find the correct class | ||
| 1220 | // with NFSCodeLookup.lookupBaseClassName. | ||
| 1221 | 38782 | path := Absyn.QUALIFIED("$ce", Absyn.IDENT(basename)); | |
| 1222 | then | ||
| 1223 | (path, item); | ||
| 1224 | |||
| 1225 | // The previous case will fail if we try to class extend a | ||
| 1226 | // non-replaceable class, because they don't have aliases. To get the | ||
| 1227 | // correct error message later we look the class up via the non-alias name | ||
| 1228 | // instead and return that result if found. | ||
| 1229 | case _ | ||
| 1230 | algorithm | ||
| 1231 | 1 | (item, _) := NFSCodeLookup.lookupInheritedName(inName, inEnv); | |
| 1232 | ✗ | path := Absyn.IDENT(inName); | |
| 1233 | then | ||
| 1234 | (path, item); | ||
| 1235 | |||
| 1236 | // If the class doesn't even exist, show an error. | ||
| 1237 | else | ||
| 1238 | algorithm | ||
| 1239 | 1 | Error.addSourceMessage(Error.INVALID_REDECLARATION_OF_CLASS, | |
| 1240 | {inName}, inInfo); | ||
| 1241 | 1 | then | |
| 1242 | fail(); | ||
| 1243 | |||
| 1244 | end matchcontinue; | ||
| 1245 | end lookupClassExtendsBaseClass; | ||
| 1246 | |||
| 1247 | public function extendEnvWithClassExtends | ||
| 1248 | "Extends the environment with the given class extends element." | ||
| 1249 | input SCode.Element inClassExtends; | ||
| 1250 | input Env inEnv; | ||
| 1251 | output Env outEnv; | ||
| 1252 | algorithm | ||
| 1253 | outEnv := match inClassExtends | ||
| 1254 | local | ||
| 1255 | SCode.Partial pp; | ||
| 1256 | SCode.Encapsulated ep; | ||
| 1257 | SCode.Restriction res; | ||
| 1258 | SCode.Prefixes prefixes; | ||
| 1259 | SourceInfo info; | ||
| 1260 | Env env, cls_env; | ||
| 1261 | SCode.Mod mods; | ||
| 1262 | SCode.ClassDef cdef; | ||
| 1263 | SCode.Element cls, ext; | ||
| 1264 | String name, el_str, env_str, err_msg; | ||
| 1265 | SCode.Comment cmt; | ||
| 1266 | |||
| 1267 | // When a 'class extends X' is encountered we insert a 'class X extends | ||
| 1268 | // BaseClass.X' into the environment, with the same elements as the class | ||
| 1269 | // extends clause. BaseClass is the class that class X is inherited from. | ||
| 1270 | // This allows us to look up elements in class extends, because lookup can | ||
| 1271 | // handle normal extends. This is the first phase where the CLASS_EXTENDS is | ||
| 1272 | // converted to a PARTS and added to the environment, and the extends is | ||
| 1273 | // added to the class environment's extends table. The rest of the work is | ||
| 1274 | // done later in updateClassExtends when we have a complete environment. | ||
| 1275 | case SCode.CLASS( | ||
| 1276 | name = name, | ||
| 1277 | prefixes = prefixes, | ||
| 1278 | encapsulatedPrefix = ep, | ||
| 1279 | partialPrefix = pp, | ||
| 1280 | restriction = res, | ||
| 1281 | classDef = SCode.CLASS_EXTENDS( | ||
| 1282 | modifications = mods, | ||
| 1283 | composition = cdef), | ||
| 1284 | cmt=cmt, info = info) | ||
| 1285 | algorithm | ||
| 1286 | // Construct a new PARTS class with the data from the class extends. | ||
| 1287 | 38783 | cls := SCode.CLASS(name, prefixes, ep, pp, res, cdef, cmt, info); | |
| 1288 | |||
| 1289 | // Construct the class environment and add the new extends to it. | ||
| 1290 | 38783 | cls_env := NFSCodeEnv.makeClassEnvironment(cls, false); | |
| 1291 | 38783 | ext := SCode.EXTENDS(Absyn.IDENT(name), SCode.PUBLIC(), mods, NONE(), info); | |
| 1292 | 38783 | cls_env := addClassExtendsInfoToEnv(ext, cls_env); | |
| 1293 | |||
| 1294 | // Finally add the class to the environment. | ||
| 1295 | 38783 | env := NFSCodeEnv.extendEnvWithItem( | |
| 1296 | NFSCodeEnv.newClassItem(cls, cls_env, NFSCodeEnv.CLASS_EXTENDS()), inEnv, name); | ||
| 1297 | then env; | ||
| 1298 | |||
| 1299 | case _ | ||
| 1300 | algorithm | ||
| 1301 | ✗ | info := SCodeUtil.elementInfo(inClassExtends); | |
| 1302 | ✗ | el_str := SCodeDump.unparseElementStr(inClassExtends,SCodeDump.defaultOptions); | |
| 1303 | ✗ | env_str := NFSCodeEnv.getEnvName(inEnv); | |
| 1304 | ✗ | err_msg := "NFSCodeFlattenRedeclare.extendEnvWithClassExtends failed on unknown element " + | |
| 1305 | el_str + " in " + env_str; | ||
| 1306 | ✗ | Error.addSourceMessage(Error.INTERNAL_ERROR, {err_msg}, info); | |
| 1307 | ✗ | then | |
| 1308 | fail(); | ||
| 1309 | |||
| 1310 | end match; | ||
| 1311 | end extendEnvWithClassExtends; | ||
| 1312 | |||
| 1313 | protected function addClassExtendsInfoToEnv | ||
| 1314 | "Adds a class extends to the environment." | ||
| 1315 | input SCode.Element inClassExtends; | ||
| 1316 | input Env inEnv; | ||
| 1317 | output Env outEnv; | ||
| 1318 | algorithm | ||
| 1319 | outEnv := matchcontinue inEnv | ||
| 1320 | local | ||
| 1321 | list<Extends> bcl; | ||
| 1322 | list<SCode.Element> re; | ||
| 1323 | String estr; | ||
| 1324 | NFSCodeEnv.ExtendsTable ext; | ||
| 1325 | |||
| 1326 | case _ | ||
| 1327 | algorithm | ||
| 1328 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 38783 times.
✓ Branch 3 taken 38783 times.
✗ Branch 4 not taken.
|
38783 | NFSCodeEnv.EXTENDS_TABLE(bcl, re, NONE()) := |
| 1329 | NFSCodeEnv.getEnvExtendsTable(inEnv); | ||
| 1330 | 38783 | ext := NFSCodeEnv.EXTENDS_TABLE(bcl, re, SOME(inClassExtends)); | |
| 1331 | 38783 | then | |
| 1332 | NFSCodeEnv.setEnvExtendsTable(ext, inEnv); | ||
| 1333 | |||
| 1334 | else | ||
| 1335 | algorithm | ||
| 1336 | estr := "- NFEnvExtends.addClassExtendsInfoToEnv: Trying to overwrite " + | ||
| 1337 | "existing class extends information, this should not happen!."; | ||
| 1338 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {estr}); | |
| 1339 | ✗ | then | |
| 1340 | fail(); | ||
| 1341 | |||
| 1342 | end matchcontinue; | ||
| 1343 | end addClassExtendsInfoToEnv; | ||
| 1344 | |||
| 1345 | annotation(__OpenModelica_Interface="frontend"); | ||
| 1346 | end NFEnvExtends; | ||
| 1347 |