aws_24.0.0_2b75fe6d/templates_parser/src/templates_parser.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
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
------------------------------------------------------------------------------
--                             Templates Parser                             --
--                                                                          --
--                     Copyright (C) 1999-2019, AdaCore                     --
--                                                                          --
--  This library 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. This library 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.                    --
--                                                                          --
--  As a special exception under Section 7 of GPL version 3, you are        --
--  granted additional permissions described in the GCC Runtime Library     --
--  Exception, version 3.1, as published by the Free Software Foundation.   --
--                                                                          --
--  You should have received a copy of the GNU General Public License and   --
--  a copy of the GCC Runtime Library Exception along with this program;    --
--  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see   --
--  <http://www.gnu.org/licenses/>.                                         --
--                                                                          --
--  As a special exception, if other files instantiate generics from this   --
--  unit, or you link this unit with other files to produce an executable,  --
--  this  unit  does not  by itself cause  the resulting executable to be   --
--  covered by the GNU General Public License. This exception does not      --
--  however invalidate any other reasons why the executable file  might be  --
--  covered by the  GNU Public License.                                     --
------------------------------------------------------------------------------

pragma Ada_2012;

with Ada.Finalization;
with Ada.Strings.Unbounded;

with Templates_Parser_Tasking;
pragma Elaborate_All (Templates_Parser_Tasking);
pragma Warnings (Off, Templates_Parser_Tasking);
--  This unit is not used in the spec but is placed here to force proper
--  finalization order.

private with Ada.Containers.Indefinite_Hashed_Maps;
private with Ada.Containers.Indefinite_Hashed_Sets;
private with Ada.Strings.Hash;

package Templates_Parser is

   use Ada.Strings.Unbounded;

   function Version return String with Inline;

   Template_Error : exception;

   Default_Begin_Tag : constant String := "@_";
   Default_End_Tag   : constant String := "_@";

   Default_Separator : constant String := ", ";

   procedure Set_Tag_Separators
     (Start_With : String := Default_Begin_Tag;
      Stop_With  : String := Default_End_Tag) with
     Pre => Start_With'Length > 0 and then Stop_With'Length > 0;
   --  Set the tag separators for the whole session. This should be changed as
   --  the very first API call and should not be changed after.

   function Tag_From_Name (Name : String) return String with
     Post => Tag_From_Name'Result'Length >= Name'Length + 2;
   --  Returns the tag given the Name, default is @_NAME_@

   -----------------
   -- Generic Tag --
   -----------------

   type Tag is private;
   --  A tag is using a by reference semantic

   function "+" (Value : String)           return Tag
     with Post => Size ("+"'Result) = 1;
   function "+" (Value : Character)        return Tag
     with Post => Size ("+"'Result) = 1;
   function "+" (Value : Boolean)          return Tag
     with Post => Size ("+"'Result) = 1;
   function "+" (Value : Unbounded_String) return Tag
     with Post => Size ("+"'Result) = 1;
   function "+" (Value : Integer)          return Tag
     with Post => Size ("+"'Result) = 1;
   function "+" (Value : Tag)              return Tag
     with Post => Size ("+"'Result) = 1;
   --  Tag constructors

   function "&" (T : Tag; Value : String)           return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (T : Tag; Value : Character)        return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (T : Tag; Value : Boolean)          return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (T : Tag; Value : Unbounded_String) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (T : Tag; Value : Integer)          return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (T : Tag; Value : Tag)              return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   --  Add Value at the end of the tag, note that "&" will modify its
   --  first parameter. It is intended to be used as [T := T & "val"],
   --  doing [T1 := T2 & "val"] will add val to T2 and set T1 as an
   --  alias. This is designed this way for efficiency.

   function "&" (Value : String;           T : Tag) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (Value : Character;        T : Tag) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (Value : Boolean;          T : Tag) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (Value : Unbounded_String; T : Tag) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   function "&" (Value : Integer;          T : Tag) return Tag
     with Post => Size ("&"'Result) = Size (T)'Old + 1;
   --  Add Value at the front of the tag, see note above

   procedure Append (T : in out Tag; Value : String)
     with Post => Size (T) = Size (T)'Old + 1;
   procedure Append (T : in out Tag; Value : Character)
     with Post => Size (T) = Size (T)'Old + 1;
   procedure Append (T : in out Tag; Value : Boolean)
     with Post => Size (T) = Size (T)'Old + 1;
   procedure Append (T : in out Tag; Value : Unbounded_String)
     with Post => Size (T) = Size (T)'Old + 1;
   procedure Append (T : in out Tag; Value : Integer)
     with Post => Size (T) = Size (T)'Old + 1;
   procedure Append (T : in out Tag; Value : Tag)
     with Post => Size (T) = Size (T)'Old + 1;
   --  Add Value at the end of tag

   procedure Set_Separator (T : in out Tag; Separator : String);
   --  Set separator to be used when building a flat representation of
   --  a composite tag.

   procedure Clear (T : in out Tag) with
     Post => Size (T) = 0;
   --  Removes all values in the tag. Current tag T is not released but
   --  the returned object is separated (not using the same reference) than
   --  the original one.

   function Size (T : Tag) return Natural;
   --  Returns the number of value into T

   function Item (T : Tag; N : Positive) return String
     with Pre => N <= Size (T);
   --  Returns the Nth Tag's item. Raises Constraint_Error if there is
   --  no such Item in T (i.e. T length < N).

   function Composite (T : Tag; N : Positive) return Tag
     with Pre => N <= Size (T);
   --  Returns the Nth Tag's item. Raises Constraint_Error if there is
   --  no such Item in T (i.e. T length < N).

   subtype Vector_Tag is Tag;
   subtype Matrix_Tag is Tag;

   ------------------
   -- Associations --
   ------------------

   type Association is private;

   Null_Association : constant Association;

   type Association_Kind is (Std, Composite);
   --  The kind of association which is either Std (a simple value), a vector
   --  tag or a Matrix tag.

   function Assoc
     (Variable : String;
      Value    : String) return Association
   with Pre  => Variable'Length > 0;
   --  Build an Association (Variable = Value) to be added to a
   --  Translate_Set. This is a standard association, value is a string.

   function Assoc
     (Variable : String;
      Value    : Unbounded_String) return Association
   with Pre  => Variable'Length > 0;
   --  Build an Association (Variable = Value) to be added to a
   --  Translate_Set. This is a standard association, value is an
   --  Unbounded_String.

   function Assoc
     (Variable : String;
      Value    : Integer) return Association
   with Pre  => Variable'Length > 0;
   --  Build an Association (Variable = Value) to be added to a
   --  Translate_Set. This is a standard association, value is an Integer.
   --  It will be displayed without leading space if positive.

   function Assoc
     (Variable : String;
      Value    : Boolean) return Association
   with Pre  => Variable'Length > 0;
   --  Build an Association (Variable = Value) to be added to a
   --  Translate_Set. It set the variable to TRUE or FALSE depending on
   --  value.

   function Assoc
     (Variable  : String;
      Value     : Tag;
      Separator : String := Default_Separator) return Association
   with Pre  => Variable'Length > 0;
   --  Build an Association (Variable = Value) to be added to Translate_Set.
   --  This is a tag association. Separator will be used when outputting the
   --  a flat representation of the Tag (outside a table statement).

   function Get (Assoc : Association) return Tag;
   --  Returns the Tag in Assoc, raise Constraint_Error if Assoc is not
   --  containing a Tag (Association_Kind is Std).
   --  See also the Templates_Parser.Query package for other functions to
   --  manipulate associations.

   function Get (Assoc : Association) return String;
   --  Returns the value in Assoc, raise Constraint_Error if Assoc is not
   --  containing a simple value (Association_Kind is Composite).
   --  See also the Templates_Parser.Query package for other functions to
   --  manipulate associations.

   ---------------------------
   -- Association table/set --
   ---------------------------

   type Translate_Table is array (Positive range <>) of Association;
   --  A table with a set of associations, note that it is better to use
   --  Translate_Set below as it is more efficient.

   No_Translation : constant Translate_Table;

   type Translate_Set is private;
   --  This is a set of association like Translate_Table but it is possible to
   --  insert item into this set more easily, furthermore there is no need to
   --  know the number of item before hand. This is the object used internally
   --  by the templates engine as it is far more efficient to retrieve a
   --  specific item from it.

   Null_Set : constant Translate_Set;

   procedure Insert (Set : in out Translate_Set; Item : Association)
     with Post => Size (Set) >= Size (Set)'Old;
   --  Add Item into the translate set. If an association for this variable
   --  already exists it just replaces it by the new item.

   procedure Insert (Set : in out Translate_Set; Items : Translate_Set)
     with Post => Size (Set) >= Size (Set)'Old;
   --  Add Items into the translate set. If an association for variables in
   --  Items already exists it just replaces it by the new one.

   function "&"
     (Left : Association; Right : Association) return Translate_Set
     with Inline;
   --  Returns new translate set created from 2 associations. If names of
   --  both associations are the same, the returned translate set will
   --  contain only Right.

   function "&"
     (Set : Translate_Set; Item : Association) return Translate_Set
     with Inline;
   --  Adds Item into Set. If an association with the same name already exists
   --  in Set it is replaced by the new one. Note that "&" will modify its
   --  first parameter. It is intended to be used as [T := T & Assoc],
   --  doing [T1 := T2 & Assoc] will add Assoc into T2 and set T1 as an
   --  alias. This is designed this way for efficiency.

   function "+" (Item : Association) return Translate_Set
     with Inline => True,
          Post   => Size ("+"'Result) = 1;
   --  Create translate set from one association

   procedure Remove (Set : in out Translate_Set; Name : String)
     with Pre  => Name'Length > 0,
          Post => not Exists (Set, Name);
   --  Removes association named Name from the Set. Does nothing if there is
   --  not such association in the set.

   function Get (Set : Translate_Set; Name : String) return Association
     with Pre  => Name'Length > 0,
          Post => (if not Exists (Set, Name)
                   then Get'Result = Null_Association);
   --  Returns the association named Name in the Set. Returns Null_Association
   --  is no such association if found in Set.

   function Size (Set : Translate_Set) return Natural;
   --  Returns size of the translate set

   function Exists (Set : Translate_Set; Variable : String) return Boolean
     with Pre  => Variable'Length > 0;
   --  Returns True if an association for Variable exists into the Set

   generic
      with procedure Action (Item : Association; Quit : in out Boolean);
   procedure For_Every_Association (Set : Translate_Set);
   --  Iterates through all associations in the set, call Action for each one.
   --  Set Quit to True to stop the iteration.

   function To_Set (Table : Translate_Table) return Translate_Set
     with Post => Size (To_Set'Result) = Table'Length;
   --  Convert a Translate_Table into a Translate_Set

   -------------
   -- Dynamic --
   -------------

   package Dynamic is

      --------------
      -- Lazy_Tag --
      --------------

      type Lazy_Tag is abstract tagged private;
      type Lazy_Tag_Access is access all Lazy_Tag'Class;

      procedure Value
        (Lazy_Tag     : not null access Dynamic.Lazy_Tag;
         Var_Name     : String;
         Translations : in out Translate_Set) is abstract;
      --  Value is called by the Parse routines below if a tag variable was not
      --  found in the set of translations. This routine must then add the
      --  association for variable Name. It is possible to add other
      --  associations in the translation table but a check is done to see if
      --  the variable Name as been set or not. The default implementation does
      --  nothing.

      Null_Lazy_Tag : constant Lazy_Tag_Access;

      ----------------
      -- Cursor_Tag --
      ----------------

      type Cursor_Tag is abstract tagged private;
      type Cursor_Tag_Access is access all Cursor_Tag'Class;
      --  In some cases it is difficult and not efficient to have to map all
      --  Ada data into a template Tag. A Cursor_Tag object gives the ability
      --  to iterate through a data structure which is living on the Ada side
      --  only.

      function Dimension
        (Cursor_Tag : not null access Dynamic.Cursor_Tag;
         Var_Name   : String) return Natural is abstract;
      --  Must return the number of dimensions for the given variable name. For
      --  a matrix this routine should return 2 for example.

      type Path is array (Positive range <>) of Natural;
      --  A Path gives the full position of a given element in the cursor tag

      function Length
        (Cursor_Tag : not null access Dynamic.Cursor_Tag;
         Var_Name   : String;
         Path       : Dynamic.Path) return Natural is abstract;
      --  Must return the number of item for the given path. The first
      --  dimension is given by the Path (1), for the second column the Path is
      --  (1, 2). Note that each dimension can have a different length. For
      --  example a Matrix is not necessary square.

      function Value
        (Cursor_Tag : not null access Dynamic.Cursor_Tag;
         Var_Name   : String;
         Path       : Dynamic.Path) return String is abstract;
      --  Must return the value for the variable at the given Path. Note that
      --  this routine will be called only for valid items as given by the
      --  Dimension and Length above.

      Null_Cursor_Tag : constant Cursor_Tag_Access;

   private

      type Lazy_Tag is abstract tagged null record;

      Null_Lazy_Tag : constant Lazy_Tag_Access := null;

      type Cursor_Tag is abstract tagged null record;

      Null_Cursor_Tag : constant Cursor_Tag_Access := null;

   end Dynamic;

   package Dyn renames Dynamic;

   --------------------
   -- User's Filters --
   --------------------

   type Filter_Context is record
      Translations : Translate_Set;
      Lazy_Tag     : Dynamic.Lazy_Tag_Access;
   end record;

   type Callback is access function
     (Value      : String;
      Parameters : String;
      Context    : Filter_Context) return String;
   --  User's filter callback

   type Callback_No_Param is access function
     (Value   : String;
      Context : Filter_Context) return String;
   --  User's filter callback

   procedure Register_Filter
     (Name    : String;
      Handler : Callback);
   --  Register user's filter Name using the specified Handler

   procedure Register_Filter
     (Name    : String;
      Handler : Callback_No_Param);
   --  Register user's filter Name using the specified Handler

   type User_Filter is abstract tagged private;
   type User_Filter_Access is access all User_Filter'Class;
   function Execute
     (Filter     : not null access User_Filter;
      Value      : String;
      Parameters : String;
      Context    : Filter_Context) return String is abstract;
   --  User filters can also be implemented through a tagged type, which allows
   --  you to add your own user data and reuse a filter in several
   --  applications, perhaps with a slightly different behavior each time.
   --  It is possible for the callback to modify the data stored in Filter, but
   --  this needs to be done with care, since multiple concurrent calls to
   --  Callback might happen.

   procedure Register_Filter
     (Name   : String;
      Filter : not null access User_Filter'Class);
   --  Register a new filter. Filter must not be freed by the caller, since no
   --  copy is made.

   procedure Free_Filters;
   --  Free all user filters registered above. This is mostly intended when
   --  you are testing memory leaks in your application.

   -----------
   -- Macro --
   -----------

   type Parameter_Set is array (Natural range <>) of Unbounded_String;

   No_Parameter : constant Parameter_Set;

   type Macro_Callback is access
     function (Name : String; Parameters : Parameter_Set) return String;

   procedure Register_Macro_Handler (Callback : Macro_Callback);
   --  Use the given callbacks for every unknown macro in the template. The
   --  default implementation of this routine just displays the macro (name
   --  and parameters).

   -----------------------------
   -- Parsing and Translating --
   -----------------------------

   type Reason_Kind is (Unused, Undefined);

   function Parse
     (Filename          : String;
      Translations      : Translate_Table       := No_Translation;
      Cached            : Boolean               := False;
      Keep_Unknown_Tags : Boolean               := False;
      Lazy_Tag          : Dyn.Lazy_Tag_Access   := Dyn.Null_Lazy_Tag;
      Cursor_Tag        : Dyn.Cursor_Tag_Access := Dyn.Null_Cursor_Tag;
      Report            : access procedure (Tag_Name : String;
                                            Filename : String := "";
                                            Line     : Natural := 0;
                                            Reason   : Reason_Kind) := null)
      return String
   with Pre => Filename'Length > 0;
   --  Parse the Template_File replacing variables' occurrences by the
   --  corresponding values. If Cached is set to True, Filename tree will be
   --  recorded into a cache for quick retrieval. If Keep_Unknown_Tags is set
   --  to True then tags that are not in the translate table are kept
   --  as-is if it is part of the template data. If this tags is part of a
   --  condition (in an IF statement tag), the condition will evaluate to
   --  False.

   function Parse
     (Filename          : String;
      Translations      : Translate_Table       := No_Translation;
      Cached            : Boolean               := False;
      Keep_Unknown_Tags : Boolean               := False;
      Lazy_Tag          : Dyn.Lazy_Tag_Access   := Dyn.Null_Lazy_Tag;
      Cursor_Tag        : Dyn.Cursor_Tag_Access := Dyn.Null_Cursor_Tag;
      Report            : access procedure (Tag_Name : String;
                                            Filename : String := "";
                                            Line     : Natural := 0;
                                            Reason   : Reason_Kind) := null)
      return Unbounded_String
   with Pre => Filename'Length > 0;
   --  Idem but returns an Unbounded_String

   function Parse
     (Filename          : String;
      Translations      : Translate_Set;
      Cached            : Boolean               := False;
      Keep_Unknown_Tags : Boolean               := False;
      Lazy_Tag          : Dyn.Lazy_Tag_Access   := Dyn.Null_Lazy_Tag;
      Cursor_Tag        : Dyn.Cursor_Tag_Access := Dyn.Null_Cursor_Tag;
      Report            : access procedure (Tag_Name : String;
                                            Filename : String := "";
                                            Line     : Natural := 0;
                                            Reason   : Reason_Kind) := null)
      return String
   with Pre => Filename'Length > 0;
   --  Idem with a Translation_Set

   function Parse
     (Filename          : String;
      Translations      : Translate_Set;
      Cached            : Boolean               := False;
      Keep_Unknown_Tags : Boolean               := False;
      Lazy_Tag          : Dyn.Lazy_Tag_Access   := Dyn.Null_Lazy_Tag;
      Cursor_Tag        : Dyn.Cursor_Tag_Access := Dyn.Null_Cursor_Tag;
      Report            : access procedure (Tag_Name : String;
                                            Filename : String := "";
                                            Line     : Natural := 0;
                                            Reason   : Reason_Kind) := null)
      return Unbounded_String
   with Pre => Filename'Length > 0;
   --  Idem with a Translation_Set

   function Translate
     (Template     : String;
      Translations : Translate_Table := No_Translation) return String;
   --  Just translate the discrete variables in the Template string using the
   --  Translations table. This function does not parse the command tag (TABLE,
   --  IF, INCLUDE). All composite tags are replaced by the empty string.

   function Translate
     (Template     : String;
      Translations : Translate_Set) return String;
   --  Idem with a Translation_Set

   procedure Release_Cache;
   --  Release the internal cache. This free the memory used for all currently
   --  loaded template trees.

private

   use Ada;
   type Integer_Access is access Integer;

   ------------------
   -- Generic Tags --
   ------------------

   type Node_Kind is (Value, Value_Set);

   type Tag_Access is access Tag;

   type Tag_Node (Kind : Node_Kind);
   type Tag_Node_Access is access Tag_Node;

   type Tag_Node (Kind : Node_Kind) is record
      Next : Tag_Node_Access;
      case Kind is
         when Value     => V  : Unbounded_String;
         when Value_Set => VS : Tag_Access;
      end case;
   end record;

   type Tag_Node_Arr is array (Positive range <>) of Tag_Node_Access;
   type Tag_Node_Arr_Access is access Tag_Node_Arr;

   package Tag_Values is new Containers.Indefinite_Hashed_Sets
     (String, Strings.Hash, "=");
   type Tag_Values_Access is access Tag_Values.Set;
   --  Map for all tag values to speed-up "in" operator

   type Tag_Data is record
      Count        : Natural;  -- Number of items
      Min, Max     : Natural;  -- Min/Max item's sizes, equal to 1 if leaf
      Nested_Level : Positive; -- Number of composite structures
      Separator    : Unbounded_String;
      Head         : Tag_Node_Access;
      Last         : Tag_Node_Access;
      Tag_Nodes    : Tag_Node_Arr_Access;
      --  This array will be setup during parsing to ensure fast iteration
      --  in reverse order.
      Values       : Tag_Values_Access;
   end record;

   type Tag_Data_Access is access Tag_Data;

   type Tag is new Ada.Finalization.Controlled with record
      Ref_Count : Integer_Access;
      Data      : Tag_Data_Access;
   end record;

   overriding procedure Initialize (T : in out Tag);
   overriding procedure Finalize   (T : in out Tag);
   overriding procedure Adjust     (T : in out Tag);

   subtype Indices is Dynamic.Path;
   --  Set of indices that reference a specific item into a composite tag.
   --  Used by the parser.

   procedure Field
     (T      : Tag;
      N      : Positive;
      Result : out Tag;
      Found  : out Boolean);
   --  Returns the N'th item in Tag. Found is set to False is there is no
   --  such item.

   ------------------
   --  Association --
   ------------------

   type Association (Kind : Association_Kind := Std) is record
      Variable : Unbounded_String;

      case Kind is
         when Std =>
            Value : Unbounded_String;

         when Composite =>
            Comp_Value : Tag;
      end case;
   end record;

   Null_Association : constant Association :=
                        (Std, Null_Unbounded_String, Null_Unbounded_String);

   No_Translation   : constant Translate_Table := (2 .. 1 => Null_Association);

   -----------
   -- Debug --
   -----------

   Expand_Macro : Boolean := False;
   --  If set to true the macro will be displayed inline instead of the named
   --  reference.

   procedure Print_Tree (Filename : String);
   --  Use for debugging purpose only, it will output the internal tree
   --  representation.

   procedure Print_Defined_Macros;
   --  Use for debugging purpose only, output all defined macros

   --------------------
   --  Translate_Set --
   --------------------

   package Association_Map is new Containers.Indefinite_Hashed_Maps
     (String, Association, Strings.Hash, "=", "=");

   type Map_Access is access Association_Map.Map;

   type Translate_Set is new Ada.Finalization.Controlled with record
      Ref_Count : Integer_Access;
      Set       : Map_Access;
   end record;

   overriding procedure Initialize (Set : in out Translate_Set);
   overriding procedure Finalize   (Set : in out Translate_Set);
   overriding procedure Adjust     (Set : in out Translate_Set);

   Null_Set : constant Translate_Set :=
                (Ada.Finalization.Controlled with null, null);

   ------------------
   -- User filters --
   ------------------

   type User_Filter is abstract tagged null record;

   No_Parameter : constant Parameter_Set := (1 .. 0 => <>);

end Templates_Parser;