def process_overload_by_arg_count(orig_method, context): logging.debug('processing a overload by arg count: %s' + orig_method.name) acount = orig_method.overloads['by_arg_count'] switch = cpp.cpp_switch('lua_gettop(L)') for by_arg_count in acount: case = cpp.cpp_case() case.expr = len(by_arg_count.parameters) params = ['L'] if by_arg_count.is_virtual: params.append('lua_self') case.body.append(cpp.cpp_return(cpp.cpp_method_call('lua_munch_' + by_arg_count.name, params=params))) switch.exprs.append(case) #we bake the overload method and add it back to our context other_method = lua_context_builder.bake([by_arg_count], preprocess = False).translated[0] other_method.public = False context.translated.append(other_method) for item in other_method.execution: if type(item) == cpp.cpp_method_call: item.expr = orig_method.name if not orig_method.parent else 'lua_self->' + orig_method.name break orig_method.translation.execution.append(switch)
def init_translated_method(orig_method, context): assert 'translation' not in orig_method.__dict__ logging.debug('entered [init_translated_method] with method:' + repr(orig_method)) method = cpp.cpp_method('lua_munch_' + orig_method.name, static=True, returns= cpp.cpp_type('int'), params=[cpp.cpp_variable('L', cpp.cpp_type('lua_State', pointer=True))]) if orig_method.parent: method.parent = orig_method.parent.translation method.orig_name = orig_method.name method.public = True #now we embed the default object with a very specific format that will be useful later method.initialization = [] # will contain initialization steps method.validation = [] # will contain validation steps method.recover = [] # will contain the steps to translate the lua arg to a C++ arg method.execution = [] # will contain execution steps, i.e, calling the native method method.lua_return = [] # will contain the steps to push a value back to lua if not 'is_overload' in method.__dict__: method.is_overload = False if orig_method.parent and orig_method.is_virtual: method.parameters.append(cpp.cpp_variable('lua_self', cpp.cpp_type(orig_method.parent.qualname, pointer=True))) method.return_value = cpp.cpp_return(0) #we 'tie' the translated method on the original method #so it's easier to work with them without needing to search for them on every callback orig_method.translation = method
def process_virtual_function_callback(orig_method, context): lua_method = copy(orig_method.translation) lua_method.parameters = orig_method.translation.parameters[:-1] lua_method.exprs = [] lua_method.return_value = cpp.cpp_return(cpp.cpp_method_call(lua_method.name, params=['L', 'nullptr'])) orig_method.translation.parent.public.append(lua_method)
def process_function(function, context): method = function.translation #will hold the real variables the method uses, after initialization method.transformed_parameters = [] #adding an index value to each positional parameter #firstly we add the default initializers for each mapped type for i, parameter in enumerate(function.parameters): overriden_variable = lua_context_builder.apply_variable_initialization(parameter, context) overriden_variable.index = parameter.index = i if function.is_constructor else i + 2 method.transformed_parameters.append(overriden_variable) method.initialization.append(overriden_variable) #this additional step will ensure that the amount of parameters is correct method.validation.append('assert(lua_gettop(L) == %d)' % (len(function.parameters) + (0 if function.is_constructor else 1))) #then we add type checking for parameter in method.transformed_parameters: method.validation.append(lua_context_builder.apply_variable_check(parameter, context)) #then we get the variables from LUA if function.parent and not function.is_constructor: if function.is_virtual: cif = cpp.cpp_if(['lua_self != nullptr']) cif.body.append('lua_self = static_cast<{}*>(lua_touserdata(L, 1))'.format(function.parent.qualname)) method.recover.append(cif) else: method.initialization.append('{0}* lua_self = static_cast<{1}*>(lua_touserdata(L, 1))'.format(function.parent.qualname, function.parent.qualname)) for parameter in method.transformed_parameters: method.recover.append(lua_context_builder.apply_variable_conversion_from_target(parameter, context)) applied_parameters = [] #then we add type casting to the original variable type for tp, fp in zip(method.transformed_parameters, function.parameters): applied_parameters.append(tp.cast(cpp.cpp_static_cast, fp.ctype)) if function.is_constructor: method.execution.append('{0}* lua_self = new {0}({1})'.format(function.parent.qualname, ','.join(map(str,applied_parameters)))) method.execution.append('lua_pushlightuserdata(L, (void*) lua_self)') method.return_value = cpp.cpp_return(1) else: #then we call the original method! fname = function.name if not function.is_overload else function.orig_name method.execution.append(cpp.cpp_method_call(fname if not function.parent else 'lua_self->' + fname, applied_parameters)) if function.returns != cpp.cpp_type('void'): logging.debug('lua_return: translating variable %r to LUA', function.returns) #if the function is not void, we recover the method execution method_execution = method.execution[0] del method.execution[:] return_var = cpp.cpp_variable('lua_return', function.returns) #create a variable assignment method.execution.append(return_var.declare(return_var.assign(method_execution))) #push the value to lua method.lua_return.append(lua_context_builder.apply_variable_conversion_to_target(return_var, context)) print 'lua return is', method.lua_return #and then change the call function to 1 so LUA knows it has one value to unpack method.return_value = cpp.cpp_return(1) method.exprs += method.initialization + method.validation + method.recover + method.execution + method.lua_return logging.debug("finished translating: %r", method)
def init_translated_class(orig_class, context): assert 'translation' not in orig_class.__dict__ lua_cls = cpp.cpp_class('lua_munch_' + orig_class.identifier_name) orig_class.translation = lua_cls luaReg = cpp.cpp_variable_array('lua_reg_' + orig_class.identifier_name, cpp.cpp_type('constexpr luaL_Reg', static=True)) logging.debug('baking methods for class: %s : %s' % (orig_class.name ,orig_class.public)) #lua_cls.public.append(make_getter(orig_class)) #we now bake all methods and subclasses from this class, but not preprocess them class_ctx = lua_context_builder.bake(orig_class.public, preprocess=False) for item in class_ctx.translated: if item.public: lua_cls.public.append(item) else: lua_cls.protected.append(item) if type(item) == cpp.cpp_method and item.public: luaReg.expr.append('{ "%s" , lua_munch_%s::%s }' % (item.orig_name, orig_class.identifier_name, item.name)) lua_cls.public.append(make_binder(orig_class, lua_cls)) #the base methods are shims that only retrieve it's self and pass it down to the #base class for base in orig_class.bases: for item in base.public: if type(item) != cpp.cpp_method: continue method = cpp.cpp_method('lua_munch_' + item.name, static=True, returns=cpp.cpp_type('int'), params=[cpp.cpp_variable('L', cpp.cpp_type('lua_State', pointer=True))]) if item.parent: item.parameters.append(cpp.cpp_variable('lua_self', cpp.cpp_type(item.parent.name, pointer=True))) method.exprs.append('%s* lua_self = lua_munch_%s::get(L, %d)' % (orig_class.qualname, orig_class.identifier_name, 1)) method.exprs.append(cpp.cpp_return(cpp.cpp_method_call('lua_munch_%s::lua_munch_%s' % (item.parent.name, item.name), params=['L', 'lua_self']))) lua_cls.public.append(method) if not item.is_constructor: luaReg.expr.append('{ "%s" , lua_munch_%s::lua_munch_%s }' % (item.name, orig_class.name, item.name)) luaReg.expr.append('{ 0, 0 }') lua_cls.public.append(luaReg) context.binder_method.exprs.append('{}::bind(L)'.format(lua_cls.name)) luaReg.parent = lua_cls vardecl = luaReg.define() vardecl = vardecl.replace('static', '') context.luareg_declarations.append(vardecl) orig_class.translation = lua_cls
def lua_preprocess(data, context): classes = filter(lambda item: type(item) == cpp.cpp_class, data) functions = filter(lambda item: type(item) == cpp.cpp_method and item.parent == None, data) other = filter(lambda item: type(item) != cpp.cpp_method and type(item) != cpp.cpp_class, data) del data[:] #resolving overloads for item in classes: item.identifier_name = item.qualname\ .replace('::', '_')\ .replace(' ', '')\ .replace('<','_')\ .replace('>', '_')\ .replace(',', '_') process_functions(item) #resolving dependencies sorted_classes = [] class_set = set([]) previous_count = len(classes) iteration = 0 while classes: current = classes.pop(0) processed = True #print 'testing', current.name, current.dependencies for dependency in current.dependencies: if 'std' in dependency or dependency == current.qualname: continue #remove this once the generator knows how to get template items if '<' in dependency: templates = dependency[dependency.find('<') + 1:dependency.find('>')].split(',') current.dependencies += templates if not dependency in class_set and not iteration == 10: #print 'I dont have dependency: ', dependency classes.append(current) processed = False break if processed: #print '### added', current.name sorted_classes.append(current) class_set.add(current.qualname) iteration = 0 if previous_count == len(classes): if iteration == 10: raise Exception("Couldn't resolve dependencies for the classes:" + str(classes)) iteration += 1 previous_count = len(classes) fake_cls = cpp.cpp_class('Fake') fake_cls.public = functions process_functions(fake_cls) data += sorted_classes + fake_cls.public + other context.binder_method = cpp.cpp_method('luaopen_gdx', returns=cpp.cpp_type('int'), attributes=['extern', '"C"'], params=[cpp.cpp_variable('L', cpp.cpp_type('lua_State', pointer=True))]) context.luareg_declarations = [] context.binder_method.exprs.append('lua_newtable(L)') context.binder_method.return_value = cpp.cpp_return(1)