Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,8 @@ public void testReflectiveAccess() throws Exception {
assertTrue(evaluateBooleanValue(instance, null, "(P meta SysML::PartDefinition).isAbstract"));
assertEquals("x", evaluateStringValue(instance, null, "(P meta SysML::PartDefinition).ownedAttribute.name"));
assertEquals("PartDefinition", evaluateStringValue(instance, null, "(SysML::PartDefinition meta KerML::Element).name"));

assertEquals("public", evaluateSingleValue(instance, null, "(P meta SysML::PartDefinition).owningMembership.visibility").getName());
}

@Test
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ public EList<Element> evaluateFeature(Feature feature, Type type) {
Type t = types.get(i);
if (t instanceof MetadataFeature && TypeUtil.specializes(feature, EvaluationUtil.getAnnotatedElementFeature((MetadataFeature)t))) {
// Evaluate "Metaobject::annotatedElement" feature.
return EvaluationUtil.results(((MetadataFeature)t).getAnnotatedElement());
return EvaluationUtil.results(feature, ((MetadataFeature)t).getAnnotatedElement());
} else if (EvaluationUtil.isMetaclassFeature(t)) {
if (!(feature instanceof Expression)) {
// Evaluate the feature as a reflective metaclass attribute.
Element element = ((AnnotatingElement)t).getAnnotatedElement().get(0);
EStructuralFeature eFeature = element.eClass().getEStructuralFeature(feature.getDeclaredName());
if (eFeature != null) {
return EvaluationUtil.results(element.eGet(eFeature, true));
return EvaluationUtil.results(feature, element.eGet(eFeature, true));
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Copy link
Copy Markdown
Contributor

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:

	// At least
		switch (object) {
		case Boolean b -> literalBoolean(b);
		case String s -> literalString(s);
		case Integer i -> literalInteger(i);
		case Double d -> literalRational(d);
		case Element el -> ElementUtil.getMetaclassFeatureFor(el);
		default -> enumUsage(context, object);
		}
		//Maybe better
		switch (object) {
		case Boolean b -> literalBoolean(b);
		case String s -> literalString(s);
		case Integer i -> literalInteger(i);
		case Double d -> literalRational(d);
		case Element el -> ElementUtil.getMetaclassFeatureFor(el);
		case Enum<?> enumeration -> enumUsage(context, object);
		default -> throw new IllegalArgumentException("Unexpected expression value: " + object);
		}

Copy link
Copy Markdown
Member Author

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.

@adaussy adaussy Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Member Author

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 elementFor will 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.

}

public static LiteralBoolean literalBoolean(boolean value) {
Expand Down Expand Up @@ -193,6 +193,22 @@ public static LiteralInfinity literalInfinity() {
return SysMLFactory.eINSTANCE.createLiteralInfinity();
}

public static Feature enumUsage(Element context, Object object) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

@seidewitz seidewitz Oct 20, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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:

  1. Install the latest public release of the Jupyter deployment from the URL below (follow the README).
    https://github.com/Systems-Modeling/SysML-v2-Release/tree/master/install/jupyter
  2. Install the latest development version of the Jupyter kernel from org.omg.sysml.jupyter.kernel. There is another README, but the basic steps are as follows.
    org.omg.sysml.jupyter.kernel % jupyter kernelSpec remove sysml
    org.omg.sysml.jupyter.kernel % ./installKernel.sh
    
    (for Windows, run installKernel.bat)
  3. Run jupyter lab.

Alternately, org.omg.sysml.interactive.SysMLInteractive, if executed directly, has a simple "Jupyter-like" REPL for testing and debuging. There is a launcher for this in org.omg.sysml.interactive, so it can be run from inside the Eclipse workbench.

1> package P { attribute x; }
Package P (0c550358-243d-4cf0-9c94-84e27af5a6cf)
2> %eval (P meta SysML::Package).ownedMembership.visibility
Feature public (7b966ee0-066c-550b-9684-89243d16c6b1)
3> 

Note that quotes are required around this expression argument to %eval in the Jupyter magic command syntax, but not when using the SysMLInteractive REPL directly.

if (object != null) {
Class<?> class_ = object.getClass();
if (class_ != null) {
String name = class_.getSimpleName() + "::" + object;
Type type = SysMLLibraryUtil.getLibraryType(context,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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 getLibraryType would still be necessary, since the actual Java object varies each time the library is loaded and parsed. But such a cache does not seem necessary for performance, since the method getLibraryType has proven to be pretty fast (at least the Xtext version).

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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));
}
Expand Down
Binary file not shown.
Loading