OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [sem_dim.adb] - Blame information for rev 750

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                         GNAT COMPILER COMPONENTS                         --
4
--                                                                          --
5
--                              S E M _ D I M                               --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--          Copyright (C) 2011-2012, Free Software Foundation, Inc.         --
10
--                                                                          --
11
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17
-- for  more details.  You should have  received  a copy of the GNU General --
18
-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19
-- http://www.gnu.org/licenses for a complete copy of the license.          --
20
--                                                                          --
21
-- GNAT was originally developed  by the GNAT team at  New York University. --
22
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
23
--                                                                          --
24
------------------------------------------------------------------------------
25
 
26
with Aspects;  use Aspects;
27
with Atree;    use Atree;
28
with Einfo;    use Einfo;
29
with Errout;   use Errout;
30
with Lib;      use Lib;
31
with Namet;    use Namet;
32
with Nlists;   use Nlists;
33
with Nmake;    use Nmake;
34
with Opt;      use Opt;
35
with Rtsfind;  use Rtsfind;
36
with Sem;      use Sem;
37
with Sem_Eval; use Sem_Eval;
38
with Sem_Res;  use Sem_Res;
39
with Sinfo;    use Sinfo;
40
with Snames;   use Snames;
41
with Stand;    use Stand;
42
with Stringt;  use Stringt;
43
with Table;
44
with Tbuild;   use Tbuild;
45
with Uintp;    use Uintp;
46
with Urealp;   use Urealp;
47
 
48
with GNAT.HTable;
49
 
50
package body Sem_Dim is
51
 
52
   -------------------------
53
   -- Rational arithmetic --
54
   -------------------------
55
 
56
   type Whole is new Int;
57
   subtype Positive_Whole is Whole range 1 .. Whole'Last;
58
 
59
   type Rational is record
60
      Numerator   : Whole;
61
      Denominator : Positive_Whole;
62
   end record;
63
 
64
   Zero : constant Rational := Rational'(Numerator =>   0,
65
                                         Denominator => 1);
66
 
67
   No_Rational : constant Rational := Rational'(Numerator =>   0,
68
                                                Denominator => 2);
69
   --  Used to indicate an expression that cannot be interpreted as a rational
70
   --  Returned value of the Create_Rational_From routine when parameter Expr
71
   --  is not a static representation of a rational.
72
 
73
   --  Rational constructors
74
 
75
   function "+" (Right : Whole) return Rational;
76
   function GCD (Left, Right : Whole) return Int;
77
   function Reduce (X : Rational) return Rational;
78
 
79
   --  Unary operator for Rational
80
 
81
   function "-" (Right : Rational) return Rational;
82
   function "abs" (Right : Rational) return Rational;
83
 
84
   --  Rational operations for Rationals
85
 
86
   function "+" (Left, Right : Rational) return Rational;
87
   function "-" (Left, Right : Rational) return Rational;
88
   function "*" (Left, Right : Rational) return Rational;
89
   function "/" (Left, Right : Rational) return Rational;
90
 
91
   ------------------
92
   -- System types --
93
   ------------------
94
 
95
   Max_Number_Of_Dimensions : constant := 7;
96
   --  Maximum number of dimensions in a dimension system
97
 
98
   High_Position_Bound : constant := Max_Number_Of_Dimensions;
99
   Invalid_Position    : constant := 0;
100
   Low_Position_Bound  : constant := 1;
101
 
102
   subtype Dimension_Position is
103
     Nat range Invalid_Position .. High_Position_Bound;
104
 
105
   type Name_Array is
106
     array (Dimension_Position range
107
              Low_Position_Bound .. High_Position_Bound) of Name_Id;
108
   --  A data structure used to store the names of all units within a system
109
 
110
   No_Names : constant Name_Array := (others => No_Name);
111
 
112
   type Symbol_Array is
113
     array (Dimension_Position range
114
              Low_Position_Bound ..  High_Position_Bound) of String_Id;
115
   --  A data structure used to store the symbols of all units within a system
116
 
117
   No_Symbols : constant Symbol_Array := (others => No_String);
118
 
119
   type System_Type is record
120
      Type_Decl : Node_Id;
121
      Names     : Name_Array;
122
      Symbols   : Symbol_Array;
123
      Count     : Dimension_Position;
124
   end record;
125
 
126
   Null_System : constant System_Type :=
127
                   (Empty, No_Names, No_Symbols, Invalid_Position);
128
 
129
   subtype System_Id is Nat;
130
 
131
   --  The following table maps types to systems
132
 
133
   package System_Table is new Table.Table (
134
     Table_Component_Type => System_Type,
135
     Table_Index_Type     => System_Id,
136
     Table_Low_Bound      => 1,
137
     Table_Initial        => 5,
138
     Table_Increment      => 5,
139
     Table_Name           => "System_Table");
140
 
141
   --------------------
142
   -- Dimension type --
143
   --------------------
144
 
145
   type Dimension_Type is
146
     array (Dimension_Position range
147
              Low_Position_Bound ..  High_Position_Bound) of Rational;
148
 
149
   Null_Dimension : constant Dimension_Type := (others => Zero);
150
 
151
   type Dimension_Table_Range is range 0 .. 510;
152
   function Dimension_Table_Hash (Key : Node_Id) return Dimension_Table_Range;
153
 
154
   --  The following table associates nodes with dimensions
155
 
156
   package Dimension_Table is new
157
     GNAT.HTable.Simple_HTable
158
       (Header_Num => Dimension_Table_Range,
159
        Element    => Dimension_Type,
160
        No_Element => Null_Dimension,
161
        Key        => Node_Id,
162
        Hash       => Dimension_Table_Hash,
163
        Equal      => "=");
164
 
165
   ------------------
166
   -- Symbol types --
167
   ------------------
168
 
169
   type Symbol_Table_Range is range 0 .. 510;
170
   function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range;
171
 
172
   --  Each subtype with a dimension has a symbolic representation of the
173
   --  related unit. This table establishes a relation between the subtype
174
   --  and the symbol.
175
 
176
   package Symbol_Table is new
177
     GNAT.HTable.Simple_HTable
178
       (Header_Num => Symbol_Table_Range,
179
        Element    => String_Id,
180
        No_Element => No_String,
181
        Key        => Entity_Id,
182
        Hash       => Symbol_Table_Hash,
183
        Equal      => "=");
184
 
185
   --  The following array enumerates all contexts which may contain or
186
   --  produce a dimension.
187
 
188
   OK_For_Dimension : constant array (Node_Kind) of Boolean :=
189
     (N_Attribute_Reference       => True,
190
      N_Defining_Identifier       => True,
191
      N_Function_Call             => True,
192
      N_Identifier                => True,
193
      N_Indexed_Component         => True,
194
      N_Integer_Literal           => True,
195
      N_Op_Abs                    => True,
196
      N_Op_Add                    => True,
197
      N_Op_Divide                 => True,
198
      N_Op_Expon                  => True,
199
      N_Op_Minus                  => True,
200
      N_Op_Mod                    => True,
201
      N_Op_Multiply               => True,
202
      N_Op_Plus                   => True,
203
      N_Op_Rem                    => True,
204
      N_Op_Subtract               => True,
205
      N_Qualified_Expression      => True,
206
      N_Real_Literal              => True,
207
      N_Selected_Component        => True,
208
      N_Slice                     => True,
209
      N_Type_Conversion           => True,
210
      N_Unchecked_Type_Conversion => True,
211
 
212
      others                      => False);
213
 
214
   -----------------------
215
   -- Local Subprograms --
216
   -----------------------
217
 
218
   procedure Analyze_Dimension_Assignment_Statement (N : Node_Id);
219
   --  Subroutine of Analyze_Dimension for assignment statement. Check that the
220
   --  dimensions of the left-hand side and the right-hand side of N match.
221
 
222
   procedure Analyze_Dimension_Binary_Op (N : Node_Id);
223
   --  Subroutine of Analyze_Dimension for binary operators. Check the
224
   --  dimensions of the right and the left operand permit the operation.
225
   --  Then, evaluate the resulting dimensions for each binary operator.
226
 
227
   procedure Analyze_Dimension_Component_Declaration (N : Node_Id);
228
   --  Subroutine of Analyze_Dimension for component declaration. Check that
229
   --  the dimensions of the type of N and of the expression match.
230
 
231
   procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id);
232
   --  Subroutine of Analyze_Dimension for extended return statement. Check
233
   --  that the dimensions of the returned type and of the returned object
234
   --  match.
235
 
236
   procedure Analyze_Dimension_Function_Call (N : Node_Id);
237
   --  Subroutine of Analyze_Dimension for function call. General case:
238
   --  propagate the dimensions from the returned type to N. Elementary
239
   --  function case (Ada.Numerics.Generic_Elementary_Functions): If N
240
   --  is a Sqrt call, then evaluate the resulting dimensions as half the
241
   --  dimensions of the parameter. Otherwise, verify that each parameters
242
   --  are dimensionless.
243
 
244
   procedure Analyze_Dimension_Has_Etype (N : Node_Id);
245
   --  Subroutine of Analyze_Dimension for a subset of N_Has_Etype denoted by
246
   --  the list below:
247
   --    N_Attribute_Reference
248
   --    N_Identifier
249
   --    N_Indexed_Component
250
   --    N_Qualified_Expression
251
   --    N_Selected_Component
252
   --    N_Slice
253
   --    N_Type_Conversion
254
   --    N_Unchecked_Type_Conversion
255
 
256
   procedure Analyze_Dimension_Object_Declaration (N : Node_Id);
257
   --  Subroutine of Analyze_Dimension for object declaration. Check that
258
   --  the dimensions of the object type and the dimensions of the expression
259
   --  (if expression is present) match. Note that when the expression is
260
   --  a literal, no error is returned. This special case allows object
261
   --  declaration such as: m : constant Length := 1.0;
262
 
263
   procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id);
264
   --  Subroutine of Analyze_Dimension for object renaming declaration. Check
265
   --  the dimensions of the type and of the renamed object name of N match.
266
 
267
   procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id);
268
   --  Subroutine of Analyze_Dimension for simple return statement
269
   --  Check that the dimensions of the returned type and of the returned
270
   --  expression match.
271
 
272
   procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id);
273
   --  Subroutine of Analyze_Dimension for subtype declaration. Propagate the
274
   --  dimensions from the parent type to the identifier of N. Note that if
275
   --  both the identifier and the parent type of N are not dimensionless,
276
   --  return an error.
277
 
278
   procedure Analyze_Dimension_Unary_Op (N : Node_Id);
279
   --  Subroutine of Analyze_Dimension for unary operators. For Plus, Minus and
280
   --  Abs operators, propagate the dimensions from the operand to N.
281
 
282
   function Create_Rational_From
283
     (Expr     : Node_Id;
284
      Complain : Boolean) return Rational;
285
   --  Given an arbitrary expression Expr, return a valid rational if Expr can
286
   --  be interpreted as a rational. Otherwise return No_Rational and also an
287
   --  error message if Complain is set to True.
288
 
289
   function Dimensions_Of (N : Node_Id) return Dimension_Type;
290
   --  Return the dimension vector of node N
291
 
292
   function Dimensions_Msg_Of (N : Node_Id) return String;
293
   --  Given a node, return "has dimension" followed by the dimension vector of
294
   --  N or "is dimensionless" if N is dimensionless.
295
 
296
   procedure Eval_Op_Expon_With_Rational_Exponent
297
     (N              : Node_Id;
298
      Exponent_Value : Rational);
299
   --  Evaluate the exponent it is a rational and the operand has a dimension
300
 
301
   function Exists (Dim : Dimension_Type) return Boolean;
302
   --  Returns True iff Dim does not denote the null dimension
303
 
304
   function Exists (Sys : System_Type) return Boolean;
305
   --  Returns True iff Sys does not denote the null system
306
 
307
   function From_Dimension_To_String_Of_Symbols
308
     (Dims   : Dimension_Type;
309
      System : System_Type) return String_Id;
310
   --  Given a dimension vector and a dimension system, return the proper
311
   --  string of symbols.
312
 
313
   function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean;
314
   --  Return True if E is the package entity of System.Dim.Float_IO or
315
   --  System.Dim.Integer_IO.
316
 
317
   function Is_Invalid (Position : Dimension_Position) return Boolean;
318
   --  Return True if Pos denotes the invalid position
319
 
320
   procedure Move_Dimensions (From : Node_Id; To : Node_Id);
321
   --  Copy dimension vector of From to To, delete dimension vector of From
322
 
323
   procedure Remove_Dimensions (N : Node_Id);
324
   --  Remove the dimension vector of node N
325
 
326
   procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type);
327
   --  Associate a dimension vector with a node
328
 
329
   procedure Set_Symbol (E : Entity_Id; Val : String_Id);
330
   --  Associate a symbol representation of a dimension vector with a subtype
331
 
332
   function Symbol_Of (E : Entity_Id) return String_Id;
333
   --  E denotes a subtype with a dimension. Return the symbol representation
334
   --  of the dimension vector.
335
 
336
   function System_Of (E : Entity_Id) return System_Type;
337
   --  E denotes a type, return associated system of the type if it has one
338
 
339
   ---------
340
   -- "+" --
341
   ---------
342
 
343
   function "+" (Right : Whole) return Rational is
344
   begin
345
      return Rational'(Numerator =>   Right,
346
                       Denominator => 1);
347
   end "+";
348
 
349
   function "+" (Left, Right : Rational) return Rational is
350
      R : constant Rational :=
351
            Rational'(Numerator =>   Left.Numerator * Right.Denominator +
352
                                       Left.Denominator * Right.Numerator,
353
                      Denominator => Left.Denominator * Right.Denominator);
354
   begin
355
      return Reduce (R);
356
   end "+";
357
 
358
   ---------
359
   -- "-" --
360
   ---------
361
 
362
   function "-" (Right : Rational) return Rational is
363
   begin
364
      return Rational'(Numerator =>   -Right.Numerator,
365
                       Denominator => Right.Denominator);
366
   end "-";
367
 
368
   function "-" (Left, Right : Rational) return Rational is
369
      R : constant Rational :=
370
            Rational'(Numerator =>   Left.Numerator * Right.Denominator -
371
                                       Left.Denominator * Right.Numerator,
372
                      Denominator => Left.Denominator * Right.Denominator);
373
 
374
   begin
375
      return Reduce (R);
376
   end "-";
377
 
378
   ---------
379
   -- "*" --
380
   ---------
381
 
382
   function "*" (Left, Right : Rational) return Rational is
383
      R : constant Rational :=
384
            Rational'(Numerator =>   Left.Numerator * Right.Numerator,
385
                      Denominator => Left.Denominator * Right.Denominator);
386
   begin
387
      return Reduce (R);
388
   end "*";
389
 
390
   ---------
391
   -- "/" --
392
   ---------
393
 
394
   function "/" (Left, Right : Rational) return Rational is
395
      R : constant Rational := abs Right;
396
      L : Rational := Left;
397
 
398
   begin
399
      if Right.Numerator < 0 then
400
         L.Numerator := Whole (-Integer (L.Numerator));
401
      end if;
402
 
403
      return Reduce (Rational'(Numerator =>   L.Numerator * R.Denominator,
404
                               Denominator => L.Denominator * R.Numerator));
405
   end "/";
406
   -----------
407
   -- "abs" --
408
   -----------
409
 
410
   function "abs" (Right : Rational) return Rational is
411
   begin
412
      return Rational'(Numerator =>   abs Right.Numerator,
413
                       Denominator => Right.Denominator);
414
   end "abs";
415
 
416
   ------------------------------
417
   -- Analyze_Aspect_Dimension --
418
   ------------------------------
419
 
420
   --  with Dimension => DIMENSION_FOR_SUBTYPE
421
   --  DIMENSION_FOR_SUBTYPE ::= (DIMENSION_STRING, DIMENSION_RATIONALS)
422
   --  DIMENSION_RATIONALS ::=
423
   --    RATIONAL,  {, RATIONAL}
424
   --  | RATIONAL {, RATIONAL}, others => RATIONAL
425
   --  | DISCRETE_CHOICE_LIST => RATIONAL
426
   --  RATIONAL ::= [-] NUMERAL [/ NUMERAL]
427
 
428
   --  (see Analyze_Aspect_Dimension_System for DIMENSION_STRING grammar)
429
 
430
   procedure Analyze_Aspect_Dimension
431
     (N    : Node_Id;
432
      Id   : Entity_Id;
433
      Aggr : Node_Id)
434
   is
435
      Def_Id    : constant Entity_Id := Defining_Identifier (N);
436
 
437
      Processed : array (Dimension_Type'Range) of Boolean := (others => False);
438
      --  This array is used when processing ranges or Others_Choice as part of
439
      --  the dimension aggregate.
440
 
441
      Dimensions : Dimension_Type := Null_Dimension;
442
 
443
      procedure Extract_Power
444
        (Expr     : Node_Id;
445
         Position : Dimension_Position);
446
      --  Given an expression with denotes a rational number, read the number
447
      --  and associate it with Position in Dimensions.
448
 
449
      function Has_Compile_Time_Known_Expressions
450
        (Aggr : Node_Id) return Boolean;
451
      --  Determine whether aggregate Aggr contains only expressions that are
452
      --  known at compile time.
453
 
454
      function Position_In_System
455
        (Id     : Node_Id;
456
         System : System_Type) return Dimension_Position;
457
      --  Given an identifier which denotes a dimension, return the position of
458
      --  that dimension within System.
459
 
460
      -------------------
461
      -- Extract_Power --
462
      -------------------
463
 
464
      procedure Extract_Power
465
        (Expr     : Node_Id;
466
         Position : Dimension_Position)
467
      is
468
      begin
469
         if Is_Integer_Type (Def_Id) then
470
            Dimensions (Position) := +Whole (UI_To_Int (Expr_Value (Expr)));
471
         else
472
            Dimensions (Position) := Create_Rational_From (Expr, True);
473
         end if;
474
 
475
         Processed (Position) := True;
476
      end Extract_Power;
477
 
478
      ----------------------------------------
479
      -- Has_Compile_Time_Known_Expressions --
480
      ----------------------------------------
481
 
482
      function Has_Compile_Time_Known_Expressions
483
        (Aggr : Node_Id) return Boolean
484
      is
485
         Comp : Node_Id;
486
         Expr : Node_Id;
487
 
488
      begin
489
         Expr := First (Expressions (Aggr));
490
         if Present (Expr) then
491
 
492
            --  The first expression within the aggregate describes the
493
            --  symbolic name of a dimension, skip it.
494
 
495
            Next (Expr);
496
            while Present (Expr) loop
497
               Analyze_And_Resolve (Expr);
498
 
499
               if not Compile_Time_Known_Value (Expr) then
500
                  return False;
501
               end if;
502
 
503
               Next (Expr);
504
            end loop;
505
         end if;
506
 
507
         Comp := First (Component_Associations (Aggr));
508
         while Present (Comp) loop
509
            Expr := Expression (Comp);
510
 
511
            Analyze_And_Resolve (Expr);
512
 
513
            if not Compile_Time_Known_Value (Expr) then
514
               return False;
515
            end if;
516
 
517
            Next (Comp);
518
         end loop;
519
 
520
         return True;
521
      end Has_Compile_Time_Known_Expressions;
522
 
523
      ------------------------
524
      -- Position_In_System --
525
      ------------------------
526
 
527
      function Position_In_System
528
        (Id     : Node_Id;
529
         System : System_Type) return Dimension_Position
530
      is
531
         Dimension_Name : constant Name_Id := Chars (Id);
532
 
533
      begin
534
         for Position in System.Names'Range loop
535
            if Dimension_Name = System.Names (Position) then
536
               return Position;
537
            end if;
538
         end loop;
539
 
540
         return Invalid_Position;
541
      end Position_In_System;
542
 
543
      --  Local variables
544
 
545
      Assoc          : Node_Id;
546
      Choice         : Node_Id;
547
      Expr           : Node_Id;
548
      Num_Choices    : Nat := 0;
549
      Num_Dimensions : Nat := 0;
550
      Others_Seen    : Boolean := False;
551
      Position       : Nat := 0;
552
      Sub_Ind        : Node_Id;
553
      Symbol         : String_Id;
554
      Symbol_Decl    : Node_Id;
555
      System         : System_Type;
556
      Typ            : Entity_Id;
557
 
558
      Errors_Count : Nat;
559
      --  Errors_Count is a count of errors detected by the compiler so far
560
      --  just before the extraction of names and values in the aggregate
561
      --  (Step 3).
562
      --
563
      --  At the end of the analysis, there is a check to verify that this
564
      --  count equals to Serious_Errors_Detected i.e. no erros have been
565
      --  encountered during the process. Otherwise the Dimension_Table is
566
      --  not filled.
567
 
568
   --  Start of processing for Analyze_Aspect_Dimension
569
 
570
   begin
571
      --  STEP 1: Legality of aspect
572
 
573
      if Nkind (N) /= N_Subtype_Declaration then
574
         Error_Msg_NE ("aspect& must apply to subtype declaration", N, Id);
575
         return;
576
      end if;
577
 
578
      Sub_Ind := Subtype_Indication (N);
579
      Typ := Etype (Sub_Ind);
580
      System := System_Of (Typ);
581
 
582
      if Nkind (Sub_Ind) = N_Subtype_Indication then
583
         Error_Msg_NE
584
           ("constraint not allowed with aspect&", Constraint (Sub_Ind), Id);
585
         return;
586
      end if;
587
 
588
      if Nkind (Aggr) /= N_Aggregate then
589
         Error_Msg_N ("aggregate expected", Aggr);
590
         return;
591
      end if;
592
 
593
      --  Each expression in dimension aggregate must be known at compile time
594
 
595
      if not Has_Compile_Time_Known_Expressions (Aggr) then
596
         Error_Msg_N ("values of aggregate must be static", Aggr);
597
         return;
598
      end if;
599
 
600
      --  The dimension declarations are useless if the parent type does not
601
      --  declare a valid system.
602
 
603
      if not Exists (System) then
604
         Error_Msg_NE
605
           ("parent type of& lacks dimension system", Sub_Ind, Def_Id);
606
         return;
607
      end if;
608
 
609
      --  STEP 2: Structural verification of the dimension aggregate
610
 
611
      --  The first entry in the aggregate is the symbolic representation of
612
      --  the dimension.
613
 
614
      Symbol_Decl := First (Expressions (Aggr));
615
 
616
      if No (Symbol_Decl)
617
        or else not Nkind_In (Symbol_Decl, N_Character_Literal,
618
                                           N_String_Literal)
619
      then
620
         Error_Msg_N ("first argument must be character or string", Aggr);
621
         return;
622
      end if;
623
 
624
      --  STEP 3: Name and value extraction
625
 
626
      --  Get the number of errors detected by the compiler so far
627
 
628
      Errors_Count := Serious_Errors_Detected;
629
 
630
      --  Positional elements
631
 
632
      Expr := Next (Symbol_Decl);
633
      Position := Low_Position_Bound;
634
      while Present (Expr) loop
635
         if Position > High_Position_Bound then
636
            Error_Msg_N
637
              ("type& has more dimensions than system allows", Def_Id);
638
            exit;
639
         end if;
640
 
641
         Extract_Power (Expr, Position);
642
 
643
         Position := Position + 1;
644
         Num_Dimensions := Num_Dimensions + 1;
645
 
646
         Next (Expr);
647
      end loop;
648
 
649
      --  Named elements
650
 
651
      Assoc := First (Component_Associations (Aggr));
652
      while Present (Assoc) loop
653
         Expr   := Expression (Assoc);
654
         Choice := First (Choices (Assoc));
655
         while Present (Choice) loop
656
 
657
            --  Identifier case: NAME => EXPRESSION
658
 
659
            if Nkind (Choice) = N_Identifier then
660
               Position := Position_In_System (Choice, System);
661
 
662
               if Is_Invalid (Position) then
663
                  Error_Msg_N ("dimension name& not part of system", Choice);
664
               else
665
                  Extract_Power (Expr, Position);
666
               end if;
667
 
668
            --  Range case: NAME .. NAME => EXPRESSION
669
 
670
            elsif Nkind (Choice) = N_Range then
671
               declare
672
                  Low      : constant Node_Id := Low_Bound (Choice);
673
                  High     : constant Node_Id := High_Bound (Choice);
674
                  Low_Pos  : Dimension_Position;
675
                  High_Pos : Dimension_Position;
676
 
677
               begin
678
                  if Nkind (Low) /= N_Identifier then
679
                     Error_Msg_N ("bound must denote a dimension name", Low);
680
 
681
                  elsif Nkind (High) /= N_Identifier then
682
                     Error_Msg_N ("bound must denote a dimension name", High);
683
 
684
                  else
685
                     Low_Pos  := Position_In_System (Low, System);
686
                     High_Pos := Position_In_System (High, System);
687
 
688
                     if Is_Invalid (Low_Pos) then
689
                        Error_Msg_N ("dimension name& not part of system",
690
                                     Low);
691
 
692
                     elsif Is_Invalid (High_Pos) then
693
                        Error_Msg_N ("dimension name& not part of system",
694
                                     High);
695
 
696
                     elsif Low_Pos > High_Pos then
697
                        Error_Msg_N ("expected low to high range", Choice);
698
 
699
                     else
700
                        for Position in Low_Pos .. High_Pos loop
701
                           Extract_Power (Expr, Position);
702
                        end loop;
703
                     end if;
704
                  end if;
705
               end;
706
 
707
            --  Others case: OTHERS => EXPRESSION
708
 
709
            elsif Nkind (Choice) = N_Others_Choice then
710
               if Present (Next (Choice))
711
                 or else Present (Prev (Choice))
712
               then
713
                  Error_Msg_N
714
                    ("OTHERS must appear alone in a choice list", Choice);
715
 
716
               elsif Present (Next (Assoc)) then
717
                  Error_Msg_N
718
                    ("OTHERS must appear last in an aggregate", Choice);
719
 
720
               elsif Others_Seen then
721
                  Error_Msg_N ("multiple OTHERS not allowed", Choice);
722
 
723
               else
724
                  --  Fill the non-processed dimensions with the default value
725
                  --  supplied by others.
726
 
727
                  for Position in Processed'Range loop
728
                     if not Processed (Position) then
729
                        Extract_Power (Expr, Position);
730
                     end if;
731
                  end loop;
732
               end if;
733
 
734
               Others_Seen := True;
735
 
736
            --  All other cases are erroneous declarations of dimension names
737
 
738
            else
739
               Error_Msg_NE ("wrong syntax for aspect&", Choice, Id);
740
            end if;
741
 
742
            Num_Choices := Num_Choices + 1;
743
            Next (Choice);
744
         end loop;
745
 
746
         Num_Dimensions := Num_Dimensions + 1;
747
         Next (Assoc);
748
      end loop;
749
 
750
      --  STEP 4: Consistency of system and dimensions
751
 
752
      if Present (Next (Symbol_Decl))
753
        and then (Num_Choices > 1
754
                   or else (Num_Choices = 1 and then not Others_Seen))
755
      then
756
         Error_Msg_N
757
           ("named associations cannot follow positional associations", Aggr);
758
 
759
      elsif Num_Dimensions > System.Count then
760
         Error_Msg_N ("type& has more dimensions than system allows", Def_Id);
761
 
762
      elsif Num_Dimensions < System.Count and then not Others_Seen then
763
         Error_Msg_N ("type& has less dimensions than system allows", Def_Id);
764
      end if;
765
 
766
      --  STEP 5: Dimension symbol extraction
767
 
768
      if Nkind (Symbol_Decl) = N_Character_Literal then
769
         Start_String;
770
         Store_String_Char (UI_To_CC (Char_Literal_Value (Symbol_Decl)));
771
         Symbol := End_String;
772
 
773
      else
774
         Symbol := Strval (Symbol_Decl);
775
      end if;
776
 
777
      if String_Length (Symbol) = 0 and then not Exists (Dimensions) then
778
         Error_Msg_N ("useless dimension declaration", Aggr);
779
      end if;
780
 
781
      --  STEP 6: Storage of extracted values
782
 
783
      --  Check that no errors have been detected during the analysis
784
 
785
      if Errors_Count = Serious_Errors_Detected then
786
         if String_Length (Symbol) /= 0 then
787
            Set_Symbol (Def_Id, Symbol);
788
         end if;
789
 
790
         if Exists (Dimensions) then
791
            Set_Dimensions (Def_Id, Dimensions);
792
         end if;
793
      end if;
794
   end Analyze_Aspect_Dimension;
795
 
796
   -------------------------------------
797
   -- Analyze_Aspect_Dimension_System --
798
   -------------------------------------
799
 
800
   --  with Dimension_System => DIMENSION_PAIRS
801
 
802
   --  DIMENSION_PAIRS ::=
803
   --    (DIMENSION_PAIR
804
   --      [, DIMENSION_PAIR]
805
   --      [, DIMENSION_PAIR]
806
   --      [, DIMENSION_PAIR]
807
   --      [, DIMENSION_PAIR]
808
   --      [, DIMENSION_PAIR]
809
   --      [, DIMENSION_PAIR])
810
   --  DIMENSION_PAIR ::= (DIMENSION_IDENTIFIER, DIMENSION_STRING)
811
   --  DIMENSION_IDENTIFIER ::= IDENTIFIER
812
   --  DIMENSION_STRING ::= STRING_LITERAL | CHARACTER_LITERAL
813
 
814
   procedure Analyze_Aspect_Dimension_System
815
     (N    : Node_Id;
816
      Id   : Entity_Id;
817
      Aggr : Node_Id)
818
   is
819
      function Is_Derived_Numeric_Type (N : Node_Id) return Boolean;
820
      --  Determine whether type declaration N denotes a numeric derived type
821
 
822
      -------------------------------
823
      -- Is_Derived_Numeric_Type --
824
      -------------------------------
825
 
826
      function Is_Derived_Numeric_Type (N : Node_Id) return Boolean is
827
      begin
828
         return
829
           Nkind (N) = N_Full_Type_Declaration
830
             and then Nkind (Type_Definition (N)) = N_Derived_Type_Definition
831
             and then Is_Numeric_Type
832
                        (Entity (Subtype_Indication (Type_Definition (N))));
833
      end Is_Derived_Numeric_Type;
834
 
835
      --  Local variables
836
 
837
      Dim_Name     : Node_Id;
838
      Dim_Pair     : Node_Id;
839
      Dim_Symbol   : Node_Id;
840
      Dim_System   : System_Type  := Null_System;
841
      Names        : Name_Array   := No_Names;
842
      Position     : Nat := 0;
843
      Symbols      : Symbol_Array := No_Symbols;
844
 
845
      Errors_Count : Nat;
846
      --  Errors_Count is a count of errors detected by the compiler so far
847
      --  just before the extraction of names and symbols in the aggregate
848
      --  (Step 3).
849
      --
850
      --  At the end of the analysis, there is a check to verify that this
851
      --  count equals Serious_Errors_Detected i.e. no errors have been
852
      --  encountered during the process. Otherwise the System_Table is
853
      --  not filled.
854
 
855
   --  Start of processing for Analyze_Aspect_Dimension_System
856
 
857
   begin
858
      --  STEP 1: Legality of aspect
859
 
860
      if not Is_Derived_Numeric_Type (N) then
861
         Error_Msg_NE
862
           ("aspect& must apply to numeric derived type declaration", N, Id);
863
         return;
864
      end if;
865
 
866
      if Nkind (Aggr) /= N_Aggregate then
867
         Error_Msg_N ("aggregate expected", Aggr);
868
         return;
869
      end if;
870
 
871
      --  STEP 2: Structural verification of the dimension aggregate
872
 
873
      if Present (Component_Associations (Aggr)) then
874
         Error_Msg_N ("expected positional aggregate", Aggr);
875
         return;
876
      end if;
877
 
878
      --  STEP 3: Name and Symbol extraction
879
 
880
      Dim_Pair     := First (Expressions (Aggr));
881
      Errors_Count := Serious_Errors_Detected;
882
      while Present (Dim_Pair) loop
883
         Position := Position + 1;
884
 
885
         if Position > High_Position_Bound then
886
            Error_Msg_N
887
              ("too many dimensions in system", Aggr);
888
            exit;
889
         end if;
890
 
891
         if Nkind (Dim_Pair) /= N_Aggregate then
892
            Error_Msg_N ("aggregate expected", Dim_Pair);
893
 
894
         else
895
            if Present (Component_Associations (Dim_Pair)) then
896
               Error_Msg_N ("expected positional aggregate", Dim_Pair);
897
 
898
            else
899
               if List_Length (Expressions (Dim_Pair)) = 2 then
900
                  Dim_Name := First (Expressions (Dim_Pair));
901
                  Dim_Symbol := Next (Dim_Name);
902
 
903
                  --  Check the first argument for each pair is a name
904
 
905
                  if Nkind (Dim_Name) = N_Identifier then
906
                     Names (Position) := Chars (Dim_Name);
907
                  else
908
                     Error_Msg_N ("expected dimension name", Dim_Name);
909
                  end if;
910
 
911
                  --  Check the second argument for each pair is a string or a
912
                  --  character.
913
 
914
                  if not Nkind_In
915
                           (Dim_Symbol,
916
                              N_String_Literal,
917
                              N_Character_Literal)
918
                  then
919
                     Error_Msg_N ("expected dimension string or character",
920
                                  Dim_Symbol);
921
 
922
                  else
923
                     --  String case
924
 
925
                     if Nkind (Dim_Symbol) = N_String_Literal then
926
                        Symbols (Position) := Strval (Dim_Symbol);
927
 
928
                     --  Character case
929
 
930
                     else
931
                        Start_String;
932
                        Store_String_Char
933
                          (UI_To_CC (Char_Literal_Value (Dim_Symbol)));
934
                        Symbols (Position) := End_String;
935
                     end if;
936
 
937
                     --  Verify that the string is not empty
938
 
939
                     if String_Length (Symbols (Position)) = 0 then
940
                        Error_Msg_N
941
                          ("empty string not allowed here", Dim_Symbol);
942
                     end if;
943
                  end if;
944
 
945
               else
946
                  Error_Msg_N
947
                    ("two expressions expected in aggregate", Dim_Pair);
948
               end if;
949
            end if;
950
         end if;
951
 
952
         Next (Dim_Pair);
953
      end loop;
954
 
955
      --  STEP 4: Storage of extracted values
956
 
957
      --  Check that no errors have been detected during the analysis
958
 
959
      if Errors_Count = Serious_Errors_Detected then
960
         Dim_System.Type_Decl := N;
961
         Dim_System.Names := Names;
962
         Dim_System.Count := Position;
963
         Dim_System.Symbols := Symbols;
964
         System_Table.Append (Dim_System);
965
      end if;
966
   end Analyze_Aspect_Dimension_System;
967
 
968
   -----------------------
969
   -- Analyze_Dimension --
970
   -----------------------
971
 
972
   --  This dispatch routine propagates dimensions for each node
973
 
974
   procedure Analyze_Dimension (N : Node_Id) is
975
   begin
976
      --  Aspect is an Ada 2012 feature
977
 
978
      if Ada_Version < Ada_2012 then
979
         return;
980
      end if;
981
 
982
      case Nkind (N) is
983
 
984
         when N_Assignment_Statement =>
985
            Analyze_Dimension_Assignment_Statement (N);
986
 
987
         when N_Binary_Op =>
988
            Analyze_Dimension_Binary_Op (N);
989
 
990
         when N_Component_Declaration =>
991
            Analyze_Dimension_Component_Declaration (N);
992
 
993
         when N_Extended_Return_Statement =>
994
            Analyze_Dimension_Extended_Return_Statement (N);
995
 
996
         when N_Function_Call =>
997
            Analyze_Dimension_Function_Call (N);
998
 
999
         when N_Attribute_Reference       |
1000
              N_Identifier                |
1001
              N_Indexed_Component         |
1002
              N_Qualified_Expression      |
1003
              N_Selected_Component        |
1004
              N_Slice                     |
1005
              N_Type_Conversion           |
1006
              N_Unchecked_Type_Conversion =>
1007
            Analyze_Dimension_Has_Etype (N);
1008
 
1009
         when N_Object_Declaration =>
1010
            Analyze_Dimension_Object_Declaration (N);
1011
 
1012
         when N_Object_Renaming_Declaration =>
1013
            Analyze_Dimension_Object_Renaming_Declaration (N);
1014
 
1015
         when N_Simple_Return_Statement =>
1016
            if not Comes_From_Extended_Return_Statement (N) then
1017
               Analyze_Dimension_Simple_Return_Statement (N);
1018
            end if;
1019
 
1020
         when N_Subtype_Declaration =>
1021
            Analyze_Dimension_Subtype_Declaration (N);
1022
 
1023
         when N_Unary_Op =>
1024
            Analyze_Dimension_Unary_Op (N);
1025
 
1026
         when others => null;
1027
 
1028
      end case;
1029
   end Analyze_Dimension;
1030
 
1031
   --------------------------------------------
1032
   -- Analyze_Dimension_Assignment_Statement --
1033
   --------------------------------------------
1034
 
1035
   procedure Analyze_Dimension_Assignment_Statement (N : Node_Id) is
1036
      Lhs         : constant Node_Id := Name (N);
1037
      Dims_Of_Lhs : constant Dimension_Type := Dimensions_Of (Lhs);
1038
      Rhs         : constant Node_Id := Expression (N);
1039
      Dims_Of_Rhs : constant Dimension_Type := Dimensions_Of (Rhs);
1040
 
1041
      procedure Error_Dim_Msg_For_Assignment_Statement
1042
        (N   : Node_Id;
1043
         Lhs : Node_Id;
1044
         Rhs : Node_Id);
1045
      --  Error using Error_Msg_N at node N. Output the dimensions of left
1046
      --  and right hand sides.
1047
 
1048
      --------------------------------------------
1049
      -- Error_Dim_Msg_For_Assignment_Statement --
1050
      --------------------------------------------
1051
 
1052
      procedure Error_Dim_Msg_For_Assignment_Statement
1053
        (N   : Node_Id;
1054
         Lhs : Node_Id;
1055
         Rhs : Node_Id)
1056
      is
1057
      begin
1058
         Error_Msg_N ("dimensions mismatch in assignment", N);
1059
         Error_Msg_N ("\left-hand side " & Dimensions_Msg_Of (Lhs), N);
1060
         Error_Msg_N ("\right-hand side " & Dimensions_Msg_Of (Rhs), N);
1061
      end Error_Dim_Msg_For_Assignment_Statement;
1062
 
1063
   --  Start of processing for Analyze_Dimension_Assignment
1064
 
1065
   begin
1066
      if Dims_Of_Lhs /= Dims_Of_Rhs then
1067
         Error_Dim_Msg_For_Assignment_Statement (N, Lhs, Rhs);
1068
      end if;
1069
   end Analyze_Dimension_Assignment_Statement;
1070
 
1071
   ---------------------------------
1072
   -- Analyze_Dimension_Binary_Op --
1073
   ---------------------------------
1074
 
1075
   --  Check and propagate the dimensions for binary operators
1076
   --  Note that when the dimensions mismatch, no dimension is propagated to N.
1077
 
1078
   procedure Analyze_Dimension_Binary_Op (N : Node_Id) is
1079
      N_Kind : constant Node_Kind := Nkind (N);
1080
 
1081
      procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id);
1082
      --  Error using Error_Msg_NE and Error_Msg_N at node N. Output the
1083
      --  dimensions of both operands.
1084
 
1085
      ---------------------------------
1086
      -- Error_Dim_Msg_For_Binary_Op --
1087
      ---------------------------------
1088
 
1089
      procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id) is
1090
      begin
1091
         Error_Msg_NE ("both operands for operation& must have same " &
1092
                       "dimensions",
1093
                       N,
1094
                       Entity (N));
1095
         Error_Msg_N ("\left operand " & Dimensions_Msg_Of (L), N);
1096
         Error_Msg_N ("\right operand " & Dimensions_Msg_Of (R), N);
1097
      end Error_Dim_Msg_For_Binary_Op;
1098
 
1099
   --  Start of processing for Analyze_Dimension_Binary_Op
1100
 
1101
   begin
1102
      if Nkind_In (N_Kind, N_Op_Add, N_Op_Expon, N_Op_Subtract)
1103
        or else N_Kind in N_Multiplying_Operator
1104
        or else N_Kind in N_Op_Compare
1105
      then
1106
         declare
1107
            L                : constant Node_Id := Left_Opnd (N);
1108
            Dims_Of_L        : constant Dimension_Type := Dimensions_Of (L);
1109
            L_Has_Dimensions : constant Boolean := Exists (Dims_Of_L);
1110
            R                : constant Node_Id := Right_Opnd (N);
1111
            Dims_Of_R        : constant Dimension_Type := Dimensions_Of (R);
1112
            R_Has_Dimensions : constant Boolean := Exists (Dims_Of_R);
1113
            Dims_Of_N        : Dimension_Type := Null_Dimension;
1114
 
1115
         begin
1116
            --  N_Op_Add, N_Op_Mod, N_Op_Rem or N_Op_Subtract case
1117
 
1118
            if Nkind_In (N, N_Op_Add, N_Op_Mod, N_Op_Rem, N_Op_Subtract) then
1119
 
1120
               --  Check both operands have same dimension
1121
 
1122
               if Dims_Of_L /= Dims_Of_R then
1123
                  Error_Dim_Msg_For_Binary_Op (N, L, R);
1124
               else
1125
                  --  Check both operands are not dimensionless
1126
 
1127
                  if Exists (Dims_Of_L) then
1128
                     Set_Dimensions (N, Dims_Of_L);
1129
                  end if;
1130
               end if;
1131
 
1132
            --  N_Op_Multiply or N_Op_Divide case
1133
 
1134
            elsif Nkind_In (N_Kind, N_Op_Multiply, N_Op_Divide) then
1135
 
1136
               --  Check at least one operand is not dimensionless
1137
 
1138
               if L_Has_Dimensions or R_Has_Dimensions then
1139
 
1140
                  --  Multiplication case
1141
 
1142
                  --  Get both operands dimensions and add them
1143
 
1144
                  if N_Kind = N_Op_Multiply then
1145
                     for Position in Dimension_Type'Range loop
1146
                        Dims_Of_N (Position) :=
1147
                          Dims_Of_L (Position) + Dims_Of_R (Position);
1148
                     end loop;
1149
 
1150
                  --  Division case
1151
 
1152
                  --  Get both operands dimensions and subtract them
1153
 
1154
                  else
1155
                     for Position in Dimension_Type'Range loop
1156
                        Dims_Of_N (Position) :=
1157
                          Dims_Of_L (Position) - Dims_Of_R (Position);
1158
                     end loop;
1159
                  end if;
1160
 
1161
                  if Exists (Dims_Of_N) then
1162
                     Set_Dimensions (N, Dims_Of_N);
1163
                  end if;
1164
               end if;
1165
 
1166
            --  Exponentiation case
1167
 
1168
            --  Note: a rational exponent is allowed for dimensioned operand
1169
 
1170
            elsif N_Kind = N_Op_Expon then
1171
 
1172
               --  Check the left operand is not dimensionless. Note that the
1173
               --  value of the exponent must be known compile time. Otherwise,
1174
               --  the exponentiation evaluation will return an error message.
1175
 
1176
               if L_Has_Dimensions
1177
                 and then Compile_Time_Known_Value (R)
1178
               then
1179
                  declare
1180
                     Exponent_Value : Rational := Zero;
1181
 
1182
                  begin
1183
                     --  Real operand case
1184
 
1185
                     if Is_Real_Type (Etype (L)) then
1186
 
1187
                        --  Define the exponent as a Rational number
1188
 
1189
                        Exponent_Value := Create_Rational_From (R, False);
1190
 
1191
                        --  Verify that the exponent cannot be interpreted
1192
                        --  as a rational, otherwise interpret the exponent
1193
                        --  as an integer.
1194
 
1195
                        if Exponent_Value = No_Rational then
1196
                           Exponent_Value :=
1197
                             +Whole (UI_To_Int (Expr_Value (R)));
1198
                        end if;
1199
 
1200
                     --  Integer operand case.
1201
 
1202
                     --  For integer operand, the exponent cannot be
1203
                     --  interpreted as a rational.
1204
 
1205
                     else
1206
                        Exponent_Value := +Whole (UI_To_Int (Expr_Value (R)));
1207
                     end if;
1208
 
1209
                     for Position in Dimension_Type'Range loop
1210
                        Dims_Of_N (Position) :=
1211
                          Dims_Of_L (Position) * Exponent_Value;
1212
                     end loop;
1213
 
1214
                     if Exists (Dims_Of_N) then
1215
                        Set_Dimensions (N, Dims_Of_N);
1216
                     end if;
1217
                  end;
1218
               end if;
1219
 
1220
            --  Comparison cases
1221
 
1222
            --  For relational operations, only dimension checking is
1223
            --  performed (no propagation).
1224
 
1225
            elsif N_Kind in N_Op_Compare then
1226
               if (L_Has_Dimensions or R_Has_Dimensions)
1227
                 and then Dims_Of_L /= Dims_Of_R
1228
               then
1229
                  Error_Dim_Msg_For_Binary_Op (N, L, R);
1230
               end if;
1231
            end if;
1232
 
1233
            --  Removal of dimensions for each operands
1234
 
1235
            Remove_Dimensions (L);
1236
            Remove_Dimensions (R);
1237
         end;
1238
      end if;
1239
   end Analyze_Dimension_Binary_Op;
1240
 
1241
   ---------------------------------------------
1242
   -- Analyze_Dimension_Component_Declaration --
1243
   ---------------------------------------------
1244
 
1245
   procedure Analyze_Dimension_Component_Declaration (N : Node_Id) is
1246
      Expr         : constant Node_Id        := Expression (N);
1247
      Id           : constant Entity_Id      := Defining_Identifier (N);
1248
      Etyp         : constant Entity_Id      := Etype (Id);
1249
      Dims_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp);
1250
      Dims_Of_Expr : Dimension_Type;
1251
 
1252
      procedure Error_Dim_Msg_For_Component_Declaration
1253
        (N    : Node_Id;
1254
         Etyp : Entity_Id;
1255
         Expr : Node_Id);
1256
      --  Error using Error_Msg_N at node N. Output the dimensions of the
1257
      --  type Etyp and the expression Expr of N.
1258
 
1259
      ---------------------------------------------
1260
      -- Error_Dim_Msg_For_Component_Declaration --
1261
      ---------------------------------------------
1262
 
1263
      procedure Error_Dim_Msg_For_Component_Declaration
1264
        (N    : Node_Id;
1265
         Etyp : Entity_Id;
1266
         Expr : Node_Id) is
1267
      begin
1268
         Error_Msg_N ("dimensions mismatch in component declaration", N);
1269
         Error_Msg_N ("\component type " & Dimensions_Msg_Of (Etyp), N);
1270
         Error_Msg_N ("\component expression " & Dimensions_Msg_Of (Expr), N);
1271
      end Error_Dim_Msg_For_Component_Declaration;
1272
 
1273
   --  Start of processing for Analyze_Dimension_Component_Declaration
1274
 
1275
   begin
1276
      if Present (Expr) then
1277
         Dims_Of_Expr := Dimensions_Of (Expr);
1278
 
1279
         --  Return an error if the dimension of the expression and the
1280
         --  dimension of the type mismatch.
1281
 
1282
         if Dims_Of_Etyp /= Dims_Of_Expr then
1283
            Error_Dim_Msg_For_Component_Declaration (N, Etyp, Expr);
1284
         end if;
1285
 
1286
         --  Removal of dimensions in expression
1287
 
1288
         Remove_Dimensions (Expr);
1289
      end if;
1290
   end Analyze_Dimension_Component_Declaration;
1291
 
1292
   -------------------------------------------------
1293
   -- Analyze_Dimension_Extended_Return_Statement --
1294
   -------------------------------------------------
1295
 
1296
   procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id) is
1297
      Return_Ent            : constant Entity_Id :=
1298
                                Return_Statement_Entity (N);
1299
      Return_Etyp           : constant Entity_Id :=
1300
                                Etype (Return_Applies_To (Return_Ent));
1301
      Dims_Of_Return_Etyp   : constant Dimension_Type :=
1302
                                Dimensions_Of (Return_Etyp);
1303
      Return_Obj_Decls      : constant List_Id :=
1304
                                Return_Object_Declarations (N);
1305
      Dims_Of_Return_Obj_Id : Dimension_Type;
1306
      Return_Obj_Decl       : Node_Id;
1307
      Return_Obj_Id         : Entity_Id;
1308
 
1309
      procedure Error_Dim_Msg_For_Extended_Return_Statement
1310
        (N             : Node_Id;
1311
         Return_Etyp   : Entity_Id;
1312
         Return_Obj_Id : Entity_Id);
1313
      --  Error using Error_Msg_N at node N. Output the dimensions of the
1314
      --  returned type Return_Etyp and the returned object Return_Obj_Id of N.
1315
 
1316
      -------------------------------------------------
1317
      -- Error_Dim_Msg_For_Extended_Return_Statement --
1318
      -------------------------------------------------
1319
 
1320
      procedure Error_Dim_Msg_For_Extended_Return_Statement
1321
        (N             : Node_Id;
1322
         Return_Etyp   : Entity_Id;
1323
         Return_Obj_Id : Entity_Id)
1324
      is
1325
      begin
1326
         Error_Msg_N ("dimensions mismatch in extended return statement", N);
1327
         Error_Msg_N ("\returned type " & Dimensions_Msg_Of (Return_Etyp), N);
1328
         Error_Msg_N ("\returned object " & Dimensions_Msg_Of (Return_Obj_Id),
1329
                      N);
1330
      end Error_Dim_Msg_For_Extended_Return_Statement;
1331
 
1332
   --  Start of processing for Analyze_Dimension_Extended_Return_Statement
1333
 
1334
   begin
1335
      if Present (Return_Obj_Decls) then
1336
         Return_Obj_Decl := First (Return_Obj_Decls);
1337
         while Present (Return_Obj_Decl) loop
1338
            if Nkind (Return_Obj_Decl) = N_Object_Declaration then
1339
               Return_Obj_Id := Defining_Identifier (Return_Obj_Decl);
1340
 
1341
               if Is_Return_Object (Return_Obj_Id) then
1342
                  Dims_Of_Return_Obj_Id := Dimensions_Of (Return_Obj_Id);
1343
 
1344
                  if Dims_Of_Return_Etyp /= Dims_Of_Return_Obj_Id then
1345
                     Error_Dim_Msg_For_Extended_Return_Statement
1346
                       (N, Return_Etyp, Return_Obj_Id);
1347
                     return;
1348
                  end if;
1349
               end if;
1350
            end if;
1351
 
1352
            Next (Return_Obj_Decl);
1353
         end loop;
1354
      end if;
1355
   end Analyze_Dimension_Extended_Return_Statement;
1356
 
1357
   -------------------------------------
1358
   -- Analyze_Dimension_Function_Call --
1359
   -------------------------------------
1360
 
1361
   --  Propagate the dimensions from the returned type to the call node. Note
1362
   --  that there is a special treatment for elementary function calls. Indeed
1363
   --  for Sqrt call, the resulting dimensions equal to half the dimensions of
1364
   --  the actual, and for other elementary calls, this routine check that
1365
   --  every actuals are dimensionless.
1366
 
1367
   procedure Analyze_Dimension_Function_Call (N : Node_Id) is
1368
      Actuals        : constant List_Id := Parameter_Associations (N);
1369
      Name_Call      : constant Node_Id := Name (N);
1370
      Actual         : Node_Id;
1371
      Dims_Of_Actual : Dimension_Type;
1372
      Dims_Of_Call   : Dimension_Type;
1373
      Ent            : Entity_Id;
1374
 
1375
      function Is_Elementary_Function_Entity (E : Entity_Id) return Boolean;
1376
      --  Given E, the original subprogram entity, return True if call is to an
1377
      --  elementary function (see Ada.Numerics.Generic_Elementary_Functions).
1378
 
1379
      -----------------------------------
1380
      -- Is_Elementary_Function_Entity --
1381
      -----------------------------------
1382
 
1383
      function Is_Elementary_Function_Entity (E : Entity_Id) return Boolean is
1384
         Loc : constant Source_Ptr := Sloc (E);
1385
 
1386
      begin
1387
         --  Is function entity in Ada.Numerics.Generic_Elementary_Functions?
1388
 
1389
         return
1390
           Loc > No_Location
1391
             and then
1392
               Is_RTU
1393
                (Cunit_Entity (Get_Source_Unit (Loc)),
1394
                 Ada_Numerics_Generic_Elementary_Functions);
1395
      end Is_Elementary_Function_Entity;
1396
 
1397
   --  Start of processing for Analyze_Dimension_Function_Call
1398
 
1399
   begin
1400
      --  Look for elementary function call
1401
 
1402
      if Is_Entity_Name (Name_Call) then
1403
         Ent := Entity (Name_Call);
1404
 
1405
         --  Get the original subprogram entity following the renaming chain
1406
 
1407
         if Present (Alias (Ent)) then
1408
            Ent := Alias (Ent);
1409
         end if;
1410
 
1411
         --  Elementary function case
1412
 
1413
         if Is_Elementary_Function_Entity (Ent) then
1414
 
1415
         --  Sqrt function call case
1416
 
1417
            if Chars (Ent) = Name_Sqrt then
1418
               Dims_Of_Call := Dimensions_Of (First (Actuals));
1419
 
1420
               if Exists (Dims_Of_Call) then
1421
                  for Position in Dims_Of_Call'Range loop
1422
                     Dims_Of_Call (Position) :=
1423
                       Dims_Of_Call (Position) * Rational'(Numerator   => 1,
1424
                                                           Denominator => 2);
1425
                  end loop;
1426
 
1427
                  Set_Dimensions (N, Dims_Of_Call);
1428
               end if;
1429
 
1430
            --  All other elementary functions case. Note that every actual
1431
            --  here should be dimensionless.
1432
 
1433
            else
1434
               Actual := First (Actuals);
1435
               while Present (Actual) loop
1436
                  Dims_Of_Actual := Dimensions_Of (Actual);
1437
 
1438
                  if Exists (Dims_Of_Actual) then
1439
                     Error_Msg_NE ("parameter should be dimensionless for " &
1440
                                   "elementary function&",
1441
                                   Actual, Name_Call);
1442
                     Error_Msg_N ("\parameter " & Dimensions_Msg_Of (Actual),
1443
                                  Actual);
1444
                  end if;
1445
 
1446
                  Next (Actual);
1447
               end loop;
1448
            end if;
1449
 
1450
            return;
1451
         end if;
1452
      end if;
1453
 
1454
      --  Other cases
1455
 
1456
      Analyze_Dimension_Has_Etype (N);
1457
   end Analyze_Dimension_Function_Call;
1458
 
1459
   ---------------------------------
1460
   -- Analyze_Dimension_Has_Etype --
1461
   ---------------------------------
1462
 
1463
   procedure Analyze_Dimension_Has_Etype (N : Node_Id) is
1464
      Etyp         : constant Entity_Id := Etype (N);
1465
      Dims_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp);
1466
 
1467
   begin
1468
      --  Propagation of the dimensions from the type
1469
 
1470
      if Exists (Dims_Of_Etyp) then
1471
         Set_Dimensions (N, Dims_Of_Etyp);
1472
      end if;
1473
 
1474
      --  Removal of dimensions in expression
1475
 
1476
      case Nkind (N) is
1477
 
1478
         when N_Attribute_Reference |
1479
              N_Indexed_Component   =>
1480
            declare
1481
               Expr  : Node_Id;
1482
               Exprs : constant List_Id := Expressions (N);
1483
 
1484
            begin
1485
               if Present (Exprs) then
1486
                  Expr := First (Exprs);
1487
                  while Present (Expr) loop
1488
                     Remove_Dimensions (Expr);
1489
                     Next (Expr);
1490
                  end loop;
1491
               end if;
1492
            end;
1493
 
1494
         when N_Qualified_Expression      |
1495
              N_Type_Conversion           |
1496
              N_Unchecked_Type_Conversion =>
1497
            Remove_Dimensions (Expression (N));
1498
 
1499
         when N_Selected_Component =>
1500
            Remove_Dimensions (Selector_Name (N));
1501
 
1502
         when others => null;
1503
 
1504
      end case;
1505
   end Analyze_Dimension_Has_Etype;
1506
 
1507
   ------------------------------------------
1508
   -- Analyze_Dimension_Object_Declaration --
1509
   ------------------------------------------
1510
 
1511
   procedure Analyze_Dimension_Object_Declaration (N : Node_Id) is
1512
      Expr        : constant Node_Id   := Expression (N);
1513
      Id          : constant Entity_Id := Defining_Identifier (N);
1514
      Etyp        : constant Entity_Id := Etype (Id);
1515
      Dim_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp);
1516
      Dim_Of_Expr : Dimension_Type;
1517
 
1518
      procedure Error_Dim_Msg_For_Object_Declaration
1519
        (N    : Node_Id;
1520
         Etyp : Entity_Id;
1521
         Expr : Node_Id);
1522
      --  Error using Error_Msg_N at node N. Output the dimensions of the
1523
      --  type Etyp and of the expression Expr.
1524
 
1525
      ------------------------------------------
1526
      -- Error_Dim_Msg_For_Object_Declaration --
1527
      ------------------------------------------
1528
 
1529
      procedure Error_Dim_Msg_For_Object_Declaration
1530
        (N    : Node_Id;
1531
         Etyp : Entity_Id;
1532
         Expr : Node_Id) is
1533
      begin
1534
         Error_Msg_N ("dimensions mismatch in object declaration", N);
1535
         Error_Msg_N ("\object type " & Dimensions_Msg_Of (Etyp), N);
1536
         Error_Msg_N ("\object expression " & Dimensions_Msg_Of (Expr), N);
1537
      end Error_Dim_Msg_For_Object_Declaration;
1538
 
1539
   --  Start of processing for Analyze_Dimension_Object_Declaration
1540
 
1541
   begin
1542
      --  Expression is present
1543
 
1544
      if Present (Expr) then
1545
         Dim_Of_Expr := Dimensions_Of (Expr);
1546
 
1547
         --  case when expression is not a literal and when dimensions of the
1548
         --  expression and of the type mismatch
1549
 
1550
         if not Nkind_In (Original_Node (Expr),
1551
                             N_Real_Literal,
1552
                             N_Integer_Literal)
1553
           and then Dim_Of_Expr /= Dim_Of_Etyp
1554
         then
1555
            Error_Dim_Msg_For_Object_Declaration (N, Etyp, Expr);
1556
         end if;
1557
 
1558
         --  Removal of dimensions in expression
1559
 
1560
         Remove_Dimensions (Expr);
1561
      end if;
1562
   end Analyze_Dimension_Object_Declaration;
1563
 
1564
   ---------------------------------------------------
1565
   -- Analyze_Dimension_Object_Renaming_Declaration --
1566
   ---------------------------------------------------
1567
 
1568
   procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id) is
1569
      Renamed_Name : constant Node_Id := Name (N);
1570
      Sub_Mark     : constant Node_Id := Subtype_Mark (N);
1571
 
1572
      procedure Error_Dim_Msg_For_Object_Renaming_Declaration
1573
        (N            : Node_Id;
1574
         Sub_Mark     : Node_Id;
1575
         Renamed_Name : Node_Id);
1576
      --  Error using Error_Msg_N at node N. Output the dimensions of
1577
      --  Sub_Mark and of Renamed_Name.
1578
 
1579
      ---------------------------------------------------
1580
      -- Error_Dim_Msg_For_Object_Renaming_Declaration --
1581
      ---------------------------------------------------
1582
 
1583
      procedure Error_Dim_Msg_For_Object_Renaming_Declaration
1584
        (N            : Node_Id;
1585
         Sub_Mark     : Node_Id;
1586
         Renamed_Name : Node_Id) is
1587
      begin
1588
         Error_Msg_N ("dimensions mismatch in object renaming declaration",
1589
                      N);
1590
         Error_Msg_N ("\type " & Dimensions_Msg_Of (Sub_Mark), N);
1591
         Error_Msg_N ("\renamed object " & Dimensions_Msg_Of (Renamed_Name),
1592
                      N);
1593
      end Error_Dim_Msg_For_Object_Renaming_Declaration;
1594
 
1595
   --  Start of processing for Analyze_Dimension_Object_Renaming_Declaration
1596
 
1597
   begin
1598
      if Dimensions_Of (Renamed_Name) /= Dimensions_Of (Sub_Mark) then
1599
         Error_Dim_Msg_For_Object_Renaming_Declaration
1600
           (N, Sub_Mark, Renamed_Name);
1601
      end if;
1602
   end Analyze_Dimension_Object_Renaming_Declaration;
1603
 
1604
   -----------------------------------------------
1605
   -- Analyze_Dimension_Simple_Return_Statement --
1606
   -----------------------------------------------
1607
 
1608
   procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id) is
1609
      Expr                : constant Node_Id := Expression (N);
1610
      Dims_Of_Expr        : constant Dimension_Type := Dimensions_Of (Expr);
1611
      Return_Ent          : constant Entity_Id := Return_Statement_Entity (N);
1612
      Return_Etyp         : constant Entity_Id :=
1613
                              Etype (Return_Applies_To (Return_Ent));
1614
      Dims_Of_Return_Etyp : constant Dimension_Type :=
1615
                              Dimensions_Of (Return_Etyp);
1616
 
1617
      procedure Error_Dim_Msg_For_Simple_Return_Statement
1618
        (N           : Node_Id;
1619
         Return_Etyp : Entity_Id;
1620
         Expr        : Node_Id);
1621
      --  Error using Error_Msg_N at node N. Output the dimensions of the
1622
      --  returned type Return_Etyp and the returned expression Expr of N.
1623
 
1624
      -----------------------------------------------
1625
      -- Error_Dim_Msg_For_Simple_Return_Statement --
1626
      -----------------------------------------------
1627
 
1628
      procedure Error_Dim_Msg_For_Simple_Return_Statement
1629
        (N           : Node_Id;
1630
         Return_Etyp : Entity_Id;
1631
         Expr        : Node_Id)
1632
      is
1633
      begin
1634
         Error_Msg_N ("dimensions mismatch in return statement", N);
1635
         Error_Msg_N ("\returned type " & Dimensions_Msg_Of (Return_Etyp), N);
1636
         Error_Msg_N ("\returned expression " & Dimensions_Msg_Of (Expr), N);
1637
      end Error_Dim_Msg_For_Simple_Return_Statement;
1638
 
1639
   --  Start of processing for Analyze_Dimension_Simple_Return_Statement
1640
 
1641
   begin
1642
      if Dims_Of_Return_Etyp /= Dims_Of_Expr then
1643
         Error_Dim_Msg_For_Simple_Return_Statement (N, Return_Etyp, Expr);
1644
         Remove_Dimensions (Expr);
1645
      end if;
1646
   end Analyze_Dimension_Simple_Return_Statement;
1647
 
1648
   -------------------------------------------
1649
   -- Analyze_Dimension_Subtype_Declaration --
1650
   -------------------------------------------
1651
 
1652
   procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id) is
1653
      Id           : constant Entity_Id := Defining_Identifier (N);
1654
      Dims_Of_Id   : constant Dimension_Type := Dimensions_Of (Id);
1655
      Dims_Of_Etyp : Dimension_Type;
1656
      Etyp         : Node_Id;
1657
 
1658
   begin
1659
      --  No constraint case in subtype declaration
1660
 
1661
      if Nkind (Subtype_Indication (N)) /= N_Subtype_Indication then
1662
         Etyp := Etype (Subtype_Indication (N));
1663
         Dims_Of_Etyp := Dimensions_Of (Etyp);
1664
 
1665
         if Exists (Dims_Of_Etyp) then
1666
 
1667
            --  If subtype already has a dimension (from Aspect_Dimension),
1668
            --  it cannot inherit a dimension from its subtype.
1669
 
1670
            if Exists (Dims_Of_Id) then
1671
               Error_Msg_N ("subtype& already" & Dimensions_Msg_Of (Id), N);
1672
            else
1673
               Set_Dimensions (Id, Dims_Of_Etyp);
1674
               Set_Symbol (Id, Symbol_Of (Etyp));
1675
            end if;
1676
         end if;
1677
 
1678
      --  Constraint present in subtype declaration
1679
 
1680
      else
1681
         Etyp := Etype (Subtype_Mark (Subtype_Indication (N)));
1682
         Dims_Of_Etyp := Dimensions_Of (Etyp);
1683
 
1684
         if Exists (Dims_Of_Etyp) then
1685
            Set_Dimensions (Id, Dims_Of_Etyp);
1686
            Set_Symbol (Id, Symbol_Of (Etyp));
1687
         end if;
1688
      end if;
1689
   end Analyze_Dimension_Subtype_Declaration;
1690
 
1691
   --------------------------------
1692
   -- Analyze_Dimension_Unary_Op --
1693
   --------------------------------
1694
 
1695
   procedure Analyze_Dimension_Unary_Op (N : Node_Id) is
1696
   begin
1697
      case Nkind (N) is
1698
         when N_Op_Plus | N_Op_Minus | N_Op_Abs =>
1699
            declare
1700
               R : constant Node_Id := Right_Opnd (N);
1701
 
1702
            begin
1703
               --  Propagate the dimension if the operand is not dimensionless
1704
 
1705
               Move_Dimensions (R, N);
1706
            end;
1707
 
1708
         when others => null;
1709
 
1710
      end case;
1711
   end Analyze_Dimension_Unary_Op;
1712
 
1713
   --------------------------
1714
   -- Create_Rational_From --
1715
   --------------------------
1716
 
1717
   --  RATIONAL ::= [-] NUMERAL [/ NUMERAL]
1718
 
1719
   --  A rational number is a number that can be expressed as the quotient or
1720
   --  fraction a/b of two integers, where b is non-zero positive.
1721
 
1722
   function Create_Rational_From
1723
     (Expr     : Node_Id;
1724
      Complain : Boolean) return Rational
1725
   is
1726
      Or_Node_Of_Expr : constant Node_Id := Original_Node (Expr);
1727
      Result          : Rational := No_Rational;
1728
 
1729
      function Process_Minus (N : Node_Id) return Rational;
1730
      --  Create a rational from a N_Op_Minus node
1731
 
1732
      function Process_Divide (N : Node_Id) return Rational;
1733
      --  Create a rational from a N_Op_Divide node
1734
 
1735
      function Process_Literal (N : Node_Id) return Rational;
1736
      --  Create a rational from a N_Integer_Literal node
1737
 
1738
      -------------------
1739
      -- Process_Minus --
1740
      -------------------
1741
 
1742
      function Process_Minus (N : Node_Id) return Rational is
1743
         Right  : constant Node_Id := Original_Node (Right_Opnd (N));
1744
         Result : Rational;
1745
 
1746
      begin
1747
         --  Operand is an integer literal
1748
 
1749
         if Nkind (Right) = N_Integer_Literal then
1750
            Result := -Process_Literal (Right);
1751
 
1752
         --  Operand is a divide operator
1753
 
1754
         elsif Nkind (Right) = N_Op_Divide then
1755
            Result := -Process_Divide (Right);
1756
 
1757
         else
1758
            Result := No_Rational;
1759
         end if;
1760
 
1761
         return Result;
1762
      end Process_Minus;
1763
 
1764
      --------------------
1765
      -- Process_Divide --
1766
      --------------------
1767
 
1768
      function Process_Divide (N : Node_Id) return Rational is
1769
         Left      : constant Node_Id := Original_Node (Left_Opnd (N));
1770
         Right     : constant Node_Id := Original_Node (Right_Opnd (N));
1771
         Left_Rat  : Rational;
1772
         Result    : Rational := No_Rational;
1773
         Right_Rat : Rational;
1774
 
1775
      begin
1776
         --  Both left and right operands are an integer literal
1777
 
1778
         if Nkind (Left) = N_Integer_Literal
1779
           and then Nkind (Right) = N_Integer_Literal
1780
         then
1781
            Left_Rat := Process_Literal (Left);
1782
            Right_Rat := Process_Literal (Right);
1783
            Result := Left_Rat / Right_Rat;
1784
         end if;
1785
 
1786
         return Result;
1787
      end Process_Divide;
1788
 
1789
      ---------------------
1790
      -- Process_Literal --
1791
      ---------------------
1792
 
1793
      function Process_Literal (N : Node_Id) return Rational is
1794
      begin
1795
         return +Whole (UI_To_Int (Intval (N)));
1796
      end Process_Literal;
1797
 
1798
   --  Start of processing for Create_Rational_From
1799
 
1800
   begin
1801
      --  Check the expression is either a division of two integers or an
1802
      --  integer itself. Note that the check applies to the original node
1803
      --  since the node could have already been rewritten.
1804
 
1805
      --  Integer literal case
1806
 
1807
      if Nkind (Or_Node_Of_Expr) = N_Integer_Literal then
1808
         Result := Process_Literal (Or_Node_Of_Expr);
1809
 
1810
      --  Divide operator case
1811
 
1812
      elsif Nkind (Or_Node_Of_Expr) = N_Op_Divide then
1813
         Result := Process_Divide (Or_Node_Of_Expr);
1814
 
1815
      --  Minus operator case
1816
 
1817
      elsif Nkind (Or_Node_Of_Expr) = N_Op_Minus then
1818
         Result := Process_Minus (Or_Node_Of_Expr);
1819
      end if;
1820
 
1821
      --  When Expr cannot be interpreted as a rational and Complain is true,
1822
      --  generate an error message.
1823
 
1824
      if Complain and then Result = No_Rational then
1825
         Error_Msg_N ("must be a rational", Expr);
1826
      end if;
1827
 
1828
      return Result;
1829
   end Create_Rational_From;
1830
 
1831
   -------------------
1832
   -- Dimensions_Of --
1833
   -------------------
1834
 
1835
   function Dimensions_Of (N : Node_Id) return Dimension_Type is
1836
   begin
1837
      return Dimension_Table.Get (N);
1838
   end Dimensions_Of;
1839
 
1840
   -----------------------
1841
   -- Dimensions_Msg_Of --
1842
   -----------------------
1843
 
1844
   function Dimensions_Msg_Of (N : Node_Id) return String is
1845
      Dims_Of_N      : constant Dimension_Type := Dimensions_Of (N);
1846
      Dimensions_Msg : Name_Id;
1847
      System         : System_Type;
1848
 
1849
      procedure Add_Dimension_Vector_To_Buffer
1850
        (Dims   : Dimension_Type;
1851
         System : System_Type);
1852
      --  Given a Dims and System, add to Name_Buffer the string representation
1853
      --  of a dimension vector.
1854
 
1855
      procedure Add_Whole_To_Buffer (W : Whole);
1856
      --  Add image of Whole to Name_Buffer
1857
 
1858
      ------------------------------------
1859
      -- Add_Dimension_Vector_To_Buffer --
1860
      ------------------------------------
1861
 
1862
      procedure Add_Dimension_Vector_To_Buffer
1863
        (Dims   : Dimension_Type;
1864
         System : System_Type)
1865
      is
1866
         Dim_Power : Rational;
1867
         First_Dim : Boolean := True;
1868
 
1869
      begin
1870
         Add_Char_To_Name_Buffer ('(');
1871
 
1872
         for Position in Dims_Of_N'First ..  System.Count loop
1873
            Dim_Power := Dims (Position);
1874
 
1875
            if First_Dim then
1876
               First_Dim := False;
1877
            else
1878
               Add_Str_To_Name_Buffer (", ");
1879
            end if;
1880
 
1881
            Add_Whole_To_Buffer (Dim_Power.Numerator);
1882
 
1883
            if Dim_Power.Denominator /= 1 then
1884
               Add_Char_To_Name_Buffer ('/');
1885
               Add_Whole_To_Buffer (Dim_Power.Denominator);
1886
            end if;
1887
         end loop;
1888
 
1889
         Add_Char_To_Name_Buffer (')');
1890
      end Add_Dimension_Vector_To_Buffer;
1891
 
1892
      -------------------------
1893
      -- Add_Whole_To_Buffer --
1894
      -------------------------
1895
 
1896
      procedure Add_Whole_To_Buffer (W : Whole) is
1897
      begin
1898
         UI_Image (UI_From_Int (Int (W)));
1899
         Add_Str_To_Name_Buffer (UI_Image_Buffer (1 .. UI_Image_Length));
1900
      end Add_Whole_To_Buffer;
1901
 
1902
   --  Start of processing for Dimensions_Msg_Of
1903
 
1904
   begin
1905
      --  Initialization of Name_Buffer
1906
 
1907
      Name_Len := 0;
1908
 
1909
      if Exists (Dims_Of_N) then
1910
         System := System_Of (Base_Type (Etype (N)));
1911
         Add_Str_To_Name_Buffer ("has dimensions ");
1912
         Add_Dimension_Vector_To_Buffer (Dims_Of_N, System);
1913
      else
1914
         Add_Str_To_Name_Buffer ("is dimensionless");
1915
      end if;
1916
 
1917
      Dimensions_Msg := Name_Find;
1918
      return Get_Name_String (Dimensions_Msg);
1919
   end Dimensions_Msg_Of;
1920
 
1921
   --------------------------
1922
   -- Dimension_Table_Hash --
1923
   --------------------------
1924
 
1925
   function Dimension_Table_Hash
1926
     (Key : Node_Id) return Dimension_Table_Range
1927
   is
1928
   begin
1929
      return Dimension_Table_Range (Key mod 511);
1930
   end Dimension_Table_Hash;
1931
 
1932
   ----------------------------------------
1933
   -- Eval_Op_Expon_For_Dimensioned_Type --
1934
   ----------------------------------------
1935
 
1936
   --  Evaluate the expon operator for real dimensioned type.
1937
 
1938
   --  Note that if the exponent is an integer (denominator = 1) the node is
1939
   --  evaluated by the regular Eval_Op_Expon routine (see Sem_Eval).
1940
 
1941
   procedure Eval_Op_Expon_For_Dimensioned_Type
1942
     (N    : Node_Id;
1943
      Btyp : Entity_Id)
1944
   is
1945
      R       : constant Node_Id := Right_Opnd (N);
1946
      R_Value : Rational := No_Rational;
1947
 
1948
   begin
1949
      if Is_Real_Type (Btyp) then
1950
         R_Value := Create_Rational_From (R, False);
1951
      end if;
1952
 
1953
      --  Check that the exponent is not an integer
1954
 
1955
      if R_Value /= No_Rational and then R_Value.Denominator /= 1 then
1956
         Eval_Op_Expon_With_Rational_Exponent (N, R_Value);
1957
      else
1958
         Eval_Op_Expon (N);
1959
      end if;
1960
   end Eval_Op_Expon_For_Dimensioned_Type;
1961
 
1962
   ------------------------------------------
1963
   -- Eval_Op_Expon_With_Rational_Exponent --
1964
   ------------------------------------------
1965
 
1966
   --  For dimensioned operand in exponentiation, exponent is allowed to be a
1967
   --  Rational and not only an Integer like for dimensionless operands. For
1968
   --  that particular case, the left operand is rewritten as a function call
1969
   --  using the function Expon_LLF from s-llflex.ads.
1970
 
1971
   procedure Eval_Op_Expon_With_Rational_Exponent
1972
     (N              : Node_Id;
1973
      Exponent_Value : Rational)
1974
   is
1975
      Dims_Of_N             : constant Dimension_Type := Dimensions_Of (N);
1976
      L                     : constant Node_Id := Left_Opnd (N);
1977
      Etyp_Of_L             : constant Entity_Id := Etype (L);
1978
      Btyp_Of_L             : constant Entity_Id := Base_Type (Etyp_Of_L);
1979
      Loc                   : constant Source_Ptr := Sloc (N);
1980
      Actual_1              : Node_Id;
1981
      Actual_2              : Node_Id;
1982
      Dim_Power             : Rational;
1983
      List_Of_Dims          : List_Id;
1984
      New_Aspect            : Node_Id;
1985
      New_Aspects           : List_Id;
1986
      New_Id                : Entity_Id;
1987
      New_N                 : Node_Id;
1988
      New_Subtyp_Decl_For_L : Node_Id;
1989
      System                : System_Type;
1990
 
1991
   begin
1992
      --  Case when the operand is not dimensionless
1993
 
1994
      if Exists (Dims_Of_N) then
1995
 
1996
         --  Get the corresponding System_Type to know the exact number of
1997
         --  dimensions in the system.
1998
 
1999
         System := System_Of (Btyp_Of_L);
2000
 
2001
         --  Generation of a new subtype with the proper dimensions
2002
 
2003
         --  In order to rewrite the operator as a type conversion, a new
2004
         --  dimensioned subtype with the resulting dimensions of the
2005
         --  exponentiation must be created.
2006
 
2007
         --  Generate:
2008
 
2009
         --  Btyp_Of_L   : constant Entity_Id := Base_Type (Etyp_Of_L);
2010
         --  System      : constant System_Id :=
2011
         --                  Get_Dimension_System_Id (Btyp_Of_L);
2012
         --  Num_Of_Dims : constant Number_Of_Dimensions :=
2013
         --                  Dimension_Systems.Table (System).Dimension_Count;
2014
 
2015
         --  subtype T is Btyp_Of_L
2016
         --    with
2017
         --      Dimension => ("",
2018
         --        Dims_Of_N (1).Numerator / Dims_Of_N (1).Denominator,
2019
         --        Dims_Of_N (2).Numerator / Dims_Of_N (2).Denominator,
2020
         --        ...
2021
         --        Dims_Of_N (Num_Of_Dims).Numerator /
2022
         --          Dims_Of_N (Num_Of_Dims).Denominator);
2023
 
2024
         --  Step 1: Generate the new aggregate for the aspect Dimension
2025
 
2026
         New_Aspects  := Empty_List;
2027
         List_Of_Dims := New_List;
2028
         Append (Make_String_Literal (Loc, ""), List_Of_Dims);
2029
 
2030
         for Position in Dims_Of_N'First ..  System.Count loop
2031
            Dim_Power := Dims_Of_N (Position);
2032
            Append_To (List_Of_Dims,
2033
               Make_Op_Divide (Loc,
2034
                 Left_Opnd  =>
2035
                   Make_Integer_Literal (Loc,
2036
                     Int (Dim_Power.Numerator)),
2037
                 Right_Opnd =>
2038
                   Make_Integer_Literal (Loc,
2039
                     Int (Dim_Power.Denominator))));
2040
         end loop;
2041
 
2042
         --  Step 2: Create the new Aspect Specification for Aspect Dimension
2043
 
2044
         New_Aspect :=
2045
           Make_Aspect_Specification (Loc,
2046
             Identifier => Make_Identifier (Loc, Name_Dimension),
2047
             Expression => Make_Aggregate (Loc, Expressions => List_Of_Dims));
2048
 
2049
         --  Step 3: Make a temporary identifier for the new subtype
2050
 
2051
         New_Id := Make_Temporary (Loc, 'T');
2052
         Set_Is_Internal (New_Id);
2053
 
2054
         --  Step 4: Declaration of the new subtype
2055
 
2056
         New_Subtyp_Decl_For_L :=
2057
            Make_Subtype_Declaration (Loc,
2058
               Defining_Identifier => New_Id,
2059
               Subtype_Indication  => New_Occurrence_Of (Btyp_Of_L, Loc));
2060
 
2061
         Append (New_Aspect, New_Aspects);
2062
         Set_Parent (New_Aspects, New_Subtyp_Decl_For_L);
2063
         Set_Aspect_Specifications (New_Subtyp_Decl_For_L, New_Aspects);
2064
 
2065
         Analyze (New_Subtyp_Decl_For_L);
2066
 
2067
      --  Case where the operand is dimensionless
2068
 
2069
      else
2070
         New_Id := Btyp_Of_L;
2071
      end if;
2072
 
2073
      --  Replacement of N by New_N
2074
 
2075
      --  Generate:
2076
 
2077
      --  Actual_1 := Long_Long_Float (L),
2078
 
2079
      --  Actual_2 := Long_Long_Float (Exponent_Value.Numerator) /
2080
      --                Long_Long_Float (Exponent_Value.Denominator);
2081
 
2082
      --  (T (Expon_LLF (Actual_1, Actual_2)));
2083
 
2084
      --  where T is the subtype declared in step 1
2085
 
2086
      --  The node is rewritten as a type conversion
2087
 
2088
      --  Step 1: Creation of the two parameters of Expon_LLF function call
2089
 
2090
      Actual_1 :=
2091
        Make_Type_Conversion (Loc,
2092
          Subtype_Mark => New_Reference_To (Standard_Long_Long_Float, Loc),
2093
          Expression   => Relocate_Node (L));
2094
 
2095
      Actual_2 :=
2096
        Make_Op_Divide (Loc,
2097
          Left_Opnd  =>
2098
            Make_Real_Literal (Loc,
2099
              UR_From_Uint (UI_From_Int (Int (Exponent_Value.Numerator)))),
2100
          Right_Opnd =>
2101
            Make_Real_Literal (Loc,
2102
              UR_From_Uint (UI_From_Int (Int (Exponent_Value.Denominator)))));
2103
 
2104
      --  Step 2: Creation of New_N
2105
 
2106
      New_N :=
2107
         Make_Type_Conversion (Loc,
2108
           Subtype_Mark => New_Reference_To (New_Id, Loc),
2109
           Expression =>
2110
             Make_Function_Call (Loc,
2111
               Name => New_Reference_To (RTE (RE_Expon_LLF), Loc),
2112
               Parameter_Associations => New_List (
2113
                 Actual_1, Actual_2)));
2114
 
2115
      --  Step 3: Rewrite N with the result
2116
 
2117
      Rewrite (N, New_N);
2118
      Set_Etype (N, New_Id);
2119
      Analyze_And_Resolve (N, New_Id);
2120
   end Eval_Op_Expon_With_Rational_Exponent;
2121
 
2122
   ------------
2123
   -- Exists --
2124
   ------------
2125
 
2126
   function Exists (Dim : Dimension_Type) return Boolean is
2127
   begin
2128
      return Dim /= Null_Dimension;
2129
   end Exists;
2130
 
2131
   function Exists (Sys : System_Type) return Boolean is
2132
   begin
2133
      return Sys /= Null_System;
2134
   end Exists;
2135
 
2136
   -------------------------------------------
2137
   -- Expand_Put_Call_With_Dimension_Symbol --
2138
   -------------------------------------------
2139
 
2140
   --  For procedure Put defined in System.Dim.Float_IO/System.Dim.Integer_IO,
2141
   --  the default string parameter must be rewritten to include the dimension
2142
   --  symbols in the output of a dimensioned object.
2143
 
2144
   --  Case 1: the parameter is a variable
2145
 
2146
   --  The default string parameter is replaced by the symbol defined in the
2147
   --  aspect Dimension of the subtype. For instance to output a speed:
2148
 
2149
   --  subtype Force is Mks_Type
2150
   --    with
2151
   --      Dimension => ("N",
2152
   --        Meter =>    1,
2153
   --        Kilogram => 1,
2154
   --        Second =>   -2,
2155
   --        others =>   0);
2156
   --  F : Force := 2.1 * m * kg * s**(-2);
2157
   --  Put (F);
2158
   --  > 2.1 N
2159
 
2160
   --  Case 2: the parameter is an expression
2161
 
2162
   --  In this case we call the procedure Expand_Put_Call_With_Dimension_Symbol
2163
   --  that creates the string of symbols (for instance "m.s**(-1)") and
2164
   --  rewrites the default string parameter of Put with the corresponding
2165
   --  the String_Id. For instance:
2166
 
2167
   --  Put (2.1 * m * kg * s**(-2));
2168
   --  > 2.1 m.kg.s**(-2)
2169
 
2170
   procedure Expand_Put_Call_With_Dimension_Symbol (N : Node_Id) is
2171
      Actuals        : constant List_Id := Parameter_Associations (N);
2172
      Loc            : constant Source_Ptr := Sloc (N);
2173
      Name_Call      : constant Node_Id := Name (N);
2174
      New_Actuals    : constant List_Id := New_List;
2175
      Actual         : Node_Id;
2176
      Dims_Of_Actual : Dimension_Type;
2177
      Etyp           : Entity_Id;
2178
      New_Str_Lit    : Node_Id := Empty;
2179
      System         : System_Type;
2180
 
2181
      function Has_Dimension_Symbols return Boolean;
2182
      --  Return True if the current Put call already has a parameter
2183
      --  association for parameter "Symbols" with the correct string of
2184
      --  symbols.
2185
 
2186
      function Is_Procedure_Put_Call return Boolean;
2187
      --  Return True if the current call is a call of an instantiation of a
2188
      --  procedure Put defined in the package System.Dim.Float_IO and
2189
      --  System.Dim.Integer_IO.
2190
 
2191
      function Item_Actual return Node_Id;
2192
      --  Return the item actual parameter node in the put call
2193
 
2194
      ---------------------------
2195
      -- Has_Dimension_Symbols --
2196
      ---------------------------
2197
 
2198
      function Has_Dimension_Symbols return Boolean is
2199
         Actual : Node_Id;
2200
 
2201
      begin
2202
         Actual := First (Actuals);
2203
 
2204
         --  Look for a symbols parameter association in the list of actuals
2205
 
2206
         while Present (Actual) loop
2207
            if Nkind (Actual) = N_Parameter_Association
2208
              and then Chars (Selector_Name (Actual)) = Name_Symbols
2209
            then
2210
 
2211
               --  return True if the actual comes from source or if the string
2212
               --  of symbols doesn't have the default value (i.e "").
2213
 
2214
               return Comes_From_Source (Actual)
2215
                        or else String_Length
2216
                                  (Strval
2217
                                    (Explicit_Actual_Parameter (Actual))) /= 0;
2218
            end if;
2219
 
2220
            Next (Actual);
2221
         end loop;
2222
 
2223
         --  At this point, the call has no parameter association
2224
         --  Look to the last actual since the symbols parameter is the last
2225
         --  one.
2226
 
2227
         return Nkind (Last (Actuals)) = N_String_Literal;
2228
      end Has_Dimension_Symbols;
2229
 
2230
      ---------------------------
2231
      -- Is_Procedure_Put_Call --
2232
      ---------------------------
2233
 
2234
      function Is_Procedure_Put_Call return Boolean is
2235
         Ent : Entity_Id;
2236
         Loc : Source_Ptr;
2237
 
2238
      begin
2239
         --  There are three different Put routines in each generic dim IO
2240
         --  package. Verify the current procedure call is one of them.
2241
 
2242
         if Is_Entity_Name (Name_Call) then
2243
            Ent := Entity (Name_Call);
2244
 
2245
            --  Get the original subprogram entity following the renaming chain
2246
 
2247
            if Present (Alias (Ent)) then
2248
               Ent := Alias (Ent);
2249
            end if;
2250
 
2251
            Loc := Sloc (Ent);
2252
 
2253
            --  Check the name of the entity subprogram is Put and verify this
2254
            --  entity is located in either System.Dim.Float_IO or
2255
            --  System.Dim.Integer_IO.
2256
 
2257
            return Chars (Ent) = Name_Put
2258
              and then Loc > No_Location
2259
              and then Is_Dim_IO_Package_Entity
2260
                         (Cunit_Entity (Get_Source_Unit (Loc)));
2261
         end if;
2262
 
2263
         return False;
2264
      end Is_Procedure_Put_Call;
2265
 
2266
      -----------------
2267
      -- Item_Actual --
2268
      -----------------
2269
 
2270
      function Item_Actual return Node_Id is
2271
         Actual : Node_Id;
2272
 
2273
      begin
2274
         --  Look for the item actual as a parameter association
2275
 
2276
         Actual := First (Actuals);
2277
         while Present (Actual) loop
2278
            if Nkind (Actual) = N_Parameter_Association
2279
              and then Chars (Selector_Name (Actual)) = Name_Item
2280
            then
2281
               return Explicit_Actual_Parameter (Actual);
2282
            end if;
2283
 
2284
            Next (Actual);
2285
         end loop;
2286
 
2287
         --  Case where the item has been defined without an association
2288
 
2289
         Actual := First (Actuals);
2290
 
2291
         --  Depending on the procedure Put, Item actual could be first or
2292
         --  second in the list of actuals.
2293
 
2294
         if Has_Dimension_System (Base_Type (Etype (Actual))) then
2295
            return Actual;
2296
         else
2297
            return Next (Actual);
2298
         end if;
2299
      end Item_Actual;
2300
 
2301
   --  Start of processing for Expand_Put_Call_With_Dimension_Symbol
2302
 
2303
   begin
2304
      if Is_Procedure_Put_Call and then not Has_Dimension_Symbols then
2305
         Actual := Item_Actual;
2306
         Dims_Of_Actual := Dimensions_Of (Actual);
2307
         Etyp := Etype (Actual);
2308
 
2309
         --  Add the symbol as a suffix of the value if the subtype has a
2310
         --  dimension symbol or if the parameter is not dimensionless.
2311
 
2312
         if Symbol_Of (Etyp) /= No_String then
2313
            Start_String;
2314
 
2315
            --  Put a space between the value and the dimension
2316
 
2317
            Store_String_Char (' ');
2318
            Store_String_Chars (Symbol_Of (Etyp));
2319
            New_Str_Lit := Make_String_Literal (Loc, End_String);
2320
 
2321
         --  Check that the item is not dimensionless
2322
 
2323
         --  Create the new String_Literal with the new String_Id generated by
2324
         --  the routine From_Dimension_To_String.
2325
 
2326
         elsif Exists (Dims_Of_Actual) then
2327
            System := System_Of (Base_Type (Etyp));
2328
            New_Str_Lit :=
2329
              Make_String_Literal (Loc,
2330
                From_Dimension_To_String_Of_Symbols (Dims_Of_Actual, System));
2331
         end if;
2332
 
2333
         if Present (New_Str_Lit) then
2334
 
2335
            --  Insert all actuals in New_Actuals
2336
 
2337
            Actual := First (Actuals);
2338
            while Present (Actual) loop
2339
 
2340
               --  Copy every actuals in New_Actuals except the Symbols
2341
               --  parameter association.
2342
 
2343
               if Nkind (Actual) = N_Parameter_Association
2344
                 and then Chars (Selector_Name (Actual)) /= Name_Symbols
2345
               then
2346
                  Append_To (New_Actuals,
2347
                     Make_Parameter_Association (Loc,
2348
                        Selector_Name => New_Copy (Selector_Name (Actual)),
2349
                        Explicit_Actual_Parameter =>
2350
                           New_Copy (Explicit_Actual_Parameter (Actual))));
2351
 
2352
               elsif Nkind (Actual) /= N_Parameter_Association then
2353
                  Append_To (New_Actuals, New_Copy (Actual));
2354
               end if;
2355
 
2356
               Next (Actual);
2357
            end loop;
2358
 
2359
            --  Create new Symbols param association and append to New_Actuals
2360
 
2361
            Append_To (New_Actuals,
2362
              Make_Parameter_Association (Loc,
2363
                Selector_Name => Make_Identifier (Loc, Name_Symbols),
2364
                Explicit_Actual_Parameter => New_Str_Lit));
2365
 
2366
            --  Rewrite and analyze the procedure call
2367
 
2368
            Rewrite (N,
2369
              Make_Procedure_Call_Statement (Loc,
2370
                Name =>                   New_Copy (Name_Call),
2371
                Parameter_Associations => New_Actuals));
2372
 
2373
            Analyze (N);
2374
         end if;
2375
      end if;
2376
   end Expand_Put_Call_With_Dimension_Symbol;
2377
 
2378
   -----------------------------------------
2379
   -- From_Dimension_To_String_Of_Symbols --
2380
   -----------------------------------------
2381
 
2382
   --  Given a dimension vector and the corresponding dimension system,
2383
   --  create a String_Id to output the dimension symbols corresponding to
2384
   --  the dimensions Dims.
2385
 
2386
   function From_Dimension_To_String_Of_Symbols
2387
     (Dims   : Dimension_Type;
2388
      System : System_Type) return String_Id
2389
   is
2390
      Dimension_Power     : Rational;
2391
      First_Symbol_In_Str : Boolean := True;
2392
 
2393
   begin
2394
      --  Initialization of the new String_Id
2395
 
2396
      Start_String;
2397
 
2398
      --  Put a space between the value and the symbols
2399
 
2400
      Store_String_Char (' ');
2401
 
2402
      for Position in Dimension_Type'Range loop
2403
         Dimension_Power := Dims (Position);
2404
         if Dimension_Power /= Zero then
2405
 
2406
            if First_Symbol_In_Str then
2407
               First_Symbol_In_Str := False;
2408
            else
2409
               Store_String_Char ('.');
2410
            end if;
2411
 
2412
            --  Positive dimension case
2413
 
2414
            if Dimension_Power.Numerator > 0 then
2415
               if System.Symbols (Position) = No_String then
2416
                  Store_String_Chars
2417
                    (Get_Name_String (System.Names (Position)));
2418
               else
2419
                  Store_String_Chars (System.Symbols (Position));
2420
               end if;
2421
 
2422
               --  Integer case
2423
 
2424
               if Dimension_Power.Denominator = 1 then
2425
                  if Dimension_Power.Numerator /= 1 then
2426
                     Store_String_Chars ("**");
2427
                     Store_String_Int (Int (Dimension_Power.Numerator));
2428
                  end if;
2429
 
2430
               --  Rational case when denominator /= 1
2431
 
2432
               else
2433
                  Store_String_Chars ("**");
2434
                  Store_String_Char ('(');
2435
                  Store_String_Int (Int (Dimension_Power.Numerator));
2436
                  Store_String_Char ('/');
2437
                  Store_String_Int (Int (Dimension_Power.Denominator));
2438
                  Store_String_Char (')');
2439
               end if;
2440
 
2441
            --  Negative dimension case
2442
 
2443
            else
2444
               if System.Symbols (Position) = No_String then
2445
                  Store_String_Chars
2446
                    (Get_Name_String (System.Names (Position)));
2447
               else
2448
                  Store_String_Chars (System.Symbols (Position));
2449
               end if;
2450
 
2451
               Store_String_Chars ("**");
2452
               Store_String_Char ('(');
2453
               Store_String_Char ('-');
2454
               Store_String_Int (Int (-Dimension_Power.Numerator));
2455
 
2456
               --  Integer case
2457
 
2458
               if Dimension_Power.Denominator = 1 then
2459
                  Store_String_Char (')');
2460
 
2461
               --  Rational case when denominator /= 1
2462
 
2463
               else
2464
                  Store_String_Char ('/');
2465
                  Store_String_Int (Int (Dimension_Power.Denominator));
2466
                  Store_String_Char (')');
2467
               end if;
2468
            end if;
2469
         end if;
2470
      end loop;
2471
 
2472
      return End_String;
2473
   end From_Dimension_To_String_Of_Symbols;
2474
 
2475
   ---------
2476
   -- GCD --
2477
   ---------
2478
 
2479
   function GCD (Left, Right : Whole) return Int is
2480
      L : Whole;
2481
      R : Whole;
2482
 
2483
   begin
2484
      L := Left;
2485
      R := Right;
2486
      while R /= 0 loop
2487
         L := L mod R;
2488
 
2489
         if L = 0 then
2490
            return Int (R);
2491
         end if;
2492
 
2493
         R := R mod L;
2494
      end loop;
2495
 
2496
      return Int (L);
2497
   end GCD;
2498
 
2499
   --------------------------
2500
   -- Has_Dimension_System --
2501
   --------------------------
2502
 
2503
   function Has_Dimension_System (Typ : Entity_Id) return Boolean is
2504
   begin
2505
      return Exists (System_Of (Typ));
2506
   end Has_Dimension_System;
2507
 
2508
   ------------------------------
2509
   -- Is_Dim_IO_Package_Entity --
2510
   ------------------------------
2511
 
2512
   function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean is
2513
   begin
2514
      --  Check the package entity corresponds to System.Dim.Float_IO or
2515
      --  System.Dim.Integer_IO.
2516
 
2517
      return
2518
        Is_RTU (E, System_Dim_Float_IO)
2519
          or Is_RTU (E, System_Dim_Integer_IO);
2520
   end Is_Dim_IO_Package_Entity;
2521
 
2522
   -------------------------------------
2523
   -- Is_Dim_IO_Package_Instantiation --
2524
   -------------------------------------
2525
 
2526
   function Is_Dim_IO_Package_Instantiation (N : Node_Id) return Boolean is
2527
      Gen_Id : constant Node_Id := Name (N);
2528
 
2529
   begin
2530
      --  Check that the instantiated package is either System.Dim.Float_IO
2531
      --  or System.Dim.Integer_IO.
2532
 
2533
      return
2534
        Is_Entity_Name (Gen_Id)
2535
          and then Is_Dim_IO_Package_Entity (Entity (Gen_Id));
2536
   end Is_Dim_IO_Package_Instantiation;
2537
 
2538
   ----------------
2539
   -- Is_Invalid --
2540
   ----------------
2541
 
2542
   function Is_Invalid (Position : Dimension_Position) return Boolean is
2543
   begin
2544
      return Position = Invalid_Position;
2545
   end Is_Invalid;
2546
 
2547
   ---------------------
2548
   -- Move_Dimensions --
2549
   ---------------------
2550
 
2551
   procedure Move_Dimensions (From, To : Node_Id) is
2552
      Dims_Of_From : constant Dimension_Type := Dimensions_Of (From);
2553
 
2554
   begin
2555
      --  Copy the dimension of 'From to 'To' and remove dimension of 'From'
2556
 
2557
      if Exists (Dims_Of_From) then
2558
         Set_Dimensions (To, Dims_Of_From);
2559
         Remove_Dimensions (From);
2560
      end if;
2561
   end Move_Dimensions;
2562
 
2563
   ------------
2564
   -- Reduce --
2565
   ------------
2566
 
2567
   function Reduce (X : Rational) return Rational is
2568
   begin
2569
      if X.Numerator = 0 then
2570
         return Zero;
2571
      end if;
2572
 
2573
      declare
2574
         G : constant Int := GCD (X.Numerator, X.Denominator);
2575
      begin
2576
         return Rational'(Numerator =>   Whole (Int (X.Numerator) / G),
2577
                          Denominator => Whole (Int (X.Denominator) / G));
2578
      end;
2579
   end Reduce;
2580
 
2581
   -----------------------
2582
   -- Remove_Dimensions --
2583
   -----------------------
2584
 
2585
   procedure Remove_Dimensions (N : Node_Id) is
2586
      Dims_Of_N : constant Dimension_Type := Dimensions_Of (N);
2587
   begin
2588
      if Exists (Dims_Of_N) then
2589
         Dimension_Table.Remove (N);
2590
      end if;
2591
   end Remove_Dimensions;
2592
 
2593
   ------------------------------
2594
   -- Remove_Dimension_In_Call --
2595
   ------------------------------
2596
 
2597
   procedure Remove_Dimension_In_Call (Call : Node_Id) is
2598
      Actual : Node_Id;
2599
 
2600
   begin
2601
      if Ada_Version < Ada_2012 then
2602
         return;
2603
      end if;
2604
 
2605
      Actual := First (Parameter_Associations (Call));
2606
 
2607
      while Present (Actual) loop
2608
         Remove_Dimensions (Actual);
2609
         Next (Actual);
2610
      end loop;
2611
   end Remove_Dimension_In_Call;
2612
 
2613
   -----------------------------------
2614
   -- Remove_Dimension_In_Statement --
2615
   -----------------------------------
2616
 
2617
   --  Removal of dimension in statement as part of the Analyze_Statements
2618
   --  routine (see package Sem_Ch5).
2619
 
2620
   procedure Remove_Dimension_In_Statement (Stmt : Node_Id) is
2621
   begin
2622
      if Ada_Version < Ada_2012 then
2623
         return;
2624
      end if;
2625
 
2626
      --  Remove dimension in parameter specifications for accept statement
2627
 
2628
      if Nkind (Stmt) = N_Accept_Statement then
2629
         declare
2630
            Param : Node_Id := First (Parameter_Specifications (Stmt));
2631
         begin
2632
            while Present (Param) loop
2633
               Remove_Dimensions (Param);
2634
               Next (Param);
2635
            end loop;
2636
         end;
2637
 
2638
      --  Remove dimension of name and expression in assignments
2639
 
2640
      elsif Nkind (Stmt) = N_Assignment_Statement then
2641
         Remove_Dimensions (Expression (Stmt));
2642
         Remove_Dimensions (Name (Stmt));
2643
      end if;
2644
   end Remove_Dimension_In_Statement;
2645
 
2646
   --------------------
2647
   -- Set_Dimensions --
2648
   --------------------
2649
 
2650
   procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type) is
2651
   begin
2652
      pragma Assert (OK_For_Dimension (Nkind (N)));
2653
      pragma Assert (Exists (Val));
2654
 
2655
      Dimension_Table.Set (N, Val);
2656
   end Set_Dimensions;
2657
 
2658
   ----------------
2659
   -- Set_Symbol --
2660
   ----------------
2661
 
2662
   procedure Set_Symbol (E : Entity_Id; Val : String_Id) is
2663
   begin
2664
      Symbol_Table.Set (E, Val);
2665
   end Set_Symbol;
2666
 
2667
   ---------------
2668
   -- Symbol_Of --
2669
   ---------------
2670
 
2671
   function Symbol_Of (E : Entity_Id) return String_Id is
2672
   begin
2673
      return Symbol_Table.Get (E);
2674
   end Symbol_Of;
2675
 
2676
   -----------------------
2677
   -- Symbol_Table_Hash --
2678
   -----------------------
2679
 
2680
   function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range is
2681
   begin
2682
      return Symbol_Table_Range (Key mod 511);
2683
   end Symbol_Table_Hash;
2684
 
2685
   ---------------
2686
   -- System_Of --
2687
   ---------------
2688
 
2689
   function System_Of (E : Entity_Id) return System_Type is
2690
      Type_Decl : constant Node_Id := Parent (E);
2691
 
2692
   begin
2693
      --  Look for Type_Decl in System_Table
2694
 
2695
      for Dim_Sys in 1 .. System_Table.Last loop
2696
         if Type_Decl = System_Table.Table (Dim_Sys).Type_Decl then
2697
            return System_Table.Table (Dim_Sys);
2698
         end if;
2699
      end loop;
2700
 
2701
      return Null_System;
2702
   end System_Of;
2703
 
2704
end Sem_Dim;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.