1
-------------------------------------------------------------------------------
3
-- This file is part of AdaBrowse.
5
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
7
-- AdaBrowse is free software; you can redistribute it and/or modify it
8
-- under the terms of the GNU General Public License as published by the
9
-- Free Software Foundation; either version 2, or (at your option) any
10
-- later version. AdaBrowse is distributed in the hope that it will be
11
-- useful, but <EM>without any warranty</EM>; without even the implied
12
-- warranty of <EM>merchantability or fitness for a particular purpose.</EM>
13
-- See the GNU General Public License for more details. You should have
14
-- received a copy of the GNU General Public License with this distribution,
15
-- see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
16
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21
-- Author:</STRONG><DD>
23
-- <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
26
-- Purpose:</STRONG><DD>
27
-- Storage of description definitions.</DL>
32
-- 06-FEB-2002 TW Initial version.
33
-- 26-FEB-2002 TW Added 'A_Component_Declaration' to function
34
-- 'Item_Class' (components of protected objs or types).
35
-- 19-MAR-2002 TW Added 'An_Object_Renaming_Declaration' to function
37
-- 25-MAR-2002 TW Changed the item class for task (type) declarations
38
-- without content ("task type X;") to Item_Type or
39
-- Item_Object instead of Item_Task.
40
-- 11-NOV-2002 TW Added 'Item_Context_Clause'.
42
-------------------------------------------------------------------------------
47
with Ada.Strings.Maps;
48
with Ada.Unchecked_Deallocation;
51
with AD.Text_Utilities;
54
with Asis.Declarations;
62
package body AD.Descriptions is
64
package ASM renames Ada.Strings.Maps;
67
use Asis.Declarations;
72
use AD.Text_Utilities;
77
Ada.Unchecked_Deallocation (Finders, Finders_Ptr);
79
type Handle is access Finders_Ptr;
82
Ada.Unchecked_Deallocation (Finders_Ptr, Handle);
90
Comment_Finders : array (Item_Classes) of Desc;
92
subtype Default_Count is Natural range 0 .. 2;
94
type Default_Desc (N : Default_Count := 0) is
97
Find : Finders (1 .. N);
100
Defaults : constant array (Item_Classes) of Default_Desc :=
102
(0, No_Item_Class, (others => (None, 0))),
103
Item_Context_Clause =>
104
(1, Item_Context_Clause, (1 => (After, 1))),
106
(1, Item_Clause, (1 => (After, 1))),
108
(1, Item_Constant, (1 => (After, 1))),
110
(2, Item_Container, ((Before, Unlimited), (Inside, Unlimited))),
112
(1, Item_Exception, (1 => (After, 1))),
113
Item_Instantiation =>
114
(1, Item_Subprogram, (1 => (After, 1))),
116
(2, Item_Library, ((Before, Unlimited), (After, Unlimited))),
117
Item_Library_Instantiation =>
118
(0, Item_Library, (others => (None, 0))),
119
Item_Library_Package =>
120
(0, Item_Library, (others => (None, 0))),
121
Item_Library_Renaming =>
122
(0, Item_Library, (others => (None, 0))),
123
Item_Library_Subprogram =>
124
(0, Item_Library, (others => (None, 0))),
126
(1, Item_Object, (1 => (After, 1))),
128
(0, Item_Container, (others => (None, 0))),
130
(1, Item_Pragma, (1 => (After, 1))),
132
(0, Item_Container, (others => (None, 0))),
134
(1, Item_Subprogram, (1 => (After, 1))),
136
(1, Item_Rep_Clause, (1 => (After, 1))),
138
(1, Item_Subprogram, (1 => (After, 1))),
140
(0, Item_Container, (others => (None, 0))),
142
(2, Item_Type, ((After, 1), (Before, Unlimited)))
145
----------------------------------------------------------------------------
148
(The_Class : in Item_Classes)
151
if Comment_Finders (The_Class).Is_Default then
154
if Defaults (The_Class).Super = The_Class then
155
Free (Comment_Finders (The_Class).Ptr.all);
156
Comment_Finders (The_Class).Ptr.all :=
157
new Finders'(Defaults (The_Class).Find);
159
Free (Comment_Finders (The_Class).Ptr.all);
160
Free (Comment_Finders (The_Class).Ptr);
161
Comment_Finders (The_Class).Ptr :=
162
Comment_Finders (Defaults (The_Class).Super).Ptr;
164
Comment_Finders (The_Class).Is_Default := True;
168
(The_Class : in Item_Classes;
172
if The_Class = No_Item_Class then raise Program_Error; end if;
173
if Comment_Finders (The_Class).Is_Default and then
174
Defaults (The_Class).Super /= The_Class
176
-- A subclass at its default setting: shares the parent data
177
-- structure. Hence we need to create a new one.
178
Comment_Finders (The_Class).Ptr := new Finders_Ptr;
180
-- It has its own data structure.
181
Free (Comment_Finders (The_Class).Ptr.all);
183
Comment_Finders (The_Class).Ptr.all := new Finders'(To);
184
Comment_Finders (The_Class).Is_Default := False;
187
----------------------------------------------------------------------------
190
(Selector : in String;
199
function Parse_Finder
201
return Comment_Finder
203
Result : Comment_Finder := (None, 0);
206
if Is_Prefix (Value, "after") then
207
Result.Where := After; N := 5;
208
elsif Is_Prefix (Value, "before") then
209
Result.Where := Before; N := 6;
210
elsif Is_Prefix (Value, "inside") then
211
Result.Where := Inside; N := 6;
212
elsif Value = "none" then
215
if Result.Where = None then
216
Ada.Exceptions.Raise_Exception
217
(AD.Config.Invalid_Config'Identity,
218
"unknown location """ & Value & '"');
220
if Value'Length = N then
221
Result.How_Far := Unlimited;
224
-- "(number)" must be following.
225
N := Index (Value (Value'First + N .. Value'Last), '(');
227
Ada.Exceptions.Raise_Exception
228
(AD.Config.Invalid_Config'Identity,
229
"invalid location """ & Value & '"');
232
I : constant Natural := N;
233
J : constant Natural :=
234
Index (Value (N + 1 .. Value'Last), ')');
235
Limit : Integer := -1;
237
if J = Value'Last then
239
Limit := Integer'Value (Value (I + 1 .. J - 1));
246
Ada.Exceptions.Raise_Exception
247
(AD.Config.Invalid_Config'Identity,
248
"invalid location """ & Value & '"');
250
Result.How_Far := Limit;
259
while I <= Value'Last loop
260
J := Index (Value, ',');
261
if J = 0 then J := Value'Last + 1; end if;
263
Item : constant String :=
264
To_Lower (Trim (Value (I .. J - 1)));
266
if Item'Last >= Item'First then
267
return Parse_Finder (Item) &
268
Parse_List (Value (J + 1 .. Value'Last));
274
Null_Finders : Finders (2 .. 1);
280
The_Class : Item_Classes;
284
The_Class := Item_Classes'Value ("ITEM_" & To_Upper (Selector));
286
when Constraint_Error =>
287
Ada.Exceptions.Raise_Exception
288
(AD.Config.Invalid_Config'Identity,
289
"unknown selector """ & Selector & '"');
292
Where : constant Finders := Parse_List (Value);
294
if Where'Last < Where'First then
297
-- Check semantics: only containers and library items can have
299
if Defaults (The_Class).Super /= Item_Container and then
300
Defaults (The_Class).Super /= Item_Library
302
for I in Where'Range loop
303
if Where (I).Where = Inside then
304
Ada.Exceptions.Raise_Exception
305
(AD.Config.Invalid_Config'Identity,
306
"this description selector cannot have an " &
307
"""Inside"" location");
312
Set (The_Class, Where);
317
----------------------------------------------------------------------------
320
(Item : in Asis.Element)
324
case Element_Kind (Item) is
326
case Clause_Kind (Item) is
327
when A_Representation_Clause |
328
A_Component_Clause =>
329
return Item_Rep_Clause;
330
when A_With_Clause =>
331
return Item_Context_Clause;
332
when A_Use_Package_Clause | A_Use_Type_Clause =>
333
-- It's a context clause if it occurs before the start
334
-- of that compilation unit's declaration.
336
Decl : constant Declaration :=
337
Unit_Declaration (Enclosing_Compilation_Unit (Item));
339
if Is_Nil (Decl) or else
340
Start (Get_Span (Decl)) > Stop (Get_Span (Item))
342
return Item_Context_Clause;
353
when A_Declaration =>
354
case Declaration_Kind (Item) is
355
when An_Exception_Renaming_Declaration |
356
An_Exception_Declaration =>
357
return Item_Exception;
359
when A_Task_Type_Declaration =>
360
if Is_Nil (Type_Declaration_View (Item)) then
366
when A_Single_Task_Declaration =>
367
if Is_Nil (Object_Declaration_View (Item)) then
373
when A_Protected_Type_Declaration |
374
A_Single_Protected_Declaration =>
375
return Item_Protected;
377
when A_Package_Declaration |
378
A_Generic_Package_Declaration =>
381
Unit_Declaration (Enclosing_Compilation_Unit (Item)))
383
return Item_Library_Package;
388
when A_Procedure_Declaration |
389
A_Function_Declaration |
390
A_Generic_Procedure_Declaration |
391
A_Generic_Function_Declaration =>
394
Unit_Declaration (Enclosing_Compilation_Unit (Item)))
396
return Item_Library_Subprogram;
398
return Item_Subprogram;
401
when A_Procedure_Renaming_Declaration |
402
A_Function_Renaming_Declaration |
403
A_Package_Renaming_Declaration |
404
A_Generic_Procedure_Renaming_Declaration |
405
A_Generic_Function_Renaming_Declaration |
406
A_Generic_Package_Renaming_Declaration =>
409
Unit_Declaration (Enclosing_Compilation_Unit (Item)))
411
return Item_Library_Renaming;
413
return Item_Renaming;
416
when A_Procedure_Instantiation |
417
A_Function_Instantiation |
418
A_Package_Instantiation =>
421
Unit_Declaration (Enclosing_Compilation_Unit (Item)))
423
return Item_Library_Instantiation;
425
return Item_Instantiation;
428
when An_Entry_Declaration =>
429
return Item_Subprogram;
431
when A_Constant_Declaration |
432
A_Deferred_Constant_Declaration |
433
An_Integer_Number_Declaration |
434
A_Real_Number_Declaration =>
435
return Item_Constant;
437
when A_Variable_Declaration |
438
A_Component_Declaration |
439
An_Object_Renaming_Declaration =>
440
-- Components can occur as the items in the private part of
441
-- a protected type or object.
445
if (Declaration_Kind (Item) in A_Type_Declaration) or else
446
(Declaration_Kind (Item) = A_Subtype_Declaration)
451
end case; -- Declaration_Kind
456
end case; -- Element_Kind
457
return No_Item_Class;
460
function Is_Container
461
(Class : in Item_Classes)
465
return Defaults (Class).Super = Item_Container or else
466
Class = Item_Library_Package;
470
(The_Class : in Item_Classes)
474
return Comment_Finders (The_Class).Ptr.all;
477
----------------------------------------------------------------------------
480
type Range_Ptr is access Text_Range;
483
Start : Asis.Text.Line_Number;
484
Stop : Asis.Text.Line_Number;
489
new Ada.Unchecked_Deallocation (Text_Range, Range_Ptr);
494
(Span : Asis.Text.Span)
497
First : constant Line_Number := Start (Span).Line;
498
Last : constant Line_Number := Stop (Span).Line;
501
-- There can be no overlaps!
502
while P /= null and then Last < P.Stop loop
506
Anchor := new Text_Range'(First, Last, P);
508
Q.Next := new Text_Range'(First, Last, P);
513
(Pos : Asis.Text.Line_Number)
516
P : Range_Ptr := Anchor;
518
while P /= null and then Pos <= P.Stop loop
519
if Pos >= P.Start then return True; end if;
525
procedure Clear_Comments
531
Q := P; P := P.Next; Free (Q);
537
(Decl : in Asis.Declaration)
540
All_Names : constant Name_List := Names (Decl);
542
return All_Names (All_Names'First);
545
procedure Find_Comment
546
(Unit : in Asis.Element;
549
Span : in out Asis.Text.Span;
550
Direction : in Ada.Strings.Direction := Ada.Strings.Forward)
552
-- 'Span' is initially nil!
554
use type Ada.Strings.Direction;
556
Comment_Pos : Position;
559
if Is_Nil (From) then return; end if;
560
if Direction = Ada.Strings.Backward then
562
Find_Comment (Unit, From.Line, Ada.Strings.Backward);
563
if Is_Nil (Comment_Pos) or else
565
Integer (From.Line - Comment_Pos.Line - 1) > Limit) or else
566
Is_Taken (Comment_Pos.Line)
570
Set_Stop (Span, Comment_Pos);
572
(Span, Expand_Comment (Unit, Comment_Pos, Ada.Strings.Backward));
574
Comment_Pos := Find_Comment (Unit, From.Line);
575
if Is_Nil (Comment_Pos) or else
577
Integer (Comment_Pos.Line - From.Line - 1) > Limit) or else
578
Is_Taken (Comment_Pos.Line)
582
Set_Start (Span, Comment_Pos);
583
Set_Stop (Span, Expand_Comment (Unit, Comment_Pos));
585
Comment_Pos := Start (Span);
586
if Comment_Pos.Line = Stop (Span).Line then
587
-- A one-liner... if it is empty after we've stripped out any blanks
588
-- and dashes, it is not a comment after all!
590
use type ASM.Character_Set;
591
L : constant Line_List := Asis.Text.Lines (Unit, Span);
592
S : constant String :=
593
Trim (To_String (Comment_Image (L (L'First))),
594
Blanks or ASM.To_Set ("-"),
595
Blanks or ASM.To_Set ("-"));
597
if S'Last < S'First then
598
Span := Asis.Text.Nil_Span;
605
(Self : in Comment_Finder;
606
Item : in Asis.Element;
607
Span : out Asis.Text.Span;
608
Class : in Item_Classes := No_Item_Class)
611
Span := Asis.Text.Nil_Span;
612
if Self.Where = None then return; end if;
614
The_Span : constant Asis.Text.Span := Get_Span (Item);
616
Find (Self, Item, Start (The_Span), Stop (The_Span), Span, Class);
620
----------------------------------------------------------------------------
623
(Self : in Comment_Finder;
624
Item : in Asis.Element;
625
From : in Asis2.Spans.Position;
626
To : in Asis2.Spans.Position;
627
Span : out Asis.Text.Span;
628
Class : in Item_Classes := No_Item_Class)
630
The_Class : Item_Classes := Class;
631
Front, Back, Inner : Position;
633
Span := Asis.Text.Nil_Span;
634
if Self.Where = None then return; end if;
637
if The_Class = No_Item_Class then
638
The_Class := Item_Class (Item);
640
if The_Class = No_Item_Class then return; end if;
641
if Defaults (The_Class).Super = Item_Container then
642
-- Find the end of the header
643
case Declaration_Kind (Item) is
644
when A_Task_Type_Declaration |
645
A_Protected_Type_Declaration =>
647
Before_Is : Asis.Element :=
648
Discriminant_Part (Item);
650
if Is_Nil (Before_Is) then
651
Before_Is := Get_Name (Item);
654
Stop (Through (Item, "is",
655
From => Stop (Get_Span (Before_Is))));
658
when A_Single_Task_Declaration |
659
A_Single_Protected_Declaration |
660
A_Package_Declaration |
661
A_Generic_Package_Declaration =>
664
(Through (Item, "is",
665
From => Stop (Get_Span (Get_Name (Item)))));
672
elsif Defaults (The_Class).Super = Item_Library then
673
-- Front is before the context clauses; Inner is the beginning of
674
-- the item, Back is the end of the item, or, if it is a package,
675
-- the end of the header.
678
Clauses : constant Context_Clause_List :=
679
Context_Clause_Elements (Enclosing_Compilation_Unit (Item),
682
if Clauses'Last >= Clauses'First then
683
Front := Start (Get_Span (Clauses (Clauses'First)));
684
if Is_Nil (Front) then Front := Inner; end if;
687
if The_Class = Item_Library_Package then
688
-- Find the end of the header, i.e. the "is" after the package
691
Stop (Through (Item, "is",
692
From => Stop (Get_Span (Get_Name (Item)))));
695
-- All right, we now have the three positions we (may) need.
697
Unit : constant Declaration :=
698
Unit_Declaration (Enclosing_Compilation_Unit (Item));
703
(Unit, Front, Self.How_Far, Span, Ada.Strings.Backward);
706
if Defaults (The_Class).Super = Item_Library then
707
-- Search backwards; 'Inner' is the beginning of the unit.
709
(Unit, Front, Self.How_Far, Span, Ada.Strings.Backward);
711
Find_Comment (Unit, Inner, Self.How_Far, Span);
715
Find_Comment (Unit, Back, Self.How_Far, Span);
722
if not Is_Nil (Span) then
727
begin -- AD.Descriptions.BODY
728
for I in Comment_Finders'Range loop
729
if I = No_Item_Class then
730
Comment_Finders (I).Ptr := null;
731
elsif Defaults (I).Super = I then
732
Comment_Finders (I).Ptr := new Finders_Ptr;
733
Comment_Finders (I).Ptr.all := new Finders'(Defaults (I).Find);
736
for I in Comment_Finders'Range loop
737
Comment_Finders (I).Is_Default := True;
738
if Defaults (I).Super /= I then
739
Comment_Finders (I).Ptr := Comment_Finders (Defaults (I).Super).Ptr;