Ada Code Generation

The detailed rules used to generate Ada code from a Rhapsody model follow this section.  But before giving the low-level rules, this section gives an overview of the generation concepts by showing simple examples of the Ada code that is generated from a particular model.

Classes

Class definition

A class in Rhapsody is represented as an Ada package, and produces a package specification and an optional package body in Ada.  The name of the Ada package is the name of the class.

  A simple class in Rhapsody.

    --++ class class_name
    package class_name is
    
        type class_name_t;
        type class_name_acc_t is access all class_name_t;
        type class_name_wide_acc_t is access all class_name_t'class;
        
        type class_name_t is tagged null record;
        
    private
     
    end class_name;
	

  The generated Ada code for a simple class.

The name of the generated file is class_name.ads .

In addition, three new types are declared in the public part of the package specification - a tagged record type, and two optional access to that type.

The access types can be generated in different way. Some properties control these types generation.

Class record type visibility

The definition of this record type appears in the public part of the specification package where the record type is declared, but it could also appear in the private part by setting the “Ada_CG.Class.Visibility” property.

  Controlling the location of the record type definition.

Inheritance

When a class inherits from another class, the record type for the subclass is an extension of the record type of the parent class.

  Inheritance in Rhapsody.

    with Superclass;
    
    --++ class Subclass
    package Subclass is
    
       type Subclass_t is new Superclass.Superclass_t with private;
    
       type Subclass_acc_t is access Subclass_t;
    
    --Public Fields/Variables accessors ---------
       function get_my_Boolean (this : in Subclass_t) return Boolean;
         pragma inline (get_my_Boolean);

       procedure set_my_Boolean (this : in Subclass_t; value : in Boolean);
         pragma inline (set_my_Boolean);
    
    private
    
       type Subclass_t is new Superclass.Superclass_t with
       record
    
         -- Fields --
         my_Boolean : Boolean;    --++ attribute my_Boolean
    
       end record;
    
    end Subclass;
    
	

  The package specification for a specialized class.

Notice that a “With” statement has been generated for the superclass in the package specification of the subclass.

Initialization code

A non-abstract class can have initialization code that is executed during elaboration of the associated package. In order to generate such code, you’ll need to edit the Ada_CG::Class::InitializationCode property for that class.

  Setting the initialization code property for a class

    --++ class class_name
    package body class_name is
    
    --Functions/Procedures section ---------------------
       procedure myOperation (this : in out class_name_t) is
       begin
          null;
          --+[ operation myOperation()
    
          --+]
       end myOperation;
    
    begin
       null;
    end class_name;
	

  Generated body for a class with initialization code

Static class

A static class is a class witch as only static attributes and operations. No tagged record type and no ”this” parameters are generated for this kind of class.

A Static class can be used for safety critical application.

  setting IsStatic property for a class

abstract class and interface

Abstract class and Interface

A class can have the stereotype "abstract" or "interface". If Ada83 or Ada95 is selected, this will generate an abstract class record type. The class access type is generated in a different way than usual classes. It is a class wide access type by default.

		type object_t;
		type object_acc_t is access all object_t'Class;
		type object_t is abstract tagged null record;
		
The class access type can be generated as usual, by setting the property Ada_CG::Operation::VirtualMethodGenerationScheme to ClassWideOperations. In this case, the property Ada_CG::Class::GenerateAccessType can be used as usual.
		type object_t;
		type object_acc_t is access all object_t;
		type object_t is abstract tagged null record;
		
For Ada2005 and latest Ada version, "interface" stereotype generates an interface type. (See Ada2005 Code Generation section.)

Attributes

Accessor and mutator

By default, a mutator and accessor are created for each attribute.

Non-static attributes

When non-static attributes are added to a class, these attributes are added to the record type.

When non-static attributes are added to a package, these attributes are handled as static attributes.

 

  Non-static attributes of a class.

--++ class class_name
package class_name is
    
    type class_name_t;    
    type class_name_acc_t is access all class_name_t;    

    type class_name_t is tagged    

    record

       -- Fields
        my_Boolean : Boolean;   --++ attribute my_Boolean
        my_Integer : Integer;   --++ attribute my_Integer
        
    end record;

    --Public Fields/Variables accessors ---------------
    function get_my_Boolean (this : in class_name_t) return Boolean;
      pragma inline (get_my_Boolean);
              
    procedure set_my_Boolean (this : in class_name_t; value : in Boolean);
      pragma inline (set_my_Boolean);
              
    function get_my_Integer (this : in class_name_t) return Integer;
      pragma inline (get_my_Integer);
              
    procedure set_my_Integer (this : in class_name_t; value : in Integer);
      pragma inline (set_my_Integer);

private
              
end class_name;
	

  The package specification for non-static attributes.

Because accessor and mutator methods are created, a package body file is created with the name class_name.adb .

--++ class class_name
package body class_name is
    
    --Fields/Variables accessors ---------------
    function get_my_Boolean (this : in class_name_t) return Boolean is
    begin
        return this.my_Boolean;
    end get_my_Boolean;
              
    procedure set_my_Boolean (this : in class_name_t; value : in Boolean) is
    begin
        this.my_Boolean := value;
    end set_my_Boolean;
              
    function get_my_Integer (this : in class_name_t) return Integer is
    begin
        return this.my_Integer;
    end get_my_Integer;
              
    procedure set_my_Integer (this : in class_name_t; value : in Integer) is
    begin
        this.my_Integer := value;
    end set_my_Integer;

end class_name;
	

  The package body for non-static attributes.

The record type now contains the two non-static attributes that were added in Rhapsody.

In addition, the attribute accessor and mutator operations contain a ‘this’ parameter that is used to pass in an instance of the type being affected.  This is true for all non-static operations that are not for singleton classes.

The accessor and mutator are generated in the public part of the package specification by default, but they can be moved to private part by clicking the “Private” radio button on the features page.

  Controlling the visibility of the accessor and mutator.

Static attributes

Attributes marked as static do not create record elements in classes, but instead are represented as variables in the Ada package.

Static attributes visibility

These variables can be defined in the public or private part of the package specification, or in the package body, depending on the setting of property “Ada_CG.Attribute.Visibility”.

  Static attributes of a class.

In this example, both attributes are marked as static.  However, the attribute privateStaticInt is marked as private, which means that the accessors will appear in the private part of the package specification, and its property “Ada_CG.Attribute.Visibility” is set to “Private”, forcing the variable definition to appear in the private part as well.

--++ class class_name
package class_name is
    
    type class_name_t;    
    type class_name_acc_t is access all class_name_t;    

    type class_name_t is tagged null record;

    -- Public Variables/Constants ---------------
    public_Static_Boolean : Boolean;  --++ attribute public_Static_Boolean


    --Public Fields/Variables accessors ---------------
    function get_public_Static_Boolean return Boolean;
      pragma inline (get_public_Static_Boolean);
              
    procedure set_public_Static_Boolean (value : in Boolean);
      pragma inline (set_public_Static_Boolean);
              
private

    -- Private Variables/Constants ---------------
    private_Static_Integer : Integer;  --++ attribute private_Static_Integer


    --Private Fields/Variables accessors ---------------
    function get_private_Static_Integer return Integer;
      pragma inline (get_private_Static_Integer);
              
    procedure set_private_Static_Integer (value : in Integer);
      pragma inline (set_private_Static_Integer);
              
              
end class_name;
	

  The package specification for static attributes.

--++ class class_name
package body class_name is
    
    --Fields/Variables accessors ---------------
    function get_private_Static_Integer return Integer is
    begin
        return private_Static_Integer;
    end get_private_Static_Integer;
              
    procedure set_private_Static_Integer (value : in Integer) is
    begin
        private_Static_Integer := value;
    end set_private_Static_Integer;

    function get_public_Static_Boolean return Boolean is
    begin
        return public_Static_Boolean;
    end get_my_Boolean;
              
    procedure set_public_Static_Boolean (value : in Boolean) is
    begin
        public_Static_Boolean := value;
    end set_public_Static_Boolean;
              
end class_name;
	

  The package body for static attributes.

Static attributes declaration position

In Ada, declaration order is important. For example, a type declaration might depend on a constant that has to be declared before being used.

In order to provide some degree of control over the declaration order of attributes, the Ada_CG.Attribute.DeclarationPosition property can be used. The table below summarize the different values that this property can take and its effects on the attribute it is being applied.

Value

Description

Default

This is the default setting provided for compatibility reasons. It is similar to the AfterClassRecord setting with the following exception:

  • For static attributes defined in a class with an “Ada_CG.Attribute.Visibility” property set to “Public”, these attributes get generated after types with an “Ada_CG.Type.Visibility” property set to “Public”.

On new models, it is advised not to use this value. Should you change this value on previous models, make sure the code compiles once you’ve regenerated it.

BeforeClassRecord

The attribute will be generated immediately before the class record

AfterClassRecord

The attribute will be generated immediately after the class record

StartOfDeclaration

The attribute will be generated immediately after the start of the section (public part of the specification, private part of the specification, package body)

EndOfDeclaration

The attribute will be generated immediately before the end of the section (public part of the specification, private part of the specification, package body)

Table 1 Ada_CG.Attribute.DeclarationPosition property values description

A few special cases:

These attributes then have no actual class record around which they can be positioned. In such cases, they are generated around a “virtual” class record location that gives a declaration order as close as possible to the one that would exist if there was a class record definition in the section the attributes are being generated into.

  Static attributes of a class with overridden declarationPosition property

  Setting the DeclarationPosition for a static attribute to BeforeClassRecord

  Setting the DeclarationPosition for a static attribute to AfterClassRecord

--++ class class_name
package class_name is
    
    type class_name_t;    
    type class_name_acc_t is access all class_name_t;    

    -- Public Variables/Constants ---------------
    public_Static_Boolean_Before_Record : Boolean;  --++ attribute public_Static_Boolean_Before_Record

    type class_name_t is tagged null record;

    -- Public Variables/Constants ---------------
    public_Static_Integer_After_Record : Integer;  --++ attribute public_Static_Integer_After_Record

    --Public Fields/Variables accessors ---------------
              
private

              
end class_name;
	

  Generated code for static attributes with overridden DeclarationPosition property

Non-Predefined Attribute Types

The attribute definitions can be entered directly in the “Ada declaration” field instead of choosing a predefined type.  In this case, it might be necessary to set the two properties “Ada_CG.Attribute.AccessorGenerate” and “Ada_CG.Attribute.MutatorGenerate” to false so that the default accessors are not generated.

  Non-static attribute definition.

  Static attribute definition.

--++ class class_name
package class_name is
    
    type class_name_t;    
    type class_name_acc_t is access all class_name_t;    

    type class_name_t is tagged

    record

      -- Fields --
      -- This is a string attribute
      my_String : Integer := "testtest";  --++ attribute my_String

    end record;

    -- Public Variables/Constants ---------------
    -- This is a public string variable
    my_Static_String : String (1..8) := "stpublic";  --++ attribute my_Static_String

    --Public Fields/Variables accessors ---------------
              
private

              
end class_name;
	

  The package specification for non-predefined type attributes.

Guarded Attributes

Access to attributes can be guarded by setting the “isGuarded” property.  There are two possible settings.  One setting is “all” which guards both the accessor and mutator of the attribute.  The other setting is “mutator” which will only guard the mutator.

  Guarding an Attribute.

When an attribute is guarded, a mutex is used to synchronize access to the attribute. Depending on the value of the “Ada_CG.<Class|Package>.UseAda83Framework property of the attribute owner, an Ada83 task based Mutex or an Ada95 protected object based Mutex will be used.

<<Discriminant>> Attributes

By setting a class instance attribute or a struct attribute stereotype to <<Discriminant>>, it is possible to generate a discriminated record type.

  Modeling a class with a <<Discriminant>> attribute

  Defining an unconstrained array type

  Setting an attribute stereotype to <<Discriminant>>

  Defining an attribute with a type definition based on the class record type discriminant

--++ class class_0
package class_0 is
    
    type class_0_t (
      Size : Integer  --++ attribute Size
    );    
    type class_0_acc_t is access all class_0_t;    

    --Public types -------------------------------------
    type Int_Array is array(Integer range <>) of Integer;

    type class_0_t (
      Size : Integer  --++ attribute Size
    )is tagged

    record

      -- Fields --
      My_Int_Array : Int_Array(1..Size);  --++ attribute My_Int_Array

    end record;

private

              
end class_0;
	

  Generated code for a class with a discriminant

Note that no setter is generated for attributes with a <<Discriminant>> stereotype, no matter the setting of its Ada_CG.Attribute.MutatorGenerate property.

Overriding and redefining discriminant attributes

If the attribute is a <<Discriminant>> non-static attribute and it has an initial value and it is defined as a <<Discriminant>> attribute in at least one of its parent classes then the attribute may be generated as a constraint on the parent discriminant, as a new discriminant hiding the one from the parent or as both.

This behavior is controlled by using the “Ada_CG.Attribute.RedefiningDiscriminantPolicy “ and “Ada_CG.Attribute.ParentDiscriminantValue” properties.

  Class with overriding and redefining discriminant

  Overriding discriminant

  Overriding and redefining discriminant

  Redefining discriminant

With Base_Class;
    
--++ Class Derived_Class
package Derived_Class is
    
    type Derived_Class_t (
      overridden_and_redefined : Integer;  --++ attribute overridden_and_redefined
      redefined : Integer  --++ attribute redefined
    );    
    type Derived_Class_acc_t is access all Derived_Class_t;    

    type Derived_Class_t (
      overridden_and_redefined : Integer;  --++ attribute overridden_and_redefined
      redefined : Integer  --++ attribute redefined
    ) is new Base_Class.Base_Class_t(
      overridden => 10, --++ attribute overridden
      overridden_and_redefined => 100 --++ attribute overridden_and_redefined
    )With null record;

private

end Derived_Class;
	

Deferred constant

The deferred constant is defined in the private part of a package. And a partial declaration is also made in public part. In order to generate a deferred constant, several conditions must be matched.

--++ package Default::Complex_Numbers
package Complex_Numbers is

  --Public types -------------------------------
  --++ Type Forward_Complex
  type Complex is private;

  -- Public Variables/Constants ----------------
  I : constant Complex;

private

  --Private types ------------------------------
  --++ Type Complex
  type Complex is 

  record

    -- Fields --
    Rl : Float;  --++ attribute Rl
    Im : Float;  --++ attribute Im

  end record;

  -- Public Deferred Constants Initialization -
  I : constant Complex := (0.0, 1.0);  --++ attribute I

end Complex_Numbers;
    

Operations

Operations created in Rhapsody will result in Ada functions if there is a return type, or procedures if there is not. In this example, myOperation will be a function with two parameters that returns an Integer. And myProc will be a procedure with one parameter.

  Operations defined on a class.

  Operation Features

  The implementation of myOperation .

  The local variables for myOperation .

--++ Class class_name
package class_name is
    
    type class_name_t;
    type class_name_acc_t is access all class_name_t;    

    type class_name_t is tagged null record;

    --Public Functions/Procedures section --------
    --++ operation myOperation(Integer, Boolean)
    function myOperation (this : in class_name_t;
      arg1 : in Integer;
      arg2 : in Boolean
    ) return Integer;

    --++ operation myProc(Integer)
    procedure myProc (
      arg1 : in Integer
    );

private

end class_name;
	

Operations in the package specification.

--++ Class class_name
package body class_name is
    
    --Functions/Procedures section --------
    function myOperation (this : in class_name_t;
      arg1 : in Integer;
      arg2 : in Boolean
    ) return Integer is
               myLocal : Boolean := TRUE;
    begin
       --+[ operation myOperation(Integer, Boolean)
       return 5;
       --+]
    end myOperation;
    

    procedure myProc (
      arg1 : in Integer
    ) is
    begin
       null;
       --+[ operation myProc(Integer)
           
       --+]
    end myProc;
       
end class_name;
	

Operations in the package body.

In the operation bodies, the implementation provided in Rhapsody has been used for myOperation , but an appropriate default statement has been created for myProc because the implementation field in Rhapsody has been left blank.  Any lines entered in this implementation field will replace this default statement.

Guarded operations

An operation can be made guarded by setting the “Concurrency” property to guarded .

  Making an Operation Guarded.

When an operation is guarded, a mutex is used to synchronize access to the operation. Depending on the value of the “Ada_CG.<Class|Package>.UseAda83Framework property of the operation owner, an Ada83 task based Mutex or an Ada95 protected object based Mutex will be used.

Template operations and their instantiations

The mechanism for supporting template operations and their instantiations is very similar to the one available for template classes and their instantiation.

  Modeling a template operation and a template operation instantiation

  features of a template operation

  setting up template parameters for a template operation

--++ package Generic_Op_Pkg
package Generic_Op_Pkg is
    
    --Public Functions/Procedures section -------
    --++ operation Generic_Function(Integer)
    generic
        gen_param : Integer;
    function Generic_Function (
      regular_param : in Integer
    ) return Integer;
    
    

private
       
end Generic_Op_Pkg;
	

generated code for a template operation specification

--++ package Generic_Op_Pkg
package body Generic_Op_Pkg is
    
    --Functions/Procedures section -------
    function Generic_Function (
      regular_param : in Integer
    ) return Integer is
       --+[ operation myOperation(Integer, Boolean).Variables
       
       --+]
    begin
       return 0;
       --+[ operation myOperation(Integer, Boolean)
       
       --+]
    end Generic_Function;

       
end Generic_Op_Pkg;
	

generated code for a template operation implementation

  features of a template operation instantiation

  setting up template arguments for a template operation instantiation

--++ package Generic_Op_Instantiation_Pkg
package Generic_Op_Instantiation_Pkg is
    
    --Public Functions/Procedures section -------
    --++ operation Generic_Function_Instantiation(Integer)
    function Generic_Function_Instantiation is new Generic_Op_Pkg.Generic_Function(
      gen_param => 8
    );

private
       
end Generic_Op_Instantiation_Pkg;
	

generated code for a template operation instantiation

Access parameters

Ada95 introduced the concept of access parameters. In order to set the mode of a parameter to be “access”, as opposed to “in”, “out”, or “in out”, first the package in which is defined the operation has to generate Ada95 code (and not Ada83), second you will need to edit the properties of the parameter to set the AsAccess property to true.

  Making a parameter passing mode "access"

You can also choose to pass the this parameter as an access mode parameter for a non-static operation, to do this you need to edit the properties of the operation to set the ThisByAccess property to true.

  Making an operation this parameter passing mode "access"

type class_name_t;
type class_name_acc_t is access all class_name_t;
    
type class_name_t is tagged null record;

    --Public Functions/Procedures section -------
    --++ operation myOperation(Integer, Boolean)
    function myOperation (this : access class_name_t;
        arg1 : access Integer;
        arg2 : in Boolean
     ) return Integer;
	

Operation using access mode parameters

Class-wide parameters

In order to specify whether a parameter is to be passed class-wide or not, you will need to set its “ClassWide” property to true.

Dependencies

<<Usage>> dependencies

Dependencies stereotyped as <<Usage>> in Rhapsody create “With” statements in the generated Ada packages.  If the “Ada_CG.Dependency.CreateUseStatement” property is set to “Use”, a “Use” statement will also be created for the target package.If it is set to “UseType”, a “Use Type” statement will also be created for the target type. By default, the “With” and “Use” statements will appear in the package specification.  They can be moved to the package body by setting the “CG.Dependency.UsageType” property to “Implementation”.

  <<Usage>> dependencies in Rhapsody Developer for Ada.

  An implementation dependency.

  Creating a "Use" statement.

With actor_3;
With class_0;
With package_0;
Use class_0;

--++ class class_1
package class_1 is
    
type class_1_t;
type class_1_acc_t is access all class_1_t;

type class_1_t is tagged null record;

    --Public Functions/Procedures section -------
    --++ operation Message_0()
    function message_0 (this : in out class_1_t);

private

end class_1;
	

  The package specification for dependencies.

With package_0.class_2;

--++ class class_1
package body class_1 is
    
type class_1_t;
type class_1_acc_t is access all class_1_t;

type class_1_t is tagged null record;

    --Functions/Procedures section -------
    function message_0 (this : in out class_1_t) is
    begin
       null;
       --+[ operation Message_0()
       
       --+]
    end message_0;

end class_1;
	

The package body for dependencies.

Note that elaboration pragmas can be generated for the supplier class or package of the dependency in the client class or package by setting the appropriate properties on the dependency:

<<Renames>> dependencies

Dependencies stereotyped as <<Renames> in Rhapsody create “renames” statements in the generated Ada packages.

Valid <<Renames>> dependencies can be modelized between any two model elements of the same kind among the following ones:

Be aware that using this feature on classes limits what you can do with the renaming class. More specifically :

Note that for operations:

Only <<renames>> dependencies between classes and packages can be drawn on the Object Model Diagrams of Rhapsody. In order to model <<renames>> dependencies between two attributes or two operations, one has to use the context menu in the Rhapsody browser.

Actors

Actors generate exactly the same code as classes.

  An Actor in Rhapsody.

With Class_0;
With Super_Actor;

--++ actor Actor_0
package  package_1.Actor_0 is
    
   type Actor_0_t;
   type Actor_0_acc_t is access all Actor_0_t;

   type Actor_0_t is new Super_Actor.Super_Actor_t with

   record

      -- Fields --
      attr_1 : Integer;   --++ attribute attr_1

   end record;

   --Public Variables/Constants -----------------
   private_static_attr : Integer; --++ attribute private_static_attr
   
   --Public Functions/Procedures section -------
   --++ operation operation()
   procedure operation (this : in out Actor_0_t);

   --++ operation static_operation()
   procedure static_operation;

   --Public Fields/Variables accessors -----------
   function get_attr_1 (this : in Actor_0_t) return Integer;
     pragma inline (get_attr_1);

   procedure set_attr_1 (this : in Actor_0_t; value : in Integer);
     pragma inline (set_attr_1);

private

   --Private Fields/Variables accessors -----------
   function get_private_static_attr (this : in Actor_0_t) return Integer;
     pragma inline (get_private_static_attr);

   procedure set_private_static_attr (this : in Actor_0_t; value : in Integer);
     pragma inline (set_private_static_attr);

end package_1.Actor_0;
	

Package specification for an Actor.

--++ actor Actor_0
package body package_1.Actor_0 is
    
   --Functions/Procedures section -------
   procedure operation (this : in out Actor_0_t) is
        --+[ operation operation().Variables
        
        --+]
   begin
      null;
      --+[ operation operation()
        
      --+]
   end operation;

   --++ operation static_operation()
   procedure static_operation is
        --+[ operation static_operation().Variables
        
        --+]
   begin
      null;
      --+[ operation static_operation()
        
      --+]
   end static_operation;

   --Fields/Variables accessors -----------
   function get_attr_1 (this : in Actor_0_t) return Integer is
   begin
      return this.attr_1;
   end get_attr_1;

   procedure set_attr_1 (this : in Actor_0_t; value : in Integer) is
   begin
       this.attr_1 := value;
   end set_attr_1;


   function get_private_static_attr (this : in Actor_0_t) return Integer is
   begin
      return this.private_static_attr;
   end get_private_static_attr;


   procedure set_private_static_attr (this : in Actor_0_t; value : in Integer) is
   begin
       this.private_static_attr := value;
   end set_private_static_attr;


end package_1.Actor_0;
	

Package body for an Actor.

Packages

Like classes, packages in Rhapsody will also be represented as Ada packages.  A package in Rhapsody can have functions and variables, which will be handled in the same manner as static operations and static attributes on a class. A package can also have initialization code.

In this example, the package specification will be named “myPackage.ads” and the package body will be “myPackage.adb”.

  A package defined in Rhapsody.

--++ package Default::my_Package
package my_Package is
    
    --Public Variables/Constants -----------------
    my_Integer : Integer;  --++ attribute my_Integer
 
    my_Boolean : Boolean;  --++ attribute my_Boolean
    


    --Public Functions/Procedures section -------
    --++ operation my_Function(Integer)
    function my_Function (
        argument_0 : in Integer
    ) return Boolean;

    --++ operation my_Procedure()
    procedure my_Procedure;

    --Public Fields/Variables accessors ---------
    function get_my_Integer return Integer;
       pragma inline (get_my_Integer);

    procedure set_my_Integer (value : in Integer);
       pragma inline (set_my_Integer);

    function get_my_Boolean return Boolean;
       pragma inline (get_my_Boolean);

    procedure set_my_Boolean (value : in Boolean);
       pragma inline (set_my_Boolean);

private

end my_Package;
	

The package specification for a Rhapsody package.

--++ package Default::my_Package
package body my_Package is
    
    --Functions/Procedures section ---------------
    --++ operation my_Function(Integer)
    function my_Function (
        argument_0 : in Integer
    ) return Boolean is
       --+[ operation my_Function(Integer).Variables
       
       --+]
    begin
      return true;
      --+[ operation my_Function(Integer)
       
      --+]
    end my_Function;

    --++ operation my_Procedure()
    procedure my_Procedure is
       --+[ operation my_Procedure().Variables
       
       --+]
    begin
      null;
      --+[ operation my_Procedure()
       
      --+]
    end my_Procedure;
    
    --Public Fields/Variables accessors ---------
    function get_my_Integer return Integer is
    begin
      return my_Integer;
    end get_my_Integer;

    procedure set_my_Integer (value : in Integer) is
    begin
       my_Integer := value;
    end set_my_Integer;

    function get_my_Boolean return Boolean is
    begin
      return my_Boolean;
    end get_my_Boolean;

    procedure set_my_Boolean (value : in Boolean) is
    begin
       my_Boolean := value;
    end set_my_Boolean;

end my_Package;
	

The package body for a Rhapsody package.

Child Packages

 When working with Ada 95, classes and packages are also used as the namespace for classes and packages contained within them.  This containment is used to create child packages.  In Ada 83, this containment does not have any effect.

  Packages and classes used as namespaces.

--++ class class_1::class_2
package my_Package.my_Sub_Package.class_1.class_2 is

    type class_2_t;
    type class_2_acc_t is access all class_2_t;

    type class_2_t is tagged null record;

private

end my_Package.my_Sub_Package.class_1.class_2;
	

The package specification for class_2.

  The resulting files including the namespaces.

In this example, the Ada package name is prefixed by the parent names.  For example, class_2 is contained in class_1 , which is found in my_Sub_Package , which itself if located inside of my_Package .  Therefore the package name for class_2 is my_Package.my_Sub_Package.class_1.class_2 .  This package will be found in the configuration directory in my_Package/my_Sub_Package/class_1 .

Also notice that class_0 is located in the “Default” package, and therefore is not considered as a child package.

Nested Packages

Child packages are in the namespace of their parent, but they are defined in separate files. Nested packages are not only in the namespace of their parent, but they are also defined in the same files as their parent.

  Example of a nested package and a nested class.

In order to generate nested packages, one has to set the Ada_CG.Package.IsNested property for a package or the Ada_CG.Class.IsNested property for a class.

  Setting a class to be generated as a nested package.

  Setting a package to be generated as a nested package.

To determine in which section of the parent package the specification of the nested package will be generated, one can use the Ada_CG.Package.NestingVisibility property for a package, or the Ada_CG.Class.NestingVisibility property for a class.

  Controlling the location of the specification of a nested package

Note that any package or class defined inside of a package or class that is itself nested will be generated as a nested package too.

Private Packages

Packages and classes can be defined as private via the use of the Ada_CG.Package.IsPrivate property for packages and Ada_CG.Class.IsPrivate property for classes.

  Example of a private package and a private class.

  Setting a class to be generated as a private package

  Setting a package to be generated as a private package

--++ class Private_Child_Class
private package Parent_Pkg.Private_Child_Class is

    type Private_Child_Class_t;
    type Private_Child_Class_acc_t is access all Private_Child_Class_t;

    type Private_Child_Class_t is tagged null record;

private

end Parent_Pkg.Private_Child_Class;
	

Specification of a private class

--++ package Parent_Pkg::Private_Child_Package
private package Parent_Pkg.Private_Child_Package is

private

end Parent_Pkg.Private_Child_Package;
	

Specification of a private package

Note that a nested class or package cannot be private.

Elaboration Pragmas

Via the use of appropriate tags, different pragmas can be generated for a class or a package

  Example of a class and a package with elaboration pragmas

  Enabling generation of elaboration pragmas on a class

  Enabling generation of elaboration pragmas on a package

--++ class Class_With_Elaboration_Pragmas
package Class_With_Elaboration_Pragmas is

    pragma elaborate_body;
    pragma preelaborate;
    pragma pure;

    type Class_With_Elaboration_Pragmas_t;
    type Class_With_Elaboration_Pragmas_acc_t is access all Class_With_Elaboration_Pragmas_t;

    type Class_With_Elaboration_Pragmas_t is tagged null record;

private

end Class_With_Elaboration_Pragmas;
	

Specification of a class with elaboration pragmas

--++ package Default::Pkg_With_Elaboration_Pragmas
package Pkg_With_Elaboration_Pragmas is

    pragma elaborate_body;
    pragma preelaborate;
    pragma pure;

private

end Pkg_With_Elaboration_Pragmas;
	

Specification of a package with elaboration pragmas

Please read the section on <<Usage>> dependencies to see how to generate “elaborate” and “elaborate_all” pragmas.

Note that other pragmas can be generated for a class or a package via the use of the following properties:

<<Container>> Packages

Any class or package that is defined within a package stereotyped as <<Container>> will not include the package in its namespace.

In the following example, Package_1 is stereotyped <<Container>>.

  A Sample <<Container>> Package.

In this example, every package is generated, but the namespaces for Class_A, Package_2, and Class_B do not include Package_1.

Types

Type declaration

Types can be created in either packages or classes.

  Types defined in Rhapsody.

The definition of the type is taken in different way.

Language Type declaration

The definition of the type is taken from the “Ada declaration” field,. In the declaration, a “%s” can be inserted to represent the name of the type.

  The declaration of a private type on a class.

  The declaration of a public type on a class.

  The declaration of a private type on a package.

  The declaration of a public type on a package.

Type visibility

A type definition can appear in the public or private portion of the resulting package specification, or in the package body.

  Controlling the visibility of a type.

--++ class class_1
package class_1 is

    type class_1_t;
    type class_1_acc_t is access all class_1_t;

    --Public types ------------------------
    -- This is the declaration of my type.
    type my_Type is new Integer range 0..5;

    type class_1_t is tagged null record;

private

    --Private types ------------------------
    -- Definition of my private type.
    subtype my_Private_Type is Integer range 1..5;

end class_1;
	

The package specification for a class with types.

--++ package package_1
package package_1 is

    --Public types ------------------------
    -- The declaration of the public type.
    type public_Type is  (one, two, three);

private

    --Private types ------------------------
    -- Declaration of the private type.
    type private_Type is new Positive;

end package_1;
	

The package specification for a package with types.

Type declaration position

In order to provide some degree of control over the declaration order of types, the Ada_CG.Type.DeclarationPosition property can be used. Its behavior is very similar to the one of the Ada_CG.Attribute.DeclarationPosition property for attributes, with the following exceptions:

Typedef type declaration

The typedef declaration will generate a new kind of type

	Type Type_0 is new Boolean;

If the "Reference" box is checked, an access type is created

	Type Type_0 is access Boolean;

The property Ada_CG.Type.AccessKind allow refining the the kind of access type

	Type Type_0 is access all Boolean; -- Ada_CG.Type.AccessKind = General 
	Type Type_1 is access constant Boolean; -- Ada_CG.Type.AccessKind = Constant

Type defined as a class

A type can be also defined with a class with a stereotype. This enables to have more visibility on type relations. The stereotypes are defined in the profile AdaCodeGenerator.

Main stereotype is “Type”. It is applicable on a class. This stereotype has a tag “IsSubtype”. If this tag is set to true, then the class will define a subtype.

Any type has a reference to another Ada type. This reference is represented by a dependency with the stereotype “New”. The dependency can be set to a Rhapsody type or a Rhapsody typed class.

Basic use cases:

Definition of a type

Representation of a typed class

	   -- Public Types -------------------------- 
	   type Integer_32 is new Integer;

Definition of a subtype

Representation of a subtype

The generated code of a subtype is:

	   -- Public Types -------------------------- 
	   subtype A_SubType is Integer;

Some other stereotypes are derived from “Type”

Range type

A range type is defined by a class which has the stereotype “RangeType”.

The range is defined by two different ways.

Basic use cases:

Case I

Representation of a range type

The generated code of a range type is:

	   -- Public Types -------------------------- 
	   type A_Range_Type is new Integer range 1..10;

Case II

  Representation of a range type with dependency to a constant

The generated code of a range type is:

	   -- Public Types -------------------------- 
	   subtype A_Range_Type_1 is Default.Integer_32_2 range 1..Default.variable_11;

Array type

An array type is defined by a class which has the stereotype “ArrayType”.

The size of the array is defined in a free text box of the tag “Size”

Representation of an array type

The generated code of an array type is:

	   -- Public Types -------------------------- 
	   type An_Array_Type is array (1..10) of Integer;

Variant record type

A variant record type is defined by a class which has the stereotype “VariantRecordType”.

This class has several elements which describe the structure of this record.

Representation of a variant record type

The class has some attributes which represent the attributes of the record type.

Some attributes have the stereotype discriminant. Those are discriminant attributes of the record type.

The class has a part with stereotype “Case”. It represents the variant part of the record. The name of this part must be the name of the discriminant attribute used in the variant part.

The “Case” part has as many “When” parts as “When” cases in the Ada variant part. Those “When” parts have attributes, and a tag “Condition”, which defines the value of the “when” condition.

The generated code of a variant recod type is:

	   -- Public Types -------------------------- 
	   type A_Variant_Record_Type (
	     attribute_00 : Default.A_Enum;
	     attribute_01 : Default.A_Range_Type;
	   ) is record
	   
	     -- fields --
	     attribute_1 : Integer;
	     attribute_2 : Integer;
	     
	     case attribute_00 is
	       when AA => attribute_1_of_when_condition : Integer;

	       when BB..CC => attribute_2_of_when_condition : Integer;
	                      attribute_3 : Integer;
	     end case;
	   
	   end record;
	   
    


Representation clause

A representation clause can be added on any type by updating the tag representationClauses.

  Representation clause definition.

       -- Public Types -------------------------- 
       type RR is 

       record

           -- Fields --
           Code : Opcode;  --++ attribute Code
           R1 : Register;  --++ attribute R1
           R2 : Register;  --++ attribute R2

       end record;

       for RR'Alignement use 2;  
    
       for RR use
       record
           Code at 0 range 0 .. 7;
           R1 at 1 range 0 .. 3;
           R2 at 1 range 4 .. 7;
       end record;
    



Template Classes and their instantiation

template classes

Creating a template class in Rhapsody results in the generation of a generic Ada package.  The arguments become the generic parameters.

In this example, arg1 is an Integer argument and arg2 is a Boolean argument.

  Definition of a template class.

    --++ class generic_Class 
    generic
        arg1 : Integer;
        arg2 : Boolean;
    package generic_Class is
    
        type generic_Class_t;
        type generic_Class_acc_t is access all generic_Class_t;

        type generic_Class_t is tagged null record;
        
    private
    
    end generic_Class;
	

  Package specification for a generic package.

template instantiations

An instantiation of this generic package is created by using an instantiation class in Rhapsody.

  An instantiation of a template class.

The generated result is an instantiation of the generic package using the supplied arguments.

    with generic_Class;

    --++ class generic_Instantiation 
    package generic_Instantiation is new generic_Class(arg1 => 5, arg2 => true);
	

  The generated Ada package for a generic instantiation.

template inheritance

Note that it is possible to have a template class inherit from another template class.

Inheritance between template classes

With generic_Parent;

--++ class generic_Child
generic
    with package  generic_Parent_Instantiation is new generic_Parent(<>);
    arg_3 : Character;
package generic_Child is

    type generic_Child_t;
    type generic_Child_acc_t is access all generic_Child_t;

    type generic_Child_t is new generic_Parent_Instantiation.generic_Parent_t with null record;

private

end generic_Child;
	

generated code for a template class derived from another template class

template instantiation inheritance

In order to fully benefit from the facilities offered by template inheritance, an efficient way to instantiate the whole class hierarchy is needed.

Modeling instantiation of a template inheritance hierarchy

Note that to specify that a derived class instantiation depends on a parent class instantiation, we use a <<Parent_Instantiation>> dependency from the derived class instantiation to the base class instantiation. This approach allows for reusing of the same parent class instantiation by several derived class instantiations

With generic_Parent;

--++ class generic_Parent_Instantiation
package generic_Parent_Instantiation is new generic_Parent(arg1 => 5, arg2 => true);
	

generated code for a base template instantiation class

With generic_Child;
With generic_Parent_Instantiation;

--++ class generic_Child_Instantiation_1
package generic_Child_Instantiation_1 is new generic_Child(
   generic_Parent_Instantiation => generic_Parent_Instantiation,
   arg3 => 'a'
);
	

generated code for a derived template instantiation class

With generic_Child;
With generic_Parent_Instantiation;

--++ class generic_Child_Instantiation_2
package generic_Child_Instantiation_2 is new generic_Child(
   generic_Parent_Instantiation => generic_Parent_Instantiation,
   arg3 => 'b'
);
	

generate code for another derived template instantiation class

Note that if the derived template class is an (Ada) child package of the base class, the generated code will slightly differ to accommodate the special visibility that the child has upon its parent

Modeling template inheritance hierarchy across (Ada) children packages

--++ class generic_Parent::generic_Child
generic
    arg3 : Character;
package generic_Parent.generic_Child is

   type generic_Child_t;
   type generic_Child_t is access all generic_Child_t;

   type generic_Child_t is new generic_Parent.generic_Parent_t with null record; 

private

end generic_Parent.generic_Child;
	

Generated code for a derived template class that is a child package of its base class

With generic_Parent.generic_Child;
With generic_Parent_Instantiation;

--++ class generic_Child_Instantiation_1
package generic_Child_Instantiation_1 is new generic_Parent_Instantiation.generic_Child(
   arg3 => 'a'
);
	

Generated code for the instantiation of a derived template class that is a child package of its base class

Concurrent Types

Tasks

Starting with Rhapsody Developer for Ada rev 8.1.4, the ada task representation changes. Before, two stereotypes were used to create ada task: <<AdaTask>> and <<AdaTaskType>> .

Now these stereotypes are deprecated and have been renamed <<D_AdaTask>> and <<D_AdaTaskType>>. The old names are used for another purpose.

Two new stereotypes, <<AdaSingleTask>> and <<AdaTaskType>>, have been created in order to be able to create Ada task types or Ada single tasks inside classes.

The legacy task representation is style available and is explained in the first part. A second part will detail how we can represent simple Ada task type and Ada single task in a Rhapsody model.

Legacy Tasks

Tasks in RiA are represented by a class with stereotype D_AdaTask or D_AdaTaskType. In this case, an Ada package is generated, with a tagged record type to represent a usual UML class. An Ada task is generated in this Ada package, and additional operations or attributes are also generated to manage the task.

A class with D_AdaTask stereotype is a usual class which will contain an Ada single task declared in specification file, and a task body in the body file. The effect of this construction, is that the Ada task will be created only once, when the Ada package will be executed.

package Ada_task_class is

  type Ada_task_class_t;
  type Ada_task_class_acc_t is access all Ada_task_class_t;

  --task type declaration
  task Ada_task_class_task is
  end Ada_task_class_task;

  type Ada_task_class_t is tagged null record;

private

end Ada_task_class;

A class with D_AdaTaskType stereotype is a usual class, which will contain an Ada task type declared in specification file, and a task body in body file. A task attribute will also be generated in class record type. The initialize function will instantiate this task attribute. In this case, at run time, the task will be created only when the Rhapsody class will be instantiated and initialized. Several instance of the task will run if several instance of the class are created.

package Ada_Task_Type_Class is

  type Ada_Task_Type_Class_t;
  type Ada_Task_Type_Class_acc_t is access all Ada_Task_Type_Class_t;

  --task type declaration
  task type Ada_Task_Type_Class_task is
  end Ada_Task_Type_Class_task;

  type Ada_Task_Type_Class_task_acc is access Ada_Task_Type_Class_task;

  type Ada_Task_Type_Class_t is tagged 
  record
    my_Ada_Task_Type_Class_task : Ada_Task_Type_Class_task_acc;
  end record;

  procedure Initialize (this : in out Ada_Task_Type_Class_t);
  procedure Finalize (this : in out Ada_Task_Type_Class_t);

private

end Ada_Task_Type_Class;
Task entries

All operations defined in this class will be considered as task entries. It is possible to add an entry stereotype on these operations. This will not change operation default behavior.

An operation will generate the following code

  type Ada_Task_Type_Class_t;
  type Ada_Task_Type_Class_acc_t is access all Ada_Task_Type_Class_t;

  task type Ada_Task_Type_Class_task is
    entry My_Entry_1 (this : in out Ada_Task_Type_Class_t);
    entry My_Entry_2 (this : in out Ada_Task_Type_Class_t);
  end Ada_Task_Type_Class_task;


  type Ada_Task_Type_Class_task_acc is access Ada_Task_Type_Class_task;

  type Ada_Task_Type_Class_t is tagged 
  record
    my_Ada_Task_Type_Class_task : Ada_Task_Type_Class_task_acc;
  end record;

  procedure My_Entry_1 (this : in out Ada_Task_Type_Class_t);
  procedure My_Entry_2 (this : in out Ada_Task_Type_Class_t);
  

The following code shows how the entries operations will be called from the Ada_Task_Class class.

  procedure My_Entry_1 (this : in out Ada_Task_Type_Class_t) is
  begin
    this.my_Ada_Task_Type_Class_task.My_Entry_1 (this);
  end My_Entry_1;

  procedure My_Entry_2 (this : in out Ada_Task_Type_Class_t) is
  begin
    this.my_Ada_Task_Type_Class_task.My_Entry_2 (this);
  end My_Entry_2;
  
Regular operation

If a user wants to generate an operation which does not represent an entry, then the Ada_CG::Operation::isEntry property must be set to false.

Pragmas

It is possible to generate some pragmas on tasks specification, by using some properties:

pragma Priority(XXX)
  --task type declaration
  task type task_with_priority is
    pragma Priority(5);

  end task_with_priority
pragma Storage_Size(XXX)
  --task type declaration
  task type task_with_storage_size is
    pragma Storage_Size(64);

  end task_with_storage_size
Task body

The task body will be automatically populated with the user defined entries. The skeleton of the task body contains an endless loop with a select statement. Each entry operation of the model will define an accept statement in the select statement. The implementation of accept statement is defined in operation implementation.

This is the default code generator behavior.

task body Ada_Task_Type_Class_task is
  begin
    loop
      select
         accept my_entry_1 do
           -- operation implementation here:
           . . .
         end my_entry_1;
      or
         accept my_entry_2 do
           -- operation implementation here:
           . . .
         end my_entry_2;
      end select;
    end loop;
  end Ada_Task_Type_Class_task;

It is possible to customize this template. In this template, you can add:

Entry condition

Guard can be set on each accept statement. It can be done with the Ada_CG::Operation::EntryCondition property of the entry operation. This property should contain the condition which must be met before executing the select statement.

task body Ada_Task_Type_Class_task is
  begin
    loop
      select
        -- property Ada_CG::Operation::EntryCondition contains
        -- A = 1 and b = 2
        when A = 1 and b = 2 =>
         accept my_entry_1 do
         end my_entry_1;
      or
         accept my_entry_2 do
         end my_entry_2;
      end select;
    end loop;
  end Ada_Task_Type_Class_task;
Synchronous execution request

Operations can have either a HSER or LSER stereotype to indicate highly synchronous or loosely synchronous execution requests respectively. If no stereotypes are set on the operations, they are considered as HSRE by default.

If LSRE stereotype is set, the following code is generated

task body Ada_Task_Type_Class_task is
  begin
    loop
      select
        -- The my_entry_1 operation has LSER stereotype;
         accept my_entry_1;
           -- Here is the place of my_entry_1 operation
           -- implementation
         
      or
        -- The my_entry_2 operation has HSER stereotype;
         accept my_entry_2 do
           -- Here is the place of my_entry_2 operation
           -- implementation
         end my_entry_2;
      end select;
    end loop;
  end Ada_Task_Type_Class_task;
Task default action

An alternative operation can be set at the end of the select statements. The Ada_CG::Operation::TaskDefaultScheme property of the class (not of the operation) must be set to conditional or timed.

The alternative operation should have the stereotype TaskDefaultAction.

Ada_CG::Operation::TaskDefaultScheme property set to conditional

task body Ada_Task_Type_Class_task is
  begin
    loop
      select
         accept my_entry_1;
      or
         accept my_entry_2 do
         end my_entry_2;
      else
         -- The Alt_Op has TaskDefaultAction stereotype
         implementation of Alt_Op
      end select;
    end loop;
  end Ada_Task_Type_Class_task;

Ada_CG::Operation::TaskDefaultScheme property set to timed

In this case a delay statement can be generated just before task default implementation. It is defined in Ada_CG::Operation::TaskDefaultSchemeDelayStatement property.

task body Ada_Task_Type_Class_task is
  begin
    loop
      select
         accept my_entry_1;
      or
         accept my_entry_2 do
         end my_entry_2;
      or
         -- Ada_CG::Operation::TaskDefaultSchemeDelayStatement
         -- property  is set to: delay 1.0;
         Delay 1.0;
         -- 
         -- The Alt_Op has TaskDefaultAction stereotype
         implementation of Alt_Op
      end select;
    end loop;
  end Ada_Task_Type_Class_task;
User defined task body

Finally, if this template cannot match with user needs, then a last property exists in order to define manually all task body implementation.

If the Ada_CG::Class::TaskBody property is not empty, then all this template is replaced by the content of this property. It should contain the whole declaration of task body

 -- task body is defined manually into Ada_CG::Class::TaskBody property
  task body User_Defined_Ada_Task_Body_task is

  begin
    -- here is the implementation defined by the user
    . . .
  end User_Defined_Ada_Task_Body_task;

New Ada Tasks representation

This second part describes a new representation of Ada tasks in Rhapsody model.

user defined Task

User can define as many single tasks or task types as needed inside a class. The whole structure of the class and the tasks is defined in the model without using any properties. User is free to define task entries, task body structure, task pragmas or task type discriminants, by adding corresponding Rhapsody element in the task model.

A Task type is represented by a nested class which has stereotype AdaTaskType. This will generate a task type inside the class or package which contains this AdaTaskType class.

A single Task is represented by an implicit part or object which has the stereotype AdaSingleTask. This will generate a single task inside the class or the package which contains this AdaSingleTask part or object.

The name of AdaTaskType class or AdaSingleTask object will give the name of the Ada task.

In the sample model shown below, the "class_with_tasks" class contains two tasks:

The class has also two parts which define two instances of the Ada task type.

Task declaration

The declaration of the tasks is

  task single_task is
    entry My_Entry_1 ;
    entry My_Entry_2(aa : integer);
  end single_task;

  task type Task_1 is
    entry My_Entry_1;
  end Task_1;

  task_1_acc is access task_1;
Entries

Entries are defined with some usual operations.

Task body and task entries

The task body is represented by an operation with the stereotype TaskBody. This operation is mandatory. This operation is automatically created in the task type. Only one operation of this kind can be created. Only implementation of the operation will be used to define the task body.

In order to use user defined entries in task body, some macro can be added inside the TaskBody operation implementation in order to copy the code of entries. TaskBody operation should contain code like that

    loop
      select
         $accept(my_entry_1);
         $accept(my_entry_2);
      end select;
    end loop;

The possible macro is $accept(<operation_name>): it will generate the call of an accept statement

If the operation has an implementation, then it will generate

        accept <operation_signature> do
         <operation_implementation>
         end <operation_name>;

If the operation has NO implementation, then it will generate

        accept <operation_signature>;

The generated code will be

task body Task_1 is
  begin
    loop
      select
         accept my_entry_1 do
         -- my_entry_1 implementation
         end my_entry_1;
         accept my_entry_2(a : integer);
      end select;
    end loop;
end Task_1;
Task pragma

Some pragma can be defined on the task and on the task type.

They are defined as constraint with stereotype pragma.

The name of the constraint will give the name of the pragma.

The specification of the constraint will give the parameter of the pragma.

  task single_task is
    pragma priority (12);
    entry My_Entry_1 (this : in out Class_With_Task_t);
  end single_task;

  task type Task_1 is
    pragma priority (10);
    entry My_Entry_2 (this : in out Class_With_Task_t);
  end Task_1;

  task_1_acc is access task_1;
Task discriminants

Task type discriminants behave like usual class discriminants. They can be added by defining some Discriminant attributes on the AdaTaskType class.

In the example above, the pragma priority specification has been set to "priority", in order to get the value of the discriminant.

 task type Task_1 (priority : Integer) is
    pragma priority (priority);
    entry My_Entry_2 (this : in out Class_With_Task_t);
  end Task_1;
Instantiation of task type with discriminants

The discriminants must be setup during instantiation of the task type, like in the example above.

-- dynamic instantiation
My_task_instance_1 : my_task_acc_t := new my_task_t(priority => 10);

-- static instantiation
My_task_instance_2 : my_task_t(priority => 10);

The discriminant value can be defined in parts or global objects. If some values are defined at that level, they will be used to initialize discriminants. Parts or global objects are the only one Rhapsody elements which allow to specify values for discriminants. So it is recommended to instantiate task types by using parts of global objects.

Protected Objects

Protected objects are represented in Rhapsody by a class stereotyped as <<AdaProtectedObject>> or <<AdaProtectedType>> .  The result is the creation of an Ada package containing a protected type.  The <<AdaProtectedObject>> stereotype should be used for singleton tasks.

  Protected objects in Rhapsody.

For <<AdaProtectedObject>> and <<AdaProtectedType>> classes, the Ada_CG.Class.Visibility property has to be set to “Private”

  Setting the record type visibility to “Private” for an <<AdaProtectedType>> class

By default, all operations in the class do not represent entries. In order to generate a protected object entry, one has to apply the <<entry>> stereotype to an operation.

  Applying the <<entry>> stereotype to a protected object operation

By default, the guard for a protected entry will be set to true, however one can define its own guard by setting the “Ada_CG.Operation.EntryCondition” property to the appropriate boolean expression.

  Setting the guard for a protected object/type entry

--++ class Protected_Object_Class
package Protected_Object_Class is 

   type Protected_Object_Class_t is tagged limited private;
   type Protected_Object_Class_acc_t is access all Protected_Object_Class_t;

   --Public Functions/Procedures section ------------
   ----++ operation entry_default_guard()
   procedure entry_default_guard (this : in out Protected_Object_Class_t);

   ----++ operation regular_function()
   function regular_function (this : in Protected_Object_Class_t) return Integer;

   ----++ operation regular_operation()
   procedure regular_operation (this : in out Protected_Object_Class_t);

private

   --protected type declaration
   
   protected Protected_Object_Class_protected is
      entry entry_default_guard (this : in out Protected_Object_Class_t);
      procedure regular_operation (this : in out Protected_Object_Class_t);
      function regular_function (this : in Protected_Object_Class_t) return Integer;

   private

   end Protected_Object_Class_protected;

   type Protected_Object_Class_t is tagged limited null record;

end Protected_Object_Class;
	

Protected object specification.

--++ class Protected_Object_Class
package body Protected_Object_Class is 


   --Functions/Procedures section ------------
   procedure entry_default_guard (this : in out Protected_Object_Class_t) is
   begin
     Protected_Object_Class_protected.entry_default_guard (this);
   procedure entry_default_guard;

   procedure regular_operation (this : in out Protected_Object_Class_t) is
   begin
     Protected_Object_Class_protected.regular_operation (this);
   procedure regular_operation;

   function regular_function (this : in Protected_Object_Class_t) return Integer is
   begin
     Protected_Object_Class_protected.regular_function (this);
   procedure regular_function;
   
   --Protected Object/Type Implementation
   protected body Protected_Object_Class_protected is
      entry entry_default_guard (this : in out Protected_Object_Class_t) when true is
      begin
         null;
         --+[ operation entry_default_guard()
         
         --+]
      end entry_default_guard;
      
      procedure regular_operation (this : in out Protected_Object_Class_t) is
            --+[ operation regular_operation().Variables
         
            --+]
      begin
         null;
         --+[ operation regular_operation()
         
         --+]
      end regular_operation;
      
      function regular_function (this : in Protected_Object_Class_t) return Integer is
            --+[ operation regular_function().Variables
         
            --+]
      begin
         return 0;
         --+[ operation regular_function()
         
         --+]
      end regular_function;

   end Protected_Object_Class_protected;

end Protected_Object_Class;
	

Protected object body.

--++ class Protected_Type_Class
package Protected_Type_Class is 

   type Protected_Type_Class_t is tagged limited private;
   type Protected_Type_Class_acc_t is access all Protected_Type_Class_t;

   --Public Variables/Constants
   static_attribute : Integer; --++ attribute static_attribute

   --Public Functions/Procedures section ------------
   --++ operation entry_function()
   function entry_function (this : in Protected_Type_Class_t) return Integer;

   --++ operation entry_true_or_false()
   procedure entry_true_or_false (this : in out Protected_Type_Class_t);

   --Public Fields/Variables accessors ------------
   function get_attribute_0 (this : in Protected_Type_Class_t) return Integer;
      pragma  inline (get_attribute_0 );

   procedure set_attribute_0 (this : in out Protected_Type_Class_t; value : in Integer);
      pragma  inline (set_attribute_0 );

   function get_static_attribute (this : in Protected_Type_Class_t) return Integer;
      pragma  inline (get_static_attribute );

   procedure set_static_attribute (this : in out Protected_Type_Class_t; value : in Integer);
      pragma  inline (set_static_attribute );

   procedure Initialize (this : in out Protected_Type_Class_t);

   procedure Finalize (this : in out Protected_Type_Class_t);

private

   --protected type declaration
   
   protected Protected_Type_Class_protected is
   
      entry entry_true_or_false (this : in out Protected_Type_Class_t);
      function entry_function (this : in Protected_Type_Class_t) return Integer;
      function get_attribute_0 (this : in Protected_Type_Class_t) return Integer;
      procedure set_attribute_0 (this : in out Protected_Type_Class_t; value : in Integer);

   private

      -- Fields --
      attribute_0 : Integer; --++ attribute attribute_0

   end Protected_Type_Class_protected;

   type Protected_Type_Class_protected_acc is access Protected_Type_Class_protected;

   type Protected_Type_Class_t is tagged limited
   
   record
     my_Protected_Type_Class_protected : Protected_Type_Class_protected_acc;

   end record;

end Protected_Type_Class;
	

Protected type specification.

With UNCHECKED_DEALLOCATION;

--++ class Protected_Type_Class
package body Protected_Type_Class is 

   --Functions/Procedures section ------------
   procedure entry_true_or_false (this : in Protected_Type_Class_t) is
   begin
      this.my_Protected_Type_Class_protected.entry_true_or_false (this);
   end entry_true_or_false;

   --Fields/Variables accessors ------------
   function get_attribute_0 (this : in Protected_Type_Class_t) return Integer is
   begin
      return this.my_Protected_Type_Class_protected.get_attribute_0 (this);
   end get_attribute_0;

   procedure set_attribute_0 (this : in out Protected_Type_Class_t; value : in Integer) is
   begin
     this.my_Protected_Type_Class_protected.set_attribute_0 (this, value);
   end set_attribute_0;

   --Protected Object/Type Implementation
   protected body Protected_Type_Class_protected is
      entry entry_true_or_false (this : in out Protected_Type_Class_t) when true or false is
      begin
         null;
         --+[ operation entry_true_or_false()
         
         --+]
      end entry_true_or_false; 
      
      function get_attribute_0 (this : in Protected_Type_Class_t) return Integer is
      begin
         return attribute_0;
      end get_attribute_0; 

      procedure set_attribute_0 (this : in out Protected_Type_Class_t; value : in Integer) is
      begin
        attribute_0 := value;
      end set_attribute_0;

   end Protected_Type_Class_protected;

   procedure Initialize (this : in out Protected_Type_Class_t) is
   begin 
      this.my_Protected_Type_Class_protected := new Protected_Type_Class_protected;
   end Initialize; 

   procedure Finalize (this : in out Protected_Type_Class_t) is
      procedure FREE is new UNCHECKED_DEALLOCATION(
         Protected_Type_Class_protected,
         Protected_Type_Class_protected_acc
      );
   begin
      FREE(this.my_Protected_Type_Class_protected);
   end Finalize; 
   
end Protected_Type_Class;
	

Protected type body.

The protected type generates the constructor and destructor as well, which create the task instance and destroy it.

Entrypoints

An entrypoint can be created in Rhapsody to represent the starting point of the Ada program.  This is done by stereotyping a class as <<Entrypoint>> .

  An entrypoint in Rhapsody.

In addition, define an operation on the class, and enter the implementation of the operation to complete the entrypoint.  The result is a single package body file generated in myEntrypoint.adb.

Procedure myEntrypoint is
      --+[ operation main().Variables
      
      --+]
begin
   --+[ operation main()
   --entrypoint implementation
   --+]
end myEntrypoint;
         

The entrypoint definition.

In order to use only this user defined entrypoint (and not default entrypoint) in the model, the CG::Configuration::MainGenerationScheme property must set to "UserInitializationOnly".

Singleton Classes

Singleton classes represent classes that have only one instance.  This is represented in Rhapsody by stereotyping the class <<Singleton>> .  A singleton class creates a private variable to contain the singleton instance, and all non-static operations access this instance instead of passing in a ‘this’ parameter.

  A singleton class in Rhapsody.

Ada 95

When the singleton class is generated using the Ada 95 rules, the non-static attributes are held in a record in the same manner as a normal class.

--++ class My_Singleton
package My_Singleton is 

   type My_Singleton_t;
   type My_Singleton_acc_t is access all My_Singleton_t;

   type My_Singleton_t is tagged limited 
   
   record;

   -- Fields --
      my_Int : Integer;  --++ attribute my_Int
   
   end record;

   --Public Variables/Constants
   my_Static_Int : Integer; --++ attribute my_Static_Int

   --Public Functions/Procedures section ------------
   --++ operation my_Operation()
   procedure my_Operation;

   --++ operation my_Static_Operation()
   procedure my_Static_Operation;

   --Public Fields/Variables accessors ------------
   function get_my_Int return Integer;
      pragma  inline (get_my_Int);

   procedure set_my_Int (value : in Integer);
      pragma  inline (set_my_Int);

   function get_my_Static_Int return Integer;
      pragma  inline (get_my_Static_Int);

   procedure set_my_Static_Int (value : in Integer);
      pragma  inline (set_my_Static_Int);

private

end My_Singleton;
	

The package specification for a singleton class in Ada 95.

--++ class My_Singleton
package body My_Singleton is 

   -- Singleton storage
   My_Singleton_unique_instance : aliased My_Singleton_t;

   -- short names for singleton attributes
  
   attribute_0 : Integer renames My_Singleton_unique_instance.attribute_0;

   --Functions/Procedures section ------------
   procedure my_Operation is 
         --+[ operation my_Operation().Variables
   
         --+]
   begin
      null; 
      --+[ operation my_Operation()
   
      --+]
   end my_Operation;

   procedure my_Static_Operation is 
         --+[ operation my_Static_Operation().Variables
   
         --+]
   begin
      null; 
      --+[ operation my_Static_Operation()
   
      --+]
   end my_Static_Operation;
   
   --Fields/Variables accessors ----------------
   function get_my_Int return Integer is
   begin
     return My_Singleton_unique_instance.my_Int;
   end get_my_Int;

   procedure set_my_Int (value : in Integer) is
   begin 
     My_Singleton_unique_instance.my_Int := value;
   end set_my_Int;

   function get_my_Static_Int return Integer is
   begin
     return My_Singleton_unique_instance.my_Static_Int;
   end get_my_Static_Int;
   
   procedure set_my_Static_Int (value : in Integer) is
   begin
     My_Singleton_unique_instance.my_Static_Int := value;
   end set_my_Static_Int;

private

end My_Singleton;
	

The package body for a singleton class in Ada 95.

Ada 83

Changing the “DefaultComponent” component to be an Ada 83 package changes the generation of the singleton class so that the rules for Ada 83 are followed.  In this case, all attributes are considered static attributes and a record type is not created for the class nor is a variable for the singleton instance created in the package body.

  Changing the component to generate Ada 83 code.

--++ class My_Singleton
package My_Singleton is 

   my_Int : Integer;  --++ attribute my_Int

   --Public Variables/Constants
   my_Static_Int : Integer; --++ attribute my_Static_Int

   --Public Functions/Procedures section ------------
   --++ operation my_Operation()
   procedure my_Operation;

   --++ operation my_Static_Operation()
   procedure my_Static_Operation;

   --Public Fields/Variables accessors ------------
   function get_my_Int return Integer;
      pragma  inline (get_my_Int);

   procedure set_my_Int (value : in Integer);
      pragma  inline (set_my_Int);

   function get_my_Static_Int return Integer;
      pragma  inline (get_my_Static_Int);

   procedure set_my_Static_Int (value : in Integer);
      pragma  inline (set_my_Static_Int);

private

end My_Singleton;
	

The package specification for a singleton class in Ada 83.

--++ class My_Singleton
package body My_Singleton is 

   --Functions/Procedures section ------------
   procedure my_Operation is 
         --+[ operation my_Operation().Variables
   
         --+]
   begin
      null; 
      --+[ operation my_Operation()
   
      --+]
   end my_Operation;

   procedure my_Static_Operation is 
         --+[ operation my_Static_Operation().Variables
   
         --+]
   begin
      null; 
      --+[ operation my_Static_Operation()
   
      --+]
   end my_Static_Operation;
   
   --Fields/Variables accessors ----------------
   function get_my_Int return Integer is
   begin
     return my_Int;
   end get_my_Int;

   procedure set_my_Int (value : in Integer) is
   begin 
     my_Int := value;
   end set_my_Int;

   function get_my_Static_Int return Integer is
   begin
     return my_Static_Int;
   end get_my_Static_Int;
   
   procedure set_my_Static_Int (value : in Integer) is
   begin
     my_Static_Int := value;
   end set_my_Static_Int;

private

end My_Singleton;
	

The package body for a singleton class in Ada 83.

Relations

Relations may need the use of containers, depending of their kind. Usually, the used containers are Booch Components. This container is not provided any more with Rhapsody Developer for Ada. The code generator provides the possiblity to choose any kind of containers. This is selected with the property "Ada_CG.Configuration.ContainerSet". This property can take the following values:

In the documentation we will identify the default container by "old implementation", and Ada2005container by "custom container". "custom container" can be modified or created by user, by using properties. This allows a very flexible implementation of containers.

The two next paragraphs describes old implementation, and the next one descibes the representation, and customization of custom containers.

Unidirectional Relations

This paragraph describes old implementation of unidirection relations. If you need to use a custom container, refer also to "custom container".

There are three different options for the implementation of relations.  Each implementation creates an Ada record field and accessor(s) and mutator(s) methods and possibly some new types and inner packages to support the implementation.  The name of the Ada record field is the name of the role for the relation.

The implementation kind is controled by the property "CG.Relation.Implementation".

Default implementation :  The default implementation uses an access type for the target object.  The access type is held in an Ada record field.  In addition, a “With” statement is added for the target package so that the access type is visible.

Fixed implementation :  The fixed implementation uses a direct reference to the target object.  The target object type is held in an Ada record field.  As with the “Default” implementation, a “With” statement is added for the target package so that the target type is visible.

Scalar implementation :  The scalar implementation is better described as the index implementation. Instead of holding a direct reference to either the target type or an access to the target type, a numerical index is used instead.  The intent is that there will be a container object in the system that will hold the instances of the target class, and that the index is used to retrieve the correct instance from the collection.  In this case, a “With” statement is not created for the target package because only an index is stored in the class, and not a reference to the target object itself.  Instead, a new type is created to represent the valid range for the indexBi-directional relations are not supported at this time, nor are unbounded multiplicities.

Multiplicity = 1

When the multiplicity = 1, the class will have a reference to only one instance of the target class.  The following example demonstrates the generated code for each of the implementation types.  Note that no accessors are generated for the “Fixed” implementation.

  Class relations with multiplicity = 1.

Multiplicity > 1, general notes

When the multiplicity is greater than 1, the same basic concepts are followed for each implementation choice, except some data structures are created to hold the instances.  In addition, new types are defined to represent the valid indices into such structures, and iterator subpackages are declared for every relation..

Unbounded relations and qualified relations (both bounded and unbounded) use data structures that rely on the Booch components.

 

Generated Method

Relation type

Bounded

Unbounded

Bounded Qualified

Unbounded Qualified

Get_At_Pos (Procedure)

Y

Y

   

Get_At_Pos (Function)

Y

Y

   

Contains

Y

Y

   

Get_Count

Y

Y

Y

Y

Set_At_Pos

Y

Y

   

Add_At_Pos

N

Y

   

Remove

N

Y

   

Remove_At_Pos

N

Y

   

Get(Key) (Procedure)

   

Y

Y

Get(Key) (Function)

       

Contains(Key)

   

Y

Y

Set(Key)

   

Y

Y

Remove(Key)

   

Y

Y

Table 2 Nary relations methods matrix

Method Name

Description

Initialize

Creates the iterator

Get_Next

Gets next element

To_Value

Get value associated to current iterator position

Is_Last

Return true if there’s no more elements to iterate over.

Table 3 Nary relations Iterator package method description

Details on the Booch components

Rhapsody Developer for Ada does not install Booch Components files. If needed, user must do it manually by following the procedure. See section Installation notes: Booch components .

Either the original Ada 83 version of the components can be used, or the Ada 95 version.  The choice is made at the component level with the Ada_CG.Component.UseBoochComponents property.

Although only part of it is used. Here is the list of packages that may be with’ed by the generated code when using Ada 83:

  1. semaphore
  2. storage_manager_concurrent
  3. list_single_unbounded_controlled
  4. list_utilities_single
  5. list_search
  6. map_simple_noncached_concurrent_bounded_managed_noniterator
  7. map_simple_noncached_concurrent_unbounded_managed_noniterator

 

Bounded

Unbounded

Unqualified relations

None

1,2,3,4,5

Qualified relations

1,6

1,2,7

Table 4 Booch 83 Components Package Dependency Matrix

Here is the list of packages that may be with’ed by the generated code when using Ada 95:

  1. BC.Support.Standard_Storage
  2. BC.Containers.Collections.Unbounded
  3. BC.Containers.Maps.Unbounded
  4. BC.Containers.Maps.Bounded

 

Bounded

Unbounded

Unqualified relations

None

1,2

Qualified relations

4

1,3

Table 5 Booch 95 Components Package Dependency Matrix

Multiplicity > 1 , bounded

An array is created to hold the instances

  Class relations with multiplicity > 1, bounded.

Multiplicity > 1, unbounded

Unbounded relations are no longer represented as arrays of 100 elements, but as data structures relying on dynamic memory allocation.

Important note : Any legacy code using unbounded relations relying on the fact that the underlying implementation is an array of 100 elements MUST be updated, as it will either not compile or potentially lead to run-time errors.

Multiplicity > 1, qualified relations

Qualified relations are represented with maps. The unbounded form relies on dynamic memory allocation.

A qualified relation is a key based association. This means that if there is an association from A to B, where the qualifier is an attribute B.id of type Integer, the relation is key based (in this case, Integer is the key type).

Only one element can be bound for each value of the qualifier domain.

Adding an element with a key that already exists has the effect of replacing the old element with the new one.

Note : only attributes of a type that is a subtype of Integer can be used as Qualifiers.

Note : with booch 95 components, if the type of the key is a subtype of integer (or any standard type) which is defined in an other package, then user must define a new “=” function in this other package.

For example, a new subtype of integer is defined into User_Type package.

User must define a new “=” function into this package.

package User_Type is
       subtype My_Subtype_Integer is Integer range 1..1000;
       function "=" (A : in My_Subtype_Integer; B : in My_Subtype_Integer)
       return Boolean;
    private
    end User_Type;  
     
    package body User_Type is
      function "=" ( A : in My_Subtype_Integer; B : in My_Subtype_Integer )
      return Boolean is
      begin
        return standard."="(A, B);
      end "=";
    end User_Type;

Bidirectional Relations

Rhapsody Developer for Ada provides two implementations for bidirectional relations. By setting the Ada_CG.Relation.BidirectionalRelationsScheme to SubtypingAndRenaming (selected by default) or IntermediateParentClasses, it is possible to select which one is to be used.

SubtypingAndRenaming scheme

Implementation principles

This implementation supports bidirectional relations via the following mechanisms:

Limitations

Note that there are limitations applicable to classes participating in bidirectional relations using that scheme which are described hereafter:

IntermediateParentClasses scheme

Implementation principles

This scheme supports bidirectional relations via the following mechanisms:

Using

Example:

Classes class_1 and class_2 have bidirectional relation.

If class_2 wants to get instance of "itsclass_1", then the following accessor should be used:

get_downcast_itsClass_1 (this : in class_2_t)

Limitations

Most of the limitations of the SubtypingAndRenaming scheme are no longer relevant with this implementation. However there are still a few remaining limitations:

Custom Containers

This paragraph will explain how to use and configure custom containers.

Choice of container set

Container set is selected by using the property "Ada_CG.Configuration.ContainerSet". Two kind of container set are provided

If user needs it, he can define himself its own container, by creating new properties. This will be explained below.

Choice of container's implementation

Container's implementation is chosen by using the property "CG.Relation.Implementation". The values are:

If default value is used, the code generator will choose himself the implementation, depending of he kind of relation and its multipicity.

multiplicity

qualified relation

implementation

1..n

no

staticArray

1..n

yes

BoundedQualified

1..*

no

Unbounded

1..*

yes

UnboundedQualified

User has the possiblity to define other kind of implementation, if the provided ones are not suitable. The way to do it is explained below.

Choice of element's kind inside the container

The type of the element stored inside the container, can be controled with the property "Ada_CG.Relation.AccessTypeUsage". This property can take the following values:

Build a new container set

User has the possibility to modify or create generated code for containers. This paragraph will explain in details all the steps to create a new container set

Create siteAda.prp file

The container's description is done inside sodius.prp file. If some new properties need to be modified or created, a new file "siteAda.prp" must be created. This new file will be automatically recognized, when the model is loaded.

Create a new container

In this example, we will create a new container set. Its name will be "NewContainers". The property "Ada_CG.Configuration.ContainerSet" must be updated in order to be able to select this new container, and a new subject is create to describe the container. The following text should be added in the file:

Subject Ada_CG
   Metaclass Configuration  
      Property ContainerSet Enum "Default, Ada2005Containers, NewContainers" "Default"
   end 
end

Subject NewContainers

	   ...

end

The "NewContainers" subject should contain some metaclass who are described below

Create a General metaclass

The General metclass contains some properties which are used to generate make files. The name of these properties respect a naming rule, in order to fit many situation. The name is constructed like that:

<environement_name>CompilerInclude[<implementation_name>]

The implementation name is optional. In this case, the content of this property will be added in makefile for any kind of implementation. If the implementation name is added, then this code is added depending on implementation kind.

Here is an example of values of these properties for GNAT compiler and ObjectAda compiler, for Booch components.

Subject NewContainers
	metaclass General
		Property GnatCompilerInclude String "-aI%OMROOT%\\LangAda95\\booch_ada_95\\src\\"
		Property ObjectAdaCompilerIncludeBounded String ""
		Property ObjectAdaCompilerIncludeUnbounded String "adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-standard_storage.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-unbounded.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-unbounded.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-collections.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-collections.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-collections-unbounded.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-collections-unbounded.adb
"
		Property ObjectAdaCompilerIncludeBoundedQualified String "adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps-bounded.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps-bounded.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-hash_tables.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-hash_tables.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-bounded_hash_tables.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-bounded_hash_tables.adb
"
		Property ObjectAdaCompilerIncludeUnboundedQualified String "adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-standard_storage.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-unbounded.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-support-unbounded.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps.adb
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps-unbounded.ads
adareg %OMROOT%\\LangAda95\\booch_ada_95\\src\\bc-containers-maps-unbounded.adb
"
	end

end

Create implementation

The minimum list of implementations is

The siteAda.prp file must contains this code

Subject NewContainers
	metaclass General
		Property GnatCompilerInclude String ""
		Property ObjectAdaCompilerIncludeBounded String ""
		Property ObjectAdaCompilerIncludeUnbounded String ""
		Property ObjectAdaCompilerIncludeBoundedQualified String ""
		Property ObjectAdaCompilerIncludeUnboundedQualified String ""
	end
	metaclass StaticArray 
	   ...
	end
	metaclass Bounded
	   ...
	end
	metaclass Unbounded
	   ...
	end
	metaclass BoundedQualified
	   ...
	end
	metaclass UnboundedQualified
	   ...
	end
end

For each metaclass, a list of properties must be defined in order to specify which code needs to be generated.

If needed, user can define other kind of implementation. For that, a new metaclass needs to be created with the name of the new implementation. The property "CG.Relation.Implementation" will have to be updated with this new implementation. The property must be copied from sodius.prp to siteAda.prp, and updated with the new implementation name

Subject CG
	Metaclass Relation
		Property Implementation Enum "Default,...,NewImplementation" "Default" 
	end
end
Subject NewContainers
	metaclass General
		Property GnatCompilerInclude String ""
		Property ObjectAdaCompilerIncludeBounded String ""
		Property ObjectAdaCompilerIncludeUnbounded String ""
		Property ObjectAdaCompilerIncludeBoundedQualified String ""
		Property ObjectAdaCompilerIncludeUnboundedQualified String ""
	end
	metaclass StaticArray 
	   ...
	end
	metaclass Bounded
	   ...
	end
	metaclass Unbounded
	   ...
	end
	metaclass BoundedQualified
	   ...
	end
	metaclass UnboundedQualified
	   ...
	end
	metaclass NewImplementation
	   ...
	end
end

Create implementation's code

For each metaclass, a set of properties will define the code to be generated. The text of the properties will be copied inside the generated code. The text can contain some macro which will be executed, and replaced by the result of their execution.

Their are properties for different parts of the code.

Subject NewContainers
	   ...
	metaclass Bounded
		Property WithClauseInSpec MultiLine ""
		Property WithClauseInBody MultiLine ""
		Property TypeDeclaration MultiLine ""
		Property TypeDeclarationAfterRecordType MultiLine ""
		Property TypeDeclarationInBody MultiLine ""
		Property RelationType String ""
		Property IndexType String ""
		Property GetAtPosProcedure MultiLine ""
		Property GetAtPosFunction MultiLine ""
		Property Contains MultiLine ""
		Property GetCount MultiLine ""
		Property Set MultiLine ""
		Property Add MultiLine ""
		Property AddAtPos MultiLine ""
		Property Remove MultiLine ""
		Property RemoveAtPos MultiLine ""
	end
	   ...
end

It is possible that implementation of an operation changes, depending on "accessTypeUsage" defined in property "Ada_CG.Relation.AccessTypeUsage". In this case it is possible to create another property which specifies the accessTypeUsage. For that the value of the accessTypeUsage must be added to the name of the property. The possible use cases are:

If the property is not present or is empty, the operation will not be generated.

The signature of the operations are autogenerated. User can control

In order to generate code for any relation in the model, some macro must be inserted in the text of the properties. Any valid rule can be used. The name of the macro must start with "$" or must be enclosed by double bracket "[[" "]]".

Property TypeDeclaration MultiLine "type [[Name]]_card_t is new Positive range 1..$Multiplicity_Upperbound;
package [[Name]]_Unbounded_list is new Ada.Containers.Vectors([[Name]]_card_t, $ADA_Relation_Target_Element_Type_Name, \"=\" => $ADA_Relation_Target_Class_Full_Name.\"=\");"
	

macro

description

Name

Gives the name of the relation

   itsClass_2

ADA_Relation_Target_Element_Type_Name

gives the type of the target. The result depends on the value of the property "Ada_CG.Relation.AccessTypeUsage"

   Package_0.class_2.class_2_acc_t

ADA_Relation_Target_Class_Full_Name

gives the full name of the target

   Package_0.class_2

ADA_Relation_Qualifier_Full_Regular_Type_Name

Gives the full regular name of the type of the qualifier of the relation

ADA_This_As_Formal_Parameter_In_List_Mode_In

Gives the this parameter to be generated, when an operation is declared in "TypeDeclaration"

   this : in class_1_t

ADA_Relation_Target_Name

Gives the name of the relation

   itsClass_2

ADA_Relation_Target_Collection_Name

Gives the target collection name to be set to call an operation of this target.

   this.itsClass_2

Ports

Limitations

Note that there are limitations applicable to usage of ports which are described hereafter:

Using ports

RiA generates code for ports in classes and for linking instances via ports.

When a class has ports, the code generator will create an additional Ada package called <class>_port. This Ada package contains all the material to declare the class’s ports. The class contains a part of this <class>_port type.

Some functions are added in order to send some messages through ports.

Get_<Port_Name>(this : class_type) : return port_type

This function gets the instance of the port we need.

<message>(this: class_type, port : port_type)

This function sends the message “message” through the port “port” of the class “this”. One function is created for each message defined in the port’s interface. The usual way to send a message is to write:

<message>(this, Get_<Port_Name>(this));

If some parameters need to be passed with the message, then they are added after the port’s instance:

<message>(this, Get_<Port_Name>(this), param : param_type);

The procedure is the same when you want to send an event through a port. Use the gen event function with port’s name:

Gen_<event_name>(this, Get_<Port_Name>(this));

When an event is received from a port, it is possible to know which port received it. It is done with the function Is_Port of class Oxf.I_Event. Its signature is:

oxf.I_Event.is_port(event : oxf.I_event_t, port_ID : System.address)

The port_ID is given by the address of the port. You must get it like that:

<port_name>.Get_Inbound(Get_<port_name>('this)).Port_ID

Example 1 : behavioral port

Create a new model with 2 classes Class_0 and Class_1 which are parts of a class Build.

Create an interface interface_1 with one operation “message_0”.

Create port “Port_0” on Class_0.

Open features window of this port. Check behavioral check button, and add a provided interface in contract tab.

Copy this port in Class_1.

Open features window of this new port. Check reversed check button

Create a link between ports of the two classes.

Add an operation message_0() in class_0. Its implementation must be:

put_line("class_0 : message_0()");

Add an operation test() in class_1. Its implementation must be:

put_line("Class_1 : test()");
message_0(this,get_port_0(this));

Add an put_line() in class Build. Its implementation must be:

put_line("Build : test()");
class_1.test(this.itsClass_1.all)

Add a with and use clause for Ada.text_IO in all classes.

In configuration features, initialize the Build class in Initialization tab, and implement initialization code with:

Build.test(p_Build.all);

You should get a model like this one:

       

In this model test() function of class_1 will send message “message_0” through its port port_0.

Example 2 : fast ports

Take the model created below.

Set Ada_CG:Component:AdaVersion Property to Ada05 in oder to build the model for Ada 2005.

In Class_0, Add a statechart with 2 states and one event “a” between the 2 states

In Class_1, Add a statechart with 2 states and one event “b” between the 2 states

Remove the contract of the 2 ports

Change the implementation of class_1.test():

gen_event(this, Default.get_a, get_port_0(this));

To send an event through a fast port you must use the function Gen_Event. Its signature is:

gen_event(this: class type, event : Oxf.Event.Event_acc_t, port : port_type);

The event must be created with the function defined in the event’s package. Its name is:

<event package>.get_<event_name>

Multicast ports

This feature allows sending a message through one port to several ports in a single operation. It uses Booch components 95 in order to create an unbounded list of interfaces. Booch components are not provided with Rhapsody install. They must be installed manually if needed. (See Installation notes: Booch components   for more information.)

Multicast generation is controlled by the property

ADA_CG::Port::Support Multicasting

This property has the following values

          Never : multicast instrumentation is never used

          Smart : multicast instrumentation is used only if needed (see algorithm below)

          Always : multicast instrumentation is always generated

Sending a multicast message

Sending a message to a port will automatically send it to all connected interfaces. The syntax is the same than with a single interface.

Example

The port Port_0 of an instance of class Class_0 is linked to several ports of instances of various other classes( which have the same interface as port_0)

To send a message “message” through Port_0 of class_0 you must write:

message(this, get_port_0(this));

A message can be a procedure, an event or a triggered operation. Functions cannot be sent through multicast ports.

Fast ports also support multicast.

Link initialization with multiplicity

Multicast can be automatically initialized only if required and provided interface of the link belongs to class instance of multiplicity 1 and if its port has also multiplicity 1. In this case there is no ambiguity for initializing the links. Multiplicity of both ends of the link must be equal to 1.

Multiplicity equals 1 in both ends of the link (in this case multicast is not useful)

There are several instances of a class with provided interface.

Other operations on multicast ports

Some other operations can be done on a multicast Port in order to control the links between ports.

A provided interface can be disconnected from required interface. The following procedure does this.

Remove_<interface_name>(this : port_type, interface : interface_type);

Example:

declare      
	currentSourcePort   : microphone_port.port_0.port_type;      
	currentTargetPort   : loudspeaker_port.port_0.port_type;    
begin      
	currentSourcePort := microphone.get_port_0(this.itsMicrophone_0.all);      
	currentTargetPort := loudspeaker.get_port_0(this.itsLoudspeaker_0.all);     
      
	microphone_port.port_0.remove_Interface_9 (                 
						currentSourcePort,                 
						loudspeaker_port.port_0.get_Interface_9(currentTargetPort)               
						);    
end;

To add a new link to port, you just need to set port interface as usual.

Example:

declare
	currentSourcePort : microphone_port.port_0.port_type;
	currentTargetPort : loudspeaker_port.port_0.port_type;
begin
	currentSourcePort := microphone.get_port_0(this.itsMicrophone_0.all);
	currentTargetPort := loudspeaker.get_port_0(this.itsLoudspeaker_0.all);

	microphone_port.port_0.set_Interface_9 (
						currentSourcePort,
						loudspeaker_port.port_0.get_Interface_9(currentTargetPort)
						);
end;

It is possible to send a message to only one link. A message “Message” can be sent to only one provided interface:

Message(this : class_type, port : port_type, interface : interface_type);

Variation Points

Variation points and there variants can be created like in CPP.

If no variant is selected at component level, for a specific variation point, then the variation point will be generated as if it is a usual class.

If a variant is selected then a package which defines a renamed package is generated for this variation point.

with Screen_HDMI;

package display renames Screen_HDMI;

The files generated for the variant will be generated from the variant class. The Ada package name will be the name of the variant class. The name of the class types will be the name of the variation point class.

--++ class Screen_HDMI
package Screen_HDMI is

  type display_t;
  type display_acc_t is access all display_t;

  type display_t is tagged null record;

  --Public Functions/Procedures section --------
  --++ operation println(String)
  procedure println (this : in out display_t;
    text : in String
  );


private


end Screen_HDMI;

Active Variation Points in SXF mode

If you are in SXF mode, then you must take care when you create active variants. The process to create active variants is a little bit complex. See the process here or here in "Simplified Execution Framework" document.

Static Generalization

Static generalization is represented by a generalization which has the stereotype “Static“.

In this case all the elements of the parent class (type, attributes, operation, etc...) will be generated in the child class.

In the example above, the Ada package of the class Child_1 will declare the following operations:

Pragma

There are many possibilities to generate pragmas, depending on which kind of pragma we want to generate, and where we want to generate it. This chapter makes the list of all possibilities, and proposes a generic method to generate any kind of pragma.

Elaboration Pragmas

Some tags enable setting ElaborateBody, Preelaborate and Pure pragmas on classes or on packages. The use of these pragmas are described here and here.

Pragmas on class and package

Some properties allow setting some user defined pragmas in particular places in spec files or body files of classes or packages. These properties are described here.

Some additional tags on class, enable generating pragma atomic and pragma volatile for the class record type.

Pragmas on Ada task

For classes which have the stereotype D_AdaTaskType, some properties allow setting pragma Priority or pragma Storage_Size. This is described here.

Pragmas on user defined Ada task

For user defined task (class with stereotype "AdaTaskType), a constraint with "pragma" stereotype can be defined. This is described here.

pragma on static attribute

Some tags defined on attribute, can be checked to define:

Some accessor and mutator can be automaically generated for attributes. Some properties defined on attribute, allow generating pragma inline on these accessor and mutator.

pragma on type

Some tags defined on type, can be checked to define:

pragma on operation

A pragma inline can be generated if the check box "inline" is checked in general tab of operation feature.

generic pragma

If you need to generate other not predefined pragma, another generic representation can be used. A pragma is represented by a constraint with "pragma" stereotype. This pragma can be added on several Rhapsody elements.

To add a pragma to an element, in the browser, right click on the element, and in the menu, select Add New>AdaCodeGenegration>pragma.

  Creating a pragma on a variable.

The pragma identifier is set by the Rhapsody pragma name.

The pragma parameter is set in the Rhasopdy pragma specification. It is possible to add some macro which will be replaced by some other text.

  Setting the pragma features.

The generated code for this pragma defined above will be:

    variable_0 : integer;
    pragma atomic(variable_0);

The pragma is generated after attribute, type and operation declaration. Pragmas defined on class and package can be generated at several places. The place where the pragma is generated is controled by two tags.

In some cases, we should need to generated the pragma for some configuration, and not for an other configuration. The choice of the configurations for which the pragmas must be generated is done with a dependency from the pragma to the configuration. The policy is the following:

Ada Libraries

Creating an Ada Library

An Ada library can be created from a project by setting the “Library” option on the component.

  Setting the Component to Create a Library.

When the project is built, a library will be created in the directory specified by the configuration using the naming conventions described in the table below.

Compiler(s)

Library naming convention

GNAT

Lib<ComponentName>.a

ObjectAda / Win32

<ComponentName>.lib

ObjectAda / Raven

N/A

Table 6 Compilers library naming conventions

Linking an Ada Library

To use an Ada library from another project, two pieces of information are required in the component properties.  The first is the name of the library to use.  This name depends on the compiler you are using, the syntax is described in the previous table.  This name is put in the “Libraries” field.  If there is more than one library to list, place a carriage return between the names.

  Using an Ada Library.

The location of the libraries also needs to be specified.  The “Include Path” field is used to capture this information.  The location of the library as well as the location of the sources for the library must be included.  If there is more than one path to enter a carriage return should be used as a separator.

Configuration of Main File Generation

If the property “CG.Configuration.MainGenerationScheme” is set to “Full” on the configuration being generated, an entrypoint will automatically be created.  The entrypoint will be named main<Component Name>.adb, and will produce an executable called <Component Name>.exe.  This entrypoint will overwrite the output from any user-created entrypoint in the model.

  Configuration Instances.

With Clauses

A “With” Clause will be created for every class selected.

Configuration Prolog

The contents of the “Ada_CG.Configuration.ImplementationProlog” property on the configuration will appear just after the “With” clauses.  It can be used to “With” other classes or packages as needed.

Instance Creation

If the selected class is not a singleton, a variable will be created to hold an access to the type of the class, and initialized with a new instance.  If the class implements an Initialize procedure, the new instance will be initialized as well.  If the class is a singleton and implements the Initialize procedure, the procedure will be called on the class.

RiADefaultActive Initialization

If there is a reactive class in the model that requires the RiADefaultActive class, the RiADefaultActive class will be initialized.

Reactive Instance Hookup

If there is both an instance of a reactive class, and an instance of the active context for this reactive class, the reactive instance will be registered on the active instance.  If the reactive instance uses the RiADefaultActive class, this registration will be done as well.

Start Behavior

The RiADefaultActive class will be started if needed

As for the configuration initial instances, the Ada_CG.Relation.ObjectInitialization (Creation, Full, None) configuration property controls their initial behavior. By default it is set to “Full”, which means instances will be initialized and their behavior will be started.  If the user would like the behavior not to be started, “Creation” should be selected.

User defined local variables

Variables declared in the “Ada_CG.Configuration.LocalVariablesDeclaration” property will appear in the declaration of the entrypoint.

User Initialization Code

Any code entered in the “Initialization Code” field on the configuration will be inserted into the entrypoint.

Configuration Epilog

The contents of the “Ada_CG.Configuration.ImplementationEpilog” property on the configuration will appear just after the “end MainDefaultComponent;” line.

with RiA_Default_Active;
with class_0;
with class_1;

procedure  MainDefaultComponent is 
    start_behavior_status : Boolean;
    p_class_0 : class_0.class_0_acc_t;
    p_class_1 : class_1.class_1_acc_t;
begin 
    -- Instance Initialization 
    RiA_Default_Active.Initialize;
    p_class_0 := new  class_0.class_0_t;
    class_0.Initialize(p_class_0.all );
    p_class_1 := new  class_1.class_1_t;
    
    -- register Reactive Classes 
    RiA_Default_Active.register_context_class_0(p_class_0.all);
    
    -- Start Behavior 
    RiA_Default_Active.start;
    class_0.start_behavior(p_class_0.all , start_behavior_status);
    
    -- Initialize Package Instances
    
    -- User Initialization Code
    -- Your Configuration Initialization Code 
    
end  MainDefaultComponent;
	

  Auto-generated Entrypoint.

The generated entrypoint can be viewed by selecting “Edit Configuration Main File” from the Configuration.

If animation is turned on, these instances will NOT be animated.

Instances Defined on a Package

Package Modifications

A child package will be created to handle the creation and initialization of any instances defined in a package.   The name of the package will be <<Ada Package Name>>.RiA_Instances, where <<Ada Package Name >> is the name of the package where the instances are defined.  When generating Ada83, the package name will be <<Ada Package Name>>_Instances.  Each instance defined in the UML package will create global variables in this generated Ada package.

  Global Instances on a Package.

  Global Instance with Mulitplicity = 1.

  Global Instance with Multiplicity > 1.

Variables will be created in the public part of the package specification for each instance defined.  The type of variable will depend on the setting of the “CG.Relation.Implementation” property for each of the relations.  If the instance is a singleton, no variable will be created.  If the multiplicity is greater than 1 but not *, an array with be used of the given size.  If the multiplicity is given as *, an array will be generated of size 100.  The elements in this array will not be initialized.

The appropriate “With” statements will be added to the package specification for each Class instantiated.

These instances will be created in the procedure Initialize_Relations , and they will be initialized if an Initialize operation exists for their class.

Likewise, these instances will be finalized in the procedure Finalize_Relations  if a Finalize operation exists for their class.

If the instances have a statechart, the start_behavior procedure will be called to start the behaviors of the instances in the Initialize_Relations procedure.  The instances will be hooked up to their active context if needed as well.  If the instances are active, they will be started by calling the start procedure.

with MyPackage.class_0;
with MyPackage.class_1;

package  MyPackage.RiA_Instances is

    -- Instance Declarations
    itsClass_0 : MyPackage.class_0.class_0_acc_t;
    
    type itsClass_1_card_t is new positive range 1..10;
    type itsClass_1_acc_lst_t is array(itsClass_1_card_t) of MyPackage.class_1.class_1_acc_t;
    itsClass_1 : itsClass_1_acc_lst_t;
    
    procedure Initialize_Relations;
    procedure Finalize_Relations;
    
end MyPackage.RiA_Instances;

  The Instances Package Specification.

with RiA_Default_Active;

package body MyPackage.RiA_Instances is

    procedure Initialize_Relations is
      start_behavior_status : Boolean;
    begin
      -- Create the global instances
      itsClass_0 := new MyPackage.class_0.class_0_t;
      MyPackage.class_0.initialize(itsClass_0.all);
      for i in itsClass_1_card_t loop
        itsClass_1(i) := new MyPackage.class_1.class_1_t;
      end loop;
      
      -- Register the contexts
      RiA_Default_Active.register_context_class_0(itsClass_0.all);
      
      -- Start Behavior
      MyPackage.class_0.start_behavior(itClass_0.all, start_behavior_status);
      
      -- Hookup instances
      
      -- Ensure tat there is at least one statement
      null;
    end Initialize_Relations;
    
    procedure Finalize_Relations is
    begin
      MyPackage.class_0.Finalize(itsClass_0.all);
      
    end Finalize_Relations;
    
end MyPackage.RiA_Instances;
      

  The Instances Package Body.

If a link is created between the instances, the relation will be initialized as well in the Initialize_Relations procedure.

Only the Initialize_Relations procedure will be called from the auto-generated entrypoint.

Instance type

In object feature window, it is possible to define the object type. There are three different ways to define this type:

User-Defined header and footers

Available properties

By modifying the following properties on the project, component, configuration, package or class level the user can get Rhapsody to use custom headers and footers instead of the default ones for generated files.

  Defining custom header and footer at the component level

The usual Rhapsody inheritance rules apply for these properties, which means that you can refine your settings from the project level all the way down to the class.

These four properties are independent, which means that you can use a single project level setting for say the specification header and have different configuration level settings for the implementation header.

Those properties can also be updated at class level or at operation level (for separate operation). This can be useful to set change history log for example.

If the value of a keyword is a MultiLine, each new line (except the first one) starts with the value of the ADA_CG::Configuration::DescriptionBeginLine property; each line ends with the value of the ADA_CG::Configuration::DescriptionEndLine property.

Keyword substitution

Keyword based substitution is supported inside of these headers and footers.

The following keywords are supported:

Note the following:

Keyword names can be written in parentheses. For example:

.

  Inserting keywords inside user-defined header and footer

--++ package default
-- Component level Specification Header 1
-- sodius InheritedSetings DefaultComponent 6.0 Sodius
-- Component level Specification Header 2

--++ class class_0
package class_0 is

    type class_0_t;
    type class_0_acc_t is access all class_0_t;
	
    type class_0_t is tagged null record;
	
private

end class_0;
-- Component level Sepcification Footer 1
-- Component level Sepcification Footer 2
	

  Example of generated code using user-defined header and footer

Script Evaluation

It is also possible to put script names inside of headers and footers so that they get evaluated at code generation time.

The name has to be framed following this convention [[scriptName]].

The script has to be applicable for the model element for which the header is being evaluated, otherwise an error message will be displayed.

Custom Makefiles

Introduction

Makefiles are usually generated by the Ada code generator. However they can also be created manually. This document describes all the features of custom makefiles, and gives some examples of makefile creation.

Features

Entry point

A makefile is built from 2 entry point properties

Ada_CG.<ENV>.MakeFileNameForExe

This property sets the name of the makefile. The extension must be inserted in this property.

Ada_CG.<ENV>. MakeFileContentForExe

This property is the file template. It can contain some text and some keywords. Keywords will be interpreted by CG.

There are some entry point properties to generate makefiles for executable project and for library projects. Different entry points will be used depending on the component property:

If several files must be generated, then property names must be followed by a number from 1 to N. The CG will automatically scan all entry point properties:

2 additional entry points must be added for Green Hills compilers in order to generate entry point build files:

Keywords

Keywords are replaced by CG with some text. This text can also contain other keywords, which will be interpreted recursively.

Keywords are preceded by the character “$”

There are 2 kinds of keywords: property keyword and macro.

Property keyword

Property keywords can be any of the properties of the current environment. This keyword will be replaced by the content of the property. Its syntax is

$<property_name>

Example

Property MakeExtension String ".bat"
Property MakeFileNameForExe String "makefile$MakeExtension”

In the second property, CG will replace $MakeExtension by the content of property Ada_CG.<ENV>.MakeExtension. The result will be:

makefile.bat

Macro

A Macro is a keyword which will be interpreted by CG to execute a script. Macros are recognized because they start with “$AdaCG”.

Some macros don’t begin by this prefix:

Creating new macro

If needed, users can add some new macros which will call Code Generator rule. The user must have knowledge of the RiA Code Generator rules in order to do this.

A property file must be created, which will make the mapping between the name of the macro and the script to call.

The file name must be:

    <Rhp_install_dir>\share\\properties\MakeFileCommand.ini

Syntax to fill this file is

    <Macro_Name>=<script_name>      for a script defined in configuration level

    <Macro_Name>=Project.<script_name>      for a script defined in project level

This procedure is now obsolete. User do not need to create this new file. He can just call the rules by there name with "$" character in front of the name.

Standard Macros and property Keywords

This list of macros already known by the code generator:

Active_Component_Name

Returns the name of the active component

Project_Name

Returns the project name

Ada_CG_Build_Set

Returns the value of the field Build set in configuration settings

AdaCGAnimationInclude

If animation is enabled, this macro will get property AnimationLibraries83Path, AnimationLibraries95Path or AnimationLibrariesNew95Path, depending on used FWK

AdaCGAnimLib

If animation is enabled, this macro will get property

    AnimationLibraries

AdaCGBehavioralInclude

If animation is enabled, or if model needs Behavioral FWK, this macro will get property BehavioralLibraries83Path, BehavioralLibraries95Path or BehavioralLibrariesNew95Path

AdaCGBehavioralLib

This macro gets properties BehavioralLibraries83Lib, BehavioralLibraries95Lib or BehavioralLibrariesNew95Lib depending on used FWK

AdaCGBoochPath

If relations are used, this macro will get property Booch83Path or Booch95Path depending on used Booch component.

AdaCGBoochFiles

This macro gets some property depending on the following condition:

if Uses_Relations_Include{

 if Use_Booch_95_Components{

      if Needs_Relations_Include_Bounded_Qualified{

          get property Booch95RelationsIncludeBoundedQualified }

     if Needs_Relations_Include_Unbounded{

           get property Booch95RelationsIncludeUnbounded}

     if Needs_Relations_Include_Unbounded_Not_Qualified{

           get property Booch95RelationsIncludeUnboundedNotQualified}

    if Needs_Relations_Include_Unbounded_Qualified{

           get property Booch95RelationsIncludeUnboundedQualified
    }

 }

 

if Use_Booch_83_Components {

     if Needs_Relations_Include_Bounded_Qualified{

          get property Booch83RelationsIncludeBoundedQualified}

     if Needs_Relations_Include_Unbounded{

           get property Booch83RelationsIncludeUnbounded}

     if Needs_Relations_Include_Unbounded_Not_Qualified{

           get property Booch83RelationsIncludeUnboundedNotQualified}

     if Needs_Relations_Include_Unbounded_Qualified{

           get property Booch83RelationsIncludeUnboundedQualified
     }

 }

}

AdaCGContainerSet

Returns a string depending on the kind of container set which should be used. The values are

  • Empty string if no container set is required
  • Booch_83
  • Booch_95
  • Ada2005Containers

AdaCGAdaPath

This macro gets all generated folders. All folders are separated by “\n”. This macro uses the property AdaPathContent in order to format this list. See AdaPathContent description for more details.

A similar marco do the same job, except that it does not include component and configurations dependencies : AdaCGGeneratedDir

AdaCGGeneratedDir

This macro gets all generated folders. All folders are separated by “\n”. This macro uses the property AdaPathContent in order to format this list. See AdaPathContent description for more details.

A similar marco do the same job, except that it includes also component and configurations dependencies : AdaCGAdaPath

AdaCGGenerateDirectory

Returns the value of the property CG.Package. GenerateDirectory. The values are:

  • TRUE
  • FALSE

AdaCGAdaVersionSwitch

This macro will get property Ada83Switch, Ada95Switch, Ada2005Switch or Ada2012Switch, depending on Ada version used. If a model in Ada83 is animated, version switch will be forced to Ada95.

AdaCGAdaVersionSwitchNoSpace

This macro is similar as AdaCGAdaVersionSwitchSpace, except that is does not add a white space before the content of the properties.

AdaCGDebugSwitch

This macro generates the text of property CompileDebug if build set of configuration setting is set to debug.

AdaCGAdditionalSources

This macro gets additional sources from configuration settings. It uses property AdditionalSourcesTemplate in order to format this text. See AdditionalSourcesTemplate description for more details.

AdaCGUserIncludPath

This macro gets user include path from configuration settings. It uses property IncludePathTemplate in order to format this text. See IncludePathTemplate description for more details.

AdaCGLibraries

This macro gets library from configuration settings. It uses property LibrariesTemplate in order to format this text. See LibrariesTemplate description for more details.

AdaCGCompileSwitches

This macro gets compile switches from configuration settings

AdaCGLinkSwitches

This macro gets link switches from configuration settings

AdaCGUserIncludePath

This macro gets user include path from configuration settings. It uses property IncludePathTemplate in order to format this text. See IncludePathTemplate description for more details

AdaCGFWK

Returns a string depending of the kind of FWK which should be used. The value are

  • Empty string if no FWK is required
  • FWK83
  • FWK95
  • newFWK95

AdaCGGetInstrumentationType

Returns a string depending on the value of instrumentation type in configuration setting.

AdaCGFileSpecList

This Macro makes the list of all generated spec files. The spec file is added to the make file using the SpecTemplate property.

This macro uses properties:

  • SpecTemplate<index of makefile>
  • ProtectedStartTagFormat<index of makefile>
  • ProtectedEndTagFormat<index of makefile>
  • <index of makefile> is the index of makefile entry point

AdaCGFileBodyList

This Macro makes the list of all generated body files This macro uses properties

  •   - BodyTemplate<index of makefile>
  •   - ProtectedStartTagFormat<index of makefile>
  •   - ProtectedEndTagFormat<index of makefile>
  • <index of makefile> is the index of makefile entry point

GNAT_File_Mapping 

This macro generates mapping file list. It uses properties

  •   - SpecTemplate<index of makefile>
  •   - BodyTemplate<index of makefile>
  •   - ProtectedStartTagFormat<index of makefile>
  •   - ProtectedEndTagFormat<index of makefile>
  • <index of makefile> is the index of makefile entry point

It enables generating all generated file list for each elements in a single time. For example

   -- package_3::class_7 Start
      for spec ("package_3.class_7_Interface") use "class_7_Interface.ads";
      for spec ("package_3.class_7_Port") use "class_7_Port.ads";
      for body ("package_3.class_7_Port") use "class_7_Port.adb";
      for spec ("package_3.class_7") use "class_7.ads";
      for body ("package_3.class_7") use "class_7.adb";
   -- package_3::class_7 End

To get this result, the properties must have this values:

SpecTemplate :

      for spec (\"$FileName\") use \"$SpecRelativeFilename\";

BodyTemplate :

      for body (\"$FileName\") use \"$SpecRelativeFilename\";

ProtectedStartTagFormat :

    -- $AdaCGRiAFullName Start

ProtectedEndTagFormat :

    -- $AdaCGRiAFullName End

AdaCGObjectAdaMakefile

This macro generates makefile for OBJECTADA compiler. “Compiler” property should be set to OBJECTADA.

AdaCGGnatMakefile

This macro generates makefile for GNAT or GNATVxWorks compiler. “Compiler” property should be set to GNAT or GNATVxWorks.

AdaCGGnatAdc

This macro generates gnat.adc file for GNAT or GNATVxWorks compiler. “Compiler” property should be set to GNAT or GNATVxWorks.

AdaCGOptionalAdaPath

This is a rule which generates the code to define the variable ADA_INCLUDE_PATH

AdaCGGnatchopCommands

Used to split AdaCGGnatMakeFile macro

AdaCGCommands

This macro returns command line. It uses the property CompileCommand to get the template of the command

AdaCGArchiveCommand

Used to split AdaCGGnatMakeFile macro

AdaCGIDEName

Get value of IDEName tag of current configuration (for RiA in eclipse)

AdaCGIDEProject

Get value of IDEProject tag of current configuration (for RiA in eclipse)

AdaCGIDEWorkspace

Get value of IDEWorkspace tag of current configuration (for RiA in eclipse)

AdaCGDefaultActiveClass

If default active class is need for FWK83, then this macro will get the property ActiveClassInclude.

AdaCGFileList

This macro generates the list of generated spec files. It uses property FileTemplate in order to format this list.

AdaCGOMROOTSingleSlashes

Generates OMROOT with back slashes.

AdaCGOMROOTDoubleSlashes

Generates OMROOT with double back slashes

AdaCGOMROOTForwardSlashes

Generates OMROOT with forward slashes.

Component_Dependencies_With_Clause

This macro is mainly used to generate GNAT gpr files

This macro returns a list of with clause for each usage dependencies which are defined from the current component to another component. The template of the with clause is

with <component_path>\<config_name><PathDelimiter><config_name>.gpr

The component path can be given by the property Ada_CG.Configuration.TargetComponentPath. This enable to specify a specific path, to use the projet on a different target than the host one.

The property Ada_CG.<environment>.PathDelimiter is also used to define the kind of path delimiter used by the target.

Configuration_Dependencies_With_Clause

This macro is mainly used to generate GNAT gpr files

This macro returns a list of with clause for each usage dependencies which are defined from the current configuration to another configuration. The template of the with clause is

with <configuration_path><PathDelimiter><config_name>.gpr

The configuration path can be given by the property Ada_CG.Configuration.TargetConfigurationPath. This enable to specify a specific path, to use the projet on a different target than the host one.

The property Ada_CG.<environment>.PathDelimiter is also used to define the kind of path delimiter used by the target.

Makefile_OMROOT_With_Optional_Quotes

Returns the OMROOT value with Quotes.

OMROOT

Generates OMROOT with back slashes. This string is quoted if the property QuoteOMROOT is set to “True”.

This list of additional properties shows properties which are used by macro listed below:

CompileDebug

This property contains debug switches. Is used by AdaCGDebugSwitch macro.

Ada83Switch

Ada95Switch

Ada2005Switch

Ada2012Switch

Those properties contain Ada version switches.

AnimationLibraries83Path

AnimationLibraries95Path

AnimationLibrariesNew95Path

Those properties contain Animation libraries path for each FWK

BehavioralLibraries83Path

BehavioralLibraries95Path

BehavioralLibrariesNew95Path

Those properties contain Behavioral libraries path for each FWK

AnimationLibraries

This property gives the animation library located at <Rhp_Install_Dir>\ Share\LangC\Lib

AdaPathContent 

This property contains patterns to be replaced. The format of this property is <”The_String_To_Replace”><”Is_Replaced_With”>

For example

<\”\\n\”><\”;\”>

This will replace "\n" by ";"

This property is used by macro AdaCGAdaPath and macro AdaCGGeneratedDir

Compiler

This property sets the name of compiler. It is used to be able to reuse already existing rules with other environment.

For example, if you create a new Environment called GNAT_1, and if you use the Macro AdaCGGnatMakefile, then some part of rules won’t work as expected because this new environment variable is unknown. So a new property is created to replace this environment name with compiler name.

If a new compiler is created, this property is not useful, because it is unknown by CG.

The values for this property should be:

  • GNAT
  • GNATVxWorks
  • OBJECTADA
  • MultiWin32
  • Multi4Win32
  • INTEGRITY
  • INTEGRITY5
  • RAVEN_PPC
  • SPARK

Booch83Path

Booch95Path

Those properties contain booch components path

Booch95RelationsIncludeBoundedQualified

Booch95RelationsIncludeUnbounded

Booch95RelationsIncludeUnboundedNotQualified

Booch95RelationsIncludeUnboundedQualified

 

Booch83RelationsIncludeBoundedQualified

Booch83RelationsIncludeUnbounded

Booch83RelationsIncludeUnboundedNotQualified

Booch83RelationsIncludeUnboundedQualified

Those properties contain the list of booch component files needed for each kind of relation.

AdditionalSourcesTemplate

IncludePathTemplate

LibrariesTemplate

Those 3 properties allow replacing some string of configuration fields by some other string. Syntax is:

[optional_string] <”The_String_To_Replace”><”Is_Replaced_With”>

For example

Property LibrariesTemplate MultiLine " -largs <\"\^\"><\" -l\"><\"\\n\"><\" -l\"><\"\\r\\n\"><\" -l\"><\",\"><\" -l\">"

If user update configuration libraries with the string “lib1,lib2”, then it will be generated like this:

-largs -llib1 -llib2

BodyTemplate

SpecTemplate

Those properties are use to format the file list generated by Macros AdaCGFileBodyList and AdaCGFileBodyList.

The following keyword can be used in this template:

  • ConfigurationRelativeFilename
  • ConfigurationRelativeBodyFilename
  • ConfigurationRelativeBodyFilename
  • SpecRelativeFilename
  • BodyRelativeFilename
  • FileName
  • GNATCommandFileName
  • AdaCGRiAFullName

For example for a class class_0 defined in default package those keywords will produce :

ConfigurationRelativeFilename : .\Default\class_0
ConfigurationRelativeBodyFilename : .\Default\class_0.adb
ConfigurationRelativeSpecFilename : .\Default\class_0.ads
SpecRelativeFilename : class_0.ads
BodyRelativeFilename : class_0.adb
FileName : class_0
FullNameDashes : class_0("." Are replaced by "-")
AdaCGRiAFullName : Default::class_0
          

ProtectedStartTagFormat

ProtectedEndTagFormat

Those properties are used to format the file list generated by Macros AdaCGFileBodyList and AdaCGFileBodyList.

They are used to add some tags in the list in order to help CG to add only new text in the file.

The same keywords than properties BodyTemplate and SpecTemplate can be used.

New environment creation

Create a new file SiteAda.prp

Add the following properties:

Subject Ada_CG
  Metaclass Configuration
    Property Environment Enum "GNAT,INTEGRITY,INTEGRITY5,MultiWin32,Multi4Win32,OBJECTADA,RAVEN_PPC,SPARK,GNATVxWorks,New_Env" "GNAT"
  end
end

Copy an environment which is as close as possible to your new one, from sodius.prp to siteAda.prp. It must be copied just before the last “end” of the file.

Then modify entry points and add some new properties which will describe your new files.

Use cases

Custom makefiles can be created for several purposes. For example user needs to make a small modification of a current makefile. Or user wants to use a new compiler which is not supported by code generator. This chapter will describe how this can be done.

Create a new makefile for an unknown compiler.

Fast solution

Just add the text of the make file in the entry point property. This will generate always the same makefile. This solution can be used to make a quick test, but it cannot take into account all possible configurations.

Configurable solution

A new environment could be used for different kind of configuration. User can use different frameworks or Ada versions, or he can set animation or not. In order to take into account automatically those configurations, custom makefiles can be written with some macros which will automatically select the desired property depending on configuration properties.

Makefiles depend also on the model structure. A list of generated files or folders can be added to makefiles with the possibility to format the list.

Take into account Framework

If your model has events or statecharts, then a Framework must be used. Three different Frameworks can be used (FWK83, FWK95, NewFWK95), depending on property Ada_CG:Component:UseAdaFramework . Those Frameworks have been first generated and compiled for your compiler and your environment. You should know what their locations are. The path of your different Framework should be set in properties BehavioralLibraries83Path, BehavioralLibraries95Path and BehavioralLibrariesNew95Path, and you should invoke them by using macro AdaCGBehavioralInclude, which will select the correct property, depending on used Framework.

Take into account animation

If model is animated, you should add some libraries

C Animation libraries which are:

%OMROOT%\LangC\lib\AdaWinaomanim.lib %OMROOT%\LangC\lib\AdaWinoxfinst.lib %OMROOT%\LangC\lib\AdaWinomcomappl.lib

C libraries should be compiled as explaind in chapter "Manually rebuilding the animation C libraries".

Ada animation libraries path which are:

%OMROOT%\LangAda\aom for FWK 83.

%OMROOT%\LangAda\aom_95 for FWK95 and newFWK95.

You should use AdaCGAnimationInclude and AdaCGAnimationLib macros with there associated properties, in order to add animation facilities into makefiles.

Take into account relations

If your model contains relations which use booch components, then some booch components files must be added to your makefile.

Booch components are located in:

%OMROOT%\LangAda95\booch_ada_83\src\

%OMROOT%\LangAda95\booch_ada_95\src\

For each kind of relation, the Code generator uses a different set of Booch components.

Booch components 83

Relations_Include_Bounded_Qualified

    map_simple_noncached_concurrent_bounded_managed_noniterator.ads
    map_simple_noncached_concurrent_bounded_managed_noniterator.adb

Relations_Include_Unbounded

    Storage_Manager_Concurrent.ads
    Storage_Manager_Concurrent.adb

Relations_Include_Unbounded_Not_Qualified

    list_single_unbounded_controlled.ads
    list_single_unbounded_controlled.adb
    list_utilities_single.ads
    list_utilities_single.adb
    list_search.ads
    list_search.adb

Relations_Include_Unbounded_Qualified

    Storage_Manager_Concurrent.ads
    Storage_Manager_Concurrent.adb
    map_simple_noncached_concurrent_unbounded_managed_noniterator.ads
    map_simple_noncached_concurrent_unbounded_managed_noniterator.adb

Booch components 95

Relations_Include_Bounded_Qualified

    bc.ads
    bc-containers.ads
    bc-containers.adb
    bc-containers-maps.ads
    bc-containers-maps.adb
    bc-containers-maps-bounded.ads
    bc-containers-maps-bounded.adb
    bc-support.ads
    bc-support-hash_tables.ads
    bc-support-hash_tables.adb
    bc-support-bounded_hash_tables.ads
    bc-support-bounded_hash_tables.adb

Relations_Include_Unbounded

    bc.ads
    bc-support.ads
    bc-support-standard_storage.ads
    bc-support-unbounded.ads
    bc-support-unbounded.adb

Relations_Include_Unbounded_Not_Qualified

    bc.ads
    bc-containers.ads
    bc-containers.adb
    bc-containers-collections.ads
    bc-containers-collections.adb
    bc-containers-collections-unbounded.ads
    bc-containers-collections-unbounded.adb

Relations_Include_Unbounded_Qualified

    bc.ads
    bc-containers.ads
    bc-containers.adb
    bc-containers-maps.ads
    bc-containers-maps.adb
    bc-containers-maps-unbounded.ads
    bc-containers-maps-unbounded.adb

You should use AdaCGBoochPath and AdaCGBoochFiles macro with their associated properties to add Booch component facilities into makefiles.

Modify the generated code of a current environment.

For example, you need to change the primaryTarget of your project for INTEGRITY5 environment. But this is hardcoded by the code generator. Instead of calling the macro AdaCGMulti4MakeFile, you will call a set of macros which are called by it. To do this you must use the Rules composer and generate code in debug mode. Open the debug hierarchy and find the script which is called by the macro.

Copy this script in a new property and change the script names into some custom names.

The script (get from Ada code generator rules) called by AdaCGMulti4MakeFile does this:

[#script]
#!gbuild
# Generated by Rhapsody

${self.MULTI_4_Top_Settings}${self.MULTI_4_Get_Library_Options}${self.MULTI_4_Get_Executable_Options}
${self.MULTI_4_Debug_Switches}${self.MULTI_4_Additional_Options}${self.Makefile_Compile_Switches}${self.Makefile_Link_Switches}
# Generation directories settings
     -object_dir=obj
     --ada_info_dir info
     --ada_xref_dir xref
${self.MULTI_4_Ada_Path}
${self.MULTI_4_User_Include_Path}${self.MULTI_4_User_Libraries}${self.MULTI_4_RiA_Anim_Libs_Linker_Options}
${self.MULTI_4_Anim_And_Behavioral_Includes}
Sources.gpj            ${self.MULTI_4_Component_Type}
${self.MULTI_4_Entrypoints}[/#script]

The Macro AdaCGMulti4MakeFile should be replaced by the following text in property MakeFileContentForExe3

#!gbuild
# Generated by Custom template
primaryTarget=NEW_PRIMARY_TARGET_integrity.tgt
[INTEGRITY Application]
     -o $ComponentName$ExeExtension
# Target definition
     -bsp $BLDTarget
     -os_dir=$IntegrityRoot
$BLDMainExecutableOptions
$MULTI4DebugSwitches$MULTI4AdditionalOptions$MakefileCompileSwitches$MakefileLinkSwitches
# Generation directories settings
     -object_dir=obj
     --ada_info_dir info
     --ada_xref_dir xref
$MULTI4AdaPath
$MULTI4UserIncludePath$MULTI4UserLibraries$MULTI4RiAAnimLibsLinkerOptions
$MULTI4AnimAndBehavioralIncludes
Sources.gpj            [Project]
Main$ComponentName$MakeExtension[program]

This new text will do the same job than the RulesComposer script. The names of the rules have been replaced by new Macros. The rule MULTI_4_Top_Settings has been replaced directly by some text, because this is the part of generation that we want to modify.

In order to enable the code generator to understand those new macros, a new initialization file must be updated, to create mappings between macros and rules.

Create the file:

<User_Share_Folder>\properties\MakeFileCommand.ini

In this file, you will map custom names to a script:

MULTI4DebugSwitches	        =Project.MULTI_4_Debug_Switches
MULTI4AdditionalOptions	        =Project.MULTI_4_Additional_Options
MakefileCompileSwitches	        =Project.Makefile_Compile_Switches
MakefileLinkSwitches	        =Project.Makefile_Link_Switches
MULTI4AdaPath	                =Project.MULTI_4_Ada_Path
MULTI4UserIncludePath	        =Project.MULTI_4_User_Include_Path
MULTI4UserLibraries             =Project.MULTI_4_User_Libraries
MULTI4RiAAnimLibsLinkerOptions  =Project.MULTI_4_RiA_Anim_Libs_Linker_Options
MULTI4AnimAndBehavioralIncludes =Project.MULTI_4_Anim_And_Behavioral_Includes

The prefix “Project.” means that this script is defined at project level. If this prefix is omitted, then the script must be defined at configuration level.

You should also take care of Framework location. You may have generated a new Framework for your new environment. So Framework location has changed. To do this, replace the Macro MULTI4AnimAndBehavioralIncludes by AdaCGBehavioralInclude. This macro will get information from properties BehavioralLibraries83Path, BehavioralLibraries95Path or BehavioralLibrariesNew95Path depending on Framework version.

Property BehavioralLibraries83Path should be for example:

--ada_elab_dirs '\'$AdaCGOMROOTForwardSlashes/LangAda83/oxf/NewEnv_sim800''
-L'$AdaCGOMROOTDoubleSlashes\\\\LangAda83\\\\oxf\\\\ NewEnv_sim800'

A new property “Compiler” should also be added and set to “INTEGRITY5” in order to be sure that the code generator will interpret the macro for the correct compiler.