Beispiel #1
0
        private void CheckWellFormedness(UnionOrComposeModuleExpr composeExpr)
        {
            if (composeExpr.ModuleInfo != null)
            {
                return;
            }

            //check that all component modules are wellformed
            foreach (var module in composeExpr.ComponentModules)
            {
                CheckWellFormedness(module);
            }

            //check if the current module is wellformed


            // TODO: Woah, this is O(n^2). Can we get this down to O(n log n) at most?
            foreach (var module1 in composeExpr.ComponentModules)
            {
                foreach (var module2 in composeExpr.ComponentModules)
                {
                    if (module1 == module2)
                    {
                        continue;
                    }

                    var module1Info      = module1.ModuleInfo;
                    var module2Info      = module2.ModuleInfo;
                    var allPrivateEvents = module1Info
                                           .PrivateEvents.Events
                                           .Union(module2Info.PrivateEvents.Events).ToList();
                    var allSendAndReceiveEvents =
                        module1Info.Sends.Events.Union(
                            module1Info.Receives.Events.Union(
                                module2Info.Receives.Events.Union(
                                    module2Info.Sends.Events))).ToList();

                    // 1) domain of interface def map is disjoint
                    foreach (var @interface in module1Info.InterfaceDef.Keys.Intersect(
                                 module2Info.InterfaceDef.Keys))
                    {
                        throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                             "bound interfaces after composition are not disjoint, e.g., " +
                                                             $"interface {@interface.Name} is bound in both the modules being composed");
                    }

                    // 2) no private events in the sends or receives events
                    foreach (var @event in allSendAndReceiveEvents.Intersect(allPrivateEvents))
                    {
                        throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                             "private events after composition are not disjoint from send and receives set, e.g., " +
                                                             $"after composition private event {@event.Name} belongs to both private and public (sends or receives) events");
                    }

                    // 3) no private events in the sends or receives permissions
                    foreach (var @event in allSendAndReceiveEvents)
                    {
                        var permissionsEmbedded = GetPermissions(@event.PayloadType.AllowedPermissions?.Value);
                        foreach (var privatePermission in allPrivateEvents.Where(
                                     ev => permissionsEmbedded.Contains(ev)))
                        {
                            throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                                 "private events after composition are not disjoint from permissions in events sent or received, e.g., " +
                                                                 $"after composition private event {privatePermission.Name} is in the permissions set of {@event.Name}");
                        }
                    }


                    var interfaceImplAndNotCreated1 =
                        module1Info.Creates.Interfaces.Except(module1Info.InterfaceDef.Keys);
                    var interfaceCreatedAndNotImpl1 =
                        module1Info.InterfaceDef.Keys.Except(module1Info.Creates.Interfaces);
                    var interfaceImplAndNotCreated2 =
                        module2Info.Creates.Interfaces.Except(module2Info.InterfaceDef.Keys);
                    var interfaceCreatedAndNotImpl2 =
                        module2Info.InterfaceDef.Keys.Except(module2Info.Creates.Interfaces);

                    foreach (var @interface in interfaceImplAndNotCreated1.Union(
                                 interfaceCreatedAndNotImpl1.Union(
                                     interfaceImplAndNotCreated2.Union(interfaceCreatedAndNotImpl2))))
                    {
                        foreach (var @event in allPrivateEvents.Where(
                                     ev => @interface.ReceivableEvents.Contains(ev)))
                        {
                            throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                                 $"After composition, private event {@event.Name} is in the received events of interface {@interface.Name} which is created or bound in the module");
                        }
                    }

                    // ensure also that the monitor maps are disjoint
                    foreach (var monitor in module1Info.MonitorMap.Keys.Intersect(module2Info.MonitorMap.Keys))
                    {
                        throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                             $"monitor {monitor.Name} is attached in more than one modules being composed");
                    }

                    // if composition then output actions must be disjoint
                    if (composeExpr.IsComposition)
                    {
                        foreach (var @event in module1Info.Sends.Events.Intersect(module2Info.Sends.Events))
                        {
                            throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                                 $"output sends are not disjoint, {@event.Name} belongs to the sends of multiple composed module");
                        }

                        foreach (var @interface in module1Info.Creates.Interfaces.Intersect(
                                     module2Info.Creates.Interfaces))
                        {
                            throw handler.InvalidCompositionExpr(module1.SourceLocation,
                                                                 $"output creates are not disjoint, {@interface.Name} belongs to the creates of multiple composed module");
                        }
                    }

                    foreach (var exportedOrCreatedInterface in module1.ModuleInfo.InterfaceDef.Keys.Union(module1.ModuleInfo
                                                                                                          .Creates.Interfaces))
                    {
                        foreach (var priEvent in module2.ModuleInfo.PrivateEvents.Events.Where(ev =>
                                                                                               GetPermissions(exportedOrCreatedInterface.PayloadType.AllowedPermissions?.Value).Contains(ev)))
                        {
                            throw handler.InvalidHideEventExpr(module2.SourceLocation,
                                                               $"private event {priEvent.Name} belongs to the permissions of the constructor type of public interface {exportedOrCreatedInterface.Name}");
                        }
                    }
                }
            }


            composeExpr.ModuleInfo = new ModuleInfo();
            var currentModuleInfo = composeExpr.ModuleInfo;

            //populate the attributes of the module

            foreach (var module in composeExpr.ComponentModules.Select(cm => cm.ModuleInfo))
            {
                currentModuleInfo.PrivateEvents.AddEvents(module.PrivateEvents.Events);
                currentModuleInfo.PrivateInterfaces.AddInterfaces(module.PrivateInterfaces.Interfaces);

                foreach (var monMap in module.MonitorMap)
                {
                    currentModuleInfo.MonitorMap[monMap.Key] = monMap.Value.ToList();
                }

                foreach (var linkMapItem in module.LinkMap)
                {
                    currentModuleInfo.LinkMap[linkMapItem.Key] = new Dictionary <Interface, Interface>();
                    foreach (var localLinkMap in linkMapItem.Value)
                    {
                        currentModuleInfo.LinkMap[linkMapItem.Key].Add(localLinkMap.Key, localLinkMap.Value);
                    }
                }

                foreach (var ipItem in module.InterfaceDef)
                {
                    currentModuleInfo.InterfaceDef.Add(ipItem.Key, ipItem.Value);
                }
            }

            // compute all the derived attributes
            currentModuleInfo.Sends.AddEvents(composeExpr.ComponentModules.SelectMany(m => m.ModuleInfo.Sends.Events));
            currentModuleInfo.Receives.AddEvents(
                composeExpr.ComponentModules.SelectMany(m => m.ModuleInfo.Receives.Events));
            currentModuleInfo.Creates.AddInterfaces(
                composeExpr.ComponentModules.SelectMany(m => m.ModuleInfo.Creates.Interfaces));
        }