2
0

qapi.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. #
  2. # QAPI helper library
  3. #
  4. # Copyright IBM, Corp. 2011
  5. # Copyright (c) 2013-2015 Red Hat Inc.
  6. #
  7. # Authors:
  8. # Anthony Liguori <aliguori@us.ibm.com>
  9. # Markus Armbruster <armbru@redhat.com>
  10. #
  11. # This work is licensed under the terms of the GNU GPL, version 2.
  12. # See the COPYING file in the top-level directory.
  13. import re
  14. from ordereddict import OrderedDict
  15. import os
  16. import sys
  17. builtin_types = {
  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. 'size': 'QTYPE_QINT',
  31. }
  32. # Whitelist of commands allowed to return a non-dictionary
  33. returns_whitelist = [
  34. # From QMP:
  35. 'human-monitor-command',
  36. 'query-migrate-cache-size',
  37. 'query-tpm-models',
  38. 'query-tpm-types',
  39. 'ringbuf-read',
  40. # From QGA:
  41. 'guest-file-open',
  42. 'guest-fsfreeze-freeze',
  43. 'guest-fsfreeze-freeze-list',
  44. 'guest-fsfreeze-status',
  45. 'guest-fsfreeze-thaw',
  46. 'guest-get-time',
  47. 'guest-set-vcpus',
  48. 'guest-sync',
  49. 'guest-sync-delimited',
  50. # From qapi-schema-test:
  51. 'user_def_cmd3',
  52. ]
  53. enum_types = []
  54. struct_types = []
  55. union_types = []
  56. events = []
  57. all_names = {}
  58. def error_path(parent):
  59. res = ""
  60. while parent:
  61. res = ("In file included from %s:%d:\n" % (parent['file'],
  62. parent['line'])) + res
  63. parent = parent['parent']
  64. return res
  65. class QAPISchemaError(Exception):
  66. def __init__(self, schema, msg):
  67. self.input_file = schema.input_file
  68. self.msg = msg
  69. self.col = 1
  70. self.line = schema.line
  71. for ch in schema.src[schema.line_pos:schema.pos]:
  72. if ch == '\t':
  73. self.col = (self.col + 7) % 8 + 1
  74. else:
  75. self.col += 1
  76. self.info = schema.parent_info
  77. def __str__(self):
  78. return error_path(self.info) + \
  79. "%s:%d:%d: %s" % (self.input_file, self.line, self.col, self.msg)
  80. class QAPIExprError(Exception):
  81. def __init__(self, expr_info, msg):
  82. self.info = expr_info
  83. self.msg = msg
  84. def __str__(self):
  85. return error_path(self.info['parent']) + \
  86. "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
  87. class QAPISchema:
  88. def __init__(self, fp, input_relname=None, include_hist=[],
  89. previously_included=[], parent_info=None):
  90. """ include_hist is a stack used to detect inclusion cycles
  91. previously_included is a global state used to avoid multiple
  92. inclusions of the same file"""
  93. input_fname = os.path.abspath(fp.name)
  94. if input_relname is None:
  95. input_relname = fp.name
  96. self.input_dir = os.path.dirname(input_fname)
  97. self.input_file = input_relname
  98. self.include_hist = include_hist + [(input_relname, input_fname)]
  99. previously_included.append(input_fname)
  100. self.parent_info = parent_info
  101. self.src = fp.read()
  102. if self.src == '' or self.src[-1] != '\n':
  103. self.src += '\n'
  104. self.cursor = 0
  105. self.line = 1
  106. self.line_pos = 0
  107. self.exprs = []
  108. self.accept()
  109. while self.tok != None:
  110. expr_info = {'file': input_relname, 'line': self.line, 'parent': self.parent_info}
  111. expr = self.get_expr(False)
  112. if isinstance(expr, dict) and "include" in expr:
  113. if len(expr) != 1:
  114. raise QAPIExprError(expr_info, "Invalid 'include' directive")
  115. include = expr["include"]
  116. if not isinstance(include, str):
  117. raise QAPIExprError(expr_info,
  118. 'Expected a file name (string), got: %s'
  119. % include)
  120. include_path = os.path.join(self.input_dir, include)
  121. for elem in self.include_hist:
  122. if include_path == elem[1]:
  123. raise QAPIExprError(expr_info, "Inclusion loop for %s"
  124. % include)
  125. # skip multiple include of the same file
  126. if include_path in previously_included:
  127. continue
  128. try:
  129. fobj = open(include_path, 'r')
  130. except IOError, e:
  131. raise QAPIExprError(expr_info,
  132. '%s: %s' % (e.strerror, include))
  133. exprs_include = QAPISchema(fobj, include, self.include_hist,
  134. previously_included, expr_info)
  135. self.exprs.extend(exprs_include.exprs)
  136. else:
  137. expr_elem = {'expr': expr,
  138. 'info': expr_info}
  139. self.exprs.append(expr_elem)
  140. def accept(self):
  141. while True:
  142. self.tok = self.src[self.cursor]
  143. self.pos = self.cursor
  144. self.cursor += 1
  145. self.val = None
  146. if self.tok == '#':
  147. self.cursor = self.src.find('\n', self.cursor)
  148. elif self.tok in ['{', '}', ':', ',', '[', ']']:
  149. return
  150. elif self.tok == "'":
  151. string = ''
  152. esc = False
  153. while True:
  154. ch = self.src[self.cursor]
  155. self.cursor += 1
  156. if ch == '\n':
  157. raise QAPISchemaError(self,
  158. 'Missing terminating "\'"')
  159. if esc:
  160. if ch == 'b':
  161. string += '\b'
  162. elif ch == 'f':
  163. string += '\f'
  164. elif ch == 'n':
  165. string += '\n'
  166. elif ch == 'r':
  167. string += '\r'
  168. elif ch == 't':
  169. string += '\t'
  170. elif ch == 'u':
  171. value = 0
  172. for x in range(0, 4):
  173. ch = self.src[self.cursor]
  174. self.cursor += 1
  175. if ch not in "0123456789abcdefABCDEF":
  176. raise QAPISchemaError(self,
  177. '\\u escape needs 4 '
  178. 'hex digits')
  179. value = (value << 4) + int(ch, 16)
  180. # If Python 2 and 3 didn't disagree so much on
  181. # how to handle Unicode, then we could allow
  182. # Unicode string defaults. But most of QAPI is
  183. # ASCII-only, so we aren't losing much for now.
  184. if not value or value > 0x7f:
  185. raise QAPISchemaError(self,
  186. 'For now, \\u escape '
  187. 'only supports non-zero '
  188. 'values up to \\u007f')
  189. string += chr(value)
  190. elif ch in "\\/'\"":
  191. string += ch
  192. else:
  193. raise QAPISchemaError(self,
  194. "Unknown escape \\%s" %ch)
  195. esc = False
  196. elif ch == "\\":
  197. esc = True
  198. elif ch == "'":
  199. self.val = string
  200. return
  201. else:
  202. string += ch
  203. elif self.tok in "tfn":
  204. val = self.src[self.cursor - 1:]
  205. if val.startswith("true"):
  206. self.val = True
  207. self.cursor += 3
  208. return
  209. elif val.startswith("false"):
  210. self.val = False
  211. self.cursor += 4
  212. return
  213. elif val.startswith("null"):
  214. self.val = None
  215. self.cursor += 3
  216. return
  217. elif self.tok == '\n':
  218. if self.cursor == len(self.src):
  219. self.tok = None
  220. return
  221. self.line += 1
  222. self.line_pos = self.cursor
  223. elif not self.tok.isspace():
  224. raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
  225. def get_members(self):
  226. expr = OrderedDict()
  227. if self.tok == '}':
  228. self.accept()
  229. return expr
  230. if self.tok != "'":
  231. raise QAPISchemaError(self, 'Expected string or "}"')
  232. while True:
  233. key = self.val
  234. self.accept()
  235. if self.tok != ':':
  236. raise QAPISchemaError(self, 'Expected ":"')
  237. self.accept()
  238. if key in expr:
  239. raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
  240. expr[key] = self.get_expr(True)
  241. if self.tok == '}':
  242. self.accept()
  243. return expr
  244. if self.tok != ',':
  245. raise QAPISchemaError(self, 'Expected "," or "}"')
  246. self.accept()
  247. if self.tok != "'":
  248. raise QAPISchemaError(self, 'Expected string')
  249. def get_values(self):
  250. expr = []
  251. if self.tok == ']':
  252. self.accept()
  253. return expr
  254. if not self.tok in "{['tfn":
  255. raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
  256. 'boolean or "null"')
  257. while True:
  258. expr.append(self.get_expr(True))
  259. if self.tok == ']':
  260. self.accept()
  261. return expr
  262. if self.tok != ',':
  263. raise QAPISchemaError(self, 'Expected "," or "]"')
  264. self.accept()
  265. def get_expr(self, nested):
  266. if self.tok != '{' and not nested:
  267. raise QAPISchemaError(self, 'Expected "{"')
  268. if self.tok == '{':
  269. self.accept()
  270. expr = self.get_members()
  271. elif self.tok == '[':
  272. self.accept()
  273. expr = self.get_values()
  274. elif self.tok in "'tfn":
  275. expr = self.val
  276. self.accept()
  277. else:
  278. raise QAPISchemaError(self, 'Expected "{", "[" or string')
  279. return expr
  280. def find_base_fields(base):
  281. base_struct_define = find_struct(base)
  282. if not base_struct_define:
  283. return None
  284. return base_struct_define['data']
  285. # Return the qtype of an alternate branch, or None on error.
  286. def find_alternate_member_qtype(qapi_type):
  287. if builtin_types.has_key(qapi_type):
  288. return builtin_types[qapi_type]
  289. elif find_struct(qapi_type):
  290. return "QTYPE_QDICT"
  291. elif find_enum(qapi_type):
  292. return "QTYPE_QSTRING"
  293. elif find_union(qapi_type):
  294. return "QTYPE_QDICT"
  295. return None
  296. # Return the discriminator enum define if discriminator is specified as an
  297. # enum type, otherwise return None.
  298. def discriminator_find_enum_define(expr):
  299. base = expr.get('base')
  300. discriminator = expr.get('discriminator')
  301. if not (discriminator and base):
  302. return None
  303. base_fields = find_base_fields(base)
  304. if not base_fields:
  305. return None
  306. discriminator_type = base_fields.get(discriminator)
  307. if not discriminator_type:
  308. return None
  309. return find_enum(discriminator_type)
  310. valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
  311. def check_name(expr_info, source, name, allow_optional = False,
  312. enum_member = False):
  313. global valid_name
  314. membername = name
  315. if not isinstance(name, str):
  316. raise QAPIExprError(expr_info,
  317. "%s requires a string name" % source)
  318. if name.startswith('*'):
  319. membername = name[1:]
  320. if not allow_optional:
  321. raise QAPIExprError(expr_info,
  322. "%s does not allow optional name '%s'"
  323. % (source, name))
  324. # Enum members can start with a digit, because the generated C
  325. # code always prefixes it with the enum name
  326. if enum_member:
  327. membername = '_' + membername
  328. if not valid_name.match(membername):
  329. raise QAPIExprError(expr_info,
  330. "%s uses invalid name '%s'" % (source, name))
  331. def check_type(expr_info, source, value, allow_array = False,
  332. allow_dict = False, allow_optional = False,
  333. allow_star = False, allow_metas = []):
  334. global all_names
  335. orig_value = value
  336. if value is None:
  337. return
  338. if allow_star and value == '**':
  339. return
  340. # Check if array type for value is okay
  341. if isinstance(value, list):
  342. if not allow_array:
  343. raise QAPIExprError(expr_info,
  344. "%s cannot be an array" % source)
  345. if len(value) != 1 or not isinstance(value[0], str):
  346. raise QAPIExprError(expr_info,
  347. "%s: array type must contain single type name"
  348. % source)
  349. value = value[0]
  350. orig_value = "array of %s" %value
  351. # Check if type name for value is okay
  352. if isinstance(value, str):
  353. if value == '**':
  354. raise QAPIExprError(expr_info,
  355. "%s uses '**' but did not request 'gen':false"
  356. % source)
  357. if not value in all_names:
  358. raise QAPIExprError(expr_info,
  359. "%s uses unknown type '%s'"
  360. % (source, orig_value))
  361. if not all_names[value] in allow_metas:
  362. raise QAPIExprError(expr_info,
  363. "%s cannot use %s type '%s'"
  364. % (source, all_names[value], orig_value))
  365. return
  366. # value is a dictionary, check that each member is okay
  367. if not isinstance(value, OrderedDict):
  368. raise QAPIExprError(expr_info,
  369. "%s should be a dictionary" % source)
  370. if not allow_dict:
  371. raise QAPIExprError(expr_info,
  372. "%s should be a type name" % source)
  373. for (key, arg) in value.items():
  374. check_name(expr_info, "Member of %s" % source, key,
  375. allow_optional=allow_optional)
  376. # Todo: allow dictionaries to represent default values of
  377. # an optional argument.
  378. check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
  379. allow_array=True, allow_star=allow_star,
  380. allow_metas=['built-in', 'union', 'alternate', 'struct',
  381. 'enum'])
  382. def check_member_clash(expr_info, base_name, data, source = ""):
  383. base = find_struct(base_name)
  384. assert base
  385. base_members = base['data']
  386. for key in data.keys():
  387. if key.startswith('*'):
  388. key = key[1:]
  389. if key in base_members or "*" + key in base_members:
  390. raise QAPIExprError(expr_info,
  391. "Member name '%s'%s clashes with base '%s'"
  392. % (key, source, base_name))
  393. if base.get('base'):
  394. check_member_clash(expr_info, base['base'], data, source)
  395. def check_command(expr, expr_info):
  396. name = expr['command']
  397. allow_star = expr.has_key('gen')
  398. check_type(expr_info, "'data' for command '%s'" % name,
  399. expr.get('data'), allow_dict=True, allow_optional=True,
  400. allow_metas=['union', 'struct'], allow_star=allow_star)
  401. returns_meta = ['union', 'struct']
  402. if name in returns_whitelist:
  403. returns_meta += ['built-in', 'alternate', 'enum']
  404. check_type(expr_info, "'returns' for command '%s'" % name,
  405. expr.get('returns'), allow_array=True, allow_dict=True,
  406. allow_optional=True, allow_metas=returns_meta,
  407. allow_star=allow_star)
  408. def check_event(expr, expr_info):
  409. global events
  410. name = expr['event']
  411. params = expr.get('data')
  412. if name.upper() == 'MAX':
  413. raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
  414. events.append(name)
  415. check_type(expr_info, "'data' for event '%s'" % name,
  416. expr.get('data'), allow_dict=True, allow_optional=True,
  417. allow_metas=['union', 'struct'])
  418. def check_union(expr, expr_info):
  419. name = expr['union']
  420. base = expr.get('base')
  421. discriminator = expr.get('discriminator')
  422. members = expr['data']
  423. values = { 'MAX': '(automatic)' }
  424. # If the object has a member 'base', its value must name a struct,
  425. # and there must be a discriminator.
  426. if base is not None:
  427. if discriminator is None:
  428. raise QAPIExprError(expr_info,
  429. "Union '%s' requires a discriminator to go "
  430. "along with base" %name)
  431. # Two types of unions, determined by discriminator.
  432. # With no discriminator it is a simple union.
  433. if discriminator is None:
  434. enum_define = None
  435. allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']
  436. if base is not None:
  437. raise QAPIExprError(expr_info,
  438. "Simple union '%s' must not have a base"
  439. % name)
  440. # Else, it's a flat union.
  441. else:
  442. # The object must have a string member 'base'.
  443. if not isinstance(base, str):
  444. raise QAPIExprError(expr_info,
  445. "Flat union '%s' must have a string base field"
  446. % name)
  447. base_fields = find_base_fields(base)
  448. if not base_fields:
  449. raise QAPIExprError(expr_info,
  450. "Base '%s' is not a valid struct"
  451. % base)
  452. # The value of member 'discriminator' must name a non-optional
  453. # member of the base struct.
  454. check_name(expr_info, "Discriminator of flat union '%s'" % name,
  455. discriminator)
  456. discriminator_type = base_fields.get(discriminator)
  457. if not discriminator_type:
  458. raise QAPIExprError(expr_info,
  459. "Discriminator '%s' is not a member of base "
  460. "struct '%s'"
  461. % (discriminator, base))
  462. enum_define = find_enum(discriminator_type)
  463. allow_metas=['struct']
  464. # Do not allow string discriminator
  465. if not enum_define:
  466. raise QAPIExprError(expr_info,
  467. "Discriminator '%s' must be of enumeration "
  468. "type" % discriminator)
  469. # Check every branch
  470. for (key, value) in members.items():
  471. check_name(expr_info, "Member of union '%s'" % name, key)
  472. # Each value must name a known type; furthermore, in flat unions,
  473. # branches must be a struct with no overlapping member names
  474. check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
  475. value, allow_array=True, allow_metas=allow_metas)
  476. if base:
  477. branch_struct = find_struct(value)
  478. assert branch_struct
  479. check_member_clash(expr_info, base, branch_struct['data'],
  480. " of branch '%s'" % key)
  481. # If the discriminator names an enum type, then all members
  482. # of 'data' must also be members of the enum type.
  483. if enum_define:
  484. if not key in enum_define['enum_values']:
  485. raise QAPIExprError(expr_info,
  486. "Discriminator value '%s' is not found in "
  487. "enum '%s'" %
  488. (key, enum_define["enum_name"]))
  489. # Otherwise, check for conflicts in the generated enum
  490. else:
  491. c_key = _generate_enum_string(key)
  492. if c_key in values:
  493. raise QAPIExprError(expr_info,
  494. "Union '%s' member '%s' clashes with '%s'"
  495. % (name, key, values[c_key]))
  496. values[c_key] = key
  497. def check_alternate(expr, expr_info):
  498. name = expr['alternate']
  499. members = expr['data']
  500. values = { 'MAX': '(automatic)' }
  501. types_seen = {}
  502. # Check every branch
  503. for (key, value) in members.items():
  504. check_name(expr_info, "Member of alternate '%s'" % name, key)
  505. # Check for conflicts in the generated enum
  506. c_key = _generate_enum_string(key)
  507. if c_key in values:
  508. raise QAPIExprError(expr_info,
  509. "Alternate '%s' member '%s' clashes with '%s'"
  510. % (name, key, values[c_key]))
  511. values[c_key] = key
  512. # Ensure alternates have no type conflicts.
  513. check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
  514. value,
  515. allow_metas=['built-in', 'union', 'struct', 'enum'])
  516. qtype = find_alternate_member_qtype(value)
  517. assert qtype
  518. if qtype in types_seen:
  519. raise QAPIExprError(expr_info,
  520. "Alternate '%s' member '%s' can't "
  521. "be distinguished from member '%s'"
  522. % (name, key, types_seen[qtype]))
  523. types_seen[qtype] = key
  524. def check_enum(expr, expr_info):
  525. name = expr['enum']
  526. members = expr.get('data')
  527. values = { 'MAX': '(automatic)' }
  528. if not isinstance(members, list):
  529. raise QAPIExprError(expr_info,
  530. "Enum '%s' requires an array for 'data'" % name)
  531. for member in members:
  532. check_name(expr_info, "Member of enum '%s'" %name, member,
  533. enum_member=True)
  534. key = _generate_enum_string(member)
  535. if key in values:
  536. raise QAPIExprError(expr_info,
  537. "Enum '%s' member '%s' clashes with '%s'"
  538. % (name, member, values[key]))
  539. values[key] = member
  540. def check_struct(expr, expr_info):
  541. name = expr['struct']
  542. members = expr['data']
  543. check_type(expr_info, "'data' for struct '%s'" % name, members,
  544. allow_dict=True, allow_optional=True)
  545. check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
  546. allow_metas=['struct'])
  547. if expr.get('base'):
  548. check_member_clash(expr_info, expr['base'], expr['data'])
  549. def check_exprs(schema):
  550. for expr_elem in schema.exprs:
  551. expr = expr_elem['expr']
  552. info = expr_elem['info']
  553. if expr.has_key('enum'):
  554. check_enum(expr, info)
  555. elif expr.has_key('union'):
  556. check_union(expr, info)
  557. elif expr.has_key('alternate'):
  558. check_alternate(expr, info)
  559. elif expr.has_key('struct'):
  560. check_struct(expr, info)
  561. elif expr.has_key('command'):
  562. check_command(expr, info)
  563. elif expr.has_key('event'):
  564. check_event(expr, info)
  565. else:
  566. assert False, 'unexpected meta type'
  567. def check_keys(expr_elem, meta, required, optional=[]):
  568. expr = expr_elem['expr']
  569. info = expr_elem['info']
  570. name = expr[meta]
  571. if not isinstance(name, str):
  572. raise QAPIExprError(info,
  573. "'%s' key must have a string value" % meta)
  574. required = required + [ meta ]
  575. for (key, value) in expr.items():
  576. if not key in required and not key in optional:
  577. raise QAPIExprError(info,
  578. "Unknown key '%s' in %s '%s'"
  579. % (key, meta, name))
  580. if (key == 'gen' or key == 'success-response') and value != False:
  581. raise QAPIExprError(info,
  582. "'%s' of %s '%s' should only use false value"
  583. % (key, meta, name))
  584. for key in required:
  585. if not expr.has_key(key):
  586. raise QAPIExprError(info,
  587. "Key '%s' is missing from %s '%s'"
  588. % (key, meta, name))
  589. def parse_schema(input_file):
  590. global all_names
  591. exprs = []
  592. # First pass: read entire file into memory
  593. try:
  594. schema = QAPISchema(open(input_file, "r"))
  595. except (QAPISchemaError, QAPIExprError), e:
  596. print >>sys.stderr, e
  597. exit(1)
  598. try:
  599. # Next pass: learn the types and check for valid expression keys. At
  600. # this point, top-level 'include' has already been flattened.
  601. for builtin in builtin_types.keys():
  602. all_names[builtin] = 'built-in'
  603. for expr_elem in schema.exprs:
  604. expr = expr_elem['expr']
  605. info = expr_elem['info']
  606. if expr.has_key('enum'):
  607. check_keys(expr_elem, 'enum', ['data'])
  608. add_enum(expr['enum'], info, expr['data'])
  609. elif expr.has_key('union'):
  610. check_keys(expr_elem, 'union', ['data'],
  611. ['base', 'discriminator'])
  612. add_union(expr, info)
  613. elif expr.has_key('alternate'):
  614. check_keys(expr_elem, 'alternate', ['data'])
  615. add_name(expr['alternate'], info, 'alternate')
  616. elif expr.has_key('struct'):
  617. check_keys(expr_elem, 'struct', ['data'], ['base'])
  618. add_struct(expr, info)
  619. elif expr.has_key('command'):
  620. check_keys(expr_elem, 'command', [],
  621. ['data', 'returns', 'gen', 'success-response'])
  622. add_name(expr['command'], info, 'command')
  623. elif expr.has_key('event'):
  624. check_keys(expr_elem, 'event', [], ['data'])
  625. add_name(expr['event'], info, 'event')
  626. else:
  627. raise QAPIExprError(expr_elem['info'],
  628. "Expression is missing metatype")
  629. exprs.append(expr)
  630. # Try again for hidden UnionKind enum
  631. for expr_elem in schema.exprs:
  632. expr = expr_elem['expr']
  633. if expr.has_key('union'):
  634. if not discriminator_find_enum_define(expr):
  635. add_enum('%sKind' % expr['union'], expr_elem['info'],
  636. implicit=True)
  637. elif expr.has_key('alternate'):
  638. add_enum('%sKind' % expr['alternate'], expr_elem['info'],
  639. implicit=True)
  640. # Final pass - validate that exprs make sense
  641. check_exprs(schema)
  642. except QAPIExprError, e:
  643. print >>sys.stderr, e
  644. exit(1)
  645. return exprs
  646. def parse_args(typeinfo):
  647. if isinstance(typeinfo, str):
  648. struct = find_struct(typeinfo)
  649. assert struct != None
  650. typeinfo = struct['data']
  651. for member in typeinfo:
  652. argname = member
  653. argentry = typeinfo[member]
  654. optional = False
  655. if member.startswith('*'):
  656. argname = member[1:]
  657. optional = True
  658. # Todo: allow argentry to be OrderedDict, for providing the
  659. # value of an optional argument.
  660. yield (argname, argentry, optional)
  661. def de_camel_case(name):
  662. new_name = ''
  663. for ch in name:
  664. if ch.isupper() and new_name:
  665. new_name += '_'
  666. if ch == '-':
  667. new_name += '_'
  668. else:
  669. new_name += ch.lower()
  670. return new_name
  671. def camel_case(name):
  672. new_name = ''
  673. first = True
  674. for ch in name:
  675. if ch in ['_', '-']:
  676. first = True
  677. elif first:
  678. new_name += ch.upper()
  679. first = False
  680. else:
  681. new_name += ch.lower()
  682. return new_name
  683. def c_var(name, protect=True):
  684. # ANSI X3J11/88-090, 3.1.1
  685. c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
  686. 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
  687. 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
  688. 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
  689. 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
  690. # ISO/IEC 9899:1999, 6.4.1
  691. c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
  692. # ISO/IEC 9899:2011, 6.4.1
  693. c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
  694. '_Static_assert', '_Thread_local'])
  695. # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
  696. # excluding _.*
  697. gcc_words = set(['asm', 'typeof'])
  698. # C++ ISO/IEC 14882:2003 2.11
  699. cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
  700. 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
  701. 'namespace', 'new', 'operator', 'private', 'protected',
  702. 'public', 'reinterpret_cast', 'static_cast', 'template',
  703. 'this', 'throw', 'true', 'try', 'typeid', 'typename',
  704. 'using', 'virtual', 'wchar_t',
  705. # alternative representations
  706. 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
  707. 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
  708. # namespace pollution:
  709. polluted_words = set(['unix', 'errno'])
  710. if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words):
  711. return "q_" + name
  712. return name.replace('-', '_').lstrip("*")
  713. def c_fun(name, protect=True):
  714. return c_var(name, protect).replace('.', '_')
  715. def c_list_type(name):
  716. return '%sList' % name
  717. def type_name(name):
  718. if type(name) == list:
  719. return c_list_type(name[0])
  720. return name
  721. def add_name(name, info, meta, implicit = False):
  722. global all_names
  723. check_name(info, "'%s'" % meta, name)
  724. if name in all_names:
  725. raise QAPIExprError(info,
  726. "%s '%s' is already defined"
  727. % (all_names[name], name))
  728. if not implicit and name[-4:] == 'Kind':
  729. raise QAPIExprError(info,
  730. "%s '%s' should not end in 'Kind'"
  731. % (meta, name))
  732. all_names[name] = meta
  733. def add_struct(definition, info):
  734. global struct_types
  735. name = definition['struct']
  736. add_name(name, info, 'struct')
  737. struct_types.append(definition)
  738. def find_struct(name):
  739. global struct_types
  740. for struct in struct_types:
  741. if struct['struct'] == name:
  742. return struct
  743. return None
  744. def add_union(definition, info):
  745. global union_types
  746. name = definition['union']
  747. add_name(name, info, 'union')
  748. union_types.append(definition)
  749. def find_union(name):
  750. global union_types
  751. for union in union_types:
  752. if union['union'] == name:
  753. return union
  754. return None
  755. def add_enum(name, info, enum_values = None, implicit = False):
  756. global enum_types
  757. add_name(name, info, 'enum', implicit)
  758. enum_types.append({"enum_name": name, "enum_values": enum_values})
  759. def find_enum(name):
  760. global enum_types
  761. for enum in enum_types:
  762. if enum['enum_name'] == name:
  763. return enum
  764. return None
  765. def is_enum(name):
  766. return find_enum(name) != None
  767. eatspace = '\033EATSPACE.'
  768. # A special suffix is added in c_type() for pointer types, and it's
  769. # stripped in mcgen(). So please notice this when you check the return
  770. # value of c_type() outside mcgen().
  771. def c_type(name, is_param=False):
  772. if name == 'str':
  773. if is_param:
  774. return 'const char *' + eatspace
  775. return 'char *' + eatspace
  776. elif name == 'int':
  777. return 'int64_t'
  778. elif (name == 'int8' or name == 'int16' or name == 'int32' or
  779. name == 'int64' or name == 'uint8' or name == 'uint16' or
  780. name == 'uint32' or name == 'uint64'):
  781. return name + '_t'
  782. elif name == 'size':
  783. return 'uint64_t'
  784. elif name == 'bool':
  785. return 'bool'
  786. elif name == 'number':
  787. return 'double'
  788. elif type(name) == list:
  789. return '%s *%s' % (c_list_type(name[0]), eatspace)
  790. elif is_enum(name):
  791. return name
  792. elif name == None or len(name) == 0:
  793. return 'void'
  794. elif name in events:
  795. return '%sEvent *%s' % (camel_case(name), eatspace)
  796. else:
  797. return '%s *%s' % (name, eatspace)
  798. def is_c_ptr(name):
  799. suffix = "*" + eatspace
  800. return c_type(name).endswith(suffix)
  801. def genindent(count):
  802. ret = ""
  803. for i in range(count):
  804. ret += " "
  805. return ret
  806. indent_level = 0
  807. def push_indent(indent_amount=4):
  808. global indent_level
  809. indent_level += indent_amount
  810. def pop_indent(indent_amount=4):
  811. global indent_level
  812. indent_level -= indent_amount
  813. def cgen(code, **kwds):
  814. indent = genindent(indent_level)
  815. lines = code.split('\n')
  816. lines = map(lambda x: indent + x, lines)
  817. return '\n'.join(lines) % kwds + '\n'
  818. def mcgen(code, **kwds):
  819. raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
  820. return re.sub(re.escape(eatspace) + ' *', '', raw)
  821. def basename(filename):
  822. return filename.split("/")[-1]
  823. def guardname(filename):
  824. guard = basename(filename).rsplit(".", 1)[0]
  825. for substr in [".", " ", "-"]:
  826. guard = guard.replace(substr, "_")
  827. return guard.upper() + '_H'
  828. def guardstart(name):
  829. return mcgen('''
  830. #ifndef %(name)s
  831. #define %(name)s
  832. ''',
  833. name=guardname(name))
  834. def guardend(name):
  835. return mcgen('''
  836. #endif /* %(name)s */
  837. ''',
  838. name=guardname(name))
  839. # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
  840. # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
  841. # ENUM24_Name -> ENUM24_NAME
  842. def _generate_enum_string(value):
  843. c_fun_str = c_fun(value, False)
  844. if value.isupper():
  845. return c_fun_str
  846. new_name = ''
  847. l = len(c_fun_str)
  848. for i in range(l):
  849. c = c_fun_str[i]
  850. # When c is upper and no "_" appears before, do more checks
  851. if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
  852. # Case 1: next string is lower
  853. # Case 2: previous string is digit
  854. if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
  855. c_fun_str[i - 1].isdigit():
  856. new_name += '_'
  857. new_name += c
  858. return new_name.lstrip('_').upper()
  859. def generate_enum_full_value(enum_name, enum_value):
  860. abbrev_string = _generate_enum_string(enum_name)
  861. value_string = _generate_enum_string(enum_value)
  862. return "%s_%s" % (abbrev_string, value_string)