-------------------------------------------------------------------------------
-- (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)
function Primary_Type_From_Context (Node    : STree.SyntaxNode;
                                    T_Stack : Type_Context_Stack.T_Stack_Type) return Dictionary.Symbol is
   New_Context_Type : Dictionary.Symbol;
   Parent, Op_Node  : STree.SyntaxNode;
begin
   Parent := STree.Parent_Node (Current_Node => Node);
   -- ASSUME Parent = factor OR annotation_factor
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.factor
        or else STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.annotation_factor,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Parent = factor OR annotation_factor in Primary_Type_From_Context");
   Op_Node := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Parent));
   -- ASSUME Op_Node = primary OR annotation_primary OR double_star OR NULL
   -- The context is unchanged for a primary, except in the case where
   -- this node is the right-hand operand of an exponentiation operator,
   -- in which case the context is Integer.
   if STree.Syntax_Node_Type (Node => Op_Node) = SP_Symbols.double_star then
      -- ASSUME Op_Node = double_star
      if STree.Next_Sibling (Current_Node => Op_Node) = Node then
         -- It's a ** operator and this primary node is the RHS operand
         New_Context_Type := Dictionary.GetPredefinedIntegerType;
      else
         New_Context_Type := Type_Context_Stack.Top (Stack => T_Stack);
      end if;
   elsif Op_Node = STree.NullNode
     or else STree.Syntax_Node_Type (Node => Op_Node) = SP_Symbols.primary
     or else STree.Syntax_Node_Type (Node => Op_Node) = SP_Symbols.annotation_primary then
      -- ASSUME Op_Node = primary OR annotation_primary OR NULL
      New_Context_Type := Type_Context_Stack.Top (Stack => T_Stack);
   else
      New_Context_Type := Dictionary.NullSymbol;
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Op_Node = primary OR annotation_primary OR double_star OR NULL in Primary_Type_From_Context");
   end if;
   return New_Context_Type;
end Primary_Type_From_Context;
