-------------------------------------------------------------------------------
-- (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)
procedure Create_Interrupt_Stream_Variable
  (For_PO              : in Dictionary.Symbol;
   The_Handler         : in LexTokenManager.Lex_String;
   The_Stream_Variable : in LexTokenManager.Lex_String;
   Error_Node_Pos      : in LexTokenManager.Token_Position)
is
   Sym           : Dictionary.Symbol;
   Type_Sym      : Dictionary.Symbol;
   Subprog_Sym   : Dictionary.Symbol;
   Unused_Symbol : Dictionary.Symbol;
   Scope         : Dictionary.Scopes;
   Found         : Boolean;
   It            : Dictionary.Iterator;
begin
   Type_Sym := Dictionary.GetType (For_PO);
   Scope    := Dictionary.GetScope (For_PO);
   It       := Dictionary.First_Visible_Subprogram (The_Package_Or_Type => Type_Sym);
   Found    := False;

   -- For all the subprograms in protected type
   while not (Found or else Dictionary.IsNullIterator (It)) loop
      Subprog_Sym := Dictionary.CurrentSymbol (It);

      -- Is it an interrupt handler?
      if Dictionary.IsInterruptHandler (Subprog_Sym) then
         -- Does the interrupt handler name in the type match the one in the
         -- interrupt property?
         if LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Dictionary.GetSimpleName (Subprog_Sym),
            Lex_Str2 => The_Handler) =
           LexTokenManager.Str_Eq then
            Found := True;

            -- Check the stream name to which it is mapped is not being used
            -- in this scope.
            Sym :=
              Dictionary.LookupItem
              (Name              => The_Stream_Variable,
               Scope             => Scope,
               Context           => Dictionary.ProofContext,
               Full_Package_Name => False);
            if Dictionary.Is_Null_Symbol (Sym) then
               -- Create the implicit own variable
               --# accept Flow, 10, Unused_Symbol, "Expected ineffective assignment";
               Dictionary.Add_Own_Variable
                 (Name                => The_Stream_Variable,
                  The_Package         => Dictionary.GetOwner (For_PO),
                  Mode                => Dictionary.InMode,
                  Is_Protected        => False,
                  Is_Interrupt_Stream => True,
                  Comp_Unit           => ContextManager.NullUnit,
                  Declaration         => Dictionary.Location'(Start_Position => LexTokenManager.Token_Position'(Start_Line_No => 0,
                                                                                                                Start_Pos     => 0),
                                                              End_Position   => LexTokenManager.Token_Position'(Start_Line_No => 0,
                                                                                                                Start_Pos     => 0)),
                  Var_Symbol          => Unused_Symbol);
               --# end accept;
            elsif not (Dictionary.IsOwnVariable (Sym) and then Dictionary.GetOwnVariableIsInterruptStream (Sym)) then
               -- The stream name is being used and is not an interrupt stream. Interrupt streams
               -- can be mapped to more than one handler.
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 954,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Error_Node_Pos,
                  Id_Str1   => Dictionary.GetSimpleName (For_PO),
                  Id_Str2   => The_Stream_Variable);
            end if;
         end if;
      end if;
      It := Dictionary.NextSymbol (It);
   end loop;
   if not Found then
      -- The handler name specified in the interrupt property is not an interrupt
      -- handler in the protected type.
      ErrorHandler.Semantic_Error_Lex1_Sym2
        (Err_Num   => 953,
         Reference => ErrorHandler.No_Reference,
         Position  => Error_Node_Pos,
         Id_Str    => The_Handler,
         Sym       => For_PO,
         Sym2      => Type_Sym,
         Scope     => Scope);
   end if;
   --# accept Flow, 33, Unused_Symbol, "Expected to be neither referenced nor exported";
end Create_Interrupt_Stream_Variable;
