1# Copyright (c) 2017-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2# Copyright (c) 2017-2018 Centre national de la recherche scientifique (CNRS)
3# Copyright (c) 2018-2020 Simons Foundation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http:#www.apache.org/licenses/LICENSE-2.0.txt
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# Authors: Gregory Kramida, Olivier Parcollet, Nils Wentzell, tayral
18
19import sys, imp
20import re
21import os
22from mako.template import Template
23import importlib
24import collections
25
26# the correspondance c type -> py_type
27c_to_py_type = {'void' : 'None', 'int' : 'int', 'long' : 'int', 'double' : "float", "std::string" : "str"}
28
29# Translation for formatting of parsing converter.
30basic_types_formatting = {'double' : 'd', 'int' : 'i'}
31
32# Translate the name of the c++ type to the python type.
33# for doc signatures.
34def translate_c_type_to_py_type(t) :
35    if t in c_to_py_type : return c_to_py_type[t]
36    m = re.match('std::vector<(.*)>',t)
37    if m: return "list[%s]"%translate_c_type_to_py_type(m.group(1))
38    # numpy, etc...
39    return t
40
41class cfunction:
42    """
43       Representation of one overload of a C++ function or method.
44    """
45    def __init__(self, signature, calling_pattern = None, no_self_c = False, is_constructor = False,
46             is_method = False,  is_static = False, release_GIL_and_enable_signal = False, c_name = None, doc = '') :
47      """
48        Parameters
49        ----------
50
51        signature : string
52             signature of the function, with types, parameter names and default value
53             rtype( arg1 name1, arg2 name2 = default2, ....)
54             it can be :
55                - a string :
56                     rtype (arg1 name1, arg2 name2 = default2, ....)
57                - a string :
58                     rtype c_name ( arg1 name1, arg2 name2 = default2, ....)
59                - a dict [expert only] : rtype -> string , args -> list of tuples [ (c_type, variable_name, default_value)]
60                           where rtype is the C++ type returned by the function.
61
62        calling_pattern : string
63              A string containing a piece of C++ code to call the C++ function.
64              This code can use :
65                - self_c  : a reference to the C++ object (except for constructor, and static method).
66                - self_class : the name of the class of the C++ object (only for static method)
67                - the name of the parameters.
68              It should define a "result" variable :
69                - unless for a constructor or if the C++ return type is void.
70                - result shall be of any type from which the C++ return type is (move) constructible.
71              If calling_pattern is None, a default one is synthesized by the generator,
72              assuming the C++ function has exactly the signature given by the signature parameter of this function
73              including the c_name in it (which is then mandatory).
74
75        no_self_c : boolean.
76                    Do not generate self_c reference in C++ code, in some rare calling_pattern. Avoid a compiler warning.
77        is_constructor : boolean
78        is_method : boolean
79        is_static : boolean.
80                    If True, it is a static method
81        release_GIL_and_enable_signal : boolean, expert only
82          - For long functions in pure C++.
83          - If True, the GIL is released in the call of the C++ function and restored after the call.
84          - It also saves the signal handler of python and restores it after the call,
85            and enables the C++ signal_handler.
86          - This allows e.g. to intercept Ctrl-C during the long C++ function.
87          - **Requirement** :
88             The function wrapped must be pure C++, i.e.  no call whatsoever to the python C API, directly or indirectly.
89             otherwise the behaviour is undefined.
90        doc : string
91            the doc string.
92
93      """
94      #c_name : internal use only
95      self._calling_pattern = calling_pattern
96      self.is_constructor = is_constructor
97      self.no_self_c = no_self_c
98      self.doc = doc
99      self.is_method = is_method
100      self.is_static = is_static
101      self._dict_call =  None
102      if is_static : assert is_method, "is_static only works with method"
103      self.release_GIL_and_enable_signal = release_GIL_and_enable_signal
104      assert isinstance(signature, str) or isinstance(signature, dict), "Signature must be a string of a dict: cf doc"
105      self.c_name = c_name # Not none for internal call only
106      ## Analyse signature.
107      self.args, self.namespace = [], ''
108      if isinstance(signature, str) : # it is a string, we analyse it to get the rtype, and args
109        signature = re.sub('operator\(\s*\)','__operator_call',signature) # temp. replacement, to make the regex easier
110        m = re.match(r"\s*(.*?)\s*\((.*)\)",signature)
111        self.rtype, args = m.group(1).strip() or None, m.group(2).strip()
112        # extract the c_name if present
113        if self.rtype :
114            spl = self.rtype.strip().rsplit(' ',1)
115            if not is_constructor and len(spl)> 1 and '>' not in spl[-1] :
116                self.rtype, c_name_fully_qualified = spl
117                self.namespace, self.c_name = c_name_fully_qualified.rsplit('::',1 ) if ':' in c_name_fully_qualified else ('', c_name_fully_qualified)
118                if self.c_name == '__operator_call' : self.c_name = "operator()"
119        if args.strip().startswith("**") : # special case : dict call
120            assert calling_pattern is None, "When ** is given as argument, no calling pattern can be provided"
121            self._dict_call =  args[2:]
122            args, self.args = '','' # no argument
123        def f(): # analyse the argument, be careful that , can also be in type, like A<B,C>, so we count the < >
124            acc = ''
125            for s in args.split(',') :
126                acc += (',' if acc else '') + s.strip()
127                if acc.count('<') == acc.count('>') :
128                    r, acc = acc,''
129                    yield r
130        def g(a) :
131            if '=' in a :
132              l,r = a.split('=')
133              return l.strip().rsplit(' ') + [r]
134            else :
135              return a.rsplit(' ',1)
136        #args = [ re.sub('=',' ',x).split() for x in f() if x] # list of (type, name, default) or (type, name)
137        args = [ g(x) for x in f() if x] # list of (type, name, default) or (type, name)
138      else:
139          # mostly internal use, give signature as a dict
140          self.rtype = signature.pop("rtype", None)
141          args = signature.pop('args',())
142          self.c_name = signature.pop("c_name", '')
143      for a in args: # put back the default if there is none
144        # treat the case when the type is const T *, or T* (e.g. const char *).
145        # Need to regroup the first pieces.
146        assert len(a)>1, 'Incorrect signature %s: did you forget the name of the parameter ?'%a
147        if a[0] == 'const' : a = [' '.join(a[:2])] + list(a[2:])
148        if a[1] == '*' : a = [' '.join(a[:2])] + list(a[2:])
149        if len(a) == 2 : (t,n),d = a,None
150        elif len(a) == 3 : t,n,d = a
151        else : raise RuntimeError("Syntax error in overload: args = %s"%args)
152        self.args.append([t.strip(),n.strip(),d])
153      # end analyze signature
154
155      # ensure no variable starts with __
156      for t,n,d in self.args :
157          assert not n.startswith('__'), "Variables names starting with __ are reserved for internal use"
158      #
159      assert self.c_name or self._calling_pattern or self.is_constructor, "You must specify a calling_pattern or the signature must contain the name of the function"
160      if self.is_constructor :
161        assert self.rtype == None,  "Constructor must not have a return type"
162        self.is_method = False
163
164    def _get_calling_pattern1(self) :
165        """Generation only: gets the calling_pattern or synthesize the default"""
166        if not self._dict_call: return ''
167        return """if (PySequence_Size(args)>0) {PyErr_SetString(PyExc_TypeError, "The function must be called only with named arguments"); goto error_return;}
168           if (!convertible_from_python<%s>(keywds,true)) goto error_return;
169           auto dict_transcript = convert_from_python<%s>(keywds);
170        """%(self._dict_call, self._dict_call)
171
172    def _get_calling_pattern(self) :
173        """Generation only: gets the calling_pattern or synthesize the default"""
174        if self._calling_pattern : return self._calling_pattern
175        s = "%s result = "%self.rtype if self.rtype != "void" else ""
176        self_c = ""
177        if self.is_method:
178            self_c = "self_c." if not self.is_static else "self_class::"
179        # the wrapped types are called by pointer
180        args = ",".join( n for t,n,d in self.args)
181        args = args if self._dict_call is None else "dict_transcript"
182        return "%s %s%s(%s)"%(s,self_c, (self.namespace + '::' if self.namespace else '') + self.c_name, args)
183
184    def _get_signature (self):
185        """Signature for the python doc"""
186        rtype = translate_c_type_to_py_type(self.rtype) if self.rtype else ''
187        args_rep = ", ".join(["%s %s%s"%(translate_c_type_to_py_type(t),n,r' = ' + str(d).replace('"',"'") if d else '') for t,n,d in self.args])
188        return "({args_rep}) -> {rtype}".format(**locals())
189
190    def _get_c_signature (self):
191        """Signature for the C++ calling errors"""
192        name = self.c_name if self.c_name else "(no C++ name)"
193        rtype = self.rtype if self.rtype else ''
194        args_rep = ", ".join(["%s %s"%(t,n) for t,n,d in self.args])
195        return "{name}({args_rep}) -> {rtype}".format(**locals())
196
197    def __repr__(self):
198        return "C++ function of signature :  %s"%(self._get_signature())
199
200    def _parsing_format(self) :
201      """Generation only: the formatting for the PyParse_xxx calls"""
202      def f(t) :
203          return basic_types_formatting[t] if t in basic_types_formatting else 'O&'
204      l1 = [ f(t) for  t,n,d in self.args if d==None]
205      l2 = [ f(t) for  t,n,d in self.args if d!=None]
206      if l2 : l2.insert(0,'|') # starts the default arguments, cf python doc
207      return ''.join(l1 + l2)
208
209    def _generate_doc(self) :
210        doc = "\n".join([ "   " + x.rstrip() for x in self.doc.split('\n')])
211        doc = doc.replace('"',"'") # the " are replaced by \"r.
212        #doc = doc.replace('"',r'\"') # the " are replaced by \"r. Does not work, makes \\"
213        if self._dict_call is not None : return doc
214        return "Signature : %s\n%s"%( self._get_signature(),doc)
215
216class pyfunction:
217    """
218       Representation of one python function of the extension
219       It is basically :
220         - a python name
221         - a list of overload
222         - possibly some preprocessing/postprocessing python code.
223    """
224    def __init__(self, name, arity = None, is_method = False, is_static = False, doc = ''):
225      """
226        - name : name given in Python
227        - arity : arity of the function
228        - is_method : boolean
229        - is_static : boolean. Is is a static method
230        - doc : the doc string.
231        - overloads : a list of cfunction objects representing the various C++ overloads of the function
232      """
233      self.py_name =name       # name given in python
234      self.arity = arity
235      self.is_method = is_method  # can be a method, a function...
236      self.is_static = is_static  #
237      self.doc = doc
238      self.overloads = [] # List of all C++ overloads
239      self.do_implement = True # in some cases, we do not want to implement it automatically, (special methods).
240      self.is_constructor = False
241
242    def add_overload(self, **kw) :
243        self.overloads.append(cfunction(**kw))
244        return self
245
246    def _generate_doc(self) :
247        if len(self.overloads) == 1 : #only one overload
248            s = "\n".join([f._generate_doc() for f in self.overloads])
249        else :
250            s = "\n".join([self.doc, "\n"] + [f._generate_doc() for f in self.overloads])
251        s=s.replace('@{','').replace('@}','')
252        return repr(s)[1:-1] # remove the ' ' made by repr
253
254
255class converter_:
256    """
257    Representation of a simple converter for a struct
258    """
259    def __init__(self, c_type, doc=''):
260        """
261        Parameters
262        ----------
263
264        c_type : string
265                C++ type to be converted.
266        """
267        self.c_type = c_type
268        self.doc = doc
269        self.members = []
270
271    class member_:
272        pass
273
274    def add_member(self, c_name, c_type, initializer = '', doc = ''):
275        """
276        Add a class member
277
278        Parameters
279        ----------
280        c_name : string
281                 name of the variable in C++
282        c_type : string
283                 type of the C++ variable
284        initializer : string
285                  Default value
286        doc : string
287              the doc string.
288        """
289        m = self.member_()
290        m.c_name, m.c_type, m.initializer, m.doc = (c_name, c_type, initializer.strip(), doc) # the strip is crucial for empty string
291        self.members.append(m)
292
293    def generate(self):
294        """ Generate the C code"""
295        # generate the code for the converters
296        script_path = os.path.dirname(os.path.abspath( __file__ ))
297        tpl = Template(filename=script_path + '/mako/converters.cxx', strict_undefined=True)
298        rendered = tpl.render(c=self)
299        return rendered
300
301class class_:
302    """
303       Representation of a wrapped type
304    """
305    def __init__(self, py_type, c_type, c_type_absolute = None, hdf5 = False, arithmetic = None, serializable = None,
306            export = True, is_printable = False, doc = '', comparisons ='') :
307      """
308        Parameters
309        ----------
310
311        py_type : string
312                Name given in Python
313        c_type : string
314                C++ type to be wrapped.
315        c_type_absolute : string
316                full path of c_type, no using, no alias (need for the py_converter hpp file)
317        hdf5 : boolean
318                generate the hdf5 write/read function from C++ triqs hdf5 protocol and register them in the hdf_archive
319        arithmetic : tuple of strings
320
321          Determines the operations to be implemented.
322          - The idea is to give an abstract description of the mathematical structure to be implemented :
323            an algebra, a group, a vector space, and so on.
324            The generator will then implement all necessary functions, by calling their C++ counterparts.
325          - Possible values :
326               - ("abelian_group") : implements + and -
327               - ("vector_space", Scalar) : implements a vector_space, with scalar Scalar
328               - ("algebra", Scalar) : implements an algebra, with scalar Scalar
329               - ("algebra_with_unit", with_options..., Scalars...) :
330                  implements an algebra, with:
331                    - scalars Scalar... : the scalars
332                    - with_options is (possibly empty) list of options :
333                        - with_unit :  +/- of an element with a scalar (injection of the scalar with the unit)
334                        - with_unary_minus  : implement unary minus
335               - "add_only" : implements only +
336               - with_inplace_operators  : option to deduce the +=, -=, ...
337                 operators from +,-, .. It deduces the possibles terms to put at the rhs, looking at the
338                 case of the +,- operators where the lhs is of the type of self.
339                 NB : The operator is mapped to the corresponding C++ operators (for some objects, this may be faster)
340                 so it has to be defined in C++ as well....
341               - .... more to be defined.
342        serializable : boolean
343           Whether and how the object is to be serialized.  Possible values are :
344           - "tuple" : reduce it to a tuple of smaller objects, using the
345              boost serialization compatible template in C++, and the converters of the smaller objects.
346           - "h5" : serialize via a string, made by
347              triqs::serialize/triqs::deserialize.
348              Requires hdf5 >1.8.9.
349           - "repr" : serialize via a string produced by python repr, reconstructed by eval.
350
351        is_printable : boolean
352             If true, generate the str, repr from the C++ << stream operator
353        comparisons : string
354             a chain with all operators separated by space, e.g. "== != < >"
355        export : boolean [True]
356             if True, the class converter are exported to modules that import this module.
357        doc : string
358             the doc string.
359      """
360      self.c_type = c_type
361      self.c_type_absolute = c_type_absolute or c_type
362      self.implement_regular_type_converter = False # Default. Overrule with add_regular_type_converter
363      self.py_type = py_type
364      c_to_py_type[self.c_type] = self.py_type # register the name translation for the doc generation
365      self.hdf5 = hdf5
366      assert serializable in [None, "h5", "tuple", "repr"]
367      self.serializable = serializable
368      self.is_printable = is_printable
369      self.comparisons = comparisons
370      self.iterator = None
371      self.doc = doc
372      self.methods = {} #  a dict : string -> pyfunction for each method name
373      self.constructor = None # a pyfunction  for the constructors.
374      self.members= [] # a list of _member
375      self.properties= [] # a list of _property
376      self.export = export
377
378      # If hdf5 is True, wrap the C++.
379      # We cannot generate a default implementation with error message as h5::group might not be available.
380      # FIXME Remove triqs dependence
381      if hdf5:
382          self.add_method("void __write_hdf5__(h5::group gr, std::string key)", calling_pattern = "h5_write(gr, key, self_c);", doc = "hdf5 writing")
383
384      # Init arithmetic
385      # expect a tuple : "algebra", "scalar1", "scalar2", etc...
386      self.number_protocol = {}
387      if arithmetic :
388          if not isinstance(arithmetic, tuple) : arithmetic = (arithmetic,)
389          # read the with_... option and clean them for the list
390          with_unary_minus = 'with_unary_minus' in arithmetic
391          with_unit = 'with_unit' in arithmetic
392          with_inplace_operators = 'with_inplace_operators' in arithmetic
393          arithmetic = [x for x in arithmetic if not x.startswith("with_")]
394          add =  arithmetic[0] in ("algebra", "abelian_group", "vector_space", "add_only")
395          abelian_group = arithmetic[0] in ("algebra",  "abelian_group", "vector_space")
396          vector_space = arithmetic[0] in ("algebra", "vector_space")
397          algebra = arithmetic[0] in ("algebra",)
398
399          if add :
400            # add
401            add = pyfunction(name ="__add__",arity = 2)
402            add.add_overload (calling_pattern = "+", signature = {'args' : [(self.c_type,'x'), (self.c_type,'y')], 'rtype' :self.c_type})
403            self.number_protocol['add'] = add
404
405          if abelian_group :
406            #sub
407            sub = pyfunction(name ="__sub__",arity = 2)
408            sub.add_overload (calling_pattern = "-", signature = {'args' :[(self.c_type,'x'), (self.c_type,'y')], 'rtype' : self.c_type})
409            self.number_protocol['subtract'] = sub
410
411          if vector_space :
412            # mul
413            mul = pyfunction(name ="__mul__", arity = 2)
414            for scalar in arithmetic[1:] :
415               mul.add_overload (calling_pattern = "*", signature = {'args' :[(self.c_type,'x'), (scalar,'y')], 'rtype' : self.c_type})
416               mul.add_overload (calling_pattern = "*", signature = {'args' :[(scalar,'x'), (self.c_type,'y')], 'rtype' : self.c_type})
417            self.number_protocol['multiply'] = mul
418            # div
419            div = pyfunction(name ="__div__", arity = 2)
420            for scalar in arithmetic[1:] :
421               div.add_overload (calling_pattern = "/", signature = {'args' :[(self.c_type,'x'), (scalar,'y')], 'rtype' : self.c_type})
422            self.number_protocol['divide'] = div
423            self.number_protocol['true_divide'] = div
424            self.number_protocol['floor_divide'] = div
425
426          if algebra :
427            mul.add_overload (calling_pattern = "*", signature = {'args' :[(self.c_type,'x'), (self.c_type,'y')], 'rtype' : self.c_type})
428
429          if with_unit: # Allow + and - between scalar and operator
430            assert algebra, "The with_unit option only makes sense for algebra"
431            for scal in arithmetic[1:] :
432                add = self.number_protocol['add']
433                add.add_overload (calling_pattern = "+", signature = {'args' :[(self.c_type,'x'), (scal,'y')], 'rtype' : self.c_type})
434                add.add_overload (calling_pattern = "+", signature = {'args' :[(scal,'x'), (self.c_type,'y')], 'rtype' : self.c_type})
435                sub = self.number_protocol['subtract']
436                sub.add_overload (calling_pattern = "-", signature = {'args' :[(self.c_type,'x'), (scal,'y')], 'rtype' : self.c_type})
437                sub.add_overload (calling_pattern = "-", signature = {'args' :[(scal,'x'), (self.c_type,'y')], 'rtype' : self.c_type})
438
439          if with_unary_minus :
440                # Allow unary - on an operator
441                neg = pyfunction(name = "__neg__", arity = 1)
442                neg.add_overload (calling_pattern = "-", signature = {'args' :[(self.c_type,'x')], 'rtype' : self.c_type})
443                self.number_protocol['negative'] = neg
444
445          if with_inplace_operators : self.deduce_inplace_arithmetic()
446
447    def add_regular_type_converter(self):
448        self.implement_regular_type_converter = True
449
450    def deduce_inplace_arithmetic(self) :
451        """Deduce all the +=, -=, *=, /= operators from the +, -, *, / operators"""
452        def one_op(op, name, iname) :
453            if name not in self.number_protocol : return
454            impl = pyfunction(name = iname, arity = 2)
455            for overload in self.number_protocol[name].overloads :
456                x_t,y_t = overload.args[0][0], overload.args[1][0]
457                if x_t == self.c_type : # only when first the object
458                  impl.add_overload (calling_pattern = op+"=", signature = {'args' : [(x_t,'x'), (y_t,'y')], 'rtype' :overload.rtype})
459            self.number_protocol['inplace_'+name] = impl
460        one_op('+',"add","__iadd__")
461        one_op('-',"subtract","__isub__")
462        one_op('*',"multiply","__imul__")
463        one_op('/',"divide","__idiv__")
464        one_op('/',"true_divide","__idiv__")
465        one_op('/',"floor_divide","__idiv__")
466
467    def add_constructor(self, signature, calling_pattern = None, intermediate_type = None, doc = ''):
468        """
469        Parameters
470        ----------
471
472        signature : string
473            signature of the function, with types, parameter names and defaut value
474            rtype( arg1 name1, arg2 name2 = default2, ....)
475            signature can be :
476               - a string of 2 possible forms (i.e. c_name can be omitted) :
477                    - rtype (arg1 name1, arg2 name2 = default2, ....)
478                    - rtype c_name ( arg1 name1, arg2 name2 = default2, ....)
479               - a dict : rtype -> string , args -> list of tuples [ (c_type, variable_name, default_value)]
480               - rtype : the C++ type returned by the function. None for constructor
481            default_value is None when there is no default.
482
483        calling_pattern : string, expert only
484            - Pattern to rewrite the call of the c++ constructor.
485            - It is a string, argument name and defining a result of the c_type
486              e.g., the default pattern is ::
487              auto result = c_type (a,b,c)
488
489        intermediate_type : string
490          - Name of a C++ type to be used for constructing the object
491            which is then constructed as c_type { intermediate_type {....}}
492            E.g. Put a regular_type here when wrapping a view.
493
494        doc : string
495            the doc string.
496        """
497        f = cfunction(signature, calling_pattern = calling_pattern, is_constructor = True, is_method = True,  doc = doc)
498        all_args = ",".join(n  for t,n,d in f.args)
499        all_args = all_args if f._dict_call is None else "convert_from_python<%s>(keywds)"%f._dict_call # call with the keywds argument
500        f._calling_pattern = '' if f._dict_call is None else "if (!convertible_from_python<%s>(keywds,true)) goto error_return;\n"%f._dict_call
501        if calling_pattern is not None :
502          f._calling_pattern, all_args = calling_pattern + ';\n', "std::move(result)"
503        if intermediate_type:
504          f._calling_pattern += "((%s *)self)->_c = new %s(%s (%s));"%(self.py_type, self.c_type, intermediate_type, all_args)
505        else :
506          f._calling_pattern += "((%s *)self)->_c = new %s (%s);"%(self.py_type, self.c_type,all_args)
507
508        if not self.constructor :
509            self.constructor =  pyfunction(name = "__init__", is_method = True, doc = doc)
510            self.constructor.is_constructor = True
511        self.constructor.overloads.append(f)
512
513    def add_method(self, signature, name =None, calling_pattern = None, no_self_c = False, is_method = False,  is_static = False,
514                   doc = '', release_GIL_and_enable_signal = False, c_name = None):
515        """
516        Add a C++ overload to a method of name name.
517
518        Parameters
519        ----------
520
521        signature : string
522            signature of the function, with types, parameter names and defaut value
523            rtype( arg1 name1, arg2 name2 = default2, ....)
524            signature can be :
525              - a string of 2 possible forms (i.e. c_name can be omitted) :
526                  - rtype (arg1 name1, arg2 name2 = default2, ....)
527                  - rtype c_name ( arg1 name1, arg2 name2 = default2, ....)
528              - a dict : rtype -> string , args -> list of tuples [ (c_type, variable_name, default_value)]
529              - rtype : the C++ type returned by the function. None for constructor
530            default_value is None when there is no default.
531
532        name : string
533               name given in Python
534
535        c_name : string
536               name given in C++
537               If None, the C++ name extracted from the signature is used.
538
539        calling_pattern : string
540          - Pattern to rewrite the call of the c++ function,
541          - It is a string, using self_c, argument name and defining result at the end if rtype != void
542            e.g., the default pattern is :
543            auto result = self_c.method_name(a,b,c).
544          - If None, the signature must contain c_name
545        no_self_c : boolean.
546                    do not generate self_c reference in C++ code, in
547                    some rare calling_pattern. Avoid a compiler warning.
548        is_method : boolean
549        is_static : boolean
550                    Is is a static method
551        doc : string
552              the doc string.
553
554        release_GIL_and_enable_signal : boolean, expert only
555         - For long functions in pure C++.
556         - If True, the GIL is released in the call of the C++ function and restored after the call.
557         - It also saves the signal handler of python and restores it after the call,
558           and enables the C++ signal_handler.
559         - This allows e.g. to intercept Ctrl-C during the long C++ function.
560         - **Requirement** :
561            The function wrapped must be pure C++, i.e.  no call whatsoever to the python C API, directly or indirectly.
562            otherwise the behaviour is undefined.
563       """
564        f = cfunction(signature, calling_pattern = calling_pattern, no_self_c = no_self_c, is_constructor = False,
565             is_method = True,  is_static = is_static, release_GIL_and_enable_signal = release_GIL_and_enable_signal, doc = doc, c_name = c_name or name)
566        name = name or f.c_name
567        if name not in self.methods :
568            self.methods[name] = pyfunction(name = name, is_method = True, is_static = is_static, doc = doc)
569        self.methods[name].overloads.append(f)
570
571    def add_call(self, **kw) :
572        """
573        Add the __call__ operator.
574
575        It just calls add_method, for the operator(), with name = "__call__"
576
577        Cf add_method documentation.
578        """
579        if 'c_name' not in kw and 'calling_pattern' not in kw : kw['c_name']= "operator()"
580        self.add_method(name = "__call__", **kw)
581
582    class _iterator:
583        def __init__(self,c_type, c_cast_type, begin, end) :
584          self.c_type, self.c_cast_type, self.begin, self.end = c_type, c_cast_type, begin, end
585
586    def add_iterator(self, c_type = "const_iterator", c_cast_type = None, begin = "std::begin", end = "std::end") :
587        """
588        Add an iterator, wrapping a C++ iterator.
589
590        Parameters
591        ----------
592
593        c_type : string
594                 type of the C++ variable
595        c_cast_type : string
596                 If not None, the result of the C++ iterator dereference if converted to the cast_type.
597        begin, end : string
598                 Functions to find begin and end.
599        """
600        self.iterator = self._iterator(c_type, c_cast_type, begin, end)
601
602    class _member:
603        def __init__(self, c_name, c_type, py_name, read_only, doc):
604            """
605            Parameters
606            ----------
607
608            c_name : string
609                     name in C
610            c_type : string
611                     type in C
612            py_name : string
613                     name in Python
614
615            """
616            self.c_name, self.c_type, self.py_name, self.doc, self.read_only = c_name, c_type, py_name or c_name, doc, read_only
617
618        def _generate_doc(self) :
619          doc = "\n".join([ "   " + x.strip() for x in self.doc.split('\n')])
620          doc = doc.replace('@{','').replace('@}','')
621          return repr(doc)[1:-1] # remove the ' ' made by repr
622
623    def add_member(self, c_name, c_type, py_name = None, read_only = False, doc = ''):
624        """
625        Add a class member
626
627        Parameters
628        ----------
629        c_name : string
630                 name of the variable in C++
631        c_type : string
632                 type of the C++ variable
633        py_name : string
634                  name of the variable in python. If None, use c_name.
635        read_only : boolean
636                    is a read only parameter
637
638        doc : string
639              the doc string.
640        """
641        self.members.append( self._member(c_name, c_type, py_name, read_only, doc))
642
643    class _property:
644        def __init__(self, name, getter, setter, doc) :
645          self.name, self.getter, self.setter, self.doc = name, getter, setter, doc
646
647        def _generate_doc(self) :
648          doc = "\n".join([ "   " + x.strip() for x in self.doc.split('\n')])
649          doc = doc.replace('@{','').replace('@}','')
650          return repr(doc)[1:-1] # remove the ' ' made by repr
651
652    def add_property(self,  getter, setter = None, name = None, doc = ''):
653        """
654        Add a property
655
656        Parameters
657        ----------
658         - getter : the cfunction representing the get part
659         - setter : the cfunction representing the set part or None if the property if read only
660         - name : name in python. If None, try to use the C++ name of the getter.
661         - doc : the doc string.
662        """
663        if not isinstance(getter, str) : getter.is_method = True
664        self.properties.append( self._property(name or getter.c_name, getter, setter, doc) )
665
666    def add_len(self, c_name = None, calling_pattern = None, doc = "Length") :
667        """
668        Add the len operator
669        """
670        if not c_name and not calling_pattern : c_name = "size"
671        self.add_method(name = "__len__impl", calling_pattern = calling_pattern, signature="int %s()"%c_name, doc= doc)
672        self.methods['__len__impl'].do_implement = False # do not implement automatically, the signature is special
673
674    def add_getitem(self, signature, calling_pattern = None, doc = "operator[]" ) :
675        """
676        Add a the __getitem__ operator
677        """
678        self.add_method(name = "__getitem__impl", calling_pattern = calling_pattern, doc = doc, signature = signature, c_name = "operator[]")
679
680    def add_setitem(self, signature, calling_pattern = None, doc = "operator[]", **d ) :
681        """
682        Add a the __setitem__ operator
683        """
684        self.add_method(name = "__setitem__impl", calling_pattern = calling_pattern or "self_c[i] = v", doc = doc, signature = signature, **d)
685
686    def add_method_copy(self, clone_function = "cpp2py::make_clone") :
687        """Add a method copy, that make a **deep** copy, using the clone function"""
688        self.add_method(name = "copy", calling_pattern = self.c_type + " result = %s(self_c)"%clone_function,
689                        signature = self.c_type +"()", doc = "Make a copy (clone) of self")
690
691    def add_method_cpp_copy(self) :
692        """Add a method sh_copy, that make an ordinary copy in C++"""
693        self.add_method(name = "sh_copy", calling_pattern = self.c_type + " result = self_c", signature = self.c_type +"()", doc = "Make a copy of self")
694
695    def add_method_copy_from(self) :
696        """Add a copy_from, using C++ assignment"""
697        # other by pointer, it is necessarly a wrapped type
698        self.add_method(name = "copy_from", calling_pattern = " self_c = other", signature = 'void(' + self.c_type +" other)", doc = "Assignment")
699
700    def _prepare_for_generation(self) :
701        """Internal :  Called just before the code generation"""
702        self.has_mapping_protocol = '__getitem__impl' in self.methods or '__len__impl' in self.methods
703        if '__setitem__impl' in self.methods and not  '__getitem__impl' in self.methods : raise RuntimeError("Cannot generate a class with a setter and no getter")
704
705class module_:
706    """
707       Representation of a module
708    """
709    def __init__(self, full_name,  doc = '', app_name = None) :
710        """
711        Parameters
712        ----------
713
714        full_name : string
715                    complete name of the module (after install, e.g.  triqs.gf)
716
717        doc : string
718              doc string
719
720        """
721        self.full_name = full_name if app_name is None or app_name=="triqs" else app_name+"."+full_name
722        self.name = full_name.rsplit('.',1)[-1]
723        self.doc = doc
724        self.classes = {}    # dict : string -> class_. Key is the Python type
725        self.converters = {} # dict : string -> converter
726        self.functions = {}  # functions : dict : string -> function_. Modules functions. Key is the python name.
727        self.include_list = []
728        self.enums = []
729        self.using =[]
730        self.imports =[]
731        self._preamble = ''
732
733    def add_class(self, cls):
734        """
735          Add a class into the module.
736          It should not exist in the module already.
737        """
738        if cls.py_type in self.classes : raise IndexError("The class %s already exists"%cls.py_type)
739        self.classes[cls.py_type] = cls
740
741    def add_converter(self, conv):
742        """
743          Add a converter into the module.
744          It should not exist in the module already.
745        """
746        if conv.c_type in self.converters : raise IndexError("The class %s already exists"%conv.c_type)
747        self.converters[conv.c_type] = conv
748
749    def add_function(self, signature, name =None, calling_pattern = None,  doc = '', release_GIL_and_enable_signal = False, c_name = None):
750        """
751        Add a C++ overload to function of the module
752
753        Parameters
754        ----------
755
756        signature : string
757           signature of the function, with types, parameter names and defaut value
758           rtype( arg1 name1, arg2 name2 = default2, ....)
759           signature can be :
760              - a string of 2 possible forms (i.e. c_name can be omitted) :
761                  - rtype (arg1 name1, arg2 name2 = default2, ....)
762                  - rtype c_name ( arg1 name1, arg2 name2 = default2, ....)
763              - a dict : rtype -> string , args -> list of tuples [ (c_type, variable_name, default_value)]
764              - rtype : the C++ type returned by the function. None for constructor
765           default_value is None when there is no default.
766
767        name : string
768               name given in Python
769
770        c_name : string
771               name given in C++
772               If None, the C++ name extracted from the signature is used.
773
774        calling_pattern : string
775          - Pattern to rewrite the call of the c++ function,
776          - It is a string, using self_c, argument name and defining result at the end if rtype != void
777            e.g., the default pattern is :
778            auto result = self_c.method_name(a,b,c).
779          - If None, the signature must contain c_name
780
781        doc : string
782              the doc string.
783
784        release_GIL_and_enable_signal : boolean, expert only
785         - For long functions in pure C++.
786         - If True, the GIL is released in the call of the C++ function and restored after the call.
787         - It also saves the signal handler of python and restores it after the call,
788           and enables the C++ signal_handler.
789         - This allows e.g. to intercept Ctrl-C during the long C++ function.
790         - **Requirement** :
791            The function wrapped MUST be pure C++, i.e.  no call whatsoever to the python C API, directly or indirectly.
792            otherwise the behaviour is undefined.
793       """
794        f = cfunction(signature, calling_pattern = calling_pattern, release_GIL_and_enable_signal = release_GIL_and_enable_signal, doc = doc,c_name = c_name or name)
795        name = name or f.c_name
796        if name not in self.functions :
797            self.functions[name] = pyfunction(name = name, doc = doc)
798        self.functions[name].overloads.append(f)
799
800    def add_include(self, *filenames) :
801        """
802        Add the filenames as C++ include in the generated wrapper and header.
803        """
804        self.include_list.extend(filenames)
805
806    def add_using(self,ns) :
807        """
808        Add the using statement into the generated wrapper (and NOT the header).
809        """
810        self.using.append(ns)
811
812    def add_imports(self, *lst):
813        """
814          Add a dependent import to the module.
815        """
816        self.imports += lst
817
818    def add_preamble(self, preamble) :
819        """
820        Add the using statement into the generated wrapper (and NOT the header).
821        """
822        self._preamble += preamble + '\n'
823
824    class _enum:
825        def __init__(self, c_name, values, c_namespace, doc) :
826            self.c_name, self.c_namespace, self.values, self.doc = c_name, c_namespace + "::", values, doc
827            self.c_name_absolute = self.c_namespace + self.c_name
828
829    def add_enum(self, c_name, values, c_namespace ="", doc = '') :
830        """
831          Add an enum into the module.
832
833          Parameters
834          ----------
835
836          c_name : string
837                  name in C++
838          c_namespace: string
839                     namespace of the enum
840          values : list of string
841                  represents the C++ enum values
842          doc : string
843                the doc string.
844        """
845        self.enums.append( self._enum(c_name, values, c_namespace, doc))
846
847    def _all_args_kw_functions(self) :
848        l = [ (f, self.name, None) for f in list(self.functions.values())]
849        for c in list(self.classes.values()) :
850            l += [(m,c.py_type, c.c_type) for m in list(c.methods.values()) if m.do_implement]
851            if c.constructor :
852                l.append( (c.constructor,c.py_type, c.c_type))
853        # Check before generation
854        for f, name, x in l:
855            n_dict_call = sum( 1 if overload._dict_call else 0 for overload in f.overloads)
856            assert n_dict_call <= 1, "At most one possible overload with ** call"
857            assert n_dict_call ==0  or len(f.overloads) == 1, ("The function %s.%s has a ** call and overloads, which is meaningless !"%(name,f.py_name))
858        return l
859
860    def generate_code(self) :
861        """
862         Generate the wrapper and the header.
863         The filenames are given in the sys.argv
864         if self.app_name is set, generate a copy of the py_converter
865         file with includes consistent with the installation (as opposed to the build):
866         e.g. #include "a.hpp" in py_converter.hpp becomes
867              #include <app_name/a.hpp> in py_converter.hpp.app_name.install
868        """
869        script_path = os.path.dirname(os.path.abspath( __file__ ))
870        mako_template = script_path + '/mako/wrap.cxx'
871        wrap_file = sys.argv[1]
872
873        # prepare generation
874        for c in list(self.classes.values()) : c._prepare_for_generation()
875
876        # call mako
877        tpl = Template(filename=mako_template, strict_undefined=True)
878        rendered = tpl.render(module=self, sys_modules = sys.modules)
879
880        with open(wrap_file,'w') as f:
881           f.write(rendered)
882