import string def _find(s, sub, start=0, end=None): """Just like string.find, except it returns end or len(s) when not found. """ if end == None: end = len(s) pos = string.find(s, sub, start, end) if pos < 0: return end else: return pos def _gen_common_key(key, n, args): if len(key) > 0 and key in '123456789': return str(args[int(key) - 1]) elif key == 'x': return str(n) else: return key def _gen_arg(template, n, args, delimiter = '%'): result = '' i = 0 while i < len(template): # until the template is consumed # consume everything up to the first delimiter delimiter_pos = _find(template, delimiter, i) result = result + template[i:delimiter_pos] # The start position of whatever comes after the delimiter+key start = delimiter_pos + 2 key = template[start - 1 : start] # the key character. If there were no # delimiters left, key will be empty if key == 'n': result = result + `n` else: result = result + _gen_common_key(key, n, args) i = start return result def gen_function(template, n, *args, **keywords): r"""gen_function(template, n, [args...] ) -> string Generate a function declaration based on the given template. Sections of the template between '%(', '%)' pairs are repeated n times. If '%:' appears in the middle, it denotes the beginning of a delimiter. Sections of the template between '%{', '%}' pairs are ommitted if n == 0. %n is transformed into the string representation of 1..n for each repetition of n. %x, where x is a digit, is transformed into the corresponding additional argument. for example, >>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void') 'void abc(int a1, int a2); // all args are ints' >>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x') 'x abc();' >>> template = ''' template ... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) { ... PyObject* self; ... %( PyObject* a%n; ... %) if (!PyArg_ParseTuple(args, const_cast("O%(O%)"), &self%(, &a%n%))) ... return 0; ... T& target = from_python(self, Type()); ... %3to_python((target.*pmf)(%( ... from_python(a%n, Type())%:,%) ... ));%4 ... }''' >>> print gen_function(template, 0, 'R ', '', 'return ', '') template static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) { PyObject* self; if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; T& target = from_python(self, Type()); return to_python((target.*pmf)( )); } >>> print gen_function(template, 2, 'R ', '', 'return ', '') template static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { PyObject* self; PyObject* a1; PyObject* a2; if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) return 0; T& target = from_python(self, Type()); return to_python((target.*pmf)( from_python(a1, Type()), from_python(a2, Type()) )); } >>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();') template static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) { PyObject* self; PyObject* a1; PyObject* a2; PyObject* a3; if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) return 0; T& target = from_python(self, Type()); to_python((target.*pmf)( from_python(a1, Type()), from_python(a2, Type()), from_python(a3, Type()) )); return none(); } """ delimiter = keywords.get('delimiter', '%') result = '' i = 0 while i < len(template): # until the template is consumed # consume everything up to the first delimiter delimiter_pos = _find(template, delimiter, i) result = result + template[i:delimiter_pos] # The start position of whatever comes after the delimiter+key start = delimiter_pos + 2 key = template[start - 1 : start] # the key character. If there were no # delimiters left, key will be empty pairs = { '(':')', '{':'}' } if key in pairs.keys(): end = string.find(template, delimiter + pairs[key], start) assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!" delimiter_pos = end if key == '{': if n > 0: result = result + gen_function(template[start:end], n, args, delimiter) else: separator_pos = _find(template, delimiter + ':', start, end) separator = template[separator_pos+2 : end] for x in range(1, n + 1): result = result + _gen_arg(template[start:separator_pos], x, args, delimiter) if x != n: result = result + separator else: result = result + _gen_common_key(key, n, args) i = delimiter_pos + 2 return result def gen_functions(template, n, *args): r"""gen_functions(template, n, [args...]) -> string Call gen_function repeatedly with from 0..n and the given optional arguments. >>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'), void abc(); void abc(int a1); // all args are ints void abc(int a1, int a2); // all args are ints """ result = '' for x in range(n + 1): result = result + apply(gen_function, (template, x) + args) return result if __name__ == '__main__': import doctest doctest.testmod()