libadalang_24.0.0_a1358075/src/libadalang-data_decomposition.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
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
--
--  Copyright (C) 2022-2023, AdaCore
--  SPDX-License-Identifier: Apache-2.0
--

--  This package provides routines to decompose composite program data into
--  elementary components, and more generally to query the representation of
--  program data.
--
--  .. ATTENTION::
--
--     This is an experimental feature, so even if it is exposed to allow
--     experiments, it is totally unsupported and the API is very likely to
--     change in the future.
--
--  Here is a small example of usage for this package:
--
--  .. code:: ada
--
--     --  Code that the program below analyzes, to be compiled with the
--     --  ``-gnatR4js`` option (``gcc -c pkg.ads -gnatR4js``) to generate the
--     --  ``pkg.ads.json`` file.
--
--     package Pkg is
--        type R (N : Natural) is record
--           case N is
--              when 0 .. 9 =>
--                 B : Boolean;
--              when 100 .. 199 | 900 .. 999 =>
--                 I : Integer;
--              when others =>
--                 null;
--           end case;
--        end record;
--     end Pkg;
--
--     --  Corresponding project file
--
--     project P is
--     end P;
--
--     --  Program using the ``Libadalang.Data_Decomposition`` API to analyze
--     --  representation information.
--
--     with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
--     with Ada.Text_IO;           use Ada.Text_IO;
--
--     with GNATCOLL.GMP.Integers; use GNATCOLL.GMP.Integers;
--     with GPR2.Context;
--     with GPR2.Path_Name;
--     with GPR2.Project.Tree;
--
--     with Libadalang.Analysis;           use Libadalang.Analysis;
--     with Libadalang.Common;             use Libadalang.Common;
--     with Libadalang.Data_Decomposition;
--     with Libadalang.Iterators;          use Libadalang.Iterators;
--     with Libadalang.Project_Provider;   use Libadalang.Project_Provider;
--
--     procedure Main is
--        package DDA renames Libadalang.Data_Decomposition;
--
--        --  Load the "p.gpr" project file, then create the unit provider (to
--        --  make Libadalang's name resolution work) and the representation
--        --  information collection for it.
--
--        Tree       : GPR2.Project.Tree.Object;
--        Provider   : Unit_Provider_Reference;
--        Collection : DDA.Repinfo_Collection;
--     begin
--        Tree.Load_Autoconf
--          (Filename => GPR2.Path_Name.Create_File
--                         (Name      => "p.gpr",
--                          Directory => GPR2.Path_Name.No_Resolution),
--           Context  => GPR2.Context.Empty);
--
--        Provider := Create_Project_Unit_Provider (Tree);
--
--        Collection := DDA.Load_From_Project (Tree);
--
--        declare
--           --  Analyze the "pkg.ads" source file
--
--           Ctx : constant Analysis_Context := Create_Context;
--           U   : constant Analysis_Unit := Ctx.Get_From_File ("pkg.ads");
--
--           --  Look for the first type declaration in "pkg.ads"
--
--           function Filter (Node : Ada_Node) return Boolean
--           is (Node.Kind in Ada_Base_Type_Decl);
--
--           Decl : constant Base_Type_Decl :=
--             Find_First (U.Root, Filter'Access).As_Base_Type_Decl;
--
--           --  Fetch type representation information
--
--           TR : constant DDA.Type_Representation :=
--             Collection.Lookup (Decl);
--
--           --  Resolve the layout for this record type for a specific
--           --  set of discriminants (N = 950).
--
--           Discs : constant DDA.Discriminant_Values :=
--             (1 => Make ("950"));
--           RR    : constant DDA.Resolved_Record_Type :=
--             DDA.Resolved_Record (TR, Discs);
--        begin
--           --  Display the size of this record (in bits) as well as the name
--           --  and position (in bytes) for each component.
--
--           Put_Line ("Record size:" & RR.Value_Size'Image);
--           for C of RR.Components loop
--              Put_Line ("Component " & C.Declaration.Image
--                        & " at position" & C.Position'Image);
--           end loop;
--        end;
--     end Main;
--
--  Expected output:
--
--  .. code:: text
--
--     Record size: 64
--     Component <DefiningName "N" pkg.ads:2:12-2:13> at position 0
--     Component <DefiningName "I" pkg.ads:7:13-7:14> at position 4

private with Ada.Containers.Hashed_Maps;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Unchecked_Deallocation;
with System;

with GNAT.Regexp;

with GNATCOLL.GMP.Integers;
with GNATCOLL.GMP.Rational_Numbers;
private with GNATCOLL.Refcount;
private with GNATCOLL.Traces;
with GPR2.Project.Tree;
with GPR2.Project.View;

private with Langkit_Support.Bump_Ptr;
private with Langkit_Support.Symbols;
with Langkit_Support.Text; use Langkit_Support.Text;
private with Langkit_Support.Vectors;

with Libadalang.Analysis;  use Libadalang.Analysis;
with Libadalang.Expr_Eval; use Libadalang.Expr_Eval;

package Libadalang.Data_Decomposition is

   package GMP_Int renames GNATCOLL.GMP.Integers;
   package GMP_RN renames GNATCOLL.GMP.Rational_Numbers;

   type Numerical_Expression is private;
   --  Expression that, when evaluated, returns an integer (arbitrary
   --  precision).
   --
   --  This data type is used to represent dynamic attributes, such as the size
   --  of a discriminated record type, which depends on the specific values for
   --  its discriminants.
   --
   --  Each numerical expression requires a specific number of integer
   --  parameters to be evaluated, each integer corresponding to a record
   --  discriminant. See the ``Discriminant_Count`` and ``Evaluate`` primitives
   --  below.
   --
   --  Note that for record types, the ``Resolved_Record`` function below
   --  resolves all attributes/components at once for a given record type given
   --  values for its discriminants. This may be more convenient than going
   --  through the evaluation of numerical expressions manually.

   No_Numerical_Expression : constant Numerical_Expression;

   function Is_Null (Self : Numerical_Expression) return Boolean;

   Unsupported_Expression : exception;
   --  Exception raised in a function that returns ``Numerical_Expression``
   --  when the expression is unsupported. For now, this happens only when the
   --  expression depends on dynamic variables that are not discriminants.

   type Type_Kind is
     (Access_Type,
      Enumeration_Type,
      Signed_Type,
      Modular_Type,
      Floating_Type,
      Decimal_Type,
      Ordinary_Type,
      Array_Type,
      Interface_Type,
      Record_Type,
      Protected_Type,
      Task_Type);

   subtype Elementary_Type is Type_Kind range Access_Type .. Ordinary_Type;
   subtype Scalar_Type is
    Elementary_Type range Enumeration_Type .. Ordinary_Type;
   subtype Discrete_Type is Scalar_Type range Enumeration_Type .. Modular_Type;
   subtype Integer_Type is Discrete_Type range Signed_Type .. Modular_Type;
   subtype Real_Type is Scalar_Type range Floating_Type .. Ordinary_Type;
   subtype Fixed_Type is Real_Type range Decimal_Type .. Ordinary_Type;
   subtype Composite_Type is Type_Kind range Array_Type .. Task_Type;

   --  All the types below have shared pointer semantics

   type Type_Representation is private;
   --  Representation information for a given type

   type Component_Representation is private;
   --  Representation information for a given record component

   type Variant_Representation is private;
   --  Representation information for a given record variant (or "variant part
   --  alternative").

   No_Type_Representation      : constant Type_Representation;
   No_Component_Representation : constant Component_Representation;
   No_Variant_Representation   : constant Variant_Representation;

   function Is_Null (Self : Type_Representation) return Boolean;
   function Is_Null (Self : Component_Representation) return Boolean;
   function Is_Null (Self : Variant_Representation) return Boolean;

   type Component_Representation_Array is
     array (Positive range <>) of Component_Representation;

   type Variant_Representation_Array is
     array (Positive range <>) of Variant_Representation;

   Type_Mismatch_Error : exception;
   --  Exception raised when an inconsistency is detected between type
   --  representation information and type declarations as found in the
   --  sources.

   -----------------------
   -- Generic accessors --
   -----------------------

   function Kind (Self : Type_Representation) return Type_Kind
   with Pre => not Is_Null (Self);
   --  Return the kind of type ``Self`` is

   function Alignment (Self : Type_Representation) return Positive
   with Pre => not Is_Null (Self);
   --  Alignment for values of this type, in bytes

   function Object_Size
     (Self : Type_Representation) return Numerical_Expression
   with Pre => not Is_Null (Self);
   --  Number of bits used to hold objects whose type is ``Self`` (See GNAT RM
   --  9.6. Value_Size and Object_Size Clauses).

   function Value_Size
     (Self : Type_Representation) return Numerical_Expression
   with Pre => not Is_Null (Self);
   --  Number of bits required to represent a value whose type is ``Self``.
   --  This corresponds to the RM defined ``'Size`` attribute (See GNAT RM 9.6.
   --  Value_Size and Object_Size Clauses).

   function Scalar_Storage_Order
     (Self : Type_Representation) return System.Bit_Order
   with Pre => Kind (Self) in Composite_Type;
   --  Byte order for scalars stored in this compound type

   ----------------------------
   -- Record types accessors --
   ----------------------------

   function Components
     (Self : Type_Representation) return Component_Representation_Array
   with Pre => Kind (Self) = Record_Type;
   --  List of components for this record, excluding components from the
   --  variant part (if any).

   function Discriminants
     (Self : Type_Representation) return Component_Representation_Array
   with Pre => Kind (Self) = Record_Type;
   --  Subset of components for this record that are discriminants

   function Has_Variant_Part (Self : Type_Representation) return Boolean
   with Pre => Kind (Self) = Record_Type;
   --  Whether this record type has a variant part

   function Variants
     (Self : Type_Representation) return Variant_Representation_Array
   with Pre => Kind (Self) = Record_Type and then Has_Variant_Part (Self);
   --  Assuming this record type has a variant part, return all variants for it

   function Bit_Order (Self : Type_Representation) return System.Bit_Order
   with Pre => Kind (Self) = Record_Type;
   --  Order for bit numbering in this record type

   -----------------------
   -- Variant accessors --
   -----------------------

   function Present
     (Self : Variant_Representation) return Numerical_Expression
   with Pre => not Is_Null (Self);
   --  Expression that evaluates to non-zero when the compoments of the variant
   --  are contained in the record type, and to zero when they are not.

   function Components
     (Self : Variant_Representation) return Component_Representation_Array
   with Pre => not Is_Null (Self);
   --  Components for this variant, excluding components from the sub-variant
   --  (if any).

   function Has_Subvariant_Part (Self : Variant_Representation) return Boolean
   with Pre => not Is_Null (Self);
   --  Whether this variant has a sub-variant part

   function Subvariants
     (Self : Variant_Representation) return Variant_Representation_Array
   with Pre => Has_Subvariant_Part (Self);
   --  Assuming this variant has a sub-variant part, return all sub-variants
   --  for it.

   -------------------------
   -- Component accessors --
   -------------------------

   function Declaration
     (Self : Component_Representation) return Defining_Name
   with Pre => not Is_Null (Self);
   --  Declaration for this component. This returns ``No_Defining_Name`` for
   --  artificial components, i.e. components not defined in the source, but
   --  introduced by the compiler (for instance the tag for tagged types).

   function Component_Name (Self : Component_Representation) return Text_Type
   with Pre => not Is_Null (Self);
   --  Name for this component. The casing of the result is not specified. This
   --  is useful as a complement to the ``Declaration`` function above for
   --  artificial components, which have no declaration.

   function Discriminant_Number
     (Self : Component_Representation) return Natural
   with Pre => not Is_Null (Self);
   --  0 if this component is *not* a discriminant. Positive number that
   --  uniquely identifies this discriminant in the record type otherwise.

   function Position
     (Self : Component_Representation) return Numerical_Expression
   with Pre => not Is_Null (Self);
   --  Expression that evaluates to the index of first byte in the record that
   --  is used to represent this component.

   function First_Bit (Self : Component_Representation) return Natural
   with Pre => not Is_Null (Self);
   --  First bit in the byte at ``Position`` that is used to represent this
   --  component.

   function Size (Self : Component_Representation) return Numerical_Expression
   with Pre => not Is_Null (Self);
   --  Size (in bits) for this component

   ---------------------------
   -- Array types accessors --
   ---------------------------

   function Component_Size
     (Self : Type_Representation) return Numerical_Expression
   with Pre => Kind (Self) = Array_Type;
   --  Expression that evaluates to the size (in bits) for each array
   --  component.

   ---------------------------------
   -- Fixed point types accessors --
   ---------------------------------

   function Small (Self : Type_Representation) return GMP_RN.Rational
   with Pre => Kind (Self) in Fixed_Type;
   --  Return the "small" number for a fixed point type. This is a positive
   --  real number, and all values for this fixed point type are multiples of
   --  this "small" number.

   function Range_First (Self : Type_Representation) return GMP_RN.Rational
   with Pre => Kind (Self) in Fixed_Type;
   --  Lower bound for the mandatory range of a fixed point type

   function Range_Last (Self : Type_Representation) return GMP_RN.Rational
   with Pre => Kind (Self) in Fixed_Type;
   --  Upper bound for the mandatory range of a fixed point type

   -------------------------------------
   -- Numerical expression evaluation --
   -------------------------------------

   function Discriminant_Count (Self : Numerical_Expression) return Natural
   with Pre => not Is_Null (Self);
   --  Return the number of discriminants needed to evaluate this expression

   type Discriminant_Values is
     array (Positive range <>) of GMP_Int.Big_Integer;
   --  Actual values for all the discriminants in a record type.
   --
   --  For discriminants that are integers, the value must be the corresponding
   --  number. For discriminants that are enumerations, the value must be the
   --  code used to represent the enumeration literal (i.e. the equivalent of
   --  GNAT's ``Enum_Rep`` attribute). The ``Discriminant_Value`` function
   --  below can be used to turn a discriminant value into the expected integer
   --  value.

   No_Discriminant_Value : constant Discriminant_Values := (1 .. 0 => <>);

   Invalid_Discriminant : exception;
   --  See the ``Discriminant_Value`` function

   function Discriminant_Value
     (Result : Eval_Result) return GMP_Int.Big_Integer;
   --  Return the discriminant value corresponding to the given evaluated
   --  static expression. Raise an ``Invalid_Discriminant`` exception if
   --  ``Result`` is not an enum literal nor an integer.

   function Evaluate
     (Self          : Numerical_Expression;
      Discriminants : Discriminant_Values) return GMP_Int.Big_Integer
   with Pre => Discriminants'First = 1
               and then Discriminants'Last >= Discriminant_Count (Self);
   --  Evaluate a numerical expression given specific values for all required
   --  discriminants.
   --
   --  Note that more discriminants than required are accepted: the evaluation
   --  of the attribute of a component for a record with 2 discriminants may
   --  need only the first discriminant that record has

   ----------------------------------
   -- Record components resolution --
   ----------------------------------

   type Size_Type is mod 2 ** 64;
   --  Number of bits or bytes to denote the size of an object in memory.
   --
   --  Note that the range for this type may change in the future, for instance
   --  if Ada ever gets ported to a 128-bit architecture.

   type Resolved_Component is record
      Declaration : Defining_Name;
      --  Declaration for this component

      Artificial_Name : Unbounded_Text_Type;
      --  If ``Declaration`` is null (i.e. if this describes an artificial
      --  component), name for that component. The casing is not specified.

      Position : Size_Type;
      --  See the corresponding ``Component_Representation`` primitive

      First_Bit : Natural;
      --  See the corresponding ``Component_Representation`` primitive

      Size : Size_Type;
      --  See the corresponding ``Component_Representation`` primitive
   end record;
   --  Description of a record component once the record discriminants are
   --  resolved.

   type Resolved_Component_Array is
     array (Positive range <>) of Resolved_Component;

   type Resolved_Record_Type (Component_Count : Natural) is record
      Alignment : Positive;
      --  See the corresponding ``Type_Representation`` primitive

      Object_Size : Size_Type;
      --  See the corresponding ``Type_Representation`` primitive

      Value_Size : Size_Type;
      --  See the corresponding ``Type_Representation`` primitive

      Bit_Order : System.Bit_Order;
      --  See the corresponding ``Type_Representation`` primitive

      Scalar_Storage_Order : System.Bit_Order;
      --  See the corresponding ``Type_Representation`` primitive

      Components : Resolved_Component_Array (1 ..  Component_Count);
      --  See the corresponding ``Type_Representation`` primitive
   end record;

   Resolution_Error : exception;
   --  See the ``Resolved_Record`` function

   function Resolved_Record
     (Self          : Type_Representation;
      Discriminants : Discriminant_Values) return Resolved_Record_Type
   with Pre => Kind (Self) = Record_Type;
   --  Resolve all components in record type ``Self`` according to the values
   --  of its discriminants.
   --
   --  Raise a ``Resolution_Error`` when resolution for the given discriminants
   --  yields nonsensical sizes or positions (usually because the discriminants
   --  are invalid).

   -------------------------------------------
   -- Representation information collection --
   -------------------------------------------

   type Repinfo_Collection is tagged private;
   --  Collection of compiler-generated representation information

   function Lookup
     (Self : Repinfo_Collection;
      Decl : Base_Type_Decl'Class) return Type_Representation;
   --  Look for the type representation corresponding to the given type
   --  declaration. Return ``No_Type_Representation`` if nothing in ``Self``
   --  matches ``Type_Name``, and raise a ``Type_Mismatch_Error`` if an
   --  inconsistency is found between ``Decl`` and the type representation
   --  found for it.

   Loading_Error : exception;
   --  Exception raised when an error occurs while loading a collection of
   --  representation information.

   type Filename_Array is array (Positive range <>) of Unbounded_String;

   function Load (Filenames : Filename_Array) return Repinfo_Collection;
   --  Load type representation information from all the given ``Filenames``
   --  and return the corresponding collection.
   --
   --  All files are supposed to be generated running GNAT on compilation units
   --  with the ``-gnatR4js`` switch.
   --
   --  Raise a ``Loading_Error`` exception if unsuccessful.

   Default_JSON_Filename_Regexp : constant GNAT.Regexp.Regexp :=
     GNAT.Regexp.Compile (".*\.(ad.|a|spc|bdy)\.json");
   --  Default matcher for JSON files created by the -gnatR4js compiler switch.
   --  It matches the JSON files created for Ada sources using the most usual
   --  file extensions: ``.ads``, ``.adb``, ``.ada``, ``.spc``, ``.bdy``, etc.

   function Load_From_Directories
     (Name_Pattern : GNAT.Regexp.Regexp := Default_JSON_Filename_Regexp;
      Directories  : Filename_Array) return Repinfo_Collection;
   --  Like ``Load``, but using automatically loading all files in any of the
   --  given ``Directories`` whose file name matches ``Name_Pattern``.

   function Load_From_Directory
     (Name_Pattern : GNAT.Regexp.Regexp := Default_JSON_Filename_Regexp;
      Directory    : String) return Repinfo_Collection;
   --  Like ``Load``, but using automatically loading all files whose name
   --  matches ``Name_Pattern`` in the given ``Directory`.

   Gprbuild_Error : exception;
   --  See ``Load_From_Project``

   function Load_From_Project
     (Tree    : GPR2.Project.Tree.Object;
      View    : GPR2.Project.View.Object := GPR2.Project.View.Undefined;
      Subdirs : String := "repinfo";
      Force   : Boolean := False) return Repinfo_Collection;
   --  Run GPRbuild on the given project ``Tree`` to compile all of its Ada
   --  units with the ``-gnatR4js`` compiler switch, then load all generated
   --  JSON files for units under the ``View`` sub-project.
   --
   --  Unless left to empty strings, the following formals are passed to
   --  ``gprbuild``'s command line:
   --
   --  * ``Subdirs`` is passed as ``--subdirs``.
   --
   --  If ``Force`` is ``True``, pass ``-f`` to gprbuild to force the build of
   --  compilation units.
   --
   --  Raise a ``Gprbuild_Error`` exception if ``gprbuild`` exits with a
   --  non-zero status code. Raise a ``Loading_Error`` exception if the loading
   --  of JSON files fails.

private

   use Langkit_Support.Symbols;
   use Langkit_Support.Bump_Ptr;

   Trace : constant GNATCOLL.Traces.Trace_Handle :=
     GNATCOLL.Traces.Create ("LIBADALANG.DDA", GNATCOLL.Traces.From_Config);

   --  The allocation model is centered around ``Repinfo_Collection``: that
   --  type is a shared pointer to the internal ``Repinfo_Collection_Data``
   --  record.
   --
   --  ``Repinfo_Collection_Data`` owns all related dynamically allocated
   --  records (all being internal): it is only when the last reference to a
   --  ``Repinfo_Collection_Data`` record disappears that all related dynamic
   --  allocations are free'd.
   --
   --  All these internal dynamically allocated records are presented to users
   --  as a kind of "fat pointer", containing both the pointer to these
   --  records, and a copy of the owning ``Repinfo_Collection``.
   --
   --  This design allows users not to worry about resources handling: as long
   --  as they get rid of their public values (``Repinfo_Collection``,
   --  ``Type_Representation``, ...), all the memory will be reclaimed, and it
   --  is not possible for them to get a dangling pointer. For the
   --  implementation, this means that all allocations are pooled in
   --  ``Repinfo_Collection_Data``, and no manual refcounting is necessary
   --  beyond what GNATCOLL.Refcount does for collections.

   type Integer_Access is access all GMP_Int.Big_Integer;
   type Rational_Access is access all GMP_RN.Rational;

   procedure Free is new Ada.Unchecked_Deallocation
     (GMP_Int.Big_Integer, Integer_Access);
   procedure Free is new Ada.Unchecked_Deallocation
     (GMP_RN.Rational, Rational_Access);

   package Integer_Vectors is new Langkit_Support.Vectors (Integer_Access);
   package Rational_Vectors is new Langkit_Support.Vectors (Rational_Access);

   type Numerical_Expression_Data;
   type Numerical_Expression_Access is access all Numerical_Expression_Data;

   type Type_Representation_Data;
   type Type_Representation_Access is access all Type_Representation_Data;

   type Component_Representation_Data;
   type Component_Representation_Access is
     access all Component_Representation_Data;

   type Variant_Representation_Data;
   type Variant_Representation_Access is
     access all Variant_Representation_Data;

   type Component_Representation_Access_Array is
     array (Positive range <>) of Component_Representation_Access;
   type Component_Representation_Access_Array_Access is
     access all Component_Representation_Access_Array;
   procedure Free is new Ada.Unchecked_Deallocation
     (Component_Representation_Access_Array,
      Component_Representation_Access_Array_Access);
   package Component_Repinfo_Array_Vectors is new Langkit_Support.Vectors
     (Component_Representation_Access_Array_Access);

   type Variant_Representation_Access_Array is
     array (Positive range <>) of Variant_Representation_Access;
   type Variant_Representation_Access_Array_Access is
     access all Variant_Representation_Access_Array;
   procedure Free is new Ada.Unchecked_Deallocation
     (Variant_Representation_Access_Array,
      Variant_Representation_Access_Array_Access);
   package Variant_Repinfo_Array_Vectors is new Langkit_Support.Vectors
     (Variant_Representation_Access_Array_Access);

   ------------------
   -- Data records --
   ------------------

   --  An expression is a tree of ``Expr_Node_Data``. Each node represents an
   --  operation, identified by its opcode, which determines the number of
   --  operands for that operation.

   type Opcode is (

      --  3 operands

      Cond_Expr,
      --  Condition (operand 1), then-expression (operand 2), else-expression
      --  (operand 3).

      --  2 operands

      Plus_Expr,
      Minus_Expr,
      Mult_Expr,
      Trunc_Div_Expr,
      Ceil_Div_Expr,
      Floor_Div_Expr,
      Trunc_Mod_Expr,
      Ceil_Mod_Expr,
      Floor_Mod_Expr,
      Exact_Div_Expr,
      Min_Expr,
      Max_Expr,
      Truth_And_Expr,
      Truth_Or_Expr,
      Truth_Xor_Expr,
      Lt_Expr,
      Le_Expr,
      Gt_Expr,
      Ge_Expr,
      Eq_Expr,
      Ne_Expr,
      Bit_And_Expr,

      --  1 operand

      Negate_Expr,
      Abs_Expr,
      Truth_Not_Expr,

      --  Misc

      Discrim_Val,
      Literal);
   --  Refer to "repinfo.ads" in GNAT for more information about opcodes

   subtype Opcode_3 is Opcode range Cond_Expr .. Cond_Expr;
   --  Opcodes which have 3 operands

   subtype Opcode_2 is Opcode range Opcode_3'First .. Bit_And_Expr;
   --  Opcodes which have at least 2 operands

   subtype Opcode_1 is Opcode range Opcode_3'First .. Truth_Not_Expr;
   --  Opcodes which have at least 1 operand

   type Expr_Node_Data;
   type Expr_Node_Access is access all Expr_Node_Data;
   type Expr_Node_Data (Code : Opcode := Opcode'First) is record
      case Code is
         when Opcode_1 =>
            Op_1 : Expr_Node_Access;

            case Code is
               when Opcode_2 =>
                  Op_2 : Expr_Node_Access;

                  case Code is
                     when Opcode_3 =>
                        Op_3 : Expr_Node_Access;
                     when others =>
                        null;
                  end case;

               when others =>
                  null;
            end case;

         when Discrim_Val =>
            Discriminant_Number : Positive;

         when Literal =>
            Value : Integer_Access;
      end case;
   end record;

   procedure Dump_Expr (Node : Expr_Node_Access);
   --  Debug helper: print a human-readable representation of the expression
   --  that ``Node`` represents.

   type Numerical_Expression_Data is record
      Discriminant_Count : Natural;
      --  Number of discriminant values required to evaluate this expression

      Root : Expr_Node_Access;
      --  Root expression node to evaluate
   end record;

   type Internal_Type_Kind is
     (Record_Type, Array_Type, Internal_Fixed_Type, Other_Type);
   subtype Internal_Composite_Type is
     Internal_Type_Kind range Record_Type ..  Array_Type;

   --  For all components in the record types below, please refer to the
   --  corresponding primitive functions for the documentation of their
   --  semantics.

   type Type_Representation_Data (Kind : Internal_Type_Kind) is record
      Alignment   : Positive;
      Object_Size : Numerical_Expression_Access;
      Value_Size  : Numerical_Expression_Access;

      case Kind is
         when Internal_Composite_Type =>
            Scalar_Storage_Order : System.Bit_Order;

            case Kind is
               when Record_Type =>
                  Discriminant_Count : Natural;
                  --  Number of components that are discriminants

                  Components : Component_Representation_Access_Array_Access;
                  Variants   : Variant_Representation_Access_Array_Access;
                  Bit_Order  : System.Bit_Order;

               when Array_Type =>
                  Component_Size : Numerical_Expression_Access;

               when others => null;
            end case;

         when Internal_Fixed_Type =>
            Small                   : Rational_Access;
            Range_First, Range_Last : Rational_Access;

         when others =>
            null;
      end case;
   end record;

   type Variant_Representation_Data is record
      Present     : Numerical_Expression_Access;
      Components  : Component_Representation_Access_Array_Access;
      Subvariants : Variant_Representation_Access_Array_Access;
   end record;

   type Component_Representation_Data is record
      Name : Symbol_Type;
      --  Name for this component

      Discriminant_Number : Natural;
      Position            : Numerical_Expression_Access;
      First_Bit           : Natural;
      Size                : Numerical_Expression_Access;
   end record;

   package Type_Representation_Maps is new Ada.Containers.Hashed_Maps
     (Key_Type        => Symbol_Type,
      Element_Type    => Type_Representation_Access,
      Hash            => Hash,
      Equivalent_Keys => "=");

   type Repinfo_Collection_Data is record
      Pool : Bump_Ptr_Pool;
      --  Pool in which all the plain records defined in this unit are
      --  allocated.

      Integers  : Integer_Vectors.Vector;
      Rationals : Rational_Vectors.Vector;
      --  List of all big integers/rationals allocated for this collection, to
      --  be free'd when the collection is finalized.

      Component_Repinfo_Arrays : Component_Repinfo_Array_Vectors.Vector;
      Variant_Repinfo_Arrays   : Variant_Repinfo_Array_Vectors.Vector;
      --  Likwise, for arrays of component/variant representation information

      Symbols : Symbol_Table;
      --  Symbol table, used to internalize all type names and component names

      Type_Representations : Type_Representation_Maps.Map;
      --  Mapping from lower case fully qualified type names to the
      --  corresponding type representations.
   end record;

   ---------------------
   -- Reference types --
   ---------------------

   type Numerical_Expression is record
      Collection : Repinfo_Collection;
      Data       : Numerical_Expression_Access;
   end record;

   type Type_Representation is record
      Collection : Repinfo_Collection;
      Data       : Type_Representation_Access;

      Declaration : Base_Type_Decl;
      --  Declaration for this type

      Kind : Type_Kind;
      --  Kind for this type, according to ``Declaration``

      --  Because of record extensions, the variant may belong to a base type.
      --  To avoid redundant computations in ``Has_Variant_Part`` and
      --  ``Variants``, pre-fetch variant part info from both the parse tree
      --  and its representation information when creating a
      --  ``Type_Representation`` object.

      Variant_Part_Node : Variant_Part;
      Variants          : Variant_Representation_Access_Array_Access;
   end record;

   type Variant_Representation is record
      Collection : Repinfo_Collection;
      Data       : Variant_Representation_Access;

      Declaration : Variant;
      --  Syntactic construct for this variant
   end record;

   type Component_Representation is record
      Collection : Repinfo_Collection;
      Data       : Component_Representation_Access;

      Declaration : Defining_Name;
      --  Declaration for this component
   end record;

   type Repinfo_Collection_Access is access all Repinfo_Collection_Data;

   procedure Release (Self : in out Repinfo_Collection_Data);

   package Collection_Refs is new GNATCOLL.Refcount.Shared_Pointers
     (Repinfo_Collection_Data, Release);
   type Repinfo_Collection is new Collection_Refs.Ref with null record;

   --------------------------
   -- Constant definitions --
   --------------------------

   No_Repinfo_Collection : constant Repinfo_Collection :=
     (Collection_Refs.Ref with null record);

   No_Numerical_Expression : constant Numerical_Expression :=
     (No_Repinfo_Collection, null);

   No_Type_Representation : constant Type_Representation :=
     (No_Repinfo_Collection,
      null,
      No_Base_Type_Decl,
      Type_Kind'First,
      No_Variant_Part,
      null);

   No_Variant_Representation : constant Variant_Representation :=
     (No_Repinfo_Collection, null, No_Variant);

   No_Component_Representation : constant Component_Representation :=
     (No_Repinfo_Collection, null, No_Defining_Name);

end Libadalang.Data_Decomposition;