asis_2019.0.0_3ca32fa2/tools/tool_utils/pp-formatting.ads

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
------------------------------------------------------------------------------
--                                                                          --
--                            GNATPP COMPONENTS                             --
--                                                                          --
--                                    Pp                                    --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--                    Copyright (C) 2001-2019, AdaCore                      --
--                                                                          --
-- GNATPP  is free software; you can redistribute it and/or modify it under --
-- terms  of  the  GNU  General  Public  License  as  published by the Free --
-- Software Foundation;  either version 3, or ( at your option)  any  later --
-- version.  GNATCHECK  is  distributed in the hope that it will be useful, --
-- but  WITHOUT  ANY  WARRANTY;   without  even  the  implied  warranty  of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General --
-- Public License for more details.  You should have received a copy of the --
-- GNU General Public License distributed with GNAT; see file  COPYING3. If --
-- not,  go  to  http://www.gnu.org/licenses  for  a  complete  copy of the --
-- license.                                                                 --
--                                                                          --
-- GNATPP is maintained by AdaCore (http://www.adacore.com)                 --
--                                                                          --
------------------------------------------------------------------------------

pragma Ada_2012;

with Ada.Containers.Bounded_Vectors;
with Ada.Containers.Indefinite_Vectors;
with System.WCh_Con;
with Namet;
with GNAT.OS_Lib; use GNAT.OS_Lib;

with ASIS_UL.Vectors;
with ASIS_UL.Char_Vectors; use ASIS_UL.Char_Vectors;
use ASIS_UL.Char_Vectors.Char_Vectors;
with Pp.Buffers; use Pp.Buffers; use Pp.Buffers.Marker_Vectors;
with Pp.Scanner; use Pp.Scanner.Token_Vectors;

package Pp.Formatting is

   type PP_Casing is
   --  Defines the casing of identifiers and keywords generated by gnatpp
    (Lower_Case,
   --  All letters are lowercase
    Upper_Case,
   --  All letters are uppercase
    Mixed,
   --  For both defining and usage occurrences of identifiers The first letter
   --  and each letter which immediately follows the underscore are uppercase,
   --  and all the other letters are lowercase
    As_Declared);
   --  All the usage occurrences of identifiers have the same casing as
   --  defining occurrences, defining occurrences have the same casing as
   --  the corresponding defining occurrences in the argument source.

   subtype Lower_Upper_PP_Casing is PP_Casing with
     Predicate => Lower_Upper_PP_Casing in Lower_Case | Upper_Case;

   subtype Lower_Upper_Mixed_PP_Casing is PP_Casing with
     Predicate => Lower_Upper_Mixed_PP_Casing
       in Lower_Case | Upper_Case | Mixed;

   Line_Len_Limit : constant Natural := 256;

   type Formatting_Options is record
      PP_Indentation : Positive range 1 .. 9 := 3;
      --  Indentation level

      PP_Cont_Line_Indentation : Positive range 1 .. 9 := 2;
      --  Indentation for continuation lines

      PP_Attribute_Casing : Lower_Upper_Mixed_PP_Casing := Mixed;

      PP_Keyword_Casing : Lower_Upper_PP_Casing := Lower_Case;

      PP_Pragma_Casing : Lower_Upper_Mixed_PP_Casing := Mixed;
      --  Specifies the casing of pragma names and identifiers specific to
      --  pragmas

      PP_Name_Casing : PP_Casing := As_Declared;
      --  Defines the casing for both defining and usage occurrences of the
      --  names

      PP_Enum_Literal_Casing : PP_Casing := As_Declared;
      --  Defines the casing for both defining and usage occurrences of the
      --  enumeration literals.

      PP_Type_Casing : PP_Casing := As_Declared;
      --  Defines the casing for both defining and usage occurrences of the
      --  type (and subtype???) names.

      PP_Nnumbers_Casing : PP_Casing := As_Declared;
      --  Defines the casing for both defining and usage occurrences of the
      --  named numbers names.

      Use_Predefined_Casing : Boolean := True;
      --  This flag specifies if for the predefined names should be used the
      --  same casing as given in RM95

      Use_Dictionary : Boolean := False;
      --  This flag specifies if the exception dictionary should be used for
      --  defining the name casing

      Dictionary_File_Names : String_Vector;
      --  Names of dictionary files specified by -D switches. Nonempty if and
      --  only if Use_Dictionary is True. (So why have Use_Dictionary???)

      Format_Comments : Boolean := True;
      --  If this flag is set OFF, all the comments (comment lines and
      --  end-of-line comments) are moved into the result unchanged (no
      --  indentation or long line splitting is performed).

      GNAT_Comment_Inden : Boolean := True;
      --  Comment lines are indented in GNAT style. The difference with
      --  Standard_Comment_Indent is that comment lines preceding if and
      --  case statements alternatives and 'begin/ keywords are indented as
      --  the corresponding alternatives or keywords, but not as enclosing
      --  statements.

      Standard_Comment_Indent : Boolean := False;
      --  Comment lines are indented as the corresponding code lines.

      GNAT_Comment_Start : Boolean := False;
      --  The comment (if non-empty) should have at least two space characters
      --  after '--'

      Reformat_Comment_Block : Boolean := False;
      --  For sequences of comment lines (separated by space lines or empty
      --  comment lines (lines containing only two minuses) the attempt should
      --  be made to reformat the text of the comment in a word processor style
      --  - that is, to put as many words in the line as possible, using only
      --  one space as a separator.

      Preserve_Special_Comments : Boolean := False;
      --  Do not change the special comment lines. A comment line is considered
      --  as a special comments if it has a special character just after '--'.
      --  See ??? for the details of the definition of a special character

      No_Tab_In_Comments : Boolean := False;
      --  Remove HT and VT from the content of the comments. If this flag is
      --  set ON, all the VT characters are removed from the comment text and
      --  replaced with spaces to get to the nearest Tab stop (the Tab step is
      --  supposed to be equal to 8), and after that the comment line may be
      --  further reformatted to get the indentation and maximum line length
      --  rules. As for now, reformattable comment blocks can not contain HT
      --  characters, and VT are removed from reformattable blocks as a part
      --  of reformatting.

      Comments_Only : Boolean := False;

      End_Labels : Boolean := True;
      --  Do set end/exit labels even if missed in the argument source;
      --  Not used.

      Add_FF : Boolean := False;
      --  Add Form Feed after a pragma Page.

      Compact_Layout : Boolean := True;
      --  Use compact layout for records and named statements;

      End_Id : Boolean := True;
      --  Change "end;" to "end Some_Name;".

      Separate_Line_For_IS : Boolean := True;
      --  Use a separate sine for IS in subprogram body in case if we need more
      --  than one line for subprogram specification

      Separate_Line_For_THEN_and_LOOP : Boolean := False;
      --  Use a separate line for THEN in if statements and LOOP in FOR and
      --  WHILE loops.

      No_Separate_Line_For_THEN_and_LOOP : Boolean := False;
      --  Do not use a separate line for THEN in if statements and LOOP in FOR
      --  and WHILE loops.
      --
      --  If both Separate_Line_For_THEN_and_LOOP and
      --  No_Separate_Line_For_THEN_and_LOOP flags are off, the layout of
      --  THEN and LOOP keywords are defined by other formatting rules

      Separate_Line_For_Label : Boolean := False;
      --  Use a separate line for statement label(s).

      Separate_Line_For_USE : Boolean := False;
      --  Use a separate line for each USE clause that is a part of a context
      --  clause, applied to both type and package use clauses.

      Separate_Line_For_Stmt_Name : Boolean := False;
      --  Use a separate line for a loop or block name and do not use an extra
      --  indentation level for a statement itself. This overrides the layout
      --  of the named statements that is specified by -l(1|2|3) option.

      Split_Line_Before_Op : Boolean := False;

      RM_Style_Spacing : Boolean := False;
      --  Follow Ada Reference Manual style when placing spaces before
      --  delimiters: - no space before '(' - no space between a statement
      --  name and colon. - what else?

      Add_Empty_Lines : Boolean := True;
      --  Add empty lines (if needed to separate compound statements, bodies
      --  and return statements)

      Insert_Blank_Lines : Boolean := False;
      --  Insert blank lines at certain places (between bodies, for example)

      Preserve_Blank_Lines : Boolean := False;
      --  Don't squeeze multiple blank lines down to one

      Max_Line_Length : Natural range 32 .. Line_Len_Limit := 79;

      Align_Colons_In_Decl : Boolean := True;
      Align_Asign_In_Decl  : Boolean := True;
      Align_Asign_In_Stmts : Boolean := True;
      Align_Arrows         : Boolean := True;
      Align_Ats            : Boolean := True;

      Case_Threshold : Natural := 10;
      --  Starting from this number an extra indentation level is not used for
      --  variants in record variant part and case statement alternatives in
      --  case statements, the value 0 means that the extra level is used for
      --  any number of variants and case alternatives

      Par_Specs_Threshold : Natural := Natural'Last;
      --  If the length of parameter specification list is greater than this
      --  number, each parameter specification is placed on a separate line
      --  (for functions the threshold is this value minus 1). The default is
      --  huge, which effectively disables this feature.

      Par_Associations_Threshold : Natural := Natural'Last;
      --  If the length of parameter association list is greater than this
      --  number, and the list contains at least one named association, then
      --  each parameter association is placed on a separate line.

      Decimal_Grouping : Natural := 0;
      --  Number of characters between underscores added to numeric literals
      --  with no base specified. E.g. "123_456". Zero means don't add
      --  underscores.
      Based_Grouping : Natural := 0;
      --  Same as Decimal_Grouping, but used when a base (including base 10)
      --  has been specified. E.g. "16#DEAD_BEEF#".

      Pp_Off_String, Pp_On_String : String_Access := null;
      --  Comment strings that cause pretty printing to be turned off and
      --  on. The initial lead "--" is not included, but initial leading
      --  blanks, if any are included.

      Output_Encoding : System.WCh_Con.WC_Encoding_Method :=
        System.WCh_Con.WCEM_Brackets;
      --  Encoding method for output of wide characters. Defaults to the input
      --  method.

      Is_PP : Boolean := False;
      --  True if this is gnatpp; False for xml2gnat. There are some formatting
      --  options that don't quite work in xml2gnat, which is why this is
      --  needed.
   end record; -- Formatting_Options

   function Comment_Filling_Enabled
     (Options : Formatting_Options) return Boolean is
      (Options.Format_Comments and Options.Reformat_Comment_Block);

   function Alignment_Enabled
     (Options : Formatting_Options) return Boolean is
       (Options.Align_Colons_In_Decl
          or else Options.Align_Asign_In_Decl
          or else Options.Align_Asign_In_Stmts
          or else Options.Align_Arrows
          or else Options.Align_Ats);
   --  The old gnatpp had the ability to individually enable different kinds of
   --  alignment; the new gnatpp does not. Instead, we align if ANY alignment
   --  option is enabled; if all alignment is turned off, we don't align.

   Token_Mismatch : exception;
   --  Raised by Tree_To_Ada if it detects a bug in itself that causes the
   --  output tokens to not match the input properly.

   ----------------

   pragma Style_Checks ("M82");
   generic
      type Ada_Tree_Base is private;
      --  For now, we make this generic, so we can pass in the ASIS-based
      --  Ada_Tree_Base type, or the libadalang-based Ada_Node type.
      with procedure Error_Message (Message : String);
      --  Should print the message and raise an exception to abort processing.
      --  The exception is different between ASIS and LAL.
      with function Is_Null (Tree : Ada_Tree_Base) return Boolean is <>;
      with function T_Img (Tree : Ada_Tree_Base) return String is <>;
   package Generic_Lines_Data is

      -------------------
      -- Line Breaking --
      -------------------

      type Nesting_Level is new Natural;

      type Line_Break is record
         Mark : Marker;
         --  Marks the (potential) line break in the buffer. For a hard line
         --  break, there is an NL character at that position. For a soft one,
         --  there is initially nothing in the buffer; an NL will be inserted
         --  at Mark if the line break becomes enabled.
         --
         --  The reason for inserting NL characters is so we can call Get_Tokens
         --  on the buffer. The reason for not doing so for soft line breaks
         --  is that it's not necessary (there will always be something to
         --  prevent two tokens running together), and it makes the line
         --  length calculation simpler.

         Hard : Boolean;
         --  True for a hard line break, False for a soft one
         Affects_Comments : Boolean;
         --  True if the indentation of this Line_Break should affect the
         --  indentation of surrounding comments. For example, True for '$' but
         --  False for '%" (see type Ada_Template).
         Enabled : Boolean;
         --  True if this line break will appear in the final output
         Level : Nesting_Level := 1000;
         --  Nesting level of [...] (continuation-line indentation, mainly for
         --  soft line breaks).
         Indentation : Natural := 1000;
         --  Indentation level of this line break
         Length : Natural := Natural'Last;
         --  Number of characters in line, not counting NL. Calculated by
         --  Split_Lines. Valid only for enabled line breaks.

         --  For debugging:

--  ????      Kind     : Ada_Tree_Kind;
         Template : Namet.Name_Id;
         UID      : Modular := 123_456_789;
      end record; -- Line_Break

      type Line_Break_Index is new Positive;
      type Line_Break_Array is array (Line_Break_Index range <>) of Line_Break;
      package Line_Break_Vectors is new ASIS_UL.Vectors
        (Line_Break_Index,
         Line_Break,
         Line_Break_Array);
      subtype Line_Break_Vector is Line_Break_Vectors.Vector;

      use Line_Break_Vectors;
      --  use all type Line_Break_Vector;

      ------------------------
      -- Tabs and Alignment --
      ------------------------

      --  We use "tabs" to implement alignment. For example, if the input is:
      --     X : Integer := 123;
      --     Long_Ident : Boolean := False;
      --     Y : constant Long_Type_Name := Something;
      --  we're going to align the ":" and ":=" in the output, like this:
      --     X          : Integer                 := 123;
      --     Long_Ident : Boolean                 := False;
      --     Y          : constant Long_Type_Name := Something;
      --
      --  A "tab" appears before each ":" and ":=" in the above. This information
      --  is recorded in Tabs, below. The position of the tab in the buffer
      --  is indicated by Mark, which gets automatically updated as unrelated
      --  passes update Out_Buf. Finally, Insert_Alignment calculates the Col
      --  and Num_Blanks for each tab, and then inserts blanks accordingly.
      --
      --  A tab always occurs at the start of a token.

      type Tab_Index_In_Line is range 1 .. 9;
      --  We probably never have more than a few tabs in a given construct, so 9
      --  should be plenty, and it allows us to use a single digit in the
      --  templates, as in "^2".

      type Tab_Rec is record
         Parent, Tree : Ada_Tree_Base;
         --  Tree is the tree whose template generated this tab, and Parent is its
         --  parent. Tree is used to ensure that the relevant tabs within a single
         --  line all come from the same tree; other tabs in the line are ignored.
         --  Parent is used across lines to ensure that all lines within a
         --  paragraph to be aligned together all come from the same parent tree.
         Token : Namet.Name_Id := Namet.Name_Find ("");
         --  This is some text associated with the Tab. Usually, it is the text of
         --  the token that follows the Tab in the template.
         Mark : Marker;
         --  Position in the buffer of the tab
         Index_In_Line   : Tab_Index_In_Line := Tab_Index_In_Line'Last;
         Col             : Positive          := Positive'Last;
         --  Column number of the tab
         Num_Blanks : Natural := 0;
         --  Number of blanks this tab should expand into
         Is_Fake : Boolean;
         --  True if this is a "fake tab", which means that it doesn't actually
         --  insert any blanks (Num_Blanks = 0). See Append_Tab for more
         --  explanation.
         Is_Insertion_Point : Boolean;
         --  False for "^", true for "&". Normally, "^" means insert blanks at the
         --  point of the "^" to align things. However, if there is a preceding
         --  (and matching) "&", then the blanks are inserted at the "insertion
         --  point" indicated by "&". This feature provides for
         --  right-justification.
         --  See Tree_To_Ada.Insert_Alignment.Calculate_Num_Blanks.Process_Line in
         --  pp-formatting.adb for more information.
      end record;

      type Tab_Index is new Positive;
      type Tab_Array is array (Tab_Index range <>) of Tab_Rec;
      package Tab_Vectors is new ASIS_UL.Vectors (Tab_Index, Tab_Rec, Tab_Array);
      subtype Tab_Vector is Tab_Vectors.Vector;

      use Tab_Vectors;
      --  use all type Tab_Vector;

      package Tab_In_Line_Vectors is new Ada.Containers.Bounded_Vectors
        (Tab_Index_In_Line,
         Tab_Index);
      use Tab_In_Line_Vectors;
      subtype Tab_In_Line_Vector is
        Tab_In_Line_Vectors
          .Vector
        (Capacity => Ada.Containers.Count_Type (Tab_Index_In_Line'Last));

      type Tab_In_Line_Vector_Index is new Positive;
      package Tab_In_Line_Vector_Vectors is new Ada.Containers.Indefinite_Vectors
        (Tab_In_Line_Vector_Index,
         Tab_In_Line_Vector);
      --  We use Indefinite_Vectors rather than Vectors because otherwise we get
      --  "discriminant check failed" at a-cobove.ads:371. I'm not sure whether
      --  that's a compiler bug.
      use Tab_In_Line_Vector_Vectors;

      type Lines_Data_Rec is record

         Out_Buf : Buffer;
         --  Buffer containing the text that we will eventually output as the
         --  final result. We first fill this with initially formatted text by
         --  walking the tree, and then we modify it repeatedly in multiple
         --  passes.

         Cur_Indentation : Natural := 0;

         Next_Line_Break_Unique_Id : Modular := 1;
         --  Used to set Line_Break.UID for debugging.

         --  Each line break is represented by a Line_Break appended onto the
         --  Line_Breaks vector. Hard line breaks are initially enabled. Soft
         --  line breaks are initially disabled, and will be enabled if
         --  necessary to make lines short enough.

         All_Line_Breaks : Line_Break_Vector;
         --  All line breaks in the whole input file. Built in two passes.

         Temp_Line_Breaks : Line_Break_Vector;
         --  Used by Insert_Comments_And_Blank_Lines to add new line breaks to
         --  All_Line_Breaks; they are appended to Temp_Line_Breaks, which is
         --  then merged with All_Line_Breaks when done. This is for efficiency
         --  and to keep the tables in source-location order.

         Enabled_Line_Breaks : Line_Break_Vector;
         --  All enabled line breaks
         Syntax_Line_Breaks : Line_Break_Vector;
         --  All (enabled) nonblank hard line breaks. These are called
         --  "Syntax_..."  because they are determined by the syntax (e.g. we
         --  always put a line break after a statement).

         --  ???Perhaps make the above tables contain Line_Break_Indexes
         --  instead of Line_Breaks. Can we use an index into a single table
         --  instead of UID?

         Tabs : Tab_Vector;
         --  All of the tabs in the whole input file, in increasing order

         Src_Tokens, -- from original source file (Src_Buf)
         Out_Tokens : -- from Out_Buf
           Scanner.Token_Vector;

         Out_Buf_Line_Ends : aliased Marker_Vector;

         -------------------------------------
         -- Support for -pp-off and --pp-on --
         -------------------------------------

         Pp_Off_On_Delimiters : Scanner.Pp_Off_On_Delimiters_Rec;

         --  Debugging:

         Check_Whitespace : Boolean := True;
         --  Used during the Subtree_To_Ada phase. True except within comments and
         --  literals. Check for two blanks in a row.
      end record; -- Lines_Data_Rec

      procedure Collect_Enabled_Line_Breaks
        (Lines_Data : in out Lines_Data_Rec; Syntax_Also : Boolean);
      --  Collect all the enabled line breaks, and (if Syntax_Also is True) also
      --  the syntax line breaks.

      function Next_Enabled
        (Line_Breaks : Line_Break_Vector; F : Line_Break_Index)
        return Line_Break_Index;
      --  Next currently-enabled line break after F. Thus, F..Next_Enabled(F) is a
      --  line.

      function Is_Empty_Line
        (Out_Buf : Buffer;
         Line_Breaks : Line_Break_Vector;
         F, L : Line_Break_Index) return Boolean;
      --  True if F..L forms an empty line (or would, if both were enabled).

      ----------------

      function Good_Column
        (PP_Indentation : Positive; Indentation : Natural)
        return Natural is
        ((Indentation / PP_Indentation) * PP_Indentation);
      --  Make sure indentation is a multiple of PP_Indentation; otherwise style
      --  checking complains "(style) bad column".

      procedure Do_Comments_Only
        (Lines_Data : in out Lines_Data_Rec;
         Src_Buf : in out Buffer;
         Options : Formatting_Options);
      --  Implement the --comments-only switch. This skips most of the usual
      --  pretty-printing passes, and just formats comments.

      procedure Post_Tree_Phases
        (Lines_Data : in out Lines_Data_Rec;
         Source_File_Name : String;
         Src_Buf : in out Buffer;
         Options : Formatting_Options);
      --  The first pretty-printing pass walks the tree and produces text,
      --  along with various tables. This performs the remaining passes, which
      --  do not make use of the tree.

      ----------------

      --  Debugging:

      function Line_Text
        (Out_Buf : Buffer;
         Line_Breaks : Line_Break_Vector;
         F, L : Line_Break_Index) return W_Str;
      --  F and L are the first and last index forming a line; returns the text of
      --  the line, not including any new-lines.

      function Tab_Image
        (Out_Buf : Buffer; Tabs : Tab_Vector; X : Tab_Index) return String;

      procedure Put_Line_Breaks
        (Out_Buf : Buffer; Line_Breaks : Line_Break_Vector);
      --  ???This doesn't work unless Line_Breaks is All_Line_Breaks, because of
      --  various global variables!

      procedure Put_Line_Break (Out_Buf : Buffer; Break : Line_Break);

      procedure Put_Buf_With_Marks (Lines_Data : Lines_Data_Rec);

      procedure Format_Debug_Output
        (Lines_Data : Lines_Data_Rec; Message : String);

      Simulate_Token_Mismatch : Boolean renames Debug.Debug_Flag_8;
      Disable_Final_Check : Boolean renames Debug.Debug_Flag_7;
      function Enable_Token_Mismatch return Boolean is
         ((Assert_Enabled or Debug.Debug_Flag_5)
            and not Simulate_Token_Mismatch
            and not Debug.Debug_Flag_6);

   end Generic_Lines_Data;
   pragma Style_Checks ("M79");

   ----------------------------------------------------------------
   --
   --  Formatting uses the following major passes. Convert_Tree_To_Ada has a
   --  version based on ASIS and a version based on libadalang. (???Software
   --  present tense!) Split_Lines through Final_Check are done by
   --  Post_Tree_Phases above.
   --
   --  Convert_Tree_To_Ada
   --     Walks the Ada_Tree, using Ada_Templates to convert the tree into
   --     text form in Out_Buf. Out_Buf is further modified by subsequent
   --     passes. Builds the Line_Break table for use by Split_Lines and
   --     Insert_NLs_And_Indentation. Builds the Tabs table for use by
   --     Insert_Alignment.
   --
   --     Subsequent passes work on the text in Out_Buf, and not the
   --     Ada_Tree. Therefore, if they need any syntactic/structural
   --     information, it must be encoded in other data structures, such as the
   --     Line_Breaks and Tabs tables.
   --
   --  Split_Lines (first time)
   --     Determine which soft line breaks should be enabled.
   --
   --  Insert_Comments_And_Blank_Lines
   --     Step through the source tokens and Out_Buf tokens. Copy comment and
   --     blank line tokens into Out_Buf as they are encountered.
   --
   --  Split_Lines (again)
   --     We do this again because inserted end-of-line comments can cause
   --     lines to be too long. We don't want to split the line just before the
   --     comment; we want to split at some auspicious soft line break(s).
   --
   --  Insert_NLs_And_Indentation
   --     Insert newline characters and leading blanks for each soft line break
   --     that was enabled by Split_Lines.
   --
   --  Insert_Alignment
   --     Walk the Tabs table to calculate how many blanks (if any) should be
   --     inserted for each Tab. Then insert those blanks in Out_Buf.
   --
   --  Keyword_Casing
   --     Convert reserved words to the appropriate case as specified by
   --     command-line options.
   --
   --  Insert_Form_Feeds
   --     Implement the -ff switch, by inserting FF characters after
   --     "pragma Page;".
   --
   --  Copy_Pp_Off_Regions
   --     Regions where pretty printing should be turned off have been
   --     formatted as usual. This phase undoes all that formatting by copying
   --     text from Src_Buf to Out_Buf.
   --
   --  Final_Check
   --     Go through the source tokens and Out_Buf tokens (the latter now
   --     containing comments and blank lines), and make sure they (mostly)
   --     match. If there is any mismatch besides a small set of allowed ones,
   --     raise an exception. This pass makes no changes, so it serves no
   --     useful purpose unless there is a bug in some previous pass; the
   --     purpose is to prevent gnatpp from damaging the user's source code.
   --     The algorithm in this pass is quite similar to the one in
   --     Insert_Comments_And_Blank_Lines.
   --
   --  Write_Out_Buf
   --     Write Out_Buf to the appropriate file (or Current_Output).
   --
   --  Each pass expects to be entered with Out_Buf's 'point' at the beginning,
   --  and returns with Out_Buf's 'point' STILL at the beginning. Thus, passes
   --  that step through Out_Buf need to call Reset(Out_Buf) before returning.
   --
   ----------------------------------------------------------------

end Pp.Formatting;