def render_ns(ns, all_functions, all_classes, all_usings): R = make_header(ns, '#') ns = ns.split('::',1)[-1] if len(all_usings) > 0: R += make_header('Type aliases') R += render_table([(t.spelling, re.sub(ns+'::','',t.underlying_typedef_type.spelling), replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in all_usings]) if all_classes: R += make_header('Classes') R += ".. table::\n :width: 50% 50%\n\n" #R += render_table([(":ref:`%s <_%s_%s>`"%(cls.spelling,escape_lg(ns), escape_lg(cls.spelling)), cls.processed_doc.elements['brief']) for cls in all_classes ]) R += render_table([(":ref:`%s <%s>`"%(escape_lg(cls.name), cls.name_for_label), cls.processed_doc.elements['brief']) for cls in all_classes ]) R += toctree_hidden for cls in all_classes: R += " {ns}/{filename}\n".format(ns = ns, filename = replace_ltgt(cls.name)) if all_functions: R += make_header('Functions') R += render_table([(":ref:`%s <%s>`"%(name, make_label(CL.fully_qualified_name(f_list[0]))), f_list[0].processed_doc.elements['brief']) for (name, f_list) in list(all_functions.items()) ]) #R += render_table([(":ref:`%s <%s>`"%(name, escape_lg(name)), f_list[0].processed_doc.elements['brief']) for (name, f_list) in all_functions.items() ]) #R += render_table([(":ref:`%s <%s_%s>`"%(name,escape_lg(ns), escape_lg(name)), f_list[0].processed_doc.elements['brief']) for (name, f_list) in all_functions.items() ]) R += toctree_hidden for f_name in all_functions: R += " {ns}/{f_name}\n".format(ns = ns, f_name = f_name) return R
def render_fnt(parent_class, f_name, f_overloads): """ Generate the rst page for a function * f_name : name of the function * overload_docs : ?? * parent_class : None or the parent class if it is a method * f_overloads : a list of WHAT ? """ # Start of the page R = rst_start # tag and name of the class parent_cls_name_fully_qualified = (CL.fully_qualified_name(parent_class) + "::") if parent_class else "" parent_cls_spelling = (parent_class.spelling + '_') if parent_class else '' f_name_full = parent_cls_name_fully_qualified + f_name R += """ .. _{class_rst_ref}: {f_name_full} """.format(f_name_full=f_name_full, class_rst_ref=parent_cls_spelling + f_name) R += '=' * (len(f_name_full) + 0) + '\n' + """ """ # Synopsis R += make_synopsis_list(f_overloads) + '\n\n' # HOW DO WE GROUP THE OVERLOAD # Enumerate all overloads for n, f in enumerate(f_overloads): doc = f.processed_doc doc_elem = doc.elements num = '%s.' % (n + 1) if len(f_overloads) > 1 else '' R += '\n' + num + ' ' + doc.brief_doc + '\n' R += doc.doc # TODO which order ? if 'note' in doc_elem: R += render_note(doc_elem.pop('note')) if 'warning' in doc_elem: R += render_warning(doc_elem.pop('warning')) if 'figure' in doc_elem: R += render_fig(doc_elem.pop('figure')) if 'tparam' in doc_elem: R += render_list(doc_elem.pop('tparam'), 'Template parameters') if 'param' in doc_elem: R += render_list(doc_elem.pop('param'), 'Parameters') if 'return' in doc_elem: R += make_header('Return value') + doc_elem.pop('return') # any example from the overloads # Should we TAKE ONLY ONE ????? Error ?? example_file_name = reduce( lambda x, y: x or y, [f.processed_doc.elements.pop('example', '') for f in f_overloads], '') R += render_example(example_file_name) return R
def __init__(self, node): raw_doc = node.raw_comment if not raw_doc : raw_doc = "\n\n" # default value # Clean *, &&, /// and co. doc = clean_doc_string(raw_doc).rstrip() # do NOT remove leading space # split : the first line is brief, and the rest doc = replace_latex(doc) if '$' in doc : print("FAILED to process the latex for node %s"%CL.fully_qualified(node)) print(doc) doc2 = doc.split('@',1)[0] # Get rid of everything after the first @ self.doc = doc2 assert '@' not in self.doc, "Internal Error in doc processing !" # Process the main part of the doc self.doc = strip_left_spaces(self.doc) # Extract the @XXXX elements with a regex @XXXX YYYY (YYYY can be multiline). d = dict( (key, []) for key in self.fields_with_multiple_entry) regex = r'@(\w+)\s(\s*[^@]*)' for m in re.finditer(regex, doc, re.DOTALL): key, val = m.group(1), replace_latex(m.group(2)).rstrip() if key not in self.fields_allowed_in_docs: print("Field %s is not recognized"%key) if key in self.fields_with_multiple_entry: d[key].append(val) else: d[key] = val self.elements = d if 'brief' not in d : d['brief']='' # if 'return' in d : print d['return'] # print doc # print raw_doc # print d['param'] # Final adjustement if 'brief' not in d : d['brief']='' if 'example' not in d : # take the default filename= "%s.cpp"%(CL.fully_qualified_name(node).replace("::",'/')) filename = os.path.join(global_vars.examples_root, filename) if os.path.exists(filename): d['example'] = filename if 'include' not in d : ns = CL.get_namespace_list(node) d['include'] = '/'.join(ns) + '.hpp'
def render_cls(cls, all_methods, all_friend_functions): """ Generate the rst page for a class * cls : node for the classf_name : name of the function * doc_methods : ?? """ cls_doc = cls.processed_doc doc_elem = cls_doc.elements R = rst_start # include incl = doc_elem.pop('include', '') # class header cls_name_fully_qualified = CL.fully_qualified_name(cls) R += """ .. _{cls.spelling}: {cls_name_fully_qualified} {separator} Defined in header <*{incl}*> .. code-block:: c {templ_synop}class {cls.spelling}; {cls_doc.brief_doc} {cls_doc.doc} """.format(cls=cls, incl=incl.strip(), separator='=' * (len(cls_name_fully_qualified)), templ_synop=make_synopsis_template_decl(cls), cls_doc=cls_doc, cls_name_fully_qualified=cls_name_fully_qualified) # R += cls_doc.doc if 'tparam' in doc_elem: R += render_list(doc_elem.pop('tparam'), 'Template parameters') if 'note' in doc_elem: R += render_note(doc_elem.pop('note')) if 'warning' in doc_elem: R += render_warning(doc_elem.pop('warning')) if 'figure' in doc_elem: R += render_fig(doc_elem.pop('figure')) # Members c_members = list(CL.get_members(cls, True)) if len(c_members) > 0: R += make_header('Public members') R += render_table([(t.spelling, t.type.spelling, replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in c_members]) # Using : TODO : KEEP THIS ? c_usings = list(CL.get_usings(cls)) for t in c_usings: t.my_tag = t.spelling if len(c_usings) > 0: R += make_header('Member types') R += render_table([(t.spelling, replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in c_usings]) # A table for all member functions and all friend functions def group_of_overload(f_list): s = set(f.processed_doc.elements['group'] for f in f_list if 'group' in f.processed_doc.elements) assert len(s) < 2, "Can not have different group for various overload" return s.pop if s else '' def make_func_list(all_f, header_name): R = '' if len(all_f) > 0: R += make_header(header_name) R += render_table([ (":ref:`%s <%s_%s>`" % (name, escape_lg(cls.spelling), escape_lg(name)), f_list[0].processed_doc.brief_doc) for (name, f_list) in all_f.items() ]) R += toctree_hidden for f_name in all_f: R += " {cls.spelling}/{f_name}\n".format(cls=cls, f_name=f_name) return R R += make_func_list(all_methods, 'Member functions') R += make_func_list(all_friend_functions, 'Non Member functions') # Example if 'example' in doc_elem: R += render_example(doc_elem.pop('example')) return R
def render_cls(cls, all_methods, all_friend_functions): """ Generate the rst page for a class * cls : node for the classf_name : name of the function * doc_methods : ?? """ cls_doc = cls.processed_doc doc_elem = cls_doc.elements R= rst_start # include incl = doc_elem.pop('include', '') # class header fully_qualified_name = CL.fully_qualified_name(cls) R +=""" .. _{cls.name_for_label}: {cls.fully_qualified_name} {separator} *#include <{incl}>* .. rst-class:: cppsynopsis {templ_synop} class :red:`{cls.name}` {cls_doc.doc} """.format(cls = cls, incl = incl.strip(), separator = '=' * (len(cls.fully_qualified_name)), templ_synop = make_synopsis_template_decl(cls), cls_doc = cls_doc) # if 'tparam' in doc_elem: R += render_list(doc_elem.pop('tparam'), 'Template parameters', '-') if 'note' in doc_elem : R += render_note(doc_elem.pop('note')) if 'warning' in doc_elem: R += render_warning(doc_elem.pop('warning')) if 'figure' in doc_elem: R += render_fig(doc_elem.pop('figure')) # Members if len(cls.members) > 0: R += make_header('Public members') R += render_table([(t.spelling,t.type.spelling, replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in cls.members]) # Usings if len(cls.usings) > 0: R += make_header('Member types') R += render_table([(t.spelling, re.sub(cls.namespace + '::','',t.underlying_typedef_type.spelling), replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in cls.usings]) # A table for all member functions and all friend functions def group_of_overload(f_list): s = set(f.processed_doc.elements['group'] for f in f_list if 'group' in f.processed_doc.elements) assert len(s) < 2, "Can not have different group for various overload" return s.pop if s else '' def make_func_list(all_f, header_name): if not all_f : return '' R = make_header(header_name) # Regroup the function by sub category D = OrderedDict() for name, flist in list(all_f.items()): cat =flist[0].processed_doc.elements.get('category', None) name_for_user = escape_lg(name) if name_for_user in ['constructor', 'destructor'] : name_for_user = '******'%name_for_user D.setdefault(cat, list()).append((":ref:`%s <%s>`"%(name_for_user,make_label(cls.fully_qualified_name + '__' + name)), flist[0].processed_doc.elements['brief'])) # Make the sub lists for cat, list_table_args in list(D.items()) : if cat : R += make_header(cat, '~') R += render_table(list_table_args) # the hidden toctree is not regrouped R += toctree_hidden for f_name in all_f: R += " {cls_name}/{f_name}\n".format(cls_name = replace_ltgt(cls.name), f_name = f_name) return R R += make_func_list(all_methods, 'Member functions') R += make_func_list(all_friend_functions, 'Non Member functions') # Example if 'example' in doc_elem: R += render_example(doc_elem.pop('example')) return R
def render_fnt(parent_class, f_name, f_overloads): """ Generate the rst page for a function * f_name : name of the function * overload_docs : ?? * parent_class : None or the parent class if it is a method * f_overloads : a list of WHAT ? """ # Start of the page R = rst_start # include incl = f_overloads[0].processed_doc.elements.pop('include', '') # tag and name of the class if parent_class: f_name_full = parent_class.fully_qualified_name + "::" + f_name else : f_name_full = CL.fully_qualified_name(f_overloads[0]) # full name of the function R += """ .. _{class_rst_ref}: {f_name_full} {separator} *#include <{incl}>* """.format(f_name_full = f_name_full, incl = incl, class_rst_ref = make_label(f_name_full), separator = '=' * (len(f_name_full)+0) ) #""".format(f_name_full = f_name_full, incl = incl, class_rst_ref = make_label(parent_cls_name + f_name), separator = '=' * (len(f_name_full)+0) ) R += """ """ # Synopsis R += make_synopsis_list(f_overloads) + '\n\n' # We regroup the overload as in cppreference def make_unique(topic) : rets = set(f.processed_doc.elements.pop(topic, '').rstrip() for f in f_overloads) rets = list(x for x in rets if x) if len(rets)> 1: print("Warning : Multiple documentation of %s across overloads. Picking first one"%topic) return rets[0] if rets else '' def make_unique_list(topic) : D = OrderedDict() for n, f in enumerate(f_overloads): plist = f.processed_doc.elements.pop(topic) # p is a string "NAME REST" for p in plist : name, desc = (p + ' ').split(' ',1) if name not in D: D[name] = desc.rstrip() else: if D[name] != desc.strip() : print("Warning : multiple definition of parameter %s at overload %s"%(name, n)) return D def render_dict(d, header, char, role): """ Make rst code for a list of items with a header It splits the first word in a separate column """ if not d: return '' head = make_header(header, char) if header else '' return head + '\n'.join(" * :%s:`%s` %s\n"%(role, k.strip(),v) for (k,v) in list(d.items())) has_overload = len(f_overloads)> 1 # Head doc head = make_unique('head') or ("Documentation" if has_overload else '') R += '%s\n\n'%head # The piece of doc which is overload dependent if has_overload : for num, f in enumerate(f_overloads): pd = f.processed_doc num_s = '**%s)** '%(num+1) if has_overload else '' if pd.doc : R += '\n\n %s %s\n '%(num_s, pd.doc.replace('\n', '\n '))+ '\n' else : R+='\n\n%s\n\n'%(f_overloads[0].processed_doc.doc) # Tail doc R += '%s\n\n' %make_unique('tail') # Figure figure = make_unique('figure') if figure : R += render_fig(figure) # tparam and param tparam_dict = make_unique_list('tparam') param_dict = make_unique_list('param') R += render_dict(tparam_dict, 'Template parameters', '^', role = 'param') R += render_dict(param_dict, 'Parameters','^', role = 'param') # Returns rets = make_unique("return") if rets : R += make_header('Returns', '^') + "%s"%rets # Examples example_file_name = make_unique("example") R += "\n" + render_example(example_file_name.strip()) # Warning w = make_unique("warning") R += render_warning(w) return R
def mkchdir_for_one_node(node): mkchdir(*(CL.fully_qualified_name(node).split('::')[:-1]))
def analyse_one_ns(self, namespace): print "*** Namespace %s ***"%namespace # ---------------------- # Filters # ---------------------- def keep_ns(n): """Given a namespace node n, shall we keep it ?""" ns = CL.fully_qualified(n) return ns in namespace def keep_cls(c): """ Given a class node, shall we keep it ? Reject if no raw_comment. Keeps if its namespace is EXACTLY in self.namespaces e.g. A::B::cls will be kept iif A::B is in self.namespaces, not it A is. The filter to keep a class/struct or an enum : it must have a raw comment if we a namespace list, it must be in it. if target_file_only it has to be in the file given to c++2py """ if c.spelling.startswith('_') : return False if not c.raw_comment : return False if namespace: qualified_ns = CL.get_namespace(c) if qualified_ns != namespace : return False return (c.location.file.name == self.filename) if self.target_file_only else True def keep_fnt(f): if not f.raw_comment : return False if f.spelling.startswith('operator') or f.spelling in ['begin','end'] : return False return keep_cls(f) def keep_using(c): if namespace: qualified_ns = CL.get_namespace(c) if qualified_ns != namespace : return False return (c.location.file.name == self.filename) if self.target_file_only else True def keep_is_documented(c): return True if c.raw_comment else False # ---------------------- # A list of AST nodes for classes classes = CL.get_classes(self.root, keep_cls, traverse_namespaces = True, keep_ns = keep_ns) classes = list(classes) # make a list to avoid exhaustion of the generator D = OrderedDict() for cls in classes: cls.namespace = CL.get_namespace(cls) cls.name = CL.get_name_with_template_specialization(cls) or cls.spelling cls.fully_qualified_name = '::'.join([cls.namespace, cls.name]) cls.fully_qualified_name_no_template = CL.fully_qualified_name(cls) cls.name_for_label = synopsis.make_label(cls.fully_qualified_name) D[cls.fully_qualified_name] = cls print " ... class : %s"%cls.fully_qualified_name, cls.location #assert ',' not in cls.fully_qualified_name, "Not implemented" # process the doc of the class and add it to the node cls.processed_doc = ProcessedDoc(cls) # all methods and constructors # we build a OrderedDict of the constructors (first) and the methods, in order of declaration constructors = list(CL.get_constructors(cls)) for f in constructors : f.is_constructor = True # tag them for later use methods = OrderedDict() if constructors: methods['constructor'] = constructors methods.update(self.regroup_func_by_names(CL.get_methods(cls, True, keep = keep_is_documented))) # True : with inherited # all non member functions friend_functions = self.regroup_func_by_names(CL.get_friend_functions(cls, keep = keep_is_documented)) # Analyse the doc string for all methods and functions, and store the result in the node itself for (n,f_list) in (methods.items() + friend_functions.items()): for f in f_list: f.processed_doc = ProcessedDoc(f) # attach to the node cls.methods, cls.friend_functions = methods, friend_functions # members cls.members = list(CL.get_members(cls, True)) # using cls.usings = list(CL.get_usings(cls)) # , keep_using)) # Eliminate doublons, like forward declarations classes = D.values() # A list of AST nodes for the methods and functions functions = CL.get_functions(self.root, keep_fnt, traverse_namespaces = True, keep_ns = keep_ns) functions = list(functions) # make a to avoid exhaustion of the generator # Analyse the doc strings for f in functions: f.processed_doc = ProcessedDoc(f) # Find the using of this namespace, and make the list unique based on the fully_qualified_name usings = list(CL.get_usings(self.root, keep_using, traverse_namespaces = True, keep_ns = keep_ns)) D = OrderedDict() for c in usings: c.namespace = CL.get_namespace(c) c.fully_qualified_name = '::'.join([c.namespace, c.spelling]) D[c.fully_qualified_name] = c usings = D.values() return classes, functions, usings
def mkchdir_for_one_node(node): mkchdir(* ( CL.fully_qualified_name(node).split('::')[:-1]))
def run(self, output_directory): print "Generating the documentation ..." mkchdir(output_directory) # Filters def keep_ns(n): ns = CL.fully_qualified(n) if 'std' in ns or 'boost' in ns or 'detail' in ns or 'impl' in ns: return False if len(self.namespaces) == 0: return True return any((ns in x) for x in self.namespaces) def keep_cls(c): """ The filter to keep a class/struct or an enum : it must have a raw comment if we a namespace list, it must be in it. if target_file_only it has to be in the file given to c++2py """ if not c.raw_comment: return False if self.namespaces: qualified_ns = CL.get_namespace(c) if not any((x in qualified_ns) for x in self.namespaces): return False return (c.location.file.name == self.filename) if self.target_file_only else True def keep_fnt(f): if not f.raw_comment: return False if f.spelling.startswith('operator') or f.spelling in [ 'begin', 'end' ]: return False return keep_cls(f) # A list of AST nodes for classes classes = CL.get_classes(self.root, keep_cls, traverse_namespaces=True, keep_ns=keep_ns) classes = list(classes) # to avoid exhaustion of the generator # A list of AST nodes for the methods and functions all_functions = CL.get_functions(self.root, keep_fnt, traverse_namespaces=True, keep_ns=keep_ns) all_functions = list( all_functions) # to avoid exhaustion of the generator # Build the doc for all functions for f in all_functions: f.processed_doc = ProcessedDoc(f) # c : AST node of name A::B::C::clsname makes and cd into A/B/C def mkchdir_for_one_node(node): mkchdir(*(CL.fully_qualified_name(node).split('::')[:-1])) # regroup the functions into a list of overloads def regroup_func_by_names(fs): """ Given a list of functions, regroup them by names""" d = OrderedDict() def decay(name): if 'operator' not in name: return name a, ca, c, co = '+ - * /', '+= -= \*= /=', "== !=", r" comparison" d = { '*=': ca, '+=': ca, '/=': ca, '-=': ca, '*': a, '+': a, '/': a, '-': a, '==': c, '!=': c, '<': co, '>': co, '<=': co, '>=': co } n = name.replace('operator', '').strip() return 'operator' + d[n] if n in d else name for f in fs: d.setdefault(decay(f.spelling), []).append(f) return d synopsis.class_list = classes synopsis.class_list_name = [n.spelling for n in classes] for c in classes: if not c.spelling.strip(): print "Skipping a class with an empty name !" continue print " ... class : " + c.spelling, CL.fully_qualified_name( c), c.kind, CL.get_name_with_template_specialization(c) # process the doc of the class and add it to the node c.processed_doc = ProcessedDoc(c) # all methods and constructors constructors = list(CL.get_constructors(c)) for f in constructors: f.is_constructor = True # tag them for later use all_methods = OrderedDict() if constructors: all_methods['constructor'] = constructors all_methods.update(regroup_func_by_names(CL.get_methods( c, True))) # True : with inherited ? # all non member functions all_friend_functions = regroup_func_by_names( CL.get_friend_functions(c)) # process the doc for all methods and functions, and store it in the node. for (n, f_list) in (all_methods.items() + all_friend_functions.items()): for f in f_list: f.processed_doc = ProcessedDoc(f) # One directory for the class cur_dir = os.getcwd() mkchdir_for_one_node(c) # the file for the class r = render_cls(c, all_methods, all_friend_functions) safe_write(c.spelling, r) # create a directory with the class name mkchdir(c.spelling) # write a file for each function def render(mess, d): for f_name, f_overloads in d.items(): print " ...... %s %s" % (mess, f_name) r = render_fnt(parent_class=c, f_name=f_name, f_overloads=f_overloads) safe_write(f_name, r) render('methods', all_methods) render('non member functions', all_friend_functions) # Change back to up directory os.chdir(cur_dir) all_functions = regroup_func_by_names(all_functions) docs = dict((n, [ProcessedDoc(f) for f in fs]) for (n, fs) in all_functions.items()) for f_name, f_overloads in all_functions.items(): print " ... function " + f_name, " [", f_overloads[ 0].location.file.name, ']' cur_dir = os.getcwd() mkchdir_for_one_node(f_overloads[0]) r = render_fnt(parent_class=None, f_name=f_name, f_overloads=f_overloads) safe_write(f_name, r) os.chdir(cur_dir) print "... done"
def render_cls(cls, all_methods, all_friend_functions): """ Generate the rst page for a class * cls : node for the classf_name : name of the function * doc_methods : ?? """ cls_doc = cls.processed_doc doc_elem = cls_doc.elements R= rst_start # include incl = doc_elem.pop('include', '') # class header fully_qualified_name = CL.fully_qualified_name(cls) R +=""" .. _{cls.name_for_label}: {cls.fully_qualified_name} {separator} Defined in header <*{incl}*> .. code-block:: c {templ_synop} class {cls.spelling} {cls_doc.brief_doc} {cls_doc.doc} """.format(cls = cls, incl = incl.strip(), separator = '=' * (len(cls.fully_qualified_name)), templ_synop = make_synopsis_template_decl(cls), cls_doc = cls_doc) # R += cls_doc.doc if 'tparam' in doc_elem: R += render_list(doc_elem.pop('tparam'), 'Template parameters', '-') if 'note' in doc_elem : R += render_note(doc_elem.pop('note')) if 'warning' in doc_elem: R += render_warning(doc_elem.pop('warning')) if 'figure' in doc_elem: R += render_fig(doc_elem.pop('figure')) # Members if len(cls.members) > 0: R += make_header('Public members') R += render_table([(t.spelling,t.type.spelling, replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in cls.members]) # Usings if len(cls.usings) > 0: R += make_header('Member types') R += render_table([(t.spelling, t.underlying_typedef_type.spelling, replace_latex(clean_doc_string(t.raw_comment)) if t.raw_comment else '') for t in cls.usings]) # A table for all member functions and all friend functions def group_of_overload(f_list): s = set(f.processed_doc.elements['group'] for f in f_list if 'group' in f.processed_doc.elements) assert len(s) < 2, "Can not have different group for various overload" return s.pop if s else '' def make_func_list(all_f, header_name): if not all_f : return '' R = make_header(header_name) # Regroup the function by sub category D = OrderedDict() for name, flist in all_f.items(): cat =flist[0].processed_doc.elements.get('category', None) D.setdefault(cat, list()).append((":ref:`%s <%s>`"%(escape_lg(name),make_label(cls.name + '_' + name)), flist[0].processed_doc.brief_doc)) # Make the sub lists for cat, list_table_args in D.items() : if cat : R += make_header(cat, '~') R += render_table(list_table_args) # the hidden toctree is not regrouped R += toctree_hidden for f_name in all_f: R += " {cls_name}/{f_name}\n".format(cls_name = replace_ltgt(cls.name), f_name = f_name) return R R += make_func_list(all_methods, 'Member functions') R += make_func_list(all_friend_functions, 'Non Member functions') # Example if 'example' in doc_elem: R += render_example(doc_elem.pop('example')) return R
def render_fnt(parent_class, f_name, f_overloads): """ Generate the rst page for a function * f_name : name of the function * overload_docs : ?? * parent_class : None or the parent class if it is a method * f_overloads : a list of WHAT ? """ # Start of the page R = rst_start # tag and name of the class parent_cls_name_fully_qualified = (CL.fully_qualified_name(parent_class) + "::") if parent_class else "" parent_cls_name = (parent_class.name + '_') if parent_class else '' f_name_full = parent_cls_name_fully_qualified + f_name R += """ .. _{class_rst_ref}: {f_name_full} """.format(f_name_full = f_name_full, class_rst_ref = make_label(parent_cls_name + f_name)) R += '=' * (len(f_name_full)+0) + '\n' + """ """ # Synopsis R += make_synopsis_list(f_overloads) + '\n\n' # We regroup the overload as in cppreference def make_unique(topic) : rets = set(f.processed_doc.elements.pop(topic, '').strip() for f in f_overloads) rets = list(x for x in rets if x) if len(rets)> 1: print "Warning : Multiple documentation of %s across overloads. Picking first one"%topic return rets[0] if rets else '' def make_unique_list(topic) : D = OrderedDict() for n, f in enumerate(f_overloads): plist = f.processed_doc.elements.pop(topic) # p is a string "NAME REST" for p in plist : name, desc = (p + ' ').split(' ',1) if name not in D: D[name] = desc.strip() else: if D[name] != desc.strip() : print "Warning : multiple definition of parameter %s at overload %s"%(name, n) return D def render_dict(d, header, char): """ Make rst code for a list of items with a header It splits the first word in a separate column """ if not d: return '' head = make_header(header, char) if header else '' return head + '\n'.join(" * **%s**: %s\n"%(k.strip(),v) for (k,v) in d.items()) has_overload = len(f_overloads)> 1 # Head doc head = make_unique('head') or ("Documentation" if has_overload else '') R += '%s\n\n'%head # The piece of doc which is overload dependent for num, f in enumerate(f_overloads): pd = f.processed_doc num_s = '**%s)** '%(num+1) if has_overload else '' if pd.doc : R += '\n\n %s %s\n '%(num_s, pd.doc)+ '\n' # Tail doc R += '%s\n\n' %make_unique('tail') # tparam and param tparam_dict = make_unique_list('tparam') param_dict = make_unique_list('param') R += render_dict(tparam_dict, 'Template parameters', '^') R += render_dict(param_dict, 'Parameters','^') # Returns rets = make_unique("return") if rets : R += make_header('Returns', '^') + " * %s"%rets # Examples example_file_name = make_unique("example") R += render_example(example_file_name.strip()) # Warning w = make_unique("warning") R += render_warning(w) return R