-------------------------------------------------------------------------------
-- (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;

separate (Declarations.OutputDeclarations.PrintDeclarations)
procedure PrintTypeRules (Write_Rules : in Boolean;
                          Rule_File   : in SPARK_IO.File_Type) is
   Empty : Boolean;
   Ok    : Boolean;
   Sym   : Dictionary.Symbol;

   type Bounds is (LowerBound, UpperBound);

   procedure PutBase (WithBase : in Boolean)
   --# global in     Rule_File;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                Rule_File,
   --#                                WithBase;
   is
   begin
      if WithBase then
         SPARK_IO.Put_String (Rule_File, "__base", 0);
      end if;
   end PutBase;

   procedure PrintLowerLessThanUpperRule (Sym      : in Dictionary.Symbol;
                                          WithBase : in Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                WithBase &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym,
   --#                                WithBase;
   is
   begin
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      PutBase (WithBase);
      SPARK_IO.Put_String (Rule_File, "__first <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      PutBase (WithBase);
      SPARK_IO.Put_Line (Rule_File, "__last may_be_deduced.", 0);

      if WithBase then --additional rule that base type is at least as big as type
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         PutBase (WithBase);
         SPARK_IO.Put_String (Rule_File, "__first <= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_Line (Rule_File, "__first may_be_deduced.", 0);

         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         PutBase (WithBase);
         SPARK_IO.Put_String (Rule_File, "__last >= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_Line (Rule_File, "__last may_be_deduced.", 0);
      end if;
   end PrintLowerLessThanUpperRule;

   procedure PrintABound (WhichBound : in Bounds;
                          WithBase   : in Boolean;
                          StoreVal   : in LexTokenManager.Lex_String)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in     Sym;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                LexTokenManager.State,
   --#                                StoreVal,
   --#                                WhichBound,
   --#                                WithBase &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                StoreVal,
   --#                                Sym,
   --#                                WhichBound,
   --#                                WithBase;
   is
   begin  --PrintABound
      if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => StoreVal,
                                                              Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq then
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         PutBase (WithBase);
         if WhichBound = LowerBound then
            SPARK_IO.Put_String (Rule_File, "__first", 0);
         else
            SPARK_IO.Put_String (Rule_File, "__last", 0);
         end if;
         Print_Replacement_Rule (Rule_File => Rule_File,
                                 Store_Val => StoreVal,
                                 Type_Mark => Sym,
                                 Scope     => Scope);
      elsif WhichBound = UpperBound then
         --if we do not know the value of the upper bound then put
         --out the less precise rule that Lower <= Upper
         PrintLowerLessThanUpperRule (Sym, WithBase);
      end if;
   end PrintABound;

   procedure PrintBounds (WithBase : in Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in     Sym;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Sym,
   --#                                WithBase &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym,
   --#                                WithBase;
   is
   begin
      PrintABound (LowerBound, WithBase, Dictionary.GetScalarAttributeValue (WithBase, LexTokenManager.First_Token, Sym));
      PrintABound (UpperBound, WithBase, Dictionary.GetScalarAttributeValue (WithBase, LexTokenManager.Last_Token, Sym));
   end PrintBounds;

   -- print a replacement rule for attribute T'Modulus where T is a modular type
   procedure PrintModulus (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from * &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
   begin -- PrintModulus
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__modulus", 0);
      Print_Replacement_Rule
        (Rule_File => Rule_File,
         Store_Val => Dictionary.GetScalarAttributeValue (False, LexTokenManager.Modulus_Token, Sym),
         Type_Mark => Sym,
         Scope     => Scope);
   end PrintModulus;

   procedure PrintSizeBoundsRule (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from * &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
   begin
      -- We _can_ produce a rule that T'Size >= 0 for all types T.
      -- On the other hand, the upper bound of T'Size is implementation-
      -- dependent, so we cannot produce a rule for that.
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__size >= 0 may_be_deduced", 0);

      End_A_Rule (Rule_File => Rule_File);
   end PrintSizeBoundsRule;

   procedure PrintSizeReplacementRule (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from * &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
      LexValue : LexTokenManager.Lex_String;
   begin
      -- convert value from Maths.Value to LexTokenManager.LexString
      LexValue := Dictionary.TypeSizeAttribute (Sym);
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__size may_be_replaced_by ", 0);

      E_Strings.Put_String (File  => Rule_File,
                            E_Str => Maths.ValueToString (Maths.ValueRep (LexValue)));
      End_A_Rule (Rule_File => Rule_File);
   end PrintSizeReplacementRule;

   procedure PrintEnumerationRules (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                Sym &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
      It                        : Dictionary.Iterator;
      PositionNumber            : Natural;
      LastLiteral, FirstLiteral : Dictionary.Symbol;

   begin --PrintEnumerationRules
         -- t__pos(t__first) may_be_replaced_by 0 .
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__first)", 0);
      SPARK_IO.Put_String (Rule_File, " may_be_replaced_by 0", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- pos and val rules for literals
      PositionNumber := 0;
      It             := Dictionary.FirstEnumerationLiteral (Sym);
      FirstLiteral   := Dictionary.CurrentSymbol (It);
      loop
         -- t__pos("a literal") may_be_replaced_by "its position number" .
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__pos(", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.CurrentSymbol (It));
         SPARK_IO.Put_String (Rule_File, ") may_be_replaced_by ", 0);
         SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
         End_A_Rule (Rule_File => Rule_File);

         -- t__val("a position number") may_be_replaced_by  "its associated literal".
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__val(", 0);
         SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
         SPARK_IO.Put_String (Rule_File, ") may_be_replaced_by ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.CurrentSymbol (It));
         End_A_Rule (Rule_File => Rule_File);

         -- keep copy of the last literal before exiting the loop
         LastLiteral := Dictionary.CurrentSymbol (It);

         It := Dictionary.NextSymbol (It);
         exit when Dictionary.IsNullIterator (It);

         PositionNumber := PositionNumber + 1;
      end loop;
      -- on exit, PositionNumber holds the highest position nunber of the type and
      --          LastLiteral holds the symbols of the last literal

      -- t__pos(t__last) may_be_replaced_by "the right value" .
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__last)", 0);
      SPARK_IO.Put_String (Rule_File, " may_be_replaced_by ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      End_A_Rule (Rule_File => Rule_File);

      -- t__pos(succ(X)) may_be_replaced_by t__pos(X) + 1 if ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(succ(X)) may_be_replaced_by ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__pos(X) + 1", 0);
      SPARK_IO.Put_String (Rule_File, "     if [X <=", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, ", X <> ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- t__pos(pred(X)) may_be_replaced_by t__pos(X) - 1 if ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(pred(X)) may_be_replaced_by ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__pos(X) - 1", 0);
      SPARK_IO.Put_String (Rule_File, "     if [X >=", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, ", X <> ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- colour__pos(X) >= 0 may_be_deduced ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__pos(X) >= 0 may_be_deduced_from", 0);
      SPARK_IO.Put_String (Rule_File, "     [", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, " <= X, X <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- colour__pos(X) <= ? may_be_deduced ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(X) <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_Line (Rule_File, " may_be_deduced_from", 0);
      SPARK_IO.Put_String (Rule_File, "     [", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, " <= X, X <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- colour__val(X) >= first literal may_be_deduced ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(X) >= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_Line (Rule_File, " may_be_deduced_from", 0);
      SPARK_IO.Put_String (Rule_File, "     [0 <= X, X <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- colour__val(X) <= last literal may_be_deduced ...
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(X) <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_Line (Rule_File, " may_be_deduced_from", 0);
      SPARK_IO.Put_String (Rule_File, "     [0 <= X, X <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- succ(colour__val(X)) may_be_replace_by colour__val(X+1) if ...
      Print_Rule_Name (Rule_File => Rule_File);
      SPARK_IO.Put_String (Rule_File, "succ(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(X)) may_be_replaced_by ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__val(X+1)", 0);
      SPARK_IO.Put_String (Rule_File, "     if [0 <= X, X < ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- pred(colour__val(X)) may_be_replace_by colour__val(X-1) if ...
      Print_Rule_Name (Rule_File => Rule_File);
      SPARK_IO.Put_String (Rule_File, "pred(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(X)) may_be_replaced_by ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__val(X-1)", 0);
      SPARK_IO.Put_String (Rule_File, "     if [0 < X, X <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- Pos to Val reciprocity
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__val(X)) may_be_replaced_by X", 0);
      SPARK_IO.Put_String (Rule_File, "     if [0 <= X, X <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- Val to pos reciprocity
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__pos(X)) may_be_replaced_by X", 0);
      SPARK_IO.Put_String (Rule_File, "     if [", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, " <= X, X <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      -- Ordering equivalence (suggested by Phil Thornley, BAe)
      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__pos(X) <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__pos(Y) & X <= Y are_interchangeable ", 0);
      SPARK_IO.Put_String (Rule_File, "     if [", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, " <= X, X <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, ", ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => FirstLiteral);
      SPARK_IO.Put_String (Rule_File, " <= Y, Y <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => LastLiteral);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

      Print_Rule_Name (Rule_File => Rule_File);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_String (Rule_File, "__val(X) <= ", 0);
      Print_Symbol (File  => Rule_File,
                    Scope => Scope,
                    Sym   => Sym);
      SPARK_IO.Put_Line (Rule_File, "__val(Y) & X <= Y are_interchangeable ", 0);
      SPARK_IO.Put_String (Rule_File, "     if [0 <= X, X <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, ", 0 <= Y, Y <= ", 0);
      SPARK_IO.Put_Integer (Rule_File, PositionNumber, 0, 10);
      SPARK_IO.Put_String (Rule_File, "]", 0);
      End_A_Rule (Rule_File => Rule_File);

   end PrintEnumerationRules;

   procedure PrintConstraintRules (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                Sym &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
   begin
      -- If the implcitly-declared constraint is associated with a formal parameter
      -- of type String then we know its lower bound must be 1 (SPARK95.doc (section 3.6.3))
      --
      -- NOTE here - a special case is needed here, since String is the only
      -- array type in SPARK that allows a null-range literal "".
      -- Where "" is passed as an actual parameter, we have the anomaly that
      -- S'First = 1 and S'Last = 0, so we need special rules here.
      if Dictionary.IsPredefinedStringType
        (Dictionary.GetType (Dictionary.GetParameterAssociatedWithParameterConstraint (Sym))) then

         -- S'First = 1
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__first may_be_replaced_by 1", 0);
         End_A_Rule (Rule_File => Rule_File);

         -- S'Last <= Positive'Last
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__last <= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.GetType (Sym));
         SPARK_IO.Put_String (Rule_File, "__last may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

         -- S'Last >= 0  -- NOT S'Last >= Positive'First - see above
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__last >= 0 may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

      else
         -- For formal array parameters that aren't String...
         --
         -- Subprogram constraint symbols are symbols representing the indexes of unconstrained
         -- objects as they are constrained by something at some point.  We typically do not know the
         -- actual bounds but we do know that the anonymous subtype represented by the symbol must
         -- at least fit within the type of the matching index of the unconstrained type declaration.
         -- i.e. for type A is array (Integer range <>) of T; and formal parameter X of type A then
         -- we will have a subprogram constraint symbol x__index_subtype__1 and we know that
         -- x__index_subtype__1__first >= integer__first and x__index_subtype__1__last <= integer__last

         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__first >= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.GetType (Sym));
         SPARK_IO.Put_String (Rule_File, "__first may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__last <= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.GetType (Sym));
         SPARK_IO.Put_String (Rule_File, "__last may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

         -- and, as free bonus
         PrintLowerLessThanUpperRule (Sym, False);

         -- and by transitivity
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__last >= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.GetType (Sym));
         SPARK_IO.Put_String (Rule_File, "__first may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, "__first <= ", 0);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Dictionary.GetType (Sym));
         SPARK_IO.Put_String (Rule_File, "__last may_be_deduced", 0);
         End_A_Rule (Rule_File => Rule_File);

      end if;
   end PrintConstraintRules;

   procedure PrintRecordEqualityRule (Sym : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                Sym &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
      ComponentIt : Dictionary.Iterator;
   begin
      if Dictionary.RecordHasSomeFields (Sym) then
         Print_Rule_Name (Rule_File => Rule_File);
         SPARK_IO.Put_String (Rule_File, "A = B may_be_deduced_from", 0);
         SPARK_IO.New_Line (Rule_File, 1);
         SPARK_IO.Put_String (Rule_File, "     [goal(checktype(A,", 0);
         Print_Symbol_No_Wrap (File  => Rule_File,
                               Scope => Scope,
                               Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, ")),", 0);
         SPARK_IO.New_Line (Rule_File, 1);
         SPARK_IO.Put_String (Rule_File, "      goal(checktype(B,", 0);
         Print_Symbol_No_Wrap (File  => Rule_File,
                               Scope => Scope,
                               Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, ")),", 0);
         SPARK_IO.New_Line (Rule_File, 1);
         if Dictionary.IsPrivateType (Sym, Scope) then
            SPARK_IO.Put_String (Rule_File, "      fld_inherit(A) = fld_inherit(B)]", 0);
         else
            ComponentIt := Dictionary.FirstRecordComponent (Sym);
            -- If all ancestors of an extended record are null records then we don't want
            -- a declaration of an Inherit field referencing first of them.
            if Dictionary.TypeIsExtendedTagged (Sym) and then Dictionary.NoFieldsBelowThisRecord (Sym) then
               --skip inherit field
               ComponentIt := Dictionary.NextSymbol (ComponentIt);
            end if;
            while not Dictionary.IsNullIterator (ComponentIt) loop
               SPARK_IO.Put_String (Rule_File, "      fld_", 0);
               Print_Symbol_No_Wrap (File  => Rule_File,
                                     Scope => Scope,
                                     Sym   => Dictionary.CurrentSymbol (ComponentIt));
               SPARK_IO.Put_String (Rule_File, "(A) = fld_", 0);
               Print_Symbol_No_Wrap (File  => Rule_File,
                                     Scope => Scope,
                                     Sym   => Dictionary.CurrentSymbol (ComponentIt));
               SPARK_IO.Put_String (Rule_File, "(B)", 0);
               ComponentIt := Dictionary.NextSymbol (ComponentIt);
               exit when Dictionary.IsNullIterator (ComponentIt);
               SPARK_IO.Put_String (Rule_File, ",", 0);
               SPARK_IO.New_Line (Rule_File, 1);
            end loop;
            SPARK_IO.Put_String (Rule_File, "]", 0);
         end if;

         End_A_Rule (Rule_File => Rule_File);
      end if;
   end PrintRecordEqualityRule;

begin --PrintTypeRules
   if Write_Rules then
      loop
         --# accept Flow, 10, Ok, "Expected ineffective assignment to Ok";
         Lists.Get_First (Heap     => L_Heap,
                          The_List => Type_List,
                          Symbol   => Sym,
                          Empty    => Empty,
                          Ok       => Ok);
         --# end accept;

         exit when Empty;
         -- Debug.PrintSym ("PrintTypeRule for ", Sym);

         if Dictionary.IsTypeMark (Sym) then

            PrintSizeBoundsRule (Sym);
            if LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Dictionary.TypeSizeAttribute (Sym),
               Lex_Str2 => LexTokenManager.Null_String) /=
              LexTokenManager.Str_Eq then
               PrintSizeReplacementRule (Sym);
            end if;

            if Dictionary.TypeIsGeneric (Sym) then
               if Dictionary.TypeIsScalar (Sym) then
                  -- Just output a lower <= upper may_be_deduced rule
                  -- TBD unsure whether we can have WithBase => True here PNA 15/12/05
                  PrintLowerLessThanUpperRule (Sym      => Sym,
                                               WithBase => False);
               end if;
               -- non-scalar generic types get no rules at all
            elsif Dictionary.IsPrivateType (Sym, Scope) then
               -- If the view of the type is private from this Scope, then no rules
               null;
            else
               if Dictionary.TypeIsScalar (Sym) then

                  PrintBounds (WithBase => False);

                  PrintBounds (WithBase => True);
                  if Dictionary.TypeIsModular (Sym) then
                     PrintModulus (Sym);
                  end if;

                  if Dictionary.TypeIsEnumeration (Sym)
                    and then Dictionary.Types_Are_Equal
                    (Left_Symbol        => Dictionary.GetRootType (Sym),
                     Right_Symbol       => Sym,
                     Full_Range_Subtype => False)
                    and then not Dictionary.IsPredefinedCharacterType (Sym) then
                     PrintEnumerationRules (Sym);
                  end if;
               elsif Dictionary.TypeIsRecord (Sym) and then not Dictionary.IsSubtype (Sym) then
                  -- If Sym denotes some sort of record then print an inference
                  -- rule for "=". Don't do this for full-range record subtypes
                  -- (the only record subtypes allowed in SPARK) because:
                  -- a. they always appear as the root type in FDL so no need
                  --    for rules about the subtype;
                  -- b. if we did allow rules to be printed for subtypes here
                  --    we would need to modify PrintRecordEqualityRule to deal
                  --    with them correctly.
                  PrintRecordEqualityRule (Sym);
               end if;
            end if;
         elsif Dictionary.IsParameterConstraint (Sym) then
            PrintConstraintRules (Sym);
         end if;
      end loop;
   end if;
   --# accept Flow, 33, Ok, "Expected Ok to be neither referenced nor exported";
end PrintTypeRules;
