aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-03-14 13:41:30 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-03-14 13:41:30 -0700
commite3f438b1088f4da77157d3240d25f4c62a8d0207 (patch)
treec51c7c0140b7f848b010f4557d4410954bd97e5d
parent5fd0826bb86bac11150ace522f652b66f02baa22 (diff)
support c strings as parameters in bindings generator
-rwxr-xr-xtests/runner.py42
-rwxr-xr-xtools/bindings_generator.py55
2 files changed, 85 insertions, 12 deletions
diff --git a/tests/runner.py b/tests/runner.py
index 27100cbb..a1d29da4 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -5358,6 +5358,48 @@ Child2:9
*ok*
''', post_build=[post2, post3])
+ def test_scriptaclass_2(self):
+ header_filename = os.path.join(self.get_dir(), 'header.h')
+ header = '''
+ #include <stdio.h>
+ #include <string.h>
+
+ class StringUser {
+ char *s;
+ int i;
+ public:
+ StringUser(char *string, int integer) : s(strdup(string)), i(integer) {}
+ void Print(int anotherInteger, char *anotherString) {
+ printf("|%s|%d|%s|%d|\\n", s, i, anotherString, anotherInteger);
+ }
+ void CallOther(StringUser *fr) { fr->Print(i, s); }
+ };
+ '''
+ open(header_filename, 'w').write(header)
+
+ basename = os.path.join(self.get_dir(), 'bindingtest')
+ output = Popen([BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ #print output
+ assert 'Traceback' not in output, 'Failure in binding generation: ' + output
+
+ src = '''
+ #include "header.h"
+
+ #include "bindingtest.cpp"
+ '''
+
+ post = '''
+def process(filename):
+ src = open(filename, 'a')
+ src.write(open('bindingtest.js').read() + '\\n\\n')
+ src.write(\'\'\'
+ var user = new Module.StringUser("hello", 43);
+ user.Print(41, "world");
+ \'\'\')
+ src.close()
+'''
+ self.do_run(src, '|hello|43|world|41|', post_build=post)
+
def test_typeinfo(self):
if self.emcc_args is not None and self.emcc_args != []: return self.skip('full LLVM opts optimize out all the code that uses the type')
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py
index 4731abf3..5f65c82e 100755
--- a/tools/bindings_generator.py
+++ b/tools/bindings_generator.py
@@ -42,8 +42,22 @@ bindings, and to prevent DFE from removing the code we care about. The
JS bindings do more serious work, creating class structures in JS and
linking them to the C bindings.
-NOTE: ammo.js is currently the biggest consumer of this code. For some
- more docs you can see that project's README
+Notes:
+ * ammo.js is currently the biggest consumer of this code. For some
+ more docs you can see that project's README,
+
+ https://github.com/kripken/ammo.js
+
+ Another project using these bindings is box2d.js,
+
+ https://github.com/kripken/box2d.js
+
+ * C strings (char *) passed to functions are treated in a special way.
+ If you pass in a pointer, it is assumed to be a pointer and left as
+ is. Otherwise it must be a JS string, and we convert it to a C
+ string on the *stack*. The C string will live for the current
+ function call. If you need it for longer, you need to create a copy
+ in your C++ code.
'''
import os, sys, glob, re
@@ -507,6 +521,12 @@ function customizeVTable(object, replacementPairs) {
return object;
}
Module['customizeVTable'] = customizeVTable;
+
+// Converts a value into a C-style string.
+function ensureString(value) {
+ if (typeof value == 'number') return value;
+ return allocate(intArrayFromString(value), 'i8', ALLOC_STACK);
+}
''')
def generate_wrapping_code(classname):
@@ -645,17 +665,25 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
#print 'zz types:', map(lambda arg: arg['type'], args)
+ has_string_convs = False
+
# We can assume that NULL is passed for null pointers, so object arguments can always
# have .ptr done on them
- def justargs_fixed(args):
- ret = justargs(args)[:]
- for i in range(len(args)):
- arg = args[i]
- if clean_type(arg['type']) in classes:
- ret[i] += '.ptr'
- return ret
+ justargs_fixed = justargs(args)[:]
+ for i in range(len(args)):
+ arg = args[i]
+ clean = clean_type(arg['type'])
+ if clean in classes:
+ justargs_fixed[i] += '.ptr'
+ elif arg['type'].replace(' ', '') == 'char*':
+ justargs_fixed[i] = 'ensureString(' + justargs_fixed[i] + ')'
+ has_string_convs = True
calls = ''
+ if has_string_convs:
+ calls += 'var stack = Runtime.stackSave();\n';
+ calls += 'try {\n'
+
#print 'js loopin', params, '|', len(args)#, args
for args in params:
i = len(args)
@@ -667,12 +695,12 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
if constructor:
if not dupe:
calls += '''this.ptr = _%s_p%d(%s);
-''' % (fullname, i, ', '.join(justargs_fixed(args)[:i]))
+''' % (fullname, i, ', '.join(justargs_fixed[:i]))
else:
calls += '''this.ptr = _%s_p%d(%s);
-''' % (fullname, i, ', '.join(justargs_fixed(args)[:i]))
+''' % (fullname, i, ', '.join(justargs_fixed[:i]))
else:
- return_value = '''_%s_p%d(%s)''' % (fullname, i, ', '.join((['this.ptr'] if need_self else []) + justargs_fixed(args)[:i]))
+ return_value = '''_%s_p%d(%s)''' % (fullname, i, ', '.join((['this.ptr'] if need_self else []) + justargs_fixed[:i]))
print 'zz making return', classname, method['name'], method['returns'], return_value
if method['returns'] in classes:
# Generate a wrapper
@@ -682,6 +710,9 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
calls += ('return ' if ret != 'void' else '') + return_value + ';'
calls += '\n'
+ if has_string_convs:
+ calls += '} finally { Runtime.stackRestore(stack) }\n';
+
print 'Maekin:', classname, generating_classname, mname, mname_suffixed
if constructor:
calls += '''