1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2010, 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 procedure Indicate_Tested (Kind : Project_Node_Kind);
38 -- Set the corresponding component of array Not_Tested to False.
39 -- Only called by pragmas Debug.
45 procedure Indicate_Tested (Kind : Project_Node_Kind) is
47 Not_Tested (Kind) := False;
54 procedure Pretty_Print
55 (Project : Prj.Tree.Project_Node_Id;
56 In_Tree : Prj.Tree.Project_Node_Tree_Ref;
57 Increment : Positive := 3;
58 Eliminate_Empty_Case_Constructions : Boolean := False;
59 Minimize_Empty_Lines : Boolean := False;
60 W_Char : Write_Char_Ap := null;
61 W_Eol : Write_Eol_Ap := null;
62 W_Str : Write_Str_Ap := null;
63 Backward_Compatibility : Boolean;
64 Id : Prj.Project_Id := Prj.No_Project;
65 Max_Line_Length : Max_Length_Of_Line :=
66 Max_Length_Of_Line'Last)
68 procedure Print (Node : Project_Node_Id; Indent : Natural);
69 -- A recursive procedure that traverses a project file tree and outputs
70 -- its source. Current_Prj is the project that we are printing. This
71 -- is used when printing attributes, since in nested packages they
72 -- need to use a fully qualified name.
74 procedure Output_Attribute_Name (Name : Name_Id; Indent : Natural);
75 -- Outputs an attribute name, taking into account the value of
76 -- Backward_Compatibility.
81 Capitalize : Boolean := True);
84 procedure Start_Line (Indent : Natural);
85 -- Outputs the indentation at the beginning of the line
87 procedure Output_String (S : Name_Id; Indent : Natural);
88 procedure Output_String (S : Path_Name_Type; Indent : Natural);
89 -- Outputs a string using the default output procedures
91 procedure Write_Empty_Line (Always : Boolean := False);
92 -- Outputs an empty line, only if the previous line was not empty
93 -- already and either Always is True or Minimize_Empty_Lines is
96 procedure Write_Line (S : String);
97 -- Outputs S followed by a new line
99 procedure Write_String
102 Truncated : Boolean := False);
103 -- Outputs S using Write_Str, starting a new line if line would
104 -- become too long, when Truncated = False.
105 -- When Truncated = True, only the part of the string that can fit on
106 -- the line is output.
108 procedure Write_End_Of_Line_Comment (Node : Project_Node_Id);
110 Write_Char : Write_Char_Ap := Output.Write_Char'Access;
111 Write_Eol : Write_Eol_Ap := Output.Write_Eol'Access;
112 Write_Str : Write_Str_Ap := Output.Write_Str'Access;
113 -- These three access to procedure values are used for the output
115 Last_Line_Is_Empty : Boolean := False;
116 -- Used to avoid two consecutive empty lines
118 Column : Natural := 0;
119 -- Column number of the last character in the line. Used to avoid
120 -- outputting lines longer than Max_Line_Length.
122 First_With_In_List : Boolean := True;
123 -- Indicate that the next with clause is first in a list such as
125 -- First_With_In_List will be True for "A", but not for "B".
127 ---------------------------
128 -- Output_Attribute_Name --
129 ---------------------------
131 procedure Output_Attribute_Name (Name : Name_Id; Indent : Natural) is
133 if Backward_Compatibility then
135 when Snames.Name_Spec =>
136 Output_Name (Snames.Name_Specification, Indent);
138 when Snames.Name_Spec_Suffix =>
139 Output_Name (Snames.Name_Specification_Suffix, Indent);
141 when Snames.Name_Body =>
142 Output_Name (Snames.Name_Implementation, Indent);
144 when Snames.Name_Body_Suffix =>
145 Output_Name (Snames.Name_Implementation_Suffix, Indent);
148 Output_Name (Name, Indent);
152 Output_Name (Name, Indent);
154 end Output_Attribute_Name;
160 procedure Output_Name
163 Capitalize : Boolean := True)
165 Capital : Boolean := Capitalize;
168 if Column = 0 and then Indent /= 0 then
169 Start_Line (Indent + Increment);
172 Get_Name_String (Name);
174 -- If line would become too long, create new line
176 if Column + Name_Len > Max_Line_Length then
181 Start_Line (Indent + Increment);
185 for J in 1 .. Name_Len loop
187 Write_Char (To_Upper (Name_Buffer (J)));
189 Write_Char (Name_Buffer (J));
194 Name_Buffer (J) = '_'
195 or else Is_Digit (Name_Buffer (J));
199 Column := Column + Name_Len;
206 procedure Output_String (S : Name_Id; Indent : Natural) is
208 if Column = 0 and then Indent /= 0 then
209 Start_Line (Indent + Increment);
214 -- If line could become too long, create new line. Note that the
215 -- number of characters on the line could be twice the number of
216 -- character in the string (if every character is a '"') plus two
217 -- (the initial and final '"').
219 if Column + Name_Len + Name_Len + 2 > Max_Line_Length then
224 Start_Line (Indent + Increment);
229 Column := Column + 1;
232 for J in 1 .. Name_Len loop
233 if Name_Buffer (J) = '"' then
236 Column := Column + 2;
238 Write_Char (Name_Buffer (J));
239 Column := Column + 1;
242 -- If the string does not fit on one line, cut it in parts and
245 if J < Name_Len and then Column >= Max_Line_Length then
249 Start_Line (Indent + Increment);
251 Column := Column + 1;
256 Column := Column + 1;
259 procedure Output_String (S : Path_Name_Type; Indent : Natural) is
261 Output_String (Name_Id (S), Indent);
268 procedure Start_Line (Indent : Natural) is
270 if not Minimize_Empty_Lines then
271 Write_Str ((1 .. Indent => ' '));
272 Column := Column + Indent;
276 ----------------------
277 -- Write_Empty_Line --
278 ----------------------
280 procedure Write_Empty_Line (Always : Boolean := False) is
282 if (Always or else not Minimize_Empty_Lines)
283 and then not Last_Line_Is_Empty then
286 Last_Line_Is_Empty := True;
288 end Write_Empty_Line;
290 -------------------------------
291 -- Write_End_Of_Line_Comment --
292 -------------------------------
294 procedure Write_End_Of_Line_Comment (Node : Project_Node_Id) is
295 Value : constant Name_Id := End_Of_Line_Comment (Node, In_Tree);
298 if Value /= No_Name then
299 Write_String (" --", 0);
300 Write_String (Get_Name_String (Value), 0, Truncated => True);
304 end Write_End_Of_Line_Comment;
310 procedure Write_Line (S : String) is
313 Last_Line_Is_Empty := False;
322 procedure Write_String
325 Truncated : Boolean := False) is
326 Length : Natural := S'Length;
328 if Column = 0 and then Indent /= 0 then
329 Start_Line (Indent + Increment);
332 -- If the string would not fit on the line,
335 if Column + Length > Max_Line_Length then
337 Length := Max_Line_Length - Column;
344 Start_Line (Indent + Increment);
349 Write_Str (S (S'First .. S'First + Length - 1));
350 Column := Column + Length;
357 procedure Print (Node : Project_Node_Id; Indent : Natural) is
359 if Present (Node) then
361 case Kind_Of (Node, In_Tree) is
364 pragma Debug (Indicate_Tested (N_Project));
365 if Present (First_With_Clause_Of (Node, In_Tree)) then
369 First_With_In_List := True;
370 Print (First_With_Clause_Of (Node, In_Tree), Indent);
371 Write_Empty_Line (Always => True);
374 Print (First_Comment_Before (Node, In_Tree), Indent);
376 Write_String ("project ", Indent);
378 if Id /= Prj.No_Project then
379 Output_Name (Id.Display_Name, Indent);
381 Output_Name (Name_Of (Node, In_Tree), Indent);
384 -- Check if this project extends another project
386 if Extended_Project_Path_Of (Node, In_Tree) /= No_Path then
387 Write_String (" extends ", Indent);
389 if Is_Extending_All (Node, In_Tree) then
390 Write_String ("all ", Indent);
394 (Extended_Project_Path_Of (Node, In_Tree),
398 Write_String (" is", Indent);
399 Write_End_Of_Line_Comment (Node);
401 (First_Comment_After (Node, In_Tree), Indent + Increment);
402 Write_Empty_Line (Always => True);
404 -- Output all of the declarations in the project
406 Print (Project_Declaration_Of (Node, In_Tree), Indent);
408 (First_Comment_Before_End (Node, In_Tree),
411 Write_String ("end ", Indent);
413 if Id /= Prj.No_Project then
414 Output_Name (Id.Display_Name, Indent);
416 Output_Name (Name_Of (Node, In_Tree), Indent);
420 Print (First_Comment_After_End (Node, In_Tree), Indent);
422 when N_With_Clause =>
423 pragma Debug (Indicate_Tested (N_With_Clause));
425 -- The with clause will sometimes contain an invalid name
426 -- when we are importing a virtual project from an
427 -- extending all project. Do not output anything in this
430 if Name_Of (Node, In_Tree) /= No_Name
431 and then String_Value_Of (Node, In_Tree) /= No_Name
433 if First_With_In_List then
434 Print (First_Comment_Before (Node, In_Tree), Indent);
437 if Non_Limited_Project_Node_Of (Node, In_Tree) =
440 Write_String ("limited ", Indent);
443 Write_String ("with ", Indent);
446 Output_String (String_Value_Of (Node, In_Tree), Indent);
448 if Is_Not_Last_In_List (Node, In_Tree) then
449 Write_String (", ", Indent);
450 First_With_In_List := False;
453 Write_String (";", Indent);
454 Write_End_Of_Line_Comment (Node);
455 Print (First_Comment_After (Node, In_Tree), Indent);
456 First_With_In_List := True;
460 Print (Next_With_Clause_Of (Node, In_Tree), Indent);
462 when N_Project_Declaration =>
463 pragma Debug (Indicate_Tested (N_Project_Declaration));
466 Present (First_Declarative_Item_Of (Node, In_Tree))
469 (First_Declarative_Item_Of (Node, In_Tree),
471 Write_Empty_Line (Always => True);
474 when N_Declarative_Item =>
475 pragma Debug (Indicate_Tested (N_Declarative_Item));
476 Print (Current_Item_Node (Node, In_Tree), Indent);
477 Print (Next_Declarative_Item (Node, In_Tree), Indent);
479 when N_Package_Declaration =>
480 pragma Debug (Indicate_Tested (N_Package_Declaration));
481 Write_Empty_Line (Always => True);
482 Print (First_Comment_Before (Node, In_Tree), Indent);
484 Write_String ("package ", Indent);
485 Output_Name (Name_Of (Node, In_Tree), Indent);
487 if Project_Of_Renamed_Package_Of (Node, In_Tree) /=
490 Write_String (" renames ", Indent);
493 (Project_Of_Renamed_Package_Of (Node, In_Tree),
496 Write_String (".", Indent);
497 Output_Name (Name_Of (Node, In_Tree), Indent);
498 Write_String (";", Indent);
499 Write_End_Of_Line_Comment (Node);
500 Print (First_Comment_After_End (Node, In_Tree), Indent);
503 Write_String (" is", Indent);
504 Write_End_Of_Line_Comment (Node);
505 Print (First_Comment_After (Node, In_Tree),
508 if First_Declarative_Item_Of (Node, In_Tree) /=
512 (First_Declarative_Item_Of (Node, In_Tree),
516 Print (First_Comment_Before_End (Node, In_Tree),
519 Write_String ("end ", Indent);
520 Output_Name (Name_Of (Node, In_Tree), Indent);
522 Print (First_Comment_After_End (Node, In_Tree), Indent);
526 when N_String_Type_Declaration =>
527 pragma Debug (Indicate_Tested (N_String_Type_Declaration));
528 Print (First_Comment_Before (Node, In_Tree), Indent);
530 Write_String ("type ", Indent);
531 Output_Name (Name_Of (Node, In_Tree), Indent);
533 Start_Line (Indent + Increment);
534 Write_String ("(", Indent);
537 String_Node : Project_Node_Id :=
538 First_Literal_String (Node, In_Tree);
541 while Present (String_Node) loop
543 (String_Value_Of (String_Node, In_Tree),
546 Next_Literal_String (String_Node, In_Tree);
548 if Present (String_Node) then
549 Write_String (", ", Indent);
554 Write_String (");", Indent);
555 Write_End_Of_Line_Comment (Node);
556 Print (First_Comment_After (Node, In_Tree), Indent);
558 when N_Literal_String =>
559 pragma Debug (Indicate_Tested (N_Literal_String));
560 Output_String (String_Value_Of (Node, In_Tree), Indent);
562 if Source_Index_Of (Node, In_Tree) /= 0 then
563 Write_String (" at", Indent);
565 (Source_Index_Of (Node, In_Tree)'Img,
569 when N_Attribute_Declaration =>
570 pragma Debug (Indicate_Tested (N_Attribute_Declaration));
571 Print (First_Comment_Before (Node, In_Tree), Indent);
573 Write_String ("for ", Indent);
574 Output_Attribute_Name (Name_Of (Node, In_Tree), Indent);
576 if Associative_Array_Index_Of (Node, In_Tree) /= No_Name then
577 Write_String (" (", Indent);
579 (Associative_Array_Index_Of (Node, In_Tree),
582 if Source_Index_Of (Node, In_Tree) /= 0 then
583 Write_String (" at", Indent);
585 (Source_Index_Of (Node, In_Tree)'Img,
589 Write_String (")", Indent);
592 Write_String (" use ", Indent);
594 if Present (Expression_Of (Node, In_Tree)) then
595 Print (Expression_Of (Node, In_Tree), Indent);
598 -- Full associative array declaration
601 Present (Associative_Project_Of (Node, In_Tree))
605 (Associative_Project_Of (Node, In_Tree),
610 Present (Associative_Package_Of (Node, In_Tree))
612 Write_String (".", Indent);
615 (Associative_Package_Of (Node, In_Tree),
621 Present (Associative_Package_Of (Node, In_Tree))
625 (Associative_Package_Of (Node, In_Tree),
630 Write_String ("'", Indent);
631 Output_Attribute_Name (Name_Of (Node, In_Tree), Indent);
634 Write_String (";", Indent);
635 Write_End_Of_Line_Comment (Node);
636 Print (First_Comment_After (Node, In_Tree), Indent);
638 when N_Typed_Variable_Declaration =>
640 (Indicate_Tested (N_Typed_Variable_Declaration));
641 Print (First_Comment_Before (Node, In_Tree), Indent);
643 Output_Name (Name_Of (Node, In_Tree), Indent);
644 Write_String (" : ", Indent);
646 (Name_Of (String_Type_Of (Node, In_Tree), In_Tree),
648 Write_String (" := ", Indent);
649 Print (Expression_Of (Node, In_Tree), Indent);
650 Write_String (";", Indent);
651 Write_End_Of_Line_Comment (Node);
652 Print (First_Comment_After (Node, In_Tree), Indent);
654 when N_Variable_Declaration =>
655 pragma Debug (Indicate_Tested (N_Variable_Declaration));
656 Print (First_Comment_Before (Node, In_Tree), Indent);
658 Output_Name (Name_Of (Node, In_Tree), Indent);
659 Write_String (" := ", Indent);
660 Print (Expression_Of (Node, In_Tree), Indent);
661 Write_String (";", Indent);
662 Write_End_Of_Line_Comment (Node);
663 Print (First_Comment_After (Node, In_Tree), Indent);
666 pragma Debug (Indicate_Tested (N_Expression));
668 Term : Project_Node_Id := First_Term (Node, In_Tree);
671 while Present (Term) loop
672 Print (Term, Indent);
673 Term := Next_Term (Term, In_Tree);
675 if Present (Term) then
676 Write_String (" & ", Indent);
682 pragma Debug (Indicate_Tested (N_Term));
683 Print (Current_Term (Node, In_Tree), Indent);
685 when N_Literal_String_List =>
686 pragma Debug (Indicate_Tested (N_Literal_String_List));
687 Write_String ("(", Indent);
690 Expression : Project_Node_Id :=
691 First_Expression_In_List (Node, In_Tree);
694 while Present (Expression) loop
695 Print (Expression, Indent);
697 Next_Expression_In_List (Expression, In_Tree);
699 if Present (Expression) then
700 Write_String (", ", Indent);
705 Write_String (")", Indent);
707 when N_Variable_Reference =>
708 pragma Debug (Indicate_Tested (N_Variable_Reference));
709 if Present (Project_Node_Of (Node, In_Tree)) then
711 (Name_Of (Project_Node_Of (Node, In_Tree), In_Tree),
713 Write_String (".", Indent);
716 if Present (Package_Node_Of (Node, In_Tree)) then
718 (Name_Of (Package_Node_Of (Node, In_Tree), In_Tree),
720 Write_String (".", Indent);
723 Output_Name (Name_Of (Node, In_Tree), Indent);
725 when N_External_Value =>
726 pragma Debug (Indicate_Tested (N_External_Value));
727 Write_String ("external (", Indent);
728 Print (External_Reference_Of (Node, In_Tree), Indent);
730 if Present (External_Default_Of (Node, In_Tree)) then
731 Write_String (", ", Indent);
732 Print (External_Default_Of (Node, In_Tree), Indent);
735 Write_String (")", Indent);
737 when N_Attribute_Reference =>
738 pragma Debug (Indicate_Tested (N_Attribute_Reference));
740 if Present (Project_Node_Of (Node, In_Tree))
741 and then Project_Node_Of (Node, In_Tree) /= Project
744 (Name_Of (Project_Node_Of (Node, In_Tree), In_Tree),
747 if Present (Package_Node_Of (Node, In_Tree)) then
748 Write_String (".", Indent);
750 (Name_Of (Package_Node_Of (Node, In_Tree), In_Tree),
754 elsif Present (Package_Node_Of (Node, In_Tree)) then
756 (Name_Of (Package_Node_Of (Node, In_Tree), In_Tree),
760 Write_String ("project", Indent);
763 Write_String ("'", Indent);
764 Output_Attribute_Name (Name_Of (Node, In_Tree), Indent);
767 Index : constant Name_Id :=
768 Associative_Array_Index_Of (Node, In_Tree);
771 if Index /= No_Name then
772 Write_String (" (", Indent);
773 Output_String (Index, Indent);
774 Write_String (")", Indent);
778 when N_Case_Construction =>
779 pragma Debug (Indicate_Tested (N_Case_Construction));
782 Case_Item : Project_Node_Id;
783 Is_Non_Empty : Boolean := False;
786 Case_Item := First_Case_Item_Of (Node, In_Tree);
787 while Present (Case_Item) loop
789 (First_Declarative_Item_Of (Case_Item, In_Tree))
790 or else not Eliminate_Empty_Case_Constructions
792 Is_Non_Empty := True;
796 Case_Item := Next_Case_Item (Case_Item, In_Tree);
801 Print (First_Comment_Before (Node, In_Tree), Indent);
803 Write_String ("case ", Indent);
805 (Case_Variable_Reference_Of (Node, In_Tree),
807 Write_String (" is", Indent);
808 Write_End_Of_Line_Comment (Node);
810 (First_Comment_After (Node, In_Tree),
814 Case_Item : Project_Node_Id :=
815 First_Case_Item_Of (Node, In_Tree);
817 while Present (Case_Item) loop
819 (Kind_Of (Case_Item, In_Tree) = N_Case_Item);
820 Print (Case_Item, Indent + Increment);
822 Next_Case_Item (Case_Item, In_Tree);
826 Print (First_Comment_Before_End (Node, In_Tree),
829 Write_Line ("end case;");
831 (First_Comment_After_End (Node, In_Tree), Indent);
836 pragma Debug (Indicate_Tested (N_Case_Item));
838 if Present (First_Declarative_Item_Of (Node, In_Tree))
839 or else not Eliminate_Empty_Case_Constructions
842 Print (First_Comment_Before (Node, In_Tree), Indent);
844 Write_String ("when ", Indent);
846 if No (First_Choice_Of (Node, In_Tree)) then
847 Write_String ("others", Indent);
851 Label : Project_Node_Id :=
852 First_Choice_Of (Node, In_Tree);
854 while Present (Label) loop
855 Print (Label, Indent);
856 Label := Next_Literal_String (Label, In_Tree);
858 if Present (Label) then
859 Write_String (" | ", Indent);
865 Write_String (" =>", Indent);
866 Write_End_Of_Line_Comment (Node);
868 (First_Comment_After (Node, In_Tree),
872 First : constant Project_Node_Id :=
873 First_Declarative_Item_Of (Node, In_Tree);
878 Print (First, Indent + Increment);
883 when N_Comment_Zones =>
885 -- Nothing to do, because it will not be processed directly
890 pragma Debug (Indicate_Tested (N_Comment));
892 if Follows_Empty_Line (Node, In_Tree) then
897 Write_String ("--", Indent);
899 (Get_Name_String (String_Value_Of (Node, In_Tree)),
904 if Is_Followed_By_Empty_Line (Node, In_Tree) then
908 Print (Next_Comment (Node, In_Tree), Indent);
913 -- Start of processing for Pretty_Print
916 if W_Char = null then
917 Write_Char := Output.Write_Char'Access;
919 Write_Char := W_Char;
923 Write_Eol := Output.Write_Eol'Access;
929 Write_Str := Output.Write_Str'Access;
936 if W_Char = null or else W_Str = null then
941 -----------------------
942 -- Output_Statistics --
943 -----------------------
945 procedure Output_Statistics is
947 Output.Write_Line ("Project_Node_Kinds not tested:");
949 for Kind in Project_Node_Kind loop
950 if Kind /= N_Comment_Zones and then Not_Tested (Kind) then
951 Output.Write_Str (" ");
952 Output.Write_Line (Project_Node_Kind'Image (Kind));
957 end Output_Statistics;