OMCompiler/Compiler/NFFrontEnd/NFInstanceAPI.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 NFInstanceAPI | ||
| 37 | "The model-instance API: instantiate a class and dump what it looks like as | ||
| 38 | JSON (issue #15219). Split out of NFApi so that a tool needing only this — | ||
| 39 | the documentation generator, which renders icons and member tables from a | ||
| 40 | model instance — does not link the backend. NFApi keeps the scripting | ||
| 41 | entry points and passes SymbolTable's program in." | ||
| 42 | |||
| 43 | import Absyn; | ||
| 44 | import AbsynUtil; | ||
| 45 | import SCode; | ||
| 46 | import DAE; | ||
| 47 | import NFModifier.Modifier; | ||
| 48 | import JSON; | ||
| 49 | |||
| 50 | protected | ||
| 51 | |||
| 52 | import NFInst; | ||
| 53 | import Inst = NFInst; | ||
| 54 | import NFCall.Call; | ||
| 55 | import NFInstContext; | ||
| 56 | import NFModifier; | ||
| 57 | import NFBinding.Binding; | ||
| 58 | import NFComponent.Component; | ||
| 59 | import ComponentRef = NFComponentRef; | ||
| 60 | import Dimension = NFDimension; | ||
| 61 | import Expression = NFExpression; | ||
| 62 | import Import = NFImport; | ||
| 63 | import NFClass.Class; | ||
| 64 | import NFInstNode; | ||
| 65 | import MutableWeak; | ||
| 66 | import NFInstNode.InstNode; | ||
| 67 | import NFInstNode.InstNodeType; | ||
| 68 | import Equation = NFEquation; | ||
| 69 | import NFType.Type; | ||
| 70 | import Subscript = NFSubscript; | ||
| 71 | import InstContext = NFInstContext; | ||
| 72 | |||
| 73 | import Absyn.Path; | ||
| 74 | import AbsynToSCode; | ||
| 75 | import Config; | ||
| 76 | import Dump; | ||
| 77 | import Error; | ||
| 78 | import ErrorExt; | ||
| 79 | import Mutable; | ||
| 80 | import ExecStat.execStat; | ||
| 81 | import FBuiltin; | ||
| 82 | import Flags; | ||
| 83 | import Global; | ||
| 84 | import List; | ||
| 85 | import Lookup = NFLookup; | ||
| 86 | import MetaModelica.Dangerous; | ||
| 87 | import MetaModelica.Dangerous.listReverseInPlace; | ||
| 88 | import Ceval = NFCeval; | ||
| 89 | import NFClassTree.ClassTree; | ||
| 90 | import NFPrefixes.{Variability, Purity}; | ||
| 91 | import NFSections.Sections; | ||
| 92 | import Parser; | ||
| 93 | import Restriction = NFRestriction; | ||
| 94 | import SimplifyExp = NFSimplifyExp; | ||
| 95 | import Settings; | ||
| 96 | import Typing = NFTyping; | ||
| 97 | import UnorderedMap; | ||
| 98 | import Util; | ||
| 99 | import SCodeUtil; | ||
| 100 | import SCodeDump; | ||
| 101 | import ElementSource; | ||
| 102 | import InstSettings = NFInst.InstSettings; | ||
| 103 | |||
| 104 | constant InstContext.Type ANNOTATION_CONTEXT = intBitOr(NFInstContext.RELAXED, NFInstContext.ANNOTATION); | ||
| 105 | constant InstContext.Type INST_API_ANNOTATION_CONTEXT = intBitOr(ANNOTATION_CONTEXT, NFInstContext.INSTANCE_API); | ||
| 106 | |||
| 107 | public | ||
| 108 | |||
| 109 | function annotationProgram | ||
| 110 | "The graphical annotation definitions, parsed from lib/omc. A copy of | ||
| 111 | InteractiveUtil.modelicaAnnotationProgram, which lives in the backend." | ||
| 112 | input String annotationVersion "1.x or 2.x or 3.x"; | ||
| 113 | output Absyn.Program program; | ||
| 114 | protected | ||
| 115 | String filename; | ||
| 116 | algorithm | ||
| 117 | 2057 | filename := Settings.getInstallationDirectoryPath() + | |
| 118 | "/lib/omc/AnnotationsBuiltin_" + | ||
| 119 | Util.stringReplaceChar(annotationVersion, ".", "_") + | ||
| 120 | ".mo"; | ||
| 121 | 2057 | program := Parser.parse(filename, "UTF-8"); | |
| 122 | end annotationProgram; | ||
| 123 | |||
| 124 | public function mkTop | ||
| 125 | "The `top` scope the instance API instantiates in. `scodeProgram` is the | ||
| 126 | already translated form of `absynProgram` when the caller has one — the | ||
| 127 | scripting API passes SymbolTable's, which saves retranslating the whole | ||
| 128 | library on every call." | ||
| 129 | input Absyn.Program absynProgram; | ||
| 130 | input Option<SCode.Program> scodeProgram = NONE(); | ||
| 131 | input String name; | ||
| 132 | output SCode.Program program; | ||
| 133 | output InstNode top; | ||
| 134 | protected | ||
| 135 | SCode.Program scode_builtin, graphicProgramSCode; | ||
| 136 | Absyn.Program placementProgram; | ||
| 137 | list<tuple<Absyn.Program, tuple<SCode.Program, InstNode>>> cache; | ||
| 138 | Boolean reuse; | ||
| 139 | algorithm | ||
| 140 | 4569 | cache := getGlobalRoot(Global.instNFNodeCacheIndex); | |
| 141 | // if absyn is the same, all fine, reuse | ||
| 142 |
4/4✓ Branch 0 taken 2562 times.
✓ Branch 1 taken 2007 times.
✓ Branch 4 taken 2512 times.
✓ Branch 5 taken 50 times.
|
4569 | reuse := if listEmpty(cache) then false else referenceEq(absynProgram, Util.tuple21(listHead(cache))); |
| 143 | if reuse then | ||
| 144 | 2512 | (program, top) := Util.tuple22(listHead(cache)); | |
| 145 | 2512 | InstNode.clearGeneratedInners(top); | |
| 146 | // Nodes made from here on belong to the cached tree, so they have to be | ||
| 147 | // rooted there rather than in whatever run was last to build a top node. | ||
| 148 | 2512 | MutableWeak.useRoots(InstNode.scopeRoots(top)); | |
| 149 | else | ||
| 150 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2007 times.
|
2057 | if not listEmpty(cache) then |
| 151 | 50 | setGlobalRoot(Global.instNFNodeCacheIndex, {}); | |
| 152 | end if; | ||
| 153 | 2057 | (_, scode_builtin) := FBuiltin.getInitialFunctions(); | |
| 154 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2057 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2057 times.
|
2057 | if isSome(scodeProgram) then |
| 155 | 2057 | SOME(program) := scodeProgram; | |
| 156 | else | ||
| 157 | ✗ | program := AbsynToSCode.translateAbsyn2SCode(absynProgram); | |
| 158 | end if; | ||
| 159 | 2057 | program := listAppend(scode_builtin, program); | |
| 160 | 2057 | placementProgram := annotationProgram(Config.getAnnotationVersion()); | |
| 161 | 2057 | graphicProgramSCode := AbsynToSCode.translateAbsyn2SCode(placementProgram); | |
| 162 | |||
| 163 | 2057 | Inst.resetGlobalFlags(); | |
| 164 | |||
| 165 | // Create a root node from the given top-level classes. | ||
| 166 | 2057 | top := NFInst.makeTopNode(program, graphicProgramSCode); | |
| 167 | |||
| 168 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2057 times.
|
2057 | if Flags.isSet(Flags.EXEC_STAT) then |
| 169 | ✗ | execStat("NFInstanceAPI.mkTop("+ name +")"); | |
| 170 | end if; | ||
| 171 | |||
| 172 | 4114 | setGlobalRoot(Global.instNFNodeCacheIndex, {(absynProgram, (program, top))}); | |
| 173 | end if; | ||
| 174 | end mkTop; | ||
| 175 | |||
| 176 | protected | ||
| 177 | |||
| 178 | uniontype InstanceTree | ||
| 179 | record COMPONENT | ||
| 180 | InstNode node; | ||
| 181 | Option<Binding> binding; | ||
| 182 | InstanceTree cls; | ||
| 183 | end COMPONENT; | ||
| 184 | |||
| 185 | record CLASS | ||
| 186 | InstNode node; | ||
| 187 | list<InstanceTree> elements; | ||
| 188 | Boolean isExtends; | ||
| 189 | end CLASS; | ||
| 190 | |||
| 191 | record BUILTIN_BASE_CLASS | ||
| 192 | String name; | ||
| 193 | end BUILTIN_BASE_CLASS; | ||
| 194 | |||
| 195 | record EMPTY | ||
| 196 | end EMPTY; | ||
| 197 | end InstanceTree; | ||
| 198 | |||
| 199 | constant InstanceTree ENUM_BASE = InstanceTree.BUILTIN_BASE_CLASS("enumeration"); | ||
| 200 | |||
| 201 | |||
| 202 | public function buildModelInstanceJSON | ||
| 203 | "Instantiates the given model and builds the JSON structure describing the | ||
| 204 | model instance. Shared by getModelInstance and getModelInstanceReference." | ||
| 205 | input Absyn.Program absynProgram; | ||
| 206 | input Option<SCode.Program> scodeProgram; | ||
| 207 | input Absyn.Path classPath; | ||
| 208 | input Absyn.Path contextPath; | ||
| 209 | input String modifier; | ||
| 210 | output JSON json; | ||
| 211 | protected | ||
| 212 | InstNode top, cls_node; | ||
| 213 | InstContext.Type context; | ||
| 214 | InstanceTree inst_tree; | ||
| 215 | InstSettings inst_settings; | ||
| 216 | Modifier mod; | ||
| 217 | algorithm | ||
| 218 | 48 | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | |
| 219 | 48 | context := InstContext.set(context, NFInstContext.INSTANCE_API); | |
| 220 | inst_settings := InstSettings.SETTINGS(mergeExtendsSections = false, resizableArrays = false); | ||
| 221 | |||
| 222 | 48 | (_, top) := mkTop(absynProgram, scodeProgram, AbsynUtil.pathString(classPath)); | |
| 223 | 48 | mod := parseModifier(modifier, top); | |
| 224 | 48 | cls_node := Inst.lookupRootClass(classPath, top, context); | |
| 225 | |||
| 226 |
2/2✓ Branch 2 taken 1 time.
✓ Branch 3 taken 47 times.
|
48 | if SCodeUtil.isFunction(InstNode.definition(cls_node)) then |
| 227 | 1 | context := InstContext.unset(context, NFInstContext.CLASS); | |
| 228 | 1 | context := InstContext.set(context, NFInstContext.FUNCTION); | |
| 229 | end if; | ||
| 230 | |||
| 231 |
3/4✓ Branch 1 taken 47 times.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 47 times.
|
48 | if AbsynUtil.pathFirstIdent(contextPath) <> "__NoContext" then |
| 232 | 1 | cls_node := InstNode.setNodeType(InstNodeType.ROOT_CLASS(NFInstNode.NO_SCOPE, SOME(contextPath)), cls_node); | |
| 233 | end if; | ||
| 234 | |||
| 235 | 48 | cls_node := Inst.instantiateRootClass(cls_node, context, mod); | |
| 236 | 48 | execStat("Inst.instantiateRootClass"); | |
| 237 | 48 | inst_tree := buildInstanceTree(cls_node); | |
| 238 | 48 | execStat("NFInstanceAPI.buildInstanceTree"); | |
| 239 | 48 | Inst.instExpressions(cls_node, context = context, settings = inst_settings); | |
| 240 | 48 | Inst.updateImplicitVariability(cls_node, Flags.isSet(Flags.EVAL_PARAM), context); | |
| 241 | 48 | execStat("Inst.instExpressions"); | |
| 242 | |||
| 243 | 48 | Typing.typeClassType(cls_node, NFBinding.EMPTY_BINDING, context, cls_node); | |
| 244 | 48 | Typing.typeComponents(cls_node, context); | |
| 245 | 48 | execStat("Typing.typeComponents"); | |
| 246 | 48 | Typing.typeBindings(cls_node, context); | |
| 247 | 48 | execStat("Typing.typeBinding"); | |
| 248 | |||
| 249 | 48 | json := dumpJSONInstanceTree(inst_tree, cls_node); | |
| 250 | 48 | execStat("NFInstanceAPI.dumpJSONInstanceTree"); | |
| 251 | end buildModelInstanceJSON; | ||
| 252 | |||
| 253 | public function buildModelInstanceAnnotationJSON | ||
| 254 | "Instantiates the given model and builds the JSON structure describing its | ||
| 255 | annotation. Shared by getModelInstanceAnnotation and | ||
| 256 | getModelInstanceAnnotationReference." | ||
| 257 | input Absyn.Program absynProgram; | ||
| 258 | input Option<SCode.Program> scodeProgram; | ||
| 259 | input Absyn.Path classPath; | ||
| 260 | input list<String> filter; | ||
| 261 | output JSON json; | ||
| 262 | protected | ||
| 263 | InstNode top, cls_node; | ||
| 264 | InstContext.Type context; | ||
| 265 | algorithm | ||
| 266 | 3 | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | |
| 267 | 3 | context := InstContext.set(context, NFInstContext.INSTANCE_API); | |
| 268 | |||
| 269 | 3 | (_, top) := mkTop(absynProgram, scodeProgram, AbsynUtil.pathString(classPath)); | |
| 270 | 3 | cls_node := Inst.lookupRootClass(classPath, top, context); | |
| 271 | 3 | cls_node := InstNode.resolveInner(cls_node); | |
| 272 | |||
| 273 | 3 | json := dumpJSONInstanceAnnotation(cls_node, filter); | |
| 274 | end buildModelInstanceAnnotationJSON; | ||
| 275 | |||
| 276 | public function buildModelInstanceIconJSON | ||
| 277 | input Absyn.Program absynProgram; | ||
| 278 | input Option<SCode.Program> scodeProgram; | ||
| 279 | input Absyn.Path classPath; | ||
| 280 | output JSON json; | ||
| 281 | protected | ||
| 282 | InstNode top; | ||
| 283 | algorithm | ||
| 284 | 15 | (_, top) := mkTop(absynProgram, scodeProgram, AbsynUtil.pathString(classPath)); | |
| 285 | 15 | json := iconJSONFromTop(top, classPath); | |
| 286 | end buildModelInstanceIconJSON; | ||
| 287 | |||
| 288 | public function diagramJSONFromTop | ||
| 289 | "What a diagram is drawn from: the class' own Diagram layer with its extends | ||
| 290 | chain, every component it shows — inherited ones included — with its | ||
| 291 | Placement and its type's Icon, and the connect equations with their Line | ||
| 292 | annotations. Nothing is typed, only looked up and expanded, so this costs | ||
| 293 | about what the icon dump costs." | ||
| 294 | input InstNode top; | ||
| 295 | input Absyn.Path classPath; | ||
| 296 | output JSON json; | ||
| 297 | protected | ||
| 298 | InstNode cls_node; | ||
| 299 | InstContext.Type context; | ||
| 300 | JSON components = JSON.emptyArray(), connections = JSON.emptyArray(); | ||
| 301 | algorithm | ||
| 302 | ✗ | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | |
| 303 | ✗ | context := InstContext.set(context, NFInstContext.INSTANCE_API); | |
| 304 | |||
| 305 | ✗ | cls_node := Inst.lookupRootClass(classPath, top, context); | |
| 306 | ✗ | cls_node := InstNode.resolveInner(cls_node); | |
| 307 | |||
| 308 | ✗ | json := dumpJSONInstanceAnnotation(cls_node, {"Diagram"}, dumpDerivedBase = true); | |
| 309 | ✗ | (components, connections) := dumpJSONDiagramParts(cls_node, context, components, connections, 0); | |
| 310 | ✗ | json := JSON.addPair("components", components, json); | |
| 311 | ✗ | json := JSON.addPair("connections", connections, json); | |
| 312 | end diagramJSONFromTop; | ||
| 313 | |||
| 314 | function dumpJSONDiagramParts | ||
| 315 | "A class' components and connections, base classes' first so a derived | ||
| 316 | component is drawn over an inherited one." | ||
| 317 | input InstNode node; | ||
| 318 | input InstContext.Type context; | ||
| 319 | input output JSON components; | ||
| 320 | input output JSON connections; | ||
| 321 | input Integer depth; | ||
| 322 | protected | ||
| 323 | InstNode ty_node; | ||
| 324 | JSON e; | ||
| 325 | SCode.Element def; | ||
| 326 | list<SCode.Equation> eqs; | ||
| 327 | algorithm | ||
| 328 | ✗ | if depth > 16 then | |
| 329 | ✗ | return; | |
| 330 | end if; | ||
| 331 | |||
| 332 | ✗ | for ext in ClassTree.getExtends(Class.classTree(InstNode.getClass(node))) loop | |
| 333 | ✗ | (components, connections) := | |
| 334 | dumpJSONDiagramParts(ext, context, components, connections, depth + 1); | ||
| 335 | end for; | ||
| 336 | |||
| 337 | ✗ | def := InstNode.definition(node); | |
| 338 | |||
| 339 | ✗ | for el in SCodeUtil.getClassElements(def) loop | |
| 340 | () := match el | ||
| 341 | case SCode.Element.COMPONENT() | ||
| 342 | algorithm | ||
| 343 | try | ||
| 344 | ✗ | ty_node := Lookup.lookupClassName(AbsynUtil.typeSpecPath(el.typeSpec), node, context, el.info); | |
| 345 | ✗ | ty_node := Inst.expand(ty_node, context); | |
| 346 | ✗ | e := JSON.addPair("$kind", JSON.STRING("component"), JSON.makeNull()); | |
| 347 | ✗ | e := JSON.addPair("name", JSON.makeString(el.name), e); | |
| 348 | ✗ | e := dumpJSONAnnotationOpt(el.comment.annotation_, node, {"Placement"}, false, e); | |
| 349 | ✗ | e := JSON.addPair("type", diagramComponentIcon(ty_node), e); | |
| 350 | ✗ | components := JSON.addElement(e, components); | |
| 351 | else | ||
| 352 | end try; | ||
| 353 | then (); | ||
| 354 | |||
| 355 | else (); | ||
| 356 | end match; | ||
| 357 | end for; | ||
| 358 | |||
| 359 | eqs := match def | ||
| 360 | case SCode.Element.CLASS(classDef = SCode.ClassDef.PARTS(normalEquationLst = eqs)) then eqs; | ||
| 361 | else {}; | ||
| 362 | end match; | ||
| 363 | |||
| 364 | ✗ | for eq in eqs loop | |
| 365 | () := match eq | ||
| 366 | case SCode.Equation.EQ_CONNECT() | ||
| 367 | algorithm | ||
| 368 | ✗ | e := dumpJSONAnnotationOpt(eq.comment.annotation_, node, {"Line"}, false, JSON.makeNull()); | |
| 369 | ✗ | if not JSON.isNull(e) then | |
| 370 | ✗ | connections := JSON.addElement(e, connections); | |
| 371 | end if; | ||
| 372 | then (); | ||
| 373 | |||
| 374 | else (); | ||
| 375 | end match; | ||
| 376 | end for; | ||
| 377 | end dumpJSONDiagramParts; | ||
| 378 | |||
| 379 | public function builtinSCode | ||
| 380 | "The builtin classes every top scope needs, so a caller assembling a universe | ||
| 381 | from separately translated libraries prepends them once." | ||
| 382 | output SCode.Program program; | ||
| 383 | algorithm | ||
| 384 | ✗ | (_, program) := FBuiltin.getInitialFunctions(); | |
| 385 | end builtinSCode; | ||
| 386 | |||
| 387 | public function builtinAbsyn | ||
| 388 | "The builtin classes as they were parsed, for a caller documenting the | ||
| 389 | OpenModelica package the compiler defines rather than instantiating it." | ||
| 390 | output Absyn.Program program; | ||
| 391 | algorithm | ||
| 392 | ✗ | (program, _) := FBuiltin.getInitialFunctions(); | |
| 393 | end builtinAbsyn; | ||
| 394 | |||
| 395 | public function programSCode | ||
| 396 | "One program's SCode. translateAbsyn2SCode carries nothing between top-level | ||
| 397 | classes, so a caller holding many libraries may translate each separately | ||
| 398 | and concatenate the results." | ||
| 399 | input Absyn.Program absynProgram; | ||
| 400 | output SCode.Program program; | ||
| 401 | algorithm | ||
| 402 | ✗ | program := AbsynToSCode.translateAbsyn2SCode(absynProgram); | |
| 403 | end programSCode; | ||
| 404 | |||
| 405 | public function topFromSCode | ||
| 406 | "A fresh top scope over already translated SCode, bypassing mkTop's reuse | ||
| 407 | cache. Fresh is the point: what a scope expands is released when it is | ||
| 408 | dropped, so a batch caller makes a new one per library instead of sharing one | ||
| 409 | and growing without bound." | ||
| 410 | input SCode.Program program; | ||
| 411 | output InstNode top; | ||
| 412 | protected | ||
| 413 | SCode.Program graphicProgramSCode; | ||
| 414 | algorithm | ||
| 415 | ✗ | graphicProgramSCode := | |
| 416 | AbsynToSCode.translateAbsyn2SCode(annotationProgram(Config.getAnnotationVersion())); | ||
| 417 | ✗ | Inst.resetGlobalFlags(); | |
| 418 | ✗ | top := NFInst.makeTopNode(program, graphicProgramSCode); | |
| 419 | end topFromSCode; | ||
| 420 | |||
| 421 | function diagramComponentIcon | ||
| 422 | "The icon dump of a class one of a diagram's components has. A library draws | ||
| 423 | the same few dozen types across thousands of diagrams, and each dump can cost | ||
| 424 | an instantiation, so they are kept for as long as the top scope they belong | ||
| 425 | to. | ||
| 426 | |||
| 427 | Keying by the class' full path is exact rather than approximate here: the | ||
| 428 | node was reached by looking the type name up and expanding it, without the | ||
| 429 | component's own modifications, so the dump depends on the class alone." | ||
| 430 | input InstNode ty_node; | ||
| 431 | output JSON json; | ||
| 432 | protected | ||
| 433 | Option<UnorderedMap<String, JSON>> cached; | ||
| 434 | UnorderedMap<String, JSON> cache; | ||
| 435 | String key; | ||
| 436 | algorithm | ||
| 437 | ✗ | cached := getGlobalRoot(Global.nfDiagramIconCache); | |
| 438 | cache := match cached | ||
| 439 | case SOME(cache) then cache; | ||
| 440 | else | ||
| 441 | algorithm | ||
| 442 | ✗ | cache := UnorderedMap.new<JSON>(stringHashDjb2, stringEq); | |
| 443 | ✗ | setGlobalRoot(Global.nfDiagramIconCache, SOME(cache)); | |
| 444 | then | ||
| 445 | cache; | ||
| 446 | end match; | ||
| 447 | |||
| 448 | ✗ | key := AbsynUtil.pathString(InstNode.fullPath(ty_node)); | |
| 449 | json := match UnorderedMap.get(key, cache) | ||
| 450 | case SOME(json) then json; | ||
| 451 | else | ||
| 452 | algorithm | ||
| 453 | ✗ | json := dumpJSONInstanceAnnotation(ty_node, {"Icon"}, dumpDerivedBase = true); | |
| 454 | ✗ | UnorderedMap.add(key, json, cache); | |
| 455 | then | ||
| 456 | json; | ||
| 457 | end match; | ||
| 458 | end diagramComponentIcon; | ||
| 459 | |||
| 460 | public function resolveNamesFromTop | ||
| 461 | "What the type references of one class denote, fully qualified, as pairs of | ||
| 462 | the name as written and the name it resolves to: the `extends` clauses and | ||
| 463 | the base of a short class definition in `bases`, the components' types in | ||
| 464 | `componentTypes` keyed by component name. | ||
| 465 | |||
| 466 | This is the frontend's own lookup -- enclosing scopes, then base classes, | ||
| 467 | then imports, with redeclares applied -- rather than a documentation | ||
| 468 | generator's approximation of it. Pairs rather than a bare list so the caller | ||
| 469 | matches on the name instead of trusting two orderings to agree." | ||
| 470 | input InstNode top; | ||
| 471 | input Absyn.Path classPath; | ||
| 472 | output list<tuple<String, String>> bases = {}; | ||
| 473 | output list<tuple<String, String>> componentTypes = {}; | ||
| 474 | protected | ||
| 475 | InstNode cls_node; | ||
| 476 | InstContext.Type context; | ||
| 477 | SCode.Element def; | ||
| 478 | SCode.ClassDef cdef; | ||
| 479 | Absyn.Path reference; | ||
| 480 | algorithm | ||
| 481 | ✗ | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | |
| 482 | ✗ | context := InstContext.set(context, NFInstContext.INSTANCE_API); | |
| 483 | |||
| 484 | try | ||
| 485 | ✗ | cls_node := Inst.lookupRootClass(classPath, top, context); | |
| 486 | ✗ | cls_node := InstNode.resolveInner(cls_node); | |
| 487 | ✗ | cls_node := Inst.expand(cls_node, context); | |
| 488 | ✗ | def := InstNode.definition(cls_node); | |
| 489 | else | ||
| 490 | ✗ | return; | |
| 491 | end try; | ||
| 492 | |||
| 493 | // A short class definition names its base in the class definition itself | ||
| 494 | // rather than in an extends element. | ||
| 495 | ✗ | cdef := SCodeUtil.getClassDef(def); | |
| 496 | () := match cdef | ||
| 497 | case SCode.ClassDef.DERIVED() | ||
| 498 | algorithm | ||
| 499 | ✗ | reference := AbsynUtil.typeSpecPath(cdef.typeSpec); | |
| 500 | ✗ | bases := resolveOne(reference, cls_node, context, SCodeUtil.elementInfo(def)) :: bases; | |
| 501 | then (); | ||
| 502 | else (); | ||
| 503 | end match; | ||
| 504 | |||
| 505 | ✗ | for el in SCodeUtil.getClassElements(def) loop | |
| 506 | () := match el | ||
| 507 | case SCode.Element.EXTENDS() | ||
| 508 | algorithm | ||
| 509 | ✗ | bases := resolveOne(el.baseClassPath, cls_node, context, el.info) :: bases; | |
| 510 | then (); | ||
| 511 | |||
| 512 | case SCode.Element.COMPONENT() | ||
| 513 | algorithm | ||
| 514 | ✗ | reference := AbsynUtil.typeSpecPath(el.typeSpec); | |
| 515 | ✗ | componentTypes := | |
| 516 | (el.name, Util.tuple22(resolveOne(reference, cls_node, context, el.info))) | ||
| 517 | :: componentTypes; | ||
| 518 | then (); | ||
| 519 | |||
| 520 | else (); | ||
| 521 | end match; | ||
| 522 | end for; | ||
| 523 | |||
| 524 | ✗ | bases := listReverseInPlace(bases); | |
| 525 | ✗ | componentTypes := listReverseInPlace(componentTypes); | |
| 526 | end resolveNamesFromTop; | ||
| 527 | |||
| 528 | function resolveOne | ||
| 529 | "The name as written, and what it resolves to -- empty when it does not." | ||
| 530 | input Absyn.Path reference; | ||
| 531 | input InstNode scope; | ||
| 532 | input InstContext.Type context; | ||
| 533 | input SourceInfo info; | ||
| 534 | output tuple<String, String> resolved; | ||
| 535 | protected | ||
| 536 | InstNode node; | ||
| 537 | String qualified; | ||
| 538 | algorithm | ||
| 539 | try | ||
| 540 | ✗ | node := Lookup.lookupClassName(reference, scope, context, info); | |
| 541 | ✗ | node := Inst.expand(node, context); | |
| 542 | ✗ | qualified := AbsynUtil.pathString(InstNode.fullPath(node)); | |
| 543 | else | ||
| 544 | qualified := ""; | ||
| 545 | end try; | ||
| 546 | ✗ | resolved := (AbsynUtil.pathString(reference), qualified); | |
| 547 | end resolveOne; | ||
| 548 | |||
| 549 | public function clearTopScopeCache | ||
| 550 | "Drop everything the last instantiation owns, so a batch caller can release a | ||
| 551 | library when it is done with it. NF nodes refer upwards weakly: what owns | ||
| 552 | them is `nfTopScope` and MutableWeak's set of identity cells, and makeTopNode | ||
| 553 | replaces those only at the next instantiation." | ||
| 554 | algorithm | ||
| 555 | 6 | setGlobalRoot(Global.instNFNodeCacheIndex, {}); | |
| 556 | 6 | setGlobalRoot(Global.nfTopScope, {}); | |
| 557 | 6 | setGlobalRoot(Global.nfDiagramIconCache, NONE()); | |
| 558 | 6 | MutableWeak.clearRoots(); | |
| 559 | end clearTopScopeCache; | ||
| 560 | |||
| 561 | public function iconJSONFromTop | ||
| 562 | "The icon dump for one class of an already built top scope. A caller doing a | ||
| 563 | whole library — the documentation generator — builds `top` once and keeps it, | ||
| 564 | rather than depending on mkTop's referenceEq cache holding across calls, and | ||
| 565 | drops it when the library is done." | ||
| 566 | input InstNode top; | ||
| 567 | input Absyn.Path classPath; | ||
| 568 | output JSON json; | ||
| 569 | protected | ||
| 570 | InstNode cls_node; | ||
| 571 | InstContext.Type context; | ||
| 572 | algorithm | ||
| 573 | 15 | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | |
| 574 | 15 | context := InstContext.set(context, NFInstContext.INSTANCE_API); | |
| 575 | |||
| 576 | 15 | cls_node := Inst.lookupRootClass(classPath, top, context); | |
| 577 | 15 | cls_node := InstNode.resolveInner(cls_node); | |
| 578 | |||
| 579 | 15 | json := dumpJSONInstanceAnnotation(cls_node, {"Icon"}, dumpConnectors = true, dumpDerivedBase = true); | |
| 580 | end iconJSONFromTop; | ||
| 581 | |||
| 582 | 15 | public function storeModelInstanceReference | |
| 583 | "Stores a boxed JSON value and returns a 1-based handle (0 on failure)." | ||
| 584 | input JSON json; | ||
| 585 | output Integer handle; | ||
| 586 | external "C" handle = ModelInstanceReference_store(json) annotation(Library = "omcruntime"); | ||
| 587 | end storeModelInstanceReference; | ||
| 588 | |||
| 589 | 15 | public function releaseModelInstanceReferenceImpl | |
| 590 | input Integer handle; | ||
| 591 | output Boolean success; | ||
| 592 | external "C" success = ModelInstanceReference_release(handle) annotation(Library = "omcruntime"); | ||
| 593 | end releaseModelInstanceReferenceImpl; | ||
| 594 | |||
| 595 | function parseModifier | ||
| 596 | input String modifierValue; | ||
| 597 | input InstNode scope; | ||
| 598 | output Modifier outMod; | ||
| 599 | protected | ||
| 600 | Absyn.Modification amod; | ||
| 601 | SCode.Mod smod; | ||
| 602 | algorithm | ||
| 603 | try | ||
| 604 | // stringMod parses a single modifier ("x(start = 1) = 2"), but here we want | ||
| 605 | // to parse just a class modifier ("(x = 1, y = 2)"). So we add a dummy name | ||
| 606 | // to the string and then extract the modifier from the ElementArg. | ||
| 607 |
4/6✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 47 times.
✓ Branch 7 taken 1 time.
|
48 | Absyn.ElementArg.MODIFICATION(modification = SOME(amod)) := |
| 608 | Parser.stringMod("dummy" + modifierValue); | ||
| 609 | |||
| 610 | // Then translate the Absyn mod to a Modifier, using the given scope (it | ||
| 611 | // doesn't matter much which scope it is, it just needs some scope or the | ||
| 612 | // instantiation will fail later). | ||
| 613 | 1 | smod := AbsynToSCode.translateMod(SOME(amod), | |
| 614 | SCode.Final.NOT_FINAL(), SCode.Each.NOT_EACH(), NONE(), Absyn.dummyInfo); | ||
| 615 | 1 | outMod := Modifier.create(smod, "", NFModifier.ModifierScope.COMPONENT(""), scope, 0); | |
| 616 | else | ||
| 617 | outMod := Modifier.NOMOD(); | ||
| 618 | end try; | ||
| 619 | end parseModifier; | ||
| 620 | |||
| 621 | function buildInstanceTree | ||
| 622 | input InstNode node; | ||
| 623 | input Boolean isDerived = false; | ||
| 624 | output InstanceTree tree; | ||
| 625 | protected | ||
| 626 | InstNode cls_node; | ||
| 627 | Class cls; | ||
| 628 | ClassTree cls_tree; | ||
| 629 | list<InstanceTree> elems; | ||
| 630 | algorithm | ||
| 631 | 168 | cls_node := InstNode.resolveInner(node); | |
| 632 | 168 | cls := InstNode.getClass(cls_node); | |
| 633 | |||
| 634 |
5/6✓ Branch 0 taken 149 times.
✓ Branch 1 taken 19 times.
✓ Branch 3 taken 61 times.
✓ Branch 4 taken 88 times.
✓ Branch 6 taken 61 times.
✗ Branch 7 not taken.
|
168 | if not isDerived and Class.isOnlyBuiltin(cls) and not Class.isEnumeration(cls) then |
| 635 | tree := InstanceTree.EMPTY(); | ||
| 636 | 61 | return; | |
| 637 | end if; | ||
| 638 | |||
| 639 | 107 | cls_tree := Class.classTree(cls); | |
| 640 | |||
| 641 | tree := match (cls, cls_tree) | ||
| 642 | case (Class.EXPANDED_DERIVED(), _) | ||
| 643 | algorithm | ||
| 644 | 10 | elems := {buildInstanceTree(cls.baseClass, isDerived = true)}; | |
| 645 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
|
19 | then |
| 646 | InstanceTree.CLASS(node, elems, isDerived); | ||
| 647 | |||
| 648 | case (_, ClassTree.INSTANTIATED_TREE()) | ||
| 649 | algorithm | ||
| 650 | 92 | elems := buildInstanceTreeElements(InstNode.definition(cls_node), cls_tree); | |
| 651 | |||
| 652 |
2/2✓ Branch 1 taken 46 times.
✓ Branch 2 taken 46 times.
|
92 | if InstNode.isRootClass(node) then |
| 653 | 46 | elems := buildInstanceTreeGeneratedInners(cls_tree, elems); | |
| 654 | end if; | ||
| 655 |
2/2✓ Branch 0 taken 79 times.
✓ Branch 1 taken 13 times.
|
171 | then |
| 656 | InstanceTree.CLASS(node, elems, isDerived); | ||
| 657 | |||
| 658 | case (_, ClassTree.FLAT_TREE()) | ||
| 659 |
3/4✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
|
9 | then InstanceTree.CLASS(node, if InstNode.isEnumerationType(cls_node) then {ENUM_BASE} else {}, isDerived); |
| 660 | |||
| 661 | else | ||
| 662 | algorithm | ||
| 663 | ✗ | Error.terminate(getInstanceName() + " got unknown class tree", sourceInfo()); | |
| 664 | ✗ | then | |
| 665 | fail(); | ||
| 666 | end match; | ||
| 667 | end buildInstanceTree; | ||
| 668 | |||
| 669 | function buildInstanceTreeElements | ||
| 670 | input SCode.Element classDefinition; | ||
| 671 | input ClassTree classTree; | ||
| 672 | output list<InstanceTree> elements = {}; | ||
| 673 | protected | ||
| 674 | list<SCode.Element> scode_elems; | ||
| 675 | array<Mutable<InstNode>> clss, comps; | ||
| 676 | array<InstNode> exts; | ||
| 677 | Integer cls_index = 1, comp_index = 1, ext_index = 1; | ||
| 678 | InstanceTree tree; | ||
| 679 | list<Integer> local_comps; | ||
| 680 | InstNode node; | ||
| 681 | algorithm | ||
| 682 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | ClassTree.INSTANTIATED_TREE(classes = clss, components = comps, exts = exts, |
| 683 | localComponents = local_comps) := classTree; | ||
| 684 | 92 | scode_elems := SCodeUtil.getClassElements(classDefinition); | |
| 685 | |||
| 686 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 21 times.
|
92 | if not listEmpty(local_comps) then |
| 687 | 71 | comp_index :: local_comps := local_comps; | |
| 688 | end if; | ||
| 689 | |||
| 690 |
2/2✓ Branch 0 taken 135 times.
✓ Branch 1 taken 92 times.
|
227 | for e in scode_elems loop |
| 691 | elements := match e | ||
| 692 | case SCode.Element.EXTENDS() | ||
| 693 | algorithm | ||
| 694 | 9 | tree := buildInstanceTree(exts[ext_index], isDerived = true); | |
| 695 | 9 | ext_index := ext_index + 1; | |
| 696 | then | ||
| 697 | tree :: elements; | ||
| 698 | |||
| 699 | case SCode.Element.CLASS() | ||
| 700 | guard SCodeUtil.isElementReplaceable(e) | ||
| 701 | algorithm | ||
| 702 |
2/4✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 11 times.
|
11 | while InstNode.name(Mutable.access(clss[cls_index])) <> e.name loop |
| 703 | ✗ | cls_index := cls_index + 1; | |
| 704 | end while; | ||
| 705 | |||
| 706 | 11 | tree := InstanceTree.CLASS(Mutable.access(clss[cls_index]), {}, false); | |
| 707 | 11 | cls_index := cls_index + 1; | |
| 708 | then | ||
| 709 | tree :: elements; | ||
| 710 | |||
| 711 | case SCode.Element.COMPONENT() | ||
| 712 | algorithm | ||
| 713 | 1 | while true loop | |
| 714 | 108 | node := Mutable.access(comps[comp_index]); | |
| 715 | |||
| 716 |
4/6✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 107 times.
|
108 | if InstNode.name(node) == e.name and not InstNode.isGeneratedInner(node) then |
| 717 | break; | ||
| 718 | end if; | ||
| 719 | |||
| 720 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | comp_index :: local_comps := local_comps; |
| 721 | end while; | ||
| 722 | //while InstNode.name(Mutable.access(comps[comp_index])) <> e.name loop | ||
| 723 | // comp_index :: local_comps := local_comps; | ||
| 724 | //end while; | ||
| 725 | |||
| 726 | 107 | tree := buildInstanceTreeComponent(node); | |
| 727 | elements := tree :: elements; | ||
| 728 | |||
| 729 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 71 times.
|
107 | if not listEmpty(local_comps) then |
| 730 | 36 | comp_index :: local_comps := local_comps; | |
| 731 | end if; | ||
| 732 | then | ||
| 733 | elements; | ||
| 734 | |||
| 735 | else elements; | ||
| 736 | end match; | ||
| 737 | end for; | ||
| 738 | |||
| 739 | 92 | elements := listReverseInPlace(elements); | |
| 740 | end buildInstanceTreeElements; | ||
| 741 | |||
| 742 | function buildInstanceTreeGeneratedInners | ||
| 743 | input ClassTree classTree; | ||
| 744 | input list<InstanceTree> elements; | ||
| 745 | output list<InstanceTree> outElements; | ||
| 746 | protected | ||
| 747 | array<Mutable<InstNode>> comps; | ||
| 748 | list<InstanceTree> elems = {}; | ||
| 749 | algorithm | ||
| 750 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
|
46 | ClassTree.INSTANTIATED_TREE(components = comps) := classTree; |
| 751 | |||
| 752 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 5 times.
|
47 | for i in arrayLength(comps):-1:1 loop |
| 753 |
2/2✓ Branch 3 taken 1 time.
✓ Branch 4 taken 41 times.
|
42 | if InstNode.isGeneratedInner(Mutable.access(comps[i])) then |
| 754 | 1 | elems := buildInstanceTreeComponent(Mutable.access(comps[i])) :: elems; | |
| 755 | else | ||
| 756 | break; | ||
| 757 | end if; | ||
| 758 | end for; | ||
| 759 | |||
| 760 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 45 times.
|
46 | if listEmpty(elems) then |
| 761 | outElements := elements; | ||
| 762 | else | ||
| 763 | 1 | outElements := listAppend(elements, elems); | |
| 764 | end if; | ||
| 765 | end buildInstanceTreeGeneratedInners; | ||
| 766 | |||
| 767 | function buildInstanceTreeComponent | ||
| 768 | input InstNode node; | ||
| 769 | output InstanceTree tree; | ||
| 770 | protected | ||
| 771 | InstNode inner_node, cls_node; | ||
| 772 | InstanceTree cls; | ||
| 773 | Binding binding; | ||
| 774 | Option<Binding> opt_binding; | ||
| 775 | algorithm | ||
| 776 | 108 | inner_node := InstNode.resolveOuter(node); | |
| 777 | 108 | cls_node := InstNode.classScope(inner_node); | |
| 778 | |||
| 779 |
2/2✓ Branch 1 taken 101 times.
✓ Branch 2 taken 7 times.
|
108 | if InstNode.isEmpty(cls_node) then |
| 780 | cls := InstanceTree.EMPTY(); | ||
| 781 | else | ||
| 782 | 101 | cls := buildInstanceTree(cls_node); | |
| 783 | end if; | ||
| 784 | |||
| 785 |
1/2✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
|
108 | if InstNode.isComponent(inner_node) then |
| 786 | 108 | binding := Component.getBinding(InstNode.component(inner_node)); | |
| 787 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 72 times.
|
108 | opt_binding := if Binding.isBound(binding) then SOME(binding) else NONE(); |
| 788 | else | ||
| 789 | opt_binding := NONE(); | ||
| 790 | end if; | ||
| 791 | |||
| 792 | 108 | tree := InstanceTree.COMPONENT(node, opt_binding, cls); | |
| 793 | end buildInstanceTreeComponent; | ||
| 794 | |||
| 795 | function dumpJSONInstanceTree | ||
| 796 | input InstanceTree tree; | ||
| 797 | input InstNode scope; | ||
| 798 | input Boolean root = true; | ||
| 799 | input Boolean isDeleted = false; | ||
| 800 | input Boolean isExtends = false; | ||
| 801 | output JSON json = JSON.makeNull(); | ||
| 802 | protected | ||
| 803 | InstNode node; | ||
| 804 | list<InstanceTree> elems; | ||
| 805 | Sections sections; | ||
| 806 | Option<SCode.Comment> cmt; | ||
| 807 | SCode.Element def; | ||
| 808 | algorithm | ||
| 809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | InstanceTree.CLASS(node = node, elements = elems) := tree; |
| 810 | 102 | node := InstNode.resolveOuter(node); | |
| 811 | 102 | def := InstNode.definition(node); | |
| 812 | 102 | cmt := SCodeUtil.getElementComment(def); | |
| 813 | |||
| 814 | 102 | json := JSON.addPair("name", dumpJSONNodePath(node), json); | |
| 815 | |||
| 816 | 102 | json := JSON.addPairNotNull("dims", dumpJSONClassDims(node, def), json); | |
| 817 | 102 | json := JSON.addPair("restriction", | |
| 818 | JSON.makeString(SCodeDump.restrictionStringPP(SCodeUtil.getClassRestriction(def))), json); | ||
| 819 | |||
| 820 | 102 | json := JSON.addPairNotNull("prefixes", dumpJSONClassPrefixes(def, InstNode.parent(node)), json); | |
| 821 | |||
| 822 | 102 | json := dumpJSONCommentOpt(cmt, scope, json); | |
| 823 | |||
| 824 | 102 | json := JSON.addPairNotNull("elements", dumpJSONElements(elems, node, isDeleted), json); | |
| 825 | |||
| 826 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 2 times.
|
102 | if not isDeleted then |
| 827 | 100 | json := dumpJSONImports(node, json); | |
| 828 | 100 | sections := Class.getSections(InstNode.getClass(node)); | |
| 829 | 100 | json := dumpJSONEquations(sections, node, json); | |
| 830 | end if; | ||
| 831 | |||
| 832 | 102 | json := JSON.addPair("source", JSON.dumpJSONSourceInfo(InstNode.info(node)), json); | |
| 833 | end dumpJSONInstanceTree; | ||
| 834 | |||
| 835 | function dumpJSONInstanceAnnotation | ||
| 836 | input InstNode node; | ||
| 837 | input list<String> filter; | ||
| 838 | input Boolean dumpConnectors = false "the class' own connector components"; | ||
| 839 | input Boolean dumpDerivedBase = false "a short class definition's base class"; | ||
| 840 | output JSON json = JSON.makeNull(); | ||
| 841 | protected | ||
| 842 | Option<SCode.Comment> cmt; | ||
| 843 | SCode.Annotation ann; | ||
| 844 | JSON j; | ||
| 845 | InstNode scope = node; | ||
| 846 | InstContext.Type context; | ||
| 847 | Boolean annotation_is_literal = true; | ||
| 848 | Boolean any_element = false; | ||
| 849 | SCode.Element def; | ||
| 850 | Class cls; | ||
| 851 | algorithm | ||
| 852 | 48 | Inst.expand(node, NFInstContext.RELAXED); | |
| 853 | 48 | def := InstNode.definition(node); | |
| 854 | 48 | json := JSON.addPair("name", dumpJSONNodePath(node), json); | |
| 855 | |||
| 856 | 48 | json := JSON.addPair("restriction", | |
| 857 | JSON.makeString(Restriction.toString(InstNode.restriction(node))), json); | ||
| 858 | |||
| 859 | 48 | json := JSON.addPairNotNull("prefixes", dumpJSONClassPrefixes(def, InstNode.parent(node)), json); | |
| 860 | |||
| 861 | 48 | cls := InstNode.getClass(node); | |
| 862 | 48 | j := JSON.emptyArray(); | |
| 863 | |||
| 864 | // Class.classTree looks through a derived class, so its extends array is the | ||
| 865 | // base's: listing both would count the base's chain twice. | ||
| 866 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 7 times.
|
48 | if dumpDerivedBase then |
| 867 | () := match cls | ||
| 868 | case Class.EXPANDED_DERIVED() | ||
| 869 | algorithm | ||
| 870 | ✗ | j := JSON.addElement(dumpJSONInstanceAnnotationExtends(cls.baseClass, filter, true), j); | |
| 871 | ✗ | any_element := true; | |
| 872 | then (); | ||
| 873 | |||
| 874 | case Class.TYPED_DERIVED() | ||
| 875 | algorithm | ||
| 876 | ✗ | j := JSON.addElement(dumpJSONInstanceAnnotationExtends(cls.baseClass, filter, true), j); | |
| 877 | ✗ | any_element := true; | |
| 878 | then (); | ||
| 879 | |||
| 880 | else (); | ||
| 881 | end match; | ||
| 882 | end if; | ||
| 883 | |||
| 884 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | if not any_element then |
| 885 |
2/2✓ Branch 3 taken 9 times.
✓ Branch 4 taken 48 times.
|
105 | for ext in ClassTree.getExtends(Class.classTree(cls)) loop |
| 886 | 9 | j := JSON.addElement(dumpJSONInstanceAnnotationExtends(ext, filter, dumpDerivedBase), j); | |
| 887 | 9 | any_element := true; | |
| 888 | end for; | ||
| 889 | end if; | ||
| 890 | |||
| 891 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 33 times.
|
48 | if dumpConnectors then |
| 892 | 15 | (j, any_element) := dumpJSONInstanceAnnotationConnectors(node, j, any_element); | |
| 893 | end if; | ||
| 894 | |||
| 895 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 39 times.
|
48 | if any_element then |
| 896 | 9 | json := JSON.addPair("elements", j, json); | |
| 897 | end if; | ||
| 898 | |||
| 899 | 48 | cmt := SCodeUtil.getElementComment(InstNode.definition(node)); | |
| 900 | |||
| 901 | cmt := match cmt | ||
| 902 | case SOME(SCode.Comment.COMMENT(annotation_ = SOME(ann as SCode.Annotation.ANNOTATION()))) | ||
| 903 | algorithm | ||
| 904 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 4 times.
|
34 | if not listEmpty(filter) then |
| 905 | 60 | ann.modification := SCodeUtil.filterSubMods(ann.modification, | |
| 906 | function SCodeUtil.filterGivenSubModNames(namesToKeep = filter)); | ||
| 907 | end if; | ||
| 908 | |||
| 909 | 34 | annotation_is_literal := SCodeUtil.onlyLiteralsInMod(ann.modification); | |
| 910 |
2/2✓ Branch 1 taken 30 times.
✓ Branch 2 taken 4 times.
|
64 | then |
| 911 | if SCodeUtil.isEmptyMod(ann.modification) then NONE() else SOME(SCode.Comment.COMMENT(SOME(ann), NONE())); | ||
| 912 | |||
| 913 | else NONE(); | ||
| 914 | end match; | ||
| 915 | |||
| 916 | // Instantiate the scope if the annotation contains component references that | ||
| 917 | // we need to be able to look up. | ||
| 918 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 33 times.
|
34 | if not annotation_is_literal then |
| 919 | 1 | ErrorExt.setCheckpoint(getInstanceName()); | |
| 920 | try | ||
| 921 | 1 | context := InstContext.set(NFInstContext.CLASS, NFInstContext.RELAXED); | |
| 922 | 1 | scope := InstNode.makeRootClass(scope); | |
| 923 | 1 | scope := Inst.instantiate(scope, context = context, instPartial = true); | |
| 924 | 1 | Inst.insertGeneratedInners(scope, InstNode.topScope(scope), context); | |
| 925 | 1 | Inst.instExpressions(scope, context = context, settings = NFInst.DEFAULT_SETTINGS); | |
| 926 | else | ||
| 927 | end try; | ||
| 928 | 1 | ErrorExt.rollBack(getInstanceName()); | |
| 929 | end if; | ||
| 930 | |||
| 931 | 48 | json := dumpJSONCommentOpt(cmt, scope, json, failOnError = true); | |
| 932 | end dumpJSONInstanceAnnotation; | ||
| 933 | |||
| 934 | function dumpJSONInstanceAnnotationConnectors | ||
| 935 | "One element per locally declared connector component: name, Placement and | ||
| 936 | the type's icon annotation. A model instance nests the inherited ones under | ||
| 937 | the extends element, so only the class' own belong here." | ||
| 938 | input InstNode node; | ||
| 939 | input output JSON json; | ||
| 940 | input output Boolean any; | ||
| 941 | protected | ||
| 942 | InstContext.Type context = InstContext.set(NFInstContext.RELAXED, NFInstContext.CLASS); | ||
| 943 | InstNode ty_node; | ||
| 944 | JSON e; | ||
| 945 | algorithm | ||
| 946 |
2/2✓ Branch 2 taken 109 times.
✓ Branch 3 taken 15 times.
|
124 | for el in SCodeUtil.getClassElements(InstNode.definition(node)) loop |
| 947 | () := match el | ||
| 948 | case SCode.Element.COMPONENT() | ||
| 949 | algorithm | ||
| 950 | try | ||
| 951 | 104 | ty_node := Lookup.lookupClassName(AbsynUtil.typeSpecPath(el.typeSpec), node, context, el.info); | |
| 952 | |||
| 953 |
2/2✓ Branch 3 taken 21 times.
✓ Branch 4 taken 83 times.
|
104 | if SCodeUtil.isConnector(SCodeUtil.getClassRestriction(InstNode.definition(ty_node))) then |
| 954 | 21 | ty_node := Inst.expand(ty_node, context); | |
| 955 | 21 | e := JSON.addPair("$kind", JSON.STRING("component"), JSON.makeNull()); | |
| 956 | 21 | e := JSON.addPair("name", JSON.makeString(el.name), e); | |
| 957 | 21 | e := dumpJSONAnnotationOpt(el.comment.annotation_, node, {"Placement"}, false, e); | |
| 958 | 21 | e := JSON.addPair("type", | |
| 959 | dumpJSONInstanceAnnotation(ty_node, {"Icon"}, dumpDerivedBase = true), e); | ||
| 960 | 21 | json := JSON.addElement(e, json); | |
| 961 | any := true; | ||
| 962 | end if; | ||
| 963 | else | ||
| 964 | end try; | ||
| 965 | then (); | ||
| 966 | |||
| 967 | else (); | ||
| 968 | end match; | ||
| 969 | end for; | ||
| 970 | end dumpJSONInstanceAnnotationConnectors; | ||
| 971 | |||
| 972 | function dumpJSONInstanceAnnotationExtends | ||
| 973 | input InstNode ext; | ||
| 974 | input list<String> filter; | ||
| 975 | input Boolean dumpDerivedBase = false; | ||
| 976 | output JSON json = JSON.makeNull(); | ||
| 977 | algorithm | ||
| 978 | 9 | json := JSON.addPair("$kind", JSON.STRING("extends"), json); | |
| 979 | 9 | json := JSON.addPair("baseClass", | |
| 980 | dumpJSONInstanceAnnotation(ext, filter, dumpDerivedBase = dumpDerivedBase), json); | ||
| 981 | end dumpJSONInstanceAnnotationExtends; | ||
| 982 | |||
| 983 | function dumpJSONNodePath | ||
| 984 | input InstNode node; | ||
| 985 | input Boolean ignoreBaseClass = false; | ||
| 986 | output JSON json = dumpJSONPath(InstNode.enclosingScopePath(node, ignoreBaseClass = ignoreBaseClass)); | ||
| 987 | end dumpJSONNodePath; | ||
| 988 | |||
| 989 | function dumpJSONNodeEnclosingPath | ||
| 990 | input InstNode node; | ||
| 991 | output JSON json = dumpJSONPath(InstNode.enclosingScopePath(node, ignoreRedeclare = true)); | ||
| 992 | end dumpJSONNodeEnclosingPath; | ||
| 993 | |||
| 994 | function dumpJSONPath | ||
| 995 | input Absyn.Path path; | ||
| 996 | output JSON json = JSON.makeString(AbsynUtil.pathString(path)); | ||
| 997 | end dumpJSONPath; | ||
| 998 | |||
| 999 | function dumpJSONElements | ||
| 1000 | input list<InstanceTree> elements; | ||
| 1001 | input InstNode scope; | ||
| 1002 | input Boolean isDeleted; | ||
| 1003 | output JSON json = JSON.makeNull(); | ||
| 1004 | protected | ||
| 1005 | JSON j; | ||
| 1006 | algorithm | ||
| 1007 |
2/2✓ Branch 0 taken 101 times.
✓ Branch 1 taken 2 times.
|
103 | if isDeleted then |
| 1008 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | for e in elements loop |
| 1009 | j := match e | ||
| 1010 | 1 | case InstanceTree.CLASS(isExtends = true) then dumpJSONExtends(e, isDeleted); | |
| 1011 | 2 | else JSON.makeNull(); | |
| 1012 | end match; | ||
| 1013 | |||
| 1014 | 3 | json := JSON.addElementNotNull(j, json); | |
| 1015 | end for; | ||
| 1016 | else | ||
| 1017 |
2/2✓ Branch 0 taken 136 times.
✓ Branch 1 taken 101 times.
|
237 | for e in elements loop |
| 1018 | j := match e | ||
| 1019 | 18 | case InstanceTree.CLASS(isExtends = true) then dumpJSONExtends(e, isDeleted); | |
| 1020 | 11 | case InstanceTree.CLASS() then dumpJSONReplaceableClass(e.node, scope); | |
| 1021 | 106 | case InstanceTree.COMPONENT() then dumpJSONComponent(e.node, e.binding, e.cls); | |
| 1022 | 1 | case InstanceTree.BUILTIN_BASE_CLASS() then dumpJSONBuiltinBaseClass(e.name); | |
| 1023 | ✗ | else JSON.makeNull(); | |
| 1024 | end match; | ||
| 1025 | |||
| 1026 | 136 | json := JSON.addElementNotNull(j, json); | |
| 1027 | end for; | ||
| 1028 | end if; | ||
| 1029 | end dumpJSONElements; | ||
| 1030 | |||
| 1031 | function dumpJSONExtends | ||
| 1032 | input InstanceTree ext; | ||
| 1033 | input Boolean isDeleted; | ||
| 1034 | output JSON json = JSON.makeNull(); | ||
| 1035 | protected | ||
| 1036 | InstNode node; | ||
| 1037 | Class cls; | ||
| 1038 | SCode.Element cls_def, ext_def; | ||
| 1039 | algorithm | ||
| 1040 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | InstanceTree.CLASS(node = node) := ext; |
| 1041 | 19 | cls_def := InstNode.definition(node); | |
| 1042 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
|
19 | SOME(ext_def) := InstNode.extendsDefinition(node); |
| 1043 | |||
| 1044 | 19 | json := JSON.addPair("$kind", JSON.STRING("extends"), json); | |
| 1045 | 19 | json := dumpJSONSCodeMod(getExtendsModifier(ext_def, node), node, json); | |
| 1046 | 19 | json := dumpJSONCommentOpt(SCodeUtil.getElementComment(ext_def), node, json); | |
| 1047 | |||
| 1048 | 19 | cls := InstNode.getClass(node); | |
| 1049 |
4/4✓ Branch 1 taken 5 times.
✓ Branch 2 taken 14 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 time.
|
19 | if Class.isOnlyBuiltin(cls) and not Class.isEnumeration(cls) then |
| 1050 | 4 | json := JSON.addPair("baseClass", JSON.makeString(InstNode.name(node)), json); | |
| 1051 | else | ||
| 1052 | 15 | json := JSON.addPair("baseClass", dumpJSONInstanceTree(ext, node, root = false, isDeleted = isDeleted, isExtends = true), json); | |
| 1053 | end if; | ||
| 1054 | end dumpJSONExtends; | ||
| 1055 | |||
| 1056 | function dumpJSONBuiltinBaseClass | ||
| 1057 | input String name; | ||
| 1058 | output JSON json = JSON.makeNull(); | ||
| 1059 | algorithm | ||
| 1060 | 1 | json := JSON.addPair("$kind", JSON.STRING("extends"), json); | |
| 1061 | 1 | json := JSON.addPair("baseClass", JSON.makeString(name), json); | |
| 1062 | end dumpJSONBuiltinBaseClass; | ||
| 1063 | |||
| 1064 | function getExtendsModifier | ||
| 1065 | input SCode.Element definition; | ||
| 1066 | input InstNode node; | ||
| 1067 | output SCode.Mod mod; | ||
| 1068 | algorithm | ||
| 1069 | mod := match definition | ||
| 1070 | 9 | case SCode.EXTENDS() then definition.modifications; | |
| 1071 | 10 | case SCode.CLASS() then SCodeUtil.elementMod(InstNode.definition(InstNode.getDerivedNode(node, recursive = false))); | |
| 1072 | else SCode.NOMOD(); | ||
| 1073 | end match; | ||
| 1074 | end getExtendsModifier; | ||
| 1075 | |||
| 1076 | function dumpJSONReplaceableClass | ||
| 1077 | input InstNode cls; | ||
| 1078 | input InstNode scope; | ||
| 1079 | output JSON json = JSON.makeNull(); | ||
| 1080 | protected | ||
| 1081 | SCode.Element elem; | ||
| 1082 | InstNode node; | ||
| 1083 | algorithm | ||
| 1084 | 11 | node := InstNode.getRedeclaredNode(cls); | |
| 1085 | 11 | elem := InstNode.definition(node); | |
| 1086 | 11 | json := dumpJSONSCodeClass(elem, scope, node, true, json); | |
| 1087 | 11 | json := JSON.addPair("source", JSON.dumpJSONSourceInfo(InstNode.info(node)), json); | |
| 1088 | end dumpJSONReplaceableClass; | ||
| 1089 | |||
| 1090 | function dumpJSONComponent | ||
| 1091 | input InstNode component; | ||
| 1092 | input Option<Binding> originalBinding; | ||
| 1093 | input InstanceTree cls; | ||
| 1094 | output JSON json = JSON.makeNull(); | ||
| 1095 | protected | ||
| 1096 | InstNode node, scope, ty_node; | ||
| 1097 | Component comp; | ||
| 1098 | SCode.Element elem; | ||
| 1099 | Boolean is_constant; | ||
| 1100 | Absyn.Path path; | ||
| 1101 | algorithm | ||
| 1102 | 106 | node := InstNode.resolveOuter(component); | |
| 1103 | 106 | comp := InstNode.component(node); | |
| 1104 | 106 | elem := InstNode.definition(node); | |
| 1105 | 106 | scope := InstNode.parent(node); | |
| 1106 | |||
| 1107 | 106 | json := JSON.addPair("$kind", JSON.STRING("component"), json); | |
| 1108 | 106 | json := JSON.addPair("name", JSON.makeString(InstNode.name(node)), json); | |
| 1109 | |||
| 1110 | () := match (comp, elem) | ||
| 1111 | case (Component.COMPONENT(), SCode.Element.COMPONENT()) | ||
| 1112 | guard Component.isDeleted(comp) | ||
| 1113 | algorithm | ||
| 1114 | 1 | json := JSON.addPair("type", dumpJSONComponentType(cls, node, comp.ty, isDeleted = true), json); | |
| 1115 | 1 | json := dumpJSONSCodeMod(elem.modifications, scope, json); | |
| 1116 | 1 | json := JSON.addPair("condition", JSON.makeBoolean(false), json); | |
| 1117 | 1 | json := JSON.addPairNotNull("prefixes", dumpJSONAttributes(elem.attributes, elem.prefixes, scope), json); | |
| 1118 | 1 | json := dumpJSONComment(elem.comment, scope, json); | |
| 1119 | then | ||
| 1120 | (); | ||
| 1121 | |||
| 1122 | case (Component.INVALID_COMPONENT(), SCode.Element.COMPONENT()) | ||
| 1123 | algorithm | ||
| 1124 | ✗ | json := JSON.addPair("type", dumpJSONComponentType(cls, node, Component.getType(comp)), json); | |
| 1125 | ✗ | json := dumpJSONSCodeMod(elem.modifications, scope, json); | |
| 1126 | ✗ | json := JSON.addPairNotNull("prefixes", dumpJSONAttributes(elem.attributes, elem.prefixes, scope), json); | |
| 1127 | ✗ | json := dumpJSONComment(elem.comment, scope, json); | |
| 1128 | ✗ | json := JSON.addPair("$error", JSON.makeString(comp.errors), json); | |
| 1129 | then | ||
| 1130 | (); | ||
| 1131 | |||
| 1132 | case (Component.COMPONENT(), SCode.Element.COMPONENT()) | ||
| 1133 | algorithm | ||
| 1134 | 101 | json := JSON.addPair("type", dumpJSONComponentType(cls, node, comp.ty), json); | |
| 1135 | |||
| 1136 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 95 times.
|
101 | if Type.isArray(comp.ty) then |
| 1137 | 6 | json := JSON.addPair("dims", | |
| 1138 | dumpJSONDims(elem.attributes.arrayDims, Type.arrayDims(comp.ty)), json); | ||
| 1139 | end if; | ||
| 1140 | |||
| 1141 | 101 | json := dumpJSONSCodeMod(elem.modifications, scope, json); | |
| 1142 | |||
| 1143 |
3/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 77 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
|
101 | is_constant := comp.attributes.variability <= Variability.PARAMETER and |
| 1144 | Binding.purity(comp.binding) == Purity.PURE; | ||
| 1145 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 65 times.
|
101 | if Binding.isExplicitlyBound(comp.binding) then |
| 1146 | 36 | json := JSON.addPair("value", dumpJSONBinding(comp.binding, originalBinding, evaluate = is_constant), json); | |
| 1147 | end if; | ||
| 1148 | |||
| 1149 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 100 times.
|
101 | if Binding.isBound(comp.condition) then |
| 1150 | 1 | json := JSON.addPair("condition", dumpJSONBinding(comp.condition), json); | |
| 1151 | end if; | ||
| 1152 | |||
| 1153 | 101 | json := JSON.addPairNotNull("prefixes", dumpJSONAttributes(elem.attributes, elem.prefixes, scope), json); | |
| 1154 | 101 | json := dumpJSONComment(comp.comment, scope, json); | |
| 1155 | |||
| 1156 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 100 times.
|
101 | if InstNode.isGeneratedInner(node) then |
| 1157 | 1 | json := JSON.addPair("generated", JSON.makeBoolean(true), json); | |
| 1158 | end if; | ||
| 1159 | then | ||
| 1160 | (); | ||
| 1161 | |||
| 1162 | case (Component.COMPONENT_DEF(), SCode.Element.COMPONENT()) | ||
| 1163 | guard AbsynUtil.isOnlyOuter(elem.prefixes.innerOuter) | ||
| 1164 | algorithm | ||
| 1165 | 4 | path := AbsynUtil.typeSpecPath(elem.typeSpec); | |
| 1166 | |||
| 1167 | try | ||
| 1168 | 4 | ty_node := Lookup.lookupName(path, scope, InstContext.set(NFInstContext.RELAXED, NFInstContext.FAST_LOOKUP), | |
| 1169 | checkAccessViolations = false); | ||
| 1170 | 4 | json := JSON.addPair("type", dumpJSONSCodeClass(InstNode.definition(ty_node), ty_node, InstNode.resolveInner(component), isRedeclare = false), json); | |
| 1171 | else | ||
| 1172 | ✗ | json := JSON.addPair("type", dumpJSONPath(path), json); | |
| 1173 | end try; | ||
| 1174 | |||
| 1175 | 4 | json := JSON.addPairNotNull("prefixes", dumpJSONAttributes(elem.attributes, elem.prefixes, scope), json); | |
| 1176 | 4 | json := dumpJSONComment(elem.comment, scope, json); | |
| 1177 | //json := JSON.addPair("inner", dumpJSONPath(InstNode.scopePath(InstNode.resolveInner(component))), json); | ||
| 1178 | then | ||
| 1179 | (); | ||
| 1180 | |||
| 1181 | else | ||
| 1182 | algorithm | ||
| 1183 | ✗ | Error.terminate(getInstanceName() + " got unknown component " + | |
| 1184 | InstNode.name(node), sourceInfo()); | ||
| 1185 | ✗ | then | |
| 1186 | fail(); | ||
| 1187 | end match; | ||
| 1188 | end dumpJSONComponent; | ||
| 1189 | |||
| 1190 | function dumpJSONComponentType | ||
| 1191 | input InstanceTree cls; | ||
| 1192 | input InstNode node; | ||
| 1193 | input Type ty; | ||
| 1194 | input Boolean isDeleted = false; | ||
| 1195 | output JSON json; | ||
| 1196 | algorithm | ||
| 1197 | json := match (cls, Type.arrayElementType(ty)) | ||
| 1198 | 1 | case (_, Type.ENUMERATION()) then dumpJSONEnumType(cls, node); | |
| 1199 | 3 | case (_, Type.UNKNOWN()) then dumpJSONSCodeElementType(InstNode.definition(node)); | |
| 1200 | 39 | case (InstanceTree.CLASS(), _) then dumpJSONInstanceTree(cls, node, isDeleted = isDeleted); | |
| 1201 | 59 | else dumpJSONTypeName(ty); | |
| 1202 | end match; | ||
| 1203 | end dumpJSONComponentType; | ||
| 1204 | |||
| 1205 | function dumpJSONSCodeElementType | ||
| 1206 | input SCode.Element elem; | ||
| 1207 | output JSON json = JSON.makeNull(); | ||
| 1208 | algorithm | ||
| 1209 | () := match elem | ||
| 1210 | case SCode.Element.COMPONENT() | ||
| 1211 | algorithm | ||
| 1212 | 3 | json := JSON.addPair("name", dumpJSONPath(AbsynUtil.typeSpecPath(elem.typeSpec)), json); | |
| 1213 | 3 | json := JSON.addPair("missing", JSON.makeBoolean(true), json); | |
| 1214 | then | ||
| 1215 | (); | ||
| 1216 | |||
| 1217 | else (); | ||
| 1218 | end match; | ||
| 1219 | end dumpJSONSCodeElementType; | ||
| 1220 | |||
| 1221 | function dumpJSONEnumType | ||
| 1222 | input InstanceTree tree; | ||
| 1223 | input InstNode enumNode; | ||
| 1224 | output JSON json; | ||
| 1225 | protected | ||
| 1226 | InstNode node = InstNode.resolveInner(InstNode.classScope(enumNode)); | ||
| 1227 | SCode.Element def; | ||
| 1228 | array<InstNode> comps; | ||
| 1229 | JSON json_elems; | ||
| 1230 | list<InstanceTree> elems; | ||
| 1231 | algorithm | ||
| 1232 | 1 | def := InstNode.definition(node); | |
| 1233 | |||
| 1234 | 1 | json := JSON.makeNull(); | |
| 1235 | 1 | json := JSON.addPair("name", dumpJSONNodePath(node), json); | |
| 1236 | 1 | json := JSON.addPairNotNull("dims", dumpJSONClassDims(node, def), json); | |
| 1237 | 1 | json := JSON.addPair("restriction", | |
| 1238 | JSON.makeString(SCodeDump.restrictionStringPP(SCodeUtil.getClassRestriction(def))), json); | ||
| 1239 | 1 | json := dumpJSONCommentOpt(SCodeUtil.getElementComment(def), node, json); | |
| 1240 | |||
| 1241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | InstanceTree.CLASS(elements = elems) := tree; |
| 1242 | 1 | json_elems := dumpJSONElements(elems, node, false); | |
| 1243 | |||
| 1244 | 1 | comps := ClassTree.getComponents(Class.classTree(InstNode.getClass(node))); | |
| 1245 | 1 | json_elems := dumpJSONEnumTypeLiterals(comps, InstNode.parent(node), json_elems); | |
| 1246 | 1 | json := JSON.addPair("elements", json_elems, json); | |
| 1247 | |||
| 1248 | 1 | json := JSON.addPair("source", JSON.dumpJSONSourceInfo(InstNode.info(node)), json); | |
| 1249 | end dumpJSONEnumType; | ||
| 1250 | |||
| 1251 | function dumpJSONEnumTypeLiterals | ||
| 1252 | input array<InstNode> literals; | ||
| 1253 | input InstNode scope; | ||
| 1254 | input output JSON json = JSON.emptyArray(); | ||
| 1255 | algorithm | ||
| 1256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
4 | for i in 6:arrayLength(literals) loop |
| 1257 | 3 | json := JSON.addElement(dumpJSONEnumTypeLiteral(literals[i], scope), json); | |
| 1258 | end for; | ||
| 1259 | end dumpJSONEnumTypeLiterals; | ||
| 1260 | |||
| 1261 | function dumpJSONEnumTypeLiteral | ||
| 1262 | input InstNode node; | ||
| 1263 | input InstNode scope; | ||
| 1264 | output JSON json = JSON.makeNull(); | ||
| 1265 | algorithm | ||
| 1266 | 3 | json := JSON.addPair("$kind", JSON.STRING("component"), json); | |
| 1267 | 3 | json := JSON.addPair("name", JSON.makeString(InstNode.name(node)), json); | |
| 1268 | 3 | json := dumpJSONComment(Component.comment(InstNode.component(node)), scope, json); | |
| 1269 | end dumpJSONEnumTypeLiteral; | ||
| 1270 | |||
| 1271 | function dumpJSONTypeName | ||
| 1272 | input Type ty; | ||
| 1273 | output JSON json; | ||
| 1274 | algorithm | ||
| 1275 | 59 | json := JSON.makeString(Type.toString(Type.arrayElementType(ty))); | |
| 1276 | end dumpJSONTypeName; | ||
| 1277 | |||
| 1278 | function dumpJSONBinding | ||
| 1279 | input Binding binding; | ||
| 1280 | input Option<Binding> originalBinding = NONE(); | ||
| 1281 | input Boolean evaluate = true; | ||
| 1282 | output JSON json = JSON.makeNull(); | ||
| 1283 | protected | ||
| 1284 | Expression exp; | ||
| 1285 | Binding bind = binding; | ||
| 1286 | InstContext.Type context; | ||
| 1287 | algorithm | ||
| 1288 | // If the binding has been evaluated by the frontend, try to use the original | ||
| 1289 | // binding that we saved when building the instance tree instead. | ||
| 1290 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 1 time.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 34 times.
|
37 | if isSome(originalBinding) and Binding.isEvaluated(binding) then |
| 1291 | try | ||
| 1292 | 2 | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.INSTANCE_API); | |
| 1293 | 2 | bind := Inst.instBinding(Util.getOption(originalBinding), context); | |
| 1294 | 2 | bind := Typing.typeBinding(bind, context); | |
| 1295 | else | ||
| 1296 | end try; | ||
| 1297 | end if; | ||
| 1298 | |||
| 1299 | 37 | exp := Binding.getExp(bind); | |
| 1300 | 37 | exp := Expression.map(exp, Expression.expandSplitIndices); | |
| 1301 | 37 | json := JSON.addPair("binding", Expression.toJSON(exp), json); | |
| 1302 | |||
| 1303 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 19 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 6 times.
|
37 | if evaluate and not Expression.isLiteral(exp) then |
| 1304 | 6 | ErrorExt.setCheckpoint(getInstanceName()); | |
| 1305 | try | ||
| 1306 | 6 | exp := Ceval.evalExp(exp, Ceval.EvalTarget.new(Absyn.dummyInfo, NFInstContext.INSTANCE_API)); | |
| 1307 | 6 | exp := Expression.map(exp, Expression.expandSplitIndices); | |
| 1308 | 6 | json := JSON.addPair("value", Expression.toJSON(exp), json); | |
| 1309 | else | ||
| 1310 | end try; | ||
| 1311 | 6 | ErrorExt.rollBack(getInstanceName()); | |
| 1312 | end if; | ||
| 1313 | end dumpJSONBinding; | ||
| 1314 | |||
| 1315 | function dumpJSONClassDims | ||
| 1316 | input InstNode node; | ||
| 1317 | input SCode.Element element; | ||
| 1318 | output JSON json; | ||
| 1319 | protected | ||
| 1320 | Type ty; | ||
| 1321 | list<Absyn.Subscript> absyn_dims; | ||
| 1322 | algorithm | ||
| 1323 | 103 | ty := InstNode.getType(node); | |
| 1324 | |||
| 1325 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 103 times.
|
103 | if Type.isArray(ty) then |
| 1326 | absyn_dims := match element | ||
| 1327 | case SCode.Element.CLASS(classDef = SCode.ClassDef.DERIVED(typeSpec = | ||
| 1328 | Absyn.TypeSpec.TPATH(arrayDim = SOME(absyn_dims)))) | ||
| 1329 | then absyn_dims; | ||
| 1330 | |||
| 1331 | else {}; | ||
| 1332 | end match; | ||
| 1333 | |||
| 1334 | ✗ | json := dumpJSONDims(absyn_dims, Type.arrayDims(ty)); | |
| 1335 | else | ||
| 1336 | 103 | json := JSON.makeNull(); | |
| 1337 | end if; | ||
| 1338 | end dumpJSONClassDims; | ||
| 1339 | |||
| 1340 | function dumpJSONDims | ||
| 1341 | input list<Absyn.Subscript> absynDims; | ||
| 1342 | input list<Dimension> typedDims; | ||
| 1343 | output JSON json = JSON.makeNull(); | ||
| 1344 | protected | ||
| 1345 | JSON ty_json; | ||
| 1346 | algorithm | ||
| 1347 | 7 | json := JSON.addPairNotNull("absyn", dumpJSONAbsynDims(absynDims), json); | |
| 1348 | |||
| 1349 | 7 | ty_json := JSON.makeNull(); | |
| 1350 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
|
13 | for d in typedDims loop |
| 1351 | 6 | ty_json := JSON.addElement(JSON.makeString(Dimension.toString(d)), ty_json); | |
| 1352 | end for; | ||
| 1353 | |||
| 1354 | 7 | json := JSON.addPairNotNull("typed", ty_json, json); | |
| 1355 | end dumpJSONDims; | ||
| 1356 | |||
| 1357 | function dumpJSONAbsynDims | ||
| 1358 | input list<Absyn.Subscript> dims; | ||
| 1359 | output JSON json = JSON.makeNull(); | ||
| 1360 | algorithm | ||
| 1361 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
|
13 | for d in dims loop |
| 1362 | 6 | json := JSON.addElement(JSON.makeString(Dump.printSubscriptStr(d)), json); | |
| 1363 | end for; | ||
| 1364 | end dumpJSONAbsynDims; | ||
| 1365 | |||
| 1366 | function dumpJSONAttributes | ||
| 1367 | input SCode.Attributes attrs; | ||
| 1368 | input SCode.Prefixes prefs; | ||
| 1369 | input InstNode scope; | ||
| 1370 | output JSON json; | ||
| 1371 | protected | ||
| 1372 | String s; | ||
| 1373 | algorithm | ||
| 1374 | 127 | json := dumpJSONSCodePrefixes(prefs, scope); | |
| 1375 | |||
| 1376 | 127 | s := SCodeDump.connectorTypeStr(attrs.connectorType); | |
| 1377 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 123 times.
|
127 | if not stringEmpty(s) then |
| 1378 | 4 | json := JSON.addPair("connector", JSON.makeString(s), json); | |
| 1379 | end if; | ||
| 1380 | |||
| 1381 | 127 | s := SCodeDump.unparseVariability(attrs.variability); | |
| 1382 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 103 times.
|
127 | if not stringEmpty(s) then |
| 1383 | 24 | json := JSON.addPair("variability", JSON.makeString(s), json); | |
| 1384 | end if; | ||
| 1385 | |||
| 1386 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 124 times.
|
127 | if AbsynUtil.isInput(attrs.direction) then |
| 1387 | 3 | json := JSON.addPair("direction", JSON.STRING("input"), json); | |
| 1388 | elseif AbsynUtil.isOutput(attrs.direction) then | ||
| 1389 | 1 | json := JSON.addPair("direction", JSON.STRING("output"), json); | |
| 1390 | end if; | ||
| 1391 | end dumpJSONAttributes; | ||
| 1392 | |||
| 1393 | function dumpJSONSCodePrefixes | ||
| 1394 | input SCode.Prefixes prefixes; | ||
| 1395 | input InstNode scope; | ||
| 1396 | output JSON json = JSON.makeNull(); | ||
| 1397 | algorithm | ||
| 1398 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 274 times.
|
275 | if not SCodeUtil.visibilityBool(prefixes.visibility) then |
| 1399 | 1 | json := JSON.addPair("public", JSON.makeBoolean(false), json); | |
| 1400 | end if; | ||
| 1401 | |||
| 1402 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 275 times.
|
275 | if SCodeUtil.finalBool(prefixes.finalPrefix) then |
| 1403 | ✗ | json := JSON.addPair("final", JSON.makeBoolean(true), json); | |
| 1404 | end if; | ||
| 1405 | |||
| 1406 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 270 times.
|
275 | if AbsynUtil.isInner(prefixes.innerOuter) then |
| 1407 | 5 | json := JSON.addPair("inner", JSON.makeBoolean(true), json); | |
| 1408 | end if; | ||
| 1409 | |||
| 1410 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 270 times.
|
275 | if AbsynUtil.isOuter(prefixes.innerOuter) then |
| 1411 | 5 | json := JSON.addPair("outer", JSON.makeBoolean(true), json); | |
| 1412 | end if; | ||
| 1413 | |||
| 1414 | 275 | json := JSON.addPairNotNull("replaceable", | |
| 1415 | dumpJSONReplaceable(prefixes.replaceablePrefix, scope), json); | ||
| 1416 | |||
| 1417 |
2/2✓ Branch 1 taken 270 times.
✓ Branch 2 taken 5 times.
|
275 | if SCodeUtil.redeclareBool(prefixes.redeclarePrefix) then |
| 1418 | 5 | json := JSON.addPair("redeclare", JSON.makeBoolean(true), json); | |
| 1419 | end if; | ||
| 1420 | end dumpJSONSCodePrefixes; | ||
| 1421 | |||
| 1422 | function dumpJSONClassPrefixes | ||
| 1423 | input SCode.Element element; | ||
| 1424 | input InstNode scope; | ||
| 1425 | output JSON json; | ||
| 1426 | protected | ||
| 1427 | SCode.ClassDef cdef; | ||
| 1428 | algorithm | ||
| 1429 | json := match element | ||
| 1430 | case SCode.CLASS(classDef = cdef, prefixes = _) | ||
| 1431 | algorithm | ||
| 1432 | json := match cdef | ||
| 1433 | 20 | case SCode.ClassDef.DERIVED() then dumpJSONAttributes(cdef.attributes, element.prefixes, scope); | |
| 1434 | 148 | else dumpJSONSCodePrefixes(element.prefixes, scope); | |
| 1435 | end match; | ||
| 1436 | |||
| 1437 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 161 times.
|
168 | if SCodeUtil.partialBool(element.partialPrefix) then |
| 1438 | 7 | json := JSON.addPair("partial", JSON.makeBoolean(true), json); | |
| 1439 | end if; | ||
| 1440 | |||
| 1441 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 168 times.
|
168 | if SCodeUtil.encapsulatedBool(element.encapsulatedPrefix) then |
| 1442 | ✗ | json := JSON.addPair("encapsulated", JSON.makeBoolean(true), json); | |
| 1443 | end if; | ||
| 1444 | then | ||
| 1445 | json; | ||
| 1446 | |||
| 1447 | ✗ | else JSON.makeNull(); | |
| 1448 | end match; | ||
| 1449 | end dumpJSONClassPrefixes; | ||
| 1450 | |||
| 1451 | function dumpJSONReplaceable | ||
| 1452 | input SCode.Replaceable repl; | ||
| 1453 | input InstNode scope; | ||
| 1454 | output JSON json; | ||
| 1455 | protected | ||
| 1456 | SCode.ConstrainClass cc; | ||
| 1457 | algorithm | ||
| 1458 | json := match repl | ||
| 1459 | case SCode.Replaceable.REPLACEABLE(cc = SOME(cc)) | ||
| 1460 | algorithm | ||
| 1461 | 4 | json := JSON.makeNull(); | |
| 1462 | 4 | json := JSON.addPair("constrainedby", dumpJSONPath(cc.constrainingClass), json); | |
| 1463 | 4 | json := dumpJSONSCodeMod(cc.modifier, scope, json); | |
| 1464 | 4 | json := dumpJSONCommentOpt(SOME(cc.comment), scope, json); | |
| 1465 | then | ||
| 1466 | json; | ||
| 1467 | |||
| 1468 | 15 | case SCode.Replaceable.REPLACEABLE() then JSON.makeBoolean(true); | |
| 1469 | 256 | else JSON.makeNull(); | |
| 1470 | end match; | ||
| 1471 | end dumpJSONReplaceable; | ||
| 1472 | |||
| 1473 | function dumpJSONCommentOpt | ||
| 1474 | input Option<SCode.Comment> cmtOpt; | ||
| 1475 | input InstNode scope; | ||
| 1476 | input output JSON json; | ||
| 1477 | input Boolean dumpComment = true; | ||
| 1478 | input Boolean dumpAnnotation = true; | ||
| 1479 | input Boolean failOnError = false; | ||
| 1480 | algorithm | ||
| 1481 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 18 times.
|
174 | if isSome(cmtOpt) then |
| 1482 | 156 | json := dumpJSONComment(Util.getOption(cmtOpt), scope, json, dumpComment, dumpAnnotation, failOnError); | |
| 1483 | end if; | ||
| 1484 | end dumpJSONCommentOpt; | ||
| 1485 | |||
| 1486 | function dumpJSONComment | ||
| 1487 | input SCode.Comment cmt; | ||
| 1488 | input InstNode scope; | ||
| 1489 | input output JSON json; | ||
| 1490 | input Boolean dumpComment = true; | ||
| 1491 | input Boolean dumpAnnotation = true; | ||
| 1492 | input Boolean failOnError = false; | ||
| 1493 | algorithm | ||
| 1494 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 284 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 277 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
284 | if isSome(cmt.comment) and dumpComment then |
| 1495 | 7 | json := JSON.addPair("comment", JSON.makeString(Util.getOption(cmt.comment)), json); | |
| 1496 | end if; | ||
| 1497 | |||
| 1498 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 273 times.
|
284 | if dumpAnnotation then |
| 1499 | 273 | json := dumpJSONAnnotationOpt(cmt.annotation_, scope, {}, failOnError, json); | |
| 1500 | end if; | ||
| 1501 | end dumpJSONComment; | ||
| 1502 | |||
| 1503 | function dumpJSONCommentAnnotation | ||
| 1504 | input Option<SCode.Comment> cmtOpt; | ||
| 1505 | input InstNode scope; | ||
| 1506 | input output JSON json; | ||
| 1507 | input list<String> filter = {}; | ||
| 1508 | input Boolean failOnError = false; | ||
| 1509 | protected | ||
| 1510 | SCode.Comment cmt; | ||
| 1511 | algorithm | ||
| 1512 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if isSome(cmtOpt) then |
| 1513 | 15 | SOME(cmt) := cmtOpt; | |
| 1514 | 15 | json := dumpJSONAnnotationOpt(cmt.annotation_, scope, filter, failOnError, json); | |
| 1515 | end if; | ||
| 1516 | end dumpJSONCommentAnnotation; | ||
| 1517 | |||
| 1518 | function dumpJSONAnnotationOpt | ||
| 1519 | input Option<SCode.Annotation> annOpt; | ||
| 1520 | input InstNode scope; | ||
| 1521 | input list<String> filter; | ||
| 1522 | input Boolean failOnError; | ||
| 1523 | input output JSON json; | ||
| 1524 | protected | ||
| 1525 | SCode.Annotation ann; | ||
| 1526 | algorithm | ||
| 1527 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 309 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 240 times.
|
309 | if isSome(annOpt) then |
| 1528 | 69 | SOME(ann) := annOpt; | |
| 1529 | 69 | json := JSON.addPair("annotation", dumpJSONAnnotationMod(ann.modification, scope, filter, failOnError), json); | |
| 1530 | end if; | ||
| 1531 | end dumpJSONAnnotationOpt; | ||
| 1532 | |||
| 1533 | function dumpJSONAnnotationMod | ||
| 1534 | input SCode.Mod mod; | ||
| 1535 | input InstNode scope; | ||
| 1536 | input list<String> filter; | ||
| 1537 | input Boolean failOnError; | ||
| 1538 | output JSON json; | ||
| 1539 | algorithm | ||
| 1540 | json := match mod | ||
| 1541 | case SCode.Mod.MOD() | ||
| 1542 | 69 | then dumpJSONAnnotationSubMods(mod.subModLst, scope, filter, failOnError); | |
| 1543 | |||
| 1544 | ✗ | else JSON.makeNull(); | |
| 1545 | end match; | ||
| 1546 | end dumpJSONAnnotationMod; | ||
| 1547 | |||
| 1548 | function dumpJSONAnnotationSubMods | ||
| 1549 | input list<SCode.SubMod> subMods; | ||
| 1550 | input InstNode scope; | ||
| 1551 | input list<String> filter; | ||
| 1552 | input Boolean failOnError; | ||
| 1553 | output JSON json = JSON.makeNull(); | ||
| 1554 | algorithm | ||
| 1555 |
2/2✓ Branch 0 taken 232 times.
✓ Branch 1 taken 179 times.
|
411 | for m in subMods loop |
| 1556 |
3/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 211 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
|
232 | if listEmpty(filter) or List.contains(filter, m.ident, stringEq) then |
| 1557 | 232 | json := dumpJSONAnnotationSubMod(m, scope, failOnError, json); | |
| 1558 | end if; | ||
| 1559 | end for; | ||
| 1560 | end dumpJSONAnnotationSubMods; | ||
| 1561 | |||
| 1562 | function dumpJSONAnnotationSubMod | ||
| 1563 | input SCode.SubMod subMod; | ||
| 1564 | input InstNode scope; | ||
| 1565 | input Boolean failOnError; | ||
| 1566 | input output JSON json; | ||
| 1567 | protected | ||
| 1568 | String name; | ||
| 1569 | SCode.Mod mod; | ||
| 1570 | Absyn.Exp absyn_binding; | ||
| 1571 | JSON j; | ||
| 1572 | algorithm | ||
| 1573 | 233 | SCode.SubMod.NAMEMOD(ident = name, mod = mod) := subMod; | |
| 1574 | |||
| 1575 | () := match (name, mod) | ||
| 1576 | case ("choices", SCode.Mod.MOD()) | ||
| 1577 | algorithm | ||
| 1578 | 1 | j := dumpJSONChoicesAnnotation(mod.subModLst, scope, mod.info, failOnError); | |
| 1579 | 1 | json := JSON.addPairNotNull(name, j, json); | |
| 1580 | then | ||
| 1581 | (); | ||
| 1582 | |||
| 1583 | case (_, SCode.Mod.MOD(binding = SOME(absyn_binding))) | ||
| 1584 | algorithm | ||
| 1585 | 121 | j := dumpJSONAnnotationExp(absyn_binding, scope, mod.info, failOnError); | |
| 1586 | 121 | json := JSON.addPair(name, j, json); | |
| 1587 | then | ||
| 1588 | (); | ||
| 1589 | |||
| 1590 | case (_, SCode.Mod.MOD()) | ||
| 1591 | algorithm | ||
| 1592 | 110 | json := JSON.addPair(name, dumpJSONAnnotationSubMods(mod.subModLst, scope, {}, failOnError), json); | |
| 1593 | then | ||
| 1594 | (); | ||
| 1595 | |||
| 1596 | case (_, SCode.Mod.NOMOD()) | ||
| 1597 | algorithm | ||
| 1598 | 1 | json := JSON.addPair(name, JSON.emptyListObject(), json); | |
| 1599 | then | ||
| 1600 | (); | ||
| 1601 | |||
| 1602 | else (); | ||
| 1603 | end match; | ||
| 1604 | end dumpJSONAnnotationSubMod; | ||
| 1605 | |||
| 1606 | function dumpJSONAnnotationExp | ||
| 1607 | input Absyn.Exp absynExp; | ||
| 1608 | input InstNode scope; | ||
| 1609 | input SourceInfo info; | ||
| 1610 | input Boolean failOnError; | ||
| 1611 | output JSON json; | ||
| 1612 | protected | ||
| 1613 | JSON j; | ||
| 1614 | algorithm | ||
| 1615 | json := match absynExp | ||
| 1616 | 19 | case Absyn.Exp.INTEGER() then JSON.makeInteger(absynExp.value); | |
| 1617 | ✗ | case Absyn.Exp.REAL() then JSON.makeNumber(stringReal(absynExp.value)); | |
| 1618 | ✗ | case Absyn.Exp.STRING() then JSON.makeString(absynExp.value); | |
| 1619 | 33 | case Absyn.Exp.BOOL() then JSON.makeBoolean(absynExp.value); | |
| 1620 | |||
| 1621 | // For non-literal arrays, dump each element separately to avoid | ||
| 1622 | // invalidating the whole array expression if any element contains invalid | ||
| 1623 | // expressions. | ||
| 1624 | case Absyn.Exp.ARRAY() | ||
| 1625 | guard not AbsynUtil.isLiteralExp(absynExp) | ||
| 1626 | algorithm | ||
| 1627 | 135 | json := JSON.emptyArray(listLength(absynExp.arrayExp)); | |
| 1628 |
2/2✓ Branch 0 taken 242 times.
✓ Branch 1 taken 135 times.
|
377 | for e in absynExp.arrayExp loop |
| 1629 | 242 | j := dumpJSONAnnotationExp(e, scope, info, failOnError); | |
| 1630 | 242 | json := JSON.addElement(j, json); | |
| 1631 | end for; | ||
| 1632 | then | ||
| 1633 | json; | ||
| 1634 | |||
| 1635 | 176 | else dumpJSONAnnotationExp2(absynExp, scope, info, failOnError); | |
| 1636 | end match; | ||
| 1637 | end dumpJSONAnnotationExp; | ||
| 1638 | |||
| 1639 | function dumpJSONAnnotationExp2 | ||
| 1640 | input Absyn.Exp absynExp; | ||
| 1641 | input InstNode scope; | ||
| 1642 | input SourceInfo info; | ||
| 1643 | input Boolean failOnError; | ||
| 1644 | output JSON json; | ||
| 1645 | protected | ||
| 1646 | Expression exp; | ||
| 1647 | algorithm | ||
| 1648 | 176 | ErrorExt.setCheckpoint(getInstanceName()); | |
| 1649 | try | ||
| 1650 | 176 | exp := Inst.instExp(absynExp, scope, INST_API_ANNOTATION_CONTEXT, info); | |
| 1651 | 175 | exp := Typing.typeExp(exp, INST_API_ANNOTATION_CONTEXT, info); | |
| 1652 | 175 | exp := SimplifyExp.simplify(exp); | |
| 1653 | 175 | json := Expression.toJSON(exp); | |
| 1654 | else | ||
| 1655 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if failOnError then |
| 1656 | ✗ | fail(); | |
| 1657 | end if; | ||
| 1658 | |||
| 1659 | 1 | json := JSON.makeNull(); | |
| 1660 | 1 | json := JSON.addPair("$error", JSON.makeString(ErrorExt.printCheckpointMessagesStr()), json); | |
| 1661 | 1 | json := JSON.addPair("value", dumpJSONAbsynExpression(absynExp), json); | |
| 1662 | end try; | ||
| 1663 | 176 | ErrorExt.delCheckpoint(getInstanceName()); | |
| 1664 | end dumpJSONAnnotationExp2; | ||
| 1665 | |||
| 1666 | |||
| 1667 | |||
| 1668 | function dumpJSONAbsynExpression | ||
| 1669 | input Absyn.Exp exp; | ||
| 1670 | output JSON json; | ||
| 1671 | protected | ||
| 1672 | Integer i; | ||
| 1673 | String r; | ||
| 1674 | algorithm | ||
| 1675 | json := match exp | ||
| 1676 | 3 | case Absyn.Exp.INTEGER() then JSON.makeInteger(exp.value); | |
| 1677 | ✗ | case Absyn.Exp.REAL() then JSON.makeNumber(stringReal(exp.value)); | |
| 1678 | 1 | case Absyn.Exp.CREF() then dumpJSONAbsynCref(exp.componentRef); | |
| 1679 | ✗ | case Absyn.Exp.STRING() then JSON.makeString(exp.value); | |
| 1680 | ✗ | case Absyn.Exp.BOOL() then JSON.makeBoolean(exp.value); | |
| 1681 | |||
| 1682 | case Absyn.Exp.UNARY(op = Absyn.Operator.UMINUS(), exp = Absyn.Exp.INTEGER(value = i)) | ||
| 1683 | ✗ | then JSON.makeInteger(-i); | |
| 1684 | |||
| 1685 | case Absyn.Exp.UNARY(op = Absyn.Operator.UMINUS(), exp = Absyn.Exp.REAL(value = r)) | ||
| 1686 | ✗ | then JSON.makeNumber(-stringReal(r)); | |
| 1687 | |||
| 1688 | case Absyn.Exp.CALL() | ||
| 1689 | algorithm | ||
| 1690 | 1 | json := JSON.makeNull(); | |
| 1691 | 1 | json := JSON.addPair("$kind", JSON.STRING("call"), json); | |
| 1692 | 1 | json := JSON.addPair("name", dumpJSONAbsynCref(exp.function_), json); | |
| 1693 | 1 | json := dumpJSONAbsynFunctionArgs(exp.functionArgs, json); | |
| 1694 | then | ||
| 1695 | json; | ||
| 1696 | |||
| 1697 | case Absyn.Exp.ARRAY() | ||
| 1698 | algorithm | ||
| 1699 | 3 | json := JSON.emptyArray(listLength(exp.arrayExp)); | |
| 1700 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | for e in exp.arrayExp loop |
| 1701 | 6 | json := JSON.addElement(dumpJSONAbsynExpression(e), json); | |
| 1702 | end for; | ||
| 1703 | then | ||
| 1704 | json; | ||
| 1705 | |||
| 1706 | ✗ | else JSON.makeString(Dump.printExpStr(AbsynUtil.stripCommentExpressions(exp, true))); | |
| 1707 | end match; | ||
| 1708 | end dumpJSONAbsynExpression; | ||
| 1709 | |||
| 1710 | function dumpJSONAbsynCref | ||
| 1711 | input Absyn.ComponentRef cref; | ||
| 1712 | output JSON json; | ||
| 1713 | algorithm | ||
| 1714 | 2 | json := JSON.makeString(Dump.printComponentRefStr(cref)); | |
| 1715 | end dumpJSONAbsynCref; | ||
| 1716 | |||
| 1717 | function dumpJSONAbsynFunctionArgs | ||
| 1718 | input Absyn.FunctionArgs args; | ||
| 1719 | input output JSON json; | ||
| 1720 | protected | ||
| 1721 | JSON json_args; | ||
| 1722 | algorithm | ||
| 1723 | () := match args | ||
| 1724 | case Absyn.FunctionArgs.FUNCTIONARGS() | ||
| 1725 | algorithm | ||
| 1726 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if not listEmpty(args.args) then |
| 1727 | ✗ | json_args := JSON.makeNull(); | |
| 1728 | ✗ | for arg in args.args loop | |
| 1729 | ✗ | json_args := JSON.addElement(dumpJSONAbsynExpression(arg), json_args); | |
| 1730 | end for; | ||
| 1731 | |||
| 1732 | ✗ | json := JSON.addPair("args", json_args, json); | |
| 1733 | end if; | ||
| 1734 | |||
| 1735 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if not listEmpty(args.argNames) then |
| 1736 | 1 | json_args := JSON.makeNull(); | |
| 1737 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for arg in args.argNames loop |
| 1738 | 1 | json_args := JSON.addPair(arg.argName, dumpJSONAbsynExpression(arg.argValue), json_args); | |
| 1739 | end for; | ||
| 1740 | |||
| 1741 | 1 | json := JSON.addPair("namedArgs", json_args, json); | |
| 1742 | end if; | ||
| 1743 | then | ||
| 1744 | (); | ||
| 1745 | |||
| 1746 | else (); | ||
| 1747 | end match; | ||
| 1748 | end dumpJSONAbsynFunctionArgs; | ||
| 1749 | |||
| 1750 | function dumpJSONImports | ||
| 1751 | input InstNode node; | ||
| 1752 | input output JSON json; | ||
| 1753 | protected | ||
| 1754 | InstNode n = node; | ||
| 1755 | array<Import> imps; | ||
| 1756 | list<Import> resolved_imps; | ||
| 1757 | JSON json_imp, json_imp_array; | ||
| 1758 | algorithm | ||
| 1759 | 100 | json_imp_array := JSON.makeNull(); | |
| 1760 | |||
| 1761 |
2/2✓ Branch 1 taken 239 times.
✓ Branch 2 taken 100 times.
|
339 | while not InstNode.isEmpty(n) loop |
| 1762 | 239 | imps := ClassTree.getImports(Class.classTree(InstNode.getClass(n))); | |
| 1763 | |||
| 1764 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 236 times.
|
239 | if not arrayEmpty(imps) then |
| 1765 | 3 | resolved_imps := Import.resolveList(imps); | |
| 1766 | 3 | resolved_imps := listReverseInPlace(resolved_imps); | |
| 1767 | |||
| 1768 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
|
8 | for imp in resolved_imps loop |
| 1769 | () := match imp | ||
| 1770 | case Import.RESOLVED_IMPORT() | ||
| 1771 | algorithm | ||
| 1772 | 5 | json_imp := JSON.makeNull(); | |
| 1773 | 5 | json_imp := JSON.addPair("path", dumpJSONPath(InstNode.fullPath(InstNode.borrow(imp.node))), json_imp); | |
| 1774 | |||
| 1775 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if not stringEmpty(imp.shortName) then |
| 1776 | ✗ | json_imp := JSON.addPair("shortName", JSON.makeString(imp.shortName), json_imp); | |
| 1777 | end if; | ||
| 1778 | |||
| 1779 | 5 | json_imp_array := JSON.addElement(json_imp, json_imp_array); | |
| 1780 | then | ||
| 1781 | (); | ||
| 1782 | |||
| 1783 | else (); | ||
| 1784 | end match; | ||
| 1785 | end for; | ||
| 1786 | end if; | ||
| 1787 | |||
| 1788 | 239 | n := InstNode.parent(n); | |
| 1789 | end while; | ||
| 1790 | |||
| 1791 | 100 | json := JSON.addPairNotNull("imports", json_imp_array, json); | |
| 1792 | end dumpJSONImports; | ||
| 1793 | |||
| 1794 | function dumpJSONEquations | ||
| 1795 | input Sections sections; | ||
| 1796 | input InstNode scope; | ||
| 1797 | input output JSON json; | ||
| 1798 | protected | ||
| 1799 | list<Equation> connections, transitions, initial_states; | ||
| 1800 | JSON j; | ||
| 1801 | InstContext.Type context; | ||
| 1802 | algorithm | ||
| 1803 | 100 | (connections, transitions, initial_states) := sortEquations(Sections.equations(sections)); | |
| 1804 | 100 | context := InstContext.set(NFInstContext.CLASS, NFInstContext.RELAXED); | |
| 1805 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
|
100 | transitions := list(Typing.typeEquation(e, context) for e in transitions); |
| 1806 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
|
100 | initial_states := list(Typing.typeEquation(e, context) for e in initial_states); |
| 1807 | |||
| 1808 | 100 | j := dumpJSONConnections(connections, scope); | |
| 1809 | 100 | json := JSON.addPairNotNull("connections", j, json); | |
| 1810 | |||
| 1811 | 100 | j := dumpJSONStateCalls(initial_states, scope); | |
| 1812 | 100 | json := JSON.addPairNotNull("initialStates", j, json); | |
| 1813 | |||
| 1814 | 100 | j := dumpJSONStateCalls(transitions, scope); | |
| 1815 | 100 | json := JSON.addPairNotNull("transitions", j, json); | |
| 1816 | end dumpJSONEquations; | ||
| 1817 | |||
| 1818 | function sortEquations | ||
| 1819 | input list<Equation> equations; | ||
| 1820 | input output list<Equation> connections = {}; | ||
| 1821 | input output list<Equation> transitions = {}; | ||
| 1822 | input output list<Equation> initialStates = {}; | ||
| 1823 | algorithm | ||
| 1824 |
4/7✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 101 times.
|
106 | for eq in listReverse(equations) loop |
| 1825 | () := match eq | ||
| 1826 | case Equation.CONNECT() | ||
| 1827 | algorithm | ||
| 1828 | connections := eq :: connections; | ||
| 1829 | then | ||
| 1830 | (); | ||
| 1831 | |||
| 1832 | case Equation.FOR() | ||
| 1833 | algorithm | ||
| 1834 | ✗ | (connections, transitions, initialStates) := | |
| 1835 | sortEquations(eq.body, connections, transitions, initialStates); | ||
| 1836 | then | ||
| 1837 | (); | ||
| 1838 | |||
| 1839 | case Equation.IF() | ||
| 1840 | algorithm | ||
| 1841 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for b in eq.branches loop |
| 1842 | () := match b | ||
| 1843 | case Equation.Branch.BRANCH() | ||
| 1844 | algorithm | ||
| 1845 | 1 | (connections, transitions, initialStates) := | |
| 1846 | sortEquations(b.body, connections, transitions, initialStates); | ||
| 1847 | then | ||
| 1848 | (); | ||
| 1849 | |||
| 1850 | else (); | ||
| 1851 | end match; | ||
| 1852 | end for; | ||
| 1853 | then | ||
| 1854 | (); | ||
| 1855 | |||
| 1856 | case Equation.NORETCALL() | ||
| 1857 | algorithm | ||
| 1858 | ✗ | if Expression.isCallNamed(eq.exp, "transition") then | |
| 1859 | ✗ | transitions := eq :: transitions; | |
| 1860 | elseif Expression.isCallNamed(eq.exp, "initialState") then | ||
| 1861 | ✗ | initialStates := eq :: initialStates; | |
| 1862 | end if; | ||
| 1863 | then | ||
| 1864 | (); | ||
| 1865 | |||
| 1866 | else (); | ||
| 1867 | end match; | ||
| 1868 | end for; | ||
| 1869 | end sortEquations; | ||
| 1870 | |||
| 1871 | function dumpJSONConnections | ||
| 1872 | input list<Equation> connections; | ||
| 1873 | input InstNode scope; | ||
| 1874 | output JSON json = JSON.makeNull(); | ||
| 1875 | algorithm | ||
| 1876 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 100 times.
|
104 | for conn in connections loop |
| 1877 | 4 | json := JSON.addElement(dumpJSONConnection(conn, scope), json); | |
| 1878 | end for; | ||
| 1879 | end dumpJSONConnections; | ||
| 1880 | |||
| 1881 | function dumpJSONConnection | ||
| 1882 | input Equation connEq; | ||
| 1883 | input InstNode scope; | ||
| 1884 | output JSON json = JSON.makeNull(); | ||
| 1885 | protected | ||
| 1886 | Expression lhs, rhs; | ||
| 1887 | DAE.ElementSource src; | ||
| 1888 | algorithm | ||
| 1889 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | Equation.CONNECT(lhs = lhs, rhs = rhs, source = src) := connEq; |
| 1890 | 4 | json := JSON.addPair("lhs", Expression.toJSON(lhs), json); | |
| 1891 | 4 | json := JSON.addPair("rhs", Expression.toJSON(rhs), json); | |
| 1892 | 4 | json := dumpJSONCommentAnnotation(ElementSource.getOptComment(src), scope, json); | |
| 1893 | end dumpJSONConnection; | ||
| 1894 | |||
| 1895 | function dumpJSONStateCalls | ||
| 1896 | input list<Equation> callEqs; | ||
| 1897 | input InstNode scope; | ||
| 1898 | output JSON json = JSON.makeNull(); | ||
| 1899 | algorithm | ||
| 1900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
|
200 | for eq in callEqs loop |
| 1901 | ✗ | json := JSON.addElement(dumpJSONStateCall(eq, scope), json); | |
| 1902 | end for; | ||
| 1903 | end dumpJSONStateCalls; | ||
| 1904 | |||
| 1905 | function dumpJSONStateCall | ||
| 1906 | input Equation callEq; | ||
| 1907 | input InstNode scope; | ||
| 1908 | output JSON json = JSON.makeNull(); | ||
| 1909 | protected | ||
| 1910 | Call call; | ||
| 1911 | list<Expression> args; | ||
| 1912 | DAE.ElementSource src; | ||
| 1913 | JSON j; | ||
| 1914 | algorithm | ||
| 1915 | () := match callEq | ||
| 1916 | case Equation.NORETCALL(exp = Expression.CALL(call = call as Call.TYPED_CALL(arguments = args)), source = src) | ||
| 1917 | algorithm | ||
| 1918 | ✗ | j := JSON.emptyArray(listLength(args)); | |
| 1919 | ✗ | for arg in args loop | |
| 1920 | ✗ | j := JSON.addElement(Expression.toJSON(arg), j); | |
| 1921 | end for; | ||
| 1922 | ✗ | json := JSON.addPair("arguments", j, json); | |
| 1923 | ✗ | json := dumpJSONCommentAnnotation(ElementSource.getOptComment(src), scope, json); | |
| 1924 | then | ||
| 1925 | (); | ||
| 1926 | |||
| 1927 | else (); | ||
| 1928 | end match; | ||
| 1929 | end dumpJSONStateCall; | ||
| 1930 | |||
| 1931 | function dumpJSONReplaceableElements | ||
| 1932 | input InstNode clsNode; | ||
| 1933 | output JSON json = JSON.makeNull(); | ||
| 1934 | protected | ||
| 1935 | ClassTree cls_tree; | ||
| 1936 | JSON j; | ||
| 1937 | algorithm | ||
| 1938 | ✗ | cls_tree := Class.classTree(InstNode.getClass(clsNode)); | |
| 1939 | |||
| 1940 | ✗ | for c in ClassTree.getComponents(cls_tree) loop | |
| 1941 | ✗ | if InstNode.isReplaceable(c) then | |
| 1942 | ✗ | j := JSON.makeNull(); | |
| 1943 | ✗ | j := JSON.addPair("name", JSON.makeString(InstNode.name(c)), j); | |
| 1944 | ✗ | j := JSON.addPair("type", dumpJSONTypeName(InstNode.getType(c)), j); | |
| 1945 | ✗ | json := JSON.addElement(j, json); | |
| 1946 | end if; | ||
| 1947 | end for; | ||
| 1948 | |||
| 1949 | ✗ | for c in ClassTree.getClasses(cls_tree) loop | |
| 1950 | ✗ | if InstNode.isReplaceable(c) then | |
| 1951 | ✗ | json := JSON.addElement(JSON.makeString(InstNode.name(c)), json); | |
| 1952 | end if; | ||
| 1953 | end for; | ||
| 1954 | end dumpJSONReplaceableElements; | ||
| 1955 | |||
| 1956 | function dumpJSONSCodeMod | ||
| 1957 | input SCode.Mod mod; | ||
| 1958 | input InstNode scope; | ||
| 1959 | input output JSON json; | ||
| 1960 | protected | ||
| 1961 | JSON j; | ||
| 1962 | algorithm | ||
| 1963 | 137 | j := dumpJSONSCodeMod_impl(mod, scope); | |
| 1964 | 137 | json := JSON.addPairNotNull("modifiers", j, json); | |
| 1965 | end dumpJSONSCodeMod; | ||
| 1966 | |||
| 1967 | function dumpJSONSCodeMod_impl | ||
| 1968 | input SCode.Mod mod; | ||
| 1969 | input InstNode scope; | ||
| 1970 | input Boolean isChoices = false; | ||
| 1971 | output JSON json = JSON.makeNull(); | ||
| 1972 | protected | ||
| 1973 | JSON binding_json; | ||
| 1974 | algorithm | ||
| 1975 | () := match mod | ||
| 1976 | case SCode.Mod.MOD() | ||
| 1977 | algorithm | ||
| 1978 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 62 times.
|
86 | for m in mod.subModLst loop |
| 1979 | 24 | json := JSON.addPair(m.ident, dumpJSONSCodeMod_impl(m.mod, scope), json); | |
| 1980 | end for; | ||
| 1981 | |||
| 1982 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 59 times.
|
62 | if SCodeUtil.finalBool(mod.finalPrefix) then |
| 1983 | 3 | json := JSON.addPair("final", JSON.makeBoolean(true), json); | |
| 1984 | end if; | ||
| 1985 | |||
| 1986 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 60 times.
|
62 | if SCodeUtil.eachBool(mod.eachPrefix) then |
| 1987 | 2 | json := JSON.addPair("each", JSON.makeBoolean(true), json); | |
| 1988 | end if; | ||
| 1989 | |||
| 1990 |
4/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
62 | if isChoices and isSome(mod.comment) then |
| 1991 | 3 | json := JSON.addPair("comment", JSON.makeString(Util.getOption(mod.comment)), json); | |
| 1992 | end if; | ||
| 1993 | |||
| 1994 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 17 times.
|
62 | if isSome(mod.binding) then |
| 1995 | 45 | binding_json := JSON.makeString(Dump.printExpStr(AbsynUtil.stripCommentExpressions(Util.getOption(mod.binding), true))); | |
| 1996 | |||
| 1997 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 37 times.
|
45 | if JSON.isNull(json) then |
| 1998 | json := binding_json; | ||
| 1999 | else | ||
| 2000 | 8 | json := JSON.addPair("$value", binding_json, json); | |
| 2001 | end if; | ||
| 2002 | end if; | ||
| 2003 | then | ||
| 2004 | (); | ||
| 2005 | |||
| 2006 | case SCode.Mod.REDECL() | ||
| 2007 | algorithm | ||
| 2008 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if SCodeUtil.finalBool(mod.finalPrefix) then |
| 2009 | ✗ | json := JSON.addPair("final", JSON.makeBoolean(true), json); | |
| 2010 | end if; | ||
| 2011 | |||
| 2012 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if SCodeUtil.eachBool(mod.eachPrefix) then |
| 2013 | ✗ | json := JSON.addPair("each", JSON.makeBoolean(true), json); | |
| 2014 | end if; | ||
| 2015 | |||
| 2016 | 4 | json := JSON.addPair("$value", dumpJSONSCodeElement(mod.element, scope), json); | |
| 2017 | then | ||
| 2018 | (); | ||
| 2019 | |||
| 2020 | else (); | ||
| 2021 | end match; | ||
| 2022 | end dumpJSONSCodeMod_impl; | ||
| 2023 | |||
| 2024 | function dumpJSONRedeclareType | ||
| 2025 | input SCode.Element element; | ||
| 2026 | input InstNode scope; | ||
| 2027 | input output JSON json; | ||
| 2028 | protected | ||
| 2029 | Absyn.Path path; | ||
| 2030 | InstContext.Type context; | ||
| 2031 | InstNode cls; | ||
| 2032 | algorithm | ||
| 2033 | () := matchcontinue element | ||
| 2034 | case SCode.Element.COMPONENT() | ||
| 2035 | algorithm | ||
| 2036 | ✗ | path := AbsynUtil.typeSpecPath(element.typeSpec); | |
| 2037 | ✗ | context := InstContext.set(NFInstContext.RELAXED, NFInstContext.FAST_LOOKUP); | |
| 2038 | ✗ | cls := Lookup.lookupName(path, scope, context, checkAccessViolations = false); | |
| 2039 | ✗ | json := JSON.addPair("$type", dumpJSONNodePath(cls), json); | |
| 2040 | then | ||
| 2041 | (); | ||
| 2042 | |||
| 2043 | else (); | ||
| 2044 | end matchcontinue; | ||
| 2045 | end dumpJSONRedeclareType; | ||
| 2046 | |||
| 2047 | function dumpJSONSCodeElement | ||
| 2048 | input SCode.Element element; | ||
| 2049 | input InstNode scope; | ||
| 2050 | input output JSON json = JSON.makeNull(); | ||
| 2051 | algorithm | ||
| 2052 | json := match element | ||
| 2053 | case SCode.Element.COMPONENT() | ||
| 2054 | algorithm | ||
| 2055 | 1 | json := JSON.addPair("$kind", JSON.STRING("component"), json); | |
| 2056 | 1 | json := JSON.addPair("name", JSON.makeString(element.name), json); | |
| 2057 | 1 | json := JSON.addPair("type", dumpJSONPath(AbsynUtil.typeSpecPath(element.typeSpec)), json); | |
| 2058 | 1 | json := JSON.addPairNotNull("dims", dumpJSONDims(element.attributes.arrayDims, {}), json); | |
| 2059 | 1 | json := dumpJSONSCodeMod(element.modifications, scope, json); | |
| 2060 | 1 | json := JSON.addPairNotNull("prefixes", dumpJSONAttributes(element.attributes, element.prefixes, scope), json); | |
| 2061 | |||
| 2062 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1 | if isSome(element.condition) then |
| 2063 | ✗ | json := JSON.addPair("condition", dumpJSONAbsynExpression(Util.getOption(element.condition)), json); | |
| 2064 | end if; | ||
| 2065 | |||
| 2066 | 1 | json := dumpJSONComment(element.comment, scope, json); | |
| 2067 | then | ||
| 2068 | json; | ||
| 2069 | |||
| 2070 | case SCode.Element.CLASS() | ||
| 2071 | 3 | then dumpJSONSCodeClass(element, InstNode.EMPTY_NODE(), scope, false, json); | |
| 2072 | |||
| 2073 | else json; | ||
| 2074 | end match; | ||
| 2075 | end dumpJSONSCodeElement; | ||
| 2076 | |||
| 2077 | function dumpJSONSCodeType | ||
| 2078 | input Absyn.Path path; | ||
| 2079 | input InstNode scope; | ||
| 2080 | input output JSON json; | ||
| 2081 | protected | ||
| 2082 | InstNode ty_node; | ||
| 2083 | algorithm | ||
| 2084 | try | ||
| 2085 | ✗ | ty_node := Lookup.lookupName(path, scope, InstContext.set(NFInstContext.RELAXED, NFInstContext.FAST_LOOKUP), | |
| 2086 | checkAccessViolations = false); | ||
| 2087 | ✗ | json := JSON.addPair("type", dumpJSONSCodeClass(InstNode.definition(ty_node), ty_node, scope, isRedeclare = false), json); | |
| 2088 | else | ||
| 2089 | ✗ | json := JSON.addPair("type", dumpJSONPath(path), json); | |
| 2090 | end try; | ||
| 2091 | end dumpJSONSCodeType; | ||
| 2092 | |||
| 2093 | function dumpJSONSCodeClass | ||
| 2094 | input SCode.Element element; | ||
| 2095 | input InstNode node; | ||
| 2096 | input InstNode scope; | ||
| 2097 | input Boolean isRedeclare; | ||
| 2098 | input output JSON json = JSON.makeNull(); | ||
| 2099 | algorithm | ||
| 2100 | () := match element | ||
| 2101 | case SCode.CLASS() | ||
| 2102 | algorithm | ||
| 2103 | 18 | json := JSON.addPair("$kind", JSON.STRING("class"), json); | |
| 2104 | |||
| 2105 |
4/4✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 4 times.
|
18 | if InstNode.isEmpty(node) or isRedeclare then |
| 2106 | 14 | json := JSON.addPair("name", JSON.makeString(element.name), json); | |
| 2107 | else | ||
| 2108 | 4 | json := JSON.addPair("name", dumpJSONNodeEnclosingPath(node), json); | |
| 2109 | end if; | ||
| 2110 | |||
| 2111 | 18 | json := JSON.addPair("restriction", | |
| 2112 | JSON.makeString(SCodeDump.restrictionStringPP(element.restriction)), json); | ||
| 2113 | 18 | json := JSON.addPairNotNull("prefixes", dumpJSONClassPrefixes(element, scope), json); | |
| 2114 | 18 | json := dumpJSONSCodeClassDef(element.classDef, scope, isRedeclare, json); | |
| 2115 | 18 | json := dumpJSONComment(element.cmt, scope, json, dumpAnnotation = not isRedeclare); | |
| 2116 | |||
| 2117 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
|
18 | if isRedeclare then |
| 2118 | 11 | json := dumpJSONCommentAnnotation(SOME(element.cmt), scope, json, | |
| 2119 | {"Dialog", "choices", "choicesAllMatching"}); | ||
| 2120 | end if; | ||
| 2121 | |||
| 2122 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
|
18 | if not isRedeclare then |
| 2123 | 7 | json := dumpJSONSCodeTypeExtends(node, scope, json); | |
| 2124 | end if; | ||
| 2125 | then | ||
| 2126 | (); | ||
| 2127 | end match; | ||
| 2128 | end dumpJSONSCodeClass; | ||
| 2129 | |||
| 2130 | function dumpJSONSCodeTypeExtends | ||
| 2131 | input InstNode node; | ||
| 2132 | input InstNode scope; | ||
| 2133 | input output JSON json; | ||
| 2134 | protected | ||
| 2135 | InstNode expanded_node; | ||
| 2136 | array<InstNode> exts; | ||
| 2137 | JSON json_elements, json_ext; | ||
| 2138 | algorithm | ||
| 2139 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
|
7 | if InstNode.isEmpty(node) then |
| 2140 | 3 | return; | |
| 2141 | end if; | ||
| 2142 | |||
| 2143 | try | ||
| 2144 | 4 | expanded_node := Inst.expand(node, NFInstContext.RELAXED); | |
| 2145 | 4 | exts := ClassTree.getExtends(Class.classTree(InstNode.getClass(expanded_node))); | |
| 2146 | |||
| 2147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if not arrayEmpty(exts) then |
| 2148 | ✗ | json_elements := JSON.makeNull(); | |
| 2149 | |||
| 2150 | ✗ | for ext in exts loop | |
| 2151 | ✗ | json_ext := JSON.makeNull(); | |
| 2152 | ✗ | json_ext := JSON.addPair("$kind", JSON.STRING("extends"), json_ext); | |
| 2153 | ✗ | json_ext := JSON.addPair("baseClass", dumpJSONSCodeClass(InstNode.definition(ext), ext, scope, false), json_ext); | |
| 2154 | ✗ | json_elements := JSON.addElement(json_ext, json_elements); | |
| 2155 | end for; | ||
| 2156 | |||
| 2157 | ✗ | json := JSON.addPair("elements", json_elements, json); | |
| 2158 | end if; | ||
| 2159 | else | ||
| 2160 | end try; | ||
| 2161 | end dumpJSONSCodeTypeExtends; | ||
| 2162 | |||
| 2163 | function dumpJSONSCodeClassDef | ||
| 2164 | input SCode.ClassDef classDef; | ||
| 2165 | input InstNode scope; | ||
| 2166 | input Boolean qualifyPath; | ||
| 2167 | input output JSON json; | ||
| 2168 | protected | ||
| 2169 | Absyn.Path path; | ||
| 2170 | Option<list<Absyn.Subscript>> odims; | ||
| 2171 | InstNode derivedNode; | ||
| 2172 | algorithm | ||
| 2173 | () := match classDef | ||
| 2174 | case SCode.ClassDef.DERIVED(typeSpec = Absyn.TypeSpec.TPATH(path = path, arrayDim = odims)) | ||
| 2175 | algorithm | ||
| 2176 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | if qualifyPath then |
| 2177 | try | ||
| 2178 | 8 | derivedNode := Lookup.lookupName(path, scope, NFInstContext.RELAXED, false); | |
| 2179 | 8 | json := JSON.addPair("baseClass", dumpJSONNodeEnclosingPath(derivedNode), json); | |
| 2180 | else | ||
| 2181 | end try; | ||
| 2182 | else | ||
| 2183 | 3 | json := JSON.addPair("baseClass", dumpJSONPath(path), json); | |
| 2184 | end if; | ||
| 2185 | |||
| 2186 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if isSome(odims) then |
| 2187 | ✗ | json := JSON.addPairNotNull("dims", dumpJSONDims(Util.getOption(odims), {}), json); | |
| 2188 | end if; | ||
| 2189 | |||
| 2190 | 11 | json := dumpJSONSCodeMod(classDef.modifications, scope, json); | |
| 2191 | then | ||
| 2192 | (); | ||
| 2193 | |||
| 2194 | case SCode.ClassDef.CLASS_EXTENDS() | ||
| 2195 | algorithm | ||
| 2196 | ✗ | json := dumpJSONSCodeMod(classDef.modifications, scope, json); | |
| 2197 | then | ||
| 2198 | (); | ||
| 2199 | |||
| 2200 | else (); | ||
| 2201 | end match; | ||
| 2202 | end dumpJSONSCodeClassDef; | ||
| 2203 | |||
| 2204 | function dumpJSONChoicesAnnotation | ||
| 2205 | input list<SCode.SubMod> mods; | ||
| 2206 | input InstNode scope; | ||
| 2207 | input SourceInfo info; | ||
| 2208 | input Boolean failOnError; | ||
| 2209 | output JSON json = JSON.makeNull(); | ||
| 2210 | protected | ||
| 2211 | SCode.SubMod smod; | ||
| 2212 | list<SCode.SubMod> choices, others; | ||
| 2213 | JSON j; | ||
| 2214 | algorithm | ||
| 2215 |
7/8✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 1 time.
|
5 | choices := list(m for m guard m.ident == "choice" in mods); |
| 2216 |
7/8✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
|
5 | others := list(m for m guard m.ident <> "choice" in mods); |
| 2217 | |||
| 2218 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if not listEmpty(choices) then |
| 2219 | 1 | j := JSON.emptyArray(listLength(choices)); | |
| 2220 | |||
| 2221 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
|
4 | for m in choices loop |
| 2222 | m := match m.mod | ||
| 2223 | case SCode.Mod.MOD(binding = NONE(), subModLst = {smod}) then smod; | ||
| 2224 | else m; | ||
| 2225 | end match; | ||
| 2226 | |||
| 2227 | 3 | j := JSON.addElement(dumpJSONSCodeMod_impl(m.mod, scope, isChoices = true), j); | |
| 2228 | end for; | ||
| 2229 | |||
| 2230 | 1 | json := JSON.addPair("choice", j, json); | |
| 2231 | end if; | ||
| 2232 | |||
| 2233 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for m in others loop |
| 2234 | 1 | json := dumpJSONAnnotationSubMod(m, scope, failOnError, json); | |
| 2235 | end for; | ||
| 2236 | end dumpJSONChoicesAnnotation; | ||
| 2237 | |||
| 2238 | public function modifierJSON | ||
| 2239 | input String modifier; | ||
| 2240 | output JSON json; | ||
| 2241 | protected | ||
| 2242 | Absyn.Modification amod; | ||
| 2243 | SCode.Mod smod; | ||
| 2244 | algorithm | ||
| 2245 | ✗ | Absyn.ElementArg.MODIFICATION(modification = SOME(amod)) := | |
| 2246 | Parser.stringMod("dummy" + modifier); | ||
| 2247 | ✗ | smod := AbsynToSCode.translateMod(SOME(amod), | |
| 2248 | SCode.Final.NOT_FINAL(), SCode.Each.NOT_EACH(), NONE(), Absyn.dummyInfo); | ||
| 2249 | ✗ | json := dumpJSONSCodeMod_impl(smod, InstNode.EMPTY_NODE()); | |
| 2250 | end modifierJSON; | ||
| 2251 | |||
| 2252 | annotation(__OpenModelica_Interface="nf_api"); | ||
| 2253 | end NFInstanceAPI; | ||
| 2254 |