Skip to content

Commit a83e872

Browse files
committed
ST6RI-886 Implemented model-level eval of equality ops on collections.
1 parent d3c89be commit a83e872

7 files changed

Lines changed: 74 additions & 23 deletions

File tree

org.omg.sysml.interactive.tests/src/org/omg/sysml/interactive/tests/ExpressionEvaluationTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
33
* Copyright (c) 2022 Mgnite, Inc.
4-
* Copyright (c) 2022, 2023 Model Driven Solutions, Inc.
4+
* Copyright (c) 2022, 2023, 2025-2026 Model Driven Solutions, Inc.
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU Lesser General Public License as published by
@@ -458,6 +458,7 @@ public void testSequenceFunctionEvaluation() throws Exception {
458458
+ " attribute collection5 = new OrderedCollection(elements = 5);\n"
459459
+ " attribute collection15 = new OrderedCollection(elements = (1, 5));\n"
460460
+ " attribute collection123 = new OrderedCollection(elements = (1, 2, 3));\n"
461+
+ " attribute collection123a = new OrderedCollection(elements = (1, 2, 3));\n"
461462
+ " attribute collection321 = new OrderedCollection(elements = (3, 2, 1));\n"
462463
+ "}";
463464

@@ -484,10 +485,13 @@ public void testCollectionFunctionEvaluation() throws Exception {
484485
assertElement("LiteralBoolean true", instance.eval("CollectionFunctions::notEmpty(collection1)", "CollectionTest"));
485486
assertElement("LiteralBoolean true", instance.eval("CollectionFunctions::notEmpty(collection123)", "CollectionTest"));
486487

487-
assertElement("LiteralBoolean true", instance.eval("CollectionFunctions::'=='(collection123, collection123)", "CollectionTest"));
488+
assertElement("LiteralBoolean true", instance.eval("CollectionFunctions::'=='(collection123, collection123a)", "CollectionTest"));
488489
assertElement("LiteralBoolean false", instance.eval("CollectionFunctions::'=='(collection123, collection321)", "CollectionTest"));
489490
assertElement("LiteralBoolean false", instance.eval("CollectionFunctions::'=='(collection123, collection15)", "CollectionTest"));
490491

492+
assertElement("LiteralInteger 2", instance.eval("CollectionFunctions::'#'(collection123, 2)", "CollectionTest"));
493+
assertList(new String[]{}, instance.eval("CollectionFunctions::'#'(collection123, 4)", "CollectionTest"));
494+
491495
assertList(new String[]{"LiteralInteger 1"}, instance.eval("CollectionFunctions::head(collection123)", "CollectionTest"));
492496
assertList(new String[]{}, instance.eval("CollectionFunctions::head(empty)", "CollectionTest"));
493497
assertList(new String[]{"LiteralInteger 2", "LiteralInteger 3"}, instance.eval("CollectionFunctions::tail(collection123)", "CollectionTest"));

org.omg.sysml.interactive.tests/src/org/omg/sysml/interactive/tests/ModelLevelEvaluationTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2021-2022, 2025 Model Driven Solutions, Inc.
3+
* Copyright (c) 2021-2022, 2025-2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -302,6 +302,10 @@ public void testListEvaluation() throws Exception {
302302
assertArrayEquals(new Object[] {1, 2, 3}, evaluateListValue(null, null, "1..3"));
303303
assertArrayEquals(new Object[] {-1, 0, 1, 2}, evaluateListValue(null, null, "-1..2"));
304304
assertArrayEquals(new Object[] {}, evaluateListValue(null, null, "5..3"));
305+
306+
assertEquals(2, evaluateIntegerValue(null, null, "(1, 2, 3)#(2)"));
307+
assertArrayEquals(new Object[] {}, evaluateListValue(null, null, "(1, 2, 3)#(4)"));
308+
305309
// assertEquals(3, evaluateIntegerValue(null, null, "SequenceFunctions::size((1, 2, 3))"));
306310
// assertEquals(true, evaluateBooleanValue(null, null, "SequenceFunctions::includes((1, 2, 3), 1)"));
307311
// assertEquals(false, evaluateBooleanValue(null, null, "SequenceFunctions::includes((1, 2, 3), 5)"));
@@ -315,6 +319,24 @@ public void testListEvaluation() throws Exception {
315319
// assertEquals(true, evaluateBooleanValue(null, null, "SequenceFunctions::notEmpty((1,2,3))"));
316320
}
317321

322+
@Test
323+
public void testCollectionEvaluation() throws Exception {
324+
SysMLInteractive instance = getSysMLInteractiveInstance();
325+
process(instance,
326+
"attribute collection15 = new Collections::OrderedCollection(elements = (1, 5));\n"
327+
+ "attribute collection123 = new Collections::OrderedCollection(elements = (1, 2, 3));\n"
328+
+ "attribute collection123a = new Collections::OrderedCollection(elements = (1, 2, 3));\n"
329+
+ "attribute collection321 = new Collections::OrderedCollection(elements = (3, 2, 1));");
330+
assertEquals(true, evaluateBooleanValue(instance, null, "collection123 == collection123a"));
331+
assertEquals(false, evaluateBooleanValue(instance, null, "collection123 == collection321"));
332+
assertEquals(false, evaluateBooleanValue(instance, null, "collection123 == collection15"));
333+
assertEquals(false, evaluateBooleanValue(instance, null, "collection123 != collection123a"));
334+
assertEquals(true, evaluateBooleanValue(instance, null, "collection123 != collection321"));
335+
assertEquals(true, evaluateBooleanValue(instance, null, "collection123 != collection15"));
336+
assertEquals(2, evaluateIntegerValue(instance, null, "collection123#(2)"));
337+
assertArrayEquals(new Object[] {}, evaluateListValue(instance, null, "collection123#(4)"));
338+
}
339+
318340
// Note: These collect and select expressions are currently not model-level evaluable, because the feature references
319341
// to parameters of the body expressions are considered non-model-level evaluable (currently per the specification).
320342
// @Test

org.omg.sysml/src/org/omg/sysml/expressions/functions/base/EqualsFunction.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2021 Model Driven Solutions, Inc.
3+
* Copyright (c) 2021, 2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -24,8 +24,12 @@
2424
import org.eclipse.emf.common.util.EList;
2525
import org.omg.sysml.expressions.ModelLevelExpressionEvaluator;
2626
import org.omg.sysml.lang.sysml.Element;
27+
import org.omg.sysml.lang.sysml.Feature;
2728
import org.omg.sysml.lang.sysml.InvocationExpression;
29+
import org.omg.sysml.lang.sysml.Type;
2830
import org.omg.sysml.util.EvaluationUtil;
31+
import org.omg.sysml.util.ExpressionUtil;
32+
import org.omg.sysml.util.TypeUtil;
2933

3034
public class EqualsFunction extends BaseFunction {
3135

@@ -34,13 +38,27 @@ public String getOperatorName() {
3438
return "'=='";
3539
}
3640

41+
protected boolean isCollection(InvocationExpression invocation, EList<Element> values) {
42+
Type collectionType = ExpressionUtil.getCollectionDataType(invocation);
43+
return values != null && values.size() == 1 && values.get(0) instanceof Type &&
44+
TypeUtil.specializes((Type)values.get(0), collectionType);
45+
}
46+
47+
protected boolean compare(EList<Element> x, EList<Element> y) {
48+
// Note: This allows comparison of arbitrary lists, even though the '==' function args have multiplicity 0..1.
49+
return EvaluationUtil.equal(x, y);
50+
}
51+
3752
@Override
3853
public EList<Element> invoke(InvocationExpression invocation, Element target, ModelLevelExpressionEvaluator evaluator) {
3954
EList<Element> x = evaluator.evaluateArgument(invocation, 0, target);
4055
EList<Element> y = evaluator.evaluateArgument(invocation, 1, target);
41-
return x == null || y == null? EvaluationUtil.singletonList(invocation):
42-
// Note: This allows comparison of arbitrary lists, even though the '==' function args have multiplicity 0..1.
43-
EvaluationUtil.booleanResult(EvaluationUtil.equal(x, y));
56+
if (isCollection(invocation, x) && isCollection(invocation, y)) {
57+
x = EvaluationUtil.getElementsOf((Feature)x.get(0));
58+
y = EvaluationUtil.getElementsOf((Feature)y.get(0));
59+
}
60+
return x == null || y == null? EvaluationUtil.singletonList(invocation):
61+
EvaluationUtil.booleanResult(compare(x, y));
4462
}
4563

4664
}

org.omg.sysml/src/org/omg/sysml/expressions/functions/base/IndexFunction.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2021, 2023 Model Driven Solutions, Inc.
3+
* Copyright (c) 2021, 2023, 2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -86,10 +86,7 @@ protected boolean isOrderedCollection(InvocationExpression invocation, EList<Ele
8686
}
8787

8888
protected EList<Element> indexCollection(InvocationExpression invocation, Feature collection, int index, ModelLevelExpressionEvaluator evaluator) {
89-
List<Feature> elementsChain = new ArrayList<>();
90-
elementsChain.add(collection);
91-
elementsChain.add(ExpressionUtil.getCollectionElementsFeature(collection));
92-
EList<Element> elements = evaluator.evaluateFeatureChain(elementsChain, collection);
89+
EList<Element> elements = EvaluationUtil.getElementsOf(collection);
9390
return elements == null? EvaluationUtil.singletonList(invocation):
9491
indexSequence(elements, index);
9592
}

org.omg.sysml/src/org/omg/sysml/expressions/functions/base/NotEqualsFunction.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2021 Model Driven Solutions, Inc.
3+
* Copyright (c) 2021, 2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -22,24 +22,21 @@
2222
package org.omg.sysml.expressions.functions.base;
2323

2424
import org.eclipse.emf.common.util.EList;
25-
import org.omg.sysml.expressions.ModelLevelExpressionEvaluator;
2625
import org.omg.sysml.lang.sysml.Element;
27-
import org.omg.sysml.lang.sysml.InvocationExpression;
2826
import org.omg.sysml.util.EvaluationUtil;
2927

30-
public class NotEqualsFunction extends BaseFunction {
28+
public class NotEqualsFunction extends EqualsFunction {
3129

3230
@Override
3331
public String getOperatorName() {
3432
return "'!='";
3533
}
3634

3735
@Override
38-
public EList<Element> invoke(InvocationExpression invocation, Element target, ModelLevelExpressionEvaluator evaluator) {
39-
EList<Element> x = evaluator.evaluateArgument(invocation, 0, target);
40-
EList<Element> y = evaluator.evaluateArgument(invocation, 1, target);
41-
Boolean result = x == null || y == null? null: !EvaluationUtil.equal(x, y);
42-
return result == null? EvaluationUtil.singletonList(invocation): EvaluationUtil.booleanResult(result);
36+
protected boolean compare(EList<Element> x, EList<Element> y) {
37+
// Note: This allows comparison of arbitrary lists, even though the !==' function args have multiplicity 0..1.
38+
return !EvaluationUtil.equal(x, y);
4339
}
40+
4441

4542
}

org.omg.sysml/src/org/omg/sysml/util/EvaluationUtil.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2022, 2025 Model Driven Solutions, Inc.
3+
* Copyright (c) 2022, 2025-2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -21,6 +21,7 @@
2121

2222
package org.omg.sysml.util;
2323

24+
import java.util.ArrayList;
2425
import java.util.Collections;
2526
import java.util.List;
2627

@@ -236,6 +237,13 @@ public static boolean equal(List<Element> x, List<Element> y) {
236237
return true;
237238
}
238239
}
240+
241+
public static EList<Element> getElementsOf(Feature collection) {
242+
List<Feature> elementsChain = new ArrayList<>();
243+
elementsChain.add(collection);
244+
elementsChain.add(ExpressionUtil.getCollectionElementsFeature(collection));
245+
return ModelLevelExpressionEvaluator.INSTANCE.evaluateFeatureChain(elementsChain, collection);
246+
}
239247

240248
public static Feature getTargetFeatureFor(Element target) {
241249
if (target instanceof Feature) {

org.omg.sysml/src/org/omg/sysml/util/ExpressionUtil.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*******************************************************************************
22
* SysML 2 Pilot Implementation
3-
* Copyright (c) 2021-2023, 2025 Model Driven Solutions, Inc.
3+
* Copyright (c) 2021-2023, 2025-2026 Model Driven Solutions, Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -51,13 +51,18 @@ public class ExpressionUtil {
5151
private ExpressionUtil() {
5252
}
5353

54+
public static final String COLLECTION_DATA_TYPE = "Collections::Collection";
5455
public static final String ORDERED_COLLECTION_DATA_TYPE = "Collections::OrderedCollection";
5556
public static final String ARRAY_DATA_TYPE = "Collections::Array";
5657

5758
public static final String SELF_REFERENCE_FEATURE = "Base::Anything::self";
5859
public static final String COLLECTION_ELEMENTS_FEATURE = "Collections::Collection::elements";
5960
public static final String ARRAY_DIMENSIONS_FEATURE = "Collections::Array::dimensions";
6061

62+
public static DataType getCollectionDataType(Element context) {
63+
return (DataType)SysMLLibraryUtil.getLibraryType(context, COLLECTION_DATA_TYPE);
64+
}
65+
6166
public static DataType getOrderedCollectionDataType(Element context) {
6267
return (DataType)SysMLLibraryUtil.getLibraryType(context, ORDERED_COLLECTION_DATA_TYPE);
6368
}

0 commit comments

Comments
 (0)