--------------------------------------- ----------------------------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- OCARINA.GENERATORS.PO_HI_C.DEPLOYMENT -- -- -- -- B o d y -- -- -- -- Copyright (C) 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; with Ocarina.Nodes; with Ocarina.Nutils; with Ocarina.Entities.Components; with Ocarina.Generators.Utils; with Ocarina.Generators.C_Values; with Ocarina.Generators.C_Tree.Nutils; with Ocarina.Generators.C_Tree.Nodes; with Ocarina.Generators.PO_HI_C.Mapping; with Ocarina.Generators.PO_HI_C.Runtime; package body Ocarina.Generators.PO_HI_C.Deployment is use Namet; use Ocarina.Nodes; use Ocarina.Entities.Components; use Ocarina.Generators.Utils; use Ocarina.Generators.C_Values; use Ocarina.Generators.C_Tree.Nutils; use Ocarina.Generators.PO_HI_C.Mapping; use Ocarina.Generators.PO_HI_C.Runtime; package AAU renames Ocarina.Nutils; package CV renames Ocarina.Generators.C_Values; package CTN renames Ocarina.Generators.C_Tree.Nodes; ----------------- -- Header_File -- ----------------- package body Header_File is procedure Visit_Architecture_Instance (E : Node_Id); procedure Visit_Component_Instance (E : Node_Id); procedure Visit_System_Instance (E : Node_Id); procedure Visit_Process_Instance (E : Node_Id); procedure Visit_Thread_Instance (E : Node_Id); function Added_Internal_Name (P : Node_Id; E : Node_Id) return Name_Id; function Is_Added (P : Node_Id; E : Node_Id) return Boolean; procedure Set_Added (P : Node_Id; E : Node_Id); procedure Append_Existing (S : Node_Id; L : List_Id; Id : in out Unsigned_Long_Long; Is_Entity : Boolean := False); -- Append a node in a List. If the node was node already processed, -- it assigns a value (using the Id) argument to the node and bind -- it to the Backend Node of S. Is a value was already assigned, it -- simply uses it and append the it in the list. -- This function is used to warrant that all entities will have -- the same values on each node. procedure Insert_Node_In_List (N : Node_Id; L : List_Id; Position : Unsigned_Long_Long); -- Insert a node in a List. The first argument (N), is the node we -- have to insert. The second is the list which will contain the -- node. The third argument (Position), is the position of the -- Node in the list. Node_Enumerator_List : List_Id; Tasks_Enumerator_List : List_Id; Entity_Enumerator_List : List_Id; Global_Port_List : List_Id; Local_Port_List : List_Id; Current_Process_Instance : Node_Id; Global_Port_To_Entity : Node_Id; Global_Port_To_Local : Node_Id; -- Point to the process currently visited. When we visit a process -- we look at all its ports and visit the called subprograms. So, -- we need to know if these subprograms are linked with the currrent -- process. Node_Identifier : Unsigned_Long_Long := 0; Global_Port_Identifier : Unsigned_Long_Long := 0; Local_Port_Identifier : Unsigned_Long_Long := 0; Entity_Identifier : Unsigned_Long_Long := 0; Task_Identifier : Unsigned_Long_Long := 0; Nb_Protected : Unsigned_Long_Long := 0; Nb_Ports_In_Process : Unsigned_Long_Long := 0; -- The Identifier are used to assign a value to an entity. For example, -- each node must have the same value in each system. Entity_Array : Node_Id; ------------------------- -- Insert_Node_In_List -- ------------------------- procedure Insert_Node_In_List (N : Node_Id; L : List_Id; Position : Unsigned_Long_Long) is M : Node_Id; Tmp : Unsigned_Long_Long; begin if Is_Empty (L) then Append_Node_To_List (N, L); else Tmp := 0; M := CTN.First_Node (L); while Present (M) loop if Position <= Tmp then -- FIXME : We have to look the position of each node -- before insert it. Insert_Before_Node (N, M, L); return; -- IMPORTANT end if; M := CTN.Next_Node (M); Tmp := Tmp + 1; end loop; Append_Node_To_List (N, L); end if; end Insert_Node_In_List; --------------------- -- Append_Existing -- --------------------- procedure Append_Existing (S : Node_Id; L : List_Id; Id : in out Unsigned_Long_Long; Is_Entity : Boolean := False) is N : Node_Id; M : Node_Id; begin if Present (Backend_Node (Identifier (S))) and then Present (CTN.Enumerator_Node (Backend_Node (Identifier (S)))) then -- If a value was already bound, we simply take the old value -- and add the entity in the list with this value. M := CTN.Enumerator_Node (Backend_Node (Identifier (S))); N := Make_Expression (Make_Defining_Identifier (Map_C_Enumerator_Name (S, Entity => Is_Entity)), Op_Equal, Make_Literal (CTN.Value (CTN.Right_Expression (M)))); Append_Node_To_List (N, L); else -- If no value has been bound, we generate a new one according -- to the Id argument, and bind it to the node. N := Make_Expression (Make_Defining_Identifier (Map_C_Enumerator_Name (S, Entity => Is_Entity)), Op_Equal, Make_Literal (CV.New_Int_Value (Id, 0, 10))); Bind_AADL_To_Enumerator (Identifier (S), N); Append_Node_To_List (N, L); Id := Id + 1; end if; end Append_Existing; ------------------------- -- Added_Internal_Name -- ------------------------- function Added_Internal_Name (P : Node_Id; E : Node_Id) return Name_Id is begin Set_Str_To_Name_Buffer ("%add%enumerator%"); Add_Nat_To_Name_Buffer (Nat (P)); Add_Char_To_Name_Buffer ('%'); Add_Nat_To_Name_Buffer (Nat (E)); return Name_Find; end Added_Internal_Name; -------------- -- Is_Added -- -------------- function Is_Added (P : Node_Id; E : Node_Id) return Boolean is I_Name : constant Name_Id := Added_Internal_Name (P, E); begin return Get_Name_Table_Byte (I_Name) = 1; end Is_Added; --------------- -- Set_Added -- --------------- procedure Set_Added (P : Node_Id; E : Node_Id) is I_Name : constant Name_Id := Added_Internal_Name (P, E); begin Set_Name_Table_Byte (I_Name, 1); end Set_Added; ----------- -- Visit -- ----------- procedure Visit (E : Node_Id) is begin case Kind (E) is when K_Architecture_Instance => Visit_Architecture_Instance (E); when K_Component_Instance => Visit_Component_Instance (E); when others => null; end case; end Visit; --------------------------------- -- Visit_Architecture_Instance -- --------------------------------- procedure Visit_Architecture_Instance (E : Node_Id) is begin Visit (Root_System (E)); end Visit_Architecture_Instance; ------------------------------ -- Visit_Component_Instance -- ------------------------------ procedure Visit_Component_Instance (E : Node_Id) is Cathegory : constant Component_Category := Get_Category_Of_Component (E); begin case Cathegory is when CC_System => Visit_System_Instance (E); when CC_Process => Visit_Process_Instance (E); when CC_Thread => Visit_Thread_Instance (E); when others => null; end case; end Visit_Component_Instance; ---------------------------- -- Visit_Process_Instance -- ---------------------------- procedure Visit_Process_Instance (E : Node_Id) is U : constant Node_Id := CTN.Distributed_Application_Unit (CTN.Naming_Node (Backend_Node (Identifier (E)))); P : constant Node_Id := CTN.Entity (U); S : constant Node_Id := Parent_Subcomponent (E); N : Node_Id; C : Node_Id; F : Node_Id; Src : Node_Id; Dst : Node_Id; Parent : Node_Id; S_Parent : Node_Id; begin Current_Process_Instance := E; Node_Enumerator_List := New_List (CTN.K_Enumeration_Literals); Entity_Enumerator_List := New_List (CTN.K_Enumeration_Literals); Tasks_Enumerator_List := New_List (CTN.K_Enumeration_Literals); Entity_Array := Make_Array_Values; Push_Entity (P); Push_Entity (U); Set_Deployment_Header; Task_Identifier := 0; Nb_Protected := 0; Nb_Ports_In_Process := 0; Append_Existing (S, Node_Enumerator_List, Node_Identifier); -- Visit all the subcomponents of the process if not AAU.Is_Empty (Subcomponents (E)) then C := First_Node (Subcomponents (E)); while Present (C) loop if Utils.Is_Data (Corresponding_Instance (C)) then N := Make_Literal (New_Int_Value (Nb_Protected, 1, 10)); Bind_AADL_To_Default_Value (Identifier (C), N); Nb_Protected := Nb_Protected + 1; else -- Visit the component instance corresponding to the -- subcomponent S. Visit (Corresponding_Instance (C)); end if; C := Next_Node (C); end loop; end if; -- For each of the processes P connected to E, (1) we add an -- enumerator corresponding to P and (2) for each one of the -- threads of P, we add an enumerator. if not AAU.Is_Empty (Features (E)) then F := First_Node (Features (E)); while Present (F) loop -- The sources of F if not AAU.Is_Empty (Sources (F)) then Src := First_Node (Sources (F)); while Present (Src) loop Parent := Parent_Component (Item (Src)); if Is_Process (Parent) and then Parent /= E and then not Is_Added (Parent, E) then -- Add the process to the deployment -- enumerators of E. S_Parent := Parent_Subcomponent (Parent); Append_Existing (S_Parent, Node_Enumerator_List, Node_Identifier); -- Traverse all the subcomponents of Parent if not AAU.Is_Empty (Subcomponents (Parent)) then C := First_Node (Subcomponents (Parent)); while Present (C) loop Visit (Corresponding_Instance (C)); C := Next_Node (C); end loop; end if; -- Mark P as being Added Set_Added (Parent, E); end if; Src := Next_Node (Src); end loop; end if; -- The destinations of F if not AAU.Is_Empty (Destinations (F)) then Dst := First_Node (Destinations (F)); while Present (Dst) loop Parent := Parent_Component (Item (Dst)); if Is_Process (Parent) and then Parent /= E and then not Is_Added (Parent, E) then -- Add the process to the deployment -- enumerators of E. S_Parent := Parent_Subcomponent (Parent); Append_Existing (S_Parent, Node_Enumerator_List, Node_Identifier); -- Traverse all the subcomponensts of P if not AAU.Is_Empty (Subcomponents (Parent)) then C := First_Node (Subcomponents (Parent)); while Present (C) loop Visit (Corresponding_Instance (C)); C := Next_Node (C); end loop; end if; -- Mark P as being Added Set_Added (Parent, E); end if; Dst := Next_Node (Dst); end loop; end if; F := Next_Node (F); end loop; end if; -- Create the node enumeration type declaration. Note that -- the type creation is possible even the enumeration list -- is incomplete. We can do this in the first traversal -- since we are sure that the enumerator list is not empty. N := Message_Comment ("For each node in the distributed" & " application add an enumerator"); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Full_Type_Declaration (Defining_Identifier => RE (RE_Node_T), Type_Definition => Make_Enum_Aggregate (Node_Enumerator_List)); Append_Node_To_List (N, CTN.Declarations (Current_File)); -- Create the thread enumeration type declaration. Note that -- the type creation is possible even the enumeration list -- is incomplete. This type may not be generated in case the -- application is local. if not Is_Empty (Entity_Enumerator_List) then N := Message_Comment ("For each thread in the distributed" & " application nodes, add an" & " enumerator"); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Full_Type_Declaration (Defining_Identifier => RE (RE_Entity_T), Type_Definition => Make_Enum_Aggregate (Entity_Enumerator_List)); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; N := Make_Full_Type_Declaration (Defining_Identifier => RE (RE_Task_Id), Type_Definition => Make_Enum_Aggregate (Tasks_Enumerator_List)); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Define_Statement (Defining_Identifier => RE (RE_Nb_Tasks), Value => Make_Literal (New_Int_Value (Task_Identifier, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); -- Add an enumerator corresponding to an INVALID server -- entity to the entity list. N := Make_Define_Statement (Defining_Identifier => RE (RE_Nb_Protected), Value => Make_Literal (New_Int_Value (Nb_Protected, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Define_Statement (Defining_Identifier => RE (RE_Nb_Nodes), Value => Make_Literal (New_Int_Value (Node_Identifier, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Define_Statement (Defining_Identifier => RE (RE_Nb_Entities), Value => Make_Literal (New_Int_Value (Entity_Identifier, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Define_Statement (Defining_Identifier => RE (RE_Nb_Ports), Value => Make_Literal (New_Int_Value (Nb_Ports_In_Process, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); Bind_AADL_To_Entities (Identifier (S), Entity_Array); if not Is_Empty (Global_Port_List) then N := Make_Full_Type_Declaration (Defining_Identifier => RE (RE_Port_T), Type_Definition => Make_Enum_Aggregate (Global_Port_List)); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; if not Is_Empty (CTN.Values (Global_Port_To_Local)) then Bind_AADL_To_Local_Port (Identifier (S), Global_Port_To_Local); end if; if not Is_Empty (CTN.Values (Global_Port_To_Entity)) then Bind_AADL_To_Global_Port (Identifier (S), Global_Port_To_Entity); end if; Pop_Entity; -- U Pop_Entity; -- P end Visit_Process_Instance; --------------------------- -- Visit_System_Instance -- --------------------------- procedure Visit_System_Instance (E : Node_Id) is S : Node_Id; begin Push_Entity (HI_Distributed_Application_Root); Global_Port_List := New_List (CTN.K_Enumeration_Literals); Global_Port_To_Entity := Make_Array_Values; Global_Port_To_Local := Make_Array_Values; -- Visit all the subcomponents of the system if not AAU.Is_Empty (Subcomponents (E)) then S := First_Node (Subcomponents (E)); while Present (S) loop -- Visit the component instance corresponding to the -- subcomponent S. Visit (Corresponding_Instance (S)); S := Next_Node (S); end loop; end if; Pop_Entity; -- HI_Distributed_Application_Root end Visit_System_Instance; --------------------------- -- Visit_Thread_Instance -- --------------------------- procedure Visit_Thread_Instance (E : Node_Id) is N : Node_Id; F : Node_Id; P : Node_Id; S : constant Node_Id := Parent_Subcomponent (E); Local_Port_Values : Node_Id; begin Local_Port_Identifier := 0; Local_Port_List := New_List (CTN.K_Enumeration_Literals); Local_Port_Values := Make_Array_Values; -- Build the enumerator corresponding to the thread. The -- enumerator name is mapped from the the thread name and -- its containing process name. Append_Existing (S, Entity_Enumerator_List, Entity_Identifier, Is_Entity => True); if Parent_Component (Parent_Subcomponent (E)) = Current_Process_Instance then N := Make_Expression (Make_Defining_Identifier (Map_C_Enumerator_Name (S, Entity => False)), Op_Equal, (Make_Literal (CV.New_Int_Value (Task_Identifier, 0, 10)))); Append_Node_To_List (N, Tasks_Enumerator_List); Task_Identifier := Task_Identifier + 1; end if; -- Get the Process parent of the thread P := Parent_Component (S); pragma Assert (Is_Process (P)); N := Make_Defining_Identifier (Map_C_Enumerator_Name (Parent_Subcomponent (P))); Insert_Node_In_List (N, CTN.Values (Entity_Array), CV.Value (CTN.Value (CTN.Right_Expression (CTN.Enumerator_Node (Backend_Node (Identifier (S)))))). IVal); if Has_Ports (E) then F := First_Node (Features (E)); while Present (F) loop if Kind (F) = K_Port_Spec_Instance then N := Make_Expression (Make_Defining_Identifier (Map_C_Enumerator_Name (F, Local_Port => True)), Op_Equal, (Make_Literal (CV.New_Int_Value (Local_Port_Identifier, 0, 10)))) ; Append_Node_To_List (N, Local_Port_List); Append_Node_To_List (Make_Defining_Identifier (Map_C_Enumerator_Name (F)), CTN.Values (Local_Port_Values)); Bind_AADL_To_Local_Port (Identifier (S), Local_Port_Values); Local_Port_Identifier := Local_Port_Identifier + 1; Nb_Ports_In_Process := Nb_Ports_In_Process + 1; if not Present (Backend_Node (Identifier (F))) or else not Present (CTN.Global_Port_Node (Backend_Node (Identifier (F)))) then N := Make_Defining_Identifier (Map_C_Enumerator_Name (F, Local_Port => True)); Append_Node_To_List (N, CTN.Values (Global_Port_To_Local)); N := Make_Defining_Identifier (Map_C_Enumerator_Name (S, Entity => True)); Append_Node_To_List (N, CTN.Values (Global_Port_To_Entity)); N := Make_Expression (Make_Defining_Identifier (Map_C_Enumerator_Name (F)), Op_Equal, (Make_Literal (CV.New_Int_Value (Global_Port_Identifier, 0, 10)))); Append_Node_To_List (N, Global_Port_List); Bind_AADL_To_Global_Port (Identifier (F), Make_Defining_Identifier (Map_C_Enumerator_Name (F))); Global_Port_Identifier := Global_Port_Identifier + 1; end if; end if; F := Next_Node (F); end loop; N := Make_Full_Type_Declaration (Defining_Identifier => Make_Defining_Identifier (Map_C_Enumerator_Name (S, Port_Type => True)), Type_Definition => Make_Enum_Aggregate (Local_Port_List)); Append_Node_To_List (N, CTN.Declarations (Current_File)); N := Make_Define_Statement (Defining_Identifier => Make_Defining_Identifier (Map_C_Define_Name (S, Nb_Ports => True)), Value => Make_Literal (New_Int_Value (Local_Port_Identifier, 1, 10))); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; end Visit_Thread_Instance; end Header_File; ----------------- -- Source_File -- ----------------- package body Source_File is procedure Visit_Architecture_Instance (E : Node_Id); procedure Visit_Component_Instance (E : Node_Id); procedure Visit_System_Instance (E : Node_Id); procedure Visit_Process_Instance (E : Node_Id); procedure Visit_Thread_Instance (E : Node_Id); ----------- -- Visit -- ----------- procedure Visit (E : Node_Id) is begin case Kind (E) is when K_Architecture_Instance => Visit_Architecture_Instance (E); when K_Component_Instance => Visit_Component_Instance (E); when others => null; end case; end Visit; --------------------------------- -- Visit_Architecture_Instance -- --------------------------------- procedure Visit_Architecture_Instance (E : Node_Id) is begin Visit (Root_System (E)); end Visit_Architecture_Instance; ------------------------------ -- Visit_Component_Instance -- ------------------------------ procedure Visit_Component_Instance (E : Node_Id) is Cathegory : constant Component_Category := Get_Category_Of_Component (E); begin case Cathegory is when CC_System => Visit_System_Instance (E); when CC_Process => Visit_Process_Instance (E); when CC_Thread => Visit_Thread_Instance (E); when others => null; end case; end Visit_Component_Instance; ---------------------------- -- Visit_Process_Instance -- ---------------------------- procedure Visit_Process_Instance (E : Node_Id) is U : constant Node_Id := CTN.Distributed_Application_Unit (CTN.Naming_Node (Backend_Node (Identifier (E)))); P : constant Node_Id := CTN.Entity (U); S : constant Node_Id := Parent_Subcomponent (E); N : Node_Id; C : Node_Id; begin Push_Entity (P); Push_Entity (U); Set_Deployment_Source; if not AAU.Is_Empty (Subcomponents (E)) then C := First_Node (Subcomponents (E)); while Present (C) loop Visit (Corresponding_Instance (C)); C := Next_Node (C); end loop; end if; if Present (Backend_Node (Identifier (S))) and then Present (CTN.Global_Port_Node (Backend_Node (Identifier (S)))) then N := Make_Expression (Left_Expr => Make_Variable_Declaration (Defining_Identifier => Make_Array_Declaration (Defining_Identifier => RE (RE_Port_Global_To_Entity), Array_Size => RE (RE_Nb_Ports)), Used_Type => RE (RE_Entity_T)), Operator => Op_Equal, Right_Expr => CTN.Global_Port_Node (Backend_Node (Identifier (S)))); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; if Present (Backend_Node (Identifier (S))) and then Present (CTN.Local_Port_Node (Backend_Node (Identifier (S)))) then N := Make_Expression (Left_Expr => Make_Variable_Declaration (Defining_Identifier => Make_Array_Declaration (Defining_Identifier => RE (RE_Port_Global_To_Local), Array_Size => RE (RE_Nb_Ports)), Used_Type => RE (RE_Port_T)), Operator => Op_Equal, Right_Expr => CTN.Local_Port_Node (Backend_Node (Identifier (S)))); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; if Present (Backend_Node (Identifier (S))) and then Present (CTN.Entities_Node (Backend_Node (Identifier (S)))) then N := Make_Expression (Left_Expr => Make_Variable_Declaration (Defining_Identifier => Make_Array_Declaration (Defining_Identifier => Make_Defining_Identifier (VN (V_Entity_Table)), Array_Size => RE (RE_Nb_Entities)), Used_Type => RE (RE_Node_T)), Operator => Op_Equal, Right_Expr => CTN.Entities_Node (Backend_Node (Identifier (S)))); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; N := Make_Expression (Left_Expr => Make_Variable_Declaration (Defining_Identifier => Make_Defining_Identifier (VN (V_Mynode)), Used_Type => RE (RE_Node_T)), Operator => Op_Equal, Right_Expr => Make_Defining_Identifier (Map_C_Enumerator_Name (Parent_Subcomponent (E)))); Append_Node_To_List (N, CTN.Declarations (Current_File)); Pop_Entity; -- U Pop_Entity; -- P end Visit_Process_Instance; --------------------------- -- Visit_Thread_Instance -- --------------------------- procedure Visit_Thread_Instance (E : Node_Id) is S : constant Node_Id := Parent_Subcomponent (E); N : Node_Id; begin if Present (Backend_Node (Identifier (S))) and then Present (CTN.Local_Port_Node (Backend_Node (Identifier (S)))) then N := Make_Expression (Left_Expr => Make_Variable_Declaration (Defining_Identifier => Make_Array_Declaration (Defining_Identifier => Make_Defining_Identifier (Map_C_Variable_Name (S, Port_Variable => True)), Array_Size => Make_Defining_Identifier (Map_C_Define_Name (S, Nb_Ports => True))), Used_Type => RE (RE_Port_T)), Operator => Op_Equal, Right_Expr => CTN.Local_Port_Node (Backend_Node (Identifier (S)))); Append_Node_To_List (N, CTN.Declarations (Current_File)); end if; end Visit_Thread_Instance; --------------------------- -- Visit_System_Instance -- --------------------------- procedure Visit_System_Instance (E : Node_Id) is S : Node_Id; begin Push_Entity (HI_Distributed_Application_Root); -- Visit all the subcomponents of the system if not AAU.Is_Empty (Subcomponents (E)) then S := First_Node (Subcomponents (E)); while Present (S) loop -- Visit the component instance corresponding to the -- subcomponent S. Visit (Corresponding_Instance (S)); S := Next_Node (S); end loop; end if; Pop_Entity; -- HI_Distributed_Application_Root end Visit_System_Instance; end Source_File; end Ocarina.Generators.PO_HI_C.Deployment;