=head1 NAME

prima-gencls - class interface compiler for Prima core modules

=head1 SYNOPSIS

  prima-gencls --h --inc --tml -O -I<name> --depend --sayparent filename.cls


=head1 DESCRIPTION

Creates C files for Prima core module object definitions.

=head1 ARGUMENTS

The prima-gencls program accepts the following arguments:

=over 4

=item --h

Generates a .h file ( with the declarations to be included in one or more files )

=item --inc

Generates a .inc file ( with the declarations to be included in only one file )

=item -O

Turns on the optimizing algorithm for the .inc files. The algorithm is based on
an assumption that some function bodies are identical, and so the duplicates
can be detected and removed.  When the C<-O> flag is set, the body of such a function
is replaced with a call to the function with an auto-generated name.  That
function is not included in the .inc file, but in a .tml file instead.  All the
duplicate declarations from a set of .tml files can be later removed by the
L<tmlink> utility.

=item --tml

Generates a .tml file. Turns the C<-O> flag on automatically.

=item -Idirname

Adds a directory to a search path, where the program searches for the .cls
files. Can be specified several times.

=item --depend

Prints out dependencies for the given file.

=item --sayparent

Prints out the immediate parent of a class inside the given file.

=back

=head1 SYNTAX

The syntax of a .cls file can be described by the following scheme:

  [ zero or more type declarations ]
  [ zero or one class declaration ]

The prima-gencls program produces .h, .inc, and .tml files with the same basename as
the .cls file if no object or package name is given, or with the name of the object
or the package inside the .cls file otherwise.

=head2 Basic scalar data types

Prima-gencls can generate the conversion code for several built-in scalar data
types that transfers data between C and perl, using the XS ( see L<perlguts> )
library interface.

These types are:

   int
   Bool
   Handle
   double
   SV*
   HV*
   char *
   string ( C declaration is char[256] )

There are also some derived built-in types, which are

   long
   short
   char
   Color
   U8

that are mapped to the C<int> type. The data undergoes no conversion to int in
the transfer process, but it is stored to the perl scalar using the newSViv()
function which may lose bits or a sign.

=head2 Derived data types

The syntax for a new data type definition is as follows:

   <scope> <prefix> <id> <definition>

A scope can be one of two pragmas, C<global> or C<local>.  That requests the
usage locality of the new data type, i e whether the type will be used only for
one class or in more than one. Usage of the C<local> scope somewhat resembles
the C predicate C<static>.  The difference between the scopes is that a
function using a complex local type in the parameter list, or as a result, will
not be optimized out with the C<-O> flag.

=head2 Scalar types

New scalar types may only be aliased to the existing ones, primarily for coding
convenience in C.  A scalar type can be defined in two ways:

=over

=item Direct aliasing

Syntax:

  <scope> $id => <basic_scalar_type>;

Example:

  global $Handle => int;

The new type id will not be visible in the C files, but the type will be
substituted over all .cls files that include this definition.

=item C macro

Syntax:

  <scope> id1 id2

Example:

  global API_HANDLE UV

Such code creates a C macro definition in the .h header file in the form

  #define id1 id2

C macros with parameters are not allowed. id1 and id2 are not required to be
present in the .cls namespace, and no substitution during .cls file processing
is made.

=back

=head2 Complex types

Complex data types can be arrays, structs, and hashes.  Prima-gencls allows
several combinations of complex data types that C language does not recognize.
These will be described below.

The complex data types do not get imported into the perl code.  A perl program
must conform to the data type used when passing the corresponding parameters to
such a function.

=over

=item Arrays

Syntax:

  <scope> @id <basic_scalar_type>[dimension];

Example:

  global @FillPattern U8[8];

Example of functions using arrays:

  Array * func( Array a1, Array * a2);

Perl code:

  @ret = func( @array1, @array2);

Note that the array references are not used, and the number of items in the
array parameters must be exactly the same as the dimensions of the arrays.

Warning: the following declaration will not compile with the C compiler, as C
cannot return arrays. However, this construct is not treated as an error by
prima-gencls:

  Array func();

=item Structs

Syntax:

  <scope> @id {
     <basic_scalar_type> <id>;
     ...
     <basic_scalar_type> <id>;
  };

Example:

  global @Struc {
     int    number;
     string id;
  }


Example of the functions using structs:

  Struc * func1( Struc a1, Struc * a2);
  Struc   func2( Struc a1, Struc * a2);

Perl code:

  @ret = func1( @struc1, @struc2);
  @ret = func2( @struc1, @struc2);

Note that the array references are not used, and both the number and order of items
in the array parameters must be exactly as the dimensions and the order of the
structs. The struct field names are not used in the perl code as well.

=item Hashes

Syntax:

  <scope> %id {
     <basic_scalar_type> <id> [with undef];
     ...
     <basic_scalar_type> <id> [with undef];
  };

Example:

  global %Hash {
     int    number;
     string id with undef;
  }


Examples of the functions using hashes:

  Hash * func1( Hash a1, Hash * a2);
  Hash   func2( Hash a1, Hash * a2);

Perl code:

  %ret = %{func1( \%hash1, \%hash2)};
  %ret = %{func2( \%hash1, \%hash2)};

Note that only the hash references are used and returned.  When a hash is
passed from the perl code it might have some or all fields unset. The C
structure is filled and passed to a C function, and the unset fields 
are assigned to a corresponding C_TYPE_UNDEF value, where TYPE is one of
NUMERIC, STRING, and POINTER literals. 

If the optional C<with undef> declarator was used, the C structure is augmented
with additional struct C<undef> with boolean fields that explicitly reflect
whether the perl value was passed or not.  The C-to-perl conversion respects
these boolean flags as well and does not populate hash fields with this bit
set.

=back

=head2 Namespace section

Syntax:

   <namespace> <ID> {
      <declaration>
      ...
      <declaration>
   }

A .cls file can have zero or one namespace sections filled with function
descriptions. Functions described here will be exported to the given ID in the
initialization code. A namespace can be either C<object> or C<package>.

The package namespace syntax only allows functions without the prefix inside the
C<package> block:

    package <Package ID> {
        <function description>
        ...
    }

The object namespace syntax allows variables and properties as
functions ( called methods in the object syntax ).  The general object
namespace syntax is

    object <Class ID> [(Parent class ID)] {
       <variables>
       <methods>
       <properties>
    }

Within the object namespace the inheritance syntax
can be also used:

    object <Class ID> (<Parent class ID>)  { ... }

=head2 Functions

Syntax:

    [<prefix>] <type> <function_name> (<parameter list>) [ => <alias>];

Examples:

 package A {
    int   func1( int a, int b);
    Point func2( Struc * x);
 }

 object B
    method int   func1( int a, int b = 1) => c_func_2;
    import Point func2( Struc * x, ...);
    c_only void  func3( HV * profile);
 }

The prefix is used with object functions ( methods ) only.  More on the prefix
in the L<Methods> section.

A function can return nothing ( void ), a scalar ( int, string, etc ), or a
complex ( array, hash ) type. It can as well accept scalar and complex
parameters, with the type conversion that corresponds to the rules described
above in the L<Basic scalar data types> section.

If a function has parameters and/or a result of the type that cannot be converted
automatically between C and perl, it gets declared but not exposed to the perl
namespace.  A warning is also issued.  It is not possible to use the gencls
syntax to declare a function with custom parameters or result types.  For such
purpose, the explicit C declaration of the code along with a call to C<newXS>
must be made.

Example: ellipsis (...) cannot be converted by prima-gencls, even though it is a
legal C construction.

  Point package_func2( Struc * x, ...);

The function syntax has several convenience additions:

=over

=item Default parameter values

Example:

  void func( int a = 15);

A function declared in such a way can be called both with 0 or 1 parameters. If
it is called with 0 parameters, an integer value of 15 will be automatically
used.  The syntax allows default parameters for types int, pointer, and string,
and their scalar aliases.

The default parameters can be as many as possible, but they have to be at the
end of the function parameter list.  The declaration C<func( int a = 1, int b)> is
incorrect.

=item Aliasing

In the generated C code, a C function has to be called after the parameters
have been parsed. Prima-gencls expects a conforming function to be present in
the C code, with the fixed name and parameter list. However, if the only task
of such a function is to be a one-to-one wrapper to the identical function
published under another name, aliasing can be performed to save both code and
speed:

Example:

   package Package {
      void func( int x) => internal;
   }

A function declared in that way will not call the Package_func() C function,
but the internal() function instead. The only request here is that the
internal() function must have the same C parameters and result as the func()
function.

=item Inline hash

If a function is declared with the last parameter of the C<HV*> type then the
parameter translation from perl to C is performed as if all the parameters
passed are a hash. This hash is passed to the C function and its content
is returned then back to perl as a hash again.  The hash content can be modified
inside the C function.

This declaration is used heavily in constructors, that are coded in perl
typically like this:

   sub init
   {
      my %ret = shift-> SUPER::init( @_);
      ...
      return %ret;
   }

and the corresponding C code is

   void Obj_init ( HV * profile) {
       inherited init( profile);
       ... [ modify profile content ] ...
   }

=back

=head2 Methods

Methods are the functions called in the context of an object.
Virtually all class methods need to have access to the object
they are bound to. Prima objects are visible in C
as the C<Handle> data type. The Handle is a pointer
to the object instance which in turn contains a pointer
to the object virtual methods table ( VMT ).
To facilitate the OO-like syntax, this Handle parameter
is rarely mentioned in the method declarations:

   method void a( int x)

however, the signature of the corresponding  C function contains the Handle parameter

   void Object_a( Handle self, int x)

Methods are accessible in C code by the direct name dereferencing of the
C<Handle self> like this:

    ((( PMyObject) self)-> self)-> my_method( self, ...);

A method can have one of the following six prefixes that produce different C code
wrappers:

=over

=item method

This is the most basic method type.  Methods of this type are expected to be
coded in C, the object handle is implicit and is not included in the .cls
function declaration:

   method void a()

results in

   void Object_a( Handle self)

C declaration. The published method automatically converts its parameters and
the result between C and perl.

=item public

When the methods need to have parameters and/or a result that cannot be
automatically converted between C and perl, or the function declaration does
not fit into the C syntax, the C<public> prefix is used. The methods declared
as C<public> are expected to communicate with perl by through the XS ( see
L<perlxs>) interface. It is also expected that the programmer declares the
REDEFINED and FROMPERL functions in C code( see L<Prima::internals>  for
details). Examples are many throughout the Prima source and will not be shown here.
C<public> methods usually have the void result and no parameters, but that does not
matter since prima-gencls provides no data conversion for such methods anyway.

=item import

For the methods that are best implemented in perl instead of C,
prima-gencls can produce the C-to-perl wrappers using the C<import> prefix. An
C<import> function does not need a C counterpart, only the auto-generated code.

=item static

If the method has to be able to work both with and without
an object instance, it needs to be prepended with the C<static> prefix.
C<static> methods are similar to C<method> except that
the C<Handle self> first parameter is not implicitly declared.
If the C<static> method is called without an object ( but with
a class ), like for example

   Class::Object-> static_method();

its first parameter is not an object but the "Class::Object" string.
If the method never uses that first parameter it is enough to 
declare it as

   static a( char * className = "");

but if it does, a

   static a( SV * class_or_object = NULL);

declaration is needed. In the latter case C code itself has to determine what
exactly has been passed, if ever. Note the default parameter here: a C<static>
method is usually legible to call as

  Class::Object::static_method();

where no parameters are passed to it. Without the default parameter, such a call
generates an 'insufficient parameters passed' runtime error.

=item weird

We couldn't find a better name for it. The C<weird> prefix
describes a method that combines properties from both the C<static>
and C<public> methods. Prima-gencls generates no conversion
code for the C<weird> methods and expects no C<Handle self> as the first parameter.
As an example, the Prima::Image::load function can be called using a wide
spectrum of calling semantics ( see L<Prima::image-load> for details).

=item c_only

The C<c_only> methods are present in the VMT but are not accessible from perl.
They can be overloaded, but from C only. Moreover, it is allowed to register a
perl function with the same name as the existing C<c_only> method, and these
entities will be completely independent.

Note: methods that have a result and/or parameters declared as data types that cannot be
converted automatically, change their prefix to C<c_only> during the .cls
processing.  Probably this is the wrong behavior, and such a condition has to
signal an error.

=back

=head2 Properties

The Prima toolkit introduces an entity named property, that is used to replace
method pairs whose function is to acquire and assign some internal object
variable, for example, an object name, color, etc. Instead of having a pair of
methods like Object::set_color and Object::get_color, a property Object::color
can be used instead. A property is a method with special considerations, in
particular, when it is called without parameters, the get-mode is implied. On
the contrary, if it is called with one parameter, such a call is treated as being
done in the set-mode. Note that in both 'set' and 'get' invocations the first
parameter C<Handle self> is implicit and is always present.

Properties can operate with different, but always fixed number
of parameters. For example,

   property char * name

has the C counterpart

   char * Object_name( Handle self, Bool set, char * name)

Depending on the calling mode, the C<Bool set> argument is either C<true> or
C<false>.  In the set-mode, the C code result is discarded, while in the
get-mode the property parameter value is undefined.

The syntax for a multi-parameter property is

   property long pixel( int x, int y);

with the C code

   long Object_pixel( Handle self, Bool set, int x, int y, long pixel)

Note that in the multi-parameter case, the parameters declared after the
property name are always initialized, in both the set- and get- modes.

=head2 Instance variables

The prima-gencls syntax allows variable declarations for the variables that are
allocated for every object instance. Although data type validation is not
performed for variables, and their declarations just get copied as is, complex
C declarations involving array, struct, and function pointers are not
supported.  As a workaround, pointers to typedef'd entities are used.  Example:

   object SampleObject {
      int x;
      List list;
      struct { int x } s; # illegal declaration
   }

The variables are accessible in C code by direct name
dereferencing the C<Handle self>:

    (( PMyObject) self)-> x;

=head1 AUTHORS

Dmitry Karasik, E<lt>dmitry@karasik.eu.orgE<gt>.
Anton Berezin, E<lt>tobez@tobez.orgE<gt>.

=head1 SEE ALSO

L<Prima::internals>, L<tmlink>

=head1 COPYRIGHT

This program is distributed under the BSD License.

