------------------------------------------------- ------------------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- O C A R I N A . A N A L Y Z E R . L E G A L I T Y _ R U L E S -- -- -- -- B o d y -- -- -- -- Copyright (C) 2006-2007, GET-Telecom Paris. -- -- -- -- Ocarina is free software; you can redistribute it and/or modify -- -- it under terms of the GNU General Public License as published by the -- -- Free Software Foundation; either version 2, or (at your option) any -- -- later version. Ocarina 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 GNU General -- -- Public License for more details. You should have received a copy of the -- -- GNU General Public License distributed with Ocarina; see file COPYING. -- -- If not, write to the Free Software Foundation, 51 Franklin Street, Fifth -- -- Floor, Boston, MA 02111-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- Ocarina is maintained by the Ocarina team -- -- (ocarina-users@listes.enst.fr) -- -- -- ------------------------------------------------------------------------------ with Locations; with Ocarina.Nodes; with Ocarina.Nutils; with Ocarina.Analyzer.Messages; with Ocarina.Entities.Components.Connections; package body Ocarina.Analyzer.Legality_Rules is use Locations; use Ocarina.Nodes; use Ocarina.Nutils; use Ocarina.Analyzer.Messages; use Ocarina.Entities.Components; use Ocarina.Entities.Components.Connections; function Check_Rules_In_Component_Type (Node : Node_Id; Rules : AADL_Legality_Rules) return Boolean; function Check_Rules_In_Component_Implementation (Node : Node_Id; Rules : AADL_Legality_Rules) return Boolean; ---------------------------- -- A_Component_Connection -- ---------------------------- function A_Component_Connection (Component : Node_Id; Connection : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Connection)); pragma Unreferenced (Rules); OK : Boolean; Component_Categ : Component_Category; Connection_Categ : Connection_Type; begin if Kind (Component) /= K_Component_Implementation then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component implementation"); return False; end if; if Kind (Connection) /= K_Connection then DAE (Loc => Loc (Connection), Node1 => Connection, Message1 => " is not a connection."); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); Connection_Categ := Connection_Type'Val (Category (Connection)); case Component_Categ is when CC_Data => OK := Connection_Categ = CT_Access_Bus or else Connection_Categ = CT_Access_Data; when CC_Subprogram | CC_System | CC_Threadgroup | CC_Process | CC_Thread => OK := True; when CC_Bus | CC_Processor | CC_Memory | CC_Device | CC_Unknown => OK := False; end case; if OK then return True; else DAE (Loc => Loc (Connection), Node1 => Component, Node2 => Connection, Message1 => "cannot have ", Message2 => " as a connection"); return False; end if; end A_Component_Connection; ------------------------- -- A_Component_Feature -- ------------------------- function A_Component_Feature (Component : Node_Id; Feature : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Feature)); OK : Boolean; Component_Categ : Component_Category; begin if Kind (Component) /= K_Component_Type and then not Is_Refinement (Feature) then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component type"); return False; end if; if Kind (Feature) /= K_Port_Group_Spec and then Kind (Feature) /= K_Port_Spec and then Kind (Feature) /= K_Parameter and then Kind (Feature) /= K_Subprogram_Spec and then Kind (Feature) /= K_Subcomponent_Access then DAE (Loc => Loc (Feature), Node1 => Feature, Message1 => " not a feature."); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); case Rules is when Standard => case Component_Categ is when CC_Data => OK := (Kind (Feature) = K_Subprogram_Spec or else (Kind (Feature) = K_Subcomponent_Access and then Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data)); when CC_Subprogram => OK := Kind (Feature) = K_Parameter or else Kind (Feature) = K_Port_Group_Spec or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data) or else (Kind (Feature) = K_Port_Spec and then not Is_In (Feature) and then Is_Event (Feature)); when CC_Thread | CC_Threadgroup | CC_Process => OK := Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Port_Spec or else (Kind (Feature) = K_Subcomponent_Access and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data) or else (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)); when CC_Processor => OK := ((Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else Kind (Feature) = K_Port_Spec or else Kind (Feature) = K_Port_Group_Spec or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Bus)); when CC_Memory | CC_Bus => OK := Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Bus; when CC_Device => OK := Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Port_Spec or else (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Bus); when CC_System => OK := (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else Kind (Feature) = K_Port_Spec or else Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Subcomponent_Access; when others => OK := False; end case; when Devel => case Component_Categ is when CC_Data => OK := (Kind (Feature) = K_Subprogram_Spec or else (Kind (Feature) = K_Subcomponent_Access and then Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data)); when CC_Subprogram => OK := Kind (Feature) = K_Parameter or else Kind (Feature) = K_Port_Group_Spec or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data) or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Subprogram) or else (Kind (Feature) = K_Port_Spec and then not Is_In (Feature) and then Is_Event (Feature)); when CC_Thread | CC_Threadgroup | CC_Process => OK := Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Port_Spec or else (Kind (Feature) = K_Subcomponent_Access and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data) or else (Kind (Feature) = K_Subcomponent_Access and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Subprogram) or else (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)); when CC_Processor => OK := ((Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else Kind (Feature) = K_Port_Spec or else Kind (Feature) = K_Port_Group_Spec or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data)); when CC_Memory | CC_Bus => OK := Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Bus; when CC_Device => OK := Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Port_Spec or else (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else (Kind (Feature) = K_Subcomponent_Access and then not Is_Provided (Feature) and then Component_Category'Val (Subcomponent_Category (Feature)) = CC_Data); when CC_System => OK := (Kind (Feature) = K_Subprogram_Spec and then Is_Server (Feature)) or else Kind (Feature) = K_Port_Spec or else Kind (Feature) = K_Port_Group_Spec or else Kind (Feature) = K_Subcomponent_Access; when others => OK := False; end case; end case; if OK then return True; else DAE (Loc => Loc (Feature), Node1 => Component, Node2 => Feature, Message1 => "cannot have ", Message2 => " as a feature"); return False; end if; end A_Component_Feature; ---------------------- -- A_Component_Flow -- ---------------------- function A_Component_Flow (Component : Node_Id; Flow : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Flow)); pragma Unreferenced (Rules); OK : Boolean; Component_Categ : Component_Category; begin if Kind (Component) /= K_Component_Implementation then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component implementation"); return False; end if; if Kind (Flow) /= K_Flow_Implementation and then Kind (Flow) /= K_End_To_End_Flow_Spec and then Kind (Flow) /= K_Flow_Implementation_Refinement and then Kind (Flow) /= K_End_To_End_Flow_Refinement then DAE (Loc => Loc (Flow), Node1 => Flow, Message1 => " is not a flow."); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); case Component_Categ is when CC_Subprogram | CC_System | CC_Threadgroup | CC_Thread | CC_Process | CC_Processor | CC_Device => OK := True; when CC_Data | CC_Bus | CC_Memory | CC_Unknown => OK := False; end case; if OK then return True; else DAE (Loc => Loc (Flow), Node1 => Component, Node2 => Flow, Message1 => "cannot have ", Message2 => " as a flow"); return False; end if; end A_Component_Flow; ------------------------------------ -- A_Component_Flow_Specification -- ------------------------------------ function A_Component_Flow_Specification (Component : Node_Id; Flow_Spec : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Flow_Spec)); pragma Unreferenced (Rules); OK : Boolean; Component_Categ : Component_Category; begin if Kind (Component) /= K_Component_Type then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component type"); return False; end if; if Kind (Flow_Spec) /= K_Flow_Spec then DAE (Loc => Loc (Flow_Spec), Node1 => Flow_Spec, Message1 => " is not a flow specification."); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); case Component_Categ is when CC_Subprogram | CC_System | CC_Threadgroup | CC_Thread | CC_Process | CC_Processor | CC_Device => OK := True; when CC_Data | CC_Bus | CC_Memory | CC_Unknown => OK := False; end case; if OK then return True; else DAE (Loc => Loc (Flow_Spec), Node1 => Component, Node2 => Flow_Spec, Message1 => "cannot have ", Message2 => " as a flow specification"); return False; end if; end A_Component_Flow_Specification; ------------------------------ -- A_Component_Subcomponent -- ------------------------------ function A_Component_Subcomponent (Component : Node_Id; Subcomponent : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Subcomponent)); OK : Boolean; Component_Categ : Component_Category; Subcomponent_Categ : Component_Category; begin if Kind (Component) /= K_Component_Implementation then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component implementation"); return False; end if; if Kind (Subcomponent) /= K_Subcomponent then DAE (Loc => Loc (Subcomponent), Node1 => Subcomponent, Message1 => " is not a subcomponent"); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); Subcomponent_Categ := Component_Category'Val (Category (Subcomponent)); case Rules is when Standard => case Component_Categ is when CC_Data => case Subcomponent_Categ is when CC_Data => OK := True; when others => OK := False; end case; when CC_Subprogram | CC_Bus | CC_Device => OK := False; when CC_Thread => case Subcomponent_Categ is when CC_Data => OK := True; when others => OK := False; end case; when CC_Threadgroup | CC_Process => case Subcomponent_Categ is when CC_Data | CC_Thread | CC_Threadgroup => OK := True; when others => OK := False; end case; when CC_Memory | CC_Processor => case Subcomponent_Categ is when CC_Memory => OK := True; when others => OK := False; end case; when CC_System => case Subcomponent_Categ is when CC_Data | CC_Process | CC_Processor | CC_Memory | CC_Device | CC_Bus | CC_System => OK := True; when others => OK := False; end case; when others => OK := False; end case; when Devel => case Component_Categ is when CC_Data => case Subcomponent_Categ is when CC_Data => OK := True; when others => OK := False; end case; when CC_Bus | CC_Device => OK := False; when CC_Subprogram => case Subcomponent_Categ is when CC_Data => OK := True; when others => OK := False; end case; when CC_Thread => case Subcomponent_Categ is when CC_Data | CC_Subprogram => OK := True; when others => OK := False; end case; when CC_Threadgroup | CC_Process => case Subcomponent_Categ is when CC_Data | CC_Thread | CC_Threadgroup | CC_Subprogram => OK := True; when others => OK := False; end case; when CC_Memory | CC_Processor => case Subcomponent_Categ is when CC_Memory => OK := True; when others => OK := False; end case; when CC_System => case Subcomponent_Categ is when CC_Data | CC_Process | CC_Processor | CC_Memory | CC_Device | CC_Bus | CC_System => OK := True; when others => OK := False; end case; when others => OK := False; end case; end case; if OK then return True; else DAE (Loc => Loc (Subcomponent), Node1 => Component, Node2 => Subcomponent, Message1 => "cannot have ", Message2 => " as a subcomponent"); return False; end if; end A_Component_Subcomponent; ------------------------------------------ -- A_Component_Subprogram_Call_Sequence -- ------------------------------------------ function A_Component_Subprogram_Call_Sequence (Component : Node_Id; Subprogram_Call_Seq : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Present (Component) and then Present (Subprogram_Call_Seq)); pragma Unreferenced (Rules); OK : Boolean; Component_Categ : Component_Category; begin if Kind (Component) /= K_Component_Implementation then DAE (Loc => Loc (Component), Node1 => Component, Message1 => " is not a component implementation"); return False; end if; if Kind (Subprogram_Call_Seq) /= K_Subprogram_Call_Sequence then DAE (Loc => Loc (Subprogram_Call_Seq), Node1 => Subprogram_Call_Seq, Message1 => " is not a subprogram call sequence."); return False; end if; -- Check the validity of the composition Component_Categ := Component_Category'Val (Category (Component)); case Component_Categ is when CC_Subprogram | CC_Thread => OK := True; when CC_Data | CC_Threadgroup | CC_Process | CC_Bus | CC_Processor | CC_Memory | CC_Device | CC_System | CC_Unknown => OK := False; end case; if OK then return True; else DAE (Loc => Loc (Subprogram_Call_Seq), Node1 => Component, Node2 => Subprogram_Call_Seq, Message1 => "cannot have ", Message2 => " as a subprogram call"); return False; end if; end A_Component_Subprogram_Call_Sequence; ----------------------------------- -- Check_Rules_In_Component_Type -- ----------------------------------- function Check_Rules_In_Component_Type (Node : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Kind (Node) = K_Component_Type); List_Node : Node_Id; Success : Boolean := True; begin -- Features if not Is_Empty (Features (Node)) then List_Node := First_Node (Features (Node)); while Present (List_Node) loop Success := A_Component_Feature (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; -- Flows if not Is_Empty (Flows (Node)) then List_Node := First_Node (Flows (Node)); while Present (List_Node) loop Success := A_Component_Flow_Specification (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; return Success; end Check_Rules_In_Component_Type; --------------------------------------------- -- Check_Rules_In_Component_Implementation -- --------------------------------------------- function Check_Rules_In_Component_Implementation (Node : Node_Id; Rules : AADL_Legality_Rules) return Boolean is pragma Assert (Kind (Node) = K_Component_Implementation); List_Node : Node_Id; Success : Boolean := True; begin -- Type refinements if not Is_Empty (Refines_Type (Node)) then List_Node := First_Node (Refines_Type (Node)); while Present (List_Node) loop Success := A_Component_Feature (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; -- Subcomponents if not Is_Empty (Subcomponents (Node)) then List_Node := First_Node (Subcomponents (Node)); while Present (List_Node) loop Success := A_Component_Subcomponent (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; -- Call sequences if not Is_Empty (Calls (Node)) then List_Node := First_Node (Calls (Node)); while Present (List_Node) loop Success := A_Component_Subprogram_Call_Sequence (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; -- Connections if not Is_Empty (Ocarina.Nodes.Connections (Node)) then List_Node := First_Node (Ocarina.Nodes.Connections (Node)); while Present (List_Node) loop Success := A_Component_Connection (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; -- Flows if not Is_Empty (Flows (Node)) then List_Node := First_Node (Flows (Node)); while Present (List_Node) loop Success := A_Component_Flow (Node, List_Node, Rules) and then Success; List_Node := Next_Node (List_Node); end loop; end if; return Success; end Check_Rules_In_Component_Implementation; -------------------------- -- Check_Legality_Rules -- -------------------------- function Check_Legality_Rules (Root : Node_Id; Options : Analyzer_Options) return Boolean is pragma Assert (Kind (Root) = K_AADL_Specification); List_Node : Node_Id; Package_List_Node : Node_Id; Success : Boolean := True; begin if not Is_Empty (Declarations (Root)) then List_Node := First_Node (Declarations (Root)); while Present (List_Node) loop case Kind (List_Node) is when K_Component_Type => Success := Check_Rules_In_Component_Type (List_Node, Options.Legality_Rules) and then Success; when K_Component_Implementation => Success := Check_Rules_In_Component_Implementation (List_Node, Options.Legality_Rules) and then Success; when K_Package_Specification => if not Is_Empty (Declarations (List_Node)) then Package_List_Node := First_Node (Declarations (List_Node)); while Package_List_Node /= No_Node loop case Kind (Package_List_Node) is when K_Component_Type => Success := Check_Rules_In_Component_Type (Package_List_Node, Options.Legality_Rules) and then Success; when K_Component_Implementation => Success := Check_Rules_In_Component_Implementation (Package_List_Node, Options.Legality_Rules) and then Success; when others => null; end case; Package_List_Node := Next_Node (Package_List_Node); end loop; end if; when others => null; end case; List_Node := Next_Node (List_Node); end loop; end if; return Success; end Check_Legality_Rules; end Ocarina.Analyzer.Legality_Rules;