-------------------------------------------------------------------------------
-- (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 Wf_Package_Initialization (Node  : in STree.SyntaxNode;
                                     Scope : in Dictionary.Scopes) is

   Stmt_Node : STree.SyntaxNode;
   Ident_Str : LexTokenManager.Lex_String;
   Pack_Sym  : Dictionary.Symbol;

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

   procedure Check_Whether_Initialization_Was_Needed
     (Pack_Sym  : in Dictionary.Symbol;
      Node_Pos  : in LexTokenManager.Token_Position;
      Ident_Str : in LexTokenManager.Lex_String)
   --# 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,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node_Pos,
   --#                                         Pack_Sym,
   --#                                         SPARK_IO.File_Sys;
   is
      Constituent_List, Init_Own_Var_List : Dictionary.Iterator;
      Init_Part_Needed                    : Boolean;
      Init_Own_Var_Sym                    : Dictionary.Symbol;
   begin
      Init_Part_Needed  := False;
      Init_Own_Var_List := Dictionary.FirstInitializedOwnVariable (Pack_Sym);
      while not Dictionary.IsNullIterator (Init_Own_Var_List) loop
         Init_Own_Var_Sym := Dictionary.CurrentSymbol (Init_Own_Var_List);
         if Dictionary.IsConcreteOwnVariable (Init_Own_Var_Sym) then
            -- filter out own vars initialized at declaration
            if not Dictionary.VariableIsInitialized (Init_Own_Var_Sym) then
               Init_Part_Needed := True;
            end if;
         else
            Constituent_List := Dictionary.FirstConstituent (Init_Own_Var_Sym);
            while not Dictionary.IsNullIterator (Constituent_List) loop
               if (not Dictionary.IsOwnVariable (Dictionary.CurrentSymbol (Constituent_List)))
                 and then (not Dictionary.VariableIsInitialized (Dictionary.CurrentSymbol (Constituent_List))) then
                  Init_Part_Needed := True;
                  exit;
               end if;
               Constituent_List := Dictionary.NextSymbol (Constituent_List);
            end loop;
         end if;
         exit when Init_Part_Needed;
         Init_Own_Var_List := Dictionary.NextSymbol (Init_Own_Var_List);
      end loop;

      if not Init_Part_Needed then
         ErrorHandler.Semantic_Error
           (Err_Num   => 66,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Pos,
            Id_Str    => Ident_Str);
      end if;
   end Check_Whether_Initialization_Was_Needed;

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

   function Null_Initialization (Node : STree.SyntaxNode) return Boolean
   --# global in STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.sequence_of_statements;
   is
      Current_Node : STree.SyntaxNode;
      Result       : Boolean;
   begin
      Current_Node := Child_Node (Current_Node => Node);
      -- ASSUME Current_Node = sequence_of_statements OR statement
      if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.sequence_of_statements then
         -- ASSUME Current_Node = sequence_of_statements
         Result := False;
      elsif Syntax_Node_Type (Node => Current_Node) = SP_Symbols.statement then
         -- ASSUME Current_Node = statement
         Current_Node := Child_Node (Current_Node => Current_Node);
         -- ASSUME Current_Node = sequence_of_labels OR simple_statement OR compound_statement OR proof_statement OR
         --                       justification_statement OR apragma
         if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.sequence_of_labels
           or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.compound_statement
           or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.proof_statement
           or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.justification_statement
           or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.apragma then
            -- ASSUME Current_Node = sequence_of_labels OR compound_statement OR proof_statement OR
            --                       justification_statement OR apragma
            Result := False;
         elsif Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_statement then
            -- ASSUME Current_Node = simple_statement
            Current_Node := Child_Node (Current_Node => Current_Node);
            -- ASSUME Current_Node = null_statement OR assignment_statement OR procedure_call_statement OR
            --                       exit_statement OR return_statement OR delay_statement
            if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.null_statement then
               -- ASSUME Current_Node = null_statement
               Result := True;
            elsif Syntax_Node_Type (Node => Current_Node) = SP_Symbols.assignment_statement
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.procedure_call_statement
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.exit_statement
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.return_statement
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.delay_statement then
               -- ASSUME Current_Node = assignment_statement OR procedure_call_statement
               --                       exit_statement OR return_statement OR delay_statement
               Result := False;
            else
               Result := False;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = null_statement OR assignment_statement OR procedure_call_statement OR " &
                    "exit_statement OR return_statement OR delay_statement in Null_Initialization");
            end if;
         else
            Result := False;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Current_Node = sequence_of_labels OR simple_statement OR compound_statement OR " &
                 "proof_statement OR justification_statement OR apragma in Null_Initialization");
         end if;
      else
         Result := False;
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Current_Node = sequence_of_statements OR statement in Null_Initialization");
      end if;
      return Result;
   end Null_Initialization;

begin -- Wf_Package_Initialization
   Pack_Sym  := Dictionary.GetRegion (Scope);
   Ident_Str := Dictionary.GetSimpleName (Pack_Sym);
   Stmt_Node := Child_Node (Current_Node => Node);
   -- ASSUME Stmt_Node = sequence_of_statements OR hidden_part
   if Syntax_Node_Type (Node => Stmt_Node) = SP_Symbols.hidden_part then
      -- ASSUME Stmt_Node = hidden_part
      ErrorHandler.Hidden_Text
        (Position => Node_Position (Node => Stmt_Node),
         Unit_Str => Ident_Str,
         Unit_Typ => SP_Symbols.package_initialization);
   elsif Syntax_Node_Type (Node => Stmt_Node) = SP_Symbols.sequence_of_statements then
      -- ASSUME Stmt_Node = sequence_of_statements
      -- not hidden so check whether it was necessary
      if not Null_Initialization (Node => Stmt_Node) then
         Check_Whether_Initialization_Was_Needed
           (Pack_Sym  => Pack_Sym,
            Node_Pos  => Node_Position (Node => Node),
            Ident_Str => Ident_Str);
      end if;
   end if;
end Wf_Package_Initialization;
