qapi.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #
  2. # QAPI helper library
  3. #
  4. # Copyright IBM, Corp. 2011
  5. #
  6. # Authors:
  7. # Anthony Liguori <aliguori@us.ibm.com>
  8. #
  9. # This work is licensed under the terms of the GNU GPLv2.
  10. # See the COPYING.LIB file in the top-level directory.
  11. from ordereddict import OrderedDict
  12. builtin_types = [
  13. 'str', 'int', 'number', 'bool',
  14. 'int8', 'int16', 'int32', 'int64',
  15. 'uint8', 'uint16', 'uint32', 'uint64'
  16. ]
  17. builtin_type_qtypes = {
  18. 'str': 'QTYPE_QSTRING',
  19. 'int': 'QTYPE_QINT',
  20. 'number': 'QTYPE_QFLOAT',
  21. 'bool': 'QTYPE_QBOOL',
  22. 'int8': 'QTYPE_QINT',
  23. 'int16': 'QTYPE_QINT',
  24. 'int32': 'QTYPE_QINT',
  25. 'int64': 'QTYPE_QINT',
  26. 'uint8': 'QTYPE_QINT',
  27. 'uint16': 'QTYPE_QINT',
  28. 'uint32': 'QTYPE_QINT',
  29. 'uint64': 'QTYPE_QINT',
  30. }
  31. def tokenize(data):
  32. while len(data):
  33. ch = data[0]
  34. data = data[1:]
  35. if ch in ['{', '}', ':', ',', '[', ']']:
  36. yield ch
  37. elif ch in ' \n':
  38. None
  39. elif ch == "'":
  40. string = ''
  41. esc = False
  42. while True:
  43. if (data == ''):
  44. raise Exception("Mismatched quotes")
  45. ch = data[0]
  46. data = data[1:]
  47. if esc:
  48. string += ch
  49. esc = False
  50. elif ch == "\\":
  51. esc = True
  52. elif ch == "'":
  53. break
  54. else:
  55. string += ch
  56. yield string
  57. def parse(tokens):
  58. if tokens[0] == '{':
  59. ret = OrderedDict()
  60. tokens = tokens[1:]
  61. while tokens[0] != '}':
  62. key = tokens[0]
  63. tokens = tokens[1:]
  64. tokens = tokens[1:] # :
  65. value, tokens = parse(tokens)
  66. if tokens[0] == ',':
  67. tokens = tokens[1:]
  68. ret[key] = value
  69. tokens = tokens[1:]
  70. return ret, tokens
  71. elif tokens[0] == '[':
  72. ret = []
  73. tokens = tokens[1:]
  74. while tokens[0] != ']':
  75. value, tokens = parse(tokens)
  76. if tokens[0] == ',':
  77. tokens = tokens[1:]
  78. ret.append(value)
  79. tokens = tokens[1:]
  80. return ret, tokens
  81. else:
  82. return tokens[0], tokens[1:]
  83. def evaluate(string):
  84. return parse(map(lambda x: x, tokenize(string)))[0]
  85. def get_expr(fp):
  86. expr = ''
  87. for line in fp:
  88. if line.startswith('#') or line == '\n':
  89. continue
  90. if line.startswith(' '):
  91. expr += line
  92. elif expr:
  93. yield expr
  94. expr = line
  95. else:
  96. expr += line
  97. if expr:
  98. yield expr
  99. def parse_schema(fp):
  100. exprs = []
  101. for expr in get_expr(fp):
  102. expr_eval = evaluate(expr)
  103. if expr_eval.has_key('enum'):
  104. add_enum(expr_eval['enum'])
  105. elif expr_eval.has_key('union'):
  106. add_union(expr_eval)
  107. add_enum('%sKind' % expr_eval['union'])
  108. elif expr_eval.has_key('type'):
  109. add_struct(expr_eval)
  110. exprs.append(expr_eval)
  111. return exprs
  112. def parse_args(typeinfo):
  113. if isinstance(typeinfo, basestring):
  114. struct = find_struct(typeinfo)
  115. assert struct != None
  116. typeinfo = struct['data']
  117. for member in typeinfo:
  118. argname = member
  119. argentry = typeinfo[member]
  120. optional = False
  121. structured = False
  122. if member.startswith('*'):
  123. argname = member[1:]
  124. optional = True
  125. if isinstance(argentry, OrderedDict):
  126. structured = True
  127. yield (argname, argentry, optional, structured)
  128. def de_camel_case(name):
  129. new_name = ''
  130. for ch in name:
  131. if ch.isupper() and new_name:
  132. new_name += '_'
  133. if ch == '-':
  134. new_name += '_'
  135. else:
  136. new_name += ch.lower()
  137. return new_name
  138. def camel_case(name):
  139. new_name = ''
  140. first = True
  141. for ch in name:
  142. if ch in ['_', '-']:
  143. first = True
  144. elif first:
  145. new_name += ch.upper()
  146. first = False
  147. else:
  148. new_name += ch.lower()
  149. return new_name
  150. def c_var(name, protect=True):
  151. # ANSI X3J11/88-090, 3.1.1
  152. c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
  153. 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
  154. 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
  155. 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
  156. 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
  157. # ISO/IEC 9899:1999, 6.4.1
  158. c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
  159. # ISO/IEC 9899:2011, 6.4.1
  160. c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
  161. '_Static_assert', '_Thread_local'])
  162. # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
  163. # excluding _.*
  164. gcc_words = set(['asm', 'typeof'])
  165. # namespace pollution:
  166. polluted_words = set(['unix'])
  167. if protect and (name in c89_words | c99_words | c11_words | gcc_words | polluted_words):
  168. return "q_" + name
  169. return name.replace('-', '_').lstrip("*")
  170. def c_fun(name, protect=True):
  171. return c_var(name, protect).replace('.', '_')
  172. def c_list_type(name):
  173. return '%sList' % name
  174. def type_name(name):
  175. if type(name) == list:
  176. return c_list_type(name[0])
  177. return name
  178. enum_types = []
  179. struct_types = []
  180. union_types = []
  181. def add_struct(definition):
  182. global struct_types
  183. struct_types.append(definition)
  184. def find_struct(name):
  185. global struct_types
  186. for struct in struct_types:
  187. if struct['type'] == name:
  188. return struct
  189. return None
  190. def add_union(definition):
  191. global union_types
  192. union_types.append(definition)
  193. def find_union(name):
  194. global union_types
  195. for union in union_types:
  196. if union['union'] == name:
  197. return union
  198. return None
  199. def add_enum(name):
  200. global enum_types
  201. enum_types.append(name)
  202. def is_enum(name):
  203. global enum_types
  204. return (name in enum_types)
  205. def c_type(name):
  206. if name == 'str':
  207. return 'char *'
  208. elif name == 'int':
  209. return 'int64_t'
  210. elif (name == 'int8' or name == 'int16' or name == 'int32' or
  211. name == 'int64' or name == 'uint8' or name == 'uint16' or
  212. name == 'uint32' or name == 'uint64'):
  213. return name + '_t'
  214. elif name == 'size':
  215. return 'uint64_t'
  216. elif name == 'bool':
  217. return 'bool'
  218. elif name == 'number':
  219. return 'double'
  220. elif type(name) == list:
  221. return '%s *' % c_list_type(name[0])
  222. elif is_enum(name):
  223. return name
  224. elif name == None or len(name) == 0:
  225. return 'void'
  226. elif name == name.upper():
  227. return '%sEvent *' % camel_case(name)
  228. else:
  229. return '%s *' % name
  230. def genindent(count):
  231. ret = ""
  232. for i in range(count):
  233. ret += " "
  234. return ret
  235. indent_level = 0
  236. def push_indent(indent_amount=4):
  237. global indent_level
  238. indent_level += indent_amount
  239. def pop_indent(indent_amount=4):
  240. global indent_level
  241. indent_level -= indent_amount
  242. def cgen(code, **kwds):
  243. indent = genindent(indent_level)
  244. lines = code.split('\n')
  245. lines = map(lambda x: indent + x, lines)
  246. return '\n'.join(lines) % kwds + '\n'
  247. def mcgen(code, **kwds):
  248. return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
  249. def basename(filename):
  250. return filename.split("/")[-1]
  251. def guardname(filename):
  252. guard = basename(filename).rsplit(".", 1)[0]
  253. for substr in [".", " ", "-"]:
  254. guard = guard.replace(substr, "_")
  255. return guard.upper() + '_H'
  256. def guardstart(name):
  257. return mcgen('''
  258. #ifndef %(name)s
  259. #define %(name)s
  260. ''',
  261. name=guardname(name))
  262. def guardend(name):
  263. return mcgen('''
  264. #endif /* %(name)s */
  265. ''',
  266. name=guardname(name))