-------------------------------------------------------------------------------
-- (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 (SparkLex.Lex)
procedure NextLex (Curr_Line : in out Line_Context;
                   Token     :    out SP_Symbols.SP_Terminal)
-- The Ada Lexis allows the class of a token to be determined by the
-- first character in the text string representing it. Given the first
-- character of the string representing the token is at the current position
-- in the line buffer, CurrLine, NextLex determines the class of the token and
-- directly recognises the token or calls a procedure to recognise that class
-- of token.
-- On exit Token is set to a value representing the token and the line buffer
-- position is updated.
is
begin

   LineManager.Record_Curr_Pos (Curr_Line => Curr_Line);

   case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                               Pos   => Curr_Line.Curr_Pos) is
      when 'a' .. 'z' | 'A' .. 'Z' | '$' =>      -- letter or '$'

         --  In Ada and SPARK, identifiers may not start with a '$'
         --  character, but these are used by GNATPREP to introduce
         --  symbols that might be replaced, and we do want
         --  SPARKFormat to be able to process these successfully in
         --  annotations.  We therefore allow '$' to introduce an
         --  identififier here.  Rejecting the illegal case (in the
         --  Examiner) is performed in SPARKLex.Lex
         GetIdent (Curr_Line => Curr_Line,
                   Token     => Token);
      when '0' .. '9' =>               -- digit
         GetNumber (Curr_Line => Curr_Line,
                    Token     => Token);
      when '-' =>                      -- minus, comment or annotation_start
         HyphIntro (Curr_Line => Curr_Line,
                    Token     => Token);
      when '"' =>                      -- string
         GetString (Curr_Line => Curr_Line,
                    Token     => Token);
      when ''' =>                      -- apostrope or character literal
         ApostIntro (Curr_Line => Curr_Line,
                     Token     => Token);
      when '<' =>                      -- < << <->
         LTIntro (Curr_Line => Curr_Line,
                  Token     => Token);
      when '=' =>                      -- check for compound delimiters
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '>' =>
               Token := SP_Symbols.arrow;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.equals;
         end case;
      when '.' =>                      -- point or double_dot
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '.' =>
               Token := SP_Symbols.double_dot;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.point;
         end case;
      when '*' =>
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '*' =>
               Token := SP_Symbols.double_star;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.multiply;
         end case;
      when ':' =>
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '=' =>
               Token := SP_Symbols.becomes;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.colon;
         end case;
      when '/' =>
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '=' =>
               Token := SP_Symbols.not_equal;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.divide;
         end case;
      when '>' =>
         LineManager.Accept_Char (Curr_Line => Curr_Line);
         case E_Strings.Get_Element (E_Str => Curr_Line.Conts,
                                     Pos   => Curr_Line.Curr_Pos) is
            when '=' =>
               Token := SP_Symbols.greater_or_equal;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when '>' =>
               Token := SP_Symbols.right_label_paren;
               LineManager.Accept_Char (Curr_Line => Curr_Line);
            when others =>
               Token := SP_Symbols.greater_than;
         end case;
      when '&' =>                      -- simple delimiters
         Token := SP_Symbols.ampersand;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '(' =>
         Token := SP_Symbols.left_paren;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when ')' =>
         Token := SP_Symbols.right_paren;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '+' =>
         Token := SP_Symbols.plus;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when ',' =>
         Token := SP_Symbols.comma;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when ';' =>
         Token := SP_Symbols.semicolon;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '|' =>
         Token := SP_Symbols.vertical_bar;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '[' =>
         Token := SP_Symbols.square_open;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when ']' =>
         Token := SP_Symbols.square_close;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '~' =>
         Token := SP_Symbols.tilde;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when '%' =>
         Token := SP_Symbols.percent;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
      when End_Of_Text =>
         Token := SP_Symbols.SPEND;
      when others =>
         Token := SP_Symbols.illegal_token;
         LineManager.Accept_Char (Curr_Line => Curr_Line);
   end case;

end NextLex;
