-------------------------------------------------------------------------------
-- (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.CompUnit)
procedure WalkStatements
  (Seq_Node       : in     STree.SyntaxNode;
   Scope          : in     Dictionary.Scopes;
   Table          : in out RefList.HashTable;
   Component_Data :    out ComponentManager.ComponentData)
is

   --# inherit CompleteCheck,
   --#         Dictionary,
   --#         ExaminerConstants,
   --#         Sem,
   --#         SPARK_IO,
   --#         SystemErrors;
   package Case_Stack
   --# own State : Stack_T;
   is

      --# type Stack_T is abstract;

      --# function Stack_Is_Valid (The_State : Stack_T) return Boolean;

      procedure Init;
      --# global in     Dictionary.Dict;
      --#           out State;
      --# derives State from  &
      --#         null  from Dictionary.Dict;
      --# post Stack_Is_Valid (State);

      procedure Push
        (Case_Flags   : in Sem.Typ_Case_Flags;
         Complete_ADT : in CompleteCheck.T;
         Sym          : in Dictionary.Symbol;
         Lower_Bound  : in Sem.Typ_Type_Bound;
         Upper_Bound  : in Sem.Typ_Type_Bound);
      --# global in     Dictionary.Dict;
      --#        in out State;
      --# derives State from *,
      --#                    Case_Flags,
      --#                    Complete_ADT,
      --#                    Lower_Bound,
      --#                    Sym,
      --#                    Upper_Bound &
      --#         null  from Dictionary.Dict;
      --# pre Stack_Is_Valid (State) and
      --#   (Complete_ADT.ActualUpperBound - Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#   (Dictionary.Is_Null_Symbol (Sym) or Dictionary.IsTypeMark (Sym, Dictionary.Dict));
      --# post Stack_Is_Valid (State);

      procedure Pop
        (Case_Flags   : out Sem.Typ_Case_Flags;
         Complete_ADT : out CompleteCheck.T;
         Sym          : out Dictionary.Symbol;
         Lower_Bound  : out Sem.Typ_Type_Bound;
         Upper_Bound  : out Sem.Typ_Type_Bound);
      --# global in     Dictionary.Dict;
      --#        in out State;
      --# derives Case_Flags,
      --#         Complete_ADT,
      --#         Lower_Bound,
      --#         State,
      --#         Sym,
      --#         Upper_Bound  from State &
      --#         null         from Dictionary.Dict;
      --# pre Stack_Is_Valid (State);
      --# post Stack_Is_Valid (State) and
      --#   (Complete_ADT.ActualUpperBound - Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#   (Dictionary.Is_Null_Symbol (Sym) or Dictionary.IsTypeMark (Sym, Dictionary.Dict));

   end Case_Stack;

   -----------------------------------------------------------------
   --  VariableUpdateHistory
   --
   --  Description:
   --    An object of the ADT, VariableUpdateHistory.History_T, is used to
   --    maintain a list of variables (represented by natural numbers) and
   --    each variable has a single associated STree.SyntaxNode
   --    The node is used to record the last occurrence of an update
   --    of each variable as the syntax tree is traversed.
   --    To use an object of History_T it must fist be
   --    created using Create_History and must disposed of when its no
   --    longer required (and certainly before leaving the scope in
   --    which the History_T object is declared) using Dispose_Of_History
   --    If the specified Heap.HeapRecord object becomes exhausted
   --    the Examiner will fail with a fatal error.
   ------------------------------------------------------------------
   --# inherit ExaminerConstants,
   --#         Heap,
   --#         Sem,
   --#         SP_Symbols,
   --#         Statistics,
   --#         STree,
   --#         SystemErrors;
   package VariableUpdateHistory is
      type History_T is private;

      -----------------------------------------------------------------
      --  Create_History
      --
      --  Description:
      --    Initialises an object of type History_T.  This subprogram
      --    must be called prior to using the object.
      --    The_Heap object must be an initialised Heap.HeapRecord Object.
      ------------------------------------------------------------------
      procedure Create_History (The_Heap : in out Heap.HeapRecord;
                                History  :    out History_T);
      --# global in out Statistics.TableUsage;
      --# derives History,
      --#         The_Heap              from The_Heap &
      --#         Statistics.TableUsage from *,
      --#                                    The_Heap;

      -----------------------------------------------------------------
      --  Dispose_Of_History
      --
      --  Description:
      --    Disposes of an object of type History_T.  This subprogram
      --    must be called when object is no longer required and
      --    certainly before leaving the scope in which the History_T
      --    object is declared.  The_Heap object must be the same object as
      --    was used in the call to Create_History for the History_T object.
      ------------------------------------------------------------------
      procedure Dispose_Of_History (The_Heap : in out Heap.HeapRecord;
                                    History  : in     History_T);
      --# derives The_Heap from *,
      --#                       History;

      -----------------------------------------------------------------
      --  Add_Update
      --
      --  Description:
      --    Adds a variable - node pair to the History_T object (History).
      --    If the Variable is not present in History, it is added to
      --    History along with its associated node (Node).
      --    Otherwise, if the Variable is present in the History, the
      --    node associated with the Variable is updated to the value
      --    of the given Node.
      --    The_Heap must be the same object as used in the preceding
      --    call to Create_History.
      ------------------------------------------------------------------
      procedure Add_Update
        (The_Heap : in out Heap.HeapRecord;
         History  : in out History_T;
         Variable : in     Natural;
         Node     : in     STree.SyntaxNode);
      --# global in     STree.Table;
      --#        in out Statistics.TableUsage;
      --# derives History,
      --#         The_Heap              from History,
      --#                                    Node,
      --#                                    The_Heap,
      --#                                    Variable &
      --#         Statistics.TableUsage from *,
      --#                                    History,
      --#                                    The_Heap,
      --#                                    Variable &
      --#         null                  from STree.Table;
      --# pre Sem.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
      --#   Sem.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.procedure_call_statement;

      -----------------------------------------------------------------
      --  Get_Last_Update
      --
      --  Description:
      --    Obtains the value of the node currently associated with the
      --    given variable in the History.  If the given Variable does
      --    not exist in the History a STree.NullNode will be
      --    returned.
      --    The_Heap must be the same object as used in the preceding
      --    call to Create_History.
      ------------------------------------------------------------------
      procedure Get_Last_Update
        (The_Heap : in     Heap.HeapRecord;
         History  : in     History_T;
         Variable : in     Natural;
         Node     :    out STree.SyntaxNode);
      --# global in STree.Table;
      --# derives Node from History,
      --#                   The_Heap,
      --#                   Variable &
      --#         null from STree.Table;
      --# post Sem.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
      --#   Sem.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.procedure_call_statement or
      --#   Node = STree.NullNode;

   private
      type History_T is range 0 .. Heap.Atom'Last;
   end VariableUpdateHistory;

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

   L_Scope                    : Dictionary.Scopes;
   Next_Node, Last_Node       : STree.SyntaxNode;
   Node_Type                  : SP_Symbols.SP_Symbol;
   Pure_Protected_Export_List : VariableUpdateHistory.History_T;

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

   package body Case_Stack
   --# own State is S,
   --#              Top_Ptr;
   is
      type Stack_Record is record
         Case_Flags   : Sem.Typ_Case_Flags;
         Complete_ADT : CompleteCheck.T;
         Sym          : Dictionary.Symbol;
         Upper_Bound  : Sem.Typ_Type_Bound;
         Lower_Bound  : Sem.Typ_Type_Bound;
      end record;

      Null_Record : constant Stack_Record :=
        Stack_Record'
        (Case_Flags   => Sem.Null_Case_Flags,
         Complete_ADT => CompleteCheck.NullT,
         Sym          => Dictionary.NullSymbol,
         Upper_Bound  => Sem.Unknown_Type_Bound,
         Lower_Bound  => Sem.Unknown_Type_Bound);

      subtype Index_Range is Integer range 1 .. ExaminerConstants.WalkStmtStackMax;
      type Stack_Array is array (Index_Range) of Stack_Record;
      subtype Top_Range is Integer range 0 .. ExaminerConstants.WalkStmtStackMax;

      S       : Stack_Array;
      Top_Ptr : Top_Range;

      procedure Init
      --# global in     Dictionary.Dict;
      --#           out S;
      --#           out Top_Ptr;
      --# derives S,
      --#         Top_Ptr from  &
      --#         null    from Dictionary.Dict;
      --# post (for all I in Index_Range range Index_Range'First .. Top_Ptr =>
      --#         ((S(I).Complete_ADT.ActualUpperBound - S(I).Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#            (Dictionary.Is_Null_Symbol (S(I).Sym) or Dictionary.IsTypeMark (S(I).Sym, Dictionary.Dict))));
      is
      begin
         Top_Ptr := 0;

         -- We allow a partial initialization of S here, mainly
         -- to avoid massive usage of stack, which is incompatible
         -- with the default stack limit on OS X. It's also much
         -- faster.

         --# accept Flow, 23, S, "Partial initialization here OK" &
         --#        Flow, 30, Dictionary.Dict, "Variable not referenced nor exported OK" &
         --#        Flow, 602, S, S, "Partial initialization here OK";
         S (Index_Range'First) := Null_Record;
      end Init;

      procedure Push
        (Case_Flags   : in Sem.Typ_Case_Flags;
         Complete_ADT : in CompleteCheck.T;
         Sym          : in Dictionary.Symbol;
         Lower_Bound  : in Sem.Typ_Type_Bound;
         Upper_Bound  : in Sem.Typ_Type_Bound)
      --# global in     Dictionary.Dict;
      --#        in out S;
      --#        in out Top_Ptr;
      --# derives S       from *,
      --#                      Case_Flags,
      --#                      Complete_ADT,
      --#                      Lower_Bound,
      --#                      Sym,
      --#                      Top_Ptr,
      --#                      Upper_Bound &
      --#         Top_Ptr from * &
      --#         null    from Dictionary.Dict;
      --# pre (for all I in Index_Range range Index_Range'First .. Top_Ptr =>
      --#        ((S(I).Complete_ADT.ActualUpperBound - S(I).Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#           (Dictionary.Is_Null_Symbol (S(I).Sym) or Dictionary.IsTypeMark (S(I).Sym, Dictionary.Dict)))) and
      --#   (Complete_ADT.ActualUpperBound - Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#   (Dictionary.Is_Null_Symbol (Sym) or Dictionary.IsTypeMark (Sym, Dictionary.Dict));
      --# post (for all I in Index_Range range Index_Range'First .. Top_Ptr =>
      --#         ((S(I).Complete_ADT.ActualUpperBound - S(I).Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#            (Dictionary.Is_Null_Symbol (S(I).Sym) or Dictionary.IsTypeMark (S(I).Sym, Dictionary.Dict))));
      is
      begin
         if Top_Ptr = ExaminerConstants.WalkStmtStackMax then
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Case_Stack_Overflow,
                                      Msg     => "in WalkStatements.Case_Stack.Push");
         end if;

         --# check Top_Ptr < ExaminerConstants.WalkStmtStackMax;

         Top_Ptr     := Top_Ptr + 1;
         S (Top_Ptr) :=
           Stack_Record'
           (Case_Flags   => Case_Flags,
            Complete_ADT => Complete_ADT,
            Sym          => Sym,
            Lower_Bound  => Lower_Bound,
            Upper_Bound  => Upper_Bound);
         --# accept Flow, 30, Dictionary.Dict, "Variable not referenced nor exported OK";
      end Push;

      procedure Pop
        (Case_Flags   : out Sem.Typ_Case_Flags;
         Complete_ADT : out CompleteCheck.T;
         Sym          : out Dictionary.Symbol;
         Lower_Bound  : out Sem.Typ_Type_Bound;
         Upper_Bound  : out Sem.Typ_Type_Bound)
      --# global in     Dictionary.Dict;
      --#        in     S;
      --#        in out Top_Ptr;
      --# derives Case_Flags,
      --#         Complete_ADT,
      --#         Lower_Bound,
      --#         Sym,
      --#         Upper_Bound  from S,
      --#                           Top_Ptr &
      --#         Top_Ptr      from * &
      --#         null         from Dictionary.Dict;
      --# pre (for all I in Index_Range range Index_Range'First .. Top_Ptr =>
      --#        ((S(I).Complete_ADT.ActualUpperBound - S(I).Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#           (Dictionary.Is_Null_Symbol (S(I).Sym) or Dictionary.IsTypeMark (S(I).Sym, Dictionary.Dict))));
      --# post (for all I in Index_Range range Index_Range'First .. Top_Ptr =>
      --#         ((S(I).Complete_ADT.ActualUpperBound - S(I).Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#            (Dictionary.Is_Null_Symbol (S(I).Sym) or Dictionary.IsTypeMark (S(I).Sym, Dictionary.Dict)))) and
      --#   (Complete_ADT.ActualUpperBound - Complete_ADT.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#   (Dictionary.Is_Null_Symbol (Sym) or Dictionary.IsTypeMark (Sym, Dictionary.Dict));
      is
      begin
         if Top_Ptr = 0 then
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Case_Stack_Underflow,
                                      Msg     => "in WalkStatements.Case_Stack.Pop");
         end if;

         --# check Top_Ptr > 0;

         Case_Flags   := S (Top_Ptr).Case_Flags;
         Complete_ADT := S (Top_Ptr).Complete_ADT;
         Sym          := S (Top_Ptr).Sym;
         Lower_Bound  := S (Top_Ptr).Lower_Bound;
         Upper_Bound  := S (Top_Ptr).Upper_Bound;
         Top_Ptr      := Top_Ptr - 1;
         --# accept Flow, 30, Dictionary.Dict, "Variable not referenced nor exported OK";
      end Pop;

   end Case_Stack;

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

   package body VariableUpdateHistory is separate;

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

   function Is_Last_In_Sequence (Node : STree.SyntaxNode) return Boolean
   --# global in STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.exit_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.return_statement;
   is
      Local_Node : STree.SyntaxNode;
      Result     : Boolean;

      function No_Node_Or_Only_Permitted_Nodes_Present (Seq_Node : STree.SyntaxNode) return Boolean
      --# global in STree.Table;
      --# pre Syntax_Node_Type (Seq_Node, STree.Table) = SP_Symbols.sequence_of_statements;
      is
         Result            : Boolean;
         Seq_Node_To_Check : STree.SyntaxNode;

         function Permitted_Statement (Seq_Node : STree.SyntaxNode) return Boolean
         --# global in STree.Table;
         --# pre Syntax_Node_Type (Seq_Node, STree.Table) = SP_Symbols.sequence_of_statements;
         is
         begin
            -- First implementation of this function only allows justification_statements.
            -- It could be extended to allow pragmas and proof statements if desired.
            return Syntax_Node_Type
              (Node => Child_Node                           -- simple, compound, justification, proof statement or apragma
                 (Next_Sibling (Current_Node => Seq_Node))) =      -- statement
              SP_Symbols.justification_statement;
         end Permitted_Statement;

      begin -- No_Node_Or_Only_Permitted_Nodes_Present
         Seq_Node_To_Check := Seq_Node;
         loop
            --# assert Syntax_Node_Type (Seq_Node_To_Check, STree.Table) = SP_Symbols.sequence_of_statements;

            -- exit when we get to the top of the sequence of statements and there are
            -- no more statements to check; this happens immediately on first pass through
            -- loop if there no statements of any kind after the one we are checking on entry
            -- to Is_Last_In_Sequence
            if Syntax_Node_Type (Node => Parent_Node (Current_Node => Seq_Node_To_Check)) /=
              SP_Symbols.sequence_of_statements then
               -- it must be subprogram_implementation or something else but there definitely no
               -- more statements
               Result := True;
               exit;
            end if;

            -- failure case, a non-permitted statement
            if not Permitted_Statement (Seq_Node => Seq_Node_To_Check) then
               Result := False;
               exit;
            end if;

            -- move up chain of sequence_of_statements
            Seq_Node_To_Check := Parent_Node (Current_Node => Seq_Node_To_Check);
         end loop;
         return Result;
      end No_Node_Or_Only_Permitted_Nodes_Present;

   begin -- Is_Last_In_Sequence

      -- On entry, node is one of: exit_statement, loop_statement or return_statement.
      -- These nodes, under certain circumstances are required to be thelast executable
      -- statement in a sequence of statements.
      --
      -- Grammar:
      --
      -- e.g. subprogram_implementation
      --                 |
      --        sequence_of_statements --- (designator, hidden part etc.)
      --                 |
      --        sequence_of_statements --- statement (last one in seq)
      --                 |
      --        sequence_of_statements --- statement
      --                 |
      --             statement  (first one in seq)
      --

      Local_Node := Parent_Node (Current_Node => Node);
      -- ASSUME Local_Node = simple_statement OR compound_statement
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.simple_statement
           or else Syntax_Node_Type (Node => Local_Node) = SP_Symbols.compound_statement,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = simple_statement OR compound_statement in Is_Last_In_Sequence");

      Local_Node := Parent_Node (Current_Node => Local_Node);
      -- ASSUME Local_Node = statement
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.statement,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = statement in Is_Last_In_Sequence");

      Local_Node := Parent_Node (Current_Node => Local_Node);
      -- ASSUME Local_Node = sequence_of_statements
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.sequence_of_statements,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = sequence_of_statements in Is_Last_In_Sequence");

      -- If the Seq we have reached has no Next_Sibling then there are no statements of any kind
      -- after the node we are checking and which was passed in a parameter Node.
      -- If there is a Next_Sibling we need to check that the associated statements are
      -- permitted ones, i.e. they are not unreachable executable statements.
      --
      -- For now, we only do the permitted node check for the loop case; this is where we have a customer report
      -- and the other two cases have separate problems: allowing something after exit confuses the flow analyser
      -- and there is a separate redundant check in wf_subprogram_body that still traps return not being last
      -- statement even if we allow it here

      if Syntax_Node_Type (Node => Node) = SP_Symbols.loop_statement then
         -- Node is what we entered with allow "permitted statements" after loop
         Result := No_Node_Or_Only_Permitted_Nodes_Present (Seq_Node => Local_Node);
      else
         -- don't allow statements after exit or return
         Result := Syntax_Node_Type (Node => Parent_Node (Current_Node => Local_Node)) /= SP_Symbols.sequence_of_statements;
      end if;

      return Result;
   end Is_Last_In_Sequence;

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

   function Parent_Of_Sequence (Node : STree.SyntaxNode) return STree.SyntaxNode
   --# global in STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.exit_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.if_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.return_statement;
   --# return Return_Node => (Return_Node /= STree.NullNode and
   --#                          Syntax_Node_Type (Return_Node, STree.Table) /= SP_Symbols.sequence_of_statements);
   is
      Local_Node : STree.SyntaxNode;
   begin
      Local_Node := Parent_Node (Current_Node => Node);
      -- ASSUME Local_Node = simple_statement OR compound_statement
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.simple_statement
           or else Syntax_Node_Type (Node => Local_Node) = SP_Symbols.compound_statement,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = simple_statement OR compound_statement in Parent_Of_Sequence");

      Local_Node := Parent_Node (Current_Node => Local_Node);
      -- ASSUME Local_Node = statement
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.statement,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = statement in Parent_Of_Sequence");

      Local_Node := Parent_Node (Current_Node => Local_Node);
      -- ASSUME Local_Node = sequence_of_statements
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Local_Node) = SP_Symbols.sequence_of_statements,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node = sequence_of_statements in Parent_Of_Sequence");

      while Syntax_Node_Type (Node => Local_Node) = SP_Symbols.sequence_of_statements loop
         --# assert Syntax_Node_Type (Local_Node, STree.Table) = SP_Symbols.sequence_of_statements;
         Local_Node := Parent_Node (Current_Node => Local_Node);
      end loop;
      -- ASSUME Local_Node /= NULL
      SystemErrors.RT_Assert
        (C       => Local_Node /= STree.NullNode,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Local_Node /= NULL in Parent_Of_Sequence");
      return Local_Node;
   end Parent_Of_Sequence;

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

   -- patch a relation so that implicit side-effects are included.  For
   -- stream exports this means adding a self-reference to the import list
   -- for stream imports it means adding a complete new relation deriving
   -- it from itself
   procedure Add_Stream_Effects
     (Table    : in out RefList.HashTable;
      The_Heap : in out Heap.HeapRecord;
      Node     : in     STree.SyntaxNode;
      Export   : in     Dictionary.Symbol;
      Imports  : in     SeqAlgebra.Seq)
   --# global in     Dictionary.Dict;
   --#        in     STree.Table;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         The_Heap              from *,
   --#                                    Dictionary.Dict,
   --#                                    Export,
   --#                                    Imports,
   --#                                    Node,
   --#                                    Table,
   --#                                    The_Heap &
   --#         Table                 from *,
   --#                                    Dictionary.Dict,
   --#                                    Imports,
   --#                                    Node,
   --#                                    The_Heap &
   --#         null                  from STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.delay_statement;
   is
      Current_Member : SeqAlgebra.MemberOfSeq;
      Current_Import : Dictionary.Symbol;

      -- add relation of the form Import <- {Import} to Node
      procedure Add_Self_Dependency
        (Table    : in out RefList.HashTable;
         The_Heap : in out Heap.HeapRecord;
         Node     : in     STree.SyntaxNode;
         Import   : in     Dictionary.Symbol)
      --# global in     STree.Table;
      --#        in out Statistics.TableUsage;
      --# derives Statistics.TableUsage,
      --#         Table,
      --#         The_Heap              from *,
      --#                                    Import,
      --#                                    Node,
      --#                                    Table,
      --#                                    The_Heap &
      --#         null                  from STree.Table;
      --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
      --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.delay_statement;
      is
         Import_Seq : SeqAlgebra.Seq;
      begin
         SeqAlgebra.CreateSeq (The_Heap, Import_Seq);
         SeqAlgebra.AddMember (The_Heap, Import_Seq, Natural (Dictionary.SymbolRef (Import)));
         RefList.AddRelation (Table, The_Heap, Node, Import, Import_Seq);
         --# accept F, 30, STree.Table, "Used for precondition only";
      end Add_Self_Dependency;

   begin -- Add_Stream_Effects

      -- traverse Import list adding self references for any IN streams found
      Current_Member := SeqAlgebra.FirstMember (The_Heap, Imports);
      while not SeqAlgebra.IsNullMember (Current_Member) loop
         --# assert Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
         --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.delay_statement;
         Current_Import :=
           Dictionary.ConvertSymbolRef
           (ExaminerConstants.RefType (SeqAlgebra.Value_Of_Member (The_Heap => The_Heap,
                                                                   M        => Current_Member)));

         -- if the Current_Import is a stream then add a new identity relation
         if Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Current_Import)) /=
           Dictionary.DefaultMode then
            -- we know it is mode in because wffs prevent reading of mode outs
            Add_Self_Dependency (Table    => Table,
                                 The_Heap => The_Heap,
                                 Node     => Node,
                                 Import   => Current_Import);
         end if;

         Current_Member := SeqAlgebra.NextMember (The_Heap, Current_Member);
      end loop;

      -- finally, see if the Export is an OutStream and if so add it to the Import list
      if Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Export)) /= Dictionary.DefaultMode then
         -- we know it is mode out because wffs prevent writing of mode ins
         SeqAlgebra.AddMember (The_Heap, Imports, Natural (Dictionary.SymbolRef (Export)));
      end if;
   end Add_Stream_Effects;

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

   procedure Wf_Assign
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         Table,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Wf_Condition
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         Table,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.condition;
   --# post STree.Table = STree.Table~;
      is separate;

   --------------------------------------------------------------------
   -- This procedure prepares the flow analyser to deal with ininite loops.  If the loop
   -- has some means of exiting (iteration scheme or exit statements) then nothing is
   -- done.  Otherwise an empty referenced variable list is associated with the
   -- end_of_loop node to act as a stable exit expression in the manner of "exit when false".
   -- A Boolean type symbol is planted in the syntax tree at this point as a signal to the
   -- flow analyser that it should model the default exit as a way of providing a syntactic
   -- exit from the loop
   procedure Setup_Default_Loop_Exit
     (Node     : in     STree.SyntaxNode;
      Scope    : in     Dictionary.Scopes;
      Table    : in out RefList.HashTable;
      The_Heap : in out Heap.HeapRecord)
   --# global in     Dictionary.Dict;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --# derives Statistics.TableUsage,
   --#         Table,
   --#         The_Heap              from *,
   --#                                    Dictionary.Dict,
   --#                                    Node,
   --#                                    Scope,
   --#                                    Table,
   --#                                    The_Heap &
   --#         STree.Table           from *,
   --#                                    Dictionary.Dict,
   --#                                    Node,
   --#                                    Scope;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.end_of_loop;
   --# post STree.Table = STree.Table~;
   is
      Ref_Var : SeqAlgebra.Seq;
   begin
      -- and end_of_loop node is placed in the syntax tree after the sequence of statements
      -- it controls.  If the loop has no exits we attach and empty referenced variable
      -- list to this node so that that the flow analyser can pretend that there is an
      -- "exit when false" at this point.  We plant type Boolean in the syntax tree to signal
      --to the flow analyser that this default exit point is active.  If the loop has an
      -- iteration scheme or already has exits then we do nothing here.
      if not Dictionary.GetLoopHasExits (Dictionary.GetRegion (Scope)) then
         SeqAlgebra.CreateSeq (The_Heap, Ref_Var);
         RefList.AddRelation (Table, The_Heap, Node, Dictionary.NullSymbol, Ref_Var);
         STree.Add_Node_Symbol (Node => Node,
                                Sym  => Dictionary.GetPredefinedBooleanType);
      end if;
   end Setup_Default_Loop_Exit;

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

   procedure Wf_Return
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# 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,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table,
   --#         Table                      from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.return_statement;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Wf_Case
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Case_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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Case_Stack.State,
   --#         Table                      from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.case_statement and
   --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
   --# post STree.Table = STree.Table~ and
   --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
      is separate;

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

   procedure Wf_Case_Choice
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Case_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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Case_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from Case_Stack.State,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from Case_Stack.State,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         Table,
   --#         TheHeap                    from *,
   --#                                         Case_Stack.State,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.case_choice and
   --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
   --# post STree.Table = STree.Table~ and
   --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
      is separate;

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

   procedure Wf_Exit
     (Node           : in     STree.SyntaxNode;
      The_Loop       : in     Dictionary.Symbol;
      Condition_Node :    out STree.SyntaxNode)
   --# 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 Condition_Node             from Node,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Loop;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.exit_statement;
   --# post Syntax_Node_Type (Condition_Node, STree.Table) = SP_Symbols.condition or
   --#   Condition_Node = STree.NullNode;
      is separate;

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

   procedure Wf_Delay_Until
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         Table,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.delay_statement;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Down_Loop (Node  : in     STree.SyntaxNode;
                        Scope : in out Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives Dictionary.Dict            from *,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table &
   --#         Scope                      from ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Node,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_statement;
      is separate;

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

   procedure Up_Loop (Node  : in     STree.SyntaxNode;
                      Scope : in out Dictionary.Scopes)
   --# 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,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table &
   --#         Scope                      from *,
   --#                                         Dictionary.Dict;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_statement;
      is separate;

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

   procedure Wf_Loop_Param
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# 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,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table,
   --#         Table                      from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_parameter_specification;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Wf_Proc_Call
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Table          : in out RefList.HashTable;
      Component_Data : in out ComponentManager.ComponentData)
   --# 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,
   --#         LexTokenManager.State,
   --#         Table                      from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         Statistics.TableUsage,
   --#         STree.Table,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap &
   --#         SLI.State                  from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.procedure_call_statement;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Up_Case (Node : in STree.SyntaxNode)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out Case_Stack.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives Case_Stack.State           from * &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Case_Stack.State,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.case_statement and
   --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
   --# post Case_Stack.Stack_Is_Valid (Case_Stack.State);
      is separate;

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

   procedure Wf_Proof_Statement_Or_Loop_Invariant
     (Node           : in     STree.SyntaxNode;
      Scope          : in     Dictionary.Scopes;
      Component_Data : in out ComponentManager.ComponentData)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        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;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table,
   --#         TheHeap                    from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         TheHeap &
   --#         Statistics.TableUsage      from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.proof_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.loop_invariant;
   --# post STree.Table = STree.Table~;
   is
      Child_Child_Node : STree.SyntaxNode;
      Unused           : Boolean;
      pragma Unreferenced (Unused);
   begin
      -- Proof_Statement and Loop_Invariant have the same shape in the
      -- grammar, so this procedure WFFs both.
      Child_Child_Node := Child_Node (Current_Node => Child_Node (Current_Node => Node));
      -- ASSUME Child_Child_Node = predicate
      SystemErrors.RT_Assert
        (C       => Syntax_Node_Type (Node => Child_Child_Node) = SP_Symbols.predicate,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Child_Child_Node = predicate in Wf_Proof_Statement_Or_Loop_Invariant");

      if Syntax_Node_Type (Node) = SP_Symbols.proof_statement and then
        Syntax_Node_Type (Child_Node (Node)) = SP_Symbols.assume_statement then

         --  Assumptions are magically assumed to be true, hence they
         --  must be justified. We raise a warning here to prompt the
         --  user to do so.
         ErrorHandler.Semantic_Warning
           (Err_Num  => 444,
            Position => Node_Position (Node),
            Id_Str   => LexTokenManager.Null_String);

      end if;

      --# accept Flow, 10, Unused, "Expected ineffective assignment to Unused";
      Wf_Predicate
        (Node           => Child_Child_Node,
         Scope          => Scope,
         Context        => Postcondition,
         Component_Data => Component_Data,
         The_Heap       => TheHeap,
         Errors_Found   => Unused);
      --# end accept;
      --# accept Flow, 33, Unused, "Expected to be neither referenced nor exported";
   end Wf_Proof_Statement_Or_Loop_Invariant;

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

   procedure Init_Component_Data
     (Scope          : in     Dictionary.Scopes;
      Component_Data :    out ComponentManager.ComponentData;
      The_Heap       : in out Heap.HeapRecord)
   --# global in     Dictionary.Dict;
   --#        in out Statistics.TableUsage;
   --# derives Component_Data,
   --#         The_Heap              from Dictionary.Dict,
   --#                                    Scope,
   --#                                    The_Heap &
   --#         Statistics.TableUsage from *,
   --#                                    Dictionary.Dict,
   --#                                    Scope,
   --#                                    The_Heap;
   is
      Subprog_Sym, Own_Var_Sym, Constituent_Sym : Dictionary.Symbol;
      It, Constituent_It                        : Dictionary.Iterator;

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

      procedure Maybe_Add
        (Sym            : in     Dictionary.Symbol;
         Component_Data : in out ComponentManager.ComponentData;
         The_Heap       : in out Heap.HeapRecord)
      --# global in     Dictionary.Dict;
      --#        in out Statistics.TableUsage;
      --# derives Component_Data,
      --#         Statistics.TableUsage,
      --#         The_Heap              from *,
      --#                                    Component_Data,
      --#                                    Dictionary.Dict,
      --#                                    Sym,
      --#                                    The_Heap;
      is
      begin
         if Dictionary.TypeIsRecord (Dictionary.GetType (Sym)) then
            ComponentManager.AddRoot (Component_Data, The_Heap, Sym);
         end if;
      end Maybe_Add;

   begin -- Init_Component_Data

      -- ensure we start with a completely fresh copy of Component_Data
      ComponentManager.Initialise (Component_Data);

      -- add roots of all record types as specified in S.P0468.53.9 para 6.1
      Subprog_Sym := Dictionary.GetRegion (Scope);
      if Dictionary.Is_Subprogram (Subprog_Sym)
        or else (Dictionary.IsType (Subprog_Sym) and then Dictionary.TypeIsTask (Subprog_Sym)) then
         -- initialize using parameters, globals and local variables
         -- first do local variables
         It := Dictionary.First_Local_Variable (Subprogram => Subprog_Sym);
         while not Dictionary.IsNullIterator (It) loop
            Maybe_Add (Sym            => Dictionary.CurrentSymbol (It),
                       Component_Data => Component_Data,
                       The_Heap       => The_Heap);
            It := Dictionary.NextSymbol (It);
         end loop;

         -- then parameters
         It := Dictionary.FirstGlobalVariable (Dictionary.GetAbstraction (Subprog_Sym, Scope), Subprog_Sym);
         while not Dictionary.IsNullIterator (It) loop
            Maybe_Add (Sym            => Dictionary.CurrentSymbol (It),
                       Component_Data => Component_Data,
                       The_Heap       => The_Heap);
            It := Dictionary.NextSymbol (It);
         end loop;

         -- then globals
         It := Dictionary.FirstSubprogramParameter (Subprog_Sym);
         while not Dictionary.IsNullIterator (It) loop
            Maybe_Add (Sym            => Dictionary.CurrentSymbol (It),
                       Component_Data => Component_Data,
                       The_Heap       => The_Heap);
            It := Dictionary.NextSymbol (It);
         end loop;

      else
         -- package init part, initialize using own variable list,
         -- looking at constituents which are not own variables of
         -- embedded packages where they are found.
         It := Dictionary.FirstOwnVariable (Subprog_Sym);
         while not Dictionary.IsNullIterator (It) loop
            Own_Var_Sym := Dictionary.CurrentSymbol (It);
            if Dictionary.IsConcreteOwnVariable (Own_Var_Sym) then
               Maybe_Add (Sym            => Own_Var_Sym,
                          Component_Data => Component_Data,
                          The_Heap       => The_Heap);
            else -- must be abstract
               Constituent_It := Dictionary.FirstConstituent (Own_Var_Sym);
               while not Dictionary.IsNullIterator (Constituent_It) loop
                  Constituent_Sym := Dictionary.CurrentSymbol (Constituent_It);
                  if not Dictionary.IsOwnVariable (Constituent_Sym) then
                     Maybe_Add (Sym            => Constituent_Sym,
                                Component_Data => Component_Data,
                                The_Heap       => The_Heap);
                  end if;
                  Constituent_It := Dictionary.NextSymbol (Constituent_It);
               end loop;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
      end if;
   end Init_Component_Data;

   -----------------------------------------------------------------
   --  CheckForMutuallyExclusiveBranches
   --
   --  Description:
   --    Given two STree.SyntaxNodes, Given_Node and
   --    Preceding_Node, this subprogram checks that the Given_Node
   --    and the Preceding_Node are on mutually exclusive branches.
   --    For checking the updates of pure exported protected variables
   --    the Preceding_Node is the last update node as the syntax tree is
   --    traversed and the Given_Node is the update node just encountered.
   --    If the subprogram is repeatedly applied for each update node
   --    encountered (with its previous node) then this is sufficient
   --    to ensure that all updates are on mutually exclusive paths
   --    provided that Are_Mutually_Exclusive always has a return value
   --    of True.  See S.P0468.53.49.
   ------------------------------------------------------------------
   procedure CheckForMutuallyExclusiveBranches
     (Given_Node, Preceding_Node : in     STree.SyntaxNode;
      The_Heap                   : in out Heap.HeapRecord;
      Are_Mutually_Exclusive     :    out Boolean)
   --# global in     STree.Table;
   --#        in out Statistics.TableUsage;
   --# derives Are_Mutually_Exclusive,
   --#         The_Heap               from Given_Node,
   --#                                     Preceding_Node,
   --#                                     STree.Table,
   --#                                     The_Heap &
   --#         Statistics.TableUsage  from *,
   --#                                     Given_Node,
   --#                                     Preceding_Node,
   --#                                     STree.Table,
   --#                                     The_Heap;
   --# pre (Syntax_Node_Type (Given_Node, STree.Table) = SP_Symbols.assignment_statement or
   --#        Syntax_Node_Type (Given_Node, STree.Table) = SP_Symbols.procedure_call_statement) and
   --#   (Syntax_Node_Type (Preceding_Node, STree.Table) = SP_Symbols.assignment_statement or
   --#      Syntax_Node_Type (Preceding_Node, STree.Table) = SP_Symbols.procedure_call_statement);
      is separate;

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

   procedure Check_Pure_Protected_Exports_Updated_Once_Only
     (Node                       : in     STree.SyntaxNode;
      Scope                      : in     Dictionary.Scopes;
      Pure_Protected_Export_List : in out VariableUpdateHistory.History_T)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Pure_Protected_Export_List,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap &
   --#         Pure_Protected_Export_List,
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Node,
   --#                                         Pure_Protected_Export_List,
   --#                                         STree.Table,
   --#                                         Table,
   --#                                         TheHeap;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.assignment_statement or
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.procedure_call_statement;
   is
      The_Export                     : Natural;
      The_Export_Atom                : Heap.Atom;
      The_Export_Sym                 : Dictionary.Symbol;
      The_Imports                    : SeqAlgebra.Seq;
      Previous_Node                  : STree.SyntaxNode;
      On_Mutually_Exclusive_Branches : Boolean;
   begin
      -- does this node has exports
      if RefList.NodeHasExportList (Table   => Table,
                                    TheHeap => TheHeap,
                                    Node    => Node) then
         -- Get the first export for this node.
         RefList.FirstExport (Table     => Table,
                              TheHeap   => TheHeap,
                              Node      => Node,
                              TheExport => The_Export_Atom);
         while not Heap.IsNullPointer (The_Export_Atom) loop
            -- Get the symbol for this export.
            The_Export_Sym :=
              Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (Heap.AValue (TheHeap => TheHeap,
                                                                                   A       => The_Export_Atom)));
            -- Is it protected?
            if Dictionary.IsOwnVariable (The_Export_Sym)
              and then -- do not report error if the thing being updates is a suspension object
              not Dictionary.IsPredefinedSuspensionObjectType (Dictionary.GetType (The_Export_Sym))
              and then Dictionary.GetOwnVariableProtected (The_Export_Sym)
              and then
              -- does it have a wellformed set of imports?
              -- Note: the imports list will be empty if there are none.
              RefList.ExportHasDependencies (TheExport => The_Export_Atom,
                                             TheHeap   => TheHeap) then
               -- Get the imports for this export.
               The_Imports := RefList.DependencyList (TheHeap   => TheHeap,
                                                      TheExport => The_Export_Atom);
               The_Export  := Heap.AValue (TheHeap => TheHeap,
                                           A       => The_Export_Atom);
               -- Is it a pure export? (pure exports don't depend on themselves)
               if not SeqAlgebra.IsMember (TheHeap    => TheHeap,
                                           S          => The_Imports,
                                           GivenValue => The_Export) then
                  -- It's a pure export.
                  -- Has this export already been updated?
                  VariableUpdateHistory.Get_Last_Update
                    (The_Heap => TheHeap,
                     History  => Pure_Protected_Export_List,
                     Variable => The_Export,
                     Node     => Previous_Node);
                  -- ASSUME Previous_Node = assignment_statement OR procedure_call_statement OR NULL
                  if Previous_Node = STree.NullNode then
                     -- ASSUME Previous_Node = NULL
                     -- The export has not been previously encountered
                     -- Add the pure export to the update history
                     VariableUpdateHistory.Add_Update
                       (The_Heap => TheHeap,
                        History  => Pure_Protected_Export_List,
                        Variable => The_Export,
                        Node     => Node);
                  elsif Syntax_Node_Type (Node => Previous_Node) = SP_Symbols.assignment_statement
                    or else Syntax_Node_Type (Node => Previous_Node) = SP_Symbols.procedure_call_statement then
                     -- ASSUME Previous_Node = assignment_statement OR procedure_call_statement
                     -- The export has previously been updated, check
                     -- that the previous update was on a mutually
                     -- exlusive path
                     CheckForMutuallyExclusiveBranches
                       (Given_Node             => Node,
                        Preceding_Node         => Previous_Node,
                        The_Heap               => TheHeap,
                        Are_Mutually_Exclusive => On_Mutually_Exclusive_Branches);
                     if On_Mutually_Exclusive_Branches then
                        -- The update is valid, add the new pair to the export list
                        -- replacing the current pair involving The_Export.
                        VariableUpdateHistory.Add_Update
                          (The_Heap => TheHeap,
                           History  => Pure_Protected_Export_List,
                           Variable => The_Export,
                           Node     => Node);
                     else
                        -- semantic error.
                        ErrorHandler.Semantic_Error_Sym
                          (Err_Num   => 957,
                           Reference => ErrorHandler.No_Reference,
                           Position  => Node_Position (Node => Node),
                           Sym       => The_Export_Sym,
                           Scope     => Scope);
                     end if;
                  end if;
               end if;
            end if;
            The_Export_Atom := RefList.NextExport (TheHeap   => TheHeap,
                                                   TheExport => The_Export_Atom);
         end loop;
      end if;
   end Check_Pure_Protected_Exports_Updated_Once_Only;

begin -- WalkStatements
   Case_Stack.Init;
   Init_Component_Data (Scope          => Scope,
                        Component_Data => Component_Data,
                        The_Heap       => TheHeap);

   -- Create a VariablUpdateHistory to retain the immediately previous
   -- node at which the update of each pure export protected varible occurred.
   VariableUpdateHistory.Create_History (The_Heap => TheHeap,
                                         History  => Pure_Protected_Export_List);

   -- scope may change locally in loops but will always
   -- be back to original scope on exit from procedure
   L_Scope := Scope;

   Next_Node := Seq_Node;
   loop
      --# assert STree.Table = STree.Table~ and
      --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
      Last_Node := Next_Node;
      Node_Type := Syntax_Node_Type (Node => Last_Node);
      case Node_Type is
         when SP_Symbols.assignment_statement =>
            -- ASSUME Last_Node = assignment_statement
            Wf_Assign (Node           => Last_Node,
                       Scope          => L_Scope,
                       Table          => Table,
                       Component_Data => Component_Data);
            Check_Pure_Protected_Exports_Updated_Once_Only
              (Node                       => Last_Node,
               Scope                      => L_Scope,
               Pure_Protected_Export_List => Pure_Protected_Export_List);
            Next_Node := STree.NullNode;
         when SP_Symbols.condition =>
            -- ASSUME Last_Node = condition
            Wf_Condition (Node           => Last_Node,
                          Scope          => L_Scope,
                          Table          => Table,
                          Component_Data => Component_Data);
            Next_Node := STree.NullNode;
         when SP_Symbols.exit_statement =>
            -- ASSUME Last_Node = exit_statement
            Dictionary.MarkLoopHasExits (Dictionary.GetRegion (L_Scope));
            Wf_Exit (Node           => Last_Node,
                     The_Loop       => Dictionary.GetRegion (L_Scope),
                     Condition_Node => Next_Node);
         when SP_Symbols.end_of_loop =>
            -- ASSUME Last_Node = Last_Node
            Setup_Default_Loop_Exit (Node     => Last_Node,
                                     Scope    => L_Scope,
                                     Table    => Table,
                                     The_Heap => TheHeap);
            Next_Node := Child_Node (Last_Node);
         when SP_Symbols.case_statement =>
            -- ASSUME Last_Node = case_statement
            Wf_Case (Node           => Last_Node,
                     Scope          => L_Scope,
                     Table          => Table,
                     Component_Data => Component_Data);
            Next_Node := Child_Node (Last_Node);
         when SP_Symbols.case_choice =>
            -- ASSUME Last_Node = case_choice
            Wf_Case_Choice (Node           => Last_Node,
                            Scope          => L_Scope,
                            Table          => Table,
                            Component_Data => Component_Data);
            Next_Node := STree.NullNode;
         when SP_Symbols.return_statement =>
            -- ASSUME Last_Node = return_statement
            Wf_Return (Node           => Last_Node,
                       Scope          => L_Scope,
                       Table          => Table,
                       Component_Data => Component_Data);
            Next_Node := STree.NullNode;
         when SP_Symbols.loop_statement =>
            -- ASSUME Last_Node = loop_statement
            Down_Loop (Node  => Last_Node,
                       Scope => L_Scope);
            Next_Node := Child_Node (Last_Node);
         when SP_Symbols.loop_invariant =>
            -- ASSUME Last_Node = loop_invariant
            -- Loop invariant which preceeds the "loop" keyword is part of the
            -- loop iteration scheme, so doesn't appear as a statement, so we
            -- must WFF is here.
            Wf_Proof_Statement_Or_Loop_Invariant (Node           => Last_Node,
                                                  Scope          => L_Scope,
                                                  Component_Data => Component_Data);
            Next_Node := STree.NullNode;
         when SP_Symbols.loop_parameter_specification =>
            -- ASSUME Last_Node = loop_parameter_specification
            Wf_Loop_Param (Node           => Last_Node,
                           Scope          => L_Scope,
                           Table          => Table,
                           Component_Data => Component_Data);
            Next_Node := Child_Node (Last_Node);
         when SP_Symbols.apragma =>
            -- ASSUME Last_Node = apragma
            Wf_Pragma (Node  => Last_Node,
                       Scope => L_Scope);
            Next_Node := STree.NullNode;
         when SP_Symbols.procedure_call_statement =>
            -- ASSUME Last_Node = procedure_call_statement
            Wf_Proc_Call (Node           => Last_Node,
                          Scope          => L_Scope,
                          Table          => Table,
                          Component_Data => Component_Data);
            Check_Pure_Protected_Exports_Updated_Once_Only
              (Node                       => Last_Node,
               Scope                      => L_Scope,
               Pure_Protected_Export_List => Pure_Protected_Export_List);
            Next_Node := STree.NullNode;
         when SP_Symbols.proof_statement =>
            -- ASSUME Last_Node = proof_statement
            Wf_Proof_Statement_Or_Loop_Invariant (Node           => Last_Node,
                                                  Scope          => L_Scope,
                                                  Component_Data => Component_Data);
            Next_Node := STree.NullNode;
         when SP_Symbols.expression =>
            -- ASSUME Last_Node = expression
            Next_Node := STree.NullNode;
         when SP_Symbols.delay_statement =>
            -- ASSUME Last_Node = delay_statement
            --# accept Flow, 41, "Expected stable expression";
            if CommandLineData.Ravenscar_Selected then
               --# end accept;
               Wf_Delay_Until (Node           => Last_Node,
                               Scope          => L_Scope,
                               Table          => Table,
                               Component_Data => Component_Data);
            else -- illegal
               ErrorHandler.Semantic_Error
                 (Err_Num   => 850,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Last_Node),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
            Next_Node := STree.NullNode;
         when SP_Symbols.justification_statement =>
            -- ASSUME Last_Node = justification_statement
            Wf_Justification_Statement (Node           => Last_Node,
                                        Scope          => L_Scope,
                                        Component_Data => Component_Data,
                                        The_Heap       => TheHeap);
            Next_Node := STree.NullNode;
         when others =>
            if Node_Type in SP_Symbols.SP_Non_Terminal then
               Next_Node := Child_Node (Last_Node);
            else
               Next_Node := STree.NullNode;
            end if;
      end case;

      if Next_Node = STree.NullNode then
         loop
            --# assert STree.Table = STree.Table~ and
            --#   Case_Stack.Stack_Is_Valid (Case_Stack.State);
            Next_Node := Next_Sibling (Last_Node);
            exit when Next_Node /= STree.NullNode; -- new branch to right

            Next_Node := Parent_Node (Current_Node => Last_Node);
            Last_Node := Next_Node;
            case Syntax_Node_Type (Node => Last_Node) is
               when SP_Symbols.loop_statement =>
                  -- ASSUME Last_Node = loop_statement
                  Up_Loop (Node  => Last_Node,
                           Scope => L_Scope);
               when SP_Symbols.case_statement =>
                  -- ASSUME Last_Node = case_statement
                  Up_Case (Node => Last_Node);
               when others =>
                  null;
            end case;
            exit when Next_Node = Seq_Node;  -- got back to top
         end loop; -- up
      end if;
      exit when Next_Node = Seq_Node; -- met start point on way up
   end loop; -- down

   -- Dispose of the update history
   VariableUpdateHistory.Dispose_Of_History (The_Heap => TheHeap,
                                             History  => Pure_Protected_Export_List);
end WalkStatements;
