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