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 ");
341 if Is_Extending_All
(Node
, In_Tree
) then
342 Write_String
("all ");
345 Output_String
(Extended_Project_Path_Of
(Node
, In_Tree
));
348 Write_String
(" is");
349 Write_End_Of_Line_Comment
(Node
);
351 (First_Comment_After
(Node
, In_Tree
), Indent
+ Increment
);
352 Write_Empty_Line
(Always
=> True);
354 -- Output all of the declarations in the project
356 Print
(Project_Declaration_Of
(Node
, In_Tree
), Indent
);
358 (First_Comment_Before_End
(Node
, In_Tree
),
361 Write_String
("end ");
362 Output_Name
(Name_Of
(Node
, In_Tree
));
364 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
366 when N_With_Clause
=>
367 pragma Debug
(Indicate_Tested
(N_With_Clause
));
369 -- The with clause will sometimes contain an invalid name
370 -- when we are importing a virtual project from an
371 -- extending all project. Do not output anything in this
374 if Name_Of
(Node
, In_Tree
) /= No_Name
375 and then String_Value_Of
(Node
, In_Tree
) /= No_Name
377 if First_With_In_List
then
378 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
381 if Non_Limited_Project_Node_Of
(Node
, In_Tree
) =
384 Write_String
("limited ");
387 Write_String
("with ");
390 Output_String
(String_Value_Of
(Node
, In_Tree
));
392 if Is_Not_Last_In_List
(Node
, In_Tree
) then
394 First_With_In_List
:= False;
398 Write_End_Of_Line_Comment
(Node
);
399 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
400 First_With_In_List
:= True;
404 Print
(Next_With_Clause_Of
(Node
, In_Tree
), Indent
);
406 when N_Project_Declaration
=>
407 pragma Debug
(Indicate_Tested
(N_Project_Declaration
));
410 First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
413 (First_Declarative_Item_Of
(Node
, In_Tree
),
415 Write_Empty_Line
(Always
=> True);
418 when N_Declarative_Item
=>
419 pragma Debug
(Indicate_Tested
(N_Declarative_Item
));
420 Print
(Current_Item_Node
(Node
, In_Tree
), Indent
);
421 Print
(Next_Declarative_Item
(Node
, In_Tree
), Indent
);
423 when N_Package_Declaration
=>
424 pragma Debug
(Indicate_Tested
(N_Package_Declaration
));
425 Write_Empty_Line
(Always
=> True);
426 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
428 Write_String
("package ");
429 Output_Name
(Name_Of
(Node
, In_Tree
));
431 if Project_Of_Renamed_Package_Of
(Node
, In_Tree
) /=
434 Write_String
(" renames ");
437 (Project_Of_Renamed_Package_Of
(Node
, In_Tree
),
440 Output_Name
(Name_Of
(Node
, In_Tree
));
442 Write_End_Of_Line_Comment
(Node
);
443 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
446 Write_String
(" is");
447 Write_End_Of_Line_Comment
(Node
);
448 Print
(First_Comment_After
(Node
, In_Tree
),
451 if First_Declarative_Item_Of
(Node
, In_Tree
) /=
455 (First_Declarative_Item_Of
(Node
, In_Tree
),
459 Print
(First_Comment_Before_End
(Node
, In_Tree
),
462 Write_String
("end ");
463 Output_Name
(Name_Of
(Node
, In_Tree
));
465 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
469 when N_String_Type_Declaration
=>
470 pragma Debug
(Indicate_Tested
(N_String_Type_Declaration
));
471 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
473 Write_String
("type ");
474 Output_Name
(Name_Of
(Node
, In_Tree
));
476 Start_Line
(Indent
+ Increment
);
480 String_Node
: Project_Node_Id
:=
481 First_Literal_String
(Node
, In_Tree
);
484 while String_Node
/= Empty_Node
loop
485 Output_String
(String_Value_Of
(String_Node
, In_Tree
));
487 Next_Literal_String
(String_Node
, In_Tree
);
489 if String_Node
/= Empty_Node
then
496 Write_End_Of_Line_Comment
(Node
);
497 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
499 when N_Literal_String
=>
500 pragma Debug
(Indicate_Tested
(N_Literal_String
));
501 Output_String
(String_Value_Of
(Node
, In_Tree
));
503 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
504 Write_String
(" at ");
505 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
508 when N_Attribute_Declaration
=>
509 pragma Debug
(Indicate_Tested
(N_Attribute_Declaration
));
510 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
512 Write_String
("for ");
513 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
515 if Associative_Array_Index_Of
(Node
, In_Tree
) /= No_Name
then
518 (Associative_Array_Index_Of
(Node
, In_Tree
));
520 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
521 Write_String
(" at ");
522 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
528 Write_String
(" use ");
529 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
531 Write_End_Of_Line_Comment
(Node
);
532 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
534 when N_Typed_Variable_Declaration
=>
536 (Indicate_Tested
(N_Typed_Variable_Declaration
));
537 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
539 Output_Name
(Name_Of
(Node
, In_Tree
));
540 Write_String
(" : ");
542 (Name_Of
(String_Type_Of
(Node
, In_Tree
), In_Tree
));
543 Write_String
(" := ");
544 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
546 Write_End_Of_Line_Comment
(Node
);
547 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
549 when N_Variable_Declaration
=>
550 pragma Debug
(Indicate_Tested
(N_Variable_Declaration
));
551 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
553 Output_Name
(Name_Of
(Node
, In_Tree
));
554 Write_String
(" := ");
555 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
557 Write_End_Of_Line_Comment
(Node
);
558 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
561 pragma Debug
(Indicate_Tested
(N_Expression
));
563 Term
: Project_Node_Id
:= First_Term
(Node
, In_Tree
);
566 while Term
/= Empty_Node
loop
567 Print
(Term
, Indent
);
568 Term
:= Next_Term
(Term
, In_Tree
);
570 if Term
/= Empty_Node
then
571 Write_String
(" & ");
577 pragma Debug
(Indicate_Tested
(N_Term
));
578 Print
(Current_Term
(Node
, In_Tree
), Indent
);
580 when N_Literal_String_List
=>
581 pragma Debug
(Indicate_Tested
(N_Literal_String_List
));
585 Expression
: Project_Node_Id
:=
586 First_Expression_In_List
(Node
, In_Tree
);
589 while Expression
/= Empty_Node
loop
590 Print
(Expression
, Indent
);
592 Next_Expression_In_List
(Expression
, In_Tree
);
594 if Expression
/= Empty_Node
then
602 when N_Variable_Reference
=>
603 pragma Debug
(Indicate_Tested
(N_Variable_Reference
));
604 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
606 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
610 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
612 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
616 Output_Name
(Name_Of
(Node
, In_Tree
));
618 when N_External_Value
=>
619 pragma Debug
(Indicate_Tested
(N_External_Value
));
620 Write_String
("external (");
621 Print
(External_Reference_Of
(Node
, In_Tree
), Indent
);
623 if External_Default_Of
(Node
, In_Tree
) /= Empty_Node
then
625 Print
(External_Default_Of
(Node
, In_Tree
), Indent
);
630 when N_Attribute_Reference
=>
631 pragma Debug
(Indicate_Tested
(N_Attribute_Reference
));
633 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
634 and then Project_Node_Of
(Node
, In_Tree
) /= Project
637 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
639 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
642 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
645 elsif Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
647 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
650 Write_String
("project");
654 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
657 Index
: constant Name_Id
:=
658 Associative_Array_Index_Of
(Node
, In_Tree
);
661 if Index
/= No_Name
then
663 Output_String
(Index
);
668 when N_Case_Construction
=>
669 pragma Debug
(Indicate_Tested
(N_Case_Construction
));
672 Case_Item
: Project_Node_Id
;
673 Is_Non_Empty
: Boolean := False;
676 Case_Item
:= First_Case_Item_Of
(Node
, In_Tree
);
677 while Case_Item
/= Empty_Node
loop
678 if First_Declarative_Item_Of
(Case_Item
, In_Tree
) /=
680 or else not Eliminate_Empty_Case_Constructions
682 Is_Non_Empty
:= True;
686 Case_Item
:= Next_Case_Item
(Case_Item
, In_Tree
);
691 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
693 Write_String
("case ");
695 (Case_Variable_Reference_Of
(Node
, In_Tree
),
697 Write_String
(" is");
698 Write_End_Of_Line_Comment
(Node
);
700 (First_Comment_After
(Node
, In_Tree
),
704 Case_Item
: Project_Node_Id
:=
705 First_Case_Item_Of
(Node
, In_Tree
);
707 while Case_Item
/= Empty_Node
loop
709 (Kind_Of
(Case_Item
, In_Tree
) = N_Case_Item
);
710 Print
(Case_Item
, Indent
+ Increment
);
712 Next_Case_Item
(Case_Item
, In_Tree
);
716 Print
(First_Comment_Before_End
(Node
, In_Tree
),
719 Write_Line
("end case;");
721 (First_Comment_After_End
(Node
, In_Tree
), Indent
);
726 pragma Debug
(Indicate_Tested
(N_Case_Item
));
728 if First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
729 or else not Eliminate_Empty_Case_Constructions
732 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
734 Write_String
("when ");
736 if First_Choice_Of
(Node
, In_Tree
) = Empty_Node
then
737 Write_String
("others");
741 Label
: Project_Node_Id
:=
742 First_Choice_Of
(Node
, In_Tree
);
744 while Label
/= Empty_Node
loop
745 Print
(Label
, Indent
);
746 Label
:= Next_Literal_String
(Label
, In_Tree
);
748 if Label
/= Empty_Node
then
749 Write_String
(" | ");
755 Write_String
(" =>");
756 Write_End_Of_Line_Comment
(Node
);
758 (First_Comment_After
(Node
, In_Tree
),
762 First
: constant Project_Node_Id
:=
763 First_Declarative_Item_Of
(Node
, In_Tree
);
765 if First
= Empty_Node
then
768 Print
(First
, Indent
+ Increment
);
773 when N_Comment_Zones
=>
775 -- Nothing to do, because it will not be processed directly
780 pragma Debug
(Indicate_Tested
(N_Comment
));
782 if Follows_Empty_Line
(Node
, In_Tree
) then
789 (Get_Name_String
(String_Value_Of
(Node
, In_Tree
)),
793 if Is_Followed_By_Empty_Line
(Node
, In_Tree
) then
797 Print
(Next_Comment
(Node
, In_Tree
), Indent
);
802 -- Start of processing for Pretty_Print
805 if W_Char
= null then
806 Write_Char
:= Output
.Write_Char
'Access;
808 Write_Char
:= W_Char
;
812 Write_Eol
:= Output
.Write_Eol
'Access;
818 Write_Str
:= Output
.Write_Str
'Access;
825 if W_Char
= null or else W_Str
= null then
830 -----------------------
831 -- Output_Statistics --
832 -----------------------
834 procedure Output_Statistics
is
836 Output
.Write_Line
("Project_Node_Kinds not tested:");
838 for Kind
in Project_Node_Kind
loop
839 if Kind
/= N_Comment_Zones
and then Not_Tested
(Kind
) then
840 Output
.Write_Str
(" ");
841 Output
.Write_Line
(Project_Node_Kind
'Image (Kind
));
846 end Output_Statistics
;