-------------------------------------------------------------------------------
-- (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 (Dictionary)
package body Dynamic_Symbol_Table
is
   procedure Initialize (The_Table : out T)
   is
      --# hide Initialize;
   begin
      The_Table := T'(Vec => ST_Vec.Empty_Vector);
   end Initialize;

   function Get_Current_Usage (The_Table : in T)
                              return Natural
   is
      --# hide Get_Current_Usage;
   begin
      return Natural (ST_Vec.Length (The_Table.Vec));
   end Get_Current_Usage;

   function Get_Info (The_Table : in T;
                      Item      : in Valid_Symbol)
                     return Symbol_Info
   is
      --# hide Get_Info;
   begin
      SystemErrors.RT_Assert (C       => Natural (Item) <= Get_Current_Usage (The_Table),
                              Sys_Err => SystemErrors.Invalid_Index,
                              Msg     => "Out of bounds access in Dictionary.Dynamic_Symbol_Table");
      return ST_Vec.Element (Container => The_Table.Vec,
                             Index     => Item);
   end Get_Info;

   procedure Set_Info (The_Table : in out T;
                       Item      : in     Valid_Symbol;
                       Info      : in     Symbol_Info)
   --# derives The_Table from *,
   --#                        Info,
   --#                        Item;
   is
      --# hide Set_Info;
   begin
      SystemErrors.RT_Assert (C       => Natural (Item) <= Get_Current_Usage (The_Table),
                              Sys_Err => SystemErrors.Invalid_Index,
                              Msg     => "Out of bounds access in Dictionary.Dynamic_Symbol_Table");
      ST_Vec.Replace_Element (Container => The_Table.Vec,
                              Index     => Item,
                              New_Item  => Info);
   end Set_Info;

   procedure Add_Symbol (The_Table    : in out T;
                         Discriminant : in     Dictionary.SymbolDiscriminant;
                         Ref          : in     Dictionary.Ref_Type;
                         Comp_Unit    : in     ContextManager.UnitDescriptors;
                         Loc          : in     LexTokenManager.Token_Position;
                         Item         :    out Dictionary.Symbol)
   is
      --# hide Add_Symbol;
   begin
      SystemErrors.RT_Assert (C       => Get_Current_Usage (The_Table) < Natural (Dictionary.Symbol'Last),
                              Sys_Err => SystemErrors.Symbol_Table_Overflow_Dynamic,
                              Msg     => "Too many symbols.");

      ST_Vec.Append (Container => The_Table.Vec,
                     New_Item  => Symbol_Info'(Discriminant => Discriminant,
                                               Ref          => Ref,
                                               Comp_Unit    => Comp_Unit,
                                               Loc          => Loc));

      Item := Dictionary.Symbol (Get_Current_Usage (The_Table));
   end Add_Symbol;

   function Get_Symbol_Discriminant (The_Table : in T;
                                     Item      : in Dictionary.Symbol)
                                    return Dictionary.SymbolDiscriminant
   is
      D : Dictionary.SymbolDiscriminant;
   begin
      if Item = Dictionary.NullSymbol then
         D := Dictionary.Null_Symbol;
      else
         D := Get_Info (The_Table, Item).Discriminant;
      end if;
      return D;
   end Get_Symbol_Discriminant;

   function Get_Symbol_Ref (The_Table : in T;
                            Item      : in Dictionary.Symbol)
                           return Dictionary.Ref_Type
   is
   begin
      SystemErrors.RT_Assert (C       => Item in Valid_Symbol,
                              Sys_Err => SystemErrors.Invalid_Index,
                              Msg     => "Out of bounds access in Dictionary.Dynamic_Symbol_Table");
      return Get_Info (The_Table, Item).Ref;
   end Get_Symbol_Ref;

   function Get_Symbol_Compilation_Unit (The_Table : in T;
                                         Item      : in Dictionary.Symbol)
                                        return ContextManager.UnitDescriptors
   is
      C : ContextManager.UnitDescriptors;
   begin
      if Item = Dictionary.NullSymbol then
         C := ContextManager.NullUnit;
      else
         C := Get_Info (The_Table, Item).Comp_Unit;
      end if;
      return C;
   end Get_Symbol_Compilation_Unit;

   function Get_Symbol_Location (The_Table : in T;
                                 Item      : in Dictionary.Symbol)
                                return LexTokenManager.Token_Position
   is
      L : LexTokenManager.Token_Position;
   begin
      if Item = Dictionary.NullSymbol then
         L := LexTokenManager.Null_Token_Position;
      else
         L := Get_Info (The_Table, Item).Loc;
      end if;
      return L;
   end Get_Symbol_Location;

   procedure Set_Symbol_Location (The_Table : in out T;
                                  Item      : in     Dictionary.Symbol;
                                  Location  : in     LexTokenManager.Token_Position)
   is
      Info : Symbol_Info;
   begin
      if Item /= Dictionary.NullSymbol then
         Info     := Get_Info (The_Table, Item);
         Info.Loc := Location;

         Set_Info (The_Table, Item, Info);
      end if;
   end Set_Symbol_Location;

end Dynamic_Symbol_Table;
