qapi.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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):
  128. return name.replace('-', '_').lstrip("*")
  129. def c_fun(name):
  130. return c_var(name).replace('.', '_')
  131. def c_list_type(name):
  132. return '%sList' % name
  133. def type_name(name):
  134. if type(name) == list:
  135. return c_list_type(name[0])
  136. return name
  137. enum_types = []
  138. def add_enum(name):
  139. global enum_types
  140. enum_types.append(name)
  141. def is_enum(name):
  142. global enum_types
  143. return (name in enum_types)
  144. def c_type(name):
  145. if name == 'str':
  146. return 'char *'
  147. elif name == 'int':
  148. return 'int64_t'
  149. elif (name == 'int8' or name == 'int16' or name == 'int32' or
  150. name == 'int64' or name == 'uint8' or name == 'uint16' or
  151. name == 'uint32' or name == 'uint64'):
  152. return name + '_t'
  153. elif name == 'size':
  154. return 'uint64_t'
  155. elif name == 'bool':
  156. return 'bool'
  157. elif name == 'number':
  158. return 'double'
  159. elif type(name) == list:
  160. return '%s *' % c_list_type(name[0])
  161. elif is_enum(name):
  162. return name
  163. elif name == None or len(name) == 0:
  164. return 'void'
  165. elif name == name.upper():
  166. return '%sEvent *' % camel_case(name)
  167. else:
  168. return '%s *' % name
  169. def genindent(count):
  170. ret = ""
  171. for i in range(count):
  172. ret += " "
  173. return ret
  174. indent_level = 0
  175. def push_indent(indent_amount=4):
  176. global indent_level
  177. indent_level += indent_amount
  178. def pop_indent(indent_amount=4):
  179. global indent_level
  180. indent_level -= indent_amount
  181. def cgen(code, **kwds):
  182. indent = genindent(indent_level)
  183. lines = code.split('\n')
  184. lines = map(lambda x: indent + x, lines)
  185. return '\n'.join(lines) % kwds + '\n'
  186. def mcgen(code, **kwds):
  187. return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
  188. def basename(filename):
  189. return filename.split("/")[-1]
  190. def guardname(filename):
  191. guard = basename(filename).rsplit(".", 1)[0]
  192. for substr in [".", " ", "-"]:
  193. guard = guard.replace(substr, "_")
  194. return guard.upper() + '_H'