private void ConstructBasicRelation(QVTRelations.IRelationalTransformation transformation, EnAr.Element relationElement) { // First we check if an empty relation doesn't already exist QVTRelations.IRelation relation = FindRelation(transformation, relationElement.Name); // If not, we create it if (relation == null) { relation = new QVTRelations.Relation() { Name = relationElement.Name }; transformation.Rule.Add(relation); // We find the unique child EA elements with the stereotype "qvtTransformationNode" List <EnAr.Element> transformationNodeElements = explorer.GetChildrenElementsWithTypeAndStereotype(relationElement, "class", "qvtTransformationNode"); EnAr.Element transformationNodeElement = transformationNodeElements.Single(); bool isTopRelation = explorer.GetTaggedValue(relationElement, "isTopRelation").ToLower() == "true"; relation.IsTopLevel = isTopRelation; relation.Transformation = transformation; relation.Overrides = null; // TODO // We browse the EA Connectors with the stereotype "qvtTransformationLink", from the qvtTransformationNode // We use the concrete syntax extension to order the domains foreach (EnAr.Connector qvtTransformationLinkConnector in explorer.GetConnectorsWithSourceWithStereotype(transformationNodeElement, "qvtTransformationLink").OrderBy(c => c.Name)) { ConstructRelationDomain(transformation, relation, qvtTransformationLinkConnector); } } }
private static ISet <EMOF.IClass> FindAllClassesUsedInRelation(QVTRelations.IRelation relation) { ISet <EMOF.IClass> result = new HashSet <EMOF.IClass>(); foreach (QVTTemplate.IObjectTemplateExp objectTemplateExp in relation.Domain.OfType <QVTRelations.IRelationDomain>().Where(d => d.Pattern != null).Select(d => d.Pattern.TemplateExpression).OfType <QVTTemplate.IObjectTemplateExp>()) { result.AddRange(FindAllClassesUsedByObjectTemplate(objectTemplateExp)); } return(result); }
/// <summary> /// Construct the OCLExpression corresponding to some CSharp expression included in the model. /// Try to create pure OCL, fallback to custom CSharpExpression object if not handled. /// </summary> /// <param name="relation">The relation containing the expression.</param> /// <param name="domainPattern">(optional) The domainPattern containing the expression.</param> /// <param name="expressionString">The expression string to parse.</param> /// <returns></returns> private EssentialOCL.IOclExpression ConstructOCLExpression(QVTRelations.IRelation relation, string expressionString, QVTBase.IPattern pattern, EMOF.IType type) { // To be able to reuse existing transfos: we consider strings with single quotes as well string expressionWithOnlyDoubleQuotes = expressionString.Replace("\'", "\""); // We parse using Roslyn ExpressionSyntax parsedExpression = CSharpParser.ParseExpression(expressionWithOnlyDoubleQuotes); // And we use the expression analysis overload variant return(ConstructOCLExpression(relation, parsedExpression, pattern, type)); }
private void SetBindings(QVTRelations.IRelation relation, QVTBase.IPattern pattern, EssentialOCL.CSharpOpaqueExpression cSharpOpaqueExpression, ExpressionSyntax parsedExpression) { ISet <string> extractedIdentifiers = CSharpParser.ExtractNonMethodIdentifiersFromExpression(parsedExpression); foreach (string extractedIdentifier in extractedIdentifiers) { EssentialOCL.IVariable variable = ConstructVariable(relation, extractedIdentifier); pattern?.BindsTo.Add(variable); cSharpOpaqueExpression.BindsTo.Add(variable); } }
private QVTRelations.IDomainPattern ConstructDomainPattern(QVTRelations.IRelation relation, EnAr.Element domainObjectElement) { QVTRelations.IDomainPattern domainPattern = new QVTRelations.DomainPattern() { // Predicate = null, // TODO }; QVTTemplate.IObjectTemplateExp objectTemplateExp = ConstructObjectTemplateExp(relation, domainPattern, domainObjectElement); domainPattern.TemplateExpression = objectTemplateExp; return(domainPattern); }
private QVTRelations.IRelationDomain ConstructPrimitiveRelationDomain(QVTRelations.IRelation relation, EnAr.Connector qvtTransformationLinkConnector, EnAr.Element domainObjectElement) { EssentialOCL.IVariable variable = ConstructVariable(relation, domainObjectElement); QVTRelations.IRelationDomain relationDomain = new QVTRelations.RelationDomain { Name = qvtTransformationLinkConnector.Name, // a primitive domain is supposed not to have a name, but we use it for ordering IsCheckable = true, IsEnforceable = false, //DefaultAssignment = null // TODO? Rule = relation, RootVariable = variable }; relation.Variable.Add(variable); return(relationDomain); }
private void FinishRelation(QVTRelations.RelationalTransformation transformation, EnAr.Element relationElement) { // We use the existing Relation object QVTRelations.IRelation relation = FindRelation(transformation, relationElement.Name); // We look for the tag "where" string whereCode = explorer.GetTaggedValue(relationElement, "Where"); if (!string.IsNullOrWhiteSpace(whereCode)) { relation.Where = ConstructWhenOrWherePattern(relation, whereCode); } // We look for the tag "when" string whenCode = explorer.GetTaggedValue(relationElement, "When"); if (!string.IsNullOrWhiteSpace(whenCode)) { relation.When = ConstructWhenOrWherePattern(relation, whenCode); } // We look for the tag 'qvtKey' string qvtKeyString = explorer.GetTaggedValue(relationElement, "qvtKey"); if (!string.IsNullOrWhiteSpace(qvtKeyString)) { relationsWithKeys.Add(relation); ISet <EMOF.IClass> classes = FindAllClassesUsedInRelation(relation); IList <QvtKeyParserResult> parsed = QvtKeyParser.Parse(qvtKeyString); foreach (QvtKeyParserResult keyParserResult in parsed) { QVTRelations.IKey key = ConstructKey(classes, keyParserResult); QVTRelations.IKey existingKey = relation.Keys().FirstOrDefault(k => k.Identifies == key.Identifies); if (existingKey == null) { relation.Keys().Add(key); } else { MergeKeyInto(existingKey, key); } } } }
private EssentialOCL.IVariable ConstructVariable(QVTRelations.IRelation relation, string name, EMOF.IType type = null) { EssentialOCL.IVariable variable = relation.Variable.FirstOrDefault(v => v.Name == name); if (variable == null) { variable = new EssentialOCL.Variable() { Name = name, Type = type, InitExpression = null, // Not taken into account }; relation.Variable.Add(variable); } // If there was an existing variable, but with no type yet, we give it the input type else if (variable.Type == null && type != null) { variable.Type = type; } return(variable); }
private QVTBase.IPattern ConstructWhenOrWherePattern(QVTRelations.IRelation relation, string whenOrwhereCode) { QVTBase.Pattern result = new QVTBase.Pattern(); List <StatementSyntax> instructions = CSharpParser.ParseInstructions(whenOrwhereCode); //TODO Filter ExpressionStatementSyntax is too restrictive, we must also create opaque expressions with eg. conditionnals foreach (ExpressionStatementSyntax expressionStatementSyntax in instructions.OfType <ExpressionStatementSyntax>()) { ExpressionSyntax expression = expressionStatementSyntax.Expression; EssentialOCL.IOclExpression oclExpression = ConstructOCLExpression(relation, expression, result); QVTBase.IPredicate predicate = new QVTBase.Predicate() { Pattern = result, ConditionExpression = oclExpression, }; result.Predicate.Add(predicate); } return(result); }
private QVTTemplate.IPropertyTemplateItem ConstructPropertyTemplateItem(QVTRelations.IRelation relation, QVTRelations.IDomainPattern domainPattern, QVTTemplate.IObjectTemplateExp objectTemplateExp, RunStateField runStateField) { ISet <EMOF.IProperty> atts = objectTemplateExp.ReferredClass.GetAllInheritedAttributes(); EMOF.IProperty property = atts.Single(p => string.Equals(p.Name, runStateField.Variable, StringComparison.CurrentCultureIgnoreCase)); QVTTemplate.IPropertyTemplateItem propertyTemplateItem = null; if (property != null) { EssentialOCL.IOclExpression expression = ConstructOCLExpression(relation, runStateField.Value, domainPattern, property.Type); propertyTemplateItem = new QVTTemplate.PropertyTemplateItem() { ReferredProperty = property, Value = expression, IsOpposite = false, // TODO? ObjContainer = objectTemplateExp }; } return(propertyTemplateItem); }
private QVTRelations.IRelationDomain ConstructNonPrimitiveRelationDomain(QVTRelations.IRelation relation, QVTBase.ITypedModel typedModel, EnAr.Connector qvtTransformationLinkConnector, EnAr.Element domainObjectElement) { //if (domainObjectElement.Stereotype != "domain") // throw new InvalidQVTRelationsModelException("A domain element must have the \"domain\" stereotype", domainObjectElement); // TODO replace by warning? QVTRelations.RelationDomain relationDomain = new QVTRelations.RelationDomain() { Name = qvtTransformationLinkConnector.Name, IsCheckable = true, IsEnforceable = explorer.GetTaggedValue(qvtTransformationLinkConnector, "CEType").ToLower() == "enforce", TypedModel = typedModel, //DefaultAssignment = null // TODO Rule = relation }; QVTRelations.IDomainPattern domainpattern = ConstructDomainPattern(relation, domainObjectElement); relationDomain.Pattern = domainpattern; relationDomain.RootVariable = domainpattern.TemplateExpression.BindsTo; domainpattern.RelationDomain = relationDomain; return(relationDomain); }
private QVTTemplate.IObjectTemplateExp ConstructObjectTemplateExp(QVTRelations.IRelation relation, QVTRelations.IDomainPattern domainPattern, EnAr.Element objectElement, ISet <EnAr.Connector> visitedConnectors = null) { EssentialOCL.IVariable variable = null; EMOF.IType type = emofImporter.ConstructTypeOfTyped(objectElement); // TODO manage the not ? if (objectElement.Name != "{not}") { variable = ConstructVariable(relation, objectElement); domainPattern?.BindsTo.Add(variable); } QVTTemplate.IObjectTemplateExp objectTemplateExp = new QVTTemplate.ObjectTemplateExp() { BindsTo = variable, ReferredClass = type as EMOF.IClass, Where = null // TODO }; objectTemplateExp.SetAntiTemplate(variable == null); objectElementToObjectTemplate.Add(objectElement, objectTemplateExp); foreach (RunStateField runStateField in EnArExplorer.GetRunState(objectElement)) { ConstructPropertyTemplateItem(relation, domainPattern, objectTemplateExp, runStateField); } foreach (EnAr.Connector connector in explorer.GetConnectorsLinkedTo(objectElement).FindAll(c => c.Stereotype != "qvtTransformationLink")) { Tuple <EnAr.ConnectorEnd, EnAr.Element> linked = explorer.GetElementOppositeTo(objectElement, connector); EnAr.ConnectorEnd connectorEnd = linked.Item1; EnAr.Element linkedElement = linked.Item2; //if (!string.IsNullOrWhiteSpace(connectorEnd.Role)) //{ ConstructPropertyTemplateItem(relation, domainPattern, objectTemplateExp, connector, connectorEnd, linkedElement, visitedConnectors); //} } return(objectTemplateExp); }
private QVTTemplate.IPropertyTemplateItem ConstructPropertyTemplateItem(QVTRelations.IRelation relation, QVTRelations.IDomainPattern domainPattern, QVTTemplate.IObjectTemplateExp objectTemplateExp, EnAr.Connector connector, EnAr.ConnectorEnd connectorEnd, EnAr.Element linkedElement, ISet <EnAr.Connector> visitedConnectors) { EssentialOCL.IOclExpression value; EMOF.IType type; QVTTemplate.IObjectTemplateExp targetObjectTemplateExp; ISet <EnAr.Connector> realVisitedConnectors = visitedConnectors ?? new HashSet <EnAr.Connector>(); ISet <EnAr.Connector> realVisitedConnectorsPropagated = new HashSet <EnAr.Connector>(realVisitedConnectors); realVisitedConnectorsPropagated.Add(connector); // Case cycle among object templates: simple variable expression if (objectElementToObjectTemplate.ContainsKey(linkedElement)) { targetObjectTemplateExp = objectElementToObjectTemplate[linkedElement]; EssentialOCL.IVariable existingVariable = targetObjectTemplateExp.BindsTo; value = new EssentialOCL.VariableExp() { ReferredVariable = existingVariable }; type = existingVariable.Type; } // Case no cycle; recursive creation of object template else { targetObjectTemplateExp = ConstructObjectTemplateExp(relation, domainPattern, linkedElement, realVisitedConnectorsPropagated); value = targetObjectTemplateExp; type = ((QVTTemplate.IObjectTemplateExp)value).BindsTo.Type; } EMOF.IProperty property = null; // If the connector end has a role, we use it to find the corresponding EMOF property if (!string.IsNullOrWhiteSpace(connectorEnd.Role)) { property = objectTemplateExp.ReferredClass.GetAllInheritedAttributes().Single(p => p.Name == connectorEnd.Role); } // If the connector end has no role (due to the else) // AND if we haven't visited the connector yet // AND if the connector has no roles whatsoever, we try to guess the type else if (!realVisitedConnectors.Contains(connector) && connector.ClientEnd.Role.IsNullOrEmpty() && connector.SupplierEnd.Role.IsNullOrEmpty()) { IList <EMOF.IProperty> candidateProperties = objectTemplateExp.ReferredClass.GetAllInheritedAttributes().Where(p => (p.Type as EMOF.IClass)?.GetAllSubTypes().Contains(type) ?? p.Type == type).ToList(); if (candidateProperties.Count == 0) { throw new InvalidQVTRelationsModelException("Relation " + relation.Name + ", invalid property connector between " + objectTemplateExp.BindsTo.Name + " and " + targetObjectTemplateExp.BindsTo.Name + ", no possible property", connector); } if (candidateProperties.Count > 1) { throw new InvalidQVTRelationsModelException("Relation " + relation.Name + ", ambiguous property connector between " + objectTemplateExp.BindsTo.Name + " and " + targetObjectTemplateExp.BindsTo.Name + ", cannot choose a property between the following: [" + string.Join(";", candidateProperties.Select(p => p.Name)) + "]", connector); } property = candidateProperties.Single(); } QVTTemplate.PropertyTemplateItem propertyTemplateItem = null; if (property != null) { propertyTemplateItem = new QVTTemplate.PropertyTemplateItem() { ReferredProperty = property, Value = value, IsOpposite = false, // TODO? ObjContainer = objectTemplateExp }; } return(propertyTemplateItem); }
private EssentialOCL.IOclExpression ConstructOCLExpression(QVTRelations.IRelation relation, ExpressionSyntax parsedExpression, QVTBase.IPattern pattern, EMOF.IType type = null) { // Case single identifier => OCL VariableExp if (parsedExpression is IdentifierNameSyntax) { EssentialOCL.IVariable variable = ConstructVariable(relation, parsedExpression.ToString(), type); pattern?.BindsTo.Add(variable); return(new EssentialOCL.VariableExp() { ReferredVariable = variable }); } // Case method call => QVT RelationCallExp (if the relation exists) of function call (if the function exists) if (parsedExpression is InvocationExpressionSyntax) { InvocationExpressionSyntax invocationExpressionSyntax = (InvocationExpressionSyntax)parsedExpression; // We are only interested in direct calls if (invocationExpressionSyntax.Expression is IdentifierNameSyntax) { IdentifierNameSyntax methodIdentifier = (IdentifierNameSyntax)invocationExpressionSyntax.Expression; ArgumentListSyntax argumentList = invocationExpressionSyntax.ArgumentList; QVTRelations.IRelation calledRelation = FindRelation((QVTRelations.IRelationalTransformation)(relation.Transformation), methodIdentifier.ToString()); QVTBase.IFunction calledFunction = FindFunction((QVTRelations.IRelationalTransformation)(relation.Transformation), methodIdentifier.ToString()); if (calledRelation != null) { QVTRelations.RelationCallExp call = new QVTRelations.RelationCallExp { ReferredRelation = calledRelation }; if (argumentList.Arguments.Count != calledRelation.Domain.Count) { throw new InvalidQVTRelationsModelException("Relation " + relation.Name + ": wrong number of arguments in relation call " + calledRelation.Name); } foreach (ArgumentSyntax argumentSyntax in argumentList.Arguments) { QVTRelations.IRelationDomain correspondingDomain = (QVTRelations.IRelationDomain)calledRelation.Domain[argumentList.Arguments.IndexOf(argumentSyntax)]; ExpressionSyntax argumentExpression = argumentSyntax.Expression; EssentialOCL.IOclExpression argumentOCLExpression = ConstructOCLExpression(relation, argumentExpression, pattern, correspondingDomain.RootVariable.Type); call.Argument.Add(argumentOCLExpression); } return(call); } else if (calledFunction != null) { string methodname = methodIdentifier.ToString(); EssentialOCL.IOperationCallExp call = new EssentialOCL.OperationCallExp() { Type = calledFunction.Type, ReferredOperation = calledFunction, Name = calledFunction.Name, }; foreach (ArgumentSyntax argumentSyntax in argumentList.Arguments) { ExpressionSyntax argumentExpression = argumentSyntax.Expression; EssentialOCL.IOclExpression argumentOCLExpression = ConstructOCLExpression(relation, argumentExpression, pattern, calledFunction.Type); call.Argument.Add(argumentOCLExpression); } return(call); } } } // Case assignment => Custom Assignment //TODO replace by OCL '=='? Meaning having to provide basic parts of OCL standard lib if (parsedExpression is AssignmentExpressionSyntax) { AssignmentExpressionSyntax assignmentExpressionSyntax = (AssignmentExpressionSyntax)parsedExpression; IdentifierNameSyntax leftIdentifier = (IdentifierNameSyntax)assignmentExpressionSyntax.Left; ExpressionSyntax right = assignmentExpressionSyntax.Right; EssentialOCL.IVariable variable = ConstructVariable(relation, leftIdentifier.ToString()); pattern?.BindsTo.Add(variable); return(new EssentialOCL.Assignment() { AssignedVariable = variable, Value = ConstructOCLExpression(relation, right, pattern) }); } // Any other case => Custom CSharpOpaqueExpression // TODO replace by QVT "Function" with a black box implementation? EssentialOCL.CSharpOpaqueExpression cSharpOpaqueExpression = new EssentialOCL.CSharpOpaqueExpression() { Code = parsedExpression.ToString() }; SetBindings(relation, pattern, cSharpOpaqueExpression, parsedExpression); return(cSharpOpaqueExpression); }
private void ConstructRelationDomain(QVTRelations.IRelationalTransformation relationTransformation, QVTRelations.IRelation relation, EnAr.Connector qvtTransformationLinkConnector) { // We look in the EA "domain" Element pointed by the qvtTransformationLinkConnector EnAr.Element domainObjectElement = explorer.GetTargetElement(qvtTransformationLinkConnector); // We construct (or get) the typed model, if any QVTBase.ITypedModel candidateTypedModel = ConstructTypedModel(relationTransformation, qvtTransformationLinkConnector); // If no typed model, it must be a primitive type // TODO maybe check for a tag? if (candidateTypedModel == null) { ConstructPrimitiveRelationDomain(relation, qvtTransformationLinkConnector, domainObjectElement); return; } // Else, we construct a regular domain ConstructNonPrimitiveRelationDomain(relation, candidateTypedModel, qvtTransformationLinkConnector, domainObjectElement); }
private EssentialOCL.IVariable ConstructVariable(QVTRelations.IRelation relation, EnAr.Element objectElement) { return(ConstructVariable(relation, objectElement.Name, emofImporter.ConstructTypeOfTyped(objectElement))); }