Below is a set of Ada83 to Ada9X philosophy transformations that NRaD is collecting. These are transformations that take advantage of new capabilities offered by Ada9X. Our near term use of these transformations is for an ATIP project for an Ada83 to Ada9X translator that is being developed by Xinotech Research Inc. These transformations are in the public domain and may be used by anyone for any purpose. We welcome comments and suggestions. Please send them to me at: mumm@nosc.mil Thanks, Hans Mumm Revised 9 March 1994 Draft, Detailed Description of the Ada 9X Philosophy Transformation Library ----------------------------------- -------------------------------------- This document describes the library of Ada 9x Philosophy Transformations developed by Xinotech Research, Inc., for transforming Ada 83 programs to incorporate the philosophy of Ada 9X. These transformations and guidelines are specified using the formal notation XPAL, the Xinotech Pattern Abstraction Language, which has been specially designed for this purpose. Some of the following transformations will restructure Ada 83 code to take advantage of the object oriented capabilities of Ada 9X, such as type extensions, access subprogram types, and abstract subprogram declarations. Other transformations aid in translating from Ada 83 vendor-supplied libraries to Ada 9X equivalen= ts. Still others aid in reorganizing program decomposition, by splitting out child library units from existing Ada 83 packages. And other transformations will map Ada 83 code written to overcome specific Ada 83 limitations into Ada 9X features which address these limitations, e.g. substituting the "use type" clause for renamed operator declarations, and eliminating redundant variable declarations needed only because Ada 83 "out" parameters cannot be read. All of the following transformations can be applied interactively during program construction and maintenance, or can be applied in a batch mode via the Composer's Guideline & Metrics Analyzer tool. When prompting the user to select a specific transformation, the Composer will only display those transformations that are relevant at the current program location. 1. P9X-O1: Find Ada83 variant record candidates for Ada9X tagged records. Guideline: This guideline locates Ada 83 variant records which may be suitable for automatic transformation into Ada 9X tagged records. The criterion is that the variant record type must have a single discriminant, which must be a value of an enumeration type. Transformation: This transformation is applied to a variant record type declaration of the form described above. Its effect is to: translate the variant record into a tagged type; produce record extension types for each case of the variant; translate all variable declarations to the appropriate extension types; and translate all CASE statements in the code into dispatched handler procedures. Rationale: This transformation would be applied in cases where the user wishes to convert existing code from a variant record model to an extended type model. The benefits of such conversion are described in Part I, section 2.1 of the Ada 9X Rationale. When it is applicable, this transformation will automate much of the conversion process. Transformation Method: Given a declaration of a record R with discriminant D of type E, which is an enumeration type whose values are (E1, E2, ...En), i.e. type is (, , .. ); type ( : ) is record : -- fields of R case is when | | ... => -- variants of R end case; end record; For each enumeration "Ei" in (E1, E2, .. En), a new tagged record type "Ei_R" is created, which is an extension of the original record type. The extension will consist of all the fields from the variant part which were present for this particular value of the discriminant. A function declaration will be inserted after the extension type declarations for a function named _OF_ which returns a value of type E corresponding to the descriminant of an input object of type R'Class. The function body will be specified as follows: function _OF_ (Item : in 'Class) return is begin case Item'Tag is when _'Tag => return ; when _'Tag => return ; : when _'Tag => return ; end case; end _OF_; Each object declaration of type R will be transformed to an object declaration of a specific type extension of R. I.e., : ( => ); is transformed into: : _; For each primitive operation on the type R (i.e. each subprogram declared in the same region as R, which has a parameter of type R), the following transformation will be applied to convert the operation to a dispatching subprogram: For a primitive subprogram S operating on type R, if the executable statements of S contain a either (1) a "case" statement whose expression is a discriminant of a parameter V of type R, or (2) an "if" statement whose condition is a comparison of such a discriminant for equality/inequality with a constant value, then the operation R will be split up into multiple procedures, one for each extension type, so that the resulting procedure will now be a dispatching one. Each of the new subprograms S will specify the type Ei_R for its parameter V, and will contain the subset of executable statements which would be executed for the particular discriminant value Ei. References elsewhere in the code to the discriminant D of an object V of type R will be transformed into calls to the function _OF_, i.e. . is transformed to _OF_ (). Example: This example is based on the example from Part I, Section 2.1 of the Ada 9X Rationale, September 1993. It can be found within the "demo" subdirectory of the Composer release, under the filename "alert.ada". The following shows the Ada 83 source code before applying the transformation: package ALERT_SYSTEM is type PRIORITY is (LOW, MEDIUM, HIGH); type ALERT (P: PRIORITY) is record TIME_OF_ARRIVAL : TIME; MESSAGE : STRING (1 .. 80); case P is when LOW => null; when MEDIUM | HIGH => ALERT_ACTION_OFFICER : PERSON; case P is when HIGH => RING_ALARM_AT : TIME; when others => null; end case; end case; end record; procedure HANDLE (A: in out ALERT): : -- other operations on type ALERT end ALERT_SYSTEM; package body ALERT_SYSTEM is procedure HANDLE (A : in out ALERT) is begin A. TIME_OF_ARRIVAL := CALENDAR. CLOCK; LOG (A); DISPLAY (A, TELETYPE); case A.P is when LOW => null; when MEDIUM | HIGH => A. ALERT_ACTION_OFFICER := ASSIGN_VOLUNTEER; DISPLAY (A, CONSOLE); case A. P is when HIGH => DISPLAY (A, BIG_SCREEN); SET_ALARM (A); when others => null; end case; end case; end HANDLE; : end ALERT_SYSTEM; procedure EXAMPLE_DECLARING_ALERT is MY_ALERT : ALERT (P => LOW); begin : HANDLE (MY_ALERT); : if MY_ALERT. P = LOW then : end if; end EXAMPLE_DECLARING_ALERT; Here is the result of applying the transformation to the type ALERT. The procedure HANDLE is now a dispatching procedure with implementations for each of the types LOW_ALERT, MEDIUM_ALERT, and HIGH_ALERT. package ALERT_SYSTEM is type PRIORITY is (LOW, MEDIUM, HIGH); type ALERT (P: PRIORITY) is tagged record TIME_OF_ARRIVAL : TIME; MESSAGE : STRING (1 .. 80); end record; type LOW_ALERT is new ALERT with null record; type MEDIUM_ALERT is new ALERT with record ALERT_ACTION_OFFICER : PERSON; end record; type HIGH_ALERT is new ALERT with record ALERT_ACTION_OFFICER : PERSON; RING_ALARM_AT : TIME; end record; function PRIORITY_OF_ALERT (Item : in ALERT'Class) return PRIORITY; procedure HANDLE (A : in out ALERT); -- other operations on type ALERT end ALERT_SYSTEM; package body ALERT_SYSTEM is function PRIORITY_OF_ALERT (Item : in ALERT'Class) return PRIORITY is begin case Item'Tag is when LOW_ALERT'Tag => return LOW; when MEDIUM_ALERT'Tag => return MEDIUM; when HIGH_ALERT'Tag => return HIGH; end case; end PRIORITY_OF_ALERT; -- Dispatching HANDLE procedures for type ALERT: procedure HANDLE (A : in out LOW_ALERT) is begin A. TIME_OF_ARRIVAL := CALENDAR. CLOCK; LOG (A); DISPLAY (A, TELETYPE); end HANDLE; procedure HANDLE (A : in out MEDIUM_ALERT) is begin A. TIME_OF_ARRIVAL := CALENDAR. CLOCK; LOG(A); DISPLAY (A, TELETYPE); A. ALERT_ACTION_OFFICER := ASSIGN_VOLUNTEER; DISPLAY (A, CONSOLE); end HANDLE; procedure HANDLE (A : in out HIGH_ALERT) is begin A. TIME_OF_ARRIVAL := CALENDAR.CLOCK; LOG (A); DISPLAY (A, TELETYPE); A. ALERT_ACTION_OFFICER := ASSIGN_VOLUNTEER; DISPLAY (A, CONSOLE); DISPLAY (A.BIG_SCREEN); SET_ALARM (A); end HANDLE; : : end ALERT_SYSTEM; procedure EXAMPLE_DECLARING_ALERT is MY_ALERT : LOW_ALERT; begin : HANDLE (MY_ALERT); : if PRIORITY_OF_ALERT (MY_ALERT) = LOW then : end if; end EXAMPLE_DECLARING_ALERT; 2. P9X-O2: Create Ada 9X tagged record type with extensions from selected fields of a record type. Transformation: This transformation is applied to a collection of record types which have common field definitions. It extracts the common fields from the record types into a new tagged types. The existing record types become extensions of this tagged type, and record field references are translated accordingly. Rationale: This transformation would be applicable only in the specific case of an Ada 83 record type (the "base" type) and a collection of Ada 83 record types each of which is a logical extension of the base type, and has one component of the base type. Such a scheme could be used in Ada 83 to approximate type extensions (i.e. define an extended type as a new record containing a field of the base type). Since Ada 9X type extensions are more general and flexible than this scheme, it would be useful to convert such an implementation to true Ada 9X extension types. When it is applicable, this transformation will automate much of that conversion process. Transformation Method: Inputs to the transformation are a record type Tb (the base type), and a collection of extension types T1, T2, .. Tn, such that each has exactly one component field of type Tb. For each Ti in T1 .. Tn, let Fi be the name of its component of type Tb. The transformation will add the keyword "tagged" to the type declaration of Tb, making it a tagged type. For each type Ti in T1 .. Tn, it will change the declaration of Ti into an extension of type Tb, with the extension record consisting of all the fields declared in Ti except for field Fi, i.e.: type is new with record : -- fields from previous declaration of Ti, : -- (minus the declaration of field Fi). end record; Each reference to field Fi in an object V declared to be of type Ti will be translated to a type conversion of the object to the base type Tb, i.e. each occurrence of V.Fi will be translated to Tb(V). Example: The following Ada 83 package defines three types: Rect_T, Circle_T, and Text_T, and a type Shape_T containing information common to all three types. package Shapes is type Shape_T is record x, y : Coordinate_T; color : A_Color; border_style : A_Border_Style; end record; type Rect_T is record shape_info : Shape_T; height, width : Distance_T; end record; type Circle_T is record shape_info : Shape_T; radius : Distance_T; end record; type Text_T is record shape_info : Shape_T; text : String (1 .. text_length); font : A_Font; end record; -- Procedures and functions operating on Rect_T, Circle_T, Text_T : end Shapes; The following Ada 9X code would result from applying the transformation with "Shape_T" as the base type and Rect_T, Circle_T, and Text_T as the extension types: package Shapes is type Shape_T is tagged record x, y : Coordinate_T; color : A_Color; border_style : A_Border_Style; end record; type Rect_T is new Shape_T with record height, width : Distance_T; end record; type Circle_T is new Shape_T with record radius : Distance_T; end record; type Text_T is new Shape_T with record text : String (1 .. text_length); font : A_Font; end record; -- etc. end Shapes; 3. P9X-O3: Transform a package to an abstract specification and corresponding implementation. Transformation: This transformation is applied to an ordinary Ada 83 package specification which provides a collection of operations on an exported data type. The result of the transformation is an abstract package specification, in which the operations on the exported data type are specified as "abstract", followed by a package specification corresponding to an implementation of the original package. The exported data type in the abstract package specification is declared as "tagged null record". In the implementation package the corresponding exported type is declared as an extension of the abstract data type. Rationale: This transformation would be applicable when the user wishes to create another implementation of an existing Ada 83 data type and its operations. For example, given a package that implements bitsets as an array of boolean, one might wish to create a second implementation as a linked list, for very sparse bitsets. Transformation Method: Given a package P that exports a type T. Type T must be a private type implemented as a record type. Supposed that the desired abstract package name is Abs_P, and the desired abstract type name corresponding to T is Abs_T. Let the collection of subprograms exported from P which operate on T be named S1, S2, .. Sn. (These are the primitive operations of type T). Further, let the collection of types declared in P (excluding T) which are referenced by one or more of S1..Sn, be named U1, U2, .. Um. (I.e. these are the types from package P referenced by the primative operations of type T). This transformation produces a package of the following form, which is inserted immediately prior to the specification of package P. If P is a library unit, then the context clauses preceding P are copied in front of package Abs_P, so that it will have the same context as P. package is type is tagged private; {declaration of }; {declaration of }; : {declaration of }; {declaration of } is abstract; {declaration of } is abstract; : {declaration of } is abstract; private type is tagged null record; end ; The specification of P is modified as follows: If P is a library unit, the context clause: with ; is added in front of the specification of P. The type declaration of T in the visible part of P is replaced with the following: type is new . with private; Each declaration of a type Ui in the range U1..Um is replaced with a declaration of the form: type is new .; Example: Given the following package specification: package SETS is type SET_ELEMENT is NATURAL; type SET is private; function EMPTY return SET; function UNIT (ELEM : SET_ELEMENT) return SET; function UNION (LEFT, RIGHT : SET) return SET; function INTERSECTION (LEFT, RIGHT : SET) return SET; procedure EXCLUDE (FROM : in out SET; ELEM : out SET_ELEMENT); : private type BIT_VECTOR is ...; type SET is record DATA : BIT_VECTOR; end record; end SETS; This transformation would produce the following code: package ABSTRACT_SETS is subtype SET_ELEMENT is NATURAL; type SET is tagged private; function EMPTY return SET is abstract; function UNIT (ELEM : SET_ELEMENT) return SET is abstract; function UNION (LEFT, RIGHT : SET) return SET is abstract; function INTERSECTION (LEFT, RIGHT : SET) return SET is abstract; procedure EXCLUDE (FROM : in out SET; ELEM : out SET_ELEMENT) is abstract; : private type SET is tagged null record; end ABSTRACT_SETS; with ABSTRACT_SETS; package SETS is type SET_ELEMENT is new ABSTRACT_SETS.SET_ELEMENT; type SET is new ABSTRACT_SETS with private; function EMPTY return SET; function UNIT (ELEM : SET_ELEMENT) return SET; function UNION (LEFT, RIGHT : SET) return SET; function INTERSECTION (LEFT, RIGHT : SET) return SET; procedure EXCLUDE (FROM : in out SET; ELEM : out SET_ELEMENT); : private type BIT_VECTOR is ...; type SET is new ABSTRACT_SETS.SET with record DATA : BIT_VECTOR; end record; end SETS; 4. P9X-O4: Encapsulate exported procedures from a package into a record type. Transformation: This transformation is applied to an ordinary Ada 83 package specification which provides a collection of operations on an exported data type. The transformation produces a record type with fields for each of the operations. Each field of the record is an access-to-subprogram whose default value points to the original exported operation. Named data types are created for each access-to-subprogram declared in the record type. Rationale: This transformation would be applicable when the user wishes to create an object class out of a particular exported data type and its operations. As a result of this transformation, the operations on the type become object "methods" which are access-to-subprogram values, making it possible for the user to override the default methods to define multiple implementations of the class. For example, a screen manager package could be implemented for several different Graphical User Interface protocols, and the desired protocol can be chosen at runtime. Transformation Method: Given a type T declared in the visible part of a package specification P, let S1, S2, .. Sn be the collection of subprograms in the visible part of P that operate on T (i.e that have a parameter or return value of type T). For each Si in S1 .. Sn, this procedure will create a type declaration Ti for an access-to-subprogram type named "_FUNCTION" (if Si is a function) or "_PROCEDURE" (if Si is a procedure). The definition of type Ti will be an "access" to the subprogram specification of Si. These type Ti's are inserted at the bottom of the visible part of package P, followed by a record type named "_OPERATIONS_TYPE" containing one component for each Si, of the form: : := 'ACCESS. Example: Given the original package SETS from example P9X-O3 above, this transformation would produce the following: package SETS is subtype SET_ELEMENT is NATURAL; type SET is private; function EMPTY return SET; function UNIT (ELEM : SET_ELEMENT) return SET; function UNION (LEFT, RIGHT : SET) return SET; function INTERSECTION (LEFT, RIGHT : SET) return SET; procedure EXCLUDE (FROM : in out SET; ELEM : out SET_ELEMENT); type EMPTY_FUNCTION is access function EMPTY return SET; type UNIT_FUNCTION is access function UNIT (ELEM : SET_ELEMENT) return SET; type UNION_FUNCTION is access function UNION (LEFT, RIGHT : SET) return SET; type INTERSECTION_FUNCTION is access function INTERSECTION (LEFT, RIGHT : SET) return SET; type EXCLUDE_PROCEDURE is access procedure EXCLUDE (FROM : in out SET; ELEM : out SET_ELEMENT); type SET_OPERATIONS_TYPE is record EMPTY : EMPTY_FUNCTION := EMPTY'ACCESS; UNIT : UNIT_FUNCTION := UNIT'ACCESS; UNION : UNION_FUNCTION := UNION'ACCESS; INTERSECTION : INTERSECTION_FUNCTION := INTERSECTION'ACCESS; EXCLUDE: EXCLUDE_PROCEDURE := EXCLUDE'ACCESS; end record; : end SETS; 5. P9X-L2: Port Verdix package "iface_sema" calls to protected record implementation. Transformation: This transformation is applied to Ada code that uses the Verdix Ada package "iface_sema" implementation of semaphores. Verdix Ada uses special procedure calls to bracket the beginnings and endings of protected regions of code. In Ada 9X, this capability can be implemented directly by defining the type "semaphore_rec" as a protected record providing the operations Enter, Leave, Suspend, and Resume. This transformation will translate all references to entities declared in package iface_sema into corresponding references to entities declared in a new package "iface_sema_9x", which provides an Ada 9X protected record implementation of the same functionality. The source code for package "iface_sema_9x" will be supplied by Xinotech. Guideline: A related guideline will check for mismatched calls to procedures Enter and Leave. The presence of such mismatched calls indicates a program error, since it implies improperly bracketed protected regions. Rationale: The functionality implemented by the "iface_sema" package, i.e. a low-level synchronization mechanism, is more properly specified in Ada 9X by a protected record. This is also a more object-oriented approach, since the procedures enter, leave, etc. are now "methods" belonging to the semaphore object itself. The guideline to detect mismatched Enter/Leave calls can be a useful debugging aid. Transformation Method: All qualified references to type "iface_sema.semaphore_rec" are translated to "iface_sema_9x.semaphore_rec". Similarly, all references to "iface_sema.a_semaphore" are translated to: "iface_sema_9x.a_semaphore". References of form: "iface_sema.enter ();" where is an object reference, are translated to: .enter; Similarly for calls to the procedures: leave, suspend, resume, exported from package iface_sema. References to package "iface_sema" within "with" clauses and "use" clauses are changed to "iface_sema_9x". Example: The following Ada 83 code: with iface_sema; procedure Has_Critical_Region is my_sema : new iface_sema.a_semaphore; begin -- : non-critical code iface_sema. enter (my sema) -- : critical region code if bad_things then iface_sema.leave (my_sema); raise bad_things_happened; end if; -- : more critical region code exception when others => iface_sema.leave(my_sema); raise bad_things_happened; -- : more non-critical code end Has_Critical_Region; is transformed as follows: with iface_sema_9x; procedure Has_Critical_Region is my_sema : new iface_sema_9x.a_semaphore; begin -- : non-critical code my_sema. enter -- critical region code if bad things then my_sema.leave; raise bad_things_happened; end if; -- : more critical region code exception when others => my_sema.leave; raise bad_things happened; -- : more non-critical code end Has_Critical_Region; 6. P9X-L3: Translate compiler-specific language interface mechanisms to Ada 9X Interface Pragmas: Import and Export. Guideline: This guideline will recognize occurrences of compiler- specific language interface mechanisms suitable to be converted to the Ada 9X standard interface pragmas. Transformation: This transformation, applied at positions recognized by the above guideline, will convert them to the Ada 9X standard interface pragmas Import and Export, using a language convention identifier supplied by the user if needed. This transformation supports the Telesoft Telegen2 Ada Compiler and the Verdix Ada Development System. Rationale: The transformation brings Ada 83 code from diverse compiler vendors into compliance with the Ada 9X standard. Transformation Method (Telegen2): Occurrences of "pragma Interface" are translated to "pragma Import", with the parameters renamed according to the Ada 9X standard. If a given "pragma Interface" has an associated "pragma Interface_Information", the link name from that pragma is used as the "Link_Name" parameter of the resulting "pragma Import". For occurrences of "pragma Export", the parameters are given their proper name associations, and if no "Language" parameter was specified, the default value of "C" is used for the "Convention" parameter of the resulting pragma. Occurrences of representation clauses using the System.Label metafunction are translated to a "pragma Import", using the specified object name from the representation clause and the link name from the System.Label metafunction argument. Transformation Method (Verdix): Occurrences of "pragma Interface" are translated to "pragma Import", with the parameters renamed according to the Ada 9X standard, including the optional link name. Occurrences of "pragma Interface_Object" are translated to "pragma Import", and occurrences of "pragma External_Name" are translated to "pragma Export". In these cases the user will be prompted for a language convention name, since none is defined by the language implementation. Examples: The following TeleGen2 Ada source code: pragma Interface (FORTRAN, Draw_Rect); pragma Interface_Information (Link_Name=> "DRAW_RECT$LINK_NAME", Name= => Draw_Rect); pragma Export (Draw_Circle, "DRAW_CIRCLE$LINK_NAME"); Object: Some_Type; for Object use at System.Label ("OBJECT$LINK_NAME"); will be translated to its Ada 9X equivalent: pragma Import ( Convention => FORTRAN, Entity => Draw_Rect, Link_Name => ="DRAW_RECT$LINK_NAME"); pragma Export ( Convention => C, Entity => Draw_Circle, Link_Name => "DRAW_CIRCLE$LINK_NAME"); Object : Some_Type; pragma Import ( Convention => Lang_Convention_Id, Entity => Object, Link_Name => "OBJECT$LINK_NAME"); The following VADS Ada source code: pragma Interface (FORTRAN, Draw_Rect); Object1, Object2 : Some_Type; pragma External_Name (Object1, "OBJECT1$LINK_NAME"); pragma Interface_Object (Object2, "OBJECT2$LINK_NAME"); will be translated to its Ada 9X equivalent: pragma Import ( Convention => FORTRAN, Entity => Draw_Rect); Object1, Object2 : Some_Type; pragma Export ( Convention => FORTRAN, Entity => Object1, Link_Name => "OBJECT1$LINK_NAME"); pragma Import ( Convention => FORTRAN, Entity => Object2, Link_Name => "OBJECT2$LINK_NAME"); 7. P9X-R1: Create child library unit by splitting out types, dependent objects and subprograms. Transformation: This transformation is applied when the user wishes to split a child library unit out from an existing Ada 83 package. The user specifies as inputs a subset of declarations from the package specification. The transformation will calculate all dependencies of the input declarations in the package, and produce a new child package which contains the input declarations and their dependencies. All references to items which get moved into the child package will be translated accordingly. Rationale: This transformation is applicable for an Ada 83 package in which two (or more) logically distinct packages have been implemented as a single package because they shared a private type. Ada 9X allows the packages to be specified separately, since a child package can refer to the private details of its parent. Thus the transformation produces code which more logically reflects the intended design. Transformation Method: Inputs to the transformation are a set of declarations D1, D2, .. Dn, in a package specification P, which are to be split out into a child package named Pc. Let E1, E2, .. Em be the collection of declarations in the specification or body of package P that depend on one or more of D1 .. Dn. This transformation will create both a package specification and a package body named P.Pc, whose contents are all of the declarations D1 .. Dn and E1 .. Em, in the same order in which they were declared in package P. That is, declarations from the visible part of P will be copied (in the same order) to the visible part of P.Pc; declarations from the private part of P will be copied to the private part of P.Pc; and declarations from the body of P will be copied to the body of P.Pc. These declarations will be deleted from the original package P. Statements from the executable part of package body P, if any, are copied to the executable part of package body P.Pc, except for those statements that are independent of any of the declarations D1 .. Dn, E1 .. En. Statements in the executable part of package body P which are dependent on declarations D1 .. Dn, E1 .. En, will be deleted. This part of the transformation should be verified by the user to ensure that package initialization takes place properly. All references to the entities D1 .. Dn, E1 .. Em that were formerly exported from package P are modified to reflect the fact that they are now exported from P.Pc, either by explicit dot notation qualification with the package name, or by changing associated context clauses. Example: The following package provides a type Complex, along with both Cartesian and Polar representations for the type. (The package body is not shown for the sake of brevity). package Complex_Arith is type Complex is private; function "+" (X, Y : Complex) return Complex; function "-" (X, Y : Complex) return Complex; function "*" (X, Y : Complex) return Complex; function "/" (X, Y : Complex) return Complex; type Cartesian is record real, imag : FLOAT; end record; type Polar is record R, Theta : FLOAT; end record; function Cartesian_To_Complex (C : in Cartesian) return Complex; function Polar_To_Complex (P : in Polar) return Complex; function Complex_To_Cartesian (X : Complex) return Cartesian; function Complex_To_Polar (X : Complex) return Polar; private type Complex is new Cartesian; end Complex_Arith; The following shows the result after applying the transformation to split out the type Polar and its dependents into a new child package Complex_Arith.Polars: package Complex_Arith is type Complex is private; function "+" (X, Y : Complex) return Complex; function "-" (X, Y : Complex) return Complex; function "*" (X, Y : Complex) return Complex; function "/" (X, Y : Complex) return Complex; type Cartesian is record real, imag : FLOAT; end record; function Cartesian_To_Complex (C : in Cartesian) return Complex; function Complex_To_Cartesian (X : Complex) return Cartesian; private type Complex is new Cartesian; end Complex_Arith; package Complex_Arith.Polars is type Polar is record R, Theta : FLOAT; end record; function Polar_To_Complex (P : in Polar) return Complex; function Complex_To_Polar (X : Complex) return Polar; end Complex_Arith; 8. P9X-P1: Add "aliased" keyword to objects referenced by 'ADDRESS attributes. Guideline: In Ada 83, access values could only refer to dynamically allocated objects. It was not possible to access statically declared objects except by defeating the compile-time type checking with an unchecked conversion. Ada 9X allows access values to refer to statically declared objects if those objects are declared as "aliased". This guideline will recognize statically-declared objects in Ada 83 code such that unchecked conversion has been used to create access values referring to them. (Such declarations are candidates for adding the 'aliased' keyword and eliminating the unchecked conversion). Transformation: This transformation will add the 'aliased' keyword as needed for object declarations recognized by the above guideline. Each corresponding type definition for an access type will be changed to general access type definition by adding the keyword 'all' following the 'access' keyword. Unchecked type conversions from type System.Address to those corresponding access types will be replaced by references to the 'Access attribute. Rationale: The transformation improves Ada 83 code by eliminating a usage of UNCHECKED_CONVERSION. Such conversion is no longer needed in Ada 9X since it allows access values to refer to non-dynamically allocated objects. Guideline Method: Given a type T such that there exists the following declarations (which need not be consecutive, nor declared in this order): type is access ; function is new Unchecked_Conversion (System.Address, ); : ... -- some object declaration in terms of ; The guideline matches each call to function Ft of the form: () where Va is either an address attribute of the form 'Address, or a reference to an object previously assigned to a value of such an address attribute, and such that Vc is a reference to V or one of V's components of type T. Transformation Method: The transformation is applied at a call to an unchecked conversion function Ft as described above. The function call is changed to an access attribute of the form: 'Access thus eliminating the unchecked conversion. The 'aliased' keyword is also added to the declaration of V so that the Vc components of V are declared to be aliased. Example: The following Ada 83 code: with System, Unchecked_Conversion; procedure P is : type int_ptr is access INTEGER; function Int_Ptr_Of is new Unchecked_Conversion (System.Address, int_ptr); a : array (1 .. 10, 1 .. 10) of INTEGER; ptr : int_ptr; : begin ptr := Int_Ptr_Of (a (i,j)'Address); will be transformed to: with System, Unchecked_Conversion; procedure P is : type int_ptr is access all INTEGER; a : array (1 .. 10, 1 .. 10) of aliased INTEGER; ptr : int_ptr; : begin ptr := a (i,j)'Access; 9. P9X-P2: Translate "delay" statement into "delay until". Guideline: This guideline recognizes a sequence of statements containing a "delay" statement which could be translated into a "delay until". Such a sequence consists of a call to function CALENDAR.CLOCK to obtain the system time, followed by a calculation to determine a duration based on the desired time to resume execution. Transformation: This transformation, applied to a delay statement as described above, will translate the "delay" to a "delay until" statement with the appropriate value of type "CALENDAR.TIME". Rationale: Using the Ada 9X "delay until" statement rather than the "delay" statement avoids the problem of a possible race condition that can occur if the current task is preempted between the evaluation of "CALENDAR.CLOCK" and the execution of the "delay". Example: The Ada 83 statement: delay (Later_Time - Calendar.Clock); is transformed to: delay until Later_Time; 10. P9X-P4: Translate generics to use formal generic package parameters. Guideline: This guideline identifies cases in which an Ada 83 generic package P1 defines as generic parameters all subprograms of another package P2, such that it would be appropriate in Ada 9X for P1 to simply define the entire package P2 as a formal parameter, rather than each of its subprograms individually. Transformation: This transformation, applied to a package P1 as described above, will replace all the generic subprogram parameters with a formal generic package parameter corresponding to P2. In the instantiations of P1, references to subprograms defined by P2 will be renamed accordingly. Rationale: The use of formal generic packages greatly simplifies the composition of generic packages, since a single formal generic package in Ada 9X can take the place of an entire collection of types and operations, which were required to be specified as separate parameters in Ada 83. 11. P9X-P5: Replace renamed operation declarations with the "use type" clause. Guideline: This guideline identifies places in Ada 83 code where it would be appropriate to have an Ada 9X "use type" clause to achieve direct visibility of only the infix operators for a particular type exported from a package. Such positions would be identified by one or more "renames" clauses in which infix operator(s) from the package are renamed to achieve direct visibility. Transformation: This transformation, applied to a position identified by the guideline above, replaces adjacent "renames" declarations for a particular exported type with a single "use type" clause. Rationale: The transformation improves the readability of existing Ada 83 source code, taking advantage of the Ada 93 "use type" clause to replace sequences of function renaming declarations whose only purpose is to achieve direct visibility of operators on a particular type. Example: The following Ada 83 code: function "+" (X, Y : Complex_Numbers.Complex) return Complex_Numbers.Complex renames Complex_Numbers."+"; function "-" (X, Y : Complex_Numbers.Complex) return Complex_Numbers.Complex renames Complex_Numbers."-"; : -- other function "renames" declarations. is transformed to simply: use type Complex_Numbers.Complex; 12. P9X-P6: Collapse multiple exception handlers by capturing exception choice. Guideline: This guideline will recognize cases where a list of exception handlers contains two or more handlers that are of parallel structure, differing only in the name of the exception being handled. Such parallel exception handlers are suitable to be transformed into a single exception handler, parameterized by the exception name. Transformation: This transformation, applied at a position determined by the above guideline, will produce a single exception handler parameterized by the exception name, equivalent to the multiple parallel exception handlers. 13. P9X-P7: Eliminate local variables introduced only to avoid reading "out" parameters. Guideline: Ada 9X relaxes the restriction imposed by Ada 83 that "out" parameters could only be assigned values, not read. This restriction made it necessary in Ada 83 to introduce redundant local variables of the same type as the "out" parameters, in cases when the values of the parameters needed to be read. This guideline identifies such redundant local variables. Transformation: This transformation, applied to a redundant local variable identified by the above guideline, will eliminate the redundant variable, substituting direct references to the "out" parameter for all references to the local variable. Rationale: The transformation simplifies and improves the readability of existing Ada 83 source code, by eliminating redundant local subprogram variables. Guideline Method: Given a subprogram S with an 'out' parameter P of type T, then the following conditions are necessary for a match of this guideline: 1. There must be a variable V declared in S which is of type T. 2. For each exit point within the executable statements of S, there must be an assignment: P := V, in the basic block immediately preceding the exit point. (For our purposes, the exit points consist of the end of the procedure body, any 'return' statements in the procedure, and the end of any exception handler in the procedure). Further, there must not be any subsequent reassignment to P in that basic block. If all of the above conditions are met, this guideline matches at the declaration position of variable V. Transformation Method: This transformation is applied at a local variable position V recognized by the above guideline. It deletes the declaration of V, as well as all assignments of the form P := V. Remaining references to V are replaced with references to P. If the declaration of V included an explicit initial value (I), then an assignment of the form: P := I; is inserted in front of the first executable statement of subprogram S. Example: procedure Do_Something (status : out BOOLEAN) is status_V : BOOLEAN := initial_status; begin : status_V := some_boolean_cond; if status_V or some_other_cond then status := status_V; return; end if; : Status := Status_V; end Do_Something; will be transformed to: procedure Do_Something (status : out BOOLEAN) is begin status := initial_status; : status := some_boolean_cond; if status or some_other_cond then return end if; : end Do_Something; 14. P9X-P8: Eliminate constants introduced only to deduce the bounds of a declared variable. Guideline: Ada 9X makes it possible to deduce the bounds of a variable (or constant) from an appropriate initial value. Thus, where in Ada 83 you were required to write: Message : constant String := Get_Message; -- "Get_Message" is a function call. S : String (Message'Range) := Message; in Ada 9X you can simply write: S : String := Get_Message; This guideline identifies constants such as "Message" above, which are needed by Ada 83 only to deduce the bounds of a declared variable, and are not otherwise referenced. Transformation: This transformation, applied to a redundant constant such as "Message" in the above example, simply eliminates the redundant constant declaration. Thus the first form of the above example would be translated to the second form. Rationale: The transformation simplifies and improves the readability of existing Ada 83 source code, by eliminating redundant constant declarations.