diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-07-03 23:51:38 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-07-03 23:51:38 -0700 |
commit | 7653c3b900216a31fd3b6d64afff486bd597111e (patch) | |
tree | 3b5a9a3f34009e54c69685d02439cb4dae9e4308 /tools/bindings_generator.py | |
parent | 15db95111555a911e295725141ddd10323a85373 (diff) |
initial work on bindings generator, using CppHeaderParser and ply. llvm-gcc only for now
Diffstat (limited to 'tools/bindings_generator.py')
-rw-r--r-- | tools/bindings_generator.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py new file mode 100644 index 00000000..99d5e889 --- /dev/null +++ b/tools/bindings_generator.py @@ -0,0 +1,108 @@ +''' +Use CppHeaderParser to parse some C++ headers, and generate binding code for them. + +Usage: + bindings_generator.py BASENAME HEADER1 HEADER2 ... + + BASENAME is the name used for output files (with added suffixes). + HEADER1 etc. are the C++ headers to parse + +We generate the following: + + * BASENAME.c: C bindings file, with generated C wrapper functions. You will + need to build this with your project, and make sure it compiles + properly by adding the proper #includes etc. You can also just + #include this file itself in one of your existing project files. + + * BASENAME.js: JavaScript bindings file, with generated JavaScript wrapper + objects. This is a high-level wrapping, using native JS classes. +''' + +import os, sys, glob + +abspath = os.path.abspath(os.path.dirname(__file__)) +def path_from_root(*pathelems): + return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems))) +exec(open(path_from_root('tools', 'shared.py'), 'r').read()) + +# Find ply and CppHeaderParser +sys.path = [path_from_root('third_party', 'ply'), path_from_root('third_party', 'CppHeaderParser')] + sys.path +import CppHeaderParser + +#print glob.glob(path_from_root('tests', 'bullet', 'src', 'BulletCollision', 'CollisionDispatch', '*.h')) + +basename = sys.argv[1] + +# First pass - read everything + +classes = {} + +for header in sys.argv[2:]: + #[('tests', 'bullet', 'src', 'BulletCollision/CollisionDispatch/btCollisionWorld.h')]: + parsed = CppHeaderParser.CppHeader(header) + #header = CppHeaderParser.CppHeader(path_from_root('tests', 'bullet', 'src', 'btBulletDynamicsCommon.h')) + #print header.classes.keys() + #print dir(header.classes['btCollisionShape']) + #print header.classes['btCollisionWorld']['methods']['public'] + for cname, clazz in parsed.classes.iteritems(): + if len(clazz['methods']['public']) > 0: # Do not notice stub classes + print 'Seen', cname + classes[cname] = clazz + +# Second pass - generate bindings + +gen_c = open(basename + '.c', 'w') +gen_js = open(basename + '.js', 'w') + +gen_c.write('extern "C" {\n') + +for cname, clazz in classes.iteritems(): + print 'Generating', cname + # TODO: Generate all parent class (recursively) data too + + constructor_counter = 0 + + for method in clazz['methods']['public']: + #print ' ', method['name'], method + + mname = method['name'] + args = method['parameters'] + constructor = mname == cname + + # C + + ret = (cname + ' *') if constructor else method['rtnType'] + callprefix = 'new ' if constructor else 'self->' + typedargs = ', '.join( ([] if constructor else [cname + ' * self']) + map(lambda arg: arg['type'] + ' ' + arg['name'], args) ) + justargs = ', '.join(map(lambda arg: arg['name'], args)) + fullname = cname + '__' + mname + + gen_c.write(''' +%s emscripten_bind_%s(%s) { + return %s%s(%s); +} +''' % (ret, fullname, typedargs, callprefix, mname, justargs)) + + # JS + + if constructor: + gen_js.write(''' +function %s(%s) { + this.ptr = _emscripten_bind_%s(%s); +} +''' % (cname + (str(constructor_counter) if constructor_counter > 0 else ''), justargs, fullname, justargs)) + constructor_counter += 1 + else: # TODO: handle case of multiple constructors + gen_js.write(''' +%s.prototype.%s = function(%s) { + %s_emscripten_bind_%s(this.ptr%s); +} +''' % (cname, mname, justargs, 'return ' if ret != 'void' else '', fullname, (', ' if len(justargs) > 0 else '') + justargs)) + +# Finish up + +gen_c.write('\n}\n') +gen_c.close() + +gen_js.close() + |