-------------------------------------------------------------------------------
-- (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 (Maths)
procedure LiteralToValue (Str : in     LexTokenManager.Lex_String;
                          Num :    out Value;
                          OK  :    out ErrorCode) is
   Decimal_Point_Found, Exponent_Found, Base_Found : Boolean;
   Base                                            : Natural;
   Core_String, Exp_String                         : E_Strings.T;
   Exp_Sign                                        : Character;
   Places_After_Point                              : E_Strings.Lengths;
   Legal_Syntax                                    : Boolean;
   Exponent                                        : Integer;
   Num_Local                                       : Value;
   OK_Local                                        : ErrorCode;

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

   procedure Make_Integer
   --# global in     Base;
   --#        in     Base_Found;
   --#        in     Core_String;
   --#        in     Exponent;
   --#        in     Exponent_Found;
   --#        in out Num_Local;
   --# derives Num_Local from *,
   --#                        Base,
   --#                        Base_Found,
   --#                        Core_String,
   --#                        Exponent,
   --#                        Exponent_Found;
   is
      Core_Local : E_Strings.T;

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

      procedure Pad_String_With_Zeros (Str : in out E_Strings.T;
                                       By  : in     Natural)
      --# derives Str from *,
      --#                  By;
      is
      begin
         for I in Integer range 1 .. By loop
            E_Strings.Append_Char (E_Str => Str,
                                   Ch    => '0');
         end loop;
      end Pad_String_With_Zeros;

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

   begin -- Make_Integer
      Num_Local.Sort := IntegerValue;
      Core_Local     := Core_String;
      if Exponent_Found then
         Pad_String_With_Zeros (Str => Core_Local,
                                By  => Exponent);
      end if;
      if Base_Found then
         Num_Local.Numerator := StripLeadingZeros (String_To_Part (Base => Base,
                                                                   Str  => Core_Local));
      else
         Num_Local.Numerator := StripLeadingZeros (Dec_String_To_Part (Str => Core_Local));
      end if;
   end Make_Integer;

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

   procedure Make_Real
   --# global in     Core_String;
   --#        in     Exponent;
   --#        in     Places_After_Point;
   --#        in out Num_Local;
   --# derives Num_Local from *,
   --#                        Core_String,
   --#                        Exponent,
   --#                        Places_After_Point;
   is
      Exp_Local          : Integer;
      Den_Part, Num_Part : Part;
   begin
      Exp_Local      := Exponent;
      Num_Local.Sort := RealValue;
      Num_Part       := Dec_String_To_Part (Str => Core_String);
      Den_Part       := OnePart;
      Exp_Local      := Exp_Local - Places_After_Point;
      if Exp_Local > 0 then
         for i in Integer range 1 .. Exp_Local loop
            Num_Part := ShiftUpPart (Num_Part);
         end loop;
      elsif Exp_Local < 0 then
         Exp_Local := -Exp_Local;
         for i in Integer range 1 .. Exp_Local loop
            Den_Part := ShiftUpPart (Den_Part);
         end loop;
         --else do nothing about exponent
      end if;
      Num_Local.Numerator   := Num_Part;
      Num_Local.Denominator := Den_Part;
      Normalize (Num_Local);
   end Make_Real;

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

begin -- LiteralToValue
   if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                           Lex_Str2 => LexTokenManager.Null_String) =
     LexTokenManager.Str_Eq then
      Num      := NoValue;
      OK_Local := NoError;
   else
      Num_Local := NoValue;  --must return something if error
      ParseString
        (LexTokenManager.Lex_String_To_String (Lex_Str => Str),
         Decimal_Point_Found,
         Exponent_Found,
         Base_Found,
         Base,
         Core_String,
         Exp_String,
         Exp_Sign,
         Places_After_Point,
         Legal_Syntax);

      if Legal_Syntax then
         OK_Local := NoError;
         Exponent := String_To_Natural (Str => Exp_String);
         if Exp_Sign = '-' then
            Exponent := -Exponent;
         end if;
         if Decimal_Point_Found then
            Make_Real;
         else
            Make_Integer;
         end if;
      else
         OK_Local := IllegalValue;
      end if;

      OK_Local := OverflowCheck (OK_Local, Num_Local);

      if OK_Local = NoError then
         Num := Num_Local;
      else
         Num := NoValue;
      end if;
   end if;
   OK := OK_Local;
end LiteralToValue;
