--------------------------------------- ----------------------------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- G A I A . P R O C E S S O R . E N T I T I E S . C O N N E C T I O N S -- -- -- -- B o d y -- -- -- -- Copyright (C) 2005-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 Namet; use Namet; with Locations; with Ocarina.Nodes; with Ocarina.Nutils; with Ocarina.Entities; with Ocarina.Entities.Components; with Gaia.Processor.Nodes; with Gaia.Processor.Nodes.Utils; with Gaia.Messages; package body Gaia.Processor.Entities.Connections is package ON renames Ocarina.Nodes; package ONU renames Ocarina.Nutils; package GN renames Gaia.Processor.Nodes; package GNU renames Gaia.Processor.Nodes.Utils; function Compute_Unique_Name_Of_Connection_Extremity (Connection_Extremity : Node_Id) return Name_Id; -- Computes a system-unique name of a connection source or destination pragma Unreferenced (Compute_Unique_Name_Of_Connection_Extremity); function Compute_Simple_Name_Of_Connection_Extremity (Connection_Extremity : Node_Id) return Name_Id; -- Computes a simple but not necessarily system-unique name of a -- connection source or destination Connection_Index : Nat := 0; function Compute_New_Connection_Name return Name_Id; -- Computes a system unique connection name in order to attribute it -- to unnamed connections function Find_Node_Before_Last (List : List_Id) return Node_Id; -- Return the element before the last ------------------------- -- Process_Connections -- ------------------------- function Process_Connections (Instance, Sp : Node_Id) return Boolean is use ON; use GN; use GNU; use Ocarina.Entities; use Ocarina.Entities.Components; use Gaia.Messages; pragma Assert (Get_Category_Of_Component (Instance) = CC_Subprogram or else Get_Category_Of_Component (Instance) = CC_Thread or else Get_Category_Of_Component (Instance) = CC_Process); pragma Assert (GN.Kind (Sp) = GN.K_Subprogram or else GN.Kind (Sp) = GN.K_Thread or else GN.Kind (Sp) = GN.K_Process); Success : constant Boolean := True; List_Node : Node_Id; Connection_Node : Node_Id; Identifier : Node_Id; I : Node_Id; C : Node_Id; Provide_Access : Node_Id := No_Node; Provide_Ref : Node_Id := No_Node; Require_Access : Node_Id := No_Node; Require_Ref : Node_Id := No_Node; begin if not ONU.Is_Empty (ON.Connections (Instance)) then List_Node := ON.First_Node (ON.Connections (Instance)); while Present (List_Node) loop Connection_Node := GNU.New_Node (GN.K_Parameter_Connection); -- If the connection is unnamed, display a warning and -- compute a new name if Get_Name_Of_Entity (List_Node) = No_Name then Display_Error ("Connection in " & Locations.Image (ON.Loc (List_Node)) & " does not have a name. Computing a new name...", Fatal => False, Warning => True); Identifier := GNU.Make_Identifier (Compute_New_Connection_Name); Bind_Identifier_To_Entity (Identifier, Connection_Node); GN.Set_Scoped_Name (Connection_Node, GNU.Append_Scoped_Name (GNU.Map_Scoped_Name (Connection_Node, Instance), Connection_Node, GN.Name (GN.Identifier (Connection_Node)))); else Identifier := GNU.Make_Identifier (Get_Name_Of_Entity (List_Node)); Bind_Identifier_To_Entity (Identifier, Connection_Node); GN.Set_Scoped_Name (Connection_Node, GNU.Map_Scoped_Name (Connection_Node, List_Node)); end if; -- Handling the connection source if Present (ON.Source (List_Node)) then I := ON.Item (ON.Last_Node (ON.Path (ON.Source (List_Node)))); Try_Perform_Link (GN.Set_Source'Access, Connection_Node, I, False); GN.Set_Simple_Source (Connection_Node, Compute_Simple_Name_Of_Connection_Extremity (ON.Source (List_Node))); if Kind (I) = ON.K_Parameter_Instance then -- The source of the connection is a parameter of a -- subprogram call. -- Two cases: -- The source of the connection is a local parameter -- In this case we do nothing. -- The source of the connection is a parameter of a -- subprogram call. In this case we link the -- connecto the subprogram call. if ONU.Length (ON.Path (ON.Source (List_Node))) > 1 then -- Retrieve the subprogram call C := ON.Item (Find_Node_Before_Last (ON.Path (ON.Source (List_Node)))); -- Link the connection to subprogram call Try_Perform_Link (GN.Set_Source_Subprogram_Call'Access, Connection_Node, C, False); end if; elsif Kind (I) = ON.K_Subcomponent_Access_Instance then -- Prepare the handling of accesses Provide_Access := I; -- Two cases: -- The source of the connection is a local access -- feature (either provides or requires). In this -- case we do nothing. -- The source of the connection is a feature of a -- subprogram call or of a subcomponent. In this -- case we link the connecto the subprogram call. if ONU.Length (ON.Path (ON.Source (List_Node))) > 1 then -- Retrieve the parent C := ON.Item (Find_Node_Before_Last (ON.Path (ON.Source (List_Node)))); if ON.Kind (C) = K_Call_Instance then Provide_Ref := C; -- Link the connection to subprogram call Try_Perform_Link (GN.Set_Source_Subprogram_Call'Access, Connection_Node, C, False); elsif ON.Kind (C) = K_Subcomponent_Instance then Provide_Ref := ON.Corresponding_Instance (C); else raise Program_Error; end if; end if; end if; else GN.Set_Simple_Source (Connection_Node, No_Name); end if; -- Handling the connection destination if Present (ON.Destination (List_Node)) then I := ON.Item (ON.Last_Node (ON.Path (ON.Destination (List_Node)))); Try_Perform_Link (GN.Set_Destination'Access, Connection_Node, I, False); GN.Set_Simple_Destination (Connection_Node, Compute_Simple_Name_Of_Connection_Extremity (ON.Destination (List_Node))); if Kind (I) = ON.K_Parameter_Instance then -- The destination of the connection is a parameter -- of a subprogram call. -- Two cases: -- The destination of the connection is a local -- parameter In this case we do nothing. -- The destination of the connection is a parameter -- of a subprogram call. In this case we link the -- connecto the subprogram call. if ONU.Length (ON.Path (ON.Destination (List_Node))) > 1 then -- Retrieve the subprogram call C := ON.Item (Find_Node_Before_Last (ON.Path (ON.Destination (List_Node)))); -- Link the connection to subprogram call Try_Perform_Link (GN.Set_Destination_Subprogram_Call'Access, Connection_Node, C, False); end if; elsif Kind (I) = ON.K_Subcomponent_Access_Instance then -- Prepare the handling of accesses Require_Access := I; -- Two cases: -- The destination of the connection is a local -- access feature (either provide or requires). In -- this case we do nothing. -- The destination of the connection is a feature -- of a subprogram call or of a subcomponent. In -- this case we link the connecto the subprogram -- call. if ONU.Length (ON.Path (ON.Destination (List_Node))) > 1 then -- Retrieve the subprogram call C := ON.Item (Find_Node_Before_Last (ON.Path (ON.Destination (List_Node)))); if ON.Kind (C) = K_Call_Instance then Require_Ref := C; -- Link the connection to subprogram call Try_Perform_Link (GN.Set_Destination_Subprogram_Call'Access, Connection_Node, C, False); elsif ON.Kind (C) = K_Subcomponent_Instance then Require_Ref := ON.Corresponding_Instance (C); else raise Program_Error; end if; end if; end if; else GN.Set_Simple_Destination (Connection_Node, No_Name); end if; -- Handle the possible access path if Present (Require_Access) or else Present (Require_Ref) then -- Complete eventual missing informations if No (Provide_Access) then Provide_Access := ON.Item (ON.Last_Node (ON.Path (ON.Source (List_Node)))); end if; -- Link the nodes -- FIXME: We support only ONE access -- (provides/require) per component. -- IMPORTANT: The order of the conditions is important -- to build correctly the "access chain". if Present (Require_Ref) and then Present (Provide_Ref) then Try_Perform_Link_From_Scratch (GN.Set_Access_Provided_By'Access, Require_Ref, Provide_Ref); elsif Present (Require_Ref) then Try_Perform_Link_From_Scratch (GN.Set_Access_Provided_By'Access, Require_Ref, Provide_Access); elsif Present (Provide_Ref) then Try_Perform_Link_From_Scratch (GN.Set_Access_Provided_By'Access, Require_Access, Provide_Ref); else Try_Perform_Link_From_Scratch (GN.Set_Access_Provided_By'Access, Require_Access, Provide_Access); end if; end if; GNU.Append_Node_To_List (Connection_Node, GN.Connections (Sp)); List_Node := ON.Next_Node (List_Node); end loop; end if; return Success; end Process_Connections; --------------------------- -- Find_Node_Before_Last -- --------------------------- function Find_Node_Before_Last (List : List_Id) return Node_Id is Current : Node_Id; Next : Node_Id; begin Current := ON.First_Node (List); Next := ON.Next_Node (Current); if Next = No_Node then return No_Node; end if; while ON.Next_Node (Next) /= No_Node loop Current := Next; Next := ON.Next_Node (Next); end loop; return Current; end Find_Node_Before_Last; ------------------------------------------------- -- Compute_Unique_Name_Of_Connection_Extremity -- ------------------------------------------------- function Compute_Unique_Name_Of_Connection_Extremity (Connection_Extremity : Node_Id) return Name_Id is use Ocarina.Entities; use ONU; The_Path : constant List_Id := ON.Path (Connection_Extremity); Path_Element : Node_Id; begin Get_Name_String (Compute_Full_Name_Of_Instance (ON.Item (ON.First_Node (The_Path)))); Path_Element := ON.Next_Node (ON.First_Node (The_Path)); while Present (Path_Element) loop Add_Str_To_Name_Buffer ("_"); Get_Name_String_And_Append (Get_Name_Of_Entity (ON.Item (Path_Element), False)); Path_Element := ON.Next_Node (Path_Element); end loop; return Name_Find; end Compute_Unique_Name_Of_Connection_Extremity; ------------------------------------------------- -- Compute_Simple_Name_Of_Connection_Extremity -- ------------------------------------------------- function Compute_Simple_Name_Of_Connection_Extremity (Connection_Extremity : Node_Id) return Name_Id is use Ocarina.Entities; The_Path : constant List_Id := ON.Path (Connection_Extremity); Path_Element : Node_Id; begin Get_Name_String (Get_Name_Of_Entity (ON.Item (ON.First_Node (The_Path)))); Path_Element := ON.Next_Node (ON.First_Node (The_Path)); while Present (Path_Element) loop Add_Str_To_Name_Buffer ("_"); Get_Name_String_And_Append (Get_Name_Of_Entity (ON.Item (Path_Element), False)); Path_Element := ON.Next_Node (Path_Element); end loop; return Name_Find; end Compute_Simple_Name_Of_Connection_Extremity; --------------------------------- -- Compute_New_Connection_Name -- --------------------------------- function Compute_New_Connection_Name return Name_Id is begin Set_Str_To_Name_Buffer ("Cnx_"); Connection_Index := Connection_Index + 1; Add_Nat_To_Name_Buffer (Connection_Index); return Name_Find; end Compute_New_Connection_Name; end Gaia.Processor.Entities.Connections;