예제 #1
0
        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);
                }
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        /// <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));
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
                    }
                }
            }
        }
예제 #8
0
 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);
 }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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);
        }
예제 #16
0
 private EssentialOCL.IVariable ConstructVariable(QVTRelations.IRelation relation, EnAr.Element objectElement)
 {
     return(ConstructVariable(relation, objectElement.Name, emofImporter.ConstructTypeOfTyped(objectElement)));
 }