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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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 procedure Indicate_Tested
(Kind
: Project_Node_Kind
);
48 -- Set the corresponding component of array Not_Tested to False.
49 -- Only called by pragmas Debug.
55 procedure Indicate_Tested
(Kind
: Project_Node_Kind
) is
57 Not_Tested
(Kind
) := False;
64 procedure Pretty_Print
65 (Project
: Prj
.Tree
.Project_Node_Id
;
66 In_Tree
: Prj
.Tree
.Project_Node_Tree_Ref
;
67 Increment
: Positive := 3;
68 Eliminate_Empty_Case_Constructions
: Boolean := False;
69 Minimize_Empty_Lines
: Boolean := False;
70 W_Char
: Write_Char_Ap
:= null;
71 W_Eol
: Write_Eol_Ap
:= null;
72 W_Str
: Write_Str_Ap
:= null;
73 Backward_Compatibility
: Boolean)
75 procedure Print
(Node
: Project_Node_Id
; Indent
: Natural);
76 -- A recursive procedure that traverses a project file tree and outputs
77 -- its source. Current_Prj is the project that we are printing. This
78 -- is used when printing attributes, since in nested packages they
79 -- need to use a fully qualified name.
81 procedure Output_Attribute_Name
(Name
: Name_Id
);
82 -- Outputs an attribute name, taking into account the value of
83 -- Backward_Compatibility.
85 procedure Output_Name
(Name
: Name_Id
; Capitalize
: Boolean := True);
88 procedure Start_Line
(Indent
: Natural);
89 -- Outputs the indentation at the beginning of the line.
91 procedure Output_String
(S
: Name_Id
);
92 -- Outputs a string using the default output procedures
94 procedure Write_Empty_Line
(Always
: Boolean := False);
95 -- Outputs an empty line, only if the previous line was not empty
96 -- already and either Always is True or Minimize_Empty_Lines is False.
98 procedure Write_Line
(S
: String);
99 -- Outputs S followed by a new line
101 procedure Write_String
(S
: String; Truncated
: Boolean := False);
102 -- Outputs S using Write_Str, starting a new line if line would
103 -- become too long, when Truncated = False.
104 -- When Truncated = True, only the part of the string that can fit on
105 -- the line is output.
107 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
);
109 Write_Char
: Write_Char_Ap
:= Output
.Write_Char
'Access;
110 Write_Eol
: Write_Eol_Ap
:= Output
.Write_Eol
'Access;
111 Write_Str
: Write_Str_Ap
:= Output
.Write_Str
'Access;
112 -- These three access to procedure values are used for the output.
114 Last_Line_Is_Empty
: Boolean := False;
115 -- Used to avoid two consecutive empty lines.
117 ---------------------------
118 -- Output_Attribute_Name --
119 ---------------------------
121 procedure Output_Attribute_Name
(Name
: Name_Id
) is
123 if Backward_Compatibility
then
125 when Snames
.Name_Spec
=>
126 Output_Name
(Snames
.Name_Specification
);
128 when Snames
.Name_Spec_Suffix
=>
129 Output_Name
(Snames
.Name_Specification_Suffix
);
131 when Snames
.Name_Body
=>
132 Output_Name
(Snames
.Name_Implementation
);
134 when Snames
.Name_Body_Suffix
=>
135 Output_Name
(Snames
.Name_Implementation_Suffix
);
144 end Output_Attribute_Name
;
150 procedure Output_Name
(Name
: Name_Id
; Capitalize
: Boolean := True) is
151 Capital
: Boolean := Capitalize
;
154 Get_Name_String
(Name
);
156 -- If line would become too long, create new line
158 if Column
+ Name_Len
> Max_Line_Length
then
163 for J
in 1 .. Name_Len
loop
165 Write_Char
(To_Upper
(Name_Buffer
(J
)));
167 Write_Char
(Name_Buffer
(J
));
172 Name_Buffer
(J
) = '_'
173 or else Is_Digit
(Name_Buffer
(J
));
177 Column
:= Column
+ Name_Len
;
184 procedure Output_String
(S
: Name_Id
) is
188 -- If line could become too long, create new line.
189 -- Note that the number of characters on the line could be
190 -- twice the number of character in the string (if every
191 -- character is a '"') plus two (the initial and final '"').
193 if Column
+ Name_Len
+ Name_Len
+ 2 > Max_Line_Length
then
199 Column
:= Column
+ 1;
202 for J
in 1 .. Name_Len
loop
203 if Name_Buffer
(J
) = '"' then
206 Column
:= Column
+ 2;
208 Write_Char
(Name_Buffer
(J
));
209 Column
:= Column
+ 1;
212 -- If the string does not fit on one line, cut it in parts
215 if J
< Name_Len
and then Column
>= Max_Line_Length
then
224 Column
:= Column
+ 1;
231 procedure Start_Line
(Indent
: Natural) is
233 if not Minimize_Empty_Lines
then
234 Write_Str
((1 .. Indent
=> ' '));
235 Column
:= Column
+ Indent
;
239 ----------------------
240 -- Write_Empty_Line --
241 ----------------------
243 procedure Write_Empty_Line
(Always
: Boolean := False) is
245 if (Always
or else not Minimize_Empty_Lines
)
246 and then not Last_Line_Is_Empty
then
249 Last_Line_Is_Empty
:= True;
251 end Write_Empty_Line
;
253 -------------------------------
254 -- Write_End_Of_Line_Comment --
255 -------------------------------
257 procedure Write_End_Of_Line_Comment
(Node
: Project_Node_Id
) is
258 Value
: constant Name_Id
:= End_Of_Line_Comment
(Node
, In_Tree
);
261 if Value
/= No_Name
then
262 Write_String
(" --");
263 Write_String
(Get_Name_String
(Value
), Truncated
=> True);
267 end Write_End_Of_Line_Comment
;
273 procedure Write_Line
(S
: String) is
276 Last_Line_Is_Empty
:= False;
285 procedure Write_String
(S
: String; Truncated
: Boolean := False) is
286 Length
: Natural := S
'Length;
288 -- If the string would not fit on the line,
291 if Column
+ Length
> Max_Line_Length
then
293 Length
:= Max_Line_Length
- Column
;
301 Write_Str
(S
(S
'First .. S
'First + Length
- 1));
302 Column
:= Column
+ Length
;
309 procedure Print
(Node
: Project_Node_Id
; Indent
: Natural) is
311 if Node
/= Empty_Node
then
313 case Kind_Of
(Node
, In_Tree
) is
316 pragma Debug
(Indicate_Tested
(N_Project
));
317 if First_With_Clause_Of
(Node
, In_Tree
) /= Empty_Node
then
321 Print
(First_With_Clause_Of
(Node
, In_Tree
), Indent
);
322 Write_Empty_Line
(Always
=> True);
325 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
327 Write_String
("project ");
328 Output_Name
(Name_Of
(Node
, In_Tree
));
330 -- Check if this project extends another project
332 if Extended_Project_Path_Of
(Node
, In_Tree
) /= No_Name
then
333 Write_String
(" extends ");
334 Output_String
(Extended_Project_Path_Of
(Node
, In_Tree
));
337 Write_String
(" is");
338 Write_End_Of_Line_Comment
(Node
);
340 (First_Comment_After
(Node
, In_Tree
), Indent
+ Increment
);
341 Write_Empty_Line
(Always
=> True);
343 -- Output all of the declarations in the project
345 Print
(Project_Declaration_Of
(Node
, In_Tree
), Indent
);
347 (First_Comment_Before_End
(Node
, In_Tree
),
350 Write_String
("end ");
351 Output_Name
(Name_Of
(Node
, In_Tree
));
353 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
355 when N_With_Clause
=>
356 pragma Debug
(Indicate_Tested
(N_With_Clause
));
358 if Name_Of
(Node
, In_Tree
) /= No_Name
then
359 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
362 if Non_Limited_Project_Node_Of
(Node
, In_Tree
) =
365 Write_String
("limited ");
368 Write_String
("with ");
369 Output_String
(String_Value_Of
(Node
, In_Tree
));
371 Write_End_Of_Line_Comment
(Node
);
372 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
375 Print
(Next_With_Clause_Of
(Node
, In_Tree
), Indent
);
377 when N_Project_Declaration
=>
378 pragma Debug
(Indicate_Tested
(N_Project_Declaration
));
381 First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
384 (First_Declarative_Item_Of
(Node
, In_Tree
),
386 Write_Empty_Line
(Always
=> True);
389 when N_Declarative_Item
=>
390 pragma Debug
(Indicate_Tested
(N_Declarative_Item
));
391 Print
(Current_Item_Node
(Node
, In_Tree
), Indent
);
392 Print
(Next_Declarative_Item
(Node
, In_Tree
), Indent
);
394 when N_Package_Declaration
=>
395 pragma Debug
(Indicate_Tested
(N_Package_Declaration
));
396 Write_Empty_Line
(Always
=> True);
397 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
399 Write_String
("package ");
400 Output_Name
(Name_Of
(Node
, In_Tree
));
402 if Project_Of_Renamed_Package_Of
(Node
, In_Tree
) /=
405 Write_String
(" renames ");
408 (Project_Of_Renamed_Package_Of
(Node
, In_Tree
),
411 Output_Name
(Name_Of
(Node
, In_Tree
));
413 Write_End_Of_Line_Comment
(Node
);
414 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
417 Write_String
(" is");
418 Write_End_Of_Line_Comment
(Node
);
419 Print
(First_Comment_After
(Node
, In_Tree
),
422 if First_Declarative_Item_Of
(Node
, In_Tree
) /=
426 (First_Declarative_Item_Of
(Node
, In_Tree
),
430 Print
(First_Comment_Before_End
(Node
, In_Tree
),
433 Write_String
("end ");
434 Output_Name
(Name_Of
(Node
, In_Tree
));
436 Print
(First_Comment_After_End
(Node
, In_Tree
), Indent
);
440 when N_String_Type_Declaration
=>
441 pragma Debug
(Indicate_Tested
(N_String_Type_Declaration
));
442 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
444 Write_String
("type ");
445 Output_Name
(Name_Of
(Node
, In_Tree
));
447 Start_Line
(Indent
+ Increment
);
451 String_Node
: Project_Node_Id
:=
452 First_Literal_String
(Node
, In_Tree
);
455 while String_Node
/= Empty_Node
loop
456 Output_String
(String_Value_Of
(String_Node
, In_Tree
));
458 Next_Literal_String
(String_Node
, In_Tree
);
460 if String_Node
/= Empty_Node
then
467 Write_End_Of_Line_Comment
(Node
);
468 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
470 when N_Literal_String
=>
471 pragma Debug
(Indicate_Tested
(N_Literal_String
));
472 Output_String
(String_Value_Of
(Node
, In_Tree
));
474 if Source_Index_Of
(Node
, In_Tree
) /= 0 then
475 Write_String
(" at ");
476 Write_String
(Source_Index_Of
(Node
, In_Tree
)'Img);
479 when N_Attribute_Declaration
=>
480 pragma Debug
(Indicate_Tested
(N_Attribute_Declaration
));
481 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
483 Write_String
("for ");
484 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
486 if Associative_Array_Index_Of
(Node
, In_Tree
) /= No_Name
then
489 (Associative_Array_Index_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);
499 Write_String
(" use ");
500 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
502 Write_End_Of_Line_Comment
(Node
);
503 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
505 when N_Typed_Variable_Declaration
=>
507 (Indicate_Tested
(N_Typed_Variable_Declaration
));
508 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
510 Output_Name
(Name_Of
(Node
, In_Tree
));
511 Write_String
(" : ");
513 (Name_Of
(String_Type_Of
(Node
, In_Tree
), In_Tree
));
514 Write_String
(" := ");
515 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
517 Write_End_Of_Line_Comment
(Node
);
518 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
520 when N_Variable_Declaration
=>
521 pragma Debug
(Indicate_Tested
(N_Variable_Declaration
));
522 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
524 Output_Name
(Name_Of
(Node
, In_Tree
));
525 Write_String
(" := ");
526 Print
(Expression_Of
(Node
, In_Tree
), Indent
);
528 Write_End_Of_Line_Comment
(Node
);
529 Print
(First_Comment_After
(Node
, In_Tree
), Indent
);
532 pragma Debug
(Indicate_Tested
(N_Expression
));
534 Term
: Project_Node_Id
:= First_Term
(Node
, In_Tree
);
537 while Term
/= Empty_Node
loop
538 Print
(Term
, Indent
);
539 Term
:= Next_Term
(Term
, In_Tree
);
541 if Term
/= Empty_Node
then
542 Write_String
(" & ");
548 pragma Debug
(Indicate_Tested
(N_Term
));
549 Print
(Current_Term
(Node
, In_Tree
), Indent
);
551 when N_Literal_String_List
=>
552 pragma Debug
(Indicate_Tested
(N_Literal_String_List
));
556 Expression
: Project_Node_Id
:=
557 First_Expression_In_List
(Node
, In_Tree
);
560 while Expression
/= Empty_Node
loop
561 Print
(Expression
, Indent
);
563 Next_Expression_In_List
(Expression
, In_Tree
);
565 if Expression
/= Empty_Node
then
573 when N_Variable_Reference
=>
574 pragma Debug
(Indicate_Tested
(N_Variable_Reference
));
575 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
577 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
581 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
583 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
587 Output_Name
(Name_Of
(Node
, In_Tree
));
589 when N_External_Value
=>
590 pragma Debug
(Indicate_Tested
(N_External_Value
));
591 Write_String
("external (");
592 Print
(External_Reference_Of
(Node
, In_Tree
), Indent
);
594 if External_Default_Of
(Node
, In_Tree
) /= Empty_Node
then
596 Print
(External_Default_Of
(Node
, In_Tree
), Indent
);
601 when N_Attribute_Reference
=>
602 pragma Debug
(Indicate_Tested
(N_Attribute_Reference
));
604 if Project_Node_Of
(Node
, In_Tree
) /= Empty_Node
605 and then Project_Node_Of
(Node
, In_Tree
) /= Project
608 (Name_Of
(Project_Node_Of
(Node
, In_Tree
), In_Tree
));
610 if Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
613 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
616 elsif Package_Node_Of
(Node
, In_Tree
) /= Empty_Node
then
618 (Name_Of
(Package_Node_Of
(Node
, In_Tree
), In_Tree
));
621 Write_String
("project");
625 Output_Attribute_Name
(Name_Of
(Node
, In_Tree
));
628 Index
: constant Name_Id
:=
629 Associative_Array_Index_Of
(Node
, In_Tree
);
632 if Index
/= No_Name
then
634 Output_String
(Index
);
639 when N_Case_Construction
=>
640 pragma Debug
(Indicate_Tested
(N_Case_Construction
));
643 Case_Item
: Project_Node_Id
;
644 Is_Non_Empty
: Boolean := False;
647 Case_Item
:= First_Case_Item_Of
(Node
, In_Tree
);
648 while Case_Item
/= Empty_Node
loop
649 if First_Declarative_Item_Of
(Case_Item
, In_Tree
) /=
651 or else not Eliminate_Empty_Case_Constructions
653 Is_Non_Empty
:= True;
657 Case_Item
:= Next_Case_Item
(Case_Item
, In_Tree
);
662 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
664 Write_String
("case ");
666 (Case_Variable_Reference_Of
(Node
, In_Tree
),
668 Write_String
(" is");
669 Write_End_Of_Line_Comment
(Node
);
671 (First_Comment_After
(Node
, In_Tree
),
675 Case_Item
: Project_Node_Id
:=
676 First_Case_Item_Of
(Node
, In_Tree
);
678 while Case_Item
/= Empty_Node
loop
680 (Kind_Of
(Case_Item
, In_Tree
) = N_Case_Item
);
681 Print
(Case_Item
, Indent
+ Increment
);
683 Next_Case_Item
(Case_Item
, In_Tree
);
687 Print
(First_Comment_Before_End
(Node
, In_Tree
),
690 Write_Line
("end case;");
692 (First_Comment_After_End
(Node
, In_Tree
), Indent
);
697 pragma Debug
(Indicate_Tested
(N_Case_Item
));
699 if First_Declarative_Item_Of
(Node
, In_Tree
) /= Empty_Node
700 or else not Eliminate_Empty_Case_Constructions
703 Print
(First_Comment_Before
(Node
, In_Tree
), Indent
);
705 Write_String
("when ");
707 if First_Choice_Of
(Node
, In_Tree
) = Empty_Node
then
708 Write_String
("others");
712 Label
: Project_Node_Id
:=
713 First_Choice_Of
(Node
, In_Tree
);
715 while Label
/= Empty_Node
loop
716 Print
(Label
, Indent
);
717 Label
:= Next_Literal_String
(Label
, In_Tree
);
719 if Label
/= Empty_Node
then
720 Write_String
(" | ");
726 Write_String
(" =>");
727 Write_End_Of_Line_Comment
(Node
);
729 (First_Comment_After
(Node
, In_Tree
),
733 First
: constant Project_Node_Id
:=
734 First_Declarative_Item_Of
(Node
, In_Tree
);
736 if First
= Empty_Node
then
739 Print
(First
, Indent
+ Increment
);
744 when N_Comment_Zones
=>
746 -- Nothing to do, because it will not be processed directly
751 pragma Debug
(Indicate_Tested
(N_Comment
));
753 if Follows_Empty_Line
(Node
, In_Tree
) then
760 (Get_Name_String
(String_Value_Of
(Node
, In_Tree
)),
764 if Is_Followed_By_Empty_Line
(Node
, In_Tree
) then
768 Print
(Next_Comment
(Node
, In_Tree
), Indent
);
773 -- Start of processing for Pretty_Print
776 if W_Char
= null then
777 Write_Char
:= Output
.Write_Char
'Access;
779 Write_Char
:= W_Char
;
783 Write_Eol
:= Output
.Write_Eol
'Access;
789 Write_Str
:= Output
.Write_Str
'Access;
796 if W_Char
= null or else W_Str
= null then
801 -----------------------
802 -- Output_Statistics --
803 -----------------------
805 procedure Output_Statistics
is
807 Output
.Write_Line
("Project_Node_Kinds not tested:");
809 for Kind
in Project_Node_Kind
loop
810 if Kind
/= N_Comment_Zones
and then Not_Tested
(Kind
) then
811 Output
.Write_Str
(" ");
812 Output
.Write_Line
(Project_Node_Kind
'Image (Kind
));
817 end Output_Statistics
;