# -*- coding: utf-8 -*- import clang.cindex from clang.cindex import CursorKind class ASTParser: def __init__(self, library_file): if not clang.cindex.Config.loaded: print("Using libclang from: %s", library_file) clang.cindex.Config.set_library_file(library_file) import sys sys.setrecursionlimit(10000) print("max recursion limit set to:", sys.getrecursionlimit()) def parse(self, filename, content=None, follow_includes=False): index = clang.cindex.Index.create() arguments = ["-x", "c"] options = clang.cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES if content: content = [(filename, content)] translation_unit = index.parse(filename, unsaved_files=content, args=arguments, options=options) ret = self._parse(translation_unit.cursor, filename, follow_includes) return ret def _get_children(self, cursor, path, follow_includes=False): if follow_includes: return [c for c in cursor.get_children()] else: return [c for c in cursor.get_children() if c.location.file and c.location.file.name == path] def _parse(self, cursor, path, follow_includes=False, parent_cursor=None): item = None dont_recurse = False; # dont parse excluded CursorKinds excluded_cursortypes = [CursorKind.INTEGER_LITERAL] if not cursor.kind in excluded_cursortypes: item = {"" "tokens": "", "kind": "", "name": "", "type": "", "file": "", "is_definition": "", } # generic info for all CursorKinds if str(cursor.get_tokens()): str_tok = "" for tok in cursor.get_tokens(): str_tok += tok.spelling + " " item["tokens"] = str_tok.rstrip() if str(cursor.kind): item["kind"] = str(cursor.kind) if cursor.spelling: item["name"] = cursor.spelling # optional "displayname" if cursor.displayname: if cursor.displayname != item["name"]: item["displayname"] = cursor.displayname if cursor.type.spelling: item["type"] = cursor.type.spelling # optional "result_type" if cursor.result_type.spelling != "": item["result_type"] = cursor.result_type.spelling item["file"] = str(cursor.location.file) # optional "semantic_parent" if cursor.semantic_parent: if cursor.semantic_parent.kind.is_translation_unit(): item["semantic_parent"] = "global" else: item["semantic_parent"] = cursor.semantic_parent.spelling item["is_definition"] = False if cursor.is_definition(): item["is_definition"] = cursor.is_definition() # ENUM specific info # optional "value" if cursor.kind == CursorKind.ENUM_CONSTANT_DECL: item["value"] = cursor.enum_value # TYPEDEF specific info # optional "utype" if cursor.kind == CursorKind.TYPEDEF_DECL: item["utype"] = cursor.underlying_typedef_type.spelling item["utypekind"] = cursor.underlying_typedef_type.kind.spelling dont_recurse = True # TYPE_REF specific info # optional "typekind" if cursor.kind == CursorKind.TYPE_REF: item["utypekind"] = cursor.type.kind.spelling if parent_cursor: if( not cursor.kind == CursorKind.TYPE_REF and parent_cursor.kind == CursorKind.FIELD_DECL): return None if not dont_recurse: # get direct children child_cursors = self._get_children(cursor, path, follow_includes) if len(child_cursors) > 0: child_arr = [] for child_cursor in child_cursors: child_result = self._parse(child_cursor, path, follow_includes=follow_includes, parent_cursor=cursor) if child_result: child_arr.append(child_result) if child_arr: item["children"] = child_arr return item