diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/bindings_generator.py | 55 | ||||
-rw-r--r-- | tools/eliminator/asm-eliminator-test-output.js | 52 | ||||
-rw-r--r-- | tools/eliminator/asm-eliminator-test.js | 23 | ||||
-rw-r--r-- | tools/js-optimizer.js | 83 | ||||
-rw-r--r-- | tools/shared.py | 15 | ||||
-rw-r--r-- | tools/webidl_binder.py | 432 |
6 files changed, 599 insertions, 61 deletions
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index 5bf0996e..9bc8b929 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -1,6 +1,61 @@ #!/usr/bin/env python2 ''' + + + + + + + + + + + + + + + + + + + + + + + + +XXX THIS IS DEPRECATED, see webidl_binder.py XXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use CppHeaderParser to parse some C++ headers, and generate binding code for them. Usage: diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 9caf99d0..1a5dca55 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -147,27 +147,25 @@ function looop3() { } } function looop4() { - var i = 0, helper = 0; + var i = 0, i$looptemp = 0; while (1) { do_it(); - helper = i + 1 | 0; - f(i, helper); - if (condition()) { - i = helper; - } else { + i$looptemp = i; + i = i + 1 | 0; + f(i$looptemp, i); + if (!condition()) { break; } } } function looop4b() { - var i = 0, helper = 0; + var i = 0, i$looptemp = 0; while (1) { do_it(); - helper = i + 1 | 0; - g(helper); - if (condition(i)) { - i = helper; - } else { + i$looptemp = i; + i = i + 1 | 0; + g(i); + if (!condition(i$looptemp)) { break; } } @@ -251,24 +249,22 @@ function multiloop($n_0, $35) { function multiloop2($n_0, $35) { $n_0 = $n_0 | 0; $35 = $35 | 0; - var $p_0 = 0, $39 = 0, $41 = 0, $46 = 0; + var $p_0 = 0, $41 = 0, $p_0$looptemp = 0; $n_0 = $35; $p_0 = (HEAP32[$15 >> 2] | 0) + ($35 << 1) | 0; while (1) { - $39 = $p_0 - 2 | 0; - $41 = HEAPU16[$39 >> 1] | 0; + $p_0$looptemp = $p_0; + $p_0 = $p_0 - 2 | 0; + $41 = HEAPU16[$p_0 >> 1] | 0; if ($41 >>> 0 < $2 >>> 0) { $_off0 = 0; } else { $_off0 = $41 - $2 & 65535; } - HEAP16[$39 >> 1] = $p_0; - $46 = $n_0 - 1 | 0; - if (($46 | 0) == 0) { + HEAP16[$p_0 >> 1] = $p_0$looptemp; + $n_0 = $n_0 - 1 | 0; + if (($n_0 | 0) == 0) { break; - } else { - $n_0 = $46; - $p_0 = $39; } } } @@ -901,4 +897,18 @@ function elimOneLoopVar4() { } } } +function elimOneLoopVarStillUsed() { + var $call10 = Math_fround(0), $curri$012 = 0, $j$010 = 0, $retval$0 = 0, $j$010$looptemp = 0; + while (1) { + $j$010$looptemp = $j$010; + $j$010 = $j$010 + 1 | 0; + if ((($curri$012 | 0) % ($j$010$looptemp | 0) & -1 | 0) == 0) { + break; + } + if (!(Math_fround($j$010 | 0) < $call10)) { + break; + } + } + return $retval$0 | 0; +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index a3de3d9d..d5bbd8d5 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -1131,5 +1131,26 @@ function elimOneLoopVar4() { } } } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4"] +function elimOneLoopVarStillUsed() { + var $0 = 0, $1 = 0, $arg$0 = 0, $arrayidx = 0, $call10 = Math_fround(0), $cmp = 0, $cmp11 = 0, $cmp119 = 0, $cmp12 = 0, $cmp7 = 0, $conv = 0, $conv8 = Math_fround(0), $conv9 = Math_fround(0), $curri$012 = 0, $inc = 0, $inc14$primes$0 = 0, $inc16 = 0, $j$010 = 0, $ok$0 = 0; + var $primes$011 = 0, $rem = 0, $retval$0 = 0, $sub = 0, $vararg_buffer1 = 0, label = 0, sp = 0; + while (1) { + $rem = ($curri$012 | 0) % ($j$010 | 0) & -1; + $cmp12 = ($rem | 0) == 0; + $inc = $j$010 + 1 | 0; + if ($cmp12) { + $ok$0 = 0; + break; + } + $conv8 = Math_fround($inc | 0); + $cmp11 = $conv8 < $call10; + if ($cmp11) { + $j$010 = $inc; + } else { + break; + } + } + return $retval$0 | 0; +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4", "elimOneLoopVarStillUsed"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index c4585b84..db85965d 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -3519,12 +3519,15 @@ function eliminate(ast, memSafe) { seenUses[name]++; } } else if (type === 'while') { + if (!asm) return; // try to remove loop helper variables specifically var stats = node[2][1]; var last = stats[stats.length-1]; if (last && last[0] === 'if' && last[2][0] === 'block' && last[3] && last[3][0] === 'block') { var ifTrue = last[2]; var ifFalse = last[3]; + clearEmptyNodes(ifTrue[1]); + clearEmptyNodes(ifFalse[1]); var flip = false; if (ifFalse[1][0] && ifFalse[1][0][0] === 'break') { // canonicalize break in the if var temp = ifFalse; @@ -3589,17 +3592,25 @@ function eliminate(ast, memSafe) { } } if (found < 0) return; + // if a loop variable is used after we assigned to the helper, we must save its value and use that. + // (note that this can happen due to elimination, if we eliminate an expression containing the + // loop var far down, past the assignment!) + var temp = looper + '$looptemp'; var looperUsed = false; - for (var i = found+1; i < stats.length && !looperUsed; i++) { + assert(!(temp in asmData.vars)); + for (var i = found+1; i < stats.length; i++) { var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition traverse(curr, function(node, type) { if (type === 'name' && node[1] === looper) { + node[1] = temp; looperUsed = true; - return true; } }); } - if (looperUsed) return; + if (looperUsed) { + asmData.vars[temp] = asmData.vars[looper]; + stats.splice(found, 0, ['stat', ['assign', true, ['name', temp], ['name', looper]]]); + } } for (var l = 0; l < helpers.length; l++) { for (var k = 0; k < helpers.length; k++) { @@ -4915,36 +4926,44 @@ function safeHeap(ast) { } } } else if (type === 'sub') { - var heap = node[1][1]; - if (heap[0] !== 'H') return; - var ptr = fixPtr(node[2], heap); - // SAFE_HEAP_LOAD(ptr, bytes, isFloat) - switch (heap) { - case 'HEAP8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAP16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAP32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAPF32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); - } - case 'HEAPF64': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + var target = node[1][1]; + if (target[0] === 'H') { + // heap access + var heap = target; + var ptr = fixPtr(node[2], heap); + // SAFE_HEAP_LOAD(ptr, bytes, isFloat) + switch (heap) { + case 'HEAP8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAPF32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + case 'HEAPF64': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + default: throw 'bad heap ' + heap; } - default: throw 'bad heap ' + heap; + } else { + assert(target[0] == 'F'); + // function table indexing mask + assert(node[2][0] === 'binary' && node[2][1] === '&'); + node[2][2] = makeAsmCoercion(['call', ['name', 'SAFE_FT_MASK'], [makeAsmCoercion(node[2][2], ASM_INT), makeAsmCoercion(node[2][3], ASM_INT)]], ASM_INT); } } }); diff --git a/tools/shared.py b/tools/shared.py index e912a700..82bdd98b 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -746,13 +746,14 @@ else: # Engine tweaks try: - new_spidermonkey = listify(SPIDERMONKEY_ENGINE) - if 'gcparam' not in str(new_spidermonkey): - new_spidermonkey += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap - if '-w' not in str(new_spidermonkey): - new_spidermonkey += ['-w'] - JS_ENGINES = map(lambda x: new_spidermonkey if x == SPIDERMONKEY_ENGINE else x, JS_ENGINES) - SPIDERMONKEY_ENGINE = new_spidermonkey + if SPIDERMONKEY_ENGINE: + new_spidermonkey = listify(SPIDERMONKEY_ENGINE) + if 'gcparam' not in str(new_spidermonkey): + new_spidermonkey += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap + if '-w' not in str(new_spidermonkey): + new_spidermonkey += ['-w'] + JS_ENGINES = map(lambda x: new_spidermonkey if x == SPIDERMONKEY_ENGINE else x, JS_ENGINES) + SPIDERMONKEY_ENGINE = new_spidermonkey except NameError: pass diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py new file mode 100644 index 00000000..0507cc78 --- /dev/null +++ b/tools/webidl_binder.py @@ -0,0 +1,432 @@ + +''' +WebIDL binder + +https://github.com/kripken/emscripten/wiki/WebIDL-Binder +''' + +import os, sys + +import shared + +sys.path.append(shared.path_from_root('third_party')) +sys.path.append(shared.path_from_root('third_party', 'ply')) + +import WebIDL + +class Dummy: + def __init__(self, init): + for k, v in init.iteritems(): + self.__dict__[k] = v + + def getExtendedAttribute(self, name): + return None + +input_file = sys.argv[1] +output_base = sys.argv[2] + +shared.try_delete(output_base + '.cpp') +shared.try_delete(output_base + '.js') + +p = WebIDL.Parser() +p.parse(open(input_file).read()) +data = p.finish() + +interfaces = {} +implements = {} + +for thing in data: + if isinstance(thing, WebIDL.IDLInterface): + interfaces[thing.identifier.name] = thing + elif isinstance(thing, WebIDL.IDLImplementsStatement): + implements.setdefault(thing.implementor.identifier.name, []).append(thing.implementee.identifier.name) + +#print interfaces +#print implements + +pre_c = [] +mid_c = [] +mid_js = [] + +pre_c += [r''' +#include <emscripten.h> +'''] + +mid_c += [r''' +extern "C" { +'''] + +def emit_constructor(name): + global mid_js + mid_js += [r'''%s.prototype = %s; +%s.prototype.constructor = %s; +%s.prototype.__class__ = %s; +%s.__cache__ = {}; +Module['%s'] = %s; +''' % (name, 'Object.create(%s.prototype)' % (implements[name][0] if implements.get(name) else 'WrapperObject'), name, name, name, name, name, name, name)] + + +mid_js += [''' +// Bindings utilities + +function WrapperObject() { +} +'''] + +emit_constructor('WrapperObject') + +mid_js += [''' +function getCache(__class__) { + return (__class__ || WrapperObject).__cache__; +} +Module['getCache'] = getCache; + +function wrapPointer(ptr, __class__) { + var cache = getCache(__class__); + var ret = cache[ptr]; + if (ret) return ret; + ret = Object.create((__class__ || WrapperObject).prototype); + ret.ptr = ptr; + return cache[ptr] = ret; +} +Module['wrapPointer'] = wrapPointer; + +function castObject(obj, __class__) { + return wrapPointer(obj.ptr, __class__); +} +Module['castObject'] = castObject; + +Module['NULL'] = wrapPointer(0); + +function destroy(obj) { + if (!obj['__destroy__']) throw 'Error: Cannot destroy object. (Did you create it yourself?)'; + obj['__destroy__'](); + // Remove from cache, so the object can be GC'd and refs added onto it released + delete getCache(obj.__class__)[obj.ptr]; +} +Module['destroy'] = destroy; + +function compare(obj1, obj2) { + return obj1.ptr === obj2.ptr; +} +Module['compare'] = compare; + +function getPointer(obj) { + return obj.ptr; +} +Module['getPointer'] = getPointer; + +function getClass(obj) { + return obj.__class__; +} +Module['getClass'] = getClass; + +// Converts a value into a C-style string. +function ensureString(value) { + if (typeof value == 'string') return allocate(intArrayFromString(value), 'i8', ALLOC_STACK); + return value; +} + +'''] + +C_FLOATS = ['float', 'double'] + +def type_to_c(t, non_pointing=False): + #print 'to c ', t + t = t.replace(' (Wrapper)', '') + if t == 'Long': + return 'int' + elif t == 'Short': + return 'short' + elif t == 'Void': + return 'void' + elif t == 'String': + return 'char*' + elif t == 'Float': + return 'float' + elif t == 'Double': + return 'double' + elif t == 'Boolean': + return 'bool' + elif t in interfaces: + return (interfaces[t].getExtendedAttribute('Prefix') or [''])[0] + t + ('' if non_pointing else '*') + else: + return t + +def take_addr_if_nonpointer(m): + if m.getExtendedAttribute('Ref') or m.getExtendedAttribute('Value'): + return '&' + return '' + +def deref_if_nonpointer(m): + if m.getExtendedAttribute('Ref') or m.getExtendedAttribute('Value'): + return '*' + return '' + +def type_to_cdec(raw): + name = ret = type_to_c(raw.type.name, non_pointing=True) + if raw.getExtendedAttribute('Const'): ret = 'const ' + ret + if name not in interfaces: return ret + if raw.getExtendedAttribute('Ref'): + return ret + '&' + if raw.getExtendedAttribute('Value'): + return ret + return ret + '*' + +def render_function(class_name, func_name, sigs, return_type, non_pointer, copy, operator, constructor, func_scope, call_content=None, const=False): + global mid_c, mid_js, js_impl_methods + + #print 'renderfunc', class_name, func_name, sigs, return_type, constructor + + bindings_name = class_name + '_' + func_name + min_args = min(sigs.keys()) + max_args = max(sigs.keys()) + + c_names = {} + + # JS + + cache = ('getCache(%s)[this.ptr] = this;' % class_name) if constructor else '' + call_prefix = '' if not constructor else 'this.ptr = ' + call_postfix = '' + if return_type != 'Void' and not constructor: call_prefix = 'return ' + if not constructor: + if return_type in interfaces: + call_prefix += 'wrapPointer(' + call_postfix += ', ' + return_type + ')' + + args = ['arg%d' % i for i in range(max_args)] + if not constructor: + body = ' var self = this.ptr;\n' + pre_arg = ['self'] + else: + body = '' + pre_arg = [] + + for i in range(max_args): + # note: null has typeof object, but is ok to leave as is, since we are calling into asm code where null|0 = 0 + body += " if (arg%d && typeof arg%d === 'object') arg%d = arg%d.ptr;\n" % (i, i, i, i) + body += " else arg%d = ensureString(arg%d);\n" % (i, i) + + for i in range(min_args, max_args): + c_names[i] = 'emscripten_bind_%s_%d' % (bindings_name, i) + body += ' if (arg%d === undefined) { %s%s(%s)%s%s }\n' % (i, call_prefix, '_' + c_names[i], ', '.join(pre_arg + args[:i]), call_postfix, '' if 'return ' in call_prefix else '; ' + (cache or ' ') + 'return') + c_names[max_args] = 'emscripten_bind_%s_%d' % (bindings_name, max_args) + body += ' %s%s(%s)%s;\n' % (call_prefix, '_' + c_names[max_args], ', '.join(pre_arg + args), call_postfix) + if cache: + body += ' ' + cache + '\n' + mid_js += [r'''function%s(%s) { +%s +}''' % ((' ' + func_name) if constructor else '', ', '.join(args), body[:-1])] + + # C + + for i in range(min_args, max_args+1): + raw = sigs.get(i) + if raw is None: continue + sig = [arg.type.name for arg in raw] + + c_arg_types = map(type_to_c, sig) + + normal_args = ', '.join(['%s arg%d' % (c_arg_types[j], j) for j in range(i)]) + if constructor: + full_args = normal_args + else: + full_args = type_to_c(class_name, non_pointing=True) + '* self' + ('' if not normal_args else ', ' + normal_args) + call_args = ', '.join(['%sarg%d' % ('*' if raw[j].getExtendedAttribute('Ref') else '', j) for j in range(i)]) + if constructor: + call = 'new ' + type_to_c(class_name, non_pointing=True) + call += '(' + call_args + ')' + elif call_content is not None: + call = call_content + else: + call = 'self->' + func_name + call += '(' + call_args + ')' + + if operator: + assert '=' in operator, 'can only do += *= etc. for now, all with "="' + cast_self = 'self' + if class_name != func_scope: + # this function comes from an ancestor class; for operators, we must cast it + cast_self = 'dynamic_cast<' + type_to_c(func_scope) + '>(' + cast_self + ')' + call = '(*%s %s %sarg0)' % (cast_self, operator, '*' if sig[0] in interfaces else '') + + pre = '' + + basic_return = 'return ' if constructor or return_type is not 'Void' else '' + return_prefix = basic_return + return_postfix = '' + if non_pointer: + return_prefix += '&'; + if copy: + pre += ' static %s temp;\n' % type_to_c(return_type, non_pointing=True) + return_prefix += '(temp = ' + return_postfix += ', &temp)' + + c_return_type = type_to_c(return_type) + mid_c += [r''' +%s%s EMSCRIPTEN_KEEPALIVE %s(%s) { +%s %s%s%s; +} +''' % ('const ' if const else '', type_to_c(class_name) if constructor else c_return_type, c_names[i], full_args, pre, return_prefix, call, return_postfix)] + + if not constructor: + if i == max_args: + dec_args = ', '.join(map(lambda j: type_to_cdec(raw[j]) + ' arg' + str(j), range(i))) + js_call_args = ', '.join(['%sarg%d' % (('(int)' if sig[j] in interfaces else '') + ('&' if raw[j].getExtendedAttribute('Ref') or raw[j].getExtendedAttribute('Value') else ''), j) for j in range(i)]) + + js_impl_methods += [r''' %s %s(%s) { + %sEM_ASM_%s({ + var self = Module['getCache'](Module['%s'])[$0]; + if (!self.hasOwnProperty('%s')) throw 'a JSImplementation must implement all functions, you forgot %s::%s.'; + %sself.%s(%s)%s; + }, (int)this%s); + }''' % (c_return_type, func_name, dec_args, + basic_return, 'INT' if c_return_type not in C_FLOATS else 'DOUBLE', + class_name, + func_name, class_name, func_name, + return_prefix, + func_name, + ','.join(['$%d' % i for i in range(1, max_args)]), + return_postfix, + (', ' if js_call_args else '') + js_call_args)] + + +for name, interface in interfaces.iteritems(): + js_impl = interface.getExtendedAttribute('JSImplementation') + if not js_impl: continue + implements[name] = [js_impl[0]] + +names = interfaces.keys() +names.sort(lambda x, y: 1 if implements.get(x) and implements[x][0] == y else (-1 if implements.get(y) and implements[y][0] == x else 0)) + +for name in names: + interface = interfaces[name] + + mid_js += ['\n// ' + name + '\n'] + mid_c += ['\n// ' + name + '\n'] + + global js_impl_methods + js_impl_methods = [] + + cons = interface.getExtendedAttribute('Constructor') + if type(cons) == list: raise Exception('do not use "Constructor", instead create methods with the name of the interface') + + js_impl = interface.getExtendedAttribute('JSImplementation') + if js_impl: + js_impl = js_impl[0] + + # Methods + + seen_constructor = False # ensure a constructor, even for abstract base classes + for m in interface.members: + if m.identifier.name == name: + seen_constructor = True + break + if not seen_constructor: + mid_js += ['function %s() { throw "cannot construct a %s, no constructor in IDL" }\n' % (name, name)] + emit_constructor(name) + + for m in interface.members: + if not m.isMethod(): continue + constructor = m.identifier.name == name + if not constructor: + parent_constructor = False + temp = m.parentScope + while temp.parentScope: + if temp.identifier.name == m.identifier.name: + parent_constructor = True + temp = temp.parentScope + if parent_constructor: + continue + if not constructor: + mid_js += [r''' +%s.prototype.%s = ''' % (name, m.identifier.name)] + sigs = {} + return_type = None + for ret, args in m.signatures(): + if return_type is None: + return_type = ret.name + else: + assert return_type == ret.name, 'overloads must have the same return type' + for i in range(len(args)+1): + if i == len(args) or args[i].optional: + assert i not in sigs, 'overloading must differentiate by # of arguments (cannot have two signatures that differ by types but not by length)' + sigs[i] = args[:i] + render_function(name, + m.identifier.name, sigs, return_type, + m.getExtendedAttribute('Ref'), + m.getExtendedAttribute('Value'), + (m.getExtendedAttribute('Operator') or [None])[0], + constructor, + func_scope=m.parentScope.identifier.name) + mid_js += [';\n'] + if constructor: + emit_constructor(name) + + for m in interface.members: + if not m.isAttr(): continue + attr = m.identifier.name + + get_name = 'get_' + attr + mid_js += [r''' + %s.prototype.%s= ''' % (name, get_name)] + render_function(name, + get_name, { 0: [] }, m.type.name, + None, + None, + None, + False, + func_scope=interface, + call_content=take_addr_if_nonpointer(m) + 'self->' + attr, + const=m.getExtendedAttribute('Const')) + + set_name = 'set_' + attr + mid_js += [r''' + %s.prototype.%s= ''' % (name, set_name)] + render_function(name, + set_name, { 1: [Dummy({ 'type': m.type })] }, 'Void', + None, + None, + None, + False, + func_scope=interface, + call_content='self->' + attr + ' = ' + deref_if_nonpointer(m) + 'arg0', + const=m.getExtendedAttribute('Const')) + + if not interface.getExtendedAttribute('NoDelete'): + mid_js += [r''' + %s.prototype.__destroy__ = ''' % name] + render_function(name, + '__destroy__', { 0: [] }, 'Void', + None, + None, + None, + False, + func_scope=interface, + call_content='delete self') + + # Emit C++ class implementation that calls into JS implementation + + if js_impl: + pre_c += [r''' +class %s : public %s { +public: +%s +}; +''' % (name, type_to_c(js_impl, non_pointing=True), '\n'.join(js_impl_methods))] + +mid_c += ['\n}\n\n'] +mid_js += ['\n'] + +# Write + +c = open(output_base + '.cpp', 'w') +for x in pre_c: c.write(x) +for x in mid_c: c.write(x) +c.close() + +js = open(output_base + '.js', 'w') +for x in mid_js: js.write(x) +js.close() + |