Skip to content

Commit ec39d4c

Browse files
pcdavidAxelRICHARD
authored andcommitted
[doc] Add shape for improved expressions support
Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
1 parent 1de0e9a commit ec39d4c

4 files changed

Lines changed: 194 additions & 0 deletions

File tree

CHANGELOG.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
=== Shapes
66

7+
- link:./doc/shapes/2026.05/expressions.adoc[Handle expressions in SysON]
8+
79
=== Breaking changes
810

911
- SysON now requires **Java 21** or later.

doc/shapes/2026.6.1/customize_elasticsearch_index_to_work_with_sysml.adoc renamed to doc/shapes/2026.01/customize_elasticsearch_index_to_work_with_sysml.adoc

File renamed without changes.
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
:author: Pierre-Charles David <pierre-charles.david@obeo.fr>
2+
:date: 2026-04-01
3+
:status: proposed
4+
:consulted: Axel Richard <axel.richard@obeo.fr>
5+
:informed: Axel Richard <axel.richard@obeo.fr>
6+
:deciders: Axel Richard <axel.richard@obeo.fr>
7+
:issue: https://github.com/eclipse-syson/syson/issues/2097
8+
9+
= (M) Handle expressions in SysON
10+
11+
== Problem
12+
13+
The SysMLv2 language supports rich _expressions_ that can be used in several places in a model.
14+
The expression sublanguage itself is defined in section 7.4.9 of the KerML specification.
15+
16+
Expressions can appear in several places (non exhaustive list): succession, transition, attribute values, constraints, assumptions, etc.
17+
18+
For example to specify the constraints of a `requirement`:
19+
20+
[source]
21+
----
22+
requirement def MaximumMass {
23+
attribute massActual : Real;
24+
attribute massRequired : Real;
25+
assume constraint { massRequired > 0 } // 'massRequired > 0' is an Expression
26+
require constraint { massActual <= massRequired } // so is 'massActual <= massRequired'
27+
}
28+
----
29+
30+
Currently SysON has poor support for these:
31+
32+
- the only way to _create_ them is indirectly through the _New object from text_ feature by creating a whole element like `RequirementDefinition` with an `assume constraint` as above or when specifying a `FeatureValue` through direct edit (e.g. `fuelLevel : Real = 42`) on a diagram;
33+
- once created, the expressions are not visible or editable from the corresponding element's _Details_ view (except for `FeatureValue`, where the text representation of the expression is visible, but not editable, on the _Details_ view);
34+
- in the _Explorer_ view expressions are exposed as their raw AST, which make them unsuable by end-users.
35+
36+
== Key Result
37+
38+
Users should be able to _create_, _view_, _edit_ and _remove_ expressions everywhere they can occur inside a model through their natural textual syntax (as defined in KerML §7.4.9).
39+
40+
When a user creates or edits the textual representation of an expression, if the user-specified text is invalid (i.e. it does not parse and/or resolve without errors), the invalid text should neither result in an invalid model nor be lost.
41+
42+
Instead the end-user should be clearly notified that the text is invalid and be given the possibility to edit it until it can be interpreted/parsed as a valid expression.
43+
44+
== Solution
45+
46+
Event though (valid) expressions are stored as modeled ASTs, the natural way for end-users to interact with expressions is through their textual representations (e.g. `totalMass == sum(partMasses)`), so we will make sure that:
47+
48+
* by default expressions are displayed using this representation;
49+
* editing expressions is also done by modifying the text representation.
50+
51+
=== Two approaches to handling invalid expressions
52+
53+
There are two possible approaches for dealing with invalid expressions:
54+
55+
1. **Validate expressions at edit time**: use a dedicated editing UI that validates the expression before accepting it.
56+
Malformed or invalid expressions are _never_ stored in the model.
57+
If the user dismisses the editing UI without having applied a valid expression, the text they entered is lost.
58+
59+
2. **Allow invalid expressions to be stored**: let the user enter invalid expressions, but clearly indicate their status in the UI.
60+
The invalid raw text is stored separately (see <<storing-raw-text>>) to allow the user to correct it at their convenience.
61+
62+
Both options are technically possible.
63+
For the moment, the first one is preferred (validating expressions at edit time), as it ensures the actual SysML model is always kept in a valid state, and it avoids the whole discussion of where and how to store the temporarily invalid user text.
64+
65+
Whichever option is finally chosen, it is crucial to inform the user at all times of the impact of their actions:
66+
67+
* Validating an empty expression results in the *deletion* of the expression.
68+
* If the user closes the editing modal without having "applied" a valid expression, their text is lost.
69+
70+
=== Expression editing UI
71+
72+
Different options have been dicussed in terms of UI to allow users to edit the textual representation of expressions:
73+
74+
1. We could leverage the existing "direct edit" support, at least in the _Explorer_ view and on _diagrams_.
75+
However the UX/workflow of simple direct-edit is too limited and does not fit the requirement above to allow for validation before actually applying a change and keep the user informed about the (in)validity of the text entered.
76+
77+
2. We discussed combining multiple existing widgets inside the _Details_ view, i.e. a group with a `Textfield` for the text itself, label(s) to indicate the validation status, and buttons to _Validate_, _Apply_ and _Clear/Delete_.
78+
However the behavior of the existing `Textfield` widget would not fit the intended workflow, as it will try send it's current text to the backend as soon as it loses focus.
79+
If a user enters some invalid text and then clicks on _Validate_, the `Textfield` would send the invalid text to the backend first, which would reject it, and then re-render the textfield using the previous value in the model.
80+
The handler for the _Validate_ button would never see the invalid text as it only existed temporarily inside the frontend.
81+
82+
3. We could create a custom widget to implement the workflow we want combining raw MUI components to work around the limitations mentioned above.
83+
This would work but requires significant developement effort.
84+
Creating suchg a rich and generic/configurable "source edition widget" could be useful for other cases, and might happen later, but given the appetite for this pitch, this option was rejected for now.
85+
86+
4. We could create a custom UI inside a modal dialog.
87+
It would be very similar to the existing _New object as text_ dialog, but only supporting _expressions_ and following a slighlity different workflow.
88+
Instead of a button to _Create object_ which returns a diagnostic/error report _after the fact_, we would have:
89+
** A text area for the user to edit the expression's text
90+
** A feedback area to show the current status of the expression: _valid_, _invalid_ (with details if possible), _unknown_ (if the user has modified the text since the last validation)
91+
** A _Validate_ button, which will send the current text to the backend for _validation_ only.
92+
It will not actally edit the model/update the expression.
93+
The backend will return a diagnstic, at the very least a valid/invalid status, and if possible details about validation errors.
94+
** An _Apply_ button, which will only be enabled if the current text is valid (i.e. it has been validated and not modified afterwards).
95+
** A _Clear_ or _Delete_ button to actually delete the expression from the model.
96+
Note that setting the expression's text to an empty (or whitespace only) text and applying it will _delete_ the expression from the model.
97+
** A _Cancel_ button to dismiss the modal without any change to the model.
98+
99+
**Decision**: we will implement the custom modal (to be detailed in a coming ADR).
100+
101+
Note that there is a possibility to later update the existing _New object as text_ to use the same dialog/UI, but this is out of scope for this iteration.
102+
103+
It might also be possible later on to convert this custom UI into a more generic and configurable custom widget that could be upstreamed in Sirius Web and used in _Form_ representations.
104+
In this case, the modal(s) in SysON would need to evolve to actually display a _Form_ using this widget, properly configured.
105+
This is not planned at the moment.
106+
107+
=== Behavior per view
108+
109+
==== Explorer view
110+
111+
Nodes representing an `Expression` will display the full serialized textual representation of the expression.
112+
This will match what is already shown on diagrams for e.g. `assume constraint` list items.
113+
114+
Direct edit will be disabled on expressions items in the Explorer.
115+
As mentioned above, the direct edit workflow does not fit the constraing for ensuring expressions validity.
116+
This requires an evolution in Sirius Web to distinguish "editable" from "label-editable" (there may be an existing ticket for this).
117+
118+
Instead, a *custom actions* in these node's context menu will open the dedicated expression editing UI (described above).
119+
The following actions available:
120+
121+
* **Edit Expression**: available on both the expression element itself and on its parent element (when the expression inside exists).
122+
Opens the dedicated expression editing UI.
123+
* **New Expression**: available on elements which can contain an expression if no such expression exists; creates a new expression and immediately opens the editing UI.
124+
* **Delete Expression**: available on both the expression element and on its parent element (when the expression inside exists).
125+
Removes the expression.
126+
127+
As a bonus, an *explorer filter* might be provided to hide the sub-elements corresponding to the AST details.
128+
129+
==== Details view
130+
131+
A dedicated *"Expression value"* group will be added to the Details view, with the following behavior:
132+
133+
* It displays the textual representation of the expression, generalizing what is already supported for `FeatureValue` (see `SysMLv2PropertiesConfigurer.createFeatureValuePropertiesGroup()`) to all elements which can contain an `Expression`.
134+
The representation is displayed more prominently than currently.
135+
* In addition to the text field itself (which is *not directly editable*), the group provides:
136+
** an *"Edit"* button that opens the dedicated expression editing modal;
137+
** a *"Clear/Delete"* button (with confirmation) to remove the expression.
138+
* The group is visible on both an `Expression` element *and* on its parent element.
139+
* On the parent element, the group is visible even if no expression exists yet.
140+
In that case, the "Edit" button is labeled *"Create & Edit"* and creates the expression upon activation.
141+
142+
==== Diagrams
143+
144+
* For *`FeatureValue`* elements, direct edit support is retained, but the `= ...` portion is removed from the `initialEditText` and from the grammar; setting the value through normal direct edit is no longer supported.
145+
Instead, new palette action(s) are provided to create, edit, and delete an expression.
146+
Multiple actions may be available depending on context (e.g. `FeatureValue` on an attribute vs. other contexts).
147+
* For elements that are "raw" expressions (e.g. `assume constraint`), there is no direct edit.
148+
Only an *"Edit expression"* action is available, which opens the dedicated editing UI.
149+
* *Keyboard shortcuts* (e.g. `Ctrl+E`) can be used to invoke the expression editing UI.
150+
151+
[[storing-raw-text]]
152+
=== Storing raw user-supplied text for invalid expressions
153+
154+
If we decided to take the approach allow invalid expressions to be stored in the model, we need a way to persist the user-supplied text for an expression even if it is currently invalid.
155+
156+
For example if a user enters `totalMass == sum(partMasses` for a constraint (missing closing paren), we can not parse this as a valid model, so instead of creating "garbage" in the model, we will store the raw string `"totalMass == sum(partMasses"`, tell the user about the problem and allow him to edit the string into a valid one.
157+
158+
Two possible options (there might be more) for storing this raw text:
159+
160+
* Use EMF `EAnnotations`, as in SysON, to root type `Element` is also an `ecore.EModelElement`. For example:
161+
[source,java]
162+
----
163+
String userSuppliedText = "...";
164+
EAnnotation rawExpressionText = EcoreFactory.eINSTANCE.createEAnnotation();
165+
rawExpressionText.setSource("syson");
166+
rawExpressionText.getDetails().put("user-input:expression", userSuppliedText);
167+
element.getEAnnotations().add(rawExpressionText);
168+
----
169+
The issue with this option is that EMF `EAnnotations` rely on EMF `EMap` and it is not clear that Sirius EMF JSON supports these correctly.
170+
171+
* Leverage SysML's notion of _textual representation_ (see § 7.4.3 of the SysML specification) with a custom language (e.g. `"syson:user-input:expression"`) to keep syntacticaly invalid user-supplied text until it is fixed and can be parsed.
172+
This has the benefit over the other option (`EAnnotation`) to only use standard EMF mechanisms, but it is not clear if this is using the SysML _textual representation_ as intended or abusing it, and if it would cause interoperability issues with other SysML tools.
173+
174+
=== Breadboarding
175+
176+
Mockup of the edit expression modal:
177+
178+
image:images/edit-expression-modal.png[]
179+
180+
=== Cutting backs
181+
182+
- Fine-grained error reporting on syntax or semantic errors in invalid textual representation of the expressions.
183+
184+
== Rabbit holes
185+
186+
- The current Sirius Web text widget may not be powerful enough to give end-user precise feedback in case of invalid expressions.
187+
It is possible to associate diagnostics to a textfield/textarea widget, but https://github.com/eclipse-sirius/sirius-web/issues/4413[only the first one is actually displayed] and only as an unstructured text.
188+
It is not possible for example to highlight the position of specific syntax errors like one would expect in a "smart" editor.
189+
190+
== No-gos
191+
192+
- When the user edits an expression as text, once the expression has been correctly parsed as a valid model, we will no try to retain any original formatting (e.g. whitespace).
79.9 KB
Loading

0 commit comments

Comments
 (0)