-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset 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 3, or (at your option) any later
-- version. The SPARK toolset 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 the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

separate (Dictionary)
procedure Add_Declaration
  (Comp_Unit       : in     ContextManager.UnitDescriptors;
   Loc             : in     Location;
   Scope           : in     Scopes;
   Context         : in     Contexts;
   The_Declaration :    out RawDict.Declaration_Info_Ref) is

   procedure Add_Visible_Declaration (The_Declaration : in RawDict.Declaration_Info_Ref;
                                      Region          : in Symbol)
   --# global in out Dict;
   --# derives Dict from *,
   --#                   Region,
   --#                   The_Declaration;
   is

      procedure Add_Visible_Declaration_To_Package
        (The_Declaration : in RawDict.Declaration_Info_Ref;
         The_Package     : in RawDict.Package_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Package;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Package_Last_Visible_Declaration (The_Package => The_Package);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Package_First_Visible_Declaration (The_Package     => The_Package,
                                                           The_Declaration => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Package_Last_Visible_Declaration (The_Package     => The_Package,
                                                       The_Declaration => The_Declaration);
      end Add_Visible_Declaration_To_Package;

      --------------------------------------------------------------------------------

      procedure Add_Visible_Declaration_To_Protected_Type
        (The_Declaration    : in RawDict.Declaration_Info_Ref;
         The_Protected_Type : in RawDict.Type_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Protected_Type;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Protected_Type_Last_Visible_Declaration (The_Protected_Type => The_Protected_Type);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Protected_Type_First_Visible_Declaration
              (The_Protected_Type => The_Protected_Type,
               The_Declaration    => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Protected_Type_Last_Visible_Declaration
           (The_Protected_Type => The_Protected_Type,
            The_Declaration    => The_Declaration);
      end Add_Visible_Declaration_To_Protected_Type;

      --------------------------------------------------------------------------------

      procedure Add_Visible_Declaration_To_Generic_Unit
        (The_Declaration  : in RawDict.Declaration_Info_Ref;
         The_Generic_Unit : in RawDict.Generic_Unit_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Generic_Unit;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Generic_Unit_Last_Declaration (The_Generic_Unit => The_Generic_Unit);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Generic_Unit_First_Declaration (The_Generic_Unit => The_Generic_Unit,
                                                        The_Declaration  => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Generic_Unit_Last_Declaration (The_Generic_Unit => The_Generic_Unit,
                                                    The_Declaration  => The_Declaration);
      end Add_Visible_Declaration_To_Generic_Unit;

   begin -- Add_Visible_Declaration
      case RawDict.GetSymbolDiscriminant (Region) is
         when Package_Symbol =>
            Add_Visible_Declaration_To_Package
              (The_Declaration => The_Declaration,
               The_Package     => RawDict.Get_Package_Info_Ref (Item => Region));
         when Type_Symbol => -- must be a protected type
            SystemErrors.RT_Assert
              (C       => Is_Protected_Type (Type_Mark => RawDict.Get_Type_Info_Ref (Item => Region)),
               Sys_Err => SystemErrors.Invalid_Symbol_Table,
               Msg     => "Dictionary.Add_Visible_Declaration");
            Add_Visible_Declaration_To_Protected_Type
              (The_Declaration    => The_Declaration,
               The_Protected_Type => RawDict.Get_Type_Info_Ref (Item => Region));
         when Generic_Unit_Symbol =>
            Add_Visible_Declaration_To_Generic_Unit
              (The_Declaration  => The_Declaration,
               The_Generic_Unit => RawDict.Get_Generic_Unit_Info_Ref (Item => Region));
         when others => -- non-exec code
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Invalid_Symbol_Table,
                                      Msg     => "Dictionary.Add_Visible_Declaration");
      end case;
   end Add_Visible_Declaration;

   --------------------------------------------------------------------------------

   procedure Add_Local_Declaration (The_Declaration : in RawDict.Declaration_Info_Ref;
                                    Region          : in Symbol)
   --# global in out Dict;
   --# derives Dict from *,
   --#                   Region,
   --#                   The_Declaration;
   is

      procedure Add_Local_Declaration_To_Package
        (The_Declaration : in RawDict.Declaration_Info_Ref;
         The_Package     : in RawDict.Package_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Package;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Package_Last_Local_Declaration (The_Package => The_Package);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Package_First_Local_Declaration (The_Package     => The_Package,
                                                         The_Declaration => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Package_Last_Local_Declaration (The_Package     => The_Package,
                                                     The_Declaration => The_Declaration);
      end Add_Local_Declaration_To_Package;

      --------------------------------------------------------------------------------

      procedure Add_Local_Declaration_To_Subprogram
        (The_Declaration : in RawDict.Declaration_Info_Ref;
         The_Subprogram  : in RawDict.Subprogram_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Subprogram;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Subprogram_Last_Declaration (The_Subprogram => The_Subprogram);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Subprogram_First_Declaration (The_Subprogram  => The_Subprogram,
                                                      The_Declaration => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Subprogram_Last_Declaration (The_Subprogram  => The_Subprogram,
                                                  The_Declaration => The_Declaration);
      end Add_Local_Declaration_To_Subprogram;

      --------------------------------------------------------------------------------

      procedure Add_Local_Declaration_To_Protected_Type
        (The_Declaration    : in RawDict.Declaration_Info_Ref;
         The_Protected_Type : in RawDict.Type_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Protected_Type;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Protected_Type_Last_Local_Declaration (The_Protected_Type => The_Protected_Type);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Protected_Type_First_Local_Declaration
              (The_Protected_Type => The_Protected_Type,
               The_Declaration    => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Protected_Type_Last_Local_Declaration
           (The_Protected_Type => The_Protected_Type,
            The_Declaration    => The_Declaration);
      end Add_Local_Declaration_To_Protected_Type;

      --------------------------------------------------------------------------------

      procedure Add_Local_Declaration_To_Task_Type
        (The_Declaration : in RawDict.Declaration_Info_Ref;
         The_Task_Type   : in RawDict.Type_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Task_Type;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Task_Type_Last_Local_Declaration (The_Task_Type => The_Task_Type);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Task_Type_First_Local_Declaration (The_Task_Type   => The_Task_Type,
                                                           The_Declaration => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Task_Type_Last_Local_Declaration (The_Task_Type   => The_Task_Type,
                                                       The_Declaration => The_Declaration);
      end Add_Local_Declaration_To_Task_Type;

   begin -- Add_Local_Declaration
      case RawDict.GetSymbolDiscriminant (Region) is
         when Package_Symbol =>
            Add_Local_Declaration_To_Package
              (The_Declaration => The_Declaration,
               The_Package     => RawDict.Get_Package_Info_Ref (Item => Region));
         when Type_Symbol =>
            case RawDict.Get_Type_Discriminant (RawDict.Get_Type_Info_Ref (Item => Region)) is
               when Protected_Type_Item =>
                  Add_Local_Declaration_To_Protected_Type
                    (The_Declaration    => The_Declaration,
                     The_Protected_Type => RawDict.Get_Type_Info_Ref (Item => Region));
               when Task_Type_Item =>
                  Add_Local_Declaration_To_Task_Type
                    (The_Declaration => The_Declaration,
                     The_Task_Type   => RawDict.Get_Type_Info_Ref (Item => Region));
               when others => -- non-exec code
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Symbol_Table,
                     Msg     => "Dictionary.Add_Local_Declaration");
            end case;
         when Subprogram_Symbol =>
            Add_Local_Declaration_To_Subprogram
              (The_Declaration => The_Declaration,
               The_Subprogram  => RawDict.Get_Subprogram_Info_Ref (Item => Region));
         when others => -- non-exec code
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Invalid_Symbol_Table,
                                      Msg     => "Dictionary.Add_Local_Declaration");
      end case;
   end Add_Local_Declaration;

   --------------------------------------------------------------------------------

   procedure Add_Private_Declaration (The_Declaration : in RawDict.Declaration_Info_Ref;
                                      Region          : in Symbol)
   --# global in out Dict;
   --# derives Dict from *,
   --#                   Region,
   --#                   The_Declaration;
   is

      procedure Add_Private_Declaration_To_Package
        (The_Declaration : in RawDict.Declaration_Info_Ref;
         The_Package     : in RawDict.Package_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Package;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Package_Last_Private_Declaration (The_Package => The_Package);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Package_First_Private_Declaration (The_Package     => The_Package,
                                                           The_Declaration => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Package_Last_Private_Declaration (The_Package     => The_Package,
                                                       The_Declaration => The_Declaration);
      end Add_Private_Declaration_To_Package;

      --------------------------------------------------------------------------------

      procedure Add_Private_Declaration_To_Protected_Type
        (The_Declaration    : in RawDict.Declaration_Info_Ref;
         The_Protected_Type : in RawDict.Type_Info_Ref)
      --# global in out Dict;
      --# derives Dict from *,
      --#                   The_Declaration,
      --#                   The_Protected_Type;
      is
         Previous : RawDict.Declaration_Info_Ref;
      begin
         Previous := RawDict.Get_Protected_Type_Last_Private_Declaration (The_Protected_Type => The_Protected_Type);
         if Previous = RawDict.Null_Declaration_Info_Ref then
            RawDict.Set_Protected_Type_First_Private_Declaration
              (The_Protected_Type => The_Protected_Type,
               The_Declaration    => The_Declaration);
         else
            RawDict.Set_Next_Declaration (The_Declaration => Previous,
                                          Next            => The_Declaration);
         end if;
         RawDict.Set_Protected_Type_Last_Private_Declaration
           (The_Protected_Type => The_Protected_Type,
            The_Declaration    => The_Declaration);
      end Add_Private_Declaration_To_Protected_Type;

   begin -- Add_Private_Declaration
      case RawDict.GetSymbolDiscriminant (Region) is
         when Package_Symbol =>
            Add_Private_Declaration_To_Package
              (The_Declaration => The_Declaration,
               The_Package     => RawDict.Get_Package_Info_Ref (Item => Region));
         when Type_Symbol => -- must be a protected type
            SystemErrors.RT_Assert
              (C       => Is_Protected_Type (Type_Mark => RawDict.Get_Type_Info_Ref (Item => Region)),
               Sys_Err => SystemErrors.Invalid_Symbol_Table,
               Msg     => "Dictionary.Add_Private_Declaration");
            Add_Private_Declaration_To_Protected_Type
              (The_Declaration    => The_Declaration,
               The_Protected_Type => RawDict.Get_Type_Info_Ref (Item => Region));
         when others => -- non-exec code
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Invalid_Symbol_Table,
                                      Msg     => "Dictionary.Add_Private_Declaration");
      end case;
   end Add_Private_Declaration;

begin -- Add_Declaration
   RawDict.Create_Declaration
     (Context         => Context,
      Scope           => Scope,
      Comp_Unit       => Comp_Unit,
      Loc             => Loc.Start_Position,
      The_Declaration => The_Declaration);
   case Get_Visibility (Scope => Scope) is
      when Visible =>
         Add_Visible_Declaration (The_Declaration => The_Declaration,
                                  Region          => GetRegion (Scope));
      when Local =>
         Add_Local_Declaration (The_Declaration => The_Declaration,
                                Region          => GetRegion (Scope));
      when Privat =>
         Add_Private_Declaration (The_Declaration => The_Declaration,
                                  Region          => GetRegion (Scope));
   end case;
end Add_Declaration;
