DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: B T

⟦9c55bfada⟧ TextFile

    Length: 34015 (0x84df)
    Types: TextFile
    Names: »B«

Derivation

└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
    └─⟦5cb1d1d7f⟧ »DATA« 
        └─⟦3b1ee7bd8⟧ 
            └─⟦this⟧ 

TextFile

with Action;
with Diana;
with Diana_Renames;
with Error_Messages;
with Directory;
with Profile;
with Log;
with Io;
with Io_Exceptions;
with String_Utilities;
with Dirty_Tree;
with Split_Util;

package body Split is
    use Diana_Renames;

    package Naming renames Directory.Naming;
    package Decl_Ops renames Directory.Declaration_Operations;
    package Ada renames Directory.Ada;
    package Traversal renames Directory.Traversal;


    function "=" (X, Y : Directory.Error_Status) return Boolean
        renames Directory."=";

    function "=" (X, Y : Naming.Name_Status) return Boolean renames Naming."=";

    Failure : exception renames Split_Util.Failure;

    type Unit_Kind is (Subprogram_Body, Task_Body, Package_Body);

    type Unit_Kinds is array (Unit_Kind) of Boolean;


    procedure Error (Msg : String; Fatal : Boolean := True)
        renames Split_Util.Error;

    procedure Check (Status : Directory.Error_Status; Msg : String)
        renames Split_Util.Check;

    generic
        with procedure Process_Unit (Root : Ada.Root;
                                     Unit : String;
                                     Kinds : Unit_Kinds;
                                     Action_Id : Action.Id);
    procedure Process_Unit_List (Root : Ada.Root;
                                 Units : String;
                                 Kinds : Unit_Kinds;
                                 Action_Id : Action.Id);

    function Is_Separable
                (Item : Diana.Tree; Items : Diana.Seq_Type; Kinds : Unit_Kinds)
                return Boolean is
    begin
        case Diana.Kind (Item) is
            when Diana.Dn_Subprogram_Body =>
                return Kinds (Subprogram_Body) and then
                          Diana.Kind (Diana.As_Block_Stub (Item)) =
                             Diana.Dn_Block and then
                          not Split_Util.Is_Overloaded (Item, Items);

            when Diana.Dn_Package_Body =>
                return Kinds (Package_Body) and then
                          Diana.Kind (Diana.As_Block_Stub (Item)) =
                             Diana.Dn_Block;

            when Diana.Dn_Task_Body =>
                return Kinds (Task_Body) and then
                          Diana.Kind (Diana.As_Block_Stub (Item)) =
                             Diana.Dn_Block;

            when others =>
                return False;
        end case;
    end Is_Separable;

    function Get_Items (Root : Diana.Tree) return Diana.Tree is
        Node : Diana.Tree;
        Block : Diana.Tree;
    begin
        if "/=" (Diana.Kind (Root), Diana.Dn_Comp_Unit) then
            Node := Root;
        else
            Node := Diana.As_Unit_Body (Root);
        end if;

        if Diana.Kind (Node) = Diana.Dn_Subunit then
            Node := Diana.As_Subunit_Body (Node);
        end if;

        case Diana.Kind (Node) is
            when Diana.Dn_Package_Body | Diana.Dn_Task_Body |
                 Diana.Dn_Subprogram_Body =>
                Block := Diana.As_Block_Stub (Node);

                if "/=" (Diana.Kind (Block), Diana.Dn_Block) then
                    Error ("Unit has no block");
                end if;

                return Diana.As_Item_S (Block);

            when others =>
                Error ("Unit is not a package, task, or subprogram body");
        end case;
    end Get_Items;

    procedure Copy_Unit (Def_Id : Diana.Tree;
                         Block : Diana.Tree;
                         Item : Diana.Tree;
                         New_Root : out Diana.Tree) is
        Subunit : Diana.Tree;
        New_Id : Diana.Tree := Dirty_Tree.Copy (Def_Id);
        Kind : Diana.Node_Name := Diana.Kind (Item);
    begin
        case Kind is
            when Diana.Dn_Subprogram_Body =>
                Subunit := Diana.Make (Diana.Dn_Subprogram_Body, New_Id,
                                       Dirty_Tree.Copy (Diana.As_Header (Item)),
                                       Dirty_Tree.Copy (Block));

            when Diana.Dn_Task_Body | Diana.Dn_Package_Body =>
                Subunit := Diana.Make (Kind, New_Id, Dirty_Tree.Copy (Block));

            when others =>
                null;
        end case;

        New_Root := Subunit;
    end Copy_Unit;

    procedure Separate_Body (Unit_Body : Diana.Tree;
                             Threshhold : Stmt_Decl_Count;
                             Action_Id : Action.Id) is
        Copy : Diana.Tree;
        Status : Directory.Error_Status;
        Block : Diana.Tree;
        Def_Id : Diana.Tree := Diana.Id_Utilities.Get_Id (Unit_Body);
        Object : Directory.Object;
        New_Root : Ada.Root;
        Key : Ada.Conversion_Key;
        Subunit : Diana.Tree;
    begin
        if Threshhold >= Split_Util.Compute_Size (Unit_Body) then
            return;
        end if;

        Log.Put_Line ("Separating " & Diana.Image (Diana.Id (Def_Id)));

        Ada.Set_Diana_Heap (Unit_Body, Status);
        Check (Status, "setting diana heap to unit");

        Block := Diana.As_Block_Stub (Unit_Body);
        Diana.As_Block_Stub (Unit_Body, Diana.Make (Diana.Dn_Stub));

        Traversal.Get_Object (Def_Id, Object, Status, Action_Id => Action_Id);
        Check (Status, "getting object for new stub");

        Ada.Open (Ada.Get_Unit (Object), Ada.Update,
                  New_Root, Key, Status, Action_Id);
        Check (Status, "opening space for subunit");

        Ada.Set_Diana_Heap (New_Root, Status);
        Check (Status, "setting diana heap to new subunit");

        Copy_Unit (Def_Id, Block, Unit_Body, Subunit);

        Ada.Set_Root (Subunit, Status, Action_Id);
        Check (Status, "setting root of new subunit");

        Ada.Close (Subunit, Status, Action_Id);
        Check (Status, "closing new subunit");
    end Separate_Body;

    procedure Separate_Bodies (Root : Ada.Root;
                               Threshhold : Stmt_Decl_Count;
                               Kinds : Unit_Kinds;
                               Action_Id : Action.Id) is
        Item : Diana.Tree;
        Items : Diana.Seq_Type := Diana.List (Get_Items (Root));
        The_Items : Diana.Seq_Type := Items;
    begin
        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);

            if Is_Separable (Item, The_Items, Kinds) then
                Separate_Body (Item, Threshhold, Action_Id);
            end if;

            Items := Diana.Tail (Items);
        end loop;
    end Separate_Bodies;

    procedure Process_Unit_To_Separate (Root : Ada.Root;
                                        Unit : String;
                                        Kinds : Unit_Kinds;
                                        Action_Id : Action.Id) is
        Items : Diana.Seq_Type := Diana.List (Get_Items (Root));
        The_Items : Diana.Seq_Type := Items;
        Item : Diana.Tree;
    begin
        if Unit = "" then
            return;
        end if;

        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);

            case Diana.Kind (Item) is
                when Diana.Dn_Subprogram_Body |
                     Diana.Dn_Package_Body | Diana.Dn_Task_Body =>
                    if Diana.Image (Diana.Id
                                       (Diana.Id_Utilities.Get_Id (Item))) =
                       String_Utilities.Upper_Case (Unit) and then
                       Is_Separable (Item, The_Items, Kinds) then
                        Separate_Body (Item, 0, Action_Id);
                        return;
                    end if;

                when others =>
                    null;
            end case;

            Items := Diana.Tail (Items);
        end loop;

        Error ("Can't find unit " & Unit, False);
    end Process_Unit_To_Separate;

    procedure Process_Unit_List (Root : Ada.Root;
                                 Units : String;
                                 Kinds : Unit_Kinds;
                                 Action_Id : Action.Id) is

        procedure Scan_Name_String (Units : String) is
            Next : Integer := Units'First;
            Start : Integer;
        begin
            loop
                while Next <= Units'Last and then Units (Next) = ' ' loop
                    Next := Next + 1;
                end loop;

                exit when Next > Units'Last;
                Start := Next;

                while Next <= Units'Last and then Units (Next) /= ' ' loop
                    Next := Next + 1;
                end loop;

                Process_Unit (Root, Units (Start .. Next - 1),
                              Kinds, Action_Id);
            end loop;
        end Scan_Name_String;


        procedure Read_Names_From_File (Units : String) is
            Infile : Io.File_Type;
        begin
            begin
                Io.Open (Infile, Io.In_File, Units);
            exception
                when others =>
                    Error ("Error opening " & Units, False);
                    return;
            end;

            loop
                Process_Unit
                   (Root, String_Utilities.Strip (Io.Get_Line (Infile)),
                    Kinds, Action_Id);
            end loop;

            Io.Close (Infile);
        exception
            when Io_Exceptions.End_Error =>
                Io.Close (Infile);

            when others =>
                Io.Close (Infile);
                raise;
        end Read_Names_From_File;
    begin
        case Units (Units'First) is
            when '\' =>
                Read_Names_From_File (Units (Units'First + 1 .. Units'Last));

            when '!' | '$' | '^' =>
                Read_Names_From_File (Units);

            when others =>
                Scan_Name_String (Units);
        end case;
    end Process_Unit_List;

    procedure Demote_Unit (Def_Id : Directory.Declaration;
                           Root : out Ada.Root;
                           Action_Id : Action.Id) is
        Errors : Error_Messages.Errors;
        Impact : Ada.Roots;
        Status : Directory.Error_Status;
        Result : Diana.Tree;
        Object : Directory.Object;
        The_Root : Ada.Root;
        Key : Ada.Conversion_Key;
        Modified : Diana.Temp_Seq;
    begin
        Traversal.Get_Object (Def_Id, Object, Status);
        Check (Status, "getting object for " &
                          Naming.Unique_Full_Name (Def_Id));

        Ada.Open (Ada.Get_Unit (Object), Ada.None,
                  The_Root, Key, Status, Action.Null_Id);
        Check (Status, "getting root for " & Naming.Unique_Full_Name (Def_Id));

        Decl_Ops.Demote (Location => The_Root,
                         Errors => Errors,
                         Result => Result,
                         Modified_Units => Modified,
                         Change_Impact => Impact,
                         Status => Status,
--    action_id  => action_id,
                         Goal_State => Decl_Ops.Source);
        Check (Status, "demoting " & Naming.Unique_Full_Name (Def_Id));
        Root := Result;
    end Demote_Unit;

    procedure Find_Unit (Unit_To_Split : Ada_Unit_Name;
                         Def_Id : out Directory.Declaration) is

        N_Status : Naming.Name_Status;
    begin
        Naming.Resolve (Unit_To_Split & "'body'c(ada)",
                        Naming.Default_Context, Def_Id, N_Status);

        if "/=" (N_Status, Naming.Successful) then
            Log.Put_Line ("Can't resolve " & Unit_To_Split & "'body");
            raise Failure;
        end if;
    end Find_Unit;



    procedure Make_Writable (Root : Diana.Tree;
                             Result : out Diana.Tree;
                             Action_Id : Action.Id) is
        Status : Directory.Error_Status;
        Version : Directory.Version;
        Key : Ada.Conversion_Key;
    begin
        Ada.Get_Version (Root, Version, Status);
        Check (Status, "getting version of root");

        Ada.Open (Version, Ada.Update, Result, Key, Status, Action_Id);
        Check (Status, "opening unit for update");
    end Make_Writable;



    procedure Process_Unit_List_To_Separate is
       new Process_Unit_List (Process_Unit_To_Separate);

    procedure Separate_Subunits (Unit_To_Split : Ada_Unit_Name;
                                 Unit_Sizes_To_Separate : Stmt_Decl_Count := 20;
                                 Subunits_To_Separate : String := "";
                                 Separate_Subprograms : Boolean := True;
                                 Separate_Tasks : Boolean := True;
                                 Separate_Packages : Boolean := True) is
        Def_Id : Directory.Declaration;
        Root : Ada.Root;
        Wroot : Ada.Root;
        Kinds : Unit_Kinds := (Separate_Subprograms,
                               Separate_Tasks, Separate_Packages);
        Status : Directory.Error_Status;
        Old_Heap : Ada.Root;
        Action_Id : Action.Id := Action.Start;
    begin
        Log.Put_Line ("[Split.Separate_Subunits, """ & Unit_To_Split &
                      """," & Integer'Image (Unit_Sizes_To_Separate) &
                      ", """ & Subunits_To_Separate & """, " &
                      Boolean'Image (Separate_Subprograms) & ", " &
                      Boolean'Image (Separate_Tasks) & ", " &
                      Boolean'Image (Separate_Packages) & "]");
        Find_Unit (Unit_To_Split, Def_Id);
        Demote_Unit (Def_Id, Root, Action_Id);
        Make_Writable (Root, Wroot, Action_Id);

        Ada.Get_Diana_Heap (Old_Heap, Status);
        Check (Status, "getting old diana heap");

        if Subunits_To_Separate /= "" then
            Process_Unit_List_To_Separate
               (Wroot, Subunits_To_Separate, Kinds, Action_Id);
        else
            Separate_Bodies (Wroot, Unit_Sizes_To_Separate, Kinds, Action_Id);
        end if;

        Ada.Set_Diana_Heap (Old_Heap, Status);

        Ada.Close (Wroot, Status, Action_Id);
        Check (Status, "closing unit");

        Action.Finish (Action_Id, Do_Commit => True);
        Log.Put_Line ("[End of Split.Separate_Subunits]");
    exception
        when Failure =>
            Action.Finish (Action_Id, Do_Commit => False);
            Ada.Set_Diana_Heap (Old_Heap, Status);
            Log.Put_Line ("[End of Split.Separate_Subunits]");

        when others =>
            Action.Finish (Action_Id, Do_Commit => False);
            Error ("Unexpected exception", False);
            Ada.Set_Diana_Heap (Old_Heap, Status);
            Log.Put_Line ("[End of Split.Separate_Subunits]");
    end Separate_Subunits;

    function No_Forward
                (Body_Id : Diana.Tree;
                 Item_S : Diana.Seq_Type;
                 Stop_Decl : Diana.Tree := Diana.Empty) return Boolean is
        Name : Diana.Symbol_Rep := Diana.Id (Body_Id);
        Items : Diana.Seq_Type := Item_S;
        Item : Diana.Tree;
    begin
        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);
            exit when Item = Stop_Decl;

            case Diana.Kind (Item) is
                when Diana.Dn_Subprogram_Decl | Diana.Dn_Generic =>
                    if Diana.Equal (Diana.Id (Diana.Id_Utilities.Get_Id (Item)),
                                    Name) then
                        return False;
                    end if;

                when others =>
                    null;
            end case;

            Items := Diana.Tail (Items);
        end loop;

        return True;
    end No_Forward;

    procedure Get_Decls (Pkg_Body_Id : Diana.Tree;
                         Decls1 : out Diana.Tree;
                         Decls2 : out Diana.Tree) is
        Status : Directory.Error_Status;
        Nstatus : Naming.Name_Status;
        Unit : Ada.Unit;
        Vis_Id : Diana.Tree;
        Spec : Diana.Tree;
        Object : Directory.Object;
        Vroot : Diana.Tree;
        Key : Ada.Conversion_Key;
    begin
        Ada.Get_Unit (Pkg_Body_Id, Unit, Status);
        Check (Status, " getiing ada.unit for root unit");

        declare
            Name : constant String :=
               Naming.Get_Prefix (Naming.Unique_Full_Name
                                     (Ada.Get_Object (Unit)));
        begin
            Naming.Resolve (Name & "." &
                            Diana.Image (Diana.Id (Pkg_Body_Id)) & "'spec",
                            Naming.Default_Context, Vis_Id, Nstatus);

            if Nstatus = Naming.Successful and then
               Diana.Kind (Vis_Id) = Diana.Dn_Package_Id then
                Spec := Diana.As_Package_Def (Diana.As_Parent (Vis_Id));

                if Diana.Kind (Spec) = Diana.Dn_Stub then
                    Traversal.Get_Object (Vis_Id, Object, Status);
                    Ada.Open (Ada.Get_Unit (Object), Ada.None,
                              Vroot, Key, Status, Action.Null_Id);
                    Vis_Id := Diana.Id_Utilities.Get_Id (Vroot);
                    Spec := Diana.As_Package_Def (Diana.As_Parent (Vis_Id));
                end if;

                if Diana.Kind (Spec) = Diana.Dn_Package_Spec then
                    Decls1 := Diana.As_Decl_S1 (Spec);
                    Decls2 := Diana.As_Decl_S2 (Spec);
                    return;
                end if;
            end if;
        end;

        Decls1 := Diana.Empty;
        Decls2 := Diana.Empty;
    exception
        when others =>
            Decls1 := Diana.Empty;
            Decls2 := Diana.Empty;
    end Get_Decls;

    function One_Part (Root : Diana.Tree;
                       Subp_Body : Diana.Tree;
                       Subp_Body_Id : Diana.Tree) return Boolean is
        First_Id : Diana.Tree := Diana.Sm_First (Subp_Body_Id);
        Root_Id : Diana.Tree;
        Items : Diana.Seq_Type;
        Decls1 : Diana.Tree;
        Decls2 : Diana.Tree;
    begin
        if not Diana.Is_Empty (First_Id) then
            return First_Id = Subp_Body_Id;
        end if;

        Items := Diana.List (Get_Items (Root));
        Root_Id := Diana.Id_Utilities.Get_Id (Root);

        case Diana.Kind (Root_Id) is
            when Diana.Dn_Package_Id =>
                if No_Forward (Subp_Body_Id, Items, Subp_Body) then
                    Get_Decls (Root_Id, Decls1, Decls2);
                    return not Diana.Is_Empty (Decls1) and then
                              No_Forward (Subp_Body_Id,
                                          Diana.List (Decls1)) and then
                              No_Forward (Subp_Body_Id, Diana.List (Decls2));
                else
                    return False;
                end if;

            when Diana.Dn_Task_Body_Id | Diana.Dn_Proc_Id |
                 Diana.Dn_Function_Id =>
                return No_Forward (Subp_Body_Id, Items, Subp_Body);

            when others =>
                return False;
        end case;
    exception
        when others =>
            return False;
    end One_Part;

    procedure Separate_Body_Into_Subunit (Root : Diana.Tree;
                                          Subp_Body : Diana.Tree;
                                          Vpart : Diana.Tree;
                                          Sroot : Ada.Root;
                                          Threshhold : Stmt_Decl_Count;
                                          Sep_Ids : in out Diana.Temp_Seq;
                                          Separated : out Boolean) is

        Subp_Id : Diana.Tree := Diana.As_Designator (Subp_Body);
        New_Body : Diana.Tree;
        Items : Diana.Tree;
        Status : Directory.Error_Status;
        Spec : Diana.Tree;
        Decls : Diana.Tree;
    begin
        if "/=" (Diana.Kind (Diana.As_Block_Stub (Subp_Body)),
                 Diana.Dn_Block) or else
           Diana.Kind (Subp_Id) = Diana.Dn_Def_Op or else
           Threshhold >= Split_Util.Compute_Size (Subp_Body) or else
           not One_Part (Root, Subp_Body, Subp_Id) then
            Separated := False;
            return;
        end if;

        Log.Put_Line ("Moving " & Diana.Image (Diana.Id (Subp_Id)) &
                      " to subunit " &
                      Diana.Image (Diana.Id (Diana.As_Id (Vpart))));

        Ada.Set_Diana_Heap (Subp_Body, Status);
        Check (Status, "setting diana heap to unit");

        Diana.Edit_Utilities.Remove (Subp_Body);

        Spec := Diana.Make
                   (Diana.Dn_Subprogram_Decl, Dirty_Tree.Copy (Subp_Id),
                    Dirty_Tree.Copy (Diana.As_Header (Subp_Body)), Diana.Empty);
        Decls := Diana.As_Decl_S1 (Diana.As_Package_Def (Vpart));
        Diana.List_Utilities.Insert
           (Decls, Spec, Diana.List_Utilities.Length (Diana.List (Decls)));

        Ada.Set_Diana_Heap (Sroot, Status);
        Check (Status, "setting diana heap to subunit");

        New_Body := Dirty_Tree.Copy (Subp_Body);
        Items := Get_Items (Sroot);
        Diana.List_Utilities.Insert
           (Items, New_Body, Diana.List_Utilities.Length (Diana.List (Items)));

        Sep_Ids := Diana.Cons (Subp_Id, Sep_Ids);
        Separated := True;
    end Separate_Body_Into_Subunit;

    procedure Separate_Bodies_Into_Subunit (Root : Ada.Root;
                                            Vpart : Diana.Tree;
                                            Sroot : Ada.Root;
                                            Threshhold : Stmt_Decl_Count;
                                            Kinds : Unit_Kinds;
                                            Action_Id : Action.Id;
                                            Sep_Ids : in out Diana.Temp_Seq) is
        Item : Diana.Tree;
        Items : Diana.Seq_Type := Diana.List (Get_Items (Root));
        The_Items : Diana.Seq_Type := Items;
        Separated : Boolean;
    begin
        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);
            Items := Diana.Tail (Items);

            case Diana.Kind (Item) is
                when Diana.Dn_Subprogram_Body =>
                    Separate_Body_Into_Subunit (Root, Item, Vpart, Sroot,
                                                Threshhold, Sep_Ids, Separated);

                when others =>
                    null;
            end case;
        end loop;
    end Separate_Bodies_Into_Subunit;

    procedure Process_Unit_List_Subunitize (Root : Ada.Root;
                                            Vpart : Diana.Tree;
                                            Sroot : Ada.Root;
                                            Units : String;
                                            Kinds : Unit_Kinds;
                                            Action_Id : Action.Id;
                                            Sep_Ids : in out Diana.Temp_Seq) is

        procedure Process_Unit (Root : Ada.Root;
                                Unit : String;
                                Kinds : Unit_Kinds;
                                Action_Id : Action.Id) is
            Items : Diana.Seq_Type := Diana.List (Get_Items (Root));
            The_Items : Diana.Seq_Type := Items;
            Item : Diana.Tree;
            Separated : Boolean;
        begin
            if Unit = "" then
                return;
            end if;

            while not Diana.Is_Empty (Items) loop
                Item := Diana.Head (Items);
                Items := Diana.Tail (Items);

                case Diana.Kind (Item) is
                    when Diana.Dn_Subprogram_Body =>
                        if Diana.Image (Diana.Id (Diana.As_Designator (Item))) =
                           String_Utilities.Upper_Case (Unit) then

                            Separate_Body_Into_Subunit
                               (Root, Item, Vpart, Sroot,
                                0, Sep_Ids, Separated);

                            if not Separated then
                                Error ("Can't separate " & Unit, False);
                            end if;

                            return;
                        end if;

                    when others =>
                        null;
                end case;
            end loop;

            Error ("Can't find unit " & Unit, False);
        end Process_Unit;

        procedure Process_Units is new Process_Unit_List (Process_Unit);
    begin
        Process_Units (Root, Units, Kinds, Action_Id);
    end Process_Unit_List_Subunitize;

    procedure Insert_Visible_Part (Vpart : Diana.Tree; Item_S : Diana.Tree) is
        Item : Diana.Tree;
        Items : Diana.Seq_Type := Diana.List (Item_S);
        The_Items : Diana.Seq_Type := Items;
        Pos : Integer := 0;
-- use_clause : diana.tree;
    begin
-- use_clause :=
--   diana.make
--     (diana.dn_use,
--      diana.list_utilities.list
--        (diana.make (diana.dn_used_name_id,
--       diana.image (diana.id (diana.as_id (vpart))))));

        if Diana.Is_Empty (Items) then
            Diana.As_List (Item_S, Diana.List_Utilities.List (Vpart));
        else
            loop
                Item := Diana.Head (Items);

                case Diana.Kind (Item) is
                    when Diana.Dn_Subprogram_Body |
                         Diana.Dn_Package_Body | Diana.Dn_Task_Body =>
                        Diana.List_Utilities.Insert (Item_S, Vpart, Pos);
--   diana.list_utilities.insert
--     (item_s, use_clause, pos + 1);
                        return;

                    when others =>
                        Items := Diana.Tail (Items);
                        exit when Diana.Is_Empty (Items);
                        Pos := Pos + 1;
                end case;
            end loop;

            Diana.List_Utilities.Nconc (The_Items, Vpart);
--     diana.list_utilities.nconc (the_items, use_clause);
        end if;
    end Insert_Visible_Part;

    function Get_Subunit_Name
                (Subunit_Name : String; Unit_Id : Diana.Tree) return String is
    begin
        if Subunit_Name /= "" then
            return Subunit_Name;
        else
            return Diana.Image (Diana.Id (Unit_Id)) & "_UTIL";
        end if;
    end Get_Subunit_Name;

    function Make_Subunit_Name (Subunit_Name : String) return Diana.Tree is
    begin
        return Diana.Make (Diana.Dn_Package_Id, Subunit_Name);
    end Make_Subunit_Name;



    function Make_Subunit_Body (Subunit_Name : String) return Diana.Tree is
    begin
        return Diana.Make
                  (Diana.Dn_Package_Body, Make_Subunit_Name (Subunit_Name),
                   Diana.Make (Diana.Dn_Block,
                               Diana.Make (Diana.Dn_Item_S, Diana.Make),
                               Diana.Make (Diana.Dn_Stm_S, Diana.Make),
                               Diana.Make (Diana.Dn_Alternative_S,
                                           Diana.Make)));
    end Make_Subunit_Body;


    function Make_Visible_Part (Subunit_Name : String) return Diana.Tree is
    begin
        return Diana.Make
                  (Diana.Dn_Package_Decl, Make_Subunit_Name (Subunit_Name),
                   Diana.Make (Diana.Dn_Package_Spec,
                               Diana.Make (Diana.Dn_Decl_S, Diana.Make),
                               Diana.Make (Diana.Dn_Decl_S, Diana.Make)));
    end Make_Visible_Part;

    procedure Find_Vis_Part (Subunit_Name : String;
                             Item_S : Diana.Tree;
                             Vispart : out Diana.Tree) is
        Item : Diana.Tree;
        Items : Diana.Seq_Type := Diana.List (Item_S);
    begin
        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);

            if Diana.Kind (Item) = Diana.Dn_Package_Decl and then
               Diana.Image (Diana.Id (Diana.As_Id (Item))) = Subunit_Name then
                Vispart := Item;
                return;
            else
                Items := Diana.Tail (Items);
            end if;
        end loop;

        Vispart := Diana.Empty;
    end Find_Vis_Part;



    procedure Find_Stub_Decl (Subunit_Name : String;
                              Item_S : Diana.Tree;
                              Stub : out Diana.Tree;
                              Stub_Id : out Diana.Tree) is
        Item : Diana.Tree;
        Items : Diana.Seq_Type := Diana.List (Item_S);
        Id : Diana.Tree;
    begin
        while not Diana.Is_Empty (Items) loop
            Item := Diana.Head (Items);

            if Diana.Kind (Item) = Diana.Dn_Package_Body and then
               Diana.Kind (Diana.As_Block_Stub (Item)) = Diana.Dn_Stub then
                Id := Diana.As_Id (Item);

                if Diana.Image (Diana.Id (Id)) = Subunit_Name then
                    Stub := Item;
                    Stub_Id := Id;
                    return;
                end if;
            end if;

            Items := Diana.Tail (Items);
        end loop;

        Stub := Diana.Empty;
        Stub_Id := Diana.Empty;
    end Find_Stub_Decl;

    procedure Create_Subunit_Space (Wroot : Ada.Root;
                                    Subunit_Name : String;
                                    Vpart : out Diana.Tree;
                                    Sroot : out Ada.Root;
                                    The_Stub : out Diana.Tree;
                                    Action_Id : Action.Id) is
        Unit_Id : Diana.Tree := Diana.Id_Utilities.Get_Id (Wroot);
        Status : Directory.Error_Status;
        Item_S : Diana.Tree := Get_Items (Wroot);
        Items : Diana.Seq_Type;
        Stub : Diana.Tree;
        Stub_Id : Diana.Tree;
        Object : Directory.Object;
        Subunit : Diana.Tree;
        Vispart : Diana.Tree;
        Key : Ada.Conversion_Key;
        Subname : constant String := Get_Subunit_Name (Subunit_Name, Unit_Id);
    begin
        Ada.Set_Diana_Heap (Wroot, Status);
        Check (Status, "setting diana heap to unit");

        Find_Vis_Part (Subname, Item_S, Vispart);

        if Diana.Is_Empty (Vispart) then
            Vispart := Make_Visible_Part (Subname);
            Insert_Visible_Part (Vispart, Item_S);
        end if;

        Find_Stub_Decl (Subname, Item_S, Stub, Stub_Id);

        if Diana.Is_Empty (Stub) then
            Items := Diana.List (Item_S);
            Stub_Id := Make_Subunit_Name (Subname);
            Stub := Diana.Make (Diana.Dn_Package_Body, Stub_Id,
                                Diana.Make (Diana.Dn_Stub));
            Diana.List_Utilities.Nconc (Items, Stub);
        end if;

        Traversal.Get_Object (Stub_Id, Object, Status, Action_Id => Action_Id);
        Check (Status, "getting object for new subunit stub");

        Ada.Open (Ada.Get_Unit (Object), Ada.Update,
                  Subunit, Key, Status, Action_Id);
        Check (Status, "opening space for subunit");

        if Diana.Kind (Subunit) = Diana.Dn_Nonterminal then
            Ada.Set_Diana_Heap (Subunit, Status);
            Check (Status, "setting diana heap to new subunit");

            Subunit := Make_Subunit_Body (Subname);

            Ada.Set_Root (Subunit, Status, Action_Id);
            Check (Status, "setting root of new subunit");
        end if;

        Sroot := Subunit;
        Vpart := Vispart;
        The_Stub := Stub;
    end Create_Subunit_Space;

    procedure Make_Subunit (Unit_To_Split : Ada_Unit_Name;
                            Unit_Sizes_To_Include : Stmt_Decl_Count := 0;
                            Subunits_To_Separate : String := "";
                            Subunit_Name : String := "") is
        Def_Id : Directory.Declaration;
        Root : Ada.Root;
        Wroot : Ada.Root;
        Kinds : Unit_Kinds := (others => True);
        Status : Directory.Error_Status;
        Old_Heap : Ada.Root;
        Sroot : Ada.Root;
        Vpart : Diana.Tree;
        Stub : Diana.Tree;
        Sep_Ids : Diana.Temp_Seq := Diana.Make;
        Parent_Name : Diana.Symbol_Rep;
        Sunit_Name : Diana.Symbol_Rep;
        Action_Id : Action.Id := Action.Start;
    begin
        Log.Put_Line ("[Split.Make_Subunit, """ & Unit_To_Split & """," &
                      Integer'Image (Unit_Sizes_To_Include) & ", """ &
                      Subunits_To_Separate & """, """ & Subunit_Name & """]");
        Ada.Get_Diana_Heap (Old_Heap, Status);
        Check (Status, "getting old diana heap");

        Find_Unit (Unit_To_Split, Def_Id);
        Demote_Unit (Def_Id, Root, Action_Id);
        Make_Writable (Root, Wroot, Action_Id);

        Create_Subunit_Space (Wroot, String_Utilities.Upper_Case (Subunit_Name),
                              Vpart, Sroot, Stub, Action_Id);

        if Subunits_To_Separate /= "" then
            Process_Unit_List_Subunitize
               (Wroot, Vpart, Sroot, Subunits_To_Separate,
                Kinds, Action_Id, Sep_Ids);
        else
            Separate_Bodies_Into_Subunit
               (Wroot, Vpart, Sroot, Unit_Sizes_To_Include,
                Kinds, Action_Id, Sep_Ids);
        end if;

        Parent_Name := Diana.Id (Diana.Id_Utilities.Get_Id (Wroot));
        Sunit_Name := Diana.Id (Diana.Id_Utilities.Get_Id (Stub));

        Split_Util.Fix_References (Wroot, Stub, Sep_Ids, Action_Id,
                                   Parent_Name, Sunit_Name, False);
        Split_Util.Fix_References (Sroot, Diana.Empty, Sep_Ids, Action_Id,
                                   Parent_Name, Sunit_Name, True);
        Ada.Close (Sroot, Status, Action_Id);
        Check (Status, "closing new subunit");

        Ada.Close (Wroot, Status, Action_Id);
        Check (Status, "closing unit");

        Ada.Set_Diana_Heap (Old_Heap, Status);

        Action.Finish (Action_Id, Do_Commit => True);
        Log.Put_Line ("[end of Split.Make_Subunit]");
    exception
        when Failure =>
            Action.Finish (Action_Id, Do_Commit => False);
            Ada.Set_Diana_Heap (Old_Heap, Status);
            Log.Put_Line ("[end of Split.Make_Subunit]");

        when others =>
            Action.Finish (Action_Id, Do_Commit => False);
            Error ("Unexpected exception", False);
            Ada.Set_Diana_Heap (Old_Heap, Status);
            Log.Put_Line ("[end of Split.Make_Subunit]");
    end Make_Subunit;

end Split;