-------------------------------------------------------------------------------
-- (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 (Sem.Walk_Expression_P)
procedure Stack_Identifier
  (Sym           : in     Dictionary.Symbol;
   Id_Str        : in     LexTokenManager.Lex_String;
   Node          : in     STree.SyntaxNode;
   Prefix        : in     Dictionary.Symbol;
   Scope         : in     Dictionary.Scopes;
   E_Stack       : in out Exp_Stack.Exp_Stack_Type;
   The_Heap      : in out Heap.HeapRecord;
   Ref_Var       : in     SeqAlgebra.Seq;
   Dotted        : in     Boolean;
   Context       : in     Sem.Tilde_Context;
   Is_Annotation : in     Boolean)
is
   Result                : Sem.Exp_Record;
   Sym_Local             : Dictionary.Symbol;
   Tagged_Parameter_Type : Dictionary.Symbol;
   Loc                   : LexTokenManager.Token_Position;

   procedure Check_Globals_Are_Visible
     (Proc_Sym : in     Dictionary.Symbol;
      Loc      : in     LexTokenManager.Token_Position;
      Prefix   : in     Dictionary.Symbol;
      Scope    : in     Dictionary.Scopes;
      Ref_Var  : in     SeqAlgebra.Seq;
      The_Heap : in out Heap.HeapRecord)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Loc,
   --#                                         Prefix,
   --#                                         Proc_Sym,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys &
   --#         Statistics.TableUsage,
   --#         The_Heap                   from *,
   --#                                         Dictionary.Dict,
   --#                                         Prefix,
   --#                                         Proc_Sym,
   --#                                         Ref_Var,
   --#                                         Scope,
   --#                                         The_Heap;
   is
      It                       : Dictionary.Iterator;
      Glob_Sym, Enclosing_Unit : Dictionary.Symbol;
      Calling_Abstraction      : Dictionary.Abstractions;

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

      function Is_Local_Variable (Calling_Sym, Glob_Sym : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return Dictionary.GetRegion (Dictionary.GetScope (Glob_Sym)) = Calling_Sym;
      end Is_Local_Variable;

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

      function Is_Own_Var_Of_Embedded_Package (Calling_Sym, Glob_Sym : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return (Dictionary.IsOwnVariable (Glob_Sym))
           and then (Dictionary.GetScope (Dictionary.GetOwner (Glob_Sym)) =
                       Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                  The_Unit       => Calling_Sym));
      end Is_Own_Var_Of_Embedded_Package;

   begin -- Check_Globals_Are_Visible

      -- first check if we are in package initialization.  If so function
      -- call is illegal and we do not proceed with global checks

      Enclosing_Unit := Dictionary.GetEnclosingCompilationUnit (Scope);

      if Sem.In_Package_Initialization (Scope => Scope) then
         if not Dictionary.IsPredefined (Proc_Sym) then
            -- only predefined function calls are allowed.
            ErrorHandler.Semantic_Error
              (Err_Num   => 329,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Id_Str    => LexTokenManager.Null_String);
         end if;

      elsif Dictionary.Is_Subprogram (Enclosing_Unit) or else Dictionary.IsTaskType (Enclosing_Unit) then
         -- we need to check that the function globals are local vars, parameters or
         -- globals of enclosing unit
         Calling_Abstraction := Dictionary.GetAbstraction (Enclosing_Unit, Scope);

         It := Dictionary.FirstGlobalVariable (Dictionary.GetAbstraction (Proc_Sym, Scope), Proc_Sym);
         while not Dictionary.IsNullIterator (It) loop
            Glob_Sym :=
              Sem.Substitute_Protected_Type_Self_Reference (Sym           => Dictionary.CurrentSymbol (It),
                                                            Prefix_Symbol => Prefix);
            SeqAlgebra.AddMember (The_Heap, Ref_Var, Natural (Dictionary.SymbolRef (Glob_Sym)));

            if (not Dictionary.Is_Global_Variable (Calling_Abstraction, Enclosing_Unit, Glob_Sym))
              and then (not Dictionary.IsFormalParameter (Enclosing_Unit, Glob_Sym))
              and then (not Is_Local_Variable (Calling_Sym => Enclosing_Unit,
                                               Glob_Sym    => Glob_Sym))
              and then (not Is_Own_Var_Of_Embedded_Package (Calling_Sym => Enclosing_Unit,
                                                            Glob_Sym    => Glob_Sym)) then
               ErrorHandler.Semantic_Error_Sym
                 (Err_Num   => 25,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Loc,
                  Sym       => Glob_Sym,
                  Scope     => Scope);
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
      elsif Dictionary.IsPackage (Enclosing_Unit) then
         -- no check required, there is no equivalent of checking the globals or parameters for a package
         -- and simple visibility of local package variables will have been checked when the function's
         -- own global anno was checked
         --
         -- NOTE.  There may be need of check if we relax declarative order rules since an own var
         --        might then be declared after the function that uses it.
         null;
      else
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Other_Internal_Error,
            Msg     => "Checking call to function in Check_Globals_Are_Visible where calling scope is " &
              "none of package, subprogram or task body");
      end if;
   end Check_Globals_Are_Visible;

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

   procedure Check_Called_Function_Is_Wellformed
     (Sym   : in Dictionary.Symbol;
      Loc   : in LexTokenManager.Token_Position;
      Scope : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Loc,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym;
   is
   begin
      if not Dictionary.SubprogramSignatureIsWellformed (Dictionary.GetAbstraction (Sym, Scope), Sym) then
         ErrorHandler.Semantic_Warning (Err_Num  => 399,
                                        Position => Loc,
                                        Id_Str   => LexTokenManager.Null_String);
      end if;
   end Check_Called_Function_Is_Wellformed;

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

   procedure Check_Package_Init_Rules
     (Sym   : in Dictionary.Symbol;
      Scope : in Dictionary.Scopes;
      Loc   : in LexTokenManager.Token_Position)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Loc,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym;
   is
   begin
      -- two checks required: (1) illegal tampering with remote own variables
      --                      (2) illegal referencing of moded own variables
      if Sem.In_Package_Initialization (Scope => Scope) then
         --(1)
         if Dictionary.IsOwnVariable (Sym)
           and then Dictionary.GetOwner (Sym) /= Dictionary.GetEnclosingCompilationUnit (Scope) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 330,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Id_Str    => LexTokenManager.Null_String);
         end if;
         --(2)
         if Dictionary.GetOwnVariableOrConstituentMode (Sym) /= Dictionary.DefaultMode then
            ErrorHandler.Semantic_Error
              (Err_Num   => 719,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Id_Str    => LexTokenManager.Null_String);
         end if;
      end if;
   end Check_Package_Init_Rules;

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

   function Is_Unresolved_Deferred_Constant (Sym   : Dictionary.Symbol;
                                             Scope : Dictionary.Scopes) return Boolean
   --# global in Dictionary.Dict;
   is
   begin
      return Dictionary.Is_Constant (Sym)
        and then not Dictionary.ConstantIsDeferredHere (Sym, Scope)
        and then not Dictionary.Is_Declared (Item => Sym)
        and then not (Dictionary.Get_Visibility (Scope => Scope) = Dictionary.Local);
   end Is_Unresolved_Deferred_Constant;

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

   procedure Check_Reference_Ability
     (Sym     : in Dictionary.Symbol;
      Scope   : in Dictionary.Scopes;
      Loc     : in LexTokenManager.Token_Position;
      Context : in Sem.Tilde_Context)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Context,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Loc,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym;
   is
      Subprog_Sym : Dictionary.Symbol;

      function Is_Protected_Element_Of (Sym, Subprog_Sym : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
         Result  : Boolean := False;
         TheUnit : Dictionary.Symbol;
         It      : Dictionary.Iterator;
      begin
         TheUnit := Dictionary.GetRegion (Dictionary.GetScope (Subprog_Sym));
         if Dictionary.IsProtectedType (TheUnit) then
            It := Dictionary.FirstProtectedElement (The_Protected_Type => TheUnit);
            while It /= Dictionary.NullIterator loop
               Result := Dictionary.CurrentSymbol (It) = Sym;
               exit when Result;
               It := Dictionary.NextSymbol (It);
            end loop;
         end if;
         return Result;
      end Is_Protected_Element_Of;

   begin -- Check_Reference_Ability
      case Context is
         when Sem.Precondition | Sem.Function_Return =>
            Subprog_Sym := Dictionary.GetEnclosingCompilationUnit (Scope);
            if not Dictionary.IsFunction (Subprog_Sym)
              and then Dictionary.Is_Variable (Sym)
              and then not Dictionary.IsQuantifiedVariable (Sym)
              and then not Dictionary.IsImport (Dictionary.GetAbstraction (Subprog_Sym, Scope), Subprog_Sym, Sym)
              and then
              -- Unconstrained formal parameters can appear in preconditions
              not (Dictionary.IsFormalParameter (Subprog_Sym, Sym)
                     and then Dictionary.IsUnconstrainedArrayType (Dictionary.GetType (Sym)))
              and then
              -- in protected bodies, allow freeer access to protected elements so that assertions
              -- can be made about relationship between entry barriers and PO state. This is a temp
              -- solution to the problem described in SEPR 1542
              not (Is_Protected_Element_Of (Sym         => Sym,
                                            Subprog_Sym => Subprog_Sym)) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 322,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Loc,
                  Id_Str    => LexTokenManager.Null_String);
            end if;
         when Sem.Postcondition =>
            null;
         when Sem.Code =>
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Precondition_Failure,
               Msg     => "Stack_Identifier.Check_Reference_Ability called with Context=Code");
      end case;
   end Check_Reference_Ability;

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

   function Context_To_Use (Is_Annotation : Boolean) return Dictionary.Contexts is
      Result : Dictionary.Contexts;
   begin
      if Is_Annotation then
         Result := Dictionary.ProofContext;
      else
         Result := Dictionary.ProgramContext;
      end if;
      return Result;
   end Context_To_Use;

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

   procedure Check_Use_Of_Unchecked_Conversion
     (Sym_Local : in Dictionary.Symbol;
      Scope     : in Dictionary.Scopes;
      Loc       : in LexTokenManager.Token_Position)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives Dictionary.Dict            from *,
   --#                                         Scope,
   --#                                         Sym_Local &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Loc,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym_Local;
   is

      function Returns_Type_With_Check (Func_Sym : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
         Return_Type : Dictionary.Symbol;
      begin
         -- Returns true if Func_Sym returns a scalar type that is not Boolean.
         -- These are types for which range check VCs are generated; other types
         -- do not have checks.  We want to generate different warnings for use of
         -- unchecked conversions depending on the type returned.
         Return_Type := Dictionary.GetType (Func_Sym);
         return Dictionary.TypeIsScalar (Return_Type) and then not Dictionary.TypeIsBoolean (Return_Type);
      end Returns_Type_With_Check;

   begin -- Check_Use_Of_Unchecked_Conversion
      if Dictionary.IsAnUncheckedConversion (Sym_Local) then
         -- mark unit as a user of U_C for benefit of VCG BuildGraph
         Dictionary.AddUsesUncheckedConversion (Dictionary.GetEnclosingCompilationUnit (Scope));
         -- warn user
         -- For each warning, use the symbol for the implicit proof function. This is done to
         -- make sure that the symbols will match if there is a justification for the warning.
         if Returns_Type_With_Check (Func_Sym => Sym_Local) then
            -- weaker warning where RTC VCs provide some further protection
            ErrorHandler.Semantic_Warning_Sym
              (Err_Num  => 12,
               Position => Loc,
               Sym      => Dictionary.GetImplicitProofFunction (Dictionary.IsAbstract, Sym_Local),
               Scope    => Scope);
         else
            -- stronger warning because no VCs to help us
            ErrorHandler.Semantic_Warning_Sym
              (Err_Num  => 13,
               Position => Loc,
               Sym      => Dictionary.GetImplicitProofFunction (Dictionary.IsAbstract, Sym_Local),
               Scope    => Scope);
         end if;
      end if;
   end Check_Use_Of_Unchecked_Conversion;

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

   -- this function checks if the symbol passed is a stream variable or
   -- a function which globally accesses a stream variable.  If it is
   -- it returns the symbol otherwise it returns NullSymbol

   function Stream_References_By (Sym   : Dictionary.Symbol;
                                  Scope : Dictionary.Scopes) return Dictionary.Symbol
   --# global in Dictionary.Dict;
   is
      Result : Dictionary.Symbol := Dictionary.NullSymbol;
      It     : Dictionary.Iterator;
   begin
      if Dictionary.IsAdaFunction (Sym) then -- IsAdaFunction used to block proof functions
         It := Dictionary.FirstGlobalVariable (Dictionary.GetAbstraction (Sym, Scope), Sym);
         while not Dictionary.IsNullIterator (It) loop
            if Dictionary.IsOwnVariableOrConstituentWithMode (Dictionary.CurrentSymbol (It)) then
               Result := Sym;
               exit;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
      else -- check for stream variable case
         if Dictionary.IsOwnVariableOrConstituentWithMode (Sym) then
            Result := Sym;
         end if;
      end if;
      return Result;
   end Stream_References_By;

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

   function Get_Enum_Lit_Value (Sym : Dictionary.Symbol) return Maths.Value
   --# global in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Value : Maths.Value;
   begin
      if Dictionary.Enumeration_Literals_Are_Equal (Left_Symbol  => Sym,
                                                    Right_Symbol => Dictionary.GetTrue) then
         Value := Maths.TrueValue;
      elsif Dictionary.Enumeration_Literals_Are_Equal (Left_Symbol  => Sym,
                                                       Right_Symbol => Dictionary.GetFalse) then
         Value := Maths.FalseValue;
      else
         Value := Maths.ValueRep (Dictionary.GetPositionNumber (Sym));
      end if;
      return Value;
   end Get_Enum_Lit_Value;

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

   function Get_Object_Value (Sym : Dictionary.Symbol) return Maths.Value
   --# global in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Value : Maths.Value;
   begin
      if Dictionary.Is_Constant (Sym) then
         Value := Maths.ValueRep (Dictionary.Get_Value (The_Constant => Sym));
      else
         Value := Maths.NoValue;
      end if;
      return Value;
   end Get_Object_Value;

begin -- Stack_Identifier
   Loc                   := STree.Node_Position (Node => Node);
   Tagged_Parameter_Type := Dictionary.NullSymbol;
   -- Tagged_Parameter_Type has a value if an inherited operation gets called; in
   -- this case it holds the value of the formal parameter of that operation
   -- that makes it inheritable.  We need this when processing parameters in
   -- wf_positional_ and wf_named_association so that we know when to convert
   -- actual parameters that are of an extended, tagged type.

   Sym_Local := Sym;
   -- if we arrive here with a null symbol then a look up in wf_identifier
   -- or wf_selected_component has failed.  Before we can simply report this
   -- we need to see if there are any inherited ops associated with tagged
   -- types that might be visible.
   --
   -- We search only if the prefix we are using is null (i.e. we are stacking a
   -- simple identifier) or if it is a package.  (The alternative, that it is a protected
   -- object means that we do not search for inherited (tagged) ops).
   if Dictionary.Is_Null_Symbol (Sym_Local)
     and then (Dictionary.Is_Null_Symbol (Prefix) or else Dictionary.IsPackage (Prefix)) then
      Dictionary.SearchForInheritedOperations
        (Name             => Id_Str,
         Scope            => Scope,
         Prefix           => Prefix,
         Context          => Context_To_Use (Is_Annotation => Is_Annotation),
         OpSym            => Sym_Local,
         ActualTaggedType => Tagged_Parameter_Type);
      if Dictionary.Is_Null_Symbol (Sym_Local) or else Dictionary.IsProcedure (Sym_Local) then -- procedure is no good
         Sym_Local := Dictionary.NullSymbol;
         -- now check that any function found is an Ada function (or an implicit proof
         -- function associated with an Ada function.  A pure proof function is not
         -- acceptable because proof functions are not primitives in SPARK
      elsif Dictionary.IsProofFunction (Sym_Local) and then not Dictionary.IsImplicitProofFunction (Sym_Local) then
         Sym_Local := Dictionary.NullSymbol;
      end if;
   end if;

   -- After looking at inherited ops we carry on as normal.  Either processing
   -- the inherited op found or reporting failure to find anything.

   if Dictionary.Is_Null_Symbol (Sym_Local) then
      Result := Unknown_Symbol_Record;
      ErrorHandler.Semantic_Error2
        (Err_Num   => 1,
         Reference => ErrorHandler.No_Reference,
         Position  => Loc,
         Id_Str1   => Id_Str,
         Id_Str2   => Dictionary.GetSimpleName (Prefix));
   elsif not Is_Annotation and then Is_Unresolved_Deferred_Constant (Sym   => Sym_Local,
                                                                     Scope => Scope) then
      Result := Unknown_Symbol_Record;
      ErrorHandler.Semantic_Error
        (Err_Num   => 611,
         Reference => ErrorHandler.No_Reference,
         Position  => Loc,
         Id_Str    => LexTokenManager.Null_String);
   elsif Dictionary.IsFunction (Sym_Local) then
      -- If we have ended calling an inherited root operation then we need to tell
      -- the VCG which subprogram actually got called.  We know that a root op has
      -- been called if TaggedParameterSym is not null.  In that case we seed the
      -- syntax node with the symbol of the root function called.
      if not Dictionary.Is_Null_Symbol (Tagged_Parameter_Type) then
         STree.Add_Node_Symbol (Node => Node,
                                Sym  => Sym_Local);
      end if;
      if Is_Annotation then
         -- provisonal callability checkwhich excludes proof functions, will
         -- need to be sorted out once dict includes implicit proof funcs
         if not (Dictionary.IsProofFunction (Sym_Local) or else Dictionary.IsCallable (Sym_Local, Dotted, Scope)) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 163,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Id_Str    => Dictionary.GetSimpleName (Sym_Local));
         end if;
      else -- not Is_Annotation
         if Dictionary.Is_Generic_Subprogram (The_Symbol => Sym_Local) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 654,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Id_Str    => Dictionary.GetSimpleName (Sym_Local));
         else
            if Dictionary.IsCallable (Sym_Local, Dotted, Scope) then
               Check_Called_Function_Is_Wellformed (Sym   => Sym_Local,
                                                    Loc   => Loc,
                                                    Scope => Scope);
               Check_Globals_Are_Visible
                 (Proc_Sym => Sym_Local,
                  Loc      => Loc,
                  Prefix   => Prefix,
                  Scope    => Scope,
                  Ref_Var  => Ref_Var,
                  The_Heap => The_Heap);
               Check_Use_Of_Unchecked_Conversion (Sym_Local => Sym_Local,
                                                  Scope     => Scope,
                                                  Loc       => Loc);
            else
               ErrorHandler.Semantic_Error
                 (Err_Num   => 163,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Loc,
                  Id_Str    => Dictionary.GetSimpleName (Sym_Local));
            end if; -- Dictionary.IsCallable
         end if; -- IsGenericSubprogram
      end if; -- Is_Annotation

      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Dictionary.GetType (Sym_Local),
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Stream_References_By (Sym   => Sym_Local,
                                                          Scope => Scope),
         Tagged_Parameter_Symbol => Tagged_Parameter_Type,
         Variable_Symbol         => Dictionary.NullSymbol,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Is_Function,
         Arg_List_Found          => False,
         Is_Static               => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Constant             => Dictionary.IsPredefined (Sym_Local),
         Is_ARange               => False,
         Is_AVariable            => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Maths.NoValue,
         Range_RHS               => Maths.NoValue);

      if Dictionary.GetNumberOfSubprogramParameters (Sym_Local) = 0 then
         Result.Sort := Sem.Is_Object;
      end if;
   elsif Dictionary.IsObject (Sym_Local) then
      if Is_Annotation then
         Check_Reference_Ability (Sym     => Sym_Local,
                                  Scope   => Scope,
                                  Loc     => Loc,
                                  Context => Context);
      else
         Check_Package_Init_Rules (Sym   => Sym_Local,
                                   Scope => Scope,
                                   Loc   => Loc);
      end if;

      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Dictionary.GetType (Sym_Local),
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Stream_References_By (Sym   => Sym_Local,
                                                          Scope => Scope),
         Tagged_Parameter_Symbol => Dictionary.NullSymbol,
         Variable_Symbol         => Dictionary.NullSymbol,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Is_Object,
         Arg_List_Found          => False,
         Is_AVariable            => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Static               => Dictionary.IsStatic (Sym_Local, Scope),
         Is_Constant             => Dictionary.Is_Constant (Sym_Local),
         Is_ARange               => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Maths.NoValue,
         Range_RHS               => Maths.NoValue);

      -- If the constant is of a string subtype then we need to recover the string's length
      -- and place it in RangeRHS because this is what we would get if a string literal was
      -- substituted for the constant and we should get the same behaviour for both cases
      if Dictionary.Is_Constant (Sym_Local)
        and then Dictionary.Types_Are_Equal
        (Left_Symbol        => Dictionary.GetRootType (Result.Type_Symbol),
         Right_Symbol       => Dictionary.GetPredefinedStringType,
         Full_Range_Subtype => False) then

         Result.String_Value := Dictionary.Get_Value (The_Constant => Sym_Local);
         Result.Range_RHS    :=
           Maths.ValueRep
           (Dictionary.GetArrayAttributeValue
              (Name      => LexTokenManager.Last_Token,
               TypeMark  => Result.Type_Symbol,
               Dimension => 1));

      else
         Result.Value := Get_Object_Value (Sym => Sym_Local);
      end if;

      if Dictionary.Is_Variable (Sym_Local) then
         Result.Variable_Symbol       := Sym_Local;
         Result.Is_AVariable          := True;
         Result.Is_An_Entire_Variable := True;
         -- Do not allow protected variables (except streams) to appear in annotation expressions
         if Is_Annotation
           and then Dictionary.IsOwnVariable (Sym_Local)
           and then not Dictionary.IsOwnVariableOrConstituentWithMode (Sym_Local)
           and then Dictionary.GetOwnVariableProtected (Sym_Local) then
            Result.Errors_In_Expression := True;
            ErrorHandler.Semantic_Error_Sym
              (Err_Num   => 940,
               Reference => ErrorHandler.No_Reference,
               Position  => Loc,
               Sym       => Sym_Local,
               Scope     => Scope);
         end if;
      end if;
   elsif Dictionary.IsEnumerationLiteral (Sym_Local) then
      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Dictionary.GetType (Sym_Local),
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Dictionary.NullSymbol,
         Tagged_Parameter_Symbol => Dictionary.NullSymbol,
         Variable_Symbol         => Dictionary.NullSymbol,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Type_Result,
         Arg_List_Found          => False,
         Is_AVariable            => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Static               => True,
         Is_Constant             => True,
         Is_ARange               => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Get_Enum_Lit_Value (Sym => Sym_Local),
         Range_RHS               => Maths.NoValue);
   elsif Dictionary.IsTypeMark (Sym_Local) then
      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Sym_Local,
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Dictionary.NullSymbol,
         Tagged_Parameter_Symbol => Dictionary.NullSymbol,
         Variable_Symbol         => Dictionary.NullSymbol,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Is_Type_Mark,
         Arg_List_Found          => False,
         Is_AVariable            => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Static               => False,
         Is_Constant             => False,
         Is_ARange               => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Maths.NoValue,
         Range_RHS               => Maths.NoValue);
   elsif Dictionary.IsPackage (Sym_Local) then
      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Dictionary.GetUnknownTypeMark,
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Dictionary.NullSymbol,
         Tagged_Parameter_Symbol => Dictionary.NullSymbol,
         Variable_Symbol         => Dictionary.NullSymbol,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Is_Package,
         Arg_List_Found          => False,
         Is_AVariable            => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Static               => False,
         Is_Constant             => False,
         Is_ARange               => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Maths.NoValue,
         Range_RHS               => Maths.NoValue);
   elsif Dictionary.IsKnownDiscriminant (Sym_Local) then
      Result :=
        Sem.Exp_Record'
        (Type_Symbol             => Dictionary.GetType (Sym_Local),
         Other_Symbol            => Sym_Local,
         Stream_Symbol           => Dictionary.NullSymbol,
         Tagged_Parameter_Symbol => Dictionary.NullSymbol,
         Variable_Symbol         => Sym_Local,
         Param_Count             => 0,
         Param_List              => Lists.Null_List,
         Sort                    => Sem.Is_Object,
         Arg_List_Found          => False,
         Is_AVariable            => False,
         Is_An_Entire_Variable   => False,
         Errors_In_Expression    => False,
         Has_Operators           => False,
         Is_Static               => True,
         Is_Constant             => True,
         Is_ARange               => False,
         String_Value            => LexTokenManager.Null_String,
         Value                   => Maths.NoValue,
         Range_RHS               => Maths.NoValue);
   else
      Result := Unknown_Symbol_Record;
      ErrorHandler.Semantic_Error (Err_Num   => 5,
                                   Reference => ErrorHandler.No_Reference,
                                   Position  => Loc,
                                   Id_Str    => Id_Str);
   end if;
   Exp_Stack.Push (X     => Result,
                   Stack => E_Stack);
end Stack_Identifier;
