-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

with SLI;

separate (Sem.Wf_Package_Declaration.Wf_Package_Specification.Wf_Anno)
procedure Wf_Init_Spec
  (Node       : in STree.SyntaxNode;
   Pack_Sym   : in Dictionary.Symbol;
   Scope_Type : in Enclosing_Scope_Types;
   Scope      : in Dictionary.Scopes)
is

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

   procedure Do_Library_Pack (Init_Spec_Node : in STree.SyntaxNode;
                              Scope          : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         STree.Table                from Dictionary.Dict,
   --#                                         Init_Spec_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Init_Spec_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Init_Spec_Node, STree.Table) = SP_Symbols.initialization_specification;
   --# post STree.Table = STree.Table~;
   is
      Ident_List_Node, Next_Node : STree.SyntaxNode;
      It                         : STree.Iterator;
      Var_Sym                    : Dictionary.Symbol;
   begin
      Ident_List_Node := Child_Node (Current_Node => Init_Spec_Node);
      -- ASSUME Ident_List_Node = package_variable_list
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Ident_List_Node) = SP_Symbols.package_variable_list,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Ident_List_Node = package_variable_list in Do_Library_Pack");
      It := Find_First_Node (Node_Kind    => SP_Symbols.identifier,
                             From_Root    => Ident_List_Node,
                             In_Direction => STree.Down);
      while not STree.IsNull (It) loop
         Next_Node := Get_Node (It => It);
         --# assert STree.Table = STree.Table~ and
         --#   Syntax_Node_Type (Next_Node, STree.Table) = SP_Symbols.identifier and
         --#   Next_Node = Get_Node (It);
         Var_Sym :=
           Dictionary.LookupImmediateScope
           (Name    => Node_Lex_String (Node => Next_Node),
            Scope   => Scope,
            Context => Dictionary.ProofContext);
         if Dictionary.Is_Null_Symbol (Var_Sym) then -- undeclared
            ErrorHandler.Semantic_Error
              (Err_Num   => 139,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Next_Node),
               Id_Str    => Node_Lex_String (Node => Next_Node));
         elsif Dictionary.IsOwnVariable (Var_Sym) then -- ok as long as not moded
            if Dictionary.GetOwnVariableMode (Var_Sym) = Dictionary.DefaultMode then
               if not Dictionary.GetOwnVariableProtected (Var_Sym) then -- ok as long as not protected
                  STree.Set_Node_Lex_String (Sym  => Var_Sym,
                                             Node => Next_Node);
                  Dictionary.AddInitializedOwnVariable
                    (Var_Sym,
                     Dictionary.Location'(Start_Position => Node_Position (Node => Next_Node),
                                          End_Position   => Node_Position (Node => Next_Node)));
               else
                  -- own protected are implicitly initialized
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 863,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Node_Position (Node => Next_Node),
                     Id_Str    => Node_Lex_String (Node => Next_Node));
               end if;
            else -- has a mode
               ErrorHandler.Semantic_Error
                 (Err_Num   => 708,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Next_Node),
                  Id_Str    => Node_Lex_String (Node => Next_Node));
            end if;
         else -- not an own variable
            ErrorHandler.Semantic_Error
              (Err_Num   => 174,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Next_Node),
               Id_Str    => Node_Lex_String (Node => Next_Node));
         end if;
         It := STree.NextNode (It);
      end loop;
   end Do_Library_Pack;

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

   procedure Do_Embedded_Pack
     (Init_Spec_Node : in STree.SyntaxNode;
      Pack_Sym       : in Dictionary.Symbol;
      Scope          : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         STree.Table                from Dictionary.Dict,
   --#                                         Init_Spec_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Init_Spec_Node,
   --#                                         LexTokenManager.State,
   --#                                         Pack_Sym,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Init_Spec_Node, STree.Table) = SP_Symbols.initialization_specification;
   --# post STree.Table = STree.Table~;
   is
      Ident_List_Node, Last_Node, Next_Node : STree.SyntaxNode;
      Node_It                               : STree.Iterator;
      Var_Sym                               : Dictionary.Symbol;
      It                                    : Dictionary.Iterator;
   begin
      Ident_List_Node := Child_Node (Current_Node => Init_Spec_Node);
      -- ASSUME Ident_List_Node = package_variable_list
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Ident_List_Node) = SP_Symbols.package_variable_list,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Ident_List_Node = package_variable_list in Do_Embedded_Pack");
      Last_Node := Ident_List_Node;

      Node_It := Find_First_Node (Node_Kind    => SP_Symbols.identifier,
                                  From_Root    => Ident_List_Node,
                                  In_Direction => STree.Down);
      while not STree.IsNull (Node_It) loop
         Next_Node := Get_Node (It => Node_It);
         --# assert STree.Table = STree.Table~ and
         --#   Syntax_Node_Type (Next_Node, STree.Table) = SP_Symbols.identifier and
         --#   Next_Node = Get_Node (Node_It);
         Last_Node := Next_Node;
         Var_Sym   :=
           Dictionary.LookupImmediateScope
           (Name    => Node_Lex_String (Node => Next_Node),
            Scope   => Scope,
            Context => Dictionary.ProofContext);
         if Dictionary.Is_Null_Symbol (Var_Sym) then -- undeclared
            ErrorHandler.Semantic_Error
              (Err_Num   => 139,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Next_Node),
               Id_Str    => Node_Lex_String (Node => Next_Node));
         elsif Dictionary.IsOwnVariable (Var_Sym) and then Dictionary.OwnVariableIsAnnounced (Var_Sym) then -- potentially ok
            if Dictionary.GetOwnVariableMode (Var_Sym) /= Dictionary.DefaultMode then
               -- it does have a mode which is not allowed
               ErrorHandler.Semantic_Error
                 (Err_Num   => 708,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Next_Node),
                  Id_Str    => Node_Lex_String (Node => Next_Node));

            elsif not Dictionary.OwnVariableIsInitialized (Dictionary.GetSubject (Var_Sym)) then
               -- initialization not allowed because subject not initialized
               ErrorHandler.Semantic_Error
                 (Err_Num   => 78,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Next_Node),
                  Id_Str    => Node_Lex_String (Node => Next_Node));

            elsif Dictionary.GetOwnVariableProtected (Var_Sym) then
               -- ok as long as not protected own protected are
               -- implicitly initialized
               ErrorHandler.Semantic_Error
                 (Err_Num   => 863,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Next_Node),
                  Id_Str    => Node_Lex_String (Node => Next_Node));
            else
               STree.Set_Node_Lex_String (Sym  => Var_Sym,
                                          Node => Next_Node);
               Dictionary.AddInitializedOwnVariable
                 (Var_Sym,
                  Dictionary.Location'(Start_Position => Node_Position (Node => Next_Node),
                                       End_Position   => Node_Position (Node => Next_Node)));

            end if;
         else -- not an announced own variable
            ErrorHandler.Semantic_Error
              (Err_Num   => 174,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Next_Node),
               Id_Str    => Node_Lex_String (Node => Next_Node));
         end if;
         Node_It := STree.NextNode (Node_It);
      end loop;

      It := Dictionary.FirstOwnVariable (Pack_Sym);
      while not Dictionary.IsNullIterator (It) loop
         --# assert STree.Table = STree.Table~;
         Var_Sym := Dictionary.CurrentSymbol (It);
         if Dictionary.OwnVariableIsInitialized (Dictionary.GetSubject (Var_Sym))
           and then not Dictionary.OwnVariableIsInitialized (Var_Sym)
           and then Dictionary.GetOwnVariableMode (Var_Sym) = Dictionary.DefaultMode then
            ErrorHandler.Semantic_Error
              (Err_Num   => 79,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Last_Node),
               Id_Str    => Dictionary.GetSimpleName (Var_Sym));
         end if;
         It := Dictionary.NextSymbol (It);
      end loop;
   end Do_Embedded_Pack;

begin -- Wf_Init_Spec
   if Scope_Type = In_Package then
      Do_Embedded_Pack (Init_Spec_Node => Node,
                        Pack_Sym       => Pack_Sym,
                        Scope          => Scope);
   else
      Do_Library_Pack (Init_Spec_Node => Node,
                       Scope          => Scope);
   end if;

   if ErrorHandler.Generate_SLI then
      SLI.Generate_Xref_Initializes (Comp_Unit  => ContextManager.Ops.Current_Unit,
                                     Parse_Tree => Node,
                                     Scope      => Scope);
   end if;
end Wf_Init_Spec;
