Example #1
0
File: latex.py Project: RebUT/REBUT
def parseBib(filename, language):
    pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
    entry = returnList(pp.Word('@', pp.alphanums) + sl('{') +
        pp.Word(pp.alphanums + "_") + sl(',') +
        CommaList(returnTuple(pp.Word(pp.alphanums) + sl('=') + pp.QuotedString('{', endQuoteChar = '}'))) +
        pp.Suppress(pp.Optional(',')) +
        sl('}'))
    r = (pp.ZeroOrMore(entry) | pp.Suppress('#' + pp.ZeroOrMore(pp.CharsNotIn('\n'))) + pp.StringEnd()).parseFile(filename)

    bibliography = QOpen(os.path.join(language, "bibliography.rst"), 'wt')
    print >>bibliography, "Bibliography"
    print >>bibliography, "============"
    print >>bibliography

    for _,e in sorted([(str(x[1]), x) for x in r]):
        (etype, tag, attrs) = str(e[0][1:]), str(e[1]), dict([(str(a), str(b)) for (a,b) in e[2]])
        
        representations = {
            'article' :         '$author, "$title". $journal $volume $number, pp $pages ($year)',
            'inproceedings' :   '$author "$title", $booktitle, $year',
            'misc' :            '$author "$title", $year',
            'techreport' :      '$author "$title", $edition, $edition ($year)',
        }
        if etype in representations:
            if 0:
                print >>bibliography, tag
                print >>bibliography, "^" * len(tag)
                print >>bibliography

            print >>bibliography, ".. [%s] %s" % (tag, Template(representations[etype]).safe_substitute(attrs))
            print >>bibliography
    bibliography.close()
Example #2
0
 def cmd_chapter(self, c):
     filename = str(c.params[0]).lower().replace(' ', '_').replace('/', '_')
     self.f_index.write("    %s\n" % filename)
     self.f_chapter = QOpen(os.path.join(self.language, filename + '.rst'),
                            'wt')
     self.f_section = None
     self.f = self.f_chapter
     self.indent = 0
     title = str(c.params[0])
     print >> self, '*' * len(title)
     print >> self, title
     print >> self, '*' * len(title)
     print >> self
     self.chapter_intoc = False
 def cmd_section(self, c):
     filename = str(c.params[0]).lower().replace(' ', '_').replace('/', '_')
     if len(self.cur_module) > 0:
         filename = self.cur_module + "_" + filename
     if not self.chapter_intoc:
         self.chapter_intoc = True
         print >> self.f_chapter
         print >> self.f_chapter, '.. toctree::'
         print >> self.f_chapter, '    :maxdepth: 2'
         print >> self.f_chapter
     self.f_chapter.write("    %s\n" % filename)
     self.f_section = QOpen(os.path.join(self.language, filename + '.rst'),
                            'wt')
     self.f = self.f_section
     self.indent = 0
     title = self.render(c.params[0].str)
     print >> self, title
     print >> self, '=' * len(title)
     print >> self
     print >> self, '.. highlight:: %s' % {
         'c': 'c',
         'cpp': 'cpp',
         'py': 'python'
     }[self.language]
     print >> self
Example #4
0
    def __init__(self, filename, language, abspath):
        assert language in ['py', 'c', 'cpp']
        self.language = language

        self.abspath = abspath
        os.path.abspath(os.path.dirname(filename))

        self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
        self.f = self.f_index
        self.f_chapter = None
        self.f_section = None
        self.indent = 0
        self.state = None
        self.envstack = []
        self.tags = {}
        self.errors = open('errors.%s' % language, 'wt')
        self.unhandled_commands = set()
        self.freshline = True
        self.function_props = {}
        self.covered = set()  # covered functions, used for error report
        self.description = ""
Example #5
0
def parseBib(filename, language):
    pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
    entry = returnList(
        pp.Word('@', pp.alphanums) + sl('{') + pp.Word(pp.alphanums + "_") +
        sl(',') + CommaList(
            returnTuple(
                pp.Word(pp.alphanums) + sl('=') +
                pp.QuotedString('{', endQuoteChar='}'))) +
        pp.Suppress(pp.Optional(',')) + sl('}'))
    r = (pp.ZeroOrMore(entry)
         | pp.Suppress('#' + pp.ZeroOrMore(pp.CharsNotIn('\n'))) +
         pp.StringEnd()).parseFile(filename)

    bibliography = QOpen(os.path.join(language, "bibliography.rst"), 'wt')
    print >> bibliography, "Bibliography"
    print >> bibliography, "============"
    print >> bibliography

    for _, e in sorted([(str(x[1]), x) for x in r]):
        (etype, tag, attrs) = str(e[0][1:]), str(e[1]), dict([
            (str(a), str(b)) for (a, b) in e[2]
        ])

        representations = {
            'article':
            '$author, "$title". $journal $volume $number, pp $pages ($year)',
            'inproceedings': '$author "$title", $booktitle, $year',
            'misc': '$author "$title", $year',
            'techreport': '$author "$title", $edition, $edition ($year)',
        }
        if etype in representations:
            if 0:
                print >> bibliography, tag
                print >> bibliography, "^" * len(tag)
                print >> bibliography

            print >> bibliography, ".. [%s] %s" % (
                tag, Template(representations[etype]).safe_substitute(attrs))
            print >> bibliography
    bibliography.close()
Example #6
0
File: latex.py Project: RebUT/REBUT
 def cmd_chapter(self, c):
     filename = str(c.params[0]).lower().replace(' ', '_').replace('/','_').replace('.','_')
     self.f_index.write("    %s\n" % filename)
     self.f_chapter = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
     self.f_section = None
     self.f = self.f_chapter
     self.indent = 0
     title = str(c.params[0])
     print >>self, '*' * len(title)
     print >>self, title
     print >>self, '*' * len(title)
     print >>self
     self.chapter_intoc = False
Example #7
0
    def __init__(self, filename, language, abspath):
        assert language in ['py', 'c', 'cpp']
        self.language = language

        self.abspath = abspath
        os.path.abspath(os.path.dirname(filename))

        self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
        self.f = self.f_index
        self.f_chapter = None
        self.f_section = None
        self.indent = 0
        self.state = None
        self.envstack = []
        self.tags = {}
        self.errors = open('errors.%s' % language, 'wt')
        self.unhandled_commands = set()
        self.freshline = True
        self.function_props = {}
        self.covered = set()        # covered functions, used for error report
        self.description = ""
Example #8
0
File: latex.py Project: RebUT/REBUT
class SphinxWriter:
    def __init__(self, filename, language, abspath):
        assert language in ['py', 'c', 'cpp']
        self.language = language

        self.abspath = abspath
        os.path.abspath(os.path.dirname(filename))

        self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
        self.f = self.f_index
        self.f_chapter = None
        self.f_section = None
        self.indent = 0
        self.state = None
        self.envstack = []
        self.tags = {}
        self.errors = open('errors.%s' % language, 'wt')
        self.unhandled_commands = set()
        self.freshline = True
        self.function_props = {}
        self.covered = set()        # covered functions, used for error report
        self.description = ""
        self.cur_module = ""

    def write(self, s):
        self.freshline = len(s) > 0 and (s[-1] == '\n')
        self.f.write(s.replace('\n', '\n' + self.indent * "    "))

    def appendspace(self):
        """ append a space to the output - if we're not at the start of a line """
        if not self.freshline:
            self.write(' ')

    def doplain(self, s):
        if (len(s) > 1) and (s[0] == '$' and s[-1] == '$') and self.state != 'math':
            s = ":math:`%s`" % s[1:-1].strip()
        elif self.state != 'math':
            s.replace('\\_', '_')
        if len(s) > 0 and s[-1] == '\n':
            s = s[:-1]
        if self.state == 'fpreamble':
            self.description += s
        else:
            self.write(s)

    def docmd(self, c):
        if self.state == 'math':
            if c.cmd != ']':
                self.default_cmd(c)
            else:
                self.indent -= 1
                self.state = None
                self.write('\n\n')
        else:
            if c.cmd == '\n':
                self.write('\\\n')
            else:
                if c.cmd == '[':
                    meth = self.cmd_gomath
                else:
                    cname = "cmd_" + c.cmd
                    meth = getattr(self, cname, self.unrecognized_cmd)
                meth(c)

    def cmd_gomath(self, c):
        self.state = 'math'
        print >>self, "\n\n.. math::"
        self.indent += 1
        print >>self

    def cmd_chapter(self, c):
        filename = str(c.params[0]).lower().replace(' ', '_').replace('/','_').replace('.','_')
        self.f_index.write("    %s\n" % filename)
        self.f_chapter = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
        self.f_section = None
        self.f = self.f_chapter
        self.indent = 0
        title = str(c.params[0])
        print >>self, '*' * len(title)
        print >>self, title
        print >>self, '*' * len(title)
        print >>self
        self.chapter_intoc = False

    def cmd_section(self, c):
        filename = str(c.params[0]).lower().replace(' ', '_').replace('/','_')
        if len(self.cur_module) > 0:
            filename = self.cur_module + "_" + filename
        if not self.chapter_intoc:
            self.chapter_intoc = True
            print >>self.f_chapter
            print >>self.f_chapter, '.. toctree::'
            print >>self.f_chapter, '    :maxdepth: 2'
            print >>self.f_chapter
        self.f_chapter.write("    %s\n" % filename)
        self.f_section = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
        self.f = self.f_section
        self.indent = 0
        title = self.render(c.params[0].str)
        print >>self, title
        print >>self, '=' * len(title)
        print >>self
        print >>self, '.. highlight:: %s' % {'c': 'c', 'cpp': 'cpp', 'py': 'python'}[self.language]
        print >>self

    def cmd_subsection(self, c):
        print >>self
        nm = str(c.params[0])
        print >>self, nm
        print >>self, '-' * len(nm)
        print >>self
        self.function_props = {}
        self.covered.add(nm)

    def cmd_includegraphics(self, c):
        filename = os.path.join('..', '..', str(c.params[0]))
        print >>self, "\n\n.. image:: %s\n\n" % filename

    def cmd_renewcommand(self, c):
        self.indent = 0
        command = self.render(c.params[0].str)
	if command == 'curModule':
		self.cur_module = self.render(c.params[1].str)

    def wikiLink(self, name):
        return '`id=%s Comments from the Wiki <http://opencv.willowgarage.com/wiki/documentation/%s/%s/%s>`__' % (random(), self.language, self.cur_module, urllib.quote(name) )

    def cmd_cvCppCross(self, c):
        self.write(":func:`%s`" % str(c.params[0]))

    def cmd_cvCPyCross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cvCross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cvclass(self, c):
        self.indent = 0
        self.state = None
        nm = self.render(list(c.params[0].str))
        print >>self, "\n.. index:: %s\n" % nm
        print >>self, ".. _%s:\n" % nm
        print >>self, nm
        print >>self, '-' * len(nm)
        print >>self
        print >>self, self.wikiLink(nm)
        print >>self
        if self.language == 'py':
            print >>self, ".. class:: " + nm + "\n"
        else:
            print >>self, ".. ctype:: " + nm + "\n"
        print >>self
        self.addtag(nm, c)
        self.state = 'class'

    def cmd_index(self, c):
        pass

    def cmd_hyperref(self, c):
        pass

    def cmd_footnote(self, c):
        pass

    def cmd_textasciitilde(self, c):
        self.write('~')

    def addtag(self, nm, c):
        if nm == "":
            self.report_error(c, "empty name")
        self.tags[nm] = "%s\t%s\t%d" % (nm, os.path.join(os.getcwd(), c.filename), c.lineno)

    def cmd_cvfunc(self, c):
        self.cmd_cvCPyFunc(c)

    def cmd_cvCPyFunc(self, c):
        self.indent = 0
        nm = self.render(c.params[0].str)
        print >>self, "\n.. index:: %s\n" % nm
        print >>self, ".. _%s:\n" % nm
        print >>self, nm
        print >>self, '-' * len(nm)
        print >>self
        print >>self, self.wikiLink(nm)
        print >>self
        self.state = 'fpreamble'
        if self.description != "":
            self.report_error(c, "overflow - preceding cvfunc (starting %s) not terminated?" % repr(self.description[:30]))
        self.description = ""
        self.addtag(nm, c)

        self.function_props = {'name' : nm}
        self.covered.add(nm)

    def cmd_cvCppFunc(self, c):
        self.indent = 0
        nm = self.render(c.params[0].str)
        print >>self, "\n.. index:: %s\n" % nm
        if 0:
            print >>self, "\n.. _%s:\n" % nm
        print >>self
        print >>self, 'cv::%s' % nm
        print >>self, '-' * (4+len(nm))
        print >>self
        print >>self, self.wikiLink(nm)
        print >>self
        self.state = 'fpreamble'
        if self.description != "":
            self.report_error(c, "overflow - preceding cvfunc (starting %s) not terminated?" % repr(self.description[:30]))
        self.description = ""
        self.addtag(nm, c)

        self.function_props = {'name' : nm}
        self.covered.add(nm)

    def cmd_cvdefC(self, c):
        if self.language != 'c':
            return
        s = str(c.params[0]).replace('\\_', '_')
        s = s.replace('\\par', '')
        s = s.replace('\n', ' ')
        s = s.replace(';', '')
        self.indent = 0
        for proto in s.split('\\newline'):
            if proto.strip() != "":
                print >>self, "\n\n.. cfunction:: " + proto.strip() + "\n"
        # print >>self, "=", repr(c.params[0].str)
        print >>self, '    ' + self.description
        self.description = ""
        print >>self
        self.state = None
        self.function_props['defpy'] = s

    def cmd_cvdefCpp(self, c):
        if self.language != 'cpp':
            return
        s = str(c.params[0]).replace('\\_', '_')
        s = s.replace('\\par', '')
        s = s.replace('\n', ' ')
        s = s.replace(';', '')
        self.indent = 0
        for proto in s.split('\\newline'):
            if proto.strip() != "":
                print >>self, "\n\n.. cfunction:: " + proto.strip() + "\n"
        # print >>self, "=", repr(c.params[0].str)
        if self.description != "":
            print >>self, '    ' + self.description
        else:
            self.report_error(c, 'empty description')
        self.description = ""
        print >>self
        self.state = None
        self.function_props['defpy'] = s

    def cmd_cvdefPy(self, c):
        if self.language != 'py':
            return
        s = str(c.params[0]).replace('\\_', '_')
        self.indent = 0
        print >>self, ".. function:: " + s + "\n"
        # print >>self, "=", repr(c.params[0].str)
        print >>self, '    ' + self.description
        print >>self
        self.description = ""
        self.state = None
        self.function_props['defpy'] = s

        pp.ParserElement.setDefaultWhitespaceChars(" \n\t")

        ident = pp.Word(pp.alphanums + "_.+-")
        ident_or_tuple = ident | (sl('(') + CommaList(ident) + sl(')'))
        initializer = ident_or_tuple
        arg = returnList(ident + pp.Optional(sl('=') + initializer))

        decl = ident + sl('(') + CommaList(arg) + sl(')') + sl("->") + ident_or_tuple + pp.StringEnd()

        try:
            l = decl.parseString(s)
            if str(l[0]) != self.function_props['name']:
                self.report_error(c, 'Decl "%s" does not match function name "%s"' % (str(l[0]), self.function_props['name']))
            self.function_props['signature'] = l
            if l[0] in python_api:
                (ins, outs) = python_api[l[0]]
                ins = [a for a in ins if not 'O' in a.flags]
                if outs != None:
                    outs = outs.split(',')
                if len(ins) != len(l[1]):
                    self.report_error(c, "function %s documented arity %d, code arity %d" % (l[0], len(l[1]), len(ins)))
                if outs == None:
                    if l[2] != 'None':
                        self.report_error(c, "function %s documented None, but code has %s" % (l[0], l[2]))
                else:
                    if isinstance(l[2], str):
                        doc_outs = [l[2]]
                    else:
                        doc_outs = l[2]
                    if len(outs) != len(doc_outs):
                        self.report_error(c, "function %s output code tuple %d, documented %d" % (l[0], len(outs), len(doc_outs)))
            else:
                # self.report_error(c, "function %s documented but not found in code" % l[0])
                pass
        except pp.ParseException, pe:
            self.report_error(c, str(pe))
            print s
            print pe
Example #9
0
class SphinxWriter:
    def __init__(self, filename, language, abspath):
        assert language in ['py', 'c', 'cpp']
        self.language = language

        self.abspath = abspath
        os.path.abspath(os.path.dirname(filename))

        self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
        self.f = self.f_index
        self.f_chapter = None
        self.f_section = None
        self.indent = 0
        self.state = None
        self.envstack = []
        self.tags = {}
        self.errors = open('errors.%s' % language, 'wt')
        self.unhandled_commands = set()
        self.freshline = True
        self.function_props = {}
        self.covered = set()  # covered functions, used for error report
        self.description = ""

    def write(self, s):
        self.freshline = len(s) > 0 and (s[-1] == '\n')
        self.f.write(s.replace('\n', '\n' + self.indent * "    "))

    def appendspace(self):
        """ append a space to the output - if we're not at the start of a line """
        if not self.freshline:
            self.write(' ')

    def doplain(self, s):
        if (len(s) > 1) and (s[0] == '$'
                             and s[-1] == '$') and self.state != 'math':
            s = ":math:`%s`" % s[1:-1].strip()
        elif self.state != 'math':
            s.replace('\\_', '_')
        if len(s) > 0 and s[-1] == '\n':
            s = s[:-1]
        if self.state == 'fpreamble':
            self.description += s
        else:
            self.write(s)

    def docmd(self, c):
        if self.state == 'math':
            if c.cmd != ']':
                self.default_cmd(c)
            else:
                self.indent -= 1
                self.state = None
                self.write('\n\n')
        else:
            if c.cmd == '\n':
                self.write('\\\n')
            else:
                if c.cmd == '[':
                    meth = self.cmd_gomath
                else:
                    cname = "cmd_" + c.cmd
                    meth = getattr(self, cname, self.unrecognized_cmd)
                meth(c)

    def cmd_gomath(self, c):
        self.state = 'math'
        print >> self, "\n\n.. math::"
        self.indent += 1
        print >> self

    def cmd_chapter(self, c):
        filename = str(c.params[0]).lower().replace(' ', '_').replace('/', '_')
        self.f_index.write("    %s\n" % filename)
        self.f_chapter = QOpen(os.path.join(self.language, filename + '.rst'),
                               'wt')
        self.f_section = None
        self.f = self.f_chapter
        self.indent = 0
        title = str(c.params[0])
        print >> self, '*' * len(title)
        print >> self, title
        print >> self, '*' * len(title)
        print >> self
        self.chapter_intoc = False

    def cmd_section(self, c):
        filename = str(c.params[0]).lower().replace(' ', '_').replace('/', '_')
        if not self.chapter_intoc:
            self.chapter_intoc = True
            print >> self.f_chapter
            print >> self.f_chapter, '.. toctree::'
            print >> self.f_chapter, '    :maxdepth: 2'
            print >> self.f_chapter
        self.f_chapter.write("    %s\n" % filename)
        self.f_section = QOpen(os.path.join(self.language, filename + '.rst'),
                               'wt')
        self.f = self.f_section
        self.indent = 0
        title = self.render(c.params[0].str)
        print >> self, title
        print >> self, '=' * len(title)
        print >> self
        print >> self, '.. highlight:: %s' % {
            'c': 'c',
            'cpp': 'cpp',
            'py': 'python'
        }[self.language]
        print >> self

    def cmd_subsection(self, c):
        print >> self
        nm = str(c.params[0])
        print >> self, nm
        print >> self, '-' * len(nm)
        print >> self
        self.function_props = {}
        self.covered.add(nm)

    def cmd_includegraphics(self, c):
        filename = os.path.join('..', '..', str(c.params[0]))
        print >> self, "\n\n.. image:: %s\n\n" % filename

    def cmd_cvCppCross(self, c):
        self.write(":func:`%s`" % str(c.params[0]))

    def cmd_cvCPyCross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cvCross(self, c):
        self.write(":ref:`%s`" % str(c.params[0]))

    def cmd_cvclass(self, c):
        self.indent = 0
        self.state = None
        nm = self.render(list(c.params[0].str))
        print >> self, "\n.. index:: %s\n" % nm
        print >> self, ".. _%s:\n" % nm
        print >> self, nm
        print >> self, '-' * len(nm)
        print >> self
        if self.language == 'py':
            print >> self, ".. class:: " + nm + "\n"
        else:
            print >> self, ".. ctype:: " + nm + "\n"
        print >> self
        self.addtag(nm, c)
        self.state = 'class'

    def cmd_index(self, c):
        pass

    def cmd_hyperref(self, c):
        pass

    def cmd_footnote(self, c):
        pass

    def cmd_textasciitilde(self, c):
        self.write('~')

    def addtag(self, nm, c):
        if nm == "":
            self.report_error(c, "empty name")
        self.tags[nm] = "%s\t%s\t%d" % (
            nm, os.path.join(os.getcwd(), c.filename), c.lineno)

    def cmd_cvfunc(self, c):
        self.cmd_cvCPyFunc(c)

    def cmd_cvCPyFunc(self, c):
        self.indent = 0
        nm = self.render(c.params[0].str)
        print >> self, "\n.. index:: %s\n" % nm
        print >> self, ".. _%s:\n" % nm
        print >> self, nm
        print >> self, '-' * len(nm)
        print >> self
        self.state = 'fpreamble'
        if self.description != "":
            self.report_error(
                c,
                "overflow - preceding cvfunc (starting %s) not terminated?" %
                repr(self.description[:30]))
        self.description = ""
        self.addtag(nm, c)

        self.function_props = {'name': nm}
        self.covered.add(nm)

    def cmd_cvCppFunc(self, c):
        self.indent = 0
        nm = self.render(c.params[0].str)
        print >> self, "\n.. index:: %s\n" % nm
        if 0:
            print >> self, "\n.. _%s:\n" % nm
        print >> self
        print >> self, 'cv::%s' % nm
        print >> self, '-' * (4 + len(nm))
        print >> self
        self.state = 'fpreamble'
        if self.description != "":
            self.report_error(
                c,
                "overflow - preceding cvfunc (starting %s) not terminated?" %
                repr(self.description[:30]))
        self.description = ""
        self.addtag(nm, c)

        self.function_props = {'name': nm}
        self.covered.add(nm)

    def cmd_cvdefC(self, c):
        if self.language != 'c':
            return
        s = str(c.params[0]).replace('\\_', '_')
        s = s.replace('\\par', '')
        s = s.replace('\n', ' ')
        s = s.replace(';', '')
        self.indent = 0
        for proto in s.split('\\newline'):
            if proto.strip() != "":
                print >> self, "\n\n.. cfunction:: " + proto.strip() + "\n"
        # print >>self, "=", repr(c.params[0].str)
        print >> self, '    ' + self.description
        self.description = ""
        print >> self
        self.state = None
        self.function_props['defpy'] = s

    def cmd_cvdefCpp(self, c):
        if self.language != 'cpp':
            return
        s = str(c.params[0]).replace('\\_', '_')
        s = s.replace('\\par', '')
        s = s.replace('\n', ' ')
        s = s.replace(';', '')
        self.indent = 0
        for proto in s.split('\\newline'):
            if proto.strip() != "":
                print >> self, "\n\n.. cfunction:: " + proto.strip() + "\n"
        # print >>self, "=", repr(c.params[0].str)
        if self.description != "":
            print >> self, '    ' + self.description
        else:
            self.report_error(c, 'empty description')
        self.description = ""
        print >> self
        self.state = None
        self.function_props['defpy'] = s

    def cmd_cvdefPy(self, c):
        if self.language != 'py':
            return
        s = str(c.params[0]).replace('\\_', '_')
        self.indent = 0
        print >> self, ".. function:: " + s + "\n"
        # print >>self, "=", repr(c.params[0].str)
        print >> self, '    ' + self.description
        print >> self
        self.description = ""
        self.state = None
        self.function_props['defpy'] = s

        pp.ParserElement.setDefaultWhitespaceChars(" \n\t")

        ident = pp.Word(pp.alphanums + "_.+-")
        ident_or_tuple = ident | (sl('(') + CommaList(ident) + sl(')'))
        initializer = ident_or_tuple
        arg = returnList(ident + pp.Optional(sl('=') + initializer))

        decl = ident + sl('(') + CommaList(arg) + sl(')') + sl(
            "->") + ident_or_tuple + pp.StringEnd()

        try:
            l = decl.parseString(s)
            if str(l[0]) != self.function_props['name']:
                self.report_error(
                    c, 'Decl "%s" does not match function name "%s"' %
                    (str(l[0]), self.function_props['name']))
            self.function_props['signature'] = l
            if l[0] in python_api:
                (ins, outs) = python_api[l[0]]
                ins = [a for a in ins if not 'O' in a.flags]
                if outs != None:
                    outs = outs.split(',')
                if len(ins) != len(l[1]):
                    self.report_error(
                        c, "function %s documented arity %d, code arity %d" %
                        (l[0], len(l[1]), len(ins)))
                if outs == None:
                    if l[2] != 'None':
                        self.report_error(
                            c, "function %s documented None, but code has %s" %
                            (l[0], l[2]))
                else:
                    if isinstance(l[2], str):
                        doc_outs = [l[2]]
                    else:
                        doc_outs = l[2]
                    if len(outs) != len(doc_outs):
                        self.report_error(
                            c,
                            "function %s output code tuple %d, documented %d" %
                            (l[0], len(outs), len(doc_outs)))
            else:
                # self.report_error(c, "function %s documented but not found in code" % l[0])
                pass
        except pp.ParseException, pe:
            self.report_error(c, str(pe))
            print s
            print pe