AadlBaNameResolver.java
/**
* AADL-BA-FrontEnd
*
* Copyright (c) 2011-2021 TELECOM ParisTech and CNRS
*
* TELECOM ParisTech/LTCI
*
* Authors: see AUTHORS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Eclipse Public License as published by Eclipse,
* either version 2.0 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Eclipse Public License for more details.
* You should have received a copy of the Eclipse Public License
* along with this program. If not, see
* https://www.eclipse.org/legal/epl-2.0/
*/
package org.osate.ba.analyzers;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.osate.aadl2.Aadl2Factory;
import org.osate.aadl2.Aadl2Package;
import org.osate.aadl2.ArrayDimension;
import org.osate.aadl2.BasicProperty;
import org.osate.aadl2.BasicPropertyAssociation;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.ClassifierFeature;
import org.osate.aadl2.ClassifierValue;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.ContainmentPathElement;
import org.osate.aadl2.Data;
import org.osate.aadl2.DataClassifier;
import org.osate.aadl2.Element;
import org.osate.aadl2.EnumerationLiteral;
import org.osate.aadl2.EnumerationType;
import org.osate.aadl2.Feature;
import org.osate.aadl2.IntegerLiteral;
import org.osate.aadl2.ListType;
import org.osate.aadl2.ListValue;
import org.osate.aadl2.ModalPropertyValue;
import org.osate.aadl2.Mode;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.NumberValue;
import org.osate.aadl2.PackageSection;
import org.osate.aadl2.ProcessorClassifier;
import org.osate.aadl2.Property;
import org.osate.aadl2.PropertyAssociation;
import org.osate.aadl2.PropertyExpression;
import org.osate.aadl2.PropertyType;
import org.osate.aadl2.Prototype;
import org.osate.aadl2.PrototypeBinding;
import org.osate.aadl2.RangeValue;
import org.osate.aadl2.RealLiteral;
import org.osate.aadl2.RecordType;
import org.osate.aadl2.RecordValue;
import org.osate.aadl2.ReferenceValue;
import org.osate.aadl2.StringLiteral;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.UnitLiteral;
import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager;
import org.osate.ba.aadlba.AadlBaPackage;
import org.osate.ba.aadlba.Any;
import org.osate.ba.aadlba.AssignmentAction;
import org.osate.ba.aadlba.BasicAction;
import org.osate.ba.aadlba.BehaviorAction;
import org.osate.ba.aadlba.BehaviorActionBlock;
import org.osate.ba.aadlba.BehaviorActionCollection;
import org.osate.ba.aadlba.BehaviorActions;
import org.osate.ba.aadlba.BehaviorAnnex;
import org.osate.ba.aadlba.BehaviorCondition;
import org.osate.ba.aadlba.BehaviorElement;
import org.osate.ba.aadlba.BehaviorIntegerLiteral;
import org.osate.ba.aadlba.BehaviorState;
import org.osate.ba.aadlba.BehaviorTransition;
import org.osate.ba.aadlba.BehaviorVariable;
import org.osate.ba.aadlba.CompletionRelativeTimeout;
import org.osate.ba.aadlba.DataRepresentation;
import org.osate.ba.aadlba.DispatchCondition;
import org.osate.ba.aadlba.DispatchConjunction;
import org.osate.ba.aadlba.DispatchTriggerCondition;
import org.osate.ba.aadlba.DispatchTriggerLogicalExpression;
import org.osate.ba.aadlba.ElementValues;
import org.osate.ba.aadlba.ElseStatement;
import org.osate.ba.aadlba.Factor;
import org.osate.ba.aadlba.ForOrForAllStatement;
import org.osate.ba.aadlba.IfStatement;
import org.osate.ba.aadlba.IntegerRange;
import org.osate.ba.aadlba.IntegerValue;
import org.osate.ba.aadlba.IntegerValueConstant;
import org.osate.ba.aadlba.IntegerValueVariable;
import org.osate.ba.aadlba.IterativeVariable;
import org.osate.ba.aadlba.ModeSwitchConjunction;
import org.osate.ba.aadlba.ModeSwitchTrigger;
import org.osate.ba.aadlba.ModeSwitchTriggerLogicalExpression;
import org.osate.ba.aadlba.ParameterLabel;
import org.osate.ba.aadlba.PropertyNameField;
import org.osate.ba.aadlba.Relation;
import org.osate.ba.aadlba.SimpleExpression;
import org.osate.ba.aadlba.Target;
import org.osate.ba.aadlba.Term;
import org.osate.ba.aadlba.TimedAction;
import org.osate.ba.aadlba.Value;
import org.osate.ba.aadlba.ValueConstant;
import org.osate.ba.aadlba.ValueExpression;
import org.osate.ba.aadlba.ValueVariable;
import org.osate.ba.aadlba.WhileOrDoUntilStatement;
import org.osate.ba.declarative.ArrayableIdentifier;
import org.osate.ba.declarative.CommAction;
import org.osate.ba.declarative.DeclarativeArrayDimension;
import org.osate.ba.declarative.DeclarativeBasicPropertyAssociation;
import org.osate.ba.declarative.DeclarativeBehaviorElement;
import org.osate.ba.declarative.DeclarativeBehaviorTransition;
import org.osate.ba.declarative.DeclarativeFactory;
import org.osate.ba.declarative.DeclarativeListValue;
import org.osate.ba.declarative.DeclarativePropertyName;
import org.osate.ba.declarative.DeclarativePropertyReference;
import org.osate.ba.declarative.DeclarativeTime;
import org.osate.ba.declarative.Identifier;
import org.osate.ba.declarative.NamedValue;
import org.osate.ba.declarative.QualifiedNamedElement;
import org.osate.ba.declarative.Reference;
import org.osate.ba.utils.AadlBaUtils;
import org.osate.ba.utils.AadlBaVisitors;
import org.osate.utils.internal.Aadl2Utils;
import org.osate.utils.internal.Aadl2Visitors;
import org.osate.utils.internal.PropertyUtils;
import org.osate.utils.internal.names.DataModelProperties;
import org.osate.xtext.aadl2.properties.linking.PropertiesLinkingService;
/**
* A AADL behavior annex name resolver.
*
*/
public class AadlBaNameResolver {
private BehaviorAnnex _ba;
private ComponentClassifier _baParentContainer;
PackageSection[] _contextsTab;
private AnalysisErrorReporterManager _errManager;
// Time units property set names.
public static final String TIME_UNITS_PROPERTY_SET = "AADL_Project";
public static final String TIME_UNITS_PROPERTY_ID = "Time_Units";
// Iterative variables scope handler.
private EList<IterativeVariable> _itvScope = new BasicEList<IterativeVariable>();
/**
* Constructs an AADL behavior annex name resolver for a given behavior annex
* and reports any errors in a given error reporter manager.
*
* @param ba the given behavior annex
* @param errManager the given error reporter manager
*/
public AadlBaNameResolver(BehaviorAnnex ba, AnalysisErrorReporterManager errManager) {
_ba = ba;
_errManager = errManager;
_baParentContainer = AadlBaVisitors.getParentComponent(ba);
_contextsTab = AadlBaVisitors.getBaPackageSections(_ba);
}
private boolean assignmentActionResolver(AssignmentAction act) {
boolean result = false;
Target t = act.getTarget();
result = targetResolver(t);
if (!(act.getValueExpression() instanceof Any)) {
result &= valueExpressionResolver(act.getValueExpression());
}
return result;
}
/**
* Document: AADL Behavior Annex draft
* Version : 0.94
* Type : Naming rule
* Section : D.3 Behavior Specification
* Object : Check naming rule D.3.(N1)
* Keys : name uniqueness
*
* Conflicts and duplicate names are reported in the given error report
* manager. Link the complete states that represent a mode.
*
* @return {@code true} if behavior annex's rule is satisfied. {@code false}
* otherwise.
*/
private boolean behaviorComponentsUniquenessCheck() {
boolean result = true;
// Separated check in order to improve visibility and performance.
result = parentComponentIdentifiersUniquenessCheck();
EList<BehaviorVariable> lvars = _ba.getVariables();
EList<BehaviorState> lstates = _ba.getStates();
EList<BehaviorTransition> ltrans = _ba.getTransitions();
for (int i = 0; i < lvars.size() - 1; i++) {
for (int j = i + 1; j < lvars.size(); j++) {
if (lvars.get(i).getName().equalsIgnoreCase(lvars.get(j).getName())) {
reportDuplicateNameError(lvars.get(j), lvars.get(i));
result = false;
}
}
}
for (int i = 0; i < lstates.size() - 1; i++) {
for (int j = i + 1; j < lstates.size(); j++) {
if (lstates.get(i).getName().equalsIgnoreCase(lstates.get(j).getName())) {
reportDuplicateNameError(lstates.get(j), lstates.get(i));
result = false;
}
}
}
for (int i = 0; i < ltrans.size() - 1; i++) {
if (ltrans.get(i).getName() == null) {
continue;
}
for (int j = i + 1; j < ltrans.size(); j++) {
if (ltrans.get(j).getName() == null) {
continue;
}
if (ltrans.get(i).getName().equalsIgnoreCase(ltrans.get(j).getName())) {
reportDuplicateNameError(ltrans.get(j), ltrans.get(i));
result = false;
}
}
}
for (BehaviorVariable v : lvars) {
String bvName = v.getName();
for (BehaviorState s : lstates) {
String bsName = s.getName();
if (bsName.equalsIgnoreCase(bvName)) {
reportDuplicateNameError(s, v);
result = false;
}
}
for (BehaviorTransition t : ltrans) {
String btName = t.getName();
if (btName != null && btName.equalsIgnoreCase(bvName)) {
reportDuplicateNameError(t, v);
result = false;
}
}
}
for (BehaviorState s : lstates) {
String bsName = s.getName();
for (BehaviorTransition t : ltrans) {
String btName = t.getName();
if (btName != null && btName.equalsIgnoreCase(bsName)) {
reportDuplicateNameError(t, s);
result = false;
}
}
}
return result;
}
private boolean basicActionResolver(BasicAction act) {
// Case of assignment action.
if (act instanceof AssignmentAction) {
return assignmentActionResolver((AssignmentAction) act);
} else // Case of communication action.
{
if (act instanceof CommAction) {
return communicationActionResolver((CommAction) act);
} else // Case of timed action.
{
return timedActionResolver((TimedAction) act);
}
}
}
private boolean transDestStateResolver(DeclarativeBehaviorTransition trans) {
BehaviorState state = null;
Identifier id = trans.getDestState();
state = AadlBaVisitors.findBehaviorState(_ba, id.getId());
if (state != null) {
id.setBaRef(state);
return true;
} else {
reportNameError(id, id.getId());
return false;
}
}
private boolean transSrcStateResolver(DeclarativeBehaviorTransition trans) {
boolean result = true;
BehaviorState state = null;
for (Identifier id : trans.getSrcStates()) {
state = AadlBaVisitors.findBehaviorState(_ba, id.getId());
if (state != null) {
id.setBaRef(state);
} else {
reportNameError(id, id.getId());
result = false;
}
}
return result;
}
/**
* Document: AADL Behavior Annex draft
* Version : 0.94
* Type : Naming rule
* Section : D.3 Behavior Specification
* Object : Check naming rule D.3.(N2)
* Keys : empty execution condition
*
* Resolves the names in behavior annex's transitions.
*
* @return {@code true} if all names are resolved. {@code false} otherwise.
*/
private boolean behaviorTransitionResolver() {
boolean result = true;
for (BehaviorTransition tmp : _ba.getTransitions()) {
DeclarativeBehaviorTransition trans = (DeclarativeBehaviorTransition) tmp;
result &= transDestStateResolver(trans);
result &= transSrcStateResolver(trans);
BehaviorCondition cond = trans.getCondition();
// According to D.3.(N2) Naming rule : behavior condition can be null
// as no condition means always true.
if (cond != null) {
// Case of a dispatch condition
if (cond instanceof DispatchCondition) {
result &= dispatchConditionResolver((DispatchCondition) cond);
}
// Case of mode switch condition
else if (cond instanceof ModeSwitchTriggerLogicalExpression) {
result &= modeSwitchTriggerLogicalExpression((ModeSwitchTriggerLogicalExpression) cond);
}
// ModeSwitchTriggerLogicalExpression
else // Case of a execute condition
{
if (cond instanceof ValueExpression) {
result &= valueExpressionResolver((ValueExpression) cond);
}
}
}
BehaviorActionBlock block = trans.getActionBlock();
// Behavior actions of an behavior transition may not exist.
if (block != null) {
result &= behaviorActionBlockResolver(block);
}
}
return result;
}
private boolean modeSwitchTriggerLogicalExpression(ModeSwitchTriggerLogicalExpression cond) {
boolean result = true;
for (ModeSwitchConjunction msc : cond.getModeSwitchConjunctions()) {
for (ModeSwitchTrigger mst : msc.getModeSwitchTriggers()) {
Reference trigg = (Reference) mst;
result &= refResolver(trigg);
}
}
return result;
}
private boolean behaviorActionBlockResolver(BehaviorActionBlock block) {
boolean result = behaviorActionsResolver(block.getContent());
// Check timeout option.
if (block.getTimeout() != null) {
result &= behaviorTimeResolver((DeclarativeTime) block.getTimeout());
}
return result;
}
private boolean baVariableResolver(Identifier id, boolean hasToReport) {
String variableName = id.getId();
BehaviorVariable v = AadlBaVisitors.findBehaviorVariable(_ba, variableName);
if (v != null) {
id.setBaRef(v);
return true;
} else {
if (hasToReport) {
reportNameError(id, variableName);
}
return false;
}
}
private boolean ifStatementResolver(IfStatement stat) {
boolean result = true;
result &= valueExpressionResolver(stat.getLogicalValueExpression());
result &= behaviorActionsResolver(stat.getBehaviorActions());
ElseStatement elseStat = stat.getElseStatement();
if (elseStat != null) {
if (elseStat instanceof IfStatement) {
result &= ifStatementResolver((IfStatement) elseStat);
} else {
result &= behaviorActionsResolver(elseStat.getBehaviorActions());
}
}
return result;
}
private boolean behaviorActionResolver(BehaviorAction act) {
boolean result = true;
// Case of basic action.
if (act instanceof BasicAction) {
result = basicActionResolver((BasicAction) act);
} else {
if (act instanceof BehaviorActionBlock) {
result = behaviorActionBlockResolver((BehaviorActionBlock) act);
} else {
// Case of IF statement.
if (act instanceof IfStatement) {
result = ifStatementResolver((IfStatement) act);
} else {
// Case if WHILE and DO UNTIL statement.
if (act instanceof WhileOrDoUntilStatement) {
WhileOrDoUntilStatement stat = (WhileOrDoUntilStatement) act;
result = valueExpressionResolver(stat.getLogicalValueExpression());
result &= behaviorActionsResolver(stat.getBehaviorActions());
} else // Case of FOR and FOR ALL statement.
{
ForOrForAllStatement stat = (ForOrForAllStatement) act;
IterativeVariable itVar = stat.getIterativeVariable();
// Resolves unique component classifier reference.
QualifiedNamedElement uccr = (QualifiedNamedElement) itVar.getDataClassifier();
result = qualifiedNamedElementResolver(uccr, true);
// Checks the for/forall's iterative variable.
result &= iterativeVariableUniquenessCheck(itVar);
// Add the for/forall statment's iterative variable to
// the scope handler.
_itvScope.add(itVar);
// Check element values.
result &= elementValuesResolver(stat.getIteratedValues());
// Check behavior actions.
result &= behaviorActionsResolver(stat.getBehaviorActions());
// remove the for/forall statment's iterative variable from
// the scope handler (after checking for/forall's behavior
// actions.
_itvScope.remove(itVar);
}
} // End of third else.
} // End of second else.
} // End of first else.
return result;
}
/**
* Document: AADL Behavior Annex draft
* Version : 0.94
* Type : Naming rule
* Section : D.6 Behavior Action Language
* Object : Check naming rule D.6.(N1)
* Keys : element variable identifier for control construct iterative variable
*/
private boolean iterativeVariableUniquenessCheck(IterativeVariable itv) {
// Check uniqueness towards AADL elements.
boolean result = featureNameUniquenessCheck(itv);
// Check uniqueness towards BA local variable.
result &= behaviorVariableNameUniquenessCheck(itv);
// Check uniqueness towards others iterative variables according
// to their scope.
result &= iterativeVariableUniquenessWithinScopeHandler(itv);
return result;
}
private boolean iterativeVariableUniquenessWithinScopeHandler(IterativeVariable itv) {
IterativeVariable sameId = AadlBaUtils.compareNamedElementList(itv.getName(), _itvScope);
if (sameId == null) {
return true;
} else {
// Report error.
_errManager.error(itv, "duplicate local variable for " + itv.getName());
return false;
}
}
// Just the opposite of featureResolver.
private boolean featureNameUniquenessCheck(IterativeVariable itv) {
String nameToFind = itv.getName();
Feature f = Aadl2Visitors.findFeatureInComponent(_baParentContainer, nameToFind);
if (f == null) {
return true;
} else {
// Report error.
_errManager.error(itv, "duplicate local variable for " + itv.getName());
return false;
}
}
// Checks if the given iterative variable is declared within the current
// scope handler.
private boolean iterativeVariableScopeCheck(Identifier itv, boolean hasToReport) {
IterativeVariable sameId = AadlBaUtils.compareNamedElementList(itv.getId(), _itvScope);
if (sameId != null) {
itv.setBaRef(sameId);
return true;
} else {
// Report error.
if (hasToReport) {
reportNameError(itv, itv.getId());
}
return false;
}
}
private boolean behaviorVariableNameUniquenessCheck(IterativeVariable itv) {
String variableName = itv.getName();
BehaviorVariable v = AadlBaVisitors.findBehaviorVariable(_ba, variableName);
if (v == null) {
return true;
} else {
// Report error.
_errManager.error(itv, "duplicate local variable for " + itv.getName());
return false;
}
}
private boolean behaviorActionsResolver(BehaviorActions acts) {
boolean result = true;
// Case of single behavior action.
if (acts instanceof BehaviorAction) {
result = behaviorActionResolver((BehaviorAction) acts);
} else // Case of behavior action collection (behavior action sequence or set)
{
for (BehaviorAction act : ((BehaviorActionCollection) acts).getActions()) {
result &= behaviorActionResolver(act);
}
}
return result;
}
private boolean behaviorTimeResolver(DeclarativeTime bt) {
Identifier timeUnit = bt.getUnitId();
boolean result = integerValueResolver(bt.getIntegerValue());
result &= timeUnitResolver(timeUnit);
if (result && bt.getIntegerValue() instanceof BehaviorIntegerLiteral) {
BehaviorIntegerLiteral bil = (BehaviorIntegerLiteral) bt.getIntegerValue();
bil.setUnit((UnitLiteral) timeUnit.getOsateRef());
}
return result;
}
private boolean communicationActionResolver(CommAction act) {
boolean result = true;
if (act.getTarget() != null) {
result &= targetResolver(act.getTarget());
}
if (act.getQualifiedName() != null) {
result &= qualifiedNamedElementResolver(act.getQualifiedName(), true);
}
if (act.getReference() != null) {
// Ambiguous cases :
// _ unqualified unique component classifier reference
// without implementation information provided, are parsed as reference
// (single name) without array index.
// _ unqualified unique component classifier reference with
// implementation information provided and a reference (two names)
// without array index.
Reference ref = act.getReference();
EList<ArrayableIdentifier> ids = ref.getIds();
boolean hasArrayIndex = false;
// unqualified unique component classifier reference have at most two
// names.
if (ids.size() > 2) {
result &= refResolver(ref);
} else {
for (ArrayableIdentifier id : ids) {
if (id.isSetArrayIndexes()) {
hasArrayIndex = true;
}
}
// unique component classifier reference can't have array index.
if (hasArrayIndex) {
result &= refResolver(ref);
} else {
// Resolves ambiguous case between unqualified unique component
// classifier reference and a reference with only one name.
ArrayableIdentifier idComponent = ids.get(0);
StringBuilder subprogramName = new StringBuilder();
subprogramName.append(idComponent.getId());
if (ids.size() == 2) {
ArrayableIdentifier idImplementation = ids.get(1);
subprogramName.append('.');
subprogramName.append(idImplementation.getId());
}
QualifiedNamedElement qne = DeclarativeFactory.eINSTANCE.createQualifiedNamedElement();
// Clone the identifier as object reference in the most of the AADLBA
// Front End emf meta model classes are unique (the containment
// attribute set to true).
Identifier idClone = DeclarativeFactory.eINSTANCE.createIdentifier();
idClone.setLocationReference(idComponent.getLocationReference());
idClone.setId(subprogramName.toString());
qne.setBaName(idClone);
qne.setBaNamespace(null);
qne.setLocationReference(idComponent.getLocationReference());
if (qualifiedNamedElementResolver(qne, false)) {
act.setReference(null);
act.setQualifiedName(qne);
act.setLocationReference(qne.getLocationReference());
result &= true;
} else {
result &= refResolver(ref);
}
}
}
}
if (act.isSetParameters()) {
result &= subprogramParameterListResolver(act.getParameters());
}
return result;
}
/*
* dispatch_condition ::=
* on dispatch [ dispatch_trigger_condition ] [ frozen frozen_ports ]
*/
private boolean dispatchConditionResolver(DispatchCondition cond) {
boolean result = true;
DispatchTriggerCondition dtc = cond.getDispatchTriggerCondition();
// Dtc can be null as no dispatch trigger condition means always true.
if (dtc != null) {
result = dispatchTriggerConditionResolver(dtc);
}
if (cond.isSetFrozenPorts()) {
for (Element id : cond.getFrozenPorts()) {
result &= refResolver((Reference) id);
}
}
return result;
}
/*
* dispatch_trigger_condition ::=
* dispatch_trigger_logical_expression
* | provides_subprogram_access_name
* | stop
* | completion_relative_timeout_condition_and_catch
* | dispatch_relative_timeout_catch
*/
private boolean dispatchTriggerConditionResolver(DispatchTriggerCondition dtc) {
boolean result = false;
// Subprogram access are parsed as dispatch trigger logical expression.
if (dtc instanceof DispatchTriggerLogicalExpression) {
result = dispatchTriggerLogicalExpressionResolver((DispatchTriggerLogicalExpression) dtc);
} else if (dtc instanceof CompletionRelativeTimeout) {
result = behaviorTimeResolver((DeclarativeTime) dtc);
} else // Cases of TimeoutCatch and DispatchTriggerConditionStop
// : no name to check for.
{
result = true;
}
return result;
}
private boolean dispatchTriggerLogicalExpressionResolver(DispatchTriggerLogicalExpression dtle) {
boolean result = true;
for (DispatchConjunction dc : dtle.getDispatchConjunctions()) {
for (Element e : dc.getDispatchTriggers()) {
Reference trigg = (Reference) e;
result &= refResolver(trigg);
}
}
return result;
}
private boolean elementValuesResolver(ElementValues values) {
// Case of integer range.
if (values instanceof IntegerRange) {
return integerRangeResolver((IntegerRange) values);
} else {
return refResolver((Reference) values);
}
}
private boolean featureResolver(Classifier parentContainer, Identifier id, boolean hasToReport) {
String nameToFind = id.getId();
Feature f = Aadl2Visitors.findFeatureInComponent(parentContainer, nameToFind);
if (f != null) {
id.setOsateRef(f);
return true;
} else {
if (hasToReport) {
reportNameError(id, nameToFind);
}
return false;
}
}
// Resolves identifier within the behavior variables and iterative variables.
private boolean identifierBaResolver(Identifier id, boolean hasToReport) {
// First try to resolve within ba's variables names but
// don't report any error.
if (baVariableResolver(id, false)) {
return true;
} else {
// Second try to resolve within iterative variable scope handler.
if (iterativeVariableScopeCheck(id, false)) {
return true;
} else {
// Report error.
if (hasToReport) {
reportNameError(id, id.getId());
}
return false;
}
}
}
// Resolves identifiers within the prototypes, features and subcomponent of
// the given component.
private boolean identifierComponentResolver(Identifier id, Classifier component, boolean hasToReport) {
// Resolves within the given component features names.
if (featureResolver(component, id, false)) {
return true;
} else {
// Resolves within the given component subcomponent names.
if (subcomponentIdResolver(id, component, false)) {
return true;
} else {
// Resolves within the given component feature prototypes.
if (featurePrototypeResolver(id, component, false)) {
return true;
} else {
// At last try to resolve within the
// property Data_Model::Element Names
if (component instanceof DataClassifier) {
return structOrUnionOrArrayIdResolver(id, (DataClassifier) component, true);
} else {
// Report error.
if (hasToReport) {
reportNameError(id, id.getId());
}
return false;
}
}
}
}
}
// Resolves the given identifier within the property Data_Model::Element
// Names of a declared struct or union component (event if element names is
// set). If the given component is not declared as a struct or union, it
// returns false and reports error according to the hasToReport flag.
private boolean structOrUnionOrArrayIdResolver(Identifier id, DataClassifier component, boolean hasToReport) {
boolean result = false;
DataRepresentation rep = AadlBaUtils.getDataRepresentation(component);
if (rep == DataRepresentation.STRUCT || rep == DataRepresentation.UNION) {
EList<PropertyExpression> lpv = PropertyUtils.findPropertyExpression(component,
DataModelProperties.ELEMENT_NAMES);
ListValue lv = null;
StringLiteral sl = null;
int index1 = 0;
int index2 = 0;
for1: for (PropertyExpression pe : lpv) {
lv = (ListValue) pe;
for (PropertyExpression pex : lv.getOwnedListElements()) {
sl = (StringLiteral) pex;
if (id.getId().equalsIgnoreCase(sl.getValue())) {
result = true;
break for1;
}
index2++;
}
index1++;
}
// Binds the element name's base type.
if (result) {
EList<PropertyExpression> lpv2 = PropertyUtils.findPropertyExpression(component,
DataModelProperties.BASE_TYPE);
ClassifierValue cv;
cv = (ClassifierValue) ((ListValue) lpv2.get(index1)).getOwnedListElements().get(index2);
id.setOsateRef(cv);
}
} else if (rep == DataRepresentation.ARRAY) {
EList<PropertyExpression> lpv = PropertyUtils.findPropertyExpression(component,
DataModelProperties.BASE_TYPE);
if (lpv.isEmpty() == false) {
ClassifierValue cv;
cv = (ClassifierValue) ((ListValue) lpv.get(0)).getOwnedListElements().get(0);
result = identifierComponentResolver(id, cv.getClassifier(), hasToReport);
} else {
result = false;
}
}
if (!result && hasToReport) {
reportNameError(id, id.getId());
}
return result;
}
private boolean featurePrototypeResolver(Identifier id, Classifier component, boolean hasToReport) {
String nameToFind = id.getId();
PrototypeBinding pb = Aadl2Visitors.findPrototypeBindingInComponent(component, nameToFind);
// first: try to find any prototype binding that matches the given
// identifier. Prototype binding means prototype refining.
if (pb != null) {
id.setOsateRef(pb);
return true;
} else // If there isn't any matching prototype binding, try to find
// a matching prototype declaration.
{
Prototype proto = Aadl2Visitors.findPrototypeInComponent(component, nameToFind);
if (proto != null) {
id.setOsateRef(proto);
return true;
} else {
if (hasToReport) {
reportNameError(id, nameToFind);
}
return false;
}
}
}
private boolean integerRangeResolver(IntegerRange range) {
boolean result = integerValueResolver(range.getUpperIntegerValue());
result &= integerValueResolver(range.getLowerIntegerValue());
return result;
}
/*
* integer_value ::=
* integer_value_variable
* | integer_value_constant
*/
private boolean integerValueResolver(IntegerValue value) {
if (value instanceof IntegerValueVariable) {
return integerValueVariableResolver((IntegerValueVariable) value);
} else {
return integerValueConstantResolver((IntegerValueConstant) value);
}
}
private boolean integerValueVariableResolver(IntegerValueVariable value) {
return valueVariableResolver(value, value);
}
private boolean integerValueConstantResolver(IntegerValueConstant value) {
return valueConstantResolver(value);
}
/**
* Resolves the names in behavior annex.
*
* @return {@code true} if all names are resolved. {@code false} otherwise.
*/
public boolean resolveNames() {
boolean result = this.behaviorComponentsUniquenessCheck();
// Continue other checking if only BA's components uniqueness
// is ensured.
if (result) {
result &= this.behaviorVariableResolver();
result &= this.behaviorTransitionResolver();
}
return result;
}
// Searches within the _baParentContainer.
private boolean refResolver(Reference nameObj) {
return refResolver(_baParentContainer, nameObj);
}
// Resolves Reference objects (arrayable identifiers)
// within parent component's features ones and ba's variables ones and
// for/forall's iterative variable scope handler.
private boolean refResolver(Classifier parentContainer, Reference ref) {
boolean result = true;
boolean currentIdResult = false;
ListIterator<ArrayableIdentifier> it = ref.getIds().listIterator();
// Checks ArrayableIdentifier objects.
while (it.hasNext()) {
ArrayableIdentifier id = it.next();
// Case of features or subcomponents without classifier.
// Can't resolve within a null parent classifier.
if (parentContainer == null) {
result = false;
reportNameError(id, id.getId());
break;
}
if (parentContainer == _baParentContainer) {
currentIdResult = identifierBaResolver(id, false);
}
if (!currentIdResult) {
currentIdResult = identifierComponentResolver(id, parentContainer, true);
}
if (id.isSetArrayIndexes()) {
// Checks array indexes names.
for (IntegerValue index : id.getArrayIndexes()) {
// Recursive call.
result &= integerValueResolver(index);
}
}
// If the current id is found, fetch the container for the next id.
if (currentIdResult && it.hasNext()) {
Element el = AadlBaTypeChecker.getBindedElement(id);
// AadlBaUtils.getClassifier is not useful as BehaviorVariables have
// not been type checked already.
if (el instanceof BehaviorVariable) {
QualifiedNamedElement qne = (QualifiedNamedElement) ((BehaviorVariable) el).getDataClassifier();
parentContainer = (Classifier) qne.getOsateRef();
} else if (el instanceof IterativeVariable) {
IterativeVariable itv = (IterativeVariable) el;
QualifiedNamedElement qne = (QualifiedNamedElement) itv.getDataClassifier();
parentContainer = (Classifier) qne.getOsateRef();
} else {
parentContainer = AadlBaUtils.getClassifier(el, parentContainer);
}
}
// Add the current id result to the global result.
result &= currentIdResult;
// Reset.
currentIdResult = false;
// Don't continue if the current id is not found.
if (result == false) {
break;
}
}
// Binds with the last id reference.
ArrayableIdentifier lastId = ref.getIds().get((ref.getIds().size() - 1));
ref.setOsateRef(lastId.getOsateRef());
ref.setBaRef(lastId.getBaRef());
return result;
}
private void reportDuplicateNameError(BehaviorElement be, NamedElement ne) {
String neName = ne.getName();
_errManager.error(be,
"duplicate name error: " + neName + " at line " + be.getLocationReference().getLine()
+ " conflict with the element" + " with the same name located at line "
+ Aadl2Utils.getLocationReference(ne).getLine());
}
/**
* Check behavior annex's sub component uniqueness within behavior annex's
* parent component scope. Conflicts are reported.
*/
private boolean parentComponentIdentifiersUniquenessCheck() {
boolean result = true;
EList<org.osate.aadl2.NamedElement> lcc = new BasicEList<org.osate.aadl2.NamedElement>(0);
// Merges parent component' subcomponents lists.
lcc.addAll(Aadl2Visitors.getElementsInNamespace(_baParentContainer, Data.class));
lcc.addAll(Aadl2Visitors.getElementsInNamespace(_baParentContainer, Mode.class));
lcc.addAll(Aadl2Visitors.getElementsInNamespace(_baParentContainer, Feature.class));
EList<BehaviorVariable> lvars = _ba.getVariables();
EList<BehaviorState> lstates = _ba.getStates();
EList<BehaviorTransition> ltrans = _ba.getTransitions();
// Check uniqueness within the parent component.
for (org.osate.aadl2.NamedElement ne : lcc) {
for (BehaviorVariable v : lvars) {
String bvName = v.getName();
String neName = ne.getName();
if (bvName.equalsIgnoreCase(neName)) {
reportDuplicateNameError(v, ne);
result = false;
}
}
for (BehaviorState s : lstates) {
String bsName = s.getName();
if (bsName.equalsIgnoreCase(ne.getName())) {
// Complete states that represent modes are exceptions of
// D.3.(N1) naming rule.
// Links the identifier with the mode.
if (ne instanceof Mode) {
if (s.isComplete() == false) {
_errManager.error(s,
"Behavior state " + bsName + " must be declared complete in order to represent "
+ "mode " + ne.getName() + " located at line "
+ Aadl2Utils.getLocationReference(ne).getLine());
result = false;
} else {
s.setBindedMode((Mode) ne);
}
} else {
reportDuplicateNameError(s, ne);
result = false;
}
}
}
for (BehaviorTransition t : ltrans) {
String btName = t.getName();
if (btName != null && btName.equalsIgnoreCase(ne.getName())) {
reportDuplicateNameError(t, ne);
result = false;
}
}
}
return result;
}
private boolean subcomponentIdResolver(Identifier id, Classifier parentComponent, boolean hasToReport) {
String nameToFind = id.getId();
Subcomponent subc = Aadl2Visitors.findSubcomponentInComponent(parentComponent, nameToFind);
if (subc != null) {
id.setOsateRef(subc);
return true;
} else {
if (hasToReport) {
reportNameError(id, nameToFind);
}
return false;
}
}
private boolean subprogramParameterListResolver(EList<ParameterLabel> spl) {
boolean result = true;
for (ParameterLabel pLabel : spl) {
// Targets are parsed as value expression with only one value.
// Targets are equivalent to value, syntactically.
result &= valueExpressionResolver((ValueExpression) pLabel);
}
return result;
}
private boolean targetResolver(Target tar) {
return refResolver((Reference) tar);
}
private boolean timedActionResolver(TimedAction act) {
boolean result = behaviorTimeResolver((DeclarativeTime) act.getLowerTime());
if (act.getUpperTime() != null) {
result &= behaviorTimeResolver((DeclarativeTime) act.getUpperTime());
}
if (act.isSetProcessorClassifier()) {
for (ProcessorClassifier pc : act.getProcessorClassifier()) {
result &= qualifiedNamedElementResolver((QualifiedNamedElement) pc, true);
}
}
return result;
}
// Checks behavior time's time unit according to property set Time_Units and
// binds if checking is successful.
private boolean timeUnitResolver(Identifier unitIdentifier) {
PackageSection context = Aadl2Visitors.getContainingPackageSection(_ba);
NamedElement pt = Aadl2Visitors.findElementInPropertySet(TIME_UNITS_PROPERTY_ID, TIME_UNITS_PROPERTY_SET,
context);
// Property set Time_Units is found.
if (pt instanceof org.osate.aadl2.UnitsType) {
org.osate.aadl2.UnitsType ut = (org.osate.aadl2.UnitsType) pt;
// Find the given time unit in the enumeration.
org.osate.aadl2.UnitLiteral ul = ut.findLiteral(unitIdentifier.getId());
// The given time unit is found.
if (ul != null) {
unitIdentifier.setOsateRef(ul);
return true;
} else {
_errManager.error(unitIdentifier, unitIdentifier.getId() + " is not a valid time unit according "
+ "to the property set Time_Units.");
return false;
}
} else {
_errManager.error(unitIdentifier, "Property set Time_Units is not found");
return false;
}
}
private boolean qualifiedNamedElementResolver(QualifiedNamedElement qne, boolean hasToReport) {
String packageName = null;
EObject ne;
boolean hasNamespace = qne.getBaNamespace() != null;
if (hasNamespace) {
packageName = qne.getBaNamespace().getId();
}
// Now check the type in each current package's sections.
for (PackageSection context : _contextsTab) {
NamedElement parent = (NamedElement) _ba.eContainer().eContainer();
ne = Aadl2Visitors.findSubcomponentInComponent((Classifier) parent, qne.getBaName().getId());
if (ne == null) {
ne = Aadl2Visitors.findFeatureInComponent((Classifier) parent, qne.getBaName().getId());
}
if (ne == null) {
ne = Aadl2Visitors.findElementInPackage(qne.getBaName().getId(), packageName, context);
}
if (ne == null) {
ne = Aadl2Visitors.findElementInPropertySet(qne.getBaName().getId(), packageName, context);
}
// An element is found.
if (ne != null && ne instanceof NamedElement) {
// Links unique component classifier reference with named element found.
qne.setOsateRef((Element) ne);
qne.getBaName().setOsateRef((Element) ne);
if (hasNamespace) {
qne.getBaNamespace().setOsateRef(((NamedElement) ne).getNamespace());
}
return true;
}
}
// The element is not found.
if (hasToReport) {
StringBuilder qualifiedName = new StringBuilder();
if (hasNamespace) {
qualifiedName.append(qne.getBaNamespace().getId());
qualifiedName.append("::");
}
qualifiedName.append(qne.getBaName().getId());
reportNameError(qne, qualifiedName.toString());
}
return false;
}
// Check constant value names means to check names
// within behavior property reference ones or property set constant ones.
/*
* value_constant ::=
* boolean_literal
* | numeric_literal
* | string_literal
* | property_constant
* | property_reference
*/
private boolean valueConstantResolver(ValueConstant value) {
if (value instanceof DeclarativePropertyReference) {
return propertyReferenceResolver((DeclarativePropertyReference) value);
} else // Other literals : they don't contain any name.
{
return true;
}
}
private boolean propertyReferenceResolver(DeclarativePropertyReference ref) {
if (ref.isPropertySet()) {
// Property reference or property constant from a property set.
return propertySetpropertyReferenceResolver(ref);
} else if (ref.getQualifiedName() != null) {
// Property reference from a qualified classifier.
return classifierPropertyReferenceResolver(ref, true) == 0;
} else {
EList<ArrayableIdentifier> ids = ref.getReference().getIds();
if (ids.size() > 2) {
// Unqualified classifier reference cannot have more then two identifiers
// so the Reference object is true classifier feature.
return classifierFeaturePropertyReferenceResolver(ref);
} else {
// Ambiguous case: between an unqualified classifier and a classifier
// feature.
// First try as an unqualified classifier
// Instantiate a QualifiedNamedElement from Reference's identifiers.
QualifiedNamedElement qne = DeclarativeFactory.eINSTANCE.createQualifiedNamedElement();
Identifier nameId = DeclarativeFactory.eINSTANCE.createIdentifier();
String name = ids.get(0).getId();
if (ids.size() == 2) {
name += '.' + ids.get(1).getId();
}
nameId.setId(name);
nameId.setLocationReference(ids.get(0).getLocationReference());
qne.setBaName(nameId);
qne.setLocationReference(nameId.getLocationReference());
ref.setQualifiedName(qne);
short classifierResult = classifierPropertyReferenceResolver(ref, false);
switch (classifierResult) {
case 0: {
ref.setReference(null); // Unset reference.
return true;
}
// Second try as a classifier feature.
case 1: {
if (classifierFeaturePropertyReferenceResolver(ref)) {
ref.setQualifiedName(null);
return true;
} else {
return false;
}
}
case 2: // The classifier has been found but one or more property
// names are not found. Errors have already been reported.
default: {
return false;
}
}
}
}
}
private boolean classifierFeaturePropertyReferenceResolver(DeclarativePropertyReference ref) {
Reference component = ref.getReference();
if (refResolver(component)) {
PropertyAssociation pa = null;
Classifier type = null;
Identifier propertyNameId = ref.getPropertyNames().get(0).getPropertyName();
Element el = (component.getOsateRef() != null) ? component.getOsateRef() : component.getBaRef();
if (el instanceof PrototypeBinding) {
PrototypeBinding pb = (PrototypeBinding) el;
type = AadlBaUtils.getClassifier(pb, pb.getContainingClassifier());
} else if (el instanceof ClassifierFeature) {
ClassifierFeature cf = (ClassifierFeature) el;
// Fetch the own property association of the classifier feature.
pa = PropertyUtils.findPropertyAssociation(propertyNameId.getId(), cf);
if (pa == null) {
type = AadlBaUtils.getClassifier(cf, cf.getContainingClassifier());
}
} else if (el instanceof BehaviorVariable) {
BehaviorVariable bv = (BehaviorVariable) el;
DeclarativeBehaviorElement de = (DeclarativeBehaviorElement) bv.getDataClassifier();
if (de.getOsateRef() instanceof Classifier) {
type = (Classifier) de.getOsateRef();
}
} else // Cannot resolve or unimplemented cases.
{
String msg = "the type of \'" + ((NamedElement) el).getName() + "\' cannot be resolved";
_errManager.error(el, msg);
}
// If the property is not found within the classifier feature definition,
// search within its type.
if (pa == null && type != null) {
pa = PropertyUtils.findPropertyAssociation(propertyNameId.getId(), type);
}
if (pa != null) {
ref.getPropertyNames().get(0).setOsateRef(pa);
propertyNameId.setOsateRef(pa);
return propertyNameResolver(ref.getPropertyNames());
} else {
reportNameError(propertyNameId, propertyNameId.getId());
return false;
}
} else {
return false; // refResolver has already reported the error.
}
}
// return result code:
// 0 : resolution has passed.
// 1 : classifier is not found.
// 2 : classifier has been found but one or more property names are not found.
private short classifierPropertyReferenceResolver(DeclarativePropertyReference ref, boolean hasToReport) {
if (qualifiedNamedElementResolver(ref.getQualifiedName(), hasToReport)) {
NamedElement klass = (NamedElement) ref.getQualifiedName().getOsateRef();
Identifier propertyNameId = ref.getPropertyNames().get(0).getPropertyName();
PropertyAssociation pa = PropertyUtils.findPropertyAssociation(propertyNameId.getId(), klass);
if (pa != null) {
ref.getPropertyNames().get(0).setOsateRef(pa);
propertyNameId.setOsateRef(pa);
return (short) ((propertyNameResolver(ref.getPropertyNames())) ? 0 : 2);
} else {
reportNameError(propertyNameId, propertyNameId.getId());
return 2;
}
} else {
return 1;
}
}
private boolean propertySetpropertyReferenceResolver(DeclarativePropertyReference ref) {
Identifier propertyNameId = ref.getPropertyNames().get(0).getPropertyName();
String packageName = null;
if (ref.getQualifiedName() != null) {
packageName = ref.getQualifiedName().getBaNamespace().getId();
}
NamedElement ne = null;
// Now check the type in each current package's sections.
for (PackageSection context : _contextsTab) {
ne = Aadl2Visitors.findElementInPropertySet(propertyNameId.getId(), packageName, context);
if (ne != null) {
propertyNameId.setOsateRef(ne);
ref.getPropertyNames().get(0).setOsateRef(ne);
if (packageName != null) {
ref.getQualifiedName().getBaNamespace().setOsateRef(ne.getNamespace());
ref.getQualifiedName().setOsateRef(ne.getNamespace());
}
if (ne instanceof Property) {
Property p = (Property) ne;
// First search within the default values.
if (p.getDefaultValue() != null) {
PropertyExpression pe = p.getDefaultValue();
propertyNameId.setOsateRef(pe);
ref.getPropertyNames().get(0).setOsateRef(pe);
}
return propertyNameResolver(ref.getPropertyNames());
} else if (ne instanceof PropertyType) {
if (ne instanceof EnumerationType) {
return propertyNameResolver(ref.getPropertyNames());
} else {
// It doesn't make any sense
// for the other types.
String msg = "reference to property type (other than enumeration" + " type) is not supported";
_errManager.error(ref.getPropertyNames().get(1).getPropertyName(), msg);
return false;
}
} else // Property constant case.
{
if (ref.getPropertyNames().size() > 1) {
// Property constants haven't any sub property.
String msg = "property names are not supported for property constant";
_errManager.error(ref.getPropertyNames().get(1).getPropertyName(), msg);
return false;
} else {
DeclarativePropertyName firstDpn = ref.getPropertyNames().get(0);
if (null != firstDpn.getField() || firstDpn.isSetIndexes()) {
// Property constants haven't any property field.
String msg = "property fields are not supported for property constant";
BehaviorElement bel = (null != firstDpn.getField()) ? firstDpn.getField()
: firstDpn.getIndexes().get(0);
_errManager.error(bel, msg);
return false;
} else {
return true;
}
}
}
}
}
reportNameError(propertyNameId, propertyNameId.getId());
return false;
}
private boolean propertyNameResolver(EList<DeclarativePropertyName> propertyNames) {
// Ambiguity between a property literal and a property name without field.
// So the next property name is evaluated.
// The first property name has already been resolved, excepted its field.
ListIterator<DeclarativePropertyName> it = propertyNames.listIterator();
DeclarativePropertyName currentName = it.next();
Element previousContainer = null;
int previousContainerId = -1;
// Then resolve the property field.
if (false == propertyIndexAndFieldResolution(currentName)) {
return false;
}
while (it.hasNext()) {
previousContainer = currentName.getOsateRef();
previousContainerId = previousContainer.eClass().getClassifierID();
currentName = it.next();
// Case of properties defined by a property association.
if (Aadl2Package.PROPERTY_ASSOCIATION == previousContainerId) {
PropertyAssociation pa = (PropertyAssociation) previousContainer;
if (propertyAssociationResolver(pa, currentName) && propertyIndexAndFieldResolution(currentName)) {
continue;
} else // Property association may exist but doesn't define the
// property that interests us. So search within the property
// definition.
{
previousContainer = pa.getProperty();
}
}
// The sub property is defined within a property expression.
if (previousContainer instanceof PropertyExpression) {
if (propertyValueResolver((PropertyExpression) previousContainer, currentName)
&& propertyIndexAndFieldResolution(currentName)) {
continue;
} else // Try with the property expression type definition.
{
previousContainer = PropertyUtils.getContainingProperty((PropertyExpression) previousContainer);
}
}
previousContainerId = previousContainer.eClass().getClassifierID();
// Try to resolve the property name within the property declaration.
if (Aadl2Package.PROPERTY == previousContainerId) {
Property p = (Property) previousContainer;
if (propertyDeclarationResolver(p, currentName) && propertyIndexAndFieldResolution(currentName)) {
continue;
} // Then the property type definition.
else if (propertyTypeResolver(p.getPropertyType(), currentName)
&& propertyIndexAndFieldResolution(currentName)) {
continue;
} else {
// propertyTypeResolver and propertyFieldResolution report any error.
return false;
}
} // BasciProperty EMF identifier == Aadl2Package.LIST_VALUE, why ????
else if (previousContainer instanceof BasicProperty) // Use instanceof instead.
{
// The sub property is defined within a Record field (basic property).
BasicProperty bp = (BasicProperty) previousContainer;
if (propertyTypeResolver(bp.getPropertyType(), currentName)
&& propertyIndexAndFieldResolution(currentName)) {
continue;
} else {
// propertyTypeResolver and propertyFieldResolution report any error.
return false;
}
} // The property is defined within the type of a record.
else if (Aadl2Package.RECORD_TYPE == previousContainerId) {
RecordType rt = (RecordType) previousContainer;
if (recordFieldResolver(rt, currentName) && propertyIndexAndFieldResolution(currentName)) {
continue;
} else {
return false;
}
} else if (Aadl2Package.ENUMERATION_TYPE == previousContainerId) {
EnumerationType type = (EnumerationType) previousContainer;
return enumerationTypeResolver(type, currentName);
} else // other types like ListType, etc.
{
// As it doesn't make any sense to look after a name in a property type
// report an error.
reportNameError(currentName.getPropertyName(), currentName.getPropertyName().getId());
return false;
}
} // End of while.
return true;
}
private boolean recordFieldResolver(RecordType rt, DeclarativePropertyName declPropertyName) {
String name = declPropertyName.getPropertyName().getId();
for (BasicProperty bp : rt.getOwnedFields()) {
if (bp.getName().equalsIgnoreCase(name)) {
declPropertyName.setOsateRef(bp);
declPropertyName.getPropertyName().setOsateRef(bp);
return true;
}
}
return false;
}
private boolean propertyValueResolver(PropertyExpression pe, DeclarativePropertyName currentName) {
String name = currentName.getPropertyName().getId();
try {
Element found = PropertyUtils.getValue(pe, name);
if (found != null) {
currentName.setOsateRef(found);
currentName.getPropertyName().setOsateRef(found);
return true;
} else {
return false;
}
} catch (UnsupportedOperationException e) {
return false;
}
}
private boolean propertyTypeResolver(PropertyType type, DeclarativePropertyName declPropertyName) {
int typeId = type.eClass().getClassifierID();
String name = declPropertyName.getPropertyName().getId();
switch (typeId) {
case Aadl2Package.ENUMERATION_TYPE: {
return enumerationTypeResolver((EnumerationType) type, declPropertyName);
}
case Aadl2Package.RECORD_TYPE: {
RecordType recordType = (RecordType) type;
for (BasicProperty bp : recordType.getOwnedFields()) {
if (bp.getName().equalsIgnoreCase(name)) {
declPropertyName.setOsateRef(bp);
declPropertyName.getPropertyName().setOsateRef(bp);
return true;
}
}
return false;
}
case Aadl2Package.LIST_TYPE: // Type of ListType is ListType and not its
// owned element type.
{
reportNameError(declPropertyName, name);
return false;
}
default: {
String msg = "property literals are only supported for enumeration and" + " record property type";
_errManager.error(declPropertyName, msg);
return false;
}
}
}
private boolean enumerationTypeResolver(EnumerationType type, DeclarativePropertyName declPropertyName) {
EnumerationType enumType = type;
for (EnumerationLiteral literal : enumType.getOwnedLiterals()) {
if (literal.getName().equalsIgnoreCase(declPropertyName.getPropertyName().getId())) {
declPropertyName.setOsateRef(literal);
declPropertyName.getPropertyName().setOsateRef(literal);
return true;
}
}
return false;
}
private boolean propertyDeclarationResolver(Property property, DeclarativePropertyName declProName) {
PropertyExpression pe = property.getDefaultValue();
String name = declProName.getPropertyName().getId();
if (pe != null) {
try {
Element found = PropertyUtils.getValue(pe, name);
if (found != null) {
declProName.setOsateRef(found);
declProName.getPropertyName().setOsateRef(found);
return true;
} else {
return false;
}
} catch (UnsupportedOperationException e) {
return false;
}
} else {
return false;
}
}
private boolean propertyAssociationResolver(PropertyAssociation pa, DeclarativePropertyName declProName) {
EList<PropertyExpression> pel = PropertyUtils.getPropertyExpression(pa);
PropertyExpression pe = pel.get(pel.size() - 1);
String name = declProName.getPropertyName().getId();
try {
Element tmp = PropertyUtils.getValue(pe, name);
if (tmp != null) {
declProName.setOsateRef(tmp);
declProName.getPropertyName().setOsateRef(tmp);
return true;
} else {
return false;
}
} catch (UnsupportedOperationException e) {
return false;
}
}
private BasicProperty getPropertyDeclaration(Element el) {
if (Aadl2Package.PROPERTY_ASSOCIATION == el.eClass().getClassifierID()) {
return ((PropertyAssociation) el).getProperty();
} else if (Aadl2Package.PROPERTY == el.eClass().getClassifierID()) {
return (Property) el;
} else if (el instanceof PropertyExpression) {
return PropertyUtils.getContainingProperty((PropertyExpression) el);
}
// BasicProperty EMF identifier == Aadl2Package.LIST_VALUE, why ????
else if (el instanceof BasicProperty) {
return (BasicProperty) el;
} else {
String msg = el.getClass().getSimpleName() + " is not supported";
System.err.println(msg);
throw new UnsupportedOperationException(msg);
}
}
private boolean propertyIndexAndFieldResolution(DeclarativePropertyName declProName) {
boolean hasField = declProName.getField() != null;
boolean hasIndex = declProName.isSetIndexes();
if (hasField) {
return propertyFieldResolution(declProName);
} else if (hasIndex) {
return propertyIndexResolver(declProName);
} else {
return true;
}
}
private boolean propertyFieldResolution(DeclarativePropertyName declProName) {
PropertyNameField field = declProName.getField();
Element el = declProName.getOsateRef();
BasicProperty bProperty = getPropertyDeclaration(el);
int nameTypeId = bProperty.getPropertyType().eClass().getClassifierID();
// Upper and lower bound fields are only supported for range property
// type.
if (nameTypeId == Aadl2Package.RANGE_TYPE) {
return true;
} else {
String msg = "upper or lower bound keyword are only supported for" + " range property type";
_errManager.error(field, msg);
return false;
}
}
private boolean propertyIndexResolver(DeclarativePropertyName declProName) {
Element el = declProName.getOsateRef();
BasicProperty bProperty = getPropertyDeclaration(el);
int nameTypeId = bProperty.getPropertyType().eClass().getClassifierID();
EList<IntegerValue> indexes = declProName.getIndexes();
if (nameTypeId == Aadl2Package.ENUMERATION_TYPE) {
if (indexes.size() == 1) {
return integerValueResolver(indexes.get(0));
} else {
String msg = "multiple integer index is not only supported for property enumeration";
_errManager.error(indexes.get(1), msg);
return false;
}
} else if (nameTypeId == Aadl2Package.LIST_TYPE || Aadl2Package.LIST_VALUE == el.eClass().getClassifierID()) {
for (int fieldIndex = 0; fieldIndex < indexes.size(); fieldIndex++) {
IntegerValue iv = indexes.get(fieldIndex);
if (propertyFieldIndexResolver(el, iv, bProperty, fieldIndex, declProName)) {
continue;
} else {
return false;
}
}
return true;
} else {
String msg = "integer index is only supported for list of properties or " + "property enumerations";
_errManager.error(indexes.get(0), msg);
return false;
}
}
private boolean propertyFieldIndexResolver(Element el, IntegerValue field, BasicProperty bProperty, int fieldIndex,
DeclarativePropertyName declProName) {
if (integerValueResolver(field)) {
// Link to the default value, if it exists.
if (Aadl2Package.LIST_VALUE == el.eClass().getClassifierID()
&& propertyFieldListValueResolver(field, (ListValue) el, fieldIndex, declProName)) {
return true;
} else if (Aadl2Package.PROPERTY_ASSOCIATION == el.eClass().getClassifierID()) {
PropertyAssociation pa = (PropertyAssociation) el;
ModalPropertyValue mpv = pa.getOwnedValues().get(pa.getOwnedValues().size() - 1);
PropertyExpression pe = mpv.getOwnedValue();
if (Aadl2Package.LIST_VALUE == pe.eClass().getClassifierID()) {
return propertyFieldListValueResolver(field, (ListValue) pe, fieldIndex, declProName);
}
}
// the else statements: link with the property type.
ListType lt = (ListType) bProperty.getPropertyType();
declProName.setOsateRef(lt.getElementType());
return true;
} else {
return false;
}
}
private boolean propertyFieldListValueResolver(IntegerValue field, ListValue lv, int fieldIndex,
DeclarativePropertyName declProName) {
if (AadlBaPackage.BEHAVIOR_INTEGER_LITERAL == field.eClass().getClassifierID()) {
BehaviorIntegerLiteral bil = (BehaviorIntegerLiteral) field;
Long index = bil.getValue();
return propertyFieldListIndexResolver(index.intValue(), lv, fieldIndex, declProName);
} else
// As field is an integer value variable, the integer
// value cannot be evaluated at compile time. So raise
// a warning
{
String msg = "integer variable as a property array index is not evaluated.";
_errManager.warning(declProName.getIndexes().get(fieldIndex), msg);
return false;
}
}
private boolean propertyFieldListIndexResolver(int index, ListValue lv, int fieldIndex,
DeclarativePropertyName declProName) {
if (index >= 0) {
// Check list bound:
EList<PropertyExpression> values = lv.getOwnedListElements();
if (values.size() < index) {
// Report out of bounds error.
String msg = "array out of bound, size is: " + values.size();
_errManager.error(declProName.getIndexes().get(fieldIndex), msg);
return false;
} else {
declProName.setOsateRef(values.get(index));
return true;
}
} else {
// Report out of bounds error.
String msg = "negative array bound";
_errManager.error(declProName.getIndexes().get(fieldIndex), msg);
return false;
}
}
private boolean valueExpressionResolver(ValueExpression expr) {
boolean result = true;
int seNb = 0;
SimpleExpression se;
Value v;
int vNb = 0;
// Iterates over relations.
for (Relation r : expr.getRelations()) {
se = r.getFirstExpression();
// Treats simple expression(s).
do {
// Iterates over Terms.
for (Term t : se.getTerms()) {
// Iterate over Factors.
for (Factor f : t.getFactors()) {
v = f.getFirstValue();
// Treats value(s).
do {
result &= valueResolver(v);
v = f.getSecondValue();
vNb++;
} while (v != null && vNb != 2);
vNb = 0;
} // End of for factors.
} // End of for terms.
se = r.getSecondExpression();
seNb++;
} while (se != null && seNb != 2);
seNb = 0;
} // End of for relations.
return result;
}
private boolean valueResolver(Value value) {
if (value instanceof ValueVariable) {
return valueVariableResolver(value, (ValueVariable) value);
} else if (value instanceof ValueConstant) {
return valueConstantResolver((ValueConstant) value);
} else // Case of value expression : recursive call.
{
return valueExpressionResolver((ValueExpression) value);
}
}
// Check data component ref, ba variable name or feature name contained
// in ValueVariable.
/*
* // value_variable ::=
* // incoming_port_name
* // | incoming_port_name ?
* // | incoming_port_data_component_reference
* // | port_name' count
* // | port_name' fresh
*/
private boolean valueVariableResolver(BehaviorElement toBeSet, ValueVariable value) {
if (value instanceof Reference) {
return refResolver((Reference) value);
} else // NamedValue case.
{
Reference ref = ((NamedValue) value).getReference();
return refResolver(ref);
}
}
/**
* Resolves the property expressions used in behavior annex.
* @param p
*
* @return {@code true} if all names are resolved. {@code false} otherwise.
*/
private boolean propertyExpressionResolver(BehaviorVariable bv, Property p, PropertyExpression pe) {
QualifiedNamedElement qne = (QualifiedNamedElement) p;
String propertyName = "";
boolean hasNamespace = qne.getBaNamespace() != null;
if (hasNamespace) {
propertyName = qne.getBaNamespace().getId() + "::";
}
propertyName += qne.getBaName().getId();
boolean result = true;
if (pe instanceof DeclarativeListValue) {
ListValue dlv = (DeclarativeListValue) pe;
for (PropertyExpression peInList : dlv.getOwnedListElements()) {
result &= propertyExpressionResolver(bv, p, peInList);
}
} else if (pe instanceof IntegerLiteral) {
IntegerLiteral il = (IntegerLiteral) pe;
if (il.getUnit() != null && il.getUnit() instanceof QualifiedNamedElement) {
result &= unitResolver(il, bv, p);
}
} else if (pe instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) pe;
if (rl.getUnit() != null && rl.getUnit() instanceof QualifiedNamedElement) {
result &= unitResolver(rl, bv, p);
}
} else if (pe instanceof RecordValue) {
RecordValue rv = (RecordValue) pe;
for (BasicPropertyAssociation bpa : rv.getOwnedFieldValues()) {
if (bpa instanceof DeclarativeBasicPropertyAssociation) {
DeclarativeBasicPropertyAssociation dbpa = (DeclarativeBasicPropertyAssociation) bpa;
String basicPropertyName = dbpa.getBasicPropertyName();
BasicProperty basicProp = getBasicPropertyResolver(bv, p, basicPropertyName);
if (basicProp == null) {
_errManager.error(bv, "Property field \'" + basicPropertyName + "\' of property " + propertyName
+ " is not found");
result = false;
}
dbpa.setProperty(basicProp);
}
}
} else if (pe instanceof RangeValue) {
RangeValue rv = (RangeValue) pe;
result &= propertyExpressionResolver(bv, p, rv.getMaximum());
result &= propertyExpressionResolver(bv, p, rv.getMinimum());
} else if (pe instanceof ReferenceValue) {
ReferenceValue rv = (ReferenceValue) pe;
Reference r = (Reference) (rv.getPath());
ContainmentPathElement firstCne = Aadl2Factory.eINSTANCE.createContainmentPathElement();
ContainmentPathElement prevCne = null;
boolean first = true;
Classifier context = _baParentContainer;
for (Identifier subPath : r.getIds()) {
ContainmentPathElement currentCne;
if (!first) {
currentCne = Aadl2Factory.eINSTANCE.createContainmentPathElement();
} else {
currentCne = firstCne;
}
first = false;
NamedElement ne = Aadl2Visitors.findSubcomponentInComponent(context, subPath.getId());
if (ne == null) {
ne = Aadl2Visitors.findFeatureInComponent(context, subPath.getId());
}
if (ne == null) {
_errManager.error(bv, "Element \'" + subPath.getId() + "\' is not found in " + context.getName()
+ "(property " + propertyName + ")");
result = false;
} else {
currentCne.setNamedElement(ne);
if (prevCne != null) {
prevCne.setPath(currentCne);
}
if (ne instanceof Subcomponent) {
Subcomponent sub = (Subcomponent) ne;
context = sub.getClassifier();
} else if (ne instanceof Feature) {
Feature f = (Feature) ne;
context = f.getClassifier();
}
}
prevCne = currentCne;
}
rv.setPath(firstCne);
} else if (pe instanceof ClassifierValue) {
ClassifierValue cv = (ClassifierValue) pe;
QualifiedNamedElement classifierQne = (QualifiedNamedElement) cv.getClassifier();
String qneClassPackageName = "";
boolean qneClassHasNamespace = classifierQne.getBaNamespace() != null;
if (qneClassHasNamespace) {
qneClassPackageName = classifierQne.getBaNamespace().getId();
}
boolean resolved = false;
for (PackageSection context : _contextsTab) {
NamedElement ne = Aadl2Visitors.findElementInPackage(classifierQne.getBaName().getId(),
qneClassPackageName, context);
if (ne != null && ne instanceof Classifier) {
cv.setClassifier((Classifier) ne);
resolved = true;
break;
}
}
if (!resolved) {
String cvQualifiedName = "";
if (!qneClassPackageName.isEmpty()) {
cvQualifiedName += qneClassPackageName + "::";
}
cvQualifiedName += classifierQne.getBaName().getId();
_errManager.error(bv, "Classifier \'" + cvQualifiedName + "\' associated to property " + propertyName
+ " is not found");
result = false;
}
}
return result;
}
private BasicProperty getBasicPropertyResolver(BehaviorVariable bv, Property p, String basicPropertyName) {
QualifiedNamedElement qne = (QualifiedNamedElement) p;
Property propNE = resolveProperty(qne);
PropertyType pt = propNE.getPropertyType();
if (pt instanceof RecordType) {
RecordType rt = (RecordType) pt;
for (BasicProperty bp : rt.getOwnedFields()) {
if (bp.getName().equalsIgnoreCase(basicPropertyName)) {
return bp;
}
}
}
return null;
}
private Property resolveProperty(QualifiedNamedElement qne) {
String packageName = "";
boolean hasNamespace = qne.getBaNamespace() != null;
if (hasNamespace) {
packageName = qne.getBaNamespace().getId();
}
NamedElement propNE = Aadl2Visitors.findElementInPropertySet(qne.getBaName().getId(), packageName,
Aadl2Visitors.getContainingPackageSection(_ba));
return (Property) propNE;
}
/**
* Resolves units used in behavior annex.
* @param p
*
* @return {@code true} if all names are resolved. {@code false} otherwise.
*/
private boolean unitResolver(NumberValue nv, BehaviorVariable bv, Property p) {
boolean result = true;
QualifiedNamedElement qne = (QualifiedNamedElement) p;
Property propNE = resolveProperty(qne);
if (propNE != null) {
Property prop = propNE;
String unitLiteralName = ((QualifiedNamedElement) nv.getUnit()).getBaName().getId();
UnitLiteral ul = PropertiesLinkingService.findUnitLiteral(prop, unitLiteralName);
if (ul != null) {
nv.setUnit(ul);
} else {
_errManager.error(bv, "Unit \'" + unitLiteralName + "\' is not found");
result = false;
}
} else {
result = false;
}
return result;
}
/**
* Resolves the behavior annex's variables.
*
* @return {@code true} if all names are resolved. {@code false} otherwise.
*/
private boolean behaviorVariableResolver() {
boolean result = true;
QualifiedNamedElement uccr;
// For each behavior variable, check if declared unique component
// classifier reference exists.
for (BehaviorVariable v : _ba.getVariables()) {
uccr = (QualifiedNamedElement) v.getDataClassifier();
result &= qualifiedNamedElementResolver(uccr, true);
for (ArrayDimension tmp : v.getArrayDimensions()) {
IntegerValueConstant ivc = ((DeclarativeArrayDimension) tmp).getDimension();
result &= integerValueConstantResolver(ivc);
}
List<PropertyAssociation> paList = v.getOwnedPropertyAssociations();
List<PropertyAssociation> paPropertyNotFound = new ArrayList<PropertyAssociation>();
Set<PropertyAssociation> paPropertyValueError = new HashSet<PropertyAssociation>();
for (PropertyAssociation pa : paList) {
QualifiedNamedElement p = (QualifiedNamedElement) pa.getProperty();
boolean valid = qualifiedNamedElementResolver(p, false);
if (valid) {
for (ModalPropertyValue mpv : pa.getOwnedValues()) {
result &= propertyExpressionResolver(v, p, mpv.getOwnedValue());
paPropertyValueError.add(pa);
}
}
if (!valid) {
paPropertyNotFound.add(pa);
}
result &= valid;
}
StringBuilder msg = new StringBuilder();
if (paPropertyNotFound.size() > 1) {
msg.append("Properties ");
} else {
msg.append("Property ");
}
boolean first = true;
for (PropertyAssociation paToRemove : paPropertyNotFound) {
QualifiedNamedElement p = (QualifiedNamedElement) paToRemove.getProperty();
StringBuilder qualifiedName = new StringBuilder();
if (p.getBaNamespace() != null) {
qualifiedName.append(p.getBaNamespace().getId());
qualifiedName.append("::");
}
qualifiedName.append(p.getBaName().getId());
if (first) {
msg.append("\'" + qualifiedName + "\' ");
} else {
msg.append(" and \'" + qualifiedName + "\' ");
}
first = false;
}
paList.removeAll(paPropertyNotFound);
paList.removeAll(paPropertyValueError);
if (paPropertyNotFound.size() > 0) {
msg.append("not found");
_errManager.error(v, msg.toString());
}
}
return result;
}
// TODO Provide column number.
private void reportNameError(BehaviorElement el, String name) {
_errManager.error(el, "\'" + name + "\' is not found");
}
}