C language metaprogramming and code generation from Python
Project description
calligra is a pure Python package that tries to modelize a subset of the C langage syntax in order to reason about C types, from Python scripts. Its main goals are to do metaprogrammation and code generation. It does not parse C code itself at all.
calligra was first designed to (un)serialize complex (but not too complex …) C structures from JSON.
1 Installation
1.1 Requirements
calligra requires Python 3. It has been tested on Python 3.6 on Linux but it should work on 3.4 and 3.6 and on Windows also. At the moment, it does not require any external Python modules/packages, but this might change in the future.
As calligra is intended to generate code, some external dependencies might be needed to compile the generated code.
1.2 From github
You can clone this repository and install it with setuptools directly:
$ python3 setup.py install --user
1.3 From pip
As every pip available package, you can install it easily with the pip package:
$ python3 -m pip install --user calligra
1.4 Tests
Tests are available in the source distribution (either from github or from pip) and are located in the tests/ directory. You can run them with setuptools:
$ python3 setup.py test
2 Howto
2.1 Introduction
As specified before, calligra is intended to reason about C types at a Python level.
Currently, you can modelize the following types:
primary types like char, int, float, double etc.
C strings (char*)
enum
struct, named and anonymous
union, named and anonymous
and the following declaration modifiers:
pointers
array
Nested array of pointers or pointers to array are not supported.
At the moment, you have to define everything from Python and generate everything.
In the future, you will be able to import definitions from :
pre-written C code (probably using pycparser)
JSON Schema
2.2 Examples
Lets start with a basic example. In the following code snippets we will be defining a C structure called person with 2 members:
a string name
an unsigned integer age
And then we will generate the associated C code.
First import the main modules:
import calligra
import calligra.stdlib
calligra module is where the C type/declaration syntax is modelized. calligra.stdlib is where standard C types are defined.
Then define the structure:
namespace = calligra.stdlib.namespace
person = calligra.struct(namespace, 'person')
person.add(
calligra.declaration(
namespace, namespace.get('char'), 'name', pointer = True
)
)
person.add(
calligra.declaration(
namespace, namespace.get('uint8_t'), 'age'
)
)
Finally, generate the C code:
print(person.define())
This should generate something similar to:
struct person {
char *name;
uint8_t age;
};
More advanced examples are located in the examples/ directory.
3 Modules
Conversion
Conversion modules are located in the calligra/convert/ directory and are meant to (un)serialize C types to and from another format (like JSON).
Currently available conversion modules are:
calligra.convert.jansson: to convert C types to and from JSON using the Jansson library.
3.1 Jansson
In order to use the jansson conversion module, just import the calligra.convert.jansson module:
import calligra.convert.jansson
After that, every type should now have a to_json and a from_json method. Those are actually calligra.functions object which you can define to generate the corresponding C code:
print(person.to_json.define())
Which should generate something similar to:
json_t *person_to_json(struct person const *person);
And for the function body:
print(person.to_json.code(body = True))
Which should generate something similar to (non-contractual code):
json_t *person_to_json(struct person const *person) {
json_t *json = json_object(), *child;
if(!json) {
return NULL;
}
/*name*/
if((person != NULL) && ((*person).name != NULL) && (*(*person).name != 0)) {
child = json_string((*person).name);
if(!child || json_object_set_new_nocheck(json, "name", child) != 0) {
if(child) {
json_decref(child);
}
json_decref(json);
return NULL;
}
}
/*age*/
if(person != NULL) {
child = json_integer((*person).age);
if(!child || json_object_set_new_nocheck(json, "age", child) != 0) {
if(child) {
json_decref(child);
}
json_decref(json);
return NULL;
}
}
return json;
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.