Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: compile

Issue 29333474: Issue 4125 - [emscripten] Convert filter classes to C++ (Closed)
Patch Set: Call parameters in JS wrappers generated statically Created Jan. 28, 2016, 9:26 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « .hgignore ('k') | compiled/ActiveFilter.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: compile
===================================================================
new file mode 100755
--- /dev/null
+++ b/compile
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+
+import json
+import os
+import re
+import subprocess
+import warnings
+
+EMSCRIPTEN_PATH = '../emscripten'
+SOURCE_DIR = './compiled'
+SOURCE_FILES = [
+ os.path.join(SOURCE_DIR, f)
+ for f in os.listdir(SOURCE_DIR)
+ if f.endswith('.cpp')
+]
+API_FILE = os.path.join(SOURCE_DIR, 'api.cpp')
+API_OUTPUT = os.path.join(SOURCE_DIR, 'api.js')
+COMPILER_OUTPUT = './lib/compiled.js'
+GENERATION_PARAMS = {
+ 'SHELL_FILE': "'%s'" % os.path.abspath(os.path.join(SOURCE_DIR, 'shell.js')),
+ 'TOTAL_MEMORY': 16*1024*1024,
+ 'TOTAL_STACK': 1*1024*1024,
+ 'ALLOW_MEMORY_GROWTH': 1,
+ 'NO_EXIT_RUNTIME': 1,
+ 'DISABLE_EXCEPTION_CATCHING': 0,
+ 'NO_DYNAMIC_EXECUTION': 1,
+ 'NO_BROWSER': 1,
+ 'NO_FILESYSTEM': 1,
+ 'INVOKE_RUN': 0,
+ 'NODE_STDOUT_FLUSH_WORKAROUND': 0,
+}
+DEFINES = ['DEBUG']
+ADDITIONAL_PARAMS = ['-O3', '-m32', '-std=gnu++11', '--memory-init-file', '0',
+ '--emit-symbol-map']
+
+def getenv():
+ path = []
+ env = {}
+ output = subprocess.check_output([
+ '/bin/sh', '-c', os.path.join(EMSCRIPTEN_PATH, 'emsdk_env.sh')])
+ for line in output.splitlines():
+ match = re.search(r'^\s*PATH\s*\+=\s*(.*)', line)
+ if match:
+ path.append(match.group(1))
+ match = re.search(r'^\s*(\w+)\s*=\s*(.*)', line)
+ if match:
+ env[match.group(1)] = match.group(2)
+ env['PATH'] = ':'.join([os.environ['PATH']] + path)
+ return env
+
+def generate_api(env):
+ params = [os.path.join(env['EMSCRIPTEN'], 'emcc'), '-E', API_FILE]
+ params.extend(ADDITIONAL_PARAMS)
+ output = subprocess.check_output(params, env=env)
+
+ differentiators = {}
+ differentiator = None
+
+ cls = None
+ method = None
+
+ def wrap_call(func, is_instance, result_type, string_args, arg_count=10):
+ params = ['arg%i' % i for i in range(arg_count)]
+ prefix = '''\
+function(%s)
+{
+''' % ', '.join(params)
+ suffix = '''\
+ return result;
+}'''
+
+ if result_type == 'string' or len(string_args):
+ prefix += ' var sp = Runtime.stackSave();\n'
+ suffix = ' Runtime.stackRestore(sp);\n' + suffix
+
+ for pos in string_args:
+ params[pos] = 'createString(%s)' % params[pos]
+
+ if is_instance:
+ params.insert(0, 'this._pointer')
+
+ if result_type == 'primitive':
+ prefix += ' var result = _%s(%s);\n' % (func, ', '.join(params))
+ elif result_type == 'string':
+ prefix += ' var result = createString();\n'
+ params.insert(0, 'result')
+ prefix += ' _%s(%s);\n' % (func, ', '.join(params))
+ prefix += ' result = getStringData(result);\n'
+ else:
+ prefix += ' var pointer = _%s(%s);\n' % (func, ', '.join(params))
+ if result_type in differentiators:
+ prefix += ' var type = _%s(pointer);\n' % differentiator['func']
+ prefix += ' if (type in %s_mapping)\n' % result_type
+ prefix += ' var result = new (exports[%s_mapping[type]])(pointer);\n' % result_type
+ prefix += ' else\n'
+ prefix += ' throw new Error("Unexpected %s type: " + type);\n' % result_type
+ else:
+ prefix += ' var result = %s(pointer);\n' % result_type
+
+ return prefix + suffix
+
+ def property_descriptor(property):
+ if property['type'] == 'static':
+ return 'value: %s' % property['getter']
+
+ result = 'get: %s' % wrap_call(
+ property['getter'], is_instance=True, result_type=property['type'],
+ string_args=[], arg_count=0
+ )
+ if property['setter'] is not None:
+ result += ', set: %s' % wrap_call(
+ property['setter'], is_instance=True, result_type='primitive',
+ string_args=[0] if property['type'] == 'string' else [],
+ arg_count=1
+ )
+ return result
+
+ def method_descriptor(method):
+ return wrap_call(
+ method['func'], is_instance=(method['type'] == 'instance'),
+ result_type=method['result'], string_args=method['string_args']
+ )
+
+ def write_class(file, cls):
+ name = cls['name']
+ if name in differentiators:
+ print >>file, 'var %s_mapping = %s;' % (
+ name, json.dumps(differentiators[name]['mapping'], sort_keys=True))
+
+ print >>file, 'exports.%s = createClass(%s);' % (
+ name, 'exports.' + cls['superclass'] if cls['superclass'] else '')
+ for property in cls['properties']:
+ print >>file, 'Object.defineProperty(exports.%s.prototype, "%s", {%s});' % (
+ name, property['name'], property_descriptor(property))
+ for method in cls['methods']:
+ obj = ('exports.%s' if method['type'] == 'class' else 'exports.%s.prototype') % name
+ print >>file, '%s.%s = %s;' % (
+ obj, method['name'], method_descriptor(method))
+ for initializer in cls['class_initializers']:
+ print >>file, '_%s();' % initializer
+
+ def handle_class(name):
+ if cls is not None:
+ write_class(file, cls)
+ differentiator = None
+ return {
+ 'name': command[1],
+ 'superclass': None,
+ 'properties': [],
+ 'methods': [],
+ 'class_initializers': [],
+ }
+
+ def handle_superclass(name):
+ if cls is None:
+ warnings.warn('Superclass declared outside a class: ' + name)
+ return
+ differentiator = None
+ cls['superclass'] = name
+
+ def handle_class_init(func):
+ if cls is None:
+ warnings.warn('Class initializer declared outside a class: ' + func)
+ return
+ differentiator = None
+ method = None
+ cls['class_initializers'].append(func)
+
+ def handle_differentiator(cls, func):
+ differentiator = {'func': func, 'mapping': {}}
+ differentiators[cls] = differentiator
+ return differentiator
+
+ def handle_differentiator_mapping(value, subclass):
+ if differentiator is None:
+ warnings.warn('Differentiator mapping declared without a differentiator: ' + subclass)
+ return
+ differentiator['mapping'][value] = subclass
+
+ def handle_property(type, name, getter, setter):
+ if cls is None:
+ warnings.warn('Property declared outside a class: ' + name)
+ return
+ method = None
+ differentiator = None
+ cls['properties'].append({
+ 'type': type,
+ 'name': name,
+ 'getter': getter,
+ 'setter': setter,
+ })
+
+ def handle_method(type, name, func):
+ if cls is None:
+ warnings.warn('Method declared outside a class: ' + name)
+ return
+ differentiator = None
+ method = {
+ 'type': type,
+ 'name': name,
+ 'func': func,
+ 'result': 'primitive',
+ 'string_args': [],
+ }
+ cls['methods'].append(method)
+ return method
+
+ def handle_method_result(type):
+ if method is None:
+ warnings.warn('Method result declared without a method definition')
+ return
+ method['result'] = type
+
+ def handle_string_arg(pos):
+ if method is None:
+ warnings.warn('Argument type declared without a method definition')
+ return
+ method['string_args'].append(int(pos))
+
+ with open(API_OUTPUT, 'w') as file:
+ for line in output.splitlines():
+ match = re.search(r'#pragma\s+comment\((.+?)\)', line)
+ if match:
+ command = match.group(1).strip().split()
+ if command[0] == 'class':
+ cls = handle_class(command[1])
+ elif command[0] == 'augments':
+ handle_superclass(command[1])
+ elif command[0] == 'class_init':
+ handle_class_init(command[1])
+ elif command[0] == 'differentiator':
+ differentiator = handle_differentiator(command[1], command[2])
+ elif command[0] == 'differentiator_mapping':
+ handle_differentiator_mapping(command[1], command[2])
+ elif command[0] == 'property':
+ handle_property('primitive', command[1], command[2], command[3] if len(command) > 3 else None)
+ elif command[0] == 'string_property':
+ handle_property('string', command[1], command[2], command[3] if len(command) > 3 else None)
+ elif command[0] == 'static_property':
+ handle_property('static', command[1], command[2], None)
+ elif command[0] == 'method':
+ method = handle_method('instance', command[1], command[2])
+ elif command[0] == 'class_method':
+ method = handle_method('class', command[1], command[2])
+ elif command[0] == 'string_result':
+ handle_method_result('string')
+ elif command[0] == 'pointer_result':
+ handle_method_result(command[1])
+ elif command[0] == 'string_arg':
+ handle_string_arg(command[1])
+ else:
+ warnings.warn('Unknown declaration: ' + str(command))
+
+ if cls is not None:
+ write_class(file, cls)
+
+def run_compiler(env):
+ params = [
+ os.path.join(env['EMSCRIPTEN'], 'emcc'),
+ '-o', COMPILER_OUTPUT,
+ '--post-js', API_OUTPUT,
+ ]
+ params.extend(SOURCE_FILES)
+ params.extend('-D' + flag for flag in DEFINES)
+ for key, value in GENERATION_PARAMS.iteritems():
+ params.extend(['-s', '%s=%s' % (key, str(value))])
+ params.extend(ADDITIONAL_PARAMS)
+ subprocess.check_call(params, env=env)
+
+if __name__ == '__main__':
+ env = getenv()
+ generate_api(env)
+ run_compiler(env)
« no previous file with comments | « .hgignore ('k') | compiled/ActiveFilter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld