parser.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from .schema import *
  2. class UnsupportedNode(Exception):
  3. def __init__(self, node: c_ast.Node):
  4. self.node = node
  5. def __str__(self):
  6. return f"'{type(self.node)}' is not supported\n{self.node!r}"
  7. class Header:
  8. def __init__(self):
  9. self.types = [] # type: list
  10. self.type_aliases = {} # type: dict[str, str]
  11. self.functions = [] # type: list[Function]
  12. def remove_types(self, names: set):
  13. self.types = [t for t in self.types if getattr(t, 'name', None) not in names]
  14. def remove_functions(self, names: set):
  15. self.functions = [f for f in self.functions if f.name not in names]
  16. def build_enum(self, node: c_ast.Enum):
  17. enum = Enum(node.name)
  18. for item in node.values.enumerators:
  19. enum.values.append(item.name)
  20. self.types.append(enum)
  21. def unalias(self, name: str):
  22. while name in self.type_aliases:
  23. name = self.type_aliases[name]
  24. return name
  25. def build_struct(self, node):
  26. if isinstance(node, c_ast.Struct):
  27. cls = Struct
  28. elif isinstance(node, c_ast.Union):
  29. cls = Union
  30. else:
  31. raise UnsupportedNode(node)
  32. if node.decls is not None:
  33. fields = {}
  34. for decl in node.decls:
  35. try:
  36. type, name = self.build_param(decl)
  37. assert name
  38. fields[name] = type
  39. except UnsupportedNode:
  40. pass
  41. self.types.append(cls(node.name, fields))
  42. else:
  43. self.types.append(cls(node.name, None))
  44. def build_type(self, name, node):
  45. if isinstance(node, c_ast.Enum):
  46. self.build_enum(node)
  47. elif isinstance(node, (c_ast.Struct, c_ast.Union)):
  48. self.build_struct(node)
  49. elif isinstance(node, c_ast.IdentifierType):
  50. assert name
  51. self.type_aliases[name] = node.names[0]
  52. else:
  53. raise UnsupportedNode(node)
  54. def get_type_name(self, node):
  55. # convert array to const T*
  56. if isinstance(node, c_ast.ArrayDecl):
  57. dims = []
  58. while isinstance(node, c_ast.ArrayDecl):
  59. dims.append(node.dim.value)
  60. node = node.type
  61. base_name = self.get_type_name(node)
  62. # return base_name + ''.join(f'[{dim}]' for dim in dims)
  63. return f'const {base_name}*'
  64. node, level = self.eat_pointers(node)
  65. if isinstance(node, c_ast.FuncDecl):
  66. assert level == 1
  67. return 'void (*)()'
  68. if not isinstance(node, (c_ast.TypeDecl, c_ast.Typename)):
  69. raise UnsupportedNode(node)
  70. is_const = node.quals and 'const' in node.quals
  71. node = node.type
  72. base_name: str
  73. if isinstance(node, c_ast.IdentifierType):
  74. base_name = node.names[0]
  75. elif isinstance(node, c_ast.Enum):
  76. base_name = 'enum ' + node.name
  77. elif isinstance(node, c_ast.Struct):
  78. base_name = 'struct ' + node.name
  79. elif isinstance(node, c_ast.Union):
  80. base_name = 'union ' + node.name
  81. else:
  82. base_name = self.get_type_name(node)
  83. if is_const:
  84. base_name = 'const ' + base_name
  85. return base_name + '*' * level
  86. def build_param(self, node):
  87. name = None
  88. if isinstance(node, c_ast.Decl):
  89. name = node.name
  90. node = node.type
  91. return self.get_type_name(node), name
  92. def eat_pointers(self, node):
  93. level = 0
  94. while isinstance(node, c_ast.PtrDecl):
  95. node = node.type
  96. level += 1
  97. return node, level
  98. def build_function(self, node: c_ast.FuncDecl):
  99. args = node.args
  100. node = node.type
  101. node, level = self.eat_pointers(node)
  102. assert isinstance(node, c_ast.TypeDecl), type(node)
  103. name = node.declname
  104. ret = node.type.names[0]
  105. func = Function(name, ret + '*' * level)
  106. if args is not None:
  107. for param in args.params:
  108. if isinstance(param, c_ast.EllipsisParam):
  109. func.args.append('...')
  110. else:
  111. T, name = self.build_param(param)
  112. if T != 'void':
  113. func.args.append(T)
  114. self.functions.append(func)
  115. def build(self, ast: c_ast.FileAST):
  116. for _, node in ast.children():
  117. if isinstance(node, c_ast.Typedef):
  118. name, node = node.name, node.type
  119. if isinstance(node, c_ast.TypeDecl):
  120. self.build_type(name, node.type)
  121. elif isinstance(node, c_ast.PtrDecl):
  122. type_name = self.get_type_name(node)
  123. self.type_aliases[name] = type_name
  124. else:
  125. # raise UnsupportedNode(node.type)
  126. # print(f"Unsupported typedef: {type(node)}")
  127. continue
  128. elif isinstance(node, c_ast.Decl):
  129. if isinstance(node.type, c_ast.FuncDecl):
  130. self.build_function(node.type)
  131. else:
  132. try:
  133. self.build_type(None, node.type)
  134. except UnsupportedNode:
  135. pass
  136. else:
  137. # raise UnsupportedNode(node.type)
  138. # print(f"Unsupported typedef: {type(node)}")
  139. continue