parser.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. # This file is part of libigl, a simple c++ geometry processing library.
  2. #
  3. # Copyright (C) 2017 Sebastian Koch <s.koch@tu-berlin.de> and Daniele Panozzo <daniele.panozzo@gmail.com>
  4. #
  5. # This Source Code Form is subject to the terms of the Mozilla Public License
  6. # v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. # obtain one at http://mozilla.org/MPL/2.0/.
  8. import sys
  9. import os
  10. from threading import Thread
  11. import clang.cindex
  12. import ccsyspath
  13. import itertools
  14. from mako.template import Template
  15. def get_annotations(node):
  16. return [c.displayname for c in node.get_children()
  17. if c.kind == clang.cindex.CursorKind.ANNOTATE_ATTR]
  18. class Function(object):
  19. def __init__(self, cursor):
  20. self.name = cursor.spelling
  21. self.annotations = get_annotations(cursor)
  22. self.access = cursor.access_specifier
  23. # template_pars = [c.extent for c in cursor.get_children() if c.kind == clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER]
  24. parameter_dec = [c for c in cursor.get_children() if c.kind == clang.cindex.CursorKind.PARM_DECL]
  25. parameters = []
  26. for p in parameter_dec:
  27. children = []
  28. for c in p.get_children():
  29. # print(c.spelling)
  30. children.append(c.spelling)
  31. parameters.append((p.spelling, p.type.spelling, children))
  32. self.parameters = parameters
  33. self.documentation = cursor.raw_comment
  34. class Enum(object):
  35. def __init__(self, cursor):
  36. self.name = cursor.spelling
  37. self.constants = [c.spelling for c in cursor.get_children() if c.kind ==
  38. clang.cindex.CursorKind.ENUM_CONSTANT_DECL]
  39. self.documentation = cursor.raw_comment
  40. class Class(object):
  41. def __init__(self, cursor):
  42. self.name = cursor.spelling
  43. # self.functions = []
  44. self.annotations = get_annotations(cursor)
  45. # for c in cursor.get_children():
  46. # if (c.kind == clang.cindex.CursorKind.CXX_METHOD and
  47. # c.access_specifier == clang.cindex.AccessSpecifier.PUBLIC):
  48. # f = Function(c)
  49. # self.functions.append(f)
  50. def traverse(c, path, objects):
  51. if c.location.file and not c.location.file.name.endswith(path):
  52. return
  53. if c.spelling == "PARULA_COLOR_MAP": # Fix to prevent python stack overflow from infinite recursion
  54. return
  55. # print(c.kind, c.spelling)
  56. if c.kind == clang.cindex.CursorKind.TRANSLATION_UNIT or c.kind == clang.cindex.CursorKind.UNEXPOSED_DECL:
  57. # Ignore other cursor kinds
  58. pass
  59. elif c.kind == clang.cindex.CursorKind.NAMESPACE:
  60. objects["namespaces"].append(c.spelling)
  61. # print("Namespace", c.spelling, c.get_children())
  62. pass
  63. elif c.kind == clang.cindex.CursorKind.FUNCTION_TEMPLATE:
  64. # print("Function Template", c.spelling, c.raw_comment)
  65. objects["functions"].append(Function(c))
  66. return
  67. elif c.kind == clang.cindex.CursorKind.FUNCTION_DECL:
  68. # print("FUNCTION_DECL", c.spelling, c.raw_comment)
  69. objects["functions"].append(Function(c))
  70. return
  71. elif c.kind == clang.cindex.CursorKind.ENUM_DECL:
  72. # print("ENUM_DECL", c.spelling, c.raw_comment)
  73. objects["enums"].append(Enum(c))
  74. return
  75. elif c.kind == clang.cindex.CursorKind.CLASS_DECL:
  76. objects["classes"].append(Class(c))
  77. return
  78. elif c.kind == clang.cindex.CursorKind.CLASS_TEMPLATE:
  79. objects["classes"].append(Class(c))
  80. return
  81. elif c.kind == clang.cindex.CursorKind.STRUCT_DECL:
  82. objects["structs"].append(Class(c))
  83. return
  84. else:
  85. # print("Unknown", c.kind, c.spelling)
  86. pass
  87. for child_node in c.get_children():
  88. traverse(child_node, path, objects)
  89. def parse(path):
  90. index = clang.cindex.Index.create()
  91. # Clang can't parse files with missing definitions, add static library definition or not?
  92. args = ['-x', 'c++', '-std=c++11', '-fparse-all-comments', '-DIGL_STATIC_LIBRARY']
  93. args.append('-I/usr/include/eigen3/') # TODO Properly add all needed includes
  94. syspath = ccsyspath.system_include_paths('clang++') # Add the system libraries
  95. incargs = [(b'-I' + inc).decode("utf-8") for inc in syspath]
  96. args.extend(incargs)
  97. tu = index.parse(path, args)
  98. objects = {"functions": [], "enums": [], "namespaces": [], "classes": [], "structs": []}
  99. traverse(tu.cursor, path, objects)
  100. return objects
  101. if __name__ == '__main__':
  102. if len(sys.argv) != 2:
  103. print("Usage: python3 parser.py <headerfile_path>")
  104. exit(-1)
  105. parse(sys.argv[1])