qapi.py 6.5 KB

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