diff options
| author | Damien George <damien.p.george@gmail.com> | 2020-02-27 15:36:53 +1100 |
|---|---|---|
| committer | Damien George <damien.p.george@gmail.com> | 2020-02-28 10:33:03 +1100 |
| commit | 69661f3343bedf86e514337cff63d96cc42f8859 (patch) | |
| tree | af5dfb380ffdb75dda84828f63cf9d840d992f0f /tools/gendoc.py | |
| parent | 3f39d18c2b884d32f0443e2e8114ff9d7a14d718 (diff) | |
all: Reformat C and Python source code with tools/codeformat.py.
This is run with uncrustify 0.70.1, and black 19.10b0.
Diffstat (limited to 'tools/gendoc.py')
| -rw-r--r-- | tools/gendoc.py | 245 |
1 files changed, 134 insertions, 111 deletions
diff --git a/tools/gendoc.py b/tools/gendoc.py index 61844d203..0f1305699 100644 --- a/tools/gendoc.py +++ b/tools/gendoc.py @@ -15,10 +15,12 @@ def re_match_first(regexs, line): return name, match return None, None + def makedirs(d): if not os.path.isdir(d): os.makedirs(d) + class Lexer: class LexerError(Exception): pass @@ -31,15 +33,15 @@ class Lexer: def __init__(self, file): self.filename = file - with open(file, 'rt') as f: + with open(file, "rt") as f: line_num = 0 lines = [] for line in f: line_num += 1 line = line.strip() - if line == '///': - lines.append((line_num, '')) - elif line.startswith('/// '): + if line == "///": + lines.append((line_num, "")) + elif line.startswith("/// "): lines.append((line_num, line[4:])) elif len(lines) > 0 and lines[-1][1] is not None: lines.append((line_num, None)) @@ -64,9 +66,10 @@ class Lexer: return l[1] def error(self, msg): - print('({}:{}) {}'.format(self.filename, self.cur_line, msg)) + print("({}:{}) {}".format(self.filename, self.cur_line, msg)) raise Lexer.LexerError + class MarkdownWriter: def __init__(self): pass @@ -75,52 +78,53 @@ class MarkdownWriter: self.lines = [] def end(self): - return '\n'.join(self.lines) + return "\n".join(self.lines) def heading(self, level, text): if len(self.lines) > 0: - self.lines.append('') - self.lines.append(level * '#' + ' ' + text) - self.lines.append('') + self.lines.append("") + self.lines.append(level * "#" + " " + text) + self.lines.append("") def para(self, text): - if len(self.lines) > 0 and self.lines[-1] != '': - self.lines.append('') + if len(self.lines) > 0 and self.lines[-1] != "": + self.lines.append("") if isinstance(text, list): self.lines.extend(text) elif isinstance(text, str): self.lines.append(text) else: assert False - self.lines.append('') + self.lines.append("") def single_line(self, text): self.lines.append(text) def module(self, name, short_descr, descr): - self.heading(1, 'module {}'.format(name)) + self.heading(1, "module {}".format(name)) self.para(descr) def function(self, ctx, name, args, descr): - proto = '{}.{}{}'.format(ctx, self.name, self.args) - self.heading(3, '`' + proto + '`') + proto = "{}.{}{}".format(ctx, self.name, self.args) + self.heading(3, "`" + proto + "`") self.para(descr) def method(self, ctx, name, args, descr): - if name == '\\constructor': - proto = '{}{}'.format(ctx, args) - elif name == '\\call': - proto = '{}{}'.format(ctx, args) + if name == "\\constructor": + proto = "{}{}".format(ctx, args) + elif name == "\\call": + proto = "{}{}".format(ctx, args) else: - proto = '{}.{}{}'.format(ctx, name, args) - self.heading(3, '`' + proto + '`') + proto = "{}.{}{}".format(ctx, name, args) + self.heading(3, "`" + proto + "`") self.para(descr) def constant(self, ctx, name, descr): - self.single_line('`{}.{}` - {}'.format(ctx, name, descr)) + self.single_line("`{}.{}` - {}".format(ctx, name, descr)) + class ReStructuredTextWriter: - head_chars = {1:'=', 2:'-', 3:'.'} + head_chars = {1: "=", 2: "-", 3: "."} def __init__(self): pass @@ -129,23 +133,23 @@ class ReStructuredTextWriter: self.lines = [] def end(self): - return '\n'.join(self.lines) + return "\n".join(self.lines) def _convert(self, text): - return text.replace('`', '``').replace('*', '\\*') + return text.replace("`", "``").replace("*", "\\*") def heading(self, level, text, convert=True): if len(self.lines) > 0: - self.lines.append('') + self.lines.append("") if convert: text = self._convert(text) self.lines.append(text) self.lines.append(len(text) * self.head_chars[level]) - self.lines.append('') + self.lines.append("") - def para(self, text, indent=''): - if len(self.lines) > 0 and self.lines[-1] != '': - self.lines.append('') + def para(self, text, indent=""): + if len(self.lines) > 0 and self.lines[-1] != "": + self.lines.append("") if isinstance(text, list): for t in text: self.lines.append(indent + self._convert(t)) @@ -153,39 +157,41 @@ class ReStructuredTextWriter: self.lines.append(indent + self._convert(text)) else: assert False - self.lines.append('') + self.lines.append("") def single_line(self, text): self.lines.append(self._convert(text)) def module(self, name, short_descr, descr): - self.heading(1, ':mod:`{}` --- {}'.format(name, self._convert(short_descr)), convert=False) - self.lines.append('.. module:: {}'.format(name)) - self.lines.append(' :synopsis: {}'.format(short_descr)) + self.heading(1, ":mod:`{}` --- {}".format(name, self._convert(short_descr)), convert=False) + self.lines.append(".. module:: {}".format(name)) + self.lines.append(" :synopsis: {}".format(short_descr)) self.para(descr) def function(self, ctx, name, args, descr): args = self._convert(args) - self.lines.append('.. function:: ' + name + args) - self.para(descr, indent=' ') + self.lines.append(".. function:: " + name + args) + self.para(descr, indent=" ") def method(self, ctx, name, args, descr): args = self._convert(args) - if name == '\\constructor': - self.lines.append('.. class:: ' + ctx + args) - elif name == '\\call': - self.lines.append('.. method:: ' + ctx + args) + if name == "\\constructor": + self.lines.append(".. class:: " + ctx + args) + elif name == "\\call": + self.lines.append(".. method:: " + ctx + args) else: - self.lines.append('.. method:: ' + ctx + '.' + name + args) - self.para(descr, indent=' ') + self.lines.append(".. method:: " + ctx + "." + name + args) + self.para(descr, indent=" ") def constant(self, ctx, name, descr): - self.lines.append('.. data:: ' + name) - self.para(descr, indent=' ') + self.lines.append(".. data:: " + name) + self.para(descr, indent=" ") + class DocValidateError(Exception): pass + class DocItem: def __init__(self): self.doc = [] @@ -202,6 +208,7 @@ class DocItem: def dump(self, writer): writer.para(self.doc) + class DocConstant(DocItem): def __init__(self, name, descr): super().__init__() @@ -211,6 +218,7 @@ class DocConstant(DocItem): def dump(self, ctx, writer): writer.constant(ctx, self.name, self.descr) + class DocFunction(DocItem): def __init__(self, name, args): super().__init__() @@ -220,6 +228,7 @@ class DocFunction(DocItem): def dump(self, ctx, writer): writer.function(ctx, self.name, self.args, self.doc) + class DocMethod(DocItem): def __init__(self, name, args): super().__init__() @@ -229,6 +238,7 @@ class DocMethod(DocItem): def dump(self, ctx, writer): writer.method(ctx, self.name, self.args, self.doc) + class DocClass(DocItem): def __init__(self, name, descr): super().__init__() @@ -240,51 +250,52 @@ class DocClass(DocItem): self.constants = {} def process_classmethod(self, lex, d): - name = d['id'] - if name == '\\constructor': + name = d["id"] + if name == "\\constructor": dict_ = self.constructors else: dict_ = self.classmethods if name in dict_: lex.error("multiple definition of method '{}'".format(name)) - method = dict_[name] = DocMethod(name, d['args']) + method = dict_[name] = DocMethod(name, d["args"]) method.add_doc(lex) def process_method(self, lex, d): - name = d['id'] + name = d["id"] dict_ = self.methods if name in dict_: lex.error("multiple definition of method '{}'".format(name)) - method = dict_[name] = DocMethod(name, d['args']) + method = dict_[name] = DocMethod(name, d["args"]) method.add_doc(lex) def process_constant(self, lex, d): - name = d['id'] + name = d["id"] if name in self.constants: lex.error("multiple definition of constant '{}'".format(name)) - self.constants[name] = DocConstant(name, d['descr']) + self.constants[name] = DocConstant(name, d["descr"]) lex.opt_break() def dump(self, writer): - writer.heading(1, 'class {}'.format(self.name)) + writer.heading(1, "class {}".format(self.name)) super().dump(writer) if len(self.constructors) > 0: - writer.heading(2, 'Constructors') - for f in sorted(self.constructors.values(), key=lambda x:x.name): + writer.heading(2, "Constructors") + for f in sorted(self.constructors.values(), key=lambda x: x.name): f.dump(self.name, writer) if len(self.classmethods) > 0: - writer.heading(2, 'Class methods') - for f in sorted(self.classmethods.values(), key=lambda x:x.name): + writer.heading(2, "Class methods") + for f in sorted(self.classmethods.values(), key=lambda x: x.name): f.dump(self.name, writer) if len(self.methods) > 0: - writer.heading(2, 'Methods') - for f in sorted(self.methods.values(), key=lambda x:x.name): + writer.heading(2, "Methods") + for f in sorted(self.methods.values(), key=lambda x: x.name): f.dump(self.name.lower(), writer) if len(self.constants) > 0: - writer.heading(2, 'Constants') - for c in sorted(self.constants.values(), key=lambda x:x.name): + writer.heading(2, "Constants") + for c in sorted(self.constants.values(), key=lambda x: x.name): c.dump(self.name, writer) + class DocModule(DocItem): def __init__(self, name, descr): super().__init__() @@ -299,22 +310,22 @@ class DocModule(DocItem): self.cur_class = None def process_function(self, lex, d): - name = d['id'] + name = d["id"] if name in self.functions: lex.error("multiple definition of function '{}'".format(name)) - function = self.functions[name] = DocFunction(name, d['args']) + function = self.functions[name] = DocFunction(name, d["args"]) function.add_doc(lex) - #def process_classref(self, lex, d): + # def process_classref(self, lex, d): # name = d['id'] # self.classes[name] = name # lex.opt_break() def process_class(self, lex, d): - name = d['id'] + name = d["id"] if name in self.classes: lex.error("multiple definition of class '{}'".format(name)) - self.cur_class = self.classes[name] = DocClass(name, d['descr']) + self.cur_class = self.classes[name] = DocClass(name, d["descr"]) self.cur_class.add_doc(lex) def process_classmethod(self, lex, d): @@ -326,10 +337,10 @@ class DocModule(DocItem): def process_constant(self, lex, d): if self.cur_class is None: # a module-level constant - name = d['id'] + name = d["id"] if name in self.constants: lex.error("multiple definition of constant '{}'".format(name)) - self.constants[name] = DocConstant(name, d['descr']) + self.constants[name] = DocConstant(name, d["descr"]) lex.opt_break() else: # a class-level constant @@ -337,50 +348,51 @@ class DocModule(DocItem): def validate(self): if self.descr is None: - raise DocValidateError('module {} referenced but never defined'.format(self.name)) + raise DocValidateError("module {} referenced but never defined".format(self.name)) def dump(self, writer): writer.module(self.name, self.descr, self.doc) if self.functions: - writer.heading(2, 'Functions') - for f in sorted(self.functions.values(), key=lambda x:x.name): + writer.heading(2, "Functions") + for f in sorted(self.functions.values(), key=lambda x: x.name): f.dump(self.name, writer) if self.constants: - writer.heading(2, 'Constants') - for c in sorted(self.constants.values(), key=lambda x:x.name): + writer.heading(2, "Constants") + for c in sorted(self.constants.values(), key=lambda x: x.name): c.dump(self.name, writer) if self.classes: - writer.heading(2, 'Classes') - for c in sorted(self.classes.values(), key=lambda x:x.name): - writer.para('[`{}.{}`]({}) - {}'.format(self.name, c.name, c.name, c.descr)) + writer.heading(2, "Classes") + for c in sorted(self.classes.values(), key=lambda x: x.name): + writer.para("[`{}.{}`]({}) - {}".format(self.name, c.name, c.name, c.descr)) def write_html(self, dir): md_writer = MarkdownWriter() md_writer.start() self.dump(md_writer) - with open(os.path.join(dir, 'index.html'), 'wt') as f: + with open(os.path.join(dir, "index.html"), "wt") as f: f.write(markdown.markdown(md_writer.end())) for c in self.classes.values(): class_dir = os.path.join(dir, c.name) makedirs(class_dir) md_writer.start() - md_writer.para('part of the [{} module](./)'.format(self.name)) + md_writer.para("part of the [{} module](./)".format(self.name)) c.dump(md_writer) - with open(os.path.join(class_dir, 'index.html'), 'wt') as f: + with open(os.path.join(class_dir, "index.html"), "wt") as f: f.write(markdown.markdown(md_writer.end())) def write_rst(self, dir): rst_writer = ReStructuredTextWriter() rst_writer.start() self.dump(rst_writer) - with open(dir + '/' + self.name + '.rst', 'wt') as f: + with open(dir + "/" + self.name + ".rst", "wt") as f: f.write(rst_writer.end()) for c in self.classes.values(): rst_writer.start() c.dump(rst_writer) - with open(dir + '/' + self.name + '.' + c.name + '.rst', 'wt') as f: + with open(dir + "/" + self.name + "." + c.name + ".rst", "wt") as f: f.write(rst_writer.end()) + class Doc: def __init__(self): self.modules = {} @@ -393,20 +405,20 @@ class Doc: def check_module(self, lex): if self.cur_module is None: - lex.error('module not defined') + lex.error("module not defined") def process_module(self, lex, d): - name = d['id'] + name = d["id"] if name not in self.modules: self.modules[name] = DocModule(name, None) self.cur_module = self.modules[name] if self.cur_module.descr is not None: lex.error("multiple definition of module '{}'".format(name)) - self.cur_module.descr = d['descr'] + self.cur_module.descr = d["descr"] self.cur_module.add_doc(lex) def process_moduleref(self, lex, d): - name = d['id'] + name = d["id"] if name not in self.modules: self.modules[name] = DocModule(name, None) self.cur_module = self.modules[name] @@ -437,41 +449,46 @@ class Doc: m.validate() def dump(self, writer): - writer.heading(1, 'Modules') - writer.para('These are the Python modules that are implemented.') - for m in sorted(self.modules.values(), key=lambda x:x.name): - writer.para('[`{}`]({}/) - {}'.format(m.name, m.name, m.descr)) + writer.heading(1, "Modules") + writer.para("These are the Python modules that are implemented.") + for m in sorted(self.modules.values(), key=lambda x: x.name): + writer.para("[`{}`]({}/) - {}".format(m.name, m.name, m.descr)) def write_html(self, dir): md_writer = MarkdownWriter() - with open(os.path.join(dir, 'module', 'index.html'), 'wt') as f: + with open(os.path.join(dir, "module", "index.html"), "wt") as f: md_writer.start() self.dump(md_writer) f.write(markdown.markdown(md_writer.end())) for m in self.modules.values(): - mod_dir = os.path.join(dir, 'module', m.name) + mod_dir = os.path.join(dir, "module", m.name) makedirs(mod_dir) m.write_html(mod_dir) def write_rst(self, dir): - #with open(os.path.join(dir, 'module', 'index.html'), 'wt') as f: + # with open(os.path.join(dir, 'module', 'index.html'), 'wt') as f: # f.write(markdown.markdown(self.dump())) for m in self.modules.values(): m.write_rst(dir) -regex_descr = r'(?P<descr>.*)' + +regex_descr = r"(?P<descr>.*)" doc_regexs = ( - (Doc.process_module, re.compile(r'\\module (?P<id>[a-z][a-z0-9]*) - ' + regex_descr + r'$')), - (Doc.process_moduleref, re.compile(r'\\moduleref (?P<id>[a-z]+)$')), - (Doc.process_function, re.compile(r'\\function (?P<id>[a-z0-9_]+)(?P<args>\(.*\))$')), - (Doc.process_classmethod, re.compile(r'\\classmethod (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$')), - (Doc.process_method, re.compile(r'\\method (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$')), - (Doc.process_constant, re.compile(r'\\constant (?P<id>[A-Za-z0-9_]+) - ' + regex_descr + r'$')), - #(Doc.process_classref, re.compile(r'\\classref (?P<id>[A-Za-z0-9_]+)$')), - (Doc.process_class, re.compile(r'\\class (?P<id>[A-Za-z0-9_]+) - ' + regex_descr + r'$')), + (Doc.process_module, re.compile(r"\\module (?P<id>[a-z][a-z0-9]*) - " + regex_descr + r"$")), + (Doc.process_moduleref, re.compile(r"\\moduleref (?P<id>[a-z]+)$")), + (Doc.process_function, re.compile(r"\\function (?P<id>[a-z0-9_]+)(?P<args>\(.*\))$")), + (Doc.process_classmethod, re.compile(r"\\classmethod (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$")), + (Doc.process_method, re.compile(r"\\method (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$")), + ( + Doc.process_constant, + re.compile(r"\\constant (?P<id>[A-Za-z0-9_]+) - " + regex_descr + r"$"), + ), + # (Doc.process_classref, re.compile(r'\\classref (?P<id>[A-Za-z0-9_]+)$')), + (Doc.process_class, re.compile(r"\\class (?P<id>[A-Za-z0-9_]+) - " + regex_descr + r"$")), ) + def process_file(file, doc): lex = Lexer(file) doc.new_file() @@ -481,11 +498,11 @@ def process_file(file, doc): line = lex.next() fun, match = re_match_first(doc_regexs, line) if fun == None: - lex.error('unknown line format: {}'.format(line)) + lex.error("unknown line format: {}".format(line)) fun(doc, lex, match.groupdict()) except Lexer.Break: - lex.error('unexpected break') + lex.error("unexpected break") except Lexer.EOF: pass @@ -495,16 +512,21 @@ def process_file(file, doc): return True + def main(): - cmd_parser = argparse.ArgumentParser(description='Generate documentation for pyboard API from C files.') - cmd_parser.add_argument('--outdir', metavar='<output dir>', default='gendoc-out', help='ouput directory') - cmd_parser.add_argument('--format', default='html', help='output format: html or rst') - cmd_parser.add_argument('files', nargs='+', help='input files') + cmd_parser = argparse.ArgumentParser( + description="Generate documentation for pyboard API from C files." + ) + cmd_parser.add_argument( + "--outdir", metavar="<output dir>", default="gendoc-out", help="ouput directory" + ) + cmd_parser.add_argument("--format", default="html", help="output format: html or rst") + cmd_parser.add_argument("files", nargs="+", help="input files") args = cmd_parser.parse_args() doc = Doc() for file in args.files: - print('processing', file) + print("processing", file) if not process_file(file, doc): return try: @@ -514,15 +536,16 @@ def main(): makedirs(args.outdir) - if args.format == 'html': + if args.format == "html": doc.write_html(args.outdir) - elif args.format == 'rst': + elif args.format == "rst": doc.write_rst(args.outdir) else: - print('unknown format:', args.format) + print("unknown format:", args.format) return - print('written to', args.outdir) + print("written to", args.outdir) + if __name__ == "__main__": main() |
