1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2008, 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 3, 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 COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
28 with Output
; use Output
;
31 package body Prj
.PP
is
35 Not_Tested
: array (Project_Node_Kind
) of Boolean := (others => True);
37 Max_Line_Length
: constant := 255;
38 -- Maximum length of a line. This is chosen to be compatible with older
39 -- versions of GNAT that had a strict limit on the maximum line length.
41 Column
: Natural := 0;
42 -- Column number of the last character in the line. Used to avoid
43 -- outputting lines longer than Max_Line_Length.
45 First_With_In_List
: Boolean := True;
46 -- Indicate that the next with clause is first in a list such as
48 -- First_With_In_List will be True for "A", but not for "B".
50 procedure Indicate_Tested
(Kind
: Project_Node_Kind
);
51 -- Set the corresponding component of array Not_Tested to False.
52 -- Only called by pragmas Debug.
58 procedure Indicate_Tested
(Kind
: Project_Node_Kind
) is
60 Not_Tested
(Kind
) := False;
67 procedure Pretty_Print
68 (Project
: Prj
.Tree
.Project_Node_Id
;
69 In_Tree
: Prj
.Tree
.Project_Node_Tree_Ref
;
70 Increment
: Positive := 3;
71 Eliminate_Empty_Case_Constructions
: Boolean := False;
72 Minimize_Empty_Lines
: Boolean := False;
73 W_Char
: Write_Char_Ap
:= null;
74 W_Eol
: Write_Eol_Ap
:= null;
75 W_Str
: Write_Str_Ap
:= null;
76 Backward_Compatibility
: Boolean;
77 Id
: Prj
.Project_Id
:= Prj
.No_Project
;
78 Id_Tree
: Prj
.Project_Tree_Ref
:= null)
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 procedure Output_String
(S
: Path_Name_Type
);
98 -- Outputs a string using the default output procedures
100 procedure Write_Empty_Line
(Always
: Boolean := False);
101 -- Outputs an empty line, only if the previous line was not empty
102 -- already and either Always is True or Minimize_Empty_Lines is False.
104 procedure Write_Line
(S
: String);
105 -- Outputs S followed by a new line
107 procedure Write_String
(S
: String; Truncated
: Boolean := False);
108 -- Outputs S using Write_Str, starting a new line if line would
109 -- become too long, when Truncated = False.
110 -- When Truncated = True, only the part of the string that can fit on
111 -- the line is output.
113 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
);
115 Write_Char
: Write_Char_Ap
:= Output
.Write_Char
'Access;
116 Write_Eol
: Write_Eol_Ap
:= Output
.Write_Eol
'Access;
117 Write_Str
: Write_Str_Ap
:= Output
.Write_Str
'Access;
118 -- These three access to procedure values are used for the output
120 Last_Line_Is_Empty
: Boolean := False;
121 -- Used to avoid two consecutive empty lines
123 ---------------------------
124 -- Output_Attribute_Name --
125 ---------------------------
127 procedure Output_Attribute_Name
(Name
: Name_Id
) is
129 if Backward_Compatibility
then
131 when Snames
.Name_Spec
=>
132 Output_Name
(Snames
.Name_Specification
);
134 when Snames
.Name_Spec_Suffix
=>
135 Output_Name
(Snames
.Name_Specification_Suffix
);
137 when Snames
.Name_Body
=>
138 Output_Name
(Snames
.Name_Implementation
);
140 when Snames
.Name_Body_Suffix
=>
141 Output_Name
(Snames
.Name_Implementation_Suffix
);
150 end Output_Attribute_Name
;
156 procedure Output_Name
(Name
: Name_Id
; Capitalize
: Boolean := True) is
157 Capital
: Boolean := Capitalize
;
160 Get_Name_String
(Name
);
162 -- If line would become too long, create new line
164 if Column
+ Name_Len
> Max_Line_Length
then
169 for J
in 1 .. Name_Len
loop
171 Write_Char
(To_Upper
(Name_Buffer
(J
)));
173 Write_Char
(Name_Buffer
(J
));
178 Name_Buffer
(J
) = '_'
179 or else Is_Digit
(Name_Buffer
(J
));
183 Column
:= Column
+ Name_Len
;
190 procedure Output_String
(S
: Name_Id
) is
194 -- If line could become too long, create new line.
195 -- Note that the number of characters on the line could be
196 -- twice the number of character in the string (if every
197 -- character is a '"') plus two (the initial and final '"').
199 if Column
+ Name_Len
+ Name_Len
+ 2 > Max_Line_Length
then
205 Column
:= Column
+ 1;
208 for J
in 1 .. Name_Len
loop
209 if Name_Buffer
(J
) = '"' then
212 Column
:= Column
+ 2;
214 Write_Char
(Name_Buffer
(J
));
215 Column
:= Column
+ 1;
218 -- If the string does not fit on one line, cut it in parts
221 if J
< Name_Len
and then Column
>= Max_Line_Length
then
230 Column
:= Column
+ 1;
233 procedure Output_String
(S
: Path_Name_Type
) is
235 Output_String
(Name_Id
(S
));
242 procedure Start_Line
(Indent
: Natural) is
244 if not Minimize_Empty_Lines
then
245 Write_Str
((1 .. Indent
=> ' '));
246 Column
:= Column
+ Indent
;
250 ----------------------
251 -- Write_Empty_Line --
252 ----------------------
254 procedure Write_Empty_Line
(Always
: Boolean := False) is
256 if (Always
or else not Minimize_Empty_Lines
)
257 and then not Last_Line_Is_Empty
then
260 Last_Line_Is_Empty
:= True;
262 end Write_Empty_Line
;
264 -------------------------------
265 -- Write_End_Of_Line_Comment --
266 -------------------------------
268 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
) is
269 Value
: constant Name_Id
:= End_Of_Line_Comment
(Node
, In_Tree
);
272 if Value
/= No_Name
then
273 Write_String
(" --");
274 Write_String
(Get_Name_String
(Value
), Truncated
=> True);
278 end Write_End_Of_Line_Comment
;
284 procedure Write_Line
(S
: String) is
287 Last_Line_Is_Empty
:= False;
296 procedure Write_String
(S
: String; Truncated
: Boolean := False) is
297 Length
: Natural := S
'Length;
299 -- If the string would not fit on the line,
302 if Column
+ Length
> Max_Line_Length
then
304 Length
:= Max_Line_Length
- Column
;
312 Write_Str
(S
(S
'First .. S
'First + Length
- 1));
313 Column
:= Column
+ Length
;
320 procedure Print
(Node
: Project_Node_Id
; Indent
: Natural) is
322 if Present
(Node
) then
324 case Kind_Of
(Node
, In_Tree
) is
327 pragma Debug
(Indicate_Tested
(N_Project
));
328 if Present
(First_With_Clause_Of
(Node
, In_Tree
)) then
332 First_With_In_List
:= True;
333 Print
(First_With_Clause_Of
(Node
, In_Tree
), Indent
);
334 Write_Empty_Line
(Always
=> True);
337 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
339 Write_String
("project ");
341 if Id
/= Prj
.No_Project
then
342 Output_Name
(Id_Tree
.Projects
.Table
(Id
).Display_Name
);
344 Output_Name
(Name_Of
(Node
, In_Tree
));
347 -- Check if this project extends another project
349 if Extended_Project_Path_Of
(Node
, In_Tree
) /= No_Path
then
350 Write_String
(" extends ");
352 if Is_Extending_All
(Node
, In_Tree
) then
353 Write_String
("all ");
356 Output_String
(Extended_Project_Path_Of
(Node
, In_Tree
));
359 Write_String
(" is");
360 Write_End_Of_Line_Comment
(Node
);
362 (First_Comment_After
(Node
, In_Tree
), Indent
+ Increment
);
363 Write_Empty_Line
(Always
=> True);
365 -- Output all of the declarations in the project
367 Print
(Project_Declaration_Of
(Node
, In_Tree
), Indent
);
369 (First_Comment_Before_End
(Node
, In_Tree
),
372 Write_String
("end ");
374 if Id
/= Prj
.No_Project
then
375 Output_Name
(Id_Tree
.Projects
.Table
(Id
).Display_Name
);
377 Output_Name
(Name_Of
(Node
, In_Tree
));
381 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
383 when N_With_Clause
=>
384 pragma Debug
(Indicate_Tested
(N_With_Clause
));
386 -- The with clause will sometimes contain an invalid name
387 -- when we are importing a virtual project from an
388 -- extending all project. Do not output anything in this
391 if Name_Of
(Node
, In_Tree
) /= No_Name
392 and then String_Value_Of
(Node
, In_Tree
) /= No_Name
394 if First_With_In_List
then
395 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
398 if Non_Limited_Project_Node_Of
(Node
, In_Tree
) =
401 Write_String
("limited ");
404 Write_String
("with ");
407 Output_String
(String_Value_Of
(Node
, In_Tree
));
409 if Is_Not_Last_In_List
(Node
, In_Tree
) then
411 First_With_In_List
:= False;
415 Write_End_Of_Line_Comment
(Node
);
416 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
417 First_With_In_List
:= True;
421 Print
(Next_With_Clause_Of
(Node
, In_Tree
), Indent
);
423 when N_Project_Declaration
=>
424 pragma Debug
(Indicate_Tested
(N_Project_Declaration
));
427 Present
(First_Declarative_Item_Of
(Node
, In_Tree
))
430 (First_Declarative_Item_Of
(Node
, In_Tree
),
432 Write_Empty_Line
(Always
=> True);
435 when N_Declarative_Item
=>
436 pragma Debug
(Indicate_Tested
(N_Declarative_Item
));
437 Print
(Current_Item_Node
(Node
, In_Tree
), Indent
);
438 Print
(Next_Declarative_Item
(Node
, In_Tree
), Indent
);
440 when N_Package_Declaration
=>
441 pragma Debug
(Indicate_Tested
(N_Package_Declaration
));
442 Write_Empty_Line
(Always
=> True);
443 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
445 Write_String
("package ");
446 Output_Name
(Name_Of
(Node
, In_Tree
));
448 if Project_Of_Renamed_Package_Of
(Node
, In_Tree
) /=
451 Write_String
(" renames ");
454 (Project_Of_Renamed_Package_Of
(Node
, In_Tree
),
457 Output_Name
(Name_Of
(Node
, In_Tree
));
459 Write_End_Of_Line_Comment
(Node
);
460 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
463 Write_String
(" is");
464 Write_End_Of_Line_Comment
(Node
);
465 Print
(First_Comment_After
(Node
, In_Tree
),
468 if First_Declarative_Item_Of
(Node
, In_Tree
) /=
472 (First_Declarative_Item_Of
(Node
, In_Tree
),
476 Print
(First_Comment_Before_End
(Node
, In_Tree
),
479 Write_String
("end ");
480 Output_Name
(Name_Of
(Node
, In_Tree
));
482 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
486 when N_String_Type_Declaration
=>
487 pragma Debug
(Indicate_Tested
(N_String_Type_Declaration
));
488 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
490 Write_String
("type ");
491 Output_Name
(Name_Of
(Node
, In_Tree
));
493 Start_Line
(Indent
+ Increment
);
497 String_Node
: Project_Node_Id
:=
498 First_Literal_String
(Node
, In_Tree
);
501 while Present
(String_Node
) loop
502 Output_String
(String_Value_Of
(String_Node
, In_Tree
));
504 Next_Literal_String
(String_Node
, In_Tree
);
506 if Present
(String_Node
) then
513 Write_End_Of_Line_Comment
(Node
);
514 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
516 when N_Literal_String
=>
517 pragma Debug
(Indicate_Tested
(N_Literal_String
));
518 Output_String
(String_Value_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);
525 when N_Attribute_Declaration
=>
526 pragma Debug
(Indicate_Tested
(N_Attribute_Declaration
));
527 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
529 Write_String
("for ");
530 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
532 if Associative_Array_Index_Of
(Node
, In_Tree
) /= No_Name
then
535 (Associative_Array_Index_Of
(Node
, In_Tree
));
537 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
538 Write_String
(" at ");
539 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
545 Write_String
(" use ");
547 if Present
(Expression_Of
(Node
, In_Tree
)) then
548 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
551 -- Full associative array declaration
554 Present
(Associative_Project_Of
(Node
, In_Tree
))
558 (Associative_Project_Of
(Node
, In_Tree
),
562 Present
(Associative_Package_Of
(Node
, In_Tree
))
567 (Associative_Package_Of
(Node
, In_Tree
),
572 Present
(Associative_Package_Of
(Node
, In_Tree
))
576 (Associative_Package_Of
(Node
, In_Tree
),
581 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
585 Write_End_Of_Line_Comment
(Node
);
586 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
588 when N_Typed_Variable_Declaration
=>
590 (Indicate_Tested
(N_Typed_Variable_Declaration
));
591 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
593 Output_Name
(Name_Of
(Node
, In_Tree
));
594 Write_String
(" : ");
596 (Name_Of
(String_Type_Of
(Node
, In_Tree
), In_Tree
));
597 Write_String
(" := ");
598 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
600 Write_End_Of_Line_Comment
(Node
);
601 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
603 when N_Variable_Declaration
=>
604 pragma Debug
(Indicate_Tested
(N_Variable_Declaration
));
605 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
607 Output_Name
(Name_Of
(Node
, In_Tree
));
608 Write_String
(" := ");
609 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
611 Write_End_Of_Line_Comment
(Node
);
612 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
615 pragma Debug
(Indicate_Tested
(N_Expression
));
617 Term
: Project_Node_Id
:= First_Term
(Node
, In_Tree
);
620 while Present
(Term
) loop
621 Print
(Term
, Indent
);
622 Term
:= Next_Term
(Term
, In_Tree
);
624 if Present
(Term
) then
625 Write_String
(" & ");
631 pragma Debug
(Indicate_Tested
(N_Term
));
632 Print
(Current_Term
(Node
, In_Tree
), Indent
);
634 when N_Literal_String_List
=>
635 pragma Debug
(Indicate_Tested
(N_Literal_String_List
));
639 Expression
: Project_Node_Id
:=
640 First_Expression_In_List
(Node
, In_Tree
);
643 while Present
(Expression
) loop
644 Print
(Expression
, Indent
);
646 Next_Expression_In_List
(Expression
, In_Tree
);
648 if Present
(Expression
) then
656 when N_Variable_Reference
=>
657 pragma Debug
(Indicate_Tested
(N_Variable_Reference
));
658 if Present
(Project_Node_Of
(Node
, In_Tree
)) then
660 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
664 if Present
(Package_Node_Of
(Node
, In_Tree
)) then
666 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
670 Output_Name
(Name_Of
(Node
, In_Tree
));
672 when N_External_Value
=>
673 pragma Debug
(Indicate_Tested
(N_External_Value
));
674 Write_String
("external (");
675 Print
(External_Reference_Of
(Node
, In_Tree
), Indent
);
677 if Present
(External_Default_Of
(Node
, In_Tree
)) then
679 Print
(External_Default_Of
(Node
, In_Tree
), Indent
);
684 when N_Attribute_Reference
=>
685 pragma Debug
(Indicate_Tested
(N_Attribute_Reference
));
687 if Present
(Project_Node_Of
(Node
, In_Tree
))
688 and then Project_Node_Of
(Node
, In_Tree
) /= Project
691 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
693 if Present
(Package_Node_Of
(Node
, In_Tree
)) then
696 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
699 elsif Present
(Package_Node_Of
(Node
, In_Tree
)) then
701 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
704 Write_String
("project");
708 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
711 Index
: constant Name_Id
:=
712 Associative_Array_Index_Of
(Node
, In_Tree
);
715 if Index
/= No_Name
then
717 Output_String
(Index
);
722 when N_Case_Construction
=>
723 pragma Debug
(Indicate_Tested
(N_Case_Construction
));
726 Case_Item
: Project_Node_Id
;
727 Is_Non_Empty
: Boolean := False;
730 Case_Item
:= First_Case_Item_Of
(Node
, In_Tree
);
731 while Present
(Case_Item
) loop
733 (First_Declarative_Item_Of
(Case_Item
, In_Tree
))
734 or else not Eliminate_Empty_Case_Constructions
736 Is_Non_Empty
:= True;
740 Case_Item
:= Next_Case_Item
(Case_Item
, In_Tree
);
745 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
747 Write_String
("case ");
749 (Case_Variable_Reference_Of
(Node
, In_Tree
),
751 Write_String
(" is");
752 Write_End_Of_Line_Comment
(Node
);
754 (First_Comment_After
(Node
, In_Tree
),
758 Case_Item
: Project_Node_Id
:=
759 First_Case_Item_Of
(Node
, In_Tree
);
761 while Present
(Case_Item
) loop
763 (Kind_Of
(Case_Item
, In_Tree
) = N_Case_Item
);
764 Print
(Case_Item
, Indent
+ Increment
);
766 Next_Case_Item
(Case_Item
, In_Tree
);
770 Print
(First_Comment_Before_End
(Node
, In_Tree
),
773 Write_Line
("end case;");
775 (First_Comment_After_End
(Node
, In_Tree
), Indent
);
780 pragma Debug
(Indicate_Tested
(N_Case_Item
));
782 if Present
(First_Declarative_Item_Of
(Node
, In_Tree
))
783 or else not Eliminate_Empty_Case_Constructions
786 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
788 Write_String
("when ");
790 if No
(First_Choice_Of
(Node
, In_Tree
)) then
791 Write_String
("others");
795 Label
: Project_Node_Id
:=
796 First_Choice_Of
(Node
, In_Tree
);
798 while Present
(Label
) loop
799 Print
(Label
, Indent
);
800 Label
:= Next_Literal_String
(Label
, In_Tree
);
802 if Present
(Label
) then
803 Write_String
(" | ");
809 Write_String
(" =>");
810 Write_End_Of_Line_Comment
(Node
);
812 (First_Comment_After
(Node
, In_Tree
),
816 First
: constant Project_Node_Id
:=
817 First_Declarative_Item_Of
(Node
, In_Tree
);
822 Print
(First
, Indent
+ Increment
);
827 when N_Comment_Zones
=>
829 -- Nothing to do, because it will not be processed directly
834 pragma Debug
(Indicate_Tested
(N_Comment
));
836 if Follows_Empty_Line
(Node
, In_Tree
) then
843 (Get_Name_String
(String_Value_Of
(Node
, In_Tree
)),
847 if Is_Followed_By_Empty_Line
(Node
, In_Tree
) then
851 Print
(Next_Comment
(Node
, In_Tree
), Indent
);
856 -- Start of processing for Pretty_Print
859 if W_Char
= null then
860 Write_Char
:= Output
.Write_Char
'Access;
862 Write_Char
:= W_Char
;
866 Write_Eol
:= Output
.Write_Eol
'Access;
872 Write_Str
:= Output
.Write_Str
'Access;
879 if W_Char
= null or else W_Str
= null then
884 -----------------------
885 -- Output_Statistics --
886 -----------------------
888 procedure Output_Statistics
is
890 Output
.Write_Line
("Project_Node_Kinds not tested:");
892 for Kind
in Project_Node_Kind
loop
893 if Kind
/= N_Comment_Zones
and then Not_Tested
(Kind
) then
894 Output
.Write_Str
(" ");
895 Output
.Write_Line
(Project_Node_Kind
'Image (Kind
));
900 end Output_Statistics
;