qapi.py 7.5 KB

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