parser.py 5.9 KB

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