3
0
mirror of https://github.com/triqs/dft_tools synced 2024-11-01 03:33:50 +01:00

desc wrapper generator: small improve, clean

- detect the use module.
- clean the code specific to wrapper generation from clang_parser.
- add support for default arguments for int, double, char.
- TODO : add more complex default arguments
This commit is contained in:
Olivier Parcollet 2014-07-26 18:37:20 +02:00
parent 03dbf576ae
commit 6fb71f50c9
4 changed files with 90 additions and 39 deletions

View File

@ -381,6 +381,7 @@ set(TRIQS_INCLUDE_ALL ${TRIQS_INCLUDE} ${TRIQS_INCLUDE_BOOST} ${TRIQS_INCLUDE_PY
list (REMOVE_DUPLICATES TRIQS_INCLUDE_ALL) list (REMOVE_DUPLICATES TRIQS_INCLUDE_ALL)
set(TRIQS_LIBCLANG_LOCATION "/usr/lib/libclang.dylib" CACHE STRING "Location of the libclang library") set(TRIQS_LIBCLANG_LOCATION "/usr/lib/libclang.dylib" CACHE STRING "Location of the libclang library")
set(TRIQS_LIBCLANG_CXX_ADDITIONAL_FLAGS "" CACHE STRING "Additional flags to be passed to libclang when parsing with clang")
#--------------------------------------------------------------------- #---------------------------------------------------------------------
# pytriqs modules : MUST be before TRIQS, to have the py_converters # pytriqs modules : MUST be before TRIQS, to have the py_converters

View File

@ -33,6 +33,10 @@ class member_(object):
def namespace(self) : def namespace(self) :
return "::".join(self.ns) return "::".join(self.ns)
class type_(object):
def __init__(self, cursor):
self.name, self.canonical_name = cursor.spelling, cursor.get_canonical().spelling
class Function(object): class Function(object):
def __init__(self, cursor, is_constructor = False, ns=() ): #, template_list =()): def __init__(self, cursor, is_constructor = False, ns=() ): #, template_list =()):
loc = cursor.location.file.name loc = cursor.location.file.name
@ -43,35 +47,33 @@ class Function(object):
self.name = cursor.spelling self.name = cursor.spelling
self.annotations = get_annotations(cursor) self.annotations = get_annotations(cursor)
self.access = cursor.access_specifier self.access = cursor.access_specifier
self.params = [] self.params = [] # a list of tuple (type, name, default_value or None).
self.params_decay = []
self.template_list = [] #template_list self.template_list = [] #template_list
self.is_constructor = is_constructor self.is_constructor = is_constructor
self.is_static = cursor.is_static_method() self.is_static = cursor.is_static_method()
def decay(s) :
s = re.sub('const','',s)
s = re.sub('&&','',s)
s = re.sub('&','',s)
return s.strip()
for c in cursor.get_children(): for c in cursor.get_children():
if c.kind == clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER : if c.kind == clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER :
self.template_list.append(c.spelling) self.template_list.append(c.spelling)
elif (c.kind == clang.cindex.CursorKind.PARM_DECL) : elif (c.kind == clang.cindex.CursorKind.PARM_DECL) :
self.params.append ( (c.type.spelling, c.spelling)) default_value = None
self.params_decay.append ( (decay(c.type.spelling), c.spelling)) for ch in c.get_children() :
# TODO : string literal do not work.. needs to use location ? useful ?
if ch.kind in [clang.cindex.CursorKind.INTEGER_LITERAL, clang.cindex.CursorKind.FLOATING_LITERAL,
clang.cindex.CursorKind.CHARACTER_LITERAL, clang.cindex.CursorKind.STRING_LITERAL] :
default_value = ch.get_tokens().next().spelling
t = type_(c.type)
self.params.append ( (t, c.spelling, default_value ))
#else : #else :
# print " node in fun ", c.kind # print " node in fun ", c.kind
# self.rtype = cursor.result_type.get_canonical().spelling self.rtype = type_(cursor.result_type) if not is_constructor else None
self.rtype = cursor.result_type.spelling if not is_constructor else None
#print 'params for ', self.name, self.params_decay
def namespace(self) : def namespace(self) :
return "::".join(self.ns) return "::".join(self.ns)
def signature_cpp(self) : def signature_cpp(self) :
s = "{name} ({args})" if not self.is_constructor else "{rtype} {name} ({args})" s = "{name} ({args})" if not self.is_constructor else "{rtype} {name} ({args})"
s = s.format(args = ', '.join( ["%s %s"%t_n for t_n in self.params]), **self.__dict__) s = s.format(args = ', '.join( ["%s %s"%(t.name,n) + "="%d if d else "" for t,n,d in self.params]), **self.__dict__)
if self.template_list : if self.template_list :
s = "template<" + ', '.join(['typename ' + x for x in self.template_list]) + "> " + s s = "template<" + ', '.join(['typename ' + x for x in self.template_list]) + "> " + s
if self.is_static : s = "static " + s if self.is_static : s = "static " + s

View File

@ -1,31 +1,78 @@
from wrap_generator import *
# The module
module = module_(full_name = "${modulename}",
doc = " ")
#
# Need to add here the necessary include for compilation
#module.add_include("<iostream>")
#module.add_include("<triqs/xxxxx.hpp>")
# Some include, using, etc... Cf doc.
module.add_preamble("""
""")
<% <%
import re
def deduce_normalized_python_class_name(s) : def deduce_normalized_python_class_name(s) :
return ''.join([x.capitalize() for x in s.split('_')]) return ''.join([x.capitalize() for x in s.split('_')])
def make_signature(m) : def decay(s) :
assert not m.template_list, "template functions can not be wrapped to Python" for tok in ['const', '&&', '&'] :
s = "{rtype} {name} ({args})" if not m.is_constructor else "({args})" s = re.sub(tok,'',s)
s = s.format(args = ', '.join( ["%s %s"%t_n for t_n in m.params_decay]), **m.__dict__)
return s.strip() return s.strip()
%> # compute used_module_list
recognized_namespace_for_using = {
'triqs::gfs::' : 'gf',
'triqs::params::' : 'parameters',
'triqs::utility::many_body_operator' : 'operators2',
}
used_module_list = []
def analyse(t) :
#global used_module_list
for ns, mod in recognized_namespace_for_using.items() :
if decay(t.canonical_name).startswith(ns) :
used_module_list.append(mod)
for c in classes :
for m in c.constructors :
for t,n,d in m.params : analyse(t)
for m in c.methods :
for t,n,d in m.params : analyse(t)
analyse(m.rtype)
for f in functions :
for t,n,d in f.params : analyse(t)
analyse(f.rtype)
used_module_list = set(used_module_list) # makes unique
def cls(t) :
tname = decay(t.name)
if 'gf' in used_module_list: tname = re.sub('triqs::gfs::','',tname)
if 'parameters' in used_module_list: tname = re.sub('triqs::params::','',tname)
return tname
def make_signature(m) :
assert not m.template_list, "template functions can not be wrapped to Python"
s = "({args})"
if not m.is_constructor :
s = cls(m.rtype) + " {name} " + s
s = s.format(args = ', '.join( ["%s %s"%(cls(t),n) + (" = %s"%d if d else "") for t,n,d in m.params]), **m.__dict__)
return s.strip()
%>
##
##
# Generated automatically using libclang
from wrap_generator import *
# The module
module = module_(full_name = "${modulename}", doc = " ")
# All the triqs C++/Python modules
%for mod in used_module_list :
module.use_module('${mod}')
%endfor
# Add here all includes beyond what is automatically included by the triqs modules
module.add_include("${args.filename}")
# Add here anything to add in the C++ code at the start, e.g. namespace using
module.add_preamble("""
// using namespace XXX;
""")
##
##
%for c in classes : %for c in classes :
# The class ${c.name}
g = class_( g = class_(
py_type = "${deduce_normalized_python_class_name(c.name)}", # name of the python class py_type = "${deduce_normalized_python_class_name(c.name)}", # name of the python class
c_type = "${c.name}", # name of the C++ class c_type = "${c.name}", # name of the C++ class

View File

@ -38,9 +38,10 @@ if __name__ == '__main__' :
compiler_options = args.compiler_options or [] compiler_options = args.compiler_options or []
compiler_options += ['-I%s'%x for x in args.includes] compiler_options += ['-I%s'%x for x in args.includes]
add_opts = '@TRIQS_LIBCLANG_CXX_ADDITIONAL_FLAGS@'.strip()
if add_opts:
compiler_options.append(add_opts)
functions, classes = parse(args.filename, debug = False, compiler_options = compiler_options, where_is_libclang = args.libclang_location) functions, classes = parse(args.filename, debug = False, compiler_options = compiler_options, where_is_libclang = args.libclang_location)