1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2005 Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
30 with Namet
; use Namet
;
31 with Output
; use Output
;
34 package body Prj
.PP
is
38 Not_Tested
: array (Project_Node_Kind
) of Boolean := (others => True);
40 Max_Line_Length
: constant := Hostparm
.Max_Line_Length
- 5;
41 -- Maximum length of a line.
43 Column
: Natural := 0;
44 -- Column number of the last character in the line. Used to avoid
45 -- outputing lines longer than Max_Line_Length.
47 First_With_In_List
: Boolean := True;
48 -- Indicate that the next with clause is first in a list such as
50 -- First_With_In_List will be True for "A", but not for "B".
52 procedure Indicate_Tested
(Kind
: Project_Node_Kind
);
53 -- Set the corresponding component of array Not_Tested to False.
54 -- Only called by pragmas Debug.
60 procedure Indicate_Tested
(Kind
: Project_Node_Kind
) is
62 Not_Tested
(Kind
) := False;
69 procedure Pretty_Print
70 (Project
: Prj
.Tree
.Project_Node_Id
;
71 In_Tree
: Prj
.Tree
.Project_Node_Tree_Ref
;
72 Increment
: Positive := 3;
73 Eliminate_Empty_Case_Constructions
: Boolean := False;
74 Minimize_Empty_Lines
: Boolean := False;
75 W_Char
: Write_Char_Ap
:= null;
76 W_Eol
: Write_Eol_Ap
:= null;
77 W_Str
: Write_Str_Ap
:= null;
78 Backward_Compatibility
: Boolean)
80 procedure Print
(Node
: Project_Node_Id
; Indent
: Natural);
81 -- A recursive procedure that traverses a project file tree and outputs
82 -- its source. Current_Prj is the project that we are printing. This
83 -- is used when printing attributes, since in nested packages they
84 -- need to use a fully qualified name.
86 procedure Output_Attribute_Name
(Name
: Name_Id
);
87 -- Outputs an attribute name, taking into account the value of
88 -- Backward_Compatibility.
90 procedure Output_Name
(Name
: Name_Id
; Capitalize
: Boolean := True);
93 procedure Start_Line
(Indent
: Natural);
94 -- Outputs the indentation at the beginning of the line.
96 procedure Output_String
(S
: Name_Id
);
97 -- Outputs a string using the default output procedures
99 procedure Write_Empty_Line
(Always
: Boolean := False);
100 -- Outputs an empty line, only if the previous line was not empty
101 -- already and either Always is True or Minimize_Empty_Lines is False.
103 procedure Write_Line
(S
: String);
104 -- Outputs S followed by a new line
106 procedure Write_String
(S
: String; Truncated
: Boolean := False);
107 -- Outputs S using Write_Str, starting a new line if line would
108 -- become too long, when Truncated = False.
109 -- When Truncated = True, only the part of the string that can fit on
110 -- the line is output.
112 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
);
114 Write_Char
: Write_Char_Ap
:= Output
.Write_Char
'Access;
115 Write_Eol
: Write_Eol_Ap
:= Output
.Write_Eol
'Access;
116 Write_Str
: Write_Str_Ap
:= Output
.Write_Str
'Access;
117 -- These three access to procedure values are used for the output.
119 Last_Line_Is_Empty
: Boolean := False;
120 -- Used to avoid two consecutive empty lines.
122 ---------------------------
123 -- Output_Attribute_Name --
124 ---------------------------
126 procedure Output_Attribute_Name
(Name
: Name_Id
) is
128 if Backward_Compatibility
then
130 when Snames
.Name_Spec
=>
131 Output_Name
(Snames
.Name_Specification
);
133 when Snames
.Name_Spec_Suffix
=>
134 Output_Name
(Snames
.Name_Specification_Suffix
);
136 when Snames
.Name_Body
=>
137 Output_Name
(Snames
.Name_Implementation
);
139 when Snames
.Name_Body_Suffix
=>
140 Output_Name
(Snames
.Name_Implementation_Suffix
);
149 end Output_Attribute_Name
;
155 procedure Output_Name
(Name
: Name_Id
; Capitalize
: Boolean := True) is
156 Capital
: Boolean := Capitalize
;
159 Get_Name_String
(Name
);
161 -- If line would become too long, create new line
163 if Column
+ Name_Len
> Max_Line_Length
then
168 for J
in 1 .. Name_Len
loop
170 Write_Char
(To_Upper
(Name_Buffer
(J
)));
172 Write_Char
(Name_Buffer
(J
));
177 Name_Buffer
(J
) = '_'
178 or else Is_Digit
(Name_Buffer
(J
));
182 Column
:= Column
+ Name_Len
;
189 procedure Output_String
(S
: Name_Id
) is
193 -- If line could become too long, create new line.
194 -- Note that the number of characters on the line could be
195 -- twice the number of character in the string (if every
196 -- character is a '"') plus two (the initial and final '"').
198 if Column
+ Name_Len
+ Name_Len
+ 2 > Max_Line_Length
then
204 Column
:= Column
+ 1;
207 for J
in 1 .. Name_Len
loop
208 if Name_Buffer
(J
) = '"' then
211 Column
:= Column
+ 2;
213 Write_Char
(Name_Buffer
(J
));
214 Column
:= Column
+ 1;
217 -- If the string does not fit on one line, cut it in parts
220 if J
< Name_Len
and then Column
>= Max_Line_Length
then
229 Column
:= Column
+ 1;
236 procedure Start_Line
(Indent
: Natural) is
238 if not Minimize_Empty_Lines
then
239 Write_Str
((1 .. Indent
=> ' '));
240 Column
:= Column
+ Indent
;
244 ----------------------
245 -- Write_Empty_Line --
246 ----------------------
248 procedure Write_Empty_Line
(Always
: Boolean := False) is
250 if (Always
or else not Minimize_Empty_Lines
)
251 and then not Last_Line_Is_Empty
then
254 Last_Line_Is_Empty
:= True;
256 end Write_Empty_Line
;
258 -------------------------------
259 -- Write_End_Of_Line_Comment --
260 -------------------------------
262 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
) is
263 Value
: constant Name_Id
:= End_Of_Line_Comment
(Node
, In_Tree
);
266 if Value
/= No_Name
then
267 Write_String
(" --");
268 Write_String
(Get_Name_String
(Value
), Truncated
=> True);
272 end Write_End_Of_Line_Comment
;
278 procedure Write_Line
(S
: String) is
281 Last_Line_Is_Empty
:= False;
290 procedure Write_String
(S
: String; Truncated
: Boolean := False) is
291 Length
: Natural := S
'Length;
293 -- If the string would not fit on the line,
296 if Column
+ Length
> Max_Line_Length
then
298 Length
:= Max_Line_Length
- Column
;
306 Write_Str
(S
(S
'First .. S
'First + Length
- 1));
307 Column
:= Column
+ Length
;
314 procedure Print
(Node
: Project_Node_Id
; Indent
: Natural) is
316 if Node
/= Empty_Node
then
318 case Kind_Of
(Node
, In_Tree
) is
321 pragma Debug
(Indicate_Tested
(N_Project
));
322 if First_With_Clause_Of
(Node
, In_Tree
) /= Empty_Node
then
326 First_With_In_List
:= True;
327 Print
(First_With_Clause_Of
(Node
, In_Tree
), Indent
);
328 Write_Empty_Line
(Always
=> True);
331 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
333 Write_String
("project ");
334 Output_Name
(Name_Of
(Node
, In_Tree
));
336 -- Check if this project extends another project
338 if Extended_Project_Path_Of
(Node
, In_Tree
) /= No_Name
then
339 Write_String
(" extends ");
340 Output_String
(Extended_Project_Path_Of
(Node
, In_Tree
));
343 Write_String
(" is");
344 Write_End_Of_Line_Comment
(Node
);
346 (First_Comment_After
(Node
, In_Tree
), Indent
+ Increment
);
347 Write_Empty_Line
(Always
=> True);
349 -- Output all of the declarations in the project
351 Print
(Project_Declaration_Of
(Node
, In_Tree
), Indent
);
353 (First_Comment_Before_End
(Node
, In_Tree
),
356 Write_String
("end ");
357 Output_Name
(Name_Of
(Node
, In_Tree
));
359 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
361 when N_With_Clause
=>
362 pragma Debug
(Indicate_Tested
(N_With_Clause
));
364 if Name_Of
(Node
, In_Tree
) /= No_Name
then
365 if First_With_In_List
then
366 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
369 if Non_Limited_Project_Node_Of
(Node
, In_Tree
) =
372 Write_String
("limited ");
375 Write_String
("with ");
378 Output_String
(String_Value_Of
(Node
, In_Tree
));
380 if Is_Not_Last_In_List
(Node
, In_Tree
) then
382 First_With_In_List
:= False;
386 Write_End_Of_Line_Comment
(Node
);
387 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
388 First_With_In_List
:= True;
392 Print
(Next_With_Clause_Of
(Node
, In_Tree
), Indent
);
394 when N_Project_Declaration
=>
395 pragma Debug
(Indicate_Tested
(N_Project_Declaration
));
398 First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
401 (First_Declarative_Item_Of
(Node
, In_Tree
),
403 Write_Empty_Line
(Always
=> True);
406 when N_Declarative_Item
=>
407 pragma Debug
(Indicate_Tested
(N_Declarative_Item
));
408 Print
(Current_Item_Node
(Node
, In_Tree
), Indent
);
409 Print
(Next_Declarative_Item
(Node
, In_Tree
), Indent
);
411 when N_Package_Declaration
=>
412 pragma Debug
(Indicate_Tested
(N_Package_Declaration
));
413 Write_Empty_Line
(Always
=> True);
414 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
416 Write_String
("package ");
417 Output_Name
(Name_Of
(Node
, In_Tree
));
419 if Project_Of_Renamed_Package_Of
(Node
, In_Tree
) /=
422 Write_String
(" renames ");
425 (Project_Of_Renamed_Package_Of
(Node
, In_Tree
),
428 Output_Name
(Name_Of
(Node
, In_Tree
));
430 Write_End_Of_Line_Comment
(Node
);
431 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
434 Write_String
(" is");
435 Write_End_Of_Line_Comment
(Node
);
436 Print
(First_Comment_After
(Node
, In_Tree
),
439 if First_Declarative_Item_Of
(Node
, In_Tree
) /=
443 (First_Declarative_Item_Of
(Node
, In_Tree
),
447 Print
(First_Comment_Before_End
(Node
, In_Tree
),
450 Write_String
("end ");
451 Output_Name
(Name_Of
(Node
, In_Tree
));
453 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
457 when N_String_Type_Declaration
=>
458 pragma Debug
(Indicate_Tested
(N_String_Type_Declaration
));
459 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
461 Write_String
("type ");
462 Output_Name
(Name_Of
(Node
, In_Tree
));
464 Start_Line
(Indent
+ Increment
);
468 String_Node
: Project_Node_Id
:=
469 First_Literal_String
(Node
, In_Tree
);
472 while String_Node
/= Empty_Node
loop
473 Output_String
(String_Value_Of
(String_Node
, In_Tree
));
475 Next_Literal_String
(String_Node
, In_Tree
);
477 if String_Node
/= Empty_Node
then
484 Write_End_Of_Line_Comment
(Node
);
485 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
487 when N_Literal_String
=>
488 pragma Debug
(Indicate_Tested
(N_Literal_String
));
489 Output_String
(String_Value_Of
(Node
, In_Tree
));
491 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
492 Write_String
(" at ");
493 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
496 when N_Attribute_Declaration
=>
497 pragma Debug
(Indicate_Tested
(N_Attribute_Declaration
));
498 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
500 Write_String
("for ");
501 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
503 if Associative_Array_Index_Of
(Node
, In_Tree
) /= No_Name
then
506 (Associative_Array_Index_Of
(Node
, In_Tree
));
508 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
509 Write_String
(" at ");
510 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
516 Write_String
(" use ");
517 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
519 Write_End_Of_Line_Comment
(Node
);
520 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
522 when N_Typed_Variable_Declaration
=>
524 (Indicate_Tested
(N_Typed_Variable_Declaration
));
525 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
527 Output_Name
(Name_Of
(Node
, In_Tree
));
528 Write_String
(" : ");
530 (Name_Of
(String_Type_Of
(Node
, In_Tree
), In_Tree
));
531 Write_String
(" := ");
532 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
534 Write_End_Of_Line_Comment
(Node
);
535 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
537 when N_Variable_Declaration
=>
538 pragma Debug
(Indicate_Tested
(N_Variable_Declaration
));
539 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
541 Output_Name
(Name_Of
(Node
, In_Tree
));
542 Write_String
(" := ");
543 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
545 Write_End_Of_Line_Comment
(Node
);
546 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
549 pragma Debug
(Indicate_Tested
(N_Expression
));
551 Term
: Project_Node_Id
:= First_Term
(Node
, In_Tree
);
554 while Term
/= Empty_Node
loop
555 Print
(Term
, Indent
);
556 Term
:= Next_Term
(Term
, In_Tree
);
558 if Term
/= Empty_Node
then
559 Write_String
(" & ");
565 pragma Debug
(Indicate_Tested
(N_Term
));
566 Print
(Current_Term
(Node
, In_Tree
), Indent
);
568 when N_Literal_String_List
=>
569 pragma Debug
(Indicate_Tested
(N_Literal_String_List
));
573 Expression
: Project_Node_Id
:=
574 First_Expression_In_List
(Node
, In_Tree
);
577 while Expression
/= Empty_Node
loop
578 Print
(Expression
, Indent
);
580 Next_Expression_In_List
(Expression
, In_Tree
);
582 if Expression
/= Empty_Node
then
590 when N_Variable_Reference
=>
591 pragma Debug
(Indicate_Tested
(N_Variable_Reference
));
592 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
594 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
598 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
600 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
604 Output_Name
(Name_Of
(Node
, In_Tree
));
606 when N_External_Value
=>
607 pragma Debug
(Indicate_Tested
(N_External_Value
));
608 Write_String
("external (");
609 Print
(External_Reference_Of
(Node
, In_Tree
), Indent
);
611 if External_Default_Of
(Node
, In_Tree
) /= Empty_Node
then
613 Print
(External_Default_Of
(Node
, In_Tree
), Indent
);
618 when N_Attribute_Reference
=>
619 pragma Debug
(Indicate_Tested
(N_Attribute_Reference
));
621 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
622 and then Project_Node_Of
(Node
, In_Tree
) /= Project
625 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
627 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
630 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
633 elsif Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
635 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
638 Write_String
("project");
642 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
645 Index
: constant Name_Id
:=
646 Associative_Array_Index_Of
(Node
, In_Tree
);
649 if Index
/= No_Name
then
651 Output_String
(Index
);
656 when N_Case_Construction
=>
657 pragma Debug
(Indicate_Tested
(N_Case_Construction
));
660 Case_Item
: Project_Node_Id
;
661 Is_Non_Empty
: Boolean := False;
664 Case_Item
:= First_Case_Item_Of
(Node
, In_Tree
);
665 while Case_Item
/= Empty_Node
loop
666 if First_Declarative_Item_Of
(Case_Item
, In_Tree
) /=
668 or else not Eliminate_Empty_Case_Constructions
670 Is_Non_Empty
:= True;
674 Case_Item
:= Next_Case_Item
(Case_Item
, In_Tree
);
679 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
681 Write_String
("case ");
683 (Case_Variable_Reference_Of
(Node
, In_Tree
),
685 Write_String
(" is");
686 Write_End_Of_Line_Comment
(Node
);
688 (First_Comment_After
(Node
, In_Tree
),
692 Case_Item
: Project_Node_Id
:=
693 First_Case_Item_Of
(Node
, In_Tree
);
695 while Case_Item
/= Empty_Node
loop
697 (Kind_Of
(Case_Item
, In_Tree
) = N_Case_Item
);
698 Print
(Case_Item
, Indent
+ Increment
);
700 Next_Case_Item
(Case_Item
, In_Tree
);
704 Print
(First_Comment_Before_End
(Node
, In_Tree
),
707 Write_Line
("end case;");
709 (First_Comment_After_End
(Node
, In_Tree
), Indent
);
714 pragma Debug
(Indicate_Tested
(N_Case_Item
));
716 if First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
717 or else not Eliminate_Empty_Case_Constructions
720 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
722 Write_String
("when ");
724 if First_Choice_Of
(Node
, In_Tree
) = Empty_Node
then
725 Write_String
("others");
729 Label
: Project_Node_Id
:=
730 First_Choice_Of
(Node
, In_Tree
);
732 while Label
/= Empty_Node
loop
733 Print
(Label
, Indent
);
734 Label
:= Next_Literal_String
(Label
, In_Tree
);
736 if Label
/= Empty_Node
then
737 Write_String
(" | ");
743 Write_String
(" =>");
744 Write_End_Of_Line_Comment
(Node
);
746 (First_Comment_After
(Node
, In_Tree
),
750 First
: constant Project_Node_Id
:=
751 First_Declarative_Item_Of
(Node
, In_Tree
);
753 if First
= Empty_Node
then
756 Print
(First
, Indent
+ Increment
);
761 when N_Comment_Zones
=>
763 -- Nothing to do, because it will not be processed directly
768 pragma Debug
(Indicate_Tested
(N_Comment
));
770 if Follows_Empty_Line
(Node
, In_Tree
) then
777 (Get_Name_String
(String_Value_Of
(Node
, In_Tree
)),
781 if Is_Followed_By_Empty_Line
(Node
, In_Tree
) then
785 Print
(Next_Comment
(Node
, In_Tree
), Indent
);
790 -- Start of processing for Pretty_Print
793 if W_Char
= null then
794 Write_Char
:= Output
.Write_Char
'Access;
796 Write_Char
:= W_Char
;
800 Write_Eol
:= Output
.Write_Eol
'Access;
806 Write_Str
:= Output
.Write_Str
'Access;
813 if W_Char
= null or else W_Str
= null then
818 -----------------------
819 -- Output_Statistics --
820 -----------------------
822 procedure Output_Statistics
is
824 Output
.Write_Line
("Project_Node_Kinds not tested:");
826 for Kind
in Project_Node_Kind
loop
827 if Kind
/= N_Comment_Zones
and then Not_Tested
(Kind
) then
828 Output
.Write_Str
(" ");
829 Output
.Write_Line
(Project_Node_Kind
'Image (Kind
));
834 end Output_Statistics
;