-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

with Debug;
with E_Strings;
with SPrint;

separate (Sem.Walk_Expression_P)
procedure Walk_Expression
  (Exp_Node                : in     STree.SyntaxNode;
   Scope                   : in     Dictionary.Scopes;
   Type_Context            : in     Dictionary.Symbol;
   Context_Requires_Static : in     Boolean;
   Ref_Var                 : in     SeqAlgebra.Seq;
   Result                  :    out Sem.Exp_Record;
   Component_Data          : in out ComponentManager.ComponentData;
   The_Heap                : in out Heap.HeapRecord)
is
   Next_Node, Last_Node, Local_Node : STree.SyntaxNode;
   Node_Type                        : SP_Symbols.SP_Symbol;
   L_Heap                           : Lists.List_Heap;
   Val                              : Maths.Value;
   E_Stack                          : Exp_Stack.Exp_Stack_Type;
   T_Stack                          : Type_Context_Stack.T_Stack_Type;
   Sym                              : Dictionary.Symbol;
   String_Value                     : LexTokenManager.Lex_String;

   --------------------------------------------------------------
   -- Procedures for debugging Expression syntax and tree walking
   -- These are hidden with "derives ;" so as not to pollute the
   -- annotations
   --------------------------------------------------------------

   procedure Dump_Syntax_Tree
   --# derives ;
   is
      --# hide Dump_Syntax_Tree;
   begin
      if CommandLineData.Content.Debug.Expressions then
         SPrint.Dump_Syntax_Tree (Exp_Node, 0);
      end if;
   end Dump_Syntax_Tree;

   procedure Dump_Down_Node
   --# derives ;
   is
      --# hide Dump_Down_Node;
   begin
      if CommandLineData.Content.Debug.Expressions then
         SPARK_IO.Put_Line
           (SPARK_IO.Standard_Output,
            "Walk_Expression DOWN encounters node" &
              ExaminerConstants.RefType'Image (STree.NodeToRef (Last_Node)) &
              ' ' &
              SP_Symbols.SP_Symbol'Image (STree.Syntax_Node_Type (Node => Last_Node)),
            0);
      end if;
   end Dump_Down_Node;

   procedure Dump_Up_Node
   --# derives ;
   is
      --# hide Dump_Up_Node;
   begin
      if CommandLineData.Content.Debug.Expressions then
         SPARK_IO.Put_Line
           (SPARK_IO.Standard_Output,
            "Walk_Expression UP   encounters node" &
              ExaminerConstants.RefType'Image (STree.NodeToRef (Last_Node)) &
              ' ' &
              SP_Symbols.SP_Symbol'Image (STree.Syntax_Node_Type (Node => Last_Node)),
            0);
      end if;
   end Dump_Up_Node;

   procedure Dump_Result
   --# derives ;
   is
      --# hide Dump_Result;
   begin
      if CommandLineData.Content.Debug.Expressions then
         if Result.Is_Constant then
            SPARK_IO.Put_String (SPARK_IO.Standard_Output, "Walk_Expression constant result is ", 0);
            E_Strings.Put_Line (File  => SPARK_IO.Standard_Output,
                                E_Str => Maths.ValueToString (Result.Value));
         else
            SPARK_IO.Put_Line (SPARK_IO.Standard_Output, "Walk_Expression result is not constant", 0);
         end if;
         SPARK_IO.Put_Line (SPARK_IO.Standard_Output, "Walk_Expression Result is: ", 0);
         Put_Exp_Record (Result);
      end if;
   end Dump_Result;

begin -- Walk_Expression
   Dump_Syntax_Tree;

   Exp_Stack.Init (Stack => E_Stack);
   Aggregate_Stack.Init;
   Lists.Init (L_Heap);
   Type_Context_Stack.Init (Stack => T_Stack);
   Type_Context_Stack.Push (X     => Type_Context,
                            Stack => T_Stack);

   Next_Node := Exp_Node;
   loop
      --# assert STree.Table = STree.Table~ and
      --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
      --#   Type_Context_Stack.Stack_Is_Valid (T_Stack);
      Last_Node := Next_Node;
      Node_Type := STree.Syntax_Node_Type (Node => Last_Node);

      Dump_Down_Node;

      case Node_Type is
         when SP_Symbols.character_literal =>
            -- ASSUME Last_Node = character_literal
            Exp_Stack.Push
              (X     => Sem.Exp_Record'(Type_Symbol             => Dictionary.GetPredefinedCharacterType,
                                        Other_Symbol            => Dictionary.NullSymbol,
                                        Stream_Symbol           => Dictionary.NullSymbol,
                                        Tagged_Parameter_Symbol => Dictionary.NullSymbol,
                                        Variable_Symbol         => Dictionary.NullSymbol,
                                        Param_Count             => 0,
                                        Param_List              => Lists.Null_List,
                                        Sort                    => Sem.Type_Result,
                                        Arg_List_Found          => False,
                                        Is_AVariable            => False,
                                        Is_An_Entire_Variable   => False,
                                        Errors_In_Expression    => False,
                                        Has_Operators           => False,
                                        Is_Constant             => True,
                                        Is_Static               => True,
                                        Is_ARange               => False,
                                        String_Value            => LexTokenManager.Null_String,
                                        Value                   => Get_Character_Literal (Node => Last_Node),
                                        Range_RHS               => Maths.NoValue),
               Stack => E_Stack);
            Next_Node := STree.NullNode;
         when SP_Symbols.string_literal =>
            -- ASSUME Last_Node = string_literal
            String_Value := STree.Node_Lex_String (Node => Last_Node);

            --# accept F, 41, "Stable expression here OK";
            if CommandLineData.Content.Debug.Expressions then
               Debug.Print_Lex_Str ("Walk_Expression pushing string literal with value: ", String_Value);
            end if;
            --# end accept;

            Exp_Stack.Push
              (X     => Sem.Exp_Record'(Type_Symbol             => Dictionary.GetPredefinedStringType,
                                        Other_Symbol            => Dictionary.NullSymbol,
                                        Stream_Symbol           => Dictionary.NullSymbol,
                                        Tagged_Parameter_Symbol => Dictionary.NullSymbol,
                                        Variable_Symbol         => Dictionary.NullSymbol,
                                        Param_Count             => 0,
                                        Param_List              => Lists.Null_List,
                                        Sort                    => Sem.Type_Result,
                                        Arg_List_Found          => False,
                                        Is_AVariable            => False,
                                        Is_An_Entire_Variable   => False,
                                        Errors_In_Expression    => False,
                                        Has_Operators           => False,
                                        Is_Constant             => True,
                                        Is_Static               => (CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83),
                                        Is_ARange               => False,
                                        String_Value            => String_Value,
                                        Value                   => Maths.NoValue,
                                        Range_RHS               => Get_String_Literal_Length (Str => String_Value)),
               Stack => E_Stack);
            Next_Node := STree.NullNode;
         when SP_Symbols.numeric_literal =>
            -- ASSUME Last_Node = numeric_literal
            Local_Node := STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Last_Node));
            -- ASSUME Local_Node = integer_number OR real_number OR based_integer OR based_real
            if STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.real_number then
               -- ASSUME Local_Node = real_number
               Sem.Get_Literal_Value (Node => Local_Node,
                                      Val  => Val);
               Exp_Stack.Push
                 (X     => Sem.Exp_Record'(Type_Symbol             => Dictionary.GetUniversalRealType,
                                           Other_Symbol            => Dictionary.NullSymbol,
                                           Stream_Symbol           => Dictionary.NullSymbol,
                                           Tagged_Parameter_Symbol => Dictionary.NullSymbol,
                                           Variable_Symbol         => Dictionary.NullSymbol,
                                           Param_Count             => 0,
                                           Param_List              => Lists.Null_List,
                                           Sort                    => Sem.Type_Result,
                                           Arg_List_Found          => False,
                                           Is_AVariable            => False,
                                           Is_An_Entire_Variable   => False,
                                           Errors_In_Expression    => False,
                                           Has_Operators           => False,
                                           Is_Constant             => True,
                                           Is_Static               => True,
                                           Is_ARange               => False,
                                           String_Value            => LexTokenManager.Null_String,
                                           Value                   => Val,
                                           Range_RHS               => Maths.NoValue),
                  Stack => E_Stack);
            elsif STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.integer_number
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.based_integer
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.based_real then
               -- ASSUME Local_Node = integer_number OR based_integer OR based_real
               Sem.Get_Literal_Value (Node => Local_Node,
                                      Val  => Val);
               Exp_Stack.Push
                 (X     => Sem.Exp_Record'(Type_Symbol             => Dictionary.GetUniversalIntegerType,
                                           Other_Symbol            => Dictionary.NullSymbol,
                                           Stream_Symbol           => Dictionary.NullSymbol,
                                           Tagged_Parameter_Symbol => Dictionary.NullSymbol,
                                           Variable_Symbol         => Dictionary.NullSymbol,
                                           Param_Count             => 0,
                                           Param_List              => Lists.Null_List,
                                           Sort                    => Sem.Type_Result,
                                           Arg_List_Found          => False,
                                           Is_AVariable            => False,
                                           Is_An_Entire_Variable   => False,
                                           Errors_In_Expression    => False,
                                           Has_Operators           => False,
                                           Is_Constant             => True,
                                           Is_Static               => True,
                                           Is_ARange               => False,
                                           String_Value            => LexTokenManager.Null_String,
                                           Value                   => Val,
                                           Range_RHS               => Maths.NoValue),
                  Stack => E_Stack);
            else
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Local_Node = integer_number OR real_number OR based_integer OR based_real in Walk_Expression");
            end if;
            Next_Node := STree.NullNode;
         when SP_Symbols.selector =>
            -- ASSUME Last_Node = selector
            Next_Node := STree.NullNode;
         when SP_Symbols.simple_name =>
            -- ASSUME Last_Node = simple_name
            Local_Node := STree.Parent_Node (Current_Node => Last_Node);
            -- ASSUME Local_Node = name OR named_argument_association OR selector OR label OR loop_statement OR exit_statement OR
            --                     procedure_specification OR return_expression OR own_variable OR proof_renaming_declaration OR
            --                     renaming_declaration OR parent_unit_name OR enumeration_representation_clause OR
            --                     record_representation_clause OR component_clause OR at_clause
            if STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.named_argument_association then
               -- ASSUME Local_Node = named_argument_association
               -- do not look at identifier in this case
               Next_Node := STree.NullNode;
            elsif STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.name
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.selector
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.label
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.loop_statement
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.exit_statement
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.procedure_specification
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.return_expression
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.own_variable
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.proof_renaming_declaration
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.renaming_declaration
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.parent_unit_name
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.enumeration_representation_clause
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.record_representation_clause
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.component_clause
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.at_clause then
               -- ASSUME Local_Node = name OR selector OR label OR loop_statement OR exit_statement OR
               --                     procedure_specification OR return_expression OR own_variable OR proof_renaming_declaration OR
               --                     renaming_declaration OR parent_unit_name OR enumeration_representation_clause OR
               --                     record_representation_clause OR component_clause OR at_clause
               Next_Node := STree.Child_Node (Current_Node => Last_Node);
               -- ASSUME Next_Node = identifier
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.identifier,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Next_Node = identifier in Walk_Expression");
            else
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Local_Node = name OR named_argument_association OR selector OR " &
                    "label OR loop_statement OR exit_statement OR " &
                    "procedure_specification OR return_expression OR own_variable OR proof_renaming_declaration OR " &
                    "renaming_declaration OR parent_unit_name OR enumeration_representation_clause OR " &
                    "record_representation_clause OR component_clause OR at_clause in Walk_Expression");
            end if;
         when SP_Symbols.identifier =>
            -- ASSUME Last_Node = identifier
            Wf_Identifier
              (Node     => Last_Node,
               Scope    => Scope,
               E_Stack  => E_Stack,
               The_Heap => The_Heap,
               Ref_Var  => Ref_Var,
               Context  => Sem.Code);
            Next_Node := STree.NullNode;
         when SP_Symbols.name_argument_list =>
            -- ASSUME Last_Node = name_argument_list
            Down_Wf_Name_Argument_List
              (Node       => Last_Node,
               Scope      => Scope,
               E_Stack    => E_Stack,
               Heap_Param => L_Heap,
               Next_Node  => Next_Node);
         when SP_Symbols.aggregate =>
            -- ASSUME Last_Node = aggregate
            Down_Wf_Aggregate (Node       => Last_Node,
                               Scope      => Scope,
                               Next_Node  => Next_Node,
                               E_Stack    => E_Stack,
                               Heap_Param => L_Heap);
         when SP_Symbols.aggregate_choice_rep =>
            -- ASSUME Last_Node = aggregate_choice_rep
            Wf_Aggregate_Choice_Rep
              (Node       => Last_Node,
               Scope      => Scope,
               E_Stack    => E_Stack,
               Heap_Param => L_Heap,
               Next_Node  => Next_Node);
         when SP_Symbols.record_component_selector_name =>
            -- ASSUME Last_Node = record_component_selector_name
            Wf_Record_Component_Selector_Name (Node       => Last_Node,
                                               Scope      => Scope,
                                               E_Stack    => E_Stack,
                                               Heap_Param => L_Heap);
            Next_Node := STree.NullNode;
         when SP_Symbols.aggregate_or_expression =>
            -- ASSUME Last_Node = aggregate_or_expression
            Down_Wf_Aggregate_Or_Expression (Node      => Last_Node,
                                             E_Stack   => E_Stack,
                                             Next_Node => Next_Node);
         when SP_Symbols.attribute_designator =>
            -- ASSUME Last_Node = attribute_designator
            Type_Context_Stack.Push
              (X     => Attribute_Designator_Type_From_Context (Exp_Node => Last_Node,
                                                                E_Stack  => E_Stack,
                                                                T_Stack  => T_Stack),
               Stack => T_Stack);
            Next_Node := STree.Child_Node (Current_Node => Last_Node);
            -- ASSUME Next_Node = attribute_designator OR attribute_ident
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.attribute_designator
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.attribute_ident,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = attribute_designator OR attribute_ident in Walk_Expression");
         when SP_Symbols.range_constraint =>
            -- ASSUME Last_Node = range_constraint
            Type_Context_Stack.Push
              (X     => Range_Constraint_Type_From_Context (Exp_Node => Last_Node,
                                                            E_Stack  => E_Stack,
                                                            T_Stack  => T_Stack),
               Stack => T_Stack);
            Next_Node := STree.Child_Node (Current_Node => Last_Node);
            -- ASSUME Next_Node = arange
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.arange,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = arange in Walk_Expression");
         when SP_Symbols.simple_expression =>
            -- ASSUME Last_Node = simple_expression
            Type_Context_Stack.Push
              (X     => Simple_Expression_Type_From_Context (Exp_Node => Last_Node,
                                                             T_Stack  => T_Stack),
               Stack => T_Stack);
            Next_Node := STree.Child_Node (Current_Node => Last_Node);
            -- ASSUME Next_Node = simple_expression OR simple_expression_opt
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.simple_expression
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.simple_expression_opt,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = simple_expression OR simple_expression_opt in Walk_Expression");
         when SP_Symbols.expression =>
            -- ASSUME Last_Node = expression
            Expression_Type_From_Context (Exp_Node         => Last_Node,
                                          E_Stack          => E_Stack,
                                          T_Stack          => T_Stack,
                                          New_Context_Type => Sym);
            Type_Context_Stack.Push (X     => Sym,
                                     Stack => T_Stack);
            Next_Node := STree.Child_Node (Current_Node => Last_Node);
            -- ASSUME Next_Node = relation
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.relation,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = relation in Walk_Expression");
         when SP_Symbols.primary =>
            -- ASSUME Last_Node = primary
            Type_Context_Stack.Push (X     => Primary_Type_From_Context (Node    => Last_Node,
                                                                         T_Stack => T_Stack),
                                     Stack => T_Stack);
            Next_Node := STree.Child_Node (Current_Node => Last_Node);
            -- ASSUME Next_Node = numeric_literal OR character_literal OR string_literal OR name OR
            --                    qualified_expression OR expression OR aattribute
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.numeric_literal
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.character_literal
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.string_literal
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.name
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.qualified_expression
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.expression
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.attribute,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = numeric_literal OR character_literal OR string_literal OR name OR " &
                 "qualified_expression OR expression OR attribute in Walk_Expression");
         when others =>
            if Node_Type in SP_Symbols.SP_Non_Terminal then
               Next_Node := STree.Child_Node (Current_Node => Last_Node);
            else
               Next_Node := STree.NullNode;
            end if;
      end case;

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

            Next_Node := STree.Parent_Node (Current_Node => Last_Node);
            Last_Node := Next_Node;

            Dump_Up_Node;

            case STree.Syntax_Node_Type (Node => Last_Node) is
               when SP_Symbols.expression =>
                  -- ASSUME Last_Node = expression
                  Wf_Expression (Node    => Last_Node,
                                 Scope   => Scope,
                                 E_Stack => E_Stack,
                                 T_Stack => T_Stack);
                  Type_Context_Stack.Pop (Stack => T_Stack);
               when SP_Symbols.expression_rep1 |
                 SP_Symbols.expression_rep2 |
                 SP_Symbols.expression_rep3 |
                 SP_Symbols.expression_rep4 |
                 SP_Symbols.expression_rep5 =>
                  -- ASSUME Last_Node = expression_rep1 OR expression_rep2 OR expression_rep3 OR expression_rep4 OR expression_rep5
                  Wf_Expression (Node    => Last_Node,
                                 Scope   => Scope,
                                 E_Stack => E_Stack,
                                 T_Stack => T_Stack);
               when SP_Symbols.simple_expression =>
                  -- ASSUME Last_Node = simple_expression
                  Wf_Simple_Expression
                    (Node                    => Last_Node,
                     Scope                   => Scope,
                     E_Stack                 => E_Stack,
                     T_Stack                 => T_Stack,
                     Context_Requires_Static => Context_Requires_Static);
                  Type_Context_Stack.Pop (Stack => T_Stack);
               when SP_Symbols.simple_expression_opt =>
                  -- ASSUME Last_Node = simple_expression_opt
                  Wf_Simple_Expression_Opt (Node    => Last_Node,
                                            Scope   => Scope,
                                            E_Stack => E_Stack,
                                            T_Stack => T_Stack);
               when SP_Symbols.term =>
                  -- ASSUME Last_Node = term
                  Wf_Term
                    (Node                    => Last_Node,
                     Scope                   => Scope,
                     E_Stack                 => E_Stack,
                     T_Stack                 => T_Stack,
                     Context_Requires_Static => Context_Requires_Static);
               when SP_Symbols.factor =>
                  -- ASSUME Last_Node = factor
                  Wf_Factor (Node    => Last_Node,
                             Scope   => Scope,
                             E_Stack => E_Stack,
                             T_Stack => T_Stack);
               when SP_Symbols.relation =>
                  -- ASSUME Last_Node = relation
                  Wf_Relation (Node    => Last_Node,
                               Scope   => Scope,
                               E_Stack => E_Stack,
                               T_Stack => T_Stack);
               when SP_Symbols.range_constraint =>
                  -- ASSUME Last_Node = range_constraint
                  Type_Context_Stack.Pop (Stack => T_Stack);
               when SP_Symbols.arange =>
                  -- ASSUME Last_Node = arange
                  Wf_Arange (Node    => Last_Node,
                             Scope   => Scope,
                             E_Stack => E_Stack);
               when SP_Symbols.selected_component =>
                  -- ASSUME Last_Node = selected_component
                  Wf_Selected_Component
                    (Node           => Last_Node,
                     Scope          => Scope,
                     Ref_Var        => Ref_Var,
                     E_Stack        => E_Stack,
                     Component_Data => Component_Data,
                     The_Heap       => The_Heap,
                     Context        => Sem.Code);
               when SP_Symbols.attribute =>
                  -- ASSUME Last_Node = attribute
                  Wf_Attribute (E_Stack => E_Stack);
               when SP_Symbols.attribute_designator =>
                  -- ASSUME Last_Node = attribute_designator
                  Wf_Attribute_Designator
                    (Node     => Last_Node,
                     Scope    => Scope,
                     E_Stack  => E_Stack,
                     The_Heap => The_Heap,
                     Ref_Var  => Ref_Var);
                  Type_Context_Stack.Pop (Stack => T_Stack);
               when SP_Symbols.primary =>
                  -- ASSUME Last_Node = primary
                  Wf_Primary
                    (Node           => Last_Node,
                     Scope          => Scope,
                     Ref_Var        => Ref_Var,
                     E_Stack        => E_Stack,
                     Component_Data => Component_Data,
                     The_Heap       => The_Heap);
                  Type_Context_Stack.Pop (Stack => T_Stack);
               when SP_Symbols.positional_argument_association =>
                  -- ASSUME Last_Node = positional_argument_association
                  Wf_Positional_Argument_Association
                    (Node           => Last_Node,
                     Scope          => Scope,
                     Ref_Var        => Ref_Var,
                     E_Stack        => E_Stack,
                     Component_Data => Component_Data,
                     The_Heap       => The_Heap);
               when SP_Symbols.named_argument_association =>
                  -- ASSUME Last_Node = named_argument_association
                  Wf_Named_Argument_Association (Node       => Last_Node,
                                                 Scope      => Scope,
                                                 E_Stack    => E_Stack,
                                                 Heap_Param => L_Heap);
               when SP_Symbols.name_argument_list =>
                  -- ASSUME Last_Node = name_argument_list
                  Up_Wf_Name_Argument_List (Node       => Last_Node,
                                            E_Stack    => E_Stack,
                                            Heap_Param => L_Heap);
               when SP_Symbols.ancestor_part =>
                  -- ASSUME Last_Node = ancestor_part
                  Wf_Ancestor_Part (Node       => Last_Node,
                                    Scope      => Scope,
                                    E_Stack    => E_Stack,
                                    Heap_Param => L_Heap);
               when SP_Symbols.aggregate_choice =>
                  -- ASSUME Last_Node = aggregate_choice
                  Wf_Aggregate_Choice (Node    => Last_Node,
                                       Scope   => Scope,
                                       E_Stack => E_Stack);
               when SP_Symbols.named_association_rep =>
                  -- ASSUME Last_Node = named_association_rep
                  Wf_Named_Association_Rep (Node       => Last_Node,
                                            Scope      => Scope,
                                            E_Stack    => E_Stack,
                                            Heap_Param => L_Heap);
               when SP_Symbols.named_record_component_association =>
                  -- ASSUME Last_Node = named_record_component_association
                  Wf_Named_Record_Component_Association (Node       => Last_Node,
                                                         Scope      => Scope,
                                                         E_Stack    => E_Stack,
                                                         Heap_Param => L_Heap);
               when SP_Symbols.positional_association | SP_Symbols.record_component_association =>
                  -- ASSUME Last_Node = positional_association OR record_component_association
                  Wf_Positional_Association (Node    => Last_Node,
                                             E_Stack => E_Stack);
               when SP_Symbols.aggregate_or_expression =>
                  -- ASSUME Last_Node = aggregate_or_expression
                  Up_Wf_Aggregate_Or_Expression (Node    => Last_Node,
                                                 Scope   => Scope,
                                                 E_Stack => E_Stack);
               when SP_Symbols.positional_record_component_association =>
                  -- ASSUME Last_Node = positional_record_component_association
                  Wf_Positional_Record_Component_Association (Node    => Last_Node,
                                                              Scope   => Scope,
                                                              E_Stack => E_Stack);
               when SP_Symbols.component_association =>
                  -- ASSUME Last_Node = component_association
                  Wf_Component_Association (Node    => Last_Node,
                                            Scope   => Scope,
                                            E_Stack => E_Stack);
               when SP_Symbols.aggregate | SP_Symbols.extension_aggregate =>
                  -- ASSUME Last_Node = aggregate OR extension_aggregate
                  Up_Wf_Aggregate (Node    => Last_Node,
                                   Scope   => Scope,
                                   E_Stack => E_Stack);
               when SP_Symbols.qualified_expression =>
                  -- ASSUME Last_Node = qualified_expression
                  Wf_Qualified_Expression (Node    => Last_Node,
                                           Scope   => Scope,
                                           E_Stack => E_Stack);
               when others =>
                  null;
            end case;
            exit when Next_Node = Exp_Node; -- got back to top
         end loop; -- up
      end if;
      exit when Next_Node = Exp_Node; -- met start point on way up
   end loop; -- down

   if not Exp_Stack.Has_One_Entry (Stack => E_Stack) then
      SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Expression_Stack_Corrupt,
                                Msg     => "in Walk_Expression");
   end if;

   if not (Type_Context_Stack.Has_One_Entry (Stack => T_Stack)
             and then Dictionary.Types_Are_Equal
             (Left_Symbol        => Type_Context_Stack.Top (Stack => T_Stack),
              Right_Symbol       => Type_Context,
              Full_Range_Subtype => False)) then
      SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Type_Context_Stack_Corrupt,
                                Msg     => "in Walk_Expression");
   end if;

   --# accept Flow, 10, E_Stack, "Expected ineffective assignment";
   Exp_Stack.Pop (Item  => Result,
                  Stack => E_Stack);
   --# end accept;

   Dump_Result;
end Walk_Expression;
