| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- P R J . P R O C -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2001-2015, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT 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 GNAT; see file COPYING3. If not, go to -- |
| -- http://www.gnu.org/licenses for a complete copy of the license. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Atree; use Atree; |
| with Err_Vars; use Err_Vars; |
| with Opt; use Opt; |
| with Osint; use Osint; |
| with Output; use Output; |
| with Prj.Attr; use Prj.Attr; |
| with Prj.Env; |
| with Prj.Err; use Prj.Err; |
| with Prj.Ext; use Prj.Ext; |
| with Prj.Nmsc; use Prj.Nmsc; |
| with Prj.Part; |
| with Prj.Util; |
| with Snames; |
| |
| with Ada.Containers.Vectors; |
| with Ada.Strings.Fixed; use Ada.Strings.Fixed; |
| |
| with GNAT.Case_Util; use GNAT.Case_Util; |
| with GNAT.HTable; |
| |
| package body Prj.Proc is |
| |
| package Processed_Projects is new GNAT.HTable.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Project_Id, |
| No_Element => No_Project, |
| Key => Name_Id, |
| Hash => Hash, |
| Equal => "="); |
| -- This hash table contains all processed projects |
| |
| package Unit_Htable is new GNAT.HTable.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Source_Id, |
| No_Element => No_Source, |
| Key => Name_Id, |
| Hash => Hash, |
| Equal => "="); |
| -- This hash table contains all processed projects |
| |
| package Runtime_Defaults is new GNAT.HTable.Simple_HTable |
| (Header_Num => Prj.Header_Num, |
| Element => Name_Id, |
| No_Element => No_Name, |
| Key => Name_Id, |
| Hash => Prj.Hash, |
| Equal => "="); |
| -- Stores the default values of 'Runtime names for the various languages |
| |
| procedure Add (To_Exp : in out Name_Id; Str : Name_Id); |
| -- Concatenate two strings and returns another string if both |
| -- arguments are not null string. |
| |
| -- In the following procedures, we are expected to guess the meaning of |
| -- the parameters from their names, this is never a good idea, comments |
| -- should be added precisely defining every formal ??? |
| |
| procedure Add_Attributes |
| (Project : Project_Id; |
| Project_Name : Name_Id; |
| Project_Dir : Name_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| Decl : in out Declarations; |
| First : Attribute_Node_Id; |
| Project_Level : Boolean); |
| -- Add all attributes, starting with First, with their default values to |
| -- the package or project with declarations Decl. |
| |
| procedure Check |
| (In_Tree : Project_Tree_Ref; |
| Project : Project_Id; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Processing_Flags); |
| -- Set all projects to not checked, then call Recursive_Check for the |
| -- main project Project. Project is set to No_Project if errors occurred. |
| -- Current_Dir is for optimization purposes, avoiding extra system calls. |
| -- If Allow_Duplicate_Basenames, then files with the same base names are |
| -- authorized within a project for source-based languages (never for unit |
| -- based languages) |
| |
| procedure Copy_Package_Declarations |
| (From : Declarations; |
| To : in out Declarations; |
| New_Loc : Source_Ptr; |
| Restricted : Boolean; |
| Shared : Shared_Project_Tree_Data_Access); |
| -- Copy a package declaration From to To for a renamed package. Change the |
| -- locations of all the attributes to New_Loc. When Restricted is |
| -- True, do not copy attributes Body, Spec, Implementation, Specification |
| -- and Linker_Options. |
| |
| function Expression |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : Prj.Tree.Environment; |
| Pkg : Package_Id; |
| First_Term : Project_Node_Id; |
| Kind : Variable_Kind) return Variable_Value; |
| -- From N_Expression project node From_Project_Node, compute the value |
| -- of an expression and return it as a Variable_Value. |
| |
| function Imported_Or_Extended_Project_From |
| (Project : Project_Id; |
| With_Name : Name_Id; |
| No_Extending : Boolean := False) return Project_Id; |
| -- Find an imported or extended project of Project whose name is With_Name. |
| -- When No_Extending is True, do not look for extending projects, returns |
| -- the exact project whose name is With_Name. |
| |
| function Package_From |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| With_Name : Name_Id) return Package_Id; |
| -- Find the package of Project whose name is With_Name |
| |
| procedure Process_Declarative_Items |
| (Project : Project_Id; |
| In_Tree : Project_Tree_Ref; |
| From_Project_Node : Project_Node_Id; |
| Node_Tree : Project_Node_Tree_Ref; |
| Env : Prj.Tree.Environment; |
| Pkg : Package_Id; |
| Item : Project_Node_Id; |
| Child_Env : in out Prj.Tree.Environment); |
| -- Process declarative items starting with From_Project_Node, and put them |
| -- in declarations Decl. This is a recursive procedure; it calls itself for |
| -- a package declaration or a case construction. |
| -- |
| -- Child_Env is the modified environment after seeing declarations like |
| -- "for External(...) use" or "for Project_Path use" in aggregate projects. |
| -- It should have been initialized first. |
| |
| procedure Recursive_Process |
| (In_Tree : Project_Tree_Ref; |
| Project : out Project_Id; |
| Packages_To_Check : String_List_Access; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : in out Prj.Tree.Environment; |
| Extended_By : Project_Id; |
| From_Encapsulated_Lib : Boolean; |
| On_New_Tree_Loaded : Tree_Loaded_Callback := null); |
| -- Process project with node From_Project_Node in the tree. Do nothing if |
| -- From_Project_Node is Empty_Node. If project has already been processed, |
| -- simply return its project id. Otherwise create a new project id, mark it |
| -- as processed, call itself recursively for all imported projects and a |
| -- extended project, if any. Then process the declarative items of the |
| -- project. |
| -- |
| -- Is_Root_Project should be true only for the project that the user |
| -- explicitly loaded. In the context of aggregate projects, only that |
| -- project is allowed to modify the environment that will be used to load |
| -- projects (Child_Env). |
| -- |
| -- From_Encapsulated_Lib is true if we are parsing a project from |
| -- encapsulated library dependencies. |
| -- |
| -- If specified, On_New_Tree_Loaded is called after each aggregated project |
| -- has been processed succesfully. |
| |
| function Get_Attribute_Index |
| (Tree : Project_Node_Tree_Ref; |
| Attr : Project_Node_Id; |
| Index : Name_Id) return Name_Id; |
| -- Copy the index of the attribute into Name_Buffer, converting to lower |
| -- case if the attribute is case-insensitive. |
| |
| --------- |
| -- Add -- |
| --------- |
| |
| procedure Add (To_Exp : in out Name_Id; Str : Name_Id) is |
| begin |
| if To_Exp = No_Name or else To_Exp = Empty_String then |
| |
| -- To_Exp is nil or empty. The result is Str |
| |
| To_Exp := Str; |
| |
| -- If Str is nil, then do not change To_Ext |
| |
| elsif Str /= No_Name and then Str /= Empty_String then |
| declare |
| S : constant String := Get_Name_String (Str); |
| begin |
| Get_Name_String (To_Exp); |
| Add_Str_To_Name_Buffer (S); |
| To_Exp := Name_Find; |
| end; |
| end if; |
| end Add; |
| |
| -------------------- |
| -- Add_Attributes -- |
| -------------------- |
| |
| procedure Add_Attributes |
| (Project : Project_Id; |
| Project_Name : Name_Id; |
| Project_Dir : Name_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| Decl : in out Declarations; |
| First : Attribute_Node_Id; |
| Project_Level : Boolean) |
| is |
| The_Attribute : Attribute_Node_Id := First; |
| |
| begin |
| while The_Attribute /= Empty_Attribute loop |
| if Attribute_Kind_Of (The_Attribute) = Single then |
| declare |
| New_Attribute : Variable_Value; |
| |
| begin |
| case Variable_Kind_Of (The_Attribute) is |
| |
| -- Undefined should not happen |
| |
| when Undefined => |
| pragma Assert |
| (False, "attribute with an undefined kind"); |
| raise Program_Error; |
| |
| -- Single attributes have a default value of empty string |
| |
| when Single => |
| New_Attribute := |
| (Project => Project, |
| Kind => Single, |
| Location => No_Location, |
| Default => True, |
| Value => Empty_String, |
| Index => 0); |
| |
| -- Special cases of <project>'Name and |
| -- <project>'Project_Dir. |
| |
| if Project_Level then |
| if Attribute_Name_Of (The_Attribute) = |
| Snames.Name_Name |
| then |
| New_Attribute.Value := Project_Name; |
| |
| elsif Attribute_Name_Of (The_Attribute) = |
| Snames.Name_Project_Dir |
| then |
| New_Attribute.Value := Project_Dir; |
| end if; |
| end if; |
| |
| -- List attributes have a default value of nil list |
| |
| when List => |
| New_Attribute := |
| (Project => Project, |
| Kind => List, |
| Location => No_Location, |
| Default => True, |
| Values => Nil_String); |
| |
| end case; |
| |
| Variable_Element_Table.Increment_Last |
| (Shared.Variable_Elements); |
| Shared.Variable_Elements.Table |
| (Variable_Element_Table.Last (Shared.Variable_Elements)) := |
| (Next => Decl.Attributes, |
| Name => Attribute_Name_Of (The_Attribute), |
| Value => New_Attribute); |
| Decl.Attributes := |
| Variable_Element_Table.Last |
| (Shared.Variable_Elements); |
| end; |
| end if; |
| |
| The_Attribute := Next_Attribute (After => The_Attribute); |
| end loop; |
| end Add_Attributes; |
| |
| ----------- |
| -- Check -- |
| ----------- |
| |
| procedure Check |
| (In_Tree : Project_Tree_Ref; |
| Project : Project_Id; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Processing_Flags) |
| is |
| begin |
| Process_Naming_Scheme (In_Tree, Project, Node_Tree, Flags); |
| |
| -- Set the Other_Part field for the units |
| |
| declare |
| Source1 : Source_Id; |
| Name : Name_Id; |
| Source2 : Source_Id; |
| Iter : Source_Iterator; |
| |
| begin |
| Unit_Htable.Reset; |
| |
| Iter := For_Each_Source (In_Tree); |
| loop |
| Source1 := Prj.Element (Iter); |
| exit when Source1 = No_Source; |
| |
| if Source1.Unit /= No_Unit_Index then |
| Name := Source1.Unit.Name; |
| Source2 := Unit_Htable.Get (Name); |
| |
| if Source2 = No_Source then |
| Unit_Htable.Set (K => Name, E => Source1); |
| else |
| Unit_Htable.Remove (Name); |
| end if; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| end; |
| end Check; |
| |
| ------------------------------- |
| -- Copy_Package_Declarations -- |
| ------------------------------- |
| |
| procedure Copy_Package_Declarations |
| (From : Declarations; |
| To : in out Declarations; |
| New_Loc : Source_Ptr; |
| Restricted : Boolean; |
| Shared : Shared_Project_Tree_Data_Access) |
| is |
| V1 : Variable_Id; |
| V2 : Variable_Id := No_Variable; |
| Var : Variable; |
| A1 : Array_Id; |
| A2 : Array_Id := No_Array; |
| Arr : Array_Data; |
| E1 : Array_Element_Id; |
| E2 : Array_Element_Id := No_Array_Element; |
| Elm : Array_Element; |
| |
| begin |
| -- To avoid references in error messages to attribute declarations in |
| -- an original package that has been renamed, copy all the attribute |
| -- declarations of the package and change all locations to New_Loc, |
| -- the location of the renamed package. |
| |
| -- First single attributes |
| |
| V1 := From.Attributes; |
| while V1 /= No_Variable loop |
| |
| -- Copy the attribute |
| |
| Var := Shared.Variable_Elements.Table (V1); |
| V1 := Var.Next; |
| |
| -- Do not copy the value of attribute Linker_Options if Restricted |
| |
| if Restricted and then Var.Name = Snames.Name_Linker_Options then |
| Var.Value.Values := Nil_String; |
| end if; |
| |
| -- Remove the Next component |
| |
| Var.Next := No_Variable; |
| |
| -- Change the location to New_Loc |
| |
| Var.Value.Location := New_Loc; |
| Variable_Element_Table.Increment_Last (Shared.Variable_Elements); |
| |
| -- Put in new declaration |
| |
| if To.Attributes = No_Variable then |
| To.Attributes := |
| Variable_Element_Table.Last (Shared.Variable_Elements); |
| else |
| Shared.Variable_Elements.Table (V2).Next := |
| Variable_Element_Table.Last (Shared.Variable_Elements); |
| end if; |
| |
| V2 := Variable_Element_Table.Last (Shared.Variable_Elements); |
| Shared.Variable_Elements.Table (V2) := Var; |
| end loop; |
| |
| -- Then the associated array attributes |
| |
| A1 := From.Arrays; |
| while A1 /= No_Array loop |
| Arr := Shared.Arrays.Table (A1); |
| A1 := Arr.Next; |
| |
| -- Remove the Next component |
| |
| Arr.Next := No_Array; |
| Array_Table.Increment_Last (Shared.Arrays); |
| |
| -- Create new Array declaration |
| |
| if To.Arrays = No_Array then |
| To.Arrays := Array_Table.Last (Shared.Arrays); |
| else |
| Shared.Arrays.Table (A2).Next := |
| Array_Table.Last (Shared.Arrays); |
| end if; |
| |
| A2 := Array_Table.Last (Shared.Arrays); |
| |
| -- Don't store the array as its first element has not been set yet |
| |
| -- Copy the array elements of the array |
| |
| E1 := Arr.Value; |
| Arr.Value := No_Array_Element; |
| while E1 /= No_Array_Element loop |
| |
| -- Copy the array element |
| |
| Elm := Shared.Array_Elements.Table (E1); |
| E1 := Elm.Next; |
| |
| -- Remove the Next component |
| |
| Elm.Next := No_Array_Element; |
| |
| Elm.Restricted := Restricted; |
| |
| -- Change the location |
| |
| Elm.Value.Location := New_Loc; |
| Array_Element_Table.Increment_Last (Shared.Array_Elements); |
| |
| -- Create new array element |
| |
| if Arr.Value = No_Array_Element then |
| Arr.Value := Array_Element_Table.Last (Shared.Array_Elements); |
| else |
| Shared.Array_Elements.Table (E2).Next := |
| Array_Element_Table.Last (Shared.Array_Elements); |
| end if; |
| |
| E2 := Array_Element_Table.Last (Shared.Array_Elements); |
| Shared.Array_Elements.Table (E2) := Elm; |
| end loop; |
| |
| -- Finally, store the new array |
| |
| Shared.Arrays.Table (A2) := Arr; |
| end loop; |
| end Copy_Package_Declarations; |
| |
| ------------------------- |
| -- Get_Attribute_Index -- |
| ------------------------- |
| |
| function Get_Attribute_Index |
| (Tree : Project_Node_Tree_Ref; |
| Attr : Project_Node_Id; |
| Index : Name_Id) return Name_Id |
| is |
| begin |
| if Index = All_Other_Names |
| or else not Case_Insensitive (Attr, Tree) |
| then |
| return Index; |
| end if; |
| |
| Get_Name_String (Index); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| return Name_Find; |
| end Get_Attribute_Index; |
| |
| ---------------- |
| -- Expression -- |
| ---------------- |
| |
| function Expression |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : Prj.Tree.Environment; |
| Pkg : Package_Id; |
| First_Term : Project_Node_Id; |
| Kind : Variable_Kind) return Variable_Value |
| is |
| The_Term : Project_Node_Id; |
| -- The term in the expression list |
| |
| The_Current_Term : Project_Node_Id := Empty_Node; |
| -- The current term node id |
| |
| Result : Variable_Value (Kind => Kind); |
| -- The returned result |
| |
| Last : String_List_Id := Nil_String; |
| -- Reference to the last string elements in Result, when Kind is List |
| |
| Current_Term_Kind : Project_Node_Kind; |
| |
| begin |
| Result.Project := Project; |
| Result.Location := Location_Of (First_Term, From_Project_Node_Tree); |
| |
| -- Process each term of the expression, starting with First_Term |
| |
| The_Term := First_Term; |
| while Present (The_Term) loop |
| The_Current_Term := Current_Term (The_Term, From_Project_Node_Tree); |
| |
| if The_Current_Term /= Empty_Node then |
| Current_Term_Kind := |
| Kind_Of (The_Current_Term, From_Project_Node_Tree); |
| |
| case Current_Term_Kind is |
| |
| when N_Literal_String => |
| case Kind is |
| when Undefined => |
| |
| -- Should never happen |
| |
| pragma Assert (False, "Undefined expression kind"); |
| raise Program_Error; |
| |
| when Single => |
| Add (Result.Value, |
| String_Value_Of |
| (The_Current_Term, From_Project_Node_Tree)); |
| Result.Index := |
| Source_Index_Of |
| (The_Current_Term, From_Project_Node_Tree); |
| |
| when List => |
| |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| if Last = Nil_String then |
| |
| -- This can happen in an expression like () & "toto" |
| |
| Result.Values := String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| else |
| Shared.String_Elements.Table |
| (Last).Next := String_Element_Table.Last |
| (Shared.String_Elements); |
| end if; |
| |
| Last := String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| Shared.String_Elements.Table (Last) := |
| (Value => String_Value_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Index => Source_Index_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Display_Value => No_Name, |
| Location => Location_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Flag => False, |
| Next => Nil_String); |
| end case; |
| |
| when N_Literal_String_List => |
| declare |
| String_Node : Project_Node_Id := |
| First_Expression_In_List |
| (The_Current_Term, |
| From_Project_Node_Tree); |
| |
| Value : Variable_Value; |
| |
| begin |
| if Present (String_Node) then |
| |
| -- If String_Node is nil, it is an empty list, there is |
| -- nothing to do. |
| |
| Value := Expression |
| (Project => Project, |
| Shared => Shared, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Pkg => Pkg, |
| First_Term => |
| Tree.First_Term |
| (String_Node, From_Project_Node_Tree), |
| Kind => Single); |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| if Result.Values = Nil_String then |
| |
| -- This literal string list is the first term in a |
| -- string list expression |
| |
| Result.Values := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| else |
| Shared.String_Elements.Table (Last).Next := |
| String_Element_Table.Last (Shared.String_Elements); |
| end if; |
| |
| Last := |
| String_Element_Table.Last (Shared.String_Elements); |
| |
| Shared.String_Elements.Table (Last) := |
| (Value => Value.Value, |
| Display_Value => No_Name, |
| Location => Value.Location, |
| Flag => False, |
| Next => Nil_String, |
| Index => Value.Index); |
| |
| loop |
| -- Add the other element of the literal string list |
| -- one after the other. |
| |
| String_Node := |
| Next_Expression_In_List |
| (String_Node, From_Project_Node_Tree); |
| |
| exit when No (String_Node); |
| |
| Value := |
| Expression |
| (Project => Project, |
| Shared => Shared, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Pkg => Pkg, |
| First_Term => |
| Tree.First_Term |
| (String_Node, From_Project_Node_Tree), |
| Kind => Single); |
| |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| Shared.String_Elements.Table (Last).Next := |
| String_Element_Table.Last (Shared.String_Elements); |
| Last := String_Element_Table.Last |
| (Shared.String_Elements); |
| Shared.String_Elements.Table (Last) := |
| (Value => Value.Value, |
| Display_Value => No_Name, |
| Location => Value.Location, |
| Flag => False, |
| Next => Nil_String, |
| Index => Value.Index); |
| end loop; |
| end if; |
| end; |
| |
| when N_Variable_Reference | N_Attribute_Reference => |
| declare |
| The_Project : Project_Id := Project; |
| The_Package : Package_Id := Pkg; |
| The_Name : Name_Id := No_Name; |
| The_Variable_Id : Variable_Id := No_Variable; |
| The_Variable : Variable_Value; |
| Term_Project : constant Project_Node_Id := |
| Project_Node_Of |
| (The_Current_Term, |
| From_Project_Node_Tree); |
| Term_Package : constant Project_Node_Id := |
| Package_Node_Of |
| (The_Current_Term, |
| From_Project_Node_Tree); |
| Index : Name_Id := No_Name; |
| |
| begin |
| <<Object_Dir_Restart>> |
| The_Project := Project; |
| The_Package := Pkg; |
| The_Name := No_Name; |
| The_Variable_Id := No_Variable; |
| Index := No_Name; |
| |
| if Present (Term_Project) |
| and then Term_Project /= From_Project_Node |
| then |
| -- This variable or attribute comes from another project |
| |
| The_Name := |
| Name_Of (Term_Project, From_Project_Node_Tree); |
| The_Project := Imported_Or_Extended_Project_From |
| (Project => Project, |
| With_Name => The_Name, |
| No_Extending => True); |
| end if; |
| |
| if Present (Term_Package) then |
| |
| -- This is an attribute of a package |
| |
| The_Name := |
| Name_Of (Term_Package, From_Project_Node_Tree); |
| |
| The_Package := The_Project.Decl.Packages; |
| while The_Package /= No_Package |
| and then Shared.Packages.Table (The_Package).Name /= |
| The_Name |
| loop |
| The_Package := |
| Shared.Packages.Table (The_Package).Next; |
| end loop; |
| |
| pragma Assert |
| (The_Package /= No_Package, "package not found."); |
| |
| elsif Kind_Of (The_Current_Term, From_Project_Node_Tree) = |
| N_Attribute_Reference |
| then |
| The_Package := No_Package; |
| end if; |
| |
| The_Name := |
| Name_Of (The_Current_Term, From_Project_Node_Tree); |
| |
| if Current_Term_Kind = N_Attribute_Reference then |
| Index := |
| Associative_Array_Index_Of |
| (The_Current_Term, From_Project_Node_Tree); |
| end if; |
| |
| -- If it is not an associative array attribute |
| |
| if Index = No_Name then |
| |
| -- It is not an associative array attribute |
| |
| if The_Package /= No_Package then |
| |
| -- First, if there is a package, look into the package |
| |
| if Current_Term_Kind = N_Variable_Reference then |
| The_Variable_Id := |
| Shared.Packages.Table |
| (The_Package).Decl.Variables; |
| else |
| The_Variable_Id := |
| Shared.Packages.Table |
| (The_Package).Decl.Attributes; |
| end if; |
| |
| while The_Variable_Id /= No_Variable |
| and then Shared.Variable_Elements.Table |
| (The_Variable_Id).Name /= The_Name |
| loop |
| The_Variable_Id := |
| Shared.Variable_Elements.Table |
| (The_Variable_Id).Next; |
| end loop; |
| |
| end if; |
| |
| if The_Variable_Id = No_Variable then |
| |
| -- If we have not found it, look into the project |
| |
| if Current_Term_Kind = N_Variable_Reference then |
| The_Variable_Id := The_Project.Decl.Variables; |
| else |
| The_Variable_Id := The_Project.Decl.Attributes; |
| end if; |
| |
| while The_Variable_Id /= No_Variable |
| and then Shared.Variable_Elements.Table |
| (The_Variable_Id).Name /= The_Name |
| loop |
| The_Variable_Id := |
| Shared.Variable_Elements.Table |
| (The_Variable_Id).Next; |
| end loop; |
| |
| end if; |
| |
| if From_Project_Node_Tree.Incomplete_With then |
| if The_Variable_Id = No_Variable then |
| The_Variable := Nil_Variable_Value; |
| else |
| The_Variable := |
| Shared.Variable_Elements.Table |
| (The_Variable_Id).Value; |
| end if; |
| |
| else |
| pragma Assert (The_Variable_Id /= No_Variable, |
| "variable or attribute not found"); |
| |
| The_Variable := |
| Shared.Variable_Elements.Table |
| (The_Variable_Id).Value; |
| end if; |
| |
| else |
| |
| -- It is an associative array attribute |
| |
| declare |
| The_Array : Array_Id := No_Array; |
| The_Element : Array_Element_Id := No_Array_Element; |
| Array_Index : Name_Id := No_Name; |
| |
| begin |
| if The_Package /= No_Package then |
| The_Array := |
| Shared.Packages.Table (The_Package).Decl.Arrays; |
| else |
| The_Array := The_Project.Decl.Arrays; |
| end if; |
| |
| while The_Array /= No_Array |
| and then Shared.Arrays.Table (The_Array).Name /= |
| The_Name |
| loop |
| The_Array := Shared.Arrays.Table (The_Array).Next; |
| end loop; |
| |
| if The_Array /= No_Array then |
| The_Element := |
| Shared.Arrays.Table (The_Array).Value; |
| Array_Index := |
| Get_Attribute_Index |
| (From_Project_Node_Tree, |
| The_Current_Term, |
| Index); |
| |
| while The_Element /= No_Array_Element |
| and then Shared.Array_Elements.Table |
| (The_Element).Index /= Array_Index |
| loop |
| The_Element := |
| Shared.Array_Elements.Table (The_Element).Next; |
| end loop; |
| |
| end if; |
| |
| if The_Element /= No_Array_Element then |
| The_Variable := |
| Shared.Array_Elements.Table (The_Element).Value; |
| |
| else |
| if Expression_Kind_Of |
| (The_Current_Term, From_Project_Node_Tree) = |
| List |
| then |
| The_Variable := |
| (Project => Project, |
| Kind => List, |
| Location => No_Location, |
| Default => True, |
| Values => Nil_String); |
| else |
| The_Variable := |
| (Project => Project, |
| Kind => Single, |
| Location => No_Location, |
| Default => True, |
| Value => Empty_String, |
| Index => 0); |
| end if; |
| end if; |
| end; |
| end if; |
| |
| -- Check the defaults |
| |
| if Current_Term_Kind = N_Attribute_Reference then |
| declare |
| The_Default : constant Attribute_Default_Value := |
| Default_Of |
| (The_Current_Term, From_Project_Node_Tree); |
| |
| begin |
| -- Check the special value for 'Target when specified |
| |
| if The_Default = Target_Value |
| and then Opt.Target_Origin = Specified |
| then |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer (Opt.Target_Value.all); |
| The_Variable.Value := Name_Find; |
| |
| -- Check the defaults |
| |
| elsif The_Variable.Default then |
| case The_Variable.Kind is |
| |
| when Undefined => |
| null; |
| |
| when Single => |
| case The_Default is |
| when Read_Only_Value => |
| null; |
| |
| when Empty_Value => |
| The_Variable.Value := Empty_String; |
| |
| when Dot_Value => |
| The_Variable.Value := Dot_String; |
| |
| when Object_Dir_Value => |
| From_Project_Node_Tree.Project_Nodes.Table |
| (The_Current_Term).Name := |
| Snames.Name_Object_Dir; |
| From_Project_Node_Tree.Project_Nodes.Table |
| (The_Current_Term).Default := |
| Dot_Value; |
| goto Object_Dir_Restart; |
| |
| when Target_Value => |
| if Opt.Target_Value = null then |
| The_Variable.Value := Empty_String; |
| |
| else |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (Opt.Target_Value.all); |
| The_Variable.Value := Name_Find; |
| end if; |
| |
| when Runtime_Value => |
| Get_Name_String (Index); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| The_Variable.Value := |
| Runtime_Defaults.Get (Name_Find); |
| if The_Variable.Value = No_Name then |
| The_Variable.Value := Empty_String; |
| end if; |
| |
| end case; |
| |
| when List => |
| case The_Default is |
| when Read_Only_Value => |
| null; |
| |
| when Empty_Value => |
| The_Variable.Values := Nil_String; |
| |
| when Dot_Value => |
| The_Variable.Values := |
| Shared.Dot_String_List; |
| |
| when Object_Dir_Value | |
| Target_Value | |
| Runtime_Value => |
| null; |
| end case; |
| end case; |
| end if; |
| end; |
| end if; |
| |
| case Kind is |
| when Undefined => |
| |
| -- Should never happen |
| |
| pragma Assert (False, "undefined expression kind"); |
| null; |
| |
| when Single => |
| case The_Variable.Kind is |
| |
| when Undefined => |
| null; |
| |
| when Single => |
| Add (Result.Value, The_Variable.Value); |
| |
| when List => |
| |
| -- Should never happen |
| |
| pragma Assert |
| (False, |
| "list cannot appear in single " & |
| "string expression"); |
| null; |
| end case; |
| |
| when List => |
| case The_Variable.Kind is |
| |
| when Undefined => |
| null; |
| |
| when Single => |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| if Last = Nil_String then |
| |
| -- This can happen in an expression such as |
| -- () & Var |
| |
| Result.Values := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| else |
| Shared.String_Elements.Table (Last).Next := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| end if; |
| |
| Last := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| Shared.String_Elements.Table (Last) := |
| (Value => The_Variable.Value, |
| Display_Value => No_Name, |
| Location => Location_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Flag => False, |
| Next => Nil_String, |
| Index => 0); |
| |
| when List => |
| |
| declare |
| The_List : String_List_Id := |
| The_Variable.Values; |
| |
| begin |
| while The_List /= Nil_String loop |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| if Last = Nil_String then |
| Result.Values := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| else |
| Shared. |
| String_Elements.Table (Last).Next := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| end if; |
| |
| Last := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| Shared.String_Elements.Table |
| (Last) := |
| (Value => |
| Shared.String_Elements.Table |
| (The_List).Value, |
| Display_Value => No_Name, |
| Location => |
| Location_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Flag => False, |
| Next => Nil_String, |
| Index => 0); |
| |
| The_List := Shared.String_Elements.Table |
| (The_List).Next; |
| end loop; |
| end; |
| end case; |
| end case; |
| end; |
| |
| when N_External_Value => |
| Get_Name_String |
| (String_Value_Of |
| (External_Reference_Of |
| (The_Current_Term, From_Project_Node_Tree), |
| From_Project_Node_Tree)); |
| |
| declare |
| Name : constant Name_Id := Name_Find; |
| Default : Name_Id := No_Name; |
| Value : Name_Id := No_Name; |
| Ext_List : Boolean := False; |
| Str_List : String_List_Access := null; |
| Def_Var : Variable_Value; |
| |
| Default_Node : constant Project_Node_Id := |
| External_Default_Of |
| (The_Current_Term, |
| From_Project_Node_Tree); |
| |
| begin |
| -- If there is a default value for the external reference, |
| -- get its value. |
| |
| if Present (Default_Node) then |
| Def_Var := Expression |
| (Project => Project, |
| Shared => Shared, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Pkg => Pkg, |
| First_Term => |
| Tree.First_Term |
| (Default_Node, From_Project_Node_Tree), |
| Kind => Single); |
| |
| if Def_Var /= Nil_Variable_Value then |
| Default := Def_Var.Value; |
| end if; |
| end if; |
| |
| Ext_List := Expression_Kind_Of |
| (The_Current_Term, |
| From_Project_Node_Tree) = List; |
| |
| if Ext_List then |
| Value := Prj.Ext.Value_Of (Env.External, Name, No_Name); |
| |
| if Value /= No_Name then |
| declare |
| Sep : constant String := |
| Get_Name_String (Default); |
| First : Positive := 1; |
| Lst : Natural; |
| Done : Boolean := False; |
| Nmb : Natural; |
| |
| begin |
| Get_Name_String (Value); |
| |
| if Name_Len = 0 |
| or else Sep'Length = 0 |
| or else Name_Buffer (1 .. Name_Len) = Sep |
| then |
| Done := True; |
| end if; |
| |
| if not Done and then Name_Len < Sep'Length then |
| Str_List := |
| new String_List' |
| (1 => new String' |
| (Name_Buffer (1 .. Name_Len))); |
| Done := True; |
| end if; |
| |
| if not Done then |
| if Name_Buffer (1 .. Sep'Length) = Sep then |
| First := Sep'Length + 1; |
| end if; |
| |
| if Name_Len - First + 1 >= Sep'Length |
| and then |
| Name_Buffer (Name_Len - Sep'Length + 1 .. |
| Name_Len) = Sep |
| then |
| Name_Len := Name_Len - Sep'Length; |
| end if; |
| |
| if Name_Len = 0 then |
| Str_List := |
| new String_List'(1 => new String'("")); |
| Done := True; |
| end if; |
| end if; |
| |
| if not Done then |
| |
| -- Count the number of strings |
| |
| declare |
| Saved : constant Positive := First; |
| |
| begin |
| Nmb := 1; |
| loop |
| Lst := |
| Index |
| (Source => |
| Name_Buffer (First .. Name_Len), |
| Pattern => Sep); |
| exit when Lst = 0; |
| Nmb := Nmb + 1; |
| First := Lst + Sep'Length; |
| end loop; |
| |
| First := Saved; |
| end; |
| |
| Str_List := new String_List (1 .. Nmb); |
| |
| -- Populate the string list |
| |
| Nmb := 1; |
| loop |
| Lst := |
| Index |
| (Source => |
| Name_Buffer (First .. Name_Len), |
| Pattern => Sep); |
| |
| if Lst = 0 then |
| Str_List (Nmb) := |
| new String' |
| (Name_Buffer (First .. Name_Len)); |
| exit; |
| |
| else |
| Str_List (Nmb) := |
| new String' |
| (Name_Buffer (First .. Lst - 1)); |
| Nmb := Nmb + 1; |
| First := Lst + Sep'Length; |
| end if; |
| end loop; |
| end if; |
| end; |
| end if; |
| |
| else |
| -- Get the value |
| |
| Value := Prj.Ext.Value_Of (Env.External, Name, Default); |
| |
| if Value = No_Name then |
| if not Quiet_Output then |
| Error_Msg |
| (Env.Flags, "?undefined external reference", |
| Location_Of |
| (The_Current_Term, From_Project_Node_Tree), |
| Project); |
| end if; |
| |
| Value := Empty_String; |
| end if; |
| end if; |
| |
| case Kind is |
| |
| when Undefined => |
| null; |
| |
| when Single => |
| if Ext_List then |
| null; -- error |
| |
| else |
| Add (Result.Value, Value); |
| end if; |
| |
| when List => |
| if not Ext_List or else Str_List /= null then |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| if Last = Nil_String then |
| Result.Values := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| else |
| Shared.String_Elements.Table (Last).Next |
| := String_Element_Table.Last |
| (Shared.String_Elements); |
| end if; |
| |
| Last := String_Element_Table.Last |
| (Shared.String_Elements); |
| |
| if Ext_List then |
| for Ind in Str_List'Range loop |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer (Str_List (Ind).all); |
| Value := Name_Find; |
| Shared.String_Elements.Table (Last) := |
| (Value => Value, |
| Display_Value => No_Name, |
| Location => |
| Location_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Flag => False, |
| Next => Nil_String, |
| Index => 0); |
| |
| if Ind /= Str_List'Last then |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| Shared.String_Elements.Table (Last).Next := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| Last := String_Element_Table.Last |
| (Shared.String_Elements); |
| end if; |
| end loop; |
| |
| else |
| Shared.String_Elements.Table (Last) := |
| (Value => Value, |
| Display_Value => No_Name, |
| Location => |
| Location_Of |
| (The_Current_Term, |
| From_Project_Node_Tree), |
| Flag => False, |
| Next => Nil_String, |
| Index => 0); |
| end if; |
| end if; |
| end case; |
| end; |
| |
| when others => |
| |
| -- Should never happen |
| |
| pragma Assert |
| (False, |
| "illegal node kind in an expression"); |
| raise Program_Error; |
| |
| end case; |
| end if; |
| |
| The_Term := Next_Term (The_Term, From_Project_Node_Tree); |
| end loop; |
| |
| return Result; |
| end Expression; |
| |
| --------------------------------------- |
| -- Imported_Or_Extended_Project_From -- |
| --------------------------------------- |
| |
| function Imported_Or_Extended_Project_From |
| (Project : Project_Id; |
| With_Name : Name_Id; |
| No_Extending : Boolean := False) return Project_Id |
| is |
| List : Project_List; |
| Result : Project_Id; |
| Temp_Result : Project_Id; |
| |
| begin |
| -- First check if it is the name of an extended project |
| |
| Result := Project.Extends; |
| while Result /= No_Project loop |
| if Result.Name = With_Name then |
| return Result; |
| else |
| Result := Result.Extends; |
| end if; |
| end loop; |
| |
| -- Then check the name of each imported project |
| |
| Temp_Result := No_Project; |
| List := Project.Imported_Projects; |
| while List /= null loop |
| Result := List.Project; |
| |
| -- If the project is directly imported, then returns its ID |
| |
| if Result.Name = With_Name then |
| return Result; |
| end if; |
| |
| -- If a project extending the project is imported, then keep this |
| -- extending project as a possibility. It will be the returned ID |
| -- if the project is not imported directly. |
| |
| declare |
| Proj : Project_Id; |
| |
| begin |
| Proj := Result.Extends; |
| while Proj /= No_Project loop |
| if Proj.Name = With_Name then |
| if No_Extending then |
| Temp_Result := Proj; |
| else |
| Temp_Result := Result; |
| end if; |
| |
| exit; |
| end if; |
| |
| Proj := Proj.Extends; |
| end loop; |
| end; |
| |
| List := List.Next; |
| end loop; |
| |
| pragma Assert (Temp_Result /= No_Project, "project not found"); |
| return Temp_Result; |
| end Imported_Or_Extended_Project_From; |
| |
| ------------------ |
| -- Package_From -- |
| ------------------ |
| |
| function Package_From |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access; |
| With_Name : Name_Id) return Package_Id |
| is |
| Result : Package_Id := Project.Decl.Packages; |
| |
| begin |
| -- Check the name of each existing package of Project |
| |
| while Result /= No_Package |
| and then Shared.Packages.Table (Result).Name /= With_Name |
| loop |
| Result := Shared.Packages.Table (Result).Next; |
| end loop; |
| |
| if Result = No_Package then |
| |
| -- Should never happen |
| |
| Write_Line |
| ("package """ & Get_Name_String (With_Name) & """ not found"); |
| raise Program_Error; |
| |
| else |
| return Result; |
| end if; |
| end Package_From; |
| |
| ------------- |
| -- Process -- |
| ------------- |
| |
| procedure Process |
| (In_Tree : Project_Tree_Ref; |
| Project : out Project_Id; |
| Packages_To_Check : String_List_Access; |
| Success : out Boolean; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : in out Prj.Tree.Environment; |
| Reset_Tree : Boolean := True; |
| On_New_Tree_Loaded : Tree_Loaded_Callback := null) |
| is |
| begin |
| Process_Project_Tree_Phase_1 |
| (In_Tree => In_Tree, |
| Project => Project, |
| Success => Success, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Packages_To_Check => Packages_To_Check, |
| Reset_Tree => Reset_Tree, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| |
| if Project_Qualifier_Of |
| (From_Project_Node, From_Project_Node_Tree) /= Configuration |
| then |
| Process_Project_Tree_Phase_2 |
| (In_Tree => In_Tree, |
| Project => Project, |
| Success => Success, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env); |
| end if; |
| end Process; |
| |
| ------------------------------- |
| -- Process_Declarative_Items -- |
| ------------------------------- |
| |
| procedure Process_Declarative_Items |
| (Project : Project_Id; |
| In_Tree : Project_Tree_Ref; |
| From_Project_Node : Project_Node_Id; |
| Node_Tree : Project_Node_Tree_Ref; |
| Env : Prj.Tree.Environment; |
| Pkg : Package_Id; |
| Item : Project_Node_Id; |
| Child_Env : in out Prj.Tree.Environment) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared; |
| |
| procedure Check_Or_Set_Typed_Variable |
| (Value : in out Variable_Value; |
| Declaration : Project_Node_Id); |
| -- Check whether Value is valid for this typed variable declaration. If |
| -- it is an error, the behavior depends on the flags: either an error is |
| -- reported, or a warning, or nothing. In the last two cases, the value |
| -- of the variable is set to a valid value, replacing Value. |
| |
| procedure Process_Package_Declaration |
| (Current_Item : Project_Node_Id); |
| procedure Process_Attribute_Declaration |
| (Current : Project_Node_Id); |
| procedure Process_Case_Construction |
| (Current_Item : Project_Node_Id); |
| procedure Process_Associative_Array |
| (Current_Item : Project_Node_Id); |
| procedure Process_Expression |
| (Current : Project_Node_Id); |
| procedure Process_Expression_For_Associative_Array |
| (Current : Project_Node_Id; |
| New_Value : Variable_Value); |
| procedure Process_Expression_Variable_Decl |
| (Current_Item : Project_Node_Id; |
| New_Value : Variable_Value); |
| -- Process the various declarative items |
| |
| --------------------------------- |
| -- Check_Or_Set_Typed_Variable -- |
| --------------------------------- |
| |
| procedure Check_Or_Set_Typed_Variable |
| (Value : in out Variable_Value; |
| Declaration : Project_Node_Id) |
| is |
| Loc : constant Source_Ptr := Location_Of (Declaration, Node_Tree); |
| |
| Reset_Value : Boolean := False; |
| Current_String : Project_Node_Id; |
| |
| begin |
| -- Report an error for an empty string |
| |
| if Value.Value = Empty_String then |
| Error_Msg_Name_1 := Name_Of (Declaration, Node_Tree); |
| |
| case Env.Flags.Allow_Invalid_External is |
| when Error => |
| Error_Msg |
| (Env.Flags, "no value defined for %%", Loc, Project); |
| when Warning => |
| Reset_Value := True; |
| Error_Msg |
| (Env.Flags, "?no value defined for %%", Loc, Project); |
| when Silent => |
| Reset_Value := True; |
| end case; |
| |
| else |
| -- Loop through all the valid strings for the |
| -- string type and compare to the string value. |
| |
| Current_String := |
| First_Literal_String |
| (String_Type_Of (Declaration, Node_Tree), Node_Tree); |
| |
| while Present (Current_String) |
| and then |
| String_Value_Of (Current_String, Node_Tree) /= Value.Value |
| loop |
| Current_String := |
| Next_Literal_String (Current_String, Node_Tree); |
| end loop; |
| |
| -- Report error if string value is not one for the string type |
| |
| if No (Current_String) then |
| Error_Msg_Name_1 := Value.Value; |
| Error_Msg_Name_2 := Name_Of (Declaration, Node_Tree); |
| |
| case Env.Flags.Allow_Invalid_External is |
| when Error => |
| Error_Msg |
| (Env.Flags, "value %% is illegal for typed string %%", |
| Loc, Project); |
| |
| when Warning => |
| Error_Msg |
| (Env.Flags, "?value %% is illegal for typed string %%", |
| Loc, Project); |
| Reset_Value := True; |
| |
| when Silent => |
| Reset_Value := True; |
| end case; |
| end if; |
| end if; |
| |
| if Reset_Value then |
| Current_String := |
| First_Literal_String |
| (String_Type_Of (Declaration, Node_Tree), Node_Tree); |
| Value.Value := String_Value_Of (Current_String, Node_Tree); |
| end if; |
| end Check_Or_Set_Typed_Variable; |
| |
| --------------------------------- |
| -- Process_Package_Declaration -- |
| --------------------------------- |
| |
| procedure Process_Package_Declaration |
| (Current_Item : Project_Node_Id) |
| is |
| begin |
| -- Do not process a package declaration that should be ignored |
| |
| if Expression_Kind_Of (Current_Item, Node_Tree) /= Ignored then |
| |
| -- Create the new package |
| |
| Package_Table.Increment_Last (Shared.Packages); |
| |
| declare |
| New_Pkg : constant Package_Id := |
| Package_Table.Last (Shared.Packages); |
| The_New_Package : Package_Element; |
| |
| Project_Of_Renamed_Package : constant Project_Node_Id := |
| Project_Of_Renamed_Package_Of |
| (Current_Item, Node_Tree); |
| |
| begin |
| -- Set the name of the new package |
| |
| The_New_Package.Name := Name_Of (Current_Item, Node_Tree); |
| |
| -- Insert the new package in the appropriate list |
| |
| if Pkg /= No_Package then |
| The_New_Package.Next := |
| Shared.Packages.Table (Pkg).Decl.Packages; |
| Shared.Packages.Table (Pkg).Decl.Packages := New_Pkg; |
| |
| else |
| The_New_Package.Next := Project.Decl.Packages; |
| Project.Decl.Packages := New_Pkg; |
| end if; |
| |
| Shared.Packages.Table (New_Pkg) := The_New_Package; |
| |
| if Present (Project_Of_Renamed_Package) then |
| |
| -- Renamed or extending package |
| |
| declare |
| Project_Name : constant Name_Id := |
| Name_Of (Project_Of_Renamed_Package, |
| Node_Tree); |
| |
| Renamed_Project : constant Project_Id := |
| Imported_Or_Extended_Project_From |
| (Project, Project_Name); |
| |
| Renamed_Package : constant Package_Id := |
| Package_From |
| (Renamed_Project, Shared, |
| Name_Of (Current_Item, Node_Tree)); |
| |
| begin |
| -- For a renamed package, copy the declarations of the |
| -- renamed package, but set all the locations to the |
| -- location of the package name in the renaming |
| -- declaration. |
| |
| Copy_Package_Declarations |
| (From => Shared.Packages.Table |
| (Renamed_Package).Decl, |
| To => Shared.Packages.Table (New_Pkg).Decl, |
| New_Loc => Location_Of (Current_Item, Node_Tree), |
| Restricted => False, |
| Shared => Shared); |
| end; |
| |
| else |
| -- Set the default values of the attributes |
| |
| Add_Attributes |
| (Project, |
| Project.Name, |
| Name_Id (Project.Directory.Display_Name), |
| Shared, |
| Shared.Packages.Table (New_Pkg).Decl, |
| First_Attribute_Of |
| (Package_Id_Of (Current_Item, Node_Tree)), |
| Project_Level => False); |
| end if; |
| |
| -- Process declarative items (nothing to do when the package is |
| -- renaming, as the first declarative item is null). |
| |
| Process_Declarative_Items |
| (Project => Project, |
| In_Tree => In_Tree, |
| From_Project_Node => From_Project_Node, |
| Node_Tree => Node_Tree, |
| Env => Env, |
| Pkg => New_Pkg, |
| Item => |
| First_Declarative_Item_Of (Current_Item, Node_Tree), |
| Child_Env => Child_Env); |
| end; |
| end if; |
| end Process_Package_Declaration; |
| |
| ------------------------------- |
| -- Process_Associative_Array -- |
| ------------------------------- |
| |
| procedure Process_Associative_Array |
| (Current_Item : Project_Node_Id) |
| is |
| Current_Item_Name : constant Name_Id := |
| Name_Of (Current_Item, Node_Tree); |
| -- The name of the attribute |
| |
| Current_Location : constant Source_Ptr := |
| Location_Of (Current_Item, Node_Tree); |
| |
| New_Array : Array_Id; |
| -- The new associative array created |
| |
| Orig_Array : Array_Id; |
| -- The associative array value |
| |
| Orig_Project_Name : Name_Id := No_Name; |
| -- The name of the project where the associative array |
| -- value is. |
| |
| Orig_Project : Project_Id := No_Project; |
| -- The id of the project where the associative array |
| -- value is. |
| |
| Orig_Package_Name : Name_Id := No_Name; |
| -- The name of the package, if any, where the associative array value |
| -- is located. |
| |
| Orig_Package : Package_Id := No_Package; |
| -- The id of the package, if any, where the associative array value |
| -- is located. |
| |
| New_Element : Array_Element_Id := No_Array_Element; |
| -- Id of a new array element created |
| |
| Prev_Element : Array_Element_Id := No_Array_Element; |
| -- Last new element id created |
| |
| Orig_Element : Array_Element_Id := No_Array_Element; |
| -- Current array element in original associative array |
| |
| Next_Element : Array_Element_Id := No_Array_Element; |
| -- Id of the array element that follows the new element. This is not |
| -- always nil, because values for the associative array attribute may |
| -- already have been declared, and the array elements declared are |
| -- reused. |
| |
| Prj : Project_List; |
| |
| begin |
| -- First find if the associative array attribute already has elements |
| -- declared. |
| |
| if Pkg /= No_Package then |
| New_Array := Shared.Packages.Table (Pkg).Decl.Arrays; |
| else |
| New_Array := Project.Decl.Arrays; |
| end if; |
| |
| while New_Array /= No_Array |
| and then Shared.Arrays.Table (New_Array).Name /= Current_Item_Name |
| loop |
| New_Array := Shared.Arrays.Table (New_Array).Next; |
| end loop; |
| |
| -- If the attribute has never been declared add new entry in the |
| -- arrays of the project/package and link it. |
| |
| if New_Array = No_Array then |
| Array_Table.Increment_Last (Shared.Arrays); |
| New_Array := Array_Table.Last (Shared.Arrays); |
| |
| if Pkg /= No_Package then |
| Shared.Arrays.Table (New_Array) := |
| (Name => Current_Item_Name, |
| Location => Current_Location, |
| Value => No_Array_Element, |
| Next => Shared.Packages.Table (Pkg).Decl.Arrays); |
| |
| Shared.Packages.Table (Pkg).Decl.Arrays := New_Array; |
| |
| else |
| Shared.Arrays.Table (New_Array) := |
| (Name => Current_Item_Name, |
| Location => Current_Location, |
| Value => No_Array_Element, |
| Next => Project.Decl.Arrays); |
| |
| Project.Decl.Arrays := New_Array; |
| end if; |
| end if; |
| |
| -- Find the project where the value is declared |
| |
| Orig_Project_Name := |
| Name_Of |
| (Associative_Project_Of (Current_Item, Node_Tree), Node_Tree); |
| |
| Prj := In_Tree.Projects; |
| while Prj /= null loop |
| if Prj.Project.Name = Orig_Project_Name then |
| Orig_Project := Prj.Project; |
| exit; |
| end if; |
| Prj := Prj.Next; |
| end loop; |
| |
| pragma Assert (Orig_Project /= No_Project, |
| "original project not found"); |
| |
| if No (Associative_Package_Of (Current_Item, Node_Tree)) then |
| Orig_Array := Orig_Project.Decl.Arrays; |
| |
| else |
| -- If in a package, find the package where the value is declared |
| |
| Orig_Package_Name := |
| Name_Of |
| (Associative_Package_Of (Current_Item, Node_Tree), Node_Tree); |
| |
| Orig_Package := Orig_Project.Decl.Packages; |
| pragma Assert (Orig_Package /= No_Package, |
| "original package not found"); |
| |
| while Shared.Packages.Table |
| (Orig_Package).Name /= Orig_Package_Name |
| loop |
| Orig_Package := Shared.Packages.Table (Orig_Package).Next; |
| pragma Assert (Orig_Package /= No_Package, |
| "original package not found"); |
| end loop; |
| |
| Orig_Array := Shared.Packages.Table (Orig_Package).Decl.Arrays; |
| end if; |
| |
| -- Now look for the array |
| |
| while Orig_Array /= No_Array |
| and then Shared.Arrays.Table (Orig_Array).Name /= Current_Item_Name |
| loop |
| Orig_Array := Shared.Arrays.Table (Orig_Array).Next; |
| end loop; |
| |
| if Orig_Array = No_Array then |
| Error_Msg |
| (Env.Flags, |
| "associative array value not found", |
| Location_Of (Current_Item, Node_Tree), |
| Project); |
| |
| else |
| Orig_Element := Shared.Arrays.Table (Orig_Array).Value; |
| |
| -- Copy each array element |
| |
| while Orig_Element /= No_Array_Element loop |
| |
| -- Case of first element |
| |
| if Prev_Element = No_Array_Element then |
| |
| -- And there is no array element declared yet, create a new |
| -- first array element. |
| |
| if Shared.Arrays.Table (New_Array).Value = |
| No_Array_Element |
| then |
| Array_Element_Table.Increment_Last |
| (Shared.Array_Elements); |
| New_Element := Array_Element_Table.Last |
| (Shared.Array_Elements); |
| Shared.Arrays.Table (New_Array).Value := New_Element; |
| Next_Element := No_Array_Element; |
| |
| -- Otherwise, the new element is the first |
| |
| else |
| New_Element := Shared.Arrays.Table (New_Array).Value; |
| Next_Element := |
| Shared.Array_Elements.Table (New_Element).Next; |
| end if; |
| |
| -- Otherwise, reuse an existing element, or create |
| -- one if necessary. |
| |
| else |
| Next_Element := |
| Shared.Array_Elements.Table (Prev_Element).Next; |
| |
| if Next_Element = No_Array_Element then |
| Array_Element_Table.Increment_Last |
| (Shared.Array_Elements); |
| New_Element := Array_Element_Table.Last |
| (Shared.Array_Elements); |
| Shared.Array_Elements.Table (Prev_Element).Next := |
| New_Element; |
| |
| else |
| New_Element := Next_Element; |
| Next_Element := |
| Shared.Array_Elements.Table (New_Element).Next; |
| end if; |
| end if; |
| |
| -- Copy the value of the element |
| |
| Shared.Array_Elements.Table (New_Element) := |
| Shared.Array_Elements.Table (Orig_Element); |
| Shared.Array_Elements.Table (New_Element).Value.Project |
| := Project; |
| |
| -- Adjust the Next link |
| |
| Shared.Array_Elements.Table (New_Element).Next := Next_Element; |
| |
| -- Adjust the previous id for the next element |
| |
| Prev_Element := New_Element; |
| |
| -- Go to the next element in the original array |
| |
| Orig_Element := Shared.Array_Elements.Table (Orig_Element).Next; |
| end loop; |
| |
| -- Make sure that the array ends here, in case there previously a |
| -- greater number of elements. |
| |
| Shared.Array_Elements.Table (New_Element).Next := No_Array_Element; |
| end if; |
| end Process_Associative_Array; |
| |
| ---------------------------------------------- |
| -- Process_Expression_For_Associative_Array -- |
| ---------------------------------------------- |
| |
| procedure Process_Expression_For_Associative_Array |
| (Current : Project_Node_Id; |
| New_Value : Variable_Value) |
| is |
| Name : constant Name_Id := Name_Of (Current, Node_Tree); |
| Current_Location : constant Source_Ptr := |
| Location_Of (Current, Node_Tree); |
| |
| Index_Name : Name_Id := |
| Associative_Array_Index_Of (Current, Node_Tree); |
| |
| Source_Index : constant Int := |
| Source_Index_Of (Current, Node_Tree); |
| |
| The_Array : Array_Id; |
| Elem : Array_Element_Id := No_Array_Element; |
| |
| begin |
| if Index_Name /= All_Other_Names then |
| Index_Name := Get_Attribute_Index (Node_Tree, Current, Index_Name); |
| end if; |
| |
| -- Look for the array in the appropriate list |
| |
| if Pkg /= No_Package then |
| The_Array := Shared.Packages.Table (Pkg).Decl.Arrays; |
| else |
| The_Array := Project.Decl.Arrays; |
| end if; |
| |
| while The_Array /= No_Array |
| and then Shared.Arrays.Table (The_Array).Name /= Name |
| loop |
| The_Array := Shared.Arrays.Table (The_Array).Next; |
| end loop; |
| |
| -- If the array cannot be found, create a new entry in the list. |
| -- As The_Array_Element is initialized to No_Array_Element, a new |
| -- element will be created automatically later |
| |
| if The_Array = No_Array then |
| Array_Table.Increment_Last (Shared.Arrays); |
| The_Array := Array_Table.Last (Shared.Arrays); |
| |
| if Pkg /= No_Package then |
| Shared.Arrays.Table (The_Array) := |
| (Name => Name, |
| Location => Current_Location, |
| Value => No_Array_Element, |
| Next => Shared.Packages.Table (Pkg).Decl.Arrays); |
| |
| Shared.Packages.Table (Pkg).Decl.Arrays := The_Array; |
| |
| else |
| Shared.Arrays.Table (The_Array) := |
| (Name => Name, |
| Location => Current_Location, |
| Value => No_Array_Element, |
| Next => Project.Decl.Arrays); |
| |
| Project.Decl.Arrays := The_Array; |
| end if; |
| |
| else |
| Elem := Shared.Arrays.Table (The_Array).Value; |
| end if; |
| |
| -- Look in the list, if any, to find an element with the same index |
| -- and same source index. |
| |
| while Elem /= No_Array_Element |
| and then |
| (Shared.Array_Elements.Table (Elem).Index /= Index_Name |
| or else |
| Shared.Array_Elements.Table (Elem).Src_Index /= Source_Index) |
| loop |
| Elem := Shared.Array_Elements.Table (Elem).Next; |
| end loop; |
| |
| -- If no such element were found, create a new one |
| -- and insert it in the element list, with the |
| -- proper value. |
| |
| if Elem = No_Array_Element then |
| Array_Element_Table.Increment_Last (Shared.Array_Elements); |
| Elem := Array_Element_Table.Last (Shared.Array_Elements); |
| |
| Shared.Array_Elements.Table |
| (Elem) := |
| (Index => Index_Name, |
| Restricted => False, |
| Src_Index => Source_Index, |
| Index_Case_Sensitive => |
| not Case_Insensitive (Current, Node_Tree), |
| Value => New_Value, |
| Next => Shared.Arrays.Table (The_Array).Value); |
| |
| Shared.Arrays.Table (The_Array).Value := Elem; |
| |
| else |
| -- An element with the same index already exists, just replace its |
| -- value with the new one. |
| |
| Shared.Array_Elements.Table (Elem).Value := New_Value; |
| end if; |
| |
| if Name = Snames.Name_External then |
| if In_Tree.Is_Root_Tree then |
| Add (Child_Env.External, |
| External_Name => Get_Name_String (Index_Name), |
| Value => Get_Name_String (New_Value.Value), |
| Source => From_External_Attribute); |
| Add (Env.External, |
| External_Name => Get_Name_String (Index_Name), |
| Value => Get_Name_String (New_Value.Value), |
| Source => From_External_Attribute, |
| Silent => True); |
| else |
| if Current_Verbosity = High then |
| Debug_Output |
| ("'for External' has no effect except in root aggregate (" |
| & Get_Name_String (Index_Name) & ")", New_Value.Value); |
| end if; |
| end if; |
| end if; |
| end Process_Expression_For_Associative_Array; |
| |
| -------------------------------------- |
| -- Process_Expression_Variable_Decl -- |
| -------------------------------------- |
| |
| procedure Process_Expression_Variable_Decl |
| (Current_Item : Project_Node_Id; |
| New_Value : Variable_Value) |
| is |
| Name : constant Name_Id := Name_Of (Current_Item, Node_Tree); |
| |
| Is_Attribute : constant Boolean := |
| Kind_Of (Current_Item, Node_Tree) = |
| N_Attribute_Declaration; |
| |
| Var : Variable_Id := No_Variable; |
| |
| begin |
| -- First, find the list where to find the variable or attribute |
| |
| if Is_Attribute then |
| if Pkg /= No_Package then |
| Var := Shared.Packages.Table (Pkg).Decl.Attributes; |
| else |
| Var := Project.Decl.Attributes; |
| end if; |
| |
| else |
| if Pkg /= No_Package then |
| Var := Shared.Packages.Table (Pkg).Decl.Variables; |
| else |
| Var := Project.Decl.Variables; |
| end if; |
| end if; |
| |
| -- Loop through the list, to find if it has already been declared |
| |
| while Var /= No_Variable |
| and then Shared.Variable_Elements.Table (Var).Name /= Name |
| loop |
| Var := Shared.Variable_Elements.Table (Var).Next; |
| end loop; |
| |
| -- If it has not been declared, create a new entry in the list |
| |
| if Var = No_Variable then |
| |
| -- All single string attribute should already have been declared |
| -- with a default empty string value. |
| |
| pragma Assert |
| (not Is_Attribute, |
| "illegal attribute declaration for " & Get_Name_String (Name)); |
| |
| Variable_Element_Table.Increment_Last (Shared.Variable_Elements); |
| Var := Variable_Element_Table.Last (Shared.Variable_Elements); |
| |
| -- Put the new variable in the appropriate list |
| |
| if Pkg /= No_Package then |
| Shared.Variable_Elements.Table (Var) := |
| (Next => Shared.Packages.Table (Pkg).Decl.Variables, |
| Name => Name, |
| Value => New_Value); |
| Shared.Packages.Table (Pkg).Decl.Variables := Var; |
| |
| else |
| Shared.Variable_Elements.Table (Var) := |
| (Next => Project.Decl.Variables, |
| Name => Name, |
| Value => New_Value); |
| Project.Decl.Variables := Var; |
| end if; |
| |
| -- If the variable/attribute has already been declared, just |
| -- change the value. |
| |
| else |
| Shared.Variable_Elements.Table (Var).Value := New_Value; |
| end if; |
| |
| if Is_Attribute and then Name = Snames.Name_Project_Path then |
| if In_Tree.Is_Root_Tree then |
| declare |
| package Name_Ids is |
| new Ada.Containers.Vectors (Positive, Name_Id); |
| Val : String_List_Id := New_Value.Values; |
| List : Name_Ids.Vector; |
| begin |
| -- Get all values |
| |
| while Val /= Nil_String loop |
| List.Prepend |
| (Shared.String_Elements.Table (Val).Value); |
| Val := Shared.String_Elements.Table (Val).Next; |
| end loop; |
| |
| -- Prepend them in the order found in the attribute |
| |
| for K in Positive range 1 .. Positive (List.Length) loop |
| Prj.Env.Add_Directories |
| (Child_Env.Project_Path, |
| Normalize_Pathname |
| (Name => Get_Name_String |
| (List.Element (K)), |
| Directory => Get_Name_String |
| (Project.Directory.Display_Name)), |
| Prepend => True); |
| end loop; |
| end; |
| |
| else |
| if Current_Verbosity = High then |
| Debug_Output |
| ("'for Project_Path' has no effect except in" |
| & " root aggregate"); |
| end if; |
| end if; |
| end if; |
| end Process_Expression_Variable_Decl; |
| |
| ------------------------ |
| -- Process_Expression -- |
| ------------------------ |
| |
| procedure Process_Expression (Current : Project_Node_Id) is |
| New_Value : Variable_Value := |
| Expression |
| (Project => Project, |
| Shared => Shared, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => Node_Tree, |
| Env => Env, |
| Pkg => Pkg, |
| First_Term => |
| Tree.First_Term |
| (Expression_Of (Current, Node_Tree), Node_Tree), |
| Kind => |
| Expression_Kind_Of (Current, Node_Tree)); |
| |
| begin |
| -- Process a typed variable declaration |
| |
| if Kind_Of (Current, Node_Tree) = N_Typed_Variable_Declaration then |
| Check_Or_Set_Typed_Variable (New_Value, Current); |
| end if; |
| |
| if Kind_Of (Current, Node_Tree) /= N_Attribute_Declaration |
| or else Associative_Array_Index_Of (Current, Node_Tree) = No_Name |
| then |
| Process_Expression_Variable_Decl (Current, New_Value); |
| else |
| Process_Expression_For_Associative_Array (Current, New_Value); |
| end if; |
| end Process_Expression; |
| |
| ----------------------------------- |
| -- Process_Attribute_Declaration -- |
| ----------------------------------- |
| |
| procedure Process_Attribute_Declaration (Current : Project_Node_Id) is |
| begin |
| if Expression_Of (Current, Node_Tree) = Empty_Node then |
| Process_Associative_Array (Current); |
| else |
| Process_Expression (Current); |
| end if; |
| end Process_Attribute_Declaration; |
| |
| ------------------------------- |
| -- Process_Case_Construction -- |
| ------------------------------- |
| |
| procedure Process_Case_Construction |
| (Current_Item : Project_Node_Id) |
| is |
| The_Project : Project_Id := Project; |
| -- The id of the project of the case variable |
| |
| The_Package : Package_Id := Pkg; |
| -- The id of the package, if any, of the case variable |
| |
| The_Variable : Variable_Value := Nil_Variable_Value; |
| -- The case variable |
| |
| Case_Value : Name_Id := No_Name; |
| -- The case variable value |
| |
| Case_Item : Project_Node_Id := Empty_Node; |
| Choice_String : Project_Node_Id := Empty_Node; |
| Decl_Item : Project_Node_Id := Empty_Node; |
| |
| begin |
| declare |
| Variable_Node : constant Project_Node_Id := |
| Case_Variable_Reference_Of |
| (Current_Item, |
| Node_Tree); |
| |
| Var_Id : Variable_Id := No_Variable; |
| Name : Name_Id := No_Name; |
| |
| begin |
| -- If a project was specified for the case variable, get its id |
| |
| if Present (Project_Node_Of (Variable_Node, Node_Tree)) then |
| Name := |
| Name_Of |
| (Project_Node_Of (Variable_Node, Node_Tree), Node_Tree); |
| The_Project := |
| Imported_Or_Extended_Project_From |
| (Project, Name, No_Extending => True); |
| The_Package := No_Package; |
| end if; |
| |
| -- If a package was specified for the case variable, get its id |
| |
| if Present (Package_Node_Of (Variable_Node, Node_Tree)) then |
| Name := |
| Name_Of |
| (Package_Node_Of (Variable_Node, Node_Tree), Node_Tree); |
| The_Package := Package_From (The_Project, Shared, Name); |
| end if; |
| |
| Name := Name_Of (Variable_Node, Node_Tree); |
| |
| -- First, look for the case variable into the package, if any |
| |
| if The_Package /= No_Package then |
| Name := Name_Of (Variable_Node, Node_Tree); |
| |
| Var_Id := Shared.Packages.Table (The_Package).Decl.Variables; |
| while Var_Id /= No_Variable |
| and then Shared.Variable_Elements.Table (Var_Id).Name /= Name |
| loop |
| Var_Id := Shared.Variable_Elements.Table (Var_Id).Next; |
| end loop; |
| end if; |
| |
| -- If not found in the package, or if there is no package, look at |
| -- the project level. |
| |
| if Var_Id = No_Variable |
| and then No (Package_Node_Of (Variable_Node, Node_Tree)) |
| then |
| Var_Id := The_Project.Decl.Variables; |
| while Var_Id /= No_Variable |
| and then Shared.Variable_Elements.Table (Var_Id).Name /= Name |
| loop |
| Var_Id := Shared.Variable_Elements.Table (Var_Id).Next; |
| end loop; |
| end if; |
| |
| if Var_Id = No_Variable then |
| if Node_Tree.Incomplete_With then |
| return; |
| |
| -- Should never happen, because this has already been checked |
| -- during parsing. |
| |
| else |
| Write_Line |
| ("variable """ & Get_Name_String (Name) & """ not found"); |
| raise Program_Error; |
| end if; |
| end if; |
| |
| -- Get the case variable |
| |
| The_Variable := Shared.Variable_Elements. Table (Var_Id).Value; |
| |
| if The_Variable.Kind /= Single then |
| |
| -- Should never happen, because this has already been checked |
| -- during parsing. |
| |
| Write_Line ("variable""" & Get_Name_String (Name) & |
| """ is not a single string variable"); |
| raise Program_Error; |
| end if; |
| |
| -- Get the case variable value |
| |
| Case_Value := The_Variable.Value; |
| end; |
| |
| -- Now look into all the case items of the case construction |
| |
| Case_Item := First_Case_Item_Of (Current_Item, Node_Tree); |
| |
| Case_Item_Loop : |
| while Present (Case_Item) loop |
| Choice_String := First_Choice_Of (Case_Item, Node_Tree); |
| |
| -- When Choice_String is nil, it means that it is the |
| -- "when others =>" alternative. |
| |
| if No (Choice_String) then |
| Decl_Item := First_Declarative_Item_Of (Case_Item, Node_Tree); |
| exit Case_Item_Loop; |
| end if; |
| |
| -- Look into all the alternative of this case item |
| |
| Choice_Loop : |
| while Present (Choice_String) loop |
| if Case_Value = String_Value_Of (Choice_String, Node_Tree) then |
| Decl_Item := |
| First_Declarative_Item_Of (Case_Item, Node_Tree); |
| exit Case_Item_Loop; |
| end if; |
| |
| Choice_String := Next_Literal_String (Choice_String, Node_Tree); |
| end loop Choice_Loop; |
| |
| Case_Item := Next_Case_Item (Case_Item, Node_Tree); |
| end loop Case_Item_Loop; |
| |
| -- If there is an alternative, then we process it |
| |
| if Present (Decl_Item) then |
| Process_Declarative_Items |
| (Project => Project, |
| In_Tree => In_Tree, |
| From_Project_Node => From_Project_Node, |
| Node_Tree => Node_Tree, |
| Env => Env, |
| Pkg => Pkg, |
| Item => Decl_Item, |
| Child_Env => Child_Env); |
| end if; |
| end Process_Case_Construction; |
| |
| -- Local variables |
| |
| Current, Decl : Project_Node_Id; |
| Kind : Project_Node_Kind; |
| |
| -- Start of processing for Process_Declarative_Items |
| |
| begin |
| Decl := Item; |
| while Present (Decl) loop |
| Current := Current_Item_Node (Decl, Node_Tree); |
| Decl := Next_Declarative_Item (Decl, Node_Tree); |
| Kind := Kind_Of (Current, Node_Tree); |
| |
| case Kind is |
| when N_Package_Declaration => |
| Process_Package_Declaration (Current); |
| |
| -- Nothing to process for string type declaration |
| |
| when N_String_Type_Declaration => |
| null; |
| |
| when N_Attribute_Declaration | |
| N_Typed_Variable_Declaration | |
| N_Variable_Declaration => |
| Process_Attribute_Declaration (Current); |
| |
| when N_Case_Construction => |
| Process_Case_Construction (Current); |
| |
| when others => |
| Write_Line ("Illegal declarative item: " & Kind'Img); |
| raise Program_Error; |
| end case; |
| end loop; |
| end Process_Declarative_Items; |
| |
| ---------------------------------- |
| -- Process_Project_Tree_Phase_1 -- |
| ---------------------------------- |
| |
| procedure Process_Project_Tree_Phase_1 |
| (In_Tree : Project_Tree_Ref; |
| Project : out Project_Id; |
| Packages_To_Check : String_List_Access; |
| Success : out Boolean; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : in out Prj.Tree.Environment; |
| Reset_Tree : Boolean := True; |
| On_New_Tree_Loaded : Tree_Loaded_Callback := null) |
| is |
| begin |
| if Reset_Tree then |
| |
| -- Make sure there are no projects in the data structure |
| |
| Free_List (In_Tree.Projects, Free_Project => True); |
| end if; |
| |
| Processed_Projects.Reset; |
| |
| -- And process the main project and all of the projects it depends on, |
| -- recursively. |
| |
| Debug_Increase_Indent ("Process tree, phase 1"); |
| |
| Recursive_Process |
| (Project => Project, |
| In_Tree => In_Tree, |
| Packages_To_Check => Packages_To_Check, |
| From_Project_Node => From_Project_Node, |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Extended_By => No_Project, |
| From_Encapsulated_Lib => False, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| |
| Success := |
| Total_Errors_Detected = 0 |
| and then |
| (Warning_Mode /= Treat_As_Error or else Warnings_Detected = 0); |
| |
| if Current_Verbosity = High then |
| Debug_Decrease_Indent |
| ("Done Process tree, phase 1, Success=" & Success'Img); |
| end if; |
| end Process_Project_Tree_Phase_1; |
| |
| ---------------------------------- |
| -- Process_Project_Tree_Phase_2 -- |
| ---------------------------------- |
| |
| procedure Process_Project_Tree_Phase_2 |
| (In_Tree : Project_Tree_Ref; |
| Project : Project_Id; |
| Success : out Boolean; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : Environment) |
| is |
| Obj_Dir : Path_Name_Type; |
| Extending : Project_Id; |
| Extending2 : Project_Id; |
| Prj : Project_List; |
| |
| -- Start of processing for Process_Project_Tree_Phase_2 |
| |
| begin |
| Success := True; |
| |
| Debug_Increase_Indent ("Process tree, phase 2", Project.Name); |
| |
| if Project /= No_Project then |
| Check (In_Tree, Project, From_Project_Node_Tree, Env.Flags); |
| end if; |
| |
| -- If main project is an extending all project, set object directory of |
| -- all virtual extending projects to object directory of main project. |
| |
| if Project /= No_Project |
| and then Is_Extending_All (From_Project_Node, From_Project_Node_Tree) |
| then |
| declare |
| Object_Dir : constant Path_Information := Project.Object_Directory; |
| |
| begin |
| Prj := In_Tree.Projects; |
| while Prj /= null loop |
| if Prj.Project.Virtual then |
| Prj.Project.Object_Directory := Object_Dir; |
| end if; |
| |
| Prj := Prj.Next; |
| end loop; |
| end; |
| end if; |
| |
| -- Check that no extending project shares its object directory with |
| -- the project(s) it extends. |
| |
| if Project /= No_Project then |
| Prj := In_Tree.Projects; |
| while Prj /= null loop |
| Extending := Prj.Project.Extended_By; |
| |
| if Extending /= No_Project then |
| Obj_Dir := Prj.Project.Object_Directory.Name; |
| |
| -- Check that a project being extended does not share its |
| -- object directory with any project that extends it, directly |
| -- or indirectly, including a virtual extending project. |
| |
| -- Start with the project directly extending it |
| |
| Extending2 := Extending; |
| while Extending2 /= No_Project loop |
| if Has_Ada_Sources (Extending2) |
| and then Extending2.Object_Directory.Name = Obj_Dir |
| then |
| if Extending2.Virtual then |
| Error_Msg_Name_1 := Prj.Project.Display_Name; |
| Error_Msg |
| (Env.Flags, |
| "project %% cannot be extended by a virtual" & |
| " project with the same object directory", |
| Prj.Project.Location, Project); |
| |
| else |
| Error_Msg_Name_1 := Extending2.Display_Name; |
| Error_Msg_Name_2 := Prj.Project.Display_Name; |
| Error_Msg |
| (Env.Flags, |
| "project %% cannot extend project %%", |
| Extending2.Location, Project); |
| Error_Msg |
| (Env.Flags, |
| "\they share the same object directory", |
| Extending2.Location, Project); |
| end if; |
| end if; |
| |
| -- Continue with the next extending project, if any |
| |
| Extending2 := Extending2.Extended_By; |
| end loop; |
| end if; |
| |
| Prj := Prj.Next; |
| end loop; |
| end if; |
| |
| Debug_Decrease_Indent ("Done Process tree, phase 2"); |
| |
| Success := Total_Errors_Detected = 0 |
| and then |
| (Warning_Mode /= Treat_As_Error or else Warnings_Detected = 0); |
| end Process_Project_Tree_Phase_2; |
| |
| ----------------------- |
| -- Recursive_Process -- |
| ----------------------- |
| |
| procedure Recursive_Process |
| (In_Tree : Project_Tree_Ref; |
| Project : out Project_Id; |
| Packages_To_Check : String_List_Access; |
| From_Project_Node : Project_Node_Id; |
| From_Project_Node_Tree : Project_Node_Tree_Ref; |
| Env : in out Prj.Tree.Environment; |
| Extended_By : Project_Id; |
| From_Encapsulated_Lib : Boolean; |
| On_New_Tree_Loaded : Tree_Loaded_Callback := null) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared; |
| |
| Child_Env : Prj.Tree.Environment; |
| -- Only used for the root aggregate project (if any). This is left |
| -- uninitialized otherwise. |
| |
| procedure Process_Imported_Projects |
| (Imported : in out Project_List; |
| Limited_With : Boolean); |
| -- Process imported projects. If Limited_With is True, then only |
| -- projects processed through a "limited with" are processed, otherwise |
| -- only projects imported through a standard "with" are processed. |
| -- Imported is the id of the last imported project. |
| |
| procedure Process_Aggregated_Projects; |
| -- Process all the projects aggregated in List. This does nothing if the |
| -- project is not an aggregate project. |
| |
| procedure Process_Extended_Project; |
| -- Process the extended project: inherit all packages from the extended |
| -- project that are not explicitly defined or renamed. Also inherit the |
| -- languages, if attribute Languages is not explicitly defined. |
| |
| ------------------------------- |
| -- Process_Imported_Projects -- |
| ------------------------------- |
| |
| procedure Process_Imported_Projects |
| (Imported : in out Project_List; |
| Limited_With : Boolean) |
| is |
| With_Clause : Project_Node_Id; |
| New_Project : Project_Id; |
| Proj_Node : Project_Node_Id; |
| |
| begin |
| With_Clause := |
| First_With_Clause_Of |
| (From_Project_Node, From_Project_Node_Tree); |
| |
| while Present (With_Clause) loop |
| Proj_Node := |
| Non_Limited_Project_Node_Of |
| (With_Clause, From_Project_Node_Tree); |
| New_Project := No_Project; |
| |
| if (Limited_With and then No (Proj_Node)) |
| or else (not Limited_With and then Present (Proj_Node)) |
| then |
| Recursive_Process |
| (In_Tree => In_Tree, |
| Project => New_Project, |
| Packages_To_Check => Packages_To_Check, |
| From_Project_Node => |
| Project_Node_Of (With_Clause, From_Project_Node_Tree), |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Extended_By => No_Project, |
| From_Encapsulated_Lib => From_Encapsulated_Lib, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| |
| if Imported = null then |
| Project.Imported_Projects := new Project_List_Element' |
| (Project => New_Project, |
| From_Encapsulated_Lib => False, |
| Next => null); |
| Imported := Project.Imported_Projects; |
| else |
| Imported.Next := new Project_List_Element' |
| (Project => New_Project, |
| From_Encapsulated_Lib => False, |
| Next => null); |
| Imported := Imported.Next; |
| end if; |
| end if; |
| |
| With_Clause := |
| Next_With_Clause_Of (With_Clause, From_Project_Node_Tree); |
| end loop; |
| end Process_Imported_Projects; |
| |
| --------------------------------- |
| -- Process_Aggregated_Projects -- |
| --------------------------------- |
| |
| procedure Process_Aggregated_Projects is |
| List : Aggregated_Project_List; |
| Loaded_Project : Prj.Tree.Project_Node_Id; |
| Success : Boolean := True; |
| Tree : Project_Tree_Ref; |
| Node_Tree : Project_Node_Tree_Ref; |
| |
| begin |
| if Project.Qualifier not in Aggregate_Project then |
| return; |
| end if; |
| |
| Debug_Increase_Indent ("Process_Aggregated_Projects", Project.Name); |
| |
| Prj.Nmsc.Process_Aggregated_Projects |
| (Tree => In_Tree, |
| Project => Project, |
| Node_Tree => From_Project_Node_Tree, |
| Flags => Env.Flags); |
| |
| List := Project.Aggregated_Projects; |
| while Success and then List /= null loop |
| Node_Tree := new Project_Node_Tree_Data; |
| Initialize (Node_Tree); |
| |
| Prj.Part.Parse |
| (In_Tree => Node_Tree, |
| Project => Loaded_Project, |
| Packages_To_Check => Packages_To_Check, |
| Project_File_Name => Get_Name_String (List.Path), |
| Errout_Handling => Prj.Part.Never_Finalize, |
| Current_Directory => Get_Name_String (Project.Directory.Name), |
| Is_Config_File => False, |
| Env => Child_Env); |
| |
| Success := not Prj.Tree.No (Loaded_Project); |
| |
| if Success then |
| if Node_Tree.Incomplete_With then |
| From_Project_Node_Tree.Incomplete_With := True; |
| end if; |
| |
| List.Tree := new Project_Tree_Data (Is_Root_Tree => False); |
| Prj.Initialize (List.Tree); |
| List.Tree.Shared := In_Tree.Shared; |
| |
| -- In aggregate library, aggregated projects are parsed using |
| -- the aggregate library tree. |
| |
| if Project.Qualifier = Aggregate_Library then |
| Tree := In_Tree; |
| else |
| Tree := List.Tree; |
| end if; |
| |
| -- We can only do the phase 1 of the processing, since we do |
| -- not have access to the configuration file yet (this is |
| -- called when doing phase 1 of the processing for the root |
| -- aggregate project). |
| |
| if In_Tree.Is_Root_Tree then |
| Process_Project_Tree_Phase_1 |
| (In_Tree => Tree, |
| Project => List.Project, |
| Packages_To_Check => Packages_To_Check, |
| Success => Success, |
| From_Project_Node => Loaded_Project, |
| From_Project_Node_Tree => Node_Tree, |
| Env => Child_Env, |
| Reset_Tree => False, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| else |
| -- use the same environment as the rest of the aggregated |
| -- projects, ie the one that was setup by the root aggregate |
| Process_Project_Tree_Phase_1 |
| (In_Tree => Tree, |
| Project => List.Project, |
| Packages_To_Check => Packages_To_Check, |
| Success => Success, |
| From_Project_Node => Loaded_Project, |
| From_Project_Node_Tree => Node_Tree, |
| Env => Env, |
| Reset_Tree => False, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| end if; |
| |
| if On_New_Tree_Loaded /= null then |
| On_New_Tree_Loaded |
| (Node_Tree, Tree, Loaded_Project, List.Project); |
| end if; |
| |
| else |
| Debug_Output ("Failed to parse", Name_Id (List.Path)); |
| end if; |
| |
| List := List.Next; |
| end loop; |
| |
| Debug_Decrease_Indent ("Done Process_Aggregated_Projects"); |
| end Process_Aggregated_Projects; |
| |
| ------------------------------ |
| -- Process_Extended_Project -- |
| ------------------------------ |
| |
| procedure Process_Extended_Project is |
| Extended_Pkg : Package_Id; |
| Current_Pkg : Package_Id; |
| Element : Package_Element; |
| First : constant Package_Id := Project.Decl.Packages; |
| Attribute1 : Variable_Id; |
| Attribute2 : Variable_Id; |
| Attr_Value1 : Variable; |
| Attr_Value2 : Variable; |
| |
| begin |
| Extended_Pkg := Project.Extends.Decl.Packages; |
| while Extended_Pkg /= No_Package loop |
| Element := Shared.Packages.Table (Extended_Pkg); |
| |
| Current_Pkg := First; |
| while Current_Pkg /= No_Package |
| and then |
| Shared.Packages.Table (Current_Pkg).Name /= Element.Name |
| loop |
| Current_Pkg := Shared.Packages.Table (Current_Pkg).Next; |
| end loop; |
| |
| if Current_Pkg = No_Package then |
| Package_Table.Increment_Last (Shared.Packages); |
| Current_Pkg := Package_Table.Last (Shared.Packages); |
| Shared.Packages.Table (Current_Pkg) := |
| (Name => Element.Name, |
| Decl => No_Declarations, |
| Parent => No_Package, |
| Next => Project.Decl.Packages); |
| Project.Decl.Packages := Current_Pkg; |
| Copy_Package_Declarations |
| (From => Element.Decl, |
| To => Shared.Packages.Table (Current_Pkg).Decl, |
| New_Loc => No_Location, |
| Restricted => True, |
| Shared => Shared); |
| end if; |
| |
| Extended_Pkg := Element.Next; |
| end loop; |
| |
| -- Check if attribute Languages is declared in the extending project |
| |
| Attribute1 := Project.Decl.Attributes; |
| while Attribute1 /= No_Variable loop |
| Attr_Value1 := Shared.Variable_Elements. Table (Attribute1); |
| exit when Attr_Value1.Name = Snames.Name_Languages; |
| Attribute1 := Attr_Value1.Next; |
| end loop; |
| |
| if Attribute1 = No_Variable or else Attr_Value1.Value.Default then |
| |
| -- Attribute Languages is not declared in the extending project. |
| -- Check if it is declared in the project being extended. |
| |
| Attribute2 := Project.Extends.Decl.Attributes; |
| while Attribute2 /= No_Variable loop |
| Attr_Value2 := Shared.Variable_Elements.Table (Attribute2); |
| exit when Attr_Value2.Name = Snames.Name_Languages; |
| Attribute2 := Attr_Value2.Next; |
| end loop; |
| |
| if Attribute2 /= No_Variable |
| and then not Attr_Value2.Value.Default |
| then |
| -- As attribute Languages is declared in the project being |
| -- extended, copy its value for the extending project. |
| |
| if Attribute1 = No_Variable then |
| Variable_Element_Table.Increment_Last |
| (Shared.Variable_Elements); |
| Attribute1 := Variable_Element_Table.Last |
| (Shared.Variable_Elements); |
| Attr_Value1.Next := Project.Decl.Attributes; |
| Project.Decl.Attributes := Attribute1; |
| end if; |
| |
| Attr_Value1.Name := Snames.Name_Languages; |
| Attr_Value1.Value := Attr_Value2.Value; |
| Shared.Variable_Elements.Table (Attribute1) := Attr_Value1; |
| end if; |
| end if; |
| end Process_Extended_Project; |
| |
| -- Start of processing for Recursive_Process |
| |
| begin |
| if No (From_Project_Node) then |
| Project := No_Project; |
| |
| else |
| declare |
| Imported, Mark : Project_List; |
| Declaration_Node : Project_Node_Id := Empty_Node; |
| |
| Name : constant Name_Id := |
| Name_Of (From_Project_Node, From_Project_Node_Tree); |
| |
| Display_Name : constant Name_Id := |
| Display_Name_Of |
| (From_Project_Node, From_Project_Node_Tree); |
| |
| begin |
| Project := Processed_Projects.Get (Name); |
| |
| if Project /= No_Project then |
| |
| -- Make sure that, when a project is extended, the project id |
| -- of the project extending it is recorded in its data, even |
| -- when it has already been processed as an imported project. |
| -- This is for virtually extended projects. |
| |
| if Extended_By /= No_Project then |
| Project.Extended_By := Extended_By; |
| end if; |
| |
| return; |
| end if; |
| |
| -- Check if the project is already in the tree |
| |
| Project := No_Project; |
| |
| declare |
| List : Project_List := In_Tree.Projects; |
| Path : constant Path_Name_Type := |
| Path_Name_Of (From_Project_Node, |
| From_Project_Node_Tree); |
| |
| begin |
| while List /= null loop |
| if List.Project.Path.Display_Name = Path then |
| Project := List.Project; |
| exit; |
| end if; |
| |
| List := List.Next; |
| end loop; |
| end; |
| |
| if Project = No_Project then |
| Project := |
| new Project_Data' |
| (Empty_Project |
| (Project_Qualifier_Of |
| (From_Project_Node, From_Project_Node_Tree))); |
| |
| -- Note that at this point we do not know yet if the project |
| -- has been withed from an encapsulated library or not. |
| |
| In_Tree.Projects := |
| new Project_List_Element' |
| (Project => Project, |
| From_Encapsulated_Lib => False, |
| Next => In_Tree.Projects); |
| end if; |
| |
| -- Keep track of this point |
| |
| Mark := In_Tree.Projects; |
| |
| Processed_Projects.Set (Name, Project); |
| |
| Project.Name := Name; |
| Project.Display_Name := Display_Name; |
| |
| Get_Name_String (Name); |
| |
| -- If name starts with the virtual prefix, flag the project as |
| -- being a virtual extending project. |
| |
| if Name_Len > Virtual_Prefix'Length |
| and then |
| Name_Buffer (1 .. Virtual_Prefix'Length) = Virtual_Prefix |
| then |
| Project.Virtual := True; |
| end if; |
| |
| Project.Path.Display_Name := |
| Path_Name_Of (From_Project_Node, From_Project_Node_Tree); |
| Get_Name_String (Project.Path.Display_Name); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Project.Path.Name := Name_Find; |
| |
| Project.Location := |
| Location_Of (From_Project_Node, From_Project_Node_Tree); |
| |
| Project.Directory.Display_Name := |
| Directory_Of (From_Project_Node, From_Project_Node_Tree); |
| Get_Name_String (Project.Directory.Display_Name); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Project.Directory.Name := Name_Find; |
| |
| Project.Extended_By := Extended_By; |
| |
| Add_Attributes |
| (Project, |
| Name, |
| Name_Id (Project.Directory.Display_Name), |
| In_Tree.Shared, |
| Project.Decl, |
| Prj.Attr.Attribute_First, |
| Project_Level => True); |
| |
| Process_Imported_Projects (Imported, Limited_With => False); |
| |
| if Project.Qualifier = Aggregate then |
| Initialize_And_Copy (Child_Env, Copy_From => Env); |
| |
| elsif Project.Qualifier = Aggregate_Library then |
| |
| -- The child environment is the same as the current one |
| |
| Child_Env := Env; |
| |
| else |
| -- No need to initialize Child_Env, since it will not be |
| -- used anyway by Process_Declarative_Items (only the root |
| -- aggregate can modify it, and it is never read anyway). |
| |
| null; |
| end if; |
| |
| Declaration_Node := |
| Project_Declaration_Of |
| (From_Project_Node, From_Project_Node_Tree); |
| |
| Recursive_Process |
| (In_Tree => In_Tree, |
| Project => Project.Extends, |
| Packages_To_Check => Packages_To_Check, |
| From_Project_Node => |
| Extended_Project_Of |
| (Declaration_Node, From_Project_Node_Tree), |
| From_Project_Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Extended_By => Project, |
| From_Encapsulated_Lib => From_Encapsulated_Lib, |
| On_New_Tree_Loaded => On_New_Tree_Loaded); |
| |
| Process_Declarative_Items |
| (Project => Project, |
| In_Tree => In_Tree, |
| From_Project_Node => From_Project_Node, |
| Node_Tree => From_Project_Node_Tree, |
| Env => Env, |
| Pkg => No_Package, |
| Item => First_Declarative_Item_Of |
| (Declaration_Node, From_Project_Node_Tree), |
| Child_Env => Child_Env); |
| |
| if Project.Extends /= No_Project then |
| Process_Extended_Project; |
| end if; |
| |
| Process_Imported_Projects (Imported, Limited_With => True); |
| |
| if Total_Errors_Detected = 0 then |
| Process_Aggregated_Projects; |
| end if; |
| |
| -- At this point (after Process_Declarative_Items) we have the |
| -- attribute values set, we can backtrace In_Tree.Project and |
| -- set the From_Encapsulated_Library status. |
| |
| declare |
| Lib_Standalone : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Standalone, |
| Project.Decl.Attributes, |
| Shared); |
| List : Project_List := In_Tree.Projects; |
| Is_Encapsulated : Boolean; |
| |
| begin |
| Get_Name_String (Lib_Standalone.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| Is_Encapsulated := Name_Buffer (1 .. Name_Len) = "encapsulated"; |
| |
| if Is_Encapsulated then |
| while List /= null and then List /= Mark loop |
| List.From_Encapsulated_Lib := Is_Encapsulated; |
| List := List.Next; |
| end loop; |
| end if; |
| |
| if Total_Errors_Detected = 0 then |
| |
| -- For an aggregate library we add the aggregated projects |
| -- as imported ones. This is necessary to give visibility |
| -- to all sources from the aggregates from the aggregated |
| -- library projects. |
| |
| if Project.Qualifier = Aggregate_Library then |
| declare |
| L : Aggregated_Project_List; |
| begin |
| L := Project.Aggregated_Projects; |
| while L /= null loop |
| Project.Imported_Projects := |
| new Project_List_Element' |
| (Project => L.Project, |
| From_Encapsulated_Lib => Is_Encapsulated, |
| Next => |
| Project.Imported_Projects); |
| L := L.Next; |
| end loop; |
| end; |
| end if; |
| end if; |
| end; |
| |
| if Project.Qualifier = Aggregate and then In_Tree.Is_Root_Tree then |
| Free (Child_Env); |
| end if; |
| end; |
| end if; |
| end Recursive_Process; |
| |
| ----------------------------- |
| -- Set_Default_Runtime_For -- |
| ----------------------------- |
| |
| procedure Set_Default_Runtime_For (Language : Name_Id; Value : String) is |
| begin |
| Name_Len := Value'Length; |
| Name_Buffer (1 .. Name_Len) := Value; |
| Runtime_Defaults.Set (Language, Name_Find); |
| end Set_Default_Runtime_For; |
| end Prj.Proc; |