Repository navigation
ST6RI-971 Reflective abstract syntax properties with enumeration values cannot be evaluated #816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,7 +129,7 @@ public static Expression expressionFor(EList<Element> results, Element context) | |
| public static Expression expressionFor(Element result) { | ||
| if (result instanceof LiteralExpression) { | ||
| Object value = valueOf(result); | ||
| return value == null? literalInfinity(): (Expression)elementFor(value); | ||
| return value == null? literalInfinity(): (Expression)elementFor(null, value); | ||
| } else if (result instanceof Feature) { | ||
| FeatureReferenceExpression featureRef = SysMLFactory.eINSTANCE.createFeatureReferenceExpression(); | ||
| NamespaceUtil.addMemberTo(featureRef, result); | ||
|
|
@@ -140,29 +140,29 @@ public static Expression expressionFor(Element result) { | |
|
|
||
| } | ||
|
|
||
| public static EList<Element> results(Object object) { | ||
| public static EList<Element> results(Element context, Object object) { | ||
| EList<Element> results = new BasicEList<>(); | ||
| if (object instanceof List) { | ||
| ((List<?>)object).stream(). | ||
| map(EvaluationUtil::elementFor). | ||
| if (object instanceof List<?> list) { | ||
| list.stream(). | ||
| map(obj->elementFor(context, obj)). | ||
| filter(e->e != null). | ||
| forEachOrdered(results::add); | ||
| } else if (object != null) { | ||
| Element element = elementFor(object); | ||
| if (object != null) { | ||
| Element element = elementFor(context, object); | ||
| if (element != null) { | ||
| results.add(element); | ||
| } | ||
| } | ||
| return results; | ||
| } | ||
|
|
||
| public static Element elementFor(Object object) { | ||
| public static Element elementFor(Element context, Object object) { | ||
| return object instanceof Boolean? literalBoolean((Boolean)object): | ||
| object instanceof String? literalString((String)object): | ||
| object instanceof Integer? literalInteger((Integer)object): | ||
| object instanceof Double? literalRational((Double)object): | ||
| object instanceof Element? ElementUtil.getMetaclassFeatureFor((Element)object): | ||
| null; | ||
| enumUsage(context, object); | ||
| } | ||
|
|
||
| public static LiteralBoolean literalBoolean(boolean value) { | ||
|
|
@@ -193,6 +193,22 @@ public static LiteralInfinity literalInfinity() { | |
| return SysMLFactory.eINSTANCE.createLiteralInfinity(); | ||
| } | ||
|
|
||
| public static Feature enumUsage(Element context, Object object) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is really hard for me to test this part because I don't know yet how to launch an evaluation but I trust it is working.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can install a development version of the Jupyter deployment locally as follows:
Alternately, Note that quotes are required around this expression argument to |
||
| if (object != null) { | ||
| Class<?> class_ = object.getClass(); | ||
| if (class_ != null) { | ||
| String name = class_.getSimpleName() + "::" + object; | ||
| Type type = SysMLLibraryUtil.getLibraryType(context, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it is acceptable for now but should not we have an exhaustive list of enumeration available in the core librairies in order to have a direct mapping between java instances and Kerml elements ?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean a list of enumeration definitions kept in memory? If so, that would basically be caching what is computed here. Calling Further, we could pre-initialize with the current "exhaustive list" of enumeration types in the abstract syntax, but this list would change if a new enumeration was added to the abstract syntax in a future language revision, which could be easily missed in maintenance. It is better to do the look up what is actually in the library.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That works for me. My main point was to have an explicit mapping between Java objects and their counterparts in the library. I tend to find naming conventions a bit less robust, but I'm fine with this approach as well.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, the Java enum and the reflective KerML/SysML enumerations are ultimately generated from the same source: the normative UML/MOF abstract syntax model. Unless there has been a release development error, the names have to correspond. |
||
| "KerML::Root::" + name, "KerML::Core::" + name, "KerML::Kernel::" + name, | ||
| "SysML::Systems::" + name); | ||
| if (type instanceof Feature feature) { | ||
| return feature; | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| public static EList<Element> booleanResult(boolean value) { | ||
| return singletonList(literalBoolean(value)); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is usually bad practice to nest some many ternary expression.
I would propose:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the change you propose necessary to make for this PR. In any case, I think I prefer the old school ternary expressions.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you wish, but my point was that the second version explicitly distinguishes between case Enum<?> and the default case, allowing us to detect invalid objects early.
With this implementation (which could also be written using a ternary operator), you can be sure that enumUsage is only called with an actual enum value. I did not test that code and it is just a suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point, but I would prefer not to use an exception here, since that has not been the convention elsewhere. The change as coded means that
elementForwill still return null if it does not recognize the input object, as it did before. This is a more conservative change that seems sufficient for the current implementation.