2018-08-29 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / ada / pprint.adb
blob230a3d37c40378dc2bc63909ff00b09f68c2dd68
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P P R I N T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2008-2018, Free Software Foundation, Inc. --
10 -- --
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. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Atree; use Atree;
27 with Csets; use Csets;
28 with Einfo; use Einfo;
29 with Namet; use Namet;
30 with Nlists; use Nlists;
31 with Opt; use Opt;
32 with Sinfo; use Sinfo;
33 with Sinput; use Sinput;
34 with Snames; use Snames;
35 with Uintp; use Uintp;
37 package body Pprint is
39 List_Name_Count : Integer := 0;
40 -- Counter used to prevent infinite recursion while computing name of
41 -- complex expressions.
43 ----------------------
44 -- Expression_Image --
45 ----------------------
47 function Expression_Image
48 (Expr : Node_Id;
49 Default : String) return String
51 From_Source : constant Boolean :=
52 Comes_From_Source (Expr)
53 and then not Opt.Debug_Generated_Code;
54 Append_Paren : Natural := 0;
55 Left : Node_Id := Original_Node (Expr);
56 Right : Node_Id := Original_Node (Expr);
58 function Expr_Name
59 (Expr : Node_Id;
60 Take_Prefix : Boolean := True;
61 Expand_Type : Boolean := True) return String;
62 -- Return string corresponding to Expr. If no string can be extracted,
63 -- return "...". If Take_Prefix is True, go back to prefix when needed,
64 -- otherwise only consider the right-hand side of an expression. If
65 -- Expand_Type is True and Expr is a type, try to expand Expr (an
66 -- internally generated type) into a user understandable name.
68 Max_List : constant := 3;
69 -- Limit number of list elements to dump
71 Max_Expr_Elements : constant := 24;
72 -- Limit number of elements in an expression for use by Expr_Name
74 Num_Elements : Natural := 0;
75 -- Current number of elements processed by Expr_Name
77 function List_Name
78 (List : Node_Id;
79 Add_Space : Boolean := True;
80 Add_Paren : Boolean := True) return String;
81 -- Return a string corresponding to List
83 ---------------
84 -- List_Name --
85 ---------------
87 function List_Name
88 (List : Node_Id;
89 Add_Space : Boolean := True;
90 Add_Paren : Boolean := True) return String
92 function Internal_List_Name
93 (List : Node_Id;
94 First : Boolean := True;
95 Add_Space : Boolean := True;
96 Add_Paren : Boolean := True;
97 Num : Natural := 1) return String;
98 -- ??? what does this do
100 ------------------------
101 -- Internal_List_Name --
102 ------------------------
104 function Internal_List_Name
105 (List : Node_Id;
106 First : Boolean := True;
107 Add_Space : Boolean := True;
108 Add_Paren : Boolean := True;
109 Num : Natural := 1) return String
111 function Prepend (S : String) return String;
112 -- ??? what does this do
114 -------------
115 -- Prepend --
116 -------------
118 function Prepend (S : String) return String is
119 begin
120 if Add_Space then
121 if Add_Paren then
122 return " (" & S;
123 else
124 return ' ' & S;
125 end if;
126 elsif Add_Paren then
127 return '(' & S;
128 else
129 return S;
130 end if;
131 end Prepend;
133 -- Start of processing for Internal_List_Name
135 begin
136 if not Present (List) then
137 if First or else not Add_Paren then
138 return "";
139 else
140 return ")";
141 end if;
142 elsif Num > Max_List then
143 if Add_Paren then
144 return ", ...)";
145 else
146 return ", ...";
147 end if;
148 end if;
150 -- ??? the Internal_List_Name calls can be factored out
152 if First then
153 return Prepend (Expr_Name (List)
154 & Internal_List_Name
155 (List => Next (List),
156 First => False,
157 Add_Paren => Add_Paren,
158 Num => Num + 1));
159 else
160 return ", " & Expr_Name (List)
161 & Internal_List_Name
162 (List => Next (List),
163 First => False,
164 Add_Paren => Add_Paren,
165 Num => Num + 1);
166 end if;
167 end Internal_List_Name;
169 -- Start of processing for List_Name
171 begin
172 -- Prevent infinite recursion by limiting depth to 3
174 if List_Name_Count > 3 then
175 return "...";
176 end if;
178 List_Name_Count := List_Name_Count + 1;
180 declare
181 Result : constant String :=
182 Internal_List_Name
183 (List => List,
184 Add_Space => Add_Space,
185 Add_Paren => Add_Paren);
186 begin
187 List_Name_Count := List_Name_Count - 1;
188 return Result;
189 end;
190 end List_Name;
192 ---------------
193 -- Expr_Name --
194 ---------------
196 function Expr_Name
197 (Expr : Node_Id;
198 Take_Prefix : Boolean := True;
199 Expand_Type : Boolean := True) return String
201 begin
202 Num_Elements := Num_Elements + 1;
204 if Num_Elements > Max_Expr_Elements then
205 return "...";
206 end if;
208 case Nkind (Expr) is
209 when N_Defining_Identifier
210 | N_Identifier
212 return Ident_Image (Expr, Expression_Image.Expr, Expand_Type);
214 when N_Character_Literal =>
215 declare
216 Char : constant Int := UI_To_Int (Char_Literal_Value (Expr));
217 begin
218 if Char in 32 .. 127 then
219 return "'" & Character'Val (Char) & "'";
220 else
221 UI_Image (Char_Literal_Value (Expr));
222 return
223 "'\" & UI_Image_Buffer (1 .. UI_Image_Length) & "'";
224 end if;
225 end;
227 when N_Integer_Literal =>
228 UI_Image (Intval (Expr));
229 return UI_Image_Buffer (1 .. UI_Image_Length);
231 when N_Real_Literal =>
232 return Real_Image (Realval (Expr));
234 when N_String_Literal =>
235 return String_Image (Strval (Expr));
237 when N_Allocator =>
238 return "new " & Expr_Name (Expression (Expr));
240 when N_Aggregate =>
241 if Present (Sinfo.Expressions (Expr)) then
242 return
243 List_Name
244 (List => First (Sinfo.Expressions (Expr)),
245 Add_Space => False);
247 -- Do not return empty string for (others => <>) aggregate
248 -- of a componentless record type. At least one caller (the
249 -- recursive call below in the N_Qualified_Expression case)
250 -- is not prepared to deal with a zero-length result.
252 elsif Null_Record_Present (Expr)
253 or else not Present (First (Component_Associations (Expr)))
254 then
255 return ("(null record)");
257 else
258 return
259 List_Name
260 (List => First (Component_Associations (Expr)),
261 Add_Space => False,
262 Add_Paren => False);
263 end if;
265 when N_Extension_Aggregate =>
266 return "(" & Expr_Name (Ancestor_Part (Expr)) & " with "
267 & List_Name
268 (List => First (Sinfo.Expressions (Expr)),
269 Add_Space => False,
270 Add_Paren => False) & ")";
272 when N_Attribute_Reference =>
273 if Take_Prefix then
274 declare
275 function To_Mixed_Case (S : String) return String;
276 -- Transform given string into the corresponding one in
277 -- mixed case form.
279 -------------------
280 -- To_Mixed_Case --
281 -------------------
283 function To_Mixed_Case (S : String) return String is
284 Result : String (S'Range);
285 Ucase : Boolean := True;
287 begin
288 for J in S'Range loop
289 if Ucase then
290 Result (J) := Fold_Upper (S (J));
291 else
292 Result (J) := Fold_Lower (S (J));
293 end if;
295 Ucase := (S (J) = '_');
296 end loop;
298 return Result;
299 end To_Mixed_Case;
301 Id : constant Attribute_Id :=
302 Get_Attribute_Id (Attribute_Name (Expr));
304 -- Always use mixed case for attributes
306 Str : constant String :=
307 Expr_Name (Prefix (Expr))
308 & "'"
309 & To_Mixed_Case
310 (Get_Name_String (Attribute_Name (Expr)));
312 N : Node_Id;
313 Ranges : List_Id;
315 begin
316 if (Id = Attribute_First or else Id = Attribute_Last)
317 and then Str (Str'First) = '$'
318 then
319 N := Associated_Node_For_Itype (Etype (Prefix (Expr)));
321 if Present (N) then
322 if Nkind (N) = N_Full_Type_Declaration then
323 N := Type_Definition (N);
324 end if;
326 if Nkind (N) = N_Subtype_Declaration then
327 Ranges :=
328 Constraints
329 (Constraint (Subtype_Indication (N)));
331 if List_Length (Ranges) = 1
332 and then
333 Nkind_In
334 (First (Ranges),
335 N_Range,
336 N_Real_Range_Specification,
337 N_Signed_Integer_Type_Definition)
338 then
339 if Id = Attribute_First then
340 return
341 Expression_Image
342 (Low_Bound (First (Ranges)), Str);
343 else
344 return
345 Expression_Image
346 (High_Bound (First (Ranges)), Str);
347 end if;
348 end if;
349 end if;
350 end if;
351 end if;
353 return Str;
354 end;
355 else
356 return "'" & Get_Name_String (Attribute_Name (Expr));
357 end if;
359 when N_Explicit_Dereference =>
360 Explicit_Dereference : declare
361 function Deref_Suffix return String;
362 -- Usually returns ".all", but will return "" if
363 -- Hide_Temp_Derefs is true and the prefix is a use of a
364 -- not-from-source object declared as
365 -- X : constant Some_Access_Type := Some_Expr'Reference;
366 -- (as is sometimes done in Exp_Util.Remove_Side_Effects).
368 ------------------
369 -- Deref_Suffix --
370 ------------------
372 function Deref_Suffix return String is
373 Decl : Node_Id;
375 begin
376 if Hide_Temp_Derefs
377 and then Nkind (Prefix (Expr)) = N_Identifier
378 and then Nkind (Entity (Prefix (Expr))) =
379 N_Defining_Identifier
380 then
381 Decl := Parent (Entity (Prefix (Expr)));
383 if Present (Decl)
384 and then Nkind (Decl) = N_Object_Declaration
385 and then not Comes_From_Source (Decl)
386 and then Constant_Present (Decl)
387 and then Present (Sinfo.Expression (Decl))
388 and then Nkind (Sinfo.Expression (Decl)) =
389 N_Reference
390 then
391 return "";
392 end if;
393 end if;
395 -- The default case
397 return ".all";
398 end Deref_Suffix;
400 -- Start of processing for Explicit_Dereference
402 begin
403 if Hide_Parameter_Blocks
404 and then Nkind (Prefix (Expr)) = N_Selected_Component
405 and then Present (Etype (Prefix (Expr)))
406 and then Is_Access_Type (Etype (Prefix (Expr)))
407 and then Is_Param_Block_Component_Type
408 (Etype (Prefix (Expr)))
409 then
410 -- Return "Foo" instead of "Parameter_Block.Foo.all"
412 return Expr_Name (Selector_Name (Prefix (Expr)));
414 elsif Take_Prefix then
415 return Expr_Name (Prefix (Expr)) & Deref_Suffix;
416 else
417 return Deref_Suffix;
418 end if;
419 end Explicit_Dereference;
421 when N_Expanded_Name
422 | N_Selected_Component
424 if Take_Prefix then
425 return
426 Expr_Name (Prefix (Expr)) & "." &
427 Expr_Name (Selector_Name (Expr));
428 else
429 return "." & Expr_Name (Selector_Name (Expr));
430 end if;
432 when N_Component_Association =>
433 return "("
434 & List_Name
435 (List => First (Choices (Expr)),
436 Add_Space => False,
437 Add_Paren => False)
438 & " => " & Expr_Name (Expression (Expr)) & ")";
440 when N_If_Expression =>
441 declare
442 N : constant Node_Id := First (Sinfo.Expressions (Expr));
443 begin
444 return
445 "if " & Expr_Name (N) & " then "
446 & Expr_Name (Next (N)) & " else "
447 & Expr_Name (Next (Next (N)));
448 end;
450 when N_Qualified_Expression =>
451 declare
452 Mark : constant String :=
453 Expr_Name
454 (Subtype_Mark (Expr), Expand_Type => False);
455 Str : constant String := Expr_Name (Expression (Expr));
456 begin
457 if Str (Str'First) = '(' and then Str (Str'Last) = ')' then
458 return Mark & "'" & Str;
459 else
460 return Mark & "'(" & Str & ")";
461 end if;
462 end;
464 when N_Expression_With_Actions
465 | N_Unchecked_Expression
467 return Expr_Name (Expression (Expr));
469 when N_Raise_Constraint_Error =>
470 if Present (Condition (Expr)) then
471 return
472 "[constraint_error when "
473 & Expr_Name (Condition (Expr)) & "]";
474 else
475 return "[constraint_error]";
476 end if;
478 when N_Raise_Program_Error =>
479 if Present (Condition (Expr)) then
480 return
481 "[program_error when "
482 & Expr_Name (Condition (Expr)) & "]";
483 else
484 return "[program_error]";
485 end if;
487 when N_Range =>
488 return
489 Expr_Name (Low_Bound (Expr)) & ".." &
490 Expr_Name (High_Bound (Expr));
492 when N_Slice =>
493 return
494 Expr_Name (Prefix (Expr)) & " (" &
495 Expr_Name (Discrete_Range (Expr)) & ")";
497 when N_And_Then =>
498 return
499 Expr_Name (Left_Opnd (Expr)) & " and then " &
500 Expr_Name (Right_Opnd (Expr));
502 when N_In =>
503 return
504 Expr_Name (Left_Opnd (Expr)) & " in " &
505 Expr_Name (Right_Opnd (Expr));
507 when N_Not_In =>
508 return
509 Expr_Name (Left_Opnd (Expr)) & " not in " &
510 Expr_Name (Right_Opnd (Expr));
512 when N_Or_Else =>
513 return
514 Expr_Name (Left_Opnd (Expr)) & " or else " &
515 Expr_Name (Right_Opnd (Expr));
517 when N_Op_And =>
518 return
519 Expr_Name (Left_Opnd (Expr)) & " and " &
520 Expr_Name (Right_Opnd (Expr));
522 when N_Op_Or =>
523 return
524 Expr_Name (Left_Opnd (Expr)) & " or " &
525 Expr_Name (Right_Opnd (Expr));
527 when N_Op_Xor =>
528 return
529 Expr_Name (Left_Opnd (Expr)) & " xor " &
530 Expr_Name (Right_Opnd (Expr));
532 when N_Op_Eq =>
533 return
534 Expr_Name (Left_Opnd (Expr)) & " = " &
535 Expr_Name (Right_Opnd (Expr));
537 when N_Op_Ne =>
538 return
539 Expr_Name (Left_Opnd (Expr)) & " /= " &
540 Expr_Name (Right_Opnd (Expr));
542 when N_Op_Lt =>
543 return
544 Expr_Name (Left_Opnd (Expr)) & " < " &
545 Expr_Name (Right_Opnd (Expr));
547 when N_Op_Le =>
548 return
549 Expr_Name (Left_Opnd (Expr)) & " <= " &
550 Expr_Name (Right_Opnd (Expr));
552 when N_Op_Gt =>
553 return
554 Expr_Name (Left_Opnd (Expr)) & " > " &
555 Expr_Name (Right_Opnd (Expr));
557 when N_Op_Ge =>
558 return
559 Expr_Name (Left_Opnd (Expr)) & " >= " &
560 Expr_Name (Right_Opnd (Expr));
562 when N_Op_Add =>
563 return
564 Expr_Name (Left_Opnd (Expr)) & " + " &
565 Expr_Name (Right_Opnd (Expr));
567 when N_Op_Subtract =>
568 return
569 Expr_Name (Left_Opnd (Expr)) & " - " &
570 Expr_Name (Right_Opnd (Expr));
572 when N_Op_Multiply =>
573 return
574 Expr_Name (Left_Opnd (Expr)) & " * " &
575 Expr_Name (Right_Opnd (Expr));
577 when N_Op_Divide =>
578 return
579 Expr_Name (Left_Opnd (Expr)) & " / " &
580 Expr_Name (Right_Opnd (Expr));
582 when N_Op_Mod =>
583 return
584 Expr_Name (Left_Opnd (Expr)) & " mod " &
585 Expr_Name (Right_Opnd (Expr));
587 when N_Op_Rem =>
588 return
589 Expr_Name (Left_Opnd (Expr)) & " rem " &
590 Expr_Name (Right_Opnd (Expr));
592 when N_Op_Expon =>
593 return
594 Expr_Name (Left_Opnd (Expr)) & " ** " &
595 Expr_Name (Right_Opnd (Expr));
597 when N_Op_Shift_Left =>
598 return
599 Expr_Name (Left_Opnd (Expr)) & " << " &
600 Expr_Name (Right_Opnd (Expr));
602 when N_Op_Shift_Right | N_Op_Shift_Right_Arithmetic =>
603 return
604 Expr_Name (Left_Opnd (Expr)) & " >> " &
605 Expr_Name (Right_Opnd (Expr));
607 when N_Op_Concat =>
608 return
609 Expr_Name (Left_Opnd (Expr)) & " & " &
610 Expr_Name (Right_Opnd (Expr));
612 when N_Op_Plus =>
613 return "+" & Expr_Name (Right_Opnd (Expr));
615 when N_Op_Minus =>
616 return "-" & Expr_Name (Right_Opnd (Expr));
618 when N_Op_Abs =>
619 return "abs " & Expr_Name (Right_Opnd (Expr));
621 when N_Op_Not =>
622 return "not (" & Expr_Name (Right_Opnd (Expr)) & ")";
624 when N_Parameter_Association =>
625 return Expr_Name (Explicit_Actual_Parameter (Expr));
627 when N_Type_Conversion =>
629 -- Most conversions are not very interesting (used inside
630 -- expanded checks to convert to larger ranges), so skip them.
632 return Expr_Name (Expression (Expr));
634 when N_Unchecked_Type_Conversion =>
636 -- Only keep the type conversion in complex cases
638 if not Is_Scalar_Type (Etype (Expr))
639 or else not Is_Scalar_Type (Etype (Expression (Expr)))
640 or else Is_Modular_Integer_Type (Etype (Expr)) /=
641 Is_Modular_Integer_Type (Etype (Expression (Expr)))
642 then
643 return Expr_Name (Subtype_Mark (Expr)) &
644 "(" & Expr_Name (Expression (Expr)) & ")";
645 else
646 return Expr_Name (Expression (Expr));
647 end if;
649 when N_Indexed_Component =>
650 if Take_Prefix then
651 return
652 Expr_Name (Prefix (Expr))
653 & List_Name (First (Sinfo.Expressions (Expr)));
654 else
655 return List_Name (First (Sinfo.Expressions (Expr)));
656 end if;
658 when N_Function_Call =>
660 -- If Default = "", it means we're expanding the name of
661 -- a gnat temporary (and not really a function call), so add
662 -- parentheses around function call to mark it specially.
664 if Default = "" then
665 return '('
666 & Expr_Name (Name (Expr))
667 & List_Name (First (Sinfo.Parameter_Associations (Expr)))
668 & ')';
669 else
670 return
671 Expr_Name (Name (Expr))
672 & List_Name
673 (First (Sinfo.Parameter_Associations (Expr)));
674 end if;
676 when N_Null =>
677 return "null";
679 when N_Others_Choice =>
680 return "others";
682 when others =>
683 return "...";
684 end case;
685 end Expr_Name;
687 -- Start of processing for Expression_Name
689 begin
690 if not From_Source then
691 declare
692 S : constant String := Expr_Name (Expr);
693 begin
694 if S = "..." then
695 return Default;
696 else
697 return S;
698 end if;
699 end;
700 end if;
702 -- Compute left (start) and right (end) slocs for the expression
703 -- Consider using Sinput.Sloc_Range instead, except that it does not
704 -- work properly currently???
706 loop
707 case Nkind (Left) is
708 when N_And_Then
709 | N_Binary_Op
710 | N_Membership_Test
711 | N_Or_Else
713 Left := Original_Node (Left_Opnd (Left));
715 when N_Attribute_Reference
716 | N_Expanded_Name
717 | N_Explicit_Dereference
718 | N_Indexed_Component
719 | N_Reference
720 | N_Selected_Component
721 | N_Slice
723 Left := Original_Node (Prefix (Left));
725 when N_Defining_Program_Unit_Name
726 | N_Designator
727 | N_Function_Call
729 Left := Original_Node (Name (Left));
731 when N_Range =>
732 Left := Original_Node (Low_Bound (Left));
734 when N_Qualified_Expression
735 | N_Type_Conversion
737 Left := Original_Node (Subtype_Mark (Left));
739 -- For any other item, quit loop
741 when others =>
742 exit;
743 end case;
744 end loop;
746 loop
747 case Nkind (Right) is
748 when N_And_Then
749 | N_Membership_Test
750 | N_Op
751 | N_Or_Else
753 Right := Original_Node (Right_Opnd (Right));
755 when N_Expanded_Name
756 | N_Selected_Component
758 Right := Original_Node (Selector_Name (Right));
760 when N_Qualified_Expression
761 | N_Type_Conversion
763 Right := Original_Node (Expression (Right));
765 -- If argument does not already account for a closing
766 -- parenthesis, count one here.
768 if not Nkind_In (Right, N_Aggregate,
769 N_Quantified_Expression)
770 then
771 Append_Paren := Append_Paren + 1;
772 end if;
774 when N_Designator =>
775 Right := Original_Node (Identifier (Right));
777 when N_Defining_Program_Unit_Name =>
778 Right := Original_Node (Defining_Identifier (Right));
780 when N_Range =>
781 Right := Original_Node (High_Bound (Right));
783 when N_Parameter_Association =>
784 Right := Original_Node (Explicit_Actual_Parameter (Right));
786 when N_Component_Association =>
787 if Present (Expression (Right)) then
788 Right := Expression (Right);
789 else
790 Right := Last (Choices (Right));
791 end if;
793 when N_Indexed_Component =>
794 Right := Original_Node (Last (Sinfo.Expressions (Right)));
795 Append_Paren := Append_Paren + 1;
797 when N_Function_Call =>
798 if Present (Sinfo.Parameter_Associations (Right)) then
799 declare
800 Rover : Node_Id;
801 Found : Boolean;
803 begin
804 -- Avoid source position confusion associated with
805 -- parameters for which Comes_From_Source is False.
807 Rover := First (Sinfo.Parameter_Associations (Right));
808 Found := False;
809 while Present (Rover) loop
810 if Comes_From_Source (Original_Node (Rover)) then
811 Right := Original_Node (Rover);
812 Found := True;
813 end if;
815 Next (Rover);
816 end loop;
818 if Found then
819 Append_Paren := Append_Paren + 1;
820 end if;
822 -- Quit loop if no Comes_From_Source parameters
824 exit when not Found;
825 end;
827 -- Quit loop if no parameters
829 else
830 exit;
831 end if;
833 when N_Quantified_Expression =>
834 Right := Original_Node (Condition (Right));
835 Append_Paren := Append_Paren + 1;
837 when N_Aggregate =>
838 declare
839 Aggr : constant Node_Id := Right;
840 Sub : Node_Id;
842 begin
843 Sub := First (Expressions (Aggr));
844 while Present (Sub) loop
845 if Sloc (Sub) > Sloc (Right) then
846 Right := Sub;
847 end if;
849 Next (Sub);
850 end loop;
852 Sub := First (Component_Associations (Aggr));
853 while Present (Sub) loop
854 if Sloc (Sub) > Sloc (Right) then
855 Right := Sub;
856 end if;
858 Next (Sub);
859 end loop;
861 exit when Right = Aggr;
863 Append_Paren := Append_Paren + 1;
864 end;
866 -- For all other items, quit the loop
868 when others =>
869 exit;
870 end case;
871 end loop;
873 declare
874 Scn : Source_Ptr := Original_Location (Sloc (Left));
875 End_Sloc : constant Source_Ptr :=
876 Original_Location (Sloc (Right));
877 Src : constant Source_Buffer_Ptr :=
878 Source_Text (Get_Source_File_Index (Scn));
880 begin
881 if Scn > End_Sloc then
882 return Default;
883 end if;
885 declare
886 Threshold : constant := 256;
887 Buffer : String (1 .. Natural (End_Sloc - Scn));
888 Index : Natural := 0;
889 Skipping_Comment : Boolean := False;
890 Underscore : Boolean := False;
892 begin
893 if Right /= Expr then
894 while Scn < End_Sloc loop
895 case Src (Scn) is
897 -- Give up on non ASCII characters
899 when Character'Val (128) .. Character'Last =>
900 Append_Paren := 0;
901 Index := 0;
902 Right := Expr;
903 exit;
905 when ' '
906 | ASCII.HT
908 if not Skipping_Comment and then not Underscore then
909 Underscore := True;
910 Index := Index + 1;
911 Buffer (Index) := ' ';
912 end if;
914 -- CR/LF/FF is the end of any comment
916 when ASCII.CR
917 | ASCII.FF
918 | ASCII.LF
920 Skipping_Comment := False;
922 when others =>
923 Underscore := False;
925 if not Skipping_Comment then
927 -- Ignore comment
929 if Src (Scn) = '-' and then Src (Scn + 1) = '-' then
930 Skipping_Comment := True;
932 else
933 Index := Index + 1;
934 Buffer (Index) := Src (Scn);
935 end if;
936 end if;
937 end case;
939 -- Give up on too long strings
941 if Index >= Threshold then
942 return Buffer (1 .. Index) & "...";
943 end if;
945 Scn := Scn + 1;
946 end loop;
947 end if;
949 if Index < 1 then
950 declare
951 S : constant String := Expr_Name (Right);
952 begin
953 if S = "..." then
954 return Default;
955 else
956 return S;
957 end if;
958 end;
960 else
961 return
962 Buffer (1 .. Index)
963 & Expr_Name (Right, False)
964 & (1 .. Append_Paren => ')');
965 end if;
966 end;
967 end;
968 end Expression_Image;
970 end Pprint;