|
The Ada language mapping is quite straightforward, as most of the YAMI4 Definition Language syntax was inspired by analogous elements of Ada.
Packages are mapped directly with similar consequences to the visibility of names in importing and parent-child relations of packages. Both package specifications and package bodies are generated with the structure that mirrors the packaging structure of YDL sources. In particular, package imports are mapped to the with
clause and parent-child package relationships are retained.
Types from YDL are mapped to record types in Ada.
Type fields are mapped to record fields.
Field types are mapped to standard Ada types or to types from the YAMI.Parameters
package in the following way:
Boolean
is mapped to standard Boolean
.Boolean_Array
is mapped to Boolean_Array_Holder
.Integer
is mapped to YAMI_Integer
.Integer_Array
is mapped to YAMI_Integer_Array_Holder
.Long_Long
is mapped to YAMI_Long_Long_Integer
.Long_Long_Array
is mapped to YAMI_Long_Long_Integer_Array_Holder
.Float
is mapped to YAMI_Long_Float
.Float_Array
is mapped to YAMI_Long_Float_Array_Holder
.String
is mapped to standard Unbounded_String
.String_Array
is mapped to String_Array
, which refers to the instantiation of standard Ada.Containers.Indefinite_Vectors
for String
.Binary
is mapped to Binary_Holder
.Binary_Array
is mapped to Binary_Array
, which refers to the instantiation of standard Ada.Containers.Indefinite_Vectors
for Ada.Streams.Stream_Element_Array
.
Optional fields are mapped to pairs of fields, where the normally generated field is accompanied by the Boolean
field named Field_Valid
that allows to express whether the given field is valid or not.
Each generated record type has two primitive operations, Write
and Read
, which can be used to automate translation of the given record type to and from Parameters_Collection
.
For example, the following type description in YDL (taken from the calculator example):
type Results is Sum : Integer; Difference : Integer; Product : Integer; Ratio : optional Integer; end Results;
is mapped to the following Ada specification:
type Results is record Sum : YAMI.Parameters.YAMI_Integer; Difference : YAMI.Parameters.YAMI_Integer; Product : YAMI.Parameters.YAMI_Integer; Ratio_Valid : Boolean := False; Ratio : YAMI.Parameters.YAMI_Integer; end record; procedure Write (V_Y4 : in Results; P_Y4 : in out YAMI.Parameters.Parameters_Collection); procedure Read (V_Y4 : out Results; P_Y4 : in YAMI.Parameters.Parameters_Collection);
and the following code in respective package body:
procedure Write (V_Y4 : in Results; P_Y4 : in out YAMI.Parameters.Parameters_Collection) is begin P_Y4.Set_Integer ("sum", V_Y4.Sum); P_Y4.Set_Integer ("difference", V_Y4.Difference); P_Y4.Set_Integer ("product", V_Y4.Product); if V_Y4.Ratio_Valid then P_Y4.Set_Integer ("ratio", V_Y4.Ratio); end if; end Write; procedure Read (V_Y4 : out Results; P_Y4 : in YAMI.Parameters.Parameters_Collection) is begin V_Y4.Sum := P_Y4.Get_Integer ("sum"); V_Y4.Difference := P_Y4.Get_Integer ("difference"); V_Y4.Product := P_Y4.Get_Integer ("product"); declare E_Y4 : YAMI.Parameters.Parameter_Entry; begin P_Y4.Find ("ratio", E_Y4, V_Y4.Ratio_Valid); if V_Y4.Ratio_Valid then V_Y4.Ratio := P_Y4.Get_Integer ("ratio"); end if; end; end Read;
As can be seen, optional fields allow to work with parameters entries that might or might not exist at all. Record types that are generated for user-defined types are used on both client- and server-side.
It should be noted that these operations do not clear the target object before performing the translation - this means that they are working in the incremental way, which can provide potential flexibility.
Interfaces, on the client-side, are mapped to tagged record types with the same name that encapsulate the connection details of the remote object - the agent object in use, the server location, object name and requested operation timeout. These details are left in the public part of the generated code just in case they are needed for diagnostic purposes, but are generally not relevant in regular use. For the calculator example, the Operations
interface is mapped to the following tagged type:
type Operations is tagged record Agent : YAMI.Agents.Agent_Access; Server_Location : Unbounded_String; Object_Name : Unbounded_String; Timeout : Duration; end record;
This tagged record type has the Initialize_
Interface operation that makes it easier to associate it with the agent object that is intended for handling physical communication. In this example, the interface named Operations
, has the following initialization procedure:
procedure Initialize_Operations (Client_Y4 : out Operations; Agent : in out YAMI.Agents.Agent; Server_Location : in String; Object_Name : in String; Timeout : in Duration := 0.0);
This tagged type offers additional primitive operations, one for each message declared in the interface. This operation encapsulates the complete interaction with remote object and takes care of parameter translation as well. In the case of calculator example, the generated Calculate
operation has the following signature:
procedure Calculate (Client_Y4 : in out Operations; Op : in Operands; Res : out Results);
As can be seen above, the user-defined types and their respective record type in generated code are used in this signature in a natural way.
The run-time implementation of this operation involves the following sequence of actions:
Initialize_
Interface\_{Name}),This sequence of actions allows to provide the remote procedure call functionality.
As a counterpart of these definitions, the generated code contains also an abstract type with primitive operations for use on the server-side. This type is intended to be a base type for user-defined extensions that provide the actual implementation for all message operations.
The Operations
interface is mapped to the following server-side abstract type in Ada:
type Operations_Server is abstract new YAMI.Incoming_Messages.Message_Handler with null record;
The specializations of this type can be directly registered as YAMI4 objects thanks to the Message_Handler
interface.
For each message in the given interface, a separate abstract procedure is generated:
procedure Calculate (Server_Y4 : in out Operations_Server; Op : in Operands; Res : out Results) is abstract;
Server programmers are expected to implement this procedure in their derived type according to the application needs. In the case of the calculator example, the implementation performs all four calculations on the given operands and puts the results in the output parameter.