]>
Commit | Line | Data |
---|---|---|
dec6faf1 AC |
1 | ------------------------------------------------------------------------------ |
2 | -- -- | |
3 | -- GNAT COMPILER COMPONENTS -- | |
4 | -- -- | |
5 | -- S E M _ D I M -- | |
6 | -- -- | |
7 | -- B o d y -- | |
8 | -- -- | |
8d0d46f4 | 9 | -- Copyright (C) 2011-2021, 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 | ||
26 | with Aspects; use Aspects; | |
27 | with Atree; use Atree; | |
76f9c7f4 BD |
28 | with Einfo; use Einfo; |
29 | with Einfo.Entities; use Einfo.Entities; | |
30 | with Einfo.Utils; use Einfo.Utils; | |
dec6faf1 | 31 | with Errout; use Errout; |
d3ef4bd6 | 32 | with Exp_Util; use Exp_Util; |
dec6faf1 AC |
33 | with Lib; use Lib; |
34 | with Namet; use Namet; | |
dec6faf1 AC |
35 | with Nlists; use Nlists; |
36 | with Nmake; use Nmake; | |
37 | with Opt; use Opt; | |
38 | with Rtsfind; use Rtsfind; | |
39 | with Sem; use Sem; | |
ed323421 | 40 | with Sem_Aux; use Sem_Aux; |
dec6faf1 AC |
41 | with Sem_Eval; use Sem_Eval; |
42 | with Sem_Res; use Sem_Res; | |
0929eaeb | 43 | with Sem_Util; use Sem_Util; |
76f9c7f4 BD |
44 | with Sinfo; use Sinfo; |
45 | with Sinfo.Nodes; use Sinfo.Nodes; | |
46 | with Sinfo.Utils; use Sinfo.Utils; | |
dec6faf1 AC |
47 | with Snames; use Snames; |
48 | with Stand; use Stand; | |
49 | with Stringt; use Stringt; | |
50 | with Table; | |
51 | with Tbuild; use Tbuild; | |
52 | with Uintp; use Uintp; | |
53 | with Urealp; use Urealp; | |
54 | ||
55 | with GNAT.HTable; | |
56 | ||
57 | package body Sem_Dim is | |
58 | ||
15954beb | 59 | ------------------------- |
7be8338d | 60 | -- Rational Arithmetic -- |
15954beb | 61 | ------------------------- |
dec6faf1 AC |
62 | |
63 | type Whole is new Int; | |
64 | subtype Positive_Whole is Whole range 1 .. Whole'Last; | |
65 | ||
66 | type Rational is record | |
67 | Numerator : Whole; | |
68 | Denominator : Positive_Whole; | |
69 | end record; | |
70 | ||
6c57023b AC |
71 | Zero : constant Rational := Rational'(Numerator => 0, |
72 | Denominator => 1); | |
73 | ||
74 | No_Rational : constant Rational := Rational'(Numerator => 0, | |
75 | Denominator => 2); | |
76 | -- Used to indicate an expression that cannot be interpreted as a rational | |
77 | -- Returned value of the Create_Rational_From routine when parameter Expr | |
78 | -- is not a static representation of a rational. | |
dec6faf1 AC |
79 | |
80 | -- Rational constructors | |
81 | ||
82 | function "+" (Right : Whole) return Rational; | |
dec6faf1 AC |
83 | function GCD (Left, Right : Whole) return Int; |
84 | function Reduce (X : Rational) return Rational; | |
85 | ||
86 | -- Unary operator for Rational | |
87 | ||
88 | function "-" (Right : Rational) return Rational; | |
6c57023b | 89 | function "abs" (Right : Rational) return Rational; |
dec6faf1 AC |
90 | |
91 | -- Rational operations for Rationals | |
92 | ||
93 | function "+" (Left, Right : Rational) return Rational; | |
94 | function "-" (Left, Right : Rational) return Rational; | |
95 | function "*" (Left, Right : Rational) return Rational; | |
6c57023b | 96 | function "/" (Left, Right : Rational) return Rational; |
dec6faf1 | 97 | |
15954beb | 98 | ------------------ |
7be8338d | 99 | -- System Types -- |
15954beb | 100 | ------------------ |
dec6faf1 | 101 | |
15954beb HK |
102 | Max_Number_Of_Dimensions : constant := 7; |
103 | -- Maximum number of dimensions in a dimension system | |
dec6faf1 | 104 | |
15954beb HK |
105 | High_Position_Bound : constant := Max_Number_Of_Dimensions; |
106 | Invalid_Position : constant := 0; | |
107 | Low_Position_Bound : constant := 1; | |
dec6faf1 | 108 | |
15954beb HK |
109 | subtype Dimension_Position is |
110 | Nat range Invalid_Position .. High_Position_Bound; | |
dec6faf1 | 111 | |
15954beb HK |
112 | type Name_Array is |
113 | array (Dimension_Position range | |
114 | Low_Position_Bound .. High_Position_Bound) of Name_Id; | |
4a28b181 | 115 | -- Store the names of all units within a system |
dec6faf1 | 116 | |
15954beb | 117 | No_Names : constant Name_Array := (others => No_Name); |
dec6faf1 | 118 | |
15954beb HK |
119 | type Symbol_Array is |
120 | array (Dimension_Position range | |
64ac53f4 | 121 | Low_Position_Bound .. High_Position_Bound) of String_Id; |
4a28b181 | 122 | -- Store the symbols of all units within a system |
dec6faf1 | 123 | |
15954beb | 124 | No_Symbols : constant Symbol_Array := (others => No_String); |
54c04d6c | 125 | |
21791d97 AC |
126 | -- The following record should be documented field by field |
127 | ||
15954beb | 128 | type System_Type is record |
df378148 AC |
129 | Type_Decl : Node_Id; |
130 | Unit_Names : Name_Array; | |
131 | Unit_Symbols : Symbol_Array; | |
132 | Dim_Symbols : Symbol_Array; | |
133 | Count : Dimension_Position; | |
15954beb | 134 | end record; |
dec6faf1 | 135 | |
15954beb | 136 | Null_System : constant System_Type := |
df378148 | 137 | (Empty, No_Names, No_Symbols, No_Symbols, Invalid_Position); |
dec6faf1 | 138 | |
15954beb | 139 | subtype System_Id is Nat; |
dec6faf1 | 140 | |
15954beb | 141 | -- The following table maps types to systems |
dec6faf1 | 142 | |
15954beb HK |
143 | package System_Table is new Table.Table ( |
144 | Table_Component_Type => System_Type, | |
145 | Table_Index_Type => System_Id, | |
146 | Table_Low_Bound => 1, | |
147 | Table_Initial => 5, | |
148 | Table_Increment => 5, | |
149 | Table_Name => "System_Table"); | |
dec6faf1 | 150 | |
15954beb | 151 | -------------------- |
7be8338d | 152 | -- Dimension Type -- |
15954beb | 153 | -------------------- |
dec6faf1 | 154 | |
15954beb HK |
155 | type Dimension_Type is |
156 | array (Dimension_Position range | |
64ac53f4 | 157 | Low_Position_Bound .. High_Position_Bound) of Rational; |
dec6faf1 | 158 | |
15954beb | 159 | Null_Dimension : constant Dimension_Type := (others => Zero); |
54c04d6c | 160 | |
15954beb HK |
161 | type Dimension_Table_Range is range 0 .. 510; |
162 | function Dimension_Table_Hash (Key : Node_Id) return Dimension_Table_Range; | |
dec6faf1 | 163 | |
15954beb | 164 | -- The following table associates nodes with dimensions |
dec6faf1 | 165 | |
15954beb | 166 | package Dimension_Table is new |
dec6faf1 | 167 | GNAT.HTable.Simple_HTable |
15954beb HK |
168 | (Header_Num => Dimension_Table_Range, |
169 | Element => Dimension_Type, | |
170 | No_Element => Null_Dimension, | |
dec6faf1 | 171 | Key => Node_Id, |
15954beb | 172 | Hash => Dimension_Table_Hash, |
dec6faf1 AC |
173 | Equal => "="); |
174 | ||
15954beb | 175 | ------------------ |
7be8338d | 176 | -- Symbol Types -- |
15954beb | 177 | ------------------ |
dec6faf1 | 178 | |
15954beb HK |
179 | type Symbol_Table_Range is range 0 .. 510; |
180 | function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range; | |
dec6faf1 | 181 | |
15954beb HK |
182 | -- Each subtype with a dimension has a symbolic representation of the |
183 | -- related unit. This table establishes a relation between the subtype | |
184 | -- and the symbol. | |
185 | ||
186 | package Symbol_Table is new | |
dec6faf1 | 187 | GNAT.HTable.Simple_HTable |
15954beb | 188 | (Header_Num => Symbol_Table_Range, |
dec6faf1 AC |
189 | Element => String_Id, |
190 | No_Element => No_String, | |
191 | Key => Entity_Id, | |
15954beb | 192 | Hash => Symbol_Table_Hash, |
dec6faf1 AC |
193 | Equal => "="); |
194 | ||
15954beb HK |
195 | -- The following array enumerates all contexts which may contain or |
196 | -- produce a dimension. | |
197 | ||
198 | OK_For_Dimension : constant array (Node_Kind) of Boolean := | |
199 | (N_Attribute_Reference => True, | |
74a78a4f | 200 | N_Case_Expression => True, |
0929eaeb | 201 | N_Expanded_Name => True, |
d29f68cf | 202 | N_Explicit_Dereference => True, |
15954beb HK |
203 | N_Defining_Identifier => True, |
204 | N_Function_Call => True, | |
205 | N_Identifier => True, | |
cc3a2986 | 206 | N_If_Expression => True, |
15954beb HK |
207 | N_Indexed_Component => True, |
208 | N_Integer_Literal => True, | |
209 | N_Op_Abs => True, | |
210 | N_Op_Add => True, | |
211 | N_Op_Divide => True, | |
212 | N_Op_Expon => True, | |
213 | N_Op_Minus => True, | |
214 | N_Op_Mod => True, | |
215 | N_Op_Multiply => True, | |
216 | N_Op_Plus => True, | |
217 | N_Op_Rem => True, | |
218 | N_Op_Subtract => True, | |
219 | N_Qualified_Expression => True, | |
220 | N_Real_Literal => True, | |
221 | N_Selected_Component => True, | |
222 | N_Slice => True, | |
223 | N_Type_Conversion => True, | |
224 | N_Unchecked_Type_Conversion => True, | |
225 | ||
226 | others => False); | |
227 | ||
dec6faf1 AC |
228 | ----------------------- |
229 | -- Local Subprograms -- | |
230 | ----------------------- | |
231 | ||
232 | procedure Analyze_Dimension_Assignment_Statement (N : Node_Id); | |
88115c2a AC |
233 | -- Subroutine of Analyze_Dimension for assignment statement. Check that the |
234 | -- dimensions of the left-hand side and the right-hand side of N match. | |
dec6faf1 AC |
235 | |
236 | procedure Analyze_Dimension_Binary_Op (N : Node_Id); | |
88115c2a AC |
237 | -- Subroutine of Analyze_Dimension for binary operators. Check the |
238 | -- dimensions of the right and the left operand permit the operation. | |
239 | -- Then, evaluate the resulting dimensions for each binary operator. | |
dec6faf1 AC |
240 | |
241 | procedure Analyze_Dimension_Component_Declaration (N : Node_Id); | |
88115c2a AC |
242 | -- Subroutine of Analyze_Dimension for component declaration. Check that |
243 | -- the dimensions of the type of N and of the expression match. | |
dec6faf1 AC |
244 | |
245 | procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id); | |
88115c2a AC |
246 | -- Subroutine of Analyze_Dimension for extended return statement. Check |
247 | -- that the dimensions of the returned type and of the returned object | |
248 | -- match. | |
dec6faf1 | 249 | |
dec6faf1 | 250 | procedure Analyze_Dimension_Has_Etype (N : Node_Id); |
6c57023b AC |
251 | -- Subroutine of Analyze_Dimension for a subset of N_Has_Etype denoted by |
252 | -- the list below: | |
88115c2a AC |
253 | -- N_Attribute_Reference |
254 | -- N_Identifier | |
255 | -- N_Indexed_Component | |
256 | -- N_Qualified_Expression | |
257 | -- N_Selected_Component | |
258 | -- N_Slice | |
259 | -- N_Type_Conversion | |
260 | -- N_Unchecked_Type_Conversion | |
dec6faf1 | 261 | |
74a78a4f AC |
262 | procedure Analyze_Dimension_Case_Expression (N : Node_Id); |
263 | -- Verify that all alternatives have the same dimension | |
264 | ||
265 | procedure Analyze_Dimension_If_Expression (N : Node_Id); | |
266 | -- Verify that all alternatives have the same dimension | |
267 | ||
df9ad6bc AC |
268 | procedure Analyze_Dimension_Number_Declaration (N : Node_Id); |
269 | -- Procedure to analyze dimension of expression in a number declaration. | |
d1915cb8 | 270 | -- This allows a named number to have nontrivial dimensions, while by |
df9ad6bc AC |
271 | -- default a named number is dimensionless. |
272 | ||
dec6faf1 | 273 | procedure Analyze_Dimension_Object_Declaration (N : Node_Id); |
88115c2a AC |
274 | -- Subroutine of Analyze_Dimension for object declaration. Check that |
275 | -- the dimensions of the object type and the dimensions of the expression | |
276 | -- (if expression is present) match. Note that when the expression is | |
9a7e930f | 277 | -- a literal, no error is returned. This special case allows object |
88115c2a | 278 | -- declaration such as: m : constant Length := 1.0; |
dec6faf1 AC |
279 | |
280 | procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id); | |
88115c2a AC |
281 | -- Subroutine of Analyze_Dimension for object renaming declaration. Check |
282 | -- the dimensions of the type and of the renamed object name of N match. | |
dec6faf1 AC |
283 | |
284 | procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id); | |
285 | -- Subroutine of Analyze_Dimension for simple return statement | |
6c57023b AC |
286 | -- Check that the dimensions of the returned type and of the returned |
287 | -- expression match. | |
dec6faf1 AC |
288 | |
289 | procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id); | |
88115c2a AC |
290 | -- Subroutine of Analyze_Dimension for subtype declaration. Propagate the |
291 | -- dimensions from the parent type to the identifier of N. Note that if | |
292 | -- both the identifier and the parent type of N are not dimensionless, | |
9a7e930f | 293 | -- return an error. |
dec6faf1 | 294 | |
ed323421 AC |
295 | procedure Analyze_Dimension_Type_Conversion (N : Node_Id); |
296 | -- Type conversions handle conversions between literals and dimensioned | |
297 | -- types, from dimensioned types to their base type, and between different | |
298 | -- dimensioned systems. Dimensions of the conversion are obtained either | |
299 | -- from those of the expression, or from the target type, and dimensional | |
300 | -- consistency must be checked when converting between values belonging | |
301 | -- to different dimensioned systems. | |
302 | ||
dec6faf1 | 303 | procedure Analyze_Dimension_Unary_Op (N : Node_Id); |
88115c2a AC |
304 | -- Subroutine of Analyze_Dimension for unary operators. For Plus, Minus and |
305 | -- Abs operators, propagate the dimensions from the operand to N. | |
dec6faf1 | 306 | |
88115c2a AC |
307 | function Create_Rational_From |
308 | (Expr : Node_Id; | |
309 | Complain : Boolean) return Rational; | |
6c57023b AC |
310 | -- Given an arbitrary expression Expr, return a valid rational if Expr can |
311 | -- be interpreted as a rational. Otherwise return No_Rational and also an | |
312 | -- error message if Complain is set to True. | |
15954beb HK |
313 | |
314 | function Dimensions_Of (N : Node_Id) return Dimension_Type; | |
315 | -- Return the dimension vector of node N | |
dec6faf1 | 316 | |
0929eaeb AC |
317 | function Dimensions_Msg_Of |
318 | (N : Node_Id; | |
319 | Description_Needed : Boolean := False) return String; | |
320 | -- Given a node N, return the dimension symbols of N, preceded by "has | |
4a28b181 AC |
321 | -- dimension" if Description_Needed. if N is dimensionless, return "'[']", |
322 | -- or "is dimensionless" if Description_Needed. | |
0929eaeb | 323 | |
ed323421 AC |
324 | function Dimension_System_Root (T : Entity_Id) return Entity_Id; |
325 | -- Given a type that has dimension information, return the type that is the | |
326 | -- root of its dimension system, e.g. Mks_Type. If T is not a dimensioned | |
327 | -- type, i.e. a standard numeric type, return Empty. | |
328 | ||
0929eaeb | 329 | procedure Dim_Warning_For_Numeric_Literal (N : Node_Id; Typ : Entity_Id); |
4a28b181 AC |
330 | -- Issue a warning on the given numeric literal N to indicate that the |
331 | -- compiler made the assumption that the literal is not dimensionless | |
0929eaeb | 332 | -- but has the dimension of Typ. |
6c57023b | 333 | |
dec6faf1 | 334 | procedure Eval_Op_Expon_With_Rational_Exponent |
6c57023b AC |
335 | (N : Node_Id; |
336 | Exponent_Value : Rational); | |
88115c2a | 337 | -- Evaluate the exponent it is a rational and the operand has a dimension |
dec6faf1 | 338 | |
15954beb | 339 | function Exists (Dim : Dimension_Type) return Boolean; |
88115c2a | 340 | -- Returns True iff Dim does not denote the null dimension |
15954beb | 341 | |
0929eaeb AC |
342 | function Exists (Str : String_Id) return Boolean; |
343 | -- Returns True iff Str does not denote No_String | |
344 | ||
15954beb | 345 | function Exists (Sys : System_Type) return Boolean; |
88115c2a | 346 | -- Returns True iff Sys does not denote the null system |
15954beb | 347 | |
df378148 AC |
348 | function From_Dim_To_Str_Of_Dim_Symbols |
349 | (Dims : Dimension_Type; | |
350 | System : System_Type; | |
351 | In_Error_Msg : Boolean := False) return String_Id; | |
352 | -- Given a dimension vector and a dimension system, return the proper | |
353 | -- string of dimension symbols. If In_Error_Msg is True (i.e. the String_Id | |
354 | -- will be used to issue an error message) then this routine has a special | |
4a28b181 | 355 | -- handling for the insertion characters * or [ which must be preceded by |
026c3cfd | 356 | -- a quote ' to be placed literally into the message. |
df378148 AC |
357 | |
358 | function From_Dim_To_Str_Of_Unit_Symbols | |
15954beb HK |
359 | (Dims : Dimension_Type; |
360 | System : System_Type) return String_Id; | |
dec6faf1 | 361 | -- Given a dimension vector and a dimension system, return the proper |
df378148 | 362 | -- string of unit symbols. |
dec6faf1 | 363 | |
2293611f AC |
364 | function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean; |
365 | -- Return True if E is the package entity of System.Dim.Float_IO or | |
366 | -- System.Dim.Integer_IO. | |
367 | ||
15954beb | 368 | function Is_Invalid (Position : Dimension_Position) return Boolean; |
88115c2a | 369 | -- Return True if Pos denotes the invalid position |
dec6faf1 | 370 | |
ba914484 VP |
371 | procedure Move_Dimensions (From : Node_Id; To : Node_Id); |
372 | -- Copy dimension vector of From to To and delete dimension vector of From | |
373 | ||
dec6faf1 | 374 | procedure Remove_Dimensions (N : Node_Id); |
15954beb | 375 | -- Remove the dimension vector of node N |
dec6faf1 | 376 | |
15954beb HK |
377 | procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type); |
378 | -- Associate a dimension vector with a node | |
dec6faf1 | 379 | |
15954beb HK |
380 | procedure Set_Symbol (E : Entity_Id; Val : String_Id); |
381 | -- Associate a symbol representation of a dimension vector with a subtype | |
54c04d6c | 382 | |
15954beb HK |
383 | function Symbol_Of (E : Entity_Id) return String_Id; |
384 | -- E denotes a subtype with a dimension. Return the symbol representation | |
385 | -- of the dimension vector. | |
54c04d6c | 386 | |
15954beb HK |
387 | function System_Of (E : Entity_Id) return System_Type; |
388 | -- E denotes a type, return associated system of the type if it has one | |
dec6faf1 | 389 | |
15954beb HK |
390 | --------- |
391 | -- "+" -- | |
392 | --------- | |
dec6faf1 | 393 | |
15954beb HK |
394 | function "+" (Right : Whole) return Rational is |
395 | begin | |
4a28b181 | 396 | return Rational'(Numerator => Right, Denominator => 1); |
15954beb | 397 | end "+"; |
dec6faf1 | 398 | |
15954beb HK |
399 | function "+" (Left, Right : Rational) return Rational is |
400 | R : constant Rational := | |
eedc5882 HK |
401 | Rational'(Numerator => Left.Numerator * Right.Denominator + |
402 | Left.Denominator * Right.Numerator, | |
403 | Denominator => Left.Denominator * Right.Denominator); | |
15954beb HK |
404 | begin |
405 | return Reduce (R); | |
406 | end "+"; | |
dec6faf1 | 407 | |
15954beb HK |
408 | --------- |
409 | -- "-" -- | |
410 | --------- | |
dec6faf1 | 411 | |
15954beb HK |
412 | function "-" (Right : Rational) return Rational is |
413 | begin | |
4a28b181 | 414 | return Rational'(Numerator => -Right.Numerator, |
15954beb HK |
415 | Denominator => Right.Denominator); |
416 | end "-"; | |
dec6faf1 | 417 | |
15954beb HK |
418 | function "-" (Left, Right : Rational) return Rational is |
419 | R : constant Rational := | |
4a28b181 AC |
420 | Rational'(Numerator => Left.Numerator * Right.Denominator - |
421 | Left.Denominator * Right.Numerator, | |
15954beb | 422 | Denominator => Left.Denominator * Right.Denominator); |
dec6faf1 | 423 | |
15954beb HK |
424 | begin |
425 | return Reduce (R); | |
426 | end "-"; | |
dec6faf1 | 427 | |
15954beb HK |
428 | --------- |
429 | -- "*" -- | |
430 | --------- | |
dec6faf1 | 431 | |
15954beb HK |
432 | function "*" (Left, Right : Rational) return Rational is |
433 | R : constant Rational := | |
4a28b181 | 434 | Rational'(Numerator => Left.Numerator * Right.Numerator, |
15954beb | 435 | Denominator => Left.Denominator * Right.Denominator); |
15954beb HK |
436 | begin |
437 | return Reduce (R); | |
438 | end "*"; | |
dec6faf1 | 439 | |
15954beb HK |
440 | --------- |
441 | -- "/" -- | |
442 | --------- | |
dec6faf1 | 443 | |
6c57023b AC |
444 | function "/" (Left, Right : Rational) return Rational is |
445 | R : constant Rational := abs Right; | |
446 | L : Rational := Left; | |
dec6faf1 | 447 | |
15954beb | 448 | begin |
6c57023b AC |
449 | if Right.Numerator < 0 then |
450 | L.Numerator := Whole (-Integer (L.Numerator)); | |
15954beb | 451 | end if; |
dec6faf1 | 452 | |
4a28b181 | 453 | return Reduce (Rational'(Numerator => L.Numerator * R.Denominator, |
6c57023b | 454 | Denominator => L.Denominator * R.Numerator)); |
15954beb | 455 | end "/"; |
df378148 | 456 | |
6c57023b AC |
457 | ----------- |
458 | -- "abs" -- | |
459 | ----------- | |
460 | ||
461 | function "abs" (Right : Rational) return Rational is | |
462 | begin | |
4a28b181 | 463 | return Rational'(Numerator => abs Right.Numerator, |
6c57023b AC |
464 | Denominator => Right.Denominator); |
465 | end "abs"; | |
dec6faf1 | 466 | |
15954beb HK |
467 | ------------------------------ |
468 | -- Analyze_Aspect_Dimension -- | |
469 | ------------------------------ | |
dec6faf1 | 470 | |
7be8338d RD |
471 | -- with Dimension => |
472 | -- ([Symbol =>] SYMBOL, DIMENSION_VALUE {, DIMENSION_Value}) | |
df378148 AC |
473 | -- |
474 | -- SYMBOL ::= STRING_LITERAL | CHARACTER_LITERAL | |
475 | ||
476 | -- DIMENSION_VALUE ::= | |
477 | -- RATIONAL | |
7be8338d | 478 | -- | others => RATIONAL |
15954beb | 479 | -- | DISCRETE_CHOICE_LIST => RATIONAL |
df378148 | 480 | |
7be8338d | 481 | -- RATIONAL ::= [-] NUMERIC_LITERAL [/ NUMERIC_LITERAL] |
dec6faf1 | 482 | |
df378148 AC |
483 | -- Note that when the dimensioned type is an integer type, then any |
484 | -- dimension value must be an integer literal. | |
dec6faf1 | 485 | |
15954beb HK |
486 | procedure Analyze_Aspect_Dimension |
487 | (N : Node_Id; | |
6c57023b | 488 | Id : Entity_Id; |
15954beb HK |
489 | Aggr : Node_Id) |
490 | is | |
7be8338d | 491 | Def_Id : constant Entity_Id := Defining_Identifier (N); |
15954beb HK |
492 | |
493 | Processed : array (Dimension_Type'Range) of Boolean := (others => False); | |
494 | -- This array is used when processing ranges or Others_Choice as part of | |
495 | -- the dimension aggregate. | |
496 | ||
497 | Dimensions : Dimension_Type := Null_Dimension; | |
498 | ||
499 | procedure Extract_Power | |
500 | (Expr : Node_Id; | |
501 | Position : Dimension_Position); | |
502 | -- Given an expression with denotes a rational number, read the number | |
503 | -- and associate it with Position in Dimensions. | |
504 | ||
15954beb HK |
505 | function Position_In_System |
506 | (Id : Node_Id; | |
507 | System : System_Type) return Dimension_Position; | |
508 | -- Given an identifier which denotes a dimension, return the position of | |
509 | -- that dimension within System. | |
510 | ||
511 | ------------------- | |
512 | -- Extract_Power -- | |
513 | ------------------- | |
514 | ||
515 | procedure Extract_Power | |
516 | (Expr : Node_Id; | |
517 | Position : Dimension_Position) | |
518 | is | |
519 | begin | |
e201023c PMR |
520 | Dimensions (Position) := Create_Rational_From (Expr, True); |
521 | Processed (Position) := True; | |
df378148 | 522 | |
e201023c PMR |
523 | -- If the dimensioned root type is an integer type, it is not |
524 | -- particularly useful, and fractional dimensions do not make | |
525 | -- much sense for such types, so previously we used to reject | |
526 | -- dimensions of integer types that were not integer literals. | |
527 | -- However, the manipulation of dimensions does not depend on | |
528 | -- the kind of root type, so we can accept this usage for rare | |
529 | -- cases where dimensions are specified for integer values. | |
dec6faf1 | 530 | |
15954beb HK |
531 | end Extract_Power; |
532 | ||
15954beb HK |
533 | ------------------------ |
534 | -- Position_In_System -- | |
535 | ------------------------ | |
dec6faf1 | 536 | |
15954beb HK |
537 | function Position_In_System |
538 | (Id : Node_Id; | |
539 | System : System_Type) return Dimension_Position | |
dec6faf1 | 540 | is |
15954beb | 541 | Dimension_Name : constant Name_Id := Chars (Id); |
dec6faf1 AC |
542 | |
543 | begin | |
df378148 AC |
544 | for Position in System.Unit_Names'Range loop |
545 | if Dimension_Name = System.Unit_Names (Position) then | |
15954beb | 546 | return Position; |
dec6faf1 | 547 | end if; |
dec6faf1 AC |
548 | end loop; |
549 | ||
15954beb HK |
550 | return Invalid_Position; |
551 | end Position_In_System; | |
dec6faf1 | 552 | |
15954beb | 553 | -- Local variables |
dec6faf1 | 554 | |
15954beb HK |
555 | Assoc : Node_Id; |
556 | Choice : Node_Id; | |
557 | Expr : Node_Id; | |
558 | Num_Choices : Nat := 0; | |
559 | Num_Dimensions : Nat := 0; | |
560 | Others_Seen : Boolean := False; | |
561 | Position : Nat := 0; | |
6c57023b | 562 | Sub_Ind : Node_Id; |
df378148 AC |
563 | Symbol : String_Id := No_String; |
564 | Symbol_Expr : Node_Id; | |
6c57023b AC |
565 | System : System_Type; |
566 | Typ : Entity_Id; | |
567 | ||
88115c2a | 568 | Errors_Count : Nat; |
6c57023b | 569 | -- Errors_Count is a count of errors detected by the compiler so far |
df378148 | 570 | -- just before the extraction of symbol, names and values in the |
21791d97 | 571 | -- aggregate (Step 2). |
88115c2a AC |
572 | -- |
573 | -- At the end of the analysis, there is a check to verify that this | |
574 | -- count equals to Serious_Errors_Detected i.e. no erros have been | |
575 | -- encountered during the process. Otherwise the Dimension_Table is | |
576 | -- not filled. | |
dec6faf1 AC |
577 | |
578 | -- Start of processing for Analyze_Aspect_Dimension | |
579 | ||
580 | begin | |
15954beb | 581 | -- STEP 1: Legality of aspect |
dec6faf1 | 582 | |
15954beb | 583 | if Nkind (N) /= N_Subtype_Declaration then |
6c57023b AC |
584 | Error_Msg_NE ("aspect& must apply to subtype declaration", N, Id); |
585 | return; | |
586 | end if; | |
587 | ||
588 | Sub_Ind := Subtype_Indication (N); | |
589 | Typ := Etype (Sub_Ind); | |
590 | System := System_Of (Typ); | |
591 | ||
592 | if Nkind (Sub_Ind) = N_Subtype_Indication then | |
88115c2a AC |
593 | Error_Msg_NE |
594 | ("constraint not allowed with aspect&", Constraint (Sub_Ind), Id); | |
dec6faf1 AC |
595 | return; |
596 | end if; | |
597 | ||
15954beb HK |
598 | -- The dimension declarations are useless if the parent type does not |
599 | -- declare a valid system. | |
dec6faf1 | 600 | |
15954beb | 601 | if not Exists (System) then |
88115c2a AC |
602 | Error_Msg_NE |
603 | ("parent type of& lacks dimension system", Sub_Ind, Def_Id); | |
dec6faf1 AC |
604 | return; |
605 | end if; | |
606 | ||
df378148 AC |
607 | if Nkind (Aggr) /= N_Aggregate then |
608 | Error_Msg_N ("aggregate expected", Aggr); | |
609 | return; | |
610 | end if; | |
611 | ||
612 | -- STEP 2: Symbol, Names and values extraction | |
613 | ||
614 | -- Get the number of errors detected by the compiler so far | |
615 | ||
616 | Errors_Count := Serious_Errors_Detected; | |
617 | ||
618 | -- STEP 2a: Symbol extraction | |
619 | ||
620 | -- The first entry in the aggregate may be the symbolic representation | |
621 | -- of the quantity. | |
dec6faf1 | 622 | |
df378148 | 623 | -- Positional symbol argument |
dec6faf1 | 624 | |
df378148 | 625 | Symbol_Expr := First (Expressions (Aggr)); |
dec6faf1 | 626 | |
df378148 AC |
627 | -- Named symbol argument |
628 | ||
629 | if No (Symbol_Expr) | |
4a08c95c AC |
630 | or else Nkind (Symbol_Expr) not in |
631 | N_Character_Literal | N_String_Literal | |
15954beb | 632 | then |
df378148 | 633 | Symbol_Expr := Empty; |
dec6faf1 | 634 | |
df378148 | 635 | -- Component associations present |
dec6faf1 | 636 | |
df378148 AC |
637 | if Present (Component_Associations (Aggr)) then |
638 | Assoc := First (Component_Associations (Aggr)); | |
639 | Choice := First (Choices (Assoc)); | |
6c57023b | 640 | |
21791d97 AC |
641 | if No (Next (Choice)) and then Nkind (Choice) = N_Identifier then |
642 | ||
df378148 AC |
643 | -- Symbol component association is present |
644 | ||
645 | if Chars (Choice) = Name_Symbol then | |
646 | Num_Choices := Num_Choices + 1; | |
647 | Symbol_Expr := Expression (Assoc); | |
648 | ||
649 | -- Verify symbol expression is a string or a character | |
650 | ||
4a08c95c AC |
651 | if Nkind (Symbol_Expr) not in |
652 | N_Character_Literal | N_String_Literal | |
df378148 AC |
653 | then |
654 | Symbol_Expr := Empty; | |
21791d97 AC |
655 | Error_Msg_N |
656 | ("symbol expression must be character or string", | |
657 | Symbol_Expr); | |
df378148 AC |
658 | end if; |
659 | ||
660 | -- Special error if no Symbol choice but expression is string | |
661 | -- or character. | |
662 | ||
4a08c95c AC |
663 | elsif Nkind (Expression (Assoc)) in |
664 | N_Character_Literal | N_String_Literal | |
df378148 AC |
665 | then |
666 | Num_Choices := Num_Choices + 1; | |
4a28b181 AC |
667 | Error_Msg_N |
668 | ("optional component Symbol expected, found&", Choice); | |
df378148 AC |
669 | end if; |
670 | end if; | |
671 | end if; | |
672 | end if; | |
673 | ||
674 | -- STEP 2b: Names and values extraction | |
6c57023b | 675 | |
15954beb | 676 | -- Positional elements |
dec6faf1 | 677 | |
df378148 AC |
678 | Expr := First (Expressions (Aggr)); |
679 | ||
680 | -- Skip the symbol expression when present | |
681 | ||
21791d97 | 682 | if Present (Symbol_Expr) and then Num_Choices = 0 then |
cbbe41d1 | 683 | Next (Expr); |
df378148 AC |
684 | end if; |
685 | ||
15954beb HK |
686 | Position := Low_Position_Bound; |
687 | while Present (Expr) loop | |
688 | if Position > High_Position_Bound then | |
689 | Error_Msg_N | |
6c57023b AC |
690 | ("type& has more dimensions than system allows", Def_Id); |
691 | exit; | |
dec6faf1 | 692 | end if; |
dec6faf1 | 693 | |
15954beb | 694 | Extract_Power (Expr, Position); |
dec6faf1 | 695 | |
15954beb HK |
696 | Position := Position + 1; |
697 | Num_Dimensions := Num_Dimensions + 1; | |
dec6faf1 | 698 | |
15954beb | 699 | Next (Expr); |
dec6faf1 AC |
700 | end loop; |
701 | ||
15954beb | 702 | -- Named elements |
dec6faf1 | 703 | |
15954beb | 704 | Assoc := First (Component_Associations (Aggr)); |
df378148 AC |
705 | |
706 | -- Skip the symbol association when present | |
707 | ||
708 | if Num_Choices = 1 then | |
709 | Next (Assoc); | |
710 | end if; | |
711 | ||
15954beb | 712 | while Present (Assoc) loop |
21791d97 | 713 | Expr := Expression (Assoc); |
df378148 | 714 | |
21791d97 | 715 | Choice := First (Choices (Assoc)); |
15954beb | 716 | while Present (Choice) loop |
dec6faf1 | 717 | |
15954beb | 718 | -- Identifier case: NAME => EXPRESSION |
dec6faf1 AC |
719 | |
720 | if Nkind (Choice) = N_Identifier then | |
15954beb | 721 | Position := Position_In_System (Choice, System); |
dec6faf1 | 722 | |
15954beb | 723 | if Is_Invalid (Position) then |
6c57023b AC |
724 | Error_Msg_N ("dimension name& not part of system", Choice); |
725 | else | |
726 | Extract_Power (Expr, Position); | |
dec6faf1 AC |
727 | end if; |
728 | ||
15954beb | 729 | -- Range case: NAME .. NAME => EXPRESSION |
dec6faf1 AC |
730 | |
731 | elsif Nkind (Choice) = N_Range then | |
732 | declare | |
15954beb HK |
733 | Low : constant Node_Id := Low_Bound (Choice); |
734 | High : constant Node_Id := High_Bound (Choice); | |
735 | Low_Pos : Dimension_Position; | |
736 | High_Pos : Dimension_Position; | |
dec6faf1 AC |
737 | |
738 | begin | |
15954beb HK |
739 | if Nkind (Low) /= N_Identifier then |
740 | Error_Msg_N ("bound must denote a dimension name", Low); | |
88115c2a | 741 | |
15954beb HK |
742 | elsif Nkind (High) /= N_Identifier then |
743 | Error_Msg_N ("bound must denote a dimension name", High); | |
88115c2a | 744 | |
6c57023b AC |
745 | else |
746 | Low_Pos := Position_In_System (Low, System); | |
747 | High_Pos := Position_In_System (High, System); | |
15954beb | 748 | |
6c57023b AC |
749 | if Is_Invalid (Low_Pos) then |
750 | Error_Msg_N ("dimension name& not part of system", | |
751 | Low); | |
15954beb | 752 | |
6c57023b AC |
753 | elsif Is_Invalid (High_Pos) then |
754 | Error_Msg_N ("dimension name& not part of system", | |
755 | High); | |
15954beb | 756 | |
6c57023b AC |
757 | elsif Low_Pos > High_Pos then |
758 | Error_Msg_N ("expected low to high range", Choice); | |
15954beb | 759 | |
6c57023b AC |
760 | else |
761 | for Position in Low_Pos .. High_Pos loop | |
762 | Extract_Power (Expr, Position); | |
763 | end loop; | |
764 | end if; | |
15954beb | 765 | end if; |
dec6faf1 AC |
766 | end; |
767 | ||
15954beb | 768 | -- Others case: OTHERS => EXPRESSION |
dec6faf1 AC |
769 | |
770 | elsif Nkind (Choice) = N_Others_Choice then | |
21791d97 | 771 | if Present (Next (Choice)) or else Present (Prev (Choice)) then |
15954beb HK |
772 | Error_Msg_N |
773 | ("OTHERS must appear alone in a choice list", Choice); | |
dec6faf1 | 774 | |
15954beb | 775 | elsif Present (Next (Assoc)) then |
dec6faf1 | 776 | Error_Msg_N |
15954beb | 777 | ("OTHERS must appear last in an aggregate", Choice); |
15954beb HK |
778 | |
779 | elsif Others_Seen then | |
780 | Error_Msg_N ("multiple OTHERS not allowed", Choice); | |
dec6faf1 | 781 | |
6c57023b AC |
782 | else |
783 | -- Fill the non-processed dimensions with the default value | |
784 | -- supplied by others. | |
dec6faf1 | 785 | |
6c57023b AC |
786 | for Position in Processed'Range loop |
787 | if not Processed (Position) then | |
788 | Extract_Power (Expr, Position); | |
789 | end if; | |
790 | end loop; | |
791 | end if; | |
15954beb | 792 | |
6c57023b | 793 | Others_Seen := True; |
dec6faf1 | 794 | |
77a40ec1 | 795 | -- All other cases are illegal declarations of dimension names |
15954beb | 796 | |
dec6faf1 | 797 | else |
6c57023b | 798 | Error_Msg_NE ("wrong syntax for aspect&", Choice, Id); |
dec6faf1 AC |
799 | end if; |
800 | ||
15954beb | 801 | Num_Choices := Num_Choices + 1; |
15954beb HK |
802 | Next (Choice); |
803 | end loop; | |
dec6faf1 | 804 | |
15954beb | 805 | Num_Dimensions := Num_Dimensions + 1; |
15954beb HK |
806 | Next (Assoc); |
807 | end loop; | |
dec6faf1 | 808 | |
df378148 | 809 | -- STEP 3: Consistency of system and dimensions |
dec6faf1 | 810 | |
df378148 AC |
811 | if Present (First (Expressions (Aggr))) |
812 | and then (First (Expressions (Aggr)) /= Symbol_Expr | |
4a28b181 | 813 | or else Present (Next (Symbol_Expr))) |
15954beb HK |
814 | and then (Num_Choices > 1 |
815 | or else (Num_Choices = 1 and then not Others_Seen)) | |
816 | then | |
817 | Error_Msg_N | |
818 | ("named associations cannot follow positional associations", Aggr); | |
df378148 | 819 | end if; |
dec6faf1 | 820 | |
df378148 | 821 | if Num_Dimensions > System.Count then |
6c57023b | 822 | Error_Msg_N ("type& has more dimensions than system allows", Def_Id); |
dec6faf1 | 823 | |
15954beb | 824 | elsif Num_Dimensions < System.Count and then not Others_Seen then |
6c57023b | 825 | Error_Msg_N ("type& has less dimensions than system allows", Def_Id); |
dec6faf1 AC |
826 | end if; |
827 | ||
df378148 | 828 | -- STEP 4: Dimension symbol extraction |
dec6faf1 | 829 | |
df378148 AC |
830 | if Present (Symbol_Expr) then |
831 | if Nkind (Symbol_Expr) = N_Character_Literal then | |
832 | Start_String; | |
833 | Store_String_Char (UI_To_CC (Char_Literal_Value (Symbol_Expr))); | |
834 | Symbol := End_String; | |
88115c2a | 835 | |
df378148 AC |
836 | else |
837 | Symbol := Strval (Symbol_Expr); | |
838 | end if; | |
15954beb | 839 | |
df378148 AC |
840 | if String_Length (Symbol) = 0 then |
841 | Error_Msg_N ("empty string not allowed here", Symbol_Expr); | |
842 | end if; | |
dec6faf1 AC |
843 | end if; |
844 | ||
df378148 | 845 | -- STEP 5: Storage of extracted values |
dec6faf1 | 846 | |
6c57023b | 847 | -- Check that no errors have been detected during the analysis |
15954beb | 848 | |
6c57023b | 849 | if Errors_Count = Serious_Errors_Detected then |
df378148 | 850 | |
21791d97 AC |
851 | -- Check for useless declaration |
852 | ||
853 | if Symbol = No_String and then not Exists (Dimensions) then | |
df378148 AC |
854 | Error_Msg_N ("useless dimension declaration", Aggr); |
855 | end if; | |
856 | ||
857 | if Symbol /= No_String then | |
6c57023b AC |
858 | Set_Symbol (Def_Id, Symbol); |
859 | end if; | |
860 | ||
861 | if Exists (Dimensions) then | |
862 | Set_Dimensions (Def_Id, Dimensions); | |
863 | end if; | |
dec6faf1 AC |
864 | end if; |
865 | end Analyze_Aspect_Dimension; | |
866 | ||
867 | ------------------------------------- | |
868 | -- Analyze_Aspect_Dimension_System -- | |
869 | ------------------------------------- | |
870 | ||
7be8338d | 871 | -- with Dimension_System => (DIMENSION {, DIMENSION}); |
54c04d6c | 872 | |
df378148 AC |
873 | -- DIMENSION ::= ( |
874 | -- [Unit_Name =>] IDENTIFIER, | |
875 | -- [Unit_Symbol =>] SYMBOL, | |
876 | -- [Dim_Symbol =>] SYMBOL) | |
dec6faf1 AC |
877 | |
878 | procedure Analyze_Aspect_Dimension_System | |
879 | (N : Node_Id; | |
6c57023b AC |
880 | Id : Entity_Id; |
881 | Aggr : Node_Id) | |
dec6faf1 | 882 | is |
6c57023b AC |
883 | function Is_Derived_Numeric_Type (N : Node_Id) return Boolean; |
884 | -- Determine whether type declaration N denotes a numeric derived type | |
dec6faf1 AC |
885 | |
886 | ------------------------------- | |
6c57023b | 887 | -- Is_Derived_Numeric_Type -- |
dec6faf1 AC |
888 | ------------------------------- |
889 | ||
6c57023b | 890 | function Is_Derived_Numeric_Type (N : Node_Id) return Boolean is |
dec6faf1 | 891 | begin |
6c57023b AC |
892 | return |
893 | Nkind (N) = N_Full_Type_Declaration | |
894 | and then Nkind (Type_Definition (N)) = N_Derived_Type_Definition | |
895 | and then Is_Numeric_Type | |
896 | (Entity (Subtype_Indication (Type_Definition (N)))); | |
897 | end Is_Derived_Numeric_Type; | |
898 | ||
88115c2a | 899 | -- Local variables |
6c57023b | 900 | |
df378148 AC |
901 | Assoc : Node_Id; |
902 | Choice : Node_Id; | |
903 | Dim_Aggr : Node_Id; | |
6c57023b | 904 | Dim_Symbol : Node_Id; |
dcd5fd67 PMR |
905 | Dim_Symbols : Symbol_Array := No_Symbols; |
906 | Dim_System : System_Type := Null_System; | |
907 | Position : Dimension_Position := Invalid_Position; | |
df378148 | 908 | Unit_Name : Node_Id; |
dcd5fd67 | 909 | Unit_Names : Name_Array := No_Names; |
df378148 | 910 | Unit_Symbol : Node_Id; |
dcd5fd67 | 911 | Unit_Symbols : Symbol_Array := No_Symbols; |
6c57023b AC |
912 | |
913 | Errors_Count : Nat; | |
914 | -- Errors_Count is a count of errors detected by the compiler so far | |
915 | -- just before the extraction of names and symbols in the aggregate | |
916 | -- (Step 3). | |
88115c2a AC |
917 | -- |
918 | -- At the end of the analysis, there is a check to verify that this | |
919 | -- count equals Serious_Errors_Detected i.e. no errors have been | |
920 | -- encountered during the process. Otherwise the System_Table is | |
921 | -- not filled. | |
dec6faf1 | 922 | |
6c57023b | 923 | -- Start of processing for Analyze_Aspect_Dimension_System |
dec6faf1 | 924 | |
6c57023b AC |
925 | begin |
926 | -- STEP 1: Legality of aspect | |
dec6faf1 | 927 | |
6c57023b AC |
928 | if not Is_Derived_Numeric_Type (N) then |
929 | Error_Msg_NE | |
930 | ("aspect& must apply to numeric derived type declaration", N, Id); | |
931 | return; | |
932 | end if; | |
dec6faf1 | 933 | |
6c57023b AC |
934 | if Nkind (Aggr) /= N_Aggregate then |
935 | Error_Msg_N ("aggregate expected", Aggr); | |
936 | return; | |
937 | end if; | |
dec6faf1 | 938 | |
6c57023b | 939 | -- STEP 2: Structural verification of the dimension aggregate |
dec6faf1 | 940 | |
6c57023b AC |
941 | if Present (Component_Associations (Aggr)) then |
942 | Error_Msg_N ("expected positional aggregate", Aggr); | |
943 | return; | |
944 | end if; | |
dec6faf1 | 945 | |
6c57023b | 946 | -- STEP 3: Name and Symbol extraction |
dec6faf1 | 947 | |
df378148 | 948 | Dim_Aggr := First (Expressions (Aggr)); |
6c57023b | 949 | Errors_Count := Serious_Errors_Detected; |
df378148 | 950 | while Present (Dim_Aggr) loop |
dcd5fd67 | 951 | if Position = High_Position_Bound then |
4a28b181 | 952 | Error_Msg_N ("too many dimensions in system", Aggr); |
6c57023b | 953 | exit; |
dec6faf1 | 954 | end if; |
dec6faf1 | 955 | |
dcd5fd67 PMR |
956 | Position := Position + 1; |
957 | ||
df378148 AC |
958 | if Nkind (Dim_Aggr) /= N_Aggregate then |
959 | Error_Msg_N ("aggregate expected", Dim_Aggr); | |
dec6faf1 | 960 | |
dec6faf1 | 961 | else |
df378148 AC |
962 | if Present (Component_Associations (Dim_Aggr)) |
963 | and then Present (Expressions (Dim_Aggr)) | |
964 | then | |
7be8338d RD |
965 | Error_Msg_N |
966 | ("mixed positional/named aggregate not allowed here", | |
967 | Dim_Aggr); | |
df378148 AC |
968 | |
969 | -- Verify each dimension aggregate has three arguments | |
970 | ||
971 | elsif List_Length (Component_Associations (Dim_Aggr)) /= 3 | |
972 | and then List_Length (Expressions (Dim_Aggr)) /= 3 | |
973 | then | |
974 | Error_Msg_N | |
4a28b181 | 975 | ("three components expected in aggregate", Dim_Aggr); |
dec6faf1 | 976 | |
6c57023b | 977 | else |
df378148 | 978 | -- Named dimension aggregate |
dec6faf1 | 979 | |
df378148 | 980 | if Present (Component_Associations (Dim_Aggr)) then |
21791d97 | 981 | |
df378148 | 982 | -- Check first argument denotes the unit name |
dec6faf1 | 983 | |
df378148 AC |
984 | Assoc := First (Component_Associations (Dim_Aggr)); |
985 | Choice := First (Choices (Assoc)); | |
986 | Unit_Name := Expression (Assoc); | |
987 | ||
988 | if Present (Next (Choice)) | |
989 | or else Nkind (Choice) /= N_Identifier | |
990 | then | |
991 | Error_Msg_NE ("wrong syntax for aspect&", Choice, Id); | |
992 | ||
993 | elsif Chars (Choice) /= Name_Unit_Name then | |
994 | Error_Msg_N ("expected Unit_Name, found&", Choice); | |
6c57023b | 995 | end if; |
dec6faf1 | 996 | |
df378148 AC |
997 | -- Check the second argument denotes the unit symbol |
998 | ||
999 | Next (Assoc); | |
1000 | Choice := First (Choices (Assoc)); | |
1001 | Unit_Symbol := Expression (Assoc); | |
dec6faf1 | 1002 | |
df378148 AC |
1003 | if Present (Next (Choice)) |
1004 | or else Nkind (Choice) /= N_Identifier | |
6c57023b | 1005 | then |
df378148 | 1006 | Error_Msg_NE ("wrong syntax for aspect&", Choice, Id); |
dec6faf1 | 1007 | |
df378148 AC |
1008 | elsif Chars (Choice) /= Name_Unit_Symbol then |
1009 | Error_Msg_N ("expected Unit_Symbol, found&", Choice); | |
1010 | end if; | |
dec6faf1 | 1011 | |
df378148 | 1012 | -- Check the third argument denotes the dimension symbol |
dec6faf1 | 1013 | |
df378148 AC |
1014 | Next (Assoc); |
1015 | Choice := First (Choices (Assoc)); | |
1016 | Dim_Symbol := Expression (Assoc); | |
dec6faf1 | 1017 | |
df378148 AC |
1018 | if Present (Next (Choice)) |
1019 | or else Nkind (Choice) /= N_Identifier | |
1020 | then | |
1021 | Error_Msg_NE ("wrong syntax for aspect&", Choice, Id); | |
df378148 AC |
1022 | elsif Chars (Choice) /= Name_Dim_Symbol then |
1023 | Error_Msg_N ("expected Dim_Symbol, found&", Choice); | |
1024 | end if; | |
dec6faf1 | 1025 | |
df378148 AC |
1026 | -- Positional dimension aggregate |
1027 | ||
1028 | else | |
1029 | Unit_Name := First (Expressions (Dim_Aggr)); | |
1030 | Unit_Symbol := Next (Unit_Name); | |
1031 | Dim_Symbol := Next (Unit_Symbol); | |
1032 | end if; | |
1033 | ||
1034 | -- Check the first argument for each dimension aggregate is | |
1035 | -- a name. | |
1036 | ||
1037 | if Nkind (Unit_Name) = N_Identifier then | |
1038 | Unit_Names (Position) := Chars (Unit_Name); | |
1039 | else | |
1040 | Error_Msg_N ("expected unit name", Unit_Name); | |
1041 | end if; | |
1042 | ||
1043 | -- Check the second argument for each dimension aggregate is | |
1044 | -- a string or a character. | |
1045 | ||
4a08c95c AC |
1046 | if Nkind (Unit_Symbol) not in |
1047 | N_String_Literal | N_Character_Literal | |
df378148 | 1048 | then |
7be8338d RD |
1049 | Error_Msg_N |
1050 | ("expected unit symbol (string or character)", | |
1051 | Unit_Symbol); | |
df378148 AC |
1052 | |
1053 | else | |
1054 | -- String case | |
1055 | ||
1056 | if Nkind (Unit_Symbol) = N_String_Literal then | |
1057 | Unit_Symbols (Position) := Strval (Unit_Symbol); | |
1058 | ||
1059 | -- Character case | |
1060 | ||
1061 | else | |
1062 | Start_String; | |
1063 | Store_String_Char | |
1064 | (UI_To_CC (Char_Literal_Value (Unit_Symbol))); | |
1065 | Unit_Symbols (Position) := End_String; | |
6c57023b | 1066 | end if; |
dec6faf1 | 1067 | |
df378148 AC |
1068 | -- Verify that the string is not empty |
1069 | ||
1070 | if String_Length (Unit_Symbols (Position)) = 0 then | |
1071 | Error_Msg_N | |
1072 | ("empty string not allowed here", Unit_Symbol); | |
1073 | end if; | |
1074 | end if; | |
1075 | ||
1076 | -- Check the third argument for each dimension aggregate is | |
1077 | -- a string or a character. | |
1078 | ||
4a08c95c AC |
1079 | if Nkind (Dim_Symbol) not in |
1080 | N_String_Literal | N_Character_Literal | |
df378148 | 1081 | then |
7be8338d RD |
1082 | Error_Msg_N |
1083 | ("expected dimension symbol (string or character)", | |
1084 | Dim_Symbol); | |
df378148 | 1085 | |
6c57023b | 1086 | else |
df378148 AC |
1087 | -- String case |
1088 | ||
1089 | if Nkind (Dim_Symbol) = N_String_Literal then | |
1090 | Dim_Symbols (Position) := Strval (Dim_Symbol); | |
1091 | ||
1092 | -- Character case | |
1093 | ||
1094 | else | |
1095 | Start_String; | |
1096 | Store_String_Char | |
1097 | (UI_To_CC (Char_Literal_Value (Dim_Symbol))); | |
1098 | Dim_Symbols (Position) := End_String; | |
1099 | end if; | |
1100 | ||
1101 | -- Verify that the string is not empty | |
1102 | ||
1103 | if String_Length (Dim_Symbols (Position)) = 0 then | |
4a28b181 | 1104 | Error_Msg_N ("empty string not allowed here", Dim_Symbol); |
df378148 | 1105 | end if; |
6c57023b AC |
1106 | end if; |
1107 | end if; | |
dec6faf1 AC |
1108 | end if; |
1109 | ||
df378148 | 1110 | Next (Dim_Aggr); |
dec6faf1 AC |
1111 | end loop; |
1112 | ||
6c57023b | 1113 | -- STEP 4: Storage of extracted values |
dec6faf1 | 1114 | |
6c57023b | 1115 | -- Check that no errors have been detected during the analysis |
dec6faf1 | 1116 | |
6c57023b | 1117 | if Errors_Count = Serious_Errors_Detected then |
df378148 AC |
1118 | Dim_System.Type_Decl := N; |
1119 | Dim_System.Unit_Names := Unit_Names; | |
1120 | Dim_System.Unit_Symbols := Unit_Symbols; | |
1121 | Dim_System.Dim_Symbols := Dim_Symbols; | |
1122 | Dim_System.Count := Position; | |
6c57023b AC |
1123 | System_Table.Append (Dim_System); |
1124 | end if; | |
dec6faf1 AC |
1125 | end Analyze_Aspect_Dimension_System; |
1126 | ||
1127 | ----------------------- | |
1128 | -- Analyze_Dimension -- | |
1129 | ----------------------- | |
1130 | ||
1131 | -- This dispatch routine propagates dimensions for each node | |
1132 | ||
1133 | procedure Analyze_Dimension (N : Node_Id) is | |
1134 | begin | |
0929eaeb | 1135 | -- Aspect is an Ada 2012 feature. Note that there is no need to check |
680d5f61 | 1136 | -- dimensions for nodes that don't come from source, except for subtype |
80007176 | 1137 | -- declarations where the dimensions are inherited from the base type, |
d9049d04 ES |
1138 | -- for explicit dereferences generated when expanding iterators, and |
1139 | -- for object declarations generated for inlining. | |
dec6faf1 | 1140 | |
680d5f61 AC |
1141 | if Ada_Version < Ada_2012 then |
1142 | return; | |
1143 | ||
fa0c3ab8 YM |
1144 | -- Inlined bodies have already been checked for dimensionality |
1145 | ||
1146 | elsif In_Inlined_Body then | |
1147 | return; | |
1148 | ||
d9049d04 | 1149 | elsif not Comes_From_Source (N) then |
4a08c95c AC |
1150 | if Nkind (N) not in N_Explicit_Dereference |
1151 | | N_Identifier | |
1152 | | N_Object_Declaration | |
1153 | | N_Subtype_Declaration | |
d9049d04 | 1154 | then |
d9049d04 ES |
1155 | return; |
1156 | end if; | |
dec6faf1 AC |
1157 | end if; |
1158 | ||
1159 | case Nkind (N) is | |
dec6faf1 AC |
1160 | when N_Assignment_Statement => |
1161 | Analyze_Dimension_Assignment_Statement (N); | |
1162 | ||
6c57023b AC |
1163 | when N_Binary_Op => |
1164 | Analyze_Dimension_Binary_Op (N); | |
dec6faf1 | 1165 | |
cc3a2986 AC |
1166 | when N_Case_Expression => |
1167 | Analyze_Dimension_Case_Expression (N); | |
1168 | ||
dec6faf1 AC |
1169 | when N_Component_Declaration => |
1170 | Analyze_Dimension_Component_Declaration (N); | |
1171 | ||
6c57023b AC |
1172 | when N_Extended_Return_Statement => |
1173 | Analyze_Dimension_Extended_Return_Statement (N); | |
dec6faf1 | 1174 | |
d8f43ee6 HK |
1175 | when N_Attribute_Reference |
1176 | | N_Expanded_Name | |
1177 | | N_Explicit_Dereference | |
1178 | | N_Function_Call | |
1179 | | N_Indexed_Component | |
1180 | | N_Qualified_Expression | |
1181 | | N_Selected_Component | |
1182 | | N_Slice | |
d8f43ee6 HK |
1183 | | N_Unchecked_Type_Conversion |
1184 | => | |
dec6faf1 AC |
1185 | Analyze_Dimension_Has_Etype (N); |
1186 | ||
cc3a2986 AC |
1187 | -- In the presence of a repaired syntax error, an identifier may be |
1188 | -- introduced without a usable type. | |
14f3895c | 1189 | |
d8f43ee6 | 1190 | when N_Identifier => |
14f3895c AC |
1191 | if Present (Etype (N)) then |
1192 | Analyze_Dimension_Has_Etype (N); | |
1193 | end if; | |
1194 | ||
cc3a2986 AC |
1195 | when N_If_Expression => |
1196 | Analyze_Dimension_If_Expression (N); | |
1197 | ||
df9ad6bc AC |
1198 | when N_Number_Declaration => |
1199 | Analyze_Dimension_Number_Declaration (N); | |
1200 | ||
6c57023b AC |
1201 | when N_Object_Declaration => |
1202 | Analyze_Dimension_Object_Declaration (N); | |
dec6faf1 | 1203 | |
6c57023b AC |
1204 | when N_Object_Renaming_Declaration => |
1205 | Analyze_Dimension_Object_Renaming_Declaration (N); | |
dec6faf1 AC |
1206 | |
1207 | when N_Simple_Return_Statement => | |
6c57023b AC |
1208 | if not Comes_From_Extended_Return_Statement (N) then |
1209 | Analyze_Dimension_Simple_Return_Statement (N); | |
1210 | end if; | |
1211 | ||
1212 | when N_Subtype_Declaration => | |
1213 | Analyze_Dimension_Subtype_Declaration (N); | |
1214 | ||
66f95f60 | 1215 | when N_Type_Conversion => |
ed323421 | 1216 | Analyze_Dimension_Type_Conversion (N); |
66f95f60 | 1217 | |
6c57023b AC |
1218 | when N_Unary_Op => |
1219 | Analyze_Dimension_Unary_Op (N); | |
dec6faf1 | 1220 | |
d8f43ee6 HK |
1221 | when others => |
1222 | null; | |
dec6faf1 AC |
1223 | end case; |
1224 | end Analyze_Dimension; | |
1225 | ||
0929eaeb AC |
1226 | --------------------------------------- |
1227 | -- Analyze_Dimension_Array_Aggregate -- | |
1228 | --------------------------------------- | |
1229 | ||
1230 | procedure Analyze_Dimension_Array_Aggregate | |
1231 | (N : Node_Id; | |
1232 | Comp_Typ : Entity_Id) | |
1233 | is | |
1234 | Comp_Ass : constant List_Id := Component_Associations (N); | |
1235 | Dims_Of_Comp_Typ : constant Dimension_Type := Dimensions_Of (Comp_Typ); | |
1236 | Exps : constant List_Id := Expressions (N); | |
1237 | ||
dcd59a99 ES |
1238 | Comp : Node_Id; |
1239 | Dims_Of_Expr : Dimension_Type; | |
1240 | Expr : Node_Id; | |
0929eaeb AC |
1241 | |
1242 | Error_Detected : Boolean := False; | |
1243 | -- This flag is used in order to indicate if an error has been detected | |
1244 | -- so far by the compiler in this routine. | |
1245 | ||
1246 | begin | |
1247 | -- Aspect is an Ada 2012 feature. Nothing to do here if the component | |
1248 | -- base type is not a dimensioned type. | |
1249 | ||
fa0c3ab8 YM |
1250 | -- Inlined bodies have already been checked for dimensionality. |
1251 | ||
0929eaeb AC |
1252 | -- Note that here the original node must come from source since the |
1253 | -- original array aggregate may not have been entirely decorated. | |
1254 | ||
1255 | if Ada_Version < Ada_2012 | |
fa0c3ab8 | 1256 | or else In_Inlined_Body |
0929eaeb AC |
1257 | or else not Comes_From_Source (Original_Node (N)) |
1258 | or else not Has_Dimension_System (Base_Type (Comp_Typ)) | |
1259 | then | |
1260 | return; | |
1261 | end if; | |
1262 | ||
1263 | -- Check whether there is any positional component association | |
1264 | ||
1265 | if Is_Empty_List (Exps) then | |
1266 | Comp := First (Comp_Ass); | |
1267 | else | |
1268 | Comp := First (Exps); | |
1269 | end if; | |
1270 | ||
1271 | while Present (Comp) loop | |
d976bf74 | 1272 | |
0929eaeb AC |
1273 | -- Get the expression from the component |
1274 | ||
1275 | if Nkind (Comp) = N_Component_Association then | |
1276 | Expr := Expression (Comp); | |
1277 | else | |
1278 | Expr := Comp; | |
1279 | end if; | |
1280 | ||
1281 | -- Issue an error if the dimensions of the component type and the | |
1282 | -- dimensions of the component mismatch. | |
1283 | ||
1284 | -- Note that we must ensure the expression has been fully analyzed | |
1285 | -- since it may not be decorated at this point. We also don't want to | |
1286 | -- issue the same error message multiple times on the same expression | |
1287 | -- (may happen when an aggregate is converted into a positional | |
888be6b1 AC |
1288 | -- aggregate). We also must verify that this is a scalar component, |
1289 | -- and not a subaggregate of a multidimensional aggregate. | |
dcd59a99 ES |
1290 | -- The expression may be an identifier that has been copied several |
1291 | -- times during expansion, its dimensions are those of its type. | |
1292 | ||
1293 | if Is_Entity_Name (Expr) then | |
1294 | Dims_Of_Expr := Dimensions_Of (Etype (Expr)); | |
1295 | else | |
1296 | Dims_Of_Expr := Dimensions_Of (Expr); | |
1297 | end if; | |
0929eaeb AC |
1298 | |
1299 | if Comes_From_Source (Original_Node (Expr)) | |
1300 | and then Present (Etype (Expr)) | |
888be6b1 | 1301 | and then Is_Numeric_Type (Etype (Expr)) |
dcd59a99 | 1302 | and then Dims_Of_Expr /= Dims_Of_Comp_Typ |
0929eaeb AC |
1303 | and then Sloc (Comp) /= Sloc (Prev (Comp)) |
1304 | then | |
1305 | -- Check if an error has already been encountered so far | |
1306 | ||
1307 | if not Error_Detected then | |
1308 | Error_Msg_N ("dimensions mismatch in array aggregate", N); | |
1309 | Error_Detected := True; | |
1310 | end if; | |
1311 | ||
d976bf74 | 1312 | Error_Msg_N |
4a28b181 AC |
1313 | ("\expected dimension " & Dimensions_Msg_Of (Comp_Typ) |
1314 | & ", found " & Dimensions_Msg_Of (Expr), Expr); | |
0929eaeb AC |
1315 | end if; |
1316 | ||
1317 | -- Look at the named components right after the positional components | |
1318 | ||
1319 | if not Present (Next (Comp)) | |
1320 | and then List_Containing (Comp) = Exps | |
1321 | then | |
1322 | Comp := First (Comp_Ass); | |
1323 | else | |
1324 | Next (Comp); | |
1325 | end if; | |
1326 | end loop; | |
1327 | end Analyze_Dimension_Array_Aggregate; | |
1328 | ||
dec6faf1 AC |
1329 | -------------------------------------------- |
1330 | -- Analyze_Dimension_Assignment_Statement -- | |
1331 | -------------------------------------------- | |
1332 | ||
1333 | procedure Analyze_Dimension_Assignment_Statement (N : Node_Id) is | |
6c57023b AC |
1334 | Lhs : constant Node_Id := Name (N); |
1335 | Dims_Of_Lhs : constant Dimension_Type := Dimensions_Of (Lhs); | |
1336 | Rhs : constant Node_Id := Expression (N); | |
1337 | Dims_Of_Rhs : constant Dimension_Type := Dimensions_Of (Rhs); | |
dec6faf1 | 1338 | |
9a7e930f AC |
1339 | procedure Error_Dim_Msg_For_Assignment_Statement |
1340 | (N : Node_Id; | |
1341 | Lhs : Node_Id; | |
1342 | Rhs : Node_Id); | |
1343 | -- Error using Error_Msg_N at node N. Output the dimensions of left | |
1344 | -- and right hand sides. | |
1345 | ||
1346 | -------------------------------------------- | |
1347 | -- Error_Dim_Msg_For_Assignment_Statement -- | |
1348 | -------------------------------------------- | |
1349 | ||
1350 | procedure Error_Dim_Msg_For_Assignment_Statement | |
1351 | (N : Node_Id; | |
1352 | Lhs : Node_Id; | |
1353 | Rhs : Node_Id) | |
1354 | is | |
dec6faf1 | 1355 | begin |
9a7e930f | 1356 | Error_Msg_N ("dimensions mismatch in assignment", N); |
d976bf74 | 1357 | Error_Msg_N ("\left-hand side " & Dimensions_Msg_Of (Lhs, True), N); |
0929eaeb | 1358 | Error_Msg_N ("\right-hand side " & Dimensions_Msg_Of (Rhs, True), N); |
9a7e930f | 1359 | end Error_Dim_Msg_For_Assignment_Statement; |
dec6faf1 AC |
1360 | |
1361 | -- Start of processing for Analyze_Dimension_Assignment | |
1362 | ||
1363 | begin | |
6c57023b | 1364 | if Dims_Of_Lhs /= Dims_Of_Rhs then |
9a7e930f | 1365 | Error_Dim_Msg_For_Assignment_Statement (N, Lhs, Rhs); |
6c57023b | 1366 | end if; |
dec6faf1 AC |
1367 | end Analyze_Dimension_Assignment_Statement; |
1368 | ||
1369 | --------------------------------- | |
1370 | -- Analyze_Dimension_Binary_Op -- | |
1371 | --------------------------------- | |
1372 | ||
6c57023b AC |
1373 | -- Check and propagate the dimensions for binary operators |
1374 | -- Note that when the dimensions mismatch, no dimension is propagated to N. | |
1375 | ||
dec6faf1 AC |
1376 | procedure Analyze_Dimension_Binary_Op (N : Node_Id) is |
1377 | N_Kind : constant Node_Kind := Nkind (N); | |
1378 | ||
df9ad6bc AC |
1379 | function Dimensions_Of_Operand (N : Node_Id) return Dimension_Type; |
1380 | -- If the operand is a numeric literal that comes from a declared | |
1381 | -- constant, use the dimensions of the constant which were computed | |
3e3bc136 AC |
1382 | -- from the expression of the constant declaration. Otherwise the |
1383 | -- dimensions are those of the operand, or the type of the operand. | |
1384 | -- This takes care of node rewritings from validity checks, where the | |
1385 | -- dimensions of the operand itself may not be preserved, while the | |
1386 | -- type comes from context and must have dimension information. | |
df9ad6bc | 1387 | |
9a7e930f AC |
1388 | procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id); |
1389 | -- Error using Error_Msg_NE and Error_Msg_N at node N. Output the | |
1390 | -- dimensions of both operands. | |
6c57023b | 1391 | |
df9ad6bc AC |
1392 | --------------------------- |
1393 | -- Dimensions_Of_Operand -- | |
1394 | --------------------------- | |
1395 | ||
1396 | function Dimensions_Of_Operand (N : Node_Id) return Dimension_Type is | |
3e3bc136 AC |
1397 | Dims : constant Dimension_Type := Dimensions_Of (N); |
1398 | ||
df9ad6bc | 1399 | begin |
3e3bc136 AC |
1400 | if Exists (Dims) then |
1401 | return Dims; | |
1402 | ||
1403 | elsif Is_Entity_Name (N) then | |
1404 | return Dimensions_Of (Etype (Entity (N))); | |
1405 | ||
1406 | elsif Nkind (N) = N_Real_Literal then | |
1407 | ||
1408 | if Present (Original_Entity (N)) then | |
1409 | return Dimensions_Of (Original_Entity (N)); | |
1410 | ||
1411 | else | |
1412 | return Dimensions_Of (Etype (N)); | |
1413 | end if; | |
1414 | ||
1415 | -- Otherwise return the default dimensions | |
1416 | ||
df9ad6bc | 1417 | else |
3e3bc136 | 1418 | return Dims; |
df9ad6bc AC |
1419 | end if; |
1420 | end Dimensions_Of_Operand; | |
1421 | ||
9a7e930f AC |
1422 | --------------------------------- |
1423 | -- Error_Dim_Msg_For_Binary_Op -- | |
1424 | --------------------------------- | |
6c57023b | 1425 | |
9a7e930f | 1426 | procedure Error_Dim_Msg_For_Binary_Op (N, L, R : Node_Id) is |
6c57023b | 1427 | begin |
4a28b181 AC |
1428 | Error_Msg_NE |
1429 | ("both operands for operation& must have same dimensions", | |
1430 | N, Entity (N)); | |
d976bf74 | 1431 | Error_Msg_N ("\left operand " & Dimensions_Msg_Of (L, True), N); |
0929eaeb | 1432 | Error_Msg_N ("\right operand " & Dimensions_Msg_Of (R, True), N); |
9a7e930f | 1433 | end Error_Dim_Msg_For_Binary_Op; |
6c57023b AC |
1434 | |
1435 | -- Start of processing for Analyze_Dimension_Binary_Op | |
1436 | ||
dec6faf1 | 1437 | begin |
f32eb591 AC |
1438 | -- If the node is already analyzed, do not examine the operands. At the |
1439 | -- end of the analysis their dimensions have been removed, and the node | |
1440 | -- itself may have been rewritten. | |
1441 | ||
1442 | if Analyzed (N) then | |
1443 | return; | |
1444 | end if; | |
1445 | ||
4a08c95c AC |
1446 | if N_Kind in N_Op_Add | N_Op_Expon | N_Op_Subtract |
1447 | | N_Multiplying_Operator | N_Op_Compare | |
dec6faf1 AC |
1448 | then |
1449 | declare | |
4a28b181 | 1450 | L : constant Node_Id := Left_Opnd (N); |
df9ad6bc AC |
1451 | Dims_Of_L : constant Dimension_Type := |
1452 | Dimensions_Of_Operand (L); | |
4a28b181 AC |
1453 | L_Has_Dimensions : constant Boolean := Exists (Dims_Of_L); |
1454 | R : constant Node_Id := Right_Opnd (N); | |
df9ad6bc AC |
1455 | Dims_Of_R : constant Dimension_Type := |
1456 | Dimensions_Of_Operand (R); | |
4a28b181 AC |
1457 | R_Has_Dimensions : constant Boolean := Exists (Dims_Of_R); |
1458 | Dims_Of_N : Dimension_Type := Null_Dimension; | |
dec6faf1 AC |
1459 | |
1460 | begin | |
6c57023b | 1461 | -- N_Op_Add, N_Op_Mod, N_Op_Rem or N_Op_Subtract case |
dec6faf1 | 1462 | |
4a08c95c | 1463 | if N_Kind in N_Op_Add | N_Op_Mod | N_Op_Rem | N_Op_Subtract then |
88115c2a | 1464 | |
6c57023b | 1465 | -- Check both operands have same dimension |
dec6faf1 | 1466 | |
6c57023b | 1467 | if Dims_Of_L /= Dims_Of_R then |
9a7e930f | 1468 | Error_Dim_Msg_For_Binary_Op (N, L, R); |
6c57023b AC |
1469 | else |
1470 | -- Check both operands are not dimensionless | |
88115c2a | 1471 | |
6c57023b AC |
1472 | if Exists (Dims_Of_L) then |
1473 | Set_Dimensions (N, Dims_Of_L); | |
dec6faf1 | 1474 | end if; |
dec6faf1 AC |
1475 | end if; |
1476 | ||
6c57023b AC |
1477 | -- N_Op_Multiply or N_Op_Divide case |
1478 | ||
4a08c95c | 1479 | elsif N_Kind in N_Op_Multiply | N_Op_Divide then |
88115c2a | 1480 | |
6c57023b AC |
1481 | -- Check at least one operand is not dimensionless |
1482 | ||
1483 | if L_Has_Dimensions or R_Has_Dimensions then | |
dec6faf1 | 1484 | |
6c57023b | 1485 | -- Multiplication case |
88115c2a | 1486 | |
6c57023b | 1487 | -- Get both operands dimensions and add them |
dec6faf1 AC |
1488 | |
1489 | if N_Kind = N_Op_Multiply then | |
6c57023b AC |
1490 | for Position in Dimension_Type'Range loop |
1491 | Dims_Of_N (Position) := | |
1492 | Dims_Of_L (Position) + Dims_Of_R (Position); | |
dec6faf1 AC |
1493 | end loop; |
1494 | ||
6c57023b | 1495 | -- Division case |
88115c2a | 1496 | |
6c57023b | 1497 | -- Get both operands dimensions and subtract them |
dec6faf1 AC |
1498 | |
1499 | else | |
6c57023b AC |
1500 | for Position in Dimension_Type'Range loop |
1501 | Dims_Of_N (Position) := | |
1502 | Dims_Of_L (Position) - Dims_Of_R (Position); | |
dec6faf1 AC |
1503 | end loop; |
1504 | end if; | |
1505 | ||
6c57023b AC |
1506 | if Exists (Dims_Of_N) then |
1507 | Set_Dimensions (N, Dims_Of_N); | |
dec6faf1 AC |
1508 | end if; |
1509 | end if; | |
1510 | ||
88115c2a AC |
1511 | -- Exponentiation case |
1512 | ||
1513 | -- Note: a rational exponent is allowed for dimensioned operand | |
dec6faf1 AC |
1514 | |
1515 | elsif N_Kind = N_Op_Expon then | |
88115c2a AC |
1516 | |
1517 | -- Check the left operand is not dimensionless. Note that the | |
1518 | -- value of the exponent must be known compile time. Otherwise, | |
1519 | -- the exponentiation evaluation will return an error message. | |
dec6faf1 | 1520 | |
dc3af7e2 AC |
1521 | if L_Has_Dimensions then |
1522 | if not Compile_Time_Known_Value (R) then | |
4a28b181 AC |
1523 | Error_Msg_N |
1524 | ("exponent of dimensioned operand must be " | |
1525 | & "known at compile time", N); | |
dc3af7e2 AC |
1526 | end if; |
1527 | ||
6c57023b AC |
1528 | declare |
1529 | Exponent_Value : Rational := Zero; | |
dec6faf1 | 1530 | |
6c57023b AC |
1531 | begin |
1532 | -- Real operand case | |
15954beb | 1533 | |
6c57023b | 1534 | if Is_Real_Type (Etype (L)) then |
dec6faf1 | 1535 | |
6c57023b | 1536 | -- Define the exponent as a Rational number |
dec6faf1 | 1537 | |
6c57023b | 1538 | Exponent_Value := Create_Rational_From (R, False); |
dec6faf1 | 1539 | |
6c57023b AC |
1540 | -- Verify that the exponent cannot be interpreted |
1541 | -- as a rational, otherwise interpret the exponent | |
1542 | -- as an integer. | |
dec6faf1 | 1543 | |
6c57023b AC |
1544 | if Exponent_Value = No_Rational then |
1545 | Exponent_Value := | |
1546 | +Whole (UI_To_Int (Expr_Value (R))); | |
1547 | end if; | |
dec6faf1 | 1548 | |
88115c2a AC |
1549 | -- Integer operand case. |
1550 | ||
6c57023b AC |
1551 | -- For integer operand, the exponent cannot be |
1552 | -- interpreted as a rational. | |
dec6faf1 | 1553 | |
6c57023b AC |
1554 | else |
1555 | Exponent_Value := +Whole (UI_To_Int (Expr_Value (R))); | |
1556 | end if; | |
dec6faf1 | 1557 | |
6c57023b AC |
1558 | for Position in Dimension_Type'Range loop |
1559 | Dims_Of_N (Position) := | |
1560 | Dims_Of_L (Position) * Exponent_Value; | |
1561 | end loop; | |
dec6faf1 | 1562 | |
6c57023b AC |
1563 | if Exists (Dims_Of_N) then |
1564 | Set_Dimensions (N, Dims_Of_N); | |
dec6faf1 | 1565 | end if; |
6c57023b AC |
1566 | end; |
1567 | end if; | |
dec6faf1 | 1568 | |
88115c2a AC |
1569 | -- Comparison cases |
1570 | ||
1571 | -- For relational operations, only dimension checking is | |
df9ad6bc AC |
1572 | -- performed (no propagation). If one operand is the result |
1573 | -- of constant folding the dimensions may have been lost | |
812e6118 | 1574 | -- in a tree copy, so assume that preanalysis has verified |
df9ad6bc | 1575 | -- that dimensions are correct. |
dec6faf1 AC |
1576 | |
1577 | elsif N_Kind in N_Op_Compare then | |
dec6faf1 | 1578 | if (L_Has_Dimensions or R_Has_Dimensions) |
88115c2a | 1579 | and then Dims_Of_L /= Dims_Of_R |
dec6faf1 | 1580 | then |
df9ad6bc AC |
1581 | if Nkind (L) = N_Real_Literal |
1582 | and then not (Comes_From_Source (L)) | |
1583 | and then Expander_Active | |
1584 | then | |
1585 | null; | |
1586 | ||
1587 | elsif Nkind (R) = N_Real_Literal | |
1588 | and then not (Comes_From_Source (R)) | |
1589 | and then Expander_Active | |
1590 | then | |
1591 | null; | |
1592 | ||
8f8f531f PMR |
1593 | -- Numeric literal case. Issue a warning to indicate the |
1594 | -- literal is treated as if its dimension matches the type | |
1595 | -- dimension. | |
1596 | ||
4a08c95c AC |
1597 | elsif Nkind (Original_Node (L)) in |
1598 | N_Integer_Literal | N_Real_Literal | |
8f8f531f PMR |
1599 | then |
1600 | Dim_Warning_For_Numeric_Literal (L, Etype (R)); | |
1601 | ||
4a08c95c AC |
1602 | elsif Nkind (Original_Node (R)) in |
1603 | N_Integer_Literal | N_Real_Literal | |
8f8f531f PMR |
1604 | then |
1605 | Dim_Warning_For_Numeric_Literal (R, Etype (L)); | |
1606 | ||
df9ad6bc AC |
1607 | else |
1608 | Error_Dim_Msg_For_Binary_Op (N, L, R); | |
1609 | end if; | |
dec6faf1 AC |
1610 | end if; |
1611 | end if; | |
1612 | ||
d1915cb8 | 1613 | -- If expander is active, remove dimension information from each |
df9ad6bc | 1614 | -- operand, as only dimensions of result are relevant. |
6c57023b | 1615 | |
df9ad6bc AC |
1616 | if Expander_Active then |
1617 | Remove_Dimensions (L); | |
1618 | Remove_Dimensions (R); | |
1619 | end if; | |
dec6faf1 AC |
1620 | end; |
1621 | end if; | |
1622 | end Analyze_Dimension_Binary_Op; | |
1623 | ||
0929eaeb AC |
1624 | ---------------------------- |
1625 | -- Analyze_Dimension_Call -- | |
1626 | ---------------------------- | |
1627 | ||
1628 | procedure Analyze_Dimension_Call (N : Node_Id; Nam : Entity_Id) is | |
1629 | Actuals : constant List_Id := Parameter_Associations (N); | |
1630 | Actual : Node_Id; | |
1631 | Dims_Of_Formal : Dimension_Type; | |
1632 | Formal : Node_Id; | |
1633 | Formal_Typ : Entity_Id; | |
1634 | ||
1635 | Error_Detected : Boolean := False; | |
1636 | -- This flag is used in order to indicate if an error has been detected | |
1637 | -- so far by the compiler in this routine. | |
1638 | ||
1639 | begin | |
2a7b8e18 | 1640 | -- Aspect is an Ada 2012 feature. Note that there is no need to check |
fa0c3ab8 YM |
1641 | -- dimensions for calls in inlined bodies, or calls that don't come |
1642 | -- from source, or those that may have semantic errors. | |
0929eaeb AC |
1643 | |
1644 | if Ada_Version < Ada_2012 | |
fa0c3ab8 | 1645 | or else In_Inlined_Body |
0929eaeb | 1646 | or else not Comes_From_Source (N) |
2352eadb | 1647 | or else Error_Posted (N) |
0929eaeb AC |
1648 | then |
1649 | return; | |
1650 | end if; | |
1651 | ||
2a7b8e18 | 1652 | -- Check the dimensions of the actuals, if any |
0929eaeb | 1653 | |
2a7b8e18 | 1654 | if not Is_Empty_List (Actuals) then |
9a6dc470 | 1655 | |
2a7b8e18 | 1656 | -- Special processing for elementary functions |
0929eaeb | 1657 | |
2a7b8e18 AC |
1658 | -- For Sqrt call, the resulting dimensions equal to half the |
1659 | -- dimensions of the actual. For all other elementary calls, this | |
1660 | -- routine check that every actual is dimensionless. | |
0929eaeb | 1661 | |
2a7b8e18 AC |
1662 | if Nkind (N) = N_Function_Call then |
1663 | Elementary_Function_Calls : declare | |
1664 | Dims_Of_Call : Dimension_Type; | |
1665 | Ent : Entity_Id := Nam; | |
0929eaeb | 1666 | |
2a7b8e18 AC |
1667 | function Is_Elementary_Function_Entity |
1668 | (Sub_Id : Entity_Id) return Boolean; | |
9a6dc470 RD |
1669 | -- Given Sub_Id, the original subprogram entity, return True |
1670 | -- if call is to an elementary function (see Ada.Numerics. | |
1671 | -- Generic_Elementary_Functions). | |
0929eaeb | 1672 | |
2a7b8e18 AC |
1673 | ----------------------------------- |
1674 | -- Is_Elementary_Function_Entity -- | |
1675 | ----------------------------------- | |
0929eaeb | 1676 | |
2a7b8e18 AC |
1677 | function Is_Elementary_Function_Entity |
1678 | (Sub_Id : Entity_Id) return Boolean | |
1679 | is | |
1680 | Loc : constant Source_Ptr := Sloc (Sub_Id); | |
0929eaeb | 1681 | |
2a7b8e18 | 1682 | begin |
9a6dc470 | 1683 | -- Is entity in Ada.Numerics.Generic_Elementary_Functions? |
d976bf74 | 1684 | |
2a7b8e18 AC |
1685 | return |
1686 | Loc > No_Location | |
1687 | and then | |
1688 | Is_RTU | |
1689 | (Cunit_Entity (Get_Source_Unit (Loc)), | |
1690 | Ada_Numerics_Generic_Elementary_Functions); | |
1691 | end Is_Elementary_Function_Entity; | |
0929eaeb | 1692 | |
2a7b8e18 | 1693 | -- Start of processing for Elementary_Function_Calls |
0929eaeb | 1694 | |
2a7b8e18 | 1695 | begin |
9a6dc470 | 1696 | -- Get original subprogram entity following the renaming chain |
0929eaeb | 1697 | |
2a7b8e18 AC |
1698 | if Present (Alias (Ent)) then |
1699 | Ent := Alias (Ent); | |
1700 | end if; | |
d976bf74 | 1701 | |
2a7b8e18 | 1702 | -- Check the call is an Elementary function call |
0929eaeb | 1703 | |
2a7b8e18 | 1704 | if Is_Elementary_Function_Entity (Ent) then |
9a6dc470 | 1705 | |
2a7b8e18 | 1706 | -- Sqrt function call case |
0929eaeb | 1707 | |
2a7b8e18 AC |
1708 | if Chars (Ent) = Name_Sqrt then |
1709 | Dims_Of_Call := Dimensions_Of (First_Actual (N)); | |
0929eaeb | 1710 | |
2a7b8e18 AC |
1711 | -- Evaluates the resulting dimensions (i.e. half the |
1712 | -- dimensions of the actual). | |
0929eaeb | 1713 | |
2a7b8e18 AC |
1714 | if Exists (Dims_Of_Call) then |
1715 | for Position in Dims_Of_Call'Range loop | |
1716 | Dims_Of_Call (Position) := | |
1717 | Dims_Of_Call (Position) * | |
9a6dc470 | 1718 | Rational'(Numerator => 1, Denominator => 2); |
2a7b8e18 | 1719 | end loop; |
0929eaeb | 1720 | |
2a7b8e18 AC |
1721 | Set_Dimensions (N, Dims_Of_Call); |
1722 | end if; | |
d976bf74 | 1723 | |
2a7b8e18 AC |
1724 | -- All other elementary functions case. Note that every |
1725 | -- actual here should be dimensionless. | |
0929eaeb | 1726 | |
2a7b8e18 AC |
1727 | else |
1728 | Actual := First_Actual (N); | |
1729 | while Present (Actual) loop | |
1730 | if Exists (Dimensions_Of (Actual)) then | |
1731 | ||
9a6dc470 | 1732 | -- Check if error has already been encountered |
2a7b8e18 AC |
1733 | |
1734 | if not Error_Detected then | |
4a28b181 AC |
1735 | Error_Msg_NE |
1736 | ("dimensions mismatch in call of&", | |
1737 | N, Name (N)); | |
2a7b8e18 AC |
1738 | Error_Detected := True; |
1739 | end if; | |
1740 | ||
4a28b181 AC |
1741 | Error_Msg_N |
1742 | ("\expected dimension '['], found " | |
1743 | & Dimensions_Msg_Of (Actual), Actual); | |
0929eaeb AC |
1744 | end if; |
1745 | ||
2a7b8e18 AC |
1746 | Next_Actual (Actual); |
1747 | end loop; | |
1748 | end if; | |
0929eaeb | 1749 | |
2a7b8e18 | 1750 | -- Nothing more to do for elementary functions |
0929eaeb | 1751 | |
2a7b8e18 AC |
1752 | return; |
1753 | end if; | |
1754 | end Elementary_Function_Calls; | |
1755 | end if; | |
0929eaeb | 1756 | |
2a7b8e18 AC |
1757 | -- General case. Check, for each parameter, the dimensions of the |
1758 | -- actual and its corresponding formal match. Otherwise, complain. | |
0929eaeb | 1759 | |
2a7b8e18 AC |
1760 | Actual := First_Actual (N); |
1761 | Formal := First_Formal (Nam); | |
2a7b8e18 | 1762 | while Present (Formal) loop |
95081e99 AC |
1763 | |
1764 | -- A missing corresponding actual indicates that the analysis of | |
1765 | -- the call was aborted due to a previous error. | |
1766 | ||
1767 | if No (Actual) then | |
ee2ba856 | 1768 | Check_Error_Detected; |
95081e99 AC |
1769 | return; |
1770 | end if; | |
1771 | ||
2a7b8e18 AC |
1772 | Formal_Typ := Etype (Formal); |
1773 | Dims_Of_Formal := Dimensions_Of (Formal_Typ); | |
0929eaeb | 1774 | |
2a7b8e18 AC |
1775 | -- If the formal is not dimensionless, check dimensions of formal |
1776 | -- and actual match. Otherwise, complain. | |
0929eaeb | 1777 | |
2a7b8e18 AC |
1778 | if Exists (Dims_Of_Formal) |
1779 | and then Dimensions_Of (Actual) /= Dims_Of_Formal | |
1780 | then | |
1781 | -- Check if an error has already been encountered so far | |
0929eaeb | 1782 | |
2a7b8e18 AC |
1783 | if not Error_Detected then |
1784 | Error_Msg_NE ("dimensions mismatch in& call", N, Name (N)); | |
1785 | Error_Detected := True; | |
1786 | end if; | |
0929eaeb | 1787 | |
9a6dc470 RD |
1788 | Error_Msg_N |
1789 | ("\expected dimension " & Dimensions_Msg_Of (Formal_Typ) | |
1790 | & ", found " & Dimensions_Msg_Of (Actual), Actual); | |
0929eaeb AC |
1791 | end if; |
1792 | ||
2a7b8e18 AC |
1793 | Next_Actual (Actual); |
1794 | Next_Formal (Formal); | |
1795 | end loop; | |
1796 | end if; | |
0929eaeb | 1797 | |
2a7b8e18 AC |
1798 | -- For function calls, propagate the dimensions from the returned type |
1799 | ||
1800 | if Nkind (N) = N_Function_Call then | |
1801 | Analyze_Dimension_Has_Etype (N); | |
1802 | end if; | |
0929eaeb AC |
1803 | end Analyze_Dimension_Call; |
1804 | ||
74a78a4f AC |
1805 | --------------------------------------- |
1806 | -- Analyze_Dimension_Case_Expression -- | |
1807 | --------------------------------------- | |
1808 | ||
1809 | procedure Analyze_Dimension_Case_Expression (N : Node_Id) is | |
cc3a2986 AC |
1810 | Frst : constant Node_Id := First (Alternatives (N)); |
1811 | Frst_Expr : constant Node_Id := Expression (Frst); | |
1812 | Dims : constant Dimension_Type := Dimensions_Of (Frst_Expr); | |
1813 | ||
74a78a4f | 1814 | Alt : Node_Id; |
cc3a2986 | 1815 | |
74a78a4f AC |
1816 | begin |
1817 | Alt := Next (Frst); | |
1818 | while Present (Alt) loop | |
1819 | if Dimensions_Of (Expression (Alt)) /= Dims then | |
1820 | Error_Msg_N ("dimension mismatch in case expression", Alt); | |
1821 | exit; | |
1822 | end if; | |
1823 | ||
1824 | Next (Alt); | |
1825 | end loop; | |
cc3a2986 AC |
1826 | |
1827 | Copy_Dimensions (Frst_Expr, N); | |
74a78a4f AC |
1828 | end Analyze_Dimension_Case_Expression; |
1829 | ||
dec6faf1 AC |
1830 | --------------------------------------------- |
1831 | -- Analyze_Dimension_Component_Declaration -- | |
1832 | --------------------------------------------- | |
1833 | ||
1834 | procedure Analyze_Dimension_Component_Declaration (N : Node_Id) is | |
88115c2a AC |
1835 | Expr : constant Node_Id := Expression (N); |
1836 | Id : constant Entity_Id := Defining_Identifier (N); | |
1837 | Etyp : constant Entity_Id := Etype (Id); | |
6c57023b AC |
1838 | Dims_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp); |
1839 | Dims_Of_Expr : Dimension_Type; | |
1840 | ||
9a7e930f | 1841 | procedure Error_Dim_Msg_For_Component_Declaration |
6c57023b AC |
1842 | (N : Node_Id; |
1843 | Etyp : Entity_Id; | |
1844 | Expr : Node_Id); | |
9a7e930f AC |
1845 | -- Error using Error_Msg_N at node N. Output the dimensions of the |
1846 | -- type Etyp and the expression Expr of N. | |
6c57023b | 1847 | |
9a7e930f AC |
1848 | --------------------------------------------- |
1849 | -- Error_Dim_Msg_For_Component_Declaration -- | |
1850 | --------------------------------------------- | |
6c57023b | 1851 | |
9a7e930f | 1852 | procedure Error_Dim_Msg_For_Component_Declaration |
6c57023b AC |
1853 | (N : Node_Id; |
1854 | Etyp : Entity_Id; | |
1855 | Expr : Node_Id) is | |
1856 | begin | |
9a7e930f | 1857 | Error_Msg_N ("dimensions mismatch in component declaration", N); |
4a28b181 AC |
1858 | Error_Msg_N |
1859 | ("\expected dimension " & Dimensions_Msg_Of (Etyp) & ", found " | |
1860 | & Dimensions_Msg_Of (Expr), Expr); | |
9a7e930f | 1861 | end Error_Dim_Msg_For_Component_Declaration; |
54c04d6c | 1862 | |
6c57023b | 1863 | -- Start of processing for Analyze_Dimension_Component_Declaration |
dec6faf1 | 1864 | |
6c57023b | 1865 | begin |
0929eaeb AC |
1866 | -- Expression is present |
1867 | ||
6c57023b AC |
1868 | if Present (Expr) then |
1869 | Dims_Of_Expr := Dimensions_Of (Expr); | |
dec6faf1 | 1870 | |
0929eaeb | 1871 | -- Check dimensions match |
dec6faf1 | 1872 | |
6c57023b | 1873 | if Dims_Of_Etyp /= Dims_Of_Expr then |
4a28b181 | 1874 | |
0929eaeb AC |
1875 | -- Numeric literal case. Issue a warning if the object type is not |
1876 | -- dimensionless to indicate the literal is treated as if its | |
1877 | -- dimension matches the type dimension. | |
1878 | ||
4a08c95c AC |
1879 | if Nkind (Original_Node (Expr)) in |
1880 | N_Real_Literal | N_Integer_Literal | |
0929eaeb AC |
1881 | then |
1882 | Dim_Warning_For_Numeric_Literal (Expr, Etyp); | |
1883 | ||
1884 | -- Issue a dimension mismatch error for all other cases | |
1885 | ||
1886 | else | |
1887 | Error_Dim_Msg_For_Component_Declaration (N, Etyp, Expr); | |
1888 | end if; | |
6c57023b | 1889 | end if; |
dec6faf1 AC |
1890 | end if; |
1891 | end Analyze_Dimension_Component_Declaration; | |
1892 | ||
1893 | ------------------------------------------------- | |
1894 | -- Analyze_Dimension_Extended_Return_Statement -- | |
1895 | ------------------------------------------------- | |
1896 | ||
1897 | procedure Analyze_Dimension_Extended_Return_Statement (N : Node_Id) is | |
0929eaeb AC |
1898 | Return_Ent : constant Entity_Id := Return_Statement_Entity (N); |
1899 | Return_Etyp : constant Entity_Id := | |
4a28b181 | 1900 | Etype (Return_Applies_To (Return_Ent)); |
0929eaeb AC |
1901 | Return_Obj_Decls : constant List_Id := Return_Object_Declarations (N); |
1902 | Return_Obj_Decl : Node_Id; | |
1903 | Return_Obj_Id : Entity_Id; | |
1904 | Return_Obj_Typ : Entity_Id; | |
6c57023b | 1905 | |
9a7e930f | 1906 | procedure Error_Dim_Msg_For_Extended_Return_Statement |
0929eaeb AC |
1907 | (N : Node_Id; |
1908 | Return_Etyp : Entity_Id; | |
1909 | Return_Obj_Typ : Entity_Id); | |
4a28b181 AC |
1910 | -- Error using Error_Msg_N at node N. Output dimensions of the returned |
1911 | -- type Return_Etyp and the returned object type Return_Obj_Typ of N. | |
6c57023b | 1912 | |
9a7e930f AC |
1913 | ------------------------------------------------- |
1914 | -- Error_Dim_Msg_For_Extended_Return_Statement -- | |
1915 | ------------------------------------------------- | |
6c57023b | 1916 | |
9a7e930f | 1917 | procedure Error_Dim_Msg_For_Extended_Return_Statement |
0929eaeb AC |
1918 | (N : Node_Id; |
1919 | Return_Etyp : Entity_Id; | |
1920 | Return_Obj_Typ : Entity_Id) | |
6c57023b AC |
1921 | is |
1922 | begin | |
9a7e930f | 1923 | Error_Msg_N ("dimensions mismatch in extended return statement", N); |
4a28b181 AC |
1924 | Error_Msg_N |
1925 | ("\expected dimension " & Dimensions_Msg_Of (Return_Etyp) | |
1926 | & ", found " & Dimensions_Msg_Of (Return_Obj_Typ), N); | |
9a7e930f | 1927 | end Error_Dim_Msg_For_Extended_Return_Statement; |
dec6faf1 | 1928 | |
6c57023b | 1929 | -- Start of processing for Analyze_Dimension_Extended_Return_Statement |
9a7e930f | 1930 | |
dec6faf1 | 1931 | begin |
6c57023b AC |
1932 | if Present (Return_Obj_Decls) then |
1933 | Return_Obj_Decl := First (Return_Obj_Decls); | |
6c57023b AC |
1934 | while Present (Return_Obj_Decl) loop |
1935 | if Nkind (Return_Obj_Decl) = N_Object_Declaration then | |
d976bf74 | 1936 | Return_Obj_Id := Defining_Identifier (Return_Obj_Decl); |
6c57023b AC |
1937 | |
1938 | if Is_Return_Object (Return_Obj_Id) then | |
0929eaeb AC |
1939 | Return_Obj_Typ := Etype (Return_Obj_Id); |
1940 | ||
1941 | -- Issue an error message if dimensions mismatch | |
6c57023b | 1942 | |
0929eaeb AC |
1943 | if Dimensions_Of (Return_Etyp) /= |
1944 | Dimensions_Of (Return_Obj_Typ) | |
1945 | then | |
9a7e930f | 1946 | Error_Dim_Msg_For_Extended_Return_Statement |
0929eaeb | 1947 | (N, Return_Etyp, Return_Obj_Typ); |
dec6faf1 AC |
1948 | return; |
1949 | end if; | |
1950 | end if; | |
1951 | end if; | |
1952 | ||
6c57023b | 1953 | Next (Return_Obj_Decl); |
dec6faf1 AC |
1954 | end loop; |
1955 | end if; | |
1956 | end Analyze_Dimension_Extended_Return_Statement; | |
1957 | ||
0929eaeb AC |
1958 | ----------------------------------------------------- |
1959 | -- Analyze_Dimension_Extension_Or_Record_Aggregate -- | |
1960 | ----------------------------------------------------- | |
dec6faf1 | 1961 | |
0929eaeb | 1962 | procedure Analyze_Dimension_Extension_Or_Record_Aggregate (N : Node_Id) is |
d976bf74 | 1963 | Comp : Node_Id; |
0929eaeb AC |
1964 | Comp_Id : Entity_Id; |
1965 | Comp_Typ : Entity_Id; | |
1966 | Expr : Node_Id; | |
98ee6f8d | 1967 | |
0929eaeb AC |
1968 | Error_Detected : Boolean := False; |
1969 | -- This flag is used in order to indicate if an error has been detected | |
1970 | -- so far by the compiler in this routine. | |
1971 | ||
1972 | begin | |
1973 | -- Aspect is an Ada 2012 feature. Note that there is no need to check | |
fa0c3ab8 YM |
1974 | -- dimensions in inlined bodies, or for aggregates that don't come |
1975 | -- from source, or if we are within an initialization procedure, whose | |
1976 | -- expressions have been checked at the point of record declaration. | |
dec6faf1 | 1977 | |
d3ef4bd6 | 1978 | if Ada_Version < Ada_2012 |
fa0c3ab8 | 1979 | or else In_Inlined_Body |
d3ef4bd6 AC |
1980 | or else not Comes_From_Source (N) |
1981 | or else Inside_Init_Proc | |
1982 | then | |
0929eaeb AC |
1983 | return; |
1984 | end if; | |
dec6faf1 | 1985 | |
d976bf74 | 1986 | Comp := First (Component_Associations (N)); |
0929eaeb AC |
1987 | while Present (Comp) loop |
1988 | Comp_Id := Entity (First (Choices (Comp))); | |
1989 | Comp_Typ := Etype (Comp_Id); | |
dec6faf1 | 1990 | |
0929eaeb AC |
1991 | -- Check the component type is either a dimensioned type or a |
1992 | -- dimensioned subtype. | |
dec6faf1 | 1993 | |
0929eaeb AC |
1994 | if Has_Dimension_System (Base_Type (Comp_Typ)) then |
1995 | Expr := Expression (Comp); | |
dec6faf1 | 1996 | |
265ca04a AC |
1997 | -- A box-initialized component needs no checking. |
1998 | ||
1999 | if No (Expr) and then Box_Present (Comp) then | |
2000 | null; | |
2001 | ||
0929eaeb AC |
2002 | -- Issue an error if the dimensions of the component type and the |
2003 | -- dimensions of the component mismatch. | |
dec6faf1 | 2004 | |
265ca04a | 2005 | elsif Dimensions_Of (Expr) /= Dimensions_Of (Comp_Typ) then |
d976bf74 | 2006 | |
0929eaeb | 2007 | -- Check if an error has already been encountered so far |
dec6faf1 | 2008 | |
0929eaeb | 2009 | if not Error_Detected then |
d976bf74 | 2010 | |
0929eaeb | 2011 | -- Extension aggregate case |
dec6faf1 | 2012 | |
0929eaeb | 2013 | if Nkind (N) = N_Extension_Aggregate then |
d976bf74 AC |
2014 | Error_Msg_N |
2015 | ("dimensions mismatch in extension aggregate", N); | |
dec6faf1 | 2016 | |
0929eaeb | 2017 | -- Record aggregate case |
dec6faf1 | 2018 | |
0929eaeb | 2019 | else |
d976bf74 AC |
2020 | Error_Msg_N |
2021 | ("dimensions mismatch in record aggregate", N); | |
0929eaeb | 2022 | end if; |
dec6faf1 | 2023 | |
0929eaeb AC |
2024 | Error_Detected := True; |
2025 | end if; | |
dec6faf1 | 2026 | |
d976bf74 | 2027 | Error_Msg_N |
4a28b181 AC |
2028 | ("\expected dimension " & Dimensions_Msg_Of (Comp_Typ) |
2029 | & ", found " & Dimensions_Msg_Of (Expr), Comp); | |
0929eaeb AC |
2030 | end if; |
2031 | end if; | |
dec6faf1 | 2032 | |
0929eaeb AC |
2033 | Next (Comp); |
2034 | end loop; | |
2035 | end Analyze_Dimension_Extension_Or_Record_Aggregate; | |
dec6faf1 | 2036 | |
0929eaeb AC |
2037 | ------------------------------- |
2038 | -- Analyze_Dimension_Formals -- | |
2039 | ------------------------------- | |
dec6faf1 | 2040 | |
0929eaeb AC |
2041 | procedure Analyze_Dimension_Formals (N : Node_Id; Formals : List_Id) is |
2042 | Dims_Of_Typ : Dimension_Type; | |
2043 | Formal : Node_Id; | |
2044 | Typ : Entity_Id; | |
dec6faf1 | 2045 | |
0929eaeb AC |
2046 | begin |
2047 | -- Aspect is an Ada 2012 feature. Note that there is no need to check | |
2048 | -- dimensions for sub specs that don't come from source. | |
dec6faf1 | 2049 | |
d976bf74 | 2050 | if Ada_Version < Ada_2012 or else not Comes_From_Source (N) then |
0929eaeb AC |
2051 | return; |
2052 | end if; | |
dec6faf1 | 2053 | |
0929eaeb | 2054 | Formal := First (Formals); |
0929eaeb AC |
2055 | while Present (Formal) loop |
2056 | Typ := Parameter_Type (Formal); | |
2057 | Dims_Of_Typ := Dimensions_Of (Typ); | |
98ee6f8d | 2058 | |
0929eaeb AC |
2059 | if Exists (Dims_Of_Typ) then |
2060 | declare | |
2061 | Expr : constant Node_Id := Expression (Formal); | |
dec6faf1 | 2062 | |
0929eaeb AC |
2063 | begin |
2064 | -- Issue a warning if Expr is a numeric literal and if its | |
2065 | -- dimensions differ with the dimensions of the formal type. | |
2066 | ||
2067 | if Present (Expr) | |
2068 | and then Dims_Of_Typ /= Dimensions_Of (Expr) | |
4a08c95c AC |
2069 | and then Nkind (Original_Node (Expr)) in |
2070 | N_Real_Literal | N_Integer_Literal | |
0929eaeb AC |
2071 | then |
2072 | Dim_Warning_For_Numeric_Literal (Expr, Etype (Typ)); | |
2073 | end if; | |
2074 | end; | |
2075 | end if; | |
dec6faf1 | 2076 | |
0929eaeb AC |
2077 | Next (Formal); |
2078 | end loop; | |
2079 | end Analyze_Dimension_Formals; | |
dec6faf1 AC |
2080 | |
2081 | --------------------------------- | |
2082 | -- Analyze_Dimension_Has_Etype -- | |
2083 | --------------------------------- | |
2084 | ||
2085 | procedure Analyze_Dimension_Has_Etype (N : Node_Id) is | |
6c57023b | 2086 | Etyp : constant Entity_Id := Etype (N); |
9a6dc470 | 2087 | Dims_Of_Etyp : Dimension_Type := Dimensions_Of (Etyp); |
dec6faf1 AC |
2088 | |
2089 | begin | |
5f49133f | 2090 | -- General case. Propagation of the dimensions from the type |
dec6faf1 | 2091 | |
6c57023b AC |
2092 | if Exists (Dims_Of_Etyp) then |
2093 | Set_Dimensions (N, Dims_Of_Etyp); | |
473e20df | 2094 | |
5f49133f | 2095 | -- Identifier case. Propagate the dimensions from the entity for |
07ef182e | 2096 | -- identifier whose entity is a non-dimensionless constant. |
473e20df | 2097 | |
07ef182e AC |
2098 | elsif Nkind (N) = N_Identifier then |
2099 | Analyze_Dimension_Identifier : declare | |
2100 | Id : constant Entity_Id := Entity (N); | |
f5f6d8d7 | 2101 | |
07ef182e | 2102 | begin |
f5f6d8d7 | 2103 | -- If Id is missing, abnormal tree, assume previous error |
2e70d415 | 2104 | |
f5f6d8d7 | 2105 | if No (Id) then |
2e70d415 AC |
2106 | Check_Error_Detected; |
2107 | return; | |
2108 | ||
4a08c95c | 2109 | elsif Ekind (Id) in E_Constant | E_Named_Real |
07ef182e AC |
2110 | and then Exists (Dimensions_Of (Id)) |
2111 | then | |
2112 | Set_Dimensions (N, Dimensions_Of (Id)); | |
2113 | end if; | |
2114 | end Analyze_Dimension_Identifier; | |
5f49133f AC |
2115 | |
2116 | -- Attribute reference case. Propagate the dimensions from the prefix. | |
2117 | ||
2118 | elsif Nkind (N) = N_Attribute_Reference | |
2119 | and then Has_Dimension_System (Base_Type (Etyp)) | |
2120 | then | |
2121 | Dims_Of_Etyp := Dimensions_Of (Prefix (N)); | |
2122 | ||
2123 | -- Check the prefix is not dimensionless | |
2124 | ||
2125 | if Exists (Dims_Of_Etyp) then | |
2126 | Set_Dimensions (N, Dims_Of_Etyp); | |
2127 | end if; | |
dec6faf1 AC |
2128 | end if; |
2129 | ||
80007176 AC |
2130 | -- Remove dimensions from inner expressions, to prevent dimensions |
2131 | -- table from growing uselessly. | |
dec6faf1 | 2132 | |
9a7e930f | 2133 | case Nkind (N) is |
d8f43ee6 HK |
2134 | when N_Attribute_Reference |
2135 | | N_Indexed_Component | |
2136 | => | |
9a7e930f | 2137 | declare |
9a7e930f | 2138 | Exprs : constant List_Id := Expressions (N); |
d8f43ee6 HK |
2139 | Expr : Node_Id; |
2140 | ||
9a7e930f AC |
2141 | begin |
2142 | if Present (Exprs) then | |
2143 | Expr := First (Exprs); | |
2144 | while Present (Expr) loop | |
2145 | Remove_Dimensions (Expr); | |
2146 | Next (Expr); | |
2147 | end loop; | |
2148 | end if; | |
2149 | end; | |
dec6faf1 | 2150 | |
d8f43ee6 HK |
2151 | when N_Qualified_Expression |
2152 | | N_Type_Conversion | |
2153 | | N_Unchecked_Type_Conversion | |
2154 | => | |
9a7e930f AC |
2155 | Remove_Dimensions (Expression (N)); |
2156 | ||
2157 | when N_Selected_Component => | |
2158 | Remove_Dimensions (Selector_Name (N)); | |
2159 | ||
d8f43ee6 HK |
2160 | when others => |
2161 | null; | |
9a7e930f | 2162 | end case; |
dec6faf1 AC |
2163 | end Analyze_Dimension_Has_Etype; |
2164 | ||
74a78a4f AC |
2165 | ------------------------------------- |
2166 | -- Analyze_Dimension_If_Expression -- | |
2167 | ------------------------------------- | |
2168 | ||
2169 | procedure Analyze_Dimension_If_Expression (N : Node_Id) is | |
2170 | Then_Expr : constant Node_Id := Next (First (Expressions (N))); | |
2171 | Else_Expr : constant Node_Id := Next (Then_Expr); | |
cc3a2986 | 2172 | |
74a78a4f AC |
2173 | begin |
2174 | if Dimensions_Of (Then_Expr) /= Dimensions_Of (Else_Expr) then | |
2175 | Error_Msg_N ("dimensions mismatch in conditional expression", N); | |
2176 | else | |
2177 | Copy_Dimensions (Then_Expr, N); | |
2178 | end if; | |
2179 | end Analyze_Dimension_If_Expression; | |
2180 | ||
df9ad6bc AC |
2181 | ------------------------------------------ |
2182 | -- Analyze_Dimension_Number_Declaration -- | |
2183 | ------------------------------------------ | |
2184 | ||
2185 | procedure Analyze_Dimension_Number_Declaration (N : Node_Id) is | |
2186 | Expr : constant Node_Id := Expression (N); | |
2187 | Id : constant Entity_Id := Defining_Identifier (N); | |
2188 | Dim_Of_Expr : constant Dimension_Type := Dimensions_Of (Expr); | |
2189 | ||
2190 | begin | |
2191 | if Exists (Dim_Of_Expr) then | |
2192 | Set_Dimensions (Id, Dim_Of_Expr); | |
2193 | Set_Etype (Id, Etype (Expr)); | |
2194 | end if; | |
2195 | end Analyze_Dimension_Number_Declaration; | |
2196 | ||
dec6faf1 AC |
2197 | ------------------------------------------ |
2198 | -- Analyze_Dimension_Object_Declaration -- | |
2199 | ------------------------------------------ | |
2200 | ||
2201 | procedure Analyze_Dimension_Object_Declaration (N : Node_Id) is | |
6c57023b AC |
2202 | Expr : constant Node_Id := Expression (N); |
2203 | Id : constant Entity_Id := Defining_Identifier (N); | |
2204 | Etyp : constant Entity_Id := Etype (Id); | |
2205 | Dim_Of_Etyp : constant Dimension_Type := Dimensions_Of (Etyp); | |
2206 | Dim_Of_Expr : Dimension_Type; | |
2207 | ||
9a7e930f | 2208 | procedure Error_Dim_Msg_For_Object_Declaration |
6c57023b AC |
2209 | (N : Node_Id; |
2210 | Etyp : Entity_Id; | |
2211 | Expr : Node_Id); | |
9a7e930f AC |
2212 | -- Error using Error_Msg_N at node N. Output the dimensions of the |
2213 | -- type Etyp and of the expression Expr. | |
dec6faf1 | 2214 | |
9a7e930f AC |
2215 | ------------------------------------------ |
2216 | -- Error_Dim_Msg_For_Object_Declaration -- | |
2217 | ------------------------------------------ | |
dec6faf1 | 2218 | |
9a7e930f | 2219 | procedure Error_Dim_Msg_For_Object_Declaration |
6c57023b AC |
2220 | (N : Node_Id; |
2221 | Etyp : Entity_Id; | |
2222 | Expr : Node_Id) is | |
2223 | begin | |
9a7e930f | 2224 | Error_Msg_N ("dimensions mismatch in object declaration", N); |
d976bf74 | 2225 | Error_Msg_N |
4a28b181 AC |
2226 | ("\expected dimension " & Dimensions_Msg_Of (Etyp) & ", found " |
2227 | & Dimensions_Msg_Of (Expr), Expr); | |
9a7e930f | 2228 | end Error_Dim_Msg_For_Object_Declaration; |
54c04d6c | 2229 | |
6c57023b | 2230 | -- Start of processing for Analyze_Dimension_Object_Declaration |
dec6faf1 | 2231 | |
6c57023b AC |
2232 | begin |
2233 | -- Expression is present | |
dec6faf1 | 2234 | |
6c57023b AC |
2235 | if Present (Expr) then |
2236 | Dim_Of_Expr := Dimensions_Of (Expr); | |
dec6faf1 | 2237 | |
0929eaeb | 2238 | -- Check dimensions match |
dec6faf1 | 2239 | |
0929eaeb | 2240 | if Dim_Of_Expr /= Dim_Of_Etyp then |
d976bf74 | 2241 | |
27eaddda HK |
2242 | -- Numeric literal case. Issue a warning if the object type is |
2243 | -- not dimensionless to indicate the literal is treated as if | |
2244 | -- its dimension matches the type dimension. | |
0929eaeb | 2245 | |
4a08c95c AC |
2246 | if Nkind (Original_Node (Expr)) in |
2247 | N_Real_Literal | N_Integer_Literal | |
0929eaeb AC |
2248 | then |
2249 | Dim_Warning_For_Numeric_Literal (Expr, Etyp); | |
2250 | ||
d976bf74 | 2251 | -- Case of object is a constant whose type is a dimensioned type |
0929eaeb AC |
2252 | |
2253 | elsif Constant_Present (N) and then not Exists (Dim_Of_Etyp) then | |
d976bf74 AC |
2254 | |
2255 | -- Propagate dimension from expression to object entity | |
473e20df | 2256 | |
473e20df AC |
2257 | Set_Dimensions (Id, Dim_Of_Expr); |
2258 | ||
27eaddda HK |
2259 | -- Expression may have been constant-folded. If nominal type has |
2260 | -- dimensions, verify that expression has same type. | |
f2474523 AC |
2261 | |
2262 | elsif Exists (Dim_Of_Etyp) and then Etype (Expr) = Etyp then | |
2263 | null; | |
2264 | ||
0929eaeb | 2265 | -- For all other cases, issue an error message |
473e20df AC |
2266 | |
2267 | else | |
2268 | Error_Dim_Msg_For_Object_Declaration (N, Etyp, Expr); | |
2269 | end if; | |
6c57023b | 2270 | end if; |
dec6faf1 | 2271 | |
27eaddda HK |
2272 | -- Remove dimensions in expression after checking consistency with |
2273 | -- given type. | |
dec6faf1 | 2274 | |
6c57023b | 2275 | Remove_Dimensions (Expr); |
dec6faf1 AC |
2276 | end if; |
2277 | end Analyze_Dimension_Object_Declaration; | |
2278 | ||
2279 | --------------------------------------------------- | |
2280 | -- Analyze_Dimension_Object_Renaming_Declaration -- | |
2281 | --------------------------------------------------- | |
2282 | ||
2283 | procedure Analyze_Dimension_Object_Renaming_Declaration (N : Node_Id) is | |
6c57023b AC |
2284 | Renamed_Name : constant Node_Id := Name (N); |
2285 | Sub_Mark : constant Node_Id := Subtype_Mark (N); | |
2286 | ||
9a7e930f | 2287 | procedure Error_Dim_Msg_For_Object_Renaming_Declaration |
6c57023b AC |
2288 | (N : Node_Id; |
2289 | Sub_Mark : Node_Id; | |
2290 | Renamed_Name : Node_Id); | |
9a7e930f AC |
2291 | -- Error using Error_Msg_N at node N. Output the dimensions of |
2292 | -- Sub_Mark and of Renamed_Name. | |
6c57023b | 2293 | |
9a7e930f AC |
2294 | --------------------------------------------------- |
2295 | -- Error_Dim_Msg_For_Object_Renaming_Declaration -- | |
2296 | --------------------------------------------------- | |
6c57023b | 2297 | |
9a7e930f | 2298 | procedure Error_Dim_Msg_For_Object_Renaming_Declaration |
6c57023b AC |
2299 | (N : Node_Id; |
2300 | Sub_Mark : Node_Id; | |
2301 | Renamed_Name : Node_Id) is | |
2302 | begin | |
0929eaeb | 2303 | Error_Msg_N ("dimensions mismatch in object renaming declaration", N); |
d976bf74 | 2304 | Error_Msg_N |
4a28b181 AC |
2305 | ("\expected dimension " & Dimensions_Msg_Of (Sub_Mark) & ", found " |
2306 | & Dimensions_Msg_Of (Renamed_Name), Renamed_Name); | |
9a7e930f | 2307 | end Error_Dim_Msg_For_Object_Renaming_Declaration; |
6c57023b AC |
2308 | |
2309 | -- Start of processing for Analyze_Dimension_Object_Renaming_Declaration | |
2310 | ||
dec6faf1 | 2311 | begin |
6c57023b | 2312 | if Dimensions_Of (Renamed_Name) /= Dimensions_Of (Sub_Mark) then |
9a7e930f | 2313 | Error_Dim_Msg_For_Object_Renaming_Declaration |
6c57023b | 2314 | (N, Sub_Mark, Renamed_Name); |
dec6faf1 AC |
2315 | end if; |
2316 | end Analyze_Dimension_Object_Renaming_Declaration; | |
2317 | ||
2318 | ----------------------------------------------- | |
2319 | -- Analyze_Dimension_Simple_Return_Statement -- | |
2320 | ----------------------------------------------- | |
2321 | ||
2322 | procedure Analyze_Dimension_Simple_Return_Statement (N : Node_Id) is | |
6c57023b | 2323 | Expr : constant Node_Id := Expression (N); |
6c57023b AC |
2324 | Return_Ent : constant Entity_Id := Return_Statement_Entity (N); |
2325 | Return_Etyp : constant Entity_Id := | |
2326 | Etype (Return_Applies_To (Return_Ent)); | |
2327 | Dims_Of_Return_Etyp : constant Dimension_Type := | |
2328 | Dimensions_Of (Return_Etyp); | |
2329 | ||
9a7e930f | 2330 | procedure Error_Dim_Msg_For_Simple_Return_Statement |
6c57023b AC |
2331 | (N : Node_Id; |
2332 | Return_Etyp : Entity_Id; | |
2333 | Expr : Node_Id); | |
9a7e930f AC |
2334 | -- Error using Error_Msg_N at node N. Output the dimensions of the |
2335 | -- returned type Return_Etyp and the returned expression Expr of N. | |
6c57023b | 2336 | |
9a7e930f AC |
2337 | ----------------------------------------------- |
2338 | -- Error_Dim_Msg_For_Simple_Return_Statement -- | |
2339 | ----------------------------------------------- | |
6c57023b | 2340 | |
9a7e930f | 2341 | procedure Error_Dim_Msg_For_Simple_Return_Statement |
6c57023b AC |
2342 | (N : Node_Id; |
2343 | Return_Etyp : Entity_Id; | |
2344 | Expr : Node_Id) | |
2345 | is | |
2346 | begin | |
9a7e930f | 2347 | Error_Msg_N ("dimensions mismatch in return statement", N); |
d976bf74 | 2348 | Error_Msg_N |
4a28b181 AC |
2349 | ("\expected dimension " & Dimensions_Msg_Of (Return_Etyp) |
2350 | & ", found " & Dimensions_Msg_Of (Expr), Expr); | |
9a7e930f | 2351 | end Error_Dim_Msg_For_Simple_Return_Statement; |
6c57023b AC |
2352 | |
2353 | -- Start of processing for Analyze_Dimension_Simple_Return_Statement | |
2354 | ||
dec6faf1 | 2355 | begin |
d29f68cf | 2356 | if Dims_Of_Return_Etyp /= Dimensions_Of (Expr) then |
9a7e930f | 2357 | Error_Dim_Msg_For_Simple_Return_Statement (N, Return_Etyp, Expr); |
dec6faf1 AC |
2358 | Remove_Dimensions (Expr); |
2359 | end if; | |
2360 | end Analyze_Dimension_Simple_Return_Statement; | |
2361 | ||
2362 | ------------------------------------------- | |
2363 | -- Analyze_Dimension_Subtype_Declaration -- | |
2364 | ------------------------------------------- | |
2365 | ||
2366 | procedure Analyze_Dimension_Subtype_Declaration (N : Node_Id) is | |
6c57023b AC |
2367 | Id : constant Entity_Id := Defining_Identifier (N); |
2368 | Dims_Of_Id : constant Dimension_Type := Dimensions_Of (Id); | |
2369 | Dims_Of_Etyp : Dimension_Type; | |
2370 | Etyp : Node_Id; | |
dec6faf1 AC |
2371 | |
2372 | begin | |
6c57023b | 2373 | -- No constraint case in subtype declaration |
dec6faf1 | 2374 | |
6c57023b AC |
2375 | if Nkind (Subtype_Indication (N)) /= N_Subtype_Indication then |
2376 | Etyp := Etype (Subtype_Indication (N)); | |
2377 | Dims_Of_Etyp := Dimensions_Of (Etyp); | |
dec6faf1 | 2378 | |
6c57023b | 2379 | if Exists (Dims_Of_Etyp) then |
88115c2a | 2380 | |
680d5f61 AC |
2381 | -- If subtype already has a dimension (from Aspect_Dimension), it |
2382 | -- cannot inherit different dimensions from its subtype. | |
dec6faf1 | 2383 | |
680d5f61 | 2384 | if Exists (Dims_Of_Id) and then Dims_Of_Etyp /= Dims_Of_Id then |
aef44df1 AC |
2385 | Error_Msg_NE |
2386 | ("subtype& already " & Dimensions_Msg_Of (Id, True), N, Id); | |
6c57023b AC |
2387 | else |
2388 | Set_Dimensions (Id, Dims_Of_Etyp); | |
2389 | Set_Symbol (Id, Symbol_Of (Etyp)); | |
dec6faf1 | 2390 | end if; |
6c57023b | 2391 | end if; |
dec6faf1 | 2392 | |
6c57023b | 2393 | -- Constraint present in subtype declaration |
dec6faf1 | 2394 | |
6c57023b AC |
2395 | else |
2396 | Etyp := Etype (Subtype_Mark (Subtype_Indication (N))); | |
2397 | Dims_Of_Etyp := Dimensions_Of (Etyp); | |
dec6faf1 | 2398 | |
6c57023b AC |
2399 | if Exists (Dims_Of_Etyp) then |
2400 | Set_Dimensions (Id, Dims_Of_Etyp); | |
2401 | Set_Symbol (Id, Symbol_Of (Etyp)); | |
2402 | end if; | |
dec6faf1 AC |
2403 | end if; |
2404 | end Analyze_Dimension_Subtype_Declaration; | |
2405 | ||
ed323421 AC |
2406 | --------------------------------------- |
2407 | -- Analyze_Dimension_Type_Conversion -- | |
2408 | --------------------------------------- | |
2409 | ||
2410 | procedure Analyze_Dimension_Type_Conversion (N : Node_Id) is | |
2411 | Expr_Root : constant Entity_Id := | |
2412 | Dimension_System_Root (Etype (Expression (N))); | |
2413 | Target_Root : constant Entity_Id := | |
2414 | Dimension_System_Root (Etype (N)); | |
2415 | ||
2416 | begin | |
2417 | -- If the expression has dimensions and the target type has dimensions, | |
2418 | -- the conversion has the dimensions of the expression. Consistency is | |
2419 | -- checked below. Converting to a non-dimensioned type such as Float | |
2420 | -- ignores the dimensions of the expression. | |
2421 | ||
2422 | if Exists (Dimensions_Of (Expression (N))) | |
2423 | and then Present (Target_Root) | |
2424 | then | |
2425 | Set_Dimensions (N, Dimensions_Of (Expression (N))); | |
2426 | ||
2427 | -- Otherwise the dimensions are those of the target type. | |
2428 | ||
2429 | else | |
2430 | Analyze_Dimension_Has_Etype (N); | |
2431 | end if; | |
2432 | ||
2433 | -- A conversion between types in different dimension systems (e.g. MKS | |
2434 | -- and British units) must respect the dimensions of expression and | |
2435 | -- type, It is up to the user to provide proper conversion factors. | |
2436 | ||
2437 | -- Upward conversions to root type of a dimensioned system are legal, | |
2438 | -- and correspond to "view conversions", i.e. preserve the dimensions | |
2439 | -- of the expression; otherwise conversion must be between types with | |
2440 | -- then same dimensions. Conversions to a non-dimensioned type such as | |
2441 | -- Float lose the dimensions of the expression. | |
2442 | ||
2443 | if Present (Expr_Root) | |
2444 | and then Present (Target_Root) | |
2445 | and then Etype (N) /= Target_Root | |
2446 | and then Dimensions_Of (Expression (N)) /= Dimensions_Of (Etype (N)) | |
2447 | then | |
2448 | Error_Msg_N ("dimensions mismatch in conversion", N); | |
2449 | Error_Msg_N | |
2450 | ("\expression " & Dimensions_Msg_Of (Expression (N), True), N); | |
2451 | Error_Msg_N | |
2452 | ("\target type " & Dimensions_Msg_Of (Etype (N), True), N); | |
2453 | end if; | |
2454 | end Analyze_Dimension_Type_Conversion; | |
2455 | ||
dec6faf1 AC |
2456 | -------------------------------- |
2457 | -- Analyze_Dimension_Unary_Op -- | |
2458 | -------------------------------- | |
2459 | ||
2460 | procedure Analyze_Dimension_Unary_Op (N : Node_Id) is | |
2461 | begin | |
2462 | case Nkind (N) is | |
4a28b181 | 2463 | |
d8f43ee6 | 2464 | -- Propagate the dimension if the operand is not dimensionless |
4a28b181 | 2465 | |
d8f43ee6 HK |
2466 | when N_Op_Abs |
2467 | | N_Op_Minus | |
2468 | | N_Op_Plus | |
2469 | => | |
dec6faf1 AC |
2470 | declare |
2471 | R : constant Node_Id := Right_Opnd (N); | |
dec6faf1 | 2472 | begin |
dec6faf1 AC |
2473 | Move_Dimensions (R, N); |
2474 | end; | |
2475 | ||
d8f43ee6 HK |
2476 | when others => |
2477 | null; | |
dec6faf1 AC |
2478 | end case; |
2479 | end Analyze_Dimension_Unary_Op; | |
2480 | ||
888be6b1 AC |
2481 | --------------------------------- |
2482 | -- Check_Expression_Dimensions -- | |
2483 | --------------------------------- | |
2484 | ||
2485 | procedure Check_Expression_Dimensions | |
a6ac7311 AC |
2486 | (Expr : Node_Id; |
2487 | Typ : Entity_Id) | |
888be6b1 AC |
2488 | is |
2489 | begin | |
2490 | if Is_Floating_Point_Type (Etype (Expr)) then | |
2491 | Analyze_Dimension (Expr); | |
2492 | ||
2493 | if Dimensions_Of (Expr) /= Dimensions_Of (Typ) then | |
2494 | Error_Msg_N ("dimensions mismatch in array aggregate", Expr); | |
2495 | Error_Msg_N | |
2496 | ("\expected dimension " & Dimensions_Msg_Of (Typ) | |
2497 | & ", found " & Dimensions_Msg_Of (Expr), Expr); | |
2498 | end if; | |
2499 | end if; | |
2500 | end Check_Expression_Dimensions; | |
2501 | ||
ba914484 VP |
2502 | --------------------- |
2503 | -- Copy_Dimensions -- | |
2504 | --------------------- | |
2505 | ||
7738270b | 2506 | procedure Copy_Dimensions (From : Node_Id; To : Node_Id) is |
ba914484 VP |
2507 | Dims_Of_From : constant Dimension_Type := Dimensions_Of (From); |
2508 | ||
2509 | begin | |
c7e152b5 AC |
2510 | -- Ignore if not Ada 2012 or beyond |
2511 | ||
ba914484 VP |
2512 | if Ada_Version < Ada_2012 then |
2513 | return; | |
ba914484 | 2514 | |
c7e152b5 | 2515 | -- For Ada 2012, Copy the dimension of 'From to 'To' |
ba914484 | 2516 | |
c7e152b5 | 2517 | elsif Exists (Dims_Of_From) then |
ba914484 VP |
2518 | Set_Dimensions (To, Dims_Of_From); |
2519 | end if; | |
2520 | end Copy_Dimensions; | |
2521 | ||
1155ae01 AC |
2522 | ----------------------------------- |
2523 | -- Copy_Dimensions_Of_Components -- | |
2524 | ----------------------------------- | |
2525 | ||
2526 | procedure Copy_Dimensions_Of_Components (Rec : Entity_Id) is | |
2527 | C : Entity_Id; | |
2528 | ||
2529 | begin | |
2530 | C := First_Component (Rec); | |
2531 | while Present (C) loop | |
2532 | if Nkind (Parent (C)) = N_Component_Declaration then | |
2533 | Copy_Dimensions | |
2534 | (Expression (Parent (Corresponding_Record_Component (C))), | |
2535 | Expression (Parent (C))); | |
2536 | end if; | |
2537 | Next_Component (C); | |
2538 | end loop; | |
2539 | end Copy_Dimensions_Of_Components; | |
2540 | ||
6c57023b AC |
2541 | -------------------------- |
2542 | -- Create_Rational_From -- | |
2543 | -------------------------- | |
dec6faf1 | 2544 | |
6c57023b | 2545 | -- RATIONAL ::= [-] NUMERAL [/ NUMERAL] |
dec6faf1 | 2546 | |
6c57023b | 2547 | -- A rational number is a number that can be expressed as the quotient or |
9a7e930f | 2548 | -- fraction a/b of two integers, where b is non-zero positive. |
dec6faf1 | 2549 | |
88115c2a AC |
2550 | function Create_Rational_From |
2551 | (Expr : Node_Id; | |
2552 | Complain : Boolean) return Rational | |
2553 | is | |
6c57023b AC |
2554 | Or_Node_Of_Expr : constant Node_Id := Original_Node (Expr); |
2555 | Result : Rational := No_Rational; | |
dec6faf1 | 2556 | |
6c57023b | 2557 | function Process_Minus (N : Node_Id) return Rational; |
88115c2a | 2558 | -- Create a rational from a N_Op_Minus node |
dec6faf1 | 2559 | |
6c57023b | 2560 | function Process_Divide (N : Node_Id) return Rational; |
88115c2a | 2561 | -- Create a rational from a N_Op_Divide node |
dec6faf1 | 2562 | |
6c57023b | 2563 | function Process_Literal (N : Node_Id) return Rational; |
88115c2a | 2564 | -- Create a rational from a N_Integer_Literal node |
dec6faf1 | 2565 | |
6c57023b AC |
2566 | ------------------- |
2567 | -- Process_Minus -- | |
2568 | ------------------- | |
dec6faf1 | 2569 | |
6c57023b AC |
2570 | function Process_Minus (N : Node_Id) return Rational is |
2571 | Right : constant Node_Id := Original_Node (Right_Opnd (N)); | |
88115c2a | 2572 | Result : Rational; |
dec6faf1 | 2573 | |
6c57023b AC |
2574 | begin |
2575 | -- Operand is an integer literal | |
dec6faf1 | 2576 | |
6c57023b AC |
2577 | if Nkind (Right) = N_Integer_Literal then |
2578 | Result := -Process_Literal (Right); | |
dec6faf1 | 2579 | |
6c57023b AC |
2580 | -- Operand is a divide operator |
2581 | ||
2582 | elsif Nkind (Right) = N_Op_Divide then | |
2583 | Result := -Process_Divide (Right); | |
88115c2a AC |
2584 | |
2585 | else | |
2586 | Result := No_Rational; | |
dec6faf1 AC |
2587 | end if; |
2588 | ||
6c57023b AC |
2589 | return Result; |
2590 | end Process_Minus; | |
dec6faf1 | 2591 | |
6c57023b AC |
2592 | -------------------- |
2593 | -- Process_Divide -- | |
2594 | -------------------- | |
2595 | ||
2596 | function Process_Divide (N : Node_Id) return Rational is | |
2597 | Left : constant Node_Id := Original_Node (Left_Opnd (N)); | |
2598 | Right : constant Node_Id := Original_Node (Right_Opnd (N)); | |
2599 | Left_Rat : Rational; | |
2600 | Result : Rational := No_Rational; | |
2601 | Right_Rat : Rational; | |
2602 | ||
2603 | begin | |
4a28b181 | 2604 | -- Both left and right operands are integer literals |
6c57023b AC |
2605 | |
2606 | if Nkind (Left) = N_Integer_Literal | |
4a28b181 AC |
2607 | and then |
2608 | Nkind (Right) = N_Integer_Literal | |
dec6faf1 | 2609 | then |
6c57023b AC |
2610 | Left_Rat := Process_Literal (Left); |
2611 | Right_Rat := Process_Literal (Right); | |
2612 | Result := Left_Rat / Right_Rat; | |
2613 | end if; | |
dec6faf1 | 2614 | |
6c57023b AC |
2615 | return Result; |
2616 | end Process_Divide; | |
dec6faf1 | 2617 | |
6c57023b AC |
2618 | --------------------- |
2619 | -- Process_Literal -- | |
2620 | --------------------- | |
dec6faf1 | 2621 | |
6c57023b AC |
2622 | function Process_Literal (N : Node_Id) return Rational is |
2623 | begin | |
2624 | return +Whole (UI_To_Int (Intval (N))); | |
2625 | end Process_Literal; | |
dec6faf1 | 2626 | |
6c57023b | 2627 | -- Start of processing for Create_Rational_From |
dec6faf1 | 2628 | |
6c57023b AC |
2629 | begin |
2630 | -- Check the expression is either a division of two integers or an | |
88115c2a AC |
2631 | -- integer itself. Note that the check applies to the original node |
2632 | -- since the node could have already been rewritten. | |
dec6faf1 | 2633 | |
6c57023b | 2634 | -- Integer literal case |
54c04d6c | 2635 | |
6c57023b AC |
2636 | if Nkind (Or_Node_Of_Expr) = N_Integer_Literal then |
2637 | Result := Process_Literal (Or_Node_Of_Expr); | |
2638 | ||
2639 | -- Divide operator case | |
2640 | ||
2641 | elsif Nkind (Or_Node_Of_Expr) = N_Op_Divide then | |
2642 | Result := Process_Divide (Or_Node_Of_Expr); | |
2643 | ||
2644 | -- Minus operator case | |
2645 | ||
2646 | elsif Nkind (Or_Node_Of_Expr) = N_Op_Minus then | |
2647 | Result := Process_Minus (Or_Node_Of_Expr); | |
2648 | end if; | |
2649 | ||
2650 | -- When Expr cannot be interpreted as a rational and Complain is true, | |
88115c2a | 2651 | -- generate an error message. |
6c57023b AC |
2652 | |
2653 | if Complain and then Result = No_Rational then | |
df378148 | 2654 | Error_Msg_N ("rational expected", Expr); |
dec6faf1 | 2655 | end if; |
15954beb HK |
2656 | |
2657 | return Result; | |
6c57023b | 2658 | end Create_Rational_From; |
dec6faf1 | 2659 | |
15954beb HK |
2660 | ------------------- |
2661 | -- Dimensions_Of -- | |
2662 | ------------------- | |
2663 | ||
2664 | function Dimensions_Of (N : Node_Id) return Dimension_Type is | |
2665 | begin | |
2666 | return Dimension_Table.Get (N); | |
2667 | end Dimensions_Of; | |
2668 | ||
6c57023b AC |
2669 | ----------------------- |
2670 | -- Dimensions_Msg_Of -- | |
2671 | ----------------------- | |
2672 | ||
0929eaeb AC |
2673 | function Dimensions_Msg_Of |
2674 | (N : Node_Id; | |
2675 | Description_Needed : Boolean := False) return String | |
2676 | is | |
6c57023b AC |
2677 | Dims_Of_N : constant Dimension_Type := Dimensions_Of (N); |
2678 | Dimensions_Msg : Name_Id; | |
2679 | System : System_Type; | |
2680 | ||
6c57023b AC |
2681 | begin |
2682 | -- Initialization of Name_Buffer | |
2683 | ||
2684 | Name_Len := 0; | |
2685 | ||
0929eaeb AC |
2686 | -- N is not dimensionless |
2687 | ||
6c57023b AC |
2688 | if Exists (Dims_Of_N) then |
2689 | System := System_Of (Base_Type (Etype (N))); | |
0929eaeb AC |
2690 | |
2691 | -- When Description_Needed, add to string "has dimension " before the | |
2692 | -- actual dimension. | |
2693 | ||
2694 | if Description_Needed then | |
2695 | Add_Str_To_Name_Buffer ("has dimension "); | |
2696 | end if; | |
2697 | ||
b6e6a4e3 AC |
2698 | Append |
2699 | (Global_Name_Buffer, | |
2700 | From_Dim_To_Str_Of_Dim_Symbols (Dims_Of_N, System, True)); | |
0929eaeb AC |
2701 | |
2702 | -- N is dimensionless | |
2703 | ||
2704 | -- When Description_Needed, return "is dimensionless" | |
2705 | ||
2706 | elsif Description_Needed then | |
6c57023b | 2707 | Add_Str_To_Name_Buffer ("is dimensionless"); |
0929eaeb | 2708 | |
4a28b181 | 2709 | -- Otherwise, return "'[']" |
0929eaeb AC |
2710 | |
2711 | else | |
4a28b181 | 2712 | Add_Str_To_Name_Buffer ("'[']"); |
6c57023b AC |
2713 | end if; |
2714 | ||
2715 | Dimensions_Msg := Name_Find; | |
2716 | return Get_Name_String (Dimensions_Msg); | |
2717 | end Dimensions_Msg_Of; | |
2718 | ||
15954beb HK |
2719 | -------------------------- |
2720 | -- Dimension_Table_Hash -- | |
2721 | -------------------------- | |
2722 | ||
2723 | function Dimension_Table_Hash | |
2724 | (Key : Node_Id) return Dimension_Table_Range | |
2725 | is | |
2726 | begin | |
2727 | return Dimension_Table_Range (Key mod 511); | |
2728 | end Dimension_Table_Hash; | |
2729 | ||
0929eaeb AC |
2730 | ------------------------------------- |
2731 | -- Dim_Warning_For_Numeric_Literal -- | |
2732 | ------------------------------------- | |
2733 | ||
2734 | procedure Dim_Warning_For_Numeric_Literal (N : Node_Id; Typ : Entity_Id) is | |
2735 | begin | |
8f8f531f PMR |
2736 | -- Consider the literal zero (integer 0 or real 0.0) to be of any |
2737 | -- dimension. | |
2738 | ||
2739 | case Nkind (Original_Node (N)) is | |
2740 | when N_Real_Literal => | |
2741 | if Expr_Value_R (N) = Ureal_0 then | |
2742 | return; | |
2743 | end if; | |
2744 | ||
2745 | when N_Integer_Literal => | |
2746 | if Expr_Value (N) = Uint_0 then | |
2747 | return; | |
2748 | end if; | |
2749 | ||
2750 | when others => | |
2751 | null; | |
2752 | end case; | |
2753 | ||
0929eaeb AC |
2754 | -- Initialize name buffer |
2755 | ||
2756 | Name_Len := 0; | |
2757 | ||
b6e6a4e3 | 2758 | Append (Global_Name_Buffer, String_From_Numeric_Literal (N)); |
0929eaeb AC |
2759 | |
2760 | -- Insert a blank between the literal and the symbol | |
0929eaeb | 2761 | |
4a28b181 | 2762 | Add_Str_To_Name_Buffer (" "); |
b6e6a4e3 | 2763 | Append (Global_Name_Buffer, Symbol_Of (Typ)); |
0929eaeb AC |
2764 | |
2765 | Error_Msg_Name_1 := Name_Find; | |
4a28b181 | 2766 | Error_Msg_N ("assumed to be%%??", N); |
0929eaeb AC |
2767 | end Dim_Warning_For_Numeric_Literal; |
2768 | ||
7738270b AC |
2769 | ---------------------- |
2770 | -- Dimensions_Match -- | |
2771 | ---------------------- | |
2772 | ||
2773 | function Dimensions_Match (T1 : Entity_Id; T2 : Entity_Id) return Boolean is | |
2774 | begin | |
2775 | return | |
2776 | not Has_Dimension_System (Base_Type (T1)) | |
2777 | or else Dimensions_Of (T1) = Dimensions_Of (T2); | |
2778 | end Dimensions_Match; | |
2779 | ||
ed323421 AC |
2780 | --------------------------- |
2781 | -- Dimension_System_Root -- | |
2782 | --------------------------- | |
2783 | ||
2784 | function Dimension_System_Root (T : Entity_Id) return Entity_Id is | |
2785 | Root : Entity_Id; | |
2786 | ||
2787 | begin | |
2788 | Root := Base_Type (T); | |
2789 | ||
2790 | if Has_Dimension_System (Root) then | |
2791 | return First_Subtype (Root); -- for example Dim_Mks | |
2792 | ||
2793 | else | |
2794 | return Empty; | |
2795 | end if; | |
2796 | end Dimension_System_Root; | |
2797 | ||
dec6faf1 AC |
2798 | ---------------------------------------- |
2799 | -- Eval_Op_Expon_For_Dimensioned_Type -- | |
2800 | ---------------------------------------- | |
2801 | ||
9a7e930f | 2802 | -- Evaluate the expon operator for real dimensioned type. |
dec6faf1 | 2803 | |
54c04d6c | 2804 | -- Note that if the exponent is an integer (denominator = 1) the node is |
6c57023b | 2805 | -- evaluated by the regular Eval_Op_Expon routine (see Sem_Eval). |
dec6faf1 AC |
2806 | |
2807 | procedure Eval_Op_Expon_For_Dimensioned_Type | |
6c57023b AC |
2808 | (N : Node_Id; |
2809 | Btyp : Entity_Id) | |
dec6faf1 | 2810 | is |
6c57023b AC |
2811 | R : constant Node_Id := Right_Opnd (N); |
2812 | R_Value : Rational := No_Rational; | |
2813 | ||
dec6faf1 | 2814 | begin |
9a7e930f | 2815 | if Is_Real_Type (Btyp) then |
6c57023b AC |
2816 | R_Value := Create_Rational_From (R, False); |
2817 | end if; | |
2818 | ||
2819 | -- Check that the exponent is not an integer | |
2820 | ||
88115c2a | 2821 | if R_Value /= No_Rational and then R_Value.Denominator /= 1 then |
6c57023b AC |
2822 | Eval_Op_Expon_With_Rational_Exponent (N, R_Value); |
2823 | else | |
2824 | Eval_Op_Expon (N); | |
dec6faf1 AC |
2825 | end if; |
2826 | end Eval_Op_Expon_For_Dimensioned_Type; | |
2827 | ||
2828 | ------------------------------------------ | |
2829 | -- Eval_Op_Expon_With_Rational_Exponent -- | |
2830 | ------------------------------------------ | |
2831 | ||
2832 | -- For dimensioned operand in exponentiation, exponent is allowed to be a | |
2833 | -- Rational and not only an Integer like for dimensionless operands. For | |
2834 | -- that particular case, the left operand is rewritten as a function call | |
2835 | -- using the function Expon_LLF from s-llflex.ads. | |
2836 | ||
2837 | procedure Eval_Op_Expon_With_Rational_Exponent | |
6c57023b AC |
2838 | (N : Node_Id; |
2839 | Exponent_Value : Rational) | |
dec6faf1 | 2840 | is |
4a28b181 | 2841 | Loc : constant Source_Ptr := Sloc (N); |
6c57023b | 2842 | Dims_Of_N : constant Dimension_Type := Dimensions_Of (N); |
4a28b181 AC |
2843 | L : constant Node_Id := Left_Opnd (N); |
2844 | Etyp_Of_L : constant Entity_Id := Etype (L); | |
2845 | Btyp_Of_L : constant Entity_Id := Base_Type (Etyp_Of_L); | |
6c57023b AC |
2846 | Actual_1 : Node_Id; |
2847 | Actual_2 : Node_Id; | |
2848 | Dim_Power : Rational; | |
2849 | List_Of_Dims : List_Id; | |
2850 | New_Aspect : Node_Id; | |
2851 | New_Aspects : List_Id; | |
2852 | New_Id : Entity_Id; | |
2853 | New_N : Node_Id; | |
2854 | New_Subtyp_Decl_For_L : Node_Id; | |
2855 | System : System_Type; | |
dec6faf1 AC |
2856 | |
2857 | begin | |
6c57023b | 2858 | -- Case when the operand is not dimensionless |
dec6faf1 | 2859 | |
6c57023b | 2860 | if Exists (Dims_Of_N) then |
dec6faf1 | 2861 | |
6c57023b AC |
2862 | -- Get the corresponding System_Type to know the exact number of |
2863 | -- dimensions in the system. | |
dec6faf1 | 2864 | |
6c57023b | 2865 | System := System_Of (Btyp_Of_L); |
dec6faf1 | 2866 | |
6c57023b | 2867 | -- Generation of a new subtype with the proper dimensions |
dec6faf1 | 2868 | |
6c57023b AC |
2869 | -- In order to rewrite the operator as a type conversion, a new |
2870 | -- dimensioned subtype with the resulting dimensions of the | |
2871 | -- exponentiation must be created. | |
dec6faf1 | 2872 | |
6c57023b | 2873 | -- Generate: |
54c04d6c | 2874 | |
6c57023b AC |
2875 | -- Btyp_Of_L : constant Entity_Id := Base_Type (Etyp_Of_L); |
2876 | -- System : constant System_Id := | |
2877 | -- Get_Dimension_System_Id (Btyp_Of_L); | |
2878 | -- Num_Of_Dims : constant Number_Of_Dimensions := | |
2879 | -- Dimension_Systems.Table (System).Dimension_Count; | |
2880 | ||
2881 | -- subtype T is Btyp_Of_L | |
2882 | -- with | |
df378148 | 2883 | -- Dimension => ( |
6c57023b AC |
2884 | -- Dims_Of_N (1).Numerator / Dims_Of_N (1).Denominator, |
2885 | -- Dims_Of_N (2).Numerator / Dims_Of_N (2).Denominator, | |
2886 | -- ... | |
2887 | -- Dims_Of_N (Num_Of_Dims).Numerator / | |
2888 | -- Dims_Of_N (Num_Of_Dims).Denominator); | |
2889 | ||
2890 | -- Step 1: Generate the new aggregate for the aspect Dimension | |
2891 | ||
2892 | New_Aspects := Empty_List; | |
6c57023b | 2893 | |
4a28b181 | 2894 | List_Of_Dims := New_List; |
64ac53f4 | 2895 | for Position in Dims_Of_N'First .. System.Count loop |
6c57023b AC |
2896 | Dim_Power := Dims_Of_N (Position); |
2897 | Append_To (List_Of_Dims, | |
2898 | Make_Op_Divide (Loc, | |
2899 | Left_Opnd => | |
4a28b181 | 2900 | Make_Integer_Literal (Loc, Int (Dim_Power.Numerator)), |
6c57023b | 2901 | Right_Opnd => |
4a28b181 | 2902 | Make_Integer_Literal (Loc, Int (Dim_Power.Denominator)))); |
6c57023b | 2903 | end loop; |
dec6faf1 | 2904 | |
6c57023b | 2905 | -- Step 2: Create the new Aspect Specification for Aspect Dimension |
dec6faf1 | 2906 | |
6c57023b AC |
2907 | New_Aspect := |
2908 | Make_Aspect_Specification (Loc, | |
2909 | Identifier => Make_Identifier (Loc, Name_Dimension), | |
2910 | Expression => Make_Aggregate (Loc, Expressions => List_Of_Dims)); | |
dec6faf1 | 2911 | |
6c57023b | 2912 | -- Step 3: Make a temporary identifier for the new subtype |
dec6faf1 | 2913 | |
6c57023b AC |
2914 | New_Id := Make_Temporary (Loc, 'T'); |
2915 | Set_Is_Internal (New_Id); | |
dec6faf1 | 2916 | |
6c57023b | 2917 | -- Step 4: Declaration of the new subtype |
dec6faf1 | 2918 | |
6c57023b AC |
2919 | New_Subtyp_Decl_For_L := |
2920 | Make_Subtype_Declaration (Loc, | |
2921 | Defining_Identifier => New_Id, | |
2922 | Subtype_Indication => New_Occurrence_Of (Btyp_Of_L, Loc)); | |
dec6faf1 | 2923 | |
6c57023b AC |
2924 | Append (New_Aspect, New_Aspects); |
2925 | Set_Parent (New_Aspects, New_Subtyp_Decl_For_L); | |
2926 | Set_Aspect_Specifications (New_Subtyp_Decl_For_L, New_Aspects); | |
dec6faf1 | 2927 | |
6c57023b | 2928 | Analyze (New_Subtyp_Decl_For_L); |
dec6faf1 | 2929 | |
88115c2a | 2930 | -- Case where the operand is dimensionless |
dec6faf1 | 2931 | |
6c57023b AC |
2932 | else |
2933 | New_Id := Btyp_Of_L; | |
2934 | end if; | |
dec6faf1 | 2935 | |
6c57023b | 2936 | -- Replacement of N by New_N |
dec6faf1 | 2937 | |
6c57023b | 2938 | -- Generate: |
dec6faf1 | 2939 | |
6c57023b | 2940 | -- Actual_1 := Long_Long_Float (L), |
dec6faf1 | 2941 | |
6c57023b AC |
2942 | -- Actual_2 := Long_Long_Float (Exponent_Value.Numerator) / |
2943 | -- Long_Long_Float (Exponent_Value.Denominator); | |
dec6faf1 | 2944 | |
6c57023b | 2945 | -- (T (Expon_LLF (Actual_1, Actual_2))); |
dec6faf1 | 2946 | |
88115c2a AC |
2947 | -- where T is the subtype declared in step 1 |
2948 | ||
2949 | -- The node is rewritten as a type conversion | |
dec6faf1 | 2950 | |
6c57023b | 2951 | -- Step 1: Creation of the two parameters of Expon_LLF function call |
dec6faf1 | 2952 | |
6c57023b AC |
2953 | Actual_1 := |
2954 | Make_Type_Conversion (Loc, | |
e4494292 | 2955 | Subtype_Mark => New_Occurrence_Of (Standard_Long_Long_Float, Loc), |
6c57023b | 2956 | Expression => Relocate_Node (L)); |
dec6faf1 | 2957 | |
6c57023b AC |
2958 | Actual_2 := |
2959 | Make_Op_Divide (Loc, | |
2960 | Left_Opnd => | |
2961 | Make_Real_Literal (Loc, | |
2962 | UR_From_Uint (UI_From_Int (Int (Exponent_Value.Numerator)))), | |
2963 | Right_Opnd => | |
2964 | Make_Real_Literal (Loc, | |
2965 | UR_From_Uint (UI_From_Int (Int (Exponent_Value.Denominator))))); | |
dec6faf1 | 2966 | |
6c57023b | 2967 | -- Step 2: Creation of New_N |
dec6faf1 | 2968 | |
6c57023b AC |
2969 | New_N := |
2970 | Make_Type_Conversion (Loc, | |
e4494292 | 2971 | Subtype_Mark => New_Occurrence_Of (New_Id, Loc), |
4a28b181 | 2972 | Expression => |
6c57023b | 2973 | Make_Function_Call (Loc, |
e4494292 | 2974 | Name => New_Occurrence_Of (RTE (RE_Expon_LLF), Loc), |
6c57023b AC |
2975 | Parameter_Associations => New_List ( |
2976 | Actual_1, Actual_2))); | |
dec6faf1 | 2977 | |
88115c2a | 2978 | -- Step 3: Rewrite N with the result |
dec6faf1 | 2979 | |
6c57023b AC |
2980 | Rewrite (N, New_N); |
2981 | Set_Etype (N, New_Id); | |
2982 | Analyze_And_Resolve (N, New_Id); | |
dec6faf1 AC |
2983 | end Eval_Op_Expon_With_Rational_Exponent; |
2984 | ||
15954beb HK |
2985 | ------------ |
2986 | -- Exists -- | |
2987 | ------------ | |
2988 | ||
2989 | function Exists (Dim : Dimension_Type) return Boolean is | |
2990 | begin | |
2991 | return Dim /= Null_Dimension; | |
2992 | end Exists; | |
2993 | ||
0929eaeb AC |
2994 | function Exists (Str : String_Id) return Boolean is |
2995 | begin | |
2996 | return Str /= No_String; | |
2997 | end Exists; | |
2998 | ||
15954beb HK |
2999 | function Exists (Sys : System_Type) return Boolean is |
3000 | begin | |
3001 | return Sys /= Null_System; | |
3002 | end Exists; | |
3003 | ||
df378148 AC |
3004 | --------------------------------- |
3005 | -- Expand_Put_Call_With_Symbol -- | |
3006 | --------------------------------- | |
3007 | ||
319c6161 AC |
3008 | -- For procedure Put (resp. Put_Dim_Of) and function Image, defined in |
3009 | -- System.Dim.Float_IO or System.Dim.Integer_IO, the default string | |
3010 | -- parameter is rewritten to include the unit symbol (or the dimension | |
3011 | -- symbols if not a defined quantity) in the output of a dimensioned | |
64ac53f4 | 3012 | -- object. If a value is already supplied by the user for the parameter |
319c6161 | 3013 | -- Symbol, it is used as is. |
df378148 AC |
3014 | |
3015 | -- Case 1. Item is dimensionless | |
3016 | ||
3017 | -- * Put : Item appears without a suffix | |
dec6faf1 | 3018 | |
df378148 | 3019 | -- * Put_Dim_Of : the output is [] |
dec6faf1 | 3020 | |
df378148 AC |
3021 | -- Obj : Mks_Type := 2.6; |
3022 | -- Put (Obj, 1, 1, 0); | |
3023 | -- Put_Dim_Of (Obj); | |
88115c2a | 3024 | |
df378148 AC |
3025 | -- The corresponding outputs are: |
3026 | -- $2.6 | |
3027 | -- $[] | |
88115c2a | 3028 | |
df378148 | 3029 | -- Case 2. Item has a dimension |
6c57023b | 3030 | |
df378148 AC |
3031 | -- * Put : If the type of Item is a dimensioned subtype whose |
3032 | -- symbol is not empty, then the symbol appears as a | |
3033 | -- suffix. Otherwise, a new string is created and appears | |
3034 | -- as a suffix of Item. This string results in the | |
3035 | -- successive concatanations between each unit symbol | |
3036 | -- raised by its corresponding dimension power from the | |
3037 | -- dimensions of Item. | |
88115c2a | 3038 | |
df378148 AC |
3039 | -- * Put_Dim_Of : The output is a new string resulting in the successive |
3040 | -- concatanations between each dimension symbol raised by | |
3041 | -- its corresponding dimension power from the dimensions of | |
3042 | -- Item. | |
88115c2a | 3043 | |
df378148 AC |
3044 | -- subtype Random is Mks_Type |
3045 | -- with | |
3046 | -- Dimension => ( | |
3047 | -- Meter => 3, | |
3048 | -- Candela => -1, | |
3049 | -- others => 0); | |
6c57023b | 3050 | |
df378148 AC |
3051 | -- Obj : Random := 5.0; |
3052 | -- Put (Obj); | |
3053 | -- Put_Dim_Of (Obj); | |
3054 | ||
3055 | -- The corresponding outputs are: | |
3056 | -- $5.0 m**3.cd**(-1) | |
3057 | -- $[l**3.J**(-1)] | |
3058 | ||
319c6161 AC |
3059 | -- The function Image returns the string identical to that produced by |
3060 | -- a call to Put whose first parameter is a string. | |
3061 | ||
df378148 | 3062 | procedure Expand_Put_Call_With_Symbol (N : Node_Id) is |
6c57023b AC |
3063 | Actuals : constant List_Id := Parameter_Associations (N); |
3064 | Loc : constant Source_Ptr := Sloc (N); | |
3065 | Name_Call : constant Node_Id := Name (N); | |
1b6897ce | 3066 | New_Actuals : constant List_Id := New_List; |
6c57023b | 3067 | Actual : Node_Id; |
6c57023b AC |
3068 | Dims_Of_Actual : Dimension_Type; |
3069 | Etyp : Entity_Id; | |
1b6897ce | 3070 | New_Str_Lit : Node_Id := Empty; |
0929eaeb | 3071 | Symbols : String_Id; |
6c57023b | 3072 | |
df378148 AC |
3073 | Is_Put_Dim_Of : Boolean := False; |
3074 | -- This flag is used in order to differentiate routines Put and | |
3075 | -- Put_Dim_Of. Set to True if the procedure is one of the Put_Dim_Of | |
3076 | -- defined in System.Dim.Float_IO or System.Dim.Integer_IO. | |
3077 | ||
3078 | function Has_Symbols return Boolean; | |
1b6897ce AC |
3079 | -- Return True if the current Put call already has a parameter |
3080 | -- association for parameter "Symbols" with the correct string of | |
3081 | -- symbols. | |
3082 | ||
6c57023b | 3083 | function Is_Procedure_Put_Call return Boolean; |
dec6faf1 | 3084 | -- Return True if the current call is a call of an instantiation of a |
7b50c4a3 AC |
3085 | -- procedure Put defined in the package System.Dim.Float_IO and |
3086 | -- System.Dim.Integer_IO. | |
dec6faf1 | 3087 | |
1b6897ce | 3088 | function Item_Actual return Node_Id; |
df378148 | 3089 | -- Return the item actual parameter node in the output call |
1b6897ce | 3090 | |
df378148 AC |
3091 | ----------------- |
3092 | -- Has_Symbols -- | |
3093 | ----------------- | |
1b6897ce | 3094 | |
df378148 | 3095 | function Has_Symbols return Boolean is |
804fc056 AC |
3096 | Actual : Node_Id; |
3097 | Actual_Str : Node_Id; | |
1b6897ce AC |
3098 | |
3099 | begin | |
1b6897ce AC |
3100 | -- Look for a symbols parameter association in the list of actuals |
3101 | ||
4a28b181 | 3102 | Actual := First (Actuals); |
1b6897ce | 3103 | while Present (Actual) loop |
c7e152b5 | 3104 | |
804fc056 AC |
3105 | -- Positional parameter association case when the actual is a |
3106 | -- string literal. | |
3107 | ||
3108 | if Nkind (Actual) = N_String_Literal then | |
3109 | Actual_Str := Actual; | |
3110 | ||
c7e152b5 | 3111 | -- Named parameter association case when selector name is Symbol |
804fc056 AC |
3112 | |
3113 | elsif Nkind (Actual) = N_Parameter_Association | |
df378148 | 3114 | and then Chars (Selector_Name (Actual)) = Name_Symbol |
1b6897ce | 3115 | then |
804fc056 AC |
3116 | Actual_Str := Explicit_Actual_Parameter (Actual); |
3117 | ||
3118 | -- Ignore all other cases | |
3119 | ||
3120 | else | |
3121 | Actual_Str := Empty; | |
3122 | end if; | |
3123 | ||
3124 | if Present (Actual_Str) then | |
c7e152b5 | 3125 | |
21791d97 | 3126 | -- Return True if the actual comes from source or if the string |
319c6161 AC |
3127 | -- of symbols doesn't have the default value (i.e. it is ""), |
3128 | -- in which case it is used as suffix of the generated string. | |
1b6897ce | 3129 | |
804fc056 AC |
3130 | if Comes_From_Source (Actual) |
3131 | or else String_Length (Strval (Actual_Str)) /= 0 | |
3132 | then | |
804fc056 AC |
3133 | return True; |
3134 | ||
3135 | else | |
3136 | return False; | |
3137 | end if; | |
1b6897ce AC |
3138 | end if; |
3139 | ||
3140 | Next (Actual); | |
3141 | end loop; | |
3142 | ||
21791d97 AC |
3143 | -- At this point, the call has no parameter association. Look to the |
3144 | -- last actual since the symbols parameter is the last one. | |
1b6897ce AC |
3145 | |
3146 | return Nkind (Last (Actuals)) = N_String_Literal; | |
df378148 | 3147 | end Has_Symbols; |
1b6897ce | 3148 | |
88115c2a AC |
3149 | --------------------------- |
3150 | -- Is_Procedure_Put_Call -- | |
3151 | --------------------------- | |
3152 | ||
6c57023b AC |
3153 | function Is_Procedure_Put_Call return Boolean is |
3154 | Ent : Entity_Id; | |
98ee6f8d | 3155 | Loc : Source_Ptr; |
dec6faf1 AC |
3156 | |
3157 | begin | |
df378148 AC |
3158 | -- There are three different Put (resp. Put_Dim_Of) routines in each |
3159 | -- generic dim IO package. Verify the current procedure call is one | |
3160 | -- of them. | |
dec6faf1 AC |
3161 | |
3162 | if Is_Entity_Name (Name_Call) then | |
3163 | Ent := Entity (Name_Call); | |
3164 | ||
98ee6f8d | 3165 | -- Get the original subprogram entity following the renaming chain |
dec6faf1 | 3166 | |
98ee6f8d AC |
3167 | if Present (Alias (Ent)) then |
3168 | Ent := Alias (Ent); | |
3169 | end if; | |
dec6faf1 | 3170 | |
98ee6f8d | 3171 | Loc := Sloc (Ent); |
dec6faf1 | 3172 | |
df378148 AC |
3173 | -- Check the name of the entity subprogram is Put (resp. |
3174 | -- Put_Dim_Of) and verify this entity is located in either | |
3175 | -- System.Dim.Float_IO or System.Dim.Integer_IO. | |
98ee6f8d | 3176 | |
df378148 | 3177 | if Loc > No_Location |
98ee6f8d | 3178 | and then Is_Dim_IO_Package_Entity |
df378148 AC |
3179 | (Cunit_Entity (Get_Source_Unit (Loc))) |
3180 | then | |
3181 | if Chars (Ent) = Name_Put_Dim_Of then | |
3182 | Is_Put_Dim_Of := True; | |
3183 | return True; | |
3184 | ||
319c6161 AC |
3185 | elsif Chars (Ent) = Name_Put |
3186 | or else Chars (Ent) = Name_Image | |
3187 | then | |
df378148 AC |
3188 | return True; |
3189 | end if; | |
3190 | end if; | |
dec6faf1 AC |
3191 | end if; |
3192 | ||
3193 | return False; | |
3194 | end Is_Procedure_Put_Call; | |
3195 | ||
1b6897ce AC |
3196 | ----------------- |
3197 | -- Item_Actual -- | |
3198 | ----------------- | |
dec6faf1 | 3199 | |
1b6897ce | 3200 | function Item_Actual return Node_Id is |
37da997b | 3201 | Actual : Node_Id; |
dec6faf1 | 3202 | |
1b6897ce | 3203 | begin |
1b6897ce | 3204 | -- Look for the item actual as a parameter association |
dec6faf1 | 3205 | |
37da997b | 3206 | Actual := First (Actuals); |
1b6897ce AC |
3207 | while Present (Actual) loop |
3208 | if Nkind (Actual) = N_Parameter_Association | |
3209 | and then Chars (Selector_Name (Actual)) = Name_Item | |
3210 | then | |
3211 | return Explicit_Actual_Parameter (Actual); | |
3212 | end if; | |
dec6faf1 | 3213 | |
1b6897ce AC |
3214 | Next (Actual); |
3215 | end loop; | |
dec6faf1 | 3216 | |
1b6897ce | 3217 | -- Case where the item has been defined without an association |
dec6faf1 | 3218 | |
1b6897ce | 3219 | Actual := First (Actuals); |
dec6faf1 | 3220 | |
1b6897ce AC |
3221 | -- Depending on the procedure Put, Item actual could be first or |
3222 | -- second in the list of actuals. | |
dec6faf1 | 3223 | |
1b6897ce AC |
3224 | if Has_Dimension_System (Base_Type (Etype (Actual))) then |
3225 | return Actual; | |
dec6faf1 | 3226 | else |
1b6897ce | 3227 | return Next (Actual); |
dec6faf1 | 3228 | end if; |
1b6897ce | 3229 | end Item_Actual; |
dec6faf1 | 3230 | |
df378148 | 3231 | -- Start of processing for Expand_Put_Call_With_Symbol |
dec6faf1 | 3232 | |
1b6897ce | 3233 | begin |
df378148 | 3234 | if Is_Procedure_Put_Call and then not Has_Symbols then |
1b6897ce AC |
3235 | Actual := Item_Actual; |
3236 | Dims_Of_Actual := Dimensions_Of (Actual); | |
3237 | Etyp := Etype (Actual); | |
dec6faf1 | 3238 | |
df378148 | 3239 | -- Put_Dim_Of case |
dec6faf1 | 3240 | |
df378148 | 3241 | if Is_Put_Dim_Of then |
21791d97 | 3242 | |
df378148 AC |
3243 | -- Check that the item is not dimensionless |
3244 | ||
3245 | -- Create the new String_Literal with the new String_Id generated | |
3246 | -- by the routine From_Dim_To_Str_Of_Dim_Symbols. | |
3247 | ||
3248 | if Exists (Dims_Of_Actual) then | |
df378148 AC |
3249 | New_Str_Lit := |
3250 | Make_String_Literal (Loc, | |
0929eaeb AC |
3251 | From_Dim_To_Str_Of_Dim_Symbols |
3252 | (Dims_Of_Actual, System_Of (Base_Type (Etyp)))); | |
df378148 AC |
3253 | |
3254 | -- If dimensionless, the output is [] | |
3255 | ||
3256 | else | |
3257 | New_Str_Lit := | |
3258 | Make_String_Literal (Loc, "[]"); | |
3259 | end if; | |
3260 | ||
3261 | -- Put case | |
3262 | ||
3263 | else | |
3264 | -- Add the symbol as a suffix of the value if the subtype has a | |
3265 | -- unit symbol or if the parameter is not dimensionless. | |
3266 | ||
0929eaeb AC |
3267 | if Exists (Symbol_Of (Etyp)) then |
3268 | Symbols := Symbol_Of (Etyp); | |
0929eaeb AC |
3269 | else |
3270 | Symbols := From_Dim_To_Str_Of_Unit_Symbols | |
3271 | (Dims_Of_Actual, System_Of (Base_Type (Etyp))); | |
3272 | end if; | |
3273 | ||
3274 | -- Check Symbols exists | |
3275 | ||
3276 | if Exists (Symbols) then | |
df378148 | 3277 | Start_String; |
dec6faf1 | 3278 | |
df378148 | 3279 | -- Put a space between the value and the dimension |
dec6faf1 | 3280 | |
df378148 | 3281 | Store_String_Char (' '); |
0929eaeb | 3282 | Store_String_Chars (Symbols); |
df378148 | 3283 | New_Str_Lit := Make_String_Literal (Loc, End_String); |
df378148 | 3284 | end if; |
1b6897ce | 3285 | end if; |
dec6faf1 | 3286 | |
1b6897ce | 3287 | if Present (New_Str_Lit) then |
37da997b | 3288 | |
1b6897ce | 3289 | -- Insert all actuals in New_Actuals |
dec6faf1 | 3290 | |
1b6897ce | 3291 | Actual := First (Actuals); |
1b6897ce | 3292 | while Present (Actual) loop |
37da997b | 3293 | |
457c5df4 AC |
3294 | -- Copy every actuals in New_Actuals except the Symbols |
3295 | -- parameter association. | |
3296 | ||
3297 | if Nkind (Actual) = N_Parameter_Association | |
df378148 | 3298 | and then Chars (Selector_Name (Actual)) /= Name_Symbol |
457c5df4 | 3299 | then |
37da997b | 3300 | Append_To (New_Actuals, |
457c5df4 AC |
3301 | Make_Parameter_Association (Loc, |
3302 | Selector_Name => New_Copy (Selector_Name (Actual)), | |
3303 | Explicit_Actual_Parameter => | |
37da997b | 3304 | New_Copy (Explicit_Actual_Parameter (Actual)))); |
457c5df4 AC |
3305 | |
3306 | elsif Nkind (Actual) /= N_Parameter_Association then | |
37da997b | 3307 | Append_To (New_Actuals, New_Copy (Actual)); |
1b6897ce | 3308 | end if; |
dec6faf1 | 3309 | |
1b6897ce AC |
3310 | Next (Actual); |
3311 | end loop; | |
dec6faf1 | 3312 | |
37da997b | 3313 | -- Create new Symbols param association and append to New_Actuals |
dec6faf1 | 3314 | |
37da997b | 3315 | Append_To (New_Actuals, |
1b6897ce | 3316 | Make_Parameter_Association (Loc, |
df378148 | 3317 | Selector_Name => Make_Identifier (Loc, Name_Symbol), |
37da997b | 3318 | Explicit_Actual_Parameter => New_Str_Lit)); |
dec6faf1 | 3319 | |
1b6897ce | 3320 | -- Rewrite and analyze the procedure call |
dec6faf1 | 3321 | |
319c6161 AC |
3322 | if Chars (Name_Call) = Name_Image then |
3323 | Rewrite (N, | |
3324 | Make_Function_Call (Loc, | |
3325 | Name => New_Copy (Name_Call), | |
3326 | Parameter_Associations => New_Actuals)); | |
3327 | Analyze_And_Resolve (N); | |
3328 | else | |
3329 | Rewrite (N, | |
3330 | Make_Procedure_Call_Statement (Loc, | |
3331 | Name => New_Copy (Name_Call), | |
3332 | Parameter_Associations => New_Actuals)); | |
3333 | Analyze (N); | |
3334 | end if; | |
dec6faf1 | 3335 | |
dec6faf1 AC |
3336 | end if; |
3337 | end if; | |
df378148 | 3338 | end Expand_Put_Call_With_Symbol; |
dec6faf1 | 3339 | |
df378148 AC |
3340 | ------------------------------------ |
3341 | -- From_Dim_To_Str_Of_Dim_Symbols -- | |
3342 | ------------------------------------ | |
dec6faf1 | 3343 | |
21791d97 AC |
3344 | -- Given a dimension vector and the corresponding dimension system, create |
3345 | -- a String_Id to output dimension symbols corresponding to the dimensions | |
3346 | -- Dims. If In_Error_Msg is True, there is a special handling for character | |
3347 | -- asterisk * which is an insertion character in error messages. | |
df378148 AC |
3348 | |
3349 | function From_Dim_To_Str_Of_Dim_Symbols | |
3350 | (Dims : Dimension_Type; | |
3351 | System : System_Type; | |
3352 | In_Error_Msg : Boolean := False) return String_Id | |
3353 | is | |
3354 | Dim_Power : Rational; | |
3355 | First_Dim : Boolean := True; | |
3356 | ||
3357 | procedure Store_String_Oexpon; | |
21791d97 AC |
3358 | -- Store the expon operator symbol "**" in the string. In error |
3359 | -- messages, asterisk * is a special character and must be quoted | |
3360 | -- to be placed literally into the message. | |
df378148 AC |
3361 | |
3362 | ------------------------- | |
3363 | -- Store_String_Oexpon -- | |
3364 | ------------------------- | |
3365 | ||
3366 | procedure Store_String_Oexpon is | |
3367 | begin | |
3368 | if In_Error_Msg then | |
3369 | Store_String_Chars ("'*'*"); | |
df378148 AC |
3370 | else |
3371 | Store_String_Chars ("**"); | |
3372 | end if; | |
3373 | end Store_String_Oexpon; | |
3374 | ||
3375 | -- Start of processing for From_Dim_To_Str_Of_Dim_Symbols | |
dec6faf1 | 3376 | |
df378148 AC |
3377 | begin |
3378 | -- Initialization of the new String_Id | |
3379 | ||
3380 | Start_String; | |
3381 | ||
3382 | -- Store the dimension symbols inside boxes | |
3383 | ||
4a28b181 AC |
3384 | if In_Error_Msg then |
3385 | Store_String_Chars ("'["); | |
3386 | else | |
3387 | Store_String_Char ('['); | |
3388 | end if; | |
df378148 AC |
3389 | |
3390 | for Position in Dimension_Type'Range loop | |
3391 | Dim_Power := Dims (Position); | |
3392 | if Dim_Power /= Zero then | |
3393 | ||
3394 | if First_Dim then | |
3395 | First_Dim := False; | |
3396 | else | |
3397 | Store_String_Char ('.'); | |
3398 | end if; | |
3399 | ||
3400 | Store_String_Chars (System.Dim_Symbols (Position)); | |
3401 | ||
3402 | -- Positive dimension case | |
3403 | ||
3404 | if Dim_Power.Numerator > 0 then | |
4a28b181 | 3405 | |
df378148 AC |
3406 | -- Integer case |
3407 | ||
3408 | if Dim_Power.Denominator = 1 then | |
3409 | if Dim_Power.Numerator /= 1 then | |
3410 | Store_String_Oexpon; | |
3411 | Store_String_Int (Int (Dim_Power.Numerator)); | |
3412 | end if; | |
3413 | ||
3414 | -- Rational case when denominator /= 1 | |
3415 | ||
3416 | else | |
3417 | Store_String_Oexpon; | |
3418 | Store_String_Char ('('); | |
3419 | Store_String_Int (Int (Dim_Power.Numerator)); | |
3420 | Store_String_Char ('/'); | |
3421 | Store_String_Int (Int (Dim_Power.Denominator)); | |
3422 | Store_String_Char (')'); | |
3423 | end if; | |
3424 | ||
3425 | -- Negative dimension case | |
3426 | ||
3427 | else | |
3428 | Store_String_Oexpon; | |
3429 | Store_String_Char ('('); | |
3430 | Store_String_Char ('-'); | |
3431 | Store_String_Int (Int (-Dim_Power.Numerator)); | |
3432 | ||
3433 | -- Integer case | |
3434 | ||
3435 | if Dim_Power.Denominator = 1 then | |
3436 | Store_String_Char (')'); | |
3437 | ||
3438 | -- Rational case when denominator /= 1 | |
3439 | ||
3440 | else | |
3441 | Store_String_Char ('/'); | |
3442 | Store_String_Int (Int (Dim_Power.Denominator)); | |
3443 | Store_String_Char (')'); | |
3444 | end if; | |
3445 | end if; | |
3446 | end if; | |
3447 | end loop; | |
3448 | ||
4a28b181 AC |
3449 | if In_Error_Msg then |
3450 | Store_String_Chars ("']"); | |
3451 | else | |
3452 | Store_String_Char (']'); | |
3453 | end if; | |
3454 | ||
df378148 AC |
3455 | return End_String; |
3456 | end From_Dim_To_Str_Of_Dim_Symbols; | |
3457 | ||
3458 | ------------------------------------- | |
3459 | -- From_Dim_To_Str_Of_Unit_Symbols -- | |
3460 | ------------------------------------- | |
3461 | ||
3462 | -- Given a dimension vector and the corresponding dimension system, | |
3463 | -- create a String_Id to output the unit symbols corresponding to the | |
3464 | -- dimensions Dims. | |
3465 | ||
3466 | function From_Dim_To_Str_Of_Unit_Symbols | |
15954beb HK |
3467 | (Dims : Dimension_Type; |
3468 | System : System_Type) return String_Id | |
dec6faf1 | 3469 | is |
df378148 AC |
3470 | Dim_Power : Rational; |
3471 | First_Dim : Boolean := True; | |
dec6faf1 AC |
3472 | |
3473 | begin | |
0929eaeb | 3474 | -- Return No_String if dimensionless |
dec6faf1 | 3475 | |
0929eaeb AC |
3476 | if not Exists (Dims) then |
3477 | return No_String; | |
3478 | end if; | |
dec6faf1 | 3479 | |
0929eaeb | 3480 | -- Initialization of the new String_Id |
dec6faf1 | 3481 | |
0929eaeb | 3482 | Start_String; |
dec6faf1 | 3483 | |
6c57023b | 3484 | for Position in Dimension_Type'Range loop |
df378148 | 3485 | Dim_Power := Dims (Position); |
21791d97 | 3486 | |
df378148 | 3487 | if Dim_Power /= Zero then |
df378148 AC |
3488 | if First_Dim then |
3489 | First_Dim := False; | |
dec6faf1 AC |
3490 | else |
3491 | Store_String_Char ('.'); | |
3492 | end if; | |
3493 | ||
df378148 | 3494 | Store_String_Chars (System.Unit_Symbols (Position)); |
dec6faf1 | 3495 | |
df378148 | 3496 | -- Positive dimension case |
dec6faf1 | 3497 | |
df378148 | 3498 | if Dim_Power.Numerator > 0 then |
21791d97 | 3499 | |
dec6faf1 AC |
3500 | -- Integer case |
3501 | ||
df378148 AC |
3502 | if Dim_Power.Denominator = 1 then |
3503 | if Dim_Power.Numerator /= 1 then | |
dec6faf1 | 3504 | Store_String_Chars ("**"); |
df378148 | 3505 | Store_String_Int (Int (Dim_Power.Numerator)); |
dec6faf1 AC |
3506 | end if; |
3507 | ||
3508 | -- Rational case when denominator /= 1 | |
3509 | ||
3510 | else | |
3511 | Store_String_Chars ("**"); | |
3512 | Store_String_Char ('('); | |
df378148 | 3513 | Store_String_Int (Int (Dim_Power.Numerator)); |
dec6faf1 | 3514 | Store_String_Char ('/'); |
df378148 | 3515 | Store_String_Int (Int (Dim_Power.Denominator)); |
dec6faf1 AC |
3516 | Store_String_Char (')'); |
3517 | end if; | |
3518 | ||
3519 | -- Negative dimension case | |
3520 | ||
3521 | else | |
dec6faf1 AC |
3522 | Store_String_Chars ("**"); |
3523 | Store_String_Char ('('); | |
3524 | Store_String_Char ('-'); | |
df378148 | 3525 | Store_String_Int (Int (-Dim_Power.Numerator)); |
dec6faf1 AC |
3526 | |
3527 | -- Integer case | |
3528 | ||
df378148 | 3529 | if Dim_Power.Denominator = 1 then |
dec6faf1 AC |
3530 | Store_String_Char (')'); |
3531 | ||
3532 | -- Rational case when denominator /= 1 | |
3533 | ||
3534 | else | |
3535 | Store_String_Char ('/'); | |
df378148 | 3536 | Store_String_Int (Int (Dim_Power.Denominator)); |
dec6faf1 AC |
3537 | Store_String_Char (')'); |
3538 | end if; | |
3539 | end if; | |
3540 | end if; | |
3541 | end loop; | |
3542 | ||
3543 | return End_String; | |
df378148 | 3544 | end From_Dim_To_Str_Of_Unit_Symbols; |
dec6faf1 | 3545 | |
15954beb HK |
3546 | --------- |
3547 | -- GCD -- | |
3548 | --------- | |
dec6faf1 | 3549 | |
15954beb HK |
3550 | function GCD (Left, Right : Whole) return Int is |
3551 | L : Whole; | |
3552 | R : Whole; | |
dec6faf1 AC |
3553 | |
3554 | begin | |
15954beb HK |
3555 | L := Left; |
3556 | R := Right; | |
3557 | while R /= 0 loop | |
3558 | L := L mod R; | |
dec6faf1 | 3559 | |
15954beb HK |
3560 | if L = 0 then |
3561 | return Int (R); | |
dec6faf1 | 3562 | end if; |
15954beb HK |
3563 | |
3564 | R := R mod L; | |
dec6faf1 AC |
3565 | end loop; |
3566 | ||
15954beb HK |
3567 | return Int (L); |
3568 | end GCD; | |
dec6faf1 AC |
3569 | |
3570 | -------------------------- | |
15954beb | 3571 | -- Has_Dimension_System -- |
dec6faf1 AC |
3572 | -------------------------- |
3573 | ||
15954beb | 3574 | function Has_Dimension_System (Typ : Entity_Id) return Boolean is |
dec6faf1 | 3575 | begin |
15954beb HK |
3576 | return Exists (System_Of (Typ)); |
3577 | end Has_Dimension_System; | |
3578 | ||
2293611f AC |
3579 | ------------------------------ |
3580 | -- Is_Dim_IO_Package_Entity -- | |
3581 | ------------------------------ | |
3582 | ||
3583 | function Is_Dim_IO_Package_Entity (E : Entity_Id) return Boolean is | |
3584 | begin | |
98ee6f8d AC |
3585 | -- Check the package entity corresponds to System.Dim.Float_IO or |
3586 | -- System.Dim.Integer_IO. | |
2293611f | 3587 | |
98ee6f8d AC |
3588 | return |
3589 | Is_RTU (E, System_Dim_Float_IO) | |
c7e152b5 AC |
3590 | or else |
3591 | Is_RTU (E, System_Dim_Integer_IO); | |
2293611f AC |
3592 | end Is_Dim_IO_Package_Entity; |
3593 | ||
6c57023b AC |
3594 | ------------------------------------- |
3595 | -- Is_Dim_IO_Package_Instantiation -- | |
3596 | ------------------------------------- | |
3597 | ||
3598 | function Is_Dim_IO_Package_Instantiation (N : Node_Id) return Boolean is | |
3599 | Gen_Id : constant Node_Id := Name (N); | |
6c57023b AC |
3600 | |
3601 | begin | |
98ee6f8d AC |
3602 | -- Check that the instantiated package is either System.Dim.Float_IO |
3603 | -- or System.Dim.Integer_IO. | |
6c57023b | 3604 | |
98ee6f8d AC |
3605 | return |
3606 | Is_Entity_Name (Gen_Id) | |
3607 | and then Is_Dim_IO_Package_Entity (Entity (Gen_Id)); | |
6c57023b AC |
3608 | end Is_Dim_IO_Package_Instantiation; |
3609 | ||
15954beb HK |
3610 | ---------------- |
3611 | -- Is_Invalid -- | |
3612 | ---------------- | |
3613 | ||
3614 | function Is_Invalid (Position : Dimension_Position) return Boolean is | |
3615 | begin | |
3616 | return Position = Invalid_Position; | |
3617 | end Is_Invalid; | |
dec6faf1 AC |
3618 | |
3619 | --------------------- | |
3620 | -- Move_Dimensions -- | |
3621 | --------------------- | |
3622 | ||
3623 | procedure Move_Dimensions (From, To : Node_Id) is | |
dec6faf1 | 3624 | begin |
0929eaeb AC |
3625 | if Ada_Version < Ada_2012 then |
3626 | return; | |
3627 | end if; | |
3628 | ||
54c04d6c | 3629 | -- Copy the dimension of 'From to 'To' and remove dimension of 'From' |
dec6faf1 | 3630 | |
ba914484 VP |
3631 | Copy_Dimensions (From, To); |
3632 | Remove_Dimensions (From); | |
dec6faf1 AC |
3633 | end Move_Dimensions; |
3634 | ||
1155ae01 AC |
3635 | --------------------------------------- |
3636 | -- New_Copy_Tree_And_Copy_Dimensions -- | |
3637 | --------------------------------------- | |
3638 | ||
3639 | function New_Copy_Tree_And_Copy_Dimensions | |
3640 | (Source : Node_Id; | |
3641 | Map : Elist_Id := No_Elist; | |
3642 | New_Sloc : Source_Ptr := No_Location; | |
3643 | New_Scope : Entity_Id := Empty) return Node_Id | |
3644 | is | |
3645 | New_Copy : constant Node_Id := | |
3646 | New_Copy_Tree (Source, Map, New_Sloc, New_Scope); | |
3647 | ||
3648 | begin | |
3649 | -- Move the dimensions of Source to New_Copy | |
3650 | ||
3651 | Copy_Dimensions (Source, New_Copy); | |
3652 | return New_Copy; | |
3653 | end New_Copy_Tree_And_Copy_Dimensions; | |
3654 | ||
15954beb HK |
3655 | ------------ |
3656 | -- Reduce -- | |
3657 | ------------ | |
dec6faf1 | 3658 | |
15954beb | 3659 | function Reduce (X : Rational) return Rational is |
dec6faf1 | 3660 | begin |
15954beb HK |
3661 | if X.Numerator = 0 then |
3662 | return Zero; | |
3663 | end if; | |
dec6faf1 | 3664 | |
15954beb HK |
3665 | declare |
3666 | G : constant Int := GCD (X.Numerator, X.Denominator); | |
15954beb | 3667 | begin |
4a28b181 | 3668 | return Rational'(Numerator => Whole (Int (X.Numerator) / G), |
15954beb HK |
3669 | Denominator => Whole (Int (X.Denominator) / G)); |
3670 | end; | |
3671 | end Reduce; | |
dec6faf1 AC |
3672 | |
3673 | ----------------------- | |
3674 | -- Remove_Dimensions -- | |
3675 | ----------------------- | |
3676 | ||
3677 | procedure Remove_Dimensions (N : Node_Id) is | |
6c57023b | 3678 | Dims_Of_N : constant Dimension_Type := Dimensions_Of (N); |
dec6faf1 | 3679 | begin |
6c57023b | 3680 | if Exists (Dims_Of_N) then |
15954beb | 3681 | Dimension_Table.Remove (N); |
dec6faf1 AC |
3682 | end if; |
3683 | end Remove_Dimensions; | |
3684 | ||
dec6faf1 AC |
3685 | ----------------------------------- |
3686 | -- Remove_Dimension_In_Statement -- | |
3687 | ----------------------------------- | |
3688 | ||
3689 | -- Removal of dimension in statement as part of the Analyze_Statements | |
3690 | -- routine (see package Sem_Ch5). | |
3691 | ||
15954beb | 3692 | procedure Remove_Dimension_In_Statement (Stmt : Node_Id) is |
dec6faf1 AC |
3693 | begin |
3694 | if Ada_Version < Ada_2012 then | |
3695 | return; | |
3696 | end if; | |
3697 | ||
3698 | -- Remove dimension in parameter specifications for accept statement | |
3699 | ||
15954beb | 3700 | if Nkind (Stmt) = N_Accept_Statement then |
dec6faf1 | 3701 | declare |
15954beb | 3702 | Param : Node_Id := First (Parameter_Specifications (Stmt)); |
dec6faf1 AC |
3703 | begin |
3704 | while Present (Param) loop | |
3705 | Remove_Dimensions (Param); | |
3706 | Next (Param); | |
3707 | end loop; | |
3708 | end; | |
3709 | ||
3710 | -- Remove dimension of name and expression in assignments | |
3711 | ||
15954beb HK |
3712 | elsif Nkind (Stmt) = N_Assignment_Statement then |
3713 | Remove_Dimensions (Expression (Stmt)); | |
3714 | Remove_Dimensions (Name (Stmt)); | |
dec6faf1 AC |
3715 | end if; |
3716 | end Remove_Dimension_In_Statement; | |
3717 | ||
3718 | -------------------- | |
3719 | -- Set_Dimensions -- | |
3720 | -------------------- | |
3721 | ||
15954beb | 3722 | procedure Set_Dimensions (N : Node_Id; Val : Dimension_Type) is |
dec6faf1 | 3723 | begin |
15954beb HK |
3724 | pragma Assert (OK_For_Dimension (Nkind (N))); |
3725 | pragma Assert (Exists (Val)); | |
3726 | ||
3727 | Dimension_Table.Set (N, Val); | |
dec6faf1 AC |
3728 | end Set_Dimensions; |
3729 | ||
15954beb HK |
3730 | ---------------- |
3731 | -- Set_Symbol -- | |
3732 | ---------------- | |
3733 | ||
3734 | procedure Set_Symbol (E : Entity_Id; Val : String_Id) is | |
3735 | begin | |
3736 | Symbol_Table.Set (E, Val); | |
3737 | end Set_Symbol; | |
3738 | ||
3739 | --------------- | |
3740 | -- Symbol_Of -- | |
3741 | --------------- | |
3742 | ||
3743 | function Symbol_Of (E : Entity_Id) return String_Id is | |
0929eaeb | 3744 | Subtype_Symbol : constant String_Id := Symbol_Table.Get (E); |
15954beb | 3745 | begin |
0929eaeb AC |
3746 | if Subtype_Symbol /= No_String then |
3747 | return Subtype_Symbol; | |
0929eaeb AC |
3748 | else |
3749 | return From_Dim_To_Str_Of_Unit_Symbols | |
3750 | (Dimensions_Of (E), System_Of (Base_Type (E))); | |
3751 | end if; | |
15954beb HK |
3752 | end Symbol_Of; |
3753 | ||
3754 | ----------------------- | |
3755 | -- Symbol_Table_Hash -- | |
3756 | ----------------------- | |
3757 | ||
3758 | function Symbol_Table_Hash (Key : Entity_Id) return Symbol_Table_Range is | |
3759 | begin | |
3760 | return Symbol_Table_Range (Key mod 511); | |
3761 | end Symbol_Table_Hash; | |
3762 | ||
3763 | --------------- | |
3764 | -- System_Of -- | |
3765 | --------------- | |
3766 | ||
3767 | function System_Of (E : Entity_Id) return System_Type is | |
3768 | Type_Decl : constant Node_Id := Parent (E); | |
dec6faf1 | 3769 | |
dec6faf1 | 3770 | begin |
6c57023b | 3771 | -- Look for Type_Decl in System_Table |
15954beb HK |
3772 | |
3773 | for Dim_Sys in 1 .. System_Table.Last loop | |
3774 | if Type_Decl = System_Table.Table (Dim_Sys).Type_Decl then | |
3775 | return System_Table.Table (Dim_Sys); | |
3776 | end if; | |
3777 | end loop; | |
3778 | ||
3779 | return Null_System; | |
3780 | end System_Of; | |
d976bf74 | 3781 | |
dec6faf1 | 3782 | end Sem_Dim; |