diff --git a/ba/org.osate.ba.edit/icons/full/ctool16/CreateForOrForAllStatement_iteratedValues_IterativeVariableHolder.gif b/ba/org.osate.ba.edit/icons/full/ctool16/CreateForOrForAllStatement_iteratedValues_IterativeVariableHolder.gif new file mode 100644 index 0000000000..95a7dfdefa Binary files /dev/null and b/ba/org.osate.ba.edit/icons/full/ctool16/CreateForOrForAllStatement_iteratedValues_IterativeVariableHolder.gif differ diff --git a/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ForOrForAllStatementItemProvider.java b/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ForOrForAllStatementItemProvider.java index 55e17887ad..ea173ecf92 100644 --- a/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ForOrForAllStatementItemProvider.java +++ b/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ForOrForAllStatementItemProvider.java @@ -194,6 +194,9 @@ protected void collectNewChildDescriptors(Collection newChildDescriptors newChildDescriptors.add(createChildParameter(AadlBaPackage.Literals.FOR_OR_FOR_ALL_STATEMENT__ITERATED_VALUES, AadlBaFactory.eINSTANCE.createIntegerRange())); + newChildDescriptors.add(createChildParameter(AadlBaPackage.Literals.FOR_OR_FOR_ALL_STATEMENT__ITERATED_VALUES, + AadlBaFactory.eINSTANCE.createIterativeVariableHolder())); + newChildDescriptors.add(createChildParameter(AadlBaPackage.Literals.FOR_OR_FOR_ALL_STATEMENT__ITERATED_VALUES, AadlBaFactory.eINSTANCE.createParameterHolder())); diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3226_Issue3226.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3226_Issue3226.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3226_NonIterableValues.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3226_NonIterableValues.txt new file mode 100644 index 0000000000..a22a693855 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3226_NonIterableValues.txt @@ -0,0 +1,2 @@ +error | semantic | 45 | 49 | 1 | '5' cannot be iterated: a for or forall iterates an integer range, an event data port, a parameter, or an array data component reference +error | semantic | 48 | 49 | 7 | 'reading' cannot be iterated: a for or forall iterates an integer range, an event data port, a parameter, or an array data component reference diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3226_Issue3226.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3226_Issue3226.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3226_NonIterableValues.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3226_NonIterableValues.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_Issue3226.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_Issue3226.txt new file mode 100644 index 0000000000..de7585d8af --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_Issue3226.txt @@ -0,0 +1,32 @@ +annex[0] owner=Issue3226::worker.i + (AssignmentAction, , 2971, 21) + (BehaviorActionBlock, , 2844, 202) + (BehaviorAnnex, behavior_specification, 2629, 418) + (BehaviorState, done, 2766, 4) + (BehaviorState, start, 2731, 5) + (BehaviorStateGroup, , 2731, 22) + (BehaviorStateGroup, , 2766, 28) + (BehaviorTransition, , 2827, 220) + (BehaviorVariable, m, 2692, 1) + (BehaviorVariable, total, 2651, 5) + (BehaviorVariableGroup, , 2651, 28) + (BehaviorVariableGroup, , 2692, 11) + (BinaryExpression, , 2980, 12) + (ElementValues, , 2880, 1) + (ElementValues, , 2940, 3) + (ForStatement, , 2862, 170) + (ForStatement, , 2905, 109) + (Reference, , 2880, 1) + (Reference, , 2940, 3) + (Reference, , 2971, 5) + (Reference, , 2980, 4) + (Reference, , 2987, 5) + (ReferenceExpression, , 2880, 1) + (ReferenceExpression, , 2940, 3) + (ReferenceExpression, , 2980, 4) + (ReferenceExpression, , 2987, 5) + (ReferenceSegment, cell, 2980, 4) + (ReferenceSegment, m, 2880, 1) + (ReferenceSegment, row, 2940, 3) + (ReferenceSegment, total, 2971, 5) + (ReferenceSegment, total, 2987, 5) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_NonIterableValues.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_NonIterableValues.txt new file mode 100644 index 0000000000..1933548da7 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3226_NonIterableValues.txt @@ -0,0 +1,31 @@ +annex[0] owner=NonIterableValues::worker.i + (AssignmentAction, , 2662, 10) + (AssignmentAction, , 2771, 10) + (BehaviorActionBlock, , 2587, 226) + (BehaviorActionSequence, , 2605, 194) + (BehaviorAnnex, behavior_specification, 2396, 418) + (BehaviorIntegerLiteral, , 2637, 1) + (BehaviorState, done, 2509, 4) + (BehaviorState, start, 2474, 5) + (BehaviorStateGroup, , 2474, 22) + (BehaviorStateGroup, , 2509, 28) + (BehaviorTransition, , 2570, 244) + (BehaviorVariable, total, 2418, 5) + (BehaviorVariableGroup, , 2418, 28) + (ElementValues, , 2637, 1) + (ElementValues, , 2740, 7) + (ForStatement, , 2605, 85) + (ForStatement, , 2708, 91) + (Reference, , 2662, 5) + (Reference, , 2671, 1) + (Reference, , 2740, 7) + (Reference, , 2771, 5) + (Reference, , 2780, 1) + (ReferenceExpression, , 2671, 1) + (ReferenceExpression, , 2740, 7) + (ReferenceExpression, , 2780, 1) + (ReferenceSegment, i, 2671, 1) + (ReferenceSegment, j, 2780, 1) + (ReferenceSegment, reading, 2740, 7) + (ReferenceSegment, total, 2662, 5) + (ReferenceSegment, total, 2771, 5) diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_Issue3226.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_Issue3226.txt new file mode 100644 index 0000000000..572f090acd --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_Issue3226.txt @@ -0,0 +1,25 @@ +annex[0] owner=Issue3226::worker.i + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + variables[0] : BehaviorVariable name=total + variables[1] : BehaviorVariable name=m + states[0] : BehaviorState name=start + states[1] : BehaviorState name=done + transitions[0] : BehaviorTransition + actions[0] : BehaviorActionBlock + content : ForOrForAllStatement + behaviorActions : ForOrForAllStatement + behaviorActions : AssignmentAction + target : BehaviorVariableHolder element=total [BehaviorVariable] + valueExpression : ValueExpression + relations[0] : Relation + firstExpression : SimpleExpression + terms[0] : Term + factors[0] : Factor + firstValue : IterativeVariableHolder element=cell [IterativeVariable] + terms[1] : Term + factors[0] : Factor + firstValue : BehaviorVariableHolder element=total [BehaviorVariable] + iteratedValues : IterativeVariableHolder element=row [IterativeVariable] + iterativeVariable : IterativeVariable name=cell + iteratedValues : BehaviorVariableHolder element=m [BehaviorVariable] + iterativeVariable : IterativeVariable name=row diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_NonIterableValues.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_NonIterableValues.txt new file mode 100644 index 0000000000..12b7846297 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3226_NonIterableValues.txt @@ -0,0 +1,28 @@ +annex[0] owner=NonIterableValues::worker.i + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + variables[0] : BehaviorVariable name=total + states[0] : BehaviorState name=start + states[1] : BehaviorState name=done + transitions[0] : BehaviorTransition + actions[0] : BehaviorActionBlock + content : BehaviorActionSequence + actions[0] : ForOrForAllStatement + behaviorActions : AssignmentAction + target : BehaviorVariableHolder element=total [BehaviorVariable] + valueExpression : ValueExpression + relations[0] : Relation + firstExpression : SimpleExpression + terms[0] : Term + factors[0] : Factor + firstValue : IterativeVariableHolder element=i [IterativeVariable] + iterativeVariable : IterativeVariable name=i + actions[1] : ForOrForAllStatement + behaviorActions : AssignmentAction + target : BehaviorVariableHolder element=total [BehaviorVariable] + valueExpression : ValueExpression + relations[0] : Relation + firstExpression : SimpleExpression + terms[0] : Term + factors[0] : Factor + firstValue : IterativeVariableHolder element=j [IterativeVariable] + iterativeVariable : IterativeVariable name=j diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_Issue3226.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_Issue3226.txt new file mode 100644 index 0000000000..418421b311 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_Issue3226.txt @@ -0,0 +1,19 @@ +===== annex[0] owner=Issue3226::worker.i ===== + + variables + total : Base_Types::Integer; + m : Matrix; + states + start : initial state; + done : complete final state; + transitions + start -[]-> done { + for (row : Row in m) { + for (cell : Base_Types::Integer in row) { + total := cell + total + } + } + }; +\s\s\s\s +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_NonIterableValues.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_NonIterableValues.txt new file mode 100644 index 0000000000..ff10075ef1 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3226_NonIterableValues.txt @@ -0,0 +1,19 @@ +===== annex[0] owner=NonIterableValues::worker.i ===== + + variables + total : Base_Types::Integer; + states + start : initial state; + done : complete final state; + transitions + start -[]-> done { + for (i : Base_Types::Integer in 5) { + total := i + }; + for (j : Base_Types::Integer in reading) { + total := j + } + }; +\s\s\s\s +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/models/issue3226/.gitignore b/ba/org.osate.ba.tests/models/issue3226/.gitignore new file mode 100644 index 0000000000..afce51184c --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3226/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/ba/org.osate.ba.tests/models/issue3226/.project b/ba/org.osate.ba.tests/models/issue3226/.project new file mode 100644 index 0000000000..2877877879 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3226/.project @@ -0,0 +1,18 @@ + + + issue3226 + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.osate.core.aadlnature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/ba/org.osate.ba.tests/models/issue3226/Issue3226.aadl b/ba/org.osate.ba.tests/models/issue3226/Issue3226.aadl new file mode 100644 index 0000000000..3b8ec7893e --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3226/Issue3226.aadl @@ -0,0 +1,65 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package Issue3226 +public + with Base_Types, Data_Model; + + data Row + properties + Data_Model::Data_Representation => Array; + Data_Model::Base_Type => (classifier (Base_Types::Integer)); + Data_Model::Dimension => (3); + end Row; + + data Matrix + properties + Data_Model::Data_Representation => Array; + Data_Model::Base_Type => (classifier (Row)); + Data_Model::Dimension => (2); + end Matrix; + + thread worker + end worker; + + -- D.6 gives the iterator of a for or forall the name scope of the construct, where it acts as a local variable, so + -- the iterated values of a nested loop can name the iterator of an enclosing one. The inner iterator then takes the + -- element type of the outer one, and 'total := cell + total' adds two integers. + thread implementation worker.i + annex behavior_specification {** + variables + total : Base_Types::Integer; + m : Matrix; + states + start : initial state; + done : complete final state; + transitions + start -[]-> done { + for (row : Row in m) { + for (cell : Base_Types::Integer in row) { + total := cell + total + } + } + }; + **}; + end worker.i; +end Issue3226; diff --git a/ba/org.osate.ba.tests/models/issue3226/NonIterableValues.aadl b/ba/org.osate.ba.tests/models/issue3226/NonIterableValues.aadl new file mode 100644 index 0000000000..8f71533a73 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3226/NonIterableValues.aadl @@ -0,0 +1,54 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package NonIterableValues +public + with Base_Types; + + thread worker + features + reading : in data port Base_Types::Integer; + end worker; + + -- D.6 admits an integer range, an event data port, or an array data component reference as the iterated values of a + -- for or forall. The shared D.7 integer value grammar also accepts an integer literal, and a data port is not one of + -- the names a data component reference can start with, so the strict model has no iterated values to carry either + -- one. Both must be reported rather than translated. + thread implementation worker.i + annex behavior_specification {** + variables + total : Base_Types::Integer; + states + start : initial state; + done : complete final state; + transitions + start -[]-> done { + for (i : Base_Types::Integer in 5) { + total := i + }; + for (j : Base_Types::Integer in reading) { + total := j + } + }; + **}; + end worker.i; +end NonIterableValues; diff --git a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3226Test.java b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3226Test.java new file mode 100644 index 0000000000..218bbbf12e --- /dev/null +++ b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3226Test.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). + * All Rights Reserved. + * + * NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE + * OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT + * MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * SPDX-License-Identifier: EPL-2.0 + * + * Created, in part, with funding and support from the United States Government. (see Acknowledgments file). + * + * This program includes and/or can make use of certain third party source code, object code, documentation and other + * files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system + * configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and + * conditions contained in any such Third Party Software or separate license file distributed with such Third Party + * Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- + * aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- + * censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + */ +package org.osate.ba.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.xtext.diagnostics.Severity; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.validation.Issue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osate.aadl2.AadlPackage; +import org.osate.aadl2.DefaultAnnexSubclause; +import org.osate.aadl2.ThreadImplementation; +import org.osate.ba.aadlba.BehaviorVariableHolder; +import org.osate.ba.aadlba.ForOrForAllStatement; +import org.osate.ba.aadlba.IterativeVariableHolder; +import org.osate.testsupport.TestHelper; +import org.osate.xtext.aadl2.ba.util.BehaviorAnnexUtil; + +import com.google.inject.Inject; +import com.itemis.xtext.testing.XtextTest; + +/** + * AS5506/3 Rev A D.6 gives the iterator of a {@code for} or {@code forall} the name scope of the construct, where it + * acts as a local variable, and admits an array data component reference as the iterated values. A nested loop over an + * array of arrays therefore iterates the iterator of the enclosing loop, and the inner iterator takes the element type + * of the outer one. Verifies that such a loop is accepted and translated, and that the iterated values the strict model + * cannot carry at all are reported instead of throwing out of translation. + */ +@RunWith(XtextRunner.class) +@InjectWith(BehaviorAnnexInjectorProvider.class) +public class Issue3226Test extends XtextTest { + private static final String PATH = "org.osate.ba.tests/models/issue3226/"; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void iteratingAnEnclosingIteratorIsAccepted() throws Exception { + validationHelper.assertNoIssues(testHelper.parseFile(PATH + "Issue3226.aadl")); + } + + /** + * The inner loop must reach the checkers with the outer iterator as its iterated values: an inner loop with no + * iterated values at all would also validate, and would say nothing about what the loop iterates. + */ + @Test + public void theInnerLoopIteratesTheOuterIterator() throws Exception { + var strict = BehaviorAnnexUtil.getStrictModel(defaultAnnex(testHelper.parseFile(PATH + "Issue3226.aadl"))); + var loops = new ArrayList(); + for (var contents = strict.eAllContents(); contents.hasNext();) { + if (contents.next() instanceof ForOrForAllStatement loop) { + loops.add(loop); + } + } + assertEquals(loops.toString(), 2, loops.size()); + var outer = loops.get(0); + var inner = loops.get(1); + assertEquals("row", outer.getIterativeVariable().getName()); + assertEquals("cell", inner.getIterativeVariable().getName()); + assertTrue(String.valueOf(outer.getIteratedValues()), + outer.getIteratedValues() instanceof BehaviorVariableHolder); + assertEquals("m", ((BehaviorVariableHolder) outer.getIteratedValues()).getBehaviorVariable().getName()); + assertTrue(String.valueOf(inner.getIteratedValues()), + inner.getIteratedValues() instanceof IterativeVariableHolder); + assertSame(outer.getIterativeVariable(), + ((IterativeVariableHolder) inner.getIteratedValues()).getIterativeVariable()); + } + + /** + * An integer literal and a data port are the two shapes the shared grammar accepts here and no strict + * {@code ElementValues} can represent, so each must be reported on the values as written. The loops are otherwise + * well formed, which is what makes the two reports the only ones. + */ + @Test + public void valuesThatAreNotIterableAreReported() throws Exception { + var root = testHelper.parseFile(PATH + "NonIterableValues.aadl"); + var source = NodeModelUtils.getNode(root).getRootNode().getText(); + // Xtext does not hand back the issues of one resource in the order the checkers report them. + var issues = validationHelper.validate(root).stream().sorted(Comparator.comparing(Issue::getOffset)).toList(); + assertEquals(issues.toString(), List.of("5", "reading"), issues.stream().map(issue -> { + var written = source.substring(issue.getOffset(), issue.getOffset() + issue.getLength()); + assertEquals(Severity.ERROR, issue.getSeverity()); + assertEquals("'" + written + "' cannot be iterated: a for or forall iterates an integer range, an event" + + " data port, a parameter, or an array data component reference", issue.getMessage()); + return written; + }).toList()); + } + + private static DefaultAnnexSubclause defaultAnnex(AadlPackage pkg) { + var implementation = (ThreadImplementation) pkg.getOwnedPublicSection().getOwnedClassifiers().stream() + .filter(ThreadImplementation.class::isInstance).findFirst().orElseThrow(); + return (DefaultAnnexSubclause) implementation.getOwnedAnnexSubclauses().getFirst(); + } +} diff --git a/ba/org.osate.ba/model/aadlba.ecore b/ba/org.osate.ba/model/aadlba.ecore index 773ae971a4..183b5e8d96 100644 --- a/ba/org.osate.ba/model/aadlba.ecore +++ b/ba/org.osate.ba/model/aadlba.ecore @@ -503,7 +503,7 @@ - +
diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/IterativeVariableHolder.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/IterativeVariableHolder.java index ae674be19c..68dd55cdec 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/IterativeVariableHolder.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/IterativeVariableHolder.java @@ -29,7 +29,7 @@ * @model * @generated */ -public interface IterativeVariableHolder extends DataHolder { +public interface IterativeVariableHolder extends DataHolder, ElementValues { /** * * diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java index 4277e48d0e..1b48779e4f 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java @@ -4028,6 +4028,7 @@ public void initializePackageContents() { integerValueVariableEClass.getESuperTypes().add(getValueVariable()); iterativeVariableEClass.getESuperTypes().add(getBehaviorNamedElement()); iterativeVariableHolderEClass.getESuperTypes().add(getDataHolder()); + iterativeVariableHolderEClass.getESuperTypes().add(getElementValues()); literalEClass.getESuperTypes().add(getValueConstant()); literalEClass.getESuperTypes().add(getIntegerValueConstant()); lockActionEClass.getESuperTypes().add(getSharedDataAction()); diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/util/AadlBaSwitch.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/util/AadlBaSwitch.java index 2c43f22043..d074f6b0fe 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/util/AadlBaSwitch.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/util/AadlBaSwitch.java @@ -1851,6 +1851,9 @@ protected T doSwitch(int classifierID, EObject theEObject) { if (result == null) { result = caseDataHolder(iterativeVariableHolder); } + if (result == null) { + result = caseElementValues(iterativeVariableHolder); + } if (result == null) { result = caseElementHolder(iterativeVariableHolder); } diff --git a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java index 980d2184e4..f63e0e2849 100644 --- a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java +++ b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java @@ -763,7 +763,11 @@ private DataClassifier iteratedElementClassifier(final org.osate.ba.aadlba.ForOr private ElementValues toElementValues(final org.osate.xtext.aadl2.ba.behaviorAnnex.ElementValues values) { if (values.getUpper() == null) { - return (ElementValues) toIntegerValue(values.getLower()); + // D.6 admits an integer range, an event data port, or an array data component reference here, and the + // shared D.7 integer value grammar accepts more than that: an integer literal, a property reference, + // and names that resolve to something no strict ElementValues can carry. Leave those out of the strict + // model, the way the rest of the translator does, and let BehaviorAnnexValidator report them. + return toIntegerValue(values.getLower()) instanceof ElementValues iterated ? iterated : null; } final var result = trace(FACTORY.createIntegerRange(), values); result.setLowerIntegerValue(toIntegerValue(values.getLower())); diff --git a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java index db358f4e78..bc0a7e3551 100644 --- a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java +++ b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java @@ -57,6 +57,7 @@ import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager; import org.osate.aadl2.parsesupport.ParseUtil; import org.osate.annexsupport.ParseResultHolder; +import org.osate.ba.aadlba.ForOrForAllStatement; import org.osate.ba.aadlba.PropertySetPropertyReference; import org.osate.ba.analyzers.AadlBaRulesCheckersDriver; import org.osate.ba.analyzers.AadlBaTypeChecker; @@ -96,6 +97,7 @@ public final class BehaviorAnnexValidator extends AbstractBehaviorAnnexValidator public static final String TIMEOUT_RESET_PORT = "org.osate.xtext.aadl2.ba.timeoutResetPort"; public static final String TIMEOUT_RESET_PORT_TIME = "org.osate.xtext.aadl2.ba.timeoutResetPortTime"; public static final String ITERATIVE_VARIABLE_TARGET = "org.osate.xtext.aadl2.ba.iterativeVariableTarget"; + public static final String ITERATED_VALUES = "org.osate.xtext.aadl2.ba.iteratedValues"; public static final String ITERATOR_CLASSIFIER = "org.osate.xtext.aadl2.ba.iteratorClassifier"; public static final String ARRAY_SIZE = "org.osate.xtext.aadl2.ba.arraySize"; public static final String PROPERTY_REFERENCE_VALUE = "org.osate.xtext.aadl2.ba.propertyReferenceValue"; @@ -135,6 +137,7 @@ public void checkBehaviorAnnex(final BehaviorAnnex source) { representable &= checkInternalConditionPorts(source, translation); representable &= checkTimeoutResetPorts(source, translation); representable &= checkIteratorTargets(source, translation); + representable &= checkIteratedValues(source, translation); checkPortStatusValues(source, translation); // The strict model does carry a property reference that denotes no value, so this one is not a gate: the strict // checkers keep their model and whatever else they have to say about it. @@ -399,6 +402,36 @@ private boolean checkIteratorTargets(final BehaviorAnnex source, final Translati return accepted; } + /** + * The AS5506/3 Rev A D.6 element_values production admits an integer range, an event data port name, or an array + * data component reference, and a data component reference starts with a data subcomponent, a data access feature, + * a local variable, or a data access feature prototype. D.6 gives the iterator of a for or forall the name scope of + * the construct, where it acts as a local variable, so an enclosing iterator is one of those names as well. The + * iterated values share the D.7 integer value grammar with the rest of the annex, which also accepts an integer + * literal, a property reference, and names that denote none of the above, and the strict model has no element values + * to carry any of them: translation drops them, and the loop would otherwise reach the strict checkers iterating + * nothing at all. Report the values as written, since an integer range never fails here and everything else is one + * expression. + * + * @return {@code true} when every loop in the annex iterates values the strict model can carry + */ + private boolean checkIteratedValues(final BehaviorAnnex source, final TranslationResult translation) { + var accepted = true; + for (var contents = source.eAllContents(); contents.hasNext();) { + if (!(contents.next() instanceof ForStatement loop) || loop.getValues() == null + || !(translation.getStrict(loop) instanceof ForOrForAllStatement strict) + || strict.getIteratedValues() != null) { + continue; + } + error("'" + NodeModelUtils.getTokenText(NodeModelUtils.findActualNodeFor(loop.getValues())) + + "' cannot be iterated: a for or forall iterates an integer range, an event data port, a parameter," + + " or an array data component reference", loop.getValues(), null, + ValidationMessageAcceptor.INSIGNIFICANT_INDEX, ITERATED_VALUES); + accepted = false; + } + return accepted; + } + /** The target an action writes, which the assignment action and the dequeue action spell the same way. */ private static Reference writtenTarget(final EObject action) { if (action instanceof AssignmentAction assignment) {