--  Semantic analysis.
--  Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold
--
--  GHDL is free software; you can redistribute it and/or modify it under
--  the terms of the GNU General Public License as published by the Free
--  Software Foundation; either version 2, or (at your option) any later
--  version.
--
--  GHDL 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
--  along with GHDL; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.
with Iirs; use Iirs;
with Types; use Types;

package Sem_Scopes is

   --  The purpose of SEM_NAME package is to handle association between
   --  identifiers and declarations.
   --  Roughly speacking, it implements ch10 of LRM: scope and visibility.
   --
   --  Basic elements are: declarations and declarative region.
   --  Declaration should be understood in the large meaning: any textual
   --   construction declaring an identifier, which can be a label.
   --  A declarative region contains declarations and possibly other
   --   declarative regions.
   --
   --  Rules are scope, visibility and overloading.
   --

   -- Create and close a declarative region.
   -- By closing a declarative region, all declarations made in this region
   --  are discarded.
   procedure Open_Declarative_Region;
   procedure Close_Declarative_Region;

   -- Add meaning DECL for its identifier to the current declarative region.
   procedure Add_Name (Decl: Iir);
   pragma Inline (Add_Name);

   -- Add meaning DECL to the identifier IDENT.
   -- POTENTIALLY is true if the identifier comes from a use clause.
   procedure Add_Name (Decl: Iir; Ident : Name_Id; Potentially: Boolean);

   --  Set the visible_flag of DECL to true.
   procedure Name_Visible (Decl : Iir);

   --  Replace the interpretation OLD of ID by DECL.
   --  ID must have a uniq interpretation OLD (ie, it must not be overloaded).
   --  The interpretation must have been done in the current scope.
   --
   --  This procedure is used when the meaning of a name is changed due to its
   --  analysis, eg: when a concurrent_procedure_call_statement becomes
   --  a component_instantiation_statement.
   procedure Replace_Name (Id: Name_Id; Old : Iir; Decl: Iir);

   --  Interpretation is a simply linked list of what an identifier means.
   --  In LRM08 12.3 Visibility, the sentence is 'the declaration defines a
   --  possible meaning of this occurrence'.
   --  FIXME: replace Interpretation by Meaning.
   type Name_Interpretation_Type is private;

   --  Return true if INTER is a valid interpretation, ie has a corresponding
   --  declaration.  There are only two invalids interpretations, which
   --  are declared just below as constants.
   function Valid_Interpretation (Inter : Name_Interpretation_Type)
                                 return Boolean;
   pragma Inline (Valid_Interpretation);

   --  This pseudo interpretation marks the end of the interpretation chain,
   --  and means there is no (more) interpretations for the name.
   --  Unless you need to discriminate between an absence of declaration and
   --  a conflict between potential declarations, you should use the
   --  VALID_INTERPRETATION function.
   No_Name_Interpretation : constant Name_Interpretation_Type;

   --  This pseudo interpretation means the name has only conflicting potential
   --  declarations, and also terminates the chain of interpretations.
   --  Unless you need to discriminate between an absence of declaration and
   --  a conflict between potential declarations, you should use the
   --  VALID_INTERPRETATION function.
   Conflict_Interpretation : constant Name_Interpretation_Type;

   -- Get the first interpretation of identifier ID.
   function Get_Interpretation (Id: Name_Id) return Name_Interpretation_Type;
   pragma Inline (Get_Interpretation);

   -- Get the next interpretation from an interpretation.
   function Get_Next_Interpretation (Ni: Name_Interpretation_Type)
                                     return Name_Interpretation_Type;
   pragma Inline (Get_Next_Interpretation);

   --  Get a declaration associated with an interpretation.
   function Get_Declaration (Ni: Name_Interpretation_Type) return Iir;
   pragma Inline (Get_Declaration);

   --  Same as Get_Declaration, but get the name of non-object alias.
   --  (ie, can never returns an object alias).
   function Get_Non_Alias_Declaration (Ni: Name_Interpretation_Type)
                                      return Iir;

   --  Get the previous interpretation of identifier ID, ie the interpretation
   --  for ID before the current interpretation of ID.
   function Get_Under_Interpretation (Id : Name_Id)
     return Name_Interpretation_Type;

   -- Return TRUE if INTER was made directly visible via a use clause.
   function Is_Potentially_Visible (Inter: Name_Interpretation_Type)
     return Boolean;
   pragma Inline (Is_Potentially_Visible);

   --  Return TRUE if INTER was made direclty visible in the current
   --  declarative region.  Note this is different from being declared in the
   --  current declarative region because of use clauses.
   function Is_In_Current_Declarative_Region (Inter: Name_Interpretation_Type)
     return Boolean;
   pragma Inline (Is_In_Current_Declarative_Region);

   -- Push and pop all interpretations.
   -- This can be used to suspend name interpretation, in case of recursive
   -- semantics.
   -- After a push, all names have no_name_interpretation.
   -- Pop restore the previous state.
   procedure Pop_Interpretations;
   procedure Push_Interpretations;

   -- Execute a use clause on NAME.
   -- Make potentially directly visible declarations of NAMES.
   --procedure Use_Selected_Name (Name : Iir);
   procedure Use_All_Names (Name: Iir);

   --  Achieves visibility of the selected_name of use clause CLAUSE.
   procedure Add_Use_Clause (Clause : Iir_Use_Clause);

   --  Add declarations for a context clause into the current declarative
   --  regions.
   procedure Add_Context_Clauses (Unit : Iir_Design_Unit);

   -- Add declarations from an entity into the current declarative region.
   -- This is needed when an architecture is analysed.
   procedure Add_Entity_Declarations (Entity : Iir_Entity_Declaration);

   -- Add declarations from a package into the current declarative region.
   -- This is needed when a package body is analysed.
   -- FIXME:  this must be done as if the declarative region was extended.
   procedure Add_Package_Declarations (Decl: Iir_Package_Declaration);

   --  Add interfaces declaration of a component into the current declarative
   --  region.
   procedure Add_Component_Declarations
     (Component : Iir_Component_Declaration);

   --  Add declarations from a protected type declaration into the current
   --  declaration region (which is expected to be the region of the protected
   --  type body).
   procedure Add_Protected_Type_Declarations
     (Decl : Iir_Protected_Type_Declaration);

   --  Add declarations of interface chain CHAIN into the current
   --  declarative region.
   procedure Add_Declarations_From_Interface_Chain (Chain : Iir);

   --  Add all declarations for concurrent statements declared in PARENT.
   procedure Add_Declarations_Of_Concurrent_Statement (Parent : Iir);

   --  Add declarations of a declaration chain CHAIN.
   procedure Add_Declarations (Chain : Iir; Potentially : Boolean := False);

   --  Scope extension area contains declarations from another declarative
   --  region.  These area are abstract and only used to be able to add
   --  and remove declarations.
   procedure Open_Scope_Extension;
   procedure Close_Scope_Extension;

   -- Add any declarations that include the end of the declarative part of
   --  the given block BLOCK.  This follow rules of LRM93 10.2
   -- FIXME: BLOCK must be an architecture at first, then blocks declared
   --  inside this architecture, then a block declared inside this block...
   -- This procedure must be called after an Open_Scope_Extension and
   --  declarations added can be removed with Close_Scope_Extension.
   procedure Extend_Scope_Of_Block_Declarations (Decl : Iir);

   --  Call HANDLE_DECL for each declaration found in DECL.
   --  This will generally call HANDLE_DECL with DECL.
   --  For types, HANDLE_DECL is first called with the type declaration, then
   --  with implicit functions, with element literals for enumeration type,
   --  and units for physical type.
   generic
      type Arg_Type is private;
      with procedure Handle_Decl (Decl : Iir; Arg : Arg_Type);
   procedure Iterator_Decl (Decl : Iir; Arg : Arg_Type);

   --  Call HANDLE_DECL for each declaration found in DECL_LIST.
   --  Generally, HANDLE_DECL must be an ITERATOR_DECL; this is not
   --  automatically done, since the user might be interested in using the
   --  ITERATOR_DECL.
   generic
      type Arg_Type is private;
      with procedure Handle_Decl (Decl : Iir; Arg : Arg_Type);
   procedure Iterator_Decl_List (Decl_List : Iir_List; Arg : Arg_Type);

   generic
      type Arg_Type is private;
      with procedure Handle_Decl (Decl : Iir; Arg : Arg_Type);
   procedure Iterator_Decl_Chain (Chain_First : Iir; Arg : Arg_Type);

private
   type Name_Interpretation_Type is new Int32 range 0 .. (2 ** 30) - 1;
   No_Name_Interpretation : constant Name_Interpretation_Type := 0;
   Conflict_Interpretation : constant Name_Interpretation_Type := 1;
   First_Valid_Interpretation : constant Name_Interpretation_Type := 2;
end Sem_Scopes;