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

separate (Sem.Walk_Expression_P)
procedure Down_Wf_Aggregate
  (Node       : in     STree.SyntaxNode;
   Scope      : in     Dictionary.Scopes;
   Next_Node  :    out STree.SyntaxNode;
   E_Stack    : in out Exp_Stack.Exp_Stack_Type;
   Heap_Param : in out Lists.List_Heap)
is
   Has_Others_Part             : Boolean;
   Association_Type            : Sem.Typ_Agg_Association_Type;
   Name_Exp                    : Sem.Exp_Record;
   Child, Parent, Others_Node  : STree.SyntaxNode;
   Ptr                         : Lists.List;
   Unknown_Or_Indiscrete_Found : Boolean;
   Index_Type_Mark             : Dictionary.Symbol;
   Error_Found                 : Boolean := False;
   Number_Of_Dimensions        : Positive;

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

   procedure Create_Aggregate_Stack_Entry
     (Index_Type_Symbol : in Dictionary.Symbol;
      Association_Type  : in Sem.Typ_Agg_Association_Type;
      Has_Others_Part   : in Boolean;
      Scope             : in Dictionary.Scopes)
   -- this procedure discriminates between the cases listed in S.P0468.53.11
   -- and sets up the stack entry accordingly
   --
   -- preconditions to entry to this procedure:
   --     aggregate is an array aggregate
   --
   -- NB aggregate may be a lone others clause
   --# global in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State from *,
   --#                                    Association_Type,
   --#                                    Dictionary.Dict,
   --#                                    Has_Others_Part,
   --#                                    Index_Type_Symbol,
   --#                                    LexTokenManager.State,
   --#                                    Scope;
   --# pre (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict)) and
   --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State);
   --# post Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State);
   is
      Complete_Check_Range_From  : Integer;
      Complete_Check_Range_To    : Integer;
      Complete_Check_Range_State : CompleteCheck.TypRangeState;
      Type_Lower_Bound           : Sem.Typ_Type_Bound;
      Type_Upper_Bound           : Sem.Typ_Type_Bound;
      Complete_Rec               : CompleteCheck.T;
      Check_Completeness         : Boolean;
      Warn_No_Others             : Boolean;
      Check_Overlap              : Boolean;
      Signal_Out_Of_Range        : Boolean;
   begin
      -- if index type unknown or not discrete then cannot do much at all
      if Dictionary.IsUnknownTypeMark (Index_Type_Symbol)
        or else not Dictionary.IsDiscreteTypeMark (Index_Type_Symbol, Scope) then
         Type_Lower_Bound          := Sem.Unknown_Type_Bound;
         Type_Upper_Bound          := Sem.Unknown_Type_Bound;
         Complete_Check_Range_From := -(ExaminerConstants.CompleteCheckSize / 2);
         Complete_Check_Range_To   := (Complete_Check_Range_From + ExaminerConstants.CompleteCheckSize) - 1;
         --NB we 'know' that Complete_Check_Range_State will return RangeDoesFit,
         --   so the value is ignored, giving a flow error
         --# accept Flow, 10, Complete_Check_Range_State, "Expected ineffective assignment to Complete_Check_Range_State";
         CompleteCheck.Init (Complete_Rec, Complete_Check_Range_From, Complete_Check_Range_To, Complete_Check_Range_State);
         --# end accept;
         Check_Completeness  := False;
         Warn_No_Others      := False;
         Signal_Out_Of_Range := False;
         if Dictionary.IsUnknownTypeMark (Index_Type_Symbol) and then Association_Type = Sem.Aggregate_Is_Named then
            Check_Overlap := True;
         else
            Check_Overlap := False;
         end if;
      else
         -- get bounds from dictionary
         Sem.Get_Type_Bounds (Type_Symbol => Index_Type_Symbol,
                              Lower_Bound => Type_Lower_Bound,
                              Upper_Bound => Type_Upper_Bound);

         if not (Type_Lower_Bound.Is_Defined and then Type_Upper_Bound.Is_Defined) then
            -- one or other bound is unknown to the dictionary
            -- set flags accordingly
            Check_Completeness := False;
            Warn_No_Others     := True;
            if Association_Type = Sem.Aggregate_Is_Positional then
               Check_Overlap       := False;
               Signal_Out_Of_Range := False;
            else
               Check_Overlap       := True;
               Signal_Out_Of_Range := True;
            end if;

            -- set up range for completeness checker
            -- if both bounds unknown use symmetric range
            if (not Type_Lower_Bound.Is_Defined) and then (not Type_Upper_Bound.Is_Defined) then
               Complete_Check_Range_From := -(ExaminerConstants.CompleteCheckSize / 2);
               Complete_Check_Range_To   := (Complete_Check_Range_From + ExaminerConstants.CompleteCheckSize) - 1;
               -- otherwise use range extending from known bound
            elsif Type_Lower_Bound.Is_Defined then
               Complete_Check_Range_From := Type_Lower_Bound.Value;
               if Complete_Check_Range_From <= (Integer'Last - ExaminerConstants.CompleteCheckSize) then
                  Complete_Check_Range_To := (Complete_Check_Range_From + ExaminerConstants.CompleteCheckSize) - 1;
               else
                  Complete_Check_Range_To := Integer'Last;
               end if;
            else -- Type_Upper_Bound.IsDefined
               Complete_Check_Range_To := Type_Upper_Bound.Value;
               if Complete_Check_Range_To >= (Integer'First + ExaminerConstants.CompleteCheckSize) then
                  Complete_Check_Range_From := (Complete_Check_Range_To - ExaminerConstants.CompleteCheckSize) + 1;
               else
                  Complete_Check_Range_From := Integer'First;
               end if;
            end if;
            --NB we 'know' that Complete_Check_Range_State will return RangeDoesFit,
            --   so the value is ignored, giving a flow error
            --# accept Flow, 10, Complete_Check_Range_State, "Expected ineffective assignment to Complete_Check_Range_State";
            CompleteCheck.Init (Complete_Rec, Complete_Check_Range_From, Complete_Check_Range_To, Complete_Check_Range_State);
            --# end accept;
         else
            -- both bounds known to dictionary
            -- set up completeness checker
            CompleteCheck.Init (Complete_Rec, Type_Lower_Bound.Value, Type_Upper_Bound.Value, Complete_Check_Range_State);

            -- for positional association, the question of whether the
            -- type is too big for the completeness checker is irrelevant
            if Association_Type = Sem.Aggregate_Is_Positional then
               Check_Completeness  := True;
               Warn_No_Others      := False;
               Check_Overlap       := False;
               Signal_Out_Of_Range := False;
            else
               -- set flags according to whether range fits in completeness checker
               if Complete_Check_Range_State = CompleteCheck.RangeDoesFit then
                  Check_Completeness  := True;
                  Warn_No_Others      := False;
                  Check_Overlap       := True;
                  Signal_Out_Of_Range := False;
               else
                  Check_Completeness  := False;
                  Warn_No_Others      := True;
                  Check_Overlap       := True;
                  Signal_Out_Of_Range := True;
               end if;
            end if;
         end if;
      end if;

      Aggregate_Stack.Push
        (Type_Sym     => Index_Type_Symbol,
         Lower_Bound  => Type_Lower_Bound,
         Upper_Bound  => Type_Upper_Bound,
         Agg_Flags    => Sem.Typ_Agg_Flags'(Check_Completeness        => Check_Completeness,
                                            Warn_No_Others            => Warn_No_Others,
                                            Check_Overlap             => Check_Overlap,
                                            Signal_Out_Of_Range       => Signal_Out_Of_Range,
                                            Out_Of_Range_Seen         => False,
                                            More_Entries_Than_Natural => False,
                                            Has_Others_Part           => Has_Others_Part,
                                            Association_Type          => Association_Type),
         Counter      => 0,
         Complete_Rec => Complete_Rec);
   end Create_Aggregate_Stack_Entry;

begin -- Down_Wf_Aggregate

   -- code to determine association type enhanced to detect the
   -- occurrence of a 'lone' others clause, and moved here so that
   -- the information is available to anonymous aggregates
   -- code determining presence of others part moved here for same reason

   Child := STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node));
   -- ASSUME Child = aggregate_or_expression            OR named_association            OR positional_association OR
   --                annotation_aggregate_or_expression OR annotation_named_association OR annotation_positional_association
   case STree.Syntax_Node_Type (Node => Child) is
      when SP_Symbols.positional_association | SP_Symbols.annotation_positional_association =>
         -- ASSUME Child = positional_association OR annotation_positional_association
         Association_Type := Sem.Aggregate_Is_Positional;
         Others_Node      := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Child));
         -- ASSUME Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression OR NULL
         if STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.aggregate_or_expression
           or else STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.annotation_aggregate_or_expression then
            -- ASSUME Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression
            Has_Others_Part := True;
         elsif Others_Node = STree.NullNode then
            -- ASSUME Others_Node = NULL
            Has_Others_Part := False;
         else
            Has_Others_Part := False;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression OR " &
                 "NULL in Down_Wf_Aggregate");
         end if;
      when SP_Symbols.named_association | SP_Symbols.annotation_named_association =>
         -- ASSUME Child = named_association OR annotation_named_association
         Association_Type := Sem.Aggregate_Is_Named;
         Others_Node      := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Child));
         -- ASSUME Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression OR NULL
         if STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.aggregate_or_expression
           or else STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.annotation_aggregate_or_expression then
            -- ASSUME Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression
            Has_Others_Part := True;
         elsif Others_Node = STree.NullNode then
            -- ASSUME Others_Node = NULL
            Has_Others_Part := False;
         else
            Has_Others_Part := False;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Others_Node = aggregate_or_expression OR annotation_aggregate_or_expression OR " &
                 "NULL in Down_Wf_Aggregate");
         end if;
      when SP_Symbols.aggregate_or_expression | SP_Symbols.annotation_aggregate_or_expression =>
         -- ASSUME Child = aggregate_or_expression OR annotation_aggregate_or_expression
         Association_Type := Sem.Aggregate_Is_Lone_Others;
         Others_Node      := STree.Child_Node (Current_Node => Child);
         -- ASSUME Others_Node = aggregate            OR expression OR
         --                      annotation_aggregate OR annotation_expression
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.aggregate
              or else STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.expression
              or else STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.annotation_aggregate
              or else STree.Syntax_Node_Type (Node => Others_Node) = SP_Symbols.annotation_expression,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Others_Node = aggregate OR expression OR " &
              "annotation_aggregate OR annotation_expression in Down_Wf_Aggregate");
         Has_Others_Part := True;
      when others =>
         Association_Type := Sem.Aggregate_Is_Lone_Others;
         Others_Node      := STree.NullNode;
         Has_Others_Part  := False;
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Child = aggregate_or_expression OR named_association OR positional_association OR " &
              "annotation_aggregate_or_expression OR annotation_named_association OR annotation_positional_association " &
              "in Down_Wf_Aggregate");
   end case;

   --# assert (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.aggregate or
   --#           STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_aggregate) and
   --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
   --#   (STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.aggregate_or_expression or
   --#      STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.annotation_aggregate_or_expression or
   --#      STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.aggregate or
   --#      STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.expression or
   --#      STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.annotation_aggregate or
   --#      STree.Syntax_Node_Type (Others_Node, STree.Table) = SP_Symbols.annotation_expression or
   --#      Others_Node = STree.NullNode);

   Parent := STree.Parent_Node (Current_Node => Node);
   -- ASSUME Parent = enumeration_representation_clause  OR code_statement OR
   --                 aggregate_or_expression            OR qualified_expression OR
   --                 annotation_aggregate_or_expression OR annotation_qualified_expression
   if STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.qualified_expression
     or else STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.annotation_qualified_expression then
      -- ASSUME Parent = qualified_expression OR annotation_qualified_expression
      -- this is a top level, not embedded, aggregate
      Exp_Stack.Pop (Item  => Name_Exp,
                     Stack => E_Stack);
      case Name_Exp.Sort is
         when Sem.Is_Type_Mark =>
            Name_Exp.Is_Constant := True;
            if Dictionary.IsArrayTypeMark (Name_Exp.Type_Symbol, Scope) then
               if Dictionary.Is_Unconstrained_Array_Type_Mark (Name_Exp.Type_Symbol, Scope)
                 and then STree.Syntax_Node_Type (Node => Node) = SP_Symbols.aggregate then
                  -- Qualified aggregates of unconstrained array types only permitted in
                  -- annotation context.
                  -- So you are allowed to say, for example, "post X = T'(others => 0)" for a
                  -- subprogram that initializes an unconstrained array or "post X /= Y" where
                  -- both X and Y are unconstrained array types.
                  Error_Found := True;
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 39,
                     Reference => ErrorHandler.No_Reference,
                     Position  => STree.Node_Position (Node => Parent),
                     Id_Str    => LexTokenManager.Null_String);
               end if;

               --# assert (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.aggregate or
               --#           STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_aggregate) and
               --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
               --#   (STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.qualified_expression or
               --#      STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.annotation_qualified_expression);

               Name_Exp.Param_Count := 1; -- used to record depth of dimension reached
               Create_Aggregate_Stack_Entry
                 (Index_Type_Symbol => Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, 1),
                  Association_Type  => Association_Type,
                  Has_Others_Part   => Has_Others_Part,
                  Scope             => Scope);
               -- check types of all array dimensions, and warn if checking
               -- may be incomplete because any of the index types is unknown
               -- or indiscrete
               Unknown_Or_Indiscrete_Found := False;

               Number_Of_Dimensions := Dictionary.GetNumberOfDimensions (Name_Exp.Type_Symbol);
               for I in Positive range 1 .. Number_Of_Dimensions
               --# assert (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.aggregate or
               --#           STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_aggregate) and
               --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
               --#   (STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.qualified_expression or
               --#      STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.annotation_qualified_expression);
               loop
                  Index_Type_Mark := Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, I);
                  if Dictionary.IsUnknownTypeMark (Index_Type_Mark)
                    or else (not Dictionary.IsDiscreteTypeMark (Index_Type_Mark, Scope)) then
                     Unknown_Or_Indiscrete_Found := True;
                  end if;
               end loop;

               --# assert (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.aggregate or
               --#           STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_aggregate) and
               --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
               --#   (STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.qualified_expression or
               --#      STree.Syntax_Node_Type (Parent, STree.Table) = SP_Symbols.annotation_qualified_expression);

               if Unknown_Or_Indiscrete_Found then
                  Error_Found := True;
                  ErrorHandler.Semantic_Warning
                    (Err_Num  => 307,
                     Position => STree.Node_Position (Node => Parent),
                     Id_Str   => LexTokenManager.Null_String);
               end if;
               Name_Exp.Errors_In_Expression := Name_Exp.Errors_In_Expression or else Error_Found;
               Exp_Stack.Push (X     => Name_Exp,
                               Stack => E_Stack);
               Next_Node := STree.Child_Node (Current_Node => Node);
               -- ASSUME Next_Node = component_association OR annotation_component_association
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.component_association
                    or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_component_association,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Next_Node = component_association OR annotation_component_association in Down_Wf_Aggregate");
            elsif Dictionary.IsRecordTypeMark (Name_Exp.Type_Symbol, Scope) then
               if Has_Others_Part then
                  Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                                  Stack => E_Stack);
                  Next_Node := STree.NullNode;
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 53,
                     Reference => ErrorHandler.No_Reference,
                     Position  => STree.Node_Position (Node => Others_Node),
                     Id_Str    => LexTokenManager.Null_String);
               elsif Dictionary.TypeIsExtendedTagged (Name_Exp.Type_Symbol)
                 and then Dictionary.ExtendedTaggedHasPrivateAncestors (Name_Exp.Type_Symbol, Scope) then
                  Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                                  Stack => E_Stack);
                  Next_Node := STree.NullNode;
                  ErrorHandler.Semantic_Error_Sym
                    (Err_Num   => 833,
                     Reference => ErrorHandler.No_Reference,
                     Position  => STree.Node_Position (Node => Parent),
                     Sym       => Name_Exp.Type_Symbol,
                     Scope     => Scope);
               else -- OK, not illegal tagged record and has no others clause

                  -- Name_Exp.TypeSymbol here might denote a record subtype.  For subsequent
                  -- checking of the aggregate, we need the root record type, so...
                  Name_Exp.Type_Symbol := Dictionary.GetRootType (Name_Exp.Type_Symbol);

                  if Association_Type = Sem.Aggregate_Is_Named then
                     Create_Name_List (List       => Ptr,
                                       Heap_Param => Heap_Param);
                     Name_Exp.Param_List := Ptr;
                     Exp_Stack.Push (X     => Name_Exp,
                                     Stack => E_Stack);
                     Next_Node := STree.Child_Node (Current_Node => Node);
                  else -- positional association
                     Name_Exp.Param_Count := 0;
                     Exp_Stack.Push (X     => Name_Exp,
                                     Stack => E_Stack);
                     Next_Node := STree.Child_Node (Current_Node => Node);
                  end if;
                  -- ASSUME Next_Node = component_association OR annotation_component_association
                  SystemErrors.RT_Assert
                    (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.component_association
                       or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_component_association,
                     Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Next_Node = component_association OR annotation_component_association " &
                       "in Down_Wf_Aggregate");
               end if;
            else -- not a record or array
               Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                               Stack => E_Stack);
               ErrorHandler.Semantic_Error
                 (Err_Num   => 33,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => Node),
                  Id_Str    => LexTokenManager.Null_String);
               Next_Node := STree.NullNode;
            end if;
         when Sem.Is_Unknown =>
            -- illegal name prefix but we can continue walk to check internal
            -- validity of any expressions that follow.
            Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                            Stack => E_Stack);
            Next_Node := STree.Child_Node (Current_Node => Node);
            -- ASSUME Next_Node = component_association OR annotation_component_association
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.component_association
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_component_association,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = component_association OR annotation_component_association in Down_Wf_Aggregate");
         when others =>
            Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                            Stack => E_Stack);
            ErrorHandler.Semantic_Error
              (Err_Num   => 95,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Parent),
               Id_Str    => LexTokenManager.Null_String);
            Next_Node := STree.Child_Node (Current_Node => Node);
            -- ASSUME Next_Node = component_association OR annotation_component_association
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.component_association
                 or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_component_association,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Next_Node = component_association OR annotation_component_association in Down_Wf_Aggregate");
      end case;
   elsif STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.enumeration_representation_clause
     or else STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.code_statement
     or else STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.aggregate_or_expression
     or else STree.Syntax_Node_Type (Node => Parent) = SP_Symbols.annotation_aggregate_or_expression then
      -- ASSUME Parent = enumeration_representation_clause OR code_statement OR
      --                 aggregate_or_expression           OR annotation_aggregate_or_expression
      -- it is an embedded aggregate of a multi-dim array
      Exp_Stack.Pop (Item  => Name_Exp,
                     Stack => E_Stack);
      -- increase depth of dimension count
      if Name_Exp.Param_Count < Natural'Last then
         Name_Exp.Param_Count := Name_Exp.Param_Count + 1;
         Create_Aggregate_Stack_Entry
           (Index_Type_Symbol => Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, Name_Exp.Param_Count),
            Association_Type  => Association_Type,
            Has_Others_Part   => Has_Others_Part,
            Scope             => Scope);
      else
         Name_Exp := Sem.Unknown_Type_Record;
      end if;
      Exp_Stack.Push (X     => Name_Exp,
                      Stack => E_Stack);
      Next_Node := STree.Child_Node (Current_Node => Node);
      -- ASSUME Next_Node = component_association OR annotation_component_association
      SystemErrors.RT_Assert
        (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.component_association
           or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_component_association,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Next_Node = component_association OR annotation_component_association in Down_Wf_Aggregate");
   else
      Next_Node := STree.NullNode;
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Parent = enumeration_representation_clause OR code_statement OR " &
           "aggregate_or_expression OR qualified_expression OR " &
           "annotation_aggregate_or_expression OR annotation_qualified_expression in Down_Wf_Aggregate");
   end if;
end Down_Wf_Aggregate;
