aboutsummaryrefslogtreecommitdiff
path: root/tools/bindings_generator.py
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-07-03 23:51:38 -0700
committerAlon Zakai <alonzakai@gmail.com>2011-07-03 23:51:38 -0700
commit7653c3b900216a31fd3b6d64afff486bd597111e (patch)
tree3b5a9a3f34009e54c69685d02439cb4dae9e4308 /tools/bindings_generator.py
parent15db95111555a911e295725141ddd10323a85373 (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.py108
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()
+