------------------------------------------------------------------------------
-- Copyright (c) 2013-2014, Natacha Porté                                   --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

package body Natools.S_Expressions.Printers.Pretty.Config is

   procedure Read_Screen_Offset
     (Expression : in out Lockable.Descriptor'Class;
      Value : in out Screen_Offset;
      Has_Value : out Boolean);
      --  Decode a screen offset from a S-expression

   procedure Update_Casing
     (Casing : in out Encodings.Hex_Casing;
      Name : in Atom);

   function To_Atom (Value : in Screen_Offset) return Atom;
   function To_Atom (Before, After : in Entity) return Atom;

   function To_String (Value : in Entity) return String;



   ------------------------------
   -- Local Helper Subprograms --
   ------------------------------

   procedure Read_Screen_Offset
     (Expression : in out Lockable.Descriptor'Class;
      Value : in out Screen_Offset;
      Has_Value : out Boolean)
   is
      Result : Screen_Offset := 0;
   begin
      Has_Value := False;

      if Expression.Current_Event /= Events.Add_Atom then
         return;
      end if;

      declare
         Data : constant Atom := Expression.Current_Atom;
      begin
         if Data'Length = 0 then
            return;
         end if;

         for I in Data'Range loop
            if Data (I) in Encodings.Digit_0 .. Encodings.Digit_9 then
               Result := Result * 10
                 + Screen_Offset (Data (I) - Encodings.Digit_0);
            else
               return;
            end if;
         end loop;

         Has_Value := True;
         Value := Result;
      end;
   end Read_Screen_Offset;


   function To_Atom (Value : in Screen_Offset) return Atom is
      Length : Count;
   begin
      Compute_Length : declare
         Left : Screen_Offset := Value;
      begin
         Length := 1;
         while Left >= 10 loop
            Length := Length + 1;
            Left := Left / 10;
         end loop;
      end Compute_Length;

      return Result : Atom (0 .. Length - 1) do
         declare
            I : Offset := Result'Last;
            Left : Screen_Offset := Value;
         begin
            loop
               Result (I) := Encodings.Digit_0 + Octet (Left mod 10);
               I := I - 1;
               Left := Left / 10;
               exit when Left = 0;
            end loop;
            pragma Assert (I + 1 = Result'First);
         end;
      end return;
   end To_Atom;


   function To_Atom (Before, After : in Entity) return Atom is
   begin
      return To_Atom (To_String (Before) & "-" & To_String (After));
   end To_Atom;


   function To_String (Value : in Entity) return String is
   begin
      case Value is
         when Opening => return "open";
         when Atom_Data => return "atom";
         when Closing => return "close";
      end case;
   end To_String;


   procedure Update_Casing
     (Casing : in out Encodings.Hex_Casing;
      Name : in Atom) is
   begin
      if Name'Length > 5 then
         declare
            Prefix : constant String
              := To_String (Name (Name'First .. Name'First + 4));
         begin
            if Prefix = "upper" then
               Casing := Encodings.Upper;
            elsif Prefix = "lower" then
               Casing := Encodings.Lower;
            end if;
         end;
      end if;
   end Update_Casing;



   ---------------------------------
   -- Public High Level Interface --
   ---------------------------------

   procedure Print
     (Output : in out Printers.Printer'Class;
      Param : in Parameters) is
   begin
      --  Newline_At and Newline

      Output.Open_List;
      Output.Append_Atom (To_Atom ("newline"));
      case Param.Newline is
         when CR =>    Output.Append_Atom (To_Atom ("cr"));
         when LF =>    Output.Append_Atom (To_Atom ("lf"));
         when CR_LF => Output.Append_Atom (To_Atom ("cr-lf"));
         when LF_CR => Output.Append_Atom (To_Atom ("lf-cr"));
      end case;

      if Param.Newline_At = Entity_Separator'(others => (others => True)) then
         Output.Append_Atom (To_Atom ("all"));
      else
         Output.Append_Atom (To_Atom ("none"));
         for Before in Entity loop
            for After in Entity loop
               if Param.Newline_At (Before, After) then
                  Output.Append_Atom (To_Atom (Before, After));
               end if;
            end loop;
         end loop;
      end if;
      Output.Close_List;

      --  Space_At

      Output.Open_List;
      Output.Append_Atom (To_Atom ("space"));
      if Param.Space_At = Entity_Separator'(others => (others => True)) then
         Output.Append_Atom (To_Atom ("all"));
      else
         Output.Append_Atom (To_Atom ("none"));
         for Before in Entity loop
            for After in Entity loop
               if Param.Space_At (Before, After) then
                  Output.Append_Atom (To_Atom (Before, After));
               end if;
            end loop;
         end loop;
      end if;
      Output.Close_List;

      --  Tab_Stop

      Output.Open_List;
      Output.Append_Atom (To_Atom ("tab-stop"));
      Output.Append_Atom (To_Atom (Param.Tab_Stop));
      Output.Close_List;

      --  Width

      if Param.Width > 0 then
         Output.Open_List;
         Output.Append_Atom (To_Atom ("width"));
         Output.Append_Atom (To_Atom (Param.Width));
         Output.Close_List;
      else
         Output.Append_Atom (To_Atom ("no-width"));
      end if;

      --  Indentation and Indent

      if Param.Indentation = 0 then
         Output.Append_Atom (To_Atom ("no-indentation"));
      else
         Output.Open_List;
         Output.Append_Atom (To_Atom ("indentation"));
         Output.Append_Atom (To_Atom (Param.Indentation));
         if Param.Indentation > 1 then
            case Param.Indent is
               when Spaces =>
                  Output.Append_Atom (To_Atom ("spaces"));
               when Tabs =>
                  Output.Append_Atom (To_Atom ("tabs"));
               when Tabs_And_Spaces =>
                  Output.Append_Atom (To_Atom ("tabbed-spaces"));
            end case;
         else
            case Param.Indent is
               when Spaces =>
                  Output.Append_Atom (To_Atom ("space"));
               when Tabs =>
                  Output.Append_Atom (To_Atom ("tab"));
               when Tabs_And_Spaces =>
                  Output.Append_Atom (To_Atom ("tabbed-space"));
            end case;
         end if;
         Output.Close_List;
      end if;

      --  Quoted

      case Param.Quoted is
         when No_Quoted    =>
            Output.Append_Atom (To_Atom ("no-quoted-string"));
         when Single_Line  =>
            Output.Append_Atom (To_Atom ("single-line-quoted-string"));
         when When_Shorter =>
            Output.Append_Atom (To_Atom ("quoted-string-when-shorter"));
      end case;

      --  Quoted_Escape

      Output.Open_List;
      Output.Append_Atom (To_Atom ("escape"));
      case Param.Quoted_Escape is
         when Octal_Escape => Output.Append_Atom (To_Atom ("octal"));
         when Hex_Escape   => Output.Append_Atom (To_Atom ("hexadecimal"));
      end case;
      Output.Close_List;

      --  Token

      Output.Open_List;
      Output.Append_Atom (To_Atom ("token"));
      case Param.Token is
         when No_Token       => Output.Append_Atom (To_Atom ("never"));
         when Extended_Token => Output.Append_Atom (To_Atom ("extended"));
         when Standard_Token => Output.Append_Atom (To_Atom ("standard"));
      end case;
      Output.Close_List;

      --  Char_Encoding

      case Param.Char_Encoding is
         when UTF_8 => Output.Append_Atom (To_Atom ("utf-8"));
         when ASCII => Output.Append_Atom (To_Atom ("ascii"));
         when Latin => Output.Append_Atom (To_Atom ("latin-1"));
      end case;

      --  Hex_Casing

      case Param.Hex_Casing is
         when Encodings.Upper => Output.Append_Atom (To_Atom ("upper-case"));
         when Encodings.Lower => Output.Append_Atom (To_Atom ("lower-case"));
      end case;

      --  Fallback

      case Param.Fallback is
         when Base64      => Output.Append_Atom (To_Atom ("base-64"));
         when Hexadecimal => Output.Append_Atom (To_Atom ("hexadecimal"));
         when Verbatim    => Output.Append_Atom (To_Atom ("verbatim"));
      end case;
   end Print;


   procedure Update
     (Param : in out Parameters;
      Expression : in out Lockable.Descriptor'Class)
   is
      Interpreter : constant Interpreters.Interpreter := Config_Interpreter;
   begin
      Update (Interpreter, Param, Expression);
   end Update;


   procedure Update
     (Interpreter : in Interpreters.Interpreter;
      Param : in out Parameters;
      Expression : in out Lockable.Descriptor'Class) is
   begin
      Interpreter.Execute (Expression, Param, True);
   end Update;



   ------------------------------
   -- Interpreter Constructors --
   ------------------------------

   function Config_Interpreter return Interpreters.Interpreter is
      Quoted_SI, Newline_SI, Space_SI, Result : Interpreters.Interpreter;
   begin
      --  Setup subinterpreters
      Add_Separator_Commands (Newline_SI, True, True);
      Add_Newline_Encoding_Commands (Newline_SI);
      Add_Quoted_Commands (Quoted_SI);
      Add_Quoted_Escape_Commands (Quoted_SI);
      Add_Separator_Commands (Space_SI, True, False);

      --  Build final interpreter
      Result.Add_Command (To_Atom ("escape"),
                          Set_Quoted_String'(Subinterpreter => Quoted_SI));
      Result.Add_Command (To_Atom ("indent"), Set_Indentation'(null record));
      Result.Add_Command (To_Atom ("indentation"),
                          Set_Indentation'(null record));
      Result.Add_Command (To_Atom ("no-indent"),
                          Set_Indentation'(null record));
      Result.Add_Command (To_Atom ("no-indentation"),
                          Set_Indentation'(null record));
      Result.Add_Command (To_Atom ("newline"),
                          Set_Newline'(Subinterpreter => Newline_SI));
      Result.Add_Command (To_Atom ("quoted"),
                          Set_Quoted_String'(Subinterpreter => Quoted_SI));
      Result.Add_Command (To_Atom ("space"),
                          Set_Space_At'(Subinterpreter => Space_SI));
      Result.Add_Command (To_Atom ("tab-stop"), Set_Tab_Stop'(null record));
      Result.Add_Command (To_Atom ("width"), Set_Width'(null record));
      Result.Add_Command (To_Atom ("no-width"), Set_Width'(null record));

      Result.Add_Command (To_Atom ("extended-token"),
                          Set_Token'(Value => Extended_Token));
      Result.Add_Command (To_Atom ("no-token"),
                          Set_Token'(Value => No_Token));
      Result.Add_Command (To_Atom ("standard-token"),
                          Set_Token'(Value => Standard_Token));
      Result.Add_Command (To_Atom ("token"),
                          Set_Token'(Value => Standard_Token));

      Result.Add_Command (To_Atom ("no-quoted"),
                          Set_Quoted'(Value => No_Quoted));
      Result.Add_Command (To_Atom ("no-quoted-string"),
                          Set_Quoted'(Value => No_Quoted));
      Result.Add_Command (To_Atom ("quoted-when-shorter"),
                          Set_Quoted'(Value => When_Shorter));
      Result.Add_Command (To_Atom ("quoted-string-when-shorter"),
                          Set_Quoted'(Value => When_Shorter));
      Result.Add_Command (To_Atom ("single-line-quoted"),
                          Set_Quoted'(Value => Single_Line));
      Result.Add_Command (To_Atom ("single-line-quoted-string"),
                          Set_Quoted'(Value => Single_Line));

      Result.Add_Command (To_Atom ("base64"),
                          Set_Fallback'(Value => Base64));
      Result.Add_Command (To_Atom ("base-64"),
                          Set_Fallback'(Value => Base64));
      Result.Add_Command (To_Atom ("lower-hex"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("lower-hexa"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("hex"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("hexa"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("hexadecimal"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("upper-hex"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("upper-hexa"),
                          Set_Fallback'(Value => Hexadecimal));
      Result.Add_Command (To_Atom ("verbatim"),
                          Set_Fallback'(Value => Verbatim));

      Add_Char_Encoding_Commands (Result);
      Add_Hex_Casing_Commands (Result);
      Add_Newline_Encoding_Commands (Result);
      return Result;
   end Config_Interpreter;


   procedure Add_Char_Encoding_Commands
     (Interpreter : in out Interpreters.Interpreter) is
   begin
      Interpreter.Add_Command (To_Atom ("utf-8"),
                               Set_Char_Encoding'(Value => UTF_8));
      Interpreter.Add_Command (To_Atom ("UTF-8"),
                               Set_Char_Encoding'(Value => UTF_8));
      Interpreter.Add_Command (To_Atom ("utf8"),
                               Set_Char_Encoding'(Value => UTF_8));
      Interpreter.Add_Command (To_Atom ("UTF8"),
                               Set_Char_Encoding'(Value => UTF_8));
      Interpreter.Add_Command (To_Atom ("ascii"),
                               Set_Char_Encoding'(Value => ASCII));
      Interpreter.Add_Command (To_Atom ("ASCII"),
                               Set_Char_Encoding'(Value => ASCII));
      Interpreter.Add_Command (To_Atom ("latin-1"),
                               Set_Char_Encoding'(Value => Latin));
      Interpreter.Add_Command (To_Atom ("latin"),
                               Set_Char_Encoding'(Value => Latin));
      Interpreter.Add_Command (To_Atom ("iso-8859-1"),
                               Set_Char_Encoding'(Value => Latin));
      Interpreter.Add_Command (To_Atom ("ISO-8859-1"),
                               Set_Char_Encoding'(Value => Latin));
   end Add_Char_Encoding_Commands;


   procedure Add_Hex_Casing_Commands
     (Interpreter : in out Interpreters.Interpreter) is
   begin
      Interpreter.Add_Command (To_Atom ("upper"),
                               Set_Hex_Casing'(Value => Encodings.Upper));
      Interpreter.Add_Command (To_Atom ("upper-case"),
                               Set_Hex_Casing'(Value => Encodings.Upper));
      Interpreter.Add_Command (To_Atom ("lower"),
                               Set_Hex_Casing'(Value => Encodings.Lower));
      Interpreter.Add_Command (To_Atom ("lower-case"),
                               Set_Hex_Casing'(Value => Encodings.Lower));
   end Add_Hex_Casing_Commands;


   procedure Add_Quoted_Commands
     (Interpreter : in out Interpreters.Interpreter) is
   begin
      Interpreter.Add_Command (To_Atom ("never"),
                               Set_Quoted'(Value => No_Quoted));
      Interpreter.Add_Command (To_Atom ("single-line"),
                               Set_Quoted'(Value => Single_Line));
      Interpreter.Add_Command (To_Atom ("when-shorter"),
                               Set_Quoted'(Value => When_Shorter));
   end Add_Quoted_Commands;


   procedure Add_Quoted_Escape_Commands
     (Interpreter : in out Interpreters.Interpreter) is
   begin
      Interpreter.Add_Command (To_Atom ("octal"),
                               Set_Quoted_Escape'(Value => Octal_Escape));
      Interpreter.Add_Command (To_Atom ("hex"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("hexa"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("hexadecimal"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("lower-hex"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("lower-hexa"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("upper-hex"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Interpreter.Add_Command (To_Atom ("upper-hexa"),
                               Set_Quoted_Escape'(Value => Hex_Escape));
      Add_Hex_Casing_Commands (Interpreter);
   end Add_Quoted_Escape_Commands;


   procedure Add_Newline_Encoding_Commands
     (Interpreter : in out Interpreters.Interpreter) is
   begin
      Interpreter.Add_Command (To_Atom ("cr"),
                               Set_Newline_Encoding'(Value => CR));
      Interpreter.Add_Command (To_Atom ("CR"),
                               Set_Newline_Encoding'(Value => CR));
      Interpreter.Add_Command (To_Atom ("lf"),
                               Set_Newline_Encoding'(Value => LF));
      Interpreter.Add_Command (To_Atom ("LF"),
                               Set_Newline_Encoding'(Value => LF));
      Interpreter.Add_Command (To_Atom ("CRLF"),
                               Set_Newline_Encoding'(Value => CR_LF));
      Interpreter.Add_Command (To_Atom ("CR-LF"),
                               Set_Newline_Encoding'(Value => CR_LF));
      Interpreter.Add_Command (To_Atom ("crlf"),
                               Set_Newline_Encoding'(Value => CR_LF));
      Interpreter.Add_Command (To_Atom ("cr-lf"),
                               Set_Newline_Encoding'(Value => CR_LF));
      Interpreter.Add_Command (To_Atom ("lf-cr"),
                               Set_Newline_Encoding'(Value => LF_CR));
      Interpreter.Add_Command (To_Atom ("lfcr"),
                               Set_Newline_Encoding'(Value => LF_CR));
      Interpreter.Add_Command (To_Atom ("LF-CR"),
                               Set_Newline_Encoding'(Value => LF_CR));
      Interpreter.Add_Command (To_Atom ("LFCR"),
                               Set_Newline_Encoding'(Value => LF_CR));
   end Add_Newline_Encoding_Commands;


   procedure Add_Separator_Commands
     (Interpreter : in out Interpreters.Interpreter;
      Value : in Boolean;
      Newline : in Boolean) is
   begin
      for Before in Entity loop
         for After in Entity loop
            Interpreter.Add_Command
              (To_Atom (Before, After),
               Set_Separator'(Before, After, Value, Newline));
         end loop;
      end loop;

      Interpreter.Add_Command
        (To_Atom ("all"),
         Set_All_Separators'(Value, Newline));
      Interpreter.Add_Command
        (To_Atom ("none"),
         Set_All_Separators'(not Value, Newline));
      Interpreter.Add_Command
        (To_Atom ("not"),
         Set_All_Separators'(not Value, Newline));
   end Add_Separator_Commands;



   -------------------------
   -- Invididual Commands --
   -------------------------

   procedure Execute
     (Self : in Set_Width;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Self, Context, Name);
   begin
      State.Width := 0;
   end Execute;


   procedure Execute
     (Self : in Set_Width;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self, Context);
      Has_Value : Boolean;
   begin
      Cmd.Next;
      Read_Screen_Offset (Cmd, State.Width, Has_Value);
   end Execute;


   procedure Execute
     (Self : in Set_Tab_Stop;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self, Context);
      Value : Screen_Offset := 0;
      Has_Value : Boolean;
   begin
      Cmd.Next;
      Read_Screen_Offset (Cmd, Value, Has_Value);
      if Has_Value and then Value /= 0 then
         State.Tab_Stop := Value;
      end if;
   end Execute;


   procedure Execute
     (Self : in Set_Indentation;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Self, Context, Name);
   begin
      State.Indentation := 0;
   end Execute;


   procedure Execute
     (Self : in Set_Indentation;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self, Context);
      Has_Value : Boolean;
      Event : Events.Event;
   begin
      Cmd.Next (Event);
      Read_Screen_Offset (Cmd, State.Indentation, Has_Value);

      if Has_Value and State.Indentation /= 0 then
         Cmd.Next (Event);
         if Event = Events.Add_Atom then
            declare
               Keyword : constant String := To_String (Cmd.Current_Atom);
            begin
               if Keyword = "tab" or Keyword = "tabs" then
                  State.Indent := Tabs;
               elsif Keyword = "space" or Keyword = "spaces" then
                  State.Indent := Spaces;
               elsif Keyword = "tabbed-space" or Keyword = "tabbed-spaces" then
                  State.Indent := Tabs_And_Spaces;
               end if;
            end;
         end if;
      end if;
   end Execute;


   procedure Execute
     (Self : in Set_Newline;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class) is
   begin
      pragma Assert (not Self.Subinterpreter.Is_Empty);
      Cmd.Next;
      Self.Subinterpreter.Execute (Cmd, State, Context);
   end Execute;


   procedure Execute
     (Self : in Set_Space_At;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class) is
   begin
      pragma Assert (not Self.Subinterpreter.Is_Empty);
      Cmd.Next;
      Self.Subinterpreter.Execute (Cmd, State, Context);
   end Execute;


   procedure Execute
     (Self : in Set_Char_Encoding;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      State.Char_Encoding := Self.Value;
   end Execute;


   procedure Execute
     (Self : in Set_Newline_Encoding;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      State.Newline := Self.Value;
   end Execute;


   procedure Execute
     (Self : in Set_Separator;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      if Self.Newline then
         State.Newline_At (Self.Before, Self.After) := Self.Value;
      else
         State.Space_At (Self.Before, Self.After) := Self.Value;
      end if;
   end Execute;


   procedure Execute
     (Self : in Set_All_Separators;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      if Self.Newline then
         State.Newline_At := (others => (others => Self.Value));
      else
         State.Space_At := (others => (others => Self.Value));
      end if;
   end Execute;


   procedure Execute
     (Self : in Set_All_Separators;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      Subinterpreter : Interpreters.Interpreter;
   begin
      Add_Separator_Commands (Subinterpreter, Self.Value, Self.Newline);
      Subinterpreter.Execute (Cmd, State, Context);
   end Execute;


   procedure Execute
     (Self : in Set_Hex_Casing;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      State.Hex_Casing := Self.Value;
   end Execute;


   procedure Execute
     (Self : in Set_Fallback;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context);
   begin
      State.Fallback := Self.Value;
      Update_Casing (State.Hex_Casing, Name);
   end Execute;


   procedure Execute
     (Self : in Set_Token;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      State.Token := Self.Value;
   end Execute;


   procedure Execute
     (Self : in Set_Token;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self, Context);
      Event : Events.Event;
   begin
      Cmd.Next (Event);
      if Event /= Events.Add_Atom then
         return;
      end if;

      declare
         Token : constant String := To_String (Cmd.Current_Atom);
      begin
         if Token = "standard" then
            State.Token := Standard_Token;
         elsif Token = "extended" then
            State.Token := Extended_Token;
         elsif Token = "never" or Token = "none" or Token = "no" then
            State.Token := No_Token;
         end if;
      end;
   end Execute;


   procedure Execute
     (Self : in Set_Quoted_Escape;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context);
   begin
      State.Quoted_Escape := Self.Value;
      Update_Casing (State.Hex_Casing, Name);
   end Execute;


   procedure Execute
     (Self : in Set_Quoted;
      State : in out Parameters;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Context, Name);
   begin
      State.Quoted := Self.Value;
   end Execute;


   procedure Execute
     (Self : in Set_Quoted_String;
      State : in out Parameters;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class) is
   begin
      pragma Assert (not Self.Subinterpreter.Is_Empty);
      Cmd.Next;
      Self.Subinterpreter.Execute (Cmd, State, Context);
   end Execute;

end Natools.S_Expressions.Printers.Pretty.Config;
