qapi.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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 parse_schema(fp):
  72. exprs = []
  73. expr = ''
  74. expr_eval = None
  75. for line in fp:
  76. if line.startswith('#') or line == '\n':
  77. continue
  78. if line.startswith(' '):
  79. expr += line
  80. elif expr:
  81. expr_eval = evaluate(expr)
  82. if expr_eval.has_key('enum'):
  83. add_enum(expr_eval['enum'])
  84. elif expr_eval.has_key('union'):
  85. add_enum('%sKind' % expr_eval['union'])
  86. exprs.append(expr_eval)
  87. expr = line
  88. else:
  89. expr += line
  90. if expr:
  91. expr_eval = evaluate(expr)
  92. if expr_eval.has_key('enum'):
  93. add_enum(expr_eval['enum'])
  94. elif expr_eval.has_key('union'):
  95. add_enum('%sKind' % expr_eval['union'])
  96. exprs.append(expr_eval)
  97. return exprs
  98. def parse_args(typeinfo):
  99. for member in typeinfo:
  100. argname = member
  101. argentry = typeinfo[member]
  102. optional = False
  103. structured = False
  104. if member.startswith('*'):
  105. argname = member[1:]
  106. optional = True
  107. if isinstance(argentry, OrderedDict):
  108. structured = True
  109. yield (argname, argentry, optional, structured)
  110. def de_camel_case(name):
  111. new_name = ''
  112. for ch in name:
  113. if ch.isupper() and new_name:
  114. new_name += '_'
  115. if ch == '-':
  116. new_name += '_'
  117. else:
  118. new_name += ch.lower()
  119. return new_name
  120. def camel_case(name):
  121. new_name = ''
  122. first = True
  123. for ch in name:
  124. if ch in ['_', '-']:
  125. first = True
  126. elif first:
  127. new_name += ch.upper()
  128. first = False
  129. else:
  130. new_name += ch.lower()
  131. return new_name
  132. def c_var(name, protect=True):
  133. # ANSI X3J11/88-090, 3.1.1
  134. c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
  135. 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
  136. 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
  137. 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
  138. 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
  139. # ISO/IEC 9899:1999, 6.4.1
  140. c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
  141. # ISO/IEC 9899:2011, 6.4.1
  142. c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
  143. '_Static_assert', '_Thread_local'])
  144. # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
  145. # excluding _.*
  146. gcc_words = set(['asm', 'typeof'])
  147. # namespace pollution:
  148. polluted_words = set(['unix'])
  149. if protect and (name in c89_words | c99_words | c11_words | gcc_words | polluted_words):
  150. return "q_" + name
  151. return name.replace('-', '_').lstrip("*")
  152. def c_fun(name, protect=True):
  153. return c_var(name, protect).replace('.', '_')
  154. def c_list_type(name):
  155. return '%sList' % name
  156. def type_name(name):
  157. if type(name) == list:
  158. return c_list_type(name[0])
  159. return name
  160. enum_types = []
  161. def add_enum(name):
  162. global enum_types
  163. enum_types.append(name)
  164. def is_enum(name):
  165. global enum_types
  166. return (name in enum_types)
  167. def c_type(name):
  168. if name == 'str':
  169. return 'char *'
  170. elif name == 'int':
  171. return 'int64_t'
  172. elif (name == 'int8' or name == 'int16' or name == 'int32' or
  173. name == 'int64' or name == 'uint8' or name == 'uint16' or
  174. name == 'uint32' or name == 'uint64'):
  175. return name + '_t'
  176. elif name == 'size':
  177. return 'uint64_t'
  178. elif name == 'bool':
  179. return 'bool'
  180. elif name == 'number':
  181. return 'double'
  182. elif type(name) == list:
  183. return '%s *' % c_list_type(name[0])
  184. elif is_enum(name):
  185. return name
  186. elif name == None or len(name) == 0:
  187. return 'void'
  188. elif name == name.upper():
  189. return '%sEvent *' % camel_case(name)
  190. else:
  191. return '%s *' % name
  192. def genindent(count):
  193. ret = ""
  194. for i in range(count):
  195. ret += " "
  196. return ret
  197. indent_level = 0
  198. def push_indent(indent_amount=4):
  199. global indent_level
  200. indent_level += indent_amount
  201. def pop_indent(indent_amount=4):
  202. global indent_level
  203. indent_level -= indent_amount
  204. def cgen(code, **kwds):
  205. indent = genindent(indent_level)
  206. lines = code.split('\n')
  207. lines = map(lambda x: indent + x, lines)
  208. return '\n'.join(lines) % kwds + '\n'
  209. def mcgen(code, **kwds):
  210. return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
  211. def basename(filename):
  212. return filename.split("/")[-1]
  213. def guardname(filename):
  214. guard = basename(filename).rsplit(".", 1)[0]
  215. for substr in [".", " ", "-"]:
  216. guard = guard.replace(substr, "_")
  217. return guard.upper() + '_H'
  218. def guardstart(name):
  219. return mcgen('''
  220. #ifndef %(name)s
  221. #define %(name)s
  222. ''',
  223. name=guardname(name))
  224. def guardend(name):
  225. return mcgen('''
  226. #endif /* %(name)s */
  227. ''',
  228. name=guardname(name))