The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Code::Class::C - Perl extension for creating ANSI C code from a set of class definitions to accomplish an object-oriented programming style.

SYNOPSIS

  use Code::Class::C;
  my $gen = Code::Class::C->new();
  
  $gen->class('Shape',
    subs => {
      'getLargest(s:Shape):Shape' => 'c/Shape.getLargest.c',
      'calcArea():float' => q{
        return 0.0;
      },
    },
  );
  
  $gen->class('Circle',
    isa => ['Shape'],
    attr => {
      'radius' => 'float',
    },
    subs => {
      'calcArea():float' => q{
        return 3.1415 * getRadius(self) * getRadius(self);
      },
    },
  );

DESCRIPTION

This module lets you define a set of classes (consisting of attributes and methods) and then convert these definitions to ANSI C code. The module creates all the object oriented abstractions so that the application logic can be programmed in an object oriented fashion (create instances of classes, access attributes, destroy instances, method dispatch etc.).

Constructor

new()

  my $gen = Code::Class::C->new();
  

The constructor of Code::Class::C takes no arguments and returns a new generator instance with the following methods.

Methods

class( name, options )

The class() method lets you define a new class:

  $gen->class('Circle',
    isa => ['Shape'],
    attr => {
      'radius' => 'float',
    },
    subs => {
      'calcArea():float' => q{
        return 3.1415 * getRadius(self) * getRadius(self);
      },
    },
    after => {
        'new' => q{...},
        # ...
    },
    top => q{...},
    bottom => q{...},
  );

The class() method takes as first argument the name of the class. The name has to start with a capitol letter and may be followed by an arbitrary amount of letters, numbers or underscore (to be compatible with the ANSI C standard).

The special class name Object is not allowed as a classname. A classname must not be longer than 256 characters.

After the first argument the optional parameters follow in any order:

isa => Arrayref of classnames

The isa option lets you specify zero or more parent classes of the class that is to be defined.

attr => Hashref of attributes

The attr option lets you define the attributes of the class that is to be defined.

The hash key is the name of the attribute (starting with a small letter and followed by zero or more letters, numbers or underscore; note: attribute names are case-insensitive).

The hash value is the C-type of the attribute. Here you can use basic C types OR class names (because each class becomes available as a native C type when the C code is generated).

subs => Hashref of methods

The subs option lets you define the methods of the class that is to be defined.

The hash key is the signature of the method, e.g.

  calcArea(float x, MyClass y):int

The hash value is the C sourcecode of the method (s.b. for details). The hash value can optionally be a filename. In this case, the file's content is used as the method's body.

top => C code or filename =head4 bottom => C code or filename

This defines arbitrary C code that is included in the top/bottom area of the generated C source.

after => <hashref> =head4 before => <hashref>

This option defines post and pre hooks for specific methods. For example:

  after => {
    'new' => q{...},
    'myMethod' => q{...},
  }

This defines two post hooks, one for the constructor and the second for a method named 'myMethod'. Ths hook code is inserted into the methods it is defined for inside an own C code block ({ ... }) so hook-local C variables can be defined as if it would be a function. Also all the parameters of the function can be accessed like in the actual method code.

attr( classname, attribute-name, attribute-type )

Defines an attribute in a class with the given name and type.

  $gen->attr('Shape','width','float');

meth( classname, method-signature, c-code )

Defines a method in a class of the given signature using the given piece of C code (or filename).

  $gen->meth('Shape','calcArea():float','...');

parent( classname, parent-classname, ... )

Defines the parent class(es) of a given class.

  $gen->parent('Shape','BaseClass1','BaseClass2');

after( classname, method-signature, c-code )

Defines a post hook for a method. The hook code is inserted into the method it is defined on, at the end of the method.

See below for special hook names.

before( classname, method-signature, c-code )

Defines a pre hook for a method. The hook code is inserted into the method it is defined on, at the beginning of the method.

The special hook names are:

  • new: The hook is attached to the constructor function.

  • delete: The hook is attached to the destructor function.

To illustrate this, here is an example of a hook that is installed after the constructor:

  $gen->after('new', q{printf("This is called when the object was constructed.\n");});

  $gen->before('new', q{printf("This is called when the object is about to be constructed.\n");});

A few things about constructor and destructor hooks should be noted: The before-new hook is called before the object (C variable "self") is created, so no manipulation of self can be done. The after-new hook however can access the self variable.

Also, the post-delete hook can access the self variable, but should be aware that it has already been free'd.

readFile( filename )

readFile() takes one argument, a filename, loads this file and extracts class, attribute and method definitions from it.

  $gen->readFile('c/Triangle.c');

Here is an example file:

  //------------------------------------------------------------------------------
  @class Triangle: Shape, Rectangle

  //------------------------------------------------------------------------------
  @top
  
        // this code is appended to the top-area of the generated C source
  
  //------------------------------------------------------------------------------
  @bottom
  
        // this code is appended to the top-area of the generated C source
  
  //------------------------------------------------------------------------------
  @attr prop:int
  
  //------------------------------------------------------------------------------
  // calculates the area of the triangle
  //
  @sub calcArea():float
  
  return self->width * self->height;
  
  //------------------------------------------------------------------------------
  // calculates the length of the outline of the triangle
  //
  @sub calcOutline():float
  
  return getWidth(self) * 2 + getHeight(self) * 2;

  //------------------------------------------------------------------------------
  @after new
  
        // this code is called in the constructor at the end
        
  //------------------------------------------------------------------------------
  @before calcArea

                // this code is called in the method 'calcArea' at the beginning

A line starting with '//' is ignored. A line that starts with an '@' is treated as a class or attribute definition line or as the start of a method definition. I hope this is self-explanatory?

Such files can be saved with an ".c" extension so that you can open them in your favourite C code editor and have fun with the highlighting.

func( signature, c-code-or-filename )

The func() method defines a normal C function. It takes as parameters the signature of the function and the code (which can be a code string or a filename):

  $gen->func('doth(float f, Shape s):int', '/* do sth... */');

generate( options )

  $gen->generate(
    file    => './main.c',
    globalheaders => ['stdio','stdlib'],
    localheaders => ['opengl'],
    main    => 'c/main.c',
    top     => 'c/top.c',
    bottom  => 'c/bottom.c',
    debug   => 1,
  );

The generate() method generates a single ANSI C compliant source file out of the given class definitions.

The options are:

file => filename

This defines the name of the C output file. This option is mandatory.

headers => Arrayref of headernames

This defines C headers that are to be included in the generated C file.

main => Source or filename of main function body

This defines the body (C code) of the main function of the generated C file. This can be either C code given as a string OR a filename which is loaded.

top => Source or filename of C code

This method adds arbitrary C code to the generated C file. The code is added after the class structs/typedefs and before the method (function) declarations.

bottom => Source or filename of C code

This method adds arbitrary C code to the generated C file. The code is added to the end of the file, but before the main function.

debug => 1/0

If the debug option is set to 1, then a stack trace is created and printed when a method could not be dispatched. This is handy for debugging but has a negative effect on the performance (due to the logbook that has to be maintained during runtime). Default is 0, so no stack trace is created and the normal message is printed.

toDot()

This method generates a Graphviz *.dot string out of the class hierarchy and additional information (attributes, methods). The dot string is returned.

toHtml()

This method creates a HTML API documentation to the class hierarchy that is defined. The HTML string is returned.

Object oriented features & C programming style

Throughout this document the style of programming that module lets the programmer use, is called object oriented, but this is just the canonical name, actually it is class oriented programming.

So you have defined a bunch of classes with attributes and methods. But how do you program the method logic in C? This module promises to make it possible to do this in an object-oriented fashion, so this is the section where this fashion is described.

For a more complete example, see the t/ directory in the module dictribution.

Class definition

This module lets you define classes and their methods and attributes. Class definition is not possible from within the C code.

Instanciation

Arbitrary instances of classes can be created from within the C code.

Suppose you defined a class named 'Circle'. You can then create an instance of that class like so (C code):

  Object c = new_Circle();

Important: All class instances in C are of the type "Object"!

There exists a type alias for the "Object" type named "my", so C code can be written a little more "Perl-like", e.g.:

  my c = new_Circle();

Instance destruction

Since there is a way to create instances, there is also a way to destroy them (free the memory they occupy).

A generic C function delete() is generated which can be used to destruct any object/instance:

  Object c = new_Circle();
  delete(c); // c now points to NULL

Instance print to STDOUT

The automatically generated C function dump() will print the content of any class instance to STDOUT:

  dump(myObject, 0, 2);

The first parameter is the object, the second the current level (always 0) and the second the maximum level to print.

Inheritance

A class inherits all attributes and methods from its parent class or classes. So multiple inheritance (multiple parent classes) is allowed.

Attribute access

Suppose you defined a class named 'Circle' with an attribute (could also be inherited). Then you can access this attribute the following:

  float r;
  float* r_ptr;
  int x = 42.0;
  Object c = new_Circle();
  r = getRadius(c);
  r_ptr = getRadiusPtr(c);
  
  setRadius(c, x);
  setRadiusPtr(c, &x);

As you can see, all methods (either getter or setter or other ones) need to get the object/instance as first parameter. This "self" parameter need not be written when defining the method, remember to define a method, only the addtional parameters are to be written:

  calcArea(int param):float

Remember: Always access the instance/object attributes via the getter or setter methods!.

Attribute overloading

Attributes once defined, must not be re-defined by child classes.

Method invocation

To invoke a method on an object/instance:

  Object c = new_Circle();
  printf("area = %f\n", calcArea(c));

The first argument of the method call is the object/instance the method is invoked on.

Method overloading

Methods once defined, can be overloaded by methods of the same class. Methods in a class can also be re-defined by child classes.

If a child class overwrites the method of one of its parent classes, the signatures must be the same, regarding the non-class typed parameters.

To illustrate this, here is an example of a parent class method signature: doSth(Shape s, float f):void - the first parameter is an object of class 'Shape', the second a native C float.

Suppose another classes tries to overwrite this method. In this case the first parameter's type is allowed to change (to any other class type!), but the second not, because its a native type. This will work: doSth(Circle s, float f):void but this not: doSth(int s, float f):void

Access "self" from within methods

When writing methods you need access to the object instance. This variable is "magically" available and is named "self". Here is an example of a method body:

  printf("radius of instance is %f\n", getRadius(self));

Default attributes

The following attributes are present in all classes. These attributes differ compared to user-defined attributes in the way that they can be accessed directly by dereferencing the instance/object pointer:

int classid

Each class has a globally unique ID, a positive number greater than zero.

  Object c = new_Circle();
  printf("c.classid = %d\n", c->classid);

char* classname

This is the name of the class of the object/instance. To access the classname, use accessor methods like for all other attributes, e.g.:

  Object c = new_Circle();
  printf("c.classname = %s\n", c->classname);

Beware, that, when you change the classname at runtime, methods may not be able to determine the actual implementation of a method to be applied to an object/instance.

LIMITATIONS & BUGS

This module is an early stage of development and has therefor some limitations and bugs. If you think, this module needs a certain feature, I would be glad to hear from you, also, if you find a bug, I would be glad to hear from you.

EXPORT

None by default.

SEE ALSO

Please send any hints on other modules trying to accomplish the same or a similar thing. I haven't found one, yet.

AUTHOR

Tom Kirchner, <tom@tomkirchner.com>

COPYRIGHT AND LICENSE

Copyright (C) 2011 by Tom Kirchner

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available.