Files
igl/python/scripts/parser.py
T
Francis Williams 230ab71e20 Python binding for igl_adjacency_list(const MatrixXi& F, vector<vector<int>& A, bool sorted). Use an opaque type for the output parameter A.
I also fixed a couple of bugs in generate_docstrings.py:
1) We were checking for an empty string where a result could also be Nonn.
2) If you forgot to end the argument path with  a slash, the output would be incorrect
3) We were coupled to a specific version of clang for no reason
4) Python 3 clang binding support was only added in April 2017 (https://reviews.llvm.org/D31568). Using python3 by default will not work on the clang bindings which ship with pip and most Linux distros. Let's change the hashbang to use python2 for now.
5) The documentation for the script was a bit confusing.
2017-07-05 13:31:03 -04:00

135 lines
4.2 KiB
Python

import sys
import os
from threading import Thread
import clang.cindex
import ccsyspath
import itertools
from mako.template import Template
def get_annotations(node):
return [c.displayname for c in node.get_children()
if c.kind == clang.cindex.CursorKind.ANNOTATE_ATTR]
class Function(object):
def __init__(self, cursor):
self.name = cursor.spelling
self.annotations = get_annotations(cursor)
self.access = cursor.access_specifier
# template_pars = [c.extent for c in cursor.get_children() if c.kind == clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER]
parameter_dec = [c for c in cursor.get_children() if c.kind == clang.cindex.CursorKind.PARM_DECL]
parameters = []
for p in parameter_dec:
children = []
for c in p.get_children():
# print(c.spelling)
children.append(c.spelling)
parameters.append((p.spelling, p.type.spelling, children))
self.parameters = parameters
self.documentation = cursor.raw_comment
class Enum(object):
def __init__(self, cursor):
self.name = cursor.spelling
self.constants = [c.spelling for c in cursor.get_children() if c.kind ==
clang.cindex.CursorKind.ENUM_CONSTANT_DECL]
self.documentation = cursor.raw_comment
class Class(object):
def __init__(self, cursor):
self.name = cursor.spelling
# self.functions = []
self.annotations = get_annotations(cursor)
# for c in cursor.get_children():
# if (c.kind == clang.cindex.CursorKind.CXX_METHOD and
# c.access_specifier == clang.cindex.AccessSpecifier.PUBLIC):
# f = Function(c)
# self.functions.append(f)
def traverse(c, path, objects):
if c.location.file and not c.location.file.name.endswith(path):
return
if c.spelling == "PARULA_COLOR_MAP": # Fix to prevent python stack overflow from infinite recursion
return
# print(c.kind, c.spelling)
if c.kind == clang.cindex.CursorKind.TRANSLATION_UNIT or c.kind == clang.cindex.CursorKind.UNEXPOSED_DECL:
# Ignore other cursor kinds
pass
elif c.kind == clang.cindex.CursorKind.NAMESPACE:
objects["namespaces"].append(c.spelling)
# print("Namespace", c.spelling, c.get_children())
pass
elif c.kind == clang.cindex.CursorKind.FUNCTION_TEMPLATE:
# print("Function Template", c.spelling, c.raw_comment)
objects["functions"].append(Function(c))
return
elif c.kind == clang.cindex.CursorKind.FUNCTION_DECL:
# print("FUNCTION_DECL", c.spelling, c.raw_comment)
objects["functions"].append(Function(c))
return
elif c.kind == clang.cindex.CursorKind.ENUM_DECL:
# print("ENUM_DECL", c.spelling, c.raw_comment)
objects["enums"].append(Enum(c))
return
elif c.kind == clang.cindex.CursorKind.CLASS_DECL:
objects["classes"].append(Class(c))
return
elif c.kind == clang.cindex.CursorKind.CLASS_TEMPLATE:
objects["classes"].append(Class(c))
return
elif c.kind == clang.cindex.CursorKind.STRUCT_DECL:
objects["structs"].append(Class(c))
return
else:
# print("Unknown", c.kind, c.spelling)
pass
for child_node in c.get_children():
traverse(child_node, path, objects)
def parse(path):
index = clang.cindex.Index.create()
# Clang can't parse files with missing definitions, add static library definition or not?
args = ['-x', 'c++', '-std=c++11', '-fparse-all-comments', '-DIGL_STATIC_LIBRARY']
args.append('-I/usr/include/eigen3/') # TODO Properly add all needed includes
syspath = ccsyspath.system_include_paths('clang++') # Add the system libraries
incargs = [(b'-I' + inc).decode("utf-8") for inc in syspath]
args.extend(incargs)
tu = index.parse(path, args)
objects = {"functions": [], "enums": [], "namespaces": [], "classes": [], "structs": []}
traverse(tu.cursor, path, objects)
return objects
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python3 parser.py <headerfile_path>")
exit(-1)
parse(sys.argv[1])