-------------------------------------------------------------------------------
-- (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.Walk_Expression_P)
procedure Wf_Percent
  (Node_Pos : in     LexTokenManager.Token_Position;
   Scope    : in     Dictionary.Scopes;
   E_Stack  : in out Exp_Stack.Exp_Stack_Type)
is
   Stack_Top : Sem.Exp_Record;
   Top_Sym   : Dictionary.Symbol;

   function In_A_For_Loop (Scope : Dictionary.Scopes) return Boolean
   --# global in Dictionary.Dict;
   is
      -- Search outwards in scope as long as we remain in a loop.
      -- Success is when a for loop is found,
      -- Failure is when anything other than a loop is found.
      Current_Scope : Dictionary.Scopes;
      Result        : Boolean := False;
   begin
      Current_Scope := Scope;
      while Dictionary.IsLoop (Dictionary.GetRegion (Current_Scope)) loop
         if not Dictionary.Is_Null_Symbol (Dictionary.GetLoopParameter (Dictionary.GetRegion (Current_Scope))) then
            -- for loop found
            Result := True;
            exit;
         end if;
         Current_Scope := Dictionary.GetEnclosingScope (Current_Scope);
      end loop;
      return Result;
   end In_A_For_Loop;

begin -- Wf_Percent

   -- Percent operator is only allowed in loop invariants of for loops.
   if In_A_For_Loop (Scope => Scope) then
      -- Percent may be allowed
      Exp_Stack.Pop (Item  => Stack_Top,
                     Stack => E_Stack);
      if Stack_Top.Sort = Sem.Is_Object then -- May be ok, further checks required
         Top_Sym := Stack_Top.Other_Symbol;
         if not Dictionary.Is_Variable (Top_Sym) then
            Stack_Top.Errors_In_Expression := True;
            ErrorHandler.Semantic_Error
              (Err_Num   => 318,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Pos,
               Id_Str    => LexTokenManager.Null_String);

         elsif not Dictionary.Types_Are_Equal
           (Left_Symbol        => Stack_Top.Type_Symbol,
            Right_Symbol       => Dictionary.GetType (Top_Sym),
            Full_Range_Subtype => False) then
            -- New check that variable is entire
            Stack_Top.Errors_In_Expression := True;
            ErrorHandler.Semantic_Error
              (Err_Num   => 320,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Pos,
               Id_Str    => LexTokenManager.Null_String);
         end if;
      else -- not an object so error message needed
         Stack_Top.Errors_In_Expression := True;
         if not (Stack_Top.Sort = Sem.Is_Unknown) then
            -- Supress error for unknown things
            ErrorHandler.Semantic_Error
              (Err_Num   => 318,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Pos,
               Id_Str    => LexTokenManager.Null_String);
         end if;
      end if;
      Exp_Stack.Push (X     => Stack_Top,
                      Stack => E_Stack);
   else
      Exp_Stack.Pop (Item  => Stack_Top,
                     Stack => E_Stack);
      Stack_Top.Errors_In_Expression := True;
      Exp_Stack.Push (X     => Stack_Top,
                      Stack => E_Stack);
      ErrorHandler.Semantic_Error
        (Err_Num   => 310,
         Reference => ErrorHandler.No_Reference,
         Position  => Node_Pos,
         Id_Str    => LexTokenManager.Null_String);
   end if;
end Wf_Percent;
