-------------------------------------------------------------------------------
-- (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 (Sem.CompUnit)
procedure CheckEmbedBodies (Comp_Sym : in Dictionary.Symbol;
                            Node_Pos : in LexTokenManager.Token_Position) is

   Pack_List         : Dictionary.Iterator;
   Embedded_Pack_Sym : Dictionary.Symbol;
   Error             : Boolean;

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

   procedure Check_For_Any_Declared_Subprograms
     (Embedded_Pack_Sym : in     Dictionary.Symbol;
      Node_Pos          : in     LexTokenManager.Token_Position;
      Error_Found       :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Embedded_Pack_Sym,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node_Pos,
   --#                                         SPARK_IO.File_Sys &
   --#         Error_Found                from Dictionary.Dict,
   --#                                         Embedded_Pack_Sym;
   is

      function Subprog_Without_Body_Found (Subprogram_Iterator : Dictionary.Iterator) return Boolean
      --# global in Dictionary.Dict;
      is
         It     : Dictionary.Iterator;
         Result : Boolean := False;
      begin
         It := Subprogram_Iterator;
         while not Dictionary.IsNullIterator (It) loop
            if not (Dictionary.HasBody (Dictionary.CurrentSymbol (It))
                      or else Dictionary.IsProofFunction (Dictionary.CurrentSymbol (It))) then
               Result := True;
               exit;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
         return Result;
      end Subprog_Without_Body_Found;

   begin -- Check_For_Any_Declared_Subprograms
      Error_Found := False;
      if Subprog_Without_Body_Found
        (Subprogram_Iterator => Dictionary.First_Visible_Subprogram (The_Package_Or_Type => Embedded_Pack_Sym))
        or else Subprog_Without_Body_Found
        (Subprogram_Iterator => Dictionary.First_Private_Subprogram (The_Package => Embedded_Pack_Sym)) then
         Error_Found := True;
         ErrorHandler.Semantic_Error
           (Err_Num   => 62,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Pos,
            Id_Str    => Dictionary.GetSimpleName (Embedded_Pack_Sym));
      end if;
   end Check_For_Any_Declared_Subprograms;

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

   procedure Check_Any_Own_Variables (Embedded_Pack_Sym : in Dictionary.Symbol;
                                      Node_Pos          : in LexTokenManager.Token_Position)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Embedded_Pack_Sym,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node_Pos,
   --#                                         SPARK_IO.File_Sys;
   is
      Own_Var_It                                        : Dictionary.Iterator;
      Own_Var_Sym                                       : Dictionary.Symbol;
      Found_Own_Variable_Not_Initialized_At_Declaration : Boolean := False;
   begin
      Own_Var_It := Dictionary.FirstInitializedOwnVariable (Embedded_Pack_Sym);
      while Own_Var_It /= Dictionary.NullIterator loop
         Own_Var_Sym                                       := Dictionary.CurrentSymbol (Own_Var_It);
         Found_Own_Variable_Not_Initialized_At_Declaration := not Dictionary.Is_Declared (Item => Own_Var_Sym)
           -- not declared in spec at all
           or else not Dictionary.VariableIsInitialized (Own_Var_Sym);
         -- declared but not initialized
         exit when Found_Own_Variable_Not_Initialized_At_Declaration;
         Own_Var_It := Dictionary.NextSymbol (Own_Var_It);
      end loop;
      if Found_Own_Variable_Not_Initialized_At_Declaration then
         ErrorHandler.Semantic_Error
           (Err_Num   => 62,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Pos,
            Id_Str    => Dictionary.GetSimpleName (Embedded_Pack_Sym));
      end if;
   end Check_Any_Own_Variables;

begin -- CheckEmbedBodies
   Pack_List := Dictionary.First_Embedded_Package (Compilation_Unit => Comp_Sym);
   while not Dictionary.IsNullIterator (Pack_List) loop
      Embedded_Pack_Sym := Dictionary.CurrentSymbol (Pack_List);
      if not (Dictionary.HasBody (Embedded_Pack_Sym) or else Dictionary.HasBodyStub (Embedded_Pack_Sym)) then
         Check_For_Any_Declared_Subprograms (Embedded_Pack_Sym => Embedded_Pack_Sym,
                                             Node_Pos          => Node_Pos,
                                             Error_Found       => Error);
         if not Error then
            Check_Any_Own_Variables (Embedded_Pack_Sym => Embedded_Pack_Sym,
                                     Node_Pos          => Node_Pos);
         end if;
      end if;
      Pack_List := Dictionary.NextSymbol (Pack_List);
   end loop;
end CheckEmbedBodies;
