-------------------------------------------------------------------------------
-- (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 Wf_Positional_Association (Node    : in     STree.SyntaxNode;
                                     E_Stack : in out Exp_Stack.Exp_Stack_Type) is
   Name_Exp    : Sem.Exp_Record;
   Error_Found : Boolean := False;

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

   procedure Check_Record_Completeness (Name_Exp    : in     Sem.Exp_Record;
                                        Node        : in     STree.SyntaxNode;
                                        Error_Found : in out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Name_Exp,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table &
   --#         Error_Found                from *,
   --#                                         Dictionary.Dict,
   --#                                         Name_Exp;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.record_component_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_record_component_association;
   is
      Highest_Field_Number, Number_Of_Fields : Positive;

      function Error_Pos (Node : STree.SyntaxNode) return LexTokenManager.Token_Position
      --# global in STree.Table;
      --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_association or
      --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.record_component_association or
      --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_association or
      --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_record_component_association;
      -- Finds the position of the right most expression in an association list
      is
         Result     : LexTokenManager.Token_Position := LexTokenManager.Null_Token_Position;
         Local_Node : STree.SyntaxNode;
      begin
         if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.positional_association
           or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_positional_association then
            -- ASSUME Node = positional_association OR annotation_positional_association
            Local_Node := STree.Child_Node (Current_Node => Node);
            -- ASSUME Local_Node = aggregate_or_expression            OR positional_association_rep OR
            --                     annotation_aggregate_or_expression OR annotation_positional_association_rep
            if STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.positional_association_rep
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_positional_association_rep then
               -- ASSUME Local_Node = positional_association_rep OR annotation_positional_association_rep
               Local_Node := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Local_Node));
            elsif STree.Syntax_Node_Type (Node => Local_Node) /= SP_Symbols.aggregate_or_expression
              and then STree.Syntax_Node_Type (Node => Local_Node) /= SP_Symbols.annotation_aggregate_or_expression then
               Local_Node := STree.NullNode;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Local_Node = aggregate_or_expression OR positional_association_rep OR " &
                    "annotation_aggregate_or_expression OR annotation_positional_association_rep in Error_Pos");
            end if;
            -- ASSUME Local_Node = aggregate_or_expression OR annotation_aggregate_or_expression
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.aggregate_or_expression
                 or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_aggregate_or_expression,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Local_Node = aggregate_or_expression OR annotation_aggregate_or_expression in Error_Pos");
            Result := STree.Node_Position (Node => Local_Node);
         elsif STree.Syntax_Node_Type (Node => Node) = SP_Symbols.record_component_association
           or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_record_component_association then
            -- ASSUME Node = record_component_association OR annotation_record_component_association
            Local_Node := STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node));
            -- ASSUME Local_Node = positional_record_component_association            OR expression OR
            --                     named_record_component_association                 OR record_component_selector_name OR
            --                     annotation_positional_record_component_association OR annotation_expression          OR
            --                     annotation_named_record_component_association
            if STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.positional_record_component_association
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.named_record_component_association
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.record_component_selector_name
              or else STree.Syntax_Node_Type (Node => Local_Node) =
              SP_Symbols.annotation_positional_record_component_association
              or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_named_record_component_association then
               -- ASSUME Local_Node = positional_record_component_association            OR
               --                     named_record_component_association                 OR record_component_selector_name OR
               --                     annotation_positional_record_component_association OR
               --                     annotation_named_record_component_association
               Local_Node := STree.Last_Sibling_Of (Start_Node => Local_Node);
            elsif STree.Syntax_Node_Type (Node => Local_Node) /= SP_Symbols.expression
              and then STree.Syntax_Node_Type (Node => Local_Node) /= SP_Symbols.annotation_expression then
               Local_Node := STree.NullNode;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Local_Node = positional_record_component_association OR expression OR " &
                    "named_record_component_association OR record_component_selector_name OR " &
                    "annotation_positional_record_component_association OR annotation_expression OR " &
                    "annotation_named_record_component_association in Error_Pos");
            end if;
            -- ASSUME Local_Node = expression OR annotation_expression
            SystemErrors.RT_Assert
              (C       => STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.expression
                 or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_expression,
               Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Local_Node = expression OR annotation_expression in Error_Pos");
            Result := STree.Node_Position (Node => Local_Node);
         end if;
         return Result;
      end Error_Pos;

   begin -- Check_Record_Completeness
      if Name_Exp.Param_Count < Natural'Last
        and then Dictionary.GetNumberOfComponents (Name_Exp.Type_Symbol) > Natural'First then
         Highest_Field_Number := Name_Exp.Param_Count + 1;
         Number_Of_Fields     := Dictionary.GetNumberOfComponents (Name_Exp.Type_Symbol);

         for I in Positive range Highest_Field_Number .. Number_Of_Fields loop
            Error_Found := True;
            ErrorHandler.Semantic_Error
              (Err_Num   => 104,
               Reference => ErrorHandler.No_Reference,
               Position  => Error_Pos (Node => Node),
               Id_Str    => Dictionary.GetSimpleName (Dictionary.GetRecordComponent (Name_Exp.Type_Symbol, I)));
         end loop;
      end if;
   end Check_Record_Completeness;

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

   function Named_Record_Extension_Aggregate (Node : STree.SyntaxNode) return Boolean
   --# global in STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.record_component_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_record_component_association;
   is
      Local_Node : STree.SyntaxNode;
      Result     : Boolean := False;
   begin
      if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.positional_association
        or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_positional_association then
         -- ASSUME Node = positional_association OR annotation_positional_association
         Result := False;
      elsif STree.Syntax_Node_Type (Node => Node) = SP_Symbols.record_component_association
        or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_record_component_association then
         -- ASSUME Node = record_component_association OR annotation_record_component_association
         Local_Node := STree.Child_Node (Current_Node => Node);
         -- ASSUME Local_Node = named_record_component_association            OR positional_record_component_association         OR
         --                     annotation_named_record_component_association OR annotation_positional_record_component_association
         if STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.named_record_component_association
           or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_named_record_component_association then
            -- ASSUME Local_Node = named_record_component_association OR annotation_named_record_component_association
            Result := True;
         elsif STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.positional_record_component_association
           or else STree.Syntax_Node_Type (Node => Local_Node) = SP_Symbols.annotation_positional_record_component_association then
            Result := False;
         else
            Result := False;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Local_Node = positional_record_component_association OR named_record_component_association OR " &
                 "annotation_positional_record_component_association OR " &
                 "annotation_named_record_component_association in Named_Record_Component_Association");
         end if;
      end if;
      return Result;
   end Named_Record_Extension_Aggregate;

begin -- Wf_Positional_Association
   if not Named_Record_Extension_Aggregate (Node => Node) then
      Exp_Stack.Pop (Item  => Name_Exp,
                     Stack => E_Stack);
      if Dictionary.TypeIsRecord (Name_Exp.Type_Symbol) then
         Check_Record_Completeness (Name_Exp    => Name_Exp,
                                    Node        => Node,
                                    Error_Found => Error_Found);
      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);
   end if;
end Wf_Positional_Association;
