-------------------------------------------------------------------------------
-- (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 E_Strings;
with SLI;

separate (Sem.CompUnit)
procedure Wf_Body_Stub
  (Node           : in     STree.SyntaxNode;
   Scope          : in     Dictionary.Scopes;
   Component_Data : in out ComponentManager.ComponentData)
is

   type Err_Lookup is array (Boolean) of Natural;
   Which_Err : constant Err_Lookup := Err_Lookup'(False => 155,
                                                  True  => 336);

   -- look up table: if First_Seen then we are dealing with Abstract spec else Refined
   type Which_Abstractions is array (Boolean) of Dictionary.Abstractions;
   Which_Abstraction : constant Which_Abstractions :=
     Which_Abstractions'(False => Dictionary.IsRefined,
                         True  => Dictionary.IsAbstract);

   Node_Type                                      : SP_Symbols.SP_Symbol;
   Ident_Node                                     : STree.SyntaxNode;
   Ident_Str                                      : LexTokenManager.Lex_String;
   Spec_Node                                      : STree.SyntaxNode;
   Formal_Node                                    : STree.SyntaxNode;
   Pragma_Node                                    : STree.SyntaxNode;
   Anno_Node                                      : STree.SyntaxNode;
   Global_Node                                    : STree.SyntaxNode;
   Dependency_Node                                : STree.SyntaxNode;
   Declare_Node                                   : STree.SyntaxNode;
   Constraint_Node                                : STree.SyntaxNode;
   Pack_Sym, Subprog_Sym, Protected_Sym, Task_Sym : Dictionary.Symbol;
   First_Seen                                     : Boolean;
   Scope_Local                                    : Dictionary.Scopes;
   Interfacing_Pragma_Found                       : Boolean := False;
   Other_Pragma_Found                             : Boolean := False;
   Unused                                         : Boolean;
   Valid_Annotation                               : Boolean := False; -- used for task type stubs
   Valid_Stub_Position                            : Boolean := True;
   Is_Overriding                                  : Boolean;

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

   procedure Check_Position (Node                : in     STree.SyntaxNode;
                             Valid_Stub_Position : in out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        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,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table &
   --#         Valid_Stub_Position        from *,
   --#                                         Node,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.body_stub;
   is
      Outer_Node : STree.SyntaxNode;
   begin
      Outer_Node := Parent_Node (Current_Node => Parent_Node (Current_Node => Parent_Node (Current_Node => Node)));
      while Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.later_declarative_item_rep loop
         -- ASSUME Outer_Node = later_declarative_item_rep
         Outer_Node := Parent_Node (Current_Node => Outer_Node);
      end loop;
      -- ASSUME Outer_Node = declarative_part
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.declarative_part,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Outer_Node = declarative_part in Check_Position");
      Outer_Node := Parent_Node (Current_Node => Parent_Node (Current_Node => Parent_Node (Current_Node => Outer_Node)));
      -- ASSUME Outer_Node = proper_body OR protected_operation_item OR generic_subprogram_body OR
      --                     main_program_declaration OR library_unit_body
      if Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.proper_body
        or else Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.protected_operation_item then
         -- ASSUME Outer_Node = proper_body OR protected_operation_item
         if Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.protected_operation_item then
            while Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.protected_operation_item loop
               -- ASSUME Outer_Node = protected_operation_item
               Outer_Node := Parent_Node (Current_Node => Outer_Node);
            end loop;
            -- ASSUME Outer_Node = protected_body
            SystemErrors.RT_Assert
              (C       => Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.protected_body,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Outer_Node = protected_body in Check_Position");
            Outer_Node := Parent_Node (Current_Node => Outer_Node);
         end if;
         -- ASSUME Outer_Node = proper_body
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.proper_body,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Outer_Node = proper_body in Check_Position");
         Outer_Node := Parent_Node (Current_Node => Outer_Node);
         -- ASSUME Outer_Node = abody OR subunit
         if Syntax_Node_Type (Node => Outer_Node) = SP_Symbols.abody then
            -- ASSUME Outer_Node = abody
            Valid_Stub_Position := False;
            ErrorHandler.Semantic_Error
              (Err_Num   => 61,
               Reference => 17,
               Position  => Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
         elsif Syntax_Node_Type (Node => Outer_Node) /= SP_Symbols.subunit then
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Outer_Node = abody OR subunit in Check_Position");
         end if;
      elsif Syntax_Node_Type (Node => Outer_Node) /= SP_Symbols.generic_subprogram_body
        and then Syntax_Node_Type (Node => Outer_Node) /= SP_Symbols.main_program_declaration
        and then Syntax_Node_Type (Node => Outer_Node) /= SP_Symbols.library_unit_body then
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Outer_Node = proper_body OR protected_operation_item OR generic_subprogram_body OR " &
              "main_program_declaration OR library_unit_body in Check_Position");
      end if;
   end Check_Position;

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

   function Requires_Second_Annotation (Subprog_Sym : Dictionary.Symbol) return Boolean
   --# global in Dictionary.Dict;
   is
      Global_Var       : Dictionary.Symbol;
      Required         : Boolean;
      Global_Item      : Dictionary.Iterator;
      Enclosing_Region : Dictionary.Symbol;
   begin
      Required := False;
      if not Dictionary.IsGlobalScope (Dictionary.GetScope (Subprog_Sym)) then
         Enclosing_Region := Dictionary.GetEnclosingCompilationUnit (Dictionary.GetScope (Subprog_Sym));
         if Dictionary.IsPackage (Enclosing_Region) then
            Global_Item := Dictionary.FirstGlobalVariable (Dictionary.IsAbstract, Subprog_Sym);
            while Global_Item /= Dictionary.NullIterator loop
               Global_Var := Dictionary.CurrentSymbol (Global_Item);
               if Dictionary.IsRefinedOwnVariable (Global_Var)
                 and then Dictionary.Packages_Are_Equal
                 (Left_Symbol  => Dictionary.GetOwner (Global_Var),
                  Right_Symbol => Enclosing_Region) then
                  Required := True;
                  exit;
               end if;
               Global_Item := Dictionary.NextSymbol (Global_Item);
            end loop;
         end if;
      end if;
      return Required;
   end Requires_Second_Annotation;

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

   function Empty_Annotation (Node : STree.SyntaxNode) return Boolean
   --# global in STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.procedure_annotation;
   is
      Current_Node : STree.SyntaxNode;
   begin
      Current_Node := Child_Node (Current_Node => Node);
      -- ASSUME Current_Node = moded_global_definition OR dependency_relation OR declare_annotation OR procedure_constraint
      if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.procedure_constraint then
         Current_Node := Child_Node (Current_Node => Current_Node);
         -- ASSUME Current_Node = precondition OR postcondition OR NULL
         SystemErrors.RT_Assert
           (C       => Current_Node = STree.NullNode
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.precondition
              or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.postcondition,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Current_Node = precondition OR postcondition OR NULL in Empty_Annotation");
      elsif Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.moded_global_definition
        and then Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.dependency_relation
        and then Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.declare_annotation then
         Current_Node := STree.NullNode;
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Current_Node = moded_global_definition OR dependency_relation OR declare_annotation OR " &
              "procedure_constraint in Empty_Annotation");
      end if;
      return Current_Node = STree.NullNode;
   end Empty_Annotation;

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

   procedure Process_Annotation
     (Anno_Node        : in     STree.SyntaxNode;
      Scope            : in     Dictionary.Scopes;
      Task_Sym         : in     Dictionary.Symbol;
      Valid_Annotation : in out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Aggregate_Stack.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SLI.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --#        in out TheHeap;
   --# derives Aggregate_Stack.State,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         Statistics.TableUsage,
   --#         STree.Table,
   --#         TheHeap                    from *,
   --#                                         Anno_Node,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Task_Sym,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from Anno_Node,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Task_Sym,
   --#                                         TheHeap &
   --#         Valid_Annotation           from *,
   --#                                         Anno_Node,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.procedure_annotation;
   --# post STree.Table = STree.Table~;
   is
      Current_Node : STree.SyntaxNode;
   begin
      Current_Node := Child_Node (Current_Node => Anno_Node);
      -- ASSUME Current_Node = moded_global_definition OR dependency_relation OR declare_annotation OR procedure_constraint
      -- to be legal, Current_Node must be a moded_global_definition
      if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.moded_global_definition then
         -- ASSUME Current_Node = moded_global_definition
         Current_Node := Last_Sibling_Of (Start_Node => Current_Node);
         -- ASSUME Current_Node = procedure_constraint
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Current_Node) = SP_Symbols.procedure_constraint,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Current_Node = procedure_constraint in Process_Annotation");
         if Child_Node (Current_Node => Current_Node) = STree.NullNode then
            -- ASSUME Child_Node (Current_Node => Current_Node) = NULL
            Valid_Annotation := True;
            Wf_Subprogram_Annotation
              (Node          => Anno_Node,
               Current_Scope => Scope,
               Subprog_Sym   => Task_Sym,
               First_Seen    => False,
               The_Heap      => TheHeap);
         elsif Syntax_Node_Type (Node => Child_Node (Current_Node => Current_Node)) = SP_Symbols.precondition
           or else Syntax_Node_Type (Node => Child_Node (Current_Node => Current_Node)) = SP_Symbols.postcondition then
            -- ASSUME Child_Node (Current_Node => Current_Node) = precondition OR postcondition
            ErrorHandler.Semantic_Error
              (Err_Num   => 990,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Current_Node),
               Id_Str    => LexTokenManager.Null_String);
         else
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Child_Node (Current_Node => Current_Node) = precondition OR postcondition OR " &
                 "NULL in Process_Annotation");
         end if;
      elsif Syntax_Node_Type (Node => Current_Node) = SP_Symbols.dependency_relation
        or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.declare_annotation
        or else Syntax_Node_Type (Node => Current_Node) = SP_Symbols.procedure_constraint then
         ErrorHandler.Semantic_Error
           (Err_Num   => 990,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Current_Node),
            Id_Str    => LexTokenManager.Null_String);
      else
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Current_Node = moded_global_definition OR dependency_relation OR declare_annotation OR " &
              "procedure_constraint in Process_Annotation");
      end if;
   end Process_Annotation;

begin -- Wf_Body_Stub
   Pragma_Node := Last_Sibling_Of (Start_Node => Child_Node (Current_Node => Node));
   -- ASSUME Pragma_Node = apragma OR procedure_annotation OR function_annotation OR
   --                      dotted_simple_name OR task_stub OR protected_stub
   if Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.apragma then
      -- ASSUME Pragma_Node = apragma
      if Is_External_Interface (Pragma_Node => Pragma_Node) then
         -- either Interface of Import correctly used for language variant
         Interfacing_Pragma_Found := True;
      else
         -- some other pragma found
         Other_Pragma_Found := True;
      end if;
   elsif Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.procedure_annotation
     or else Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.function_annotation
     or else Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.dotted_simple_name
     or else Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.task_stub
     or else Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.protected_stub then
      -- ASSUME Pragma_Node = procedure_annotation OR function_annotation OR dotted_simple_name OR task_stub OR protected_stub
      Check_Position (Node                => Node,
                      Valid_Stub_Position => Valid_Stub_Position);
   else
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Node = apragma OR procedure_annotation OR function_annotation OR dotted_simple_name OR " &
           "task_stub OR protected_stub in Wf_Body_Stub");
   end if;
   --# assert STree.Table = STree.Table~ and
   --#   (Interfacing_Pragma_Found -> (Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma));
   Node_Type := Syntax_Node_Type (Node => Child_Node (Current_Node => Node));
   -- ASSUME Node_Type = overriding_indicator OR procedure_specification OR function_specification OR
   --                    dotted_simple_name OR task_stub OR protected_stub
   if Node_Type = SP_Symbols.dotted_simple_name then
      -- ASSUME Node_Type = dotted_simple_name
      Ident_Node := Child_Node (Current_Node => Child_Node (Current_Node => Node));
      -- ASSUME Ident_Node = dotted_simple_name OR identifier
      if Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.dotted_simple_name then
         -- ASSUME Ident_Node = dotted_simple_name
         ErrorHandler.Semantic_Error
           (Err_Num   => 613,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Ident_Node),
            Id_Str    => LexTokenManager.Null_String);
      elsif Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.identifier then
         -- ASSUME Ident_Node = identifier
         Pack_Sym :=
           Dictionary.LookupImmediateScope
           (Name    => Node_Lex_String (Ident_Node),
            Scope   => Scope,
            Context => Dictionary.ProgramContext);
         if Dictionary.Is_Null_Symbol (Pack_Sym) or else not Dictionary.IsPackage (Pack_Sym) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 11,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Ident_Node),
               Id_Str    => Node_Lex_String (Ident_Node));
         elsif Dictionary.HasBody (Pack_Sym) or else Dictionary.HasBodyStub (Pack_Sym) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 16,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Ident_Node),
               Id_Str    => Node_Lex_String (Ident_Node));
         elsif Dictionary.IsPackage (Dictionary.GetRegion (Scope))
           and then not Dictionary.IsEmbeddedPackage (Dictionary.GetRegion (Scope))
           and then not Dictionary.Is_Null_Symbol
           (Dictionary.LookupSelectedItem
              (Prefix   => Dictionary.GetRegion (Scope),
               Selector => Node_Lex_String (Ident_Node),
               Scope    => Dictionary.GlobalScope,
               Context  => Dictionary.ProofContext)) then
            -- name exists as child
            ErrorHandler.Semantic_Error
              (Err_Num   => 10,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Ident_Node),
               Id_Str    => Node_Lex_String (Ident_Node));
         else
            STree.Set_Node_Lex_String (Sym  => Pack_Sym,
                                       Node => Ident_Node);
            if Valid_Stub_Position then
               Dictionary.AddBodyStub
                 (CompilationUnit => Pack_Sym,
                  Comp_Unit       => ContextManager.Ops.Current_Unit,
                  BodyStub        => Dictionary.Location'(Start_Position => Node_Position (Node => Node),
                                                          End_Position   => Node_Position (Node => Node)));
            end if;
         end if;
      else
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Ident_Node = dotted_simple_name OR identifier in Wf_Body_Stub");
      end if;
   elsif Node_Type = SP_Symbols.procedure_specification
     or else Node_Type = SP_Symbols.function_specification
     or else (Node_Type = SP_Symbols.overriding_indicator
                and then (Syntax_Node_Type (Node => Next_Sibling (Current_Node => Child_Node (Current_Node => Node))) =
                            SP_Symbols.procedure_specification
                            or else Syntax_Node_Type (Node => Next_Sibling (Current_Node => Child_Node (Current_Node => Node))) =
                            SP_Symbols.function_specification)) then
      -- ASSUME Node_Type = procedure_specification OR function_specification OR overriding_indicator
      if Valid_Stub_Position then
         Scope_Local   := Scope;
         Is_Overriding := False;
         if Node_Type = SP_Symbols.overriding_indicator then
            -- ASSUME Node_Type = overriding_indicator
            -- ASSUME Child_Node (Current_Node => Node_Type) = RWoverriding OR RWnot
            if Syntax_Node_Type (Node => Last_Child_Of (Start_Node => Node)) = SP_Symbols.RWoverriding then
               -- ASSUME Child_Node (Current_Node => Node_Type) = RWoverriding
               Is_Overriding := True;
            end if;
            Spec_Node := Next_Sibling (Current_Node => Child_Node (Current_Node => Node));
         else
            Spec_Node := Child_Node (Current_Node => Node);
         end if;
         -- ASSUME Spec_Node = procedure_specification OR function_specification
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.procedure_specification
              or else Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.function_specification,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Spec_Node = procedure_specification OR function_specification in Wf_Body_Stub");
         Anno_Node := Next_Sibling (Current_Node => Spec_Node);
         -- ASSUME Anno_Node = procedure_annotation OR function_annotation
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Anno_Node) = SP_Symbols.procedure_annotation
              or else Syntax_Node_Type (Node => Anno_Node) = SP_Symbols.function_annotation,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Anno_Node = procedure_annotation OR function_annotation in Wf_Body_Stub");
         Get_Subprogram_Anno_Key_Nodes
           (Node            => Anno_Node,
            Global_Node     => Global_Node,
            Dependency_Node => Dependency_Node,
            Declare_Node    => Declare_Node,
            Constraint_Node => Constraint_Node);
         --# assert STree.Table = STree.Table~ and
         --#   (Interfacing_Pragma_Found -> (Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma)) and
         --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
         --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
         --#   (Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.procedure_annotation or
         --#      Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.function_annotation) and
         --#   (Syntax_Node_Type (Global_Node, STree.Table) = SP_Symbols.moded_global_definition or
         --#      Global_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Dependency_Node, STree.Table) = SP_Symbols.dependency_relation or
         --#      Dependency_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Declare_Node, STree.Table) = SP_Symbols.declare_annotation or
         --#      Declare_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
         --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
         Formal_Node := Next_Sibling (Current_Node => Child_Node (Current_Node => Spec_Node));
         -- ASSUME Formal_Node = formal_part OR type_mark OR NULL
         if Syntax_Node_Type (Node => Formal_Node) = SP_Symbols.type_mark then
            -- ASSUME Formal_Node = type_mark
            Formal_Node := STree.NullNode;
         elsif Formal_Node /= STree.NullNode and then Syntax_Node_Type (Node => Formal_Node) /= SP_Symbols.formal_part then
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Formal_Node = formal_part OR type_mark OR NULL in Wf_Body_Stub");
         end if;
         Subprogram_Specification.Wf_Subprogram_Specification_From_Body
           (Node          => Spec_Node,
            Hidden        => False,
            Current_Scope => Scope_Local,
            Subprog_Sym   => Subprog_Sym,
            First_Seen    => First_Seen);
         --# assert STree.Table = STree.Table~ and
         --#   (Interfacing_Pragma_Found -> (Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma)) and
         --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
         --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
         --#   (Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.procedure_annotation or
         --#      Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.function_annotation) and
         --#   (Syntax_Node_Type (Global_Node, STree.Table) = SP_Symbols.moded_global_definition or
         --#      Global_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Dependency_Node, STree.Table) = SP_Symbols.dependency_relation or
         --#      Dependency_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Declare_Node, STree.Table) = SP_Symbols.declare_annotation or
         --#      Declare_Node = STree.NullNode) and
         --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
         --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
         if not Dictionary.Is_Null_Symbol (Subprog_Sym) then
            if Syntax_Node_Type (Node => Pragma_Node) = SP_Symbols.apragma and then not First_Seen then -- illegal redeclaration
               ErrorHandler.A_Pragma
                 (Pragma_Name => Node_Lex_String (Child_Node (Current_Node => Pragma_Node)),
                  Position    => Node_Position (Node => Pragma_Node));
               ErrorHandler.Semantic_Error
                 (Err_Num   => 10,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Node),
                  Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
            else -- this else means we don't process illegal redeclarations further
               if First_Seen and then Other_Pragma_Found then -- only an interfacing pragma will do
                  case CommandLineData.Content.Language_Profile is
                     when CommandLineData.SPARK83 =>
                        ErrorHandler.Semantic_Error
                          (Err_Num   => 70,
                           Reference => 18,
                           Position  => Node_Position (Node => Pragma_Node),
                           Id_Str    => LexTokenManager.Interface_Token);
                     when CommandLineData.SPARK95_Onwards =>
                        ErrorHandler.Semantic_Error
                          (Err_Num   => 70,
                           Reference => 18,
                           Position  => Node_Position (Node => Pragma_Node),
                           Id_Str    => LexTokenManager.Import_Token);
                  end case;
               end if; -- wrong pragma

               -- If we are here then we have either:
               --               a legal declaration using a correct interfacing pragma; or
               --               a declaration with the wrong pragma that we have reported; or
               --               a legal "is separate"
               -- In each case we can go on to check formal parts and annotations

               if Syntax_Node_Type (Node => Formal_Node) = SP_Symbols.formal_part then
                  Wf_Formal_Part
                    (Node             => Formal_Node,
                     Current_Scope    => Scope_Local,
                     Subprog_Sym      => Subprog_Sym,
                     First_Occurrence => First_Seen,
                     Context          => Dictionary.ProgramContext);
               elsif Dictionary.GetNumberOfSubprogramParameters (Subprog_Sym) /= 0 then
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 152,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Node_Position (Node => Node),
                     Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
               end if; -- formal part to check

               --# assert STree.Table = STree.Table~ and
               --#   (Interfacing_Pragma_Found -> (Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma)) and
               --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
               --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
               --#   (Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.procedure_annotation or
               --#      Syntax_Node_Type (Anno_Node, STree.Table) = SP_Symbols.function_annotation) and
               --#   (Syntax_Node_Type (Global_Node, STree.Table) = SP_Symbols.moded_global_definition or
               --#      Global_Node = STree.NullNode) and
               --#   (Syntax_Node_Type (Dependency_Node, STree.Table) = SP_Symbols.dependency_relation or
               --#      Dependency_Node = STree.NullNode) and
               --#   (Syntax_Node_Type (Declare_Node, STree.Table) = SP_Symbols.declare_annotation or
               --#      Declare_Node = STree.NullNode) and
               --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
               --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
               if (First_Seen or else Requires_Second_Annotation (Subprog_Sym => Subprog_Sym))
                 and then (Syntax_Node_Type (Node => Global_Node) = SP_Symbols.moded_global_definition
                             or else Syntax_Node_Type (Node => Dependency_Node) = SP_Symbols.dependency_relation
                             or else Syntax_Node_Type (Node => Declare_Node) = SP_Symbols.declare_annotation) then
                  Wf_Subprogram_Annotation
                    (Node          => Anno_Node,
                     Current_Scope => Scope_Local,
                     Subprog_Sym   => Subprog_Sym,
                     First_Seen    => First_Seen,
                     The_Heap      => TheHeap);
                  -- We have processed a procedure annotation. We can use this to suppress the all-from-all behaviour if
                  -- flow=auto, but we need to know whether or not the procedure annotation consisted of global and derives
                  -- or global only. This is recorded in the Dictionary "HasDerivesAnnotation" by Wf_Subprogram_Annotation.
               elsif not First_Seen
                 and then Requires_Second_Annotation (Subprog_Sym => Subprog_Sym)
                 and then Global_Node = STree.NullNode
                 and then Dependency_Node = STree.NullNode
                 and then Declare_Node = STree.NullNode then
                  -- ASSUME Global_Node = NULL AND Dependency_Node = NULL AND Declare_Node = NULL
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 87,
                     Reference => 16,
                     Position  => Node_Position (Node => Spec_Node),
                     Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
                  if Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.procedure_specification then
                     -- ASSUME Spec_Node = procedure_specification
                     Dictionary.SetSubprogramSignatureNotWellformed (Dictionary.IsRefined, Subprog_Sym);
                  end if;
               elsif Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.procedure_specification
                 and then First_Seen
                 and then (CommandLineData.Content.Language_Profile = CommandLineData.SPARK83
                             or else CommandLineData.Content.Flow_Option = CommandLineData.Info_Flow)
                 and then Global_Node = STree.NullNode
                 and then Dependency_Node = STree.NullNode
                 and then Declare_Node = STree.NullNode then
                  -- ASSUME Global_Node = NULL AND Dependency_Node = NULL AND Declare_Node = NULL
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 154,
                     Reference => 19,
                     Position  => Node_Position (Node => Spec_Node),
                     Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
                  Dictionary.SetSubprogramSignatureNotWellformed (Dictionary.IsAbstract, Subprog_Sym);
               elsif Syntax_Node_Type (Node => Global_Node) = SP_Symbols.moded_global_definition
                 or else Syntax_Node_Type (Node => Dependency_Node) = SP_Symbols.dependency_relation
                 or else Syntax_Node_Type (Node => Declare_Node) = SP_Symbols.declare_annotation then
                  ErrorHandler.Semantic_Error
                    (Err_Num   => Which_Err (Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.function_specification),
                     Reference => 16,
                     Position  => Node_Position (Node => Spec_Node),
                     Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
               end if;

               --# assert STree.Table = STree.Table~ and
               --#   (Interfacing_Pragma_Found -> (Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma)) and
               --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
               --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
               --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
               --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
               if Interfacing_Pragma_Found then
                  --# accept Flow, 10, Unused, "Export not required here";
                  Wf_External_Interface (Pragma_Node => Pragma_Node,
                                         Entity_Sym  => Subprog_Sym,
                                         Error_Found => Unused);
                  --# end accept;
               end if;

               --# assert STree.Table = STree.Table~ and
               --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
               --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
               --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
               --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
               --
               -- Synthesise an 'all from all' dependency if necessary.
               if Syntax_Node_Type (Node => Spec_Node) = SP_Symbols.procedure_specification
                 and then Needs_Synthetic_Dependency (Proc_Task_Or_Entry => Subprog_Sym)
                 and then (First_Seen or else Requires_Second_Annotation (Subprog_Sym => Subprog_Sym)) then
                  Dependency_Relation.Create_Full_Subprog_Dependency
                    (Node_Pos    => Node_Position (Node => Node),
                     Subprog_Sym => Subprog_Sym,
                     Abstraction => Which_Abstraction (First_Seen),
                     The_Heap    => TheHeap);
               end if;

               --# assert STree.Table = STree.Table~ and
               --#   (Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.procedure_specification or
               --#      Syntax_Node_Type (Spec_Node, STree.Table) = SP_Symbols.function_specification) and
               --#   (Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.procedure_constraint or
               --#      Syntax_Node_Type (Constraint_Node, STree.Table) = SP_Symbols.function_constraint);
               if Syntax_Node_Type (Node => Child_Node (Current_Node => Constraint_Node)) = SP_Symbols.precondition
                 or else Syntax_Node_Type (Node => Child_Node (Current_Node => Constraint_Node)) = SP_Symbols.postcondition
                 or else Syntax_Node_Type (Node => Child_Node (Current_Node => Constraint_Node)) = SP_Symbols.return_expression
               then
                  -- ASSUME Child_Node (Current_Node => Constraint_Node) = precondition OR postcondition OR return_expression
                  -- a pre/post/return exists. Should it?
                  -- checks to see if constraint found is allowed
                  if not (First_Seen
                            or else Requires_Second_Annotation (Subprog_Sym => Subprog_Sym)
                            or else Has_Parameter_Global_Or_Return_Of_Local_Private_Type (Subprog_Sym => Subprog_Sym)) then
                     -- annotation not required
                     -- two possible errors: misplaced anno or duplicate anno
                     if Dictionary.HasPrecondition (Dictionary.IsAbstract, Subprog_Sym)
                       or else Dictionary.HasPostcondition (Dictionary.IsAbstract, Subprog_Sym) then -- illegal duplicate anno
                        ErrorHandler.Semantic_Error
                          (Err_Num   => 343,
                           Reference => ErrorHandler.No_Reference,
                           Position  => Node_Position (Node => Constraint_Node),
                           Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
                     else -- misplaced anno
                        ErrorHandler.Semantic_Error
                          (Err_Num   => 342,
                           Reference => ErrorHandler.No_Reference,
                           Position  => Node_Position (Node => Constraint_Node),
                           Id_Str    => Dictionary.GetSimpleName (Subprog_Sym));
                     end if;
                  else -- annotation is required so continue
                     Wf_Subprogram_Constraint
                       (Node           => Constraint_Node,
                        Subprogram_Sym => Subprog_Sym,
                        First_Seen     => First_Seen,
                        Component_Data => Component_Data,
                        The_Heap       => TheHeap);
                  end if;
               elsif Child_Node (Current_Node => Constraint_Node) /= STree.NullNode then
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Child_Node (Current_Node => Constraint_Node = precondition OR postcondition OR " &
                       "NULL in Wf_Body_Stub");
               end if;
            end if; -- not an illegal redclaration
         end if; -- subprogsym not null

         -- Prior to SPARK 2005, the check is only required when the procedure
         -- has not been previously declared. For SPARK 2005, the check is
         -- always required as the overriding_indicator for a
         -- subprogram body stub may be incorrect.
         if First_Seen or else CommandLineData.Content.Language_Profile in CommandLineData.SPARK2005_Profiles then
            Ident_Node := Child_Node (Current_Node => Child_Node (Current_Node => Spec_Node));
            -- ASSUME Ident_Node = identifier
            SystemErrors.RT_Assert
              (C       => Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.identifier,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Ident_Node = identifier in Wf_Body_Stub");
            Check_No_Overloading_From_Tagged_Ops
              (Ident_Node    => Ident_Node,
               Subprog_Sym   => Subprog_Sym,
               Scope         => Scope,
               Abstraction   => Dictionary.IsRefined,
               Is_Overriding => Is_Overriding);
         end if;
      end if; -- don't add stub if position illegal
   elsif Node_Type = SP_Symbols.task_stub then
      -- ASSUME Node_Type = task_stub
      if CommandLineData.Ravenscar_Selected then
         if Valid_Stub_Position then
            Ident_Node := Child_Node (Current_Node => Child_Node (Current_Node => Node));
            -- ASSUME Ident_Node = identifier
            SystemErrors.RT_Assert
              (C       => Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.identifier,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Ident_Node = identifier in Wf_Body_Stub");
            Ident_Str := Node_Lex_String (Ident_Node);
            Task_Sym  :=
              Dictionary.LookupItem
              (Name              => Node_Lex_String (Ident_Node),
               Scope             => Scope,
               Context           => Dictionary.ProgramContext,
               Full_Package_Name => False);
            if Dictionary.Is_Null_Symbol (Task_Sym) or else not Dictionary.IsTaskType (Task_Sym) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 898,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Ident_Node),
                  Id_Str    => Node_Lex_String (Ident_Node));
            elsif Dictionary.HasBody (Task_Sym) or else Dictionary.HasBodyStub (Task_Sym) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 899,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Ident_Node),
                  Id_Str    => Node_Lex_String (Ident_Node));
            else
               -- valid so far
               Dictionary.AddBodyStub
                 (CompilationUnit => Task_Sym,
                  Comp_Unit       => ContextManager.Ops.Current_Unit,
                  BodyStub        => Dictionary.Location'(Start_Position => Node_Position (Node => Node),
                                                          End_Position   => Node_Position (Node => Node)));
               -- check annotation
               Anno_Node := Next_Sibling (Current_Node => Ident_Node);
               -- ASSUME Anno_Node = procedure_annotation
               SystemErrors.RT_Assert
                 (C       => Syntax_Node_Type (Node => Anno_Node) = SP_Symbols.procedure_annotation,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Anno_Node = procedure_annotation in Wf_Body_Stub");
               if Requires_Second_Annotation (Subprog_Sym => Task_Sym) then
                  if Empty_Annotation (Node => Anno_Node) then
                     ErrorHandler.Semantic_Error
                       (Err_Num   => 154,
                        Reference => ErrorHandler.No_Reference,
                        Position  => Node_Position (Node => Node),
                        Id_Str    => Ident_Str);
                  else -- anno present and required
                     STree.Set_Node_Lex_String (Sym  => Task_Sym,
                                                Node => Ident_Node);
                     Process_Annotation
                       (Anno_Node        => Anno_Node,
                        Scope            => Scope,
                        Task_Sym         => Task_Sym,
                        Valid_Annotation => Valid_Annotation);
                  end if;
               else -- second anno not required
                  if Empty_Annotation (Node => Anno_Node) then
                     STree.Set_Node_Lex_String (Sym  => Task_Sym,
                                                Node => Ident_Node);
                  else
                     ErrorHandler.Semantic_Error
                       (Err_Num   => 155,
                        Reference => ErrorHandler.No_Reference,
                        Position  => Node_Position (Node => Anno_Node),
                        Id_Str    => Ident_Str);
                  end if;
               end if;

               -- Create "full" derives if annotation is present, valid and IFA is not selected.
               -- We know we are in SPARK 95 or 2005 as this is a task stub.
               -- Actually, we must only create the 'full' derives annotation if there is no explicit derives
               if Valid_Annotation
                 and then CommandLineData.Content.Flow_Option /= CommandLineData.Info_Flow
                 and then not Dictionary.GetHasDerivesAnnotation (Task_Sym) then
                  Dependency_Relation.Create_Full_Subprog_Dependency
                    (Node_Pos    => Node_Position (Node => Node),
                     Subprog_Sym => Task_Sym,
                     Abstraction => Dictionary.IsRefined,
                     The_Heap    => TheHeap);
               end if;
            end if;
         end if; -- don't process stub if illegally positioned
      else -- illegal
         ErrorHandler.Semantic_Error
           (Err_Num   => 850,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Node),
            Id_Str    => LexTokenManager.Null_String);
      end if;

   elsif Node_Type = SP_Symbols.protected_stub then
      -- ASSUME Node_Type = protected_stub
      if CommandLineData.Ravenscar_Selected then
         if Valid_Stub_Position then
            Ident_Node := Child_Node (Current_Node => Child_Node (Current_Node => Node));
            -- ASSUME Ident_Node = identifier
            SystemErrors.RT_Assert
              (C       => Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.identifier,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Ident_Node = identifier in Wf_Body_Stub");
            Protected_Sym :=
              Dictionary.LookupItem
              (Name              => Node_Lex_String (Ident_Node),
               Scope             => Scope,
               Context           => Dictionary.ProgramContext,
               Full_Package_Name => False);
            if Dictionary.Is_Null_Symbol (Protected_Sym)
              or else not (Dictionary.IsType (Protected_Sym) and then Dictionary.IsProtectedTypeMark (Protected_Sym)) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 898,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Ident_Node),
                  Id_Str    => Node_Lex_String (Ident_Node));
            elsif Dictionary.HasBody (Protected_Sym) or else Dictionary.HasBodyStub (Protected_Sym) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 899,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Ident_Node),
                  Id_Str    => Node_Lex_String (Ident_Node));
            else
               STree.Set_Node_Lex_String (Sym  => Protected_Sym,
                                          Node => Ident_Node);
               Dictionary.AddBodyStub
                 (CompilationUnit => Protected_Sym,
                  Comp_Unit       => ContextManager.Ops.Current_Unit,
                  BodyStub        => Dictionary.Location'(Start_Position => Node_Position (Node => Node),
                                                          End_Position   => Node_Position (Node => Node)));
            end if;
         end if; -- don't process stub if illegally positioned
      else -- illegal
         ErrorHandler.Semantic_Error
           (Err_Num   => 850,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Node),
            Id_Str    => LexTokenManager.Null_String);
      end if;
   else
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Node_Type = overriding_indicator OR procedure_specification OR function_specification OR " &
           "dotted_simple_name OR task_stub OR protected_stub in Wf_Body_Stub");
   end if;

   if ErrorHandler.Generate_SLI then
      SLI.Increment_Nb_Separates (Comp_Unit  => ContextManager.Ops.Current_Unit,
                                  Parse_Tree => Node);
   end if;
   --# accept F, 33, Unused, "Export not required here";
end Wf_Body_Stub;
