A CORBA IDL compiler for SWI-Prolog
Jan Wielemaker
SWI,
University of Amsterdam
The Netherlands
E-mail: jan@swi.psy.uva.nl
This document contains a brief overview of a CORBA IDL compiler for (SWI-)Prolog.
CORBA is the emerging standard for distributed computing. It makes components of a distributed system independent on the platform and language as well as accesible over the network.
A component in a distributed system is described using an IDL, (Interface Description Language) module. IDL is an object oriented language. It describes the component in terms of interfaces (classes in normal OO systems), which have attributes and methods. Method arguments are typed. The type system of IDL contains the usual primitives: various length integers, floating point numbers and strings, as well as constructs for aggregate types: (un)bounded sequences, arrays, structures and unions (switch-type).
A language binding describes how constructs from the IDL are mapped onto constructs of the target language. Well defined bindings exist for various languages, including C, C++, Java and Lisp. No such binding is defined for Prolog.
This document describes an evolving binding and its implementation for Prolog.
There is a wide range of implementations of the C and C++ bindings available. As this project was carried out with limited resources, it appeared natural to base the implementation on these bindings. Using an existing binding, we avoid involvement in the broker and protocol layers of CORBA. The architecture is outlined in figure 1.
A mapping describes what the IDL looks like from the target language. In this section we will go through all mapped IDL construcs.
All scalar integer types ((un)signed long, (un)signed short, char, octed are mapped into Prolog integers. If an argument is passed to the CORBA interface the Prolog integer should satisfy the limitations of the IDL type. A floating point number representing an integer in the required range of the type is accepted too. If an argument is passed to Prolog, it always appears as a Prolog integer. (1)
The types float
and double
are mapped into
Prolog floating point numbers.
The CORBA type CORBA_Boolean is mapped onto the Prolog constants
true
and false
.
Enum types are mapped onto atoms holding the name of the member of the enum type.
Strings are mapped onto atoms. Especially on Prolog systems lacking atom garbage-collection, this is possibly not the proper choice.
A structure is mapped into a Prolog term. The principal functor is the name of the structure. The arguments of the term denote the fields of the structure by position. (2)
Both bound and unbound sequences are mapped into Prolog lists.
The current IDL compiler does not support arrays. On Prolog systems with unbound term-arity they could be mapped onto terms, providing arg/3 for accessing the elements in a natural and efficient fashion. On other systems, trees may be appropriate. To ensure portability, the support libraries should include predicates to build and analyse arrays.
An IDL switch-type
is the combination of a union and a
type identifier (scalar or enum). It is mapped onto a term named after
the switch-type holding the type identifier and the actual value.
If the type identifier is an enum, a good alternative mapping would be <Enum>(<Value>). This however does not allow for integer type identifiers.
Constants are not yet available to the implementation module. They are handled by the IDL compiler for type specifications. The IDL compiler should generate a predicate to access the constants. For example:
IDL modules are mapped onto Prolog modules. The current compiler cannot deal with interfaces appearing outside modules or nested modules. In the future, the code for interfaces without a module should be in the Prolog user module and nested modules should be mapped onto Prolog modules where the name is the concatenation of the module-path, separated by underscores.
For a generic mapping, Modules cannot be used as modules are not yet part of the (ISO) Prolog standard.
Interfaces are not mapped explicitely.
A method is mapped onto a predicate in the implementation module. The name of the predicate is constructed from the interface name and the method name, separated by an underscore.
The first argument to the predicate is a reference to the interface object. Next are the arguments describing the input/output arguments. At the server side, input arguments are bound and output arguments are unbound. At the client input arguments must be bound. For output arguments, the converted value is unified with the argument. Arguments of type inout are not yet supported. They will probably be passed as a term inout(In, Out) . Finally, if the method has a return-type, this is appended as the last argument. The argument conventions for the return-value are the same as for output arguments.
IDL exceptions are mapped onto ISO Prolog catch/throw exception handling. The exception-term is a term whose name is the exception name. The arguments are mapped as structure arguments. A server raising an exception calls throw/1 using the exception term. A client calls catch/3 for handling these exceptions.
Instances are create using the predicate
<interface>_create_true(+Marker, -Handle)
The Orbix loader is activated by the Orbix deamon to create instances of a specified interface with a specified marker. The loader calls the predicate user:corba_loader/3 to create objects:
*_create_true
predicate.
It would be better to define a corba_loader/3 predicate in each module and pass the plain interface name.
The Prolog mapping defines a number of predicates to deal with the overall control of the session, as well as other environment control. As the possibilities differ widely between the various CORBA implementations, this set of predicates is tentative.
Common options | |
server(ServerId) | Denotes the identifier under which the server is registered. |
ILU options | |
protocol(ProtocolId) | The protocol used
for communication. Default is the ILU internal protocol,
iiop_1_0_1 should be used to switch to the CORBA IIOP
protocol. |
transport(Stack) | Determines the
transport layer(s) used. Default is Sun RPC, ['tcp_0_0']
should be used with IIOP to communicate to other brokers. |
OmniBroker options | |
Orbix options | |
timeout(Seconds) | After this idle-time, corba_main_loop/1 will return. Can be used to exit from the server. The Orbix deamon will relaunch the server if a new request is made. |
Stringified object references can be used to establish communication between any two `IIOP' compliant broker implementations.
This section discusses client-specific issues.
The Orbix Class::_bind() call is mapped onto the Prolog predicate <interface>__bind/4:
The Prolog IDL compiler is a Prolog program. Figure 2 outlines the design of the compiler.
The shell-script pl-stubber provides a simple toplevel for the program. Use `pl-stubber --help' to see the commandline options.
Initially, the IDL compiler was used in combination with the ILU CORBA/C mapping, for which we realised both the client and server side. Later we moved to the Omnibroker/C++ mapping for which we realised only the server mapping. Finally, we moved to Orbix/C++.
While changing platforms due to external requirements, we generalised the code generator to deal with subtle differences in the mappings. The tested ORB's are below:
ORB | server | client |
ILU 2.0a10 (Linux and Solaris, gcc 2.7) | ok | ok |
OmniBroker 1.0 | ok | ok |
Orbix 2.1 | not tested | not implemented |
Orbix 2.2 (NT 4.0, MSVC4.2) | ok | ok |
We intend to support a wide variety of ORB implementations, including both commercial and free versions.
The outlined mapping was inspired by the CORBA/C mapping. Some aspects of the mapping need further investigation.
The only problem occurs of two elements of the switch map onto the same Prolog datatype, and this information conveys semantic information.
<Module>:<Interface>(Self, Args ..., Return)
we could opt for
corba_send(Self, Args ...)
corba_get(Self, Args ..., Return)