Code::Class::C - Perl extension for creating ANSI C code from a set of class definitions to accomplish an object-oriented programming style.
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); }, }, );
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.).
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.
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:
The isa option lets you specify zero or more parent classes of the class that is to be defined.
isa
The attr option lets you define the attributes of the class that is to be defined.
attr
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).
The subs option lets you define the methods of the class that is to be defined.
subs
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.
This defines arbitrary C code that is included in the top/bottom area of the generated C source.
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.
{ ... }
Defines an attribute in a class with the given name and type.
$gen->attr('Shape','width','float');
Defines a method in a class of the given signature using the given piece of C code (or filename).
$gen->meth('Shape','calcArea():float','...');
Defines the parent class(es) of a given class.
$gen->parent('Shape','BaseClass1','BaseClass2');
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.
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() 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.
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... */');
$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:
This defines the name of the C output file. This option is mandatory.
This defines C headers that are to be included in the generated C file.
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.
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.
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.
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.
This method generates a Graphviz *.dot string out of the class hierarchy and additional information (attributes, methods). The dot string is returned.
This method creates a HTML API documentation to the class hierarchy that is defined. The HTML string is returned.
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.
This module lets you define classes and their methods and attributes. Class definition is not possible from within the C code.
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();
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
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.
A class inherits all attributes and methods from its parent class or classes. So multiple inheritance (multiple parent classes) is allowed.
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!.
Attributes once defined, must not be re-defined by child classes.
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.
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.
doSth(Shape s, float f):void
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
doSth(Circle s, float f):void
doSth(int s, float f):void
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));
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:
Each class has a globally unique ID, a positive number greater than zero.
Object c = new_Circle(); printf("c.classid = %d\n", c->classid);
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.
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.
None by default.
Please send any hints on other modules trying to accomplish the same or a similar thing. I haven't found one, yet.
Tom Kirchner, <tom@tomkirchner.com>
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.
To install Code::Class::C, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Code::Class::C
CPAN shell
perl -MCPAN -e shell install Code::Class::C
For more information on module installation, please visit the detailed CPAN module installation guide.