From 27575598a342bfe24c78d0c3eeb6ed852029d2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Fri, 26 Apr 2024 16:08:04 +0200 Subject: [PATCH] Dump annotation array elements separately (#12325) - Dump elements of array expressions in annotations separately, to avoid e.g. an invalid graphical element invalidating the whole graphics arrays. --- OMCompiler/Compiler/FrontEnd/AbsynUtil.mo | 32 +++++ OMCompiler/Compiler/Script/NFApi.mo | 76 +++++++++--- doc/instanceAPI/expression.schema.json | 14 +++ doc/instanceAPI/getModelInstance.schema.json | 14 --- .../GetModelInstanceAnnotation12.mos | 115 ++++++++++++++++++ testsuite/openmodelica/instance-API/Makefile | 1 + 6 files changed, 219 insertions(+), 33 deletions(-) create mode 100644 testsuite/openmodelica/instance-API/GetModelInstanceAnnotation12.mos diff --git a/OMCompiler/Compiler/FrontEnd/AbsynUtil.mo b/OMCompiler/Compiler/FrontEnd/AbsynUtil.mo index a21888437d3..a0489ffa22b 100644 --- a/OMCompiler/Compiler/FrontEnd/AbsynUtil.mo +++ b/OMCompiler/Compiler/FrontEnd/AbsynUtil.mo @@ -6608,5 +6608,37 @@ algorithm end match; end setClassDefType; +function isLiteralExp + input Absyn.Exp exp; + output Boolean literal; +algorithm + literal := match exp + case Absyn.Exp.INTEGER() then true; + case Absyn.Exp.REAL() then true; + case Absyn.Exp.STRING() then true; + case Absyn.Exp.BOOL() then true; + case Absyn.Exp.ARRAY() then List.all(exp.arrayExp, isLiteralExp); + + case Absyn.Exp.MATRIX() + algorithm + literal := true; + for row in exp.matrix loop + literal := literal and List.all(row, isLiteralExp); + if not literal then + break; + end if; + end for; + then + literal; + + case Absyn.Exp.RANGE() + then isLiteralExp(exp.start) and + Util.applyOptionOrDefault(exp.step, isLiteralExp, true) and + isLiteralExp(exp.stop); + + else false; + end match; +end isLiteralExp; + annotation(__OpenModelica_Interface="frontend"); end AbsynUtil; diff --git a/OMCompiler/Compiler/Script/NFApi.mo b/OMCompiler/Compiler/Script/NFApi.mo index 2ba367881fb..60f7113ca04 100644 --- a/OMCompiler/Compiler/Script/NFApi.mo +++ b/OMCompiler/Compiler/Script/NFApi.mo @@ -1793,25 +1793,8 @@ algorithm case (_, SCode.Mod.MOD(binding = SOME(absyn_binding))) algorithm - ErrorExt.setCheckpoint(getInstanceName()); - - try - binding_exp := Inst.instExp(absyn_binding, scope, ANNOTATION_CONTEXT, mod.info); - binding_exp := Typing.typeExp(binding_exp, ANNOTATION_CONTEXT, mod.info); - binding_exp := SimplifyExp.simplify(binding_exp); - json := JSON.addPair(name, Expression.toJSON(binding_exp), json); - else - if failOnError then - fail(); - end if; - - j := JSON.makeNull(); - j := JSON.addPair("$error", JSON.makeString(ErrorExt.printCheckpointMessagesStr()), j); - j := JSON.addPair("value", dumpJSONAbsynExpression(absyn_binding), j); - json := JSON.addPair(name, j, json); - end try; - - ErrorExt.delCheckpoint(getInstanceName()); + j := dumpJSONAnnotationExp(absyn_binding, scope, mod.info, failOnError); + json := JSON.addPair(name, j, json); then (); @@ -1825,6 +1808,61 @@ algorithm end match; end dumpJSONAnnotationSubMod; +function dumpJSONAnnotationExp + input Absyn.Exp absynExp; + input InstNode scope; + input SourceInfo info; + input Boolean failOnError; + output JSON json; +protected + JSON j; +algorithm + json := match absynExp + // For non-literal arrays, dump each element separately to avoid + // invalidating the whole array expression if any element contains invalid + // expressions. + case Absyn.Exp.ARRAY() + guard not AbsynUtil.isLiteralExp(absynExp) + algorithm + json := JSON.emptyArray(listLength(absynExp.arrayExp)); + for e in absynExp.arrayExp loop + j := dumpJSONAnnotationExp2(e, scope, info, failOnError); + json := JSON.addElement(j, json); + end for; + then + json; + + else dumpJSONAnnotationExp2(absynExp, scope, info, failOnError); + end match; +end dumpJSONAnnotationExp; + +function dumpJSONAnnotationExp2 + input Absyn.Exp absynExp; + input InstNode scope; + input SourceInfo info; + input Boolean failOnError; + output JSON json; +protected + Expression exp; +algorithm + ErrorExt.setCheckpoint(getInstanceName()); + try + exp := Inst.instExp(absynExp, scope, ANNOTATION_CONTEXT, info); + exp := Typing.typeExp(exp, ANNOTATION_CONTEXT, info); + exp := SimplifyExp.simplify(exp); + json := Expression.toJSON(exp); + else + if failOnError then + fail(); + end if; + + json := JSON.makeNull(); + json := JSON.addPair("$error", JSON.makeString(ErrorExt.printCheckpointMessagesStr()), json); + json := JSON.addPair("value", dumpJSONAbsynExpression(absynExp), json); + end try; + ErrorExt.delCheckpoint(getInstanceName()); +end dumpJSONAnnotationExp2; + function dumpJSONSourceInfo input SourceInfo info; output JSON json = JSON.makeNull(); diff --git a/doc/instanceAPI/expression.schema.json b/doc/instanceAPI/expression.schema.json index abc49fb261f..6f98bfd310b 100644 --- a/doc/instanceAPI/expression.schema.json +++ b/doc/instanceAPI/expression.schema.json @@ -429,6 +429,20 @@ } }, "required": ["$kind", "name", "arguments"] + }, + { + "description": "An invalid expression", + "type": "object", + "properties": { + "$error": { + "description": "Error message", + "type": "string" + }, + "value": { + "description": "The invalid expression", + "$ref": "#" + } + } } ], "definitions": { diff --git a/doc/instanceAPI/getModelInstance.schema.json b/doc/instanceAPI/getModelInstance.schema.json index d61d17a4ccb..59f122e7330 100644 --- a/doc/instanceAPI/getModelInstance.schema.json +++ b/doc/instanceAPI/getModelInstance.schema.json @@ -132,20 +132,6 @@ }, { "$ref": "expression.schema.json" - }, - { - "description": "An invalid annotation", - "type": "object", - "properties": { - "$error": { - "description": "Error message", - "type": "string" - }, - "value": { - "description": "Annotation dumped as a string", - "type": "string" - } - } } ] } diff --git a/testsuite/openmodelica/instance-API/GetModelInstanceAnnotation12.mos b/testsuite/openmodelica/instance-API/GetModelInstanceAnnotation12.mos new file mode 100644 index 00000000000..e18e0128c8c --- /dev/null +++ b/testsuite/openmodelica/instance-API/GetModelInstanceAnnotation12.mos @@ -0,0 +1,115 @@ +// name: GetModelInstanceAnnotation12 +// keywords: +// status: correct +// cflags: -d=newInst +// +// + +loadString(" + model M + annotation(Icon(graphics = {Rectangle(extent = {{1, 1}, {2, x}}), Text(textString = \"str\")})); + end M; +"); + +getModelInstance(M, prettyPrint=true); +getErrorString(); + +// Result: +// true +// "{ +// \"name\": \"M\", +// \"restriction\": \"model\", +// \"annotation\": { +// \"Icon\": { +// \"graphics\": [ +// { +// \"$error\": \"[:3:21-3:96:writable] Error: Variable x not found in scope M.\\n\", +// \"value\": { +// \"$kind\": \"call\", +// \"name\": \"Rectangle\", +// \"namedArgs\": { +// \"extent\": [ +// [ +// 1, +// 1 +// ], +// [ +// 2, +// \"x\" +// ] +// ] +// } +// } +// }, +// { +// \"$kind\": \"record\", +// \"name\": \"Text\", +// \"elements\": [ +// true, +// [ +// 0, +// 0 +// ], +// 0, +// [ +// 0, +// 0, +// 0 +// ], +// [ +// 0, +// 0, +// 0 +// ], +// { +// \"$kind\": \"enum\", +// \"name\": \"LinePattern.Solid\", +// \"index\": 2 +// }, +// { +// \"$kind\": \"enum\", +// \"name\": \"FillPattern.None\", +// \"index\": 1 +// }, +// 0.25, +// [ +// [ +// -10, +// -10 +// ], +// [ +// 10, +// 10 +// ] +// ], +// \"str\", +// 0, +// [ +// -1, +// -1, +// -1 +// ], +// \"\", +// [ +// +// ], +// { +// \"$kind\": \"enum\", +// \"name\": \"TextAlignment.Center\", +// \"index\": 2 +// } +// ] +// } +// ] +// } +// }, +// \"source\": { +// \"filename\": \"\", +// \"lineStart\": 2, +// \"columnStart\": 3, +// \"lineEnd\": 4, +// \"columnEnd\": 8 +// } +// }" +// "" +// endResult diff --git a/testsuite/openmodelica/instance-API/Makefile b/testsuite/openmodelica/instance-API/Makefile index 5008bcbb5c7..71707de05d5 100644 --- a/testsuite/openmodelica/instance-API/Makefile +++ b/testsuite/openmodelica/instance-API/Makefile @@ -13,6 +13,7 @@ GetModelInstanceAnnotation8.mos \ GetModelInstanceAnnotation9.mos \ GetModelInstanceAnnotation10.mos \ GetModelInstanceAnnotation11.mos \ +GetModelInstanceAnnotation12.mos \ GetModelInstanceAttributes1.mos \ GetModelInstanceAttributes2.mos \ GetModelInstanceBinding1.mos \